/* ==========================================================================
   Токены и контраст - общий слой
   Раньше эти переменные жили в product-page.css на body.tp-product-page,
   то есть были доступны только карточке товара. Листинги про них не знали,
   и на них вперемешку стояли rounded-3 / rounded-4 / rounded-5 и цвета
   Bootstrap по умолчанию.
   Файл подключается последним, чтобы перебивать утилиты Bootstrap:
   у них !important, и при равной специфичности выигрывает то, что ниже.
   ========================================================================== */

:root {
    /* --- Палитра. Каждое значение проверено на контраст WCAG 2.1 AA --- */
    --tp-ink: #16232b;          /* основной текст, 16.04:1 на белом */
    --tp-ink-muted: #5c6b73;    /* вторичный текст, 5.23:1 на #f8f9fa */
    --tp-ink-faint: #8a969d;    /* только для крупного текста и иконок */
    --tp-link: #0a58ca;         /* 6.11:1 на #f8f9fa, у Bootstrap #0d6efd было 4.26 */
    --tp-price: #0f7a5a;        /* 5.31:1 */
    --tp-cta: #ffc107;          /* фон CTA */
    --tp-cta-hover: #ffcd39;
    --tp-cta-ink: #16232b;      /* темный текст на CTA: 9.84:1, белый давал 1.63 */
    --tp-amber-ink: #8a6100;    /* янтарный текст на светлом: 5.54:1, #ffc107 давал 1.63 */
    --tp-cyan-ink: #087990;     /* 5.06:1 на белом, у Bootstrap #0dcaf0 было 1.95 */

    --tp-surface: #ffffff;
    --tp-surface-tint: #f5f7f9;
    --tp-surface-accent: #eef4f7;
    --tp-border: #e2e8ec;
    --tp-border-strong: #c9d4db;

    /* --- Шкала отступов, шаг 4 --- */
    --tp-1: 4px;
    --tp-2: 8px;
    --tp-3: 12px;
    --tp-4: 16px;
    --tp-5: 24px;
    --tp-6: 32px;
    --tp-7: 48px;
    --tp-8: 64px;

    /* --- Радиусы --- */
    --tp-r-sm: 8px;
    --tp-r-md: 12px;
    --tp-r-lg: 16px;
    --tp-r-pill: 999px;

    /* --- Слои --- */
    --tp-ring: 0 0 0 1px var(--tp-border);
    --tp-shadow-sm: 0 1px 2px rgba(22, 35, 43, .06);
    --tp-shadow-md: 0 6px 16px rgba(22, 35, 43, .08);
    --tp-shadow-lg: 0 12px 32px rgba(22, 35, 43, .12);

    /* --- Типографика --- */
    --tp-fs-xs: .8125rem;   /* 13 */
    --tp-fs-sm: .875rem;    /* 14 */
    --tp-fs-md: 1rem;       /* 16 */
    --tp-fs-lg: 1.125rem;   /* 18 */
    --tp-fs-xl: 1.375rem;   /* 22 */
    --tp-fs-2xl: 1.75rem;   /* 28 */

    /* --- Один радиус на все, кроме аватаров и пилюль. Переменные Bootstrap
           перекрываются здесь, чтобы не править rounded-4 / rounded-5 в разметке. --- */
    --bs-border-radius: var(--tp-r-md);
    --bs-border-radius-sm: var(--tp-r-sm);
    --bs-border-radius-lg: var(--tp-r-md);
    --bs-border-radius-xl: var(--tp-r-md);
    --bs-border-radius-xxl: var(--tp-r-md);

    /* --- Ссылки --- */
    --bs-link-color: var(--tp-link);
    --bs-link-color-rgb: 10, 88, 202;
    --bs-link-hover-color: #084298;
    --bs-link-hover-color-rgb: 8, 66, 152;
}

/* ==========================================================================
   Контраст
   Замер axe до правок на трех страницах листинга: 352 узла color-contrast,
   восемь пар цветов. Пять пар ниже давали 340 узлов из 352.
   ========================================================================== */

/* 170 узлов: #6c757d на #f8f9fa = 4.44 при нужных 4.5 */
.text-secondary,
.text-muted {
    color: var(--tp-ink-muted) !important;
}

/* Цены и рейтинги. Фирменный янтарь по решению заказчика: контраст на белом
   1.63 при норме WCAG 4.5. Кнопки и контуры на него не переведены, у них
   остается --tp-amber-ink, иначе они стали бы нечитаемыми целиком. */
.text-warning {
    color: #ffc107 !important;
}

/* Поверх фотографии подложка непредсказуема, поэтому под текстом скрим. */
.tp-on-media {
    background: rgba(0, 0, 0, .55) !important;
}

.tp-on-media,
.tp-on-media .text-secondary,
.tp-on-media .text-muted {
    color: #ffffff !important;
}


/* 22 узла: #0dcaf0 на белом = 1.95 */
.btn-outline-info {
    --bs-btn-color: var(--tp-cyan-ink);
    --bs-btn-border-color: var(--tp-cyan-ink);
    --bs-btn-hover-bg: var(--tp-cyan-ink);
    --bs-btn-hover-border-color: var(--tp-cyan-ink);
    --bs-btn-active-bg: var(--tp-cyan-ink);
    --bs-btn-active-border-color: var(--tp-cyan-ink);
}

.text-info {
    color: var(--tp-cyan-ink) !important;
}

/* 3 узла: белый текст на янтарной кнопке = 1.63 */
.btn-warning {
    --bs-btn-color: var(--tp-cta-ink);
    --bs-btn-hover-color: var(--tp-cta-ink);
    --bs-btn-active-color: var(--tp-cta-ink);
}

.btn-warning.text-white {
    color: var(--tp-cta-ink) !important;
}

/* ==========================================================================
   Цели нажатия и кнопки
   ========================================================================== */

/* Цель не меньше 24x24 по A2. btn-sm у Bootstrap дает 31px по высоте,
   но у иконочных кнопок без текста ширина схлопывалась. */
.btn {
    min-height: 40px;
}

.btn-sm {
    min-height: 32px;
}

.btn-check + .btn {
    min-height: 32px;
}

/* 36 узлов: серый контур кнопок. --bs-btn-color у btn-outline-secondary
   это #6c757d, тот же провал 4.44, что и у текста. */
.btn-outline-secondary {
    --bs-btn-color: var(--tp-ink-muted);
    --bs-btn-border-color: var(--tp-border-strong);
    --bs-btn-hover-bg: var(--tp-ink-muted);
    --bs-btn-hover-border-color: var(--tp-ink-muted);
    --bs-btn-active-bg: var(--tp-ink-muted);
    --bs-btn-active-border-color: var(--tp-ink-muted);
}

.btn-outline-warning {
    --bs-btn-color: var(--tp-amber-ink);
    --bs-btn-border-color: var(--tp-amber-ink);
    --bs-btn-hover-bg: var(--tp-cta);
    --bs-btn-hover-color: var(--tp-cta-ink);
    --bs-btn-border-color: var(--tp-amber-ink);
}

/* ==========================================================================
   Сортировка листинга
   Было: opacity-50 утилитой на всех четырех кнопках всегда. Выбранный
   вариант ничем не отличался от остальных, а полупрозрачный белый на синем
   давал контраст 2.23. Теперь невыбранные - контурные, выбранная - залитая.
   ========================================================================== */

.tp-sort-btn {
    --bs-btn-bg: transparent;
    --bs-btn-color: var(--tp-ink-muted);
    --bs-btn-border-color: var(--tp-border-strong);
    --bs-btn-hover-bg: var(--tp-surface-tint);
    --bs-btn-hover-color: var(--tp-ink);
    --bs-btn-hover-border-color: var(--tp-border-strong);
    min-height: 32px;
}

.btn-check:checked + .tp-sort-btn {
    --bs-btn-bg: var(--tp-link);          /* белый на нем 6.44:1 */
    --bs-btn-color: #ffffff;
    --bs-btn-border-color: var(--tp-link);
}

.btn-check:focus-visible + .tp-sort-btn {
    outline: 2px solid var(--tp-link);
    outline-offset: 2px;
}

/* ==========================================================================
   Первый экран
   Замер на 390x844 до правок: шапка сущности 585px, первая карточка
   начиналась на 957px, то есть за пределами экрана. Целевое по A1 -
   карточки видны без прокрутки.
   ========================================================================== */

@media (max-width: 767.98px) {
    .hero-section {
        padding: var(--tp-4) 0 var(--tp-5);
        margin-bottom: var(--tp-4);
    }

    .hero-section h1 {
        font-size: 1.35rem;
        line-height: 1.25;
        margin-bottom: var(--tp-2);
    }

    /* Ответ-абзац остается в разметке целиком: его читают и его извлекают
       генеративные системы. На мобильном он просто набран мельче. */
    .hero-section .container > .container {
        font-size: var(--tp-fs-sm);
        line-height: 1.4;
        margin-bottom: var(--tp-3) !important;
    }

    .hero-section .categories-container {
        margin-bottom: var(--tp-3) !important;
    }

    .hero-section .categories-container .d-flex {
        gap: var(--tp-2) !important;
    }

    .hero-section .categories-container .btn {
        min-height: 32px;
        padding: 4px 10px !important;
        font-size: var(--tp-fs-sm);
    }
}

/* ==========================================================================
   Фильтр листинга
   ========================================================================== */


/* ==========================================================================
   Факт-блок листинга, bento
   Набор фактов на разных страницах разный: на одной их два, на другой девять.
   Поэтому сетка не рассчитывает на фиксированное число плиток - остаток
   последнего ряда растягивается селекторами nth-child, без счета в шаблоне.
   ========================================================================== */

.tp-facts-bento {
    padding: var(--tp-3);
    border: 1px solid var(--tp-border);
    border-radius: var(--tp-r-lg);
    background: var(--tp-surface);
}

.tp-facts-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--tp-2) var(--tp-3);
    margin-bottom: var(--tp-3);
    padding: var(--tp-3);
    border-radius: var(--tp-r-md);
    background: linear-gradient(100deg, #e9f0fb 0%, #f4f8fd 60%, var(--tp-surface) 100%);
}

.tp-facts-head-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    border-radius: var(--tp-r-sm);
    background: #f9d3a4;
    color: #9a5b06;
    font-size: 1.25rem;
}

.tp-facts-title {
    flex: 1 1 12rem;
    margin: 0;
    /* Заголовок бывает и в три слова, и в восемь: размер тянется по ширине,
       чтобы на 390px он не съедал первый экран. */
    font-size: clamp(1.125rem, 1.2vw + .85rem, 1.6rem);
    font-weight: 700;
    line-height: 1.25;
    color: var(--tp-ink);
}

.tp-facts-place {
    display: inline-flex;
    align-items: center;
    gap: var(--tp-1);
    flex: 0 0 auto;
    padding: var(--tp-1) var(--tp-3);
    border-radius: var(--tp-r-pill);
    background: #d7e5fa;
    color: #17439c;             /* 6.02:1 на подложке чипа */
    font-size: var(--tp-fs-sm);
    font-weight: 500;
}

/* --- Сетка ---------------------------------------------------------------
   Мобильный: две колонки. Планшет: две плитки в ряд. Десктоп: три.
   Правила на nth-child растягивают остаток последнего ряда, иначе при семи
   или восьми фактах справа оставалась бы дыра в треть ширины.
   ------------------------------------------------------------------------- */

.tp-facts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--tp-2);
    margin: 0;
}

.tp-facts > * { grid-column: span 1; }
.tp-facts > :last-child:nth-child(2n + 1) { grid-column: span 2; }

@media (min-width: 576px) {
    .tp-facts {
        grid-template-columns: repeat(4, minmax(0, 1fr));
        gap: var(--tp-3);
    }

    .tp-facts > * { grid-column: span 2; }
    .tp-facts > :last-child:nth-child(2n + 1) { grid-column: span 4; }
}

@media (min-width: 992px) {
    .tp-facts { grid-template-columns: repeat(6, minmax(0, 1fr)); }

    .tp-facts > * { grid-column: span 2; }
    /* Правило планшета перекрывается явно: на шести колонках оно дало бы
       остатку две трети ряда вместо трети. */
    .tp-facts > :last-child:nth-child(2n + 1) { grid-column: span 2; }

    .tp-facts > :last-child:nth-child(3n + 1) { grid-column: span 6; }

    .tp-facts > :nth-last-child(2):nth-child(3n + 1),
    .tp-facts > :nth-last-child(2):nth-child(3n + 1) + * { grid-column: span 3; }
}

/* --- Плитка --------------------------------------------------------------- */

/* Значок лежит внутри dt, а не в отдельной обертке: dl допускает
   группировку через div, но dt и dd обязаны быть его прямыми детьми.
   Промежуточный блок давал 16 нарушений dlitem на страницу. */
.tp-fact {
    position: relative;
    /* Без min-width длинные значения вроде перечисления транспорта распирают
       ячейку сетки и ломают ряд. */
    min-width: 0;
    padding: var(--tp-3);
    border-radius: var(--tp-r-md);
    background: var(--tp-fact-tint, var(--tp-surface-tint));
}

.tp-fact-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    margin-bottom: var(--tp-2);
    border-radius: var(--tp-r-sm);
    background: var(--tp-fact-badge, var(--tp-surface-accent));
    color: var(--tp-fact-ink, var(--tp-ink-muted));
    font-size: 1.05rem;
}

/* От планшета значок уходит влево и стоит рядом с обеими строками сразу. */
@media (min-width: 576px) {
    .tp-fact {
        padding: var(--tp-4);
        padding-left: calc(var(--tp-4) + 36px + var(--tp-3));
    }

    .tp-fact-icon {
        position: absolute;
        top: var(--tp-4);
        left: var(--tp-4);
        margin-bottom: 0;
    }
}

/* Слова вроде «индивидуальных» и «достопримечательностей» шире плитки в
   166px на 390px экране и выпирали за ее край. Перенос по слогам только на
   узких колонках: на десктопе он не нужен и рвал бы слова без причины. */
.tp-fact dt,
.tp-fact dd {
    overflow-wrap: break-word;
}

@media (max-width: 575.98px) {
    .tp-fact dt,
    .tp-fact dd {
        hyphens: auto;
    }

    /* Город уже назван в заголовке, а отдельной строкой чип съедал ряд. */
    .tp-facts-place {
        display: none;
    }
}

.tp-fact dt {
    font-size: var(--tp-fs-xs);
    font-weight: 400;
    line-height: 1.3;
    color: var(--tp-ink-muted);
}

.tp-fact dd {
    margin: 2px 0 0;
    font-size: var(--tp-fs-md);
    font-weight: 600;
    line-height: 1.25;
    color: var(--tp-ink);
    /* Цифры в соседних плитках должны стоять в одной сетке, иначе диапазон
       цен выглядит набранным вручную. */
    font-variant-numeric: tabular-nums;
}

@media (min-width: 576px) {
    .tp-fact dd { font-size: var(--tp-fs-lg); }
}

/* На широком экране плитка просторнее: пропорции подписи, значка и значения
   те же, что в макете. */
@media (min-width: 992px) {
    .tp-fact {
        padding: var(--tp-4) var(--tp-5);
        padding-left: calc(var(--tp-5) + 44px + var(--tp-4));
    }

    .tp-fact-icon {
        top: var(--tp-4);
        left: var(--tp-5);
        width: 44px;
        height: 44px;
        font-size: 1.25rem;
    }

    .tp-fact dd { font-size: 1.25rem; }
}

/* Служебные слова внутри значения: «до», «из 5». Они часть факта, но не
   его суть, поэтому не спорят с цифрой по весу. */
.tp-fact-sep {
    font-weight: 400;
    color: var(--tp-ink-muted);
}

.tp-fact-note {
    display: block;
    margin-top: 2px;
    font-size: var(--tp-fs-xs);
    font-weight: 400;
    color: var(--tp-ink-muted);
}

/* --- Палитра плиток -------------------------------------------------------
   Каждая тройка проверена на контраст: подпись на подложке не ниже 4.74,
   значение не ниже 13.78, иконка на бейдже не ниже 3.74 при норме 3.
   ------------------------------------------------------------------------- */

.tp-fact--amber  { --tp-fact-tint: #fef4e8; --tp-fact-badge: #f9d3a4; --tp-fact-ink: #9a5b06; }
.tp-fact--blue   { --tp-fact-tint: #eaf1fd; --tp-fact-badge: #c6d9f9; --tp-fact-ink: #1d4ed8; }
.tp-fact--violet { --tp-fact-tint: #f2edfd; --tp-fact-badge: #dbcefa; --tp-fact-ink: #6d28d9; }
.tp-fact--green  { --tp-fact-tint: #eaf7ee; --tp-fact-badge: #c3e7cf; --tp-fact-ink: #15803d; }
.tp-fact--pink   { --tp-fact-tint: #fdeef4; --tp-fact-badge: #f8cbde; --tp-fact-ink: #be185d; }
.tp-fact--indigo { --tp-fact-tint: #eeecfc; --tp-fact-badge: #d3ccf7; --tp-fact-ink: #4338ca; }
.tp-fact--teal   { --tp-fact-tint: #e8f5f3; --tp-fact-badge: #c2e2dd; --tp-fact-ink: #0f766e; }
.tp-fact--sky    { --tp-fact-tint: #e9f2fb; --tp-fact-badge: #c4dcf4; --tp-fact-ink: #0369a1; }

/* ==========================================================================
   Списки «Выбор туристов»
   Было: ol с маркерами по умолчанию и синими подчеркнутыми ссылками в две
   строки. Номер и текст не выравнивались, колонки разъезжались.
   ========================================================================== */

.tp-toplist-card {
    padding: var(--tp-4);
    background: var(--tp-surface);
    border: 1px solid var(--tp-border);
    border-radius: var(--tp-r-md);
}

.tp-toplist-title {
    margin: 0 0 var(--tp-2);
    font-size: var(--tp-fs-sm);
    font-weight: 600;
    letter-spacing: .02em;
    color: var(--tp-ink-muted);
}

.tp-toplist {
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: tp-top;
}

.tp-toplist li {
    display: grid;
    grid-template-columns: 24px 1fr auto;
    align-items: start;
    gap: var(--tp-3);
    padding: var(--tp-2) 0;
    border-top: 1px solid var(--tp-border);
    counter-increment: tp-top;
}

.tp-toplist li:first-child {
    border-top: 0;
    padding-top: 0;
}

.tp-toplist li::before {
    content: counter(tp-top);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--tp-surface-accent);
    color: var(--tp-ink-muted);
    font-size: var(--tp-fs-xs);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.tp-toplist a {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    color: var(--tp-ink);
    text-decoration: none;
    line-height: 1.35;
}

.tp-toplist a:hover,
.tp-toplist a:focus-visible {
    color: var(--tp-link);
    text-decoration: underline;
}

.tp-toplist-meta {
    white-space: nowrap;
    font-size: var(--tp-fs-sm);
    font-weight: 600;
    color: var(--tp-ink);
    font-variant-numeric: tabular-nums;
}

.tp-toplist-meta .bi {
    color: #ffc107;
}

/* В колонке без оценок третья дорожка сетки не нужна. */
.tp-toplist-plain li {
    grid-template-columns: 24px 1fr;
}

/* ==========================================================================
   Чипы характеристик
   Жили в product-page.css, то есть были доступны только карточке товара.
   В листинге тем временем стояла серая плашка bg-light со своими отступами.
   ========================================================================== */

.tp-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--tp-2);
}

.tp-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--tp-2);
    min-height: 32px;
    max-width: 100%;
    padding: 0 var(--tp-3);
    border-radius: var(--tp-r-pill);
    background: var(--tp-surface-tint);
    color: var(--tp-ink);
    font-size: var(--tp-fs-sm);
    line-height: 1.3;
    /* Перечисления вроде языков или видов транспорта бывают длиной в строку */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tp-chip i { color: var(--tp-ink-muted); }

.tp-chip--accent { background: var(--tp-surface-accent); }

.tp-chip--urgent {
    background: #fff4e0;
    color: #7a4b00;
}

.tp-chip--free {
    background: #e6f4ee;
    color: #0b5c45;
}

/* В карточке листинга чипов до трех в ряд шириной 400px, поэтому мельче. */
.tp-chips--sm .tp-chip {
    min-height: 26px;
    padding: 0 var(--tp-2);
    font-size: var(--tp-fs-xs);
    gap: var(--tp-1);
}

/* ==========================================================================
   Карточка товара в листинге
   Замеры до правок на странице категории, 1440px: заголовок обрезался с
   просветом третьей строки на 6 карточках из 36, на 390px - на 20 из 36;
   цена в ряду стояла на разной высоте в 11 рядах из 12, разброс до 37px;
   левый край содержимого шел по трем линиям - 16, 20 и 24px.
   ========================================================================== */

.tp-product-card {
    border: 0;
    border-radius: var(--tp-r-md);
    overflow: hidden;
    background: var(--tp-surface);
}

.tp-product-card .card-body {
    display: flex;
    flex-direction: column;
    gap: var(--tp-2);
    padding: var(--tp-4);
    color: var(--tp-ink);
}

/* Строка оценки и счетчиков. Отступы задавались ms-3 на каждом элементе:
   пустой блок отзывов оставлял 16px пустоты, а обертка с px-2 сдвигала всю
   строку на 8px вправо от левого края остального содержимого. */
.tp-card-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--tp-1) var(--tp-4);
    min-height: 24px;
    font-size: var(--tp-fs-sm);
    color: var(--tp-ink-muted);
}

.tp-card-meta .badge {
    font-weight: 500;
}

/* Заголовок. line-clamp считает по content box, а overflow скрывает по
   padding box: с py-2 в разметке 8px третьей строки оставались видны и
   налезали на строку характеристик. Отступы здесь только внешние. */
.tp-card-title {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin: 0;
    padding: 0;
    min-height: 2.6em;
    font-size: var(--tp-fs-lg);
    font-weight: 600;
    line-height: 1.3;
    color: var(--tp-ink);
}

a:hover > .tp-card-title,
a:focus-visible > .tp-card-title {
    color: var(--tp-link);
}

.tp-card-desc {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin: 0;
    font-size: var(--tp-fs-sm);
    line-height: 1.45;
    color: var(--tp-ink-muted);
}

/* Подвал прижат к низу. Карточки в ряду равной высоты, но цена в них стояла
   на разной высоте, потому что ее положение зависело от длины описания. */
.tp-card-footer {
    display: flex;
    flex-direction: column;
    gap: var(--tp-2);
    margin-top: auto;
    padding-top: var(--tp-3);
}

.tp-card-price {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--tp-1);
    font-size: var(--tp-fs-xl);
    font-weight: 600;
    line-height: 1.2;
    color: var(--tp-ink);
}

.tp-card-price-from,
.tp-card-price-per {
    font-size: var(--tp-fs-sm);
    font-weight: 400;
    color: var(--tp-ink-muted);
}

/* ==========================================================================
   Бейдж вида товара
   Не всякий товар это экскурсия: 2 506 авторских туров и 109 входных
   билетов из 55 559 активных. В листинге бейдж лежит поверх фотографии,
   поэтому фон плотный, а не полупрозрачный: под ним может оказаться что
   угодно. Цвет у каждого вида свой, иначе бейджи не различить с расстояния.
   ========================================================================== */

.tp-badge-kind {
    display: inline-flex;
    align-items: center;
    gap: var(--tp-1);
    padding: var(--tp-1) var(--tp-3);
    border-radius: var(--tp-r-pill);
    background: #3730a3;
    color: #ffffff;
    font-size: var(--tp-fs-xs);
    font-weight: 600;
    line-height: 1.4;
    white-space: nowrap;
}

.tp-badge-kind--tour     { background: #3730a3; }   /* белый на нем 9.93:1 */
.tp-badge-kind--ticket   { background: #115e59; }   /* 7.58:1 */
.tp-badge-kind--transfer { background: #334155; }   /* 10.35:1 */

/* ==========================================================================
   Панель листинга
   Было: строка селектов с состоянием только в памяти страницы и ряд кнопок
   сортировки, где ни одна не была отмечена по умолчанию. Стало: даты,
   кнопка расширенных фильтров со счетчиком, сортировка рядом, а не внутри,
   и строка выбранного.
   ========================================================================== */

.tp-panel {
    display: flex;
    flex-direction: column;
    gap: var(--tp-3);
    padding: var(--tp-3);
    border: 1px solid var(--tp-border);
    border-radius: var(--tp-r-lg);
    background: var(--tp-surface);
}

.tp-panel__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--tp-2);
}

/* Даты */
.tp-panel__dates {
    display: inline-flex;
    align-items: center;
    gap: var(--tp-2);
    min-height: 40px;
    padding: 0 var(--tp-3);
    border: 1px solid var(--tp-border-strong);
    border-radius: var(--tp-r-sm);
    color: var(--tp-ink-muted);
    background: var(--tp-surface);
}

.tp-panel__dates-input {
    /* Пустое поле держит только подсказку, с выбранным периодом
       расширяется под него: 23 знака в 11ch обрывались на середине
       второй даты - «27.08.2026 - 0». */
    width: 23ch;
    /* Поле должно занимать всю высоту обертки: иначе цель нажатия 21px */
    align-self: stretch;
    border: 0;
    padding: 0;
    background: transparent;
    color: var(--tp-ink);
    font-size: var(--tp-fs-sm);
}

.tp-panel__dates-input:placeholder-shown { width: 11ch; }
.tp-panel__dates-input::placeholder { color: var(--tp-ink-muted); }
.tp-panel__dates:focus-within { border-color: var(--tp-link); }

/* Кнопка расширенных фильтров */
.tp-panel__filters {
    display: inline-flex;
    align-items: center;
    gap: var(--tp-2);
    min-height: 40px;
    padding: 0 var(--tp-4);
    border: 1px solid var(--tp-border-strong);
    border-radius: var(--tp-r-sm);
    background: var(--tp-surface);
    color: var(--tp-ink);
    font-size: var(--tp-fs-sm);
    font-weight: 500;
}

.tp-panel__filters:hover { background: var(--tp-surface-tint); }

.tp-panel__badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: var(--tp-r-pill);
    background: var(--tp-link);
    color: #ffffff;
    font-size: var(--tp-fs-xs);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* Сортировка */
.tp-sort {
    display: flex;
    flex-wrap: wrap;
    gap: var(--tp-1);
    padding: 3px;
    border-radius: var(--tp-r-sm);
    background: var(--tp-surface-tint);
}

.tp-sort__item {
    display: inline-flex;
    align-items: center;
    min-height: 34px;
    padding: 0 var(--tp-3);
    border-radius: 6px;
    color: var(--tp-ink-muted);
    font-size: var(--tp-fs-sm);
    text-decoration: none;
    white-space: nowrap;
}

.tp-sort__item:hover { color: var(--tp-ink); }

/* Выбранный вариант виден без открытия: раньше по умолчанию не был отмечен
   ни один, хотя выдача была отсортирована по популярности. */
.tp-sort__item.is-active {
    background: var(--tp-surface);
    color: var(--tp-ink);
    font-weight: 600;
    box-shadow: var(--tp-shadow-sm);
}

.tp-panel__total {
    margin: 0 0 0 auto;
    color: var(--tp-ink-muted);
    font-size: var(--tp-fs-sm);
    font-variant-numeric: tabular-nums;
}

/* Выбранное */
.tp-panel__chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--tp-2);
    padding-top: var(--tp-3);
    border-top: 1px solid var(--tp-border);
}

.tp-chip--removable {
    gap: var(--tp-2);
    border: 1px solid var(--tp-border-strong);
    background: var(--tp-surface);
    color: var(--tp-ink);
    text-decoration: none;
}

.tp-chip--removable:hover { background: var(--tp-surface-tint); }
.tp-chip--removable .bi { font-size: 11px; color: var(--tp-ink-muted); }

.tp-panel__reset {
    display: inline-flex;
    align-items: center;
    min-height: 32px;
    padding: 0 var(--tp-2);
    color: var(--tp-link);
    font-size: var(--tp-fs-sm);
    text-decoration: none;
}

.tp-panel__reset:hover { text-decoration: underline; }

/* Плавающая панель.
   Маячок отмечает исходное место панели, распорка занимает ее высоту после
   того, как панель ушла из потока. Обе служебные и ничего не показывают. */
.tp-panel__sentinel { height: 1px; margin-bottom: -1px; }
.tp-panel__spacer[hidden] { display: none; }

.tp-panel.is-stuck {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1020;  /* ниже модалки Bootstrap (1055), выше карточек */
    padding: var(--tp-3) 0;  /* горизонтальный отступ отдан строке ниже */
    border-radius: 0;
    border-width: 0 0 1px;
    box-shadow: var(--tp-shadow-md);
}

/* Внутри страница ограничена контейнером, а прилипшая панель во всю ширину.
   Строку возвращаем на ту же сетку, иначе контролы уезжают к краю экрана.

   width и min-width обязательны. Без width поля auto-отступы отключают
   растягивание строки, и ее ширину начинает диктовать минимальный размер
   содержимого: лента сортировки в четыре пункта требует 433px, и на экране
   393px кнопка «Фильтры» уезжала за правый край. */
.tp-panel.is-stuck .tp-panel__row {
    width: 100%;
    min-width: 0;
    max-width: 1320px;
    margin: 0 auto;
    padding: 0 var(--tp-3);
}

/* Выбранное в прилипшей панели не показываем: строка чипов вырастает до двух
   рядов и на телефоне съедает треть экрана. Количество условий видно на
   бейдже кнопки «Фильтры», а сами чипы остаются на месте панели. */
.tp-panel.is-stuck .tp-panel__chips { display: none; }

@media (max-width: 575.98px) {
    .tp-panel__total { width: 100%; margin-left: 0; order: 3; }
    /* min-width нужен, чтобы лента могла сжаться и прокручиваться внутри
       себя, а не распирать строку до суммы всех четырех пунктов */
    .tp-sort { order: 4; width: 100%; min-width: 0; overflow-x: auto; flex-wrap: nowrap; }
    .tp-panel__dates { flex: 1 1 auto; min-width: 0; }
    /* Обертка растягивается на всю строку, а поле внутри оставалось шириной
       11ch: из 243px видимого поля нажатие ловили 83px, и палец попадал в
       мертвую зону чаще, чем в поле - календарь просто не открывался.
       Заодно выбранный период (23 знака) перестает обрезаться. */
    .tp-panel__dates-input { flex: 1 1 auto; width: auto; min-width: 0; }

    /* Календарь на телефоне - лист снизу.
       Он высотой 391px и раскрывается под полем: на экране 658px кнопка
       «Показать» оказывалась за нижним краем, и выбрать даты было нечем.
       Плагин ставит координаты инлайном, перебить их можно только
       !important. Метку tp-drp-sheet вешает filter.js, чтобы правило не
       задело такой же календарь на странице товара. */
    .daterangepicker.tp-drp-sheet {
        position: fixed !important;
        inset: auto 0 0 0 !important;
        width: auto !important;
        max-width: none !important;
        max-height: 85vh;
        overflow-y: auto;
        border-radius: var(--tp-r-lg) var(--tp-r-lg) 0 0;
        box-shadow: 0 -8px 32px rgba(22, 35, 43, .18);
    }

    /* Хвостик-стрелка привязан к полю, у листа снизу он повисает сбоку */
    .daterangepicker.tp-drp-sheet:before,
    .daterangepicker.tp-drp-sheet:after { display: none; }

    /* На телефоне календарь один, но плагин оставляет обе половины в потоке */
    .daterangepicker.tp-drp-sheet .drp-calendar { max-width: 100%; float: none; }

    /* На телефоне прилипшая панель должна оставаться полосой, а не экраном:
       общее число уходит (оно есть на кнопке «Показать» и под листингом),
       отступы и цели ужимаются до минимально допустимых. */
    .tp-panel.is-stuck { gap: var(--tp-2); padding: var(--tp-2) 0; }
    .tp-panel.is-stuck .tp-panel__total { display: none; }
    .tp-panel.is-stuck .tp-panel__dates,
    .tp-panel.is-stuck .tp-panel__filters { min-height: 36px; }
    .tp-panel.is-stuck .tp-sort__item { min-height: 30px; }
}

/* ==========================================================================
   Модалка расширенных фильтров
   ========================================================================== */

.tp-filters__dialog { max-width: 560px; }

.tp-filters__content {
    border: 0;
    border-radius: var(--tp-r-lg);
}

.tp-filters__header {
    align-items: center;
    padding: var(--tp-4) var(--tp-5);
    border-bottom: 1px solid var(--tp-border);
}

.tp-filters__title {
    margin: 0;
    font-size: var(--tp-fs-xl);
    font-weight: 700;
    color: var(--tp-ink);
}

.tp-filters__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    margin: 0 0 0 auto;
    border: 0;
    border-radius: var(--tp-r-sm);
    background: var(--tp-surface-tint);
    color: var(--tp-ink);
}

.tp-filters__close:hover { background: var(--tp-surface-accent); }

.tp-filters__body {
    display: flex;
    flex-direction: column;
    gap: var(--tp-6);
    padding: var(--tp-5);
}

.tp-filters__group { border: 0; margin: 0; padding: 0; min-width: 0; }

.tp-filters__legend {
    float: none;          /* legend в Bootstrap растянут на всю ширину */
    width: auto;
    margin-bottom: var(--tp-3);
    font-size: var(--tp-fs-lg);
    font-weight: 700;
    color: var(--tp-ink);
}

.tp-filters__list {
    display: flex;
    flex-direction: column;
    gap: var(--tp-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

.tp-filters__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: var(--tp-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.tp-filters__chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--tp-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* --- Чекбокс с подписью --- */

.tp-check {
    display: grid;
    grid-template-columns: 22px 1fr;
    gap: var(--tp-3);
    align-items: start;
    cursor: pointer;
}

.tp-check input {
    grid-area: 1 / 1;
    width: 22px;
    height: 22px;
    margin: 0;
    opacity: 0;
}

.tp-check__box {
    grid-area: 1 / 1;
    width: 22px;
    height: 22px;
    border: 2px solid var(--tp-border-strong);
    border-radius: 6px;
    background: var(--tp-surface);
    pointer-events: none;
}

.tp-check input:checked + .tp-check__box {
    border-color: var(--tp-link);
    background: var(--tp-link) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5 6.5 12 13 4.5'/%3E%3C/svg%3E") center / 14px no-repeat;
}

.tp-check input:focus-visible + .tp-check__box {
    outline: 2px solid var(--tp-link);
    outline-offset: 2px;
}

.tp-check__text { display: block; min-width: 0; }

.tp-check__title {
    display: flex;
    align-items: baseline;
    gap: var(--tp-2);
    font-size: var(--tp-fs-md);
    font-weight: 600;
    color: var(--tp-ink);
    line-height: 1.3;
}

.tp-check__count,
.tp-tile__count,
.tp-toggle__count {
    color: var(--tp-ink-muted);
    font-size: var(--tp-fs-xs);
    font-weight: 400;
    font-variant-numeric: tabular-nums;
}

.tp-check__hint {
    display: block;
    margin-top: 2px;
    font-size: var(--tp-fs-sm);
    color: var(--tp-ink-muted);
    line-height: 1.35;
}

/* --- Плитка способа передвижения --- */

.tp-tile {
    display: flex;
    align-items: center;
    gap: var(--tp-2);
    min-height: 44px;
    padding: var(--tp-2) var(--tp-3);
    border: 1px solid var(--tp-border);
    border-radius: var(--tp-r-sm);
    cursor: pointer;
}

.tp-tile input { position: absolute; opacity: 0; width: 0; height: 0; }

.tp-tile__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    border-radius: 8px;
    background: var(--tp-surface-tint);
    color: var(--tp-ink-muted);
}

.tp-tile__label {
    flex: 1 1 auto;
    min-width: 0;
    font-size: var(--tp-fs-sm);
    color: var(--tp-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tp-tile:hover { border-color: var(--tp-border-strong); }

.tp-tile:has(input:checked) {
    border-color: var(--tp-link);
    background: #eef4fd;
}

.tp-tile:has(input:checked) .tp-tile__icon {
    background: var(--tp-link);
    color: #ffffff;
}

.tp-tile:has(input:focus-visible) {
    outline: 2px solid var(--tp-link);
    outline-offset: 2px;
}

/* --- Чип-переключатель длительности --- */

.tp-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--tp-2);
    min-height: 36px;
    padding: 0 var(--tp-4);
    border: 1px solid var(--tp-border-strong);
    border-radius: var(--tp-r-pill);
    font-size: var(--tp-fs-sm);
    color: var(--tp-ink);
    cursor: pointer;
}

.tp-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.tp-toggle:hover { background: var(--tp-surface-tint); }

.tp-toggle:has(input:checked) {
    border-color: var(--tp-link);
    background: var(--tp-link);
    color: #ffffff;
}

/* .75 давало 4.32:1 на синем - ниже порога AA для мелкого текста */
.tp-toggle:has(input:checked) .tp-toggle__count { color: rgba(255, 255, 255, .85); }

.tp-toggle:has(input:focus-visible) {
    outline: 2px solid var(--tp-link);
    outline-offset: 2px;
}

/* Значение, которое дало бы пустую выдачу, остается видимым, но выключенным:
   так понятно, что параметр есть, и нельзя собрать ноль карточек. */
.tp-check.is-empty,
.tp-tile.is-empty,
.tp-toggle.is-empty {
    opacity: .45;
    cursor: not-allowed;
}

/* --- Цена --- */

.tp-range { display: flex; flex-direction: column; gap: var(--tp-4); }

.tp-range__inputs {
    display: flex;
    align-items: center;
    gap: var(--tp-3);
}

.tp-range__field { flex: 1 1 0; min-width: 0; }

.tp-range__field input {
    width: 100%;
    min-height: 44px;
    padding: 0 var(--tp-3);
    border: 1px solid var(--tp-border-strong);
    border-radius: var(--tp-r-sm);
    background: var(--tp-surface);
    color: var(--tp-ink);
    font-size: var(--tp-fs-md);
    font-variant-numeric: tabular-nums;
}

.tp-range__field input:focus-visible {
    outline: 2px solid var(--tp-link);
    outline-offset: 1px;
    border-color: var(--tp-link);
}

.tp-range__dash { color: var(--tp-ink-muted); }

.tp-range__slider { position: relative; height: 24px; }

.tp-range__track,
.tp-range__fill {
    position: absolute;
    top: 11px;
    height: 3px;
    border-radius: 2px;
}

.tp-range__track { left: 0; right: 0; background: var(--tp-border-strong); }
.tp-range__fill { background: var(--tp-link); }

.tp-range__thumb {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 24px;
    margin: 0;
    background: none;
    pointer-events: none;
    appearance: none;
}

.tp-range__thumb::-webkit-slider-thumb {
    appearance: none;
    width: 22px;
    height: 22px;
    border: 3px solid var(--tp-link);
    border-radius: 50%;
    background: var(--tp-surface);
    pointer-events: auto;
    cursor: grab;
}

.tp-range__thumb::-moz-range-thumb {
    width: 22px;
    height: 22px;
    border: 3px solid var(--tp-link);
    border-radius: 50%;
    background: var(--tp-surface);
    pointer-events: auto;
    cursor: grab;
}

.tp-range__thumb:focus-visible::-webkit-slider-thumb {
    outline: 2px solid var(--tp-link);
    outline-offset: 2px;
}

/* --- Подвал модалки --- */

.tp-filters__footer {
    gap: var(--tp-4);
    justify-content: space-between;
    padding: var(--tp-4) var(--tp-5);
    border-top: 1px solid var(--tp-border);
    background: var(--tp-surface);
}

.tp-filters__submit {
    flex: 1 1 auto;
    min-height: 48px;
    padding: 0 var(--tp-5);
    border: 0;
    border-radius: var(--tp-r-sm);
    background: var(--tp-link);
    color: #ffffff;
    font-size: var(--tp-fs-md);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.tp-filters__submit:hover { background: #084298; }

.tp-filters__reset {
    flex: 0 0 auto;
    color: var(--tp-link);
    font-size: var(--tp-fs-md);
    text-decoration: none;
}

.tp-filters__reset:hover { text-decoration: underline; }

@media (max-width: 575.98px) {
    .tp-filters__body { padding: var(--tp-4); gap: var(--tp-5); }
    .tp-filters__header,
    .tp-filters__footer { padding: var(--tp-3) var(--tp-4); }
    .tp-filters__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ==========================================================================
   Пагинация и подгрузка
   ========================================================================== */

.tp-listing__more {
    display: flex;
    justify-content: center;
    margin: var(--tp-5) 0 var(--tp-4);
}

.tp-listing__more-btn {
    min-height: 48px;
    padding: 0 var(--tp-7);
    border: 1px solid var(--tp-border-strong);
    border-radius: var(--tp-r-pill);
    background: var(--tp-surface);
    color: var(--tp-ink);
    font-weight: 600;
}

.tp-listing__more-btn:hover { background: var(--tp-surface-tint); }
.tp-listing__more-btn[disabled] { opacity: .6; }

.tp-pager {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--tp-2);
    margin-bottom: var(--tp-6);
}

.tp-pager__list {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: var(--tp-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

.tp-pager__item,
.tp-pager__arrow,
.tp-pager__gap {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 40px;
    height: 40px;
    padding: 0 var(--tp-2);
    border-radius: var(--tp-r-pill);
    color: var(--tp-ink);
    font-size: var(--tp-fs-sm);
    text-decoration: none;
    font-variant-numeric: tabular-nums;
}

.tp-pager__item:hover,
.tp-pager__arrow:hover { background: var(--tp-surface-tint); }

.tp-pager__item.is-current {
    background: var(--tp-surface-accent);
    font-weight: 600;
}

.tp-pager__arrow.is-disabled,
.tp-pager__gap { color: var(--tp-ink-faint); }

.tp-pager__summary {
    margin: 0;
    color: var(--tp-ink-muted);
    font-size: var(--tp-fs-sm);
    font-variant-numeric: tabular-nums;
}

.tp-empty {
    padding: var(--tp-7) var(--tp-4);
    text-align: center;
}

.tp-empty__title {
    margin: 0 0 var(--tp-2);
    font-size: var(--tp-fs-lg);
    font-weight: 600;
    color: var(--tp-ink);
}

.tp-empty__hint {
    margin: 0 0 var(--tp-4);
    color: var(--tp-ink-muted);
}
