/* Публичная страница салона — «Cinematic Noir».
 *
 * Задача страницы: тенант открывает её впервые и говорит «вау», а его клиент
 * доходит до кнопки записи. Отсюда решения:
 *   • почти чёрный холст — фото работ на нём выглядят дороже всего;
 *   • акцент владельца (--accent) не красит блоки, а СВЕТИТСЯ: аура за хиро,
 *     подсветка активных элементов. Один цвет на всю страницу, без радуги;
 *   • движение только через transform/opacity (GPU), параллакс — на CSS
 *     scroll-timeline там, где браузер умеет, иначе просто статичный кадр;
 *   • backdrop-blur только на фиксированных элементах (навигация, шторка карты) —
 *     на скроллящемся контенте он роняет мобильный фреймрейт.
 *
 * Один файл на все салоны (кэшируется), персонализация — inline-токеном --accent.
 */

/* Гарнитуры страницы лежат У НАС (web/static/fonts, вшиты в бинарь), а не на
   Google Fonts: страница салона открывается его клиентами, и лишний запрос к
   третьей стороне — это и задержка на слабой сети, и утечка визита. Переменные
   шрифты, unicode-range разводит кириллицу и латиницу.
   Latin-ext у Unbounded намеренно не берём: 114 КБ ради редких глифов, которые
   подставит системный фолбэк. */
  @font-face {
    font-family: 'Unbounded'; font-style: normal; font-weight: 600 700;
    font-display: swap; src: url('/static/fonts/unbounded-cyrillic.woff2') format('woff2');
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
  }
  @font-face {
    font-family: 'Unbounded'; font-style: normal; font-weight: 600 700;
    font-display: swap; src: url('/static/fonts/unbounded-latin.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: 'Onest'; font-style: normal; font-weight: 400 700;
    font-display: swap; src: url('/static/fonts/onest-cyrillic.woff2') format('woff2');
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
  }
  @font-face {
    font-family: 'Onest'; font-style: normal; font-weight: 400 700;
    font-display: swap; src: url('/static/fonts/onest-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
  }
  @font-face {
    font-family: 'Onest'; font-style: normal; font-weight: 400 700;
    font-display: swap; src: url('/static/fonts/onest-latin.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;
  }

/* ─── Токены ────────────────────────────────────────────────────────────── */
:root {
  --ink: #08080b;          /* холст: почти чёрный с холодным подтоном */
  --ink-2: #0e0e13;        /* приподнятая поверхность */
  --paper: #f4f4f7;        /* основной текст */
  --paper-dim: rgba(244, 244, 247, .58);
  /* .34 на --ink даёт 2.9:1 — ниже AA даже для крупного текста. Поэтому faint
     только ДЕКОР: точки, штрихи, черта прокрутки. Любой текст, который читают
     (длительность услуги, согласие, подвал, «выходной»), берёт --paper-dim
     (6.35:1). Аудит 07.09.2026: им были набраны в том числе согласие на
     обработку ПДн и подписи отзывов. */
  --paper-faint: rgba(244, 244, 247, .34);
  --hair: rgba(255, 255, 255, .09);   /* волосяная линия вместо серых бордеров */
  --hair-2: rgba(255, 255, 255, .16);
  --glass: rgba(255, 255, 255, .05);

  --shell: 1180px;
  --gutter: clamp(20px, 5vw, 56px);
  --section: clamp(88px, 14vh, 168px);   /* макро-воздух: секции дышат */
  --r-lg: 32px;
  --r-md: 22px;

  /* Пружина: масса и инерция вместо линейного скольжения. */
  --ease: cubic-bezier(.32, .72, 0, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);

  --display: "Unbounded", "Onest", system-ui, sans-serif;
  --text: "Onest", system-ui, -apple-system, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--paper);
  font: 400 clamp(15px, 1.05vw, 17px)/1.68 var(--text);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

h1, h2, h3 { margin: 0; font-family: var(--display); font-weight: 700; letter-spacing: -.035em; line-height: .95; }
p { margin: 0; }
img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }

.wrap { width: 100%; max-width: var(--shell); margin-inline: auto; padding-inline: var(--gutter); }
section { padding-block: var(--section); position: relative; }

/* ─── Атмосфера: зерно ──────────────────────────────────────────────────── */
/* Слой фиксирован и не ловит события: на скроллящемся контенте зерно заставляло
   бы GPU перерисовывать кадр целиком. Зерно — НАД контентом (z-50): плёночная
   текстура всему кадру.
   Фонового свечения акцентом («аура» за страницей — два размытых пятна на
   fixed-слое и их WebGL-версия) больше нет (27.08.2026): цветной туман за всеми
   секциями читался как грязный фон, а не как свет. Акцент теперь светится только
   там, где у него есть предмет: хиро без обложки (hero-mesh), карточки призыва,
   кнопки. Возвращать fixed-слои с blur не надо — это ещё и полноэкранный
   пересчёт размытия на каждом кадре прокрутки. */
.grain {
  position: fixed; inset: 0; z-index: 50; pointer-events: none; opacity: .04;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* Контент — над атмосферными слоями. Селектор по тегам, а НЕ body > *:not(...):
   тот имеет специфичность (0,2,1) и перебивал бы position:fixed у .isle и .dock. */
header, section, footer { position: relative; z-index: 2; }

/* ─── Плавающая навигация ───────────────────────────────────────────────── */
/* Не приклеена к краю: остров с отступом, как физическая деталь над страницей. */
.isle {
  position: fixed; z-index: 40; top: 14px; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 14px;
  max-width: calc(100vw - 24px);
  padding: 7px 7px 7px 20px;
  border-radius: 999px;
  background: rgba(12, 12, 17, .62);
  border: 1px solid var(--hair);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .5);
  transition: transform .5s var(--ease), opacity .5s var(--ease);
}
.isle-name {
  font-family: var(--display); font-weight: 600; font-size: .9rem; letter-spacing: -.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 42vw;
}
/* Ушли далеко вниз — остров прячется, чтобы не спорить с контентом. visibility
   снимает его и с фокуса: прозрачная кнопка «Записаться» ловила Tab. */
.isle.tuck {
  transform: translateX(-50%) translateY(-140%); opacity: 0; visibility: hidden;
  transition: transform .5s var(--ease), opacity .5s var(--ease), visibility 0s linear .5s;
}

/* ─── Кнопки: пилюля + иконка в своём кружке ────────────────────────────── */
.cta {
  --pad: 8px;
  display: inline-flex; align-items: center; gap: 14px;
  padding: var(--pad) var(--pad) var(--pad) 24px;
  border-radius: 999px;
  background: var(--accent); color: var(--accent-fg);
  font-family: var(--display); font-weight: 600; font-size: .95rem; letter-spacing: -.01em;
  border: 0; cursor: pointer;
  /* Высота пилюли задана явно, а не выходит из кружка иконки: кнопка без
     .cta-ic (например, submit формы) иначе получалась на 14px ниже соседних —
     и мельче цели касания. 50px = 34px кружка + два --pad. */
  min-height: calc(34px + var(--pad) * 2);
  line-height: 1.2;
  transition: transform .4s var(--ease), box-shadow .4s var(--ease), filter .4s var(--ease);
  box-shadow: 0 10px 34px color-mix(in srgb, var(--accent) 34%, transparent);
}
.cta-ic {
  width: 34px; height: 34px; flex: none; border-radius: 999px;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--accent-fg) 16%, transparent);
  transition: transform .4s var(--ease);
}
.cta:hover { filter: brightness(1.06); box-shadow: 0 16px 46px color-mix(in srgb, var(--accent) 46%, transparent); }
.cta:hover .cta-ic { transform: translate(3px, -3px); }
.cta:active { transform: scale(.975); }        /* физика нажатия */
.cta.sm { font-size: .85rem; padding-left: 18px; --pad: 6px; min-height: calc(28px + var(--pad) * 2); }
.cta.sm .cta-ic { width: 28px; height: 28px; }

.cta-ghost {
  background: var(--glass); color: var(--paper);
  border: 1px solid var(--hair-2); box-shadow: none;
}
.cta-ghost .cta-ic { background: rgba(255, 255, 255, .1); }
.cta-ghost:hover { background: rgba(255, 255, 255, .1); box-shadow: none; }

/* Кикеров («Прайс», «Портфолио», «Онлайн-запись» над названием) на витрине нет
   (аудит 07.09.2026): плашка 10–11px капсом над каждым заголовком — типовая
   генеративная разметка, заголовок несёт смысл сам, целевое действие — кнопка. */

/* ─── Хиро ──────────────────────────────────────────────────────────────── */
.hero {
  /* svh, не dvh: dvh пересчитывается при каждом схлопывании адресной строки во
     время прокрутки — хиро менял высоту на ходу, обложка перекраивалась, и всё под
     ним прыгало (жалоба 07.09.2026). svh — высота с показанной панелью браузера,
     статичная во время скролла; vh — фолбэк для браузеров без новых единиц. */
  min-height: 100vh; min-height: 100svh;
  display: flex; align-items: flex-end;
  /* Нижний отступ не меньше 88px: внизу хиро стоит подсказка «листайте»
     (26px от края + 36px высоты), и при 56px она ложилась на последнюю строку. */
  padding-block: 148px clamp(88px, 9vh, 112px);
  overflow: hidden;
}
.hero-bg { position: absolute; inset: 0; z-index: -1; overflow: hidden; }
.hero-bg img {
  width: 100%; height: 100%; object-fit: cover;
  opacity: .58; transform: scale(1.12);
}
/* Параллакс хиро при прокрутке — три слоя с разной скоростью: обложка (или
   живой градиент без обложки) отстаёт от страницы сильнее всего, текст —
   мягче и гаснет, подсказка «листайте» уходит со страницей. Ведёт CSS
   scroll-timeline: прогресс — прокрутка от 0 до высоты окна (хиро и есть
   первый экран), компоновщик двигает слои без событий scroll. Где timeline не
   поддержан, тот же прогресс пишет site.js в --hp (0..1), и работают правила
   из @supports not — геометрия одна, двигателя два. Без JS и без timeline —
   статичный кадр. При prefers-reduced-motion слои стоят. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .hero-bg img, .hero-mesh, .hero-copy {
      animation: linear both; animation-timeline: scroll(root block); animation-range: 0 100vh;
    }
    .hero-bg img { animation-name: heroPar; }
    .hero-mesh { animation-name: heroParMesh; }
    .hero-copy { animation-name: heroParCopy; }
  }
}
@supports not (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .hero-bg img { transform: scale(1.16) translate3d(0, calc(-3% + var(--hp, 0) * 12%), 0); }
    .hero-mesh { transform: translate3d(0, calc(var(--hp, 0) * 22%), 0); }
    .hero-copy { transform: translate3d(0, calc(var(--hp, 0) * 14%), 0); opacity: calc(1 - var(--hp, 0) * .6); }
  }
}
@keyframes heroPar {
  from { transform: scale(1.16) translate3d(0, -3%, 0); }
  to   { transform: scale(1.16) translate3d(0, 9%, 0); }
}
@keyframes heroParMesh { to { transform: translate3d(0, 22%, 0); } }
@keyframes heroParCopy { to { transform: translate3d(0, 14%, 0); opacity: .4; } }
/* Интро-канвас (WebGL, site.js): 1.4с шумовой волны поверх обложки, затем
   кросс-фейд в обычный <img> и самоудаление. Шторка ::after рисуется позже
   детей .hero-bg, так что текст читаем и во время эффекта. */
.hero-fx {
  position: absolute; inset: 0; width: 100%; height: 100%;
  transition: opacity .6s var(--ease);
}
.hero-fx.out { opacity: 0; }
/* Живой градиент вместо обложки (WebGL, site.js): витрина без фото получала
   ровную черноту под именем салона. Слой непрозрачный и подменяет фон хиро,
   поэтому лежит на z-index -1 — над фоном .hero (стек создаёт правило
   `header, section, footer { z-index: 2 }`), но под текстом. Появляется
   плавно: холст без первого кадра мигнул бы. */
.hero-mesh {
  position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1;
  pointer-events: none;
  opacity: 0; transition: opacity 1.4s var(--ease);
}
.hero-mesh.on { opacity: 1; }
/* Шторка: текст должен читаться поверх любой фотографии. */
.hero-bg::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(to top, var(--ink) 4%, color-mix(in srgb, var(--ink) 72%, transparent) 38%, transparent 78%),
    linear-gradient(to right, color-mix(in srgb, var(--ink) 78%, transparent), transparent 62%);
}
/* Колонку не сужаем: .hero-copy — это ещё и .wrap, и обе задавали бы max-width
   с равной специфичностью. Меру строки ограничиваем у заголовка и лида. */
.hero h1 { max-width: 13ch; }
.hero h1 {
  /* Нижняя граница 2.4rem, а не 3.1: при 320–390px «Парикмахерская» одним словом
     не влезала в строку, а .hero { overflow: hidden } срезал хвост — на стенде
     было «Парикмахер|» (аудит 07.09.2026). Перенос внутри слова и мягкие переносы
     решают остальное: заголовок тенанта — произвольное слово, и подобрать кегль
     «на все случаи» нельзя. hyphens работает от lang="ru" на <html>. */
  font-size: clamp(2.4rem, 13vw, 8.2rem);
  line-height: .88; margin: 18px 0 0;
  overflow-wrap: anywhere; hyphens: auto;
}
.hero .lede {
  margin-top: 22px; max-width: 46ch; font-size: clamp(1rem, 1.5vw, 1.2rem);
  color: var(--paper-dim);
}
.hero .cta { margin-top: 34px; }

/* Статус работы: точка пульсирует, только когда открыто. */
.open {
  display: inline-flex; align-items: center; gap: 9px; margin-top: 20px;
  font-size: .92rem; color: var(--paper-dim);
}
.open i {
  width: 7px; height: 7px; border-radius: 999px; background: var(--paper-faint); flex: none;
}
.open.on i { background: #43d17a; box-shadow: 0 0 0 0 rgba(67, 209, 122, .6); animation: pulse 2.4s infinite; }
@keyframes pulse {
  70% { box-shadow: 0 0 0 9px rgba(67, 209, 122, 0); }
  100% { box-shadow: 0 0 0 0 rgba(67, 209, 122, 0); }
}

/* Подсказка «листайте» — исчезает, как только страница тронулась. */
.scrollcue {
  position: absolute; left: 50%; bottom: 26px; transform: translateX(-50%);
  width: 22px; height: 36px; border: 1px solid var(--hair-2); border-radius: 999px;
  transition: opacity .5s var(--ease);
}
.scrollcue::after {
  content: ""; position: absolute; left: 50%; top: 7px; width: 3px; height: 7px;
  margin-left: -1.5px; border-radius: 999px; background: var(--paper-faint);
  animation: cue 1.9s var(--ease) infinite;
}
@keyframes cue { 0%, 100% { transform: translateY(0); opacity: 1 } 60% { transform: translateY(11px); opacity: 0 } }
.scrolled .scrollcue { opacity: 0; }
/* На телефоне подсказки нет: экран листают пальцем без напоминаний, внизу и так
   стоит док с кнопкой, а на длинном хиро (заголовок + два действия + согласие)
   кружок ложился прямо на «Оставить заявку». */
@media (max-width: 760px) { .scrollcue { display: none; } }

/* ─── Заголовки секций ──────────────────────────────────────────────────── */
.head { margin-bottom: clamp(34px, 5vw, 60px); }
.head h2 { font-size: clamp(2rem, 5.4vw, 3.6rem); margin-top: 16px; }

/* ─── Услуги: редакторский список, не «три карточки» ────────────────────── */
.svc { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--hair); }
.svc li {
  display: flex; align-items: baseline; gap: 18px;
  padding: clamp(18px, 2.4vw, 26px) 4px;
  border-bottom: 1px solid var(--hair);
  transition: background .45s var(--ease), padding-inline .45s var(--ease);
}
.svc li:hover { background: rgba(255, 255, 255, .028); padding-inline: 14px 14px; }
.svc-name { font-family: var(--display); font-weight: 600; font-size: clamp(1.05rem, 2vw, 1.45rem); letter-spacing: -.02em; }
.svc-name em { font-style: normal; color: var(--paper-dim); font-family: var(--text); font-weight: 400; font-size: .84rem; margin-left: 12px; }
.svc-dots { flex: 1 1 auto; height: 1px; background: repeating-linear-gradient(90deg, var(--hair-2) 0 2px, transparent 2px 8px); }
.svc-price { font-family: var(--display); font-weight: 600; font-size: clamp(1rem, 1.8vw, 1.3rem); white-space: nowrap; color: color-mix(in srgb, var(--accent) 62%, white); }

/* ─── Галерея: горизонтальная лента со снапом ───────────────────────────── */
.gallery { padding-inline: 0; }
.gallery .head { padding-inline: var(--gutter); }
.strip {
  display: flex; gap: 16px; overflow-x: auto; scroll-snap-type: x mandatory;
  padding-inline: var(--gutter); padding-bottom: 16px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.strip::-webkit-scrollbar { display: none; }
.strip figure {
  margin: 0; flex: none; scroll-snap-align: center;
  width: clamp(230px, 34vw, 360px); aspect-ratio: 3 / 4;
  border-radius: var(--r-md); overflow: hidden;
  background: var(--ink-2); border: 1px solid var(--hair);
}
.strip figure.tall { aspect-ratio: 3 / 4.5; }
.strip img { width: 100%; height: 100%; object-fit: cover; transition: transform 1s var(--ease); }
.strip figure:hover img { transform: scale(1.06); }
.strip.lb-on figure { cursor: zoom-in; }   /* класс ставит JS: без него тапать некуда */
.strip-hint { padding-inline: var(--gutter); margin-top: 6px; font-size: .8rem; color: var(--paper-dim); }

/* ─── Лайтбокс галереи ──────────────────────────────────────────────────── */
/* Собирается скриптом по первому тапу; выше зерна (z-50) — фото смотрят чистым. */
.lb {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: rgba(8, 8, 11, .93);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  opacity: 0; transition: opacity .35s var(--ease);
}
.lb.on { opacity: 1; }
.lb[hidden] { display: none; }   /* display:flex перебивает UA-правило [hidden] */
.lb-body { margin: 0; text-align: center; }
.lb-body img {
  max-width: min(1100px, 92vw); max-height: 80vh;
  width: auto; height: auto; margin-inline: auto;
  border-radius: var(--r-md); border: 1px solid var(--hair);
}
.lb-cap { margin-top: 14px; font-size: .88rem; color: var(--paper-dim); }
.lb-cap:empty { display: none; }
.lb button {
  position: absolute; width: 44px; height: 44px; border-radius: 999px;
  display: grid; place-items: center; cursor: pointer; padding: 0;
  background: rgba(255, 255, 255, .07); border: 1px solid var(--hair-2);
  color: var(--paper);
  transition: background .3s var(--ease);
}
.lb button:hover { background: rgba(255, 255, 255, .15); }
.lb button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.lb-x { top: max(14px, env(safe-area-inset-top)); right: 14px; }
.lb-nav { top: 50%; margin-top: -22px; }
.lb-prev { left: 12px; }
.lb-next { right: 12px; }
.lb-count {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: max(16px, env(safe-area-inset-bottom));
  font-size: .8rem; letter-spacing: .08em; color: var(--paper-dim);
}
body.lb-open { overflow: hidden; }   /* страница под оверлеем не скроллится */

/* ─── Двойной безель: карточка как физическая деталь в оправе ───────────── */
.bezel {
  padding: 7px; border-radius: var(--r-lg);
  background: var(--glass); border: 1px solid var(--hair);
}
.bezel > * {
  border-radius: calc(var(--r-lg) - 7px);
  background: var(--ink-2);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .07);
}

/* ─── Команда ───────────────────────────────────────────────────────────── */
.crew { display: grid; gap: 18px; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.master { padding: 7px; border-radius: var(--r-md); background: var(--glass); border: 1px solid var(--hair); }
.master-in {
  border-radius: calc(var(--r-md) - 7px); background: var(--ink-2);
  padding: 20px; text-align: center;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .07);
  transition: transform .5s var(--ease);
}
.master:hover .master-in { transform: translateY(-4px); }
.master img, .master .ava {
  width: 84px; height: 84px; border-radius: 999px; object-fit: cover; margin: 0 auto 14px;
}
.master .ava {
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--accent) 22%, transparent);
  color: color-mix(in srgb, var(--accent) 70%, white);
  font-family: var(--display); font-weight: 700; font-size: 1.7rem;
}
.master b { display: block; font-family: var(--display); font-weight: 600; letter-spacing: -.02em; }
.master p { margin-top: 7px; font-size: .88rem; color: var(--paper-dim); }

/* ─── Отзывы ────────────────────────────────────────────────────────────── */
/* Средняя оценка под заголовком: те же числа уходят в aggregateRating, и разметка
   без видимой цифры — нарушение (сниппеты снимаются со всего хоста). Поэтому
   строка читаемая, а не декоративная: --paper-dim, не faint. */
.rating { margin-top: 12px; color: var(--paper-dim); font-size: .95rem; }
.quotes { display: grid; gap: 18px; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); }
blockquote {
  margin: 0; padding: 26px; border-radius: var(--r-md);
  background: var(--ink-2); border: 1px solid var(--hair);
  transition: transform .5s var(--ease), border-color .5s var(--ease);
}
blockquote:hover { transform: translateY(-4px); border-color: var(--hair-2); }
.stars { color: var(--accent); letter-spacing: 3px; font-size: .9rem; }
blockquote p { margin: 14px 0 16px; color: var(--paper); }
blockquote cite { font-style: normal; font-size: .85rem; color: var(--paper-dim); }

/* ─── Вопросы и ответы ──────────────────────────────────────────────────── */
/* Тот же список «Частые вопросы», что клиент листает в боте: редакторский
   список на волосяных линиях, как прайс, — не карточки. Раскрытие нативным
   <details>: без JS работает, с клавиатуры доступно. Маркер — своя стрелка,
   поворачивается при раскрытии. */
.faq { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--hair); }
.faq details { border-bottom: 1px solid var(--hair); }
.faq summary {
  display: flex; align-items: baseline; justify-content: space-between; gap: 18px;
  padding: clamp(16px, 2.2vw, 22px) 4px; cursor: pointer; list-style: none;
  font-family: var(--display); font-weight: 600; font-size: clamp(1rem, 1.7vw, 1.25rem); letter-spacing: -.02em;
  transition: padding-inline .45s var(--ease), color .3s var(--ease);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; flex: none; width: 9px; height: 9px; align-self: center;
  border-right: 1.5px solid var(--paper-dim); border-bottom: 1.5px solid var(--paper-dim);
  transform: rotate(45deg); transition: transform .4s var(--ease);
}
.faq details[open] summary::after { transform: rotate(-135deg); }
.faq summary:hover { padding-inline: 14px; }
.faq summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 8px; }
.faq details p {
  padding: 0 4px clamp(18px, 2.4vw, 24px); max-width: 62ch;
  color: var(--paper-dim); white-space: pre-line;   /* владелец переносит строки в ответе руками */
}

/* ─── Часы, адрес, карта ────────────────────────────────────────────────── */
.info { display: grid; gap: 26px; grid-template-columns: 1fr 1.1fr; align-items: start; }
.hours { display: grid; gap: 2px; }
.hrow { display: flex; justify-content: space-between; gap: 16px; padding: 12px 2px; border-bottom: 1px solid var(--hair); }
.hrow b { font-weight: 600; }
.hrow.off { color: var(--paper-dim); }
.addr { margin-top: 26px; }
.addr b { display: block; font-family: var(--display); font-weight: 600; margin-bottom: 6px; }
.addr p { color: var(--paper-dim); }
.addr .cta { margin-top: 18px; }

.map-wrap { position: relative; border-radius: calc(var(--r-lg) - 7px); overflow: hidden; aspect-ratio: 4 / 3; }
.map-frame { width: 100%; height: 100%; border: 0; display: block; filter: grayscale(1) invert(.92) contrast(.86); }
.map-wrap.live .map-frame { filter: none; }
/* Шторка: до тапа палец по карте скроллит страницу, а не карту. */
.map-veil {
  position: absolute; inset: 0; border: 0; cursor: pointer; color: var(--paper);
  background: rgba(8, 8, 11, .34); backdrop-filter: blur(1px);
  display: grid; place-items: center; font: inherit; font-size: .86rem;
  transition: opacity .4s var(--ease);
}
.map-veil span { padding: 9px 16px; border-radius: 999px; background: rgba(12, 12, 17, .8); border: 1px solid var(--hair-2); }
.map-wrap.live .map-veil { opacity: 0; pointer-events: none; }

/* ─── Финальный призыв ──────────────────────────────────────────────────── */
.final {
  position: relative; overflow: hidden;
  border-radius: var(--r-lg); padding: clamp(40px, 7vw, 84px) var(--gutter);
  text-align: center;
  background: var(--ink-2); border: 1px solid var(--hair);
}
.final::before {
  content: ""; position: absolute; inset: -40% 20% auto; height: 80%;
  background: radial-gradient(50% 60% at 50% 0, color-mix(in srgb, var(--accent) 46%, transparent), transparent 70%);
  filter: blur(38px); pointer-events: none;
}
.final > * { position: relative; }
/* Сияние в блоках призыва (WebGL, site.js). Селектор с ДВУМЯ классами не ради
   красоты: `.final > *` выше даёт всем прямым детям position: relative и иначе
   сломал бы холсту absolute. Потолок непрозрачности живёт здесь, а не в
   шейдере, и он жёсткий: акцент выбирает владелец, он может прислать хоть
   лимонный, и на этом фоне стоит светлый текст --paper-dim. */
.final .fx-sheen {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none;
  opacity: 0; transition: opacity 1.6s var(--ease);
}
.final .fx-sheen.on { opacity: .5; }
.final h2 { font-size: clamp(1.9rem, 5vw, 3.2rem); }
.final p { margin: 16px auto 30px; max-width: 46ch; color: var(--paper-dim); }

/* ─── Подвал ────────────────────────────────────────────────────────────── */
.foot {
  display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between;
  padding-block: 40px 120px; border-top: 1px solid var(--hair);
  font-size: .84rem; color: var(--paper-dim);
}
.foot a:hover { color: var(--paper); }

/* ─── Согласие с юрдокументом салона (152-ФЗ) ───────────────────────────── */
/* Тихая строка под кнопкой записи: юридически обязательна, но конкурировать
   с CTA за внимание не должна. Ссылка — на документ владельца. */
.consent {
  margin-top: 14px; max-width: 52ch;
  font-size: .78rem; line-height: 1.5; color: var(--paper-dim);
}
.final .consent { margin: 18px auto 0; }
.consent a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.consent a:hover { color: var(--paper); }

/* ─── Липкая кнопка на телефоне ─────────────────────────────────────────── */
/* Главный конверсионный элемент: на мобильном он всегда под большим пальцем. */
.dock {
  position: fixed; z-index: 35; left: 12px; right: 12px;
  /* Страница отдаётся с viewport-fit=cover, поэтому 12px отсчитываются от края
     стекла: на iPhone кнопка ложилась на полосу home indicator. */
  bottom: max(12px, env(safe-area-inset-bottom));
  display: none; justify-content: center;
  /* visibility, а не только transform: уведённый вниз док остаётся в потоке
     фокуса, и Tab уходил на ссылку, которой не видно. Гасим ПОСЛЕ проезда
     (задержка = длительность), показываем сразу. */
  visibility: hidden;
  transform: translateY(140%);
  transition: transform .55s var(--ease), visibility 0s linear .55s;
}
.dock.up { transform: none; visibility: visible; transition: transform .55s var(--ease), visibility 0s; }
.dock .cta { width: 100%; justify-content: space-between; }
@media (max-width: 760px) { .dock { display: flex; } .foot { padding-bottom: 104px; } }

/* ─── Появление при скролле ─────────────────────────────────────────────── */
/* Тяжёлый вход: элемент «доезжает» с расфокуса, а не мигает opacity. */
.reveal { opacity: 0; transform: translate3d(0, 34px, 0); filter: blur(9px); }
.reveal.in {
  opacity: 1; transform: none; filter: blur(0);
  transition: opacity .9s var(--ease-out), transform .9s var(--ease-out), filter .9s var(--ease-out);
}
.strip.reveal { filter: none; }   /* блюр на скролл-контейнере роняет фреймрейт */
.reveal.d1.in { transition-delay: .09s; }
.reveal.d2.in { transition-delay: .18s; }
.reveal.d3.in { transition-delay: .27s; }

/* ─── Мобильная раскладка ───────────────────────────────────────────────── */
@media (max-width: 860px) {
  .info { grid-template-columns: 1fr; }
  .hero h1 { max-width: none; }
  .hero .lede { max-width: none; }
}
@media (max-width: 620px) {
  .hero { padding-block: 132px 44px; }
  .svc li { gap: 12px; }
  .svc-dots { display: none; }
  .svc li { justify-content: space-between; }
}

/* ─── Соцсети в подвале ─────────────────────────────────────────────────── */
/* Ссылки владельца: иконка в круге на стекле. Отдельной строкой над копирайтом
   (order:-1 + flex-basis:100% в .foot, у которого flex-wrap:wrap), цель касания
   44px — минимум, который считает удобным Apple HIG. */
.socials { display: flex; gap: 10px; flex-basis: 100%; order: -1; margin-bottom: 18px; }
.socials a {
  width: 44px; height: 44px; flex: none; border-radius: 999px;
  display: grid; place-items: center;
  background: var(--glass); border: 1px solid var(--hair); color: var(--paper-dim);
  transition: transform .4s var(--ease), color .4s var(--ease), border-color .4s var(--ease);
}
.socials a:hover {
  color: var(--paper); border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  transform: translateY(-3px);
}
.socials a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ─── Два действия в хиро ───────────────────────────────────────────────── */
/* Запись в Telegram и «оставить заявку» стоят рядом: у части клиентов Telegram
   нет, и для них второй путь — единственный. Ряд переносится, чтобы на узком
   экране кнопки не сжимались в нечитаемые полоски. */
.hero-acts { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 34px; }
.hero-acts .cta { margin-top: 0; }

/* ─── Форма заявки на звонок ────────────────────────────────────────────── */
/* Вход для клиента без Telegram: имя, телефон, свободный вопрос. Живёт блоком на
   мини-сайте и отдельной страницей /lead/<slug> — разметка одна (шаблон
   «leadform»), поэтому и стили одни.
   Поля выровнены по левому краю внутри центрированной карточки .final: форму
   заполняют, а не читают, и центрированные подписи над полями сбивают взгляд. */
/* Якорь из хиро и дока: без запаса заголовок блока уезжает под остров навигации. */
#lead { scroll-margin-top: 96px; }
.lead-block { text-align: left; }
.lead-block h2, .lead-block > p { text-align: center; }

.lead-form { display: grid; gap: 6px; max-width: 30rem; margin: 0 auto; }
.lead-form label {
  font-size: .8rem; letter-spacing: .04em; color: var(--paper-dim); margin-top: 10px;
}
.lead-opt { color: var(--paper-dim); }
.lead-form input[type="text"], .lead-form input[type="tel"], .lead-form textarea {
  width: 100%; padding: 13px 15px; border-radius: var(--r-md);
  background: var(--glass); border: 1px solid var(--hair-2);
  color: var(--paper); font: inherit; font-size: 1rem;   /* не меньше 16px — иначе iOS зумит форму */
  transition: border-color .3s var(--ease), background .3s var(--ease);
}
.lead-form textarea { resize: vertical; min-height: 5.2rem; }
.lead-form input::placeholder, .lead-form textarea::placeholder { color: var(--paper-dim); }
.lead-form input:focus, .lead-form textarea:focus {
  outline: none; background: rgba(255, 255, 255, .08);
  border-color: color-mix(in srgb, var(--accent) 62%, transparent);
}
.lead-form input:focus-visible, .lead-form textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Согласие на обработку ПДн: обязательно и по закону, и на сервере. Тон тише
   полей, но не .paper-faint — это то, на что клиент соглашается, а не сноска. */
.lead-check {
  display: flex; align-items: flex-start; gap: 10px; margin-top: 16px;
  font-size: .82rem; line-height: 1.5; color: var(--paper-dim); letter-spacing: 0;
}
.lead-check input { flex: none; width: 20px; height: 20px; margin-top: 1px; accent-color: var(--accent); }
.lead-check a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.lead-check a:hover { color: var(--paper); }

.lead-send { margin-top: 20px; width: 100%; justify-content: space-between; }

/* Ошибка над формой (валидация, лимит) — красный тон замешан на холст страницы,
   чтобы не выглядеть системным алертом из другого дизайна. */
.lead-err {
  margin: 0; padding: 11px 15px; border-radius: var(--r-md);
  background: rgba(196, 72, 72, .14); border: 1px solid rgba(196, 72, 72, .4);
  color: #f0c9c9; font-size: .86rem;
}
.lead-err[hidden] { display: none; }

/* «Заявка принята» — на месте формы, без прыжка страницы вверх. */
.lead-done { text-align: center; padding: 22px 0; }
.lead-done b { font-family: var(--display); font-size: 1.3rem; }
.lead-done p { margin: 10px auto 0; max-width: 34ch; color: var(--paper-dim); }

/* Honeypot: скрыт от человека, но существует в разметке — простой бот заполняет
   всё, что видит. Именно поэтому НЕ display:none и не hidden: часть ботов такие
   поля пропускает. Уводим за пределы вьюпорта. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ─── Отдельная страница заявки ─────────────────────────────────────────── */
/* Тонкая страница по ссылке из шапки профиля или с визитки: только форма.
   Хиро с фото здесь нет намеренно — клиент пришёл по обещанию «оставить заявку»,
   и любая витрина между ним и полями снижает шанс, что он их заполнит. */
/* svh, не dvh — по той же причине, что у хиро: dvh меняется на ходу при прокрутке. */
.lead-page .lead-wrap { min-height: 100vh; min-height: 100svh; display: flex; flex-direction: column; justify-content: center; padding-block: var(--section); }
.lead-page h1 { font-size: clamp(2.1rem, 6vw, 3.4rem); margin: 18px 0 0; max-width: 18ch; }
.lead-page .lede { margin-top: 18px; max-width: 44ch; color: var(--paper-dim); }
/* Имя заведения над формой заявки — обычная строка, не капс-плашка. */
.lead-biz { align-self: flex-start; margin: 0 0 12px; font-family: var(--display); font-weight: 600;
  font-size: .95rem; color: var(--paper-dim); }
.lead-page .lead-form { margin: 26px 0 0; }
.lead-page .foot { padding-bottom: 40px; }
