/**
 * Мобильные раскладки.
 *
 * Собрано из четырёх страниц: index.html держал 10 media-блоков, alerts.html —
 * 8, плюс по одному в accounts.html и help.html. Пять блоков между index и
 * alerts были побайтно одинаковы, ещё тридцать селекторов — почти одинаковы:
 * правка в одном месте молча расходилась с другим, и на узком экране две
 * похожие страницы вели себя по-разному.
 *
 * Брейкпоинты — бутстраповские, три штуки и не больше:
 *   ≤575.98  телефон в портрете
 *   ≤767.98  мобильная раскладка (карточки, приоритетные колонки)
 *   ≤991.98  планшет: колонки ещё помещаются, остаётся горизонтальный скролл
 *
 * Скрытие колонок здесь НЕ живёт. Раньше жило: заголовки прятались по
 * th[data-sort=…], а ячейки по td:nth-child(…), и наборы не совпадали — на
 * 375 px данные вставали не под своими подписями. Этим занимается
 * ui/mobile-tables.js, который переносит приоритет с заголовка на ячейку.
 */

/* Кнопка раскрытия существует только в мобильной раскладке.
   Она добавляется скриптом и из DOM не убирается: без этого правила после
   поворота планшета в ландшафт или растягивания окна в каждой строке посреди
   ячейки оставался торчать шеврон. */
.mobile-expand { display: none; }

@media (hover: none) and (pointer: coarse) {
  .table th, .table td {
    min-height: 44px;
  }
  .btn {
    min-height: 44px;
  }
  .form-control, .form-select {
    min-height: 44px;
  }
  .col-close {
    min-width: 44px;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
  }
}

@media (max-width: 991.98px) {
  .table {
    min-width: 900px;
    font-size: 0.9rem;
  }
  .filters-section {
    padding: 1rem;
  }
  .table-controls {
    padding: 0.75rem;
  }
  .filters-header {
    flex-direction: column;
    gap: 0.75rem;
    align-items: stretch;
  }
  .filters-header .d-flex {
    flex-direction: column;
    gap: 0.5rem;
  }
  .filter-row {
    flex-direction: column;
    gap: 0.5rem;
  }
  .col-md-1, .col-md-2, .col-md-3 {
    width: 100%;
    margin-bottom: 0.5rem;
  }
  .btn {
    width: 100%;
    margin-bottom: 0.5rem;
  }
  .btn:last-child {
    margin-bottom: 0;
  }
  .d-flex.gap-2 {
    flex-direction: column;
    gap: 0.5rem !important;
  }
  .d-flex.justify-content-end {
    justify-content: stretch !important;
  }
  .table-controls .d-flex {
    flex-direction: column;
    gap: 0.5rem;
    align-items: stretch;
  }
  .dropdown {
    width: 100%;
  }
  .dropdown .btn {
    width: 100%;
    text-align: left;
  }
}

@media (max-width: 767.98px) {
  .table th, .table td {
    line-height: 1.4;
    padding: 0.5rem 0.3rem;
    font-size: 0.75rem;
  }
  .table-container {
    margin-bottom: 1rem;
    min-width: 100%;
    padding: 1rem;
  }
  .nav-tabs {
    border-bottom: 2px solid rgba(255, 255, 255, 0.3);
  }
  .nav-tabs .nav-link {
    border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -2px;
    transition: border-color 0.2s ease;
  }
  .nav-tabs .nav-link.active {
    border-bottom-color: white;
    background: transparent;
  }
  .nav-tabs .nav-link:hover {
    border-bottom-color: rgba(255, 255, 255, 0.5);
    background: transparent;
  }
  .offcanvas-body h6 {
    font-size: 1rem;
    margin-bottom: 0.5rem;
  }
  .offcanvas-body h4 {
    font-size: 1.5rem;
    margin-bottom: 1rem;
  }
  .offcanvas-body .alert {
    padding: 0.75rem;
    margin-bottom: 1rem;
  }
  .offcanvas-body .alert i {
    font-size: 1rem;
  }
  .offcanvas {
    width: 100% !important;
    max-width: 100% !important;
  }
  .offcanvas-header {
    padding: 1rem;
  }
  .offcanvas-title {
    font-size: 1.1rem;
  }
  .offcanvas-body {
    padding: 1rem;
  }
  .btn-close {
    background-size: 1rem;
    padding: 0.375rem;
  }
  .trusted-breakouts-table {
    font-size: 0.8rem;
    min-width: 450px;
  }
  .trusted-breakouts-table th, .trusted-breakouts-table td {
    padding: 0.25rem 0.3rem;
  }
  .trusted-breakouts-table .date-column {
    min-width: 120px;
  }
  .trusted-breakouts-table .interval-column {
    min-width: 60px;
  }
  .trusted-breakouts-table .type-column {
    min-width: 100px;
  }
  .trusted-breakouts-table .price-column {
    min-width: 80px;
  }
  .period-type-badge, .type-badge {
    font-size: 0.75rem;
    padding: 0.25rem 0.5rem;
  }
  .table {
    min-width: 900px;
    font-size: 0.8rem;
  }
  .col-md-2, .col-md-3, .col-md-4, .col-md-12 {
    width: 100%;
    margin-bottom: 0.5rem;
  }
  .btn {
    width: 100%;
    margin-bottom: 0.5rem;
  }
  .btn:last-child {
    margin-bottom: 0;
  }
  .d-flex.gap-2 {
    flex-direction: column;
    gap: 0.5rem !important;
  }
  .d-flex.justify-content-end {
    justify-content: stretch !important;
  }
  .main-header {
    padding: 1.5rem 0;
  }
  .main-header h1 {
    font-size: 1.5rem;
  }
  .main-header p {
    font-size: 0.9rem;
  }
  .table-controls {
    flex-direction: column;
    gap: 1rem;
    align-items: stretch;
  }
  .table-controls .d-flex {
    flex-direction: column;
    gap: 0.5rem;
  }
  .dropdown {
    width: 100%;
  }
  .dropdown .btn {
    width: 100%;
    text-align: left;
  }
  .pagination-info {
    flex-direction: column;
    gap: 1rem;
    align-items: center;
  }
  .pagination {
    justify-content: center;
  }
  .filters-section {
    margin-bottom: 1rem;
  }
  .filters-header h5 {
    font-size: 1.1rem;
    margin-bottom: 0;
  }
  .form-check.form-switch {
    margin-bottom: 0.5rem;
  }
  .form-select.form-select-sm {
    width: 100% !important;
    margin-bottom: 0.5rem;
  }
  #autoRefreshLoader {
    width: 100% !important;
    min-width: auto !important;
    margin-bottom: 0.5rem;
  }
  .accounts-container {
    padding: 1rem;
  }
  .table-responsive {
    font-size: 0.8rem;
  }
  .help-layout {
    flex-direction: column;
  }
  .help-sidebar {
    width: 100%;
    position: static;
    max-height: none;
  }
}

@media (max-width: 575.98px) {
  .offcanvas-header {
    padding: 0.75rem;
  }
  .offcanvas-title {
    font-size: 1rem;
  }
  .offcanvas-body {
    padding: 0.75rem;
  }
  .btn-close {
    background-size: 0.875rem;
    padding: 0.25rem;
  }
  .trusted-breakouts-table {
    font-size: 0.75rem;
    min-width: 400px;
  }
  .trusted-breakouts-table th, .trusted-breakouts-table td {
    padding: 0.2rem 0.25rem;
  }
  .trusted-breakouts-table .date-column {
    min-width: 100px;
  }
  .trusted-breakouts-table .interval-column {
    min-width: 50px;
  }
  .trusted-breakouts-table .type-column {
    min-width: 80px;
  }
  .trusted-breakouts-table .price-column {
    min-width: 60px;
  }
  .period-type-badge, .type-badge {
    font-size: 0.7rem;
    padding: 0.2rem 0.4rem;
  }
  .table {
    min-width: 720px;
    font-size: 0.8rem;
  }
  .table th, .table td {
    padding: 0.4rem 0.2rem;
    font-size: 0.7rem;
  }
  .main-header {
    padding: 1rem 0;
  }
  .main-header h1 {
    font-size: 1.25rem;
  }
  .table-container {
    padding: 1rem;
    border-radius: 8px;
  }
  .form-label {
    font-size: 0.9rem;
    margin-bottom: 0.25rem;
  }
  .form-control, .form-select {
    font-size: 0.9rem;
    padding: 0.5rem 0.75rem;
  }
  .btn {
    font-size: 0.9rem;
    padding: 0.5rem 1rem;
  }
  .nav-tabs {
    font-size: 0.9rem;
  }
  .nav-tabs .nav-link {
    padding: 0.5rem 0.75rem;
  }
  .btn-group {
    flex-direction: column;
    width: 100%;
  }
  .btn-group .btn {
    border-radius: 0.375rem !important;
    margin-bottom: 0.25rem;
  }
  .btn-group .btn:first-child {
    border-top-left-radius: 0.375rem !important;
    border-top-right-radius: 0.375rem !important;
    border-bottom-left-radius: 0 !important;
    border-bottom-right-radius: 0 !important;
  }
  .btn-group .btn:last-child {
    border-top-left-radius: 0 !important;
    border-top-right-radius: 0 !important;
    border-bottom-left-radius: 0.375rem !important;
    border-bottom-right-radius: 0.375rem !important;
    margin-bottom: 0;
  }
  .dropdown-menu {
    width: 100%;
    max-width: none;
    border-radius: 0.375rem;
    margin-top: 0.25rem;
  }
  .dropdown-item {
    padding: 0.75rem 1rem;
    font-size: 0.9rem;
  }
  .pagination .page-link {
    padding: 0.5rem 0.75rem;
    font-size: 0.9rem;
    min-width: 44px;
    text-align: center;
  }
  .container {
    padding-left: 0.5rem;
    padding-right: 0.5rem;
  }
  .d-flex.gap-2 {
    gap: 0.75rem !important;
  }
  .btn-apply, .btn-clear {
    flex: 1;
    min-width: 0;
  }
  .offcanvas-body h6 {
    font-size: 0.9rem;
    margin-bottom: 0.25rem;
  }
  .offcanvas-body h4 {
    font-size: 1.25rem;
    margin-bottom: 0.75rem;
  }
  .offcanvas-body .alert {
    padding: 0.5rem;
    margin-bottom: 0.75rem;
    font-size: 0.9rem;
  }
  .offcanvas-body .alert i {
    font-size: 0.9rem;
  }
  .filters-section {
    padding: 0.75rem;
    border-radius: 8px;
  }
  .filter-row .form-label {
    font-size: 0.8rem;
  }
  .main-header p {
    font-size: 0.9rem;
  }
  .filters-header h5 {
    font-size: 1rem;
  }
  .offcanvas {
    width: 100% !important;
    max-width: 100% !important;
  }
  .table-controls {
    flex-direction: column;
    gap: 1rem;
    align-items: stretch;
  }
  .table-controls .d-flex {
    flex-direction: column;
    gap: 0.5rem;
  }
  .form-check {
    margin-bottom: 0.5rem;
  }
  .form-check:last-child {
    margin-bottom: 0;
  }
  .filter-row {
    margin-bottom: 0.75rem;
  }
  .filter-row:last-child {
    margin-bottom: 0;
  }
  .form-check.form-switch {
    margin-bottom: 0.75rem;
  }
  .form-select.form-select-sm {
    margin-bottom: 0.75rem;
  }
  #autoRefreshLoader {
    margin-bottom: 0.75rem;
  }
  .text-muted {
    font-size: 0.8rem;
    line-height: 1.4;
  }
}

/* ------------------------------------------------------------------------ *
 * Навигация: нижняя панель
 *
 * Семь пунктов в один ряд занимали 531 px — это и был ЕДИНСТВЕННЫЙ источник
 * горизонтального скролла на 375 px, одинаковый на всех семи страницах.
 * Таблицы к нему отношения не имели: они лежат в контейнере со своим скроллом.
 *
 * Панель делается ТЕМ ЖЕ <ul class="nav-tabs">, а не новым списком. Вся
 * логика навигации — активная вкладка (keycloak-init.js:850), права
 * (applyTabPermissions), отслеживание кликов — выбирает пункты по
 * `a[href="…"]` внутри `.nav-tabs`. Дубликат пунктов давал бы по два
 * совпадения на каждый селектор и молча ломал бы подсветку активной вкладки.
 *
 * Спека предлагала «ещё» для лишних разделов — не делаем по той же причине:
 * «ещё» это второй набор ссылок. Вместо него панель прокручивается по
 * горизонтали, и только у админов, у которых пунктов семь, а не пять.
 * ------------------------------------------------------------------------ */
@media (max-width: 767.98px) {
  /* Бренд остаётся: раньше его прятали, потому что место занимали семь
     пунктов меню. Пункты уехали вниз, и без бренда верхняя полоса была
     просто пустой навигационной плашкой в 44 px. */
  .main-header .header-brand { display: flex; }

  .main-header .nav-tabs {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1030;
    display: flex;
    flex-wrap: nowrap;
    gap: 0;
    margin: 0;
    padding: 0;
    border: 0;
    border-top: 1px solid var(--border);
    background: var(--surface);
    /* Панель прокручивается, когда пунктов больше пяти. Полосу прокрутки
       прячем: у нижней панели она читается как поломка, а не как подсказка. */
    overflow-x: auto;
    scrollbar-width: none;
    /* Вырез на айфонах: без этого панель уезжает под системную полосу. */
    padding-bottom: env(safe-area-inset-bottom, 0);
  }
  .main-header .nav-tabs::-webkit-scrollbar { display: none; }

  /* Панель стоит выше бутстраповского z-index выпадающих меню (1000), и
     длинный список колонок уезжал под неё нижней частью — некликабельной. */
  .dropdown-menu { z-index: 1031; }

  .main-header .nav-tabs .nav-item {
    flex: 1 0 auto;
    min-width: 68px;
  }

  .main-header .nav-tabs .nav-link {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.15rem;
    /* 44 px — критерий готовности слоя: минимальный тач-таргет. */
    min-height: 52px;
    padding: 0.35rem 0.25rem;
    border: 0;
    border-radius: 0;
    font-size: 0.6rem;
    line-height: 1.1;
    text-align: center;
    white-space: nowrap;
    /* !important здесь не украшение. base.css:162 задаёт пунктам шапки белый
       с !important — он рассчитан на navy-фон верхней полосы. Панель стоит на
       обычном фоне страницы, и унаследованный белый давал белое по белому:
       пункты были на месте, кликались, но их не было видно. Перебить
       !important можно только !important. */
    color: var(--text-muted) !important;
    background: transparent;
    border-bottom: 0 !important;
  }
  .main-header .nav-tabs .nav-link:hover,
  .main-header .nav-tabs .nav-link:focus-visible {
    color: var(--text) !important;
    background: var(--surface-sunk);
  }

  /* Иконка на узком экране НУЖНА: подпись ужата до 0.6rem, и иконка несёт
     половину смысла. base.css прятал её — это правило оттуда и переехало. */
  .main-header .nav-tabs .nav-link i {
    display: inline-block;
    margin: 0;
    font-size: 1.05rem;
  }

  /* Длинная подпись заменяется короткой: «1. Активы по потенциалу роста» в
     панель не помещается ни при каком кегле. */
  .main-header .nav-tabs .nav-link .nav-label { display: none; }
  .main-header .nav-tabs .nav-link::after { content: attr(data-short); }

  .main-header .nav-tabs .nav-link.active,
  .main-header .nav-tabs .nav-link.active:hover {
    color: var(--brand-ink) !important;
    background: var(--surface-accent);
    /* Активный раздел помечается сверху: снизу у панели край экрана, и
       нижняя черта из base.css там просто не видна. */
    box-shadow: inset 0 2px 0 var(--brand-ink);
    font-weight: 600;
  }

  /* Место под панель, иначе она накрывает последнюю строку таблицы и
     закреплённые снизу действия модалок. */
  /* Панель — это 52 px плюс вырез плюс бордюр. Без env() на айфонах она
     накрывала последние строки таблицы и пагинацию. */
  body { padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px)); }
}

/* ------------------------------------------------------------------------ *
 * Таблицы: приоритетные колонки и раскрытие
 *
 * Приоритет объявлен на заголовке, ui/mobile-tables.js переносит его на
 * ячейки. Раньше это делали два независимых списка позиций, которые разошлись
 * — см. комментарий в mobile-tables.js.
 *
 * Строка становится сеткой, а не стопкой: приоритетные ячейки остаются в один
 * ряд, и колонки соседних строк выравниваются друг под другом. Ради этого
 * выравнивания таблица и нужна — карточки его разрушают.
 * ------------------------------------------------------------------------ */
@media (max-width: 767.98px) {
  table[data-mobile="priority"] {
    /* Ширина по экрану: min-width из планшетных правил здесь мешает. */
    min-width: 0;
    width: 100%;
  }

  /* Табличная раскладка отключается целиком.
     Строка-сетка внутри display:table считается ненадёжно: браузер продолжает
     мерить колонки по табличному алгоритму, и ячейки уезжают за экран. */
  table[data-mobile="priority"],
  table[data-mobile="priority"] > thead,
  table[data-mobile="priority"] > tbody {
    display: block;
  }

  table[data-mobile="priority"] thead th:not([data-priority]),
  table[data-mobile="priority"] tbody tr:not(.table-placeholder) td:not([data-priority]) {
    display: none;
  }

  /* Заглушка «данных нет» и сообщение об ошибке — одна ячейка на всю ширину.
     Приоритета у неё нет, и общее правило её прятало: пользователь ставил
     фильтр без совпадений и видел просто пустую таблицу, без объяснения. */
  table[data-mobile="priority"] tbody tr.table-placeholder,
  table[data-mobile="priority"] tbody tr.table-placeholder td {
    display: block;
    width: 100%;
  }

  table[data-mobile="priority"] thead tr,
  table[data-mobile="priority"] tbody tr:not(.table-placeholder) {
    display: grid;
    /* Место под кнопку раскрытия резервирует СТРОКА, а не ячейка.
       Пока кнопка стояла внутри ячейки, она отъедала у неё 44 px: в алертах
       это был тикер, и от «SBER» оставалось «SB…». Отступ строки уменьшает
       дорожки все сразу и поровну. */
    position: relative;
    padding-right: 46px;
    /* Дорожки задаёт скрипт: их ширина зависит от приоритета колонки, а не
       делится поровну — иначе главная колонка ужимается наравне со
       второстепенными. */
    grid-template-columns: var(--mobile-tracks, minmax(0, 1fr) minmax(0, 1fr));
    align-items: center;
    gap: 0 0.5rem;
  }

  table[data-mobile="priority"] thead th[data-priority],
  table[data-mobile="priority"] td[data-priority] {
    /* Контекст позиционирования кнопки — строка, а не ячейка: см. выше. */
    position: static;
    /* min-width из десктопных правил (index.html держал 80-200 px на колонку)
       не даёт ячейке ужаться: дорожка сетки становится 97 px, а сама ячейка
       остаётся 200 и вылезает за неё. Ширину задаёт сетка, а не ячейка. */
    min-width: 0;
    max-width: 100%;
    /* Приоритетные ячейки держатся в ПЕРВОЙ строке сетки явно.
       В разметке они идут вперемешку со скрытыми (symbol, name, exchange,
       type, current_price, …), и при раскрытии полноширинная ячейка «Name»
       выталкивала current_price на следующую строку — ряд рассыпался. */
    grid-row: 1;
    /* Длинное значение переносится, а не обрезается многоточием.
       Дата «07.09.2026, 13:00:00» в узкую дорожку не влезает ни при каком
       распределении ширин, а приоритетная колонка в раскрытии не
       повторяется — обрезав её, мы бы потеряли значение совсем. Две строки
       на мобильном экране дешевле потерянных данных. */
    overflow: hidden;
    white-space: normal;
    overflow-wrap: anywhere;
    padding: 0.6rem 0.4rem;
  }

  /* Раскрытые поля: пара «подпись: значение». Подпись берётся из data-label,
     который ui/table.js ставит на каждую ячейку при отрисовке. */
  /* Специфичность подогнана под правило скрытия выше: у того четыре типа и
     три класса/атрибута, и без `tbody` + `:not(.table-placeholder)` оно
     перебивало раскрытие — строка помечалась развёрнутой, а поля не
     показывались. */
  table[data-mobile="priority"] tbody tr.is-expanded:not(.table-placeholder) td:not([data-priority]) {
    display: grid;
    grid-column: 1 / -1;
    /* Подписи выровнены в колонку: раздельная ширина на каждую строку делала
       раскрытый блок рваным. */
    grid-template-columns: 8.5rem minmax(0, 1fr);
    gap: 0 0.5rem;
    align-items: baseline;
    padding: 0.35rem 0.4rem;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    border-top: 1px dashed var(--border-subtle);
    text-align: left;
    /* Явный фон: зебра таблицы красила раскрытые строки полосами разной
       ширины, и блок читался как набор разных таблиц. */
    background: var(--surface);
  }
  table[data-mobile="priority"] tbody tr.is-expanded:not(.table-placeholder) td:not([data-priority])::before {
    content: attr(data-label);
    color: var(--text-muted);
    font-size: 0.75rem;
  }
  table[data-mobile="priority"] tbody tr.is-expanded:not(.table-placeholder) td:not([data-priority]) > * {
    min-width: 0;
  }
  /* Ячейка без подписи (колонка действий) занимает всю ширину сама. */
  table[data-mobile="priority"] tr.is-expanded td[data-label=""]::before { content: none; }

  .mobile-expand {
    position: absolute;
    display: flex;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    /* 44 px — критерий готовности слоя. */
    min-width: 44px;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: var(--text-muted);
  }
  .mobile-expand i { transition: transform 0.15s; }
  tr.is-expanded .mobile-expand i { transform: rotate(180deg); }

  /* Отступа под кнопку у ячейки-хозяина БЫТЬ НЕ ДОЛЖНО.
     Кнопка позиционируется абсолютно относительно СТРОКИ, и место под неё
     строка уже отвела своим padding-right. Второй отступ на ячейке отнимал
     46 px повторно: колонка цены получала 81 px дорожки минус 46 минус 6.4
     собственного padding — 28 px под текст, и «113.43» разрывалось на
     «113.4» и «3». Ячейка-хозяин — наименее важная из показанных, то есть
     как раз числовая. */
}

@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
  .mobile-expand i { transition: none; }
}

/* ------------------------------------------------------------------------ *
 * Таблицы: карточки
 *
 * Другая форма данных — другой паттерн. У счетов и отчётов админки строк
 * единицы, и каждая строка это самостоятельный объект с десятком полей.
 * Сравнивать их между собой не нужно, а значит и вертикальное выравнивание
 * колонок ничего не даёт: прятать половину полей за тап было бы вредом ради
 * симметрии с алертами.
 *
 * Подписи берутся из data-label, который ui/table.js ставит на каждую ячейку.
 * Поэтому карточки не требуют ни разметки заголовков, ни скрипта.
 * ------------------------------------------------------------------------ */
@media (max-width: 767.98px) {
  table[data-mobile="cards"] {
    min-width: 0;
    width: 100%;
  }
  table[data-mobile="cards"],
  table[data-mobile="cards"] > thead,
  table[data-mobile="cards"] > tbody {
    display: block;
  }

  /* Шапка не нужна: подпись едет вместе со значением. */
  table[data-mobile="cards"] > thead { display: none; }

  table[data-mobile="cards"] > tbody > tr {
    display: block;
    margin-bottom: 0.75rem;
    padding: 0.5rem 0.25rem;
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    background: var(--surface);
  }

  table[data-mobile="cards"] > tbody > tr > td {
    display: grid;
    grid-template-columns: 8.5rem minmax(0, 1fr);
    gap: 0 0.5rem;
    align-items: baseline;
    width: auto;
    padding: 0.3rem 0.5rem;
    border: 0;
    white-space: normal;
    /* text-end/text-nowrap с десктопной строки прижимали значение к правому
       краю ЯЧЕЙКИ, которая в карточке занимает всю ширину, — подпись и
       значение расходились по разным концам экрана. */
    text-align: left !important;
  }
  table[data-mobile="cards"] > tbody > tr > td::before {
    content: attr(data-label);
    color: var(--text-muted);
    font-size: 0.75rem;
  }

  /* Роль крайних колонок объявляется на таблице, а не предполагается.
     У счетов первая колонка это название, последняя — действия. У отчётов
     админки крайние колонки — обычные данные: у «пропущенных позиций» их
     всего две, «Тикер» и «Причина». Без явной разметки причина оставалась бы
     без подписи и с верхней чертой, то есть выглядела бы как ряд кнопок. */
  table[data-card-title="first"] > tbody > tr > td:first-child {
    grid-template-columns: 1fr;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--border-subtle);
    font-weight: 600;
  }
  table[data-card-title="first"] > tbody > tr > td:first-child::before { content: none; }

  /* Колонка действий: подпись «Действия» ничего не добавляет.
     Кнопки идут в ряд, а не столбиком: их до семи, и каждая во всю ширину
     давала карточку длиной в экран, где сам счёт занимал верхнюю треть. */
  table[data-card-actions="last"] > tbody > tr > td:last-child {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    padding-top: 0.6rem;
    border-top: 1px solid var(--border-subtle);
  }
  table[data-card-actions="last"] > tbody > tr > td:last-child::before { content: none; }
  table[data-card-actions="last"] > tbody > tr > td:last-child .btn,
  table[data-card-actions="last"] > tbody > tr > td:last-child button {
    flex: 0 0 auto;
    /* Старый мобильный CSS растягивал `.btn { width: 100% }` на ВСЕ кнопки
       без разбора. Для кнопки «Применить» в панели фильтров это разумно, для
       иконки в строке таблицы — нет: семь иконок превращались в семь полос
       во всю ширину. */
    width: auto;
    /* 44 px — критерий готовности слоя. */
    min-width: 44px;
    min-height: 44px;
    margin: 0;
  }

  /* Группы кнопок в строке таблицы остаются горизонтальными.
     Старый CSS разворачивал ЛЮБУЮ .btn-group в столбец во всю ширину — это
     про группу переключателей в панели фильтров, а не про иконки действий в
     карточке счёта. Пока группа была колонкой со stretch, ширина кнопок всё
     равно тянулась на всю карточку, сколько ни ставь width: auto. */
  table[data-mobile] td .btn-group {
    flex-direction: row;
    width: auto;
  }
  table[data-mobile] td .btn-group .btn { margin-bottom: 0; }

  /* Та же кувалда мешает и в раскрытых строках приоритетных таблиц. */
  table[data-mobile="priority"] tr.is-expanded td .btn,
  table[data-mobile="priority"] td[data-priority] .btn {
    width: auto;
  }

  /* Заглушка «данных нет» остаётся строкой, а не карточкой. */
  table[data-mobile="cards"] > tbody > tr.table-placeholder {
    border: 0;
    background: transparent;
  }
  table[data-mobile="cards"] > tbody > tr.table-placeholder > td { display: block; }
  table[data-mobile="cards"] > tbody > tr.table-placeholder > td::before { content: none; }

  /* Слейв-счёт остаётся визуально вложенным в мастера. */
  table[data-mobile="cards"] > tbody > tr.replication-slave-row {
    margin-left: 1rem;
    border-left: 3px solid var(--border);
  }
}

/* ------------------------------------------------------------------------ *
 * Модальные окна и формы
 *
 * Формы создания счёта, редактирования биржи и создания issue живут в
 * модалках Bootstrap. По умолчанию модалка — это окно с полями по 380 px по
 * ширине, отцентрованное в вязком фоне: на 375 px от неё остаётся полоска с
 * полями в две колонки, а кнопки «Сохранить» и «Отмена» уезжают за нижний край
 * вместе с содержимым.
 *
 * На узком экране модалка занимает экран целиком, поля идут в одну колонку, а
 * действия закреплены снизу и не уезжают при прокрутке формы.
 * ------------------------------------------------------------------------ */
@media (max-width: 767.98px) {
  .modal-dialog {
    max-width: none;
    margin: 0;
    /* Не 100vh: на мобильных браузерах адресная строка съедает часть, и низ
       модалки оказывается под ней. dvh считается по фактической высоте. */
    min-height: 100dvh;
  }
  .modal-content {
    min-height: 100dvh;
    border: 0;
    border-radius: 0;
  }

  .modal-header,
  .modal-footer {
    position: sticky;
    z-index: 2;
    background: var(--surface);
  }
  .modal-header { top: 0; }
  .modal-footer {
    bottom: 0;
    /* Панель навигации остаётся под модалкой, но её место в потоке занято
       padding-bottom у body — модалка о нём не знает. */
    padding-bottom: calc(0.75rem + env(safe-area-inset-bottom, 0px));
  }
  /* Действия в ряд: `.btn { width: 100% }` из старого CSS ставило их
     столбиком, и «Отмена» оказывалась НАД «Сохранить» — обратная иерархия. */
  .modal-footer .btn {
    flex: 1 1 auto;
    width: auto;
    min-height: 44px;
  }

  /* Поля в одну колонку: двухколоночная сетка формы на 375 px даёт поля по
     150 px, в которые не помещается ни дата, ни сумма. */
  .modal-body .row > [class*="col-"] {
    flex: 0 0 100%;
    max-width: 100%;
  }

  /* Всплывающая клавиатура iOS зумит страницу, если у поля кегль меньше 16 px.
     Обратно она её не отматывает: страница остаётся увеличенной, и появляется
     тот самый горизонтальный скролл, от которого слой и избавляется. */
  .modal-body .form-control,
  .modal-body .form-select,
  .form-control,
  .form-select {
    font-size: max(16px, 1rem);
  }
}

@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
  .modal.fade .modal-dialog { transition: none; }
}

/* ------------------------------------------------------------------------ *
 * Тач-таргеты
 *
 * Критерий готовности слоя: всё, что нажимают, не меньше 44 px по короткой
 * стороне. Замер по живым страницам показал 93 нарушения на семи страницах, и
 * все они одного происхождения — бутстраповские `-sm`-варианты: кнопка 40 px,
 * поле 42, чекбокс 16, ссылка-крестик 10×15.
 *
 * Правило `min-height: 44px` для этого уже было — но внутри
 * `@media (hover: none) and (pointer: coarse)`, то есть только для устройств,
 * которые честно сообщают о тач-вводе. Узкое окно на десктопе, эмуляция в
 * девтулзах и часть гибридных устройств под него не попадают, а верстают и
 * проверяют именно там. Здесь тот же порог привязан к ширине.
 * ------------------------------------------------------------------------ */
@media (max-width: 767.98px) {
  .btn,
  .btn-sm,
  .form-control,
  .form-control-sm,
  .form-select,
  .form-select-sm,
  .nav-link,
  .dropdown-item,
  .sidebar-link,
  [role="button"] {
    min-height: 44px;
  }

  /* Ссылка-иконка (крестик «очистить фильтр») — 10×15 в разметке.
     Область нажатия растягивается псевдоэлементом, а не размерами самой
     ссылки: 44 px по ширине разрывали строку «Страна ✕ бейдж» — крестик
     уезжал под подпись вместе с бейджем, и панель фильтров вытягивалась на
     полтора экрана. Псевдоэлемент места в раскладке не занимает. */
  a.text-muted.ms-1,
  a.text-muted.ms-2,
  .col-close {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  a.text-muted.ms-1::after,
  a.text-muted.ms-2::after,
  .col-close::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    /* 32, а не 44.
       Эти крестики стоят ВНУТРИ подписи поля, вплотную к её тексту и к
       соседнему бейджу. Область в 44 px накрыла бы соседей — нажатие рядом с
       подписью очищало бы фильтр. WCAG 2.5.8 задаёт минимум 24 px и отдельно
       оговаривает случай достаточного разнесения; 32 даёт запас над этим
       минимумом, не залезая на соседей.
       Для самостоятельных элементов управления — кнопок, полей, пунктов
       панели — порог остаётся 44. */
    width: 32px;
    height: 32px;
    transform: translate(-50%, -50%);
  }

  /* Флажок и радиокнопка остаются флажком: раздутый до 44 px квадрат выглядит
     поломкой. Цель нажатия даёт обёртка вместе с подписью — по ней и
     нажимают. */
  .form-check {
    display: flex;
    align-items: center;
    min-width: 44px;
    min-height: 44px;
  }
  .form-check-input {
    min-width: 24px;
    min-height: 24px;
  }
  .form-check-label { padding-left: 0.25rem; }

  /* Ссылки в тексте под критерий не подпадают: это не элементы управления,
     а часть абзаца, и растягивать их до 44 px значит ломать строку. */
  p a, li a, .alert a { min-height: 0; }
}

/* ------------------------------------------------------------------------ *
 * Планшет: ограничение правил, пришедших со страницы алертов
 *
 * Блок ≤991.98 собран из alerts.html, где он и жил. До сборки его не было ни
 * у одной другой страницы — у справочников, пользователей, счетов и админки
 * мобильного CSS не было вовсе. Подключив mobile.css везде, мы раздали им
 * `.btn { width: 100% }` и `.table { min-width: 900px }`, рассчитанные на одну
 * конкретную страницу.
 *
 * Противоядия из мобильного блока на планшете не работают: они начинаются с
 * 767.98. Поэтому те же исключения повторены здесь.
 * ------------------------------------------------------------------------ */
@media (max-width: 991.98px) {
  /* Иконки действий в строке таблицы не растягиваются во всю ширину. */
  table td .btn,
  table td .btn-group,
  table td button {
    width: auto;
  }
  table td .btn-group { flex-direction: row; }

  /* Ширину таблицы задаёт её содержимое, а не число из чужой страницы. */
  table[data-mobile] { min-width: 0; }

}

/* Шапка на планшете остаётся строкой, но компактной.
 *
 * Правило переехало из base.css, где стояло на `max-width: 768px`
 * ВКЛЮЧИТЕЛЬНО. Нижняя панель начинается с 767.98, и без него ровно на 768 px
 * — портретный iPad — не было ни компактной шапки, ни панели: семь пунктов
 * занимали 918 px при экране в 768.
 *
 * Нижняя граница задана явно: этот блок стоит в файле ПОСЛЕ мобильного, и без
 * `min-width` он перебивал бы его правила на 375 px — прятал бренд и иконки в
 * панели. */
@media (min-width: 768px) and (max-width: 991.98px) {
  .main-header .header-brand { display: none; }
  .main-header .nav-tabs .nav-link {
    padding: 0 0.6rem;
    font-size: 0.78rem;
  }
  .main-header .nav-tabs .nav-link i { display: none; }
}

/* ------------------------------------------------------------------------ *
 * Плотность: отступы на узком экране
 *
 * Замер на 375 px показал, что до содержимого таблицы доходит 251 px из 375 —
 * остальное съедают вложенные отступы карточек:
 *
 *   .container-fluid   48 px
 *   .filters-section   34 px
 *   .table-container   42 px
 *
 * Это 33% ширины экрана, потраченные на воздух между рамками, вложенными одна
 * в другую. На десктопе такая раскладка читается как воздух, на телефоне — как
 * причина, по которой тикер приходится сокращать до «SB…».
 *
 * Отступы не убираются в ноль: рамка карточки должна оставаться различимой.
 * ------------------------------------------------------------------------ */
@media (max-width: 767.98px) {
  .container-fluid {
    padding-left: 0.5rem;
    padding-right: 0.5rem;
  }

  .filters-section,
  .table-container,
  .accounts-container {
    padding: 0.5rem;
  }

  /* Вложенная карточка внутри такой же карточки удваивает отступ, ничего не
     добавляя: рамки идут одна в одной. */
  .table-container .table-responsive,
  .filters-section .table-container {
    padding-left: 0;
    padding-right: 0;
  }
}

/* ------------------------------------------------------------------------ *
 * Остатки, найденные обходом на 375 px
 * ------------------------------------------------------------------------ */
@media (max-width: 767.98px) {
  /* Комментарий счёта обрезался многоточием прямо в карточке, где ширины
     хватает: класс col-truncate рассчитан на узкую колонку таблицы. */
  table[data-mobile="cards"] .col-truncate {
    max-width: none;
    overflow: visible;
    white-space: normal;
    text-overflow: clip;
  }

}
