/*
 * app.css
 * Страница: все
 * Блок: общая оболочка кабинета
 *
 * Правки поверх AdminLTE, которые касаются всего кабинета целиком:
 * шапка и крошки, карточки, кнопки, поля ввода, поведение на мелких
 * экранах.
 *
 * Стили отдельных страниц сюда не попадают — они живут своими файлами
 * рядом со страницей и называются по ней (правило 5.5):
 * `modules/company/web/views/company/token.css`.
 *
 * Раньше файл назывался `cabinet.css`. Имя выглядело английским,
 * но `cabinet` по-английски — шкаф, а не личный кабинет. Такое имя
 * хуже транслита: транслит виден сразу, а это читается как правильное
 * и потому не вызывает подозрений. `app` совпадает с тем, как названы
 * классы самого AdminLTE: `app-wrapper`, `app-main`, `app-content`.
 *
 * Подключается после adminlte.css, поэтому переопределять его можно
 * без восклицательных знаков.
 */

/* --- Поле, которое оформляет скрипт, до его работы не разваливается --- */

/*
 * Выпадающие списки собирает скрипт, а скрипты стоят в конце страницы.
 * До их работы браузер рисует список как умеет сам: с несколькими
 * значениями — простынёй во всю высоту. Строка отбора распухает,
 * таблица уезжает вниз, и на мгновение страница выглядит сломанной.
 *
 * Видно это на медленной связи и при жёсткой перезагрузке. Александр
 * увидел это 01.09.2026 и сказал прямо: выглядит так, будто человека
 * застали не одетым.
 *
 * Поэтому до превращения такое поле показывается ровно как обычное —
 * одной строкой. Скрипт отработал, поставил свой класс — правило
 * перестаёт действовать само.
 *
 * Признаки те же, по которым скрипт ищет поля: `data-record-multi` —
 * списки в строке отбора, `data-select` — обычные формы.
 */
select[data-record-multi]:not(.tomselected),
select[data-select]:not(.tomselected) {
    height: calc(1.5em + .75rem + 2px);
    overflow: hidden;
}

/* --- Место под полосу прокрутки на всю страницу не резервируем --- */

/*
 * Раньше здесь стояло `html { scrollbar-gutter: stable }` — место под
 * полосу держалось всегда, даже когда полосы нет.
 *
 * Ставили это ради того, чтобы страница не дёргалась вбок: когда
 * содержимое дорастает до прокрутки, полоса забирает около пятнадцати
 * точек, и всё, что помещалось впритык, перестаёт помещаться. Тогда
 * от этого ломались хлебные крошки — переносились на вторую строку.
 *
 * **Причина отпала.** Крошки переехали на свою строку во всю ширину
 * и обрезаются многоточием (6.2 и разметка макета); пятнадцать точек
 * им теперь безразличны.
 *
 * **А цена осталась и видна всегда.** Подвал кабинета белый, а полоса
 * запаса показывает фон страницы — серый. На короткой странице, где
 * прокрутки нет вовсе, справа тянется серая кромка рядом с белым
 * подвалом. Постоянная заметная щель против мгновенного сдвига
 * при переходе — обмен невыгодный.
 *
 * **Резерв остаётся только там, где он оправдан, — в полях ввода**
 * (см. ниже). На блоки с прокруткой — карточки, списки, окна —
 * правило не распространяется: у их правого края ничего не стоит,
 * прятаться нечему.
 */

/*
 * Хлебные крошки не переносятся на вторую строку.
 *
 * Длинное название документа не должно ломать шапку: пусть лучше
 * обрежется многоточием. Целиком его всё равно видно в заголовке
 * страницы.
 */
.breadcrumb {
    flex-wrap: nowrap;
    overflow: hidden;
}

/*
 * Обрезается только длинная крошка, короткие остаются целыми.
 *
 * Длинной бывает не последняя, как думалось сначала, а любая:
 * на странице замены ключа крошки идут «Начало / Компании /
 * Индивидуальный предприниматель Ковалёва Мария Александровна /
 * Ключ», и длинная стоит третьей.
 *
 * Ужимать их через `flex-shrink` нельзя — он ужимает всех сразу,
 * и «Начало» превращается в «Н…». Поэтому не ужимаем вовсе,
 * а ставим каждой потолок по ширине: кто короче потолка, тот
 * не пострадал, кто длиннее — обрезался многоточием.
 *
 * `ch` — ширина цифры в текущем шрифте, то есть потолок задан
 * примерно в знаках, а не в пикселях. При уменьшении шрифта
 * на мелких экранах он уменьшается сам.
 */
.breadcrumb-item {
    flex: 0 0 auto;
    max-width: min(60ch, 100%);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/*
 * Разделитель «/» рисуется через `::before` и в ужимание не входит —
 * без этого он обрезается вместе с текстом, и крошки слипаются.
 */
.breadcrumb-item + .breadcrumb-item::before {
    flex: 0 0 auto;
}

/*
 * Крошки не вылезают за свою половину шапки.
 *
 * В шапке слева заголовок, справа крошки, каждый в своей половине.
 * Крошки прижаты вправо через `float`, а плавающий блок шириной
 * не ограничен — он растягивался по содержимому и залезал влево,
 * прямо поверх заголовка. С длинным названием компании они
 * печатались друг по другу.
 */
.app-content-header .breadcrumb {
    max-width: 100%;
}

/* --- Поля ввода и полоса прокрутки --- */

/*
 * Значок проверки не прячется под полосой прокрутки.
 *
 * Bootstrap рисует зелёную галочку и красный кружок фоном в правом
 * верхнем углу поля. У поля с прокруткой полоса стоит ровно там
 * и закрывает значок собой. Вылезает это не сразу: пока текста мало,
 * прокрутки нет и всё видно. Появляется она у клиента с длинным
 * ключом, а не у нас на пустой форме.
 *
 * Ширину полосы замеряет `scrollbar.js` и кладёт в `--wms-scrollbar`.
 * Не подбираем число на глаз: в Windows полоса около 15 точек,
 * на телефоне и в macOS она накладывается поверх и не занимает
 * места вовсе.
 *
 * Места под полосу заранее **не резервируем**. Сначала так и было
 * сделано, но резерв съедает 15 точек ширины поля впустую: значку он
 * не нужен, тот и так отодвинут на ширину полосы независимо от того,
 * появилась она или нет.
 *
 * Правило касается **только полей ввода**. На блоки, внутри которых
 * бывает прокрутка — карточки, списки, окна, — оно не распространяется:
 * там у правого края ничего не стоит, прятаться нечему.
 */
textarea.form-control.is-valid,
textarea.form-control.is-invalid {
    background-position: top .55rem right calc(.55rem + var(--wms-scrollbar, 15px));
    padding-right: calc(2.2rem + var(--wms-scrollbar, 15px));
}

/* --- Кнопки в теле карточки --- */

/*
 * Гасим невидимый довесок, который AdminLTE вешает на тело карточки.
 *
 * `.card-body::after` — приём для обтекания: пустой блок с `clear:
 * both`, чтобы карточка охватывала плавающие элементы внутри. В обычном
 * блоке он безвреден и невидим.
 *
 * Но в гибкой раскладке пустой псевдоэлемент становится **полноправным
 * третьим элементом строки**. Свободное место делится не на один
 * промежуток, а на два, правый край достаётся пустышке, и кнопка
 * съезжает в середину — при том что `justify-content` стоит `between`
 * и по нему кнопка обязана быть у края.
 *
 * Ищется это плохо: в разметке два элемента, в стилях всё верно,
 * а кнопка посреди карточки.
 *
 * В гибкой раскладке обтекание не нужно вовсе — плавающих элементов
 * там не бывает. Поэтому убираем.
 */
.card-body.d-flex::before,
.card-body.d-flex::after {
    content: none;
}

/* --- Мелкие экраны --- */

/*
 * На телефоне и планшете всё уменьшается разом, а не рисуется заново.
 *
 * Отдельный вид для мобильных пришлось бы поддерживать вторым
 * комплектом: добавили колонку в таблицу — не забудь про мобильный.
 * Через полгода они разъедутся, и человек с телефона увидит систему
 * годичной давности.
 *
 * Здесь другой путь: тот же вид, но плотнее. Размер шрифта задан
 * корню, а остальное считается от него — значит уменьшается всё
 * сразу, включая отступы Bootstrap.
 *
 * Числа подбираются на живой странице: станет нечитаемо — поправим
 * их, а не заведём второй интерфейс.
 */
@media (max-width: 991px) {
    html {
        font-size: 15px;
    }

    /* Таблицы плотнее: на узком экране каждая строка на счету. */
    .table > :not(caption) > * > * {
        padding: .4rem .5rem;
    }

    .card-body {
        padding: .85rem;
    }

    h1, .h1 { font-size: 1.6rem; }
    h2, .h2 { font-size: 1.4rem; }
    h3, .h3 { font-size: 1.2rem; }
}

@media (max-width: 575px) {
    html {
        font-size: 14px;
    }

    .table > :not(caption) > * > * {
        padding: .35rem .4rem;
    }

    .card-body {
        padding: .7rem;
    }

    /*
     * Кнопки остаются нажимаемыми пальцем. Меньше сорока точек
     * по высоте — и человек промахивается, особенно по кнопке
     * в строке таблицы.
     *
     * Число вынесено в переменную: рядом с кнопкой в одном ряду
     * стоят поля, и они должны быть той же высоты. Держать число
     * в двух файлах — верный способ однажды поправить одно и забыть
     * второе; так и вышло с полем поиска на телефоне: кнопки были
     * 38 точек, а поле 35.
     */
    :root {
        --wms-touch: 38px;
    }

    .btn {
        min-height: var(--wms-touch);
    }

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

/*
 * Виды кнопок (`wms-btn-plain`, `wms-btn-danger`) убраны совсем:
 * своего css для кнопок больше нет, разметка ровно `btn btn-<color>`,
 * весь вид — рамка, тень, padding, radius, наведение — даёт сам
 * AdminLTE/Bootstrap; белый фон кнопки без цвета — переменная
 * `--bs-btn-bg` в `common/assets/button/button.css` (задачи №124–125,
 * Александр 11.09.2026).
 */

/*
 * Выключенная кнопка — одна на все виды.
 *
 * Bootstrap выключенную только приглушает прозрачностью, и у пустых
 * кнопок это давало серое на сером: «Показать все товары в наличии»
 * ничем не отличалась от рабочей. Здесь у выключенной своя заливка
 * и свой текст — видно с одного взгляда, не вчитываясь.
 *
 * Опасная кнопка выключенной тоже теряет красный: красная, но
 * не нажимаемая, читается как «сейчас рванёт», а она просто недоступна.
 *
 * Курсор говорит то же самое рукой. `pointer-events` Bootstrap для
 * `:disabled` не ставит, поэтому курсор виден.
 */
/*
 * Задаём переменными, а не свойствами. Bootstrap 5.3 рисует кнопку
 * через `--bs-btn-*`, и каждый вид кнопки объявляет свои. Прямое
 * `color` мимо переменных перебивалось видом кнопки, причём молча:
 * рамка бралась наша, а текст оставался бутстраповский.
 */
/*
 * Класс повторён намеренно. Каждый вид кнопки — `btn-light`,
 * `btn-primary`, `btn-outline-danger` — объявляет эти переменные
 * у себя, и одиночный `.btn` их не перебивает: вес одинаковый.
 * Повтор поднимает вес на ступень и накрывает все виды сразу,
 * не перечисляя их поимённо.
 */
.btn.btn {
    --bs-btn-disabled-bg: var(--bs-secondary-bg, #e9ecef);
    --bs-btn-disabled-border-color: var(--bs-border-color, #dee2e6);
    /*
     * Текст заметно бледнее обычного, а не «приглушённый на четверть»:
     * приглушённый рядом с рабочей кнопкой не читается как выключенный,
     * а именно это и надо увидеть с одного взгляда.
     */
    --bs-btn-disabled-color: #adb5bd;
    --bs-btn-disabled-opacity: 1;
}

/*
 * Цвет текста задан ещё и прямо, поверх переменных. Одних переменных
 * не хватило: у выключенной кнопки текст оставался тёмным и
 * полупрозрачным, то есть почти как у рабочей.
 */
.btn.btn:disabled,
.btn.btn.disabled,
fieldset:disabled .btn.btn {
    /*
     * Заливка и рамка задаются здесь же, а не только переменными:
     * виды кнопок ставят свой фон напрямую и с тем же весом, и без
     * этого выключенная белела вместе с рабочей.
     */
    background-color: var(--bs-secondary-bg, #e9ecef);
    border-color: var(--bs-border-color, #dee2e6);
    color: #adb5bd;

    /* Курсор говорит то же самое рукой. */
    cursor: not-allowed;
}

/* --- Срочные предупреждения видны на каждой странице --- */

.cabinet-alerts {
    position: sticky;
    top: 4rem;
    z-index: 1025;
}

.cabinet-alert,
.storage-overage-alert {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin-bottom: 1rem;
    box-shadow: 0 .2rem .55rem rgba(125, 18, 28, .24);
}

.storage-overage-alert {
    position: static;
}

.cabinet-alert > .bi,
.storage-overage-alert > .bi {
    flex: 0 0 auto;
    font-size: 1.45rem;
}

.cabinet-alert__message,
.storage-overage-alert__message {
    flex: 1 1 auto;
    min-width: 0;
}

.cabinet-alert__details,
.storage-overage-alert__details,
.storage-overage-alert__note {
    margin-top: .15rem;
}

@media (max-width: 575px) {
    .cabinet-alerts {
        top: 3.75rem;
    }

    .cabinet-alert,
    .storage-overage-alert {
        align-items: stretch;
        flex-wrap: wrap;
        gap: .45rem .65rem;
        padding: .7rem;
    }

    .cabinet-alert > .bi,
    .storage-overage-alert > .bi {
        margin-top: .05rem;
    }

    .cabinet-alert__message,
    .storage-overage-alert__message {
        flex-basis: calc(100% - 2.2rem);
    }

    .cabinet-alert .btn,
    .storage-overage-alert .btn {
        width: 100%;
    }
}

/* --- Рабочая область кабинета не заводит своей прокрутки --- */

/*
 * У AdminLTE на широком экране стоит своё правило:
 *
 *     .sidebar-expand-lg.layout-fixed .app-main {
 *         flex: 1 1 auto;
 *         overflow: auto;
 *     }
 *
 * `overflow: auto` делает рабочую область **своей областью
 * прокрутки**. А липкое — шапка блока, названия столбцов, строка
 * отбора — держится не за окно, а за ближайшую такую область.
 * Прокручивается у нас страница целиком, `.app-main` растёт вместе
 * с содержимым и сама никуда не едет: липкое честно держится за то,
 * что стоит на месте, и уезжает вверх вместе с ним.
 *
 * Ловится это плохо (нашли 06.09.2026, замеры координатора): свойства
 * верные, `position` у всех ступеней `sticky`, а после прокрутки
 * на 1500 точек их `top` равен −1332, −1301 и −1169. Шапка кабинета
 * при этом липнет как надо — она прямой ребёнок `.app-wrapper`,
 * и `.app-main` до неё не достаёт.
 *
 * Правило AdminLTE написано под другую его разметку — с обёрткой
 * `.app-main-wrapper`, где рабочая область и правда прокручивается
 * сама, в высоту окна. У нас такой обёртки нет, `.app-wrapper` —
 * сетка, и `flex: 1 1 auto` из того же правила не действует вовсе.
 * Осталось одно `overflow`, от которого только вред.
 *
 * Что меняется взамен: содержимое шире экрана теперь прокручивает
 * страницу вбок, а не саму рабочую область. Так и надо — иначе
 * широкую таблицу пришлось бы двигать отдельно от всего остального.
 *
 * Медиазапрос повторяет запрос AdminLTE, а селектор — его селектор:
 * вес одинаковый, наш файл идёт следом и перекрывает без
 * восклицательных знаков.
 */
@media (min-width: 992px) {
    .sidebar-expand-lg.layout-fixed .app-main {
        overflow: visible;
    }
}

/* --- Подвал — строка состояния --- */

/*
 * Подвал закреплён внизу и стал строкой состояния (слово Александра
 * 17.09.2026: «в футер, где написано учёт для маркетплейсов, туда же
 * WMSdb, а справа — что сейчас делает; сделать максимально маленьким,
 * небольшой шрифт, как строка состояния»). Слева — WMSdb, справа —
 * текущий шаг фоновой работы (подключение модуля, докачка истории,
 * фото товаров); фон ничего не делает — справа пусто.
 *
 * Высота — одна переменная `--wms-footer`: на неё же поднимаются
 * плавающие подвалы таблиц и полоса прокрутки (`lists.css`), иначе
 * строка состояния легла бы поверх итогов. Закрепление — класс
 * `fixed-footer` у `body` (правило AdminLTE `position: sticky; bottom: 0`).
 */
:root {
    --wms-footer: 1.75rem;
}

.app-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    min-height: 0;
    height: var(--wms-footer);
    padding: 0 .75rem;
    font-size: .8rem;
    line-height: 1;
    white-space: nowrap;
    overflow: hidden;
}

.app-footer .app-footer-status {
    /* Слева, во всю свободную ширину; длинный текст обрезается
       многоточием, название справа не сжимается. */
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}
