/* ═══════════════════════════════════════════════════════════════════════════
   МАТРЁШКА ТУР — ДИЗАЙН-СИСТЕМА (2026-09)
   Подключается ПОСЛЕ styles.css: дисциплинирует то, что уже есть, а не
   переписывает сайт. Правило слоя: токены → типографика → хром → компоненты
   → движение → доступность.

   Почему слой, а не правка 4500 строк: styles.css накопил историю (редизайны
   06/19, 07/22), правки в нём дают регрессии. Здесь — один источник правды по
   шкалам, и его видно целиком.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 1. ТОКЕНЫ ─────────────────────────────────────────────────────────────
   Было: 14 кеглей, 6 весов, 12 радиусов, тени трёх разных «температур».
   Стало: одна шкала на всё.                                                  */

:root {
  /* Типографика: fluid-шкала 375px → 1440px, шаг ≈1.25 (мажорная терция).
     Кегли не выбираются «на глаз» — берутся отсюда. */
  --fs-micro:  clamp(0.6875rem, 0.67rem + 0.08vw, 0.75rem);    /* 11 → 12 */
  --fs-caption:clamp(0.75rem,  0.73rem + 0.11vw, 0.8125rem);   /* 12 → 13 */
  --fs-small:  clamp(0.8125rem,0.78rem + 0.15vw, 0.875rem);    /* 13 → 14 */
  --fs-body:   clamp(0.9375rem,0.91rem + 0.15vw, 1rem);        /* 15 → 16 */
  --fs-lead:   clamp(1.0625rem,1.01rem + 0.24vw, 1.1875rem);   /* 17 → 19 */
  --fs-h6:     clamp(1rem,     0.96rem + 0.19vw, 1.125rem);    /* 16 → 18 */
  --fs-h5:     clamp(1.125rem, 1.05rem + 0.32vw, 1.375rem);    /* 18 → 22 */
  --fs-h4:     clamp(1.25rem,  1.14rem + 0.47vw, 1.625rem);    /* 20 → 26 */
  --fs-h3:     clamp(1.5rem,   1.33rem + 0.75vw, 2rem);        /* 24 → 32 */
  --fs-h2:     clamp(1.75rem,  1.36rem + 1.66vw, 2.75rem);     /* 28 → 44 */
  --fs-h1:     clamp(2.125rem, 1.62rem + 2.15vw, 3.5rem);      /* 34 → 56 */

  --lh-display: 1.06;
  --lh-tight:   1.18;
  --lh-snug:    1.32;
  --lh-body:    1.55;
  --lh-relaxed: 1.65;

  /* Трекинг: чем крупнее кегль, тем плотнее — иначе крупный заголовок
     «рассыпается», а капслок-эйбрау без разрядки читается как опечатка. */
  --tr-display: -0.028em;
  --tr-head:    -0.018em;
  --tr-body:     0em;
  --tr-caps:     0.11em;

  /* Веса. Montserrat: 400 текст, 600 акцент, 800 сильный.
     Playfair Display: 700/900 только для дисплейных заголовков. */
  --fw-regular: 400;
  --fw-medium:  600;
  --fw-bold:    800;

  /* Спейсинг: сетка 4px. Всё вертикальное и горизонтальное — отсюда. */
  --sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 20px;  --sp-6: 24px;  --sp-8: 32px;  --sp-10: 40px;
  --sp-12: 48px; --sp-16: 64px; --sp-20: 80px; --sp-24: 96px;

  /* Ритм секций: одна величина на весь сайт вместо 42px/38px/26px вразнобой. */
  --section-gap: clamp(var(--sp-10), 6vw, var(--sp-20));
  --block-gap:   clamp(var(--sp-5), 3vw, var(--sp-8));
  --gutter:      clamp(var(--sp-4), 4vw, var(--sp-8));
  --measure:     68ch;   /* предел длины строки для читаемости */

  /* Радиусы: 5 ступеней. Правило — чем крупнее блок, тем крупнее радиус. */
  --r-xs:   8px;
  --r-sm:  12px;
  --r-md:  16px;
  --r-lg:  22px;
  --r-xl:  28px;
  --r-full: 999px;

  /* Тени: один источник света (сверху), одна тёплая «земляная» температура.
     Каждый уровень = ближняя тень контакта + дальняя тень объёма. */
  --shadow-1: 0 1px 2px rgba(74, 45, 20, 0.05), 0 2px 6px rgba(74, 45, 20, 0.05);
  --shadow-2: 0 2px 4px rgba(74, 45, 20, 0.05), 0 8px 20px rgba(74, 45, 20, 0.07);
  --shadow-3: 0 4px 8px rgba(74, 45, 20, 0.06), 0 18px 38px rgba(74, 45, 20, 0.10);
  --shadow-4: 0 8px 16px rgba(74, 45, 20, 0.07), 0 30px 60px rgba(74, 45, 20, 0.13);
  --shadow-brand: 0 6px 14px rgba(31, 90, 58, 0.18), 0 18px 34px rgba(31, 90, 58, 0.16);

  /* Цвет. Бренд не меняется — исправлены только тексты, не бравшие AA.
     #d33a2c на кремовом = 4.34:1 (норма 4.5) → для ТЕКСТА берём --ink-red.
     Заливки и бейджи остаются фирменными: там контраст к белому свой. */
  --ink-red:    #b02a1c;   /* красный для текста/эйбрау — проходит AA */
  --ink-green:  #17512f;   /* зелёный для текста на светлом */
  --brand-press:#164a30;   /* нажатое состояние зелёной кнопки */
  --line-soft:  rgba(159, 110, 55, 0.14);
  --line-firm:  rgba(159, 110, 55, 0.26);
  --surface-1:  #ffffff;
  --surface-2:  #fffaf1;
  --focus-ring: #0f6b45;

  /* Движение. Длительность = смыслу: чем меньше объект, тем быстрее.
     Кривые: выход мягкий (объект «догоняет»), вход резкий. */
  --dur-instant: 90ms;
  --dur-fast:   140ms;
  --dur-quick:  200ms;
  --dur-base:   280ms;
  --dur-slow:   420ms;
  --dur-page:   340ms;
  --ease-out:      cubic-bezier(0.22, 0.68, 0.24, 1);
  --ease-emphasis: cubic-bezier(0.2, 0.9, 0.16, 1);
  --ease-in-out:   cubic-bezier(0.65, 0.05, 0.36, 1);
  --ease-spring:   cubic-bezier(0.34, 1.42, 0.64, 1);

  /* Высота хрома — считается один раз, ею пользуются таб-бар, FAB, sticky. */
  --tabbar-h: 62px;
  --header-h: 58px;
}

/* ── 2. ТИПОГРАФИКА ────────────────────────────────────────────────────────
   Заголовки — Playfair (дисплей), интерфейс и текст — Montserrat.
   Playfair в кириллице тонкий: держим его только на крупных кеглях и
   не ниже 700, иначе на телефоне заголовок «пылит».                          */

body {
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  letter-spacing: var(--tr-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

h1, .h1 {
  font-size: var(--fs-h1);
  line-height: var(--lh-display);
  letter-spacing: var(--tr-display);
}
h2, .h2 {
  font-size: var(--fs-h2);
  line-height: var(--lh-display);
  letter-spacing: var(--tr-display);
}
h3, .h3 { font-size: var(--fs-h3); line-height: var(--lh-tight); letter-spacing: var(--tr-head); }
h4      { font-size: var(--fs-h4); line-height: var(--lh-tight); letter-spacing: var(--tr-head); }
h5      { font-size: var(--fs-h5); line-height: var(--lh-snug);  letter-spacing: var(--tr-head); }
h6      { font-size: var(--fs-h6); line-height: var(--lh-snug); }

h1, h2, h3, h4, h5, h6 {
  text-wrap: balance;          /* заголовок не оставляет одинокое слово в строке */
  overflow-wrap: break-word;
}
p, li { text-wrap: pretty; }

/* Дисплейные заголовки Playfair: оптический размер и цифры в строку. */
.hero-cat h1,
.section-head h2,
.tour-card__title,
.doc-hero h1,
.doc-section h2 {
  font-optical-sizing: auto;
  font-feature-settings: "lnum" 1, "kern" 1;
}

/* Эйбрау (КАПСЛОК-надзаголовки): один стиль на весь сайт. */
.section-kicker,
.doc-eyebrow,
.hero-cat__cities,
.country__kicker,
.path-group__title {
  font-size: var(--fs-caption);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--ink-red);
  line-height: var(--lh-snug);
}

/* Лид-абзац под заголовком — крупнее body, но не конкурирует с ним. */
.hero-cat__lead,
.section-head p,
.doc-hero p,
.country__lead {
  font-size: var(--fs-lead);
  line-height: var(--lh-relaxed);
  color: var(--muted);
  max-width: var(--measure);
}

/* ── 3. ХРОМ ИНТЕРФЕЙСА ────────────────────────────────────────────────────
   Было на телефоне: шапка в два этажа ≈190px + таб-бар 90px = треть экрана
   занята навигацией ещё до контента, а лента разделов обрывалась у края без
   единого признака, что её можно листать.
   Стало: шапка ≈104px, уезжает при прокрутке вниз и возвращается при
   прокрутке вверх; у ленты — растушёвка края и снап; тач-цели от 44px.      */

@media (max-width: 900px) {
  .site-header {
    padding: 7px var(--sp-3) 8px;
    gap: var(--sp-2) var(--sp-2);
    transition: transform var(--dur-base) var(--ease-emphasis),
                box-shadow var(--dur-base) var(--ease-out);
    will-change: transform;
  }

  /* Прокрутка вниз — шапка уходит: экран отдаётся контенту.
     Вверх — возвращается мгновенно, «под большой палец». */
  body.chrome-hidden .site-header {
    transform: translateY(calc(-100% - 8px));
  }
  /* Оторвались от верха — у шапки появляется тень, она «над» контентом. */
  body.is-scrolled .site-header {
    box-shadow: var(--shadow-2);
  }

  .brand {
    width: min(42vw, 176px);
    padding: 2px var(--sp-1);
  }
  .brand-mark-image { max-height: 34px; }

  /* Главный CTA шапки: полноценная тач-цель, а не 41px-«таблетка». */
  .site-header > .cart-pill {
    min-height: 44px;
    padding: var(--sp-2) var(--sp-4);
    font-size: var(--fs-small);
    font-weight: var(--fw-bold);
    border-radius: var(--r-full);
  }

  /* Лента разделов: край растушёван, значит «дальше есть ещё». */
  .cat-nav {
    padding: 3px;
    scroll-snap-type: x proximity;
    scroll-padding-inline: var(--sp-3);
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 34px), transparent 100%);
            mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 34px), transparent 100%);
  }
  .cat-nav::-webkit-scrollbar { display: none; }
  .cat-nav__item {
    min-height: 40px;
    padding: var(--sp-2) var(--sp-3);
    font-size: var(--fs-caption);
    gap: var(--sp-1);
    scroll-snap-align: start;
    border-radius: var(--r-full);
    transition: background var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out),
                transform var(--dur-instant) var(--ease-out);
  }
  .cat-nav__item:active { transform: scale(0.96); }
}

/* ── Таб-бар: главный навигационный орган на телефоне ──────────────────────
   Активный пункт получает подложку-пилюлю: цвет текста один не читается как
   состояние, когда рядом пять одинаковых иконок.                            */
@media (max-width: 900px) {
  .tabbar {
    padding: var(--sp-1) var(--sp-1) calc(var(--sp-1) + env(safe-area-inset-bottom));
    background: rgba(255, 251, 243, 0.92);
    -webkit-backdrop-filter: saturate(1.6) blur(18px);
            backdrop-filter: saturate(1.6) blur(18px);
    border-top: 1px solid var(--line-soft);
    box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.7) inset, 0 -8px 24px rgba(74, 45, 20, 0.06);
    transition: transform var(--dur-base) var(--ease-emphasis);
  }
  .tabbar__item {
    position: relative;
    min-height: 48px;
    align-content: center;
    padding: var(--sp-1) 2px;
    gap: 2px;
    font-size: var(--fs-micro);
    font-weight: var(--fw-medium);
    letter-spacing: 0.005em;
    border-radius: var(--r-sm);
    -webkit-tap-highlight-color: transparent;
    transition: color var(--dur-fast) var(--ease-out);
  }
  .tabbar__item svg {
    width: 23px;
    height: 23px;
    transition: transform var(--dur-quick) var(--ease-spring);
  }
  .tabbar__item:active svg { transform: scale(0.88); }
  .tabbar__item:active { background: transparent; }

  /* Подложка активного пункта: рисуется псевдоэлементом, чтобы не трогать
     разметку и не ломать существующие правила цвета. */
  .tabbar__item::before {
    content: "";
    position: absolute;
    inset: 2px 6px;
    border-radius: var(--r-sm);
    background: rgba(31, 107, 69, 0.1);
    opacity: 0;
    transform: scale(0.82);
    transition: opacity var(--dur-quick) var(--ease-out),
                transform var(--dur-quick) var(--ease-spring);
  }
  body[data-view="home"]    .tabbar__item--home::before,
  body[data-view="catalog"] .tabbar__item--catalog::before,
  body[data-view="tickets"] .tabbar__item--tickets::before,
  .tabbar__item[aria-current="page"]::before {
    opacity: 1;
    transform: scale(1);
  }
  body[data-view="home"]    .tabbar__item--home,
  body[data-view="catalog"] .tabbar__item--catalog,
  body[data-view="tickets"] .tabbar__item--tickets,
  .tabbar__item[aria-current="page"] {
    color: var(--ink-green);
    font-weight: var(--fw-bold);
  }

  /* Контент не прячется за таб-баром — величина одна, из токена. */
  body { padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom)); }
}

/* ── Плавающие кнопки связи ────────────────────────────────────────────────
   Было: два кружка висели ровно над таб-баром и накрывали «Подробнее →»,
   поле поиска в каталоге и правый край списка городов.
   Стало: подняты над таб-баром, уменьшены до 46px и уезжают вместе с шапкой
   при прокрутке вниз — под пальцем остаётся контент, кнопка возвращается,
   как только человек останавливается или листает вверх.                     */
@media (max-width: 900px) {
  .tg-fab,
  .wa-fab {
    width: 46px;
    height: 46px;
    padding: 0;
    display: grid;
    place-items: center;
    opacity: 1;
    bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + var(--sp-3));
    transition: transform var(--dur-base) var(--ease-emphasis),
                opacity var(--dur-quick) var(--ease-out),
                box-shadow var(--dur-quick) var(--ease-out);
  }
  .tg-fab { right: var(--sp-4); }
  .wa-fab { right: calc(var(--sp-4) + 46px + var(--sp-2)); }
  .tg-fab__icon,
  .wa-fab__icon { width: 22px; height: 22px; }

  /* Кнопки связи живут по своим правилам: их нет на первом экране (там
     контент важнее, а связь есть в шапке и в таб-баре), они уходят на время
     активной прокрутки вниз и возвращаются, как только человек остановился.
     Раньше они постоянно накрывали «Подробнее →» и поле поиска в каталоге. */
  body:not(.fab-ready) .tg-fab,
  body:not(.fab-ready) .wa-fab {
    transform: translateY(calc(var(--tabbar-h) + 90px)) scale(0.9);
    opacity: 0;
    pointer-events: none;
  }
  body.fab-hidden .tg-fab,
  body.fab-hidden .wa-fab {
    transform: translateY(calc(var(--tabbar-h) + 90px));
    opacity: 0;
    pointer-events: none;
  }
  .tg-fab:active,
  .wa-fab:active { transform: scale(0.92); }
}

/* Тени кнопок связи — из системы, а не два разных цветных ореола. */
.tg-fab { box-shadow: 0 4px 10px rgba(34, 158, 217, 0.28), 0 12px 28px rgba(34, 158, 217, 0.24); }
.wa-fab { box-shadow: 0 4px 10px rgba(37, 211, 102, 0.26), 0 12px 28px rgba(37, 211, 102, 0.22); }

/* ── 4. КОМПОНЕНТЫ ─────────────────────────────────────────────────────────
   Правило цвета, которого раньше не было: зелёный = навигация и действие,
   красный = деньги и срочность (цена, «акция», «хит»), жёлтый = микро-акцент.
   До этого красным был и выбранный город, и надзаголовок, и цена — акцент
   переставал что-либо значить.                                             */

/* Карточка тура ------------------------------------------------------------
   Было: содержимое лежало в grid, строки растягивались, и под однострочным
   заголовком зияла пустота в полстроки, а цены в соседних карточках стояли
   на разной высоте.
   Стало: колонка, подвал прижат вниз — цена и «Подробнее» выровнены по всему
   ряду, пустот нет.                                                         */
.tour-card--lite .tour-card__content {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--sp-2);
  padding: var(--sp-4) var(--sp-4) var(--sp-4);
  min-height: 0;
}
.tour-card--lite .tour-card__title {
  font-size: var(--fs-h5);
  line-height: var(--lh-tight);
  letter-spacing: var(--tr-head);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.tour-card--lite .tour-card__route {
  font-size: var(--fs-small);
  line-height: var(--lh-snug);
  max-height: calc(var(--lh-snug) * 2em);
}
.tour-card--lite .tour-card__includes {
  font-size: var(--fs-caption);
  font-weight: var(--fw-medium);
  color: var(--ink-green);
  line-height: var(--lh-snug);
}
.tour-card--lite .tour-card__foot {
  margin-top: auto;          /* подвал вниз: цены выровнены по ряду */
  padding-top: var(--sp-2);
  border-top: 1px solid var(--line-soft);
}
.tour-card--lite .tour-card__price {
  font-size: var(--fs-h6);
  font-weight: var(--fw-bold);
  color: var(--ink-red);
  letter-spacing: var(--tr-head);
}
.tour-card--lite .tour-card__more {
  font-size: var(--fs-caption);
  font-weight: var(--fw-bold);
  color: var(--ink-green);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  transition: gap var(--dur-quick) var(--ease-out);
}
.tour-card--lite:hover .tour-card__more { gap: var(--sp-2); }

.tour-card--lite {
  border-radius: var(--r-lg);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-2);
  transition: transform var(--dur-quick) var(--ease-out),
              box-shadow var(--dur-quick) var(--ease-out),
              border-color var(--dur-quick) var(--ease-out);
}
.tour-card--lite:hover,
.tour-card--lite:focus-within {
  transform: translateY(-4px);
  box-shadow: var(--shadow-4);
  border-color: rgba(31, 107, 69, 0.2);
}
.tour-card--lite:active { transform: translateY(-1px) scale(0.994); }
.tour-card--lite .tour-card__media { background: linear-gradient(135deg, #ece2d5, #f6efe4); }
.tour-card--lite .tour-card__media img {
  transition: transform var(--dur-slow) var(--ease-out);
}

/* Бейдж на фото: тень нужна не для красоты — она отделяет белый текст от
   светлых участков снимка. */
.tour-card__badge {
  padding: var(--sp-1) var(--sp-3);
  font-size: var(--fs-micro);
  letter-spacing: var(--tr-caps);
  border-radius: var(--r-full);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.22), 0 8px 18px rgba(0, 0, 0, 0.14);
  backdrop-filter: saturate(1.2);
}

/* Кнопки -------------------------------------------------------------------
   Одна лестница размеров и один способ реакции на нажатие.                  */
.button {
  min-height: 48px;
  padding: var(--sp-3) var(--sp-6);
  border-radius: var(--r-full);
  font-size: var(--fs-small);
  font-weight: var(--fw-bold);
  letter-spacing: 0.01em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  -webkit-tap-highlight-color: transparent;
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-quick) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}
.button-primary {
  background: linear-gradient(135deg, #246844, #17512f);
  box-shadow: var(--shadow-brand);
}
.button-primary:hover {
  filter: none;                                  /* было brightness() — дешёвый приём */
  background: linear-gradient(135deg, #2a7a4f, #1a5c37);
  transform: translateY(-2px);
  box-shadow: 0 8px 18px rgba(31, 90, 58, 0.22), 0 22px 40px rgba(31, 90, 58, 0.2);
}
.button-primary:active {
  transform: translateY(0) scale(0.97);
  background: var(--brand-press);
  box-shadow: 0 2px 6px rgba(31, 90, 58, 0.24);
}
.button:active { transform: scale(0.97); }

/* Чипы выбора: города и категории — один орган, один вид, одно активное
   состояние (зелёное). Радиус и высота из системы. */
.from-chip,
.filter-chip {
  min-height: 44px;
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--r-full);
  border: 1.5px solid var(--line-firm);
  background: rgba(255, 255, 255, 0.8);
  font-size: var(--fs-small);
  font-weight: var(--fw-bold);
  color: var(--text);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  -webkit-tap-highlight-color: transparent;
  transition: transform var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}
.from-chip:hover,
.filter-chip:hover {
  border-color: rgba(31, 107, 69, 0.4);
  background: #fff;
  box-shadow: var(--shadow-1);
}
.from-chip:active,
.filter-chip:active { transform: scale(0.96); }
.from-chip.is-active,
.filter-chip.is-active {
  background: linear-gradient(135deg, #246844, #17512f);
  border-color: transparent;
  color: #fff;
  box-shadow: 0 4px 10px rgba(31, 90, 58, 0.22);
}

/* Поля ввода: одна высота с кнопками, видимое состояние фокуса. */
.catalog-search input,
.request-form input,
.request-form textarea {
  min-height: 48px;
  border-radius: var(--r-md);
  border: 1.5px solid var(--line-firm);
  background: var(--surface-1);
  font-size: var(--fs-body);
  transition: border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}
.catalog-search input:focus,
.request-form input:focus,
.request-form textarea:focus {
  outline: none;
  border-color: var(--focus-ring);
  box-shadow: 0 0 0 4px rgba(15, 107, 69, 0.16);
}
.request-form textarea { min-height: 112px; }

/* ── 5. ДВИЖЕНИЕ ───────────────────────────────────────────────────────────
   Принцип: движение объясняет, откуда взялся элемент, и подтверждает нажатие.
   Ничего декоративного. Длительности из токенов, кривая одна на весь сайт.  */

/* Появление при прокрутке. Было 600ms и сдвиг 18px — на телефоне контент
   «догонял» палец и читался как подтормаживание. Стало 420ms / 12px. */
.has-reveal .reveal {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-emphasis);
  transition-delay: var(--reveal-delay, 0ms);
}
.has-reveal .reveal.is-visible {
  opacity: 1;
  transform: none;
}
/* will-change снимаем сразу после появления: держать его на десятках
   карточек — это отдельный слой композитора на каждую. */
.has-reveal .reveal:not(.is-visible) { will-change: opacity, transform; }
.has-reveal .reveal.is-visible { will-change: auto; }
.tour-card, .cat-card, .path-stop, .service-tile { will-change: auto; }

/* Фотографии проявляются, а не «щёлкают» из пустого прямоугольника.
   Пока картинка не загружена, место держит тёплая подложка (см. media выше),
   после загрузки JS ставит data-loaded. */
.tour-card__media img,
.trust-photo img,
.doc-card__media img {
  opacity: 0;
  transform: scale(1.03);
  transition: opacity var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out);
}
.tour-card__media img[data-loaded],
.trust-photo img[data-loaded],
.doc-card__media img[data-loaded],
.no-js .tour-card__media img,
.no-js .trust-photo img {
  opacity: 1;
  transform: none;
}
/* Страховка: если JS не отработал, фото всё равно видно. */
html:not(.has-imgfx) .tour-card__media img,
html:not(.has-imgfx) .trust-photo img,
html:not(.has-imgfx) .doc-card__media img {
  opacity: 1;
  transform: none;
  transition: none;
}

/* Переход между экранами (Главная ↔ Каталог ↔ Акция ↔ Билеты).
   Раньше экран подменялся мгновенно — интерфейс «прыгал». Теперь снимок
   старого экрана уходит, новый приходит: видно, что это переход, а не сбой. */
::view-transition-old(root) {
  animation: mtViewOut var(--dur-quick) var(--ease-out) both;
}
::view-transition-new(root) {
  animation: mtViewIn var(--dur-page) var(--ease-emphasis) both;
}
@keyframes mtViewOut {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(-6px); }
}
@keyframes mtViewIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* Сигнатура: маршрут по стране с севера на юг.
   Линия между городами прорисовывается по мере прокрутки — она и есть
   содержание блока (порядок городов вдоль побережья), а не украшение. */
.country-path__inner { position: relative; }
.path-stop__dot,
.path-stop::before {
  transition: transform var(--dur-base) var(--ease-spring),
              background-color var(--dur-base) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out);
}
.path-stop.is-visible .path-stop__dot { transform: scale(1); }

/* Нажатие: единый отклик для всего, что кликается пальцем. */
a, button, [role="button"], .cat-card, .path-stop, .service-tile, .tabbar__item {
  -webkit-tap-highlight-color: transparent;
}

/* ── 6. ДОСТУПНОСТЬ ────────────────────────────────────────────────────────  */

/* Одно кольцо фокуса на весь сайт — видимое и на светлом, и на фото. */
:where(a, button, input, textarea, select, [tabindex]):focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}
.button:focus-visible,
.from-chip:focus-visible,
.filter-chip:focus-visible,
.tour-card__open:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 3px;
}

/* Уважение к «уменьшить движение»: гасим и новые эффекты тоже. */
@media (prefers-reduced-motion: reduce) {
  .has-reveal .reveal,
  .has-reveal .reveal.is-visible {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .tour-card__media img,
  .trust-photo img,
  .doc-card__media img {
    opacity: 1;
    transform: none;
    transition: none;
  }
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; }
  .site-header,
  .tabbar,
  .tg-fab,
  .wa-fab { transition: none; }
  body.chrome-hidden .site-header { transform: none; }
  body.fab-hidden .tg-fab,
  body.fab-hidden .wa-fab,
  body:not(.fab-ready) .tg-fab,
  body:not(.fab-ready) .wa-fab { transform: none; opacity: 1; pointer-events: auto; }
}

/* ── 7. МОДАЛКА ТУРА ───────────────────────────────────────────────────────
   Было: панель действий висела поверх галереи полупрозрачной плёнкой и
   разрезала нижний ряд фотографий пополам.
   Стало: плотная подложка с размытием и достаточной растушёвкой сверху —
   панель читается как отдельный слой, а не как дефект вёрстки.             */
.dialog-actions {
  padding: var(--sp-5) 0 calc(var(--sp-2) + env(safe-area-inset-bottom));
  margin-top: var(--sp-2);
  background: linear-gradient(180deg,
    rgba(255, 248, 242, 0) 0%,
    rgba(255, 248, 242, 0.88) 38%,
    rgba(255, 248, 242, 0.99) 62%);
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
}
/* Контенту модалки — воздух под панелью, иначе последний блок всегда «под ней». */
.dialog-body,
.dialog-scroll { scroll-padding-bottom: 120px; }

/* ── 8. КОНТЕНТНЫЕ СТРАНИЦЫ (Афиша, гиды, статьи) ──────────────────────────
   Было: свой визуальный язык — другая шапка, другая шкала и три разных
   левых края в одной колонке (хлебные крошки, заголовок и «Ближайшие
   поводы» начинались в разных местах).
   Стало: одна вертикаль слева, одна типографика с остальным сайтом.        */
.afisha-hero,
.city-hero,
.art { margin-left: 0; margin-right: auto; }

.art-hero h1,
.city-hero h1,
.afisha-hero h1 {
  font-size: var(--fs-h1);
  line-height: var(--lh-display);
  letter-spacing: var(--tr-display);
  margin: 0 0 var(--sp-4);
}
.art-lead { font-size: var(--fs-lead); line-height: var(--lh-relaxed); }
.art-kicker,
.acard__kicker,
.weave-card__kicker {
  font-size: var(--fs-caption);
  letter-spacing: var(--tr-caps);
  font-weight: var(--fw-bold);
  color: var(--ink-red);
}
.art-body { font-size: var(--fs-body); line-height: var(--lh-relaxed); }
.art-body h2 { font-size: var(--fs-h3); line-height: var(--lh-tight); letter-spacing: var(--tr-head); }
.art-body h3 { font-size: var(--fs-h5); line-height: var(--lh-snug); }
.weave > h2,
.art-related > h2,
.city-afisha > h2,
.afisha-block > h2 {
  font-size: var(--fs-h3);
  line-height: var(--lh-tight);
  letter-spacing: var(--tr-head);
  margin: 0 0 var(--sp-5);
}

/* Шапка контентных страниц — той же высоты и плотности, что в приложении. */
.doc-header {
  padding: var(--sp-2) var(--gutter);
  background: rgba(255, 248, 235, 0.92);
  -webkit-backdrop-filter: saturate(1.5) blur(18px);
          backdrop-filter: saturate(1.5) blur(18px);
  border-bottom: 1px solid var(--line-soft);
}
.doc-logo img { height: 32px; }
.doc-nav a { font-size: var(--fs-small); font-weight: var(--fw-medium); }
.doc-nav__tg {
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  padding: var(--sp-2) var(--sp-4);
  font-weight: var(--fw-bold);
  background: linear-gradient(135deg, #246844, #17512f);
  box-shadow: var(--shadow-1);
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-quick) var(--ease-out);
}
.doc-nav__tg:hover { transform: translateY(-1px); box-shadow: var(--shadow-2); }
.doc-nav__tg:active { transform: scale(0.97); }

/* Карточки афиши: единый радиус, тень и отклик с карточками туров. */
.acard,
.weave-card,
.hub-chip {
  border-radius: var(--r-lg);
  border-color: var(--line-soft);
  box-shadow: var(--shadow-2);
  transition: transform var(--dur-quick) var(--ease-out),
              box-shadow var(--dur-quick) var(--ease-out),
              border-color var(--dur-quick) var(--ease-out);
}
.acard:hover,
.weave-card:hover,
.hub-chip:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-4);
  border-color: rgba(31, 107, 69, 0.2);
}
.acard:active,
.weave-card:active,
.hub-chip:active { transform: translateY(-1px) scale(0.995); }
.acard__title { font-size: var(--fs-h5); line-height: var(--lh-tight); letter-spacing: var(--tr-head); }
.acard__date { color: var(--ink-red); font-weight: var(--fw-bold); font-size: var(--fs-caption); }
.acard__lead { font-size: var(--fs-small); line-height: var(--lh-snug); }
.acard__body { gap: var(--sp-2); padding: var(--sp-4); }

/* Заглушка вместо фото: раньше три ярко-оранжевых прямоугольника подряд
   читались как ошибка загрузки. Теперь — спокойная бумажная подложка
   с диагональной насечкой: видно, что снимка нет, и это не мешает читать. */
.acard__img--ph {
  background:
    repeating-linear-gradient(135deg,
      rgba(31, 90, 58, 0.05) 0 2px,
      rgba(31, 90, 58, 0) 2px 11px),
    linear-gradient(140deg, #f6efe1, #efe4d1 58%, #e9dcc6);
  position: relative;
}
.acard__img--ph::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 74% 26%, rgba(242, 201, 76, 0.22), transparent 58%);
}

/* ── 9. СЕТКА И РИТМ ───────────────────────────────────────────────────────
   Замер на телефоне 375px показал четыре разных левых края в одной ленте:
   герой начинался с 18px, «Где мы работаем» с 16px, блок акции с 40px,
   финальный блок с 46px. Глаз читает это как «съехало», даже не понимая
   почему, а карточки акции выглядели уже остальных на 50px.

   Правило: у контента одна вертикаль — var(--gutter). Секции-панели
   (акция, доверие, финальный CTA) на телефоне становятся полосами во всю
   ширину, и их внутренний отступ совпадает с общей вертикалью.             */

.hero-cat,
.country {
  padding-inline: var(--gutter);
}

@media (max-width: 680px) {
  .akcia-home,
  .trust,
  .home-final {
    width: 100%;
    margin-inline: 0;
    border-radius: 0;
    padding: var(--sp-8) var(--gutter);
  }
}

/* Вертикальный ритм: было 42px у одних секций и clamp(...) у других. */
.top-tours,
.akcia-home,
.trust,
.home-final,
.process {
  margin-top: var(--section-gap);
}

/* Отступ под липкой шапкой при переходе по якорю — считается от её высоты,
   а не от «примерно 128px», иначе заголовок уезжает под шапку. */
:target,
.screen-section,
[id] { scroll-margin-top: calc(var(--header-h) + 56px); }

/* ── 10. ТОЧЕЧНЫЕ ИСПРАВЛЕНИЯ КОНТРАСТА ───────────────────────────────────
   Замер на проде: #d33a2c на кремовом = 4.34:1 при норме AA 4.5.
   Эти три места остались от старой палитры — переводим на --ink-red.       */
.hero-route-line,
.seo-tour__price,
.field-req,
.tour-card__price,
.acard__date,
.weave-card__price { color: var(--ink-red); }

/* ── 11. ТАЧ-ЦЕЛИ ─────────────────────────────────────────────────────────
   Лента разделов была 31px, стала 40px — доводим до канонических 44px.     */
@media (max-width: 900px) {
  .cat-nav__item { min-height: 44px; }
  .site-header { padding: var(--sp-1) var(--sp-3) var(--sp-2); }
  .brand-mark-image { max-height: 32px; }
}

/* ── 12. ШАПКА: анимация появления не должна держать transform ─────────────
   .site-header анимируется при загрузке с fill-mode: both — конечный кадр
   анимации фиксировал transform и перебивал уезжание шапки при прокрутке
   (проверено на проде: класс chrome-hidden стоял, а шапка не двигалась).
   backwards держит только начальный кадр — до старта анимации.            */
.site-header { animation-fill-mode: backwards; }

/* ── 13. СИГНАТУРА: маршрут по стране ─────────────────────────────────────
   Единственный элемент, который есть только у этого сайта: страна читается
   сверху вниз, как её и едут — с севера на юг. Линия между городами
   прорисовывается по мере прокрутки, станции зажигаются по очереди.
   Это не декор: порядок городов вдоль побережья — и есть содержание блока.  */
.path-region__stops { position: relative; }

.path-region__stops::after {
  content: "";
  position: absolute;
  left: 10.5px;
  top: 26px;
  bottom: 26px;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(180deg, #1f6b45, #2f9160);
  transform-origin: top;
  transform: scaleY(0);
  pointer-events: none;
}

/* Современные браузеры: прогресс линии привязан к прокрутке — линия растёт
   ровно настолько, насколько блок прошёл через экран. */
@supports (animation-timeline: view()) {
  .path-region__stops::after {
    animation: pathDraw linear both;
    animation-timeline: view();
    animation-range: entry 24% cover 58%;
  }
}
@keyframes pathDraw {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}

/* Где прокрутки-таймлайна нет (Firefox, старый Safari) — линия появляется
   вместе с блоком, без привязки к прогрессу. */
@supports not (animation-timeline: view()) {
  .has-reveal .path-region__stops::after {
    transition: transform var(--dur-slow) var(--ease-out);
  }
  .path-region__stops:has(.reveal.is-visible)::after,
  html:not(.has-reveal) .path-region__stops::after { transform: scaleY(1); }
}

/* Станции: город с экскурсиями — залитая точка с ореолом, город пока только
   с гидом — полая. Разница видна за долю секунды, без чтения подписи. */
.path-stop__dot {
  width: 11px;
  height: 11px;
  box-shadow: 0 0 0 4px rgba(31, 107, 69, 0.12);
}
.path-stop:hover { background: rgba(31, 107, 69, 0.05); }
.path-stop:hover .path-stop__dot { transform: scale(1.25); }
.path-stop__count { font-size: var(--fs-caption); font-weight: var(--fw-bold); }

/* ── 14. ПЕРВЫЙ ЭКРАН НА ДЕСКТОПЕ ─────────────────────────────────────────
   Было: заголовок и лид занимали левую треть, справа — пустой градиент на
   пол-экрана, а разделы начинались ниже линии сгиба. Холодный трафик видел
   обещание без единого способа его проверить.
   Стало: слева обещание, справа — три раздела, куда это обещание ведёт.
   Разметка не менялась: те же блоки, другая раскладка.
   !important здесь вынужденный — исходная сетка объявлена через !important
   переключателем экранов.                                                  */
@media (min-width: 1080px) {
  .hero-cat {
    grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr) !important;
    grid-template-areas:
      "copy  hubs"
      "svc   svc"
      "promo promo" !important;
    column-gap: clamp(var(--sp-8), 4vw, var(--sp-16));
    row-gap: var(--sp-6);
    align-content: center;
    padding-block: clamp(var(--sp-10), 4vw, var(--sp-16));
  }
  .hero-cat .hero-copy {
    grid-area: copy;
    align-self: center;
    margin-bottom: 0;
    max-width: 46ch;
  }
  .hero-cat .home-hubs {
    grid-area: hubs;
    grid-template-columns: minmax(0, 1fr);
    align-content: center;
    margin-bottom: 0;
    gap: var(--sp-3);
  }
  .hero-cat .home-services { grid-area: svc; }
  .hero-cat .hero-promo { grid-area: promo; }

  /* Ряд услуг: последняя плитка не должна оставаться сиротой в новой строке. */
  .home-services__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-3);
  }
  .home-services__row > * { flex: 1 1 200px; }
}

/* Карточки-разделы: отклик и иерархия. Ведущая — плотнее по цвету,
   остальные — спокойные, чтобы вести взгляд по порядку. */
.home-hub {
  border-radius: var(--r-lg);
  border-color: var(--line-soft);
  box-shadow: var(--shadow-1);
  transition: transform var(--dur-quick) var(--ease-out),
              box-shadow var(--dur-quick) var(--ease-out),
              border-color var(--dur-quick) var(--ease-out);
}
.home-hub:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-3);
  border-color: rgba(31, 107, 69, 0.22);
}
.home-hub:active { transform: translateY(0) scale(0.995); }
.home-hub__arrow { transition: transform var(--dur-quick) var(--ease-spring); }
.home-hub:hover .home-hub__arrow { transform: translateX(4px); }
.home-hub__name { font-size: var(--fs-h6); line-height: var(--lh-snug); letter-spacing: var(--tr-head); }
.home-hub__note { font-size: var(--fs-small); line-height: var(--lh-snug); color: var(--muted); }

/* ── 15. МОДАЛКА: мелочи, которые видно ───────────────────────────────────
   Плитки галереи обрезали снимок на 5px по нижнему краю (картинка выше
   контейнера), а пустой блок тегов держал зазор на ровном месте.          */
.dialog-gallery__card > img,
.dialog-gallery__card img {
  height: 100%;
  object-fit: cover;
}
.dialog-tags:empty,
.dialog-prices:empty,
.tour-card__includes:empty { display: none; }

/* Панель действий не должна закрывать последнюю плитку галереи. */
.dialog-copy { scroll-padding-bottom: 160px; }

/* Подзаголовки фильтров каталога: у городов он был, у категорий — нет,
   и второй ряд читался как продолжение первого. */
.from-head { font-size: var(--fs-h6); font-weight: var(--fw-bold); margin: 0 0 var(--sp-3); }
.from-head--second { margin-top: var(--sp-5); }

/* ── 16. КНОПКИ СВЯЗИ НА ШИРОКИХ ЭКРАНАХ ──────────────────────────────────
   То же правило, что и на телефоне: первый экран остаётся чистым, кнопки
   появляются, когда человек начал читать. Плюс вес: было два тяжёлых
   цветных «пузыря» с ореолом, стало спокойнее — они помощник, а не герой. */
.tg-fab,
.wa-fab {
  font-size: var(--fs-caption);
  font-weight: var(--fw-bold);
  padding: var(--sp-3) var(--sp-4) var(--sp-3) var(--sp-3);
  transition: transform var(--dur-base) var(--ease-emphasis),
              opacity var(--dur-quick) var(--ease-out),
              box-shadow var(--dur-quick) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}
.tg-fab { box-shadow: 0 2px 6px rgba(34, 158, 217, 0.2), 0 10px 22px rgba(34, 158, 217, 0.18); }
.wa-fab { box-shadow: 0 2px 6px rgba(37, 211, 102, 0.18), 0 10px 22px rgba(37, 211, 102, 0.16); }
.tg-fab:hover,
.wa-fab:hover { transform: translateY(-2px); }

@media (min-width: 901px) {
  body:not(.fab-ready) .tg-fab,
  body:not(.fab-ready) .wa-fab {
    opacity: 0;
    transform: translateY(18px) scale(0.96);
    pointer-events: none;
  }
}

/* ── 17. МАРШРУТ ПО СТРАНЕ НА ШИРОКОМ ЭКРАНЕ ──────────────────────────────
   На 1280px строка растягивалась во всю ширину: между «Нячанг» и
   «22 экскурсии» оставалось ~900px пустоты, и связь между городом и его
   счётчиком терялась. Список — это таблица из двух колонок, а не полоса:
   держим его в читаемой мере.                                              */
.country-path__inner { max-width: 860px; }
@media (min-width: 901px) {
  .path-stop {
    padding-block: var(--sp-3);
    gap: var(--sp-4);
  }
  .path-stop__name { font-size: var(--fs-h6); }
}

/* ── 18. КАРТОЧКИ В БЛОКЕ АКЦИИ ───────────────────────────────────────────
   Три карточки в правой колонке получают ~200px: маршрут переносился в две
   строки, а цена и «Подробнее» слипались. В этом блоке решает цена, состав
   человек смотрит уже в карточке тура — убираем лишнее и разводим подвал.  */
.lite-grid--mini .tour-card__includes { display: none; }
.lite-grid--mini .tour-card__route {
  -webkit-line-clamp: 1;
  max-height: calc(var(--lh-snug) * 1em);
}
.lite-grid--mini .tour-card__title { font-size: var(--fs-h6); }
.lite-grid--mini .tour-card__foot {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-1);
}
.lite-grid--mini .tour-city-chip { font-size: var(--fs-micro); }
@media (min-width: 901px) {
  .akcia-home__inner { grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr); }
}

/* ── 19. ФИНАЛЬНЫЙ CTA НА ТЁМНОМ ФОНЕ ─────────────────────────────────────
   Зелёная кнопка на тёмно-зелёном блоке сливалась с фоном. На тёмном
   первичное действие — светлое: это самый контрастный элемент экрана.      */
.home-final .button-primary,
.home-final__tg {
  background: #fffaf1;
  color: var(--ink-green);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18), 0 14px 30px rgba(0, 0, 0, 0.14);
}
.home-final .button-primary:hover,
.home-final__tg:hover {
  background: #ffffff;
  color: var(--brand-press);
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.22), 0 18px 36px rgba(0, 0, 0, 0.18);
}
.home-final .button-primary:active,
.home-final__tg:active { transform: scale(0.97); background: #f6efe1; }
.home-final .button-primary svg,
.home-final__tg svg { color: currentColor; }

/* ── 20. КАРТОЧКИ АФИШИ БЕЗ СНИМКА ────────────────────────────────────────
   Заглушка держала пропорцию настоящего фото — 213px пустоты на телефоне,
   и текст события уходил под сгиб. Нет снимка — нет и места под него:
   остаётся узкая цветная «шапка», которая отбивает карточки друг от друга.
   Оттенок слегка сдвигается по позиции в сетке, чтобы три подряд не
   выглядели одинаковыми клонами.                                           */
.acard__img--ph {
  aspect-ratio: 16 / 4;
}
@media (max-width: 680px) {
  .acard__img--ph { aspect-ratio: 16 / 2.6; }
}
.acard:nth-child(3n + 2) .acard__img--ph::after {
  background: radial-gradient(circle at 28% 34%, rgba(31, 107, 69, 0.16), transparent 62%);
}
.acard:nth-child(3n) .acard__img--ph::after {
  background: radial-gradient(circle at 62% 68%, rgba(211, 58, 44, 0.14), transparent 60%);
}

/* Шапка контентных страниц уступает место так же, как в приложении. */
.doc-header {
  transition: transform var(--dur-base) var(--ease-emphasis),
              box-shadow var(--dur-base) var(--ease-out);
}
body.is-scrolled .doc-header { box-shadow: var(--shadow-2); }
@media (max-width: 900px) {
  body.chrome-hidden .doc-header { transform: translateY(calc(-100% - 8px)); }
  .doc-nav a:not(.doc-nav__tg) { font-size: var(--fs-caption); }
}
@media (prefers-reduced-motion: reduce) {
  .doc-header { transition: none; }
  body.chrome-hidden .doc-header { transform: none; }
}

/* ── 21. СТАРЫЕ ПЕРЕМЕННЫЕ РАДИУСОВ ───────────────────────────────────────
   styles.css оперирует --radius-xl/lg/md/sm. Переводим их на общую шкалу,
   чтобы на странице не встречались 24px и 18px рядом с 22px и 16px.       */
:root {
  --radius-xl: var(--r-xl);
  --radius-lg: var(--r-lg);
  --radius-md: var(--r-md);
  --radius-sm: var(--r-sm);
}

/* ── 22. ТАЧ-ЦЕЛИ В ШАПКЕ КОНТЕНТНЫХ СТРАНИЦ ──────────────────────────────
   Ссылки навигации были 47×20 — по такой в движущемся автобусе не попасть. */
.doc-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--sp-1);
}
.crumbs a { padding-block: var(--sp-1); }

/* ── 23. ИКОНКА БИЛЕТА ────────────────────────────────────────────────────
   «%» означал скидку, а раздел — про билеты на события. Своя анимация:
   билет отрывается по перфорации.                                         */
[data-anim="i-ticket"]:hover svg,
[data-anim="i-ticket"]:active svg { animation: an-tear 0.55s var(--ease-out); }
@keyframes an-tear {
  0%   { transform: rotate(0) translateX(0); }
  35%  { transform: rotate(-7deg) translateX(-1.5px); }
  70%  { transform: rotate(4deg) translateX(1px); }
  100% { transform: rotate(0) translateX(0); }
}

/* ── 24. ДОЧИСТКА ─────────────────────────────────────────────────────────
   Замер на проде показал три хвоста: красный «обязательно» перебивался
   более специфичным старым правилом, а плитки услуг держали радиус 13px
   вне шкалы.                                                              */
.request-form .field-req { color: var(--ink-red); }

.home-hub__ico { border-radius: var(--r-sm); }
.home-svc {
  border-radius: var(--r-md);
  font-size: var(--fs-small);
  transition: transform var(--dur-quick) var(--ease-out),
              box-shadow var(--dur-quick) var(--ease-out),
              border-color var(--dur-quick) var(--ease-out);
}
.home-svc:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-2);
  border-color: rgba(31, 107, 69, 0.2);
}
.home-svc:active { transform: scale(0.98); }
.home-svc__rate { font-size: var(--fs-caption); font-weight: var(--fw-bold); color: var(--ink-green); }

/* Последние радиусы вне шкалы: карточки акции, фото и цифры в блоке доверия. */
.promo-tour { border-radius: var(--r-lg); }
.trust-photo { border-radius: var(--r-md); }
.trust-stat { border-radius: var(--r-md); }
.cart-empty { border-radius: var(--r-lg); }
