/* Шрифты — свои, а не с Google Fonts: ни внешних доменов в <head>, ни
   блокирующего чужого CSS. Переменные начертания, кириллица и латиница
   отдельными файлами: браузер берёт только нужный диапазон. */
@font-face{font-family:'Inter';font-style:normal;font-weight:400 600;font-display:swap;src:url("../fonts/inter-cyr.de93fdc85e3d.woff2") format('woff2');unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116}
@font-face{font-family:'Inter';font-style:normal;font-weight:400 600;font-display:swap;src:url("../fonts/inter-lat.260c81a4759b.woff2") format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Playfair Display';font-style:italic;font-weight:500 600;font-display:swap;src:url("../fonts/playfair-it-cyr.de347c8e5dcd.woff2") format('woff2');unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116}
@font-face{font-family:'Playfair Display';font-style:italic;font-weight:500 600;font-display:swap;src:url("../fonts/playfair-it-lat.2175449f9d44.woff2") format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Playfair Display';font-style:normal;font-weight:500 600;font-display:swap;src:url("../fonts/playfair-cyr.66a1a9a1a310.woff2") format('woff2');unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116}
@font-face{font-family:'Playfair Display';font-style:normal;font-weight:500 600;font-display:swap;src:url("../fonts/playfair-lat.ef05b30d6e5c.woff2") format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
/* Оформление — набор токенов Rouge & Or поверх дизайн-системы Nocturne.
   Так называется сам набор из пакета дизайна; площадка называется
   «На массаж», а Rouge & Or — имя салона-арендатора внутри неё.
   Nocturne даёт шкалы (плотность 0,7×, скругления, тени) и грамматику
   компонентов; тема проекта переопределена на светлую по прямому указанию
   заказчика: белая бумага, гранатовый акцент, календула на бонусах и рейтинге,
   лиловый на закрытых каналах, мята на живых событиях.
   Токены взяты дословно из design/design_handoff_rouge_et_or/tokens.json —
   свои значения не выдумываются, это требование спецификации.
   Цена по-прежнему не выделяется цветом сверх положенного акцента: связь цены
   с просмотрами −0,07, при равном месте дороже значит медленнее (−9,74). */
:root{color-scheme:light;
  /* --- набор Rouge & Or: цвет --- */
  --paper:#ffffff;--ro-ink:#4a2a26;--ro-ink2:#8a625c;--hair:#e7e0de;
  --rouge:#d24a45;--rouge-deep:#9e2f2c;
  --marigold:#e5a63c;--lilac:#8f7fd8;--lilac-ink:#544399;--mint:#39b98b;
  --verify-bg:#dcf5ea;--verify-ink:#1f6b52;
  --fresh-bg:#fbeed6;--fresh-ink:#7a5416;
  --bonus-bg:#fdf8f1;--bonus-edge:#eadfc9;--telegram:#2AABEE;
  /* «Стол» под листом страницы: тёплый песочный, на полтона темнее бумаги. */
  --desk:oklch(.955 .012 30);
  /* --- шкалы Nocturne, плотность 0,7× --- */
  --space-1:2.8px;--space-2:5.6px;--space-3:8.4px;--space-4:11.2px;
  --space-6:16.8px;--space-8:22.4px;
  --radius-sm:4px;--radius-md:8px;--radius-lg:14px;--radius-pill:100px;
  --shadow-pill:0 2px 8px rgba(90,20,30,.14);
  --font-display:"Playfair Display",Georgia,serif;
  --font-body:"Inter",system-ui,-apple-system,"Segoe UI",sans-serif;

  /* --- смысловые имена каталога поверх токенов проекта --- */
  --bg:var(--paper);--card:var(--paper);--card2:var(--paper);
  --line:var(--hair);--ink:var(--ro-ink);--muted:var(--ro-ink2);
  --accent:var(--rouge);--on-accent:var(--paper);
  /* Акцентный текст на белом берёт глубокий гранат: у основного граната
     контраст к бумаге ниже, чем нужно строке в 12 пунктов. */
  --accent-text:var(--rouge-deep);
  /* Оценка — календула, как задано токенами: «бонусы, рейтинг, с 19:00». */
  --ok-bg:var(--fresh-bg);--ok-ink:var(--fresh-ink);
  --warn:var(--rouge)}
*{box-sizing:border-box}
/* Спрайт значков лежит в потоке нулевым размером: `display:none` убил бы
   ссылки на символы в Safari. Значок наследует цвет и кегль места вставки. */
.sprite{position:absolute;width:0;height:0;overflow:hidden}
.ico{width:1em;height:1em;fill:currentColor;flex:none;vertical-align:-.12em}
/* Атрибут `hidden` весит меньше любого класса: `.btn{display:inline-flex}`
   показывал спрятанную кнопку. Правило сильнее — иначе прятать нечем. */
[hidden]{display:none!important}
/* Фон окна — тёплый песочный «стол», страница лежит на нём белым листом. */
body{margin:0;background:var(--desk);color:var(--ink);
  font:15px/1.55 var(--font-body);-webkit-font-smoothing:antialiased}
/* Ширина в процентах, а не `auto`-поля: на 1280 лист иначе прилипал к краям
   окна, а скруглённые углы срезались — это читалось как обрезанная страница. */
.page{width:calc(100% - 48px);max-width:1440px;margin:24px auto;
  background:var(--paper);border-radius:20px;
  box-shadow:0 1px 3px rgba(90,20,30,.05),0 18px 48px rgba(90,20,30,.07);
  /* `clip`, а не `hidden`: `hidden` делает лист контейнером прокрутки, и все
     липкие панели внутри — фильтры каталога, панель записи, сводка — молча
     перестают липнуть. Проверено замером: фильтры уезжали вверх вместе со
     страницей. `clip` срезает углы, но контейнером прокрутки не становится. */
  overflow:clip}
/* Ниже 1200 лист раскрывается на всю ширину: рамка в четыре пикселя по краям
   экрана — не поля, а мусор, и на телефоне она отъедает те самые пиксели. */
@media (max-width:1200px){
  .page{width:100%;max-width:none;margin:0;border-radius:0;box-shadow:none}
}
/* Заголовки — Playfair Display весом 500. Жирнее не набираются: иерархия
   строится размером и воздухом, это правило дизайн-системы. */
/* Playfair по умолчанию набирает цифры минускульными: «1000 бонусов» выходило
   «1ооо», а «24 мастера» — с приплюснутой двойкой. В заголовках нужны
   прописные цифры: в справочнике их больше, чем слов. */
h1,h2,h3,h4,h5,h6{font-family:var(--font-display);font-weight:500;
  line-height:1.05;letter-spacing:-.015em;margin:0 0 var(--space-2);
  font-variant-numeric:lining-nums}
/* Все числа сайта выровнены по разрядам: в справочнике их больше, чем слов. */
.num,.bignum,.hub-station b,.chip-rating,.reviews,.price{font-variant-numeric:tabular-nums}
h1{font-size:clamp(34px,5.4vw,58px);line-height:1;margin:var(--space-8) 0 var(--space-3);
  text-wrap:balance}
h2{font-size:clamp(22px,3vw,34px);margin:calc(var(--space-8) * 1.6) 0 var(--space-3)}
h3{font-size:20px}
a{color:var(--accent);text-underline-offset:3px}
::selection{background:color-mix(in srgb,var(--color-accent) 30%,transparent)}
/* Контейнер страницы — один на весь сайт. Без максимума на мониторе 2560
   ряд из пяти карточек растягивается в нечитаемую ленту, а строки текста
   уходят за комфортные 75 знаков. Поля 40/24/16 по ширине окна. */
/* Боковое поле контейнера — переменной: полноширинные блоки внутри (карта)
   разворачиваются ровно на него, и при смене поля им ничего не надо править. */
.wrap{--wrap-pad:40px;
  width:100%;max-width:1240px;margin-inline:auto;
  padding:20px var(--wrap-pad) 60px;box-sizing:border-box}
@media (max-width:1024px){.wrap{--wrap-pad:24px}}
@media (max-width:640px){.wrap{--wrap-pad:16px}}
/* Полоса шапки и фон подвала красятся во всю ширину, их содержимое стоит по
   тем же полям, что и контент. Внешний блок задаёт фон, внутренний держит
   содержимое — не наоборот. */
.chrome{background:var(--paper);border-bottom:1px solid var(--line)}
/* Полоса доверия — первая строка шапки: гость узнаёт про проверку раньше,
   чем видит первую анкету. Занимает всю строку сетки шапки. */
.trustbar{flex:1 0 100%;margin:0;padding:6px 0 0;font:500 10px/1.4 var(--font-body);
  letter-spacing:.06em;text-transform:uppercase;color:var(--verify-ink)}
.nav-item{font-size:13px;color:var(--muted);text-decoration:none;white-space:nowrap}
.nav-item:hover{color:var(--accent-text)}
/* Поле поиска в шапке. Узкое по умолчанию и расширяется в фокусе: на широком
   экране оно не должно спорить с кнопкой записи, а в работе — быть удобным. */
.navsearch{display:flex;align-items:center;gap:0;margin-left:auto}
.navsearch input{width:118px;transition:width .18s ease;font-size:13px;
  padding:5px 9px;border:1px solid var(--line);border-right:0;
  border-radius:var(--radius-pill) 0 0 var(--radius-pill);
  background:var(--surface);color:var(--ink)}
.navsearch input:focus{width:182px;outline:none;border-color:var(--accent)}
.navsearch button{display:flex;align-items:center;padding:5px 9px;cursor:pointer;
  border:1px solid var(--line);border-left:0;
  border-radius:0 var(--radius-pill) var(--radius-pill) 0;
  background:var(--surface);color:var(--muted)}
.navsearch button:hover{color:var(--accent-text)}
/* На телефоне поле сжимается до иконки и раскрывается по нажатию: строка
   поиска рядом с логотипом не помещается, но убирать поиск нельзя — имя
   мастера называют вслух и набирают именно с телефона. */
@media (max-width:900px){
  .navsearch{margin-left:auto}
  .navsearch input{width:0;padding-left:0;padding-right:0;border-width:0;
    opacity:0;pointer-events:none}
  .navsearch input:focus{width:150px;padding:5px 9px;border-width:1px;opacity:1;
    pointer-events:auto}
  .navsearch.open input{width:150px;padding:5px 9px;border-width:1px;opacity:1;
    pointer-events:auto}
}
/* `.topbar a` из блока для пальца (элемент + класс) весит больше голого
   `.nav-item` и стоит ниже: ссылки возвращались на телефон и разваливали
   шапку на две строки. Селектор с родителем весит столько же и идёт после. */
@media (max-width:900px){.topbar .nav-item{display:none}}
.wrap-chrome{padding-top:0;padding-bottom:0}
a{color:var(--accent)}
.crumbs{font-size:13px;color:var(--muted);margin-bottom:12px}
.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));
  gap:12px;margin:18px 0}
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-md);
  padding:var(--space-4);transition:transform .35s cubic-bezier(.2,.8,.2,1),
  border-color .35s ease}
.card:hover{transform:translateY(-4px);border-color:var(--accent)}
@media (prefers-reduced-motion:reduce){.card{transition:none}.card:hover{transform:none}}
.card h3{margin:0;font:500 20px/1.05 var(--font-display)}
.card h3 a{color:var(--ink);text-decoration:none}
.card h3 a:hover{text-decoration:underline}
.card-actions{display:flex;gap:8px;margin-top:10px}
.meta{color:var(--muted);font-size:13px}
.links{margin:22px 0;padding-top:14px;border-top:1px solid var(--line);font-size:14px}
.links a{margin-right:12px;display:inline-block;padding:2px 0}
/* `small` по умолчанию 0,83em — на нашем кегле это 11,7px, мельче читаемого. */
small{font-size:12.5px}
.age{position:fixed;left:0;right:0;bottom:0;background:var(--card);border-top:1px solid var(--line);padding:10px 16px;font-size:14px}
/* Главное действие — заливка гранатом, второстепенное — белая пилюля с
   волосяной рамкой. В самой Nocturne primary это контур; проект отступает
   осознанно, расхождение записано в ДОДЕЛКИ (пункт 6.2). */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;
  padding:11px 20px;border-radius:var(--radius-pill);border:1px solid var(--accent);
  background:var(--accent);color:var(--on-accent);text-decoration:none;
  font:500 14px/1.3 var(--font-body);white-space:nowrap;
  transition:transform .25s ease,background .25s ease}
.btn:hover{transform:translateY(-2px)}
.btn.secondary{background:var(--paper);color:var(--ink);border-color:var(--line)}
.btn.secondary:hover{border-color:var(--accent);color:var(--accent-text)}
.btn.small{padding:7px 14px;font-size:13px}
a:focus-visible,button:focus-visible,input:focus-visible,summary:focus-visible{
  outline:2px solid var(--accent);outline-offset:2px;border-radius:var(--radius-sm)}
@media (prefers-reduced-motion:reduce){.btn{transition:none}.btn:hover{transform:none}}
button.link{background:none;border:none;color:var(--accent);cursor:pointer;padding:0;font:inherit;text-decoration:underline}
/* Кнопки кабинета были браузерными серыми: единственный путь владельца к
   публикации карточки не должен выглядеть черновиком. */
button[type=submit]:not(.link){display:inline-flex;align-items:center;justify-content:center;
  padding:11px 20px;border-radius:var(--radius-pill);
  border:1px solid var(--accent);background:var(--accent);color:var(--on-accent);
  font:500 14px/1.3 var(--font-body);cursor:pointer}
button[type=submit]:not(.link):hover{filter:brightness(1.06)}
/* Раскладка — от ширины экрана. */
@media (max-width:600px){
  .wrap:not(.wrap-chrome){padding-top:14px;padding-bottom:48px}
  .cards{grid-template-columns:1fr;gap:10px}
  h1{font-size:23px}
  .topbar{gap:4px 12px}
}
/* Размер цели — от того, чем тыкают, а не от ширины: планшет шире телефона, но
   палец у него тот же. Списки станций — основная навигация, на хабе таких
   ссылок больше трёхсот, и по строке текста пальцем не попасть. */
@media (pointer:coarse){
  .btn{padding:12px 16px}
  .btn.small{padding:9px 12px}
  .links a{padding:9px 0;margin-right:16px}
  .crumbs a,.crumbs span{display:inline-block;padding:6px 0}
  footer.site a,.topbar a{padding:6px 0;display:inline-block}
  footer.site .linkbtn{padding:6px 0}
  p a,dd a,li a,h3 a{display:inline-block;padding:7px 0}
  /* Поля и кнопки форм: вход и claim — единственный путь владельца в кабинет. */
  input:not([type=checkbox]):not([type=radio]),select,textarea,
  button:not(.link){font:inherit;padding:10px 12px;min-height:44px}
  button{cursor:pointer}
  /* Подпись сверху, поле на всю ширину: в строку они складывались в кашу —
     «Услуга [поле] Цена, ₽ [поле] Минут [поле]» на 390 точках нечитаемо. */
  form label{display:block;margin:0 0 12px}
  form label input:not([type=checkbox]):not([type=radio]),
  form label select,form label textarea{display:block;width:100%;margin-top:5px}
  /* Галочка слева, текст обычным потоком: флекс разрывал строку согласия —
     «(» оставалась на одной строке, «политика» уезжала вправо, «)» следом. */
  form label:has(input[type=checkbox]){display:block;position:relative;padding-left:30px}
  form label:has(input[type=checkbox])>input[type=checkbox]{position:absolute;left:0;top:4px;
    width:20px;height:20px}
  /* Ссылка внутри подписи остаётся в строке; область нажатия даёт вертикальный
     отступ — у строчного элемента он расширяет её, не двигая вёрстку. */
  form label a,label a{display:inline;padding:9px 3px}
  form button[type=submit]:not(.link){width:100%}
  /* «убрать» — текстовая ссылка внутри строки, а не кнопка в 44 точки. */
  button.link{min-height:0;padding:4px 0}
}
.actions2{display:flex;flex-wrap:wrap;gap:8px;margin:10px 0}
/* Таблицы прокручиваются в своей рамке, а не растягивают страницу: на телефоне
   четыре колонки в 360 точек не помещаются, и вместе с ними уезжает вся вёрстка. */
table{max-width:100%;display:block;overflow-x:auto;border-collapse:collapse}
textarea,input,select{max-width:100%}
.path,.meta code{overflow-wrap:anywhere}
/* Телефон переносится целиком, а не разрывается посреди номера. */
.nowrap{white-space:nowrap}
.topbar{display:flex;flex-wrap:wrap;gap:6px 18px;align-items:center;font-size:14px;padding:10px 0;border-bottom:1px solid var(--line);margin-bottom:14px}
.topbar .brand{display:inline-flex;align-items:center;gap:9px;
  font:italic 500 17px/1 var(--font-display);letter-spacing:.004em;
  color:var(--rouge);text-decoration:none}
/* Второе слово чернильным: рубиновым на светлом фоне красить нельзя. */
.topbar .brand em{font-style:italic;color:var(--ink)}
/* Знак в рубиновом круге занимает 0,62 диаметра — одно правило на все размеры. */
.topbar .brand .word{white-space:nowrap}
.topbar .brand .brandmark{display:inline-flex;align-items:center;justify-content:center;
  width:26px;height:26px;border-radius:50%;background:var(--rouge);color:var(--paper);
  flex:none}
/* Маска, а не картинка: цвет наследуется от текста, и один файл работает
   белым на рубине и рубиновым на бумаге. Контур из SVG — PNG мылится. */
.flame{display:inline-block;width:.62em;height:.62em;background:currentColor;
  -webkit-mask:url("/static/img/flame.8cd889b82ddb.svg") center/contain no-repeat;
  mask:url("/static/img/flame.8cd889b82ddb.svg") center/contain no-repeat}
.topbar .brand .brandmark .flame{width:16.1px;height:16.1px;flex:none}
/* --- степень контакта: три огонька ------------------------------------- */
/* Тот же знак, что в логотипе, с прозрачностью у незасчитанных. Не серый и не
   контур: так читается «два из трёх», а не «два огонька и что-то ещё». */
.ct{--fl:13px;--fl-gap:3px;position:relative;display:inline-flex;align-items:center;
  gap:6px;cursor:help;vertical-align:middle}
.ct .flames{display:inline-flex;align-items:center;gap:var(--fl-gap);color:var(--rouge);
  line-height:0}
.fl{display:inline-block;width:var(--fl);height:var(--fl);background:currentColor;
  opacity:.2;flex:none;
  -webkit-mask:url("/static/img/flame.8cd889b82ddb.svg") center/contain no-repeat;
  mask:url("/static/img/flame.8cd889b82ddb.svg") center/contain no-repeat}
.fl.on{opacity:1}
.ct-name{font:500 10px/1.2 var(--font-body);color:var(--ink-2);white-space:nowrap}
/* Все три уровня равны: это разные предпочтения, а не градация качества,
   поэтому третий не красится золотом и ничем не выделяется. */

/* Размеры по контексту. Ниже 9px три знака сливаются в пятно. */
.ct-card{--fl:13px;--fl-gap:3px}
.ct-badge{--fl:13px;--fl-gap:3px}
.ct-badge .flames{color:#fff}
.ct-badge .ct-name{color:#fff}
.ct-big{--fl:27px;--fl-gap:5px;gap:10px}
.ct-big .ct-name{font:500 21px/1.15 var(--font-display);color:var(--ink)}
.ct-row{--fl:15px;--fl-gap:3px}
.ct-row .ct-name{font:500 12.5px/1.2 var(--font-body)}
.ct-filter{--fl:11px;--fl-gap:2px}
.ct-cab{--fl:15px;--fl-gap:3px}
.ct-cab .ct-name{font:500 13px/1.2 var(--font-body);color:var(--ink)}
.ct-map{--fl:9px;--fl-gap:3px}
.ct-map .ct-name{font:500 9.5px/1.2 var(--font-body)}
.ct-pop{--fl:12px;--fl-gap:3px}
.ct-landing{--fl:22px;--fl-gap:4px}
.ct-landing .ct-name{font:500 15px/1.2 var(--font-body)}
@media (max-width:640px){
  .ct-card{--fl:11px;--fl-gap:2px}
  .ct-card .ct-name{font-size:9px}
}

/* Тултип. На тёмной подложке, всплывает вверх со сдвигом. На карточке внутри
   ссылки раскрывается только наведением: тапом там открывается сама анкета,
   и перехватывать тап значит ломать карточку. */
.ct-tip{position:absolute;left:50%;bottom:calc(100% + 4px);transform:translateX(-50%);
  width:252px;max-width:min(252px,80vw);z-index:40;
  padding:10px 12px;border-radius:var(--radius-md);
  background:oklch(.24 .04 18);color:oklch(.96 .01 60);
  box-shadow:0 10px 28px oklch(.2 .04 18/.34);
  font:400 11px/1.45 var(--font-body);text-align:left;
  opacity:0;visibility:hidden;transition:opacity .12s ease;pointer-events:none}
.ct:hover .ct-tip,.ct:focus-visible .ct-tip,.ct.open .ct-tip{opacity:1;visibility:visible}
.ct-tip b{display:block;margin-bottom:4px;font:600 11px/1.3 var(--font-body);
  color:#fff}
.ct-tip .ct-warn{display:block;margin-top:7px;padding-top:7px;
  border-top:1px solid oklch(1 0 0/.18);color:oklch(.86 .02 60);font-size:10px}
.ct:focus-visible{outline:2px solid var(--rouge);outline-offset:3px;border-radius:4px}
/* Крупный блок степени в анкете. Все три уровня показаны списком: гость видит
   не только выбранный, но и чем он отличается от соседних — иначе цифра «2»
   не значит ничего. */
.ctblock{margin:var(--space-8) 0;padding:var(--space-6);border:1px solid var(--line);
  border-radius:var(--radius-lg);background:var(--paper)}
.ctblock h2{margin:0 0 var(--space-4);font:600 15px/1.2 var(--font-display);color:var(--ink)}
.ctb-now{margin-bottom:var(--space-3)}
.ctb-desc{margin:0 0 var(--space-5);font:400 13px/1.5 var(--font-body);color:var(--ink-2);
  max-width:56ch}
.ctb-all{list-style:none;margin:0 0 var(--space-5);padding:0;display:grid;
  gap:var(--space-2)}
.ctb-item{display:flex;align-items:baseline;gap:var(--space-4);flex-wrap:wrap;
  padding:7px 10px;border-radius:var(--radius-md);opacity:.55}
.ctb-item.is-now{opacity:1;background:var(--bonus-bg)}
.ctb-txt{font:400 11.5px/1.4 var(--font-body);color:var(--muted)}
.ctb-note{margin:0 0 4px;font:400 10.5px/1.45 var(--font-body);color:var(--muted);
  max-width:60ch}
/* Чип фильтра: огоньки перед подписью, поэтому строчный ряд и небольшой зазор. */
.ctchip{display:inline-flex;align-items:center;gap:6px}
.ctchip .ct{cursor:inherit}
.ctchip .ct-tip{display:none}
.fnote{margin:6px 0 0;font:400 9.5px/1.4 var(--font-body);color:var(--muted);max-width:30ch}
/* Плашка степени в шапке анкеты: рубиновая заливка, белые огоньки и подпись. */
.pill.ctpill{display:inline-flex;align-items:center;padding:3px 10px;
  background:var(--rouge);border-color:var(--rouge);color:#fff}
/* Степень на личной странице: крупнее, чем в карточке, но тише, чем в анкете —
   лендинг и так ведёт одним голосом. */
.lct{margin:var(--space-7) 0 var(--space-6)}
.lct-desc{margin:8px 0 4px;font:400 13px/1.5 var(--font-body);color:var(--ink-2);max-width:54ch}
.lct-note{margin:0;font:400 10px/1.45 var(--font-body);color:var(--muted);max-width:54ch}
/* Панель выбора степени в кабинете. Вариант — цельная мишень: клик по любой
   части строки переключает радиокнопку, иначе в неё надо целиться. */
.ctform{display:grid;gap:var(--space-3)}
.ctopt{display:grid;grid-template-columns:auto 1fr;gap:4px var(--space-4);
  align-items:center;padding:10px 12px;border:1px solid var(--line);
  border-radius:var(--radius-md);cursor:pointer}
.ctopt.is-now{border-color:var(--rouge);background:var(--bonus-bg)}
.ctopt input{grid-row:1/3;margin:0}
.ctopt-desc{grid-column:2;font:400 11.5px/1.45 var(--font-body);color:var(--muted)}
.meta.warn{color:var(--rouge-deep)}
/* Ярлык реестра с непустым счётчиком проблем: виден до чтения подписи. */
.chip.warn{color:var(--rouge-deep);box-shadow:inset 0 0 0 1px var(--rouge-deep)}
/* Выбор степени на регистрации: рамка группы, чтобы шаг читался как один
   вопрос, а не как три отдельных переключателя среди полей формы. */
.ctpick{margin:var(--space-6) 0;padding:var(--space-5);border:1px solid var(--line);
  border-radius:var(--radius-lg)}
.ctpick legend{padding:0 6px;font:600 13px/1.2 var(--font-display);color:var(--ink)}
.ctpick .ctopt{margin-top:var(--space-3)}
.hint{margin:4px 0;font:400 11px/1.45 var(--font-body);color:var(--muted);max-width:56ch}

/* --- кабинет: меню слева, содержимое справа ---------------------------- */
/* Раньше кабинет был одним потоком в десятки полей: мастер не находил нужное
   и не понимал, чего ещё не хватает. Меню превращает его в набор задач. */
.cab{display:grid;grid-template-columns:212px minmax(0,1fr);gap:var(--space-8);
  align-items:start}
.cabnav{position:sticky;top:var(--space-6);display:flex;flex-direction:column;gap:2px}
.cabnav-item{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);
  padding:7px 10px;border-radius:var(--radius-md);text-decoration:none;
  font:500 12.5px/1.3 var(--font-body);color:var(--ink-2)}
.cabnav-item:hover{background:var(--bonus-bg)}
.cabnav-item b{font:500 10.5px/1.2 var(--font-body);color:var(--muted);
  font-variant-numeric:tabular-nums;white-space:nowrap}
/* Активный пункт подсвечивается заливкой и точкой справа. Ставится скриптом
   по видимому разделу: без него меню показывает состояние, которого нет. */
.cabnav-item.on{background:oklch(.97 .025 20);color:var(--rouge-deep)}
.cabnav-item.on::after{content:"";width:5px;height:5px;border-radius:50%;
  background:var(--rouge);flex:none}
.cabnav-item.on b{color:var(--rouge-deep)}
.cabbody{min-width:0}
.botlist{margin:4px 0 var(--space-5);padding-left:20px;
  font:400 12px/1.5 var(--font-body);color:var(--ink-2)}
.botlist.no{color:var(--muted)}
/* --- реестр мастеров салона -------------------------------------------- */
.rsum{margin:0 0 var(--space-5);font:500 13px/1.4 var(--font-body);color:var(--ink-2)}
table.roster{font-size:12.5px}
table.roster td{vertical-align:middle}
.rtag{display:inline-block;padding:2px 7px;border-radius:var(--radius-pill);
  font:500 10px/1.4 var(--font-body);white-space:nowrap}
.rtag.s-free{background:oklch(.95 .05 22);color:var(--rouge-deep)}
.rtag.s-from{background:var(--bonus-bg);color:#8a5a12}
.rtag.s-busy,.rtag.off{background:#f2efec;color:var(--muted)}
.rtag.wait{background:var(--bonus-bg);color:#8a5a12}
.rtag.chan{background:oklch(.95 .04 300);color:oklch(.42 .12 300)}
.qr{border:1px solid var(--line);border-radius:var(--radius-md);background:#fff;padding:6px}
@media (max-width:900px){
  /* На телефоне таблица из семи столбцов нечитаема: строка становится
     карточкой, заголовки уходят в подписи ячеек. */
  table.roster{font-size:12px}
}
.botlist li{margin:3px 0}
@media (max-width:900px){
  /* На телефоне колонка не помещается: меню становится рядом чипов под шапкой
     и выходит за поля контейнера — крайние уходят под край экрана, и это
     единственная понятная подсказка, что ряд листается. */
  .cab{display:block}
  .cabnav{position:static;flex-direction:row;gap:6px;overflow-x:auto;
    margin:0 -16px var(--space-5);padding:0 16px;scrollbar-width:none}
  .cabnav::-webkit-scrollbar{display:none}
  .cabnav-item{flex:none;border:1px solid var(--line);white-space:nowrap}
  .cabnav-item.on::after{display:none}
}
@media (max-width:640px){.ctblock{padding:var(--space-5)}}


.topbar .badge{border:1px solid var(--line);border-radius:var(--radius-pill);padding:3px 9px;
  font:500 10px/1.3 var(--font-body);color:var(--rouge-deep)}
.topbar form{display:inline}
.topbar .menu{display:contents}
.topbar .book{margin-left:auto}
.topbar .menu>summary{display:none}
.topbar .menu-items{display:contents}

/* Липкая панель действий: на телефоне звонок — главная конверсия, а кнопка
   уезжает вверх, как только человек начинает читать услуги и часы. */
.stickybar{display:none}

@media (max-width:640px),(pointer:coarse){
  .topbar{gap:var(--space-2);justify-content:space-between}
  .topbar .menu{display:block}
  .topbar .book{margin-left:auto;margin-right:var(--space-3);padding:8px 14px}
  .topbar .menu>summary{display:inline-block;list-style:none;cursor:pointer;
    border:1px solid var(--line);border-radius:8px;padding:8px 12px;color:var(--accent)}
  .topbar .menu>summary::-webkit-details-marker{display:none}
  .topbar .menu[open]>summary{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
  .topbar .menu-items{display:flex;flex-direction:column;position:absolute;right:16px;z-index:30;
    background:var(--card);border:1px solid var(--line);border-radius:10px;
    padding:6px 14px;box-shadow:0 8px 24px rgba(0,0,0,.12);min-width:190px}
  .topbar .menu-items a,.topbar .menu-items button{padding:11px 0;text-align:left}

  /* Закреплена у нижнего края, а не `sticky`: липкая отклеивалась на трети
     прокрутки, потому что упиралась в конец своего родителя. */
  .stickybar{display:flex;gap:8px;position:fixed;left:0;right:0;bottom:0;z-index:30;
    padding:10px 12px calc(10px + env(safe-area-inset-bottom));
    background:var(--bg);border-top:1px solid var(--line)}
  .stickybar .btn{flex:1;text-align:center;padding:14px 10px}
  .stickybar .btn.secondary{flex:0 0 auto;padding:14px 14px}
  /* Место под панель, чтобы она не закрывала подвал и последние строки. */
  body:has(.stickybar) .wrap:not(.wrap-chrome){padding-bottom:96px}
}
/* Ворота не закрашивают страницу наглухо: под ними должно просвечивать
   обещание — заголовок и строка про источник данных, — иначе первый экран
   сайта это пустой чёрный лист. */
.age-gate{position:fixed;inset:0;background:rgba(74,42,38,.72);color:var(--ink);z-index:1000;
  display:flex;align-items:flex-end;justify-content:center;padding:24px}
.age-gate .box{max-width:460px;background:var(--card);border:1px solid var(--line);
  border-radius:12px;padding:24px;margin-bottom:8vh}
.age-gate h2{margin:0 0 8px}
.age-gate .lead{font-size:13px;font-weight:600;color:var(--muted);margin:0 0 10px}
.age-gate p{color:var(--muted)}
/* Вход обязан быть заметнее выхода. Было наоборот: `button[type=submit]`
   имеет специфичность (0,2,1) и перебивал `.age-gate .btn` (0,2,0), поэтому
   золото доставалось ссылке «Уйти» — контраст 6,81 против 2,67 у входа. */
.age-gate button[type=submit]{background:var(--accent);border-color:var(--accent);
  color:var(--on-accent)}
.age-gate .btn.secondary{background:transparent;color:var(--muted);border-color:var(--line)}
footer.site{margin-top:36px;border-top:1px solid var(--line);font-size:12px;
  color:var(--muted)}
/* Колонки живут в контейнере, а не в самом подвале: фон во всю ширину,
   содержимое по общим полям страницы. */
footer.site .wrap-chrome{display:grid;grid-template-columns:repeat(4,1fr);
  gap:16px 28px;padding-top:20px;padding-bottom:20px}
footer.site .col{display:flex;flex-direction:column;gap:6px;align-items:flex-start}
/* Реквизиты оператора: одна мелкая строка, не спорит с навигацией подвала */
footer.site .legal{font-size:11px;line-height:1.4;color:var(--muted);opacity:.8;
  font-variant-numeric:tabular-nums}
footer.site .linkform{margin:0}
footer.site .linkbtn{border:0;background:none;padding:0;font:inherit;color:inherit;cursor:pointer;
  text-align:left}
footer.site .linkbtn:hover{text-decoration:underline}
footer.site .name{font-size:13px;font-weight:700;color:var(--ink)}
footer.site .badge{border:1px solid var(--line);border-radius:var(--radius-pill);padding:3px 9px;
  font:500 10px/1.3 var(--font-body);color:var(--rouge-deep)}
.gate{border-left:3px solid var(--marigold);background:var(--bonus-bg);padding:10px 14px;
  margin:12px 0;border-radius:0 var(--radius-md) var(--radius-md) 0;font-size:14px}
.error{color:var(--warn)}.ok{color:var(--ok)}.wait{color:var(--accent)}
.gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}
.gallery img{width:100%;height:120px;object-fit:cover;border-radius:6px}
.gallery figure{margin:0}.gallery figcaption{font-size:12px;color:var(--muted)}
/* Флекс, а не сетка: у грид-элемента высота считается от содержимого, и
   прижать действия к низу карточки не выходило — кнопки в ряду висели на
   разных уровнях. */
.card{display:flex;gap:12px;align-items:stretch}
.card>a.thumb{flex:0 0 96px}
.card>div{flex:1;min-width:0;display:flex;flex-direction:column}
/* Строки карточки не сжимаются: колоночный флекс ужимал строку станции до
   семи точек, и «Трубная · 6 мин пешком» превращалось в полоску. */
.card>div>*{flex-shrink:0}
/* Действия прижаты к низу: в ряду карточки одной высоты, и без этого кнопки
   висят на разных уровнях. Правило идёт после базового — иначе не применится. */
.card-actions{margin-top:auto;padding-top:10px}
/* Арочная форма — визуальная подпись проекта: скругление сверху, прямые углы
   снизу. В карточке списка арка уменьшена под миниатюру 96 точек. */
.card .thumb{width:96px;height:96px;border-radius:48px 48px var(--radius-md) var(--radius-md);
  object-fit:cover;background:var(--bonus-bg);border:1px solid var(--line);
  display:flex;align-items:center;justify-content:center;
  font:500 32px/1 var(--font-display);color:var(--muted);overflow:hidden}
/* Схема тянется под плашку: у svg свои width/height в разметке, и на телефоне
   96 точек вылезали из уменьшенной до 72 рамки. */
.card .thumb svg{display:block;width:100%;height:100%}
/* Элемент сетки не ужимается сам: у него min-width:auto, и самая длинная
   строка внутри карточки распирала колонку за край экрана. */
.cards>.card{min-width:0}
.card h3 a{overflow-wrap:anywhere}
.card .tags{display:flex;flex-wrap:wrap;gap:4px;font-size:12px;margin-top:var(--space-2)}
/* ТРЕБОВАНИЕ спецификации для всех пилюль: inline-flex, без переносов,
   межстрочный 1,3. При межстрочном 1 и фиксированном отступе текст переносился
   и вылезал за скругление — это был реальный дефект вёрстки прототипов. */
.card .tags span,.chip-rating,.verified,.fresh,.topbar .badge,.hints a,
.reviews,footer.site .badge{display:inline-flex;align-items:center;gap:5px;
  white-space:nowrap;line-height:1.3}
.card .tags span{border:1px solid var(--line);border-radius:var(--radius-pill);
  padding:3px 9px;color:var(--muted);font-size:11px}

/* Верхняя строка: название слева, оценка и число отзывов прижаты вправо. */
.card .head{display:flex;gap:8px;align-items:baseline;justify-content:space-between}
.card .head h3{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}
/* Оценка — календула: токены отдают ей «бонусы, рейтинг, с 19:00». */
.chip-rating{background:var(--ok-bg);color:var(--ok-ink);border-radius:var(--radius-pill);
  padding:3px 9px;font:500 11px/1.3 var(--font-body)}
.reviews{font-size:12px;color:var(--muted)}
/* Лента отзывов — не плашка с оценкой и не сетка карточек `.rlist`. Список
   звался `.reviews`, как плашка, и вставал в строку inline-flex: страница
   отзывов уезжала за край на двадцать тысяч точек. Поймано только замером. */
.rfeed{list-style:none;margin:var(--space-6) 0;padding:0;display:flex;
  flex-direction:column;gap:var(--space-6);max-width:70ch}
.rfeed li{min-width:0}
.rfeed a{font-weight:500}
.rfeed div{margin-top:var(--space-2);font-size:14px;line-height:1.7;color:var(--ink)}
.rfeed .answer{margin-top:var(--space-2);padding-left:var(--space-4);
  border-left:2px solid var(--line);color:var(--muted);font-size:13px}
/* Верификация — мятная пара, как в прототипе «✓ фото и ID». */
.verified{background:var(--verify-bg);color:var(--verify-ink);border-radius:var(--radius-pill);
  padding:3px 9px;font:500 10px/1.3 var(--font-body)}
/* Станция и расстояние — одной строкой без переносов. */
/* Минуты пешком не обрезаются вместе со станцией: «Красные Ворота · 5 мин
   пешк…» — обрезано ровно то, ради чего строка и написана. Ужимается только
   название станции. */
.card .where{font-size:13px;font-weight:600;margin-top:var(--space-2);display:flex;gap:5px;
  align-items:baseline;min-width:0}
.card .where .st{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.card .where .far{flex:none}
.dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--muted);
  vertical-align:middle;margin-right:6px}
.card .where .far{font-weight:400;color:var(--muted)}
/* Строка происхождения. Здесь же живёт свежесть, когда она появится: слова
   «заглушка», «не заполнено», «нет данных» запрещены — карточка справочная,
   а не сломанная. */
.origin{font-size:12px;color:var(--muted);margin-top:var(--space-2)}
.origin a{font-weight:700}
/* «Свободна» — белая пилюля с гранатовым текстом и тенью, как в прототипе:
   акцент здесь работает точкой и текстом, а не заливкой площади. */
.fresh{background:var(--paper);color:var(--rouge-deep);border-radius:var(--radius-pill);
  padding:4px 10px;font:500 10px/1.3 var(--font-body);box-shadow:var(--shadow-pill)}
.card .line{margin-top:var(--space-2)}
.rubrics{font-size:11px;font-weight:700;color:var(--muted);margin-top:var(--space-2);letter-spacing:.02em}
.card .addr{font-size:13px;color:var(--muted);margin-top:var(--space-2);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.price{font-size:13px;font-weight:600;margin-top:var(--space-2)}
/* Номер в разметке списка не печатается: 330 номеров делят 780 карточек, до 56
   на один — при сканировании страницы это видно сразу и обесценивает весь
   список. Звонок идёт через переход `/go/<pk>/call/`, который и подставляет
   номер, и записывает событие. */

/* ---- главная: числа, поле станции, хаб линий ---- */
.lead{font-size:13px;color:var(--muted);max-width:640px;margin:0 0 20px}
.entry{display:flex;flex-wrap:wrap;gap:24px 36px;align-items:flex-start;margin:20px 0 14px}
.station-field input{height:56px;width:420px;max-width:100%;background:var(--paper);
  border:1px solid var(--line);border-radius:var(--radius-pill);padding:0 20px;
  color:var(--ink);font:400 17px/1.4 var(--font-body)}
.station-field input::placeholder{color:var(--muted)}
.hints{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
/* Зазор задаётся флексом: `inline-flex` из правила пилюль схлопывает пробел
   между текстовыми узлами, и название станции слипалось с числом.
   Настоящих названий в комментариях не приводим: тесты проверяют, что слова
   нет на странице, и комментарий срабатывает на себя — так уже было трижды. */
.hints a{border:1px solid var(--line);border-radius:var(--radius-pill);padding:6px 13px;
  gap:6px;font-size:13px;color:var(--ink);text-decoration:none}
.hints a:hover{border-color:var(--accent);color:var(--accent-text)}
.hints a b{font-variant-numeric:tabular-nums;color:var(--muted);font-weight:600}
.stats{display:flex;gap:36px}
.bignum{font:500 44px/1 var(--font-display);letter-spacing:-.03em;display:block}
.stats span{font-size:12px;color:var(--muted);display:block;margin-top:6px}
/* Число подтверждённых набирается тем же кеглем, что и вся строка: три
   карточки крупно означают, что сайта нет. */
.trust{font-size:12px;color:var(--muted);margin:0 0 24px}
.hub{margin-top:16px}
.hub-line{display:flex;align-items:center;gap:8px;margin:24px 0 8px}
.hub-line .bar{width:3px;height:18px;border-radius:2px;background:var(--muted)}
.hub-line b{font-size:13px;font-weight:700;letter-spacing:.04em}
.hub-line span{font-size:12px;color:var(--muted)}
.hub-stations{columns:4;column-gap:28px}
.hub-station{break-inside:avoid;display:flex;justify-content:space-between;gap:10px;
  padding:5px 0;font-size:13px;text-decoration:none;color:var(--ink)}
/* Имя станции ужимается, счётчик — нет: счётчик и есть содержание строки, а
   длинное имя без этого выталкивало его за край колонки. */
.hub-station>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hub-station:hover{color:var(--accent)}
.hub-station b{font-size:12px;font-weight:400;color:var(--muted);white-space:nowrap}
.hub-station b.dim{opacity:.55}


/* ════════════════════════ витрина мастеров «На массаж» ════════════════════ */

.hero{display:grid;grid-template-columns:minmax(0,1.45fr) minmax(0,1fr);
  gap:var(--space-8) calc(var(--space-8) * 2);align-items:end;
  margin:var(--space-8) 0 calc(var(--space-8) * 1.6)}
.kicker{display:flex;align-items:center;gap:7px;margin:0 0 var(--space-4);
  font:500 10px/1.3 var(--font-body);letter-spacing:.16em;text-transform:uppercase;
  color:var(--rouge-deep)}
.blink{width:6px;height:6px;border-radius:50%;background:var(--rouge);
  animation:blink 1.8s ease-in-out infinite}
@keyframes blink{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.28;transform:scale(.65)}}
.hero h1{margin:0 0 var(--space-4)}
/* Вторая строка заголовка курсивом гранатом — подпись проекта. */
.hero h1 em{font-style:italic;color:var(--rouge);display:block}
.hero-sub{max-width:46ch;margin:0 0 var(--space-6);font-size:14px;line-height:1.7;
  color:var(--muted)}
.hero-actions{display:flex;flex-wrap:wrap;gap:var(--space-3);margin-bottom:var(--space-4)}
.hero-side{display:flex;flex-direction:column;gap:var(--space-4)}
/* Без живой ленты правая колонка пуста: герой встаёт в одну, а строка текста
   держит меру — на 1160 точках она бы разъехалась за читаемые 75 знаков. */
.hero-solo{grid-template-columns:minmax(0,1fr)}
.hero-solo h1{max-width:18ch}

/* Живая лента. Пустая не рендерится вовсе: крутить старое запрещено. */
/* Лента идёт отдельной строкой во всю ширину: в углу героя ей было тесно, и
   события обрывались на полуслове — это читается как поломка, а не как
   бегущая строка. Метка слева и оговорка справа закреплены и не едут. */
.live{display:flex;align-items:center;gap:var(--space-4);min-width:0;max-width:100%;
  margin:var(--space-6) 0;padding:9px var(--space-6);
  border-radius:var(--radius-pill);background:oklch(.97 .025 165);overflow:hidden}
.live-tag{flex:none;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;
  font:500 9.5px/1.3 var(--font-body);letter-spacing:.14em;text-transform:uppercase;
  color:oklch(.42 .1 165)}
.live-tag .blink{width:5px;height:5px;background:var(--mint)}
/* Растворяются оба края: слева событие уезжает из-под метки, справа приезжает. */
.live-wrap{flex:1;min-width:0;overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 16px,#000 calc(100% - 16px),transparent);
  mask-image:linear-gradient(90deg,transparent,#000 16px,#000 calc(100% - 16px),transparent)}
.live-items{display:flex;gap:26px;width:max-content;
  font:400 11px/1.3 var(--font-body);color:var(--ink)}
.live-items i{font-style:normal;white-space:nowrap}
.live-note{flex:none;white-space:nowrap;font:400 9.5px/1.3 var(--font-body);
  color:var(--muted)}
.hero>*{min-width:0}

/* --- полоса правил под шапкой ------------------------------------------ */
.rulesbar{background:oklch(.985 .012 24);border-bottom:1px solid var(--line)}
.rulesbar .wrap-chrome{display:flex;flex-wrap:wrap;align-items:center;
  justify-content:center;gap:var(--space-4) var(--space-8);padding:9px 40px}
.rulesbar span{display:inline-flex;align-items:center;gap:7px;white-space:nowrap;
  font:500 10px/1.3 var(--font-body);color:var(--muted)}
.rb-mark{display:inline-flex;align-items:center;justify-content:center;flex:none;
  width:18px;height:18px;border-radius:50%;background:var(--bonus-bg);
  font:600 9px/1 var(--font-body);color:var(--rouge-deep)}
.rb-mark.no{background:oklch(.95 .03 20);color:var(--rouge-deep)}
.rb-mark.spa{background:var(--verify-bg);color:var(--verify-ink)}
@media (max-width:640px){
  /* На телефоне три условия в строку не встают: оставляем колонкой у левого
     края — по центру они читаются как подпись, а это правила. */
  .rulesbar .wrap-chrome{justify-content:flex-start;gap:var(--space-2);
    flex-direction:column;align-items:flex-start;padding:8px 16px}
}
/* --- четыре факта о городе справа от заголовка ------------------------- */
/* Выровнены по низу заголовка: сетка фактов — подпись под ним, а не вторая
   колонка текста. */
.facts-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3);
  align-self:end}
/* Нечётный факт занимает строку целиком: три карточки в двух колонках
   оставляют дырку, а дырка на первом экране читается как недогруз. */
.fact:last-child:nth-child(odd){grid-column:1 / -1}
.fact{display:flex;flex-direction:column;gap:3px;padding:var(--space-6);
  border-radius:var(--radius-md);background:var(--paper);
  box-shadow:inset 0 0 0 1px var(--line)}
.fact-label{font:400 9px/1.3 var(--font-body);letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted)}
.fact-value{font:500 22px/1.1 var(--font-display);color:var(--ink);
  font-variant-numeric:lining-nums tabular-nums}
.fact-value.hot{color:var(--rouge)}
.fact-value.ok{color:var(--verify-ink)}
.fact-note{font:400 9.5px/1.45 var(--font-body);color:var(--muted)}
.bonus{border:1px solid var(--bonus-edge);background:var(--bonus-bg);
  border-radius:var(--radius-lg);padding:var(--space-4) var(--space-6)}
.bonus-title{margin:0 0 var(--space-2);font:500 18px/1.1 var(--font-display)}
.bonus-text{margin:0 0 var(--space-4);font-size:13px;line-height:1.6;color:var(--muted)}
.bonus-text:last-child{margin-bottom:0}

.grid-head{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-4);
  margin:calc(var(--space-8) * 1.6) 0 var(--space-4)}
.grid-head h2{margin:0}
.grid-head h2 em{font-style:normal;color:var(--rouge)}
.grid-note{margin:var(--space-3) 0 var(--space-6);font-size:13px;color:var(--muted);
  max-width:70ch}

.chips{display:flex;flex-wrap:wrap;gap:var(--space-2);margin-bottom:var(--space-8)}
.chip{display:inline-flex;align-items:center;white-space:nowrap;line-height:1.3;
  border:1px solid var(--line);border-radius:var(--radius-pill);padding:6px 13px;
  font-size:12px;color:var(--ink);text-decoration:none}
.chip:hover{border-color:var(--accent);color:var(--accent-text)}

/* Витрина — ровно пять колонок при контейнере 1240: на этой ширине
   проверены размеры плашек поверх фото. Ширину карточки не задаём. */
.mgrid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));
  gap:var(--space-8) var(--space-6)}
/* --- полоса вовлечения на главной ------------------------------------- */
/* Первая карточка шире: в ней четыре чипа приза и кнопка во всю ширину. */
.engage{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr) minmax(0,1fr);
  gap:var(--space-6);margin:var(--space-8) 0}
.ecard{display:flex;flex-direction:column;gap:var(--space-4);
  padding:var(--space-6) var(--space-8);border-radius:var(--radius-lg);
  box-shadow:inset 0 0 0 1px var(--line)}
.ebonus{background:var(--bonus-bg);box-shadow:inset 0 0 0 1px var(--bonus-edge)}
/* Рамка гранатом — только у удержания: это единственная карточка ряда,
   у которой есть срок, и её нужно отличать от двух вечных. */
.ehold{box-shadow:inset 0 0 0 1px var(--rouge)}
.ehead{display:flex;align-items:center;gap:var(--space-4)}
.edisc{flex:none;position:relative;width:40px;height:40px;border-radius:50%;
  background:conic-gradient(from 0deg,var(--marigold),var(--rouge),var(--lilac),var(--marigold));
  animation:ringspin 11s linear infinite}
.edisc .ico{position:absolute;inset:0;margin:auto;width:17px;height:17px;
  color:var(--rouge-deep);z-index:1}
.edisc::after{content:"";position:absolute;inset:4px;border-radius:50%;background:var(--paper)}
.etitles{flex:1;display:flex;flex-direction:column;gap:3px;min-width:0}
.etitle{display:inline-flex;align-items:center;gap:7px;flex-wrap:wrap;
  font:500 16px/1.15 var(--font-display)}
.etag{display:inline-flex;align-items:center;gap:4px;white-space:nowrap;padding:3px 8px;
  border-radius:var(--radius-pill);background:var(--marigold);color:var(--ink);
  font:500 8.5px/1.3 var(--font-body);letter-spacing:.08em;text-transform:uppercase}
.esub{font:400 10.5px/1.55 var(--font-body);color:var(--muted)}
.eprizes{display:flex;flex-wrap:wrap;gap:5px}
.eprize{display:inline-flex;align-items:center;white-space:nowrap;padding:6px 11px;
  border-radius:var(--radius-pill);background:var(--paper);color:var(--ink);
  font:500 10px/1.3 var(--font-body)}
.ewon{margin:0;font:400 12px/1.5 var(--font-body)}
.ewon b{font-weight:500}
.emeta{margin:0;font:400 9.5px/1.55 var(--font-body);color:var(--muted)}
.erow{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:var(--space-3)}
.elabel{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;color:var(--muted);
  font:500 9.5px/1.3 var(--font-body);letter-spacing:.14em;text-transform:uppercase}
.elabel .ico{width:12px;height:12px;color:var(--marigold)}
.elabel.hot{color:var(--rouge)}
.elabel.hot .ico{color:var(--rouge)}
.eto{font:500 10.5px/1.3 var(--font-body);color:var(--accent-text)}
.ebar{height:7px;border-radius:7px;background:#f5e9e9;overflow:hidden}
.ebar i{display:block;height:100%;border-radius:7px;
  background:linear-gradient(90deg,var(--marigold),var(--rouge))}
.esteps{display:flex;flex-direction:column;gap:5px}
.estep{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-4);
  font:400 11px/1.45 var(--font-body);color:var(--muted)}
.estep b{flex:none;font:500 10.5px/1.3 var(--font-body);color:var(--ink)}
/* Часы набраны моноширинным: цифры прыгают шириной, и плашка дёргалась бы. */
.eclock{display:inline-flex;align-items:center;white-space:nowrap;padding:4px 10px;
  border-radius:var(--radius-pill);background:var(--rouge);color:var(--paper);
  font:600 11px/1.3 ui-monospace,Menlo,monospace;font-variant-numeric:tabular-nums}
.eclock.out{background:var(--muted)}
/* Playfair набирает цифры минускульными: «1000 бонусов» выходило «1ооо».
   Полоса вовлечения — про числа, им нужны прописные цифры и общая ширина. */
.ewho{margin:0;font:500 15px/1.2 var(--font-display);
  font-variant-numeric:lining-nums tabular-nums}
.erow-actions{display:flex;flex-wrap:wrap;gap:6px}
.erow-actions .btn{flex:1 1 auto;justify-content:center;text-align:center;min-width:110px}
.ecode{display:flex;align-items:center;gap:var(--space-3);align-self:flex-start;
  padding:7px 13px;border-radius:var(--radius-pill);background:var(--paper);
  box-shadow:inset 0 0 0 1px var(--line)}
.ecode code{font:500 11px/1.3 ui-monospace,Menlo,monospace}
/* Блик по кнопке спина: 4,5 с на пробег, как в макете. Перекрытие скрыто. */
/* Кнопка спина — во всю ширину карточки: это единственное её действие. */
.ebonus form{display:flex}
.btn.sheen{position:relative;overflow:hidden;justify-content:center;flex:1}
.btn.sheen::after{content:"";position:absolute;top:0;bottom:0;width:52px;
  background:linear-gradient(90deg,transparent,oklch(1 0 0/.45),transparent);
  animation:sheen 4.5s ease-in-out infinite}
@keyframes ringspin{to{transform:rotate(360deg)}}
@keyframes sheen{0%{left:-60px}55%,100%{left:110%}}
/* Движение — только по желанию: вращение и блик выключаются вместе. */
@media (prefers-reduced-motion:reduce){
  .edisc,.btn.sheen::after{animation:none}
}
/* --- след чужого в кабинете ------------------------------------------- */
.touches{list-style:none;margin:var(--space-3) 0;padding:0;display:flex;
  flex-direction:column;gap:var(--space-2)}
.touches li{margin:0;padding:var(--space-3) var(--space-4);border-radius:var(--radius-md);
  background:var(--bonus-bg);font:400 12px/1.5 var(--font-body)}
.touches b{font-weight:500;margin-right:6px}
.trole{display:inline-block;padding:1px 7px;border-radius:var(--radius-pill);
  background:var(--paper);font:500 9.5px/1.5 var(--font-body);color:var(--muted)}
/* --- карусель новинок -------------------------------------------------- */
/* Ряд, а не сетка: новинки — дополнение к витрине, и вторую витрину из них
   делать нельзя. Карточка держит ширину колонки основной сетки. */
.newrow{display:flex;gap:var(--space-4);overflow-x:auto;scroll-snap-type:x proximity;
  scrollbar-width:none;padding-bottom:var(--space-3)}
.newrow::-webkit-scrollbar{display:none}
.newrow > .mcard{flex:none;width:236px;scroll-snap-align:start}
@media (max-width:640px){.newrow > .mcard{width:63vw}}
/* --- рефералка под витриной ------------------------------------------- */
.refer{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(0,1fr);
  align-items:center;gap:var(--space-8);margin:var(--space-8) 0;
  padding:var(--space-8);border-radius:var(--radius-lg);background:var(--bonus-bg);
  box-shadow:inset 0 0 0 1px var(--bonus-edge)}
.refer h2{margin:var(--space-2) 0 var(--space-3);font-size:26px}
.refer .lead{margin:0;font-size:12.5px;line-height:1.6;color:var(--muted);max-width:52ch}
.refer .kicker{display:inline-flex;align-items:center;gap:6px}
.refer .kicker .ico{width:12px;height:12px;color:var(--marigold)}
.refer-act{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-3)}
.refer-act .meta{margin:0;max-width:34ch}
.refer-act .ecode{align-self:stretch;justify-content:space-between}
@media (max-width:640px){
  .refer{grid-template-columns:minmax(0,1fr);gap:var(--space-4);padding:var(--space-6)}
  .refer h2{font-size:21px}
  .refer-act{align-self:stretch}
  .refer-act .btn{align-self:stretch;justify-content:center}
}
/* --- сетка разделов --------------------------------------------------- */
/* Четыре колонки, а не «сколько влезет»: при пяти в ряд плитка сужается до
   232 точек, и пояснение уходит в многоточие ровно там, где оно и нужно. */
.sections{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:var(--space-3);margin:var(--space-8) 0}
.stile{display:flex;align-items:center;gap:var(--space-4);min-width:0;
  padding:var(--space-4) var(--space-6);border-radius:var(--radius-md);
  box-shadow:inset 0 0 0 1px var(--line);color:inherit;text-decoration:none;
  transition:box-shadow .16s ease,transform .16s ease}
.stile:hover{box-shadow:inset 0 0 0 1px var(--rouge);transform:translateY(-2px)}
.sicon{flex:none;display:inline-flex;align-items:center;justify-content:center;
  width:32px;height:32px;border-radius:var(--radius-sm);
  background:var(--bonus-bg);color:var(--rouge-deep)}
.sicon .ico{width:16px;height:16px}
.sbody{flex:1;display:flex;flex-direction:column;gap:2px;min-width:0}
.sname{display:inline-flex;align-items:center;gap:6px;
  font:500 12px/1.3 var(--font-body)}
.snew{display:inline-flex;align-items:center;white-space:nowrap;padding:2px 6px;
  border-radius:3px;background:var(--ink);color:var(--paper);
  font:600 7px/1.3 var(--font-body);letter-spacing:.1em;text-transform:uppercase}
/* Пояснение — одной строкой: в двух оно перестаёт читаться на бегу. */
.sabout{font:400 9.5px/1.4 var(--font-body);color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.scount{flex:none;font:500 13px/1.2 var(--font-display);color:var(--accent-text);
  font-variant-numeric:lining-nums tabular-nums}
@media (max-width:1024px){.mgrid{grid-template-columns:repeat(3,minmax(0,1fr))}}
/* На планшете три плотных карточки не помещаются: бонус занимает верхнюю
   строку целиком, клуб и третья карточка делят нижнюю. */
@media (max-width:1024px){
  .sections{grid-template-columns:repeat(2,minmax(0,1fr))}
  .engage{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .ebonus{grid-column:1 / -1}
}
@media (max-width:640px){
  /* Значок «18+» из шапки убран: то же самое теперь сказано словами в полосе
     правил строкой ниже, а в строку шапки на 390 точках он не помещался —
     кнопка «Разделы» уезжала на второй ряд. */
  .topbar .badge{display:none}
  .topbar .book{padding:9px 13px}
}
/* Узкие телефоны — 360 и 320 точек. Шапка в одну строку держится только если
   ужать всё разом: имя, кнопку записи и «Разделы». Вторая строка в шапке —
   это минус экран на каждой странице. */
@media (max-width:400px){
  /* Хвост про свободных уезжает: то же число стоит кикером над заголовком и
     карточкой в фактах, а здесь оно ломало полосу доверия на две строки. */
  .tb-free{display:none}
  .topbar{gap:4px 8px}
  .topbar .brand{font-size:15px;gap:7px}
  .topbar .brandmark{width:23px;height:23px}
  .topbar .brand .brandmark .flame{width:14.3px;height:14.3px}
  .topbar .book{padding:8px 11px;font-size:12px}
  .topbar .menu>summary{padding:7px 10px;font-size:12px}
  /* Факты остаются сеткой два на два: в столбик они занимают весь экран, а
     ради них человек сюда не шёл. Число мельче, подпись сохранена. */
  .facts-grid{gap:var(--space-2)}
  .fact{padding:var(--space-4)}
  .fact-value{font-size:18px}
  /* Оговорка про имена гостей рядом с лентой не влезает: она уходит под
     строку, но остаётся видимой — прятать её нельзя. */
  .live{gap:var(--space-3);padding:8px var(--space-4);flex-wrap:wrap}
  .live-wrap{order:3;flex-basis:100%}
  /* На телефоне сетка становится рядом пилюль: восемь плиток в столбик — это
     экран прокрутки до витрины, ради которой человек и пришёл. */
  .sections{display:flex;grid-template-columns:none;gap:var(--space-2);
    overflow-x:auto;scrollbar-width:none}
  .sections::-webkit-scrollbar{display:none}
  .stile{flex:none;border-radius:var(--radius-pill);padding:var(--space-3) var(--space-4)}
  .stile .sabout{display:none}
  .engage{grid-template-columns:minmax(0,1fr);gap:var(--space-4)}
  .ecard{padding:var(--space-4) var(--space-6)}
  .etitle{font-size:15px}
  .ewho{font-size:14px}
}
@media (max-width:640px){.mgrid{grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--space-6) var(--space-4)}}
/* Элемент сетки не ужимается сам: сетка расписания внутри карточки задаёт
   минимальную ширину и распирала колонку за край экрана. */
.mgrid>*{min-width:0}
.mday{overflow:hidden}
.mcard{display:flex;flex-direction:column;gap:var(--space-3);color:var(--ink);
  text-decoration:none;transition:transform .35s cubic-bezier(.2,.8,.2,1)}
.mcard:hover{transform:translateY(-7px)}
/* Арка — визуальная подпись проекта: скругление сверху, прямые углы снизу. */
.arch{border-radius:100px 100px var(--radius-md) var(--radius-md);overflow:hidden}
.mphoto{position:relative;aspect-ratio:3/4}
.mphoto img{width:100%;height:100%;object-fit:cover;display:block}
/* Заглушки под съёмку: полосатые градиенты из токенов проекта, четыре вида,
   чтобы ряд карточек различался, пока фотографий нет.
   Имена начинаются со `stub`, а не с `ph`: последний занят иконочным шрифтом
   Phosphor, и свои классы с таким началом ломают все иконки. */
/* Базовая заглушка: сам класс отвечает за подпись по центру, оттенок задаёт
   второй класс. Имена начинаются со `stub`, чтобы не столкнуться с Phosphor. */
.stub{position:relative}
/* Обложка личной страницы: 21:9, знак проверки и статус поверх неё. */
.cover{position:relative;aspect-ratio:21/9;border-radius:var(--radius-lg);
  background-size:cover;background-position:center;
  margin:var(--space-4) 0 var(--space-8);overflow:hidden}
.cover .ver-cover{position:absolute;left:12px;bottom:12px;padding:5px 11px}
.cover .cover-status{position:absolute;right:12px;bottom:12px;padding:5px 11px}
.stub-rose{background:repeating-linear-gradient(150deg,oklch(.94 .045 26) 0 8px,oklch(.90 .055 22) 8px 16px)}
.stub-lilac{background:repeating-linear-gradient(150deg,oklch(.94 .04 292) 0 8px,oklch(.90 .05 288) 8px 16px)}
.stub-gold{background:repeating-linear-gradient(150deg,oklch(.95 .05 66) 0 8px,oklch(.91 .06 62) 8px 16px)}
.stub-red{background:repeating-linear-gradient(150deg,oklch(.93 .04 16) 0 8px,oklch(.89 .05 12) 8px 16px)}
.stub-cap{position:absolute;inset:auto 0 78px 0;text-align:center;
  font:400 8px/1.3 ui-monospace,Menlo,monospace;letter-spacing:.14em;text-transform:uppercase;
  color:oklch(.48 .07 24)}

/* Все пилюли поверх фото — по обязательному правилу спецификации. */
.pill{display:inline-flex;align-items:center;gap:5px;white-space:nowrap;line-height:1.3;
  border-radius:var(--radius-pill);font:500 9.5px/1.3 var(--font-body)}
.mphoto .pill{position:absolute}
.pill.status{box-shadow:var(--shadow-pill)}
.pill.status.s-free{background:var(--paper);color:var(--rouge-deep)}
.pill.status.s-free::before{content:"";width:4px;height:4px;border-radius:50%;
  background:var(--rouge);animation:blink 1.8s ease-in-out infinite}
.pill.status.s-from{background:var(--marigold);color:var(--ink)}
.pill.status.s-busy{background:oklch(.95 .006 20);color:var(--muted)}
.ov{position:absolute;bottom:10px;display:flex;flex-direction:column;gap:5px}
.ov.left{left:10px;align-items:flex-start}
.ov.right{right:10px;align-items:flex-end}
.ov .pill{position:static}
.pill.verify{padding:4px 9px;background:var(--verify-bg);color:var(--verify-ink)}
.pill.price{padding:5px 10px;background:var(--paper);color:var(--rouge-deep);
  font-size:10px;box-shadow:var(--shadow-pill)}
.pill.media{padding:4px 9px;background:rgba(74,42,38,.62);color:#fff;backdrop-filter:blur(3px)}
.pill.channel{padding:4px 9px;background:var(--paper);color:var(--lilac-ink);
  box-shadow:var(--shadow-pill)}
.pill[class*="badge-"]{padding:4px 8px;background:var(--marigold);color:var(--ink);font-size:9px}

/* Расписание и строка канала прижаты к низу: без этого они плавали внутри
   ряда, когда метка свежести переносилась на вторую строку, и карточки
   переставали сравниваться взглядом. */
.mbody{display:flex;flex-direction:column;gap:2px;flex:1}
/* Прижатие к низу оставляет над расписанием только зазор флекса в две точки,
   когда свободного места нет: просвет задаём отступом, а не полагаемся на него. */
.mbody .mdays{margin-top:auto;padding-top:var(--space-3)}
.mbody h3{margin:0;font:500 19px/1.05 var(--font-display)}
.mname{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-2)}
.counts{display:inline-flex;gap:7px;font:400 10px/1.3 var(--font-body);color:var(--muted);
  white-space:nowrap}
/* Цена — заголовок строки: она отвечает на первый вопрос гостя. */
.mprice{margin:3px 0 0;font:500 20px/1.1 var(--font-display);color:var(--rouge-deep)}
.mprice span{font:400 9px/1.3 var(--font-body);color:var(--muted);margin-left:4px}
.mprice .bydeal{font:400 12px/1.3 var(--font-body);color:var(--muted);margin:0}
.mmeta{margin:3px 0 0;font:400 10.5px/1.5 var(--font-body);color:var(--muted)}
.mtrust{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:5px 0 0;
  font:500 10px/1.3 var(--font-body)}
/* «Оценок пока нет» — не метрика, а её отсутствие: тем же кеглем, но тише,
   чтобы строка не читалась как плохая оценка. */
.noscore{color:var(--muted);font-weight:400}
.fresh-mark{padding:2px 7px;border-radius:var(--radius-pill);background:var(--bonus-bg);
  color:var(--muted);font:500 9px/1.3 var(--font-body);white-space:nowrap}
.fresh-mark.hot{background:var(--fresh-bg);color:var(--fresh-ink)}
.mnote{margin:4px 0 0;font:400 9.5px/1.3 var(--font-body);color:var(--muted)}
.mchan{margin:5px 0 0;font:500 10px/1.3 var(--font-body);color:var(--lilac-ink)}

/* Расписание на четыре дня. «?» и «отдых» — разные состояния и красятся
   по-разному: первое значит «мы не знаем», второе — «мастер не работает». */
.mdays{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:5px;margin-top:6px}
.mday{display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 2px;
  border-radius:var(--radius-sm);font:500 9px/1.2 var(--font-body);text-align:center}
.mday b{font:500 8px/1 var(--font-body);letter-spacing:.06em;text-transform:uppercase;
  opacity:.75}
.d-work{background:oklch(.96 .04 165);color:var(--verify-ink)}
.d-today{background:oklch(.97 .025 20);color:var(--rouge-deep)}
.d-off{background:oklch(.97 .01 20);color:var(--muted)}
.d-unknown{background:var(--paper);color:var(--muted);opacity:.6;
  box-shadow:inset 0 0 0 1px var(--line)}

/* Часы работы на странице карточки: вся неделя, сегодня выделено. Плитке хватает
   четырёх дней, здесь человек решает окончательно. Состояния красятся как в
   полоске: «отдых» — мастер не работает, «?» — график не подтверждён. */
.whours{background:var(--card);border-radius:var(--radius-md);padding:16px 18px 14px;
  box-shadow:0 1px 2px oklch(0 0 0/.05),inset 0 0 0 1px var(--line)}
.whours h2{font:600 15px/1.2 var(--font-display);margin:0 0 10px}
.whours ul{list-style:none;margin:0;padding:0;display:grid;gap:3px}
.whours .wd{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  padding:4px 8px;border-radius:var(--radius-sm);
  font:400 13px/1.3 var(--font-body)}
.whours .wd span{text-transform:uppercase;letter-spacing:.07em;font-size:11px;
  opacity:.8}
.whours .wd b{font-weight:500;font-variant-numeric:tabular-nums}
.whours .wd-work{background:oklch(.97 .03 165);color:var(--verify-ink)}
.whours .wd-off{background:oklch(.975 .008 20);color:var(--muted)}
.whours .wd-unknown{color:var(--muted);box-shadow:inset 0 0 0 1px var(--line)}
.whours .wd-today{outline:1.5px solid var(--rouge-deep);outline-offset:-1.5px}
.whours .meta{margin:10px 0 0}

/* Титул — ярлык у левого края под дугой арки, «новая» — тёмный ярлык справа. */
.title-tag{position:absolute;top:74px;left:0;padding:3px 9px 3px 8px;
  border-radius:0 var(--radius-pill) var(--radius-pill) 0;
  font:500 9px/1.3 var(--font-body);white-space:nowrap}
.t-premium{background:var(--marigold);color:var(--ink)}
.t-salon_star{background:var(--lilac);color:var(--paper)}
.t-tantra{background:var(--verify-bg);color:var(--verify-ink)}
.t-pro{background:#cfe4f5;color:#1d4f73}
.new-tag{position:absolute;top:102px;right:0;padding:3px 9px 3px 8px;
  border-radius:var(--radius-pill) 0 0 var(--radius-pill);background:var(--ro-ink);
  color:var(--paper);font:500 9px/1.3 var(--font-body)}
/* Значок канала — над плашкой верификации и не в одной полосе с титулом. */
/* Фраза мастера поверх фото — в одной линии со значком канала, слева от него. */
/* Слой поверх фото. Было: плотная плашка под фразой, плоские пилюли и мелкий
   значок в белом круге — набор наклеек на разных высотах. Стало: мягкий скрим
   по низу, фраза лежит прямо на нём, плашки стеклянные, всё в одном блоке. */
.scrim{position:absolute;inset:auto 0 0 0;height:58%;pointer-events:none;
  background:linear-gradient(to top,oklch(.20 .04 18/.80),
    oklch(.20 .04 18/.42) 38%,oklch(.20 .04 18/.06) 74%,transparent)}
.overlay{position:absolute;inset:auto 10px 10px 10px;display:flex;
  flex-direction:column;gap:8px}
/* У карточки с каналом нижний блок отступает справа: иначе плашки заезжают
   под значок и обрезаются краем фото. */
.overlay.with-chan{padding-right:38px}
.phrase{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;font:500 italic 13px/1.35 var(--font-display);color:#fff;
  text-shadow:0 1px 6px rgba(20,6,10,.6)}
.glassrow{display:flex;flex-wrap:wrap;align-items:center;gap:5px}
.glass{display:inline-flex;align-items:center;gap:5px;white-space:nowrap;
  padding:5px 11px;border-radius:var(--radius-pill);
  backdrop-filter:blur(10px) saturate(1.6);-webkit-backdrop-filter:blur(10px) saturate(1.6);
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.34);
  font:500 10px/1.3 var(--font-body);color:#fff}
.g-free{background:oklch(.62 .21 22/.72)}
.g-from{background:oklch(.80 .16 68/.82);color:oklch(.24 .05 40)}
.g-busy{background:oklch(1 0 0/.16)}
.g-checking{background:oklch(.80 .16 68/.72);color:oklch(.24 .05 40);
  padding:5px 9px;font-size:9.5px}
.g-verify{background:oklch(1 0 0/.16);padding:5px 9px;font-size:9.5px;
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.3)}
.glass .dot{width:5px;height:5px;border-radius:50%;background:currentColor;
  box-shadow:0 0 0 3px oklch(.60 .195 20/.28);animation:blink 1.8s ease-in-out infinite}
/* Значок канала: 22 точки в стеклянном круге 32, правый нижний угол. */
.chan-mark{position:absolute;right:10px;bottom:10px;z-index:1;display:inline-flex;
  align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;
  background:oklch(.22 .04 18/.34);backdrop-filter:blur(10px) saturate(1.6);
  -webkit-backdrop-filter:blur(10px) saturate(1.6);
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.36)}
.chan-mark svg{width:22px;height:22px}
.chan-mark i{position:absolute;right:-6px;bottom:-6px;font-style:normal;font-size:15px;
  filter:drop-shadow(0 1px 2px rgba(20,6,10,.5))}
/* Титул строкой — тот же ярлык, но в потоке текста. */
.title-tag.inline{position:static;border-radius:var(--radius-pill);padding:3px 10px}
/* Выбор причины жалобы: подпись последствия под каждой строкой. */
/* Общее правило формы `.rform label{display:block}` весит столько же, сколько
   класс строки, и стоит ниже — кружок выбора уезжал на строку выше подписи.
   Селектор с элементом и классом весит больше и не зависит от порядка. */
form label.radio-row,.radio-row{display:flex;align-items:flex-start;gap:var(--space-3);padding:var(--space-3) 0;
  border-bottom:1px solid var(--line);cursor:pointer}
.radio-row input{margin:3px 0 0;width:18px;height:18px;flex:none}
.radio-row span{display:flex;flex-direction:column;gap:var(--space-1)}
.radio-row b{font:500 14px/1.3 var(--font-body);color:var(--ink)}
.radio-row i{font-style:normal;font-size:12px;color:var(--muted)}
/* Голос редакции: портрет и реплика конкретного человека. */
.editor{display:grid;grid-template-columns:150px minmax(0,1fr);gap:var(--space-8);
  align-items:center;margin:calc(var(--space-8) * 1.6) 0;padding:var(--space-8);
  border:1px solid var(--bonus-edge);background:var(--bonus-bg);
  border-radius:var(--radius-lg)}
.editor-face{aspect-ratio:3/4;border-radius:75px 75px var(--radius-md) var(--radius-md);
  position:relative;overflow:hidden}
.editor picture{display:block}
img.editor-face{display:block;width:100%;height:auto;object-fit:cover;object-position:50% 30%}
.editor h2{margin:0 0 var(--space-3)}
.editor .lead{margin-bottom:var(--space-3)}
.more{margin-top:calc(var(--space-8) * 1.4);text-align:center}
/* Нумерация страниц каталога: окно вокруг текущей плюс края. Живёт для
   робота и без JS; лента с догрузкой прячет её скриптом. */
.pagenums{display:flex;flex-wrap:wrap;gap:6px;justify-content:center;
  margin-top:var(--space-6);font-variant-numeric:tabular-nums}
.pagenums a,.pagenums b,.pagenums .gap{min-width:36px;padding:6px 10px;text-align:center;
  border:1px solid var(--line);border-radius:var(--radius-md);text-decoration:none;
  color:var(--ink);font-weight:500}
.pagenums a:hover{border-color:var(--accent);color:var(--accent-text)}
.pagenums b{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
.pagenums .gap{border-color:transparent;color:var(--muted)}
.empty{margin:var(--space-8) 0;font-size:14px;color:var(--muted);max-width:60ch}

@media (prefers-reduced-motion:reduce){
  .blink,.marquee>span{animation:none}
  .mcard{transition:none}
  .mcard:hover{transform:none}
}


/* ═══════════════════════════════ онлайн-запись ═══════════════════════════ */

.steps{display:flex;flex-wrap:wrap;gap:var(--space-4);list-style:none;margin:var(--space-6) 0 0;
  padding:0;font:500 10px/1.3 var(--font-body);letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);counter-reset:st}
.steps li{counter-increment:st;display:inline-flex;align-items:center;gap:6px}
.steps li::before{content:counter(st);display:inline-flex;align-items:center;
  justify-content:center;width:18px;height:18px;border-radius:50%;
  border:1px solid var(--line);font-size:9px}
.steps li.on{color:var(--rouge-deep)}
.steps li.on::before{border-color:var(--rouge);background:var(--rouge);color:var(--paper)}
.steps li.done::before{border-color:var(--rouge);color:var(--rouge-deep)}

.pcards{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  gap:var(--space-4);margin:var(--space-6) 0}
.pcard{display:block;padding:var(--space-6);border:1px solid var(--line);
  border-radius:var(--radius-lg);color:var(--ink);text-decoration:none;
  transition:transform .25s ease,border-color .25s ease}
.pcard:hover{transform:translateY(-4px);border-color:var(--accent)}
.pcard h3{margin:0 0 var(--space-2)}
.ptag{margin:0 0 var(--space-3);font:500 10px/1.3 var(--font-body);letter-spacing:.12em;
  text-transform:uppercase;color:var(--rouge-deep)}
.pwhat{margin:0 0 var(--space-3);font-size:13px;line-height:1.6;color:var(--muted)}
.pfor{margin:0 0 var(--space-2);font-size:12px;color:var(--muted)}

.byday{margin:var(--space-3) 0}
.byday summary{cursor:pointer;font:500 13px/1.4 var(--font-body);color:var(--rouge-deep)}
.byday .schedule{margin:var(--space-2) 0 0;padding-left:var(--space-5)}

.days{display:flex;gap:var(--space-2);overflow-x:auto;padding-bottom:6px;margin:var(--space-6) 0}
.day{flex:none;display:flex;flex-direction:column;gap:2px;padding:9px 15px;
  border:1px solid var(--line);border-radius:var(--radius-lg);color:var(--ink);
  text-decoration:none;text-align:center}
.day b{font:500 14px/1.2 var(--font-body)}
.day span{font-size:10px;color:var(--muted)}
.day.on{border-color:var(--rouge);background:var(--bonus-bg)}

.mrow{padding:var(--space-6) 0;border-bottom:1px solid var(--line)}
.mrow-head{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-3)}
.mrow-head h3{margin:0}
.mrow-head a{text-decoration:none;color:var(--ink)}
.mrow-price{margin-left:auto;font:500 14px/1.3 var(--font-body);color:var(--rouge-deep)}
/* Снизу отступ обязателен: следующая кнопка вставала вплотную к последнему
   ряду окон, а при наведении поднимается на две точки и наезжала на него. */
.slots{display:flex;flex-wrap:wrap;gap:var(--space-2);
  margin:var(--space-3) 0 var(--space-4)}
.slots form{display:contents}
.slot{display:inline-flex;align-items:center;justify-content:center;white-space:nowrap;
  line-height:1.3;padding:9px 15px;border:1px solid var(--line);border-radius:var(--radius-pill);
  background:var(--paper);color:var(--ink);font:500 13px/1.3 var(--font-body);cursor:pointer}
.slot:hover{border-color:var(--rouge);color:var(--rouge-deep)}
/* Окно — белая пилюля с рамкой, и только главное действие залито гранатом.
   Правило `button[type=submit]` имеет специфичность выше класса и заливало
   окна тоже: ряд одинаковых кнопок сливался, а «Выбрать практику» читалась
   как ещё одно окно. Селектор ниже эту специфичность повторяет и идёт после. */
button[type=submit].slot{background:var(--paper);color:var(--ink);
  border:1px solid var(--line);font:500 13px/1.3 var(--font-body);padding:9px 15px;
  border-radius:var(--radius-pill)}
button[type=submit].slot:hover{border-color:var(--rouge);color:var(--rouge-deep)}
/* Занятое окно — пунктиром и без нажатия: фальшивый выбор хуже отсутствия выбора. */
.slot.busy{border-style:dashed;color:var(--muted);cursor:default;opacity:.7}
.slot.busy:hover{border-color:var(--line);color:var(--muted)}

.bsplit{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(0,1fr);
  gap:var(--space-8) calc(var(--space-8) * 2);align-items:start}
.bsum{border:1px solid var(--bonus-edge);background:var(--bonus-bg);
  border-radius:var(--radius-lg);padding:var(--space-6);position:sticky;top:var(--space-6);
  display:flex;flex-direction:column;gap:var(--space-3);align-items:flex-start}
.bsum>*{margin-top:0;margin-bottom:0;max-width:100%}
.bsum dl,.bsum .slots{width:100%}
.bsum.wide{position:static;max-width:520px;margin:var(--space-6) 0}
.bsum h2{margin:0 0 var(--space-4);font-size:20px}
.bsum dl{display:grid;grid-template-columns:auto 1fr;gap:var(--space-2) var(--space-4);margin:0}
.bsum dt{font-size:12px;color:var(--muted)}
.bsum dd{margin:0;font-size:13px}
.bsum-price{font:500 18px/1.2 var(--font-display);color:var(--rouge-deep)}
.hold{display:inline-block;padding:var(--space-3) var(--space-4);border-radius:var(--radius-md);
  background:var(--bonus-bg);border:1px solid var(--bonus-edge);font-size:13px;
  margin:var(--space-4) 0 var(--space-3)}
.hold b{font-variant-numeric:tabular-nums;color:var(--rouge-deep)}
.extend{margin:0 0 var(--space-6)}
.ferr{display:block;margin:4px 0 var(--space-3);font-size:11px;color:var(--rouge-deep)}
.input{width:100%;max-width:420px;padding:9px 12px;border:1px solid var(--line);
  border-radius:var(--radius-md);background:var(--paper);color:var(--ink);
  font:400 14px/1.4 var(--font-body)}
.input[aria-invalid]{border-color:var(--rouge)}
.chan{border:0;padding:0;margin:0 0 var(--space-4)}
.chan legend{padding:0;font-size:12px;color:var(--muted)}
.chan .radio{display:inline-flex;align-items:center;gap:6px;margin-right:var(--space-6)}
.what-next{max-width:60ch;font-size:14px;line-height:1.7;color:var(--muted)}
.what-next li{margin-bottom:var(--space-2)}

/* Классы, которые стояли в разметке без единого правила: у них не было ни
   отступов, ни ритма, и строки внутри слипались. */
.faq{margin:0 0 var(--space-8);max-width:66ch}
.faq dt{margin-top:var(--space-6);font:500 16px/1.3 var(--font-display)}
.faq dd{margin:var(--space-2) 0 0;font-size:14px;line-height:1.7;color:var(--muted)}
.text{margin:0 0 var(--space-8);max-width:66ch;font-size:14px;line-height:1.8;
  color:var(--muted)}
.text p{margin:0 0 var(--space-4)}
.answer{margin:var(--space-3) 0 0;padding-left:var(--space-4);
  border-left:2px solid var(--bonus-edge);font-size:13px;color:var(--muted)}
.hours{margin:0 0 var(--space-4);font-size:14px}
.hours-line{margin:0 0 var(--space-4);font-size:15px}
.posts{display:flex;flex-direction:column;gap:var(--space-4);margin:0 0 var(--space-8)}
.review{padding:var(--space-4) 0;border-bottom:1px solid var(--line)}
.review:last-child{border-bottom:0}
.hero-copy{min-width:0}
.bpanel{border:1px solid var(--bonus-edge);background:var(--bonus-bg);
  border-radius:var(--radius-lg);padding:var(--space-6);margin:var(--space-6) 0;
  max-width:560px;display:flex;flex-direction:column;gap:var(--space-3);
  align-items:flex-start}
.bpanel>*{margin-top:0;margin-bottom:0}
.bpanel-head{margin:0 0 var(--space-3);font:500 16px/1.2 var(--font-display)}
.bpanel .meta{margin:var(--space-3) 0 var(--space-4)}

/* Форма контакта: подпись сверху, поле под ней. В строку они складывались в
   кашу — «Телефон [поле] Промокод [поле]» вперемешку с согласиями. Правило
   действует на всех ширинах, а не только на телефоне. */
.bsplit form label{display:block;margin:0 0 var(--space-4);font-size:13px;color:var(--muted)}
.bsplit form label .input,.bsplit form label>input,.bsplit form label>textarea{
  display:block;margin-top:5px}
/* Галочка слева, текст обычным потоком: иначе согласие разрывается посреди фразы. */
.bsplit form label:has(input[type=checkbox]){position:relative;padding-left:28px;
  color:var(--ink);line-height:1.5}
.bsplit form label:has(input[type=checkbox])>input[type=checkbox]{position:absolute;
  left:0;top:2px;width:18px;height:18px;margin:0}
.bsplit form .chan label{display:inline-flex;margin:0 var(--space-6) 0 0;color:var(--ink)}
.bsplit form .chan label>input{margin:0}
/* Второстепенная кнопка остаётся контурной и будучи `submit`: правило
   `button[type=submit]` имеет специфичность выше и без этого заливает её. */
button.btn.secondary{background:var(--paper);color:var(--ink);border-color:var(--line)}
button.btn.secondary:hover{border-color:var(--accent);color:var(--accent-text)}


/* ═════════════════ практики, отзывы, правила, каналы ═════════════════════ */

.facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:var(--space-6);margin:var(--space-8) 0}
.facts .bignum{font-size:32px}
.facts span{font-size:12px;color:var(--muted);display:block;margin-top:5px}

.pcard.static{cursor:default}
.pcard.static:hover{transform:none;border-color:var(--line)}
.pprice{margin:0 0 var(--space-3);font:500 15px/1.3 var(--font-body);color:var(--rouge-deep)}
.pint{margin:var(--space-3) 0;font-size:11px;color:var(--muted);letter-spacing:.2em}
.plain{margin:0 0 var(--space-6);padding-left:18px;font-size:14px;line-height:1.8;
  color:var(--muted);max-width:66ch}
.plain li{margin-bottom:var(--space-2)}
.threecol{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:var(--space-8);margin:var(--space-8) 0}
.threecol h3{margin:0 0 var(--space-3);font-size:17px}
.doclist{list-style:none;padding:0;margin:0 0 var(--space-8);font-size:14px}
/* Список документов: ссылка и пояснение — одна строка, и на телефоне пояснение
   наезжало на ссылку, потому что у ссылки там строчный отступ сверху и снизу. */
.doclist li{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--space-2);
  padding:var(--space-4) 0;border-bottom:1px solid var(--line)}
.doclist li:last-child{border-bottom:0}
/* Списки без класса тоже получают воздух: голый `ul` встречается на страницах
   станции и в кабинете, и строки в нём слипались. */
.wrap ul:not([class]) li,.wrap ol:not([class]) li{margin-bottom:var(--space-2)}

/* Таблица использовалась на правилах и в кабинете салона, но оформлена не была:
   ячейки стояли вплотную, строки сливались. */
.table{width:100%;border-collapse:collapse;font-size:14px;margin:0 0 var(--space-6)}
.table th{text-align:left;padding:var(--space-3) var(--space-4) var(--space-3) 0;
  font:500 10px/1.3 var(--font-body);letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);border-bottom:1px solid var(--line);white-space:nowrap}
.table td{padding:var(--space-4) var(--space-4) var(--space-4) 0;
  border-bottom:1px solid var(--line);vertical-align:top}
.table th:last-child,.table td:last-child{padding-right:0}
.tablewrap{overflow-x:auto;margin:0 0 var(--space-6)}

/* Распределение оценок. Рисуется только на выборке от двадцати отзывов. */
.bars{display:flex;flex-direction:column;gap:var(--space-2);max-width:520px;
  margin:0 0 var(--space-8)}
.bar{display:grid;grid-template-columns:52px 1fr 44px;align-items:center;gap:var(--space-3);
  font-size:12px;color:var(--muted)}
.bar-track{height:7px;border-radius:var(--radius-pill);background:var(--bonus-bg);
  border:1px solid var(--bonus-edge);overflow:hidden}
.bar-fill{display:block;height:100%;border-radius:var(--radius-pill);
  background:linear-gradient(90deg,var(--marigold),var(--rouge))}
.bar-value{text-align:right;font-variant-numeric:tabular-nums}

.rlist{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));
  gap:var(--space-4);margin:var(--space-6) 0}
.rcard{border:1px solid var(--line);border-radius:var(--radius-lg);padding:var(--space-6)}
.rchips{display:flex;flex-wrap:wrap;gap:var(--space-2);margin-bottom:var(--space-3)}
.pill.neutral{padding:3px 9px;background:var(--bonus-bg);color:var(--muted);
  border:1px solid var(--bonus-edge)}
.rwho{margin:0 0 var(--space-2);font-size:12px;color:var(--muted)}
.rwho a{color:var(--ink)}
.rtext{margin:0 0 var(--space-3);font-size:14px;line-height:1.7}
.ranswer{margin:0 0 var(--space-2);padding-left:var(--space-4);
  border-left:2px solid var(--bonus-edge);font-size:13px;color:var(--muted)}
.pages{display:flex;gap:var(--space-4);align-items:center;font-size:13px;
  margin:var(--space-6) 0}

/* Карточка канала: превью размыты всегда, это условие мастера. */
.mcard.static{cursor:default}
.mcard.static:hover{transform:none}
.blurred{filter:blur(3px)}
.progress{height:8px;border-radius:var(--radius-pill);background:var(--bonus-bg);
  border:1px solid var(--bonus-edge);overflow:hidden;max-width:520px;margin:var(--space-4) 0}
.progress-fill{display:block;height:100%;border-radius:var(--radius-pill);
  background:linear-gradient(90deg,var(--marigold),var(--rouge))}
.rform{max-width:520px;margin:var(--space-6) 0}
.rform label{display:block;margin:0 0 var(--space-4);font-size:13px;color:var(--muted)}
.rform label .input{display:block;margin-top:5px}
.rform label:has(input[type=checkbox]){position:relative;padding-left:28px;color:var(--ink)}
.rform label:has(input[type=checkbox])>input[type=checkbox]{position:absolute;left:0;top:2px;
  width:18px;height:18px;margin:0}
.catalog{display:grid;grid-template-columns:240px minmax(0,1fr);
  gap:var(--space-8) calc(var(--space-8) * 1.6);align-items:start;margin-top:var(--space-6)}
.filters{position:sticky;top:var(--space-6)}
.filters h2{margin:0 0 var(--space-4);font-size:20px}
.filters .chip{display:inline-flex;margin:0 var(--space-2) var(--space-2) 0}
.chip.on{border-color:var(--rouge);background:var(--bonus-bg);color:var(--rouge-deep)}
.fgroup{margin:var(--space-6) 0 var(--space-3);font:500 10px/1.3 var(--font-body);
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.pricefilter{display:flex;gap:var(--space-2);align-items:center}
.pricefilter .input{width:110px}
.chips.sorts{margin-bottom:var(--space-6)}
.results .grid-head{margin-top:0}

/* Тумблер: в дизайн-системе его нет, а нужен в трёх кабинетах. */
.switch{display:inline-flex;align-items:center;gap:var(--space-3);cursor:pointer;
  font-size:13px}
.switch input{position:absolute;opacity:0;width:0;height:0}
.switch .track{width:38px;height:22px;border-radius:var(--radius-pill);background:var(--paper);
  border:1px solid var(--line);position:relative;transition:background .2s ease,
  border-color .2s ease;flex:none}
.switch .track::after{content:"";position:absolute;left:2px;top:2px;width:16px;height:16px;
  border-radius:50%;background:var(--muted);transition:transform .2s ease,background .2s ease}
.switch input:checked+.track{background:var(--rouge);border-color:var(--rouge)}
.switch input:checked+.track::after{transform:translateX(16px);background:var(--paper)}
.switch input:focus-visible+.track{outline:2px solid var(--accent);outline-offset:2px}

/* Бегущая строка ленты. Останавливается при prefers-reduced-motion. */
.marquee{overflow:hidden;-webkit-mask-image:linear-gradient(to right,transparent,#000 24px,
  #000 calc(100% - 24px),transparent);mask-image:linear-gradient(to right,transparent,#000 24px,
  #000 calc(100% - 24px),transparent)}
.marquee>span{display:inline-flex;gap:var(--space-6);white-space:nowrap;
  animation:marquee 26s linear infinite}
@keyframes marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}

/* Плитка загрузки файлов в кабинете. */
.upload-tile{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:var(--space-2);aspect-ratio:3/4;border:1px dashed var(--rouge);
  border-radius:var(--radius-md);color:var(--rouge-deep);font-size:12px;text-align:center;
  padding:var(--space-4);cursor:pointer;background:var(--bonus-bg)}

/* Нижняя навигация телефона. */
.tabbar{display:none}
.mcard.static .mbody form{margin-top:var(--space-3)}


/* ═══════════════════════════════ анкета мастера ═══════════════════════════ */

.topline{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-4);
  margin:var(--space-4) 0 var(--space-6)}
.back{margin:0;font-size:13px}
.topline form{margin-left:auto}
.mpage{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(0,1fr);
  gap:var(--space-8) calc(var(--space-8) * 2);align-items:start}
.mmain{min-width:0}
.mside{min-width:0;position:sticky;top:var(--space-6);display:flex;flex-direction:column;
  gap:var(--space-4)}
.mside h2{margin:var(--space-6) 0 var(--space-3);font-size:20px}
.mmeta+.quote{margin-top:var(--space-4)}
/* Страница салона: кабинеты списком, «что входит» и «как войти» — простые
   перечисления, их читают глазами по одному, а не сравнивают между собой. */
.cabins{list-style:none;display:flex;flex-wrap:wrap;gap:var(--space-3);
  margin:var(--space-3) 0 var(--space-6);padding:0}
.cabins li{display:flex;align-items:baseline;gap:6px;padding:7px 13px;
  border:1px solid var(--line);border-radius:var(--radius-pill);font-size:12px}
.cabins b{font-weight:500}
.cabins span{color:var(--muted)}
.included{margin:var(--space-3) 0 var(--space-6);padding-left:var(--space-6);
  font-size:14px;line-height:1.8;color:var(--ink)}
.entrance{margin:var(--space-3) 0 var(--space-4);max-width:52ch;font-size:14px;
  line-height:1.7;color:var(--muted)}

/* Строки списка и раскрывашки стояли вплотную: у них нет собственных
   отступов, а межстрочный интервал просветом между пунктами не работает. */
li+li{margin-top:var(--space-1)}
/* Таблицы без класса тоже нужно кормить отступами: заголовки колонок клуба
   стояли в двух точках друг от друга. Правило по элементу — класс `.table`
   со своими значениями по-прежнему сильнее. */
table{border-collapse:collapse}
th,td{padding:var(--space-2) var(--space-4) var(--space-2) 0;vertical-align:top}
details{margin:var(--space-4) 0}
fieldset legend{margin-bottom:var(--space-2)}

/* Числа кабинета: величина крупно, подпись мелко, пояснение ещё мельче. */
/* Сам сертификат: крупная сумма, код моноширинным — его диктуют голосом. */
.certbox{border:1px solid var(--bonus-edge);border-radius:var(--radius-lg);
  background:var(--bonus-bg);padding:var(--space-8);margin:var(--space-6) 0;
  max-width:520px}
.certsum{margin:0 0 var(--space-3);font:500 42px/1 var(--font-display);
  color:var(--rouge-deep);font-variant-numeric:tabular-nums}
.certcode{margin:0 0 var(--space-3);font:500 22px/1.2 ui-monospace,Menlo,monospace;
  letter-spacing:.08em;color:var(--ink)}
.numbers{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:var(--space-6);margin:var(--space-4) 0 var(--space-6)}
.numbers div{display:flex;flex-direction:column;gap:2px;min-width:0}
.numbers b{font:500 26px/1 var(--font-display);color:var(--rouge-deep);
  font-variant-numeric:tabular-nums}
.numbers span{font-size:11px;color:var(--muted)}
.numbers i{font-style:normal;font-size:11px;color:var(--faint,var(--muted));opacity:.85}

/* Галерея кабинета: порядок кадров задаётся перетаскиванием, метки читаются
   поверх кадра. Имена меток свои (`m-`): `.chan` и `.wait` в этом файле уже
   значат другое, и общее имя отдало бы кадру чужой вид. */
.gallery.drag figure{position:relative;cursor:grab;transition:opacity .2s;
  aspect-ratio:3/4;overflow:hidden;border-radius:var(--radius-md);margin:0}
.gallery.drag figure img{width:100%;height:100%;object-fit:cover;display:block}
.gallery.drag figcaption{position:absolute;left:0;right:0;bottom:0;
  padding:4px 7px;background:rgba(255,255,255,.86);text-align:right}
.gallery.drag .stub-cap{position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);font:400 8px/1.3 var(--font-body);
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.gallery.drag figure.dragging{opacity:.35;cursor:grabbing}
.gallery.drag figure.over{outline:2px dashed var(--accent);outline-offset:2px}
.marks{position:absolute;left:6px;top:6px;display:flex;flex-wrap:wrap;gap:4px;
  max-width:calc(100% - 12px)}
.mark{padding:2px 7px;border-radius:var(--radius-pill);font:500 9px/1.4 var(--font-body);
  white-space:nowrap;background:var(--paper);color:var(--muted);
  box-shadow:inset 0 0 0 1px var(--line)}
.m-main{background:var(--rouge);color:var(--paper);box-shadow:none}
.m-vid{background:var(--bonus-bg);color:var(--ro-ink)}
.m-chan{background:var(--lilac);color:var(--paper);box-shadow:none}
.m-wait{background:var(--fresh-bg);color:var(--fresh-ink);box-shadow:none}
.order-form{margin:0 0 var(--space-4)}
/* Строка кабинета: имя, состояние и два действия в одну линию. Каждый
   элемент своей формой уводил кнопку на новый ярус, и семь кабинетов
   занимали целый экран. */
.cabinrow{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-3)}
.cabinrow form{display:flex;align-items:center;gap:var(--space-2);margin:0}
.cabinrow b{min-width:110px}
.cabinrow .input{width:auto;min-width:120px}
.inline-del{display:inline-block;margin:0 var(--space-3) var(--space-3) 0}

/* Вход через телеграм: виджет рисует сам телеграм, наше дело — место под него
   и обещания приватности рядом, чтобы их читали до нажатия, а не после. */
.tg-login{margin:var(--space-6) 0;min-height:48px}
.promises{margin:0 0 var(--space-8);padding-left:var(--space-6);color:var(--muted);
  font-size:13px;line-height:1.7}

/* Личная страница мастера: четыре акцента из палитры проекта. Меняются только
   смысловые имена — правила ниже написаны через них и подхватывают цвет сами. */
.acc-rouge{--accent:var(--rouge);--accent-text:var(--rouge-deep);--on-accent:var(--paper)}
.acc-marigold{--accent:var(--marigold);--accent-text:var(--fresh-ink);--on-accent:var(--ro-ink)}
.acc-lilac{--accent:var(--lilac);--accent-text:var(--lilac-ink);--on-accent:var(--paper)}
.acc-mint{--accent:var(--mint);--accent-text:var(--verify-ink);--on-accent:var(--paper)}
/* Крупные числа и цена внутри личной страницы берут её акцент, а не гранат. */
.lpage .bignum,.lpage .mprice,.lpage .metrics b,
.lpage h2{color:var(--accent-text)}
.lpage{display:contents}
.quote{margin:0 0 var(--space-6);max-width:52ch;font:400 15px/1.7 var(--font-body);
  color:var(--muted)}
.badges{display:flex;flex-wrap:wrap;gap:var(--space-2);margin-bottom:var(--space-8)}
.pill.fresh-pill{padding:3px 9px;background:var(--fresh-bg);color:var(--fresh-ink)}

/* Панель метрик: четыре числа из отзывов, крупно и без украшений. */
.metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));
  gap:var(--space-4);padding:var(--space-6);border:1px solid var(--line);
  border-radius:var(--radius-lg);margin-bottom:var(--space-8)}
.metrics div{display:flex;flex-direction:column;gap:2px}
.metrics b{font:500 26px/1 var(--font-display);color:var(--rouge-deep)}
.metrics span{font-size:11px;color:var(--muted)}
.metrics i{font-style:normal;font-size:11px;color:var(--muted)}

/* Галерея: арочный портрет 4:5 и два кадра 4:3 рядом. */
.gallery-arch{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(0,1fr);
  gap:var(--space-3);margin-bottom:var(--space-8)}
.arch-hero{border-radius:190px 190px var(--radius-md) var(--radius-md);overflow:hidden}
.ghero{position:relative;aspect-ratio:4/5}
.ghero img{width:100%;height:100%;object-fit:cover;display:block}
.gframes{display:flex;flex-direction:column;gap:var(--space-3)}
.gframe{position:relative;flex:1;aspect-ratio:4/3;border-radius:var(--radius-md);
  overflow:hidden}
.gframe img{width:100%;height:100%;object-fit:cover;display:block}
.gmore{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  background:rgba(74,42,38,.45);color:var(--paper);font:500 24px/1 var(--font-display);
  backdrop-filter:blur(2px)}

.params{display:grid;grid-template-columns:auto 1fr;gap:var(--space-2) var(--space-6);
  margin:0 0 var(--space-8);max-width:520px}
.params dt{font-size:12px;color:var(--muted)}
.params dd{margin:0;font-size:14px}

/* Блок канала. Превью размыты всегда — это условие мастера. */
.chanbox{border:1px solid var(--line);border-radius:var(--radius-lg);
  padding:var(--space-6);margin-bottom:var(--space-8);max-width:560px}
.chanbox p{font-size:13px;line-height:1.7;color:var(--muted)}
.chanpreview{display:flex;gap:var(--space-2);margin-bottom:var(--space-4)}
.chanpreview span{flex:1;aspect-ratio:3/4;border-radius:var(--radius-sm);max-width:90px}

.refcode{margin:var(--space-3) 0 0;font:500 13px/1.3 var(--font-body);
  letter-spacing:.12em;color:var(--rouge-deep)}
.nearby{display:flex;flex-direction:column;gap:var(--space-2)}
/* Колонки задаются явно: при автоматической расстановке цена уезжала в первую
   ячейку и вставала перед именем. */
.nrow{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px var(--space-3);
  padding:var(--space-3) var(--space-4);border:1px solid var(--line);
  border-radius:var(--radius-md);text-decoration:none;color:var(--ink)}
.nrow:hover{border-color:var(--accent)}
.nname{grid-column:1;grid-row:1;font:500 15px/1.2 var(--font-display)}
.nmeta{grid-column:1;grid-row:2;font-size:11px;color:var(--muted)}
.nprice{grid-column:2;grid-row:1 / span 2;align-self:center;font-size:13px;
  color:var(--rouge-deep);white-space:nowrap}

/* ---- телефон и планшет: правила идут последними, чтобы перекрывать базовые ----
   Условие двойное. Тип указателя ловит настоящие телефоны и планшеты, где
   ширина окна равна ширине экрана. Ширина ловит узкое окно на мониторе: без
   неё каталог оставался там в две колонки, и выдаче доставалось 82 точки из
   390 — карточки уезжали за край, а страница ехала вбок. */
@media (max-width:640px),(pointer:coarse){
  /* Миниатюра занимала треть ширины, и текст ломался посреди цены. */
  .card{gap:10px;padding:12px 12px 14px;flex-wrap:wrap}
  .card>a.thumb{flex:0 0 72px}
  .card .thumb{width:72px;height:72px;font-size:26px}
  .card h3{margin:0}
  /* Ссылка остаётся строчной: `inline-block` из общего правила для `h3 a`
     ломает обрезку в две строки, и длинное название занимало три. Отступ
     сохраняется — у строчного элемента он расширяет область нажатия, не
     двигая вёрстку. */
  .card h3 a{display:inline;padding:7px 0}
  .card .tags{gap:4px}
  .card .tags span{font-size:12px;padding:2px 6px}
  /* `flex-basis` тут задаёт уже не ширину, а высоту: действия переехали
     внутрь колоночного тела карточки, и 100% растягивали строку кнопок
     на всю карточку — они вылезали за нижний край. */
  h2{font-size:19px;margin-top:18px}
  .crumbs{margin-bottom:8px}
  /* Часы работы: семь строк по четыре колонки не помещались, и колонка
     «выходной» оставалась за краем экрана. Раскладываем по дням. */
  .schedule,.schedule tbody{display:block;width:100%}
  .schedule tr{display:grid;grid-template-columns:1fr 1fr;gap:8px 10px;align-items:center;
    padding:10px 0;border-bottom:1px solid var(--line)}
  .schedule th,.schedule td{display:block;padding:0}
  .schedule th{grid-column:1 / -1;text-align:left;font-weight:600}
  .schedule td:last-child{grid-column:1 / -1}
  .schedule td label{display:flex;align-items:center;gap:8px;margin:0}

  /* --- запись на телефоне --- */
  .bsplit{grid-template-columns:1fr;gap:var(--space-6)}
  /* `1fr` берёт минимум по содержимому, и колонка фильтров не ужималась под
     чипами с запретом переноса: нужен явный ноль. */
  .catalog{grid-template-columns:minmax(0,1fr);gap:var(--space-6)}
  /* Анкета на телефоне: одна колонка, панель записи в потоке, не липкая. */
  .mpage{grid-template-columns:minmax(0,1fr);gap:var(--space-6)}
  .mside{position:static}
  .gallery-arch{grid-template-columns:minmax(0,1fr)}
  .arch-hero{border-radius:130px 130px var(--radius-md) var(--radius-md)}
  .gframes{flex-direction:row}
  .metrics{grid-template-columns:repeat(2,1fr);padding:var(--space-4)}
  .filters{min-width:0}
  .filters .chip{max-width:100%}
  .tabbar{display:grid;grid-template-columns:repeat(5,1fr);position:fixed;left:0;right:0;
    bottom:0;z-index:25;background:var(--paper);border-top:1px solid var(--line);
    padding-bottom:env(safe-area-inset-bottom)}
  .tabbar a{padding:12px 4px;text-align:center;font-size:11px;color:var(--muted);
    text-decoration:none}
  .tabbar a:hover{color:var(--accent-text)}
  /* Место под панель, чтобы она не закрывала подвал. */
  body:has(.tabbar) .wrap:not(.wrap-chrome){padding-bottom:76px}
  /* Липкая панель карточки и таб-бар не соседствуют: побеждает панель. */
  body:has(.stickybar) .tabbar{display:none}
  .filters{position:static}
  .filters .chip{padding:9px 14px}
  .facts{grid-template-columns:repeat(2,1fr);gap:var(--space-4)}
  .editor{grid-template-columns:minmax(0,1fr);gap:var(--space-4);padding:var(--space-6)}
  .editor-face{max-width:140px}
  .rlist{grid-template-columns:1fr}
  .threecol{grid-template-columns:1fr;gap:var(--space-6)}
  .bsum{position:static}
  .pcards{grid-template-columns:1fr}
  .steps{gap:var(--space-3);font-size:9px}
  .slot{padding:11px 16px}

  /* --- витрина на телефоне: две колонки, арка ниже --- */
  .hero{grid-template-columns:1fr;gap:var(--space-6)}
  .mgrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-6) var(--space-4)}
  /* Кегли на телефоне на полтора пункта меньше — так задано спецификацией. */
  .mbody h3{font-size:17px}
  .mprice{font-size:18px}
  .mday{padding:3px 1px;font-size:8px}
  .overlay{inset:auto 6px 6px 6px;gap:5px}
  .overlay.with-chan{padding-right:24px}
  .phrase{font-size:9px;line-height:1.3;text-shadow:0 1px 4px rgba(20,6,10,.6)}
  .glass{padding:3px 7px;font-size:8.5px;gap:3px}
  .g-verify{padding:3px 6px;font-size:8px}
  .glass .dot{width:4px;height:4px;box-shadow:0 0 0 2px oklch(.60 .195 20/.28)}
  .chan-mark{right:6px;bottom:6px;width:22px;height:22px}
  .chan-mark svg{width:16px;height:16px}
  .chan-mark i{right:-4px;bottom:-4px;font-size:10px}
  .scrim{height:52%}
  /* Ниже восьми точек не опускаемся — это правило набора, а не вкус: буквы
     дня в семь точек на телефоне уже не читаются, а именно по ним человек
     выбирает вечер. */
  .mday b{font-size:8px}
  .counts{font-size:9px;gap:5px}
  .arch{border-radius:82px 82px var(--radius-md) var(--radius-md)}
  .mbody h3{font-size:17px}
  .grid-head{gap:var(--space-3)}
  /* Горизонтальный ряд полей не имеет: карточки должны уходить под край
     экрана — обрезанный элемент это единственная понятная подсказка, что ряд
     листается. Но крайние к самому стеклу не прилипают: выходим из полей
     контейнера и возвращаем отступ изнутри. */
  .chips,.scroll-row{margin-left:-16px;margin-right:-16px;
    padding-left:16px;padding-right:16px;
    overflow-x:auto;scrollbar-width:none;scroll-snap-type:x proximity;
    scroll-padding-left:16px;scroll-padding-right:16px}
  .chips{flex-wrap:nowrap;padding-bottom:4px}
  .chips::-webkit-scrollbar,.scroll-row::-webkit-scrollbar{display:none}
  .chips>*,.scroll-row>*{scroll-snap-align:start;flex:none}
  .scroll-row{display:flex;gap:var(--space-3)}
  .chip{flex:none;padding:9px 14px}
  .mcard{gap:var(--space-2)}

  /* Список — первым: за текстом станции на телефоне полтора экрана прокрутки. */
  .station-page{display:flex;flex-direction:column}
  .station-page .station-text{order:5;margin-top:22px;padding-top:14px;
    border-top:1px solid var(--line)}

  /* ---- справочник на телефоне ---- */
  h1{font-size:23px;margin-top:16px}
  .bignum{font-size:32px}
  .stats{gap:24px}
  .entry{gap:16px;margin:16px 0 12px}
  .station-field input{width:100%;height:52px;font-size:16px}
  /* Четыре колонки станций на 390 точках дают колонку в 80 пикселей: строка
     «Александровский сад 12 салонов» в неё не помещается ни при каком кегле. */
  .hub-stations{columns:1}
  .hub-station{padding:9px 0}
  .card .thumb{width:72px;height:72px;font-size:26px}
  .card-actions{flex-wrap:wrap}
  .card-actions .btn{flex:1 1 auto;text-align:center;min-width:0}
  footer.site .wrap-chrome{grid-template-columns:1fr;gap:18px}
  /* Ворота нижним листом: до кнопки на телефоне дотягивается большой палец. */
  .age-gate{padding:0;align-items:flex-end}
  .age-gate .box{margin-bottom:0;width:100%;max-width:none;border-radius:20px 20px 0 0;
    padding:20px 16px calc(20px + env(safe-area-inset-bottom))}
}

/* Таблицы статистики: кабинет карточки и сводная панель */
.table-scroll{overflow-x:auto;max-width:100%}
table.behaviour{border-collapse:collapse;font-size:14px;min-width:100%}
table.behaviour th,table.behaviour td{padding:5px 10px;border-bottom:1px solid var(--line);
  text-align:left;vertical-align:top}
table.behaviour th{font-weight:600;color:var(--muted);font-size:12px}
table.behaviour td.num,table.behaviour th.num{text-align:right;font-variant-numeric:tabular-nums}
.grid-2{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px 24px}
/* Станция в заголовке карточки: отдельная строка, имя остаётся главным */
.h1-where{display:block;margin-top:.45em;font-family:var(--font-body);font-weight:500;
  font-size:max(.36em,14px);line-height:1.3;color:var(--muted);letter-spacing:0}
/* Чистый режим (переход из рекламы): непроверенный кадр закрыт пеленой */
.veiled{background:linear-gradient(160deg,var(--rouge-deep,#7a2a2a),#2a1416);display:flex;
  align-items:center;justify-content:center;cursor:default}
.veil-cap{color:#fff;font:600 13px/1 var(--font-body);letter-spacing:.08em;text-transform:uppercase;
  opacity:.85;border:1px solid rgba(255,255,255,.5);border-radius:999px;padding:6px 12px}
/* Раздел «Директ» в кабинете */
.linkform.inline{display:inline}
/* Кнопка-ссылка: общий стиль button красит её в полноразмерную кнопку */
.linkform.inline button.linkbtn{border:0;background:none;box-shadow:none;padding:0;min-height:0;
  width:auto;font:inherit;color:var(--rouge-deep);cursor:pointer;text-decoration:underline;border-radius:0}
.direct-login{max-width:360px;display:flex;flex-direction:column;gap:var(--space-3)}
.direct-login input{width:100%;padding:10px 12px;border:1px solid var(--line);border-radius:var(--radius-md);font:inherit}
.direct-error{border-left-color:var(--rouge)}
