/* ========================================
   COURTS — List & Detail Pages
   Styles with ct- prefix
   Leaflet map + cards grid + detail
   ======================================== */

/* ---- HERO ---- */
/* Высота общая для всех карточек: игрок, тренер, корт, турнир */
/* Высота, кегли и отступы — те же, что у «Турниров» и категорий:
   один сайт, шапки разделов должны читаться одинаково */
/* ОБЛОЖКА СТОИТ НА ОБЩИХ КРУТИЛКАХ РАЗДЕЛА — решение Кости 04.10,
   доска 482:9 блок N. «Корты» были последним разделом со своими числами:
   пол 460 при 360 у остальных, на 768 — наоборот 275, а воздух снизу
   давал 37.4 на десктопе и 26.6 на 1024, мимо шкалы (замер 07.10).
   Компонент один на ДВЕ страницы — список кортов и страницу корта. */
.ct-hero {
    position: relative;
    min-height: var(--oblozhka-pol);
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: var(--oblozhka-vozduh) var(--pad-x) var(--oblozhka-vozduh-niz);
    overflow: hidden;
}

.ct-hero::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, var(--modal-bg-heavy) 0%, var(--alpha-black-85) 60%, var(--bg-primary) 100%);
    z-index: 1;
}

.ct-hero-bg {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    opacity: 0.75;
}

.ct-hero-content {
    position: relative;
    z-index: 2;
    max-width: 700px;
}

/* Кегль — ступень шкалы, а не доля ширины. Было 22.6 · 33.8 · 37.1 ·
   45.1 · 49.6 — ни одного числа со шкалы. Стало 26 · 32 · 32 · 40 · 40,
   как у «Турниров», «Рейтинга» и «Услуг». */
.ct-hero-title {
    font-size: var(--fs-hero);
    font-weight: var(--fw-extrabold);
    line-height: var(--lh-tight);
    letter-spacing: -0.02em;
    margin-bottom: var(--space-4);
}

.ct-hero-title span {
    color: var(--accent);
}

.ct-hero-subtitle {
    font-size: var(--fs-hero-sub);
    font-weight: var(--fw-semibold);
    color: var(--text-secondary);
    max-width: 720px;
    margin: 0 auto;
    line-height: var(--lh-normal);
}

/* ---- CONTAINER ---- */
/* ВИТРИНА ИДЁТ ПО ШИРОКОЙ КОРОБКЕ, ТАБЛИЦА — ПО УЗКОЙ (правило 07.10).
   1100 — ширина СТРОК рейтинга по ATP/WTA/ITF; карточки у тех же ATP, у
   Airbnb и у нашего лендинга идут по широкой. При 1100 четыре карточки
   дают 245, при 1400 — 332 (посчитано и проверено в браузере). */
.ct-container {
    max-width: var(--container-max);
    margin: 0 auto;
    padding: var(--section-y) var(--pad-x) var(--section-y);
}

/* ---- ПОЛОСА ФИЛЬТРОВ ----
   СВОЕЙ ПОЛОСЫ У КОРТОВ НЕТ. Разметка берёт общие классы `trn-filters`,
   `trn-back`, `trn-search-wrap`, `trn-search-input`, `trn-chips` из
   style.css (js/courts.js:644) — те же, что на страницах категорий
   турниров. Замер 07.10 подтвердил совпадение: назад 14, поиск 320 × 44
   радиусом 8, выпадашки 44 высотой и 12 кеглем.

   ЗДЕСЬ ЛЕЖАЛА ВТОРАЯ ПОЛОСА — тринадцать классов (`.ct-filters-wrap`,
   `.ct-filters-row`, `.ct-search-wrap`, `.ct-search-icon`,
   `.ct-search-input`, `.ct-filter-group`, `.ct-filter-divider`,
   `.ct-filter-label`, `.ct-filter-chips`, `.ct-back-links`,
   `.ct-back-sep`, `.ct-back-link`, `.ct-back-service`), и в ней поле
   поиска было таблеткой на 480. МЁРТВЫМ КОД НАЗВАН ПОСЛЕ ПРОВЕРКИ:
   ни один из тринадцати не встречается ни в одной разметке и ни в одном
   скрипте — проверено по всему дереву 07.10. Второе определение одного
   понятия ждало только того, кто его применит.
   ---- */

/* ---- COURTS GRID ---- */
/* ЧИСЛО КОЛОНОК — СЛЕДСТВИЕ ШИРИНЫ КАРТОЧКИ, А НЕ ГРАНИЦЫ ЭКРАНА.
   Правило выведено на «Услугах» 07.10 и применяется без нового разбора.
   `auto-fill` с минимумом 300 даёт 4 · 3 · 2 · 2 на наших пяти видах —
   замерено. Четыре в ряд — слово Кости 07.10; четыре на 1024 ставить
   нельзя: там карточка 226, метка «Партнёр» вылезает за край и обе
   кнопки переносятся на вторую строку (замер ночью 07.10). */
.ct-grid {
    /* РЯДОВ НА СТРАНИЦЕ — ЧЕТЫРЕ НА ШИРОКИХ, ТРИ НА УЗКИХ. Слово Кости
       07.10. Число читает js и умножает на колонки: шаг страницы — это
       отношение «колонок × рядов», а не число. Замер длины страницы:
       3 ряда дают 1.8 · 2.1 · 1.7 · 1.6 · 3.9 экрана, 4 ряда —
       2.2 · 2.6 · 2.1 · 1.9 · 5.1. */
    --ct-ryadov: 4;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: var(--space-6);
}

@media (max-width: 992px) {
    .ct-grid { --ct-ryadov: 3; }
}

/* ДВЕ В РЯД НА ТЕЛЕФОНЕ — своим минимумом, а не числом колонок: при
   минимуме 300 экран 390 давал бы одну карточку, а двадцать кортов в
   столбик — это пять экранов. Граница 640: ширин в медиа две. */
@media (max-width: 640px) {
    .ct-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--space-3);
    }

    /* Кегли имени, меты и числа здесь НЕ переопределяются: у витрины
       один уровень на все виды, как у лендинга. Правится только то, что
       зависит от узости колонки. */
    .ct-card-cta {
        width: 100%;
        font-size: var(--fs-xs);
        text-align: center;
        justify-content: center;
    }

    .ct-card-partner {
        font-size: var(--fs-2xs);
        padding: 2px 6px;
        margin-left: 4px;
    }
}

.ct-card {
    background: var(--surface-glass);
    border: var(--bw-hair) solid var(--border-subtle);
    border-radius: var(--radius-lg);
    overflow: hidden;
    transition: border-color var(--transition-base), transform var(--transition-base);
    display: flex;
    flex-direction: column;
    cursor: pointer;
    text-decoration: none;
    color: inherit;
}

.ct-card:hover {
    border-color: var(--alpha-lime-20);
    transform: translateY(-4px);
}

.ct-card-img-wrap {
    position: relative;
    overflow: hidden;
}

/* ОТНОШЕНИЕ СТОРОН — СВОЙСТВО КАРТОЧКИ, А НЕ ЧИСЛО. Высота стояла 180 и
   110, и отношение гуляло от 1.55 до 3.27 — на планшете фотография была
   полоской (замер 07.10). 4:3 объявлено ОДИН раз на корт и тренера, как
   на лендинге (css/style.css:3740). `display: block` убирает щель
   базовой строки: объявлено было 180, занимала 187. */
.ct-card-img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
    object-fit: cover;
}

/* ПЛАШКИ РАЗДЕЛА — ОДНО ОПРЕДЕЛЕНИЕ НА ДВА МЕСТА, И ОНО ИЗ `Badge 27:53`.
   Компонент говорит прямо: «Height 24px, horizontal padding 8px, radius/full,
   11px Medium uppercase with 0.5px letter spacing». До 13.10 «Новый» носил
   своё сочетание (поле 3/10, вес 800, радиус числом 100px), а партнёрская
   плашка вообще жила инлайн-стилем внутри js (`courts.js`, строка карточки):
   два написания одной идеи, и ни одно не совпадало с компонентом. */
.ct-new-badge,
.ct-partner-badge {
    display: inline-flex;
    align-items: center;
    height: 24px;
    padding-inline: 8px;
    background: var(--accent);
    color: var(--accent-on);
    font-size: var(--fs-2xs);
    font-weight: var(--fw-medium);
    border-radius: var(--radius-full);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

/* Место на снимке карточки — у «Нового», и только оно своё */
.ct-new-badge {
    position: absolute;
    top: 12px;
    left: 12px;
    z-index: 2;
}

/* Map links */
.ct-map-embed {
    margin-bottom: 12px;
    border-radius: 12px;
    overflow: hidden;
}
.ct-map-embed iframe {
    width: 100%;
    height: 300px;
    border: var(--bw-hair) solid var(--border-subtle);
    border-radius: 12px;
}
.ct-map-links {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
}
/* КНОПКА 36 ЗАКОННА, ЕСЛИ У НЕЁ ЕСТЬ СЛОЙ ЦЕЛИ 44 — правило куплено на
   кнопке страницы (04.10) и на чипе пола (07.10), применяется сюда без
   нового разбора. Замер 13.10: коробка 39 — такой ступени на шкале кнопок
   нет вовсе (28 · 36 · 44 · 52), попадание 38. */
.ct-map-link {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-height: var(--btn-h-sm);
    padding-inline: 16px;
    background: var(--alpha-white-08);
    border: var(--bw-hair) solid var(--border-subtle);
    border-radius: 8px;
    color: var(--accent);
    font-size: var(--fs-sm);
    font-weight: 600;
    text-decoration: none;
    transition: background 0.2s;
}
.ct-map-link::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    height: var(--btn-h-md);
}

.ct-map-link:hover {
    background: var(--alpha-lime-12);
}

/* ПЛОТНОСТЬ Dense 12 ПО ОПИСАНИЮ `Card 29:65`, между строками 8 —
   те же числа, что у витрины лендинга (css/style.css:3758). Ритм задаёт
   ОДИН `gap`, а не поля у каждой строки по отдельности. */
.ct-card-body {
    padding: var(--space-3);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    flex-grow: 1;
}

.ct-card-top {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
}

/* ИМЯ — СТУПЕНЬ `card title` 16 С ЛЕНДИНГА, А НЕ 18. Карточка кортов
   была на ступень крупнее эталонной по двум уровням сразу, а вес в
   иерархии у неё тот же. Две строки с многоточием — чтобы ряд не
   разъезжался по высоте от длины названия. */
.ct-card-name {
    font-size: var(--fs-base);
    font-weight: 700;
    /* 1.25 не ступень лестницы 1 · 1.1 · 1.3 · 1.5 · 1.65 — замер 12.10 */
    line-height: 1.3;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.ct-card-partner {
    background: var(--accent);
    color: var(--neutral-black);
    font-size: var(--fs-2xs);
    font-weight: 700;
    padding: 3px 8px;
    border-radius: var(--radius-full);
    white-space: nowrap;
    flex-shrink: 0;
    margin-left: 8px;
    letter-spacing: 0.03em;
}

/* Мета — 12 с межстрочным 1.4, один уровень на все виды (было 14 и 12).
   Лайм отсюда уходит: ВНУТРИ ВИТРИНЫ ЛАЙМА НЕТ, он принадлежит одному
   главному действию в поле зрения (правило 109:370). Покрытие — значимая
   мета, 72 % белого: 5.33 при пороге 4.5. */
.ct-card-type {
    font-size: var(--fs-xs);
    /* 1.4 мимо лестницы — замер 12.10 */
    line-height: 1.5;
    color: var(--text-secondary);
    font-weight: 600;
}

/* ПРЕДПОЛОЖЕНИЕ, ПОМЕЧЕНО КАК ДОГАДКА: описание уходит из карточки на
   ВСЕХ видах. На ≤768 оно и так было спрятано, а при карточке 332 на
   десктопе занимало 90 из 250 пикселей тела — больше трети. Карточка
   сама ссылка на страницу корта, и подробности живут там. У витрины
   лендинга описания нет вовсе. Если скажешь вернуть — вернём двумя
   строками с многоточием. */
.ct-card-desc {
    display: none;
}

.ct-card-stats {
    display: flex;
    gap: var(--space-4);
    flex-wrap: wrap;
}

.ct-card-stat {
    text-align: center;
}

/* Число — ступень 16, вровень с именем: два уровня, а не три. Было 18,
   то есть крупнее имени карточки. Лайм снят по тому же правилу 109:370. */
.ct-card-stat-num {
    font-size: var(--fs-base);
    font-weight: 700;
    color: var(--text-primary);
    line-height: var(--lh-none);
}

.ct-card-stat-label {
    font-size: var(--fs-2xs);
    color: var(--text-muted);
    margin-top: 2px;
}

.ct-card-price {
    font-size: var(--fs-xs);
    /* 1.4 мимо лестницы — замер 12.10, та же правка, что у типа карточки */
    line-height: 1.5;
    color: var(--text-secondary);
}

.ct-card-price strong {
    color: var(--text-primary);
    font-weight: 700;
}

/* Membership Modal */
.ct-membership-overlay {
    position: fixed;
    inset: 0;
    z-index: 10000;
    background: var(--modal-bg-heavy);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    opacity: 0;
    transition: opacity 0.3s ease;
}

.ct-membership-overlay.visible {
    opacity: 1;
}

.ct-membership-overlay.visible .ct-membership-modal {
    transform: translateY(0);
}

.ct-membership-modal {
    background: var(--neutral-800);
    border: var(--bw-hair) solid var(--border-subtle);
    border-radius: var(--radius-xl);
    padding: 40px 32px;
    max-width: 400px;
    width: 100%;
    text-align: center;
    position: relative;
    transform: translateY(20px);
    transition: transform 0.3s ease;
}

.ct-membership-close {
    position: absolute;
    top: 12px; right: 16px;
    background: none;
    border: none;
    color: var(--alpha-white-50);
    font-size: var(--fs-xl);
    cursor: pointer;
    transition: color 0.2s;
}

.ct-membership-close:hover {
    color: var(--neutral-white);
}

.ct-membership-icon {
    margin-bottom: 16px;
}

.ct-membership-modal h3 {
    font-size: var(--fs-md);
    font-weight: 700;
    margin-bottom: 10px;
    color: var(--text-primary);
}

.ct-membership-modal p {
    color: var(--text-secondary);
    font-size: var(--fs-sm);
    line-height: var(--lh-relaxed);
    margin-bottom: 24px;
}

.ct-membership-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--accent);
    color: var(--neutral-black);
    font-weight: 700;
    font-size: var(--fs-base);
    padding: 12px 32px;
    border-radius: var(--radius-full);
    text-decoration: none;
    transition: background var(--transition-fast), transform var(--transition-fast);
}

.ct-membership-btn:hover {
    background: var(--accent-hover);
    transform: translateY(-2px);
}

/* Discount overlay on card photo */
.ct-discount-overlay {
    position: absolute;
    top: 12px;
    right: 12px;
    /* СКИДКА ГОВОРИТ ЛАЙМОМ — так она уже сказана в шести местах из девяти:
       `.ct-discount-percent`, `.co-vh-discount`, `.ct-svc-discount`,
       `.vr-discount-badge` и другие. Красным она была только на трёх
       обложках, и это второе определение одного понятия. Красный к тому
       же занят отказом и эфиром: выгода не должна выглядеть тревогой. */
    background: var(--accent);
    color: var(--neutral-black);
    font-size: var(--fs-xs);
    font-weight: 700;
    padding: 4px 10px;
    border-radius: 100px;
    z-index: 2;
    letter-spacing: 0.02em;
    backdrop-filter: blur(4px);
}

.ct-card-actions {
    display: flex;
    gap: 10px;
    align-items: center;
    margin-top: auto;
    width: 100%;
}

/* `.ct-card-btn` («Подробнее →») снята вместе со своей разметкой:
   карточка сама ссылка на корт, и кнопка была нажимаемым внутри
   нажимаемого. Осталось ОДНО действие, которое карточку не повторяет, —
   и ровно поэтому лайм на нём законен (правило 109:370). */
.ct-card-cta {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* ЦЕЛЬ НАЖАТИЯ — СТУПЕНЬ 44, А НЕ СЛЕДСТВИЕ ПОЛЕЙ. Было 41 (замер). */
    min-height: var(--btn-h-md);
    padding: 0 var(--space-3);
    border-radius: var(--radius-full);
    font-size: var(--fs-sm);
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    transition: all var(--transition-fast);
}

.ct-card-cta {
    background: var(--accent);
    color: var(--bg-primary);
    font-weight: 700;
    border: none;
}

.ct-card-cta:hover {
    opacity: 0.85;
}

/* ---- DETAIL PAGE ---- */

/* Back links — sticky */
.ct-detail-photo {
    width: 360px;
    height: 240px;
    border-radius: var(--radius-lg);
    object-fit: cover;
    border: var(--bw-thick) solid var(--border-subtle);
    flex-shrink: 0;
}

.ct-detail-info {
    flex-grow: 1;
}

/* ИМЯ В КАРТОЧКЕ — КЛАСС, А НЕ ТЕГ. До 13.10 селектор держался за `h1`, и
   это был ВТОРОЙ `h1` страницы: первый несёт обложка, а здесь то же имя
   повторялось заголовком первого уровня. Слово Кости 13.10: «имя оставляем
   на H1, на обложке». Текст и вид остались прежними, заголовком он быть
   перестал — значит и правило больше не может держаться за тег. */
.ct-detail-name {
    font-size: var(--fs-2xl);
    font-weight: 800;
    margin-bottom: 6px;
    letter-spacing: -0.02em;
}

.ct-detail-type {
    color: var(--accent);
    font-size: var(--fs-base);
    font-weight: 600;
    margin-bottom: 10px;
}

.ct-detail-address {
    color: var(--text-secondary);
    font-size: var(--fs-sm);
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 6px;
}

.ct-detail-phone {
    color: var(--text-secondary);
    font-size: var(--fs-sm);
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 16px;
}

/* ЦЕЛЬ НАЖАТИЯ 44 — ВЫСОТОЙ САМОЙ ССЫЛКИ. Замер 13.10 на 390: коробка 21,
   попадание 20 — телефон, WhatsApp и Instagram не брались пальцем вовсе.
   Прозрачный слой `::after` здесь не годится: строка живёт во флексе с
   иконкой, и слой забрал бы нажатие у иконки.
   ПЕРВАЯ ПОПЫТКА БЫЛА ХУЖЕ, И ЭТО ПОКАЗАЛ ЗАМЕР: поле 12 с отрицательным
   отступом −12 дало коробку 45, а попадание всего 36 — соседняя строка
   контакта наезжала на нижнюю половину зоны. Высота свойством соседей не
   трогает: строка контакта просто становится 44, как строка в карточке
   организации у Google. */
.ct-detail-phone a {
    display: inline-flex;
    align-items: center;
    min-height: var(--btn-h-md);
    color: var(--text-secondary);
    text-decoration: none;
    transition: color var(--transition-fast);
}

.ct-detail-phone a:hover {
    color: var(--accent);
}

/* Detail stats */
.ct-detail-stats {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 16px;
    margin-bottom: 48px;
}

.ct-detail-stat {
    background: var(--surface-glass);
    border: var(--bw-hair) solid var(--border-subtle);
    border-radius: var(--radius-lg);
    padding: 24px 16px;
    text-align: center;
}

/* Combined stat card */
.ct-detail-stats-single {
    display: flex;
    justify-content: center;
    grid-template-columns: none;
}

.ct-detail-stat-combined {
    background: var(--surface-glass);
    border: var(--bw-hair) solid var(--border-subtle);
    border-radius: var(--radius-lg);
    /* ПИЛЮЛЯ СТАЛА НА СТУПЕНЬ МЕНЬШЕ — слово Кости 13.10: «давай сделаем её
       чуть поменьше». Поля 20/32 → 16/24, обе ступени шкалы. Вместе с кеглем
       ниже это снимает и столкновение: показатель был 21/800, ровно как
       заголовок секции 21/700, и спорил с ним за первый взгляд. */
    padding: 16px 24px;
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    justify-content: center;
}

/* ПОКАЗАТЕЛЬ СТРОГО МЕЛЬЧЕ ЗАГОЛОВКА СЕКЦИИ — отношение, а не число.
   Было 21 при заголовке 21; стало 18 при 21. */
.ct-stat-item {
    font-size: var(--fs-md);
    font-weight: 800;
    color: var(--accent);
    white-space: nowrap;
}

.ct-stat-sep {
    color: var(--text-muted);
    font-size: var(--fs-md);
}

/* Court Types & Services tables */
.ct-types-table,
.ct-services-table {
    background: var(--alpha-white-04);
    border-radius: 12px;
    overflow: hidden;
    border: var(--bw-hair) solid var(--alpha-white-08);
}

.ct-types-header,
.ct-services-header {
    display: grid;
    padding: 10px 16px;
    font-size: var(--fs-xs);
    /* КОНТРАСТ 3.14 ПРИ НОРМЕ 4.5 — мерено 13.10, единственный провальный
       уровень страницы (остальные 10.25–16.85). Та же поправка уже записана
       в описании `Section stat strip 135:170`: «labels moved from text/dim
       (0.35) to text/muted (0.50)», и причина там названа та же. */
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-weight: 600;
    border-bottom: var(--bw-hair) solid var(--alpha-white-08);
}

.ct-types-header {
    grid-template-columns: 1fr 1fr 80px 120px;
}

.ct-services-header {
    grid-template-columns: 1fr 120px;
}

.ct-types-row,
.ct-services-row {
    display: grid;
    padding: 12px 16px;
    border-bottom: var(--bw-hair) solid var(--alpha-white-04);
    font-size: var(--fs-sm);
    color: var(--text-secondary);
    align-items: center;
}

.ct-types-row:last-child,
.ct-services-row:last-child {
    border-bottom: none;
}

.ct-types-row {
    grid-template-columns: 1fr 1fr 80px 120px;
}

.ct-services-row {
    grid-template-columns: 1fr 120px;
}

/* Center qty & price columns */
.ct-types-header span:nth-child(3),
.ct-types-header span:nth-child(4),
.ct-types-row span:nth-child(3),
.ct-types-row span:nth-child(4),
.ct-services-header span:nth-child(2),
.ct-services-row span:nth-child(2) {
    text-align: center;
}

.ct-svc-discount {
    background: var(--alpha-lime-12);
    color: var(--accent);
    font-size: var(--fs-xs);
    padding: 2px 8px;
    border-radius: 100px;
    font-weight: 600;
    white-space: nowrap;
    margin-left: 4px;
}

/* Detail sections */
.ct-section {
    margin-bottom: 48px;
}

.ct-section-title {
    font-size: var(--fs-lg);
    font-weight: 700;
    margin-bottom: 20px;
    padding-bottom: 10px;
    border-bottom: var(--bw-hair) solid var(--border-subtle);
}

.ct-section-title span {
    color: var(--accent);
}

/* МЕРА АБЗАЦА И СТУПЕНЬ МЕЖСТРОЧНОГО. Замер 13.10: 1.8 — мимо лестницы
   (1 · 1.1 · 1.3 · 1.5 · 1.65), а строка на 1512 выходила в 125 знаков при
   норме 45–75: потолка ширины у текста не было вовсе. */
.ct-about-text {
    color: var(--text-secondary);
    font-size: var(--fs-base);
    line-height: var(--lh-relaxed);
    /* 62ch, А НЕ 72ch — ПОТОМУ ЧТО ЕДИНИЦА СЧИТАЕТ НОЛЬ, А НЕ БУКВУ.
       `ch` — это ширина знака «0», а кириллица у Inter уже него: при 72ch
       замер дал 85 знаков в строке, то есть мера молча уехала за норму
       45–75. Число подобрано ЗАМЕРОМ, а не формулой. */
    max-width: 62ch;
}

/* Amenities */
.ct-amenities {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
}

.ct-amenity {
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--surface-glass);
    border: var(--bw-hair) solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: 14px 16px;
    color: var(--text-secondary);
    font-size: var(--fs-sm);
}

.ct-amenity::before {
    content: '✓';
    color: var(--accent);
    font-weight: 700;
    flex-shrink: 0;
}

/* Schedule */
.ct-schedule {
    display: grid;
    gap: 8px;
}

.ct-schedule-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 14px 20px;
    border-radius: var(--radius-sm);
    background: var(--surface-glass);
    border: var(--bw-hair) solid var(--border-subtle);
}

.ct-schedule-day {
    font-weight: 600;
}

.ct-schedule-time {
    color: var(--text-secondary);
    font-size: var(--fs-sm);
}

/* Gallery */
.ct-gallery {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
}

.ct-gallery-img {
    width: 100%;
    height: 200px;
    object-fit: cover;
    border-radius: var(--radius-md);
    border: var(--bw-hair) solid var(--border-subtle);
    cursor: pointer;
    transition: transform var(--transition-base), border-color var(--transition-base);
}

.ct-gallery-img:hover {
    transform: scale(1.03);
    border-color: var(--accent-glow);
}

/* Mini map on detail */
.ct-detail-map {
    width: 100%;
    height: 280px;
    border-radius: var(--radius-lg);
    border: var(--bw-hair) solid var(--border-subtle);
    overflow: hidden;
}

.ct-detail-map .leaflet-tile-pane {
    filter: brightness(0.85) contrast(1.1);
}

.ct-detail-map .leaflet-control-zoom a {
    background: var(--bg-elevated) !important;
    color: var(--text-primary) !important;
    border-color: var(--border-subtle);
}

/* CTA */
.ct-cta {
    background: var(--surface-glass);
    border: var(--bw-hair) solid var(--border-subtle);
    border-radius: var(--radius-xl);
    padding: 48px 40px;
    text-align: center;
    margin-top: 20px;
}

.ct-cta h3 {
    font-size: var(--fs-xl);
    font-weight: 700;
    margin-bottom: 12px;
}

.ct-cta h3 span {
    color: var(--accent);
}

.ct-cta p {
    color: var(--text-secondary);
    /* Тот же абзац, та же мера: замер 13.10 давал 139 знаков в строке на
       1512 — вдвое выше нормы. Блок по центру, поэтому ширину держит
       margin-inline: auto. */
    max-width: 62ch;
    margin-inline: auto;
    margin-bottom: 24px;
}

.ct-cta-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: var(--accent);
    color: var(--neutral-black);
    font-size: var(--fs-base);
    font-weight: 700;
    /* ВЫСОТА СВОЙСТВОМ, А НЕ ПОЛЕМ — `Button 17:82`: «Height is set by the
       height property, never by vertical padding — otherwise it drifts with
       the line-height of the content». Замер 13.10 давал 41 при ступенях
       28 · 36 · 44 · 52, и 44 там же названо минимальной целью нажатия на
       телефоне (Apple HIG). Поле осталось только боковым. */
    min-height: var(--btn-h-md);
    padding-inline: 32px;
    border: none;
    border-radius: var(--radius-full);
    cursor: pointer;
    text-decoration: none;
    transition: background var(--transition-fast), transform var(--transition-fast);
}

.ct-cta-btn:hover {
    background: var(--accent-hover);
    transform: translateY(-2px);
}

/* Scroll animations */
.ct-fade-in {
    opacity: 0;
    transform: translateY(24px);
    transition: opacity 0.6s ease, transform 0.6s ease;
}

.ct-fade-in.visible {
    opacity: 1;
    transform: translateY(0);
}

/* ---- RESPONSIVE ---- */
@media (max-width: 992px) {
    /* Правило `.ct-grid` на две колонки снято: число колонок — следствие
       ширины карточки, `auto-fill` сам даёт 3 на 1024 и 2 на 768. */
    .ct-amenities {
        grid-template-columns: repeat(3, 1fr);
    }
    .ct-detail-stats {
        grid-template-columns: repeat(2, 1fr);
    }
    .ct-detail-header {
        gap: 24px;
    }
    .ct-detail-photo {
        width: 280px;
        height: 200px;
    }
}

/* ГРАНИЦА 768 ОСТАЛАСЬ ТОЛЬКО У СТРАНИЦЫ КОРТА — отдельный кусок, не
   мерен, в этот заход не трогается. Правила витрины отсюда ушли на 640:
   поля контейнера теперь держат крутилки `--section-y` и `--pad-x`,
   а кнопка и метка «Партнёр» переехали в блок ≤640 выше по файлу. */
/* ГРАНИЦА 768 РАЗЛОЖЕНА ПО ДВУМ ДОМАШНИМ — 16.10, кусок 75.
   Каждое правило отправлено туда, где оно по смыслу живёт, а не скопом.
   Чем платим названо отдельно: трёхступенчатая лестница «3 · 2 · 1
   колонки» теряет среднюю ступень везде, где она была. */

/* ПЛАНШЕТ И УЖЕ. Карта и снимки ужимаются уже на планшете: на 844 и 900
   прежняя высота съедала экран целиком. Галерея и удобства идут по две —
   три колонки на планшете дают 235 пикселей на снимок, это марка, а не
   фотография. Имя корта на ступень мельче десктопного. */
@media (max-width: 992px) {
    .ct-map {
        height: 300px;
    }
    .ct-detail-name {
        font-size: var(--fs-xl);
    }
    .ct-amenities {
        grid-template-columns: repeat(2, 1fr);
    }
    .ct-gallery {
        grid-template-columns: repeat(2, 1fr);
    }
    .ct-gallery-img {
        height: 160px;
    }
    .ct-cta {
        /* было 36/24 — 36 не ступень шкалы отступов */
        padding: 32px 24px;
    }
    .ct-detail-map {
        height: 220px;
    }
}

/* ТОЛЬКО ТЕЛЕФОН. Шапка корта складывается в колонку и отдаёт фото всю
   ширину. На планшете стоя места хватает на оба: фото 280 и текст 456
   при ширине 736. Раньше это срабатывало и там — фото растягивалось во
   всю ширину на экране, где рядом оставалось полтетради пустоты. */
@media (max-width: 640px) {
    .ct-detail-header {
        flex-direction: column;
        gap: 20px;
    }
    .ct-detail-photo {
        width: 100%;
        height: 220px;
    }
}

@media (max-width: 640px) {
    .ct-types-header {
        grid-template-columns: 1fr 1fr 50px 90px;
        padding: 8px 12px;
        font-size: var(--fs-2xs);
    }
    .ct-types-row {
        grid-template-columns: 1fr 1fr 50px 90px;
        padding: 10px 12px;
        font-size: var(--fs-sm);
    }
    .ct-services-header {
        grid-template-columns: 1fr 90px;
        padding: 8px 12px;
        font-size: var(--fs-2xs);
    }
    .ct-services-row {
        grid-template-columns: 1fr 90px;
        padding: 10px 12px;
        font-size: var(--fs-sm);
    }
    .ct-detail-stats {
        grid-template-columns: 1fr 1fr;
        gap: 10px;
    }
    .ct-detail-stat {
        padding: 16px 12px;
    }

    /* Кегль заголовка обложки отсюда убран: его держит `--fs-hero` в
       tokens.css, и своё объявление спорило бы с общей крутилкой.
       Компонент обложки один на список кортов и на страницу корта. */

    .ct-detail-stat-combined {
        padding: 12px 16px;
        font-size: var(--fs-sm);
    }

    .ct-about-text {
        font-size: var(--fs-sm);
        line-height: var(--lh-normal);
    }

    .ct-cta {
        padding: 20px 16px;
    }

    .ct-cta h3 {
        /* Было clamp(1.15rem, 5vw, 1.32rem) — замер 13.10 на 390 дал 19.5,
           такой ступени на шкале кеглей нет. */
        font-size: var(--fs-md);
    }

    .ct-cta p {
        font-size: var(--fs-sm);
        line-height: var(--lh-snug);
    }

    .ct-cta-btn {
        /* высоту держит min-height у самого правила — одно место на все виды */
        padding-inline: 20px;
        font-size: var(--fs-sm);
    }
    .ct-amenities {
        grid-template-columns: 1fr;
    }
    .ct-gallery {
        grid-template-columns: 1fr;
    }
    .ct-gallery-img {
        height: clamp(160px, 42.7vw, 200px);
    }
}

/* ГРАНИЦА 375 ОСТАЛАСЬ ТОЛЬКО У СТРАНИЦЫ КОРТА — отдельный кусок, он не
   мерен и в этот заход не трогается. Всё, что принадлежало витрине
   (поля тела, кегль имени, высота фото, поля контейнера), отсюда снято:
   у витрины ОДИН уровень на все виды, как у лендинга. */
@media (max-width: 640px) {
    .ct-detail-name {
        font-size: var(--fs-lg);
    }
    .ct-schedule-row {
        flex-direction: column;
        align-items: flex-start;
        gap: 4px;
        padding: 12px 14px;
    }
}

/* === ПОЛОСА СТРАНИЦ ===
   Своих кнопок у кортов больше нет: полоса — общий компонент, он лежит в
   `css/style.css` вместе со своим скриптом `js/polosa-stranic.js`.
   Пять классов (`.ct-pagination`, `.ct-page-btn`, `-num`, `-prev`,
   `-next`) снесены: проверено по всему дереву — после перехода на общую
   полосу ни один из них не встречается ни в одной разметке и ни в одном
   скрипте. Кнопки были 40 × 40 мимо ступеней 28 · 36 · 44 · 52.
   Остаётся только обёртка секции: у кортов она своя по ширине. */
.ct-pagination-section {
    /* Полоса идёт по витрине, а не по умолчанию компонента: сетка кортов
       живёт в широкой коробке, и полоса обязана стоять над её краями. */
    --polosa-shirina: 100%;
    max-width: var(--container-max);
    margin: 0 auto;
    padding: 0 var(--pad-x) var(--space-xl);
}

.ct-pagination-section:empty {
    padding: 0;
}

/* === DISCOUNT / VOUCHER === */
.ct-discount-section {
    border: var(--bw-hair) solid var(--accent-subtle);
    border-radius: 16px;
    padding: 24px;
    background: var(--alpha-lime-06);
}
.ct-discount-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.ct-discount-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 18px;
    background: var(--alpha-white-04);
    border-radius: 12px;
    border: var(--bw-hair) solid var(--alpha-white-08);
}
.ct-discount-info {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 1;
}
.ct-discount-name {
    font-size: var(--fs-base);
    color: var(--alpha-white-72);
}
.ct-discount-percent {
    font-size: var(--fs-md);
    font-weight: 700;
    color: var(--accent);
    white-space: nowrap;
}
.ct-discount-btn {
    background: var(--accent);
    color: var(--neutral-black);
    border: none;
    padding: 8px 20px;
    border-radius: 8px;
    font-weight: 600;
    font-size: var(--fs-sm);
    cursor: pointer;
    transition: opacity 0.2s;
    white-space: nowrap;
}
.ct-discount-btn:hover {
    opacity: 0.85;
}
.ct-discount-hint {
    font-size: var(--fs-xs);
    color: var(--text-muted);
    margin: 0;
    text-align: right;
}

/* ВАУЧЕРНОЕ ОКНО, ВЫБОР УСЛУГИ И ИСТОРИЯ — ПЕРЕЕХАЛИ В
   `css/kslt-vaucher.css` куском 148. Здесь лежали 42 правила с приставкой
   `ct-`, побайтово равные таким же в соседнем разделе: один вид, описанный
   дважды, плюс своя пара `@keyframes` — та же анимация под другим именем.
   Приставка снята совсем: имя класса теперь `kslt-`, и расходиться
   нечему. */


@media (max-width: 640px) {
    .ct-discount-item {
        flex-direction: column;
        align-items: flex-start;
        gap: 10px;
    }
    .ct-discount-btn {
        width: 100%;
        text-align: center;
    }
            }

/* === SPONSORS === */

/* ===== ВЫПАДАЮЩИЕ ФИЛЬТРЫ (город, покрытие) ===== */
/* Рядом кнопок города и покрытия не помещались в строку фильтров, да и
   городов со временем станет больше. Кнопка показывает выбранное, список
   раскрывается под ней. */

/* Выпадающий фильтр живёт в style.css, раздел «Выпадающий фильтр в
   полосе»: тем же списком пользуются тренеры */

/* Пусто: связь с базой оборвалась, поиск ничего не нашёл или кортов ещё
   не завели. Раньше при сбое подставлялись пять выдуманных кортов —
   человек мог поехать по адресу, которого не существует */
.ct-empty {
    padding: var(--space-xl) var(--space-md);
    text-align: center;
    color: var(--text-muted);
}

.ct-empty-icon {
    font-size: var(--fs-3xl);
    margin-bottom: 12px;
    opacity: 0.5;
}

.ct-empty p {
    margin: 0;
    font-size: var(--fs-base);
}

/* Страница корта, которого нет среди опубликованных. Берёт тот же .ct-empty,
   что и пустой список: состояние одно — «показывать нечего» */
.ct-empty-title {
    margin: 0 0 var(--space-3);
    font-size: var(--fs-xl);
    font-weight: 700;
    color: var(--text-primary);
}

.ct-empty-text {
    margin: 0 0 var(--space-md);
    font-size: var(--fs-base);
}

/* ============================================
   СТРАНИЦА КОРТА НА ТЕЛЕФОНЕ
   ============================================ */

/* Цифра «1 корт» шла 22-м кеглем при весе 800 — крупнее заголовков
   разделов рядом. Подписи под названием тоже: тип 16, адрес 14.7, текст
   описания 14. Приводим к общей шкале: цифра как на обложках разделов,
   текст 0.82rem, подписи 0.72rem */

/* ПЛАНШЕТ И УЖЕ: текст страницы корта мельче десктопного уже на планшете,
   строка иначе уходит за удобную длину. */
@media (max-width: 992px) {
    .ct-detail-stat-combined {
        /* 10 и 14 — не ступени шкалы отступов (4 · 8 · 12 · 16 · 20 · 24),
           поймано при правке пилюли 13.10 */
        padding: 12px 16px;
    }

    .ct-stat-item {
        font-size: var(--fs-base);
    }

    .ct-detail-type {
        font-size: var(--fs-sm);
    }

    .ct-detail-address {
        font-size: var(--fs-xs);
    }

    .ct-about-text {
        font-size: var(--fs-sm);
    }

    .ct-types-row {
        font-size: var(--fs-xs);
    }
}


/* ═══ ДОСТУПНОСТЬ СТРАНИЦЫ КОРТА — ДОБАВЛЕНО 13.10 ════════════════════════
   Замер 13.10: слова `focus-visible` в этом файле не было НИ РАЗУ, при том
   что `Button 17:82` требует кольцо прямо: «Focus is a 3px accent/glow ring
   outside the button. Required on every button: WCAG 2.4.7». Обводка та же,
   что у чипов и карточек витрины (style.css, 12.10): 2px accent с отступом 2.
   Переход перечислен поимённо, а не `all`: `all` анимирует outline-width, и
   замер сразу после Tab видит `0px solid` при горящем фокусе (09.10). */
.ct-cta-btn:focus-visible,
.ct-map-link:focus-visible,
.ct-detail-phone a:focus-visible,
.ct-gallery-img:focus-visible,
.kslt-back:focus-visible {
    outline: var(--bw-thick) solid var(--accent);
    outline-offset: 2px;
}


