/* ============ Поводок — дизайн-система ============ */
/* Токены (палитра, отступы, кегли, радиусы, тени) вынесены в tokens.css —
   один источник значений для портала и админки. main.css без него не
   работает: tokens.css подключается первым в base.html обоих. */

* { box-sizing: border-box; }

html {
  /* scroll-behavior: smooth убран: в Chrome он ломает восстановление позиции
     при возврате назад — из каталога в клинику и обратно список открывался
     с начала, а не с того места, где ушли. Плюс любой программный переход
     занимал около секунды. Плавность там, где она нужна, задаётся в JS
     точечно (полоса разделов на странице клиники). */
  /* якорные переходы не должны нырять под шапку и прилипшую строку */
  scroll-padding-top: calc(var(--header-h) + 76px);
}

/* Главная — исключение: полосу сокращаем до высоты шапки.

   Прилипшая строка поиска стоит на var(--header-h) + 10px, то есть внутри
   этой полосы. Браузер на каждой нажатой букве показывает каретку и, считая
   поле «под полосой», прокручивает страницу вверх; sticky тут же возвращает
   поле на прежнее место — и на следующей букве всё повторяется. Страница
   уезжала вверх на высоту поля с каждым символом (и сразу на 420px при
   клике в строку). Якорных ссылок на главной нет, полные 76px здесь ничего
   не защищают. На телефоне строка не липкая (mobile.css), поэтому правило
   только для десктопа — иначе оно перебило бы мобильный scroll-padding. */
@media (min-width: 881px) {
  html:has(.home-search) { scroll-padding-top: var(--header-h); }
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--text-base);
  /* 1.65 наследовался на всё подряд — кнопки, чипы, счётчики раздувались
     высотой строки, рассчитанной на длинный абзац. Читаемый интерлиньяж живёт
     там, где есть что читать: в .prose и .cl-about ниже. */
  line-height: var(--leading-normal);
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* цифры одной ширины: рейтинги, цены и телефоны не пляшут при смене цифр */
  font-variant-numeric: tabular-nums;
}

h1, h2, h3, h4 {
  color: var(--ink);
  text-wrap: balance;
  margin: 0 0 0.5em;
}
/* Трекинг по кеглю: крупному нужен минус, мелкому — нет. Раньше все уровни
   получали одинаковые -0.015em, и мелкие заголовки выглядели сжатыми. */
h1 { font-size: var(--t-h1); font-weight: 800; line-height: var(--leading-tight); letter-spacing: -0.025em; }
h2 { font-size: var(--t-h2); font-weight: 700; line-height: var(--leading-tight); letter-spacing: -0.018em; }
h3 { font-size: var(--t-h3); font-weight: 700; line-height: var(--leading-snug); letter-spacing: -0.01em; }
h4 { font-size: var(--text-base); font-weight: 700; line-height: var(--leading-snug); }

/* Длинный текст читается с воздухом, интерфейс — нет */
.prose, .cl-about, .lead, .tagline { line-height: var(--leading-relaxed); }
.prose p { text-wrap: pretty; }

p { margin: 0 0 1em; }
a { color: var(--violet-deep); text-decoration: none; }
@media (hover: hover) and (pointer: fine) {
  a:hover { text-decoration: underline; text-underline-offset: 3px; }
}
img { max-width: 100%; }

:focus-visible {
  outline: 2px solid var(--violet);
  outline-offset: 2px;
  border-radius: 4px;
}

.container {
  max-width: 1140px;
  margin: 0 auto;
  padding: 0 20px;
}
/* Две раскладки портала, и только две:
   контентная  — 1140px, читаемая колонка (главная, статьи, породы, болезни);
   каталожная  — во всю ширину, карте нужно место (клиники, врачи, поиск).
   Класс ставится на body, поэтому шапку и подвал тянет заодно с контентом —
   иначе логотип оказывается по центру, а содержимое у левого края. */

.section { margin: 56px 0; }
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-lg);
  margin-bottom: var(--space-xl);
}
.section-head h2 { margin: 0; }
.section-link {
  flex-shrink: 0;
  font-weight: 500;
  font-size: var(--text-sm);
  white-space: nowrap;
}

.eyebrow {
  display: inline-block;
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-strong);
  margin-bottom: 10px;
}

.muted { color: var(--text-muted); }
.small { font-size: var(--text-sm); }

/* ---------- Вертикальные отступы ---------- */
/* Единственные утилитарные классы в проекте, и заведены они не «чтобы было»,
   а взамен ста тридцати атрибутов style= по шаблонам: там стояли сырые
   margin-top:24px / margin-bottom:32px, то есть шкала --space-* объявлена
   единственным источником отступов, а половина страниц её обходила. Заодно
   в разметке встречались 28, 36, 18, 10 и 6 пикселей — значения не из
   шкалы вовсе; они сведены к ближайшей ступени.

   Набор намеренно короткий и только вертикальный: горизонтальные поля здесь
   задаёт контейнер, и утилита на них была бы лазейкой мимо раскладки. Если
   отступ нужен постоянно — ему место в правиле компонента, а не в классе
   у каждого вхождения. */
.mt-0 { margin-top: 0; }
.mt-sm { margin-top: var(--space-sm); }
.mt-md { margin-top: var(--space-md); }
.mt-lg { margin-top: var(--space-lg); }
.mt-xl { margin-top: var(--space-xl); }
.mt-2xl { margin-top: var(--space-2xl); }
.mt-3xl { margin-top: var(--space-3xl); }
.mb-0 { margin-bottom: 0; }
.mb-xs { margin-bottom: var(--space-xs); }
.mb-sm { margin-bottom: var(--space-sm); }
.mb-md { margin-bottom: var(--space-md); }
.mb-lg { margin-bottom: var(--space-lg); }
.mb-xl { margin-bottom: var(--space-xl); }
.mb-2xl { margin-bottom: var(--space-2xl); }
.mb-3xl { margin-bottom: var(--space-3xl); }
.m-0 { margin: 0; }

/* Ряд «значок/портрет + текст». Тоже взамен инлайна: по шаблонам стояло
   семь копий display:flex с зазорами 12, 14, 16, 20 и 22 — пять разных
   чисел на одно и то же решение, причём 14 и 22 не из шкалы вовсе. */
.row-flex { display: flex; gap: var(--space-lg); align-items: flex-start; }
.row-flex-mid { align-items: center; }
.row-flex-wrap { flex-wrap: wrap; }
.row-flex-md { gap: var(--space-md); }
.row-flex-xl { gap: var(--space-xl); }

/* Карточка-плитка без ссылки: .card задаёт курсор указателя, а эти
   плитки никуда не ведут. */
.card-static { cursor: default; }
/* Лид под заголовком раздела. По шаблонам стояло max-width:640/680/700px —
   три значения на одну задачу: не дать строке разъехаться до нечитаемой.
   Ограничение в ch, а не в пикселях: длину строки глаз меряет в знаках,
   и при смене кегля пиксельный предел перестаёт ей соответствовать. */
.measure { max-width: 68ch; }

/* Крупный значок над пустой выдачей — приглушённый, чтобы не спорить
   с текстом «ничего не нашлось». */
.lead-soft { color: var(--accent-soft); }


/* ---------- Шапка ---------- */

.header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(253, 253, 255, 0.85);
  backdrop-filter: saturate(1.4) blur(14px);
  -webkit-backdrop-filter: saturate(1.4) blur(14px);
  border-bottom: 1px solid var(--line);
}
.header-in {
  position: relative;
  display: flex;
  align-items: center;
  gap: 24px;
  height: var(--header-h);
}
/* Логотип: знак слева, справа надпись и подпись в столбик.
   Подпись — живой текст, а не часть картинки: в контурах она была высотой
   в четыре пикселя и не читалась (см. комментарий в base.html). Размеры
   подобраны так, чтобы строка подписи по ширине не выходила за надпись —
   в исходном локапе она занимает 81% её ширины. */
.logo {
  display: flex;
  align-items: center;
  gap: 10px;
  /* См. .logo-lockup ниже: логотип сжимается последним, но сжимается. */
  flex-shrink: 1;
  min-width: 0;
  color: inherit;
}
.logo-mark { height: 46px; width: auto; display: block; }
/* align-items: flex-start обязателен. У флекс-колонки выравнивание по умолчанию
   stretch, и картинка с width: auto растягивалась на всю ширину колонки —
   то есть по длине строки подписи. Надпись povodoc.ru от этого расплывалась
   по горизонтали на 10% на десктопе и на 36% на телефоне. */
.logo-lockup {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  min-width: 0;
  /* Логотип уступает место последним, но уступает. Раньше здесь стоял
     flex-shrink: 0 на .logo, и на 320px шапка (логотип 179 + поиск 44 +
     город 85 + зазоры) выезжала за строку в 280px — горизонтальную
     прокрутку получала вся страница, а не только шапка.

     Сжатие не задаётся медиазапросом намеренно: порог «узкого телефона»
     зависит от того, что ещё стоит в шапке (у вошедшего это кружок вместо
     кнопки «Войти»), и вычислять его числом значит промахиваться. Флекс
     считает сам: пока места хватает — локап нетронут и пропорция надписи
     к подписи та же, что в макете; когда не хватает — правый край надписи
     уходит под обрез, и это заметно куда меньше, чем уехавшая страница. */
  overflow: hidden;
}
/* Кегль надписи подобран под ширину подписи: в исходном локапе строка
   «сервис заботы о питомцах» чуть уже povodoc.ru, и эту пропорцию держим. */
.logo-word { height: 27px; width: auto; display: block; }
.logo-tagline {
  font-size: 11px;
  line-height: 1;
  font-weight: 500;
  letter-spacing: 0.005em;
  color: var(--text-muted);
  white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) {
  .logo:hover { text-decoration: none; }
}

.nav {
  display: flex;
  align-items: center;
  gap: 4px;
}
.nav-item { position: relative; }

/* Простая ссылка и кнопка-группа выглядят одинаково: разница только в
   поведении, визуально это один ряд пунктов. */
.nav-link,
.nav-trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding: 8px 14px;
  border: 0;
  border-radius: var(--r-pill);
  background: none;
  font: inherit;
  font-weight: 500;
  font-size: var(--text-base);
  color: var(--text);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .nav-link:hover,
  .nav-trigger:hover { background: var(--surface-1); text-decoration: none; color: var(--accent-strong); }
}
.nav-link:focus-visible,
.nav-trigger:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
/* Текущий раздел — цветом и насыщенностью, без заливки. Залитая таблетка
   весила ровно столько же, сколько раскрытое меню, и «вы здесь» спорило
   с «меню открыто»; фон в этом ряду теперь значит только взаимодействие.
   Где человек находится, дублируют хлебные крошки и панель вкладок. */
.nav-link.active,
.nav-trigger.active { color: var(--accent-ink); font-weight: 600; }
/* Открытая группа держит подсветку, пока список виден — иначе связь кнопки
   с висящей под ней панелью читается только по геометрии. Активный пункт
   отдельного правила больше не требует: фон у всех групп один. */
.nav-trigger[aria-expanded="true"] { background: var(--surface-1); color: var(--accent-strong); }

/* Базовая иконка chevron нарисована вправо — доворачиваем вниз, при открытии вверх */
.nav-caret {
  display: flex;
  color: var(--text-subtle);
  transform: rotate(90deg);
  transition: transform var(--t-med) var(--ease-out);
}
.nav-trigger[aria-expanded="true"] .nav-caret { transform: rotate(-90deg); color: currentColor; }

.nav-menu {
  position: absolute;
  top: calc(100% + var(--space-sm));
  left: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  min-width: 100%;
  padding: var(--space-xs);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  /* Тень — только у всплывающих слоёв: панель отрывается от шапки, а не
     лежит в потоке. */
  box-shadow: var(--shadow-md);
  /* Тот же выезд, что у меню сортировки: два выпадающих списка на сайте
     должны появляться одинаково */
  animation: nav-menu-in 160ms var(--ease-out) both;
}
@keyframes nav-menu-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .nav-menu { animation: none; }
  .nav-caret { transition: none; }
}
.nav-menu[hidden] { display: none; }
.nav-menu a {
  padding: 9px 12px;
  border-radius: var(--r-sm);
  color: var(--text);
  font-size: var(--text-sm);
  white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) {
  .nav-menu a:hover { background: var(--surface-1); color: var(--accent-strong); text-decoration: none; }
}
.nav-menu a:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }

@media (hover: hover) and (pointer: fine) and (min-width: 881px) {
  /* Мостик через зазор между кнопкой и панелью. Без него курсор по дороге
     вниз выходит за границы .nav-item, mouseleave срабатывает, и список
     закрывается на полпути к первой строке. */
  .nav-menu::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: calc(var(--space-sm) * -1);
    height: var(--space-sm);
  }
}

/* Правая часть шапки: город и вход. Геометрия у них общая — они стоят
   в одной строке, и разъехавшаяся высота там заметна сразу. До этого её
   задавали порознь: 9px/16px против 8px/14px, то есть 41px против 37px,
   четыре разных числа на одно решение и ни одного из шкалы --space-*. */
.city-btn,
.acc-login {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-lg);
  /* Рамка есть всегда и прозрачна: она проявляется при наведении у города,
     и без неё в этот момент прыгала бы ширина. */
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 500;
  white-space: nowrap;
  transition: background-color var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out);
}

/* Город — это контекст, а не действие: он отвечает на вопрос «где я»,
   и меняют его от силы один раз. Поэтому заливки у него нет.

   Раньше город и вход были залиты одним и тем же цветом (--lav-1 у одного,
   --surface-1 у другого — разные имена одного значения), одинаково скруглены
   и набраны одним весом. Два одинаковых пятна рядом не давали глазу понять,
   что здесь главное, и одинаковый вид у элементов разной важности читается
   как «компоненты совпали не по замыслу, а потому что так вышло». */
.city-btn {
  background: transparent;
  color: var(--text);
  cursor: pointer;
}
/* Город с подсказкой прижаты вправо вместе: margin-left переехал с кнопки
   на блок, иначе внутри него кнопка отжимала бы саму себя. */
.city-slot { position: relative; margin-left: auto; }
.city-btn svg { color: var(--accent-strong); flex-shrink: 0; }
@media (hover: hover) and (pointer: fine) {
  /* Наведение поднимает город до вида кнопки — но только на время наведения */
  .city-btn:hover { background-color: var(--surface-1); border-color: var(--border); }
}
.city-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
/* Пара подписей «Выберите город»/«Город»: длинная живёт на широких экранах,
   короткая включается на узких (см. медиазапрос 560px ниже). */
.city-btn-label-short { display: none; }
/* Строка шапки заполнена целиком: логотип 218 + меню 555 + город + вход
   при контейнере 1140. С кнопкой входа длинная подпись «Выберите город»
   переставала помещаться и переносилась на вторую строку — в этом проекте
   подпись кнопки не переносится никогда. Поэтому рядом с входом город
   подписан коротко; полностью вопрос задаёт карточка-подсказка под шапкой,
   там места достаточно. :has() выбирает именно случай «гость», у вошедшего
   на месте кнопки кружок 32px и длинная подпись помещается. */
.header-in:has(.acc-login) .city-btn-label-full { display: none; }
.header-in:has(.acc-login) .city-btn-label-short { display: inline; }
.city-btn { white-space: nowrap; }

/* Подтверждение города — карточка под кнопкой города.
   Считается от .city-slot, то есть от самой кнопки. Раньше — от .header-in,
   и тогда положение уголка приходилось задавать отступом от правого края
   шапки. Между этим краем и городом стоит «Войти», ширина которого меняется
   от состояния и подписи, — уголок с фиксированным отступом от края уехал
   на «Войти» и спрашивал про город, указывая на вход.

   Уголок сидит на --arrow-inset от правого края карточки, а карточка
   отодвинута так, чтобы эта точка пришлась ровно на центр кнопки:
   right: 50% ставит правый край карточки в центр кнопки, +inset возвращает
   уголок на него. Ширина кнопки, карточки и всего, что справа, в расчёт
   не входит — отсюда одна формула на все экраны. */
.city-hint {
  /* Отступ уголка от правого края карточки. Больше радиуса скругления
     плюс половина уголка — иначе он сидит на закруглении. */
  --arrow-inset: 30px;
  position: absolute;
  top: calc(100% + var(--space-sm));
  right: calc(50% - var(--arrow-inset));
  z-index: 60;
  width: 268px;
  padding: var(--space-xl);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  text-align: center;
  animation: city-hint-in var(--t-med) var(--ease-out) both;
}
.city-hint[hidden] { display: none; }
@keyframes city-hint-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .city-hint { animation: none; } }
/* Уголок к кнопке города */
.city-hint::before {
  content: "";
  position: absolute;
  top: -7px;
  right: calc(var(--arrow-inset) - 6px);   /* -6px: половина ширины уголка */
  width: 12px;
  height: 12px;
  background: var(--surface);
  border-left: 1px solid var(--border);
  border-top: 1px solid var(--border);
  transform: rotate(45deg);
}
.city-hint-title { margin: 0 0 var(--space-sm); font-size: var(--text-lg); font-weight: 700; }
.city-hint-text {
  margin: 0 0 var(--space-lg);
  font-size: var(--text-sm);
  color: var(--text-muted);
  line-height: var(--leading-normal);
}
.city-hint-yes { width: 100%; }
.city-hint-other {
  margin-top: var(--space-md);
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--text-sm);
  color: var(--text-muted);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.city-hint-other:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; border-radius: var(--r-sm); }
@media (hover: hover) and (pointer: fine) {
  .city-hint-other:hover { color: var(--accent-strong); }
}

/* ---------- Модальное окно выбора города ---------- */

body.modal-open { overflow: hidden; }

.city-modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.city-modal[hidden] { display: none; }
.city-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(39, 39, 108, 0.45);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.city-modal-card {
  position: relative;
  width: 100%;
  /* Ширина под два столбца городов; «Санкт-Петербург» и «Нижний Новгород» —
     самые длинные названия, по ним и считан минимум колонки. */
  max-width: 520px;
  /* Прокрутка остаётся страховкой для низких экранов (телефон в альбомной
     ориентации), в обычной раскладке список помещается целиком. */
  max-height: calc(100vh - 32px);
  overflow-y: auto;
  background: var(--card);
  border-radius: var(--r-lg, 20px);
  box-shadow: var(--shadow-md);
  padding: 22px 22px 18px;
  animation: city-modal-in var(--t-med, 0.25s) var(--ease-out, ease) both;
}
@keyframes city-modal-in {
  from { opacity: 0; transform: translateY(10px) scale(0.98); }
  to { opacity: 1; transform: none; }
}
/* Закрытие тоже анимировано: слой, исчезающий кадром, читается как сбой.
   Класс вешает скрипт в base.html и прячет узел по её окончании; на телефоне
   та же метка запускает уезжающий вниз лист (mobile.css). */
.city-modal.is-closing .city-modal-card { animation: city-modal-out 180ms var(--ease-out) both; }
.city-modal.is-closing .city-modal-backdrop { animation: city-modal-fade 180ms var(--ease-out) both; }
@keyframes city-modal-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(8px) scale(0.98); }
}
@keyframes city-modal-fade { from { opacity: 1; } to { opacity: 0; } }
.city-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}
.city-modal-title { margin: 0; font-size: var(--text-lg); }
.city-modal-close {
  border: none;
  background: var(--lav-1);
  border-radius: var(--r-pill);
  padding: 8px;
  line-height: 0;
  color: var(--muted);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .city-modal-close:hover { background: var(--lav-2); color: var(--indigo); }
}
/* Два столбца: шестнадцать городов в один столбик не помещаются на экран, а
   прокрутка внутри модалки прячет половину списка. Grid, а не columns: на
   узком экране «Санкт-Петербург» не влезает в столбец 148px и переносится —
   в многоколоночной раскладке от этого съезжает весь столбец, в сетке
   растёт только своя строка, и столбцы остаются на одной линии. */
.city-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2px var(--space-sm);
}
.city-list button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 11px 14px;
  border: none;
  border-radius: var(--r-sm, 10px);
  background: none;
  font: inherit;
  font-size: var(--text-base);
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .city-list button:hover { background: var(--lav-1); color: var(--violet-deep); }
}
.city-list button.active { background: var(--lav-2); color: var(--indigo); font-weight: 700; }
.city-list button svg { color: var(--violet-deep); flex-shrink: 0; }
.city-list-empty { padding: 11px 14px; color: var(--muted); font-size: var(--text-sm); }


.burger {
  display: none;
  margin-left: auto;
  border: 1px solid var(--line);
  background: var(--card);
  border-radius: var(--r-sm);
  padding: 9px 11px;
  cursor: pointer;
  line-height: 0;
  /* Значок берётся из общего набора и красится currentColor. Раньше он был
     врисован в разметку с stroke="#27276c" — цвет мимо токенов, который
     не менялся бы при смене брендового индиго. */
  color: var(--accent-ink);
}

/* Промежуточная ступень шапки. С четырьмя группами меню в строку перестаёт
   помещаться уже около 1000px: подпись кнопки города ломается на две строки,
   дальше появляется горизонтальная прокрутка. Уходить в бургер на 1000px
   нельзя — под него попадают ноутбуки 1024, поэтому сначала отыгрываем
   ширину на полях, зазорах и кегле, и только потом сворачиваемся. */
@media (min-width: 881px) and (max-width: 1100px) {
  .header-in { gap: 14px; }
  /* Логотип отдаёт ширину вместе с меню и городом: с подписью живым текстом
     локап стал на 25px шире прежней картинки, и на 900px кнопка города
     вылезала за поле контейнера. */
  .logo-mark { height: 40px; }
  .logo-word { height: 22px; }
  .logo-tagline { font-size: 9px; }
  .nav { gap: 0; }
  .nav-link,
  .nav-trigger { padding: 8px 10px; font-size: var(--text-sm); }
  /* Оба контрола вместе, иначе высота снова разъедется */
  .city-btn,
  .acc-login { padding: var(--space-sm) var(--space-md); }
  .city-btn-label { max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* Нижний край той же ступени. Отыгранного выше не хватало: на 881–920px
   логотип, меню, город и вход в сумме давали 876px при 841px под них —
   шапка получала горизонтальную прокрутку, и вместе с ней вся страница.
   Снимаем подпись логотипа: из всего, что стоит в шапке, она единственная
   ничего не открывает. Знак и слово povodoc.ru остаются, ссылка «на главную»
   и её aria-label — тоже, поэтому ни функция, ни доступность не страдают. */
@media (min-width: 881px) and (max-width: 1000px) {
  .logo-tagline { display: none; }
  /* Знак задаёт высоту, слово идёт следом — уменьшать надо слово: подпись
     снята, и теперь именно оно определяет ширину локапа. */
  .logo-word { height: 19px; }
  .nav-link,
  .nav-trigger { padding: 8px 7px; }
  /* Город и вход поджимаются вместе — порознь они снова разъедутся */
  .city-btn,
  .acc-login { padding: var(--space-sm) var(--space-md); }
}


/* Неразрывный фрагмент: фильтр nobr_times оборачивает им диапазоны времени */
.nobr { white-space: nowrap; }

/* Текст только для скринридеров — там, где смысл несёт значок без подписи */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- Хлебные крошки ---------- */

.crumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  padding: 18px 0 0;
  font-size: var(--text-sm);
  color: var(--text-subtle);
}
/* База .crumbs даёт padding-top:18px для обычных страниц — в панели ритм
   задаёт gap, поэтому свой отступ крошек гасим. */
.agg-panel .crumbs { padding-top: 0; }
.crumbs a { color: var(--text-muted); }
.crumbs .sep { color: var(--surface-3); }

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  padding: var(--space-md) 22px;
  border-radius: var(--r-pill);
  border: none;
  font: inherit;
  font-weight: 700;
  font-size: var(--text-base);
  cursor: pointer;
  text-decoration: none !important;
  /* Подпись кнопки не переносится: «На карте» в две строки давала кнопки
     разной высоты в одном ряду. Если не влезает — ужимаем паддинг, не текст. */
  white-space: nowrap;
  transition: transform var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
}
/* Иконка в кнопке не сжимается: как флекс-элемент SVG ужимался до нуля, когда
   подпись переставала влезать, и в узкой карточке каталога у кнопки с номером
   телефона значок пропадал совсем. */
.btn svg { flex: none; }
.btn:active { transform: scale(0.97); }
.btn-primary {
  background: var(--accent);
  color: var(--on-accent);
  /* Двухслойная тень: плотный контактный слой держит край, мягкий даёт объём.
     Тонирована в индиго — без фиолетовой подсветки. */
  box-shadow: 0 1px 2px rgba(39, 39, 108, 0.26), 0 3px 10px rgba(39, 39, 108, 0.18);
}
@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover {
    background: var(--accent-strong);
    box-shadow: 0 1px 2px rgba(39, 39, 108, 0.28), 0 5px 14px rgba(39, 39, 108, 0.22);
  }
}
.btn-ghost {
  background: var(--surface-1);
  color: var(--accent-ink);
}
@media (hover: hover) and (pointer: fine) {
  .btn-ghost:hover { background: var(--surface-2); }
}

.chips { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-sm) var(--space-lg);
  border-radius: var(--r-pill);
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: 500;
  transition: transform var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out);
}
.chip:active { transform: scale(0.97); }
@media (hover: hover) and (pointer: fine) {
  .chip:hover { border-color: var(--accent-soft); background: var(--surface-1); text-decoration: none; }
}
.chip.active {
  background: var(--accent-ink);
  border-color: var(--accent-ink);
  color: var(--on-accent);
}

/* ---------- Карточки ---------- */

.grid { display: grid; gap: 16px; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1000px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .grid-3 { grid-template-columns: repeat(2, 1fr); }
}

/* Карточка держится бордером, а не тенью. Раньше здесь было и то, и другое
   плюс подъём на 3px при наведении — набор, по которому интерфейс узнаётся
   как сгенерированный: тень на каждой плитке и «карточка подпрыгивает» это
   язык лендинга, а не справочника.

   Фон страницы (--bg) холоднее белого именно затем, чтобы белую карточку
   было видно без тени — подпорка не нужна. Тени остаются там, где они
   означают высоту по-настоящему: у всплывающих слоёв (модалка, лист,
   поповер, подсказка города).

   Отклик на наведение — цвет обводки и подложка: он такой же заметный,
   но не двигает раскладку и не спорит с соседними карточками. */
.card {
  display: block;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--space-xl);
  color: var(--text);
  text-decoration: none !important;
  transition: border-color var(--t-fast) var(--ease-out), background var(--t-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  a.card:hover {
    border-color: var(--accent-soft);
    background: var(--surface-1);
  }
}
a.card:active { background: var(--surface-2); }

.card h3 { margin: 0 0 6px; }
.card .muted { margin: 0; font-size: var(--text-sm); }

/* Аватар-заглушка с градиентом по hue */
.avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-md);
  background:
    radial-gradient(120% 120% at 20% 0%, hsl(var(--h, 255) 84% 92%) 0%, hsl(var(--h, 255) 72% 82%) 100%);
  color: hsl(var(--h, 255) 55% 32%);
  font-weight: 800;
  overflow: hidden;
  flex-shrink: 0;
  user-select: none;
}
.avatar-lg { width: 100%; aspect-ratio: 16/9; font-size: var(--text-3xl); border-radius: var(--r-md) var(--r-md) 0 0; }
/* Крупный портретный аватар (карточка врача, эксперта, породы). Раньше три
   шаблона задавали его инлайном разными кеглями: 2rem, 2rem и 2.2rem. */
.avatar-xl { width: 96px; height: 96px; font-size: var(--t-h2); }
/* Имя эксперта в сетке — размер брался инлайном в шаблоне */
.expert-name { font-size: var(--text-base); }
.avatar-md { width: 64px; height: 64px; font-size: var(--text-xl); border-radius: 18px; }
.avatar-sm { width: 44px; height: 44px; font-size: var(--text-base); border-radius: 13px; }
.avatar-round { border-radius: 50%; }
/* Аватар-картинка (иллюстрированный портрет эксперта): те же рамки,
   заливка кадром вместо градиента с инициалами. */
img.avatar { object-fit: cover; }

.card-cover { padding: 0; overflow: hidden; }
.card-cover .card-body { padding: 16px 20px 20px; }

/* Рейтинг */
.stars { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-sm); color: var(--muted); }
.stars .val { color: var(--amber-ink); font-weight: 700; }
.stars svg { color: #f2a91e; }

/* ---------- Каталог-агрегатор: панель, список, карта ---------- */

/* Шапка каталога: вертикальный ритм между заголовком, поиском, фильтрами
   и счётчиком. */
.agg-panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Поиск по каталогу. Стоит первым в левой колонке, поэтому его верх
   совпадает с верхом карты — обе в первом ряду одной сетки. */
/* Прежняя версия поля — пилюля с тенью и прозрачным инпутом внутри — удалена.
   Новая рамка задаётся у самого инпута (ниже, в разделе каталога), и вместе
   они давали коробку внутри пилюли. Поле теперь одно и совпадает по рамке
   и радиусу с фильтрами под ним. */
.agg-search input::-webkit-search-cancel-button { display: none; }

/* Строка фасетов-чипов удалена вместе с прежней шапкой каталога. */
.fchip {
  flex-shrink: 0;
  padding: 7px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--card);
  color: var(--indigo);
  font-size: var(--text-xs);
  font-weight: 500;
  text-decoration: none !important;
  white-space: nowrap;
  transition: border-color var(--t-fast) var(--ease-out),
              background-color var(--t-fast) var(--ease-out);
}
.fchip.on { background: var(--indigo); border-color: var(--indigo); color: #fff !important; }
@media (hover: hover) and (pointer: fine) {
  .fchip:hover { border-color: var(--violet-soft); }
  .fchip.on:hover { border-color: var(--indigo); }
}

.agg-head {
  display: flex;
  align-items: baseline;
  gap: 18px;
  flex-wrap: wrap;
  /* Вертикальный ритм задаёт gap панели — свои поля тут сдвоили бы его */
  margin: 0;
}
.agg-h1 {
  margin: 0;
  /* тот же текучий корень, что у h1/h2 — иначе заголовок каталога
     масштабировался со своей скоростью и ломал общую пропорцию */
  font-size: var(--t-h2);
  font-weight: 800;
  letter-spacing: -0.018em;
}
.agg-count { margin: 0; font-size: var(--text-sm); font-weight: 700; color: var(--muted); }
/* Сортировка — иконка-кнопка с выпадающим списком */
.sort { position: relative; margin-left: auto; }
.sort-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--card);
  color: var(--indigo);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 500;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease-out),
              background-color var(--t-fast) var(--ease-out);
}
.sort-btn svg { color: var(--violet-deep); }
@media (hover: hover) and (pointer: fine) {
  .sort-btn:hover { border-color: var(--violet-soft); }
}
.sort-btn:focus-visible { outline: 2px solid var(--violet-soft); outline-offset: 2px; }
@keyframes sort-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

.catalog {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr);
  gap: 20px;
  align-items: start;
  margin-top: 16px;
}

/* Каталог врачей — тот же компонент, но одна колонка: карты справа у него
   нет. У врача нет своих координат, он привязан к клинике, и точка на карте
   отвечала бы на вопрос «где клиника», а не «какой врач». */
.catalog-wide { grid-template-columns: minmax(0, 1fr); }

/* Крошки вынесены под выдачу — отделяем их линией от карточек */
.catalog-crumbs {
  margin-top: 28px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}
.catalog-crumbs .crumbs { padding-top: 0; }
/* Крошки в конце страницы клиники — тот же приём, что в каталоге */
.crumbs-bottom {
  margin-top: var(--space-2xl);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--line);
}
.crumbs-bottom .crumbs { padding-top: 0; }
.catalog-list { display: flex; flex-direction: column; gap: 12px; }


/* Навигация страниц каталога */
.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: 14px;
  padding-top: 4px;
}
.pager-now { font-size: var(--text-sm); font-weight: 700; color: var(--muted); }
.pager-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--lav-1);
  color: var(--indigo);
  transition: background-color var(--t-fast) var(--ease-out);
}
.pager-arrow.prev, .pager-arrow:not(.next) { transform: rotate(180deg); }
.pager-arrow.off { opacity: 0.35; pointer-events: none; }
@media (hover: hover) and (pointer: fine) {
  .pager-arrow:hover { background: var(--lav-2); text-decoration: none; }
}

/* Скроллит страница, карта и панель фильтров прилипают (position: sticky).
   Раньше здесь был внутренний скролл списка фиксированной высоты со сжатием
   панели — но сжатие меняло высоту скролл-области, а это на коротком списке
   давало петлю: контент вдруг помещался целиком, браузер сбрасывал scrollTop,
   сжатие снималось — и список дёргался, не прокручиваясь. Sticky-раскладка
   (как у отельных агрегаторов) убирает петлю: высота ничего не меняет.
   Панель остаётся видимой при скролле — то, ради чего задумывалось сжатие. */
/* Липкая панель убрана. Она задумывалась под прежнюю раскладку, где сверху
   был компактный бар поиска, а sticky-search.js сжимал его при прокрутке.
   Новая шапка каталога — заголовок, широкий поиск, два фильтра, флажок
   и счётчик, около 340px: прилипая целиком, она примораживалась над списком
   и клиники уезжали под неё. Классы .is-stuck удалены вместе с ней. */

@media (min-width: 1101px) and (prefers-reduced-motion: reduce) {
  .agg-search, .agg-search input, .agg-search .search-submit,
  .fchip, .agg-h1 { transition: none; }
}

/* --- карточка: фото | сведения | действия --- */
/* Прежняя карточка каталога — плитка с каруселью фото, рамкой, радиусом 22
   и тенью на ховере — удалена вместе с разметкой: выдача перестроена
   в список строк, а карусель, .hc-addr, .hc-geo, .hc-score, .hc-svc,
   .hc-docs и .hc-tel в шаблоне больше не встречаются. Новые правила
   лежат ниже, в разделе каталога. */

.catalog-map {
  position: sticky;
  /* Точка прилипания совпадает с естественным положением карты: над сеткой
     ничего нет, только шапка и отступ .catalog. Если бы сверху стояли крошки,
     при нулевой прокрутке карта начиналась бы ниже и её низ уходил бы за
     край экрана — высота считается от точки прилипания, а не от факта. */
  top: calc(var(--header-h) + 16px);
  height: calc(100vh - var(--header-h) - 36px);
  min-height: 420px;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--lav-1);
}
.map-canvas { width: 100%; height: 100%; }

.map-stub {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding: 28px;
  text-align: center;
  color: var(--faint);
}
.map-stub-title { margin: 12px 0 4px; font-weight: 700; color: var(--muted); }
.map-stub-text { margin: 0; font-size: var(--text-sm); max-width: 280px; }

/* Метка на карте: пилюля с рейтингом — как ценник у отельных агрегаторов.
   Рисуется шаблоном Яндекса, поэтому это div, а не кнопка. */
.map-pin {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transform: translate(-50%, -50%);
  min-width: 40px;
  height: 28px;
  padding: 0 10px;
  border: 2px solid #fff;
  border-radius: var(--r-pill);
  background: var(--violet);
  color: #fff;
  font-size: var(--text-2xs);
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(58, 33, 148, 0.3), 0 3px 10px rgba(125, 91, 247, 0.3);
  transition: background-color var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.map-pin.is-active,
.map-pin:hover { background: var(--indigo); transform: translate(-50%, -50%) scale(1.12); }

.map-balloon { font-family: var(--font); line-height: 1.4; }
.map-balloon .bl-name { font-weight: 700; color: var(--ink); font-size: var(--text-base); }
.map-balloon .bl-addr { color: var(--muted); font-size: var(--text-xs); margin-top: 3px; }
.map-balloon .bl-rate { color: var(--amber-ink); font-weight: 700; font-size: var(--text-xs); margin-top: 6px; }
.map-balloon .bl-24 {
  display: inline-block;
  margin-top: 7px;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: var(--green-bg);
  color: var(--green-ink);
  font-size: var(--text-2xs);
  font-weight: 700;
}

/* Раскладки «список слева + липкая карта справа» здесь больше нет.
   Карта стала отдельным видом по ?vid=karta (см. .catalog { display: block }
   ниже по файлу), поэтому колонок у каталога нет вовсе, а карточка выдачи
   описана одним разделом «Карточка клиники» — там же её медиазапросы.

   Раньше на этом месте стояла лестница 1699 / 1360 / 1081–1240 / 1080 / 720
   от прежнего поколения. Она уже ничего не решала: grid-template-columns
   задавались блочному элементу, а .hc и .catalog-map переопределялись
   безусловными правилами ниже по файлу — из всего блока доезжали только
   обрывки вроде padding у колонок и flex-направления, из-за которых
   карточка на 1100–1240px собиралась не так, как на 1280px. */

/* ---------- Hero ---------- */

/* ---------- Шапка раздела ---------- */
/* Заголовок, строка-пояснение и переходы в подразделы. Раньше это был блок
   .hero: лавандовая панель со скруглением 28px, двумя радиальными
   градиентами-«свечениями» и лапой в 240px водяным знаком, высотой около
   330px на десктопе.

   Что с ним было не так. Хаб и «О проекте» — справочные страницы: человек
   приходит на них за переходом дальше, а не за впечатлением. Панель отдавала
   первый экран заголовку, одной строке и двум чипам — на /sobaki/zdorove/
   это пять ссылок на весь первый экран. Мягкое цветное свечение за крупным
   заголовком вдобавок ровно тот приём, по которому страница читается как
   сгенерированная, а к бренду он отношения не имеет: у «Поводка» язык
   справочника, а не лендинга.

   Стало: та же информация без подложки, прижатая к левому краю и отбитая
   снизу линией. Заголовок и пояснение никуда не делись, чипы остались
   навигацией, а содержимое поднялось примерно на 240px — на хабе первый
   экран теперь занимают сами разделы. */
.page-head {
  margin-top: var(--space-2xl);
  padding-bottom: var(--space-2xl);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-3xl);
}
.page-head h1 { max-width: 20ch; }
.page-head .lead {
  max-width: 60ch;
  margin: var(--space-md) 0 0;
  font-size: var(--text-lg);
  line-height: var(--leading-normal);
  color: var(--text-muted);
}
/* Чипы — переходы в подразделы, поэтому они ближе к содержимому,
   чем к заголовку. */
.page-head .chips { margin-top: var(--space-xl); }
/* Шапка уже отбита снизу линией и своим полем — верхнее поле первой секции
   к ним прибавлялось, и под линией зияло 88px пустоты. */
.page-head + .section { margin-top: 0; }

/* Панели в ряду держат свою высоту, а не тянутся под самую высокую соседку:
   в справочнике разделы наполнены неравномерно (симптомов три, болезней
   две), и растянутая панель показывает не содержимое, а полупустой блок. */
.grid-2 > .card,
.grid-2 > .panel { align-self: start; }
.grid-2 { align-items: start; }

.hero-search { max-width: 620px; }

/* ---------- Правила и обязательства списком ---------- */
/* Термин и его объяснение в строку, строки разделены хайрлайном. Замена
   трём одинаковым карточкам в ряд: там каждый пункт был отдельным блоком,
   здесь их можно сравнить взглядом сверху вниз, и занимают они втрое
   меньше высоты. Тот же приём, что у «Документов» ниже по странице —
   у страницы получается один язык, а не два. */
.rules { margin: 0; }
.rules-row {
  display: grid;
  grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
  gap: var(--space-lg) var(--space-3xl);
  padding: var(--space-lg) 0;
  border-top: 1px solid var(--border);
}
.rules-row:last-child { border-bottom: 1px solid var(--border); }
.rules dt {
  margin: 0;
  font-weight: 600;
  color: var(--text);
}
.rules dd {
  margin: 0;
  color: var(--text-muted);
  line-height: var(--leading-normal);
}

/* ---------- Контентная страница ---------- */

.page-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 40px;
  align-items: start;
}
@media (max-width: 1000px) {
  /* minmax(0, 1fr), а не 1fr: у 1fr минимальная ширина — min-content, и любой
     широкий потомок (сетка врачей с колонкой 340px, лента чипов сортировки
     отзывов) распирал колонку изнутри. На 390px страница клиники получала
     горизонтальную прокрутку в 504px при экране в 390. */
  .page-grid { grid-template-columns: minmax(0, 1fr); }
}

.prose { max-width: 72ch; }
.prose h2 {
  margin-top: 1.8em;
  padding-top: 0.4em;
}
.prose ul { padding-left: 1.2em; margin: 0 0 1em; }
.prose li { margin-bottom: 0.35em; }
/* Списки-компоненты внутри .prose — не маркированные перечни, а разметка
   разделов: прайс, таймлайн, станции рядом. `.prose ul` (0,1,1) специфичнее
   их собственных классов, поэтому отступ маркера сдвигал прайс на 19px
   вправо относительно заголовка своего раздела. Тот же случай уже разбирался
   у .dr-time — здесь он закрыт для всех разом. */
.prose :is(.sv-groups, .sv-items, .dr-time, .rv-criteria, .metro-near-list, .cl-facts, .near-list) {
  padding-left: 0;
  list-style: none;
}

.callout {
  border-radius: var(--r-md);
  padding: 18px 22px;
  margin: 0 0 24px;
}
.callout .ttl {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  margin-bottom: 6px;
}
.callout p:last-child { margin-bottom: 0; }
.callout-tldr { background: var(--surface-1); border: 1px solid var(--surface-2); }
.callout-tldr .ttl { color: var(--accent-ink); }
.callout-urgent { background: var(--rose-bg); border: 1px solid #f7d5de; }
.callout-urgent .ttl { color: var(--rose-ink); }
.callout-ok { background: var(--green-bg); border: 1px solid #cdeeda; }
.callout-ok .ttl { color: var(--green-ink); }

/* Таблицы */
.table-wrap { overflow-x: auto; border-radius: var(--r-md); border: 1px solid var(--line); }
table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  background: var(--card);
}
table.data th, table.data td {
  padding: 12px 16px;
  text-align: left;
  border-bottom: 1px solid var(--line);
}
table.data th {
  background: var(--lav-1);
  color: var(--indigo);
  font-weight: 700;
  white-space: nowrap;
}
table.data tr:last-child td { border-bottom: none; }
table.data tr:nth-child(even) td { background: #fbfaff; }

/* Характеристики породы */
.facts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px;
  margin: 22px 0;
}
.fact {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 12px 16px;
}
.fact .k { font-size: var(--text-2xs); color: var(--faint); margin-bottom: 2px; }
.fact .v { font-weight: 700; font-size: var(--text-sm); }

/* Плюсы/минусы */
.pros-cons { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin: 22px 0; }
.pc {
  border-radius: var(--r-md);
  padding: 18px 22px;
}
.pc.pros { background: var(--green-bg); }
.pc.cons { background: var(--rose-bg); }
.pc h3 { margin-bottom: 10px; }
.pc.pros h3 { color: var(--green-ink); }
.pc.cons h3 { color: var(--rose-ink); }
.pc ul { margin: 0; padding-left: 1.2em; }
.pc li { margin-bottom: 6px; }

/* FAQ */
.faq details {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  margin-bottom: 10px;
  overflow: hidden;
}
.faq summary {
  padding: 16px 20px;
  font-weight: 700;
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  transition: background-color var(--t-fast) var(--ease-out);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "";
  width: 10px;
  height: 10px;
  flex-shrink: 0;
  border-right: 2px solid var(--faint);
  border-bottom: 2px solid var(--faint);
  transform: rotate(45deg);
  transition: transform var(--t-med) var(--ease-out);
}
.faq details[open] summary::after { transform: rotate(225deg); }
@media (hover: hover) and (pointer: fine) {
  .faq summary:hover { background: var(--lav-1); }
}
.faq .faq-a { padding: 0 20px 16px; color: var(--muted); }

/* E-E-A-T блок */
.eeat {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 28px;
  align-items: center;
  background: var(--lav-1);
  border: 1px solid var(--lav-2);
  border-radius: var(--r-md);
  padding: 16px 20px;
  margin: 28px 0;
  font-size: var(--text-sm);
}
.eeat .person { display: flex; align-items: center; gap: 10px; }
.eeat .person a { font-weight: 700; color: var(--indigo); }
.eeat .lbl { color: var(--faint); font-size: var(--text-2xs); display: block; }
.eeat .dates { margin-left: auto; color: var(--faint); font-size: var(--text-xs); }
/* Галочка — значок набора вместо текстового ✓, поэтому строка становится
   флексом: у block-элемента значок вставал бы на базовую линию и «ехал». */
.eeat .check {
  color: var(--green-ink);
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: 4px;
}
.eeat .check svg { flex-shrink: 0; }

/* Сайдбар */
/* Зазор между коробками сайдбара ужат с 16 до 8: место отдано карте,
   а коробки и так разделены рамкой и фоном. */
.side { position: sticky; top: 88px; display: grid; gap: var(--space-sm); }
.side-box {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 20px;
}
.side-box h3 { font-size: var(--text-base); margin-bottom: 12px; }
.side-box ul { list-style: none; margin: 0; padding: 0; }
.side-box li { margin-bottom: 10px; }
.side-box li a { color: var(--ink); font-size: var(--text-sm); font-weight: 500; }
@media (hover: hover) and (pointer: fine) {
  .side-box li a:hover { color: var(--violet-deep); }
}
.side-cta {
  background: linear-gradient(135deg, var(--indigo) 0%, #3a3691 100%);
  color: #fff;
  border: none;
}
.side-cta h3 { color: #fff; }
.side-cta p { color: #cfcbf2; font-size: var(--text-sm); }

/* Источники */
.sources {
  border-top: 1px solid var(--line);
  margin-top: 32px;
  padding-top: 18px;
  font-size: var(--text-xs);
  color: var(--muted);
}
.sources ol { padding-left: 1.3em; margin: 8px 0 0; }

/* ---------- Заглушки разделов ---------- */

.stub-hero {
  text-align: center;
  padding: clamp(48px, 8vw, 96px) 20px;
  background:
    radial-gradient(55% 80% at 50% 0%, var(--lav-2) 0%, transparent 65%),
    var(--lav-1);
  border-radius: var(--r-xl);
  margin-top: 20px;
}
.stub-hero .emoji { line-height: 1; display: block; margin-bottom: 18px; color: var(--violet); }
.stub-hero h1 { margin-bottom: 12px; }
.stub-hero .lead { max-width: 520px; margin: 0 auto 26px; color: var(--muted); }
.stub-points {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-bottom: 30px;
}
.badge-soon {
  display: inline-block;
  background: var(--lav-2);
  color: var(--indigo);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-radius: var(--r-pill);
  padding: 6px 14px;
  margin-bottom: 18px;
}

/* ---------- Подвал ---------- */

.footer {
  margin-top: 80px;
  background: var(--indigo);
  color: #c9c5ee;
  padding: 52px 0 36px;
}
.footer a { color: #e6e3fa; }
.footer-grid {
  display: grid;
  /* Бренд шире рубрик, дальше четыре равные колонки ссылок */
  grid-template-columns: 1.3fr repeat(4, minmax(0, 1fr));
  gap: var(--space-3xl) var(--space-2xl);
}
@media (max-width: 1100px) { .footer-grid { grid-template-columns: 1.3fr repeat(2, minmax(0, 1fr)); } }
.footer h4 {
  color: #fff;
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 14px;
}
/* Колонка подвала — <details>. На широком экране она обязана выглядеть ровно
   как раньше: заголовок и список под ним, без намёка на сворачивание.
   Содержимое показываем стилями поверх состояния details (::details-content
   для новых браузеров, display — для остальных), поэтому атрибут [open]
   на десктопе ни на что не влияет и скрипт не нужен. */
.footer-col-head {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  list-style: none;
  cursor: default;
}
.footer-col-head::-webkit-details-marker { display: none; }
.footer-col-head h4 { margin: 0 0 14px; }
/* Шеврон нужен только там, где колонка правда сворачивается */
.footer-col-head svg { display: none; }
@media (min-width: 881px) {
  .footer-col::details-content { content-visibility: visible; }
  .footer-col > ul { display: block; }
}
.footer ul { list-style: none; margin: 0; padding: 0; }
.footer li { margin-bottom: 9px; font-size: var(--text-sm); }
.footer .brand { font-weight: 800; font-size: var(--text-xl); color: #fff; letter-spacing: -0.02em; }
.footer .tagline { font-size: var(--text-sm); margin-top: 8px; max-width: 260px; }
/* Правовая сноска между колонками и копирайтом — место и для реквизитов,
   когда они появятся. */
.footer-legal {
  /* Рамка во всю ширину, длина строки ограничена у абзаца: иначе разделитель
     обрывался посреди подвала по ширине текста. */
  margin-top: var(--space-4xl);
  padding-top: var(--space-2xl);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}
.footer-legal p {
  margin: 0;
  max-width: 78ch;
  font-size: var(--text-2xs);
  line-height: var(--leading-normal);
  color: #9b96cc;
}
/* Реквизиты юрлица: название и номера идут одним рядом, адрес — своей строкой.
   Флекс, а не текст с точками-разделителями: на переносе точка повисала бы
   в конце строки. Селектор с .footer-legal — чтобы перебить margin абзаца
   выше без !important. */
.footer-legal .footer-req {
  display: flex;
  flex-wrap: wrap;
  gap: 6px var(--space-xl);
  margin-top: var(--space-2xl);
  /* Не 78ch, как у абзаца выше: мера нужна тексту для чтения, а реквизиты —
     строка данных. С мерой абзаца адрес ломался на две строки даже на широком
     экране, где помещается в одну. */
  max-width: none;
  text-wrap: pretty;
}
.footer-req .req-line { flex-basis: 100%; }
.footer-req .req-org { color: #fff; font-weight: 600; }
.footer-req .req-nb { white-space: nowrap; }
.footer-req .req-nums { display: inline-flex; gap: var(--space-xl); }
/* Подписи над адресами: сам адрес — действие, подпись объясняет, куда писать */
.footer-contacts li { margin-bottom: var(--space-lg); }
.footer-contact-note {
  display: block;
  margin-bottom: 2px;
  font-size: var(--text-2xs);
  color: #9b96cc;
}
/* Личные кабинеты: пункты на месте, страниц ещё нет. Выглядят как строки
   подвала, но приглушены и с пометкой — чтобы по ним не пытались кликать. */
.footer-soon {
  list-style: none;
  margin: var(--space-xl) 0 0;
  padding: var(--space-lg) 0 0;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}
.footer-soon li {
  margin-bottom: var(--space-md);
  font-size: var(--text-sm);
  color: #9b96cc;
}

.footer-bottom-links { display: flex; flex-wrap: wrap; gap: var(--space-lg); }

.footer-bottom {
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  margin-top: var(--space-2xl);
  padding-top: 22px;
  font-size: var(--text-2xs);
  color: #9b96cc;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 24px;
  justify-content: space-between;
}

/* ---------- Анимации появления ---------- */

@media (prefers-reduced-motion: no-preference) {
  .reveal { animation: reveal 480ms var(--ease-out) both; }
  .grid > .stagger { animation: reveal 420ms var(--ease-out) both; }
  .grid > .stagger:nth-child(1) { animation-delay: 0ms; }
  .grid > .stagger:nth-child(2) { animation-delay: 45ms; }
  .grid > .stagger:nth-child(3) { animation-delay: 90ms; }
  .grid > .stagger:nth-child(4) { animation-delay: 135ms; }
  .grid > .stagger:nth-child(n + 5) { animation-delay: 170ms; }
}
@keyframes reveal {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ---------- Мелочи ---------- */

.row-ico { display: flex; align-items: center; color: var(--violet); flex-shrink: 0; }

.list-plain { list-style: none; margin: 0; padding: 0; }
.list-plain > li { border-bottom: 1px solid var(--line); }
.list-plain > li:last-child { border-bottom: none; }
.row-link {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 15px 6px;
  color: var(--ink);
  text-decoration: none !important;
  border-radius: var(--r-sm);
  transition: background-color var(--t-fast) var(--ease-out), padding-left var(--t-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .row-link:hover { background: var(--lav-1); padding-left: 12px; }
}
.row-link .t { font-weight: 700; }
.row-link .d { color: var(--muted); font-size: var(--text-xs); }
.row-link .arr { margin-left: auto; color: var(--lav-3); flex-shrink: 0; }

.empty {
  text-align: center;
  color: var(--muted);
  padding: 48px 20px;
  background: var(--lav-1);
  border-radius: var(--r-lg);
}

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

   Правая колонка и появилась затем, чтобы 1140px были заняты содержанием:
   до этого строка несла заголовок, обрезанный tldr и стрелку у самого края,
   и половина ширины уходила в пустоту. */
.sy-h2 { display: flex; align-items: center; gap: var(--space-sm); }
.sy-h2-ico { display: flex; color: var(--accent); }

.sy-list { list-style: none; margin: 0; padding: 0; }
.sy-row {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 24rem);
  gap: var(--space-md) var(--space-3xl);
  align-items: start;
  padding: var(--space-lg) var(--space-md);
  border-top: 1px solid var(--border);
  border-radius: var(--r-sm);
}
.sy-row:last-child { border-bottom: 1px solid var(--border); }
/* Подсветка строки — фон, а не сдвиг: строка тут двухколоночная, и сдвиг
   левого края разъезжался бы со второй колонкой. */
@media (hover: hover) and (pointer: fine) {
  .sy-row:hover { background: var(--surface-1); }
  .sy-row:hover .sy-ttl a { color: var(--accent-strong); }
}

.sy-ttl { margin: 0; font-size: var(--text-base); line-height: var(--leading-snug); }
.sy-ttl a { color: var(--text); text-decoration: none; }
/* Строку открывает вся её площадь. Вложенных ссылок в ней нет — иначе этот
   приём отобрал бы у них клик. */
.sy-ttl a::after { content: ""; position: absolute; inset: 0; }

.sy-tldr {
  margin: var(--space-xs) 0 0;
  max-width: 62ch;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--text-muted);
}

/* Признаки «ехать сейчас» — единственное красное на странице, и цветом дело
   не ограничивается: рядом значок и слово «Срочно», иначе смысл держался бы
   на одном оттенке. Подложки нет — плашка на каждой строке превратила бы
   список в шесть тревожных плиток, где ни одна не тревожнее другой. */
.sy-urgent {
  display: flex;
  gap: var(--space-sm);
  margin: 0;
  padding-left: var(--space-lg);
  /* Линия колонки в тон плашки «срочно» на страницах материалов (#f7d5de):
     сам --rose-bg на белом фоне не виден и границу колонки не держал. */
  border-left: 2px solid #f7d5de;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--text-muted);
}
.sy-urgent-ico { display: flex; flex: none; margin-top: 2px; color: var(--rose-ink); }
.sy-urgent b { color: var(--rose-ink); font-weight: 700; }


/* ---------- Страница клиники ---------- */

/* Полотно во всю ширину окна: до трёх кадров в ряд, первый шире.
   Строка задана явно (minmax(0, 1fr)) — при height без grid-template-rows ряд
   тянулся бы по собственной высоте картинок и вылезал за рамку. */
.cl-cover {
  position: relative;
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  grid-template-rows: minmax(0, 1fr);
  gap: 3px;
  height: 300px;
  /* Полотно примыкает к шапке вплотную. Отступ был нужен, пока над ним стояли
     хлебные крошки; крошки уехали в конец страницы — ушёл и он. */
  background: var(--surface-2);
}
.cl-cover > * { min-height: 0; }
/* Один и два кадра не должны оставлять пустые колонки */
.cl-cover-one { grid-template-columns: 1fr; }
.cl-cover-two { grid-template-columns: 2fr 1fr; }
.cl-cover-cell { position: relative; display: block; overflow: hidden; }
.cl-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--t-med) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .cl-cover-cell:hover img { transform: scale(1.04); }
}
/* Счётчик кадров — над полотном, но выше зоны, куда наезжает карточка */
.cl-cover-all {
  position: absolute;
  right: var(--space-xl);
  bottom: calc(var(--cl-card-overlap) + var(--space-lg));
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-sm) var(--space-lg);
  border-radius: var(--r-pill);
  background: rgba(17, 20, 31, 0.62);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: #fff;
  font-size: var(--text-sm);
  font-weight: 500;
}
.cl-cover-all .num { opacity: 0.75; }
@media (hover: hover) and (pointer: fine) {
  .cl-cover-all:hover { background: rgba(17, 20, 31, 0.8); text-decoration: none; color: #fff; }
}
.cl-cover-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  height: 220px;
  background: var(--surface-1);
  color: var(--text-subtle);
  font-size: var(--text-sm);
}

/* Карточка, наезжающая на полотно снизу */
.cl-card {
  position: relative;
  z-index: 1;
  margin-top: calc(-1 * var(--cl-card-overlap));
  padding: var(--space-2xl) var(--space-3xl) var(--space-2xl);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  background: var(--surface);
  /* тень поднимает карточку над фотографией — без неё край над снимком
     держался только на разнице цветов */
  box-shadow: var(--shadow-md);
}
/* Тень отбрасывает и строка разделов — она продолжает ту же карточку */
.cl-card + .anchor-nav { box-shadow: var(--shadow-md); }

/* Шапка сведений */
/* Шапка карточки: слева название и факты, справа — оценка. Grid, а не флекс
   с абсолютом: оценка должна прижиматься к верху и не наезжать на длинное
   название, когда оно занимает две строки. */
.cl-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  column-gap: var(--space-2xl);
}
.cl-head > *:not(.cl-score) { grid-column: 1; }

.cl-head-title {
  display: flex;
  align-items: center;
  /* значок стоит вплотную к названию — это отметка к нему, а не соседний блок */
  gap: var(--space-sm);
  flex-wrap: wrap;
  margin-bottom: var(--space-md);
}
.cl-head-title h1 { margin: 0; font-size: calc(var(--t-display) / 1.2); }
/* Значок проверки: идёт вплотную к названию, как в справочниках. Цвет —
   акцент бренда, чтобы читался как отметка площадки, а не статус работы. */
.cl-verified {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  /* значок стоит в потоке заголовка — опускаем к оптической середине строчных */
  vertical-align: -0.08em;
  color: var(--accent);
  cursor: help;
}
.cl-verified svg { display: block; }

.cl-meta {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  flex-wrap: wrap;
  margin-bottom: var(--space-md);
}
/* Оценка клиники блоком: словесная слева, балл — плашкой справа.
   Цвет плашки смысловой (пары --green/--amber/--rose), не акцентный: фиолетовый
   на портале означает действие, а не «хорошо». */
.cl-score {
  grid-column: 2;
  grid-row: 1;
  display: inline-flex;
  align-items: center;
  gap: var(--space-md);
  color: var(--text);
  text-decoration: none !important;
  white-space: nowrap;
}
.cl-score-text { display: flex; flex-direction: column; gap: 2px; }
.cl-score-word {
  font-size: var(--text-lg);
  font-weight: 700;
  line-height: var(--leading-snug);
}
.cl-score-cnt { font-size: var(--text-sm); color: var(--text-subtle); }
.cl-score-num {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 58px;
  /* Нижнее поле больше верхнего: вырез закладки съедает часть высоты, и без
     запаса цифра оптически сползала бы к краю. */
  padding: var(--space-md) var(--space-md) var(--space-xl);
  border-radius: var(--r-sm);
  font-size: var(--text-xl);
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1;
  /* Форма закладки: прямоугольник с вырезом снизу по центру */
  clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 78%, 0 100%);
}
.cl-score-good .cl-score-num  { background: var(--green-ink); color: var(--on-accent); }
.cl-score-so-so .cl-score-num { background: var(--amber-ink); color: var(--on-accent); }
.cl-score-bad .cl-score-num   { background: var(--rose-ink);  color: var(--on-accent); }
@media (hover: hover) and (pointer: fine) {
  .cl-score:hover .cl-score-word { color: var(--accent-strong); }
}
.cl-score:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; border-radius: var(--r-sm); }

.cl-open-inline.is-open { color: var(--green-ink); }
.cl-open-inline.is-closed { color: var(--rose-ink); }

/* Факты клиники — единый список: иконки образуют ровную колонку, строки
   не разъезжаются по левому краю при переносе текста. */
.cl-facts {
  list-style: none;
  margin: 0 0 var(--space-xl);
  padding: 0;
  color: var(--text-muted);
}
.cl-facts li {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr);
  align-items: start;
  gap: var(--space-sm);
  line-height: var(--leading-normal);
}
.cl-facts li + li { margin-top: var(--space-sm); }
.cl-facts .row-ico {
  display: flex;
  color: var(--accent);
  margin-top: 2px;
}

.cl-actions { display: flex; gap: var(--space-sm); flex-wrap: wrap; align-items: center; }
/* Ряд действий компактнее обычных кнопок: их тут четыре, и в базовом размере
   (57px) строка спорила по весу с названием клиники. */
.cl-actions .btn {
  padding: 10px 18px;
  font-size: var(--text-sm);
  /* 44px — и общая высота ряда (номер крупнее подписей и тянул бы кнопку выше
     соседей), и нижняя граница удобной тач-цели. */
  min-height: 44px;
}
/* Мессенджеры и карта — квадратные кнопки без подписи: значки узнаваемы, а
   подписи рядом с телефоном перегрузили бы строку. Сторона равна высоте
   соседних кнопок, чтобы ряд не рябил. */
.cl-actions .cl-action-icon {
  /* Селектор с .cl-actions намеренно: у соседнего правила .cl-actions .btn
     та же специфичность, и без неё его боковой паддинг сплющивал значок. */
  flex: 0 0 44px;
  width: 44px;
  padding-inline: 0;
  justify-content: center;
}
/* Номер — единственное, что крупнее подписей: он тут главное. Моноширинные
   цифры, чтобы ширина кнопки не прыгала при подстановке скрытых. */
.cl-phone-num {
  font-variant-numeric: tabular-nums;
  font-size: var(--text-base);
}
/* «показать» — подсказка внутри кнопки, тише номера, но не настолько, чтобы
   потерять контраст к фиолетовому. */
.cl-phone-show {
  margin-left: 2px;
  opacity: 0.82;
  font-weight: 500;
  /* Кегль ниже номера, а не только прозрачность: подсказка тише по замыслу,
     и она же наследовала 16px от кнопки там, где номер уже ужали до 14 —
     в узкой карточке каталога из-за этого обрезалось содержимое. */
  font-size: var(--text-sm);
}
.cl-actions-note {
  margin: var(--space-md) 0 0;
  font-size: var(--text-sm);
  color: var(--text-subtle);
}

/* Якорная навигация — прилипает под шапкой */
/* Строка разделов примыкает к карточке снизу: те же боковые отступы и фон,
   сверху — разделитель. Прилипает под шапкой на всю длину страницы. */
.anchor-nav {
  position: sticky;
  top: var(--header-h);
  z-index: 30;
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  margin: 0;
  padding: 0 var(--space-3xl);
  background: var(--surface);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}
/* Прокручиваются вкладки, а не панель: справа от них стоит телефон, и он
   обязан оставаться на месте. min-width: 0 обязателен — без него флекс-элемент
   не даёт себя сжать ниже содержимого, и вкладки выдавили бы номер за край
   вместо того, чтобы прокручиваться. */
.anchor-nav__tabs {
  position: relative;   /* точка отсчёта для offsetLeft вкладок в clinic-page.js */
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  /* stretch, а не center: подчёркивание активной вкладки садится на нижнюю
     границу панели через margin-bottom: -1px и обязано доставать до неё. */
  align-items: stretch;
  gap: var(--space-2xs);
  overflow-x: auto;
  scrollbar-width: none;
}
.anchor-nav__tabs::-webkit-scrollbar { display: none; }
/* Скрытый скроллбар прячет сам факт прокрутки: обрезанный пункт «Как д…»
   читался как дефект, а не как «дальше есть ещё». Затухание у края говорит
   об этом явно; классы вешает clinic-page.js по фактическому положению. */
.anchor-nav__tabs.fade-right {
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 44px), transparent);
  mask-image: linear-gradient(90deg, #000 calc(100% - 44px), transparent);
}
.anchor-nav__tabs.fade-left {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 44px);
  mask-image: linear-gradient(90deg, transparent, #000 44px);
}
.anchor-nav__tabs.fade-left.fade-right {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 44px, #000 calc(100% - 44px), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 44px, #000 calc(100% - 44px), transparent);
}
.anchor-nav__tabs a {
  flex-shrink: 0;
  padding: var(--space-md) var(--space-2xs);
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  color: var(--text-muted);
  font-weight: 500;
  font-size: var(--text-sm);
  white-space: nowrap;
  transition: color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out);
}
.anchor-nav__tabs a + a { margin-left: var(--space-lg); }
@media (hover: hover) and (pointer: fine) {
  .anchor-nav__tabs a:hover { color: var(--text); text-decoration: none; }
}
/* Активная вкладка отличается и весом, а не только цветом с подчёркиванием */
.anchor-nav__tabs a.is-active { color: var(--accent-ink); border-bottom-color: var(--accent); font-weight: 700; }
/* Счётчик у вкладки — как в каталогах: цифра приглушена, чтобы не спорить
   с названием раздела. */
.tab-count {
  margin-left: var(--space-2xs);
  color: var(--text-subtle);
  font-weight: 500;
  font-size: var(--text-xs);
}
.anchor-nav__tabs a.is-active .tab-count { color: var(--accent); }

/* Телефон в строке разделов.

   Кегль и паддинги ужаты против обычной .btn намеренно: панель прилипшая,
   её высота зафиксирована токеном --anchor-nav-h (50px), от которого считают
   scroll-margin секций и точку прилипания сайдбара. Кнопка в полный рост
   (44px + отступы) растянула бы панель, и все якоря на странице начали бы
   нырять под неё. 34px укладываются в 50 с воздухом сверху и снизу.

   Ведёт себя как нижняя липкая панель на телефоне: до ухода кнопок шапки
   из виду её нет вовсе (visibility, а не только прозрачность — иначе она
   ловила бы фокус и клики, будучи невидимой). */
.cl-nav-phone {
  flex: none;
  align-self: center;
  gap: var(--space-xs);
  padding: var(--space-sm) var(--space-lg);
  font-size: var(--text-sm);
  /* Тень обычной .btn-primary здесь лишняя: панель сама лежит поверх
     страницы, и вторая тень внутри неё читается как слой поверх слоя. */
  box-shadow: none;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity var(--t-med) var(--ease-out), transform var(--t-med) var(--ease-out), visibility var(--t-med);
}
.cl-nav-phone.is-visible { opacity: 1; visibility: visible; transform: none; }
/* Номер в панели — тем же кеглем, что и подпись: 16px спорили бы по весу
   с названиями разделов рядом. */
.cl-nav-phone .cl-phone-num { font-size: var(--text-sm); }
.cl-nav-phone .cl-phone-show { font-size: var(--text-xs); }

/* Прилипший сайдбар должен вставать под якорной навигацией, а не под неё:
   .anchor-nav липнет на var(--header-h) и имеет непрозрачный фон с z-index 30,
   поэтому при .side { top: 88px } она срезала верх карточки с телефоном. */
.clinic-side { top: calc(var(--header-h) + var(--anchor-nav-h) + var(--space-lg)); }

/* Секции контента — такие же плитки, как в сайдбаре: раньше они были
   прозрачными и разделялись только отступом 40px, из-за чего пять разделов
   разной высоты читались сплошным потоком. */
.cl-section {
  padding: var(--space-2xl) var(--space-3xl);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
  /* якорь не должен нырять под шапку и строку разделов */
  scroll-margin-top: calc(var(--header-h) + var(--anchor-nav-h) + var(--space-lg));
}
/* Зазор между секциями 8px, как между коробками сайдбара: секции — такие же
   плитки с рамкой и фоном, и разделять их ещё и воздухом в 24px незачем.
   .page-grid не трогаем — он общий для десяти страниц, у клиники свой класс. */
.cl-section + .cl-section { margin-top: var(--space-sm); }
.clinic-grid { gap: var(--space-lg); }
/* Заголовки секций спокойнее заголовка страницы — 5 секций не должны
   кричать наравне с H1. Размер фиксирован, а не clamp «как у H1». */
.cl-section > h2,
.cl-section-head > h2 {
  margin: 0 0 var(--space-lg);
  padding-top: 0;
  font-size: var(--text-xl);
  font-weight: 700;
  letter-spacing: -0.01em;
}
/* В .cl-section-head отступ снизу держит сам блок-обёртка */
.cl-section-head > h2 { margin-bottom: 0; }

/* Подзаголовки внутри описания («## Оснащение») — компактные метки, а не
   вторые заголовки: убирают шаблонный ритм «крупный заголовок + одна строка». */
/* Ограничение строки живёт на тексте (.cl-about), а не на колонке: иначе
   плитки секций были бы уже своей колонки и не совпадали с сайдбаром. */
.clinic-body { max-width: none; }
.cl-about { max-width: 68ch; color: var(--text); }
.cl-about > :first-child { margin-top: 0; }
.cl-about :is(h2, h3) {
  margin: var(--space-xl) 0 var(--space-xs);
  padding: 0;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-subtle);
}
.cl-about p { margin-bottom: var(--space-md); line-height: var(--leading-relaxed); }
.cl-about p:last-child { margin-bottom: 0; }

/* Заголовок секции со счётчиком и ссылкой «все» */
.cl-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-lg);
  margin-bottom: var(--space-lg);
}
.cl-section-head h2 { margin: 0; }
.cl-section-head .section-link { flex-shrink: 0; }
.cl-count {
  margin-left: var(--space-2xs);
  color: var(--text-subtle);
  font-weight: 500;
  font-size: var(--text-base);
}

/* Врачи — карточки равной ширины: колонки тянутся на всю ширину колонки
   текста, поэтому ряд не обрывается «лесенкой» справа. */
/* Врачи — вертикальные плитки с портретом. Ширина сетки ограничена числом
   врачей (--doc-cols из шаблона): при auto-fit и двух врачах плитки растянуло
   бы на всю колонку, а вместе с ними и портрет. */
/* Свёртка длинного состава. Высоту подрезает скрипт: ряд плиток зависит от
   числа колонок, а оно меняется с шириной экрана — в CSS это не выразить. */
.doc-collapse { position: relative; }
.doc-collapse.is-clamped { overflow: hidden; }
/* Градиент к фону секции: следующий ряд уходит в белый, и обрез читается как
   «дальше есть ещё», а не как ошибка вёрстки. */
.doc-fade {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  /* Высоту ставит скрипт — ровно по подглядывающему ряду. Здесь запасное
     значение: градиент не должен приглушать текст последнего полного ряда. */
  height: 96px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0), var(--surface) 88%);
  pointer-events: none;
}
.doc-more { display: block; margin: var(--space-lg) auto 0; }

/* Список врачей клиники. Плитки с портретом 4:5, рамкой, скруглением 16px,
   тенью на ховере и чипами-пилюлями — ровно тот набор, который DESIGN.md
   называет AI-шаблоном. Здесь: строки, тонкие разделители, радиусы 8–10,
   ни одной тени и ни одной пилюли. */
.doc-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: var(--space-md) var(--space-2xl);
}
.doc-card {
  position: relative;
  display: flex;
  /* По верхнему краю, а не по центру: при центрировании карточка с именем
     в одну строку и карточка с именем в две ставили текст на разной высоте,
     и ряд выглядел кривым. */
  align-items: flex-start;
  gap: var(--space-md);
  padding: var(--space-sm);
  /* Разделительной линии нет: строки разведены отступом, и линия под каждой
     превращалась бы в подчёркивание. Рамки и фона в покое тоже нет — иначе
     это снова плавающие карточки, от которых мы ушли. */
  border-radius: var(--r-sm);
  color: var(--text);
  transition: background-color var(--t-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  /* Подсветка строки вместо подъёма и зума фото: в справочнике наведение
     показывает, где курсор, а не устраивает представление. */
  .doc-card:hover { background: var(--surface-1); text-decoration: none; }
  .doc-card:hover .doc-name { color: var(--accent-strong); }
}
.doc-card:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }

/* Портрет ужат с 289px до 56: в списке он опознавательный знак, а не витрина.
   Все 67 сняты в одной студии — на большом размере они не различали врачей. */
.doc-photo {
  /* 106px: на 56 лица не читались вовсе, 88 было мало. */
  flex: 0 0 106px;
  width: 106px;
  height: 106px;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--surface-2);
}
.doc-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Лицо в верхней трети кадра — центрирование срезало бы его */
  object-position: center 22%;
  display: block;
}
.doc-body { min-width: 0; display: flex; flex-direction: column; gap: 2px; padding-top: 2px; }
/* Под имя всегда отведены две строки: половина ФИО в колонку 200px не влезает
   в одну, и без резерва специализация с ценой прыгали бы по вертикали от
   карточки к карточке. Длиннее двух строк не бывает — обрезаем. */
.doc-name {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(2 * var(--text-sm) * var(--leading-snug));
  font-weight: 700;
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
}
/* Факты одной строкой через точку — как в справочнике, а не тремя
   ступенями серого одна под другой. */
.doc-facts {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 var(--space-sm);
  font-size: var(--text-xs);
  color: var(--text-subtle);
  line-height: var(--leading-snug);
}
.doc-spec {
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
  color: var(--text-muted);
  /* Длинные названия вроде «Врач визуальной диагностики» — в одну строку
     с многоточием, иначе они снова сдвигают строку фактов вниз. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.doc-fact + .doc-fact::before { content: "· "; }
/* Цена — единственное число, по которому сравнивают врачей */
.doc-price { color: var(--text); font-weight: 700; }

/* Сайдбар: карта, контакты */

/* ---------- Страница врача ---------- */
/* Язык тот же, что у карточки клиники (белая плитка, тонкие разделители,
   плотный список фактов), поэтому шапка переиспользует .cl-card, .cl-facts,
   .cl-actions и .cl-score, а не заводит их копии. Отличий два: полотна
   с фотографиями нет — у врача один портрет, и растянутый во всю ширину он
   показывал бы поры вместо фактов; и телефон в шапке принадлежит клинике,
   отсюда подпись под кнопкой. */
.dr-card {
  /* Наезжать не на что: обложки над карточкой нет, поэтому отрицательное
     поле .cl-card здесь обнуляется. */
  margin-top: var(--space-2xl);
}
.dr-card + .anchor-nav { box-shadow: var(--shadow-md); }
/* Кнопка карты приподнята над нижним краем: у карточки врача карта выше, чем
   у клиники, и в обычном положении кнопка ложилась на подпись «© Яндекс Карты»
   — её закрывать нельзя. По той же причине превью прижато правым краем:
   подпись впечатана в картинку справа внизу, и при центрировании её срезало. */
.dr-card .cl-map-open { bottom: var(--space-3xl); }
.dr-card .cl-card-map { object-position: right center; }
/* Правая зона шапки занята картой (см. .cl-card-map). Маска гасит её по
   диагонали, но содержимое всё равно не должно доезжать до непрозрачной
   части — иначе длинный адрес ложится на дома и подписи улиц. Правило общее
   для карточек врача и клиники: карта в них одна и та же. */
@media (min-width: 881px) {
  .cl-card:has(.cl-card-map) .dr-head,
  .cl-card:has(.cl-card-map) .cl-head { max-width: 62%; }
}

/* Портрет, имя и оценка — одной строкой, дальше факты и кнопки во всю ширину.
   Портрет на всю высоту шапки (гридом) оставлял бы под собой пустую полосу
   у каждого, у кого нет оценки, — то есть сейчас у всех. */
.dr-top {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2xl);
  margin-bottom: var(--space-xl);
}
/* Оценка прижата к правому краю строки, а на узком экране переносится
   под имя целой строкой: разрывать «Очень хорошо» нельзя. */
.dr-top .cl-score { margin-left: auto; }
.dr-portrait {
  flex: 0 0 132px;
  width: 132px;
  height: 132px;
  border-radius: var(--r-md);
  object-fit: cover;
  /* Лицо в верхней трети кадра — центрирование срезало бы его */
  object-position: center 22%;
  background: var(--surface-2);
}
/* min-width: 0 обязателен: без него длинное ФИО распирает флекс-элемент
   и портрет ужимается вместо переноса имени. */
.dr-ident { min-width: 0; flex: 1 1 320px; }
/* Перенос внутри слова: у русских отчеств («Вячеславовна») длина слова на
   узком экране превышает колонку рядом с портретом, и без него имя вылезало
   за карточку. */
.dr-ident h1 { margin: 0; font-size: calc(var(--t-display) / 1.2); overflow-wrap: break-word; }
/* Должность: главная отличающая строка профиля, поэтому крупнее мелкой меты,
   но тише имени. Ширина ограничена — «Главный ветеринарный врач филиала
   Коньково и Крылатское, заведующая кардиологическим отделением» на всю
   колонку читалось бы как абзац. */
.dr-title {
  margin: var(--space-sm) 0 0;
  max-width: 60ch;
  color: var(--text-muted);
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
}
/* Станция метро внутри строки фактов: кружок цвета ветки и название не
   должны разрываться переносом. */
.metro-tag { display: inline-flex; align-items: baseline; gap: var(--space-xs); white-space: nowrap; }
/* Строка фактов с переносом: адрес, станции, расстояние. Расстояние держит
   gap, а не точка-разделитель и не боковое поле: точка при переносе висла
   в конце строки, а поле сдвигало перенесённую станцию.
   Обе роли общие для карточек врача и клиники, поэтому имена без префикса. */
.fact-flow { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2xs) var(--space-md); }
/* Кружок ветки не садится на базовую линию текста: у inline-flex в baseline он
   выравнивается низом, а нужен по оптической середине строчных. */
.metro-tag .hc-metro-dot { align-self: center; }
/* Время пешком идёт внутри плашки станции, расстояние держит её gap —
   боковое поле из каталога здесь дало бы двойной зазор. */
.metro-tag .hc-metro-min { margin-left: 0; }


/* Ограничение строки живёт на тексте разделов, а не на колонке: иначе
   плитки были бы уже своей колонки и не совпадали с сайдбаром. */
.dr-body { max-width: none; }

/* Образование и практика — таймлайн: год, рельс с точкой, запись. Рельс —
   тонкая линия того же цвета, что разделители в остальном справочнике, точка
   не залита акцентом: фиолетовый на портале означает действие, и кружок им
   читался бы как кликабельный. Без дат (у 40% врачей их нет вовсе) рельса нет
   — линия времени без времени ничего не сообщает, остаётся простой список. */
.dr-time { list-style: none; margin: 0; padding: 0; }
.dr-time-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-lg);
  padding: var(--space-md) 0;
  border-top: 1px solid var(--border);
}
/* Поле пунктов из .prose (0.35em) обнуляем селектором с двумя классами:
   у `.prose li` специфичность выше одиночного класса, и рельс таймлайна
   разрывался на отрезки ровно по этим полям. */
.dr-time .dr-time-row { margin: 0; }
.dr-time-row:first-child { border-top: 0; padding-top: 0; }
.dr-time-row:last-child { padding-bottom: 0; }

/* Датированный вариант: колонка года, рельс в зазоре, дальше запись.
   Ширина колонки — под самую длинную форму «2011–2018»; год прижат к рельсу,
   чтобы числа стояли ровным столбцом у самой линии. */
.dr-time-dated .dr-time-row {
  position: relative;
  grid-template-columns: 62px minmax(0, 1fr);
  gap: var(--space-2xl);
  /* Разделителей между строками нет: их работу делает рельс, а вместе они
     превращали раздел в решётку. */
  border-top: 0;
  padding: var(--space-md) 0;
}
.dr-time-dated .dr-time-year { text-align: right; }
/* Линия рельса: 62px колонка + половина зазора 24px. Абсолют на строке,
   а не фон ячейки, — иначе линия рвалась бы на вертикальных отступах. */
.dr-time-dated .dr-time-row::before {
  content: "";
  position: absolute;
  left: calc(62px + var(--space-md));
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--border);
}
/* Точка — по оптической середине первой строки записи. Залита индиго, а не
   акцентом: фиолетовый на портале означает действие, и кружок им читался бы
   как кликабельный. Белое кольцо вокруг отделяет точку от рельса. */
.dr-time-dated .dr-time-row::after {
  content: "";
  position: absolute;
  left: calc(62px + var(--space-md) - 3.5px);
  top: calc(var(--space-md) + 0.6em);
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent-ink);
  box-shadow: 0 0 0 3px var(--surface);
}
/* Запись без даты — полая точка: это факт биографии, а не веха на линии
   времени, и заливать её наравне с датированными было бы неправдой. */
.dr-time-dated .dr-time-row:has(.dr-time-year:empty)::after {
  background: var(--surface);
  box-shadow: 0 0 0 3px var(--surface), inset 0 0 0 2px var(--surface-3);
}
/* Линия начинается на первой точке и заканчивается на последней: свисающие
   хвосты сверху и снизу читались бы как обрезанный список. */
.dr-time-dated .dr-time-row:first-child::before { top: calc(var(--space-md) + 0.6em); }
.dr-time-dated .dr-time-row:last-child::before {
  bottom: auto;
  height: calc(var(--space-md) + 0.6em);
}
.dr-time-year {
  color: var(--text-subtle);
  font-weight: 600;
  font-size: var(--text-sm);
  /* Цифры по верхней строке записи, даже если она в три строки */
  line-height: var(--leading-relaxed);
}
.dr-time-text { max-width: 68ch; line-height: var(--leading-relaxed); }
/* Пустой раздел — одна строка без плашек и кнопок: раздел стоит всегда,
   и объяснять в нём нечего, кроме самого факта. */
.dr-empty-note { margin: 0; color: var(--text-muted); }
/* Пустая ячейка года не должна занимать строку в потоке одноколоночной сетки */
.dr-time:not(.dr-time-dated) .dr-time-year { display: none; }


/* Сайдбар: врачи того же профиля. Подпись под заголовком вместо склонения
   специализации во множественное — профилей восемнадцать, и «Врачи визуальной
   диагностики» рядом с «Зоопсихологи» звучали бы по-разному кривовато. */
.dr-peers-sub {
  margin: calc(-1 * var(--space-sm)) 0 var(--space-md);
  color: var(--text-subtle);
  font-size: var(--text-xs);
}
.dr-peers li { margin-bottom: var(--space-md); }
.dr-peers li:last-child { margin-bottom: 0; }
.dr-peer-meta {
  display: block;
  margin-top: 2px;
  color: var(--text-subtle);
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
}
.dr-peers-all {
  display: inline-block;
  margin-top: var(--space-md);
  font-size: var(--text-sm);
  font-weight: 600;
}

/* Ссылка в справочник симптомов: та же коробка сайдбара, что у остальных,
   с обычной ссылкой вместо кнопки. */
.dr-help p {
  margin: 0 0 var(--space-md);
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}
.dr-help-link { font-size: var(--text-sm); font-weight: 600; }

/* Откуда сведения: сноска редакции, а не действие, поэтому и текст, и значки
   приглушены — фиолетовый на портале означает «сюда можно нажать». */
.dr-source-row {
  display: grid;
  grid-template-columns: 17px minmax(0, 1fr);
  gap: var(--space-sm);
  margin: 0 0 var(--space-md);
  color: var(--text-subtle);
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
}
.dr-source-row:last-child { margin-bottom: 0; }
/* Значок держится первой строки: .row-ico растягивается на всю высоту ячейки
   и центрирует svg — у сноски в три строки он оказывался напротив второй. */
.dr-source .row-ico { align-self: start; margin-top: var(--space-2xs); color: var(--text-subtle); }

/* ---------- Каталог клиник: шапка в формате агрегатора ---------- */
/* Раскладка больше не «список + липкая карта»: карта стала отдельным видом,
   поэтому список идёт во всю ширину. */
.catalog { display: block; }
.catalog-list { display: block; }

.agg-panel { margin-bottom: var(--space-2xl); }
.agg-hero { text-align: center; margin-bottom: var(--space-xl); }
.agg-hero .agg-h1 { margin: 0 0 var(--space-sm); }
.agg-sub { margin: 0; color: var(--text-muted); }

/* Строка инструментов каталога — тот же язык, что у списка записей в админке:
   контролы одной высоты, тонкий бордер, радиус 10, никаких теней и пилюль.
   Раньше поиск был белой плашкой в 56px с радиусом 22, а фасеты — плавающими
   белыми таблетками на лавандовом фоне; DESIGN.md прямо называет этот набор
   признаком шаблона. */
.agg-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
}
.agg-search { position: relative; flex: 1 1 100%; }
.agg-search input {
  width: 100%;
  height: 40px;
  padding: 0 var(--space-4xl) 0 var(--space-md);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  font: inherit;
  font-size: var(--text-sm);
  color: var(--text);
}
.agg-search input::placeholder { color: var(--text-subtle); }
.agg-search input:focus-visible { outline: 2px solid var(--focus); outline-offset: -1px; }
.agg-search .search-submit {
  position: absolute;
  top: 50%;
  right: var(--space-sm);
  transform: translateY(-50%);
  display: flex;
  padding: var(--space-xs);
  border: 0;
  border-radius: var(--r-xs);
  background: none;
  color: var(--text-subtle);
  cursor: pointer;
  line-height: 0;
}
@media (hover: hover) and (pointer: fine) {
  .agg-search .search-submit:hover { background: var(--surface-1); color: var(--accent-strong); }
}
.agg-search .search-submit:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }

.agg-selects { display: flex; flex-wrap: wrap; gap: var(--space-sm); flex: 1 1 auto; }

/* Фасет — своя кнопка с меню вместо системного <select>: выпадающий список
   ОС не стилизуется и в нашей панели выглядел чужим, а главное — в нём
   нельзя выбрать несколько значений. Пунктирная рамка у незаданного фасета,
   сплошная с акцентом — у выбранного: тот же приём, что у фильтров админки. */
.agg-facet { position: relative; flex: 0 1 auto; }
.agg-facet-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  height: 40px;
  padding: 0 var(--space-md);
  border: 1px dashed var(--surface-3);
  border-radius: var(--r-sm);
  background: var(--surface);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--text-muted);
  white-space: nowrap;
  cursor: pointer;
  list-style: none;
}
.agg-facet-btn::-webkit-details-marker { display: none; }
.agg-facet-btn svg { color: var(--text-subtle); transition: transform var(--t-fast) var(--ease-out); }
.agg-facet[open] .agg-facet-btn { border-style: solid; border-color: var(--accent-soft); }
.agg-facet[open] .agg-facet-btn svg { transform: rotate(180deg); }
.agg-facet-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .agg-facet-btn:hover { border-color: var(--accent-soft); }
}
/* Выбранный фасет: сплошная рамка, акцентный текст и число значений —
   иначе применённый фильтр отличается от пустого только строкой чипов. */
.agg-facet-btn.on {
  border-style: solid;
  border-color: var(--accent-soft);
  color: var(--accent-ink);
  font-weight: 600;
}
.agg-facet-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: var(--on-accent);
  font-size: var(--text-2xs);
  font-weight: 700;
}

/* Меню. Тень здесь по делу: это всплывающий слой, единственное место,
   где манифест её разрешает. */
.agg-facet-menu {
  position: absolute;
  z-index: 40;
  top: calc(100% + var(--space-xs));
  left: 0;
  width: max-content;
  min-width: 260px;
  max-width: min(360px, calc(100vw - var(--space-2xl)));
  padding: var(--space-sm);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  box-shadow: var(--shadow-md);
}
/* У правых фасетов меню открывается влево, иначе оно уезжает за край окна.
   Класс вешает скрипт по замеру — в CSS положение соседа не выразить. */
.agg-facet-menu.to-left { left: auto; right: 0; }
.agg-facet-search {
  width: 100%;
  height: 36px;
  margin-bottom: var(--space-xs);
  padding: 0 var(--space-md);
  border: 1px solid var(--border);
  border-radius: var(--r-xs);
  background: var(--surface-1);
  font: inherit;
  font-size: var(--text-sm);
}
.agg-facet-search:focus-visible { outline: 2px solid var(--focus); outline-offset: -1px; }
.agg-facet-list {
  max-height: 280px;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.agg-facet-opt {
  display: grid;
  grid-template-columns: 16px auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-sm);
  border-radius: var(--r-xs);
  font-size: var(--text-sm);
  cursor: pointer;
}
/* Без кружка ветки колонок три — иначе название уезжало бы на её место */
.agg-facet-opt:not(:has(.hc-metro-dot)) { grid-template-columns: 16px minmax(0, 1fr) auto; }
.agg-facet-opt input { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; }
.agg-facet-opt[hidden] { display: none; }
@media (hover: hover) and (pointer: fine) {
  .agg-facet-opt:hover { background: var(--surface-1); }
}
.agg-facet-opt:has(:focus-visible) { outline: 2px solid var(--focus); outline-offset: -2px; }
.agg-facet-opt:has(:checked) { color: var(--accent-ink); font-weight: 600; }
.agg-facet-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.agg-facet-count { color: var(--text-subtle); font-size: var(--text-xs); font-weight: 500; }
.agg-facet-empty, .agg-facet-note {
  margin: var(--space-sm) 0 0;
  padding: 0 var(--space-sm);
  color: var(--text-subtle);
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
}
.agg-facet-empty[hidden] { display: none; }
.agg-facet-apply {
  width: 100%;
  height: 40px;
  margin-top: var(--space-sm);
  border-radius: var(--r-sm);
  font-size: var(--text-sm);
}

/* Флажок — такой же контрол, как фасеты: та же высота, та же рамка.
   Голый чекбокс рядом с ними выпадал из строки. */
.agg-check {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  height: 40px;
  padding: 0 var(--space-lg) 0 var(--space-md);
  border: 1px dashed var(--surface-3);
  border-radius: var(--r-sm);
  background: var(--surface);
  cursor: pointer;
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--text-muted);
  white-space: nowrap;
}
.agg-check input { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; }
.agg-check:has(:checked) {
  border-style: solid;
  border-color: var(--accent-soft);
  color: var(--accent-ink);
  font-weight: 600;
}
@media (hover: hover) and (pointer: fine) {
  .agg-check:hover { border-color: var(--accent-soft); }
}
.agg-check:has(:focus-visible) { outline: 2px solid var(--focus); outline-offset: 1px; }

/* Кнопка нужна тем, у кого нет JS: со скриптом форма уходит по выбору */
.agg-apply { height: 40px; padding: 0 var(--space-xl); border-radius: var(--r-sm); font-size: var(--text-sm); }
/* display у .btn перебивает атрибут hidden — скрипт прятал кнопку, а она
   оставалась на экране. Тот же случай, что у выпадающих меню. */
.agg-apply[hidden] { display: none; }

/* Набор фильтров. На широком экране раскрыт всегда, кнопка-сводка скрыта;
   на узком сворачивается в «Фильтры · 2» — четыре селекта подряд занимали
   там весь первый экран, и до карточек приходилось листать.

   Атрибута open в разметке нет: он один на все ширины, а нужно «свёрнуто
   на мобильном, раскрыто на десктопе». Поэтому на широком экране содержимое
   показываем стилями поверх состояния details — ::details-content для новых
   браузеров, display для тех, где его ещё нет. Скрипт для этого не нужен,
   и панель работает без JS. */
.agg-filters { flex: 1 1 100%; }
.agg-filters-toggle { display: none; }
.agg-filters-body {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  flex-wrap: wrap;
}
/* Порог свёртки фильтров совпадает с порогом мобильной оболочки (880px):
   ниже него портал работает как приложение, и раскрытый набор фасетов внутри
   липкой панели занимал бы половину экрана планшета. Держать в паре
   с --sticky-top и .agg-bar в mobile.css. */
@media (min-width: 881px) {
  .agg-filters::details-content { content-visibility: visible; }
  .agg-filters .agg-filters-body { display: flex; }
}

/* Применённые фильтры: чип с крестиком снимает свой, последний — все.
   Без этой строки выбор не виден, и короткая выдача читается как «клиник
   почти нет», а не «вы сузили поиск». */
.agg-active {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin-bottom: var(--space-lg);
}
.agg-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding: 7px var(--space-md);
  border: 1px solid var(--surface-3);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--accent-ink);
  font-size: var(--text-sm);
  font-weight: 600;
  text-decoration: none !important;
}
.agg-chip svg { color: var(--text-subtle); }
@media (hover: hover) and (pointer: fine) {
  .agg-chip:hover { border-color: var(--accent-soft); }
  .agg-chip:hover svg { color: var(--accent-strong); }
}
.agg-chip:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
/* Сброс всего — не чип-фильтр, поэтому без рамки и тише */
.agg-chip-reset { border-color: transparent; color: var(--text-muted); font-weight: 500; }

/* Сортировка — выпадающее меню ссылками: работает без скрипта, на выбранный
   порядок можно дать ссылку. Тот же приём, что у фильтров в админке. */
.agg-sort { position: relative; }
/* Сам контрол — квадрат со значком. Высота берётся от соседа (переключателя
   вида) через align-items: stretch у .agg-head-tools: подгонять её числом
   значит ломать пару при любой правке отступов кнопки вида. */
.agg-sort > summary {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  /* Нижняя граница нужна выдаче врачей: там сортировка стоит в строке одна,
     тянуться не от кого, и по содержимому квадрат выходил в 20px. */
  min-height: 38px;
  aspect-ratio: 1;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  list-style: none;
}
.agg-sort > summary::-webkit-details-marker { display: none; }
@media (hover: hover) and (pointer: fine) {
  .agg-sort > summary:hover { border-color: var(--accent-soft); color: var(--accent-ink); }
}
/* Открытое меню и выбранный порядок — одна и та же подсветка: у значка нет
   подписи, и другого способа сказать «выдача отсортирована» не остаётся. */
.agg-sort[open] > summary,
.agg-sort.on > summary { border-color: var(--accent-soft); color: var(--accent-ink); }
.agg-sort > summary:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
/* Заголовок нужен только листу на телефоне: у поповера на десктопе якорем
   служит сам значок, над которым он раскрывается. */
.agg-sort-title { display: none; }
.agg-sort-menu {
  position: absolute;
  right: 0;
  z-index: 20;
  min-width: 200px;
  margin-top: var(--space-xs);
  padding: var(--space-xs);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  box-shadow: var(--shadow-md);
}
.agg-sort-menu a {
  display: block;
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--r-xs);
  color: var(--text);
  font-size: var(--text-sm);
}
@media (hover: hover) and (pointer: fine) {
  .agg-sort-menu a:hover { background: var(--surface-1); text-decoration: none; }
}
.agg-sort-menu a[aria-current] { background: var(--surface-2); color: var(--accent-ink); font-weight: 600; }

.agg-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-lg);
  flex-wrap: wrap;
}
/* Обёртка над формой и строкой счётчика. На десктопе её нет вовсе
   (display: contents): группировка контролов по смыслу — поиск с фильтрами
   в форме, счётчик с сортировкой ниже — здесь правильная. На телефоне из тех
   же узлов собирается одна липкая панель, и без общего родителя её не собрать
   (см. .agg-bar в mobile.css). */
.agg-bar { display: contents; }
/* stretch, а не center: значок сортировки тянется по высоте переключателя
   вида и остаётся с ним одной высоты (см. .agg-sort > summary). */
.agg-head-tools { display: flex; align-items: stretch; gap: var(--space-md); }
.agg-count { margin: 0; font-size: var(--text-lg); color: var(--text-muted); }
.agg-count b { color: var(--text); font-weight: 700; }

/* Переключатель вида — сегментированная пара, активный на подложке */
.agg-view {
  display: inline-flex;
  gap: var(--space-2xs);
  padding: var(--space-2xs);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
}
.agg-view-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: var(--space-sm) var(--space-lg);
  border-radius: var(--r-xs);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text-muted);
  text-decoration: none !important;
}
.agg-view-btn.on { background: var(--surface-2); color: var(--accent-ink); }
.agg-view-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* Карта в своём виде занимает всю ширину */
.catalog-map { position: static; width: auto; height: 640px; }
.catalog-map .map-canvas { height: 100%; border-radius: var(--r-md); }

/* ---------- Карточка клиники: фото с оценкой | суть | факты и действие ---------- */
/* Карточка выдачи — белая плитка с полями, как на референсе агрегатора:
   три колонки, между карточками воздух. */
.hc {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr) 280px;
  gap: var(--space-3xl);
  align-items: start;
  margin-bottom: var(--space-lg);
  padding: var(--space-3xl);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
}
.hc:last-of-type { margin-bottom: 0; }


.hc-media { display: flex; flex-direction: column; align-items: center; gap: var(--space-md); }
.hc-media img,
.hc-media-stub {
  width: 190px;
  height: 190px;
  border-radius: var(--r-md);
  object-fit: cover;
  background: var(--surface-1);
}
.hc-media-stub { display: flex; align-items: center; justify-content: center; color: var(--accent-ink); }
/* Оценка плашкой под логотипом: на референсе она наезжает на нижний край
   снимка и читается как его подпись, а не как отдельная строка. */
.hc-rate {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  margin: -26px 0 0;
  padding: 5px 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  font-size: var(--text-sm);
  font-weight: 700;
}
.hc-rate svg { color: #f2a91e; }
.hc-rate-cnt { display: inline-flex; align-items: center; gap: 4px; color: var(--text-subtle); font-weight: 500; }
.hc-rate-cnt svg { color: var(--text-subtle); }
.hc-review {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-sm);
  color: var(--text-muted);
}
.hc-review svg { color: var(--accent-strong); }

.hc-info { display: flex; flex-direction: column; gap: var(--space-sm); }
.hc-name { margin: 0; font-size: var(--t-h2); line-height: var(--leading-snug); }
.hc-name a { color: var(--text); }
@media (hover: hover) and (pointer: fine) {
  .hc-name a:hover { color: var(--accent-strong); }
}
/* Плашки смыслом, а не цветом: у каждой свой текст, цвет лишь усиливает */
.hc-badges { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.hc-badge {
  padding: 4px 10px;
  border-radius: var(--r-xs);
  font-size: var(--text-xs);
  font-weight: 500;
}
.hc-badge-round { background: var(--green-bg); color: var(--green-ink); }
.hc-badge-docs { background: var(--amber-bg); color: var(--amber-ink); }
.hc-badge-ok { background: var(--surface-2); color: var(--accent-ink); }
.hc-desc {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  /* Ровно две строки: описания разной длины иначе растягивали карточки
     по-разному и ряд выдачи выглядел рваным. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.hc-more { font-size: var(--text-sm); font-weight: 600; }

.hc-side { display: flex; flex-direction: column; gap: var(--space-md); }
.hc-fact {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}
.hc-fact .row-ico { color: var(--accent-strong); flex-shrink: 0; display: flex; }
/* Кружок вместо иконки — как метка линии метро в справочниках. Цвет приходит
   из справочника линий: --line ставится инлайном в шаблоне, значение по
   умолчанию нужно на случай станции без линии. */
.hc-metro { flex-wrap: wrap; row-gap: 4px; }
.hc-metro-item { display: flex; gap: var(--space-sm); align-items: flex-start; width: 100%; }
.hc-metro-dot {
  flex-shrink: 0;
  width: 10px;
  height: 10px;
  border-radius: var(--r-pill);
  background: var(--line, var(--accent));
  /* Тонкая обводка: светлые ветки (жёлтая, салатовая) на белом теряются */
  box-shadow: inset 0 0 0 1px rgba(17, 20, 31, 0.12);
}
/* В карточке клиники кружок занимает слот иконки — 16px, как у булавки и
   часов. Без этого название станции начиналось на 18px от края блока, а
   соседние строки — на 24px, и правая колонка выглядела рваной. */
.hc-metro-item .hc-metro-dot {
  display: grid;
  place-items: center;
  width: 16px;
  height: 16px;
  background: none;
  box-shadow: none;
}
.hc-metro-item .hc-metro-dot::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: var(--r-pill);
  background: var(--line, var(--accent));
  box-shadow: inset 0 0 0 1px rgba(17, 20, 31, 0.12);
}
/* Пунктир подчёркиванием, а не border-bottom: рамка рисуется по краю бокса
   и уезжает вниз, как только у ссылки появляется вертикальный паддинг —
   а он появляется на телефоне, где строчную ссылку в 18px надо дотянуть
   до пальца. Подчёркивание держится базовой линии при любом паддинге. */
.hc-metro-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-style: dashed;
  text-decoration-color: var(--surface-3);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
@media (hover: hover) and (pointer: fine) {
  .hc-metro-link:hover { color: var(--accent-strong); text-decoration-color: var(--accent-soft); }
}
/* Время пешком: значок пешехода и «≈9 мин» в скобках. Скобки и «≈» — прямое
   указание, что число примерное: оно посчитано не по маршруту, а редакцией
   и справочником, и владелец проверит его ногами. */
.hc-metro-min { color: var(--text-subtle); font-size: var(--text-xs); margin-left: 6px; white-space: nowrap; }
/* Значок садится на базовую линию строчных, а не на нижнюю кромку текста.
   Отрицательные поля съедают пустоту квадратного бокса значка — без них
   скобка отстояла от пешехода на четыре пикселя. */
.hc-metro-min svg { vertical-align: -0.2em; margin: 0 -1px 0 -3px; }
/* ── Карточка врача в каталоге ──
   Строка справочника: портрет | «кто это» и «где принимает» | телефон.

   Высота одна на все карточки, и это главное свойство. Прежняя версия
   несла описание врача (есть у 25%) и ссылку «Профиль врача»; на списке
   из двадцати это давало пять разных высот от 162 до 214px, а весь
   список — 4166px. Стало 130px на каждую (после увеличения ниже — 182px)
   и ровный ритм, по которому список просматривают, а не читают: высота
   в списке одна на всех, чем бы ни был заполнен профиль.

   Ширины колонок: портрет 132 (лицо читается, галереей не выглядит),
   действие 268, остальное — тексту. 250, а не 210: phone-reveal.js
   дорисовывает в кнопку подпись «— показать», и с ней содержимое кнопки
   занимает 231px, а у самых длинных номеров и больше — при 210 подпись вылезала за скруглённую рамку.

   Масштаб строки на десктопе поднят на пятую часть от исходного (портрет
   110→132, поля 20→24, имя 18→22, факты 14→16): в прежнем размере портрет
   был меньше строки текста рядом, и карточка человека читалась мельче
   карточки клиники над ней. Телефонная раскладка осталась прежней — там
   лишние 30px высоты стоят одной карточки на экран. */
.hc-doc {
  grid-template-columns: 132px minmax(0, 1fr) 268px;
  gap: var(--space-2xl);
  align-items: center;
  padding: var(--space-2xl);
  /* Якорь для растянутой ссылки — см. .hc-doc-link ниже */
  position: relative;
}
.hc-media-doc img {
  width: 132px;
  height: 132px;
  font-size: var(--text-xl);
  /* Кадр смещён вверх: снимки чаще поясные, и по центру в квадрат
     попадал халат, а лицо уходило под верхнюю кромку. */
  object-position: 50% 28%;
  /* Хайрлайн по контуру: у студийных снимков на белом фоне край
     растворялся в белой карточке, и фотографии будто не было. */
  box-shadow: 0 0 0 1px var(--border);
}
.hc-doc .hc-info { gap: var(--space-sm); min-width: 0; }
.hc-doc .hc-name { font-size: var(--text-xl); }

/* Вся карточка — цель перехода в профиль. Псевдоэлемент, а не обёртка
   в <a>: вложенные ссылки ломают клавиатуру и скринридер, а так в дереве
   доступности остаются три обычные ссылки — врач, клиника, телефон. */
.hc-doc-link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
/* Клиника, станции и телефон лежат выше растяжки, иначе она перехватывала
   бы клики по ним */
.hc-doc-clinic,
.hc-doc-where a,
.hc-doc-call { position: relative; z-index: 1; }

/* ── «Кто это» ──
   Специализация, должность, стаж, круглосуточность одной строкой.
   Разделители рисует ::before у последующих кусков, поэтому при любом
   наборе полей висящей точки не остаётся. */
.hc-doc-who {
  display: flex;
  align-items: baseline;
  gap: 4px var(--space-md);
  margin: 0;
  font-size: var(--text-base);
  /* Строго одна строка. У одного врача из двадцати четырёх должность
     длиннее колонки («Кандидат биологических наук, ветеринарный врач»),
     и её перенос делал карточку выше на 18px — ровно тот разнобой
     высот, ради устранения которого карточку и переделывали. Хвост
     обрезается многоточием, целиком должность есть в профиле. */
  flex-wrap: nowrap;
  overflow: hidden;
  white-space: nowrap;
}
.hc-doc-role { overflow: hidden; text-overflow: ellipsis; }
/* Стаж и круглосуточность не сжимаются: они короткие и одинаковой длины,
   а обрезать надо длинную должность. */
.hc-doc-spec,
.hc-doc-exp { flex-shrink: 0; }
.hc-doc-spec { font-weight: 600; color: var(--accent-ink); }
.hc-doc-role { color: var(--text); }
.hc-doc-exp { color: var(--text-muted); }
.hc-doc-role::before,
.hc-doc-exp::before {
  content: "·";
  color: var(--text-subtle);
  margin-right: var(--space-md);
}

/* ── «Где принимает» ──
   Одна строка фиксированной высоты. Станций у 55% каталога две, и если
   дать им переноситься, высота карточки станет зависеть от данных —
   ровно то, из-за чего прежний список читался рвано. */
.hc-doc-where {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  margin: 0;
  /* Единственная строка карточки, не выросшая вместе с ней: в неё уложены
     клиника, город и две станции с временем пешком, и на 16px название
     клиники начинало обрезаться до «Вас…» уже на 1000px. Ступень между
     ней и строкой «кто это» тут кстати — это меты, а не суть. */
  font-size: var(--text-sm);
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
}
.hc-doc-at {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 44%;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hc-doc-at svg { color: var(--accent-strong); flex-shrink: 0; }
.hc-doc-at a { overflow: hidden; text-overflow: ellipsis; }
.hc-doc-where .hc-metro {
  display: inline-flex;
  align-items: center;
  gap: var(--space-lg);
  min-width: 0;
  flex-wrap: nowrap;
}
.hc-doc-where .hc-metro-item { width: auto; align-items: center; }

/* ── Действие ──
   Телефон клиники, единственная кнопка карточки. Контур, а не заливка:
   заливка делала номер самым громким элементом карточки врача, хотя
   номер принадлежит клинике, а не человеку. Рамка --accent даёт 4.46:1
   к белому — граница элемента управления видна (WCAG 1.4.11 просит 3:1). */
.hc-doc .hc-side { justify-content: center; }
.hc-doc-call {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  /* Кегль остался 14: колонка под кнопку рассчитана по самому длинному
     номеру с подписью «— показать» (231px из 268), и на 16px он бы из неё
     вылез. Выросшую карточку кнопка догоняет полями, а не буквами. */
  padding: var(--space-md) var(--space-lg);
  border: 1px solid var(--accent);
  border-radius: var(--r-pill);
  color: var(--accent-strong);
  font-size: var(--text-sm);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--t-fast) var(--ease-out);
}
.hc-doc-call svg { color: var(--accent-strong); flex-shrink: 0; }
/* Кнопка занимает колонку целиком: иначе при разной длине номеров
   у соседних карточек правый край гуляет. */
.hc-doc-call { width: 100%; }
/* Подпись «показать» дорисовывает phone-reveal.js */
.hc-doc-call .cl-phone-show { color: var(--text-muted); font-weight: 500; }
/* Отклик на наведение.

   Задача у него ровно одна: сказать «кликнешь — попадёшь в эту строку».
   Всё, что сверх этого, мешает читать список.

   Заливки под курсором здесь нет, и это не экономия, а исправление.
   Карточка белая (--surface) на лавандовом фоне страницы (--bg), и они
   отличаются на 33 единицы из 765. Подсветка через --surface-1 давала
   разницу в 9 единиц — то есть под курсором карточка отличалась от фона
   в 3.7 раза СЛАБЕЕ, чем в покое, и буквально растворялась в странице.
   Подсветка обязана усиливать фигуру, а не гасить её.

   Осталось одно изменение: имя врача набирает акцент. Обводка под курсором
   больше не красится — в списке из двадцати одинаковых строк рамка, бегущая
   за курсором, тянет взгляд к границам карточек, а не к людям в них.
   Имя — и цель перехода, и единственное, чем строки различаются, поэтому
   отклика на нём достаточно. Подчёркивание имени снято отдельно (см. ниже):
   глобальное a:hover ставит его всем ссылкам, а на заголовке в 22px
   оно весит слишком много. */
@media (hover: hover) and (pointer: fine) {
  /* Растянутая ссылка ловит наведение по всей площади карточки, поэтому
     имя реагирует, даже когда курсор далеко от него. Цвета достаточно —
     подчёркивание здесь читалось бы как «строка сломалась». */
  .hc-doc:hover .hc-doc-link,
  .hc-doc-link:hover { text-decoration: none; }
  /* Кнопка заливается только при наведении на неё саму. Отдельного фона
     на время подсветки строки ей не нужно — её держит рамка --accent. */
  .hc-doc-call:hover { background-color: var(--accent); color: var(--on-accent); }
  .hc-doc-call:hover svg,
  .hc-doc-call:hover .cl-phone-show { color: var(--on-accent); }
}
.hc-doc-link:focus-visible { outline: none; }
.hc-doc:has(.hc-doc-link:focus-visible) {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.doc-empty { display: grid; gap: var(--space-sm); justify-items: center; }
.doc-empty p { margin: 0; }
.doc-empty .btn { margin-top: var(--space-sm); }

/* Соседние станции ветки — выход с посадочной страницы метро, чтобы
   страница с одной клиникой не была тупиком */
.metro-near { margin: var(--space-lg) 0 var(--space-2xl); }
.metro-near-title {
  margin: 0 0 var(--space-sm);
  font-size: var(--text-xs); font-weight: 700; color: var(--text-subtle);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.metro-near-list { display: flex; flex-wrap: wrap; gap: var(--space-sm); list-style: none; margin: 0; padding: 0; }
.metro-near-list a {
  display: inline-flex; align-items: center; gap: var(--space-sm);
  padding: 6px var(--space-md);
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface); color: var(--text);
  font-size: var(--text-sm); font-weight: 500;
}
.metro-near-list a:hover { border-color: var(--surface-3); background: var(--surface-1); text-decoration: none; }
.metro-near-list .hc-metro-dot { margin-top: 0; }
.hc-cta { margin-top: var(--space-md); padding: var(--space-md) var(--space-2xl); }
/* Та же кнопка, что на странице клиники, но в узкой колонке карточки: номер
   с подписью «показать» и значком в 24px отступов по бокам не помещался —
   первым сжимался значок. Отступы здесь меньше на всех ширинах; кегль номера
   на телефоне уменьшает правило .cl-phone-num выше по файлу. */
.hc-cta.cl-phone-btn { padding-inline: var(--space-md); }
/* Полосы 1241–1360 здесь больше нет: она лечила последствие правила
   .hc { … 170px } из прежнего поколения, а с ним ушла и причина —
   правая колонка карточки теперь всегда 280px и номер в неё помещается. */

/* Ступень карточки каталога на узком десктопе.

   Через .hc, а не .hc:not(.hc-doc): второй вариант имеет специфичность
   (0,2,0) и перебивал бы одноклассовые правила mobile.css — карточка
   КЛИНИКИ на телефоне получала десктопную раскладку и уезжала за экран.
   Здесь достаточно объявить врача следом при равном весе: правило ниже
   побеждает порядком, а не весом, и мобильный слой остаётся главным. */
@media (max-width: 1100px) {
  .hc { grid-template-columns: 150px minmax(0, 1fr); gap: var(--space-2xl); padding: var(--space-2xl); }
  .hc-media img, .hc-media-stub { width: 150px; height: 150px; }
  /* Факты уезжают под текст, а не в третью колонку: 300px справа при такой
     ширине оставляли описанию треть строки. */
  .hc-side { grid-column: 2; }

  /* У врача колонки узкие (132 / текст / 268) и в 1100px помещаются —
     сжимать его нечего, а двухколоночная раскладка ломала бы ровный
     ритм списка: высота прыгала со 130 до 266px. */
  /* Колонки те же, но зазоры прежние: на 1000px выросший портрет и без того
     забрал у текста 22px, и на этой ширине клиника со станциями обрезается
     первой. Колонку под телефон сжать нельзя — 231px занимает сам номер
     с подписью. */
  .hc-doc {
    grid-template-columns: 132px minmax(0, 1fr) 268px;
    gap: var(--space-xl);
    padding: var(--space-2xl) var(--space-xl);
  }
  .hc-doc .hc-media img { width: 132px; height: 132px; }
  .hc-doc .hc-side { grid-column: auto; }
}


/* ---------- Услуги клиники: поиск и аккордеон по отделениям ---------- */
/* Происхождение прайса: сообщение о процессе, поэтому тише самих цен
   и стоит один раз над поиском, а не в каждой группе. */
/* Оговорка над списком врачей на странице филиала сети: сообщение о
   границе наших данных, поэтому тише самого списка. */
.doc-network-note {
  margin: calc(-1 * var(--space-sm)) 0 var(--space-lg);
  font-size: var(--text-sm);
  color: var(--text-subtle);
}
.sv-search { position: relative; margin-bottom: var(--space-xl); }
.sv-search input {
  width: 100%;
  padding: var(--space-md) var(--space-4xl) var(--space-md) var(--space-lg);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface-1);
  font: inherit;
  font-size: var(--text-base);
  color: var(--text);
}
.sv-search input::placeholder { color: var(--text-subtle); }
.sv-search input:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.sv-search svg {
  position: absolute;
  top: 50%;
  right: var(--space-lg);
  transform: translateY(-50%);
  color: var(--text-subtle);
  pointer-events: none;
}
.sv-empty { margin: 0 0 var(--space-lg); color: var(--text-muted); }
.sv-empty[hidden] { display: none; }

.sv-groups { list-style: none; margin: 0; padding: 0; }
.sv-group { border-top: 1px solid var(--border); }
.sv-group:first-child { border-top: 0; }
.sv-group[hidden] { display: none; }
.sv-group-head {
  display: flex;
  /* baseline, а не center: у группы с датой актуализации заголовок стал
     двухстрочным, и при центрировании счётчик с шевроном сползали к
     середине блока, теряя связь с названием. */
  align-items: baseline;
  gap: var(--space-sm);
  width: 100%;
  padding: var(--space-lg) 0;
  border: 0;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.sv-group-head:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
/* Заголовок забирает свободное место, чтобы счётчик и шеврон стояли
   у правого края, а не вплотную к тексту переменной длины. */
.sv-group-title { flex: 1 1 auto; min-width: 0; font-size: var(--text-base); font-weight: 700; color: var(--text); }
/* Счётчик акцентом — он отвечает на «сколько тут», а не украшает */
.sv-group-count { flex: none; color: var(--accent-strong); font-size: var(--text-sm); font-weight: 700; }
.sv-group-caret {
  display: flex;
  margin-left: auto;
  color: var(--accent-strong);
  transform: rotate(90deg);
  transition: transform var(--t-fast) var(--ease-out);
}
.sv-group-head[aria-expanded="true"] .sv-group-caret { transform: rotate(-90deg); }
@media (prefers-reduced-motion: reduce) { .sv-group-caret { transition: none; } }
@media (hover: hover) and (pointer: fine) {
  .sv-group-head:hover .sv-group-title { color: var(--accent-strong); }
}

/* Список услуг внутри группы. Две колонки на широком экране: перечень
   в 116 позиций одной колонкой растягивает страницу без нужды. */
.sv-items {
  list-style: none;
  margin: 0;
  padding: 0 0 var(--space-lg);
}
.sv-items[hidden] { display: none; }
.sv-items li[hidden] { display: none; }

/* Строка прайса: услуга слева, цена у правого края. Одна колонка, а не две:
   при columns: 2 читать приходилось сверху вниз по левой колонке, потом
   по правой, а цены вставали на случайной высоте после названия переменной
   длины. Теперь все числа в одной вертикали, строки разделены хайрлайнами.

   Сетка, а не флекс: у названия в две строки цена обязана держаться первой
   строки, и baseline-выравнивание грида делает это без хаков. */
.sv-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--space-md);
  padding: var(--space-sm) 0;
  border-top: 1px solid var(--border);
  font-size: var(--text-sm);
  color: var(--text-muted);
  line-height: var(--leading-normal);
}
.sv-item:first-child { border-top: 0; }
.sv-item-name { min-width: 0; color: var(--text); }
/* Уточнение из скобок — второй строкой и тише: «КТ-топометрия (включая
   скрининг и заключение)» одним кеглем читается как одна длинная фраза. */
.sv-item-qual {
  display: block;
  color: var(--text-subtle);
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
}
.sv-item-price {
  color: var(--text);
  font-weight: 700;
  white-space: nowrap;
}
/* Единица измерения («за приём», «за сутки») мельче и тише самой цены:
   это уточнение, а не второе число. */
.sv-item-unit {
  color: var(--text-subtle);
  font-weight: 400;
  font-size: var(--text-2xs);
}

/* ---------- Отзывы: сводка с разбивкой и карточки ---------- */
/* Сводка: балл плашкой, рядом словесная оценка, справа разбивка по критериям */
.rv-summary {
  display: grid;
  grid-template-columns: minmax(220px, auto) minmax(0, 1fr);
  gap: var(--space-2xl);
  align-items: center;
  margin-bottom: var(--space-2xl);
  padding-bottom: var(--space-2xl);
  border-bottom: 1px solid var(--border);
}
.rv-summary-total { display: flex; align-items: center; gap: var(--space-lg); }
.rv-summary-text { display: flex; flex-direction: column; gap: var(--space-2xs); }
.rv-summary-word { font-size: var(--text-xl); font-weight: 700; line-height: var(--leading-snug); }
.rv-summary-base { font-size: var(--text-sm); color: var(--text-subtle); }

/* Балл-закладка: тот же приём, что у оценки в шапке карточки */
.rv-score {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 62px;
  padding: var(--space-lg) var(--space-md) var(--space-2xl);
  border-radius: var(--r-sm);
  color: var(--on-accent);
  font-size: var(--text-xl);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.01em;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 78%, 0 100%);
}
.rv-score-sm { min-width: 46px; padding: var(--space-md) var(--space-sm) var(--space-xl); font-size: var(--text-lg); }
.rv-score-good { background: var(--green-ink); }
.rv-score-so-so { background: var(--amber-ink); }
.rv-score-bad { background: var(--rose-ink); }

/* Разбивка: две колонки полосок. Полоска над подписью — так строка читается
   слева направо «сколько → чего», а не наоборот. */
.rv-criteria {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: var(--space-md) var(--space-2xl);
}
.rv-criterion {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 2px var(--space-md);
  margin: 0;
}
.rv-criterion-bar {
  grid-column: 1 / -1;
  height: 4px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  overflow: hidden;
}
/* Цвет полоски по тем же порогам, что и словесная оценка: сплошь зелёные
   полоски врали бы про «Цена/качество 6,8». */
.rv-criterion-fill { display: block; height: 100%; background: var(--green-ink); }
.rv-fill-so-so { background: var(--amber-ink); }
.rv-fill-bad { background: var(--rose-ink); }
.rv-criterion-label { font-size: var(--text-sm); color: var(--text-muted); }
.rv-criterion-val { font-size: var(--text-sm); font-weight: 700; }

/* Карточка отзыва: кто слева, оценка и текст справа */
.rv-list { display: flex; flex-direction: column; }
.rv-item {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  gap: var(--space-2xl);
  padding: var(--space-2xl) 0;
  border-bottom: 1px solid var(--border);
}
.rv-item:last-child { border-bottom: 0; padding-bottom: 0; }
.rv-who { display: flex; flex-direction: column; gap: var(--space-sm); }
.rv-who-name { display: flex; align-items: center; gap: var(--space-sm); }
.rv-who-name b { font-weight: 700; }
.rv-who-date { font-size: var(--text-sm); color: var(--text-subtle); }
.rv-body-head { display: flex; align-items: center; gap: var(--space-md); margin-bottom: var(--space-lg); }
.rv-body-word { font-size: var(--text-lg); font-weight: 700; }
/* Подписи разделов отзыва цветом повторяют смысл, но не только цветом —
   рядом всегда слово «понравилось» или «не понравилось». */
.rv-mark {
  margin: 0 0 var(--space-2xs);
  font-size: var(--text-xs);
  font-weight: 700;
}
.rv-mark-good { color: var(--green-ink); }
.rv-mark-bad { color: var(--rose-ink); }
.rv-mark + .rv-text { margin-top: 0; }
.rv-text { margin: 0 0 var(--space-md); }
.rv-text:last-child { margin-bottom: 0; }

/* Пустое состояние с действием. Одной серой строкой оно читалось как «здесь
   ничего нет и не будет»; на странице врача это состояние сейчас у всех —
   отзывов о врачах в базе ещё ни одного, — и способ это изменить показан
   прямо тут. Рамкой не выделяем: раздел и так стоит в своей плитке. */
/* Свой отзыв на проверке — виден только автору.

   Оформлен подложкой, а не как обычная карточка отзыва: это не часть
   общего списка, а сообщение о состоянии. Янтарь здесь уместен именно
   потому, что означает «ждёт действия» — в отличие от каталога, где той
   же плашкой был покрашен нейтральный факт. */
.rv-own {
  margin-bottom: var(--space-2xl);
  padding: var(--space-xl);
  border: 1px solid var(--amber-ink);
  border-radius: var(--r-md);
  background: var(--amber-bg);
}
.rv-own-rejected { border-color: var(--rose-ink); background: var(--rose-bg); }
.rv-own-head {
  display: flex; align-items: center; gap: var(--space-md);
  margin-bottom: var(--space-sm);
}
.rv-own-title { font-size: var(--text-lg); }
.rv-own-status {
  padding: 2px var(--space-sm);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--amber-ink);
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.rv-own-rejected .rv-own-status { color: var(--rose-ink); }
.rv-own-rate { display: inline-flex; gap: 2px; margin-bottom: var(--space-sm); }
.rv-own-star { color: var(--lav-3); line-height: 0; }
.rv-own-star.on { color: var(--amber-ink); }
.rv-own-text {
  margin: 0 0 var(--space-md);
  line-height: var(--leading-relaxed);
}
.rv-own-note {
  margin: 0 0 var(--space-md);
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}
.rv-own-link { font-weight: 500; font-size: var(--text-sm); }

/* Кнопка в шапке, пока отзыв на проверке: остаётся ссылкой к своему
   отзыву, но не зовёт писать ещё один. */
.btn.is-pending {
  color: var(--amber-ink);
  border-color: var(--amber-ink);
  background: var(--amber-bg);
}

.rv-empty { max-width: 58ch; }
.rv-empty-title { margin: 0 0 var(--space-xs); font-weight: 700; }
.rv-empty-text {
  margin: 0 0 var(--space-lg);
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

/* Сортировка отзывов — обычные ссылки-чипы, работают без JS */
.rv-sort { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-bottom: var(--space-xl); }

.rv-avatar {
  width: 40px;
  height: 40px;
  border-radius: var(--r-pill);
  object-fit: cover;
  background: var(--surface-1);
  flex-shrink: 0;
}
.rv-who-context { font-size: var(--text-sm); color: var(--text-muted); }

/* Фотографии от посетителя */
.rv-photos { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-bottom: var(--space-md); }
.rv-photo {
  display: block;
  width: 96px;
  height: 96px;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--surface-2);
}
.rv-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.rv-photo:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .rv-photo:hover img { transform: scale(1.05); transition: transform var(--t-med) var(--ease-out); }
}

/* Ответ клиники: внутри карточки отзыва, с отбивкой слева — видно, что это
   реплика на конкретный отзыв, а не отдельное сообщение. */
.rv-reply {
  margin-top: var(--space-lg);
  padding: var(--space-md) var(--space-lg);
  border-left: 2px solid var(--surface-3);
  background: var(--surface-1);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
}
.rv-reply-head {
  margin: 0 0 var(--space-xs);
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--accent-ink);
}
.rv-reply-head span { font-weight: 500; }
.rv-reply-head time { color: var(--text-subtle); font-weight: 400; }

/* Оценки по критериям в форме */
.rv-crit-input {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--space-sm) var(--space-2xl);
  margin-bottom: var(--space-lg);
}
.rv-crit-row { display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-md); margin: 0; padding: 0; border: 0; }
.rv-crit-row legend { padding: 0; font-size: var(--text-sm); color: var(--text-muted); }
.rating-input-sm label { padding: 2px; }


/* ---------- Карта в шапке карточки клиники ---------- */
/* Превью занимает правую треть и гасится диагональной маской. Маска, а не
   градиентная подложка: работает на любом фоне карточки и не требует правок,
   если фон сменится. */
.cl-card { position: relative; overflow: hidden; }
.cl-card-map {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 46%;
  /* height: 100% обязателен. У картинки высота auto берётся из собственных
     пропорций, а `bottom` для замещённого элемента при этом игнорируется:
     превью 650×450 разворачивалось в 350px и обрывалось белой полосой, как
     только карточка становилась выше (в карточке врача она 397px). */
  height: 100%;
  object-fit: cover;
  -webkit-mask-image: linear-gradient(108deg, transparent 0%, transparent 18%, #000 58%);
  mask-image: linear-gradient(108deg, transparent 0%, transparent 18%, #000 58%);
  /* Клики уходят на кнопку «Открыть карту», а не в картинку */
  pointer-events: none;
}
/* Оценка ложится поверх карты — обе сущности делят одну зону вместо драки
   за неё. Подложка нужна: на пёстрой карте текст без неё не читается.
   Селектор через :has — без карты (у клиники без координат и в шапке врача)
   абсолют и стеклянная плашка остались бы бликом на белом фоне без причины,
   а сама оценка выпадала бы из потока фактов. */
.cl-card:has(.cl-card-map) .cl-score {
  position: absolute;
  top: var(--space-xl);
  right: var(--space-xl);
  z-index: 2;
  padding: var(--space-sm) var(--space-sm) var(--space-sm) var(--space-lg);
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: var(--shadow-md);
}
.cl-map-open {
  position: absolute;
  right: var(--space-xl);
  bottom: var(--space-xl);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 15px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.94);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: var(--shadow-sm);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--accent-ink);
  cursor: pointer;
}
.cl-map-open svg { color: var(--accent-strong); }
.cl-map-open:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .cl-map-open:hover { border-color: var(--accent-soft); }
}

/* Модалка формы отзыва — те же правила, что у модалки карты */
.review-modal {
  /* Ширина под две колонки: слева письмо, справа необязательное. При 620px
     колонка получалась по 280 — в неё не помещались ни звёзды, ни поле,
     в которое хочется писать. На телефоне ширину задаёт лист снизу
     (mobile.css), и это число там ни на что не влияет. */
  width: min(940px, calc(100vw - var(--space-3xl)));
  max-width: none;
  max-height: calc(100vh - var(--space-3xl));
  padding: 0;
  border: 0;
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  /* Прокрутки у самого окна больше нет: внутри оболочка с закреплённой
     шапкой и низом, а между ними панель ровно по остатку высоты.
     Раньше здесь стояло overflow: auto, и форма в 1418px просто прокручивалась
     внутри — до кнопки отправки было два экрана. */
  overflow: hidden;
  flex-direction: column;
}
/* display — только у открытого. В базовом правиле он перебивал правило
   браузера «dialog:not([open]) { display: none }», и закрытая модалка
   оставалась нарисованной на странице обычным блоком: диалог закрыт,
   а форма видна. Та же ловушка, что с атрибутом hidden. */
.review-modal[open] { display: flex; }
.review-modal::backdrop { background: rgba(39, 39, 108, 0.45); backdrop-filter: blur(3px); }
/* Форма в модалке: оболочка задаёт ширину сама. max-width из общего правила
   .review-form (560px) остался от времён, когда форма стояла блоком на
   странице; в окне он резал вторую колонку и оставлял треть окна пустой. */
.review-modal .review-form {
  margin: 0;
  border: 0;
  padding: 0;
  background: none;
  max-width: none;
  width: 100%;
}

/* Модалка телефона: название клиники, номер и вопрос «дозвонились?».
   Номер — самое крупное на экране: за ним сюда и пришли. Опрос отделён
   подложкой, а не рамкой: это другой разговор, но не другой раздел. */
.phone-modal {
  width: min(460px, calc(100vw - var(--space-3xl)));
  max-width: none;
  padding: var(--space-2xl);
  border: 0;
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}
.phone-modal::backdrop { background: rgba(39, 39, 108, 0.45); backdrop-filter: blur(3px); }
.phone-modal .lightbox-close {
  position: absolute;
  top: var(--space-lg);
  right: var(--space-lg);
  background: none;
  color: var(--text-subtle);
}
@media (hover: hover) and (pointer: fine) {
  .phone-modal .lightbox-close:hover { background: var(--surface-1); color: var(--text); }
}
.phone-modal-title {
  margin: 0 var(--space-4xl) var(--space-lg) 0;   /* место под крестик */
  font-size: var(--text-lg);
  font-weight: 700;
  line-height: var(--leading-snug);
}
/* Номер в своём поле: с телефона по нему звонят, с компьютера переписывают,
   поэтому рядом кнопка «скопировать». Поле белое с бордером, а блок опроса
   ниже — на лавандовой подложке: два одинаковых прямоугольника подряд
   читались бы как один разъехавшийся. */
.phone-modal-field {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  margin-bottom: var(--space-md);
  padding: var(--space-md);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}
/* Пустышка шириной с кнопку копирования. Номер выключен по центру, и без
   этого противовеса справа центр съезжал бы влево на половину кнопки —
   в поле шириной с модалку такой сдвиг видно сразу.

   Сжимается (0 1 40px, не none): на 360px распорка в полную ширину съедала
   место у номера, и он разваливался на две строки. Ровный центр — роскошь,
   номер в одну строку — обязанность. */
.phone-modal-field::before {
  content: "";
  flex: 0 1 40px;
}
.phone-modal-num {
  /* Растёт, но не сжимается: свободное место забирает номер и центрует
     себя в нём, а нехватку целиком отдувает распорка слева. */
  flex: 1 0 auto;
  text-align: center;
  /* Номер не переносится никогда: «+7 (961) 881-34-» и «14» на второй строке
     читаются как два разных числа. */
  white-space: nowrap;
  color: var(--text);
  font-size: var(--text-xl);
  font-weight: 800;
  letter-spacing: -0.01em;
}
@media (hover: hover) and (pointer: fine) {
  .phone-modal-num:hover { color: var(--accent-strong); text-decoration: none; }
}
.phone-modal-copy {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  /* 40px — нижняя граница удобной тач-цели; меньше делать нельзя, хотя значок
     занимает половину. */
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: var(--r-sm);
  background: var(--surface-1);
  color: var(--accent-ink);
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .phone-modal-copy:hover { background: var(--surface-2); }
}
.phone-modal-copy:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
/* Скопировано: на секунду вместо значка копии — галочка на зелёной подложке.
   Подтверждение нужно там, где произошло действие, а не строкой под полем. */
.phone-modal-copy.is-done { background: var(--green-bg); color: var(--green-ink); }
.phone-modal-copy-idle, .phone-modal-copy-done { display: flex; }
.phone-modal-copy-done { display: none; }
.phone-modal-copy.is-done .phone-modal-copy-idle { display: none; }
.phone-modal-copy.is-done .phone-modal-copy-done { display: flex; }
.phone-modal-tips { margin-bottom: var(--space-lg); }
.phone-modal-note {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}
.phone-modal-note + .phone-modal-note { margin-top: var(--space-sm); }
.phone-modal-ask {
  padding: var(--space-lg);
  border-radius: var(--r-sm);
  background: var(--surface-1);
}
.phone-modal-ask-title { margin: 0 0 var(--space-md); font-weight: 700; }
.phone-modal-btns { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.phone-modal-btns .btn {
  flex: 1 1 auto;
  justify-content: center;
  padding: 10px 16px;
  font-size: var(--text-sm);
  min-height: 44px;
}
/* Ghost-кнопки на лавандовой подложке опроса теряли фон и читались голым
   текстом — здесь они белые с бордером, как в остальных рядах действий. */
.phone-modal-btns .btn-ghost { background: var(--surface); border: 1px solid var(--border); }
@media (hover: hover) and (pointer: fine) {
  .phone-modal-btns .btn-ghost:hover { border-color: var(--accent-soft); background: var(--surface); }
}
.phone-modal-hint {
  margin: var(--space-md) 0 0;
  color: var(--text-subtle);
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
}
/* Ответ на месте опроса: та же подложка, чтобы блок не «прыгнул» после клика */
.phone-modal-thanks {
  margin: 0;
  padding: var(--space-lg);
  border-radius: var(--r-sm);
  background: var(--green-bg);
  color: var(--green-ink);
  font-size: var(--text-sm);
  font-weight: 500;
}

/* Модалка с картой — единственная интерактивная карта на странице */
.map-modal {
  width: min(940px, calc(100vw - var(--space-3xl)));
  max-width: none;
  padding: 0;
  border: 0;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}
.map-modal::backdrop { background: rgba(39, 39, 108, 0.45); backdrop-filter: blur(3px); }
.map-modal-canvas { height: min(460px, 60vh); background: var(--surface-1); }
.map-modal-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2xl);
  padding: var(--space-xl) var(--space-2xl);
}
.map-modal-addr { margin: 0; font-size: var(--text-sm); }
.map-modal-addr b { display: block; font-size: var(--text-lg); margin-bottom: var(--space-xs); }
.map-modal-addr span { color: var(--text-subtle); }
/* Крестик над картой: базовый .lightbox-close сделан для тёмного лайтбокса —
   белый значок на полупрозрачной подложке. На светлой карте он растворялся,
   поэтому здесь подложка плотная, а значок тёмный. Размытие под ней — не
   украшение: под кнопкой мелкие подписи улиц. */
.map-modal .lightbox-close {
  position: absolute;
  top: var(--space-lg);
  right: var(--space-lg);
  z-index: 2;
  background: rgba(255, 255, 255, 0.94);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: var(--shadow-sm);
  color: var(--accent-ink);
}
@media (hover: hover) and (pointer: fine) {
  .map-modal .lightbox-close:hover { background: #fff; }
}


.cl-contacts { display: flex; flex-direction: column; }
.cl-trust {
  margin-top: var(--space-lg);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--border);
}
.cl-trust-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
  margin: 0 0 var(--space-sm);
  font-size: var(--text-sm);
  color: var(--text-muted);
}
.cl-trust-row:last-child { margin-bottom: 0; }
.cl-trust-row .row-ico { color: var(--green-ink); flex-shrink: 0; }
.cl-trust-row.is-verified .row-ico { color: var(--accent); display: flex; }
.cl-license { color: var(--text-subtle); font-variant-numeric: tabular-nums; }

/* Чипы внутри белой плитки берут мягкую подложку: белое на белом различалось
   только по светлой рамке #eae7f6 и не читалось.
   Строки врачей отсюда убраны: правило писалось под прежние плитки-карточки
   и красило их подложкой в покое, а на наведении делало белыми. В списке это
   давало обратную подсветку — строка под курсором сливалась с секцией. */
.cl-section .chip { background: var(--surface-1); }
@media (hover: hover) and (pointer: fine) {
  .cl-section .chip:hover { background: var(--surface); }
}

/* Форма отзыва внутри плитки секции — не вторая карточка в карточке,
   а подблок, отделённый линией. */
.cl-section .review-form {
  margin-top: var(--space-2xl);
  padding: var(--space-2xl) 0 0;
  border: 0;
  border-top: 1px solid var(--border);
  border-radius: 0;
  background: transparent;
}

/* ── Разделы сайдбара карточки клиники ──────────────────────────────────
   Плитка, как и секции контента слева: белый фон, рамка, тот же радиус.
   Плавающие карточки манифест не любит, и была попытка снять их здесь —
   но страница ещё не переведена на белый фон, соседние .cl-section остаются
   плитками, и колонка без поверхности оказалась единственным элементом
   без опоры: текст с линейками прямо на лавандовом. Пока карточками
   выглядит вся страница, сайдбар обязан выглядеть так же; снимать их
   нужно всей страницей разом, а не одной колонкой. */
.side-sec {
  padding: var(--space-xl);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
}
.side-sec-title {
  margin: 0 0 var(--space-sm);
  padding-bottom: var(--space-sm);
  border-bottom: 1px solid var(--border);
  font-size: var(--text-sm);
  font-weight: 700;
  line-height: var(--leading-snug);
}

.near-list { list-style: none; margin: 0; padding: 0; }

/* Строка целиком — цель нажатия. Раньше кликался только текст ссылки:
   на телефоне это полоска в двадцать пикселей высотой. */
.near-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 var(--space-md);
  padding: 10px 0;
  min-height: var(--tap);
  align-content: center;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  text-decoration: none;
}
.near-list li:last-child .near-row { border-bottom: 0; }
@media (hover: hover) and (pointer: fine) {
  /* Подсветка выходит в поля плитки: иначе фон обрывается по тексту и
     строка не читается как одна цель. Величина равна padding у .side-sec. */
  .near-row:hover {
    background: var(--surface-1);
    box-shadow: calc(var(--space-xl) * -1) 0 0 var(--surface-1),
                var(--space-xl) 0 0 var(--surface-1);
  }
  .near-row:hover .near-name { color: var(--accent-ink); }
}
.near-row:focus-visible { outline: 2px solid var(--violet); outline-offset: 2px; }

.near-name {
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: var(--leading-snug);
  /* Длинное название не должно выталкивать расстояние из строки */
  min-width: 0;
  overflow-wrap: anywhere;
}
/* Расстояние прижато вправо и набрано цифрами таблицы (tabular-nums стоит
   на body): колонка чисел выравнивается сама и читается по вертикали —
   это и превращает список ссылок в справочник. */
.near-km {
  grid-column: 2;
  align-self: start;
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
}
.near-meta {
  grid-column: 1 / -1;
  margin-top: 2px;
  font-size: var(--text-2xs);
  color: var(--text-subtle);
  line-height: var(--leading-snug);
}
/* Круглосуточно — единственная метка, способная решить выбор прямо здесь:
   так работает половина клиник, а на страницу часто приходят ночью.

   Точкой, а не заливкой: три зелёные плашки подряд перетягивали внимание
   с названий, ради которых список и читают. Точка — тот же словарь, что
   у .pill-live в шапке, но без пульсации: мигающая анимация уместна для
   одного живого статуса, а в списке из четырёх строк это мельтешение. */
.near-tag {
  grid-column: 1 / -1;
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 3px;
  color: var(--green-ink);
  font-size: var(--text-2xs);
  font-weight: 600;
}
.near-tag::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--green-ink);
  flex: none;
}

.side-sec-more {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: var(--space-md);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--accent-ink);
}
.side-sec-more svg { flex: none; }


/* Лайтбокс */
/* Лайтбокс занимает всё окно, а не облегает снимок: стрелки, крестик и
   счётчик стоят по краям окна и не переезжают вслед за пропорцией кадра —
   иначе при листании портрета после панорамы стрелка уходит из-под курсора. */
.lightbox {
  inset: 0;
  width: 100vw;
  max-width: 100vw;
  height: 100dvh;
  max-height: 100dvh;
  margin: 0;
  border: none;
  background: transparent;
  padding: 0;
  overflow: hidden;
}
.lightbox::backdrop { background: rgba(17, 20, 31, 0.82); }
.lightbox-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}
/* Ширина оставляет поля под стрелки: снимок под кнопкой листания не читается */
.lightbox-img {
  display: block;
  max-width: min(92vw, calc(100vw - 200px));
  max-height: 84vh;
  border-radius: var(--r-md);
  object-fit: contain;
}
.lightbox > .lightbox-close { top: var(--space-xl); right: var(--space-xl); }
.lightbox-nav {
  position: absolute;
  top: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  margin-top: -26px;
  border: none;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out);
}
.lightbox-prev { left: var(--space-2xl); }
.lightbox-next { right: var(--space-2xl); }
/* Одна иконка на обе стрелки: зеркалим, а не заводим второй контур */
.lightbox-prev svg { transform: scaleX(-1); }
@media (hover: hover) and (pointer: fine) {
  .lightbox-nav:hover { background: rgba(255, 255, 255, 0.26); }
}
.lightbox-nav:active { transform: scale(0.94); }
.lightbox-nav[hidden] { display: none; }
/* Счётчик и авторство — одной плашкой внизу, тем же словарём, что и «Все фото»
   на полотне: это продолжение той же кнопки, только в полный экран. */
.lightbox-meta {
  position: absolute;
  left: 50%;
  bottom: var(--space-2xl);
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  max-width: min(80vw, 560px);
  margin: 0;
  padding: var(--space-xs) var(--space-lg);
  border-radius: var(--r-pill);
  background: rgba(17, 20, 31, 0.62);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: #fff;
  font-size: var(--text-sm);
}
.lightbox-meta[hidden] { display: none; }
.lightbox-count { white-space: nowrap; }
/* У одиночного кадра счётчика нет: пустой span оставлял бы за собой отступ
   и точку-разделитель перед авторством. */
.lightbox-count:empty { display: none; }
.lightbox-count:empty + .lightbox-credit::before { content: none; }
.lightbox-credit {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  opacity: 0.75;
}
.lightbox-credit::before { content: '·'; margin-right: var(--space-sm); }
.lightbox-credit[hidden] { display: none; }
/* Скрытые кадры полотна: в ряд помещаются три, листается вся галерея */
.cl-cover-rest { display: none; }
.lightbox-close {
  position: absolute;
  top: -44px;
  right: 0;
  display: flex;
  padding: var(--space-sm);
  border: none;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .lightbox-close:hover { background: rgba(255, 255, 255, 0.26); }
}

/* Липкая панель действий — только на узких экранах и только после того,
   как кнопки в шапке ушли из виду (класс вешает clinic-page.js). */
/* Липкая панель действий — только на узких экранах. На десктопе она
   выпрыгивала поверх контента, а телефон там всегда виден в шапке. */
.cl-sticky-cta { display: none; }


/* ---------- Клиники, врачи и отзывы ---------- */

.pill {
  display: inline-block;
  background: var(--green-bg);
  color: var(--green-ink);
  font-size: var(--text-2xs);
  font-weight: 700;
  border-radius: var(--r-pill);
  padding: 4px 11px;
}
/* Круглосуточно — с зелёной точкой «в эфире» */
.pill-live {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
}
.pill-live::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--green-ink);
}
@media (prefers-reduced-motion: no-preference) {
  .pill-live::before { animation: pill-pulse 1.8s var(--ease-in-out) infinite; }
}
@keyframes pill-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

.review { border-bottom: 1px solid var(--line); padding: 20px 0; }
.review:last-child { border-bottom: none; }
.review-stars { display: inline-flex; gap: 1px; color: #f2a91e; }
.review-stars span { display: inline-flex; }
.review-stars .off { color: var(--lav-3); }
.review p { margin: 0; }

.review-form {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--space-2xl);
  margin-top: var(--space-2xl);
  max-width: 560px;
}
.review-form h3 { margin-bottom: 4px; }
.review-form label { display: block; font-weight: 500; font-size: var(--text-sm); margin: 16px 0 6px; }
.review-form input[type="text"],
.review-form textarea {
  width: 100%;
  border: 1px solid var(--lav-3);
  border-radius: var(--r-sm);
  padding: 10px 14px;
  font: inherit;
  color: var(--ink);
  background: #fff;
  transition: border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
}
.review-form input[type="text"]:focus,
.review-form textarea:focus {
  outline: none;
  border-color: var(--violet);
  box-shadow: 0 0 0 3px var(--lav-2);
}
.form-error { color: var(--rose-ink); font-size: var(--text-xs); margin: 4px 0 0; }

/* Звёзды-радио: разметка 5→1 + row-reverse, «закрашиваем» выбранную и все левее */
.rating-input { display: inline-flex; flex-direction: row-reverse; gap: 2px; }
.rating-input input { position: absolute; opacity: 0; width: 0; height: 0; }
.rating-input label {
  cursor: pointer;
  color: var(--lav-3);
  margin: 0;
  padding: 2px;
  transition: color var(--t-fast) var(--ease-out);
}
.rating-input label svg { display: block; }
.rating-input input:checked ~ label { color: #f2a91e; }
@media (hover: hover) and (pointer: fine) {
  .rating-input label:hover,
  .rating-input label:hover ~ label { color: #f2a91e; }
}
.rating-input input:focus-visible + label { outline: 2px solid var(--violet); border-radius: 6px; }

/* Honeypot: поле недоступно людям */
.hp-field { position: absolute !important; left: -9999px; top: -9999px; height: 0; overflow: hidden; }

.contact-list { list-style: none; margin: 0; padding: 0; }
.contact-list li {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin-bottom: 12px;
  font-size: var(--text-sm);
  color: var(--muted);
}
.contact-list li:last-child { margin-bottom: 0; }
.contact-list .row-ico { margin-top: 1px; }
.contact-list a { color: var(--indigo); font-weight: 500; }

/* ---------- Строка поиска и подсказки ---------- */

.home-search {
  position: sticky;
  top: calc(var(--header-h) + 10px);
  z-index: 45;
  margin-top: 22px;
}
.home-search .search-form {
  max-width: 100%;
  margin: 0 auto;
  transition: max-width 380ms var(--ease-out),
              padding 380ms var(--ease-out),
              box-shadow 380ms var(--ease-out),
              border-color var(--t-fast) var(--ease-out);
}
.home-search .search-form input,
.home-search .search-form .search-submit {
  transition: padding 380ms var(--ease-out), font-size 380ms var(--ease-out),
              width 380ms var(--ease-out), height 380ms var(--ease-out);
}
/* Пристыкованное состояние: полоса сжимается в компактную пилюлю */
.home-search.is-stuck .search-form {
  max-width: 660px;
  padding: 4px;
  box-shadow: 0 8px 28px rgba(39, 39, 108, 0.16), 0 1px 3px rgba(39, 39, 108, 0.1);
}
.home-search.is-stuck .search-form input { padding: 7px 4px 7px 14px; font-size: var(--text-sm); }
.home-search.is-stuck .search-form .search-submit { width: 38px; height: 38px; }


@media (prefers-reduced-motion: reduce) {
  .home-search .search-form,
  .home-search .search-form input,
  .home-search .search-form .search-submit { transition: none; }
}

.search-form {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-md);
  transition: border-color var(--t-fast) var(--ease-out);
}
.search-form:focus-within { border-color: var(--violet-soft); }
.search-form input {
  flex: 1;
  min-width: 0;
  padding: 10px 4px 10px 16px;
  border: none;
  background: transparent;
  font: inherit;
}
/* Submit без фона: цветом отделяется от плейсхолдера, размер держим 44×44
   ради тач-цели, хотя визуально кнопка — только иконка. */
.search-submit {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--violet);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .search-submit:hover { background: var(--lav-1); color: var(--violet-deep); }
}
.search-submit:focus-visible { outline: 2px solid var(--violet-soft); outline-offset: 2px; }
.search-form input:focus { outline: none; }
.search-form input::-webkit-search-cancel-button { display: none; }
.search-clear {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--faint);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
.search-clear[hidden] { display: none; }
@media (hover: hover) and (pointer: fine) {
  .search-clear:hover { background: var(--lav-1); color: var(--muted); }
}

.suggest {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  z-index: 40;
  max-height: min(62vh, 440px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 8px 0;
  text-align: left;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
}
.suggest[hidden] { display: none; }
.suggest-group + .suggest-group {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--line);
}
.suggest-group-title {
  padding: 8px 20px 4px;
  font-size: var(--text-2xs);
  color: var(--faint);
}
.suggest-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 20px;
  color: var(--ink);
}
.suggest-item.is-active { background: var(--lav-1); text-decoration: none; }
.suggest-ico {
  display: flex;
  justify-content: center;
  flex-shrink: 0;
  width: 26px;
  color: var(--violet-soft);
}
/* Снимок врача или клиники в строке подсказки. Один квадрат 44px на все
   строки списка: инициалы (.avatar-sm) и иллюстрации разделов уже такие,
   и колонка картинок читается как колонка, а не как лесенка.
   Кадр смещён вверх — снимки врачей поясные, по центру в квадрат попадал
   халат; то же правило, что у портрета в каталоге (.hc-media-doc). */
.suggest-pic {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 13px;
  object-fit: cover;
  object-position: 50% 28%;
  background: var(--lav-1);
  /* Хайрлайн: у студийных снимков на белом фоне край растворялся в белой
     подложке подсказок, и фотографии будто не было. */
  box-shadow: 0 0 0 1px var(--line);
}

/* Стартовое меню разделов — до ввода запроса */
.suggest-menu .suggest-item { padding: 10px 20px; }
/* Иллюстрация раздела. Лавандовая подложка остаётся у плитки, а не у
   картинки: картинки с прозрачным фоном, и общий квадрат держит строй
   строк — без него силуэты кошки и листа стояли бы на разной ширине. */
.suggest-illus {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 13px;
  background: var(--lav-2);
}
.suggest-ico-box {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 13px;
  background: var(--lav-2);
  color: var(--violet-deep);
}
.suggest-menu .suggest-text .t { font-weight: 700; }
.suggest-arrow {
  display: flex;
  margin-left: auto;
  padding-left: 12px;
  color: var(--faint);
}
.suggest-text { min-width: 0; }
/* Заголовок строки — всегда в одну строку. «Авдиянц Елизавета Андреевна»
   на 360px разъезжалось на две, и строка с фото становилась вдвое выше
   соседних; отчество теряется безболезненнее, чем ритм списка. */
.suggest-text .t {
  display: block;
  overflow: hidden;
  font-weight: 500;
  line-height: 1.35;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.suggest-text .t .hl { color: var(--violet-deep); font-weight: 700; }
.suggest-text .d {
  display: block;
  overflow: hidden;
  font-size: var(--text-xs);
  color: var(--muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.suggest-empty { padding: 12px 20px; font-size: var(--text-sm); color: var(--muted); }


/* ---------- Главная: интро ---------- */

.intro { margin-top: 44px; text-align: center; }
.intro-head { margin-bottom: 32px; }
.intro h1 { margin: 0 0 10px; }
.intro-sub {
  max-width: 62ch;
  margin: 0 auto;
  color: var(--muted);
  font-size: var(--text-base);
}

/* ---------- Главная: бенто разделов ---------- */

.bento {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
  text-align: left;
}

/* Каталог пород: компактная bento-сетка эмоциональных портретов.
   Плитки нарочно мелкие (решение владельца): страница обзорная, деталь
   живёт на странице породы. Фото квадратные с полями по краям, поэтому
   заголовок сверху ложится на чистый фон — как на плитках главной. */
.breeds-bento {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.breeds-bento a {
  position: relative;
  display: block;
  aspect-ratio: 1;
  overflow: hidden;
  border-radius: var(--r-md);
  color: #fff;
}
.breeds-bento img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 600ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .breeds-bento a:hover { text-decoration: none; }
  .breeds-bento a:hover img { transform: scale(1.05); }
}
.breeds-bento .bento-title {
  position: relative;
  z-index: 1;
  display: block;
  padding: 12px 14px;
  font-size: var(--text-sm);
}
@media (max-width: 640px) {
  .breeds-bento { grid-template-columns: repeat(auto-fill, minmax(136px, 1fr)); gap: 10px; }
  .breeds-bento .bento-title { padding: 10px 12px; }
}
/* Клиники — высокая плитка на две строки, вокруг неё раскладывается остальное */
.bento-lg { grid-column: span 2; grid-row: span 2; }
.bento-wide { grid-column: span 2; }
.bento-full { grid-column: 1 / -1; }

.bento a {
  position: relative;
  display: block;
  height: 100%;
  /* 230, а не 172: на плитках теперь студийные портреты питомцев, и в полосу
     3.15:1 животное не помещалось — оставалась одна морда у края. */
  min-height: 230px;
  overflow: hidden;
  border-radius: var(--r-lg);
  color: #fff;
  transition: box-shadow var(--t-med) var(--ease-out);
}
.bento-lg a { min-height: 100%; }
.bento img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 600ms var(--ease-out);
}
/* Кадрирование привязано к правому краю: животное на всех кадрах стоит справа
   и упирается в край файла, а пустой цвет — слева. При центральной привязке
   на ширинах 901–1140px, где большая плитка уже пропорции файла, обрезка
   срезала собаке ухо; теперь лишнее забирается из пустого поля слева. */
.bento img { object-position: 100% 50%; }
/* По вертикали кадр берём выше центра: на планшете и телефоне плитка
   вытягивается в полосу, и обрезка по центру пришлась бы животному на грудь.
   22% — середина диапазона 17..26%, при котором голова целиком в кадре на всех
   трёх брейкпоинтах сразу (посчитано по положению животных в файлах). */
.bento-lg img, .bento-sm img { object-position: 100% 22%; }
/* Плитка на всю строку (главная без раздела врачей) вдвое шире своего кадра:
   cover срезал бы животное до полоски. Кадр стоит справа в родных пропорциях,
   а слева продолжается его же плоский фон — цвет снят с края файла. */
.bento-full a { background: linear-gradient(#3c5782, #39537a); }
.bento-full img {
  left: auto; width: auto; max-width: 100%;
  /* Фон кадра к центру светлее, чем у края: без растушёвки левая граница
     снимка читалась ступенькой на заливке. */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 35%);
  mask-image: linear-gradient(to right, transparent, #000 35%);
}
/* Вуали под текстом больше нет: фон кадра — плоский цвет, подобранный так,
   чтобы белый заголовок давал контраст не ниже 4.5:1 (самый светлый фон,
   груминг #7C6F74, даёт 4.8). Тёмный градиент поверх чистого цвета читался
   бы грязью — ровно тем, от чего уходим. */
@media (hover: hover) and (pointer: fine) {
  /* Отклик плитки — движение самого кадра, а не тень под ним: снимок здесь
     и есть содержимое, и он уже отделён от фона своими границами. */
  .bento a:hover { text-decoration: none; }
  .bento a:hover img { transform: scale(1.04); }
}

.bento-body {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  /* Заголовок сверху: питомец на кадре сидит внизу и справа, и текст внизу
     лёг бы ему на грудь. Сверху слева — чистый фон при любом кропе. */
  justify-content: flex-start;
  height: 100%;
  min-height: inherit;
  padding: 20px 22px;
}
.bento-title {
  font-size: var(--text-base);
  font-weight: 700;
  line-height: 1.3;
  text-shadow: 0 1px 12px rgba(17, 20, 31, 0.35);
}
.bento-lg .bento-title { font-size: var(--text-xl); }
.bento-meta {
  margin-top: 3px;
  font-size: var(--text-sm);
  color: rgba(255, 255, 255, 0.78);
}
.bento-meta .num { font-variant-numeric: tabular-nums; }
.bento-soon {
  align-self: flex-start;
  margin-top: 8px;
  padding: 2px 10px;
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: var(--r-pill);
  font-size: var(--text-2xs);
  font-weight: 700;
}


/* ---------- Главная: популярное ---------- */

/* ---------- Свежие статьи на главной ---------- */
/* Тот же вертикальный шаг, что у «Карты клиник» и «Популярного» — три
   секции подряд обязаны идти одним ритмом. */
.fresh { margin: 56px 0; }
/* Заголовок, стрелки и выход в каталог — одной строкой: «Все статьи»
   справа даёт выход из блока, не занимая отдельной строки под полосой. */
.fresh-head {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  margin-bottom: var(--space-2xl);
}
.fresh-head h2 { margin: 0; margin-right: auto; }
/* Стрелки ставит скрипт и прячет сам, когда листать нечего (см.
   carousel.js): в разметке этот блок пустой. */
.fresh-tools { display: flex; gap: var(--space-sm); }
.fresh-tools[hidden] { display: none; }
.car-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
}
.car-prev svg { transform: scaleX(-1); }
@media (hover: hover) and (pointer: fine) {
  .car-btn:not(:disabled):hover { border-color: var(--accent-soft); color: var(--accent-ink); }
}
.car-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
/* На краю кнопка гаснет, а не исчезает: пропадающий контрол дёргал бы
   строку заголовка при каждом листании. */
.car-btn:disabled { color: var(--surface-3); cursor: default; }

/* Полоса-карусель. Прокрутка нативная: пальцем, колесом, табом по
   карточкам — стрелки только надстройка для мыши. */
.fresh-list {
  --fresh-gap: var(--space-2xl);
  /* Сколько выглядывает следующая карточка. Без этого полоса выглядит
     как ряд из трёх карточек и листать её никто не пробует — тот же
     приём, что у галереи клиники на телефоне. */
  --fresh-peek: 52px;
  display: flex;
  gap: var(--fresh-gap);
  margin: 0;
  /* Поле снизу — под тень фокуса и чтобы карточка не липла к краю
     скроллера при табе. */
  padding: 0 0 var(--space-2xs);
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  /* Полоска прокрутки под карточками спорит с подвалом карточки, а на
     тач-устройствах её и так нет. Прокрутка остаётся полноценной. */
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.fresh-list::-webkit-scrollbar { display: none; }
.fresh-list > li {
  flex: 0 0 calc((100% - 2 * var(--fresh-gap) - var(--fresh-peek)) / 3);
  scroll-snap-align: start;
}
/* Карточка — колонка: обложка, тело, прижатый к низу подвал. Растягиваем
   на всю высоту ячейки, иначе в ряду с заголовками разной длины карточки
   получаются разной высоты и нижний край ряда рвётся. */
.fresh-card { display: flex; flex-direction: column; height: 100%; }
.fresh-card .card-body { display: flex; flex-direction: column; flex: 1 1 auto; }
/* Заголовок максимум в три строки: у самых длинных названий он забирал
   всю карточку, и выжимка под ним оставалась одной строкой. */
.fresh-card h3 {
  margin: 0 0 var(--space-sm);
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.fresh-lead {
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--text-muted);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.fresh-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  /* Прижимает подвал к низу карточки при любой длине заголовка */
  margin: var(--space-xl) 0 0;
  font-size: var(--text-sm);
  color: var(--text-subtle);
}
/* Единственное акцентное пятно карточки: действие. Обложка, заголовок
   и дата — чёрно-серые, фиолетовый в проекте закреплён за действиями. */
.fresh-more {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  color: var(--accent-strong);
  font-weight: 600;
}
/* Отклик на наведение — стрелка и заголовок, но не контур.

   Общая .card под курсором красит обводку и подкладывает --surface-1.
   Здесь и то и другое лишнее: три карточки стоят рядом, и вспыхивающая
   рамка тянет взгляд к границам плиток, а не к статьям; заливка же на
   лавандовом фоне главной делает белую карточку почти неотличимой от
   страницы — подсветка обязана усиливать фигуру, а не гасить её (то же
   решение, что у карточки врача в выдаче). */
.fresh-card h3 { transition: color var(--t-fast) var(--ease-out); }
.fresh-more svg { transition: transform var(--t-fast) var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  a.card.fresh-card:hover {
    border-color: var(--border);
    background: var(--surface);
  }
  .fresh-card:hover h3 { color: var(--accent-strong); }
  .fresh-card:hover .fresh-more svg { transform: translateX(3px); }
}
@media (prefers-reduced-motion: reduce) {
  .fresh-card h3 { transition: none; }
}
@media (prefers-reduced-motion: reduce) {
  .fresh-more svg { transition: none; }
}

.popular { margin: 56px 0; }
/* По левому краю, а не по центру. Выше на главной уже стоит центрированный
   блок с h1 и подзаголовком; второй центрированный заголовок подряд читается
   как «каждая секция — заголовок посередине и сетка под ним», то есть как
   шаблон. Один центрированный момент на страницу — решение, два — приём. */
.popular-head { margin-bottom: var(--space-2xl); }
.popular-head h2 { margin: 0; }
/* Пунктир подчёркиванием, а не рамкой — по той же причине, что у ссылок
   на станции метро: рамка уезжает от текста, как только у кнопки появляется
   вертикальный паддинг под тач-цель. */
.town-link {
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  color: var(--violet-deep);
  text-decoration: underline;
  text-decoration-style: dashed;
  text-decoration-color: var(--violet-soft);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .town-link:hover { color: var(--violet); text-decoration-color: var(--violet); }
}

.nav-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
.nav-card {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  /* Как и .card: держится бордером. Тень и подъём при наведении сняты —
     см. комментарий у .card. */
  transition: border-color var(--t-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .nav-card:hover { border-color: var(--accent-soft); }
}
.nav-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 20px 22px;
  color: var(--ink);
}
.nav-card-title { font-size: var(--text-lg); font-weight: 700; }
.nav-card-total { flex-shrink: 0; color: var(--faint); font-size: var(--text-sm); font-weight: 500; }
.nav-card-main { flex: 1; padding: 0 22px; }
.nav-card-list {
  margin: 0;
  padding: 10px 0;
  list-style: none;
  border-top: 1px solid var(--line);
}
.nav-card-list li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.nav-card-list a {
  flex: 1;
  padding: 7px 0;
  color: var(--indigo);
  font-size: var(--text-base);
  font-weight: 500;
}
.nav-card-list .n { flex-shrink: 0; color: var(--faint); font-size: var(--text-sm); }
.nav-card-foot { padding: 6px 22px 22px; }
.nav-card-foot .btn { width: 100%; }

@media (max-width: 1000px) {
  .nav-cards { grid-template-columns: 1fr 1fr; }
}

/* Плашка «Проверено ветврачом» в карточках статей.
   Галочка — значок из общего набора, а не текстовый ✓ через ::before:
   этот символ каждая система рисует своим шрифтом (в Windows он тоньше и
   ниже строки), он не подчиняется размеру остальных значков и, стоя
   в content, читается скринридером как часть текста. */
.verified {
  color: var(--green-ink);
  margin: 4px 0 0;
  display: flex;
  align-items: center;
  gap: 5px;
}
.verified svg { flex-shrink: 0; }

/* ---------- Главная: выход в каталог картой ---------- */

.citymap { margin: 56px 0; }
.citymap-head { margin-bottom: var(--space-2xl); }
.citymap-head h2 { margin: 0 0 6px; }
.citymap-sub { max-width: 62ch; margin: 0; color: var(--muted); }

.citymap-plate {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-lg);
  /* Обводкой, а не тенью — как все карточки портала. Рисунок карты светлее
     подложки страницы всего на несколько единиц, и без линии скруглённый
     край читался как ошибка кадрирования, а не как край плиты. */
  border: 1px solid var(--border);
  /* Пропорция задана картинке, а не плите: без неё блок схлопывается в ноль
     до загрузки ленивого изображения и страница прыгает под курсором. */
}
.citymap-bg {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 2.5 / 1;
  object-fit: cover;
}

/* Метки. Раскладка percentages'ами по плите, а не в разметке: положение
   декорации — оформление, а не данные записи, и инлайновому style здесь
   не место. Координаты подобраны так, чтобы ни одна метка не попадала
   в центральную полосу, где стоит кнопка. */
.citymap-pins { position: absolute; inset: 0; }
.citymap-pin {
  position: absolute;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  margin: -30px 0 0 -15px;    /* точка привязки — низ «хвоста», а не центр */
  border-radius: 50% 50% 50% 50% / 55% 55% 45% 45%;
  background: var(--accent);
  color: var(--on-accent);
  /* Тень здесь допустима: метка изображает слой, поднятый над картой,
     ровно как всплывающие слои портала. */
  box-shadow: 0 2px 6px rgba(39, 39, 108, 0.28);
}
/* Хвост метки: тот же фиолетовый, сужается книзу. Отдельным элементом,
   а не поворотом квадрата, — поворот размывал бы значок внутри. */
.citymap-pin::after {
  content: "";
  position: absolute;
  top: 27px;
  left: 50%;
  width: 2px;
  height: 9px;
  margin-left: -1px;
  border-radius: 0 0 1px 1px;
  background: var(--accent);
  opacity: 0.85;
}
.citymap-pin:nth-child(1)  { left: 7%;  top: 34%; }
.citymap-pin:nth-child(2)  { left: 16%; top: 62%; }
.citymap-pin:nth-child(3)  { left: 25%; top: 24%; }
.citymap-pin:nth-child(4)  { left: 35%; top: 76%; }
.citymap-pin:nth-child(5)  { left: 43%; top: 34%; }
.citymap-pin:nth-child(6)  { left: 59%; top: 30%; }
.citymap-pin:nth-child(7)  { left: 66%; top: 78%; }
.citymap-pin:nth-child(8)  { left: 76%; top: 22%; }
.citymap-pin:nth-child(9)  { left: 85%; top: 60%; }
.citymap-pin:nth-child(10) { left: 93%; top: 36%; }

.citymap-btn {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  /* Своей тени не заводим: у .btn-primary она уже двухслойная и выверенная,
     а перебивать её здесь значит ещё и разойтись с :hover, который её
     меняет по-своему. */
}
/* transform у кнопки уже занят центрированием, и общий .btn:active со своим
   scale() сдёрнул бы её из центра. Нажатие остаётся цветом. */
.citymap-btn:active { transform: translate(-50%, -50%); }

/* ---------- Фото-обложки ---------- */

.card-cover .cover {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  border-radius: var(--r-md) var(--r-md) 0 0;
}
.breed-photo {
  width: 84px;
  height: 84px;
  border-radius: 18px;
  object-fit: cover;
  flex-shrink: 0;
}
/* ═══════════════════════ Страница статьи ═══════════════════════ */
/* Файлы: templates/portal/article_detail.html, views.article_detail,
   models.body_sections, фильтр typo в portal_extras.

   Раскладка — ОДНА колонка (формат задан владельцем по референсу vetsy.ru,
   2026-08-08): белый лист во всю ширину контейнера, внутри него шапка,
   обложка, лид, оглавление и текст. Боковой колонки нет.

   Ширина строки при этом остаётся читаемой: содержимое идёт колонкой .art-col
   в 72 знака по центру листа, а не во всю его ширину. В референсе текст
   набран на 1050px — это 120 знаков в строке, то есть ровно та длина,
   на которой глаз теряет начало следующей строки.

   Лист белый не ради красоты: фон портала холоднее белого именно затем,
   чтобы поверхность читалась отдельным документом. */

.art-sheet {
  /* Поле листа — своей переменной: обложка выходит в него отрицательным
     margin'ом, и два числа обязаны меняться вместе. */
  --art-pad: var(--space-4xl);
  margin-top: var(--space-lg);
  padding: var(--space-5xl) var(--art-pad) var(--space-5xl);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
}
/* Читаемая колонка: 72 знака при кегле 18 — верхняя граница нормы.
   По центру листа, поэтому поля слева и справа одинаковые и выглядят
   намеренными, а не забытыми. */
.art-col { max-width: 72ch; margin-inline: auto; }

/* ---------- Шапка статьи ---------- */
/* Рубрика, заголовок и автор — по центру, как в референсе: это единственный
   центрированный блок страницы, дальше всё по левому краю. */
.art-head { text-align: center; padding-bottom: var(--space-3xl); }
.art-kicker {
  margin: 0 0 var(--space-md);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-subtle);
}
.art-kicker a { color: var(--accent-strong); }
.art-head h1 { margin-bottom: var(--space-2xl); }

/* Строка авторства. У медицинского материала она работает до чтения, а не
   после, поэтому стоит в шапке.

   Всё в ОДНУ строку на одной базовой линии: портрет, имя, должность, дата.
   До этого имя с должностью стояли двухстрочным блоком слева, а дата — одна
   строка справа, и под центрированным заголовком это читалось как два
   несвязанных острова: у композиции оказывалось два разных центра, и ни один
   не совпадал с центром заголовка. Один кегль на всю строку — по той же
   причине: три разных (14 / 12 / 13) читались как три разные мысли. */
.art-by {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  color: var(--text-subtle);
}
.art-by-person {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  min-height: var(--tap);
  color: var(--text);
}
/* Портрет мельче общего .avatar-sm (44px): рядом со строкой в 14px тот
   выглядел значком, к которому приписали текст, а не частью строки. */
.art-by .avatar {
  width: 32px;
  height: 32px;
  font-size: var(--text-2xs);
}
.art-by-name { font-weight: 700; }
.art-by-sep { color: var(--surface-3); }
@media (hover: hover) and (pointer: fine) {
  .art-by-person:hover { text-decoration: none; }
  .art-by-person:hover .art-by-name { color: var(--accent-ink); }
}

/* ---------- Обложка ---------- */
/* Шире колонки текста, но уже листа — так она отделяет шапку от текста
   и не превращается в баннер во всю страницу. Пропорция задана здесь:
   без неё высоту задаёт сама картинка, и до её загрузки страница прыгает. */
.art-cover {
  max-width: 880px;
  margin: 0 auto var(--space-4xl);
}
.art-cover img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--r-md);
}
.art-cover figcaption {
  margin-top: var(--space-sm);
  font-size: var(--text-2xs);
  color: var(--text-subtle);
}

/* ---------- Лид ---------- */
/* Кегль крупнее текста, цвет мягче заголовка: вводит в статью, а не спорит
   с ней. */
.art-lede {
  margin: 0 0 var(--space-3xl);
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--text-muted);
  /* Иначе последней строкой лида остаётся «через часы.» — два слова
     под четырьмя полными строками. */
  text-wrap: pretty;
  overflow-wrap: break-word;
}

/* ---------- Полоса действия ---------- */
/* Одна на страницу и до текста: отвечает тому, кто пришёл в тревоге и читать
   не готов. Подложка лавандовая, а не акцентная заливка: фиолетовый в этом
   проекте — действие и ссылка, а не фон. Действие здесь несёт кнопка. */
.art-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md) var(--space-xl);
  margin-bottom: var(--space-3xl);
  padding: var(--space-lg) var(--space-xl);
  border: 1px solid var(--surface-2);
  border-radius: var(--r-md);
  background: var(--surface-1);
  color: var(--text);
}
.art-cta-text { display: grid; gap: 2px; }
.art-cta-ttl { font-weight: 700; }
.art-cta-sub { font-size: var(--text-sm); color: var(--text-muted); }
/* Кнопка нарисована внутри ссылки, а не вложена в неё: вложенных <a>
   в проекте нет — они ломают клавиатуру и скринридер. */
.art-cta-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  flex: none;
  min-height: var(--tap);
  padding: 0 var(--space-lg);
  border-radius: var(--r-sm);
  background: var(--accent);
  color: var(--on-accent);
  font-size: var(--text-sm);
  font-weight: 600;
  white-space: nowrap;
}
.art-cta-btn svg { flex: none; }
@media (hover: hover) and (pointer: fine) {
  .art-cta:hover { text-decoration: none; border-color: var(--surface-3); }
  .art-cta:hover .art-cta-btn { background: var(--accent-strong); }
}

/* Тревожное исполнение полосы (сводный список симптомов): геометрия и кнопка
   те же, меняется регистр цвета. Объявлено ПОСЛЕ `.art-cta` — вес одинаковый,
   и выше по файлу шорткат `border` перебивал бы модификатор. */
.art-cta-urgent { border-color: #f7d5de; background: var(--rose-bg); }
.art-cta-urgent .art-cta-ttl { color: var(--rose-ink); }
@media (hover: hover) and (pointer: fine) {
  .art-cta-urgent:hover { border-color: #f0bccc; }
}

/* ---------- Оглавление ---------- */
/* Списком в потоке текста, а не липкой плиткой сбоку: боковой колонки
   у страницы больше нет. Подложки под ним тоже нет — рядом стоит полоса
   действия, и две плашки подряд читались бы как панель управления,
   а не как начало статьи. Держится линиями сверху и снизу. */
.art-toc {
  margin-bottom: var(--space-3xl);
  padding: var(--space-xl) 0;
  border-block: 1px solid var(--border);
}
.art-toc-ttl { font-size: var(--text-base); margin-bottom: var(--space-md); }
/* Нумерация своя, а не браузерная: цифра приглушена, чтобы не спорить
   с названиями разделов, ради которых список и читают. */
.art-toc-list {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: art-toc;
  columns: 2;
  column-gap: var(--space-3xl);
}
.art-toc-list li {
  counter-increment: art-toc;
  break-inside: avoid;
}
/* Флекс, а не строчный номер: у длинного названия вторая строка иначе
   заезжает под цифру («…перегреваются быстрее / нас»). */
.art-toc-list a {
  display: flex;
  gap: var(--space-sm);
  padding: 6px 0;
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  color: var(--accent-strong);
}
.art-toc-list a::before {
  content: counter(art-toc) ".";
  flex: none;
  min-width: 1.1em;
  color: var(--text-subtle);
  font-variant-numeric: tabular-nums;
}

/* ---------- Текст ---------- */
/* Кегль крупнее интерфейсного: это длинное чтение, а не UI. Ограничение
   ширины строки живёт на .art-col — .prose со своими 72ch здесь просто
   совпадает с колонкой. */
.art-body { font-size: var(--text-lg); }
/* Медицинский текст полон слов в сорок знаков: «электроэнцефалография»,
   «гипербилирубинемия», названия препаратов. На 360px такое слово шире
   экрана, и горизонтальную прокрутку получает вся страница. */
.art-body, .art-head h1 { overflow-wrap: break-word; }
.art-body ul { padding-left: 1.1em; }
.art-body li { margin-bottom: var(--space-sm); }

/* Нумерованный список — порядок действий («первая помощь по шагам»), а не
   перечень равнозначных советов. Номер в кружке: маркерами браузера цифра
   теряется на фоне текста в 18px, а человек в спешке должен видеть, где
   начинается шаг. */
.art-body ol {
  list-style: none;
  margin: 0 0 1em;
  padding: 0;
  counter-reset: art-step;
}
.art-body ol > li {
  counter-increment: art-step;
  position: relative;
  padding-left: 42px;
  margin-bottom: var(--space-md);
}
.art-body ol > li::before {
  content: counter(art-step);
  position: absolute;
  left: 0;
  /* Кружок садится на первую строку пункта, а не на середину блока. */
  top: 3px;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--accent-ink);
  font-size: var(--text-sm);
  font-weight: 700;
}

/* Врезка «! » — одна на статью и не выбирается автором из палитры цветов:
   три цветных блока подряд перестают что-либо значить. Рельсом, а не
   рамкой по кругу: на белом листе рамка читалась бы как вторая карточка. */
.art-body .callout {
  border: none;
  border-left: 3px solid var(--rose-ink);
  border-radius: 0 var(--r-xs) var(--r-xs) 0;
  padding: var(--space-lg) var(--space-xl);
  margin: var(--space-2xl) 0;
  font-size: var(--text-base);
}
.art-body .callout .ttl { font-size: var(--text-sm); }

/* Шкалы оценок породы (контент-завод): строка «название — пять сегментов»,
   членение тонкими линейками, без карточки — плотный справочник. */
.art-body .art-scales {
  margin: var(--space-2xl) 0;
  border-top: 1px solid var(--surface-2);
}
.art-body .art-scales .row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-lg);
  padding: var(--space-sm) 0;
  border-bottom: 1px solid var(--surface-2);
}
.art-body .art-scales .lbl { font-size: var(--text-base); }
.art-body .art-scales .segs {
  display: inline-flex;
  gap: 4px;
  flex-shrink: 0;
}
.art-body .art-scales .segs i {
  width: 22px;
  height: 6px;
  border-radius: 2px;
  background: var(--surface-2);
}
.art-body .art-scales .segs i.on { background: var(--indigo); }

/* Таблица из текста статьи (контент-завод). Обёртка с прокруткой:
   широкая таблица скроллится сама, а не растягивает колонку текста. */
.art-body .art-table {
  margin: var(--space-2xl) 0;
  overflow-x: auto;
}
.art-body .art-table table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-base);
}
.art-body .art-table th,
.art-body .art-table td {
  padding: var(--space-sm) var(--space-lg);
  border-bottom: 1px solid var(--surface-2);
  text-align: left;
  vertical-align: top;
}
.art-body .art-table th {
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* Иллюстрация раздела (директива img:) — той же ширины, что текст. */
.art-body figure {
  margin: var(--space-2xl) 0;
}
.art-body figure img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r-md);
}
.art-body figcaption {
  margin-top: var(--space-sm);
  font-size: var(--text-2xs);
  color: var(--text-subtle);
}

/* FAQ — раздел того же листа, а не собственная поверхность. .section (56px)
   внутри листа слишком много: поля листа уже дают воздух. */
.art-sheet .section { margin: var(--space-4xl) 0 0; }
/* Нижнее поле последнего абзаца складывалось с полем листа: у статьи без
   FAQ низ был на 18px просторнее верха. */
.art-body > :last-child { margin-bottom: 0; }
.art-sheet .faq details { border-radius: var(--r-xs); }

/* Источники. Мелкий кегль — это сноски, а не раздел для чтения. Ссылок
   в них может не быть вовсе: у болезней в поле лежат строки без адресов. */
.art-sources {
  margin-top: var(--space-4xl);
  padding-top: var(--space-2xl);
  border-top: 1px solid var(--border);
  font-size: var(--text-sm);
  color: var(--text-muted);
}
.art-sources-t { font-size: var(--text-base); margin-bottom: var(--space-md); }
.art-sources ol { margin: 0; padding-left: 1.4em; }
.art-sources li { margin-bottom: var(--space-sm); line-height: var(--leading-normal); }

/* Оценка породы под строкой авторства: та же строка меты, поэтому и кегль,
   и цвет те же — крупная звезда рядом с именем автора спорила бы с ним. */
.art-rating {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  margin-top: var(--space-sm);
  font-size: var(--text-sm);
  color: var(--text-subtle);
}
.art-rating svg { color: var(--amber-ink); }
.art-rating .val { font-weight: 700; color: var(--text); }

/* Обложка с мордой: кадр смещён вверх — то же правило, что у портретов
   врачей. По центру в широкий кадр попадает корпус, а не морда. */
.art-cover-face img { object-position: 50% 32%; }

/* Портрет вместо обложки — у профиля эксперта. Занимает место обложки
   в потоке, но кадром во всю ширину лицо не подаётся. */
.art-portrait {
  display: flex;
  justify-content: center;
  margin-bottom: var(--space-3xl);
}

/* ---------- Соседние статьи ---------- */
/* Под листом и сеткой: в одну колонку они были бы четвёртым списком подряд
   после FAQ. Четыре в ряд — столько же, сколько отдаёт представление. */
.art-more { margin: var(--space-5xl) 0 var(--space-4xl); }
/* Несколько групп подряд (у болезни их три: симптомы, породы риска, другие
   болезни) разделяются между собой, а не слипаются в один ряд чипов. */
.art-more-block + .art-more-block { margin-top: var(--space-3xl); }
.art-more-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-lg);
}


/* ═══════════════════════ Вход и личный кабинет ═══════════════════════ */

/* Общее поле формы. До сих пор поля были стилизованы только внутри
   .review-form — второй форме на портале пришлось бы копировать её правила.
   Здесь тот же вид, вынесенный под собственный класс: .review-form трогать
   не стали, чтобы не переверстывать работающий экран ради причёсывания. */
.field { display: grid; gap: 6px; margin-bottom: var(--space-lg); }
.field > label { font-weight: 500; font-size: var(--text-sm); color: var(--text); }
.field input[type="text"],
.field input[type="tel"],
.field input[type="file"],
.field select {
  width: 100%;
  border: 1px solid var(--lav-3);
  border-radius: var(--r-sm);
  padding: 11px 14px;
  /* 16px минимум: Safari увеличивает страницу при фокусе на поле мельче и
     обратно её не возвращает. Тот же порог, что у остальных полей портала. */
  font: inherit;
  font-size: var(--text-base);
  color: var(--ink);
  background: #fff;
  transition: border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
}
.field input:focus, .field select:focus {
  outline: none;
  border-color: var(--violet);
  box-shadow: 0 0 0 3px var(--lav-2);
}
.field-hint { margin: 0; font-size: var(--text-xs); color: var(--faint); }
/* Подсказка с отладочным кодом. Намеренно выглядит как служебная пометка,
   а не как часть интерфейса: её видно только на стенде без SMS, и она
   не должна читаться как обычный элемент формы. */
.auth-debug {
  padding: 7px 10px;
  border: 1px dashed var(--amber-ink);
  border-radius: var(--r-sm);
  background: var(--amber-bg);
  color: var(--amber-ink);
}
.auth-debug b { font-variant-numeric: tabular-nums; letter-spacing: 0.08em; }
/* Ошибка стоит НАД полем: под ним её перекрывает всплывающая клавиатура
   телефона, и человек видит только то, что кнопка не сработала. */
.field .form-error { margin: 0; }

/* Состояние отправки. Подпись не подменяем — текст кнопки в этом проекте
   не переносится, а «Отправляем…» другой длины дёргало бы ширину слоя. */
.btn:disabled, .btn[aria-busy="true"] { opacity: .6; cursor: default; }
.btn:disabled:active, .btn[aria-busy="true"]:active { transform: none; }
.btn[aria-busy="true"] { position: relative; color: transparent !important; }
.btn[aria-busy="true"]::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 16px; height: 16px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: var(--r-pill);
  color: var(--on-accent);
  animation: btn-spin 620ms linear infinite;
}
.btn-ghost[aria-busy="true"]::after { color: var(--accent-ink); }
@keyframes btn-spin { to { transform: rotate(1turn); } }
@media (prefers-reduced-motion: reduce) {
  .btn[aria-busy="true"]::after { animation-duration: 2s; }
}

/* ── Модалка входа ───────────────────────────────────────────────────── */
/* Разметка и поведение повторяют модалку города: у неё уже есть проверенное
   превращение в нижний лист (mobile.css) и общий скрипт блокировки прокрутки. */
.auth-modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.auth-modal[hidden] { display: none; }
.auth-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(39, 39, 108, 0.45);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.auth-modal-card {
  position: relative;
  /* 400px — ширина под «+7 (900) 000-00-00» и подпись провайдера в одну
     строку. Шире слой начинает выглядеть страницей, а не вопросом. */
  width: 100%;
  max-width: 400px;
  max-height: calc(100vh - 32px);
  overflow-y: auto;
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
  padding: 22px 22px 18px;
  animation: city-modal-in var(--t-med) var(--ease-out) both;
}
.auth-modal.is-closing .auth-modal-card { animation: city-modal-out 180ms var(--ease-out) both; }
.auth-modal.is-closing .auth-modal-backdrop { animation: city-modal-fade 180ms var(--ease-out) both; }
.auth-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}
.auth-modal-title { margin: 0; font-size: var(--text-lg); }
.auth-modal-close {
  border: none;
  background: var(--lav-1);
  border-radius: var(--r-pill);
  padding: 8px;
  line-height: 0;
  color: var(--muted);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .auth-modal-close:hover { background: var(--lav-2); color: var(--indigo); }
}

/* ── Тело входа: одинаково в модалке и на странице ───────────────────── */
.auth-lead {
  margin: 0 0 var(--space-lg);
  font-size: var(--text-sm);
  color: var(--text-muted);
  line-height: var(--leading-snug);
}
.auth-phone { color: var(--text); white-space: nowrap; }
.auth-form { margin: 0; }
.auth-submit { width: 100%; }

/* Код — крупно и вразрядку: шесть цифр читаются группой, а не словом.
   tabular-nums уже на body, поэтому ширина не пляшет при наборе. */
.auth-code {
  text-align: center;
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: 0.34em;
  /* Разрядка добавляет пустое место справа от последней цифры — гасим
     половиной шага, иначе строка выглядит смещённой влево. */
  text-indent: 0.34em;
}

/* «или» с линейками по бокам. Псевдоэлементы, а не три узла в разметке:
   разделитель — оформление, а не содержание. */
.auth-or {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  margin: var(--space-lg) 0;
  color: var(--faint);
  font-size: var(--text-xs);
}
.auth-or::before, .auth-or::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}
.auth-providers { display: grid; gap: var(--space-sm); }

/* Кнопка Яндекс ID. Внутри — их файл целиком, включая чёрную пилюлю: чужую
   кнопку нельзя ни перекрашивать, ни пересобирать своей вёрсткой.

   Числа ниже (56px, радиус 28px, чёрный) — не наши токены, а размеры L из
   правил Яндекса; подложка повторяет их же пилюлю, чтобы кнопку можно было
   растянуть на всю ширину формы — увеличивать ширину они разрешают.
   Оттого же и цвет тут литералом: подставить сюда токен значило бы
   перекрасить кнопку при следующей правке палитры.

   Ниже 260px картинка ужимается пропорционально: узкие экраны сжимают её
   целиком, а не рвут отступы внутри. */
.btn-yandex-id {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 56px;
  border-radius: 28px;
  background: #000;
  overflow: hidden;
}
.btn-yandex-id img { max-width: 100%; height: auto; display: block; }
/* Наведение и нажатие не трогают цвет — только глубина и отклик. */
@media (hover: hover) and (pointer: fine) {
  .btn-yandex-id:hover { box-shadow: 0 3px 12px rgba(0, 0, 0, 0.22); }
}
.btn-yandex-id:active { transform: scale(0.97); }

/* Провайдеры без готовой кнопки — своя, в языке портала. Не btn-ghost:
   вход по телефону остаётся главным (подтверждённый номер и есть основание
   доверять отзыву), поэтому чужой вход не спорит с «Получить код» заливкой. */
.auth-provider {
  width: 100%;
  background: var(--surface);
  color: var(--accent-ink);
  border: 1px solid var(--border);
}
@media (hover: hover) and (pointer: fine) {
  .auth-provider:hover {
    background: var(--surface);
    border-color: var(--accent-soft);
  }
}

.auth-legal {
  margin: var(--space-lg) 0 0;
  font-size: var(--text-2xs);
  color: var(--faint);
  line-height: var(--leading-snug);
}
.auth-legal a { color: var(--faint); text-decoration: underline; }
@media (hover: hover) and (pointer: fine) {
  .auth-legal a:hover { color: var(--accent-ink); }
}

.auth-again {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  margin-top: var(--space-lg);
  flex-wrap: wrap;
}
.auth-again form { margin: 0; }
/* Ссылка-действие: и <a>, и <button> должны выглядеть одинаково — «Другой
   номер» это переход, а «отправить снова» это отправка формы. */
.auth-link {
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  font-size: var(--text-sm);
  color: var(--accent-ink);
  cursor: pointer;
  text-decoration: none;
}
.auth-link:disabled { color: var(--faint); cursor: default; }
@media (hover: hover) and (pointer: fine) {
  .auth-link:not(:disabled):hover { text-decoration: underline; }
}

/* ── Страница /vhod/ ─────────────────────────────────────────────────── */
/* Панель, а не форма на голом фоне: страница входа — единственное на экране
   действие, и без опоры поля висели в лавандовой пустоте. Тень не ставим —
   она в этом проекте только у всплывающих слоёв; хватает белого и рамки. */
.auth-page {
  max-width: 400px;
  margin: var(--space-4xl) auto var(--space-6xl);
  padding: var(--space-2xl);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}
.auth-page-title { margin: 0 0 var(--space-lg); font-size: var(--t-h3); }

/* ── Вход в шапке ────────────────────────────────────────────────────── */
/* Вход — единственное действие в правой части шапки, поэтому единственная
   заливка там же. Геометрия общая с городом, см. выше. */
.acc-login {
  flex-shrink: 0;
  background: var(--surface-1);
  color: var(--accent-ink);
  text-decoration: none;
}
@media (hover: hover) and (pointer: fine) {
  .acc-login:hover { background: var(--surface-2); }
}
.acc-btn {
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  line-height: 0;
  border-radius: var(--r-pill);
}
.acc-ava {
  display: grid;
  place-items: center;
  width: 32px; height: 32px;
  border-radius: var(--r-pill);
  overflow: hidden;
  background: hsl(var(--h, 255) 62% 92%);
  color: hsl(var(--h, 255) 52% 34%);
  font-size: var(--text-xs);
  font-weight: 700;
  line-height: 1;
}
.acc-ava img { width: 100%; height: 100%; object-fit: cover; }
/* Меню профиля прижато к правому краю: у последнего элемента строки
   выпадающий список, растущий вправо, уезжает за окно. */
.acc-menu { right: 0; left: auto; }
.acc-menu form { margin: 0; }
.acc-menu button {
  display: block;
  width: 100%;
  text-align: left;
  border: none;
  background: none;
  font: inherit;
  cursor: pointer;
}

/* ── Личный кабинет ──────────────────────────────────────────────────── */
.pf { max-width: 720px; margin: var(--space-2xl) 0 var(--space-6xl); }
.pf-title { margin: 0 0 var(--space-xl); font-size: var(--t-h2); }
.pf-head {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  padding-bottom: var(--space-xl);
  border-bottom: 1px solid var(--border);
}
.pf-ava {
  display: grid;
  place-items: center;
  width: 56px; height: 56px;
  flex-shrink: 0;
  border-radius: var(--r-pill);
  overflow: hidden;
  background: hsl(var(--h, 255) 62% 92%);
  color: hsl(var(--h, 255) 52% 34%);
  font-weight: 700;
}
.pf-ava img { width: 100%; height: 100%; object-fit: cover; }
.pf-who { min-width: 0; }
.pf-who h1 { margin: 0; font-size: var(--t-h3); }
.pf-who p { margin: 2px 0 0; }
.pf-settings { margin-left: auto; flex-shrink: 0; }
.pf-section { margin: var(--space-2xl) 0 var(--space-lg); font-size: var(--text-lg); }

.pf-list { list-style: none; margin: 0; padding: 0; }
/* Разделители, а не карточки: список своих отзывов — справочник, и каждая
   строка в собственной плашке превращала бы пять отзывов в пять экранов. */
.pf-item { padding: var(--space-lg) 0; border-top: 1px solid var(--border); }
.pf-item:first-child { border-top: none; padding-top: 0; }
.pf-item-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
}
.pf-target { font-weight: 600; }
.pf-status {
  flex-shrink: 0;
  padding: 2px 9px;
  border-radius: var(--r-pill);
  font-size: var(--text-2xs);
  font-weight: 600;
  white-space: nowrap;
}
/* Статус передаётся не только цветом — в плашке всегда есть слово. */
.pf-status-moderation { background: var(--amber-bg); color: var(--amber-ink); }
.pf-status-published { background: var(--green-bg); color: var(--green-ink); }
.pf-status-rejected, .pf-status-banned { background: var(--rose-bg); color: var(--rose-ink); }
.pf-meta { display: flex; align-items: center; gap: var(--space-sm); margin: 6px 0; }
.pf-note {
  margin: var(--space-sm) 0;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  background: var(--rose-bg);
  color: var(--rose-ink);
  font-size: var(--text-sm);
}
.pf-text { margin: 0 0 var(--space-sm); color: var(--text-muted); }
.pf-empty { display: grid; gap: var(--space-sm); justify-items: center; }
.pf-empty p { margin: 0; }
.pf-empty .btn { margin-top: var(--space-sm); }

/* Настройки живут в одной колонке: при форме 420px и списках во всю ширину
   720px правый край страницы ломался посередине, и разделы переставали
   читаться как один экран. Список отзывов — другой случай, ему ширина нужна. */
.pf-narrow { max-width: 460px; }
.pf-ways { list-style: none; margin: 0; padding: 0; }
.pf-way {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-md) 0;
  border-top: 1px solid var(--border);
  font-size: var(--text-sm);
}
.pf-way:first-child { border-top: none; }
.pf-way-ico { line-height: 0; color: var(--muted); flex-shrink: 0; }
.pf-way-name { font-weight: 500; }
.pf-way-val {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--text-muted);
}
.pf-way form { margin: 0; }
.pf-foot { margin-top: var(--space-2xl); }
.pf-foot form { margin: 0; }

/* Удаление профиля свёрнуто и не окрашено в акцент: разрушающее действие
   не должно попадаться под руку рядом с «Сохранить». */
.pf-danger { margin-top: var(--space-4xl); border-top: 1px solid var(--border); padding-top: var(--space-lg); }
.pf-danger summary { cursor: pointer; color: var(--muted); font-size: var(--text-sm); }
.pf-danger p { font-size: var(--text-sm); color: var(--text-muted); max-width: 60ch; }
.pf-danger-btn {
  border: 1px solid var(--rose-ink);
  background: none;
  color: var(--rose-ink);
  border-radius: var(--r-sm);
  padding: 9px 16px;
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .pf-danger-btn:hover { background: var(--rose-bg); }
}

/* ── Отметки в отзывах ───────────────────────────────────────────────── */
.rv-verified { line-height: 0; color: var(--accent); flex-shrink: 0; }
.rv-who-when { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rv-who-source { font-size: var(--text-2xs); color: var(--faint); }

/* ═══════════════════════ Форма отзыва ═══════════════════════ */
/* Порядок и состав полей — в шаблоне _review_form.html; здесь только вид.
   Правило экрана: прокрутки нет — окно это оболочка с закреплёнными шапкой
   и низом, а необязательное вынесено во вторую панель. */

.rf-title {
  margin: 0 0 2px;
  font-size: var(--text-lg);
  /* Длинное название клиники не должно раздувать закреплённую шапку:
     две строки максимум, дальше многоточие. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.rf-note { margin: 0; font-size: var(--text-sm); color: var(--text-muted); }

/* ── Оболочка окна ──────────────────────────────────────────────────────
   Шапка и низ закреплены, между ними ровно одна панель по остатку высоты.
   Прокрутки нет по устройству, а не по счастливому совпадению длины формы:
   что не помещается в основное — переехало во вторую панель. */
.rf-shell {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1;
}
.rf-head {
  position: relative;
  flex: none;
  padding: var(--space-xl) var(--space-3xl) var(--space-md);
  padding-right: 56px;   /* под крестик */
  border-bottom: 1px solid var(--border);
}
.rf-close {
  position: absolute;
  top: var(--space-lg);
  right: var(--space-lg);
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--surface-1);
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .rf-close:hover { background: var(--surface-2); color: var(--text); }
}
.rf-panes { flex: 1; min-height: 0; display: flex; }
/* min-height у панели НЕ обнуляем: иначе она сжимается под содержимое,
   и окно не вырастает под более высокую вкладку — остаётся размером
   с первую, а содержимое уезжает в прокрутку. */
.rf-pane {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  /* Единый шаг между блоками вместо разрозненных margin у каждого: раньше
     зазоры выходили 24, 4, 0 и 16 пикселей подряд — глаз читает такую
     разноголосицу как неаккуратную сетку, даже не понимая, что именно
     не так. */
  gap: var(--space-lg);
  padding: var(--space-md) var(--space-3xl);
  /* Не «на всякий случай», а страховка для крайних случаев вроде телефона
     в альбомной ориентации: там экран 380px высотой, и уместить панель без
     потерь нельзя. В обычных условиях прокрутка не появляется. */
  overflow-y: auto;
}
.rf-pane[hidden] { display: none; }

/* ── Полоса шагов ──
   Показывается только в пошаговом режиме (телефон); на широком экране
   шагов нет, и полосу скрывает медиазапрос в mobile.css наоборот —
   здесь она просто выключена по умолчанию. */
.rf-prog { display: none; gap: 4px; margin-top: var(--space-md); }
.rf-prog i {
  flex: 1;
  height: 3px;
  border-radius: 2px;
  background: var(--surface-2);
  transition: background-color var(--t-med) var(--ease-out);
}
.rf-prog i.on { background: var(--accent); }

/* ── Широкий экран: одна колонка, поля во весь рост ──
   Боковой колонки нет ни в каком виде: предпросмотр повторял бы то, что
   и так видно в поле, а лишнюю ширину полю отдавать нельзя — после
   восьмидесяти знаков в строке текст тяжело и писать, и перечитывать.
   Поэтому окно у́же, а место уходит в высоту. */
/* ── Широкий экран: две колонки, ноль прокрутки ──
   Одной колонкой большие поля в окно не помещались: раскрытые минусы или
   снимки добавляли высоту, которую взять неоткуда, и появлялась прокрутка.
   Ширина же простаивала.

   Поэтому слева то, ради чего человек пришёл, — оценка и рассказ; справа
   необязательное: минусы, снимки, оценки по пунктам, подпись. Высота окна
   становится не суммой блоков, а высотой более длинной колонки, и всё
   помещается даже когда раскрыто всё сразу.

   Прокрутки нет ни в одном состоянии — это проверяется в
   tools/uitests/review-form.js. */
.rf-panes {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  /* Верхняя строка — по содержимому, нижняя забирает остаток: иначе грид
     растягивает ОБЕ строки поровну (align-content по умолчанию тянет
     авторазмерные строки), и лишняя высота расползается пустотой между
     оценкой и полем — ровно та «кривая сетка», что видно на снимке.

     Минимум у нижней строки оставлен: поле для отзыва — смысл окна, и оно
     не уступает место раскрытому списку пунктов. */
  grid-template-rows: auto minmax(280px, 1fr);
  align-content: start;
  overflow: hidden;
}
.rf-pane { flex: none; overflow: visible; min-width: 0; }
/* fieldset и flex-строки распирают колонку своим содержимым: у них
   min-width: auto. Без обнуления звёзды вылезали из левой колонки
   поверх правой. */
.rf-pane fieldset,
.rf-pane .rf-rate-row,
.rf-pane .rf-chips { min-width: 0; }
.rf-pane[data-pane="rate"] { grid-column: 1; grid-row: 1; overflow-y: auto; }
.rf-pane[data-pane="good"] {
  grid-column: 1;
  grid-row: 2;
  min-height: 0;
  /* Последний рубеж: если после всех уступок содержимое всё равно не влезло
     (раскрыты пункты на низком окне), колонка письма прокручивается сама —
     это лучше, чем налезающие друг на друга блоки. Окно при этом остаётся
     неподвижным. */
  overflow-y: auto;
}
.rf-pane[data-pane="bad"] {
  grid-column: 2;
  grid-row: 1 / span 2;
  border-left: 1px solid var(--border);
  overflow-y: auto;   /* страховка на очень низком окне: столбец, а не всё окно */
}
.rf-pane[data-pane="rate"] { padding-bottom: 0; }
/* Поля внутри панелей тоже без своих отступов: шаг задаёт панель. */
.rf-pane .field { margin-bottom: 0; }
.rf-cons-block { display: flex; flex-direction: column; gap: var(--space-md); }
.rf-pane[data-pane="good"] { padding-top: var(--space-sm); }
.rf-pane[data-pane="good"] { padding-top: var(--space-md); }

.rf-rate-hint {
  margin: var(--space-xs) 0 0;
  font-size: var(--text-xs);
  color: var(--text-subtle);
}

/* Главное поле: восемь строк вместо трёх. Приглашение написать, а не
   заполнить строчку. */

.rf-second textarea { min-height: 88px; }
.rf-second[hidden] { display: none; }
.rf-opt { font-weight: 400; color: var(--text-subtle); font-size: var(--text-xs); }

/* Ноутбучное окно (около 800px). Здесь ещё всё помещается, но впритык:
   подрезаем только воздух — поля шапки, подвала и панелей. Тексты и
   размеры остаются, их черёд наступает ниже 720. */
@media (min-width: 881px) and (max-height: 880px) {
  .rf-head { padding-top: var(--space-lg); padding-bottom: var(--space-sm); }
  .rf-foot { padding-top: var(--space-sm); padding-bottom: var(--space-lg); }
  .rf-pane { padding-top: var(--space-sm); padding-bottom: var(--space-sm); }
  .rf-chips-cap { margin: var(--space-xs) 0; }
  .rf-chip span { min-height: 28px; }
  .rf-rate .rating-input-lg svg { width: 30px; height: 30px; }
  .rv-crit-row { min-height: 36px; }
}

/* Короткое окно браузера (ноутбук с открытой панелью закладок и консолью).
   Форма обязана уместиться и здесь: прокрутка внутри окна не допускается.
   Ужимаем то, что дешевле всего, — воздух вокруг оценки и подпись
   над метками; поле остаётся нетронутым, оно и есть смысл окна. */
@media (min-width: 881px) and (max-height: 800px) {
  .rf-head { padding-top: var(--space-md); padding-bottom: var(--space-sm); }
  .rf-foot { padding-top: var(--space-sm); padding-bottom: var(--space-md); }
  .rf-pane { padding-top: var(--space-sm); padding-bottom: var(--space-sm); }
  .rf-rate .rating-input-lg svg { width: 28px; height: 28px; }
  .rf-rate-hint { display: none; }
  .rf-chips-cap { display: none; }
  .rf-chip span { min-height: 28px; }
  /* Строки пунктов и заголовок свёрнутого блока — последнее, что можно
     ужать, не трогая содержания. Ниже этого окно уже нельзя обслужить
     без прокрутки, и она честнее обрезанного списка. */
  .rv-crit-row { min-height: 32px; }
  .rf-more summary { min-height: 38px; }
  .rf-drop { padding: var(--space-md); }
}

/* ── Метки ──
   Обычные чекбоксы, спрятанные под подпись: набор закрытый, и выглядеть
   он должен как выбор словами, а не как список галочек. */
.rf-chips-cap {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--text-subtle);
}
.rf-chips { display: flex; flex-wrap: wrap; gap: var(--space-xs); align-content: flex-start; }
.rf-chip input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.rf-chip span {
  display: inline-flex;
  align-items: center;
  min-height: 30px;
  padding: 0 var(--space-md);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--text-muted);
  font-size: var(--text-xs);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
.rf-chip.on span {
  border-color: var(--accent);
  background: var(--surface-1);
  color: var(--accent-strong);
  font-weight: 500;
}
.rf-chip input:focus-visible + span { outline: 2px solid var(--focus); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .rf-chip:not(.on) span:hover { border-color: var(--surface-3); }
}

/* ── Снимки: видимая область загрузки ──
   Строка со стрелкой читалась как ещё один раздел неизвестно о чём.
   Пунктирная рамка со значком и приглашением — общепринятый вид области
   прикрепления файлов, и назначение блока понятно до нажатия. */
.review-form .rf-drop {
  display: grid;
  justify-items: center;
  gap: 2px;
  padding: var(--space-lg);
  border: 1px dashed var(--surface-3);
  border-radius: var(--r-sm);
  background: var(--surface);
  text-align: center;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out);
}
.rf-drop input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.rf-drop-icon { color: var(--accent); line-height: 0; }
.rf-drop-title { font-size: var(--text-sm); font-weight: 600; color: var(--accent-strong); }
.rf-drop-note { font-size: var(--text-xs); color: var(--text-subtle); }
/* Состояние перетаскивания: без отклика человек не понимает, попал ли он
   в область, и отпускает файл мимо. */
.rf-drop.is-over { border-color: var(--accent); background: var(--surface-1); }
.rf-drop:focus-within { outline: 2px solid var(--focus); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .rf-drop:hover { border-color: var(--accent-soft); background: var(--surface-1); }
}
.rf-file-note { font-size: var(--text-xs); color: var(--text-subtle); }
.rf-thumbs { display: flex; flex-wrap: wrap; gap: var(--space-md); margin-top: var(--space-md); }
.rf-thumbs[hidden] { display: none; }
.rf-thumb { position: relative; width: 72px; height: 72px; }
.rf-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--r-sm);
  display: block;
}
.rf-thumb-x {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 22px;
  height: 22px;
  border: 0;
  border-radius: var(--r-pill);
  background: rgba(17, 20, 31, 0.72);
  color: #fff;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}

/* ── Свёрнутые уточнения ── */
.rf-more { margin: 0; }
.rf-more summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: var(--tap, 44px);
  padding: 0 var(--space-md);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-size: var(--text-sm);
  color: var(--text-subtle);
  cursor: pointer;
  list-style: none;
}
.rf-more summary::-webkit-details-marker { display: none; }
.rf-more summary b { font-weight: 500; color: var(--text); }
.rf-more[open] summary { margin-bottom: var(--space-md); }
/* Раскрытый список пунктов не должен выдавливать поле для отзыва: пять
   строк — это двести пикселей, и на невысоком окне они съедали ровно ту
   высоту, ради которой всё и затевалось. Ограничиваем список, а не
   колонку: прокрутка внутри перечня из пяти строк — нормальное дело,
   прокрутка поля, в которое пишут, — нет. */
.rf-crit { max-height: min(200px, 32vh); overflow-y: auto; }
/* Строка критерия целиком — цель нажатия в 44px: пять звёзд по 28px
   впритык давали промах по соседней, а снять оценку радиокнопкой нельзя. */
.rv-crit-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  /* 40px вместо 44: пять строк подряд, и каждая лишняя четвёрка пикселей
     умножается на пять. Цель нажатия остаётся достаточной за счёт поля
     вокруг звезды (см. .rating-input-sm label ниже). */
  min-height: 40px;
}
.rv-crit-row + .rv-crit-row { border-top: 1px solid var(--border); }
.rv-crit-label { font-size: var(--text-sm); color: var(--text-muted); }
/* Звезда критерия — рисунок в 20px, но цель нажатия должна быть больше:
   пять штук подряд при ширине пальца в 8 мм иначе дают промах по соседней.
   Растим полем, а не размером значка: крупные звёзды в свёрнутом блоке
   спорили бы с главной оценкой. */
.rv-crit-row .rating-input-sm label { padding: 9px 5px; }

/* ── Предпросмотр (только в пошаговом режиме) ── */
.rf-pane-done { gap: var(--space-md); }
.rf-done-cap {
  margin: 0 0 var(--space-md);
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-subtle);
}
.rf-preview { background: var(--surface-1); border-radius: var(--r-md); padding: var(--space-lg); }
.rf-prev-star { color: var(--surface-3); }
.rf-prev-star.on { color: #f0a500; }
.rv-text-second { color: var(--text-muted); }

/* Метки в карточке отзыва — отдельной строкой, не подмешиваясь в текст. */
.rv-tags { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-top: var(--space-md); }
.rv-tags[hidden] { display: none; }
.rv-tag {
  padding: 3px var(--space-md);
  border-radius: var(--r-pill);
  font-size: var(--text-xs);
}
.rv-tag-good { background: var(--green-bg); color: var(--green-ink); }
.rv-tag-bad { background: var(--amber-bg); color: var(--amber-ink); }

.rf-foot {
  flex: none;
  padding: var(--space-md) var(--space-3xl) var(--space-xl);
  border-top: 1px solid var(--border);
}
/* Кнопка отправки не растягивается на всю ширину окна: в двух колонках
   это 900 пикселей заливки ради одного действия. Прижата вправо — туда,
   где заканчивается чтение. */
.rf-actions { display: flex; align-items: center; justify-content: flex-end; gap: var(--space-md); }
/* Свой display перебивает атрибут hidden — ловушка, записанная в манифесте. */
.rf-actions[hidden] { display: none; }
/* Кнопки шагов существуют в разметке всегда: показывать их скриптом значит
   мигать подвалом при каждой загрузке. Скрытые не должны занимать место —
   атрибут hidden тут бессилен, у кнопок свой display. */
.rf-actions button[hidden] { display: none; }
.rf-submit { flex: 0 0 auto; min-width: 240px; margin: 0; }

/* Подтверждение закрытия — полосой в том же низу, вместо кнопок. Второй
   модалкой поверх первой это делать нельзя: слой в слое в проекте запрещён. */
.rf-confirm[hidden] { display: none; }
.rf-confirm { display: grid; gap: var(--space-md); }
.rf-confirm-text { margin: 0; font-size: var(--text-sm); color: var(--text); }
.rf-confirm-btns { display: flex; gap: var(--space-md); }
.rf-confirm-btns .btn { flex: 1; }
/* Закрыть — разрушающее действие: контуром и в розовом, не акцентом,
   и стоит после безопасного «Продолжить». */
.rf-confirm-drop {
  flex: none;
  border: 1px solid var(--rose-ink);
  border-radius: var(--r-pill);
  background: none;
  padding: 11px 18px;
  min-height: var(--tap);
  font: inherit;
  font-size: var(--text-base);
  font-weight: 700;
  color: var(--rose-ink);
  white-space: nowrap;
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .rf-confirm-drop:hover { background: var(--rose-bg); }
}

/* ── Оценка ── */
.rf-rate { margin: 0 0 var(--space-xl); padding: 0; border: 0; }
.rf-rate legend {
  padding: 0;
  margin-bottom: var(--space-sm);
  font-weight: 500;
  font-size: var(--text-sm);
  color: var(--text);
}
.rf-rate-row { display: flex; align-items: center; gap: var(--space-lg); }
/* Крупные звёзды: это первое и самое дешёвое действие в форме, и цель
   нажатия на телефоне должна быть заведомо больше пальца. */
.rating-input-lg label { padding: 4px; }
/* Подпись выбранной оценки. Ширина фиксирована по самому длинному слову
   («Нормально»), иначе строка звёзд дёргалась бы при каждом выборе. */
.rf-rate-word {
  min-width: 7.5em;
  font-weight: 600;
  font-size: var(--text-base);
  color: var(--text-muted);
}
.rf-rate-word:empty::after {
  content: "выберите оценку";
  font-weight: 400;
  color: var(--faint);
}
/* Предпросмотр на наведении приглушён: это ещё не выбор, и выглядеть
   как выбранное значение он не должен. */
.rf-rate-word[data-preview] { color: var(--faint); }

/* ── Поля ── */
/* .field уже описан в разделе входа; здесь только то, чем поля формы
   отзыва от него отличаются. */
.rf-field { margin-bottom: var(--space-lg); }
/* Поле отзыва забирает всю оставшуюся высоту панели: на большом экране это
   просто больше места для письма, на маленьком — способ уложиться без
   прокрутки, не подгоняя rows под каждую ширину. */
/* Главное поле: одна колонка на широком экране, поэтому высота задаётся
   числом, а не растяжением. Растягивается оно только в пошаговом режиме —
   там панель одна и высоту задаёт она (см. mobile.css). */
/* Контейнер главного поля. min-height обязателен и не может быть нулевым:
   при нуле он сжимается ниже собственного поля, поле вылезает за его
   границы, а метки под ним печатаются поверх текста. 112px — подпись
   плюс минимальная высота поля. */
.rf-text { flex: 1; min-height: 112px; display: flex; flex-direction: column; }
/* height числом, а не от атрибута rows: иначе поле не отдаёт высоту, когда
   окно ниже. Растёт за счёт flex, ужимается до 120px — ниже оно перестаёт
   быть приглашением написать. */
.rf-text textarea { flex: 1 1 auto; height: 120px; min-height: 88px; }
.rf-second textarea { min-height: 96px; }
.rf-cons-block .rf-field { margin-bottom: var(--space-sm); }
.rf-field textarea {
  width: 100%;
  border: 1px solid var(--lav-3);
  border-radius: var(--r-sm);
  padding: 11px 14px;
  font: inherit;
  font-size: var(--text-base);
  color: var(--ink);
  background: #fff;
  resize: vertical;
  transition: border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
}
.rf-field textarea:focus {
  outline: none;
  border-color: var(--violet);
  box-shadow: 0 0 0 3px var(--lav-2);
}
.rf-label-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
}
.rf-label-row label { margin: 0; }
/* Счётчик показывает набранное, а не остаток: у поля важен минимум,
   до потолка в 2000 знаков доходят единицы. Пока минимума нет — приглушён. */
.rf-count { font-size: var(--text-2xs); color: var(--faint); white-space: nowrap; }
.rf-count[data-state="ok"] { color: var(--green-ink); }
.rf-count[data-state="over"] { color: var(--rose-ink); }

/* ── Необязательное под крышкой ── */
.rf-crit { margin: 0 0 var(--space-lg); padding: 0; border: 0; }
/* .rv-crit-input несёт свой нижний отступ для блока отзывов; внутри
   формы он складывался с отступом .rf-crit в двойную пустоту. */
.rf-crit .rv-crit-input { margin-bottom: 0; }
.rf-crit > legend {
  padding: 0;
  margin-bottom: var(--space-sm);
  font-weight: 500;
  font-size: var(--text-sm);
}
/* Две колонки и на телефоне: поля короткие, а в столбик они добавляли
   панели «подробности» лишние двести пикселей высоты. */
.rf-two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-md); }

/* ── Снимки ── */
/* Родной контрол спрятан, а не удалён: он остаётся полем формы и целью
   для клавиатуры — фокус ловится через :focus-visible на подписи. */
.rf-file { display: flex; align-items: center; gap: var(--space-md); flex-wrap: wrap; }
.rf-file input[type="file"] {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.rf-file-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0 !important;
  padding: 9px 14px;
  min-height: var(--tap);
  border: 1px dashed var(--lav-3);
  border-radius: var(--r-sm);
  color: var(--accent-ink);
  font-size: var(--text-sm);
  font-weight: 500;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .rf-file-btn:hover { border-color: var(--violet); background: var(--lav-1); }
}
.rf-file input[type="file"]:focus-visible + .rf-file-btn {
  outline: 2px solid var(--violet);
  outline-offset: 2px;
}
.rf-file-list { font-size: var(--text-xs); color: var(--faint); min-width: 0; }
.rf-file-list[data-state="over"] { color: var(--rose-ink); }

/* ── Подпись ── */
/* Подпись именем — последняя строка колонки, ей нужен отступ от
   свёрнутых блоков: без него она читается как их часть. */


/* ============================================================
   Заглушка портрета врача — static/img/doctor-placeholder.webp
   Фотографии нет у 403 профилей из 1585. Раньше на их месте стояли
   инициалы на подложке своего оттенка; общий силуэт занимает тот же
   квадрат, что и снимок, и живёт по правилам снимка — размеры задают
   слоты (.hc-media img, .dr-portrait, .doc-photo img), здесь остаётся
   только подложка.

   Селектор с тегом (img.doc-ph), а не один класс: слоты задают
   background правилами вида «.hc-media img» той же специфичности,
   и одноклассовое правило проигрывало бы им независимо от порядка.
   Правило стоит в конце файла — при равной специфичности выигрывает
   последнее.

   Подложка на ступень плотнее, чем у снимков (--surface-2 против
   --surface-1): халат на картинке белый, и на почти белой подложке
   у фигуры пропадали плечи.
   ============================================================ */
img.doc-ph {
  background: var(--surface-2);
  /* Картинка квадратная и заполняет кадр целиком: object-fit: cover
     от снимков ничего не обрезает, но смещение кадра вверх
     (object-position у .hc-media-doc и .doc-photo img) увело бы халат
     под нижнюю кромку. */
  object-position: 50% 50%;
}


/* ============================================================
   Скелетоны ожидания

   Одна анимация на весь портал: мягкая полоса, проходящая по подложке
   слота слева направо. Полоса — --surface-2 по --surface-1, то есть
   те же лавандовые нейтрали, на которых собран весь интерфейс:
   фиолетовый в проекте закреплён за действиями, и «загружается» его
   тратить нельзя — иначе ожидание кричит громче кнопок.

   Скелетон занимает готовую рамку слота и ничего не двигает: у всех
   мест, где он появляется, размер задан заранее (квадрат портрета,
   колонка карты, строка подсказки). Перекладывания страницы после
   загрузки не происходит.

   Класс вешает и снимает скрипт (skeleton.js, clinic-map.js,
   clinic-point.js, suggest.js) — в разметке его нет: без JS ни ленивых
   снимков, ни карты, ни подсказок не будет, и бесконечная полоска
   обещала бы то, что уже не приедет.
   ============================================================ */
/* Проценты у background-position считаются от «сколько картинка не влезла»,
   а не от ширины блока: при фоне в 220% позиция 100% уводит полосу за левый
   край, 0% — за правый. Поэтому цикл идёт ровно от 100 к 0, без запаса:
   с запасом (160 → -60) полоса больше половины периода стояла за кадром,
   и на месте карты был просто пустой прямоугольник. */
@keyframes skel-sweep {
  from { background-position: 100% 0; }
  to   { background-position: 0 0; }
}
/* linear, а не проектные ease: у бесконечного цикла ускорение и
   торможение читаются как рывок на стыке периодов. */
.is-loading {
  --skel-band: var(--surface-2);
  background-image: linear-gradient(
    100deg,
    transparent 32%,
    var(--skel-band) 50%,
    transparent 68%
  );
  background-size: 220% 100%;
  background-repeat: no-repeat;
  animation: skel-sweep 1.6s linear infinite;
}
/* Снимки: правило стоит последним в файле и с тем же весом, что у слотов
   (.hc-media img, img.doc-ph), — при равной специфичности выигрывает
   последнее. Отсюда и место блока: заглушка портрета выше задаёт фон
   сокращённой записью background, а она сбрасывает background-image. */
/* Картинка под плашкой: сама она грузится своим чередом, а рисовать её
   нечем — content подменён прозрачным градиентом, и сквозь картинку
   видно её же подложку с полосой. Через content, а не через снятый src:
   картинка без src рисует рамку с alt, и карточка на эти полсекунды
   выглядела битой ссылкой. Браузеру без поддержки content на замещённых
   элементах достаётся просто снимок без плашки — это не поломка. */
img.is-loading,
.hc.is-loading img {
  content: linear-gradient(transparent, transparent);
}
img.is-loading {
  --skel-band: var(--surface-2);
  background-color: var(--surface-1);
  background-image: linear-gradient(
    100deg,
    transparent 32%,
    var(--skel-band) 50%,
    transparent 68%
  );
  background-size: 220% 100%;
  background-repeat: no-repeat;
  animation: skel-sweep 1.6s linear infinite;
}
/* ── Карточка выдачи целиком ──
   В карточке ждёт один снимок, но плашка на портрете рядом с готовым
   именем, метро и телефоном читается как «сломалась картинка». Ждёт
   карточка — ждёт вся карточка: содержимое становится брусками, снимок
   и заглушка — светлым квадратом.

   Полоса при этом одна на всю карточку и идёт поверх (::after). Если
   отдать её каждому бруску, каждый мерцает в своём ритме — по короткому
   полоса пробегает мгновенно, по длинному ползёт, — и карточка рябит
   вместо того чтобы дышать. */
.hc.is-loading { position: relative; }
.hc.is-loading::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  pointer-events: none;
  /* Полупрозрачная: волна идёт и по белому полю карточки, и по брускам,
     непрозрачная стирала бы их под собой. */
  background-image: linear-gradient(
    100deg,
    transparent 32%,
    color-mix(in srgb, var(--surface-3) 65%, transparent) 50%,
    transparent 68%
  );
  background-size: 220% 100%;
  background-repeat: no-repeat;
  animation: skel-sweep 1.6s linear infinite;
}
/* Бруски. Кегль и поля остаются прежними, поэтому карточка в ожидании
   ровно того же размера, что и готовая, — при снятии плашки ничего
   не переезжает. */
.hc.is-loading :is(
  .hc-name, .hc-desc, .hc-more, .hc-rate, .hc-review, .hc-badge, .hc-fact,
  .hc-cta, .hc-doc-who, .hc-doc-where, .hc-doc-call
) {
  border-radius: var(--r-pill);
  border-color: transparent;
  background-color: var(--surface-1);
  background-image: none;
  box-shadow: none;
  color: transparent;
}
/* Строки разной длины — иначе три бруска во всю колонку читаются как
   бланк, а не как подгружающаяся карточка. Ширину задаём только тем
   строкам, которые и так в одну строку с многоточием (nowrap): у
   переносимых текст перевёрстывался бы, карточка меняла высоту, и при
   снятии плашки список дёргался бы. */
.hc-doc.is-loading .hc-doc-who { width: 30%; }
.hc-doc.is-loading .hc-doc-where { width: 64%; }
/* Значки, кружки веток и ссылки внутри брусков — скрыть, но место
   оставить: visibility, а не display. */
.hc.is-loading :is(
  .hc-name, .hc-desc, .hc-more, .hc-rate, .hc-review, .hc-badge, .hc-fact,
  .hc-cta, .hc-doc-who, .hc-doc-where, .hc-doc-call
) * { visibility: hidden; }
/* Снимок и заглушка — тот же светлый квадрат в своей рамке */
.hc.is-loading :is(img, .hc-media-stub) {
  background-color: var(--surface-1);
  color: transparent;
  box-shadow: none;
}
.hc.is-loading .hc-media-stub > * { visibility: hidden; }

/* Карта: полотно в десяток раз больше портрета. Полоса той же скорости
   пробегала бы его суетливо, а той же светлоты — терялась: на площади
   в половину экрана разница в две единицы яркости не читается вовсе.
   Отсюда ступень контраста и вдвое более долгий проход. */
.map-canvas.is-loading,
.map-modal-canvas.is-loading {
  --skel-band: var(--surface-3);
  animation-duration: 2.4s;
}

/* Строки подсказок поиска: кружок под снимок и две полосы под заголовок
   с подписью — ровно та же сетка, что у настоящей строки, поэтому при
   подмене ничего не прыгает. */
.suggest-skel {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-sm) var(--space-md);
}
.suggest-skel-pic {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: var(--r-sm);
  background-color: var(--surface-1);
}
/* Ширина полос ограничена: список подсказок тянется во всю строку поиска,
   и полоса на всю его ширину — это уже не «здесь будет название клиники»,
   а линейка. Настоящие заголовки в подсказках короче четверти строки. */
.suggest-skel-text {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  min-width: 0;
  flex: 1 1 auto;
  max-width: 420px;
}
.suggest-skel-line {
  height: 10px;
  border-radius: var(--r-pill);
  background-color: var(--surface-1);
}
.suggest-skel-line.short { width: 52%; }
/* Строки разной длины: четыре одинаковых бруска выглядят напечатанным
   бланком, а не подгружающимся списком. */
.suggest-skel:nth-child(2) .suggest-skel-line { width: 78%; }
.suggest-skel:nth-child(2) .suggest-skel-line.short { width: 40%; }
.suggest-skel:nth-child(3) .suggest-skel-line { width: 92%; }
.suggest-skel:nth-child(3) .suggest-skel-line.short { width: 60%; }
.suggest-skel:nth-child(4) .suggest-skel-line { width: 70%; }
.suggest-skel:nth-child(4) .suggest-skel-line.short { width: 45%; }

/* Уважение к prefers-reduced-motion: полоса замирает, подложка остаётся.
   Место занято и видно, что содержимое ещё не пришло, — без движения. */
@media (prefers-reduced-motion: reduce) {
  .is-loading,
  img.is-loading,
  .map-canvas.is-loading,
  .map-modal-canvas.is-loading { animation: none; }
  /* У карточки полоса — отдельный слой; гасим сам слой, бруски остаются */
  .hc.is-loading::after { display: none; }
}

/* ═══════════════════════ Кабинет клиники ═══════════════════════
   Язык плотного справочника: белые панели с тонкими рамками, акцент
   только на действиях. Разметка простая намеренно — это рабочий
   инструмент клиники, а не витрина. */
.cab { max-width: 720px; margin-top: var(--space-2xl); }
.cab-narrow { max-width: 560px; }
.cab-head h1 { margin: 2px 0 4px; }
.cab-nav {
  display: flex;
  gap: var(--space-xl);
  margin: var(--space-xl) 0 var(--space-2xl);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  scrollbar-width: none;
}
.cab-nav::-webkit-scrollbar { display: none; }
.cab-nav a {
  padding: var(--space-sm) 0 var(--space-md);
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: 500;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
}
.cab-nav a[aria-current="page"] { color: var(--text); border-bottom-color: var(--accent); }

.cab-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-md);
  margin-bottom: var(--space-2xl);
}
.cab-stat {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--space-lg);
  background: var(--surface);
}
.cab-stat b { display: block; font-size: var(--text-xl); }
.cab-stat span { font-size: var(--text-xs); color: var(--text-muted); }

.cab-sub { margin: var(--space-2xl) 0 var(--space-md); font-size: var(--text-lg); }
.cab-list { list-style: none; margin: 0; padding: 0; }
.cab-list > li {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  padding: var(--space-lg);
  margin-bottom: var(--space-md);
}
.cab-list-link { display: block; color: var(--text); }
.cab-list-link b { display: block; }
.cab-form { max-width: 480px; }
.cab-form .field { margin-bottom: var(--space-lg); }
.cab-check { display: flex; gap: var(--space-sm); align-items: center; font-weight: 500; }
.cab-pending {
  border: 1px solid var(--amber-ink);
  background: var(--amber-bg);
  border-radius: var(--r-md);
  padding: var(--space-md) var(--space-lg);
  margin-bottom: var(--space-xl);
}
.cab-reply {
  margin-top: var(--space-md);
  padding: var(--space-md);
  border-left: 3px solid var(--surface-3);
  background: var(--surface-1);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
}
.cab-reply-form summary { cursor: pointer; color: var(--accent-strong); font-weight: 500; margin-top: var(--space-md); }
.cab-reply-form textarea { width: 100%; margin: var(--space-md) 0 var(--space-sm); }
.cab-photos {
  list-style: none;
  margin: var(--space-xl) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--space-md);
}
.cab-photos img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--r-sm);
  display: block;
}
.cab-member { position: relative; }
.cab-inline-form { display: inline; }
.cab-remove {
  border: 0;
  background: none;
  color: var(--rose-ink);
  font: inherit;
  font-size: var(--text-xs);
  cursor: pointer;
  padding: 0;
  margin-left: var(--space-md);
}

/* Плашка черновика на предпросмотре статьи (виден только сотрудникам). */
.art-draft-note {
  display: flex; align-items: center; gap: var(--space-sm);
  margin-bottom: var(--space-lg);
  padding: var(--space-sm) var(--space-lg);
  border: 1px solid var(--rose-ink);
  border-radius: var(--r-md);
  color: var(--rose-ink);
  font-size: var(--text-sm); font-weight: 600;
}
