@import url("booking-card-layout.css");

/*
 * Карточка записи (модалка брони) — стили ПЕРЕИСПОЛЬЗУЕМОГО компонента.
 *
 * Компонент живёт в трёх файлах и подключается страницей-хостом целиком:
 *   partials/_booking_card.html  — разметка (+ модалки оплаты/переноса участника)
 *   static/js/booking-card.js    — состояние и операции (Alpine-миксин)
 *   static/css/booking-card.css  — этот файл
 *
 * Хосты: журнал (`timetable.html`) и карточка клиента (`client_detail.html`).
 * До 27.07.2026 всё это жило внутри timetable.html, и открыть карточку записи
 * можно было только из сетки — при том, что запись и клиент связаны в обе
 * стороны (из карточки записи ссылка на клиента была всегда).
 *
 * Только токены брендбука (`--bp-*`, `--ff-*`), никаких новых зависимостей.
 */

/* Тост сообщений компонента (и ошибок drag'а в сетке журнала) */
.journal-drag-toast {
    position: fixed; top: 76px; left: 50%; transform: translateX(-50%);
    /* 1060: ВЫШЕ модалки карточки (1055) — тосты операций из открытой
       карточки («Ссылка скопирована», ошибка кассы) тонули под ней */
    z-index: 1060; background: var(--bp-stamp-red); color: #fff;
    border-radius: var(--bp-radius-sm);
    padding: 8px 16px; font-size: 0.85rem; box-shadow: var(--bp-shadow-pop);
}
/* Успех (напр. «Перенесено») — зелёный, а не красный */
.journal-drag-toast.is-ok { background: var(--bp-green) !important; }

/* Фиолетовый акцент групп и турниров: бейджи карточки и плитки сетки. */
.bg-purple-subtle {
    background-color: #e8daef !important;
}

.bg-purple {
    background-color: #8e44ad !important;
}

.text-purple {
    color: #8e44ad !important;
}

/* «Долг» участника/записи: оранжевый, НЕ красный (красный = отмена) */
.pay-due {
    color: var(--bp-orange);
}

.badge-due {
    background: var(--bp-orange);
    color: var(--bp-on-accent);
}

/* Тренер записи в карточке: фото или инициалы */
.bk-trainer-photo,
.bk-trainer-initials {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    box-shadow: 0 0 0 1px rgba(142, 68, 173, 0.35);
}

.bk-trainer-photo {
    object-fit: cover;
}

.bk-trainer-initials {
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(142, 68, 173, 0.14);
    color: #8e44ad;
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1;
}

/* Модель секций (13.07): секция = услуги + её оплата. Оплаченная — заморожена
   (зелёная кромка + замок), открытая — редактируемый черновик нового чека. */
.pay-sec {
    border: 1px solid var(--bp-line);
    border-radius: 8px;
    background: var(--bp-paper-1, #fff);
    padding: .5rem .6rem;
    margin-bottom: .5rem;
}
.pay-sec--paid {
    border-left: 4px solid var(--bp-green-dark);
    background: var(--bp-green-tint, #f2f7ee);
}
.pay-sec--open { border-left: 4px solid var(--bp-warning, #c98a1b); }
/* Визит: соседние брони клиента в одном окне — своя левая кромка, чтобы блок
   не путался с составом самой записи. */
.pay-sec--visit { border-left: 4px solid var(--bp-accent, #3f6ad8); }
/* Бронь внутри визита — отдельный блок, а не строка в общем потоке. Пока
   заголовок и состав шли одним уровнем, соседние брони читались как один
   длинный список, и глазом было не найти, где кончается одна и начинается
   другая (Паша 11.08.2026). Кромка слева отделяет брони друг от друга, отступ
   состава показывает подчинение: услуги принадлежат броне над ними. */
.pay-sec__visit-booking {
    margin-top: .5rem;
    padding-left: .5rem;
    border-left: 2px solid var(--bp-line);
}
.pay-sec__visit-booking:first-of-type { margin-top: .35rem; }
/* ❗ Цветной кромки у активной брони НЕТ (Паша 11.08.2026): линия непонятного
   цвета шумит и ничего не объясняет, а «эта бронь» уже подписана бейджем. */

.pay-sec__visit-booking .pay-sec__table { margin-left: .35rem; }
/* Внутри брони две ступени, а не сплошной серый (Паша 11.08.2026 — «основная
   услуга серой быть не должна»): игра, ради которой бронь и создана, читается
   обычным цветом, а ракетки и мячи — тише и с отступом, как дополнения к ней.
   Так видно и границы броней, и что к чему относится. */
.pay-sec__visit-booking .pay-sec__line--extra .pay-sec__line-name {
    padding-left: .9rem;
    color: var(--bp-ink-soft, #55575e);
    font-size: .95em;
}
/* Итоги «визит / эта бронь» под шапкой панели: сумма в шапке относится к
   открытой брони, и на визите из нескольких она читалась как итог всего. */
/* Две области денег в шапке, когда клиент пришёл на несколько броней: строка
   брони и строка визита живут в одной сетке — подпись слева, сумма и статус
   справа. Сумма визита тише суммы брони: карточка всё-таки про бронь. */
.bk-sec__scopes {
    display: grid;
    gap: .25rem;
    margin: -.2rem 0 .6rem;
}
.bk-sec__scope {
    display: flex;
    align-items: baseline;
    gap: .5rem;
}
.bk-sec__scope-label {
    flex: 1 1 auto;
    font-size: .78rem;
    color: var(--bp-ink-soft, #55575e);
    white-space: normal;
    overflow-wrap: anywhere;
}
/* Обе строки — равноправные области денег, поэтому ОДИН размер: разный кегль
   читался как случайная иерархия. */
.bk-sec__scope-sum {
    flex: none;
    font-size: 1.15rem;
    line-height: 1.15;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--bp-ink, #17181a);
}
/* Бейджи статуса в колонку одинаковой ширины — иначе суммы «плавают». */
.bk-sec__scope .badge { flex: 0 0 auto; min-width: 7.5rem; text-align: center; }
/* Заголовок брони внутри визита — ОГЛАВЛЕНИЕ своего списка услуг, а не
   подпись под ним (Паша 11.08.2026). Раскладка та же (.pay-sec__head), но
   вес и цвет — как у обычного заголовка: приглушённым он сливался с
   услугами, и время с кортом приходилось выискивать. Тише здесь состав —
   см. ниже по тексту. */
.pay-sec__head--sub {
    margin-bottom: .15rem;
    font-size: .9rem;
    font-weight: 600;
    color: var(--bp-ink, #1c1a16);
}
/* Итог и способы визита рисуются классами оплаты записи (.pay-sec__topay,
   .bk-pay-quick / .bk-pay-card) — своего оформления у них нет и быть не
   должно, включая разделители: в составе записи черты над «К оплате» нет. */
.pay-sec--done {
    border: none;
    padding: .25rem 0;
    color: var(--bp-green-dark);
    font-size: .9rem;
    background: none;
}
/* `.pay-sec__head` и `.pay-sec__title` живут в pay-card.css: тот же заголовок
   рисует панель оплаты продажи без записи, где стилей карточки нет. */
.pay-sec__sum { flex: none; font-variant-numeric: tabular-nums; font-weight: 700; }
.pay-sec__lines { margin-top: .25rem; }
/* Состав записи — НАСТОЯЩАЯ таблица (10.08.2026): оператор читает его как чек
   («услуга, сколько, почём, сколько платить»), и колонки обязаны стоять друг
   под другом.

   ❗ Сеткой на КАЖДОЙ строке это не решается: дорожки `auto` считаются в каждой
   строке отдельно, поэтому пустая ячейка (скидки на позиции нет) схлопывалась
   и уносила соседние значения из-под их заголовков. Ширины колонок — забота
   таблицы, а не наша: `width: auto` по содержимому, имя тянется. */
.pay-sec__table {
    width: 100%;
    margin-top: .25rem;
    border-collapse: collapse;
    font-size: .84rem;
}
.pay-sec__table thead th {
    padding: .15rem .3rem;
    font-size: .68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--bp-muted);
    border-bottom: 1px solid var(--bp-line);
    white-space: nowrap;
}
.pay-sec__table td {
    padding: .25rem .3rem;
    border-bottom: 1px dashed var(--bp-line);
    vertical-align: middle;
}
.pay-sec__table tr:last-child td { border-bottom: none; }
/* Числовые колонки прижимаем вправо — суммы читаются столбиком */
.pay-sec__col-num { text-align: right; }
/* Количество — по ЦЕНТРУ колонки: у строк с кнопками «−/+» число стоит между
   ними, и прижатая вправо единица основной услуги вставала бы вплотную к цене,
   выбиваясь из ряда. */
.pay-sec__col-qty,
.pay-sec__table td.pay-sec__line-qty { text-align: center; }
.pay-sec__table td.pay-sec__line-price,
.pay-sec__table td.pay-sec__line-disc,
.pay-sec__table td.pay-sec__line-sum {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.pay-sec__col-pick, .pay-sec__col-act { width: 1%; }
.pay-sec__col-name { text-align: left; }
.pay-sec__line-price {
    font-variant-numeric: tabular-nums;
    color: var(--bp-ink-soft);
    white-space: nowrap;
}
/* Ряд чипов (доп-продажа, её редактор). Тоже свой класс: контейнер живёт под
   x-show, и bootstrap-овский `d-flex` не дал бы его скрыть — пустой ряд держал
   бы свой нижний отступ. */
.pay-sec__chips {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem;
}

/* Кнопки количества внутри ячейки «Кол-во». Свой класс, а не `d-inline-flex`:
   bootstrap-овские `d-*` ставят display с !important и не дают x-show скрыть
   элемент — рядом с кнопками показывалось ещё и запасное число. */
.pay-sec__line-steps {
    display: inline-flex;
    align-items: center;
    gap: .2rem;
}

/* Ячейка действий: кнопки строки в один ряд, без переносов */
.pay-sec__line-act {
    white-space: nowrap;
    text-align: right;
}
/* Скидка строки: показывает процент, кликом открывает форму на этой позиции */
.pay-sec__line-disc {
    white-space: nowrap;
}
.pay-sec__disc-btn {
    border: 0;
    background: none;
    padding: 0 .15rem;
    font-size: .72rem;
    line-height: 1.2;
    color: var(--bp-muted);
    border-radius: 4px;
    cursor: pointer;
}
.pay-sec__disc-btn:hover { background: var(--bp-paper-2); color: var(--bp-ink); }
.pay-sec__disc-btn--on {
    color: var(--bp-stamp-red);
    font-weight: 600;
}
/* Сама форма скидки (и зачёркнутый прайс рядом с её ценой) переехала в
   `discount-form.css`: разметка у карточки и у продажи без записи одна, и
   стиль обязан быть один — карточка подключает оба файла. */
.pay-sec__line:last-child { border-bottom: none; }
/* Пооперационная оплата (plan 19.07): чекбокс выбора позиции к текущей оплате.
   Снятая строка ОСТАЁТСЯ в заказе — просто не входит в этот чек/ссылку; поэтому
   НЕ зачёркиваем (читалось как «убрали из заказа», фидбек 21.07) — лишь мягко
   приглушаем и подписываем «не в этой оплате». */
.pay-sec__line-pick { margin: 0; }
.pay-sec__line-pick input {
    margin: 0; accent-color: var(--bp-blue);
    width: 1.15rem; height: 1.15rem;  /* крупнее дефолтных ~13px — удобнее целиться */
    pointer-events: none;  /* клик ловит вся строка (.pay-sec__line--pick), не сам чекбокс */
}
/* Кликабельная строка выбора: курсор-рука + лёгкая подсветка при наведении */
.pay-sec__line--pick { cursor: pointer; border-radius: 4px; }
.pay-sec__line--pick:hover { background: var(--bp-paper-2); }
.pay-sec__line--off { opacity: .62; }
/* Закрытая деньгами позиция — приглушённым фоном, чтобы взгляд шёл по тем
   строкам, где ещё есть что собрать. Класс биндился в обеих таблицах состава,
   но стиля не имел и ничего не показывал (ревью 11.08.2026). */
.pay-sec__line--paid { background: var(--bp-surface-soft, #f6f7f5); }
.pay-sec__line-note {
    font-size: .68rem; color: var(--bp-ink-soft);
    font-style: italic; white-space: nowrap;
}
/* Подсказка «оставьте ≥1 услугу» при клике по последней выбранной позиции */
.pay-sec__lastwarn {
    margin-top: .3rem; font-size: .78rem;
    color: var(--bp-stamp-red);
    background: rgba(160, 48, 30, .07);
    border-radius: 4px; padding: .25rem .5rem;
}
/* Сумма к оплате над кнопками (subset, меняется по чекбоксам) — итог чека,
   поэтому крупно (фидбек 21.07). */
/* Черта отделяет итог от списка позиций — одинаково и в текущей броне, и в
   визите. */
.pay-sec__topay {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .5rem;
    padding-top: .45rem;
    border-top: 1px solid var(--bp-line);
}
.pay-sec__topay-label { font-weight: 600; font-size: 1.05rem; }
.pay-sec__topay-sum { font-weight: 700; font-size: 1.4rem; font-variant-numeric: tabular-nums; color: var(--bp-blue); }
/* Имя услуги — единственная тянущаяся колонка; текст переносится, а не режется */
.pay-sec__line-name { width: 100%; white-space: normal; overflow-wrap: anywhere; }
.pay-sec__line-x {
    flex: none;
    border: none;
    background: none;
    color: var(--bp-ink-soft);
    line-height: 1;
    padding: 0 .15rem;
    cursor: pointer;
}
.pay-sec__line-x:hover { color: var(--bp-stamp-red); }
/* ❗ У ячеек таблицы НЕ переопределяем `display`: любой flex вместо
   table-cell выбивает ячейку из колонки — единица основной услуги уезжала
   влево, а пунктир строки рвался. Раскладку внутри ячейки задаёт вложенный
   `.pay-sec__line-steps`. */
.pay-sec__line-step {
    border: 1px solid var(--bp-line);
    background: none;
    color: var(--bp-ink-soft);
    line-height: 1;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: var(--bp-radius-sm, 4px);
    cursor: pointer;
    font-variant-numeric: tabular-nums;
}
.pay-sec__line-step:hover { color: var(--bp-ink); border-color: var(--bp-ink-soft); }
.pay-sec__line-step:disabled { opacity: .4; cursor: default; }
.pay-sec__line-cnt { min-width: 1rem; text-align: center; font-variant-numeric: tabular-nums; }
/* Поле количества между ±: рамка и высота — как у кнопок шага, чтобы тройка
   читалась одним контролом. Родные стрелки поля прячем — их роль у ±. */
.pay-sec__line-cnt--input {
    width: 2.4rem;
    height: 1.25rem;
    padding: 0 .15rem;
    border: 1px solid var(--bp-line);
    border-radius: var(--bp-radius-sm, 4px);
    background: var(--bp-sheet);
    color: var(--bp-ink);
    font: inherit;
    line-height: 1;
    appearance: textfield;
    -moz-appearance: textfield;
}
.pay-sec__line-cnt--input::-webkit-inner-spin-button,
.pay-sec__line-cnt--input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.pay-sec__line-cnt--input:focus { outline: none; border-color: var(--bp-ink-soft); }
.pay-sec__meta {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    font-size: .74rem;
    color: var(--bp-ink-soft);
    margin-top: .25rem;
}
.pay-sec__add { margin-top: .4rem; }
/* Ряд «чем уменьшаем сумму»: поле баллов и кнопка скидки бок о бок. Обе части
   показываются по своему условию (баллы зависят от баланса, скидка — от того,
   осталась ли позиция под неё), поэтому ряд переживает и «баллов нет», и
   «скидывать нечего», не оставляя пустот. */
.pay-sec__reduce-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .4rem;
}

/* Статус визита ОДИНОЧНОЙ брони — сегмент-переключатель над её деньгами:
   ставят его в одно движение, и прятать четыре варианта за раскрытием списка
   значит добавить клик там, где его не было. */
.visit-status-bar {
    display: flex;
    border: 1px solid var(--bp-line-strong);
    border-radius: var(--bp-radius-sm);
    overflow: hidden;
}
.visit-status-bar .vsb-btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 8px 4px;
    background: var(--bp-sheet);
    border: none;
    border-right: 1px solid var(--bp-line);
    font-family: var(--ff-ui);
    font-size: .78rem;
    color: var(--bp-ink-soft);
    cursor: pointer;
}
.visit-status-bar .vsb-btn:last-child { border-right: none; }
.visit-status-bar .vsb-btn:hover { background: var(--bp-paper); }
.visit-status-bar .vsb-btn.active { color: #fff; font-weight: 700; }
.visit-status-bar .vsb-wait.active { background: var(--bp-muted); }
.visit-status-bar .vsb-confirmed.active { background: var(--bp-blue); }
.visit-status-bar .vsb-came.active { background: var(--bp-green-dark); }
.visit-status-bar .vsb-noshow.active { background: var(--bp-stamp-red); }

/* Статус УЧАСТНИКА события — выпадашка (`partials/_visit_status.html`):
   участников в строке много, и три кнопки у каждого занимали больше места,
   чем весит решение. Цвет кнопки называет текущий статус, поэтому его видно
   не раскрывая список. */
.vs-drop__btn {
    display: inline-flex;
    align-items: center;
    font-family: var(--ff-ui);
    font-size: .78rem;
    font-weight: 600;
    color: #fff;
    border: none;
    white-space: nowrap;
}
.vs-drop__btn:hover, .vs-drop__btn:focus { color: #fff; filter: brightness(.94); }
/* ❗ Цвет статуса повторяется для :hover и :focus СОЗНАТЕЛЬНО. У кнопки нет
   bootstrap-варианта (btn-primary и подобных), а `.btn:hover` специфичнее
   одиночного класса и подставляет свой `--bs-btn-hover-bg` — пустой. Заливка
   пропадала, белый текст оставался на белом, и кнопка исчезала с экрана при
   наведении (Паша 11.08.2026). */
.vs-drop__btn--wait,
.vs-drop__btn--wait:hover,
.vs-drop__btn--wait:focus { background: var(--bp-muted); }
.vs-drop__btn--confirmed,
.vs-drop__btn--confirmed:hover,
.vs-drop__btn--confirmed:focus { background: var(--bp-blue); }
.vs-drop__btn--came,
.vs-drop__btn--came:hover,
.vs-drop__btn--came:focus { background: var(--bp-green-dark); }
.vs-drop__btn--noshow,
.vs-drop__btn--noshow:hover,
.vs-drop__btn--noshow:focus { background: var(--bp-stamp-red); }
/* Пункт списка красим точкой слева: заливать весь пункт цветом статуса —
   получить четыре разноцветные полосы вместо читаемого меню. */
.vs-drop__item { display: flex; align-items: center; font-size: .82rem; }
.vs-drop__item .bi { color: var(--bp-ink-soft); }
.vs-drop__item--wait .bi { color: var(--bp-muted); }
.vs-drop__item--confirmed .bi { color: var(--bp-blue); }
.vs-drop__item--came .bi { color: var(--bp-green-dark); }
.vs-drop__item--noshow .bi { color: var(--bp-stamp-red); }
.vs-drop__item.active { background: var(--bp-paper-2); color: var(--bp-ink); font-weight: 600; }

/* Сводка клиента: чипы под телефоном */
.client-summary-row {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    /* Воздух с обеих сторон: бейджи липли к примечанию (фидбек 13.07) */
    margin: 6px 0 10px;
}
/* Переход по броням визита — крупные стрелки у краёв экрана, как в
   просмотрщике фотографий (Паша 11.08.2026). Кнопка в шапке для этого мелка:
   по соседним броням оператор ходит часто, и рука должна попадать не целясь.

   `position: fixed` относительно окна, а не модалки: диалог у карточки широкий
   и его край гуляет по ширине экрана, а стрелки обязаны стоять на месте.
   z-index выше самой модалки (1055), иначе они уходят под её фон. */
.bk-visit-arrow {
    position: fixed;
    top: 50%;
    transform: translateY(-50%);
    z-index: 1060;
    width: 3rem;
    height: 3rem;
    border: none;
    border-radius: 50%;
    background: rgba(28, 26, 22, .38);
    color: #fff;
    font-size: 1.4rem;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background .12s ease;
}
.bk-visit-arrow:hover { background: rgba(28, 26, 22, .62); }
/* Идёт операция — стрелка видна, но явно нерабочая: молчаливый отказ читался
   как «кнопка сломана». */
.bk-visit-arrow:disabled { opacity: .35; cursor: default; }
.bk-visit-arrow:disabled:hover { background: rgba(28, 26, 22, .38); }
.bk-visit-arrow:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.bk-visit-arrow--prev { left: 1rem; }
.bk-visit-arrow--next { right: 1rem; }
/* На узком экране места по краям нет — стрелка легла бы поверх карточки.
   Переход там остаётся клавишами и счётчиком в шапке. */
@media (max-width: 1200px) {
    .bk-visit-arrow { display: none; }
}
/* Размер — как у бейджа «Групповое» рядом (.94rem): в шапке это две метки
   одного порядка, вторичные по отношению к дате и времени. Прежние .74rem
   читались как сноска и терялись у края. Приглушённый цвет и вес 500 держат
   иерархию: крупнее сноски, но не спорит с заголовком. */
.bk-visit-nav__pos {
    font-size: .94rem;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--bp-ink-soft);
    margin-left: .75rem;
}
/* Счётчик — ровно по центру шапки, а не «где встал в потоке»: он про весь
   визит, а не про эту запись, и центр отделяет его от заголовка слева и
   крестика справа. Абсолют — потому что честный центр шапки не совпадает с
   центром промежутка между ними. Только с 992px: на узком экране заголовок
   занимает всю ширину, и центрированный счётчик лёг бы поверх него —
   там он остаётся в потоке, следом за датой и временем. */
@media (min-width: 992px) {
    .booking-modal-dialog .modal-header { position: relative; }
    .booking-modal-dialog .bk-visit-nav__pos {
        position: absolute;
        left: 50%;
        transform: translateX(-50%);
        margin-left: 0;
    }
}

/* Шапка колонки клиента: подпись, имя, контакт — тремя строками. Имя не
   гигантское (fs-5 спорил с заголовками карточки), телефон и «сменить клиента»
   идут одной строкой под ним: и то и другое отвечает на вопрос «кто эта
   запись», и разносить их по разным блокам незачем. */
.bk-client__label {
    display: block;
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--bp-muted);
    margin-bottom: .1rem;
}
.bk-client__name {
    display: block;
    font-size: 1.05rem;
    font-weight: 600;
    line-height: 1.25;
    color: var(--bp-blue);
    overflow-wrap: anywhere;
}
span.bk-client__name { color: var(--bp-ink); }
.bk-client__contact {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .1rem .6rem;
    margin-top: .15rem;
    font-size: .88rem;
}
/* Номер и кнопка «скопировать» — общий блок `.bp-phone` (styles.css), один на
   всю CRM; здесь остаётся только его место в строке контакта. */

/* Действие второго плана: рядом с телефоном, но тише его — иначе смена
   клиента читается как основное, что тут можно сделать. */
.bk-client__swap { font-size: .78rem; text-decoration: none; }
.bk-client__swap:hover { text-decoration: underline; }

/* Чип — мелкая справочная метка карточки. Живёт без привязки к контейнеру:
   тем же видом подписаны и клиент (визиты, баллы, абонемент), и оплата (чек,
   ОФД, кассир). Одинаковое рисуем одинаково — второй набор классов под ту же
   роль расходился бы с первым на первой же правке. */
.cs-chip {
    font-size: .74rem;
    padding: 2px 10px;
    background: var(--bp-paper-2);
    border: 1px solid var(--bp-line-strong);
    border-radius: 999px;
    color: var(--bp-ink-soft);
    cursor: help;
}

/* Абонемент клиента — зелёный чип: остаток = «оплату можно закрыть им» */
.cs-abonement {
    background: var(--bp-green-tint);
    border-color: var(--bp-green-dark);
    color: var(--bp-green-dark);
    font-weight: 600;
}
.cs-points {
    border-color: var(--bp-warning-fill);
    color: var(--bp-warning-deep);
    background: var(--bp-warning-tint);
}
/* Депозит — деньги клиента: зелёный «денежный» чип, отличимый от баллов. */
.cs-deposit {
    border-color: var(--bp-green-dark);
    color: var(--bp-green-dark);
    background: var(--bp-green-tint);
}
.cs-new {
    border-color: var(--bp-blue);
    color: var(--bp-blue);
}
/* Ссылка-чип (чек в ОФД): подчёркивания нет, курсор — рука, а не «help». */
a.cs-chip {
    cursor: pointer;
    text-decoration: none;
}
a.cs-chip:hover { border-color: var(--bp-ink-2); color: var(--bp-ink); }

/* ── Секции модалки записи (редизайн 13.07) ────────────────────────────
   Правая колонка была плоским списком кнопок вперемешку — оператор не
   находил оплату и путал её с правкой записи. Теперь три смысловые зоны:
   деньги / состав записи / опасное. Только токены брендбука, без новых
   зависимостей. */
.bk-sec {
    border: 1px solid var(--bp-line, #e6e1d8);
    border-radius: 10px;
    padding: .75rem .85rem;
    margin-bottom: .75rem;
    background: var(--bp-paper-1, #fff);
}
/* Оверлей ожидания на секции (свап основной): карточка обновляется от бэка
   (перечитка хоста + пере-синк), чтобы окно не выглядело «зависшим». */
.bk-sec--busy { position: relative; }
/* Сам оверлей (.bk-sec__overlay) и хост вне секции (.bk-busy-host) переехали в
   busy-overlay.css: тот же вид нужен странице платежей, которая этот файл не
   подключает. */
.bk-sec__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .5rem;
    margin-bottom: .6rem;
}
.bk-sec__title {
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--bp-ink-2, #6b6357);
}
.bk-sec__sum {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1;
    color: var(--bp-ink, #1c1a16);
    font-variant-numeric: tabular-nums;
}
.bk-sec__sum--done {
    font-size: 1rem;
    color: var(--bp-green-dark);
    white-space: nowrap;
}
/* Деньги — единственная акцентная секция: оператор должен цеплять её взглядом */
.bk-sec--pay {
    background: var(--bp-paper-2, #eef0f4);
    border-color: var(--bp-line-strong, #d3d7de);
}
.bk-sec--danger { border-color: rgba(220, 53, 69, .35); background: rgba(220, 53, 69, .03); }

/* `.bk-hint` переехал в pay-card.css — его же читает форма скидки продажи. */

/* Корты турнира: соседние события того же времени списком с галочками.
   Турнир занимает 3-4 корта, и выбирать их надо в одном месте, а не собирать
   по сетке. Свой корт всегда в наборе — строка заблокирована, чтобы его не
   сняли по ошибке; корт, уже занятый другим турниром, серый и не кликается. */
.bk-courts {
    border: 1px solid var(--bp-line, #e2dccc);
    border-radius: .5rem;
    overflow: hidden;
}
.bk-courts__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .5rem;
    padding: .4rem .6rem;
    background: var(--bp-paper-2, #f7f6f1);
    font-size: .72rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--bp-ink-2, #6b6357);
}
.bk-courts__count {
    text-transform: none;
    letter-spacing: 0;
    font-weight: 600;
}
.bk-court {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .4rem .6rem;
    border-top: 1px solid var(--bp-line, #e2dccc);
    font-size: .84rem;
    cursor: pointer;
    margin: 0;
}
.bk-court:hover:not(.bk-court--taken):not(.bk-court--own) {
    background: var(--bp-paper-2, #f7f6f1);
}
.bk-court__name { flex: 1 1 auto; overflow-wrap: anywhere; }
/* Строка корта турнира: тот же разделитель, что у выбора кортов, но она не
   кликается — это показ, а не выбор, поэтому без cursor и подсветки. */
.bk-court-line {
    padding: .4rem .6rem;
    border-top: 1px solid var(--bp-line, #e2dccc);
    font-size: .84rem;
}
.bk-court__people { color: var(--bp-ink-2, #6b6357); font-size: .78rem; }
.bk-court__badge {
    font-size: .7rem;
    padding: .05rem .35rem;
    border-radius: .3rem;
    background: var(--bp-paper-2, #f7f6f1);
    color: var(--bp-ink-2, #6b6357);
    white-space: normal;
}
.bk-court--own { cursor: default; }
.bk-court--taken { cursor: not-allowed; opacity: .6; }

/* История кассовых операций: компактная лента, возврат — у своей операции */
.bk-ops__title {
    font-size: .72rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--bp-ink-2, #6b6357);
    margin-bottom: .35rem;
}
.bk-op {
    position: relative;
    padding: .45rem .6rem;
    border: 1px solid var(--bp-line, #e6e1d8);
    border-radius: 8px;
    background: var(--bp-paper-1, #fff);
    margin-bottom: .35rem;
}
.bk-op__main { display: flex; align-items: baseline; flex-wrap: wrap; gap: .4rem; }
.bk-op__time { font-size: .78rem; color: var(--bp-ink-2, #6b6357); font-variant-numeric: tabular-nums; }
.bk-op__kind { font-weight: 600; font-size: .86rem; }
.bk-op__sum { font-weight: 600; font-size: .86rem; font-variant-numeric: tabular-nums; margin-left: auto; }
.bk-op__meta { font-size: .78rem; color: var(--bp-ink-2, #6b6357); display: flex; flex-wrap: wrap; gap: .3rem; }

/* Чипы доп-продаж: теперь живут
   в открытой секции оплаты (модель секций 13.07) */
.ub-chip {
    background: var(--bp-sheet);
    color: var(--bp-green-dark);
    border: 1px solid var(--bp-green-dark);
    border-radius: var(--bp-radius-sm);
    font-weight: 600;
    transition: background .12s ease, color .12s ease;
}
.ub-chip:hover {
    background: var(--bp-green-dark);
    color: #fff;
    border-color: var(--bp-green-dark);
}

/* Строка участника события: сверху «кто он» и действия на одной линии, под
   ними — заметка о клиенте и комментарий во всю ширину. Имя с телефоном
   рисует общий блок `.bk-client` (партиал `_client_identity.html`) — тот же,
   что в колонке «Клиент» одиночной брони. min-width:0 — чтобы длинное имя не
   распирало колонку, а переносилось. */
.tt-participant-info {
    flex: 1 1 auto;
    min-width: 0;
}
.tt-participant-notes {
    margin-top: .35rem;
}
/* Действия участника — колонка фиксированной ширины, а не резиновая половина.
   Подписи статуса разной длины («Ожидание» против «Пришёл»), и на резиновых
   размерах строка ломалась у каждого участника в своём месте: у одного
   «Оплата» стояла рядом со статусом, у другого уезжала на вторую строку, а
   сами кнопки не выстраивались в колонки. Ширины ниже заданы по самому
   длинному содержимому, поэтому ряд помещается в строку целиком и одинаково
   у всех. */
.tt-participant-actions {
    flex: 0 0 auto;
    flex-wrap: nowrap;
}
.tt-participant-actions > * {
    flex: 0 0 auto;
}
/* Сумма — по правому краю: цены разной длины («2 500 ₽» против «10 000 ₽»)
   иначе сдвигают весь ряд вслед за собой. */
.tt-pact__sum {
    min-width: 4.5rem;
    text-align: right;
}
/* Кнопки ряда одной высоты. Bootstrap `btn-sm` даёт свои вертикальные
   отступы, а выпадашка статуса — свои, и кнопки стояли разного роста. */
.tt-participant-actions .btn {
    display: inline-flex;
    align-items: center;
    height: 1.75rem;
    padding-top: 0;
    padding-bottom: 0;
}
/* Ширина под самую длинную подпись («Подтвердил»), стрелка прижата к краю —
   иначе смена статуса двигала бы «Оплату» и «⋯» по горизонтали. */
.tt-participant-actions .vs-drop__btn {
    justify-content: space-between;
    min-width: 7.5rem;
}
/* Индикатор оплаты — квадрат: ширина по содержимому делала галочку кружком,
   а «не оплачено» — вдвое более широким овалом. */
.tt-participant-actions .badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
}
/* Узкий экран: карточка сложилась в одну колонку, ряду может не хватить
   места — разрешаем перенос. Ширины остаются фиксированными, поэтому
   переносится он у всех участников одинаково. */
@media (max-width: 575.98px) {
    .tt-participant-actions {
        flex-wrap: wrap;
    }
}

/* Плашка «О клиенте» в строке участника — заметка о ЧЕЛОВЕКЕ (clients.note),
   а не о его записи. Стоит НАД полем комментария к записи и отбита фоном
   ровно затем, чтобы два поля рядом не читались как одно и то же: одно едет
   с человеком по всем клубам, второе живёт в этой записи. Тёплый warning-фон
   — потому что по смыслу это предупреждение оператору («не оплачен турнир»,
   «не звонить»). Показывается только когда заметка есть или её начали
   писать: пустая плашка у каждого участника раздувала бы список. */
.tt-cnote {
    margin-top: .4rem;
    padding: .3rem .45rem .35rem;
    border-left: 3px solid var(--bp-warning, #b07a1f);
    border-radius: var(--bp-radius-xs, 4px);
    background: var(--bp-warning-tint, #f9e9c2);
}
.tt-cnote__title {
    display: flex;
    align-items: center;
    gap: .3rem;
    margin-bottom: .15rem;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--bp-warning-deep, #8a5e15);
}
/* Read-only вид (нет прав на правку): текст ЦЕЛИКОМ, с переносами. Высоту
   не режем — заметки короткие (медиана 17 символов), а редкая простыня
   прокручивается внутри себя, чтобы не растянуть список на весь экран. */
.tt-cnote__text {
    max-height: 7.5em;
    overflow-y: auto;
    font-size: .82rem;
    line-height: 1.35;
    color: var(--bp-ink, #17181a);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}
/* Кнопка «добавить заметку» вместо плашки, когда заметки ещё нет. */
.tt-cnote-add {
    margin-top: .35rem;
    padding: 0;
    border: 0;
    background: none;
    font-size: .75rem;
    color: var(--bp-ink-soft, #55575e);
}
.tt-cnote-add:hover { color: var(--bp-warning-deep, #8a5e15); }

/* Переиспользуемое поле комментария (макрос partials/_comment_field.html):
   единый вид для события/брони/участника. textarea с АВТО-ростом — текст
   виден целиком; resize:none убирает ручной уголок (правило проекта: тянуть
   вручную не надо, всё само). Синяя галочка в конце появляется при
   изменении. */
.cmt-field-input {
    font-size: 0.85rem;
    resize: none;
    overflow: hidden;
    line-height: 1.3;
    min-width: 0;
}
/* Авто-рост БЕЗ JS: обёртка-grid кладёт в одну ячейку textarea и невидимую
   копию текста (::after из data-value) — высоту ячейки задаёт копия, поле
   растягивается за ней. Высоту считает лейаут в момент ПОКАЗА, поэтому
   работает и когда поле заполнили скрытым (модалка карточки поднимается
   асинхронно, «Примечание о клиенте» ждёт clientSummary). Прежний JS-
   измеритель ловил там scrollHeight = 0, ставил height:0 и срезал текст при
   каждом переоткрытии карточки (30.07.2026). rows= остаётся минимумом:
   строка grid = max(высота textarea по rows, высота копии).
   ⚠️ Метрики копии и textarea (шрифт, line-height, padding, ширина рамки)
   обязаны совпадать до пикселя — иначе тень врёт на строку. */
.cmt-field-grow {
    display: grid;
    flex: 1 1 auto;
    width: 1%;  /* как у .input-group > .form-control — база для flex-раздачи */
    min-width: 0;
}
.cmt-field-grow::after {
    content: attr(data-value) " ";  /* хвостовой пробел держит высоту пустой последней строки */
    visibility: hidden;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    border: 1px solid transparent;  /* компенсирует рамку textarea */
}
.cmt-field-grow > .cmt-field-input,
.cmt-field-grow::after {
    grid-area: 1 / 1 / 2 / 2;
    font-family: inherit;
    font-size: 0.85rem;
    line-height: 1.3;
    padding: 0.25rem 0.5rem;
    width: 100%;
}
/* Правый край — под кнопки: скругление возвращает .cmt-field-input-solo,
   когда кнопок нет (обёртка сняла с textarea правила input-group). */
.cmt-field-grow > .cmt-field-input {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}
/* Нет изменений → кнопок нет → textarea одна в input-group; закругляем её
   правый край (input-group по умолчанию держит его квадратным под кнопку). */
.cmt-field-input-solo {
    border-top-right-radius: var(--bs-border-radius-sm) !important;
    border-bottom-right-radius: var(--bs-border-radius-sm) !important;
}
/* Симметричная пара «отмена/сохранить» встроена в строку (input-group):
   единый базовый вид, различие только в акценте. Контур акцентного цвета →
   заливка акцентом на hover (одинаковое поведение у обеих). Через brand-
   токены, НЕ Bootstrap btn-outline-* (те рассинхронивались в теме). */
.cmt-field-btn {
    background: #fff;
    border: 1px solid var(--bp-line);
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.cmt-field-cancel {
    color: var(--bp-stamp-red);
    border-color: var(--bp-stamp-red);
}
.cmt-field-cancel:hover:not(:disabled) {
    background: var(--bp-stamp-red);
    color: #fff;
}
.cmt-field-save {
    color: var(--bp-blue);
    border-color: var(--bp-blue);
}
.cmt-field-save:hover:not(:disabled) {
    background: var(--bp-blue);
    color: #fff;
}
.cmt-field-hint {
    font-size: 0.68rem;
    line-height: 1.2;
    margin-top: 2px;
}

/* ─────────────── Последние брони клиента (колонка «Клиент») ───────────────
   Панель отвечает на вопрос «этот человек вообще платит?», за которым раньше
   приходилось лазить по журналу за разные дни. Долги идут первыми — так их
   кладёт сервер, здесь порядок не пересобираем.

   Долг подчёркнут ЦВЕТОМ СТРОКИ, а не значком у каждой: значок на каждой
   строке — это тот же красный экран, на котором глаз перестаёт различать
   важное. Оплаченные строки нейтральны, и красное в панели ровно там, где
   деньги не пришли. */
.bk-history {
    margin-top: 12px;
    border-top: 1px solid var(--bp-line);
    padding-top: 8px;
}

.bk-history__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    font-size: 0.74rem;
    color: var(--bp-muted);
    margin-bottom: 4px;
}

.bk-history__due {
    color: var(--bp-stamp-red, #dc3545);
    font-weight: 600;
    cursor: help;
}

.bk-history__row {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 8px;
    align-items: baseline;
    padding: 3px 6px;
    border-radius: 6px;
    font-size: 0.78rem;
}

.bk-history__row.is-due {
    background: rgba(220, 53, 69, 0.08);
    color: var(--bp-stamp-red, #dc3545);
}

/* Бронь, которая открыта прямо сейчас: чтобы человек видел, где он в списке. */
.bk-history__row.is-current {
    outline: 1px solid var(--bp-line-strong);
}

.bk-history__when {
    color: var(--bp-muted);
    white-space: nowrap;
}

.bk-history__row.is-due .bk-history__when { color: inherit; }

/* Неявка — приглушённая строка: она не долг и не оплата, а третий случай. */
.bk-history__row.is-noshow { color: var(--bp-muted); }

/* Выход к полному списку. Нейтральная, а не кнопка: это продолжение панели,
   а не действие с деньгами — рядом с красными строками долга акцентная
   кнопка перетягивала бы внимание на себя. 40px — палец на телефоне. */
.bk-history__more {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-height: 40px;
    margin-top: 4px;
    border-radius: 6px;
    font-size: 0.78rem;
    color: var(--bp-blue);
    text-decoration: none;
}

.bk-history__more:hover {
    background: var(--bp-blue-tint);
    color: var(--bp-blue);
}

/* ❌ Без ellipsis: обрезанный текст — баг, а не фича (web/CLAUDE.md).
   Длинное название услуги переносится строкой. */
.bk-history__what {
    white-space: normal;
    overflow-wrap: anywhere;
}

.bk-history__sum {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* ── Способы оплаты ──
   Ряд плашек (`bk-pay-quick` / `bk-pay-card`) переехал в `pay-card.css`: он
   один и тот же в карточке записи, в кассе визита и в продаже без записи, а
   этот файл на страницу продажи не подключён. Правишь вид ряда — правь там. */
