/* =============================================================================
   ash-catalog.css — компонентные стили каталога asho.to
   Карточка листинга · сетка витрины · страница анкеты · салон.

   ПОДКЛЮЧАТЬ ВТОРЫМ, после ash-tokens.css: здесь используются токены тем
   (--Special-*, --Badges-*, --Text-*) и служебные классы (.row, .gap-8,
   .ellipsis, .comma-separated, .rounded, .q-pa-sm …), объявленные там.

   ОТКУДА ЧИСЛА. Каждое значение снято с боевого CSS источника
   /var/www/asho_to_usr/data/_handoff/style/index-Cwib1x1t.css
   и разобрано в research/card.md §12, research/profile-page.md §3,
   research/salon-page.md §3 и §5. Ничего «на глаз».

   ПРО АТРИБУТЫ. Источник красит компоненты НЕСТАНДАРТНЫМИ атрибутами без
   префикса: variant="listing", premium="true", starred="true", polee="true",
   kind="person", answer="true", type="page", active="true". Это невалидный
   HTML, поэтому card.md §3 предложил перевести их на data-*. Чей вариант
   напечатает рендер — на момент написания вёрстки не решено, поэтому ниже
   ВЕЗДЕ объявлены ОБА написания. Дублирование селектора стоит ~20 байт,
   а рассинхрон рендера и вёрстки стоил бы белой страницы.

   ЧЕГО ЗДЕСЬ НЕТ: шапки, подвала, фильтров, пагинации, заглушки 18+ —
   они в ash-chrome.css.
   ============================================================================= */


/* =============================================================================
   0-А. ДОБОР: ЦВЕТ ТЕКСТА ТЕЛА
   Найдено замером headless-браузера: в ash-tokens.css у body объявлен только
   background-color, а color — нет. В светлой теме это незаметно (чёрный по
   белому), а в ТЁМНОЙ текст остаётся чёрным на #121212, то есть пропадает.
   У источника этого не бывает, потому что там действует правило Quasar
      body.body--dark { color:#fff; background:var(--q-dark-page) }
   которое в токены не попало.

   ПОЧЕМУ #000/#fff, А НЕ var(--Text-Primary). Сначала я поставил токен: он
   «правильнее» по дизайн-системе. Но замер САМОГО ИСТОЧНИКА (qa/REFERENCE.md,
   слепок qa/source-listing-reference.json) показывает у имени карточки
   color: rgb(0,0,0) — чистый чёрный, а не #242424. Так и должно быть: в светлой
   теме источник вообще не задаёт цвет тела, работает дефолт браузера, а токен
   --Text-Primary применяется только там, где на элементе есть .text-text-primary.
   Разница #000 против #242424 видна глазом, а наша задача — чтобы посетитель
   не заметил разницы. Поэтому повторяем ровно источник: дефолтный чёрный в
   светлой и #fff в тёмной.
   Правка живёт здесь, а не в ash-tokens.css: тот файл сдан и не переписывается.
   ============================================================================= */
body.body--light { color: #000; }
body.body--dark  { color: #fff; }


/* =============================================================================
   0. МИНИМАЛЬНЫЙ НАБОР QUASAR, КОТОРЫЙ РЕАЛЬНО ЕСТЬ В РАЗМЕТКЕ ИСТОЧНИКА
   Не «Quasar целиком»: только кнопка, иконка, карточка, список, разделитель и
   аккордеон — ровно те классы, что встречаются в сохранённых страницах дампа.
   Без них разметка источника рассыпается, потому что она на них и написана.
   ============================================================================= */

/* --- иконка ---------------------------------------------------------------
   Устройство источника: <i class="q-icon h-icon" style="font-size:24px">
                           <svg viewBox="0 0 24 24"><use xlink:href="#id"></svg>
                         </i>
   Размер задаётся font-size на обёртке, svg тянется в 1em. Заливку несёт сам
   <symbol> (fill="none" + stroke="currentColor"), поэтому здесь красить нечего
   — только наследовать currentColor. */
.q-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1em;
  height: 1em;
  line-height: 1;
  flex-shrink: 0;
  vertical-align: middle;
  color: inherit;
}
.q-icon > svg,
.h-icon > svg { width: 1em; height: 1em; display: block; }
/* .h-icon применяется и без .q-icon (например .price-icon), задаём базу */
.h-icon { flex-shrink: 0; }

/* --- кнопка ---------------------------------------------------------------
   Из всего QBtn источник использует шесть модификаторов. text-transform:none
   ОБЯЗАТЕЛЕН: у Quasar базовый .q-btn — uppercase, и источник гасит его
   отдельным правилом. Без этого все кнопки закричат капсом. */
.q-btn,
.ash-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  /* БАГ 46: margin:0 отсюда УБРАН — правило на классе перебивало утилиты
     .q-mt-* (тот же вес, но ash-catalog подключается позже ash-tokens), и
     кнопки теряли заданный в разметке отступ. Нулевой отступ теперь даёт
     тип-селектор в ash-tokens.css («БАЗОВЫЙ СБРОС»), как у источника. */
  padding: 4px 16px;
  /* БАГ 46: у источника базовый .q-btn = min-height:2.572em (замер
     index-Cwib1x1t.css). Без этого иконочные кнопки выходили 26px вместо 40. */
  min-height: 2.572em;
  border: 0;
  border-radius: 8px;
  outline: 0;
  background: transparent;
  color: inherit;
  font-family: inherit;
  font-size: var(--Font-Size-Body-Small, 14px);
  font-weight: var(--Font-Weight-Regular, 400);
  /* БАГ 46: у источника line-height базовой кнопки — относительный 1.715em,
     а не фиксированные 16px: именно он вместе с min-height даёт высоту 41px. */
  line-height: 1.715em;
  text-align: center;
  text-decoration: none;
  text-transform: none;
  white-space: nowrap;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
}
/* БАГ 46: правило источника один в один (index-Cwib1x1t.css). Пять :not()
   выводят из-под него мелкие/круглые кнопки — именно они у источника остаются
   на 14px. Без этого правила «Войти и оставить отзыв» выходит 36px вместо 41. */
.q-btn:not(.q-btn--fab-mini):not(.selector):not(.q-btn--round):not(.special-btn):not(.text-body-m),
input {
  letter-spacing: 0;
  font-size:   var(--Font-Size-Body, 16px);
  font-weight: var(--Font-Weight-Regular, 400);
  line-height: var(--Line-Height-Body, 20px);
}
.q-btn:disabled,
.ash-btn:disabled { cursor: not-allowed; opacity: .6; }
.q-btn__content {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: 100%;
  height: 100%;
}
.q-btn__content > .block { display: block; }
.q-btn--rectangle   { border-radius: 8px; }
.q-btn--rounded     { border-radius: 28px; }
.q-btn--round       { border-radius: 50%; padding: 0; }
.q-btn--dense       { padding: 0 4px; min-height: 0; }
.q-btn--flat        { background: transparent; }
.q-btn--unelevated  { box-shadow: none; }
/* БАГ 46: у источника обводка нарисована псевдоэлементом, а не border — иначе
   рамка съедает внутреннюю ширину и кнопка становится на 2px уже/ниже. */
.q-btn--outline     { background: transparent !important; }
.q-btn--outline::before {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  border: 1px solid;
  border-radius: inherit;
  box-shadow: none;
  pointer-events: none;
}
/* fab-mini у источника перебит до 44×44 в шапке и до 40×40 в карусели;
   базовое значение Quasar — 40. Локальные правила ниже сильнее. */
.q-btn--fab-mini    { width: 40px; min-width: 40px; height: 40px; min-height: 40px; padding: 0; }
.q-btn:hover:not(.no-hover),
.ash-btn:hover:not(.no-hover) { opacity: .9; }
.no-hover:hover { opacity: 1; }

/* --- карточка, список, разделитель --------------------------------------- */
.q-card {
  position: relative;
  box-sizing: border-box;
  border-radius: 8px;
  background: var(--Background-Layer1);
  color: var(--Text-Primary);
}
.q-card__section { position: relative; }
.q-card__section--vert { display: flex; flex-direction: column; }
.q-list { padding: 0; margin: 0; list-style: none; }
.q-separator {
  border: 0;
  margin: 0;
  flex: 0 0 auto;
  background: var(--Border-Secondary);
}
.q-separator--horizontal { display: block; height: 1px; width: 100%; }

/* --- аккордеон -----------------------------------------------------------
   Источник отдаёт все семь блоков РАСКРЫТЫМИ и складывает их скриптом Vue.
   У нас скрипта нет, поэтому правила написаны так, чтобы работали ОБА варианта
   разметки: дивы Quasar (если рендер копирует источник побайтно) и родной
   <details class="expansion-block"><summary class="expansion-title">
   (тогда блоки складываются без единой строки JS). */
.q-expansion-item__container { position: relative; }
.expansion-block .q-expansion-item__container > .q-item:first-child {
  min-height: unset;
  padding: 4px 0;
}
.expansion-block .q-expansion-item__content { margin-top: 8px; }
.q-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  min-height: 48px;
  color: inherit;
}
.q-item__section--main { flex: 1 1 0; min-width: 0; }
.q-item__section--side { flex: 0 0 auto; }
.expansion-block .q-item__label {
  letter-spacing: 0;
  font-size:   var(--Font-Size-H2, 20px);
  font-weight: var(--Font-Weight-Bold, 700);
  line-height: var(--Line-Height-H2, 24px);
}
/* Стрелка аккордеона: развёрнута вниз у раскрытого блока */
.q-expansion-item__toggle-icon { font-size: 24px; color: var(--Icon-Primary); transition: transform .2s; }
.q-expansion-item__toggle-icon--rotated { transform: rotate(180deg); }

/* Вариант на <details>: тот же вид, но складывается штатно браузером. */
details.expansion-block > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 4px 0;
  cursor: pointer;
  list-style: none;
}
details.expansion-block > summary::-webkit-details-marker { display: none; }
details.expansion-block > summary::marker { content: ""; }
details.expansion-block > summary > .q-icon { transition: transform .2s; }
details.expansion-block[open] > summary > .q-icon { transform: rotate(180deg); }
details.expansion-block > summary + * { margin-top: 8px; }


/* =============================================================================
   1. СЕТКА ВИТРИНЫ
   ГЛАВНОЕ: колонок столько, сколько влезает, а не «три». 392px и 3 колонки —
   это СЛЕДСТВИЕ формулы при контейнере 1200: floor((1200+12)/(343+12)) = 3.
   При 1024–1439 контейнер 992 → две колонки по ~490. Замена на
   repeat(3, 392px) разваливает витрину на всех ширинах кроме 1440+
   (card.md §9.2 п.1). Сам контейнер .main-listing — в ash-tokens.css.
   ============================================================================= */
.persons-grid {
  display: grid;
  gap: 12px;
  /* min(343px, 100%) вместо просто 343px — единственное наше отступление от
     источника в этой строке, и оно вынужденное. У источника здесь minmax(343px,1fr),
     и при окне 320px колонка не сжимается: карточка остаётся 343px и страница
     получает 23px горизонтальной прокрутки (замерено, у источника защиты от этого
     нет — card.md §10 это и просил проверить). min() схлопывает минимум до ширины
     контейнера, когда места меньше. При 1200 оба варианта дают одно и то же:
     min(343px,1200px) = 343px → те же три колонки по 392px. */
  grid-template-columns: repeat(auto-fill, minmax(min(343px, 100%), 1fr));
}
@media (max-width: 1023.98px) { .persons-grid { gap: 8px; } }
@media (max-width: 599.98px)  { .persons-grid { gap: 0; } }

/* Лента карточек «Анкеты рядом» на странице анкеты и полосы главной:
   горизонтальная прокрутка, не сетка. */
.person-grid { display: flex; flex-wrap: nowrap; gap: 20px; }
@media (max-width: 1023.98px) { .person-grid { gap: 8px; } }

/* Полосы главной (вертикальный вариант person-card[variant=main]).
   Снято с источника дословно, index-Cwib1x1t.css:
     <=1023.98  НЕ сетка, а горизонтальная прокрутка: flex-wrap:nowrap + overflow-x
                со СПРЯТАННОЙ полосой прокрутки (три префикса, иначе на Windows
                появится серая полоса, которой у источника нет);
     >=1024     сетка 4 колонки, зазор 16;
     >=1440     сетка 5 колонок, зазор 8.
   Было: сетка на всех ширинах с двумя колонками до 1024 — карточки вставали
   столбиками вместо ленты, и это расходилось с источником. */
.card-block { display: grid; gap: 16px; grid-template-columns: repeat(4, 1fr); }
@media (min-width: 1440px) { .card-block { display: grid; gap: 8px; grid-template-columns: repeat(5, 1fr); } }
@media (max-width: 1023.98px) {
  .card-block {
    display: flex;
    flex-wrap: nowrap;
    gap: 8px;
    width: 100%;
    overflow-x: scroll;
    -ms-overflow-style: none;
    scrollbar-width: none;
  }
  .card-block::-webkit-scrollbar { display: none; }
}


/* =============================================================================
   2. КАРТОЧКА АНКЕТЫ
   Замеры: 392×278 при контейнере 1200 = (262 фото + 2×8 padding) по высоте.
   Высоту задаёт ФОТОГРАФИЯ, а не содержимое правой колонки (самое высокое
   содержимое — 252px, card.md §9.3). Поэтому НЕ height:278px, а min-height от
   фото: длинный тег тогда растянет карточку, а не вылезет из неё.
   ============================================================================= */
.person-card {
  display: grid;
  border-radius: 8px;
  --media-width: 224px;
  --content-width: calc(var(--media-width) - 8px);
}
@media (max-width: 1023.98px) { .person-card { --media-width: 168px; } }

/* Премиум: КРЕМОВАЯ ПОДЛОЖКА. Это главный визуальный признак премиума, и в
   ДИЗАЙН_ASHOO.md §4 его нет («карточка без фона» — верно только для обычной,
   card.md §9.2 п.4). #fff4d9 в светлой теме, #1a160f в тёмной. */
.person-card[premium="true"],
.person-card[data-premium="1"],
.person-card[data-premium="true"] { background: var(--Badges-PremiumBG); }

/* --- вариант listing: фото слева, данные справа ------------------------- */
.person-card[variant="listing"],
.person-card[data-variant="listing"] {
  width: unset;
  height: 100%;
  padding: 8px;
  border-radius: 16px;
  grid-template: "media info" 1fr / auto minmax(0, 1fr);
  column-gap: 8px;
  align-items: stretch;
}
@media (max-width: 599.98px) {
  /* на телефоне карточка во всю ширину без скруглений (card.md §9.2 п.3) */
  .person-card[variant="listing"],
  .person-card[data-variant="listing"] { border-radius: 0; }
}

.person-card .media { display: block; position: relative; }
.person-card[variant="listing"] .media,
.person-card[data-variant="listing"] .media {
  grid-area: media;
  width: 168px;
  height: 262px;
  /* Двухколоночность карточки не ломается даже на 320px: фото фиксированное,
     правая колонка сжимается. Проверка на узких экранах — в front.md. */
  flex: none;
}

/* --- вариант main: фото сверху, данные снизу (главная, «Анкеты рядом») --- */
.person-card[variant="main"],
.person-card[data-variant="main"] {
  grid-template: "media" "info" 1fr / 1fr;
  width: var(--media-width);
  flex: 0 0 var(--media-width);
  padding: 0;
  row-gap: 8px;
}
.person-card[variant="main"] .media,
.person-card[data-variant="main"] .media { grid-area: media; width: var(--media-width); height: 332px; }
@media (max-width: 1023.98px) {
  .person-card[variant="main"] .media,
  .person-card[data-variant="main"] .media { height: 252px; }
}

/* --- правая колонка ----------------------------------------------------- */
.person-card .info {
  grid-area: info;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
  overflow: hidden;
}
.person-card .info .title { display: flex; flex-direction: column; gap: 4px; min-width: 0; }


/* =============================================================================
   3. КАРУСЕЛЬ КАРТОЧКИ
   Три слайда-фотографии + ЧЕТВЁРТЫЙ промо-слайд с подписью «+N фотографий и
   M видео». Подпись лежит ВНУТРИ четвёртого слайда поверх размытой копии
   последнего снимка, а не висит над фотографией (card.md §9.2 п.10).
   Фотография скруглена на 8, карточка — на 16 (п.12).
   ============================================================================= */
.card-carousel {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-width: 0;
  height: 100%;
  border-radius: 8px;
}
.card-carousel .stage {
  position: relative;
  flex: auto;
  width: 100%;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  border-radius: inherit;
}
.card-carousel .viewport {
  width: 100%;
  height: 100%;
  overflow: hidden;
  touch-action: pan-y pinch-zoom;
  -webkit-user-select: none;
  user-select: none;
}
.card-carousel .container {
  display: flex;
  width: 100%;
  height: 100%;
  backface-visibility: hidden;
  /* Без JS карусель не листается, но слайды обязаны СТОЯТЬ В РЯД, а не
     сваливаться в столбец: тогда видно первый, а прокрутка пальцем работает
     штатно, как у источника на мобильном. */
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.card-carousel .container::-webkit-scrollbar { display: none; }
.card-carousel .slide {
  flex: 0 0 100%;
  min-width: 0;
  height: 100%;
  position: relative;
  scroll-snap-align: start;
}
.card-carousel .img { display: block; width: 100%; height: 100%; object-fit: cover; }
.card-carousel .img.pending { background: var(--Elements-Light-Gray); }

/* промо-слайд: размытая подложка + плёнка + подпись */
.promote-media-slide {
  position: relative;
  display: flex;
  overflow: hidden;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background: var(--Elements-Light-Gray);
}
.promote-media-slide .backdrop {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: blur(20px);
  transform: scale(1.15);
  pointer-events: none;
}
.promote-media-slide .shade { position: absolute; inset: 0; background: #00000059; }
.promote-media-slide .label {
  position: relative;
  max-width: calc(100% - 32px);
  padding: 4px 8px;
  border-radius: 8px;
  background: #00000080;
  color: var(--Special-White);
  font-size: var(--Font-Size-Body-Small, 14px);
  line-height: var(--Line-Height-Body-Small, 16px);
  font-weight: var(--Font-Weight-Regular, 400);
  text-align: center;
  text-wrap: balance;
}

/* Индикатор слайдов — НЕ точки, а полоски 2px во всю ширину фотографии.
   Число колонок задаётся инлайновым --dots-count из разметки. */
.card-carousel .dots,
.media-slider .dots {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 2px;
  display: grid;
  gap: 1px;
  pointer-events: none;
  grid-template-columns: repeat(var(--dots-count, 5), 1fr);
}
.card-carousel .dots > .item,
.media-slider .dots > .item { height: 2px; background-color: var(--Elements-Gray); }
.card-carousel .dots > .item[active="true"],
.card-carousel .dots > .item[data-active="true"],
.media-slider .dots > .item[active="true"],
.media-slider .dots > .item[data-active="true"] { background-color: var(--Special-Primary); }


/* =============================================================================
   4. НАКЛАДКИ ПОВЕРХ ФОТОГРАФИИ КАРТОЧКИ
   В карточке .top-health-icons абсолютные и колонкой; на СТРАНИЦЕ анкеты тот же
   класс стоит под галереей и в ряд (инлайновый flex-direction:row у источника).
   Базовое правило — в ash-tokens.css, здесь только абсолютный вариант.
   ============================================================================= */
.person-card .top-health-icons,
.card-carousel .top-health-icons {
  position: absolute;
  top: 0;
  left: 0;
  margin: 8px 0 0 8px;
  display: flex;
  flex-flow: column;
  align-items: flex-start;
  gap: 4px;
  z-index: 1;
}
.top-health-icons > img,
.top20-icon { width: auto; height: 20px; }

.favorite-btn {
  position: absolute;
  top: 0;
  right: 0;
  margin: 8px 8px 0 0;
  width: 34px;
  min-width: 34px;
  height: 34px;
  min-height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background-color: #00000080;
  color: #fff;
  cursor: pointer;
  z-index: 1;
}
.favorite-btn .h-icon { width: 18px; height: 18px; font-size: 18px; }
/* заглушка «избранного» в SSR — серый кружок того же размера */
.favorite-btn-skeleton { width: 34px; height: 34px; border-radius: 50%; }

.icon-container {
  position: absolute;
  bottom: 0;
  right: 0;
  margin: 0 8px 8px 0;
  display: flex;
  flex-wrap: nowrap;
  gap: 4px;
  z-index: 1;
}
.icon-container > div {
  display: flex;
  align-items: center;
  min-width: 20px;
  height: 20px;
  padding: 4px;
  border-radius: 4px;
  background: #00000080;
  color: var(--Special-White);
  font-size:   var(--font-size-label-m, 12px);
  line-height: var(--line-height-label-m, 16px);
  font-weight: var(--Font-Weight-Regular, 400);
}
.icon-container > div.with-count { gap: 2px; }
.icon-container .h-icon { width: 12px; height: 12px; font-size: 12px; }


/* =============================================================================
   5. ТЕКСТОВАЯ ЧАСТЬ КАРТОЧКИ
   ============================================================================= */

/* ИМЯ. Вес 700, а не 400. В ДИЗАЙН_ASHOO.md §3 сказано «имя не полужирное»,
   но в CSS источника .text-h3 = font-weight:var(--Font-Weight-Bold,700), токен
   --Font-Weight-Bold нигде не объявлен → работает запасное 700, и переопределения
   для .name нет (только .name{min-width:0}). Делаем КАК В CSS (card.md §9.2 п.5). */
.person-card-name {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex-wrap: nowrap;
  max-width: 100%;
  min-width: 0;
}
.person-card-name .name,
.person-card .info .name {
  min-width: 0;
  color: inherit;
  text-decoration: none;
  font-size:   var(--Font-Size-H3, 16px);
  line-height: var(--Line-Height-H3, 20px);
  font-weight: var(--Font-Weight-Bold, 700);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Город и район — синие ссылки через запятую, одной строкой с многоточием. */
.person-card .info .address {
  color: var(--Special-Accent);
  font-size:   var(--Font-Size-Body-Small, 14px);
  line-height: var(--Line-Height-Body-Small, 16px);
  font-weight: var(--Font-Weight-Regular, 400);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.person-card .info .address a { color: unset; text-decoration: none; }

/* Метро. У анкеты 12px, у САЛОНА 14px — разный размер по атрибуту kind. */
.metro-list {
  color: var(--Text-Secondary);
  font-size:   var(--font-size-label-m, 12px);
  line-height: var(--line-height-label-m, 16px);
  font-weight: var(--Font-Weight-Regular, 400);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.metro-list a { color: unset; text-decoration: none; white-space: nowrap; }
.metro-list[kind="person"],
.metro-list[data-kind="person"] {
  font-size:   var(--font-size-label-m, 12px);
  line-height: var(--line-height-label-m, 16px);
}
.metro-list[kind="salon"],
.metro-list[data-kind="salon"] {
  font-size:   var(--Font-Size-Body-Small, 14px);
  line-height: var(--Line-Height-Body-Small, 16px);
}

/* Параметры «19 лет · 155 см · 1 грудь». Перенос разрешён: на 320px строка
   уезжает на две, и в 262px по-прежнему укладывается (card.md §10). */
.person-card .info .properties {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
  font-size:   var(--Font-Size-Body-Small, 14px);
  line-height: var(--Line-Height-Body-Small, 16px);
  font-weight: var(--Font-Weight-Regular, 400);
}
.person-card .info .properties .prop { display: flex; flex-wrap: nowrap; align-items: center; gap: 4px; }
.gray-dot { width: 3px; height: 3px; border-radius: 50%; background: var(--Elements-Gray); flex: none; }

/* ЦЕНЫ. Сетка 2×2, а не одна строка (card.md §9.2 п.8): три цены занимают два
   ряда, четвёртая клетка — «Только выезд» либо «Есть экспресс».
   Число розовое и полужирное, знак рубля серый и обычный. */
.image-prices { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
.image-prices > div { display: flex; flex-wrap: nowrap; align-items: center; gap: 4px; height: 20px; }
.image-prices .price-icon {
  width: 16px;
  height: 16px;
  font-size: 16px;
  flex-shrink: 0;
  color: var(--Special-Primary);
}
.image-prices .price,
.person-card .price {
  color: var(--Special-Primary);
  font-size:   var(--Font-Size-Body-Small, 14px);
  line-height: var(--Line-Height-Body-Small, 16px);
  font-weight: var(--Font-Weight-Bold, 700);
}
.image-prices .symbol,
.person-card .symbol {
  color: var(--Text-Secondary);
  font-size:   var(--Font-Size-Body-Small, 14px);
  line-height: var(--Line-Height-Body-Small, 16px);
  font-weight: var(--Font-Weight-Regular, 400);
}
.travel-only {
  color: var(--Special-Primary);
  justify-content: start;
  padding: 2px;
  font-size:   var(--font-size-label-m, 12px);
  line-height: var(--line-height-label-m, 16px);
  font-weight: var(--Font-Weight-Regular, 400);
}

/* price-grid — компонент ЛИСТИНГА источника (.price-grid[data-v-60502c7b]).
   На странице анкеты его нет ни в одном из девяти сохранённых HTML
   (profile-page.md §10), но объявление переносим, раз оно есть в источнике. */
.price-grid { display: grid; gap: 32px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }

/* На странице анкеты рендер использует .price-grid как обойму тарифов и добавляет
   .column (стопка). Без этой оговорки работало правило листинга выше: «Днём» и
   «Ночью» вставали ДВУМЯ КОЛОНКАМИ рядом по 583px, а карточка тарифа сжималась до
   288 вместо 595. У источника периоды идут строками одна под другой — замер
   profile-10107.html: карточка 595x122. */
.price-grid.column {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* ТЕГИ. max-height:64px + overflow:hidden = ровно три ряда по 20px. Это и есть
   «сколько тегов видно» — числом оно не задаётся, в DOM уходят все. */
.person-card .info .tags {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  max-height: 64px;
  overflow-y: hidden;
}

/* Обычный тег — СВЕТЛО-СИНИЙ #e0e8ff. #3d4758 (--Badges-MainBG) — это фон
   ПРИОРИТЕТНОГО тега (starred), в ДИЗАЙН_ASHOO.md §2 он ошибочно назван
   «фоном обычного тега» (card.md §9.2 п.6). Сделав все теги тёмными,
   получите совсем другую карточку. */
.person-tag {
  display: inline-flex;
  align-items: center;
  background: var(--Badges-SecondBG);
  color: var(--Badges-TextTag);
  border-radius: 4px;
  padding: 2px 4px;
  text-decoration: none;
  font-size:   var(--font-size-label-m, 12px);
  line-height: var(--line-height-label-m, 16px);
  font-weight: var(--Font-Weight-Regular, 400);
}
.person-tag:hover { opacity: .8; }
/* На СТРАНИЦЕ анкеты тег крупнее по отступам: type="page" → padding 4px 8px */
.person-tag[type="page"],
.person-tag[data-type="page"] { padding: 4px 8px; }
.person-tag[starred="true"],
.person-tag[data-starred="true"] { background: var(--Badges-MainBG); color: var(--Special-White); }
.person-tag[premium="true"],
.person-tag[data-premium="true"] {
  background: var(--Badges-PremiumMain);
  color: var(--Special-Black);
  font-weight: var(--Font-Weight-Bold, 700);
}
/* Polee — авто-тег внешнего сервиса. Градиент взят из CSS источника; токен
   --Special-Polee в этом правиле НЕ используется (card.md П-4). */
.person-tag[polee="true"],
.person-tag[data-polee="true"] {
  color: var(--Special-White);
  background: linear-gradient(90deg, #c243fe 0%, #7481ff 100%);
}

/* КНОПКА. Текст — «Показать контакты» (148 из 148 карточек дампа), не «Контакты».
   В карточке высота 40, на странице анкеты — 44. Базовый стиль компонента у
   источника светло-синий (--Info-Back), сплошной синий даётся классами
   bg-special-accent text-white; здесь сразу синий, потому что в карточке он
   всегда такой. */
.card-contact-button {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: auto;
  height: 40px;
  padding: 12px 14px;
  border: 0;
  border-radius: 8px;
  cursor: pointer;
  background-color: var(--Special-Accent);
  color: #fff;
  font-family: inherit;
  font-size:   var(--Font-Size-Body-Small, 14px);
  line-height: var(--Line-Height-Body-Small, 16px);
  font-weight: var(--Font-Weight-Regular, 400);
  text-transform: none;
  text-wrap: nowrap;
}
/* На анкете и салоне кнопка крупнее и с текстом 16px */
.person-page .card-contact-button,
.salon-page .card-contact-button {
  height: 44px;
  font-size:   var(--Font-Size-Body, 16px);
  line-height: var(--Line-Height-Body, 20px);
}
/* КОНТАКТЫ САЛОНА. БАГ 37/48: у источника это кнопка в липкой полосе
   (.contact-sticky-block > .card-contact-button: 344x41 на 360, радиус 8,
   паддинг 12/14, белый текст на bg-special-accent). Мы вместо мёртвой кнопки
   «Показать контакты» печатаем живые ссылки — значит и одеваем их кнопками, а
   не списком с маркерами-точками и отступом 40px, как было.
   Высота 44 и кегль 16 — это размер кнопки НА СТРАНИЦЕ (см. правило
   .salon-page .card-contact-button выше); задаём явно, потому что у нашего
   <main> класса salon-page нет (его ставит шаблон, не роутер фасетов). */
.ash-salon-contacts ul {
  list-style: none;
  margin: 16px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.ash-salon-contacts .ash-contact { display: block; }
.ash-salon-contacts .ash-contact > a {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  padding: 12px 14px;
  border-radius: 8px;
  background-color: var(--Special-Accent);
  color: #fff;
  font-size:   var(--Font-Size-Body, 16px);
  line-height: var(--Line-Height-Body, 20px);
  text-decoration: none;
  text-wrap: nowrap;
}

/* СКРЫТЫЙ СПИСОК КОНТАКТОВ НА АНКЕТЕ (БАГ 23). Рендер пока его не печатает —
   правило стоит заранее, чтобы разметка появилась уже одетой. Открывает список
   скрипт, снимая атрибут hidden; [hidden] гасим сами, потому что display:flex
   ниже иначе перебил бы браузерное правило. */
.ash-contact-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.ash-contact-list[hidden] { display: none; }
.ash-contact-list .ash-contact > a { color: var(--Special-Accent); }

/* Плашка вместо кнопки: анкета снята с публикации либо контактов нет вовсе */
.contact-unavailable {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 41px;
  padding: 8px;
  border-radius: 8px;
  background: #c10015;
  color: #fff;
  font-size: var(--Font-Size-Body-Small, 14px);
  line-height: var(--Line-Height-Body-Small, 16px);
}
.contact-unavailable[kind="empty"],
.contact-unavailable[data-kind="empty"] {
  background: var(--Elements-Light-Gray);
  color: var(--Text-Secondary);
}


/* =============================================================================
   6. СТРАНИЦА АНКЕТЫ: КАРКАС ДВУХ КОЛОНОК
   left-content тянется, справа прилипшая колонка 388px с зазором 20.
   Разметки правой колонки в дампе нет — есть только размеры (profile-page.md
   §3.12), поэтому здесь объявлены классы, а наполнение за рендером.
   ============================================================================= */
.page-content { display: flex; flex-wrap: nowrap; gap: 20px; width: 100%; }
.page-content > .left-content { flex-grow: 1; min-width: 0; }
@media (max-width: 1023.98px) { .page-content { gap: 0; } }

.sticky-box { width: 388px; min-width: 310px; flex: 0 0 388px; }
@media (min-width: 600px)     { .sticky-box { min-width: 230px; } }
@media (min-width: 1023.98px) { .sticky-box { min-width: 388px; } }
@media (max-width: 1023.98px) { .sticky-box { display: none; } }
/* .sticky у источника — ГЛОБАЛЬНАЯ утилита без top (index-Cwib1x1t.css), а
   значения top живут под scope правой колонки анкеты. БАГ 56: наши глобальные
   top приклеивали крошки/фильтры на всех страницах — сузили до .page-content. */
.sticky { position: sticky; }
@media (min-width: 600px)     { .page-content .sticky { top: 44px; } }
@media (min-width: 1023.98px) { .page-content .sticky { top: 16px; } }

/* Прилипшая полоса контактов снизу (мобильный вид SSR источника).
   pointer-events выключены у обёртки и включены у содержимого — иначе
   невидимая полоса перехватывала бы клики по всей ширине экрана. */
.q-page-sticky {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 5000;
  display: flex;
  justify-content: center;
}
.q-page-sticky--shrink { pointer-events: none; }
.q-page-sticky--shrink > div { pointer-events: auto; display: inline-block; }
.q-page-sticky > div { width: 100%; }
/* БАГ 47: фон полосе даёт класс q-dark у источника. Держим и готовое правило
   .q-dark (рендер его допечатает), и фон прямо на .absolute-bottom — иначе до
   перерендера полоса просвечивает содержимым страницы. */
.q-page-sticky .absolute-bottom { position: static; background: var(--Background-BG); }
.q-dark { background-color: var(--Background-BG); }
@media (max-width: 1023.98px) {
  /* БАГ 21: полоса обязана встать НАД нижним меню (меню 50px). У источника то
     же смещение даёт Quasar трансформом translate(0,-50px); замер ashoo.me —
     полоса 737..794 при меню 794..844. */
  .q-page-sticky { bottom: 50px; }
}
/* КОНФЛИКТ БАГ 21 против БАГ 10, решён замером. БАГ 21 предлагал на десктопе
   гасить полосу целиком (у источника на 1280 её нет). ПРОВЕРИЛ — нельзя:
   у источника контакты на десктопе живут в правой липкой колонке, а у нас
   .sticky-box на странице анкеты НЕ ПЕЧАТАЕТСЯ вовсе (замер на 1024 и 1440:
   элемента нет). display:none убирал «Показать контакты» с десктопа насмерть —
   ровно то, о чём предупреждал БАГ 10. Поэтому мёртвое правило
   `.q-page-sticky.contacts-bar{display:none}` просто УДАЛЕНО (как и советует
   БАГ 10), полоса на десктопе остаётся, а кнопку «наверх» поднимает над ней
   правило body:has(.q-page-sticky) в ash-chrome.css.
   Гасить полосу на десктопе можно будет только после того, как рендер начнёт
   печатать правую колонку с контактами. */


/* =============================================================================
   7. ГАЛЕРЕЯ АНКЕТЫ И САЛОНА (media-slider / page-carousel)
   Пропорция кадра переключается: 4/5 на мобильном, 3/2 на десктопе.
   Под вписанным (contain) кадром лежит его же копия по cover с blur(20px) —
   так закрываются поля у вертикальных фотографий.
   ============================================================================= */
.media-slider {
  --arrow-size: 48px;
  --thumb-size: 52px;
  --thumbs-gap: 4px;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-width: 0;
  position: relative;
}
.media-slider .stage {
  position: relative;
  flex: auto;
  width: 100%;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  border-radius: inherit;
}
.media-slider .viewport {
  width: 100%;
  height: 100%;
  overflow: hidden;
  touch-action: pan-y pinch-zoom;
  -webkit-user-select: none;
  user-select: none;
}
.media-slider .container {
  display: flex;
  width: 100%;
  height: 100%;
  backface-visibility: hidden;
  /* см. комментарий у .card-carousel .container: без JS листаем прокруткой */
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.media-slider .container::-webkit-scrollbar { display: none; }
.media-slider .slide {
  flex: 0 0 100%;
  min-width: 0;
  height: 100%;
  position: relative;
  scroll-snap-align: start;
}

.media-slider .arrow {
  width: var(--arrow-size);
  height: var(--arrow-size);
  min-width: var(--arrow-size);
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  border-radius: 50%;
  background: var(--Elements-Light-Gray);
  color: var(--Special-Primary);
}
.media-slider .arrow.prev { left: 16px; }
.media-slider .arrow.next { right: 16px; }
@media (max-width: 1023.98px) { .media-slider .arrow { display: none; } }

.media-slider .counter {
  position: absolute;
  bottom: 16px;
  left: 16px;
  padding: 2px 6px;
  border-radius: 4px;
  background: #00000080;
  color: var(--Special-White);
  font-size:   var(--font-size-label-m, 12px);
  line-height: var(--line-height-label-m, 16px);
  pointer-events: none;
  z-index: 2;
}

/* Лента миниатюр 52×52. Центрируется, пока влезает — это делают
   margin:auto у первого и последнего ребёнка (profile-page.md §9 п.8). */
.media-slider .thumbs-wrap {
  width: 100%;
  flex: none;
  position: relative;
  height: calc(var(--thumb-size) + var(--thumbs-gap));
}
.media-slider .thumbs {
  position: absolute;
  inset: 0;
  display: flex;
  gap: 2px;
  padding-top: var(--thumbs-gap);
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.media-slider .thumbs::-webkit-scrollbar { display: none; }
.media-slider .thumb {
  flex: 0 0 var(--thumb-size);
  width: var(--thumb-size);
  height: var(--thumb-size);
  padding: 0;
  overflow: hidden;
  cursor: pointer;
  border-radius: 4px;
  border: 2px solid transparent;
  background: var(--Elements-Light-Gray);
}
.media-slider .thumb:first-child { margin-left: auto; }
.media-slider .thumb:last-child  { margin-right: auto; }
.media-slider .thumb.active { border-color: var(--Special-Primary); }
.media-slider .thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

.media-slider.fullscreen {
  position: fixed;
  inset: 0;
  margin: 0;
  padding: 0;
  width: auto;
  max-width: none;
  height: auto;
  background: #000;
  overflow: hidden;
  z-index: 9000;
}
.media-slider.fullscreen .thumbs-wrap {
  --thumbs-gap: 8px;
  background: var(--Background-BG);
  height: calc(var(--thumb-size) + var(--thumbs-gap) * 2);
}
.media-slider.fullscreen .thumbs { padding: var(--thumbs-gap) 16px; }

/* --- кадр -------------------------------------------------------------- */
.page-carousel .frame {
  width: 100%;
  position: relative;
  overflow: hidden;
  background: var(--Elements-Light-Gray);
}
/* Границы 1023.98 / 1023.98 у источника перекрываются на один пиксель —
   это его дефект. У нас честная пара 1023.98 / 1024. */
@media (max-width: 1023.98px) { .page-carousel .frame { aspect-ratio: 4 / 5; } }
@media (min-width: 1024px)    { .page-carousel .frame { aspect-ratio: 3 / 2; } }
.page-carousel .image,
.page-carousel .video { position: absolute; inset: 0; width: 100%; height: 100%; }
.page-carousel .image { object-fit: contain; }
.page-carousel .video { object-fit: contain; background: #000; }
.page-carousel .backdrop {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: blur(20px);
  transform: scale(1.15);
  pointer-events: none;
}
.page-carousel.fullscreen .frame { aspect-ratio: auto; height: 100%; background: #000; }

.page-carousel .top-left,
.page-carousel .top-right,
.page-carousel .bottom-right { position: absolute; display: flex; gap: 8px; z-index: 2; }
.page-carousel .top-left     { top: 16px; left: 16px; flex-direction: column; align-items: flex-start; gap: 4px; }
.page-carousel .top-right    { top: 16px; right: 16px; flex-wrap: nowrap; }
.page-carousel .bottom-right { bottom: 16px; right: 16px; }
/* в галерее кнопка «избранное» крупнее, чем в карточке листинга */
.page-carousel .favorite-btn,
.page-carousel .favorite-btn-skeleton {
  position: static;
  margin: 0;
  width: 40px;
  min-width: 40px;
  height: 40px;
  min-height: 40px;
}


/* =============================================================================
   8. СТРАНИЦА АНКЕТЫ: ШАПКА БЛОКА (пометки, H1, география, отзывы)
   .top-health-icons на анкете идёт В РЯД: у источника это инлайновый стиль
   поверх колоночного правила. Инлайн-стили мы не печатаем, поэтому ряд задан
   классом-модификатором.
   ============================================================================= */
.top-health-icons[row],
.top-health-icons[data-row],
.person-page > .page-content .top-health-icons:not([class*="absolute"]) { flex-direction: row; }
.person-page h1 { display: flex; flex-wrap: nowrap; align-items: center; justify-content: space-between; gap: 8px; }
/* Ссылка «💬 N» под H1 */
.comments-link { display: flex; align-items: center; gap: 4px; color: var(--Text-Primary); }
.comments-link .h-icon { font-size: 20px; }


/* =============================================================================
   9. ТАРИФЫ
   Карточка тарифа — сетка 2 столбца × 3 ряда «auto minmax(0,1fr)».
   container-query: при ширине карточки ≤155px иконка падает с 44 до 32, а
   подпись с 20px на 16px — без этого «2 часа» переносится (profile-page.md §9 п.6).
   Цвет фона привязан ТОЛЬКО к строке: день жёлтый, ночь тёмно-синяя.
   ============================================================================= */
.tariff-grid {
  display: grid;
  /* Замер источника: карточка 595x122, колонки 285.5px 285.5px — то есть РАВНЫЕ
     половины, а не «иконка + остаток». Было auto minmax(0,1fr): подпись «1 час»
     прижималась к иконке вместо середины карточки. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  container-type: inline-size;
  /* align-items НЕ задаём: у источника ячейки растянуты по высоте строки
     (замер: «1 час» 50px под иконку 50px, подписи по 20px), а content внутри
     каждой ячейки центрируется своим же flex/flex-center. С align-items:center
     ячейки сжимались до высоты текста — 24 и 16 вместо 50 и 20. */
}
/* Иконка периода: у источника 50x50 (замер), было 44. */
.tariff-grid .tariff-icon { width: 50px; height: 50px; }

/* Выравнивание внутри карточки тарифа. Источник ставит это инлайновыми
   justify-self на каждой ячейке (profile-10107.html):
     [иконка]            [«1 час», justify-self:end]
     [«У меня», start]   [цена, end]
     [«У тебя*», start]  [цена, end]
   то есть подписи прижаты влево, цены и заголовок периода — вправо, к середине
   карточки. Без этого все ячейки растягивались на всю колонку и текст стоял по
   центру: расхождение видно сразу. Делаем классами, а не инлайном. */
.tariff-grid > :nth-child(even)          { justify-self: end; }
.tariff-grid > :nth-child(odd):not(img)  { justify-self: start; }
.tariff-grid .tariff-title { white-space: nowrap; }
@container (width <= 155px) {
  .tariff-grid .tariff-icon { width: 32px; height: 32px; }
  .tariff-grid .tariff-title {
    font-size:   var(--Font-Size-H3, 16px);
    line-height: var(--Line-Height-H3, 20px);
    font-weight: var(--Font-Weight-Bold, 700);
  }
}
/* Запасной путь для браузеров без container queries: та же правка по
   ширине окна. 620px — ширина, при которой карточка тарифа падает до ~150px. */
@supports not (container-type: inline-size) {
  @media (max-width: 620px) {
    .tariff-grid .tariff-icon { width: 32px; height: 32px; }
    .tariff-grid .tariff-title {
      font-size:   var(--Font-Size-H3, 16px);
      line-height: var(--Line-Height-H3, 20px);
      font-weight: var(--Font-Weight-Bold, 700);
    }
  }
}

/* Способы оплаты: подпись слева, чипы прижаты вправо и не переносятся. */
.payment-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
}
.payment-row__label {
  font-size:   var(--Font-Size-Body-Small, 14px);
  line-height: var(--Line-Height-Body-Small, 16px);
  font-weight: var(--Font-Weight-Regular, 400);
}
.payment-chips { display: flex; flex-wrap: nowrap; flex-shrink: 0; justify-content: flex-end; gap: 4px; }
.payment-chip {
  background: var(--Badges-SecondBG);
  color: var(--Badges-TextTag);
  border-radius: 4px;
  padding: 4px 8px;
  white-space: nowrap;
}

/* «Контактов в час» / «Дорога на выезде» / «Экспресс»: подпись — значение.
   Нечётные ячейки обычные, чётные прижаты вправо и полужирные. */
.price-options-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
}
.price-options-grid > div:nth-child(odd) {
  font-size:   var(--Font-Size-Body-Small, 14px);
  line-height: var(--Line-Height-Body-Small, 16px);
  font-weight: var(--Font-Weight-Regular, 400);
}
.price-options-grid > div:nth-child(2n) {
  text-align: right;
  font-size:   var(--Font-Size-H4, 14px);
  line-height: var(--Line-Height-H4, 20px);
  font-weight: var(--Font-Weight-Bold, 700);
}


/* =============================================================================
   10. ПАРАМЕТРЫ
   Две колонки на десктопе, одна до 1024. Каждая строка подчёркнута тонкой
   линией --Border-Primary. Значения внутри строки — через запятую из CSS
   (.comma-separated в ash-tokens.css), а не из текста.
   ============================================================================= */
.property-block { display: grid; grid-template-columns: repeat(2, 1fr); column-gap: 16px; }
@media (max-width: 1023.98px) { .property-block { grid-template-columns: 1fr; } }
.property {
  display: flex;
  /* БАГ 43: именно nowrap, и явно. Класс .no-wrap из разметки не спасает —
     .property идёт по каскаду позже. С wrap значение падало на вторую строку и
     блок раздувался до 750px вместо 430. */
  flex-wrap: nowrap;
  justify-content: space-between;
  gap: 12px;
  border-bottom: 1px solid var(--Border-Primary);
  margin-bottom: 10px;
  padding-bottom: 8px;
}
.property > :first-child { color: var(--Text-Secondary); }
.property a { color: var(--Text-Primary); }
/* БАГ 43: правило источника .property>div{text-align:left;width:50%} — ровно
   оно делит строку пополам. space-between и gap выше остаются безвредными:
   при 50%+50% свободного места не остаётся. */
.property > div { width: 50%; text-align: left; }


/* =============================================================================
   11. ОПИСАНИЕ И УСЛУГИ
   .html-content — сырой HTML анкеты. Свёртка ровно в 4 строки и «Подробнее»
   есть ВСЕГДА, независимо от длины текста (profile-page.md §3.6).
   ============================================================================= */
.html-content { overflow-wrap: anywhere; }
/* базовое .html-content a — в ash-tokens.css (цвет + подчёркивание) */
.html-content p:last-child { margin-bottom: 0; }
.html-content img { max-width: 100%; height: auto; }
.show-more { color: var(--Special-Accent); cursor: pointer; }

/* УСЛУГИ. Это НЕ grid и НЕ flex, а многоколоночный текст: группы разной длины
   «плывут» по колонкам и не разрываются. Повторить надо именно column-count —
   иначе сетка выстроится ровно и это сразу видно. */
.feature-grid { column-count: 3; column-gap: 16px; width: 100%; }
@media (max-width: 1023.98px) { .feature-grid { column-count: 2; } }
/* Своего правила «одна колонка ниже 600px» здесь НЕТ намеренно: у источника
   на телефоне колонок по-прежнему две, и это решение сходства, а не удобства.
   Если владелец захочет одну — дописать
   @media (max-width:599.98px){ .feature-grid{column-count:1} } */
.feature-grid .group { display: flex; flex-direction: column; gap: 8px; break-inside: avoid; }
.feature-grid .group .item { display: flex; flex-flow: row; align-items: flex-start; }
.feature-grid .group .item:last-child { margin-bottom: 16px; }
.feature-grid .group .item .icon {
  display: flex;
  justify-content: center;
  align-items: center;
  /* Иконка услуги у всех услуг ОДНА — галочка #tick-02 (350 из 350 проверенных
     элементов). Тематических иконок у услуг нет (profile-page.md §3.8). */
  color: var(--Special-Primary);
  font-size: 24px;
  flex: none;
}
.feature-grid .group .item .icon .h-icon { font-size: 24px; }
.feature-grid .group .item .info { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 0; }
/* !important обязателен: в ash-tokens.css действует глобальное
   a{text-decoration:none!important}, и без него подчёркивание названий услуг
   не появляется (замерено: было computed «none»). У источника здесь ровно та же
   причина и ровно то же !important. */
.feature-grid .group .item .info .title { flex-grow: 1; text-decoration: underline !important; }
/* max-width:100% + overflow-wrap — добор к правилу источника.
   У источника здесь только align-self:flex-start, а из-за него блок получает
   собственную ширину по содержимому и НЕ ограничен колонкой: замерено на
   анкете 10350 при окне 390px — примечание «💰 (с твоей подружкой…)» выросло
   до 178px в колонке 147px и вытолкнуло страницу на 15px вправо, то есть
   появилась горизонтальная прокрутка. Выравнивание влево сохранено. */
.feature-grid .group .item .info .comment {
  color: var(--Special-Primary);
  align-self: flex-start;
  max-width: 100%;
  overflow-wrap: anywhere;
}
.feature-grid .group .item .info .title { max-width: 100%; overflow-wrap: anywhere; }
.feature-grid .group .item .info .comment.plain { color: inherit; }
/* У источника у .item НЕТ gap — галочка стоит вплотную к тексту, отбив даёт
   только поле глифа внутри viewBox 24×24. Это поведение источника, не ошибка. */


/* =============================================================================
   12. КАРТА
   Содержимое рисует Leaflet на клиенте; здесь только контейнер, чтобы блок
   не прыгал после загрузки карты.
   ============================================================================= */
div.map-container {
  --map-drawer-width: 375px;
  height: calc(100vh - 200px);
  min-height: 550px;
  border: 1px solid var(--Border-Primary);
  border-radius: 16px;
  overflow: hidden;
}
/* БАГ 38: у источника карта задана ПАРОЙ классов — .person-page-map и
   .salon-page-map. Без второго карта салона на телефоне не раздвигается
   на всю ширину и сохраняет скругление. */
.person-page-map.map-container--map,
.salon-page-map.map-container--map { border-radius: 8px; }
@media (max-width: 599.98px) {
  .person-page-map,
  .salon-page-map {
    margin-left: -16px;
    margin-right: -16px;
    border-radius: 0 !important;
    width: calc(100% + 32px) !important;
  }
}
.osm-attribution-control {
  background: var(--Background-Layer1);
  padding: 2px 5px;
  font-size: 11px;
  border-top-left-radius: 8px;
  margin: 0 !important;
}


/* =============================================================================
   13. ОТЗЫВЫ
   Ответ анкеты — тот же блок, но сдвинут на 32px и на фоне --Info-Back.
   Подписан ИМЕНЕМ АНКЕТЫ с приставкой «Отвечает •» (profile-page.md §3.10).
   ============================================================================= */
.person-comment {
  display: flex;
  flex-direction: column;
  padding: 16px;
  border-radius: 8px;
  background: var(--Elements-Light-Gray);
}
/* БАГ 41: !important обязателен — у источника он есть, и без него утилита
   .bg-elements-light-gray с самого блока перебивает фон ответа. */
.person-comment[answer="true"],
.person-comment[data-answer="true"] { margin-left: 32px; background: var(--Info-Back) !important; }
/* Сдвиг ответа НЕ уменьшаем на телефоне: у источника он 32px на любой ширине.
   Проверено замером — при 358px содержимого остаётся 326px, текст читается. */
.person-comment .text { overflow-wrap: anywhere; }
.like-btn { color: var(--Text-Secondary); background: transparent; border: 0; cursor: pointer; }
.like-btn[bold="true"],
.like-btn[data-bold="true"],
.like-btn:hover { color: var(--Icon-Primary); }
.comments-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 8px;
  color: var(--Text-Secondary);
}


/* =============================================================================
   14. САЛОН
   Карточка салона ПРОЩЕ карточки анкеты: одна статичная картинка, нет карусели,
   цен, тегов, параметров и счётчиков — зато есть описание на две строки
   (salon-page.md §5.3). Переиспользовать карточку анкеты нельзя: из 15 отличий
   совпадают только заголовок и география.
   ============================================================================= */
.salon-list { display: flex; flex-wrap: nowrap; gap: 20px; }
@media (max-width: 1023.98px) { .salon-list { gap: 8px; } }

/* Сетка листинга салонов. Точной ширины карточки в дампе нет: её правила лежат
   в salon-card-main-*.css, который в набор не попал (salon-page.md §5.2).
   Берём ту же формулу, что у анкет, — она даёт 3 колонки при 1200. */
.salons-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(min(343px, 100%), 1fr)); }
@media (max-width: 1023.98px) { .salons-grid { gap: 8px; } }
@media (max-width: 599.98px)  { .salons-grid { gap: 0; } }

.salon-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  border-radius: 16px;
  padding: 8px;
  min-width: 0;
}
/* БАГ 39/50: нарезка НАЙДЕНА в чанках источника (salon-card-main-DOHYKXKU.css и
   salon-card-listing-CBISmo7C.css, оба один в один): пропорция 3/2 стоит на
   .image-block, а .card-img тянется в 100%/100% по cover. Прежние 3/4 на самом
   снимке давали на телефоне фото 374x499 — полэкрана под один кадр. */
.salon-card .image-block {
  position: relative;
  aspect-ratio: 3 / 2;
  width: 100%;
  border-radius: 8px;
  overflow: hidden;
}
.salon-card .card-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.salon-card .title {
  font-size:   var(--Font-Size-H3, 16px);
  line-height: var(--Line-Height-H3, 20px);
  font-weight: var(--Font-Weight-Bold, 700);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* БАГ 44: класса card-width в нашей разметке карточки салона нет, поэтому
   правило было мёртвым, а длинный заголовок/строка метро вылезали за карточку
   (замер: .title 179px при карточке 168px). Цепляемся за реальную колонку —
   и отдельно за её детей, иначе заголовок всё равно вылезает. */
.salon-card .card-width      { max-width: 100%; min-width: 0; }
.salon-card > .column        { max-width: 100%; min-width: 0; }
.salon-card > .column > *    { max-width: 100%; min-width: 0; }
/* CTA салона — не кнопка, а текст «Подробнее», прижатый к низу */
.salon-card .more { margin-top: auto; color: var(--Special-Accent); }

/* Вертикальная карточка салона в горизонтальной полосе (.salon-list).
   БАГ 39: числа взяты из чанка источника salon-card-main-DOHYKXKU.css —
   285px и 213px до 1024. Раньше тут стояла --media-width: это переменная
   .person-card, на .salon-card-main она не наследуется, работал только
   фолбэк 224/168 — хрупко и не совпадало с источником. */
.salon-card-main { flex: 0 0 285px; width: 285px; }
@media (max-width: 1023.98px) { .salon-card-main { flex-basis: 213px; width: 213px; } }
/* БАГ 39/50/64: в СЕТКЕ ширину диктует ячейка, а не карточка. Рендер печатает
   salon-card-main и для листинга, поэтому в сетке фиксированную ширину снимаем,
   иначе карточка 213px болтается в ячейке 390px. Вес (0,2,0) перебивает и
   правило выше, и его медиа-вариант — !important не нужен. */
.salons-grid > .salon-card-main { flex: initial; flex-basis: auto; width: auto; }

/* Страница салона: «Время работы» полужирным, ростер анкет — если он есть.
   Ростер в дампе ПУСТ (salon-page.md §2), поэтому блок рисуется только при
   непустом списке; заглушки нет намеренно. */
.salon-roster { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(min(343px, 100%), 1fr)); }
@media (max-width: 1023.98px) { .salon-roster { gap: 8px; } }


/* =============================================================================
   14a. ПУСТАЯ ВЫДАЧА  (БАГ 35)
   Правил на .ash-empty не было вовсе, блок печатался голым текстом без отступов
   и без иерархии. У источника своего класса под это нет (пустых витрин в дампе
   нет), поэтому держим минимум: отбивка, центровка, приглушённая подсказка.
   Ни фона-карточки, ни padding-шортхенда: блок печатается как <div class="main
   ash-empty">, а `padding` у .main (16px на узких, 8px на 1024, 0 на 1440)
   перебился бы шортхендом отсюда и обойма потеряла бы отбив от кромки экрана.
   Поэтому только вертикальный отступ логической записью padding-block.
   ============================================================================= */
.ash-empty {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-block: 24px;
  text-align: center;
  color: var(--Text-Primary);
}
.ash-empty > p { margin: 0; }
.ash-empty__title {
  font-size:   var(--Font-Size-H3, 16px);
  line-height: var(--Line-Height-H3, 20px);
  font-weight: var(--Font-Weight-Bold, 700);
}
.ash-empty__hint { color: var(--Text-Secondary); }


/* =============================================================================
   15. ХВОСТЫ, БЕЗ КОТОРЫХ БЛОКИ «ПЛЫВУТ»
   ============================================================================= */

/* Заголовок полосы «Салоны» / «Анкеты рядом» + ссылка «Все» справа */
.section-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.show-all-btn,
.show-all-bottom { color: var(--Special-Accent); }
/* БАГ 72/73: правило один в один из index-Cwib1x1t.css источника, там со
   scope-атрибутом [data-v-a80ba064] — у нас scope не нужен, класс встречается
   только в строке счётчика главной. Без правила это был неокрашенный div 0x0. */
.green-dot { background: var(--Special-Green); border-radius: 50%; width: 8px; height: 8px; }

/* БАГ 61: у источника «Все» — 14/16 и прижата вправо своими margin:auto.
   Отдельным правилом, а не расширением строки выше: там же красится
   .show-all-bottom, которой ни размер 14px, ни margin-left:auto не нужны. */
.show-all-btn {
  margin-left: auto;
  margin-block: auto;
  font-size:   var(--Font-Size-Label, 14px);
  line-height: var(--Line-Height-Label, 16px);
  font-weight: var(--Font-Weight-Regular, 400);
}
/* БАГ 63: у источника кнопка под полосой — 327x41 и кегль 16px
   (.show-all-bottom{border-radius:8px;width:327px} + базовый .q-btn).
   height:40px заменён на min-height:41px, иначе текст 16px её распирает. */
.show-all-bottom {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 327px;
  max-width: 100%;
  min-height: 41px;
  /* padding как у базового .q-btn источника (4px 16px): с прежними 12px кнопка
     выходила 46px вместо 41 — min-height её уже не сдерживал. */
  padding: 4px 16px;
  border: 1px solid var(--Special-Primary);
  border-radius: 8px;
  color: var(--Special-Primary);
  font-size: var(--Font-Size-Body, 16px);
}

/* Плашка «анкета недоступна» поверх карточки/галереи. В дампе примера нет
   (card.md П-7), поэтому правила ровно те, что объявлены в CSS источника. */
.unavailable-overlay { position: absolute; inset: 0; background: #0009; color: #fff; z-index: 3; }
.unavailable-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px;
  border-radius: 8px;
  background: #0009;
  color: #fff;
}
