/* ============================================================
   Дизайн-система BusCRM.
   Все цвета, радиусы и тени вынесены в переменные ниже ("токены") —
   чтобы поменять внешний вид всего приложения, правьте их в одном месте.
   Тема: светлый фон рабочей области + тёмное меню слева, акцент синий.
   Стиль — "Современный SaaS" (Soft UI Evolution): мягкие многослойные тени,
   скруглённые карточки, мягкие цветные бейджи, зелёный цвет для денег.
   ============================================================ */

/* Шрифт Inter — чистый современный шрифт (как в референсах заказчика).
   Лежит локально в static/vendor/inter/ (без интернета). Один вариативный
   файл покрывает все толщины; кириллица и латиница — отдельными субсетами,
   браузер сам берёт нужный по unicode-range.

   font-display: optional — намеренно, против «дёрганья» страницы. При swap
   браузер имеет право перерисовать УЖЕ показанный текст, когда шрифт наконец
   пришёл: у Inter и системного шрифта разная ширина букв, поэтому строки
   таблицы меняли высоту прямо на глазах. При optional подмены в текущей
   загрузке не происходит вовсе: либо шрифт готов к первой отрисовке (он
   предзагружается, см. base.html, так что почти всегда так и есть), либо
   страница разово рисуется системным шрифтом — но без скачка.

   Адреса файлов продублированы в <link rel="preload"> в base.html — меняя
   их здесь, поменяйте и там, иначе шрифт скачается дважды. */
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 100 900;
    font-display: optional;
    src: url("../vendor/inter/inter-cyrillic.woff2") format("woff2");
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 100 900;
    font-display: optional;
    src: url("../vendor/inter/inter-latin.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
        U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC,
        U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Шрифт значков Bootstrap Icons: объявляем его ещё раз, поверх вендорного
   (vendor/bootstrap-icons/bootstrap-icons.css подключён раньше, поэтому
   выигрывает объявление отсюда). Нужно ради адреса файла: у вендорного к
   адресу приписан хэш (…woff2?e34853…), и предзагрузка в base.html по чистому
   адресу считалась бы другим файлом — шрифт скачался бы дважды.
   Сам вендорный файл не трогаем, чтобы его можно было обновлять как есть. */
@font-face {
    font-family: bootstrap-icons;
    font-display: block;
    src: url("../vendor/bootstrap-icons/fonts/bootstrap-icons.woff2") format("woff2");
}

/* Место под значок занимаем заранее. Все значки Bootstrap Icons нарисованы в
   квадрате 1em, поэтому ширину можно задать, не дожидаясь загрузки шрифта.
   Без этого значок до прихода шрифта занимает чужую ширину, а в момент
   загрузки «выстреливает» в свою — и строка тегов заказа (она с переносом,
   .order-meta) перескакивает на вторую строку, утягивая вниз весь список. */
.bi::before,
[class^="bi-"]::before,
[class*=" bi-"]::before {
    display: inline-block;
    width: 1em;
}

:root {
    /* --- Цвета (палитра под тип продукта «CRM & Client Management») --- */
    --bg: #f3f6fb;             /* фон рабочей области (прохладный светлый) */
    --surface: #ffffff;        /* карточки, панели */
    --muted: #f1f5fd;          /* лёгкая подложка (шапки таблиц и т.п.) */
    --text: #0f172a;           /* основной текст (высокий контраст, AA+) */
    --text-muted: #64748b;     /* второстепенный текст (на белом ≈ 4.7:1) */
    --text-faint: #94a3b8;     /* приглушённые ЗНАЧКИ, не текст (см. ниже) */
    --border: #e6ebf3;         /* тонкие разделители */

    --sidebar-bg: #131a2a;     /* тёмная панель меню слева */
    --sidebar-fg: #98a2b6;     /* неактивный пункт меню */
    --sidebar-fg-hover: #ffffff;
    --sidebar-active-bg: #d7e6ff;  /* активный пункт — нежно-голубой фон */
    --sidebar-active-fg: #1b2a44;  /* тёмный текст активного пункта */
    --sidebar-width: 250px;        /* ширина панели (развёрнутой) */
    --sidebar-width-collapsed: 72px; /* ширина свёрнутой панели (только иконки) */

    --accent: #2563eb;         /* акцент: кнопки, активный пункт, ссылки */
    --accent-strong: #1d4ed8;  /* акцент при наведении/нажатии */
    --accent-rgb: 37, 99, 235;

    /* Кнопка «Быстрый заказ» — цвет и белый текст выбраны заказчиком.

       ОСОЗНАННОЕ ОТСТУПЛЕНИЕ, не недосмотр — не «чинить» молча. Белый текст на
       этой заливке даёт 3.64:1 при норме WCAG AA 4.5:1. Заказчику показывали
       снимки в настоящем размере и называли цифры на каждом шаге; зелёный он
       подбирал сам и остановился здесь. Пользователь у системы один — он же и
       решает, чем платить за вид.

       Если однажды покажется, что текст «моет»: заливка #048a02 почти не
       отличается на глаз, но даёт белому тексту 4.52:1 — норма проходится
       без потери узнаваемости цвета.

       Силуэт кнопки этот оттенок держит уже сам (край к фону 3.36:1 при норме
       3.0), поэтому рамка ниже — не подпорка, а просто чёткий край. */
    --quick: #049c02;
    --quick-strong: #038a00;   /* при наведении/нажатии */
    --quick-border: #037300;   /* контур: чёткий край кнопки на светлом фоне */
    --quick-fg: #ffffff;
    --quick-rgb: 4, 156, 2;

    /* Семантические цвета: деньги/успех — зелёный, предупреждение, опасность */
    --success: #059669;        /* «получено», оплачено, cashback, LTV */
    --success-rgb: 5, 150, 105;

    /* Тот же зелёный, но пригодный под БЕЛЫЙ ТЕКСТ: --success даёт белому
       всего 3.77:1 при норме 4.5:1 для мелкого текста, а этот — 5.55:1.
       Сейчас им ничего не залито (строка-уведомление о СМС переехала на
       пастельную подложку, как у прочих служебных сообщений) — переменная
       оставлена под следующий блок с белым текстом на зелёном. */
    --success-strong: #047857;
    --warning: #b45309;        /* частичная оплата, «без СМС» и т.п. */
    --danger: #dc2626;         /* удаление, ошибки */
    --danger-rgb: 220, 38, 38;

    /* Пастельные подложки (карточки-показатели, чипы иконок, бейджи) */
    --tint-blue: #e8f0fe;
    --tint-green: #e7f6ec;
    --tint-purple: #efeafe;
    --tint-peach: #fdeede;
    --tint-amber: #fef3e2;
    --tint-red: #fdecec;
    --tint-slate: #eef1f6;

    /* --- Скругления и тени --- */
    --radius-card: 16px;       /* карточки */
    --radius-control: 11px;    /* кнопки, поля ввода, пункты меню */
    --radius-pill: 999px;      /* бейджи-пилюли */
    --radius-sm: 8px;          /* мелкие чипы */

    /* Мягкие многослойные тени холодного оттенка (Soft UI Evolution) */
    --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.04);
    --shadow: 0 1px 2px rgba(15, 23, 42, 0.04), 0 6px 16px rgba(15, 23, 42, 0.06);
    --shadow-hover: 0 2px 6px rgba(15, 23, 42, 0.06), 0 14px 30px rgba(15, 23, 42, 0.12);

    /* Подключаем акцент в переменные Bootstrap (ссылки и т.п.) */
    --bs-link-color-rgb: var(--accent-rgb);
    --bs-link-hover-color-rgb: 29, 78, 216;
}

/* Размер текста и межстрочный интервал заданы плотно намеренно: главный экран —
   список заказов, и владельцу важно видеть за раз 8-9 заказов, а не 5. Меняя
   эти два значения, вы меняете плотность всего приложения сразу (остальные
   размеры заданы в rem и подстроятся). */
body {
    background: var(--bg);
    color: var(--text);
    font-family: "Inter", system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    font-size: 15px;
    line-height: 1.45;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Заголовки: чуть плотнее и жирнее — современная типографическая иерархия */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--text);
}

/* Ровные («табличные») цифры — для сумм, телефонов, данных в колонках:
   не «прыгают» по ширине. Класс вешается на ячейки/числа по месту. */
.tabular-nums {
    font-variant-numeric: tabular-nums;
}

/* Видимая обводка фокуса для навигации с клавиатуры (доступность).
   Только для :focus-visible — мышкой обводка не мозолит глаза. */
:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* --- Кнопки --- */
.btn {
    font-weight: 500;
    border-radius: var(--radius-control);
    transition: background-color 0.15s, border-color 0.15s, color 0.15s,
        box-shadow 0.15s, transform 0.05s;
}

.btn:active {
    transform: translateY(1px);
}

/* Кнопки-«акцент»: перекрашиваем стандартный btn-primary Bootstrap в наш синий */
.btn-primary {
    --bs-btn-bg: var(--accent);
    --bs-btn-border-color: var(--accent);
    --bs-btn-hover-bg: var(--accent-strong);
    --bs-btn-hover-border-color: var(--accent-strong);
    --bs-btn-active-bg: var(--accent-strong);
    --bs-btn-active-border-color: var(--accent-strong);
    --bs-btn-disabled-bg: var(--accent);
    --bs-btn-disabled-border-color: var(--accent);
    --bs-btn-focus-shadow-rgb: var(--accent-rgb);
}

/* Контурная кнопка — второстепенное действие рядом с главным (например
   «Новый заказ» рядом с «Быстрым заказом»).

   Своё правило обязательно: выше перекрашен только .btn-primary, а
   .btn-outline-primary взял бы СВОЙ синий Bootstrap #0d6efd. От нашего #2563eb
   он отличается едва заметно — и именно поэтому такое расхождение живёт в
   интерфейсе годами, никому не бросаясь в глаза. */
.btn-outline-primary {
    --bs-btn-color: var(--accent);
    --bs-btn-border-color: var(--accent);
    --bs-btn-hover-bg: var(--accent);
    --bs-btn-hover-border-color: var(--accent);
    --bs-btn-active-bg: var(--accent-strong);
    --bs-btn-active-border-color: var(--accent-strong);
    --bs-btn-disabled-color: var(--accent);
    --bs-btn-disabled-border-color: var(--accent);
    --bs-btn-focus-shadow-rgb: var(--accent-rgb);
}

/* Кнопка «Быстрый заказ»: собрана из тех же переменных Bootstrap, что и
   .btn-primary выше, — тогда размеры, отступы и фокус у обеих одинаковые, и
   рядом в шапке они смотрятся парой, а не самоделкой. */
.btn-quick {
    --bs-btn-color: var(--quick-fg);
    --bs-btn-bg: var(--quick);
    --bs-btn-border-color: var(--quick-border);
    --bs-btn-hover-color: var(--quick-fg);
    --bs-btn-hover-bg: var(--quick-strong);
    --bs-btn-hover-border-color: var(--quick-border);
    --bs-btn-active-color: var(--quick-fg);
    --bs-btn-active-bg: var(--quick-strong);
    --bs-btn-active-border-color: var(--quick-border);
    --bs-btn-disabled-color: var(--quick-fg);
    --bs-btn-disabled-bg: var(--quick);
    --bs-btn-disabled-border-color: var(--quick-border);
    --bs-btn-focus-shadow-rgb: var(--quick-rgb);
    font-weight: 600;
}

/* --- Карточки — мягкие, скруглённые, без жёсткой рамки --- */
.card {
    border: 0;
    border-radius: var(--radius-card);
    box-shadow: var(--shadow);
    background: var(--surface);
}

/* --- Поля ввода --- */
.form-control,
.form-select {
    border-radius: var(--radius-control);
    border-color: var(--border);
    /* Высота поля связана с высотой строки списка заказов: правка идёт прямо
       в ячейке тем же .form-control, и если поле выше строки — строка при входе
       в правку подрастает и список «дёргается». Меняя это число, проверьте
       высоту строки до и во время правки (scratchpad/live_density.py). */
    min-height: 38px;
    padding: 0.35rem 0.7rem;
}

.form-label {
    font-weight: 500;
    color: var(--text);
    margin-bottom: 0.35rem;
}

.form-control:focus,
.form-select:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 0.2rem rgba(var(--accent-rgb), 0.15);
}

.form-text {
    color: var(--text-muted);
}

/* --- Таблицы --- */
.table {
    --bs-table-hover-bg: var(--tint-blue);
}

.table > thead th {
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--text-muted);
    background: var(--muted);
    border-bottom: 1px solid var(--border);
    padding: 0.4rem 0.7rem;
}

.table > tbody td {
    padding: 0.45rem 0.7rem;
    vertical-align: middle;
    border-color: var(--border);
}

.table-hover > tbody > tr {
    transition: background-color 0.12s;
}

/* Кликабельная строка целиком (списки-справочники) */
tr[role="button"] {
    cursor: pointer;
}

/* --- Мягкие бейджи-пилюли (мягкий фон + насыщенный текст) --- */
.badge-soft {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.22rem 0.5rem;
    border-radius: var(--radius-pill);
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
}

.badge-soft.green { background: var(--tint-green); color: #067a54; }
.badge-soft.blue { background: var(--tint-blue); color: #1d4ed8; }
.badge-soft.amber { background: var(--tint-amber); color: #b45309; }
.badge-soft.red { background: var(--tint-red); color: #c81e1e; }
.badge-soft.purple { background: var(--tint-purple); color: #6d28d9; }
.badge-soft.slate { background: var(--tint-slate); color: #475569; }

/* --- Иконочный «чип»: скруглённый цветной квадрат с иконкой --- */
.icon-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 12px;
    font-size: 1.35rem;
    flex-shrink: 0;
}

.icon-chip.blue { background: var(--tint-blue); color: #2563eb; }
.icon-chip.green { background: var(--tint-green); color: #059669; }
.icon-chip.purple { background: var(--tint-purple); color: #7c3aed; }
.icon-chip.peach { background: var(--tint-peach); color: #ea7317; }
.icon-chip.slate { background: var(--tint-slate); color: #475569; }

/* --- Перетаскивание строк (порядок статусов и вкладок) --- */
.sortable-handle {
    cursor: grab;
    color: var(--text-muted);
    /* Палец на телефоне должен таскать строку, а не листать страницу */
    touch-action: none;
}

.sortable-active .sortable-handle { cursor: grabbing; }

/* Строка «в руке»: приподнята тенью и слегка прозрачна, чтобы было
   видно, куда она встанет */
.sortable-dragging {
    opacity: 0.75;
    box-shadow: var(--shadow-hover);
}

/* Пока тащим — не подсвечиваем строки под курсором (мешает целиться) */
.sortable-active tr:hover { background: transparent; }

/* --- Выбор цвета статуса: кружки-переключатели вместо списка --- */
.color-choice { display: flex; flex-wrap: wrap; gap: 0.75rem; }

/* Сам радио-переключатель не показываем — кликается цветной кружок (label) */
.color-choice input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.color-choice label {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.7rem 0.35rem 0.4rem;
    border: 2px solid transparent;
    border-radius: var(--radius-pill);
    cursor: pointer;
    font-size: 0.9rem;
    color: var(--text-muted);
    transition: border-color 0.15s ease, color 0.15s ease;
}

/* Кружок с цветом — перед подписью. Цвет тот же, что у бейджа статуса
   (пастельный), поэтому тонкая рамка — чтобы светлые кружки были видны */
.color-choice label::before {
    content: "";
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--swatch, var(--tint-slate));
    border: 1px solid rgba(15, 23, 42, 0.1);
}

.color-choice label:hover { color: var(--text); }

/* Выбранный цвет обведён — видно и без цвета (важно при дальтонизме) */
.color-choice input:checked + label {
    border-color: var(--accent);
    color: var(--text);
    font-weight: 500;
}

/* Клавиатурная навигация: обводка при переходе табом */
.color-choice input:focus-visible + label { border-color: var(--accent); }

/* --- Плитка фотографии (галерея машины и блок фото в её форме) --- */
.photo-tile img {
    width: 100%;
    /* Все превью одной высоты (4:3), кадр подрезается по центру —
       иначе плитки «прыгали» бы из-за разных пропорций снимков */
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: var(--radius-control);
    border: 1px solid var(--border);
    background: var(--muted);
    box-shadow: var(--shadow-sm);
    transition: box-shadow 0.2s ease, transform 0.2s ease;
}

a.photo-tile:hover img {
    box-shadow: var(--shadow-hover);
    transform: translateY(-2px);
}

/* --- Всплывающие сообщения (alerts) — мягкие, с цветной левой полосой --- */
.alert {
    border: 0;
    border-left: 4px solid transparent;
    border-radius: var(--radius-control);
    box-shadow: var(--shadow-sm);
}

.alert-success { background: var(--tint-green); color: #0f5132; border-left-color: var(--success); }
.alert-danger { background: var(--tint-red); color: #8f1d1d; border-left-color: var(--danger); }
.alert-warning { background: var(--tint-amber); color: #7c4a09; border-left-color: var(--warning); }
.alert-info { background: var(--tint-blue); color: #1d4ed8; border-left-color: var(--accent); }
.alert-secondary { background: var(--tint-slate); color: #475569; border-left-color: #94a3b8; }

/* --- Пустое состояние: иконка + текст + кнопка действия --- */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 2.5rem 1.5rem;
    color: var(--text-muted);
}

.empty-state-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 68px;
    height: 68px;
    border-radius: 18px;
    margin-bottom: 0.9rem;
    font-size: 2.2rem;
    background: var(--tint-blue);
    color: var(--accent);
}

.empty-state p {
    margin-bottom: 1rem;
    max-width: 380px;
}

/* ============================================================
   Макет: меню слева + рабочая область справа
   ============================================================ */

.app-layout {
    display: flex;
    min-height: 100vh;
}

/* --- Панель меню --- */
.sidebar {
    /* На телефоне это выезжающая панель (Bootstrap offcanvas), на десктопе — статичная */
    --bs-offcanvas-width: 250px;
    --bs-offcanvas-bg: var(--sidebar-bg);
}

.sidebar-inner {
    width: 100%;
    height: 100%;
    background: var(--sidebar-bg);
    color: var(--sidebar-fg);
    display: flex;
    flex-direction: column;
}

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 18px 16px;
    font-weight: 700;
    font-size: 1.2rem;
    color: #fff;
    text-decoration: none;
}

/* Логотип-чип в меню: скруглённый акцентный квадрат с иконкой автобуса */
.brand-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 10px;
    background: var(--accent);
    color: #fff;
    font-size: 1.15rem;
    flex-shrink: 0;
}

.sidebar-nav {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px;
    flex: 1;
    overflow-y: auto;
}

/* Пункт меню: иконка + подпись */
.nav-item-link {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    border-radius: var(--radius-control);
    color: var(--sidebar-fg);
    text-decoration: none;
    font-weight: 500;
    transition: background 0.15s, color 0.15s;
}

.nav-item-link i {
    font-size: 1.15rem;
    width: 1.4rem;
    text-align: center;
    flex-shrink: 0;
}

.nav-item-link:hover {
    background: rgba(255, 255, 255, 0.06);
    color: var(--sidebar-fg-hover);
}

.nav-item-link.active,
.nav-item-link.active:hover {
    background: var(--sidebar-active-bg);
    color: var(--sidebar-active-fg);
}

/* Цифра у «Чатов» (Шаг 12б): сколько диалогов ждут владельца — непрочитанное
   или «ждёт ответа». Пилюля прижата вправо; ставит её chat-notify.js. Тег <b>,
   а не <span>: свёрнутое меню прячет подписи `.nav-item-link span`, а цифра
   там нужна — точкой на иконке (правило в блоке свёрнутого меню ниже).
   Красная (--danger), и в развёрнутом меню, и точкой в свёрнутом — решение
   владельца от 17.10.2026: синяя на тёмном меню не бросалась в глаза. Белый
   на --danger — контраст 4.8:1. Счётчики внутри «Чатов» остаются синими. */
.nav-item-link { position: relative; }

.nav-badge {
    margin-left: auto;
    min-width: 1.5rem;
    padding: 0 0.45rem;
    border-radius: var(--radius-pill);
    background: var(--danger);
    color: #fff;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.35rem;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.nav-badge[hidden] { display: none; }

/* Кнопка выхода внизу панели */
.sidebar-logout {
    padding: 8px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.sidebar-logout button {
    width: 100%;
    background: transparent;
    border: 0;
    cursor: pointer;
}

/* --- Рабочая область --- */
.app-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

/* Верхняя строка: кнопка-меню (на телефоне), заголовок, пользователь */
.topbar {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 16px;
    background: rgba(255, 255, 255, 0.9);
    backdrop-filter: blur(6px);
    border-bottom: 1px solid var(--border);
}

/* Заголовок НЕ растягивается: сразу за ним стоят кнопки раздела (например
   «+ Новый заказ» в списке заказов), а всё остальное вправо отжимает
   .topbar-lead. */
.topbar-title {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 600;
    white-space: nowrap;
}

/* Кнопки раздела рядом с заголовком; пустая обёртка работает распоркой */
.topbar-lead {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

/* Обёртка значков раздела нужна скрипту как узел для подмены (section-nav.js),
   а вёрстке она не нужна вовсе: display: contents убирает сам блок из раскладки,
   и значки остаются прямыми элементами флекс-строки .topbar — ровно как было,
   когда обёртки не существовало.

   Имя не «topbar-actions» намеренно: тест вёрстки считает в разметке подстроку
   «topbar-action» (значков должно быть ровно два), и обёртка с таким именем
   попадала бы в счёт. */
.topbar-icons {
    display: contents;
}

.topbar-user {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--text-muted);
    font-weight: 500;
    white-space: nowrap;
}

.hamburger {
    font-size: 1.4rem;
    line-height: 1;
    padding: 2px 8px;
    border: 0;
    background: transparent;
    color: var(--text);
}

.content {
    padding: 14px 16px;
}

/* Кнопка «свернуть/развернуть меню» в верхней строке (только десктоп) */
.collapse-toggle {
    display: none;
    font-size: 1.35rem;
    line-height: 1;
    padding: 2px 8px;
    border: 0;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
}

/* На десктопе панель фиксирована по высоте экрана, а прокручивается контент */
@media (min-width: 992px) {
    .sidebar {
        flex: 0 0 var(--sidebar-width);
        width: var(--sidebar-width);
    }

    .sidebar-inner {
        position: sticky;
        top: 0;
        height: 100vh;
    }

    .collapse-toggle {
        display: inline-flex;
        align-items: center;
    }

    /* --- Свёрнутое меню: узкая полоска только с иконками --- */
    html.sidebar-collapsed .sidebar {
        flex-basis: var(--sidebar-width-collapsed);
        width: var(--sidebar-width-collapsed);
    }

    /* Прячем текстовые подписи, оставляем иконки/чип по центру.
       У логотипа прячем только текст, но не сам чип-иконку (.brand-chip). */
    html.sidebar-collapsed .nav-item-link span,
    html.sidebar-collapsed .sidebar-brand span:not(.brand-chip),
    html.sidebar-collapsed .sidebar-logout span {
        display: none;
    }

    html.sidebar-collapsed .nav-item-link,
    html.sidebar-collapsed .sidebar-brand {
        justify-content: center;
    }

    /* В свёрнутом меню цифре места нет — точка на углу иконки «Чатов».
       Число видно в подсказке пункта (title ставит chat-notify.js). */
    html.sidebar-collapsed .nav-badge {
        position: absolute;
        top: 6px;
        right: 16px;
        min-width: 0;
        width: 0.6rem;
        height: 0.6rem;
        padding: 0;
        font-size: 0;
        line-height: 0;
        box-shadow: 0 0 0 2px var(--sidebar-bg);
    }

    /* Ободок отделяет точку от фона пункта, поэтому он цвета этого фона: у
       активного пункта фон светлый, и тёмный ободок читался бы толстой
       чёрной обводкой (замечание владельца, 17.10.2026). */
    html.sidebar-collapsed .nav-item-link.active .nav-badge {
        box-shadow: 0 0 0 2px var(--sidebar-active-bg);
    }
}

/* ============================================================
   Прочее
   ============================================================ */

/* Пастельные подложки для карточек-показателей */
.tile-blue { background: var(--tint-blue); }
.tile-green { background: var(--tint-green); }
.tile-purple { background: var(--tint-purple); }
.tile-peach { background: var(--tint-peach); }

/* Плитки разделов на главной */
.section-card {
    transition: box-shadow 0.15s, transform 0.15s;
}

.section-card:hover {
    box-shadow: var(--shadow-hover);
    transform: translateY(-2px);
}

/* Страница входа (без меню) — центрируем карточку */
.auth-wrap {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}

/* Логотип-чип на странице входа (крупнее, чем в меню) */
.auth-logo {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border-radius: 16px;
    background: var(--accent);
    color: #fff;
    font-size: 1.7rem;
}

/* Кнопка показа/скрытия пароля внутри поля */
.password-wrap {
    position: relative;
}

.password-toggle {
    position: absolute;
    top: 0;
    right: 0;
    height: 100%;
    padding: 0 0.75rem;
    border: 0;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
}

.password-toggle:hover {
    color: var(--text);
}

/* Автоподсказка: выпадающий список под полем ввода */
.ac-wrap {
    position: relative;
    /* Рядом с кнопкой «＋» поле-поиск лежит в Bootstrap-овском .input-group
       (это flex-контейнер). Без явного flex обёртка сжималась бы по содержимому,
       и поле вместе с выпадающим списком получались узкими. min-width: 0 —
       чтобы длинный текст подсказки обрезался многоточием, а не распирал строку. */
    flex: 1 1 auto;
    min-width: 0;
}

/* Список — position: fixed, координаты считает JS (см. place в autocomplete.js).
   Не absolute: список заказов лежит в контейнере с прокруткой (.table-responsive),
   а тот обрезает всё, что вылезает за его границы — выпадающий список уезжал под
   край рабочего поля, и его приходилось доставать полосой прокрутки. Элемент с
   fixed выходит из-под любого такого контейнера.

   Раз координаты у JS, здесь их нет совсем: оставь top/left — и они бы спорили
   с вычисленными. */
.ac-dropdown {
    position: fixed;
    z-index: 1080; /* выше модалок Bootstrap (1055): подсказка бывает и в них */
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
    box-shadow: var(--shadow-hover);
    /* По вертикали прокручивается сам список, если вариантов много и они не
       влезают в экран; по горизонтали — обрезаем, строки и так с многоточием. */
    overflow-x: hidden;
    overflow-y: auto;
}

.ac-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 8px 12px;
    border: 0;
    background: transparent;
    cursor: pointer;
    font-size: 0.95rem;
}

.ac-item:hover {
    background: var(--tint-blue);
}

/* Пункт, который выберется по Enter.
   Заметнее, чем подсветка мышью, и намеренно: при выборе с клавиатуры глазами
   ищут «а что сейчас выберется?», и еле заметного фона для этого мало —
   на светлом фоне таблицы он читался как ничего. Полоска слева видна сразу. */
.ac-item-active {
    background: var(--tint-blue);
    box-shadow: inset 3px 0 0 var(--accent);
    font-weight: 600;
}

/* Пункт «＋ Добавить: «…»» — не найденная запись, а действие: заводит нового
   клиента прямо из строки заказа. Отделён чертой сверху и выкрашен акцентом,
   чтобы не читался как ещё один человек из базы (иначе владелец выбрал бы его,
   думая, что выбирает клиента). Стоит всегда последним — см. autocomplete.js. */
.ac-item-create {
    border-top: 1px solid var(--border);
    color: var(--accent);
    font-weight: 600;
}

.ac-item-create .bi {
    margin-right: 0.15rem;
}

/* Строка подсказки с организацией: имя/телефон слева, чип организации справа */
.ac-item-rich {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* Текст (имя · телефон) — занимает всё место, длинное обрезаем многоточием */
.ac-item .ac-main {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Нежно-голубой чип организации (как .badge-soft.blue, но компактнее) */
.ac-item .ac-org {
    flex-shrink: 0;
    background: var(--tint-blue);
    color: #1d4ed8;
    padding: 0.15rem 0.5rem;
    border-radius: var(--radius-pill);
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
}

/* На hover фон строки тоже голубой — даём чипу светлую подложку с контуром,
   чтобы он не сливался со строкой */
.ac-item:hover .ac-org,
.ac-item-active .ac-org {
    background: var(--surface);
    box-shadow: inset 0 0 0 1px rgba(37, 99, 235, 0.25);
}

/* --- Ввод «в виде тега» (одно значение), напр. район базирования --- */
/* Внешне повторяет обычное поле, но внутри — чип значения + строка ввода. */
.tags-input {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    min-height: 44px;
    padding: 0.3rem 0.6rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
    cursor: text;
}

.tags-input:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 0.15rem rgba(var(--accent-rgb), 0.25);
}

.tags-input-chips { display: inline-flex; }
.tags-input-chip { gap: 0.25rem; }

.tags-input-remove {
    display: inline-flex;
    align-items: center;
    padding: 0;
    margin-left: 0.1rem;
    border: 0;
    background: transparent;
    color: inherit;
    opacity: 0.7;
    line-height: 1;
    cursor: pointer;
}

.tags-input-remove:hover { opacity: 1; }

.tags-input-field {
    flex: 1 1 120px;
    min-width: 120px;
    padding: 0.2rem 0;
    border: 0;
    outline: none;
    background: transparent;
    font: inherit;
    color: inherit;
}

/* Ряд «уже используемых районов» под полем-тегом (клик — выбрать). */
.tags-pick {
    display: flex;
    flex-wrap: wrap;       /* районы переносятся строкой, а не режутся */
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.5rem;
}

.tags-pick-label {
    font-size: 0.8rem;
    color: var(--bs-secondary-color, #6c757d);
}

/* Пилюля-кнопка: оформление задаёт .badge-soft (как чипу в самом поле),
   здесь — только превратить <button> в ту же пилюлю: у кнопок свои шрифт,
   рамка и фон, без сброса они бы выбивались из ряда. Одна и та же пилюля
   у двух «наборных» рядов проекта: районов в форме машины и вставок
   плейсхолдеров в окне СМС. */
.tags-pick-chip,
.sms-insert-chip {
    border: 0;
    cursor: pointer;
    font-family: inherit;
}

/* Лёгкая реакция на наведение — «это можно нажать» (без смены размеров,
   иначе пилюли бы «прыгали» строкой). */
.tags-pick-chip:hover,
.sms-insert-chip:hover {
    box-shadow: inset 0 0 0 1px rgba(29, 78, 216, 0.45);
}

/* Клавиатурная навигация: контур только при фокусе с клавиатуры. */
.tags-pick-chip:focus-visible,
.sms-insert-chip:focus-visible {
    outline: 2px solid rgba(29, 78, 216, 0.6);
    outline-offset: 1px;
}

/* ============================================================
   Список заказов: группировка по заказам + инлайн-редактирование
   ============================================================ */

/* Фиксированная таблица: ширина колонок не зависит от содержимого, поэтому
   при входе в редактирование ячейки строка не «прыгает». */
.orders-table {
    table-layout: fixed;
}
/* Шесть колонок: даты и маршрут живут в одной широкой (решение заказчика).
   Так маршрут получает половину таблицы и перестаёт переноситься, а даты
   умещаются в одну строчку каждая. */
.orders-table thead th:nth-child(1) { width: 7%; }  /* мест */
.orders-table thead th:nth-child(2) { width: 51%; } /* даты (туда/обратно) + маршрут */
.orders-table thead th:nth-child(3) { width: 16%; } /* кто везёт */
.orders-table thead th:nth-child(4) { width: 10%; } /* сумма */
.orders-table thead th:nth-child(5) { width: 10%; } /* cashback */
.orders-table thead th:nth-child(6) { width: 6%; }  /* удаление маршрута */
/* Постоянная минимальная высота строки рейса — тоже против вертикального скачка */
.orders-table .trip-row > td {
    height: 2.6rem;
    overflow-wrap: anywhere; /* длинный маршрут переносится, в т.ч. по слову */
}

/* Каждый заказ — свой <tbody>. Внутренние линии между строками рейсов убираем,
   а заказы отделяем друг от друга плотной чертой снизу строки-тегов. */
.orders-table tbody.order-group > tr > td {
    border-bottom: 0;
}
.orders-table tr.order-meta-row > td {
    background: var(--muted);
    border-top: 1px dashed var(--border);
    border-bottom: 2px solid var(--border);
    padding-top: 0.3rem;
    padding-bottom: 0.3rem;
}
/* Строку-теги не подсвечиваем как обычную строку при наведении */
.orders-table tr.order-meta-row {
    --bs-table-hover-bg: var(--muted);
}
.order-open {
    font-size: 1.05rem;
    line-height: 1;
    text-decoration: none;
}
.order-open:hover {
    color: var(--accent) !important;
}

/* ---- Объединённая ячейка «даты и маршрут» ----
   Сверху две подачи рядом (туда и обратно), под ними маршрут во всю ширину.
   Каждый из трёх кусков правится отдельно: класс cell-edit висит на них, а не
   на ячейке (правка навешана делегированием, см. inline-edit.js). */
.trip-main {
    white-space: normal;
}
.trip-dates {
    display: flex;
    align-items: center;
    gap: 1.1rem;
    /* Место под редактор даты держится ЗДЕСЬ: в показе строка дат занимает
       одну строчку текста, а поля ввода выше — без этого запаса строка
       подскакивала бы при каждом входе в правку (замер в live_row.py).
       Запас стоит высоты: каждый лишний пиксель здесь умножается на число
       рейсов на экране, поэтому держим его минимальным — ровно под поле. */
    min-height: 1.85rem;
}
/* Дата и время в одну строчку: «22.07.2026 09:00» */
.trip-dates .cell-date + .cell-time {
    margin-left: 0.35rem;
}
/* Правимые куски внутри ячейки — блочно-строчные: иначе подсветка при
   наведении и редактор внутри них схлопнулись бы по ширине */
.trip-dates .cell-edit {
    display: inline-block;
    padding: 0 0.15rem;
}
.trip-route {
    display: block;
    margin-top: 0.1rem;
    padding: 0 0.15rem;
}
/* Ширину полю ввода даты задаём явно: раньше её держала ячейка таблицы, а
   теперь вокруг строчный элемент — без этого поля сжались бы до нуля */
.trip-dates .cell-edit .dt-quick {
    width: 14rem;
}
/* Значок возврата перед датой «обратно» — подсказывает, что это за дата */
.cell-return-icon {
    margin-right: 0.2rem;
    font-size: 0.8rem;
}

/* Подача «обратно» приглушена — это необязательное поле. Когда её нет, вместо
   даты бледная подсказка, она проявляется при наведении на строку, чтобы
   таблица не пестрила. */
.cell-return {
    color: var(--text-muted);
}
.cell-return-empty {
    font-size: 0.78rem;
    opacity: 0;
    transition: opacity 0.15s ease;
}
.trip-row:hover .cell-return-empty {
    opacity: 0.55;
}

/* Кнопка «+ Маршрут» в строке-тегах: добавляет заказу ещё одну машину или
   обратную поездку. Неброская, как и «открыть карточку» рядом. */
.order-add-trip {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.1rem 0.5rem;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text-muted);
    background: var(--surface);
    border: 1px dashed var(--border);
    border-radius: var(--radius-pill);
}
.order-add-trip:hover {
    color: var(--accent);
    border-color: var(--accent);
    border-style: solid;
}

/* Конверт СМС в строке заказа: уйдёт ли клиенту сообщение при смене статуса.
   Разметку даёт партиал _order_sms_flag.html, он же решает, показывать ли его
   вообще (при выключенной отправке конверта нет).

   Цвет отвечает ровно на один вопрос — «уйдёт ли»: зелёный да, серый нет
   (клиент просил не писать, нет телефона, нет самого клиента). Причина — в
   подсказке при наведении; красить три причины в три цвета нельзя, строка
   заказа и так пёстрая от бейджей.

   Зелёный — тот же --quick, что у кнопки «Быстрый заказ» и у счётчика
   выделенной вкладки (выбор заказчика): в списке заказов один зелёный, и
   второй оттенок рядом читался бы как другой смысл.

   Курсор-указатель только у кнопки: у заказа без клиента это <span>, и
   переключать там нечего. */
.order-sms {
    padding: 0;
    font-size: 1.05rem;
    line-height: 1;
    color: var(--quick);
    background: none;
    border: 0;
}
/* Светло-серый (выбор заказчика, 28.08.2026): к белому это 2.6:1 против 4.7:1
   у --text-muted. Для ТЕКСТА так нельзя, для этого значка допустимо: состояние
   несёт не только цвет — форма значка другая (bi-envelope-slash-fill против
   bi-envelope-fill), плюс подсказка при наведении. Смысл приглушения в том,
   чтобы «СМС не уйдёт» не спорило в строке с бейджами и суммами. */
.order-sms.order-sms-off {
    color: var(--text-faint);
}
button.order-sms {
    cursor: pointer;
}
button.order-sms:hover {
    color: var(--accent);
}

/* Крестик удаления маршрута. Виден только у заказа с несколькими маршрутами
   (класс multi-trip ставит шаблон, а после правки — скрипт): последний
   маршрут удалять нельзя, поэтому и кнопки у него нет. */
.trip-delete {
    display: none;
    padding: 0.2rem 0.35rem;
    line-height: 1;
    color: var(--text-muted);
    background: none;
    border: 0;
    border-radius: var(--radius-sm);
    opacity: 0;
    transition: opacity 0.15s ease;
}
.order-group.multi-trip .trip-delete {
    display: inline-flex;
}
.trip-row:hover .trip-delete {
    opacity: 1;
}
.trip-delete:hover {
    color: var(--danger);
    background: rgba(var(--danger-rgb), 0.08);
}

/* Редактируемая ячейка: при наведении — подложка и тонкая рамка-подсказка.

   Подсветка ОТКЛЮЧАЕТСЯ выбором селектора, а не переопределением фона ниже, и
   это принципиально. Bootstrap рисует подсветку строки под курсором тем же
   свойством box-shadow: inset прямо на ячейке. Попытка погасить нашу подсветку
   через `box-shadow: none` сносит заодно и подсветку строки — ячейка становится
   белым пятном на подсвеченной строке, заметным сильнее, чем исходная подсказка
   (наступали на это, видно только на снимке). Поэтому у закрытого заказа
   правило просто не применяется, и фон строки остаётся нетронутым.

   cell-edit встречается только внутри tbody.order-group (_trip_row.html и
   _order_group.html) — вынести его за пределы списка значит сломать эту
   подсветку. Бейдж статуса подсвечивается всегда: он кликается и у закрытого
   заказа, им заказ возвращают в работу. */
.cell-edit {
    cursor: pointer;
}
.order-group:not(.order-locked) .cell-edit:hover,
.order-group.order-locked .cell-edit[data-edit="status"]:hover {
    background: rgba(var(--accent-rgb), 0.06);
    box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.25);
    border-radius: var(--radius-sm);
}
.cell-edit.editing {
    background: transparent;
    box-shadow: none;
}

/* ---- Закрытый заказ (класс order-locked на tbody) ----
   Его статус лежит во вкладке с замком: в списке заказ только показывается,
   правится через карточку. Здесь снимается всё остальное, что зовёт кликнуть;
   саму подсветку под курсором отключает селектор правила .cell-edit:hover
   выше — почему именно так, написано там же.

   Бейдж статуса — исключение везде: им заказ возвращают в работу, и он
   остаётся полноценно кликабельным (то же исключение в inline-edit.js и в
   order_update). */
.order-group.order-locked .cell-edit:not([data-edit="status"]) {
    cursor: default;
}
/* Подсказка «обратно» появляется при наведении на строку и зовёт вписать дату —
   у закрытого заказа вписать её некуда, поэтому не показываем вовсе */
.order-group.order-locked .trip-row:hover .cell-return-empty {
    opacity: 0;
}
/* Маршруты закрытому заказу не добавляют и не удаляют.
   У крестика селектор нарочно длиннее правила .order-group.multi-trip выше:
   при равной силе всё решал бы порядок строк в файле — молчаливая ловушка. */
.order-group.order-locked .order-add-trip {
    display: none;
}
.order-group.order-locked .trip-row .trip-delete {
    display: none;
}

/* Бейджи статуса/тега/оплаты в строке-тегах кликаются как единое целое */
.order-badge-edit {
    display: inline-flex;
    border-radius: var(--radius-pill);
}

/* «Канал не указан» — не бейдж, а пунктирная пометка на пустом фоне.
   Заливку убираем намеренно: серый бейдж рядом с настоящими тегами читался бы
   как ещё один канал, и размеченная строка не отличалась бы от неразмеченной —
   а вся ценность тега именно в этом различии. Пунктир и приглушённый текст
   говорят «здесь пусто, можно заполнить». Класс ставит и шаблон, и скрипт
   (commitBadge в inline-edit.js) — снятый тег должен выглядеть так же сразу,
   без перезагрузки. */
/* Два класса в селекторе — не для красоты: у `.badge-soft.slate` специфичность
   выше одиночного класса, и одиночный `.order-tag-empty` проиграл бы ему
   заливку, где бы он ни стоял в файле. */
.badge-soft.order-tag-empty {
    background: transparent;
    border: 1px dashed var(--border);
    color: var(--text-muted);
    font-weight: 500;
}

/* Поле ввода прямо в ячейке — во всю ширину ячейки (таблица фиксированная).
   Высота задаётся здесь, а не наследуется от .form-control: то поле рассчитано
   на формы и выше строки списка, из-за чего строка при входе в правку
   подрастала бы и список дёргался. Проверяется замером в live_density.py. */
.cell-input {
    width: 100%;
    min-width: 0;
    min-height: 0;
    height: 1.9rem;
    padding: 0.15rem 0.4rem;
}

/* ---- Быстрый ввод даты: пара полей «дата + время» (datetime-quick.js) ----
   Поля стоят колонкой, как и показ значения (дата сверху, время под ней),
   поэтому вход в правку не меняет высоту строки. */
.dt-quick {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
}
.dt-quick-row {
    display: flex;
    align-items: center;
    gap: 0.1rem;
    min-width: 0;
}
.dt-quick input {
    min-width: 0;
}

/* ---- Правка даты прямо в строке списка (внутри ячейки) ----
   Показ остаётся в столбик (дата сверху, время снизу), а поля ввода встают
   В СТРОКУ: по вертикали тогда нужно место под одно поле, а не под два, и
   поле получается нормального размера — в столбик оно выходило вдвое ниже,
   и попасть в него было тяжело.

   Все правила — только под .cell-edit. Форма заказа использует ту же разметку
   и должна остаться вертикальной с полями обычного размера (уже наступали:
   общее правило испортило форму). */
.cell-edit .dt-quick {
    flex-direction: row;
    align-items: center;
    gap: 0.2rem;
    /* Высоту держит .trip-dates (см. её min-height), а не сам редактор:
       иначе поля ввода распирали бы строку при каждом входе в правку. */
    min-height: 0;
}
.cell-edit .dt-quick-row {
    flex: 1 1 auto;
}
/* Время короче даты («09:30» против «21.07.2026») — фиксированной ширины,
   всё остальное отдаём полю даты: иначе полная дата в нём не помещается
   и уезжает за левый край (наступали). */
.cell-edit .dt-quick [data-dt-role="time"] {
    flex: 0 0 3.1rem;
}
/* min-height обязателен: у .form-control он рассчитан на формы (38px) и
   строку списка распирал бы */
.cell-edit .dt-quick input {
    min-height: 0;
    /* Вдвое выше прежних 17px, но не настолько, чтобы под поле пришлось
       резервировать место и терять высоту на каждом рейсе */
    height: 1.75rem;
    /* Поля по бокам поджаты: полная дата «21.07.2026» иначе помещается
       впритык и обрезается на узких окнах */
    padding: 0.2rem 0.25rem;
    font-size: 0.85rem;
}
.dt-quick-row input {
    flex: 1 1 auto;
}
/* Значок календаря: неброский, до наведения — как подпись */
.dt-cal {
    flex: 0 0 auto;
    padding: 0.1rem 0.15rem;
    font-size: 0.85rem;
    line-height: 1;
    color: var(--text-muted);
    background: none;
    border: 0;
}
.dt-cal:hover {
    color: var(--accent);
}
/* Скрытый input type=date — он нужен только чтобы показать родной календарь */
.dt-picker {
    position: absolute;
    width: 0;
    height: 0;
    padding: 0;
    border: 0;
    opacity: 0;
    pointer-events: none;
}

/* В форме заказа поля не растягиваются на всю ширину — дата и время короткие */
.dt-quick-form {
    align-items: flex-start;
}
.dt-quick-form .dt-quick-row {
    width: 100%;
    max-width: 13rem;
}
.dt-quick-form input {
    padding: 0.375rem 0.75rem;
    font-size: 1rem;
}
.dt-quick-form input[data-dt-role="time"] {
    width: 11.5rem;
}
textarea.cell-input {
    resize: vertical;
}

/* Комментарий заказа в строке-тегах: показываем текст, перенос по строкам */
.order-comment {
    display: inline-flex;
    align-items: flex-start;
    gap: 0.3rem;
    max-width: 24rem;
    color: var(--text-muted);
}
.order-comment .comment-text {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* Пока сохраняем — гасим и блокируем; успех/ошибка — короткая подсветка */
.cell-saving {
    opacity: 0.5;
    pointer-events: none;
}
.cell-ok {
    background: rgba(var(--success-rgb), 0.18) !important;
    transition: background 0.3s ease;
}
.cell-error {
    background: rgba(var(--danger-rgb), 0.16) !important;
    transition: background 0.3s ease;
}

/* Плавающая подсказка с текстом ошибки под ячейкой */
.cell-bubble {
    position: absolute;
    z-index: 1090;
    max-width: 18rem;
    padding: 0.4rem 0.6rem;
    background: var(--danger);
    color: #fff;
    font-size: 0.8rem;
    line-height: 1.35;
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
}

/* Мини-меню выбора статуса/оплаты (клонируется из <template>) */
.inline-menu {
    position: absolute;
    z-index: 1085;
    min-width: 9rem;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.35rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
    box-shadow: var(--shadow-hover);
}
.inline-opt {
    display: flex;
    align-items: center;
    width: 100%;
    text-align: left;
    background: transparent;
    border: 0;
    padding: 0.25rem 0.35rem;
    border-radius: var(--radius-sm);
    cursor: pointer;
}
.inline-opt:hover {
    background: var(--muted);
}
.inline-opt.active {
    background: rgba(var(--accent-rgb), 0.1);
}

/* Модал «Кто везёт»: список перевозчиков с поиском */
.carrier-list {
    max-height: 260px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
}
.carrier-item {
    display: block;
    width: 100%;
    text-align: left;
    background: transparent;
    border: 0;
    border-bottom: 1px solid var(--border);
    padding: 0.5rem 0.75rem;
    cursor: pointer;
}
.carrier-item:last-child {
    border-bottom: 0;
}
.carrier-item:hover {
    background: var(--muted);
}
.carrier-item.active {
    background: rgba(var(--accent-rgb), 0.12);
    font-weight: 600;
}

/* Круглые значки-кнопки в верхней строке: лупа (показывает панель поиска)
   и шестерёнка (настройки раздела). Один класс на оба, чтобы они не разъехались
   по виду; активное состояние подсвечивается — по нему видно, что панель
   поиска открыта. */
.topbar-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border: 0;
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--text-muted);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}
.topbar-action:hover {
    background: var(--muted);
    color: var(--text);
}
.topbar-action.active {
    background: rgba(var(--accent-rgb), 0.12);
    color: var(--accent);
}

/* Панель поиска и фильтров над списком заказов (Шаг 7б).
   По умолчанию скрыта целиком — её показывает лупа в шапке (класс search-open).
   Пока поиск открыт, вкладки не показываем: они всё равно перестают собирать
   список, как только нажали «Найти». */
.orders-head .order-filter {
    display: none;
}
.orders-head.search-open .order-filter {
    display: block;
}
.orders-head.search-open .order-tabs {
    display: none;
}

.order-filter-line {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
}
.order-filter-search {
    position: relative;
    flex: 1 1 20rem;
}
.order-filter-search .bi {
    position: absolute;
    left: 0.7rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-muted);
    pointer-events: none; /* иначе клик по значку не попадёт в поле */
}
.order-filter-search input {
    padding-left: 2.1rem;
}
.order-filter-more {
    margin-top: 0.75rem;
    padding: 0.85rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
    background: var(--muted);
}
.order-filter-more .form-label {
    margin-bottom: 0.25rem;
    font-size: 0.82rem;
    color: var(--text-muted);
}
.order-filter-note {
    margin-top: 0.6rem;
    font-size: 0.85rem;
    color: var(--text-muted);
}

/* Вкладки заказов: пилюли-ссылки, у активной — акцентная заливка.
   Счётчик — компактный бейдж; у «Не оплаченные» он амбер (дебиторка на виду). */
.order-tabs {
    flex-wrap: wrap;
    gap: 0.35rem;
    padding-left: 0;
    margin-bottom: 0.75rem;
    list-style: none;
}
/* Одна вкладка. Используется и ссылкой (вкладки списка заказов, где вкладка —
   отдельный адрес), и кнопкой (вкладки внутри карточки подрядчика, где
   переключение происходит на месте). Поэтому здесь гасится и фон кнопки,
   и подчёркивание ссылки — иначе кнопка приезжала бы серой «системной». */
.order-tab {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.3rem 0.7rem;
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--text-muted);
    text-decoration: none;
    font-weight: 500;
    border: 1px solid transparent;
    transition: background 0.15s ease, color 0.15s ease;
}
.order-tab:hover {
    background: var(--muted);
    color: var(--text);
}
.order-tab.active {
    background: var(--accent);
    color: #fff;
}
.order-tab-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.4rem;
    height: 1.4rem;
    padding: 0 0.4rem;
    border-radius: var(--radius-pill);
    background: var(--muted);
    color: var(--text-muted);
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1;
}
.order-tab.active .order-tab-count {
    background: rgba(255, 255, 255, 0.25);
    color: #fff;
}
/* «Не оплаченные» — счётчик амбер, чтобы дебиторка бросалась в глаза */
.order-tab-unpaid .order-tab-count {
    background: var(--tint-amber);
    color: #b45309;
}
.order-tab-unpaid.active {
    background: #b45309;
}
.order-tab-unpaid.active .order-tab-count {
    background: rgba(255, 255, 255, 0.25);
    color: #fff;
}
/* Счётчик «того, что ждёт выполнения» — зелёный с кнопки «Быстрый заказ».
   Какой вкладке его дать, решает галочка highlight_count в настройках, а НЕ
   название вкладки: переименовав её, владелец потерял бы цвет молча.

   :not(.active) — прямо требование заказчика: у выделенной вкладки кружок
   остаётся белым на акцентной заливке (правило .order-tab.active выше).
   Написано условием, а не расчётом на порядок правил: так видно требование.

   Оттенок — --quick, ТОТ ЖЕ, что у кнопки «Быстрый заказ» (выбор заказчика:
   ему показывали более тёмный --quick-strong, он выбрал одинаковый с кнопкой).
   Белая цифра на нём даёт 3.64:1 при норме 4.5:1 — то же осознанное
   отступление, что записано выше у самой кнопки, и здесь оно даже заметнее:
   цифра 12px, а не текст кнопки. Молча «чинить» не надо; если однажды
   покажется, что цифра моет, --quick-strong (#038a00) даёт 4.53:1 и на глаз
   почти не отличается.

   Правило стоит ПОСЛЕ амбера «Не оплаченные»: специфичность у них одинаковая,
   и при совпадении победит галочка, поставленная руками. Системной вкладке её
   не дают вовсе (OrderTabForm), так что случай гипотетический. */
.order-tab-highlight:not(.active) .order-tab-count {
    background: var(--quick);
    color: var(--quick-fg);
}

/* Аванс (полученная сумма) в строке-тегах — отдельный визуальный блок-чип.
   Белый фон + рамка выделяют его на общей серой подложке строки-тегов. */
.order-paid {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.15rem 0.55rem 0.15rem 0.6rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
}
.order-paid-icon {
    color: var(--accent);
    font-size: 0.9rem;
}
.order-paid-label {
    font-weight: 600;
    color: var(--text-muted);
}
/* Кликабельное число аванса: заметная ширина, чтобы поле ввода не сжималось в 1 символ */
.order-paid-edit {
    display: inline-block;
    min-width: 3rem;
    padding: 0 0.25rem;
    text-align: right;
    border-radius: var(--radius-sm);
    font-weight: 600;
}
.order-paid-edit .cell-input {
    display: inline-block;
    width: 7rem;
    text-align: right;
}

/* Заказ вышел из открытой вкладки — плавно гасим его блок перед удалением.
   Тем же классом гаснет и строка-уведомление о СМС, вставшая на его место, —
   поэтому селектор без .order-group. */
.orders-table tbody.order-removing > tr > td {
    opacity: 0;
    transition: opacity 0.35s ease;
}

/* ------------------------------------------------------------------
   Строка-уведомление о СМС (партиал _order_sms_notice.html).

   Встаёт на место заказа, уехавшего из вкладки после смены статуса, и держится
   там несколько секунд — только потом список сдвигается вверх. До этого заметка
   показывалась плашкой у ячейки статуса, но заказ исчезал за 0.35 сек, и она
   оставалась висеть над съехавшим списком (жалоба заказчика 29.08.2026).

   Вид — ровно как у служебного сообщения проекта («Изменения сохранены»,
   .alert выше): пастельная подложка, тёмный текст, полоска цвета слева,
   та же тень и тот же радиус, размер шрифта обычный (решение заказчика
   29.08.2026 — сплошная тёмная заливка с белым текстом была слишком тяжёлой и
   не похожа на остальные сообщения системы).

   Значения НЕ наследуются от .alert и не дублируются «на глаз» — берутся из
   тех же переменных: поменяешь оформление сообщений, полосу поправишь тут же
   рядом. Классы .alert прямо на партиал не вешаем: у Bootstrap свои отступы и
   margin-bottom, а полоса живёт внутри ячейки таблицы.
   ------------------------------------------------------------------ */
.orders-table tbody.order-sms-notice > tr > td {
    border-bottom: 2px solid var(--border);
    padding: 0.35rem 0.5rem;
}
/* min-height полосе ставит JS — ровно ту высоту, что занимал уехавший заказ,
   иначе список подтягивается вверх раньше, чем сообщение прочитано
   (см. replaceOrderWithNotice в inline-edit.js). */
.sms-notice {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.75rem 1rem;
    border-left: 4px solid transparent;
    border-radius: var(--radius-control);
    box-shadow: var(--shadow-sm);
}
.sms-notice-ok {
    background: var(--tint-green);
    color: #0f5132;
    border-left-color: var(--success);
}
.sms-notice-fail {
    background: var(--tint-red);
    color: #8f1d1d;
    border-left-color: var(--danger);
}
.sms-notice-icon {
    flex: 0 0 auto;
    line-height: 1.5;
}
.sms-notice-body {
    flex: 1 1 auto;
    min-width: 0; /* длинный текст СМС переносится, а не растягивает строку */
}
/* Строка «№ · клиент · телефон» — единственная приглушённая: это опознавание
   заказа, а не сообщение. Сам текст СМС идёт обычным размером. */
.sms-notice-sub {
    font-size: 0.875rem;
    opacity: 0.75;
}
.sms-notice-text {
    margin-top: 0.15rem;
    overflow-wrap: anywhere;
}

/* ============================================================
   Уважение к системной настройке «меньше движения» (доступность):
   гасим анимации и переходы для пользователей с prefers-reduced-motion.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }

    .section-card:hover {
        transform: none;
    }
}

/* ============================================================
   Крупная цифра с подписью — показатель.

   Заведено для карточки клиента (сумма оплаченных заказов, cashback, число
   заказов), теперь тем же классом свёрстаны плитки раздела «Аналитика»:
   вид у показателя один на всё приложение, и расходиться ему незачем.
   Крупно, но без кричащих плашек — цвет даёт подложка .tile-*, а не сама цифра.
   ============================================================ */
.stat-value {
    font-size: 1.6rem;
    font-weight: 600;
    line-height: 1.2;
    color: var(--text);
}

/* ============================================================
   Столбики помесячной динамики («Аналитика», Шаг 9б).

   Своими руками на CSS, без библиотеки графиков: нужен ровно один вид
   диаграммы, а сторонний скрипт — это ещё 200 КБ в проекте, который
   намеренно обходится без сборщиков.

   Высоты приходят инлайн-стилем из шаблона (проценты считает view): это
   единственный способ передать данные в CSS, и он тут уместен — значение
   у каждого столбика своё.
   ============================================================ */
.chart-scroll {
    /* На узком экране двенадцать столбиков не помещаются. Прокручиваем
       ВНУТРИ блока: страница целиком ездить по горизонтали не должна. */
    overflow-x: auto;
}

.chart-bars {
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;
    min-width: 520px;
    /* Ось вместо подложки у каждого столбика: залитая дорожка во всю высоту
       читается как ЗАПОЛНЕННЫЙ столбик, и пустые месяцы выглядели «полными»
       (поймано снимком — цифрами такое не ловится). Теперь пустой месяц —
       это пустое место над осью, а сумму под ним всё равно видно. */
    border-bottom: 1px solid var(--border);
}

.chart-month {
    flex: 1;
    min-width: 0;
    text-align: center;
}

.chart-col {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;  /* столбик растёт снизу вверх */
    height: 150px;
}

/* Скругляем только САМЫЙ ВЕРХНИЙ сегмент столбика, а не оба: у составного
   столбика скруглённая серединка выглядела бы разрывом. */
.chart-col > :first-child {
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}

.chart-bar-paid {
    background: var(--success);
}

.chart-bar-pending {
    /* Бледнее «полученного»: ожидаемые деньги — ещё не деньги, и вес у них
       на глаз должен быть меньше. */
    background: var(--tint-peach);
}

.chart-label {
    margin-top: 0.35rem;
    font-size: 0.72rem;
    color: var(--text-muted);
    white-space: nowrap;
}

/* Главная цифра под столбиком — cashback (заработанное). Крупнее и темнее
   оборота: оборот показывает масштаб работы, но деньгами владельца не
   является — из него почти всё уходит перевозчику. */
.chart-cashback {
    font-size: 0.85rem;
    font-weight: 600;
    line-height: 1.25;
    color: var(--text);
    white-space: nowrap;
}

/* Оборот — второстепенная строка: видно, но за главную цифру не примешь */
.chart-revenue {
    font-size: 0.68rem;
    color: var(--text-muted);
    white-space: nowrap;
}

/* Квадратики в легенде — теми же цветами, что и сами столбики */
.chart-key-paid { color: var(--success); }
.chart-key-pending { color: var(--tint-peach); }

/* Значок бокового меню, нарисованный своей SVG (руль у «Подрядчиков»):
   встаёт на место шрифтовых .bi того же размера и красится цветом строки. */
.nav-icon-svg {
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.nav-icon-svg svg {
    width: 1.15rem;
    height: 1.15rem;
}

/* ============================================================
   Переходы между разделами меню без белой вспышки.

   Замер показал: сервер отдаёт страницу за 6–34 мс, а 255–358 мс браузер
   собирает документ заново (при замедлении процессора в 6 раз). Ускорить
   эту пересборку нечем — файлы и так берутся из кэша, в сеть уходит один
   запрос. Но её можно не показывать: браузер умеет придержать снимок старой
   страницы, пока новая не готова. Сам по себе он делает это ненадёжно —
   вспышка появлялась через раз; правило ниже превращает эвристику в
   обязательство, и показывать пустой кадр становится нечего.

   Работает только для переходов внутри сайта и только там, где браузер это
   умеет (Edge, Chrome). Не умеет — переход останется обычным, как сейчас:
   хуже не станет. Вкладок в списке заказов правило не касается — они
   меняются через fetch, документ при этом не перезагружается.

   Плавного перетекания намеренно НЕТ, но и выключить анимацию совсем нельзя —
   проверено замером: при `animation: none` браузер перестаёт придерживать
   кадр и белая вспышка возвращается (88–183 мс). Придерживание живёт ровно
   столько, сколько идёт анимация.

   Поэтому анимация оставлена, а перетекание убрано ступенчатой функцией
   `steps(1, end)`: прозрачность не меняется плавно, а скачком в самом конце.
   Старый кадр держится непрозрачным, затем разом сменяется новым. Обе
   страницы одновременно не видны — на плотных таблицах их наложение
   выглядело бы рябью.

   Длительность короткая: это чистая задержка, добавляемая уже ПОСЛЕ того,
   как новая страница готова.
   ============================================================ */
@view-transition {
    navigation: auto;
}

::view-transition-old(root),
::view-transition-new(root) {
    animation-duration: 90ms;
    animation-timing-function: steps(1, end);
}

/* ============================================================
   ТРАНСПОРТ: вид карточками с фотографиями
   ============================================================
   Список машин показывается либо таблицей (как раньше), либо сеткой карточек
   с фото. Оба вида есть в разметке всегда, видно тот, что назван в атрибуте
   data-vehicles-view на карточке-обёртке; ставит его сервер по cookie
   (см. _view_mode в core/views/vehicles.py), переключает vehicle-view.js.

   Почему переключение сделано показом/скрытием, а не перерисовкой: так оно
   мгновенное и не требует запроса. Фотографии скрытого вида при этом не
   качаются — loading="lazy" внутри display:none браузер не грузит.
   ============================================================ */
[data-vehicles-view="table"] .vehicles-as-cards,
[data-vehicles-view="cards"] .vehicles-as-table {
    display: none;
}

/* --- Переключатель вида (сегмент из двух значков) ---
   Своё правило обязательно: проект перекрашивает только .btn-primary, а
   контурные кнопки Bootstrap взяли бы свой серый #6c757d и синий #0d6efd —
   от проектного #2563eb он отличается едва заметно и уехал бы незамеченным.

   Активный сегмент подсвечен светло-голубым, а НЕ залит акцентом: сплошная
   кнопка в разделе уже есть («Добавить машину»), и вторая заливка спорила бы
   с ней за роль главного действия. Контраст #2563eb на #e8f0fe ≈ 6.3:1. */
.view-toggle .btn {
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-muted);
    padding: 0.375rem 0.7rem;
}

.view-toggle .btn:hover {
    background: var(--muted);
    color: var(--text);
}

.view-toggle .btn.active {
    background: var(--tint-blue);
    border-color: rgba(var(--accent-rgb), 0.45);
    color: var(--accent);
    z-index: 1;  /* иначе рамку соседней кнопки видно поверх подсветки */
}

.view-toggle .btn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* --- Сетка карточек ---
   auto-fill с минимумом 280px: на широком экране 4 в ряд, на ноутбуке 3,
   на телефоне 1. Медиа-запросы не нужны, горизонтальной прокрутки не бывает. */
.vehicle-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 1rem;
}

.vehicle-card {
    position: relative;  /* якорь для растянутой ссылки названия */
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
    transition: box-shadow 0.2s ease, transform 0.2s ease;
}

.vehicle-card:hover {
    box-shadow: var(--shadow-hover);
    transform: translateY(-2px);
}

/* --- Фотография и листание --- */
.card-gallery {
    position: relative;
    /* Место под фото занято заранее: без aspect-ratio карточки «подпрыгивали»
       бы по мере загрузки снимков — та же болезнь, что лечили у шрифтов. */
    aspect-ratio: 4 / 3;
    background: var(--muted);
    overflow: hidden;
}

.gallery-slide {
    display: none;
    width: 100%;
    height: 100%;
    object-fit: cover;  /* разные пропорции снимков не ломают сетку */
}

.gallery-slide.is-active {
    display: block;
}

.gallery-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: #b6c0d2;
    font-size: 2rem;
}

/* Стрелки лежат ВЫШЕ растянутой ссылки названия (у неё z-index 1), иначе клик
   по стрелке уводил бы на карточку машины вместо листания фото. */
.gallery-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    background: var(--surface);  /* непрозрачный: на светлом снимке стрелку иначе не видно */
    color: var(--text);
    box-shadow: var(--shadow-sm);
    cursor: pointer;
}

.gallery-prev { left: 0.5rem; }
.gallery-next { right: 0.5rem; }

.gallery-arrow:hover {
    background: var(--muted);
}

.gallery-arrow:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* На мыши стрелки проявляются при наведении на карточку — сетка не пестрит
   кнопками. На сенсорных экранах наведения нет, поэтому там они видны всегда
   (и крупнее: минимальная цель касания 44px). */
@media (hover: hover) {
    .gallery-arrow {
        opacity: 0;
        transition: opacity 0.15s ease;
    }

    .vehicle-card:hover .gallery-arrow,
    .gallery-arrow:focus-visible {
        opacity: 1;
    }
}

@media (hover: none) {
    .gallery-arrow {
        width: 44px;
        height: 44px;
    }
}

.gallery-dots {
    position: absolute;
    right: 0.6rem;
    bottom: 0.6rem;
    z-index: 2;
    display: flex;
    gap: 0.3rem;
}

.gallery-dot {
    width: 7px;
    height: 7px;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.65);
    box-shadow: 0 0 0 1px rgba(15, 23, 42, 0.25);
}

.gallery-dot.is-active {
    background: #ffffff;
    box-shadow: 0 0 0 1px rgba(15, 23, 42, 0.45);
}

/* Счётчик вместо точек, когда фото много: десяток точек сливается в кашу */
.gallery-counter {
    position: absolute;
    right: 0.6rem;
    bottom: 0.6rem;
    z-index: 2;
    padding: 0.1rem 0.45rem;
    border-radius: var(--radius-pill);
    background: var(--surface);
    border: 1px solid var(--border);
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--text-muted);
}

/* --- Плашка с числом мест ---
   Главный вопрос при подборе машины, поэтому вынесена на фото. Фон
   НЕПРОЗРАЧНЫЙ: полупрозрачная плашка на светлом снимке теряет контраст. */
.seat-chip {
    position: absolute;
    left: 0.6rem;
    bottom: 0.6rem;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 62px;
    padding: 0.3rem 0.5rem;
    border-radius: var(--radius-control);
    background: var(--tint-blue);
    border: 1px solid rgba(var(--accent-rgb), 0.25);
    box-shadow: var(--shadow-sm);
}

.seat-chip-num {
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.05;
    color: var(--accent);
}

.seat-chip-label {
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted);
}

/* Метка неактивной машины — в противоположном углу от плашки мест */
.vehicle-flag {
    position: absolute;
    top: 0.6rem;
    right: 0.6rem;
    z-index: 2;
    background: var(--surface);
    box-shadow: var(--shadow-sm);
}

/* Неактивная машина: снимок приглушён, чтобы в сетке она не выглядела рабочей */
.vehicle-card.is-inactive .gallery-slide {
    filter: grayscale(0.75) opacity(0.75);
}

/* --- Текстовая часть карточки --- */
.vehicle-card-body {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    padding: 0.85rem 0.9rem 0.9rem;
}

.vehicle-card-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.3;
}

.vehicle-card-title a {
    color: var(--text);
    text-decoration: none;
}

.vehicle-card-title a:hover {
    color: var(--accent);
}

.vehicle-card-meta {
    margin: 0;
    font-size: 0.8rem;
    color: var(--text-muted);
}

.vehicle-card-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin-top: 0.15rem;
}

/* Гос. номер моноширинно и в рамке — читается как номер, а не как текст */
.plate-chip {
    display: inline-flex;
    align-items: center;
    padding: 0.16rem 0.45rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    color: var(--text);
    white-space: nowrap;
}

.vehicle-card-owner {
    margin: 0.15rem 0 0;
    font-size: 0.82rem;
    color: var(--text);
}

.vehicle-card-owner .bi {
    color: var(--text-muted);
    margin-right: 0.2rem;
}

/* --- Тумблер активности машины ---
   Один клик выключает машину из работы: она не предлагается при выборе в
   заказе, но остаётся в списках и истории рейсов. Тумблер показывает
   ТЕКУЩЕЕ состояние (включён = зелёная дорожка, ручка справа, подпись
   «Активна»; выключен = серая дорожка, ручка слева, «Неактивна»), а не
   действие: бейдж «неактивна» наверху карточки и тумблер обязаны
   соглашаться, а не спорить. z-index: 2 — выше растянутой ссылки названия
   (приём стрелок галереи), иначе клик доставался бы ссылке.
   align-self: flex-start — не тянуть тумблер на всю ширину тела карточки. */
.vehicle-switch {
    position: relative;
    z-index: 2;
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    margin-top: 0.25rem;
    padding: 0;
    border: 0;
    background: none;
    font-size: 0.78rem;
    line-height: 1;
    color: var(--text-muted);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.vehicle-switch-track {
    position: relative;
    flex: none;
    width: 38px;
    height: 22px;
    border-radius: var(--radius-pill);
    background: var(--success);
    transition: background-color 0.15s ease-in-out;
}

.vehicle-switch-knob {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.25);
    transition: transform 0.15s ease-in-out;
}

/* Включён: ручка уходит вправо (38 − 16 − 3 − 3 = 16px хода) */
.vehicle-switch:not(.is-off) .vehicle-switch-knob {
    transform: translateX(16px);
}

/* Выключен: серая дорожка — контраст к белой ручке достаточен, чтобы
   положение читалось без подписи (компактный вид в таблице) */
.vehicle-switch.is-off .vehicle-switch-track {
    background: #cbd5e1;
}

.vehicle-switch-label {
    transition: color 0.15s ease-in-out;
}

.vehicle-switch:not(.is-off) .vehicle-switch-label {
    color: var(--text);
}

.vehicle-switch:hover .vehicle-switch-track {
    background: var(--success-strong);
}

.vehicle-switch.is-off:hover .vehicle-switch-track {
    background: #b6c2d2;
}

.vehicle-switch:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: var(--radius-pill);
}

/* На время запроса JS ставит disabled — показываем, что клик принят */
.vehicle-switch:disabled {
    opacity: 0.55;
    cursor: default;
}

/* Компактный тумблер без подписи — для строки таблицы: состояние рядом
   несут серый текст строки и бейдж «неактивна» у названия */
.vehicle-switch.is-compact {
    margin-top: 0;
    margin-right: 0.4rem;
    gap: 0;
}

/* Задел: строка опций машины (кондиционер, USB, откидные сиденья). Самих
   опций в модели пока нет — правило стоит заранее, чтобы вёрстка карточки не
   переделывалась, когда они появятся. */
.vehicle-options {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    margin-top: 0.35rem;
}

/* --- Доска статусов заказов (Заказы → шестерёнка → Статусы) ---
   Вид воронки, как в статусах заказов amoCRM: статусы стоят в ряд, под каждым —
   что произойдёт при переходе в него. Раньше это была таблица, и текст СМС был
   спрятан внутри формы статуса. */
.status-board {
    display: flex;
    /* Колонки тянутся до высоты самой высокой — чтобы низ ряда был ровным и
       кнопки «+ добавить действие» стояли одной линией. Иначе ряд выглядит
       осыпавшимся — цифрами это не поймать, видно только на снимке.
       Куда уходит лишняя высота — см. .status-slots ниже: это НЕ карточка. */
    align-items: stretch;
    gap: 0.9rem;
    /* Статусов может стать много — тогда ряд прокручивается вбок.
       Отступ снизу оставлен под полосу прокрутки, иначе она наезжает на
       пунктирный «+ добавить действие» последней колонки. */
    overflow-x: auto;
    padding-bottom: 0.75rem;
}

.status-column {
    flex: 0 0 220px;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.status-card {
    position: relative;
    /* Карточка лишнюю высоту НЕ забирает (правка 29.08.2026 по замечанию
       заказчика). Раньше стояло flex: 1 0 auto — и добавление второго СМС в
       один статус раздувало карточки у ВСЕХ остальных: правил один статус,
       менялись все, это принимали за поломку. Слабину теперь забирает
       .status-slots. Не возвращать «чтобы блоки стояли ровно» — ровный низ
       ряда держится и без этого. */
    flex: 0 0 auto;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-sm);
    padding: 0.7rem 0.75rem;
    /* Верхняя полоса цветом статуса: --tint приходит из шаблона (в шаблонах
       Django нет вычислений, имя токена собирается строкой). Полоса нужна,
       чтобы колонку было видно целиком, а не только по бейджу названия. */
    border-top: 3px solid var(--tint, var(--border));
}

.status-card-head {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

/* Название может не влезть в узкую колонку — переносим его, а не режем:
   владелец должен читать свой статус целиком */
.status-card-head .badge-soft {
    white-space: normal;
    text-align: left;
    flex: 1 1 auto;
}

/* Правка и удаление — бледными значками: они нужны редко, а название и блок
   действия должны читаться первыми */
.status-card-actions {
    display: flex;
    gap: 0.35rem;
    flex-shrink: 0;
}

.status-card-actions a {
    color: var(--text-muted);
    text-decoration: none;
    line-height: 1;
}

.status-card-actions a:hover { color: var(--accent); }
.status-card-actions a.text-danger:hover { color: #c81e1e !important; }

/* Пометки-галочки статуса (быстрый заказ, с сайта, просчёт, выполнен) */
.status-marks {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem 0.5rem;
    margin-top: 0.5rem;
    font-size: 0.72rem;
    color: var(--text-muted);
}

.status-card-foot {
    display: flex;
    flex-wrap: wrap;
    gap: 0.2rem 0.6rem;
    margin-top: 0.5rem;
    font-size: 0.75rem;
    color: var(--text-muted);
}

/* Вкладок у статуса может быть несколько — длинный список обрезаем строкой,
   полный виден в подсказке при наведении */
.status-card-tabs {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --- Действия под статусом ---
   Сообщений у статуса может быть несколько: столько блоков, сколько настроено.
   Пустых блоков не бывает — молчащий статус просто не показывает ничего, кроме
   пунктирного «+ добавить действие» ниже. */
.status-slots {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    /* Лишнюю высоту колонки (её задаёт самый длинный сосед) забирает именно
       этот список: у обёртки нет ни рамки, ни фона, поэтому пустое место под
       конвертами не видно, а карточка статуса остаётся своего размера.
       Конверты при этом прижаты к верху — justify-content по умолчанию. */
    flex: 1 0 auto;
}

.status-slot {
    display: flex;
    align-items: flex-start;
    gap: 0.45rem;
    width: 100%;
    text-align: left;
    padding: 0.55rem 0.6rem;
    /* Сплошная рамка и белая подложка (страница сама светло-серая): блок
       читается как настроенная вещь. Соседний «+ добавить действие» оставлен
       пунктирным и прозрачным — это приглашение, а не действие, и спорить за
       внимание с настроенным сообщением оно не должно. */
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
    background: var(--surface);
    color: var(--text);
    box-shadow: var(--shadow-sm);
    font-size: 0.78rem;
    line-height: 1.35;
    cursor: pointer;
}

.status-slot:hover { border-color: var(--accent); }

/* Метка «всегда СМС» в блоке действия на доске (09.09.2026): такое сообщение
   уходит платной СМС даже клиенту с активным ботом. Редкий, но платный выбор
   владельца — его должно быть видно с одного взгляда, не открывая окно.
   Приглушена намеренно: поясняет блок, а не спорит с ним за внимание. */
.status-slot-always {
    display: inline-block;
    margin-left: 0.3rem;
    padding: 0 0.3rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: 0.7rem;
    white-space: nowrap;
    color: var(--text-faint, #94a3b8);
}

.status-slot-icon {
    flex-shrink: 0;
    color: var(--accent);
}

/* «+ добавить действие» — задел под будущие автодействия. Намеренно легче
   блока СМС: это приглашение, а не действие, и спорить за внимание с
   настроенным конвертом оно не должно. */
.status-add {
    width: 100%;
    padding: 0.35rem 0.5rem;
    border: 1px dashed var(--border);
    border-radius: var(--radius-control);
    background: transparent;
    color: var(--text-muted);
    font-size: 0.74rem;
    cursor: pointer;
}

.status-add:hover { border-color: var(--accent); color: var(--accent); }

.status-add-menu { font-size: 0.85rem; }

/* «позже» у неактивных пунктов: видно, что пункт не сломан, а ещё не сделан */
.status-add-soon {
    margin-left: 0.3rem;
    font-size: 0.7rem;
    color: var(--text-muted);
}

/* Кнопки-вставки плейсхолдеров в окне СМС. Вид кнопок — общий с рядом
   «уже используемых районов» (см. .sms-insert-chip рядом с
   .tags-pick-chip выше): два наборных ряда проекта выглядят одинаково. */
.sms-inserts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.5rem;
}

/* Редактор текста СМС (09.09.2026): вместо textarea — contenteditable,
   чтобы плейсхолдеры жили в самом поле пилюлями. Рамку, паддинги и
   фокус-обводку даёт .form-control (Bootstrap), здесь — только то, чего
   у textarea не было: высота «как 4 прежних строки», скролл длинных
   текстов и честные переносы строк. */
.sms-editor {
    display: block;
    min-height: calc(1.5em * 4 + 1rem);
    max-height: 40vh;
    overflow-y: auto;
    white-space: pre-wrap;
    overflow-wrap: break-word;
    cursor: text;
}

/* Подсказка пустого поля — та же, что раньше была placeholder у textarea.
   :empty гаснет от первого символа; <br>, остающийся после стирания всего
   текста, вычищает скрипт (status-sms.js) — иначе подсказка не вернулась
   бы никогда. */
.sms-editor:empty::before {
    content: attr(data-placeholder);
    color: var(--text-muted);
    pointer-events: none;
}

/* Пилюля плейсхолдера В тексте: вид задаёт тот же badge-soft blue, что у
   кнопок «Подставить:» (классы вешает status-sms.js), здесь — только
   поведение: нажать её нельзя, она часть текста. contenteditable="false"
   не даёт править её нутро, а user-select: all выделяет пилюлю целиком
   первым кликом — удалить или заменить проще, чем пытаться попасть
   курсором в скобку. */
.sms-chip {
    cursor: default;
    user-select: all;
}

/* Значок «i» с пояснением у галочек окна СМС (09.09.2026): постоянно видимый
   form-text разрастал окно, а пояснение нужно, только когда владелец
   сомневается. Текст прежний, показывается плашкой при наведении (и по фокусу
   с клавиатуры — tabindex на обёртке). Чистый CSS без JS: bootstrap-тултипы
   в проекте не инициализируются, а их инициализация не пережила бы подмену
   раздела section-nav без лишней логики. */
.sms-opt-hint {
    position: relative;
    display: inline-flex;
    margin-left: 0.3rem;
    color: var(--text-muted);
    vertical-align: -0.15em;
    cursor: help;
}

.sms-opt-hint .bi {
    font-size: 0.9em;
}

/* Подсветка значка — сигнал «здесь что-то есть», тот же акцент, что у рамок
   блоков при наведении (.status-slot:hover) */
.sms-opt-hint:hover,
.sms-opt-hint:focus-visible {
    color: var(--accent);
}

.sms-opt-hint-bubble {
    display: none;
    position: absolute;
    left: 0;
    top: 1.4em;
    width: max-content;
    max-width: 22rem;
    padding: 0.4rem 0.6rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
    box-shadow: var(--shadow-hover);
    color: var(--text);
    font-size: 0.78rem;
    font-weight: 400;
    line-height: 1.35;
    text-align: left;
    white-space: normal;
    /* Внутри модала достаточно встать над его содержимым; внешние слои
       (выпадашки списка) в окне не живут — про расчёт z-index см. .chat-panel */
    z-index: 10;
}

.sms-opt-hint:hover .sms-opt-hint-bubble,
.sms-opt-hint:focus-visible .sms-opt-hint-bubble {
    display: block;
}

/* ============================================================
   Чат клиента — панель справа (Шаг 10г)

   Вся история общения одной лентой: СМС и личные заметки владельца (строки
   заказов из неё убраны 03.09.2026, см. core/chat.py). Открывается значком в строке заказа, разметка панели — в
   order_list.html, поведение — static/js/chat-panel.js.

   Главное правило вида: ЗАМЕТКА ОБЯЗАНА ОТЛИЧАТЬСЯ ОТ СМС ФОРМОЙ, а не только
   цветом — полоса слева, замок и подпись «только я», без пузыря. Цвет тут
   лишь один из трёх сигналов: владелец не должен вглядываться, чтобы понять,
   что запись видит только он. Клиенту заметка не уйдёт никогда (белый список
   ВНЕШНИЕ_ВИДЫ в core/models.py), и вид обязан это обещать.
   ============================================================ */

/* Ширина 525px — прежние 420px, увеличена на четверть по просьбе владельца
   (05.09.2026). На телефоне Bootstrap сам делает её во всю ширину.

   z-index ОБЯЗАТЕЛЕН и вычислен, а не подобран. Панель идёт без подложки
   (data-bs-backdrop="false" в order_list.html), то есть список под ней живой
   и кликается — а в проекте поверх списка рисуются свои слои: .ac-dropdown
   1080, .inline-menu 1085, .cell-bubble 1090. Со штатными 1045 мини-меню
   статуса нарисовалось бы ПОВЕРХ открытой панели. Ставим выше всех.
   Правишь любое из этих чисел — правь и это; цифрами дефект не ловится,
   только снимком «открытое мини-меню + открытый чат». */
.chat-panel {
    --bs-offcanvas-width: 525px;
    --bs-offcanvas-zindex: 1100;
}

/* Шапка не прокручивается вместе с лентой: имя клиента и «сколько работаем»
   нужны всё время, пока читаешь историю. Отсюда и два куска в ответе сервера. */
.chat-panel-header {
    align-items: flex-start;
    border-bottom: 1px solid var(--border);
    padding-bottom: 0.75rem;
}

.chat-head-slot {
    flex: 1;
    min-width: 0;  /* иначе длинное имя растянет шапку и вытолкнет крестик */
}

.chat-head-name {
    display: block;
    font-weight: 600;
    font-size: 1.05rem;
    color: var(--text);
    text-decoration: none;
}

.chat-head-name:hover { color: var(--accent); }

.chat-head-nick {
    color: var(--text-muted);
    font-size: 0.85rem;
    margin-left: 0.25rem;
}

.chat-head-org {
    display: inline-block;
    background: var(--tint-blue);
    color: var(--accent);
    border-radius: var(--radius-sm);
    padding: 0.05rem 0.4rem;
    font-size: 0.8rem;
    margin-top: 0.15rem;
}

.chat-head-meta {
    color: var(--text-muted);
    font-size: 0.85rem;
    margin-top: 0.15rem;
}

.chat-head-dot { margin: 0 0.35rem; }

/* Кнопка «Ссылка-приглашение» в шапке панели (05.09.2026): копирует личную
   ссылку клиента на бота — та же, что уезжает плейсхолдером в СМС. Ручная
   отправка выручает там, где СМС не дошла или просили не писать. Пилюля в
   фирменном цвете Telegram (#2aabee, как значок выше) — канал читается без
   чтения подписи. После копирования на 2 секунды зеленеет с галочкой —
   класс вешает chat-panel.js, возвращается кнопке исходный вид сама. */
.chat-invite {
    border: 1px solid #2aabee;
    background: transparent;
    color: #2aabee;
    border-radius: var(--radius-pill);
    padding: 0.15rem 0.7rem;
    font-size: 0.8rem;
    margin-top: 0.45rem;
}

.chat-invite:hover { background: var(--tint-blue); }

.chat-invite-done {
    border-color: var(--success);
    color: var(--success);
}

/* Тело панели — колонка: фильтр и поле ввода прижаты, прокручивается только
   лента. Без этого прокручивалось бы всё разом, и поле ввода уезжало бы вниз
   ровно тогда, когда оно нужно. */
.chat-panel-body {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    overflow: hidden;  /* прокрутка живёт внутри .chat-feed, а не здесь */
}

.chat-filter { align-self: flex-start; }

.chat-feed {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    padding-right: 0.25rem;  /* полоса прокрутки не наезжает на пузыри */
}

/* Строка ленты — сама flex-колонка: сторона пузыря задаётся align-self у
   него самого, а align-self работает только внутри flex/grid-контейнера.
   Убрать это правило — разметка останется корректной, но вся лента молча
   прижмётся влево: стороны пузырей перестанут действовать (на этом лента
   и споткнулась, 05.09.2026; сторож — ChatFeedTests.test_storony_puzyrey). */
.chat-item {
    display: flex;
    flex-direction: column;
}

/* Фильтр «Всё / Клиент / Заметки» — на атрибуте, лента уже загружена целиком.

   «Заметки» — всё приватное; «Клиент» — только то, что реально уходит клиенту:
   СМС и (позже) переписка. Строк-опор «Заказ №77» в ленте больше нет вовсе
   (убраны 03.09.2026, см. core/chat.py) — поэтому фильтру хватает одного
   вопроса: приватная запись или нет.

   Приватность спрашивается атрибутом data-chat-internal, а не видом «note»:
   то же самое правило, что в шаблоне строки и в ChatMessage.is_internal, и
   третьей его копии тут быть не должно — иначе заведённый позже внутренний
   вид останется в ленте видимым, а замок ему нарисует только шаблон.

   Значение "true" в селекторе обязательно: на голом [data-chat-internal]
   правило поймало бы и ="false", и фильтр вывернулся бы наизнанку. */
.chat-feed[data-chat-filter-mode="note"] .chat-item:not([data-chat-internal="true"]),
.chat-feed[data-chat-filter-mode="client"] .chat-item[data-chat-internal="true"] {
    display: none;
}

/* Служебная строка (Шаг 12б) приватна (клиенту не видна), но заметкой не
   является: вид «Заметки» её тоже прячет. В «Клиенте» её прячет правило
   выше — по приватности. */
.chat-feed[data-chat-filter-mode="note"] .chat-item[data-chat-event] {
    display: none;
}

/* Служебная строка: по центру, мелко, без пузыря и замка — это отметка о
   том, что случилось, а не реплика. */
.chat-event {
    align-self: center;
    max-width: 90%;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.15rem 0.6rem;
    border-radius: var(--radius-pill);
    background: var(--tint-slate);
    color: var(--text-muted);
    font-size: 0.8rem;
    text-align: center;
}

.chat-empty,
.chat-empty-client,
.chat-loading { margin: auto 0; text-align: center; font-size: 0.9rem; }

/* Подсказка «Клиенту пока ничего не отправляли»: вид «Клиент» показывает одни
   СМС, и у клиента без единой отправки он остался бы пустым белым полем —
   владелец принял бы это за поломку.

   Скрытые строки CSS посчитать не может, зато `:has` спрашивает обратное:
   осталась ли в этом виде хоть одна показываемая строка (не приватная). Нет —
   показываем подсказку. Браузер без `:has` её просто не покажет: лента при
   этом верна, деградация безопасная. */
.chat-empty-client { display: none; }

.chat-feed[data-chat-filter-mode="client"]:not(:has(.chat-item:not([data-chat-internal="true"]))) .chat-empty-client {
    display: block;
}

/* --- СМС и переписка: пузырь ---
   Стороны — как в Telegram (решение заказчика, 05.09.2026): всё, что уходит
   клиенту (СМС и исходящие в Telegram), прижимается к ПРАВОМУ краю; входящие
   от клиента — к левому, см. .chat-bubble-in. Прижатый нижний угол со своей
   стороны — «хвост» пузыря, фирменный признак мессенджера.

   Цвета пузырей поменяны местами по просьбе владельца (05.09.2026):
   исходящие клиенту — бледно-зелёные, входящие от клиента — бледно-голубые. */
.chat-bubble {
    align-self: flex-end;
    max-width: 85%;
    background: var(--tint-green);
    border-radius: var(--radius-card);
    border-bottom-right-radius: var(--radius-sm);
    padding: 0.5rem 0.7rem;
}

/* Входящее от клиента — слева и бледно-голубым (цвета пузырей поменяны
   местами по просьбе владельца, 05.09.2026): своя сторона и свой цвет,
   иначе разговор читается как монолог. */
.chat-bubble-in {
    align-self: flex-start;
    background: var(--tint-blue);
    border-bottom-left-radius: var(--radius-sm);
}

/* Ошибка отправки: клиент НИЧЕГО не получил, хотя отправку ждали. Это должно
   быть видно с одного взгляда — пропуски сюда не доходят вовсе. */
.chat-bubble-fail { background: var(--tint-red); }

.chat-bubble-head {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.75rem;
    color: var(--text-muted);
    margin-bottom: 0.2rem;
}

.chat-fail-mark { color: var(--danger); font-weight: 600; }
.chat-fail-detail { font-size: 0.75rem; color: var(--danger); margin-top: 0.25rem; }

/* --- Заметка владельца: стикер, а не пузырь ---
   Отличается формой (полоса слева, прямой левый край, замок), а не только
   цветом — см. правило в начале блока.

   Компактная (решение заказчика от 28.09.2026): отступы меньше, чем у
   пузыря, а замок с «только я», время и № заказа — одна мелкая строка под
   текстом (.chat-note-meta) вместо отдельной шапки сверху. */
.chat-note {
    align-self: stretch;
    background: var(--tint-amber);
    border-left: 3px solid var(--warning);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    padding: 0.35rem 0.6rem;
}

/* Служебная строка заметки заметно мельче обычной .chat-meta (0.75rem) —
   о том и просили: текст заметки главный, подпись под ним вторична.

   Селектор из двух классов намеренно: общее правило .chat-meta стоит в
   файле НИЖЕ и при равном весе перебило бы размер — строка молча осталась
   бы прежней (на этом живая проверка и споткнулась, 28.09.2026). */
.chat-note .chat-note-meta {
    align-items: center;
    gap: 0.4rem;
    font-size: 0.625rem;  /* 10px — размер задал заказчик (28.09.2026; 8px оказались нечитаемы) */
    margin-top: 0.1rem;
}

.chat-note-lock { color: var(--warning); font-weight: 600; }

/* Отступ замка от «только я» — в em, а не в px/rem: растёт и уменьшается
   вместе с размером строки, если его поменяют. Одного пробела в разметке
   на мелком шрифте не видно — замок прилипал к слову. */
.chat-note-lock .bi { margin-right: 0.4em; }

/* Карандаш — значок без рамки, прижат к правому краю строки. Бледный, пока
   на него не навели: он нужен изредка и не должен спорить с текстом. */
.chat-note-edit {
    margin-left: auto;
    border: 0;
    background: none;
    padding: 0 0.1rem;
    line-height: 1;
    font-size: 0.8rem;
    color: var(--text-faint);
}

.chat-note-edit:hover,
.chat-note-edit:focus-visible { color: var(--accent); }

/* Редактор заметки. Сам блок display не задаёт намеренно: его прячет
   атрибут hidden, а любой свой display перебил бы его, и редактор висел бы
   открытым под каждой заметкой. */
.chat-note-editor .form-control { resize: vertical; min-height: 4rem; }

/* Запас снизу, когда chat-box.js докручивает ленту к открытому редактору:
   без него кнопки «Отмена/Сохранить» вставали вплотную к краю ленты, а
   нижний отступ самой заметки обрезался. Это не display — hidden не ломает. */
.chat-note-editor { scroll-margin-bottom: 0.75rem; }

.chat-note-editor-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-top: 0.35rem;
}

.chat-note-editor-buttons { display: flex; gap: 0.35rem; flex-shrink: 0; }

/* Текст записи: переносы владельца сохраняются, длинное слово не рвёт панель */
.chat-text { white-space: pre-wrap; overflow-wrap: anywhere; }

.chat-meta {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    font-size: 0.75rem;
    color: var(--text-muted);
    margin-top: 0.25rem;
}

.chat-time { font-variant-numeric: tabular-nums; }

/* Подпись «бот» у исходящего, написанного ботом сам (приветствие,
   Telegram-действия статусов) — Шаг 12б */
.chat-origin { font-weight: 600; }

/* --- Поле ввода --- */
.chat-composer {
    border-top: 1px solid var(--border);
    padding-top: 0.75rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.chat-mode { display: flex; gap: 0.4rem; align-items: center; }

.chat-mode-btn {
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-muted);
    border-radius: var(--radius-pill);
    padding: 0.15rem 0.6rem;
    font-size: 0.8rem;
}

.chat-mode-btn.active {
    background: var(--tint-amber);
    border-color: var(--warning);
    color: var(--warning);
    font-weight: 600;
}

/* Включённый «Клиенту» — зелёный (решение владельца от 17.10.2026). Раньше
   оба режима горели одним янтарём, и на глаз было не понять, уйдёт текст
   клиенту или ляжет в заметку. Заливка — та же --tint-green, что у пузыря
   исходящего, янтарь — цвет заметки: кнопка говорит, во что превратится
   текст. Текст — --success-strong: обычный --success мелким шрифтом на
   светлом фоне читается хуже (контраст ниже 4.5:1). */
.chat-mode-btn[data-chat-mode="out"].active {
    background: var(--tint-green);
    border-color: var(--success);
    color: var(--success-strong);
}

/* «Клиенту» выключен, когда у клиента канал Telegram не жив (can_out от
   сервера, шаг 11ж). Показан, а не спрятан, — заказчик просил кнопку серой и
   без всплывающих подсказок (04.09.2026). */
.chat-mode-btn:disabled { opacity: 0.55; cursor: not-allowed; }

.chat-input { resize: vertical; min-height: 4.5rem; }

.chat-send-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.chat-hint { font-size: 0.75rem; }

/* Ошибка живёт внутри панели: набранный текст не должен пропасть вместе с
   закрытым окном. Отступы у .alert свои, поэтому здесь только размер. */
.chat-error { padding: 0.4rem 0.6rem; font-size: 0.85rem; margin: 0; }

/* Значок чата в строке заказа — рядом с конвертом СМС, тем же весом:
   это два соседних значка одного ряда, и разный размер читался бы как
   разная важность. */
.order-chat {
    border: 0;
    background: none;
    padding: 0;
    line-height: 1;
    color: var(--text-faint);
    /* Точка непрочитанного встаёт в угол значка (Шаг 11е) */
    position: relative;
}

.order-chat:hover { color: var(--accent); }

/* Точка непрочитанного на значке чата: клиент писал, панель не открывали.
   Обводка цветом строки — без неё точка сливается с текстом на пёстрой
   строке тегов и статусов. */
.chat-unread-dot {
    position: absolute;
    top: -2px;
    right: -3px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--danger, #dc3545);
    box-shadow: 0 0 0 2px var(--surface, #fff);
}

/* Значок Telegram у имени клиента (Шаг 11е): синий — дойдёт, серый — клиент
   остановил бота. Цвет Telegram-фирменный, а не Bootstrap-синий: владелец
   узнаёт канал по цвету, и «почти такой же синий» работал бы хуже. */
.chat-tg { color: #2aabee; }

.chat-tg-blocked { color: var(--text-faint); }

/* Ссылка «Открыть в «Чатах»» в шапке панели «Заказов» (Шаг 12а) — тот же
   разговор в разделе «Чаты», где рядом видна карточка клиента. Обычная
   ссылка мелким шрифтом: это переход, а не действие над клиентом. */
.chat-open-chats {
    display: inline-block;
    margin-top: 0.45rem;
    margin-left: 0.5rem;
    font-size: 0.8rem;
    text-decoration: none;
}

/* ============================================================
   Раздел «Чаты» (Шаг 12а): диалоги, переписка, клиент

   Разметка — chats.html, _chats_list.html, _chats_card.html; поведение —
   static/js/chats-page.js (список, карточка) и chat-box.js (окно переписки,
   общее с панелью «Заказов»).

   ДВЕ РАСКЛАДКИ, И РЕШАЕТ ИХ ТОЛЬКО CSS — по ширине самой страницы
   (container query на .chats-wrap), а не окна браузера: свёрнутое и
   развёрнутое меню дают разную ширину при одном окне. Скрипт своих точек
   перелома не знает, иначе их стало бы две.
     - широко — три колонки: диалоги | переписка | карточка;
     - уже 1100px — две колонки, карточка выезжает поверх переписки справа
       по кнопке «i» (атрибут data-card="open" на .chats) и закрывается
       крестиком.
   Телефонной версии (один экран) нет — отложена до переезда на сервер.

   Ничто здесь не держится на фиксированной высоте строки: в Chrome владельца
   стоит минимальный шрифт 14px, и всё, что задано мельче, рисуется крупнее.
   ============================================================ */

/* Страница — ровно в высоту окна: колонки прокручиваются каждая сама, а не
   вся страница целиком (иначе поле ввода уезжало бы вниз за длинной лентой).
   Через :has, а не классом на body: раздел подменяется без перезагрузки
   (section-nav.js), и класс пришлось бы ставить и снимать скриптом. Без
   магических чисел «100vh минус шапка»: шапка остаётся флекс-строкой, а
   содержимое забирает остаток. */
.app-main:has(.chats) {
    height: 100dvh;
}

.content:has(.chats) {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.chats-wrap {
    container: chats / inline-size;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.chats {
    flex: 1;
    min-height: 0;
    position: relative;  /* сюда встаёт выезжающая карточка в суженном окне */
    display: grid;
    grid-template-columns: 320px minmax(0, 1fr) 300px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow);
    overflow: hidden;
}

/* --- Колонка 1: диалоги --- */
.chats-list-col {
    display: flex;
    flex-direction: column;
    min-height: 0;
    border-right: 1px solid var(--border);
}

.chats-search {
    position: relative;
    padding: 0.75rem;
    border-bottom: 1px solid var(--border);
}

.chats-search .bi {
    position: absolute;
    left: 1.5rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-faint);
    pointer-events: none;
}

.chats-search .form-control { padding-left: 2.1rem; }

.chats-list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

.chats-row {
    display: flex;
    gap: 0.7rem;
    align-items: flex-start;
    padding: 0.65rem 0.85rem;
    border-bottom: 1px solid var(--border);
    color: var(--text);
    text-decoration: none;
}

.chats-row:hover { background: var(--muted); color: var(--text); }

.chats-row.active { background: var(--tint-blue); }

/* Кружок с буквами. Цвет — от номера клиента (Dialog.color), шесть тинтов
   с тёмными цветами из палитры бейджей: контраст букв тот же, что у них. */
.chats-avatar {
    flex-shrink: 0;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-weight: 600;
    font-size: 0.9rem;
}

.chats-avatar-0 { background: var(--tint-blue); color: #1d4ed8; }
.chats-avatar-1 { background: var(--tint-green); color: #067a54; }
.chats-avatar-2 { background: var(--tint-purple); color: #6d28d9; }
.chats-avatar-3 { background: var(--tint-peach); color: #c2410c; }
.chats-avatar-4 { background: var(--tint-amber); color: #b45309; }
.chats-avatar-5 { background: var(--tint-slate); color: #475569; }

.chats-row-main {
    flex: 1;
    min-width: 0;  /* иначе длинное превью растянет строку вместо многоточия */
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}

.chats-row-top,
.chats-row-bottom {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
}

.chats-row-name,
.chats-row-preview {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.chats-row-name { font-weight: 500; }

.chats-row-time {
    flex-shrink: 0;
    color: var(--text-muted);
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
}

.chats-row-preview { color: var(--text-muted); font-size: 0.875rem; }

.chats-row-you { color: var(--text); }

/* Непрочитанное — жирное имя и тёмное превью: строка видна и без счётчика */
.chats-row-unread .chats-row-name { font-weight: 700; }
.chats-row-unread .chats-row-preview { color: var(--text); }

.chats-count {
    flex-shrink: 0;
    align-self: center;
    min-width: 1.5em;
    padding: 0 0.45em;
    border-radius: var(--radius-pill);
    background: var(--accent);
    color: #fff;
    font-size: 0.75rem;
    font-weight: 600;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* У открытой строки счётчика нет: всё в ней уже на экране */
.chats-row.active .chats-count { display: none; }

.chats-row-mark {
    color: var(--text-muted);
    font-size: 0.75rem;
}

/* Метки строки (Шаг 12б): «новый · нет телефона», «ждёт ответа»,
   «остановил бота» — одной строкой под превью. */
.chats-row-marks {
    display: flex;
    flex-wrap: wrap;
    gap: 0.2rem 0.5rem;
}

.chats-row-mark-new { color: #6d28d9; font-weight: 600; }
.chats-row-mark-waiting { color: var(--warning); font-weight: 600; }

/* Превью-служебная строка — курсивом, без «Вы:» */
.chats-row-event { font-style: italic; }

/* Фильтры над списком: «Все / Ждут ответа N / Новые N» */
.chats-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border);
}

.chats-filter {
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-muted);
    border-radius: var(--radius-pill);
    padding: 0.15rem 0.7rem;
    font-size: 0.85rem;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.chats-filter:hover { color: var(--text); border-color: var(--text-faint); }

.chats-filter.active {
    background: var(--tint-blue);
    border-color: var(--accent);
    color: var(--accent);
    font-weight: 600;
}

.chats-filter-count {
    min-width: 1.4em;
    padding: 0 0.35em;
    border-radius: var(--radius-pill);
    background: var(--accent);
    color: #fff;
    font-size: 0.75rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* Строка уведомлений над поиском (chat-notify.js показывает нужную фразу) */
.chats-notify {
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border);
    background: var(--tint-blue);
    color: #1d4ed8;
    font-size: 0.85rem;
}

.chats-notify-enable {
    border: 0;
    background: none;
    padding: 0;
    color: inherit;
    font-weight: 600;
    text-decoration: underline;
}

.chats-bot-off {
    margin: 0.75rem;
    padding: 0.5rem 0.7rem;
    border-radius: var(--radius-sm);
    background: var(--tint-amber);
    color: #7c4a09;
    font-size: 0.85rem;
}

.chats-empty-list { padding: 1rem; font-size: 0.9rem; }
.chats-empty { padding: 1rem; text-align: center; margin: 0; }

/* --- Колонка 2: переписка --- */
.chats-dialog {
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
}

.chats-dialog-head {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--border);
}

/* Тело — та же флекс-колонка, что у панели (.chat-panel-body): прокручивается
   только лента, поле ввода прижато вниз. */
.chats-dialog-body {
    flex: 1;
    min-height: 0;
    padding: 0.75rem 1rem 1rem;
}

.chats-stub {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
}

.chats-stub .bi { font-size: 2rem; color: var(--text-faint); }

/* Диалог не выбран — видна только заглушка; выбран — только переписка */
.chats[data-dialog="none"] .chats-dialog-head,
.chats[data-dialog="none"] .chats-dialog-body,
.chats[data-dialog="none"] .chats-card-col > * { display: none; }

.chats[data-dialog="open"] .chats-stub { display: none; }

/* «i» и крестик карточки нужны только в суженном окне (см. ниже) */
.chats-info,
.chats-card-close { display: none; }

.chats-info {
    flex-shrink: 0;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-muted);
    border-radius: 50%;
    width: 2rem;
    height: 2rem;
    padding: 0;
    align-items: center;
    justify-content: center;
}

.chats-info:hover { color: var(--accent); }

/* «Ответ не нужен» — рядом с «i», не растягивается */
.chats-no-reply { flex-shrink: 0; white-space: nowrap; }

/* --- Колонка 3: карточка клиента --- */
.chats-card-col {
    min-height: 0;
    overflow-y: auto;
    border-left: 1px solid var(--border);
    background: var(--surface);
}

.chats-card { padding: 1rem; }

.chats-card-head { margin-bottom: 0.75rem; padding-right: 1.5rem; }

.chats-card-name {
    display: block;
    font-weight: 600;
    font-size: 1.05rem;
    color: var(--text);
    text-decoration: none;
}

.chats-card-name:hover { color: var(--accent); }

.chats-card-facts { margin: 0 0 0.75rem; font-size: 0.9rem; }
.chats-card-facts dt { color: var(--text-muted); font-weight: 400; font-size: 0.8rem; }
.chats-card-facts dd { margin-bottom: 0.5rem; }

.chats-card-orders {
    border-top: 1px solid var(--border);
    padding-top: 0.75rem;
    margin-bottom: 0.75rem;
}

.chats-card-subtitle { font-weight: 600; margin-bottom: 0.4rem; }

.chats-card-order {
    display: block;
    padding: 0.4rem 0.5rem;
    margin: 0 -0.5rem;
    border-radius: var(--radius-sm);
    color: var(--text);
    text-decoration: none;
    font-size: 0.875rem;
}

.chats-card-order:hover { background: var(--muted); color: var(--text); }

.chats-card-order-top {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 0.5rem;
}

.chats-card-order-route {
    display: block;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.chats-card-cancelled { font-size: 0.85rem; margin-top: 0.25rem; }

.chats-card-link { font-size: 0.9rem; text-decoration: none; }

/* --- Шаг 12в: «Попросить номер», плашка, форма заказа, вспышка ---
   Шрифты не мельче 0.875rem: Chrome владельца всё равно не рисует мельче
   14px, и мелкий кегль только ломал бы выравнивание. */

/* «Попросить номер» — голубая кнопка-пилюля под «Телефон» (выбор владельца).
   Стоит ВМЕСТО «нет телефона»: кнопка сама говорит, что номера нет. Текст —
   --accent-strong, а не --accent: на голубой заливке --accent даёт 4.4:1,
   ниже нормы 4.5:1. Те же переменные Bootstrap, что у .btn-primary. */
.chats-ask-phone {
    --bs-btn-color: var(--accent-strong);
    --bs-btn-bg: var(--tint-blue);
    --bs-btn-border-color: transparent;
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--accent);
    --bs-btn-hover-border-color: var(--accent);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--accent-strong);
    --bs-btn-active-border-color: var(--accent-strong);
    --bs-btn-focus-shadow-rgb: var(--accent-rgb);
    border-radius: var(--radius-pill);
    padding: 0.25rem 0.85rem;
    font-size: 0.875rem;
}

.chats-card-orders-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.4rem;
}

.chats-card-orders-head .chats-card-subtitle { margin-bottom: 0; }

/* Плашка «Похоже, это клиент из базы»: янтарная, как всё «обратите
   внимание» в проекте (заметки, частичная оплата) */
.chats-merge {
    background: var(--tint-amber);
    border-left: 3px solid var(--warning);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    padding: 0.6rem 0.75rem;
    margin-bottom: 0.75rem;
    font-size: 0.9rem;
}

.chats-merge-title { font-weight: 600; margin-bottom: 0.4rem; }
.chats-merge-title .bi { color: var(--warning); }

.chats-merge-row {
    padding: 0.4rem 0;
    border-top: 1px solid var(--border);
}

.chats-merge-who { margin-bottom: 0.35rem; }
.chats-merge-name { font-weight: 600; color: var(--text); text-decoration: none; margin-right: 0.35rem; }
.chats-merge-name:hover { color: var(--accent); }

.chats-merge-warn { color: var(--warning); margin-bottom: 0.4rem; }

.chats-merge-note { color: var(--text-muted); margin: 0.4rem 0; }

/* Строка-вспышка над карточкой: что сделала последняя кнопка */
.chats-flash {
    margin: 0.75rem 1rem 0;
    padding: 0.5rem 0.75rem;
    border-radius: var(--radius-sm);
    background: var(--tint-green);
    color: var(--success-strong);
    font-size: 0.9rem;
}

.chats-flash-error { background: var(--tint-red); color: var(--danger); }

/* Форма заказа стоит на месте карточки: пока она открыта, карточка скрыта
   (автообновление продолжает её подменять — набранное в форме не страдает) */
.chats[data-order="open"] .chats-card { display: none; }
.chats[data-order="closed"] .chats-order-slot { display: none; }

.chats-order { padding: 1rem; }

.chats-order-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-bottom: 0.75rem;
}

.chats-order-head .chats-card-subtitle { margin-bottom: 0; }

.chats-order .form-label { margin-bottom: 0.2rem; font-size: 0.9rem; color: var(--text-muted); }

.chats-order-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 0.75rem;
}

/* Лента: пилюля «Поделиться номером» под просьбой — владелец видит ту же
   кнопку, что клиент в Telegram (она там, а не здесь: нажать её нельзя) */
.chat-contact-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    margin-top: 0.35rem;
    padding: 0.15rem 0.65rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--text-muted);
    font-size: 0.875rem;
}

.chat-map-link {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    margin-top: 0.25rem;
    font-size: 0.875rem;
    text-decoration: none;
}

/* --- Фото, голосовые, видео и файлы в ленте (Шаг 12д) ---
   Пузырь с файлом — с меньшим отступом: картинка почти до края, как в
   мессенджере. Размер картинки и видео задают атрибуты width/height из
   разметки (ChatMessage.media_box) — место под них браузер держит до
   загрузки, и лента не прыгает. Здесь только «не шире пузыря». */
.chat-bubble-media { padding: 0.3rem; }
.chat-bubble-media .chat-text,
.chat-bubble-media .chat-meta { padding: 0 0.4rem; }

.chat-media-link { display: block; line-height: 0; }

.chat-media-img,
.chat-media-video {
    display: block;
    max-width: 100%;
    height: auto;
    border-radius: var(--radius-sm);
    background: var(--tint-slate);  /* пока картинка грузится — серое место, а не дыра */
}

.chat-media-link:focus-visible .chat-media-img { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Кружок: квадратное видео, обрезанное кругом — как в Telegram */
.chat-media-round {
    width: 200px;
    height: 200px;
    border-radius: 50%;
    object-fit: cover;
}

/* Плеер голосового — во всю ширину пузыря, но не уже, чем нужно кнопкам */
.chat-media-audio { display: block; width: 280px; max-width: 100%; }

/* Файл: значок, имя (длинное обрезается многоточием) и серый размер. Размер
   не мельче 14px — меньше Chrome владельца не рисует (см. память проекта). */
.chat-file {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    max-width: 100%;
    padding: 0.35rem 0.45rem;
    text-decoration: none;
}
.chat-file .bi { font-size: 1.4rem; flex-shrink: 0; }
.chat-file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-file-size { flex-shrink: 0; font-size: 0.875rem; color: var(--text-muted); }

/* Заметка «!» с фото: файл над подписью, с небольшим воздухом */
.chat-note-media { margin: 0.15rem 0 0.25rem; }

/* --- Суженное окно: две колонки, карточка выезжает по «i» --- */
@container chats (max-width: 1099.98px) {
    .chats { grid-template-columns: minmax(240px, 300px) minmax(0, 1fr); }

    .chats-card-col {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        width: min(320px, 85%);
        box-shadow: var(--shadow-hover);
        z-index: 2;
        display: none;
    }

    .chats[data-card="open"] .chats-card-col { display: block; }

    .chats[data-dialog="open"] .chats-info { display: inline-flex; }

    .chats-card-close {
        display: block;
        position: absolute;
        top: 0.85rem;
        right: 0.85rem;
    }
}

/* --- «Настройки»: группа для ответов с телефона (Шаг 12г) --- */
/* Шаги подключения — нумерованный список с воздухом между пунктами */
.settings-group-steps { padding-left: 1.25rem; margin-bottom: 1rem; }
.settings-group-steps li + li { margin-top: 0.25rem; }

/* Команда подключения: моноширинная строка и «Копировать» рядом; на узком
   экране кнопка переносится под строку, а не вылезает за карточку */
.settings-group-command {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}
.settings-group-command code {
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: 0.95rem;
    color: var(--text);
    background: var(--tint-slate);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.35rem 0.6rem;
    word-break: break-all;
    user-select: all;
}

/* --- Окно просмотра фото из ленты чата (Шаг 12д) ---
   Поверх всего, включая панель чата «Заказов» (--bs-offcanvas-zindex: 1100),
   подсказки и мини-меню (1080–1090): фото открывают в том числе из панели.
   Разметка — в base.html снаружи .content, ведёт её chat-photo.js.

   Свой display стоит только у открытого окна (:not([hidden])): любой display
   у самого .photo-viewer перебил бы атрибут hidden, и пустое окно висело бы
   поверх CRM всегда. Кнопки белые на почти чёрной подложке — контраст выше
   4.5:1, текст 14px и крупнее. */
.photo-viewer {
    position: fixed;
    inset: 0;
    z-index: 1200;
    background: rgba(15, 23, 42, 0.92);
}

.photo-viewer:not([hidden]) {
    display: flex;
    align-items: center;
    justify-content: center;
}

.photo-viewer-img {
    max-width: 92vw;
    max-height: 88vh;
    object-fit: contain;
    border-radius: var(--radius-sm);
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
    cursor: default;
}

.photo-viewer-bar {
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    display: flex;
    gap: 0.5rem;
}

.photo-viewer-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    min-height: 2.5rem;
    padding: 0.4rem 0.85rem;
    border: 1px solid rgba(255, 255, 255, 0.35);
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
    font-size: 0.95rem;
    text-decoration: none;
    cursor: pointer;
}

.photo-viewer-btn:hover,
.photo-viewer-btn:focus-visible {
    background: rgba(255, 255, 255, 0.25);
    color: #fff;
    outline: 2px solid #fff;
    outline-offset: 2px;
}
