/* ============================================================
   CoEx Design System — overrides on top of Bootstrap 5
   See docs/DESIGN_SYSTEM.md for full spec
   FIR-42 #343 — multi-leg office/currency cols → VARCHAR
   FIR-42 #340 — staff users page fast-path (skip broker/refovod joins)
   ============================================================ */

:root {
  /* Ink */
  --ink: #0a0a0a;
  --ink-2: #525252;
  --ink-3: #737373;
  --ink-4: #a3a3a3;

  /* Surfaces */
  --bg: #ffffff;
  --bg-2: #fafafa;
  --bg-3: #f5f5f5;

  /* Lines */
  --line: #e7e7e7;
  --line-strong: #d4d4d4;

  /* Accent */
  --accent: #5e6ad2;
  --accent-soft: #eef0fb;
  --accent-hover: #4d59c5;

  /* Signal */
  --ok: #16a34a;
  --warn: #d97706;
  --bad: #dc2626;

  /* Type */
  --sans: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Radius */
  --r-sm: 4px;
  --r: 6px;
  --r-lg: 8px;

  /* Bootstrap overrides */
  --bs-body-font-family: var(--sans);
  --bs-body-color: var(--ink);
  --bs-body-bg: var(--bg);
  --bs-body-font-size: 14px;
  --bs-body-line-height: 1.4;
  --bs-border-color: var(--line);
  --bs-border-radius: var(--r);
  --bs-border-radius-sm: var(--r-sm);
  --bs-border-radius-lg: var(--r-lg);
  --bs-primary: var(--accent);
  --bs-primary-rgb: 94, 106, 210;
  --bs-link-color: var(--accent);
  --bs-link-hover-color: var(--accent-hover);
  --bs-secondary-color: var(--ink-3);
  --bs-tertiary-bg: var(--bg-2);
}

/* ---------- Base ---------- */
html, body {
  font-family: var(--sans);
  color: var(--ink);
  background: var(--bg);
  font-size: 14px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--sans);
  letter-spacing: -0.01em;
  color: var(--ink);
}
h1 { font-size: 22px; font-weight: 600; letter-spacing: -0.015em; }
h2 { font-size: 18px; font-weight: 600; }
h3 { font-size: 15px; font-weight: 600; }
h4, .h4 { font-size: 14px; font-weight: 600; }
h5 { font-size: 13px; font-weight: 600; }

/* All numeric values default to tabular */
input[type="number"], input.num, td.num, .tabular {
  font-feature-settings: 'tnum' 1;
  font-variant-numeric: tabular-nums;
}

/* ---------- Bootstrap component overrides ---------- */

/* Buttons */
.btn {
  --bs-btn-padding-y: 6px;
  --bs-btn-padding-x: 12px;
  --bs-btn-font-size: 13px;
  --bs-btn-font-weight: 500;
  --bs-btn-border-radius: var(--r);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  line-height: 1.4;
}
.btn-primary {
  --bs-btn-bg: var(--accent);
  --bs-btn-border-color: var(--accent);
  --bs-btn-hover-bg: var(--accent-hover);
  --bs-btn-hover-border-color: var(--accent-hover);
  --bs-btn-active-bg: var(--accent-hover);
  --bs-btn-active-border-color: var(--accent-hover);
  --bs-btn-disabled-bg: var(--accent);
  --bs-btn-disabled-border-color: var(--accent);
  color: #fff;
}
.btn-outline-secondary,
.btn-secondary {
  --bs-btn-color: var(--ink);
  --bs-btn-bg: #fff;
  --bs-btn-border-color: var(--line-strong);
  --bs-btn-hover-bg: var(--bg-2);
  --bs-btn-hover-border-color: var(--line-strong);
  --bs-btn-hover-color: var(--ink);
  --bs-btn-active-bg: var(--bg-3);
  --bs-btn-active-border-color: var(--line-strong);
  --bs-btn-active-color: var(--ink);
}
.btn-ghost {
  --bs-btn-color: var(--ink-2);
  --bs-btn-bg: transparent;
  --bs-btn-border-color: transparent;
  --bs-btn-hover-bg: var(--bg-3);
  --bs-btn-hover-color: var(--ink);
  --bs-btn-hover-border-color: transparent;
}

/* Disabled inputs — muted but not blue */
.form-control:disabled,
.form-control[readonly],
.form-select:disabled {
  background: var(--bg-2) !important;
  color: var(--ink-3) !important;
  cursor: not-allowed;
  border-color: var(--line);
  opacity: 1;
}

/* Select2 — make it match our form-control style, no purple/lavender chrome */
.select2-container .select2-selection--single,
.select2-container .select2-selection--multiple {
  border: 1px solid var(--line) !important;
  border-radius: var(--r) !important;
  background: #fff !important;
  min-height: 34px !important;
  height: auto !important;
  padding: 3px 8px !important;
  font: inherit !important;
  font-size: 14px !important;
  color: var(--ink) !important;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
  color: var(--ink) !important;
  line-height: 26px !important;
  padding-left: 0 !important;
  padding-right: 20px !important;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
  height: 32px !important;
  top: 0 !important;
}
.select2-container--default .select2-selection--single .select2-selection__placeholder,
.select2-container--default .select2-selection--multiple .select2-selection__placeholder {
  color: var(--ink-4) !important;
}
.select2-container--default.select2-container--focus .select2-selection--multiple,
.select2-container--default.select2-container--focus .select2-selection--single {
  border-color: var(--accent) !important;
  box-shadow: 0 0 0 3px rgba(94, 106, 210, 0.15) !important;
}
/* Disabled select2 wrapper (when underlying <select> is disabled) */
.select2-container--disabled .select2-selection--single,
.select2-container--disabled .select2-selection--multiple,
select:disabled + .select2-container .select2-selection--single,
select:disabled + .select2-container .select2-selection--multiple {
  background: var(--bg-2) !important;
  border-color: var(--line) !important;
  color: var(--ink-3) !important;
  cursor: not-allowed;
}
.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__rendered,
.select2-container--default.select2-container--disabled .select2-selection--multiple .select2-selection__rendered {
  color: var(--ink-3) !important;
}
.select2-dropdown {
  border: 1px solid var(--line) !important;
  border-radius: var(--r) !important;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08) !important;
}
/* Select2 results — палитра состояний option.
   ЯКОРЬ FIR-48 #60: highlighted (hover/keyboard) НЕ красим в var(--accent)
   и в любой насыщенный бренд-цвет. Select2 — глобальный компонент: одно
   правило ломает дропдауны по ВСЕМУ проекту разом (фильтры, формы операций,
   справочники). Selected и hover должны быть визуально различимы — иначе
   пользователь не видит, что он уже выбрал.
   Контракт: hover = нейтральный серый (--bg-3), selected = белый + левая
   2px-полоска var(--accent) + bold, combined = серый + полоска + bold. */

/* HOVER / клавиатурная навигация — нейтральная серая подложка, текст-чернила */
.select2-container--default .select2-results__option--highlighted,
.select2-container--default .select2-results__option--highlighted[aria-selected] {
  background: var(--bg-3) !important;   /* #f5f5f5 — самый светлый "пресс" из темы */
  color: var(--ink) !important;          /* #0a0a0a — основной текст */
  font-weight: 400 !important;
}

/* SELECTED — уже выбранный пункт. Маркер: левая акцент-полоса 2px +
   жирность шрифта. Фон остаётся белым, чтобы НЕ конкурировать с hover. */
.select2-container--default .select2-results__option[aria-selected="true"] {
  background: #fff !important;
  color: var(--ink) !important;
  font-weight: 600 !important;
  box-shadow: inset 2px 0 0 0 var(--accent) !important;
}

/* SELECTED + HOVER (курсор поверх уже выбранного) — комбинация:
   серая подложка от hover + акцент-полоса и жирный шрифт от selected.
   Различимо от обоих чистых состояний. */
.select2-container--default .select2-results__option--highlighted[aria-selected="true"] {
  background: var(--bg-3) !important;
  color: var(--ink) !important;
  font-weight: 600 !important;
  box-shadow: inset 2px 0 0 0 var(--accent) !important;
}
/* FIR-48 #71 — строка поиска в дропдауне Select2 (.make-select2-with-search).
   До фикса: border:0, outline:0, без placeholder, без иконки — пользователь
   не видит, что внутри dropdown можно печатать. Возвращаем видимую рамку
   в стиле form-control, единый placeholder «Поиск…» (инжектится JS-ом
   на select2:open — см. scripts.js), и SVG-иконку лупы фоном слева. */
.select2-container--default .select2-search--dropdown {
  padding: 8px !important;
}
.select2-container--default .select2-search--dropdown .select2-search__field {
  width: 100% !important;
  box-sizing: border-box !important;
  border: 1px solid var(--line) !important;
  border-radius: var(--r) !important;
  background: #fff
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23a3a3a3'><path d='M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z'/></svg>")
    no-repeat 10px center !important;
  background-size: 14px 14px !important;
  padding: 6px 10px 6px 32px !important;
  font-size: 14px !important;
  line-height: 1.4 !important;
  color: var(--ink) !important;
  outline: 0 !important;
  transition: border-color .12s, box-shadow .12s;
}
.select2-container--default .select2-search--dropdown .select2-search__field::placeholder {
  color: var(--ink-4) !important;
  opacity: 1 !important;
}
.select2-container--default .select2-search--dropdown .select2-search__field:focus {
  border: 1px solid var(--accent) !important;
  box-shadow: 0 0 0 3px rgba(94, 106, 210, 0.15) !important;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice {
  background: var(--bg-3) !important;
  border: 1px solid var(--line) !important;
  color: var(--ink) !important;
  border-radius: var(--r-sm) !important;
  padding: 2px 8px !important;
  font-size: 12.5px !important;
  /* FIR-42 #202/#204 — выравниваем X-крестик и текст по центру chip-а,
     а сам chip — по центру строки. До этого padding 1px давал зрительный
     сдвиг крестика наверх (визуально «съезжал»). */
  display: inline-flex !important;
  align-items: center !important;
  gap: 4px;
  line-height: 1.2 !important;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove,
.select2-selection__choice__remove,
span.select2-selection__choice__remove {
  /* FIR-42 #294 v3 — X-крестик в multi-select chip. User жалуется
     несколько раз что крестики не выровнены. Root cause: select2
     рендерит `<span>×</span>` который inline-element с line-height
     наследованным из chip-а, плюс bootstrap-overrides на span. Лечим
     каскадом: убираем все наследства и явно flex-центруем. */
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  width: 18px !important;
  height: 18px !important;
  margin: 0 4px 0 0 !important;
  padding: 0 !important;
  font-size: 14px !important;
  font-weight: 700 !important;
  line-height: 1 !important;
  vertical-align: middle !important;
  color: #555 !important;
  background: transparent !important;
  border: 0 !important;
  text-align: center !important;
  cursor: pointer !important;
}

/* FIR-42 #294 v4 — GLOBAL close-button centering. User: «можно везде
   нахуй крестики выровнять а не только там?». Применяем единый рецепт
   ко ВСЕМ × close-buttons в приложении: modal-header, alert-dismiss,
   toast-close, custom .close-button, .btn-close, и т.п. Всегда
   flex-центровка по обеим осям, фиксированный square box, без
   наследованного line-height/vertical-align. */
.btn-close,
button.btn-close,
.modal-header .btn-close,
.close-button,
.close,
button.close,
[data-bs-dismiss="modal"].btn-close,
[data-bs-dismiss="alert"],
.alert .btn-close,
.toast .btn-close,
.quick-add-cancel,
.coex-close-x,
[aria-label="Close"],
[aria-label="Закрыть"] {
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  vertical-align: middle !important;
  line-height: 1 !important;
  text-align: center !important;
}
/* Bootstrap btn-close (использует SVG background image) — единый
   квадрат 24×24, чтобы крестики во ВСЕХ modal-header / alert
   выглядели одинаково. */
.btn-close {
  width: 24px !important;
  height: 24px !important;
  padding: 6px !important;
  box-sizing: border-box !important;
  background-position: center center !important;
  background-size: 12px 12px !important;
}
/* Legacy text-«×» close buttons (`<button>×</button>`). */
.close-button,
.close,
button.close {
  width: 24px !important;
  height: 24px !important;
  padding: 0 !important;
  font-size: 18px !important;
  font-weight: 700 !important;
  color: var(--ink-3, #6B7280) !important;
  background: transparent !important;
  border: 0 !important;
  cursor: pointer !important;
  opacity: .7;
  transition: opacity .12s;
}
.close-button:hover,
.close:hover,
button.close:hover {
  opacity: 1;
  color: var(--ink) !important;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice {
  display: inline-flex !important;
  align-items: center !important;
  vertical-align: middle !important;
  line-height: 1.2 !important;
  padding: 2px 6px !important;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice > *,
.select2-container--default .select2-selection--multiple .select2-selection__choice .select2-selection__choice__display {
  vertical-align: middle !important;
  line-height: 1.2 !important;
}

/* FIR-49 #23 round 2: дублирующий FIR-43 #8 блок удалён — единый источник правды
   для переноса длинных имён касс живёт в style.css (FIR-49 #23). Логика та же
   (white-space:normal + word-break), но без двух конкурирующих правил с
   разными line-height (15px vs 1.25), которые мешали мерджу. */

/* FIR-49 #32 — контрагент на форме долговой операции (#agent, users-select).
   Select2 по умолчанию обрезает rendered-значение через overflow:hidden+ellipsis;
   длинные имена (например «Иванов Иван Иванович») не видны целиком в узкой колонке.
   Разрешаем перенос — аналог правила boxes-select выше. Только #agent, не глобально. */
select#agent + .select2-container .select2-selection--single .select2-selection__rendered {
  white-space: normal !important;
  overflow-wrap: anywhere !important;
  line-height: 15px !important;
  padding-top: 3px !important;
  padding-bottom: 3px !important;
}

/* FIR-42 #295 — поддержка soft-hyphen (&shy;) в form-labels и sidebar-метках.
   Браузер сам решит, переносить слово или нет, на основе доступной ширины.
   Без hyphens:manual браузер игнорирует &shy;. */
.form-label,
.coex-page-title h1,
.sidebar .nav-link,
.list-group-item {
  hyphens: manual;
  -webkit-hyphens: manual;
  -ms-hyphens: manual;
}

/* FIR-42 #291 — z-index alert-container выше modal (1055+), чтобы тосты
   об ошибках удаления / сохранения были видны поверх открытой модалки.
   Раньше alert просто терялся за backdrop-ом, и пользователь думал «click
   ничего не делает». */
#alert-container {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 2000;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
#alert-container .alert {
  pointer-events: auto;
  box-shadow: 0 6px 24px rgba(0,0,0,0.15);
}

/* FIR-42 #292 — type-to-confirm input в delete-modal-е. Слегка крупнее
   обычного inputа, чтобы пользователь визуально понял что от него ждут
   text-input, а не просто прочитал заголовок. */
.coex-delete-confirm-input {
  font-family: var(--mono, ui-monospace, SFMono-Regular, monospace);
  font-size: 14px;
}
.coex-delete-phrase {
  font-family: var(--mono, ui-monospace, SFMono-Regular, monospace);
  color: var(--bad);
  background: rgba(192, 57, 43, 0.07);
  padding: 1px 6px;
  border-radius: 4px;
  user-select: all;
  word-break: break-word;
}
.coex-delete-mismatch {
  display: block;
  color: var(--bad);
  font-size: 12px;
  margin-top: 4px;
}
/* delete-modal крестик-close — small dialog, lift sm-only-class. */
.delete-modal-dialog .modal-body {
  padding-top: 0;
}

/* Inputs / form-control */
.form-control,
.form-select {
  font-size: 14px;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  color: var(--ink);
  transition: border-color .12s, box-shadow .12s;
}

/* Suppress Chrome/Edge autofill yellow/blue background */
.form-control:-webkit-autofill,
.form-control:-webkit-autofill:hover,
.form-control:-webkit-autofill:focus,
.form-control:-webkit-autofill:active {
  -webkit-text-fill-color: var(--ink);
  -webkit-box-shadow: 0 0 0 1000px #fff inset;
  box-shadow: 0 0 0 1000px #fff inset;
  caret-color: var(--ink);
  transition: background-color 99999s ease-in-out 0s;
}
.form-control::placeholder { color: var(--ink-4); }
.form-control:focus,
.form-select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(94, 106, 210, 0.15);
  outline: 0;
}
.form-control.is-valid {
  border-color: var(--ok);
  box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.12);
}
/* FIR-55 #3 (баг 1147) — зелёная рамка сходящейся выдачи перебивалась
   theme-metis/bootstrap (галка была, рамки нет). Поднимаем специфичность
   как в грабле CSS-специфичности (.coex-app + !important). */
.coex-app .form-control.is-valid,
.coex-app input.form-control.is-valid {
  border-color: var(--ok) !important;
  box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.12) !important;
}
.form-control.is-invalid {
  border-color: var(--bad);
  box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.12);
}
.form-control.num,
.form-control[type="number"] {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}
.form-label {
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-3);
  font-weight: 500;
  margin-bottom: 5px;
}
.form-text {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 5px;
}

/* Card */
.card {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: #fff;
  box-shadow: none;
}
.card-header,
.card-head {
  padding: 14px 18px;
  border-bottom: 1px solid var(--line);
  background: transparent;
}
.card-header h1, .card-header h2, .card-header h3 { margin: 0; }
.card-body { padding: 18px; }

/* Table */
.table {
  --bs-table-bg: transparent;
  --bs-table-border-color: var(--line);
  --bs-table-color: var(--ink);
  --bs-table-hover-bg: var(--bg-2);
  --bs-table-hover-color: var(--ink);
  font-size: 13.5px;
  margin-bottom: 0;
}
.table > thead > tr > th,
.table thead th {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-3);
  padding: 10px 14px;
  background: var(--bg-2);
  border-bottom: 1px solid var(--line);
  border-top: 0;
  vertical-align: middle;
}
.table > tbody > tr > td,
.table tbody td {
  padding: 11px 14px;
  border-bottom: 1px solid var(--line);
  border-top: 0;
  vertical-align: middle;
  color: var(--ink);
}
.table > tbody > tr:last-child > td { border-bottom: 0; }
.table-hover > tbody > tr:hover > td { background: var(--bg-2); }
.table .num,
.table td.num,
.table th.num {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
/* FIR-48 #9 v2 — компактная таблица на /admin/balances/ для влезания
   10 колонок без горизонтального скролла. Шрифт заголовков 9.5px,
   padding меньше, числа 12.5px вместо 13.5. */
.table.coex-balances-compact > thead > tr > th,
.table.coex-balances-compact thead th {
  font-size: 9.5px;
  padding: 8px 8px;
  letter-spacing: 0.04em;
}
.table.coex-balances-compact > tbody > tr > td,
.table.coex-balances-compact tbody td {
  padding: 8px 8px;
  font-size: 12.5px;
}
.table.coex-balances-compact .num {
  white-space: nowrap;
}

/* FIR-48 #5 — колонка ID операций всегда по центру (а не right-aligned
   как остальные числа). Без правки числа «съезжают» вправо особенно
   когда у соседнего ID есть ✏️-badge правок и колонка растягивается. */
.table th.op-id,
.table td.op-id {
  text-align: center;
}
/* FIR-48 #17 — «Принял зелёным, Отдал красным» во всех таблицах с этими
   колонками (журнал «Все операции» на /admin/operations/ и operator-аналог
   через partials/operations_table.php). Спокойные, не «радужные» оттенки:
   получили (in) — приглушённый зелёный, отдали (out) — приглушённый красный.
   Только цвет текста, без громких фоновых заливок. Применяется и к header-
   ячейкам (<th>), и к значениям сумм в <td>.
   FIR-48 #17 v2 — фикс «цвет не появлялся»: общие табличные правила
   `.table thead th` (color:var(--ink-3), spec 0,1,2),
   `.table > tbody > tr > td` (color:var(--ink), spec 0,1,3) и
   `#data-table-wrp .table thead th` (color:var(--ink-3), spec 1,1,2)
   перебивали `.amt-in/.amt-out` (spec 0,1,0) по каскаду — поэтому
   суммы/заголовки оставались чёрными. Утилита-класс существует
   исключительно ради цвета, поэтому помечаем !important — выигрывает
   над всеми табличными color-правилами независимо от их специфичности.
   Пустые ячейки рендерят «—» в собственном <span class="text-muted">,
   у которого свой color, так что плейсхолдеры остаются серыми. */
.amt-in  { color: #15803d !important; }
.amt-out { color: #b42318 !important; }
.table td.muted { color: var(--ink-3); }
.table td.tag,
.table .op-tag {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink);
}

.table-wrap {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  /* FIR-48 #50 — было overflow:hidden → при таблице шире контейнера последняя
     колонка обрезалась «насухо» посередине, давая рваный «дизайнерский артефакт»
     у правого края (виден в «Все операции» на узких окнах). Горизонтальный скролл
     даёт чистый край вместо обрубка; вертикаль скрыта для скруглений. */
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  background: #fff;
}

/* FIR-48 #50 — «Все операции» должна влезать БЕЗ горизонтального скролла
   (юзер: «не хочу скролл — сокращай расстояние между столбцами, уменьшай шрифт
   даты/времени, сокращай рефовод»). Плотнее колонки + компактная дата. */
.coex-app .table-wrap .table.coex-ops-fit th,
.coex-app .table-wrap .table.coex-ops-fit td,
table.coex-ops-fit th, table.coex-ops-fit td { padding-left: 7px !important; padding-right: 7px !important; }
table.coex-ops-fit .coex-op-date { font-size: 11.5px !important; line-height: 1.2; white-space: nowrap; }
table.coex-ops-fit th { font-size: 11px; }
/* FIR-51 #8 — фикс-ширины курсовых колонок. НЕскоуплено (table.coex-ops-fit),
   т.к. у оператора обёртка .card.no-transform, а не .table-wrap — скоупленный
   .coex-app .table-wrap ... селектор у оператора НЕ применится. */
table.coex-ops-fit th.coex-ops-course, table.coex-ops-fit td.coex-ops-course { width: 78px; white-space: nowrap; }
table.coex-ops-fit th.coex-ops-mktprofit, table.coex-ops-fit td.coex-ops-mktprofit { width: 82px; white-space: nowrap; }

/* FIR-48 #13/#51 — generic админ-таблицы (Офисы/Пользователи/Валюты/…) должны
   влезать БЕЗ горизонтального скролла (юзер: «скролла быть не должно», «дизайн
   полетел офис»). Раньше .table-responsive скроллился/обрубал крайнюю колонку
   ДЕЙСТВИЯ. Плотнее колонки + длинные значения через … (как просил в #43).
   Тот же приём, что и для «Все операции» — разнесён по ШАГ 12. */
#data-table th, #data-table td { padding: 7px 6px !important; font-size: 12.5px; }
#data-table td { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* FIR-48 #51 round 2 — /admin/debts/ имеет 12 колонок (ID, Дата, Тип, Метка,
   Контрагент, Оператор, Офис-приход, Нам должны, Валюта, Офис-расход,
   Мы должны, Валюта) и при стандартном .table padding 14px не влезает
   в 1162px контейнер (scrollWidth=1222, дефицит ~60px). Глобально ужимать
   .table нельзя — поломает балансы/операции, где плотность уже подобрана.
   Scoped-класс по образцу .coex-ops-fit / .coex-balances-compact. */
.coex-app .table-wrap .table.coex-debts-fit { table-layout: fixed !important; width: 100%; }
.coex-app .table-wrap .table.coex-debts-fit thead th {
  padding: 6px 3px;
  font-size: 10px;
  line-height: 1.25;
  letter-spacing: 0.02em;
}
.coex-app .table-wrap .table.coex-debts-fit tbody td {
  padding: 6px 3px;
  font-size: 12px;
  line-height: 1.25;
}
/* фиксированные ширины колонок (порядок: №, Дата, Тип, Метка, Контрагент, Оператор, Офис(приход), Нам должны, Валюта, Офис(расход), Мы должны, Валюта) */
.coex-app .table-wrap .table.coex-debts-fit th:nth-child(1),
.coex-app .table-wrap .table.coex-debts-fit td:nth-child(1) { width: 40px; white-space: nowrap; }
.coex-app .table-wrap .table.coex-debts-fit th:nth-child(2),
.coex-app .table-wrap .table.coex-debts-fit td:nth-child(2) { width: 70px; white-space: nowrap; }
.coex-app .table-wrap .table.coex-debts-fit th:nth-child(3),
.coex-app .table-wrap .table.coex-debts-fit td:nth-child(3) { width: 76px; white-space: nowrap; }
.coex-app .table-wrap .table.coex-debts-fit th:nth-child(4),
.coex-app .table-wrap .table.coex-debts-fit td:nth-child(4) { width: 74px; white-space: nowrap; }
.coex-app .table-wrap .table.coex-debts-fit th:nth-child(5),
.coex-app .table-wrap .table.coex-debts-fit td:nth-child(5) { width: 130px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.coex-app .table-wrap .table.coex-debts-fit th:nth-child(6),
.coex-app .table-wrap .table.coex-debts-fit td:nth-child(6) { width: 94px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.coex-app .table-wrap .table.coex-debts-fit th:nth-child(7),
.coex-app .table-wrap .table.coex-debts-fit td:nth-child(7) { width: 78px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.coex-app .table-wrap .table.coex-debts-fit th:nth-child(8),
.coex-app .table-wrap .table.coex-debts-fit td:nth-child(8) { white-space: nowrap; font-variant-numeric: tabular-nums; padding-left: 6px; padding-right: 6px; text-align: right; }
.coex-app .table-wrap .table.coex-debts-fit th:nth-child(9),
.coex-app .table-wrap .table.coex-debts-fit td:nth-child(9) { width: 52px; white-space: nowrap; }
.coex-app .table-wrap .table.coex-debts-fit th:nth-child(10),
.coex-app .table-wrap .table.coex-debts-fit td:nth-child(10) { width: 78px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.coex-app .table-wrap .table.coex-debts-fit th:nth-child(11),
.coex-app .table-wrap .table.coex-debts-fit td:nth-child(11) { white-space: nowrap; font-variant-numeric: tabular-nums; padding-left: 6px; padding-right: 6px; text-align: right; }
.coex-app .table-wrap .table.coex-debts-fit th:nth-child(12),
.coex-app .table-wrap .table.coex-debts-fit td:nth-child(12) { width: 52px; white-space: nowrap; }
.coex-app .table-wrap .table.coex-debts-fit td:nth-child(4) .badge { padding: 1px 5px; font-size: 10px; }
.table-responsive { overflow-x: auto; }   /* worst-case — чистый скролл, не обрубок */

/* Dropdown menus */
.dropdown-menu {
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  padding: 4px;
  font-size: 13.5px;
}
.dropdown-item {
  border-radius: var(--r-sm);
  padding: 7px 10px;
  color: var(--ink);
}
.dropdown-item:hover,
.dropdown-item:focus {
  background: var(--bg-3);
  color: var(--ink);
}

/* Modal */
.modal-content {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.16);
}
.modal-header {
  border-bottom: 1px solid var(--line);
  padding: 14px 18px;
}
.modal-footer {
  border-top: 1px solid var(--line);
  padding: 12px 18px;
  gap: 8px;
}

/* Compact admin modals — 2-column form layout where possible.
   The legacy markup uses `.row.form-group` with .col-4 label + .col input.
   We turn the modal-form into a 2-column CSS grid and let each .row.form-group
   stay as a single grid item with horizontal label+input. */
.modal-form { padding-top: 4px; }
/* FIR-42 #83 — spacing between rows lives on the parent grid (row-gap), not
   on each row's margin-bottom. With margin-bottom, the row's box used to be
   followed by transparent margin that some users perceived as belonging to
   the row (hover/cursor felt extended into the gap). Using row-gap clips the
   row's visual hit-zone to exactly its content. */
.modal-form > .row.form-group,
.modal-form .coex-modal-section > .row.form-group,
.modal-form .container-fluid > .row.form-group,
.modal-form .office-extra-section > .row.form-group,
.modal-form .repeatable-fields .row.form-group {
  display: grid !important;
  /* FIR-42 #283 / #302 — label-колонка 100px → 110px: 100 рвало
     «ПРИМЕЧАНИЕ» (10 chars × ~9px uppercase mono ≈ 90px + padding
     не помещалось). 110px достаточно для длинных одно-слов
     («ПРИМЕЧАНИЕ» / «РУКОВОДИТЕЛЬ») без переноса. «КРИПТОКОШЕЛЕК»
     и др. используют &shy; soft-hyphen для red-line wrap. */
  grid-template-columns: 110px 1fr !important;
  align-items: center;
  gap: 8px;
  margin: 0 !important;
  padding: 0;
}
/* FIR-42 #195 — общий design-pass: footer-кнопки форм оператора (Сбросить
   форму / Отправить в учёт) и primary-кнопки «Все получено / Все отдано»
   в operator-accounting были w-100 — буквально на всю ширину блока. Это
   некрасиво и не соответствует HIG: footer-actions должны быть выровнены
   вправо c auto-width. Не правим все 6 шаблонов индивидуально — гасим
   w-100 через CSS-override и центрируем родительский flex-контейнер. */
#main-form .d-flex.justify-content-center > .btn.w-100,
#main-form .d-flex.justify-content-center > .revision-clean.w-100 {
  width: auto !important;
  min-width: 160px;
  padding-left: 24px !important;
  padding-right: 24px !important;
}
#main-form .d-flex.justify-content-center {
  justify-content: flex-end !important;
  gap: 12px !important;
}
/* «Все получено / Все отдано» — должны быть размером с input справа от
   которого стоят, не на всю колонку. */
#main-form .button-all.w-100 {
  width: auto !important;
  min-width: 120px;
  padding-left: 16px !important;
  padding-right: 16px !important;
}
/* Inline «+ Добавить нового …» кнопки внутри селектов: были w-100,
   получались квадратной размером с input. col-auto + auto-width. */
#main-form .add-btn.btn-sm.w-100 {
  width: auto !important;
  padding-left: 10px !important;
  padding-right: 10px !important;
}

/* FIR-42 #239 — компактная upload-кнопка для прикрепления документа.
   Раньше было поле 200px с облачком cloud-upload и занимало half-row.
   Теперь — inline button-styled label с paperclip-иконкой. */
.upload-area.coex-upload-compact {
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
  height: 36px;
  width: auto !important;
  padding: 6px 14px !important;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  color: var(--ink);
  cursor: pointer;
  font-size: 13px;
  white-space: nowrap;
  margin: 0;
}
.upload-area.coex-upload-compact:hover {
  background: var(--bg-2, #f7f7f8);
}
.upload-area.coex-upload-compact .bi {
  font-size: 14px;
}

/* FIR-42 #245 — в horizontal grid coex-user-roles-cell (#228) chip-список
   многоуровневых селектов (Посредники / Рефоводы) при добавлении 2-3 имён
   разворачивался во вторую строку и наезжал на следующую row-grid (Источник
   / Тип клиента). Жёстко обрезаем переполнение: chip-rendered внутри cell
   получает overflow:hidden + max-height одной строки; внутри select2-
   selection__rendered включаем горизонтальный скролл (как уже сделано для
   .quick-add-row--inline в #204). */
.coex-user-roles-cell .select2-container--default .select2-selection--multiple {
  min-height: 38px;
}
.coex-user-roles-cell .select2-container--default .select2-selection--multiple .select2-selection__rendered {
  flex-wrap: nowrap !important;
  overflow-x: auto !important;
  overflow-y: hidden !important;
  scrollbar-width: thin;
  max-width: 100%;
}
.coex-user-roles-cell .select2-container--default .select2-selection--multiple .select2-selection__rendered::-webkit-scrollbar {
  height: 4px;
}
.coex-user-roles-cell .select2-container--default .select2-selection--multiple .select2-selection__rendered::-webkit-scrollbar-thumb {
  background: var(--line);
  border-radius: 2px;
}
.coex-user-roles-cell .select2-container--default .select2-selection--multiple .select2-selection__choice {
  flex-shrink: 0;
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* FIR-42 #228 — user-modal: Криптокошелек full-row (snap из 2-col grid)
   и horizontal layout для роле-cells. */
.modal-form .row.form-group.coex-full-row {
  grid-column: 1 / -1 !important;
}
.coex-user-extra-card {
  grid-column: 1 / -1; /* card шире 2-col grid */
}
.coex-user-roles-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  /* FIR-48 #22 — строки СВЯЗИ должны занимать собственную высоту в нормальном
     потоке и не давать содержимому вылезти на следующую секцию при поздней
     инициализации Select2. align-items:start не даёт ячейкам растягиваться по
     высоте друг друга; min-height гарантирует ненулевую высоту строки даже до
     init (когда поля скрыты JS-ом по роли — они display:none и не влияют). */
  align-items: start;
}
/* FIR-48 #22 — «Примечание к источнику» идёт ОТДЕЛЬНОЙ секцией ниже grid-строк.
   Чёткий отступ сверху + clear гарантируют, что чипы Рефоводов/Отдела продаж
   из верхних строк не наезжают на него, даже если Select2 раздулся при поздней
   инициализации. */
#user-client-source-field {
  clear: both;
  margin-top: 12px !important;
  position: relative;
  z-index: 1;
  /* FIR-48 #22 (2123) — textarea «Примечание к источнику» упиралась/наезжала
     на ПРАВУЮ границу card-а. Причина: это Bootstrap `.row` с дефолтными
     отрицательными боковыми margin-ами (-.5*--bs-gutter-x ≈ -12px), которые
     «съедают» внутренний padding card-а (.px-3 = 16px). В отличие от других
     полей формы, эта строка — прямой ребёнок .coex-user-extra-card, а не
     .coex-modal-section/.container-fluid, поэтому grid-rule (margin:0) её не
     ловит и негативные margin-ы остаются. Нейтрализуем их, чтобы поле жило
     ровно внутри padding-а card-а. */
  margin-left: 0 !important;
  margin-right: 0 !important;
}
/* Внутренние колонки строки «Примечание» — симметричный gutter внутри card-а,
   textarea не должен прилипать к правой границе. Левый col-label держит свой
   стандартный gutter, textarea-col получает небольшой правый отступ. */
#user-client-source-field > .form-control,
#user-client-source-field > .col {
  padding-right: 4px;
}
@media (min-width: 768px) {
  .coex-user-roles-row {
    grid-template-columns: 1fr 1fr 1fr;
  }
  /* Источник + Тип клиента — 2 cells; на md+ выкладываются 2 cols. */
  .coex-user-roles-row:nth-of-type(2) {
    grid-template-columns: 1fr 1fr;
  }
}
.coex-user-roles-cell {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
/* FIR-48 #22 (2123) — блок СВЯЗИ: «Отдел продаж»/чипы Рефоводы НАЕЗЖАЛИ на
   «ПРИМЕЧАНИЕ К ИСТОЧНИКУ» при поздней (flaky) инициализации Select2. Причина:
   до init нативный <select multiple> рендерится высоким многострочным listbox
   (≈80-100px), а одиночный — ≈31px; после init Select2-контейнер схлопывается
   до 34-38px. Разная высота до/после init заставляет grid-строки скакать и
   перекрывать соседнюю секцию. Фикс (только layout/CSS, без scripts.js):
   резервируем стабильную высоту под поле, чтобы footprint не менялся при
   поздней инициализации. */
.coex-user-roles-cell {
  /* label (≈19px) + поле (38px) + gap — строка не схлопывается и не прыгает */
  min-height: 62px;
}
/* Нативный <select> ДО инициализации Select2 держим той же высоты, что и
   будущий .select2-container (38px), чтобы не было скачка высоты строки.
   Особенно важно для multiple — иначе браузер рисует высокий listbox. */
.coex-user-roles-cell > select.form-select {
  height: 38px;
  min-height: 38px;
  max-height: 38px;
  overflow: hidden;
}
/* После init Select2 заменяет <select> своим контейнером — ему высоту не
   ограничиваем (chip-список горизонтально скроллится, см. правило #245). */
.coex-user-roles-cell .select2-container {
  min-height: 38px;
}
.coex-user-roles-cell .form-label {
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-3);
  margin-bottom: 4px;
}

/* FIR-42 #234 — admin /boxes/ unified table: чередуем фон между офисами,
   первая строка офиса получает разделительную верхнюю границу. Делает
   единую таблицу читаемой как сгруппированный список.
   v2: разделитель усилен — 3px var(--accent)-полоса + extra padding-top
   у первой строки группы, плюс bottom-border внутри alt-a для нативного
   ощущения «строки этого офиса заканчиваются здесь». */
.coex-boxes-unified tbody tr.coex-office-row--alt-a > td {
  background: #fff;
}
.coex-boxes-unified tbody tr.coex-office-row--alt-b > td {
  background: var(--bg-2, #f7f7f8);
}
.coex-boxes-unified tbody tr.coex-office-first > td {
  /* FIR-42 — раньше 3px solid var(--ink) = чёрно-черный. User: «можно
     не настолько чёрными сделать разделительные линии?». Снижаем до
     1.5px + var(--line) (#E5E7EB) — мягкий gray, как Bootstrap-default
     table-border. Группы офисов всё ещё визуально разделены, но без
     визуального крика. */
  border-top: 1.5px solid var(--line, #E5E7EB);
  padding-top: 14px;
}
.coex-boxes-unified tbody tr.coex-office-first:first-child > td {
  border-top: 0; /* первая строка таблицы — без doubled-border с thead */
  padding-top: 8px;
}
/* Имя офиса в первой строке группы выделяем — даёт ассоциацию «заголовок группы». */
.coex-boxes-unified tbody tr.coex-office-first > td:first-child {
  font-weight: 600 !important;
  color: var(--ink) !important;
  font-size: 13px !important;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* FIR-42 #223 — drill-down link на цифрах баланса. Цифры выглядят как
   обычные числа (inherit color), но при hover подчёркиваются и курсор
   меняется — намёк на «можно нажать». */
a.coex-drill {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dotted transparent;
  transition: border-color .12s, color .12s;
}
a.coex-drill:hover,
a.coex-drill:focus {
  color: var(--ink);
  border-bottom-color: currentColor;
  cursor: pointer;
}

/* FIR-48 #10 — Кассы: кликабельные цифры в трёх местах admin-boxes.php
   (top-summary, per-office strip, per-box «Остаток» column). Цифры
   рендерятся как <a class="coex-cash-drill">, ведут в /admin/operations/
   с готовыми фильтрами office/box/currency. Визуально остаются цифрами;
   hover — тонкое подчёркивание + cursor:pointer. */
a.coex-cash-drill {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dotted transparent;
  transition: border-color .12s, color .12s;
}
a.coex-cash-drill:hover,
a.coex-cash-drill:focus {
  border-bottom-color: currentColor;
  cursor: pointer;
}

/* FIR-42 #220 — Балансировка: валюта + количество визуально один блок
   (input-group), типа кассы — рядом. Узкий select-валюты + растяжимый input. */
.coex-balance-row .input-group {
  flex-wrap: nowrap;
}
/* FIR-48 #18 (2119) — «Сумма» has no left border + ~32px gap after chevron.
   Покупки/Продажи: select-ВАЛЮТА и input-«Сумма» НЕ образуют единую рамку.
   Две причины разрыва:
   1) После init Select2 нативный <select class="coex-cur-narrow form-select">
      получает класс .select2-hidden-accessible — но он остаётся flex-ребёнком
      .input-group. Если clip/position не сняли его из потока полностью (или у
      него осталась .form-select min-width/ширина), он занимает реальную ширину
      между .select2-container и input-ом → видимый «пустой» зазор после
      chevron-а, на который смотрит пользователь как на «32px gap».
   2) Bootstrap `.input-group > :not(:first-child)` навешивает на input
      `margin-left: -1px` для склейки border-ов; но т.к. посередине «висит»
      hidden-select, отрицательный margin съедается им, и input-«Сумма»
      выглядит как отдельный box без левой границы (она перекрыта).
   Fix: жёстко убираем hidden-select из потока (0×0, без border/padding) и
   делаем input соседом select2-container с общей вертикальной границей. */
.coex-balance-row .input-group > select.select2-hidden-accessible,
#main-form .input-group > select.select2-hidden-accessible {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  min-width: 0 !important;
  max-width: 1px !important;
  padding: 0 !important;
  margin: 0 !important;
  border: 0 !important;
  flex: 0 0 0 !important;
  overflow: hidden !important;
  clip: rect(0 0 0 0) !important;
}
/* input «Сумма» примыкает вплотную к select2-container валюты: тянем его
   влево на 1px чтобы их вертикальные границы наложились в одну линию
   (input-group-семантика), и select2-container не отдаёт правую границу. */
.coex-balance-row .input-group > input.form-control {
  margin-left: -1px !important;
}
.coex-balance-row .input-group > .select2-container {
  /* select2 заворачивает <select> в .select2-container — ему нужен явный
     flex-shrink:0 и фикс-ширина, чтобы валюта оставалась компактной.
     FIR-42 #237 — 96px было мало: «EUR» обрезалось до «Е…». Ставим
     130px, читаемо для всех ISO-кодов (USDT, RUB, AED, USD, EUR). */
  flex: 0 0 auto !important;
  width: 140px !important;
  min-width: 140px;
}
.coex-balance-row .input-group > .select2-container .select2-selection {
  border-top-right-radius: 0 !important;
  border-bottom-right-radius: 0 !important;
  /* FIR-42 #336 — select2-selection ровно 36px, чтобы совпадал по
     высоте с input.form-control «Количество» рядом. До этого
     min-height:34px давал расхождение, и border визуально выглядел
     тоньше/светлее у input. */
  height: 36px !important;
  min-height: 36px !important;
  box-sizing: border-box !important;
  /* FIR-48 #18 — «обралмение справа отсутствует линия по дизайну ...
     это покупка продажа просто когда юсдт выбрали так изменилась».
     При выборе валюты (USDT и т.п.) у select2-selection пропадала
     правая граница — между chevron-«v» и полем «Сумма» был разрыв.
     Root cause: focus/open-состояния select2 в input-group уносили
     border-right в transparent; явно фиксируем все четыре стороны. */
  border: 1px solid var(--line) !important;
  border-right: 1px solid var(--line) !important;
}
/* FIR-48 #18 — даже в focus/open состоянии правый border остаётся,
   чтобы граница между select-валюты и input-«Сумма» была сплошной. */
.coex-balance-row .input-group > .select2-container--default.select2-container--focus .select2-selection,
.coex-balance-row .input-group > .select2-container--default.select2-container--open .select2-selection {
  border-right: 1px solid var(--line) !important;
}
/* FIR-48 #2119 — на operator-accounting (Покупка/Продажа) выбор USDT
   триггерит auto-mirror на противоположную сторону через
   .trigger('change.select2'); во время re-render select2 у второго
   <select> outer .select2-container получает .select2-container--focus,
   а Bootstrap-овский .input-group > :not(:last-child) сбрасывает
   border-right в 0. Покрываем ВСЕ возможные состояния (default + focus +
   open + above/below) и любой селект внутри input-group формы accounting,
   чтобы граница между currency-select и amount-input не пропадала. */
#main-form .input-group > .select2-container .select2-selection,
#main-form .input-group > .select2-container--default .select2-selection,
#main-form .input-group > .select2-container--default.select2-container--focus .select2-selection,
#main-form .input-group > .select2-container--default.select2-container--open .select2-selection,
#main-form .input-group > .select2-container--default.select2-container--above .select2-selection,
#main-form .input-group > .select2-container--default.select2-container--below .select2-selection {
  border-right: 1px solid var(--line) !important;
}
.coex-balance-row .input-group > input.form-control {
  /* FIR-42 #336 — border явный и одинаковый с .select2-selection
     (1px solid var(--line)), height 36px box-sizing:border-box.
     border-left:0 сохраняем, чтобы input приклеивался к select без
     дублирующейся вертикальной линии — это input-group семантика. */
  flex: 1 1 auto;
  min-width: 0;
  border-top-left-radius: 0 !important;
  border-bottom-left-radius: 0 !important;
  border: 1px solid var(--line) !important;
  border-left: 0 !important;
  height: 36px !important;
  box-sizing: border-box !important;
}
.coex-balance-row .input-group > input.form-control:disabled,
.coex-balance-row .input-group > input.form-control[readonly] {
  border: 1px solid var(--line) !important;
  border-left: 0 !important;
}

/* FIR-42 #215 — служебная колонка row-selection (radio для edit/delete
   dropdown) ВСЕГДА скрыта от пользователя. Множественные слои защиты
   нужны потому что alpine-таблица переписывает style при перерисовке. */
.coex-row-selection-hidden,
td.coex-row-selection-hidden,
th.coex-row-selection-hidden {
  display: none !important;
  width: 0 !important;
  padding: 0 !important;
  border: 0 !important;
}

.modal-form .row.form-group > .form-label,
.modal-form .row.form-group > label.form-label {
  width: auto !important;
  max-width: none !important;
  flex: none !important;
  padding: 0 !important;
  margin-bottom: 0 !important;
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-3);
  /* FIR-42 #204 / #302 — переносы по русским правилам. Раньше
     word-break: break-word рвал слова посередине («ПРИМЕЧА|НИЕ»,
     «ДАТА ПОЯВЛЕ|НИЯ», «КРИПТО|КОШЕЛЕК»). Меняем на keep-all +
     overflow-wrap: break-word + hyphens: manual — перенос идёт
     по пробелам или по &shy; (см. #295 в config.php $user_names
     для «Крипто&shy;кошельки»). Многословные labels («ДАТА
     ПОЯВЛЕНИЯ», «ПРИМЕЧАНИЕ К ИСТОЧНИКУ») переносятся между
     словами; односложные («КРИПТОКОШЕЛЕК») остаются на одной
     строке (если влезают) или wrap-ятся по soft-hyphen. */
  white-space: normal;
  line-height: 1.2;
  hyphens: manual;
  -webkit-hyphens: manual;
  word-break: keep-all;
  overflow-wrap: break-word;
}
.modal-form .row.form-group > .col,
.modal-form .row.form-group > .form-control,
.modal-form .row.form-group > .form-select,
.modal-form .row.form-group > div {
  width: auto !important;
  max-width: none !important;
  flex: 1 1 auto !important;
  min-width: 0;
}

/* Pack the modal-form into 2-column grid on wider screens */
@media (min-width: 768px) {
  .modal-form {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 24px;
    row-gap: 10px;
    align-items: start;
  }
  .modal-form > .row.form-group {
    margin-bottom: 0 !important;
    /* FIR-48 #13 — cell внутри grid должен иметь min-width:0 + overflow,
       иначе .quick-add-row--inline ("+ Новый" кнопка) выезжает за границу
       cell-а и налезает на label соседней колонки (см. скрин юзера:
       «+» рядом с «Кассы (фиат)» налегает на label «СТРАНА:»). */
    min-width: 0;
    overflow: hidden;
  }
  /* FIR-48 #41 — full-row ряд (Оборотка) рендерит Select2-dropdown, который
     должен выходить за пределы строки; overflow:hidden из правила выше его
     обрезает. Делаем overflow:visible только для этого full-row + строки
     внутри listing-контейнера. */
  .modal-form > .row.form-group.coex-full-row,
  .modal-form #office-turnover-rows,
  .modal-form #office-turnover-rows .office-turnover-row {
    overflow: visible;
  }
  /* FIR-48 #13 — col-* внутри row.form-group тоже нуждаются в min-width:0
     чтобы flex-children (select + quick-add-btn) сжимались правильно. */
  .modal-form > .row.form-group > .col,
  .modal-form > .row.form-group > [class*="col-"] {
    min-width: 0;
  }
  /* FIR-48 #13 — quick-add-row внутри grid-cell должен сжиматься (select растёт,
     button не сжимается, но обоих укладывает в одну строку без overflow). */
  .modal-form .quick-add-row--inline {
    min-width: 0;
  }
  .modal-form .quick-add-row--inline > select,
  .modal-form .quick-add-row--inline > .select2-container {
    flex: 1 1 0;
    min-width: 0;
  }
  .modal-form .quick-add-row--inline .quick-add-btn {
    flex-shrink: 0;
  }
  /* Multiline fields and footers always span both columns */
  .modal-form > .row.form-group:has(textarea),
  .modal-form > .modal-footer,
  .modal-form > .form-fields,
  .modal-form > #user-operator-fields,
  .modal-form > #user-refovod-fields,
  .modal-form > #user-client-fields,
  .modal-form > .row.form-group.span-2,
  /* FIR-42 #331 — секции #338 (Контакты / Криптокошельки / Учётные данные /
     Должность / Связи / Дополнительно) теперь являются прямыми детьми
     .modal-form вместо `.row.form-group`. Раньше 2-col grid распределял
     эти секции как 2-колоночные cell-ы (Контакты слева, Криптокошельки
     справа — с разными ширинами label-ов внутри). Pin-аем секции к
     full-row, и rows внутри секций сами выравниваются по 110px label-grid
     (см. правило выше). */
  .modal-form > .coex-modal-section {
    grid-column: 1 / -1;
  }
  /* Внутри секции — снова 2-col grid для row.form-group, чтобы 2 коротких
     поля (например «Имя» + «Ник») лежали рядом, как было до введения
     .coex-modal-section wrapper-а. */
  .modal-form .coex-modal-section {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 24px;
    row-gap: 10px;
    align-items: start;
  }
  /* Заголовок секции — full-row внутри её собственного 2-col grid */
  .modal-form .coex-modal-section > .coex-section-title {
    grid-column: 1 / -1;
  }
  /* Карточные блоки и textarea-rows внутри секции — full-row */
  .modal-form .coex-modal-section > .form-fields,
  .modal-form .coex-modal-section > #user-operator-fields,
  .modal-form .coex-modal-section > #user-post-fields,
  .modal-form .coex-modal-section > .coex-user-extra-card,
  .modal-form .coex-modal-section > #user-client-fields,
  .modal-form .coex-modal-section > .row.form-group:has(textarea),
  .modal-form .coex-modal-section > .row.form-group.coex-full-row,
  .modal-form .coex-modal-section > .row.form-group.span-2 {
    grid-column: 1 / -1;
  }
  /* FIR-53 #3 — секция «Криптокошельки, кассы и оборотка» в офис-модале
     использует .office-extra-section (НЕ .coex-modal-section). Зеркалим
     для неё ту же раскладку: секция на всю ширину modal-form-grid, внутри —
     свой 2-col grid, заголовок и оборотка (coex-full-row/textarea/span-2) —
     full-row. Поля Криптокошельки/Кассы легли по 110px label-grid через
     правило выше (.modal-form .office-extra-section > .row.form-group). */
  .modal-form > .office-extra-section {
    grid-column: 1 / -1;
  }
  .modal-form .office-extra-section {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 24px;
    row-gap: 10px;
    align-items: start;
  }
  .modal-form .office-extra-section > .coex-section-title {
    grid-column: 1 / -1;
  }
  .modal-form .office-extra-section > .row.form-group.coex-full-row,
  .modal-form .office-extra-section > .row.form-group:has(textarea),
  .modal-form .office-extra-section > .row.form-group.span-2 {
    grid-column: 1 / -1;
  }
}

/* Nested card sections inside the modal — flatten the borders/padding */
.modal-form .form-fields.card {
  border: 1px solid var(--line) !important;
  border-radius: var(--r) !important;
  background: var(--bg-2);
  padding: 14px 16px !important;
  margin: 4px 0 12px !important;
}
.modal-form .form-fields.card .container-fluid { padding: 0; }
.modal-form .form-fields .row.form-group { margin-bottom: 8px !important; }

/* Repeatable +/- buttons (the indigo + red squares from bug #7) — compact icon-only */
.modal-form .repeatable-add-row,
.modal-form .repeatable-remove-row {
  height: 32px !important;
  padding: 0 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  font-size: 14px !important;
  line-height: 1 !important;
  border-radius: var(--r) !important;
}
/* Icon-only кнопки (remove + add без текста) — фиксированная ширина 32px */
.modal-form .repeatable-remove-row { width: 32px !important; }
/* FIR-43 #35 — кнопка «Добавить должность» содержит icon + text → ширина auto,
   плюс паддинги по бокам чтобы текст не упирался в края и не уезжал за карточку. */
.modal-form .repeatable-add-row {
  width: auto !important;
  min-width: 32px !important;
  padding: 0 12px !important;
  position: relative !important;
  left: 0 !important;
  margin-left: 0 !important;
  max-width: 100%;
}
.modal-form .repeatable-add-row .bi,
.modal-form .repeatable-remove-row .bi { font-size: 14px !important; line-height: 1 !important; }
.modal-form .repeatable-add-row { background: var(--accent) !important; border-color: var(--accent) !important; }
.modal-form .repeatable-remove-row { background: #fff !important; border: 1px solid var(--line-strong) !important; color: var(--bad) !important; }
.modal-form .repeatable-remove-row:hover { background: var(--bg-2) !important; }

/* Hide the empty placeholder in repeatable button container row */
.repeatable-button-container { margin: 8px 0 0 !important; }

/* Modal footer — single column at bottom */
.modal-form .modal-footer {
  border-top: 1px solid var(--line);
  margin: 16px 0 0 0;
  padding: 14px 0 4px 0;
  background: transparent;
}

/* Switch (status toggle) — keep label+switch on one row */
.modal-form .row.form-group:has(.switch) {
  grid-template-columns: 140px auto !important;
  justify-content: start;
}

/* #17 — when the user-modal is opened from operator's "+ Контрагент" we
   reorder fields so Источник + Тип + Рефовод + Посредник come first,
   Базовый офис moves to the bottom, and primary form is 2 columns.
   We use CSS order: on form children. */
.modal-form.coex-client-mode {
  display: grid !important;
  grid-template-columns: 1fr 1fr !important;
  column-gap: 24px;
}
/* primary fields each span 1 column */
.modal-form.coex-client-mode > .row.form-group { grid-column: auto / auto; }
/* Wide elements (textarea / nested fields card / modal-footer) span both columns */
.modal-form.coex-client-mode > .row.form-group:has(textarea),
.modal-form.coex-client-mode > #user-operator-fields,
.modal-form.coex-client-mode > #user-refovod-fields,
.modal-form.coex-client-mode > #user-client-fields,
.modal-form.coex-client-mode > .modal-footer { grid-column: 1 / -1; }
/* Field order in client-add mode — uses CSS order on direct children. */
.modal-form.coex-client-mode > #user-client-fields  { order: 1; }   /* Источник, Тип, Посредники, Рефоводы */
.modal-form.coex-client-mode > .row.form-group:has(#user-name)       { order: 2; }
.modal-form.coex-client-mode > .row.form-group:has(#user-telegram)   { order: 3; }
.modal-form.coex-client-mode > .row.form-group:has(#user-phone)      { order: 4; }
.modal-form.coex-client-mode > .row.form-group:has(#user-date-added) { order: 5; }
.modal-form.coex-client-mode > .row.form-group:has(#user-description){ order: 6; } /* Примечание — wide */
.modal-form.coex-client-mode > .row.form-group:has(#user-role-ids)   { order: 9; }
.modal-form.coex-client-mode > .row.form-group:has(#user-wallet-ids) { order: 10; }
.modal-form.coex-client-mode > .row.form-group:has(#user-office-id)  { order: 11; }
.modal-form.coex-client-mode > .row.form-group:has(.switch)          { order: 12; }
.modal-form.coex-client-mode > .modal-footer                          { order: 13; }
/* Inside #user-client-fields card — make Источник/Тип first, then Посредники/Рефоводы */
.modal-form.coex-client-mode #user-client-fields .row.form-group:has(#user-client-source-id)          { order: 1; }
.modal-form.coex-client-mode #user-client-fields .row.form-group:has(#user-client-type)               { order: 2; }
.modal-form.coex-client-mode #user-client-fields .row.form-group:has(#user-client-broker-ids)         { order: 3; }
.modal-form.coex-client-mode #user-client-fields .row.form-group:has(#user-client-refovod-ids)        { order: 4; }
.modal-form.coex-client-mode #user-client-fields .row.form-group:has(#user-client-source-description) { order: 5; }
.modal-form.coex-client-mode #user-client-fields .container-fluid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 16px;
}
.modal-form.coex-client-mode #user-client-fields .row.form-group:has(textarea) { grid-column: 1 / -1; }

/* In client-add mode, refovod is single-select (not multi) for operators */
.modal-form.coex-client-mode #user-client-refovod-ids { /* tag via JS */ }

/* #18 — Hint marker on form labels: subtle "?" icon with bootstrap tooltip */
.coex-hint {
  display: inline-block;
  margin-left: 6px;
  color: var(--ink-4);
  font-size: 12px;
  cursor: help;
  vertical-align: middle;
  opacity: 0.7;
  transition: color .12s, opacity .12s;
}
.coex-hint:hover { color: var(--accent); opacity: 1; }

/* Bootstrap tooltip restyle to match the design system */
.tooltip-inner {
  background: var(--ink) !important;
  color: #fff !important;
  font: 500 12.5px var(--sans) !important;
  border-radius: var(--r-sm) !important;
  padding: 6px 10px !important;
  max-width: 260px;
  text-align: left;
}
.tooltip .tooltip-arrow::before { border-top-color: var(--ink) !important; border-bottom-color: var(--ink) !important; }

/* Password group — input + eye reveal + reset-generate button */
.coex-pass-group {
  display: flex;
  align-items: stretch;
  gap: 6px;
  flex-wrap: wrap;
}
.coex-pass-group .form-control { flex: 1 1 auto; min-width: 0; }
/* FIR-43 #34 v2 — индикатор «Пароль установлен (••••)» должен
   занимать всю ширину flex-row и стоять над input-ом. flex-basis:100%
   заставляет его перенестись на свою строку, order:-1 поднимает
   выше input-а независимо от порядка в DOM. */
.coex-pass-group .coex-pass-set-indicator {
  flex: 0 0 100%;
  order: -1;
  margin-bottom: 4px;
  font-size: 12px;
  line-height: 1.2;
}
.coex-pass-toggle,
.coex-pass-reset {
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--line);
  background: #fff;
  color: var(--ink-3);
  border-radius: var(--r);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.coex-pass-toggle:hover,
.coex-pass-reset:hover { background: var(--bg-2); color: var(--ink); }
.coex-pass-reset { color: var(--accent); }
.coex-pass-reset:hover { color: var(--accent-hover); background: var(--accent-soft); }
.coex-pass-toggle .bi,
.coex-pass-reset .bi { font-size: 14px; line-height: 1; }

/* Reset-password notice (one-time temp password)
   FIR-42 #117 — inline single-line chip, not the old huge stacked block.
   Sits next to the password row, не растягиваясь на всю ширину формы. */
.coex-temp-pass {
  display: none;
  margin-top: 6px;
  padding: 4px 10px;
  border: 1px solid #fde68a;
  background: #fffbeb;
  border-radius: var(--r-sm);
  font-size: 12px;
  line-height: 1.5;
  color: #78350f;
  white-space: nowrap;
  width: auto;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}
.coex-temp-pass.show { display: inline-block; }
.coex-temp-pass code {
  font-family: var(--mono);
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
  background: #fff;
  border: 1px solid #fde68a;
  padding: 2px 6px;
  border-radius: var(--r-sm);
  user-select: all;
}

/* Nav */
.nav-link { color: var(--ink-2); }
.nav-link:hover { color: var(--ink); }
.nav-link.active { color: var(--ink); }

/* ---------- Custom components ---------- */

/* Sidebar */
.coex-sidebar {
  background: var(--bg-2);
  border-right: 1px solid var(--line);
  padding: 20px 12px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  min-width: 232px;
  max-width: 232px;
}
.coex-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 8px 16px;
  border-bottom: 1px solid var(--line);
}
.coex-brand-mark {
  width: 22px; height: 22px;
  border-radius: 6px;
  background: var(--ink);
  color: #fff;
  font-family: var(--mono);
  font-weight: 600;
  font-size: 11px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  letter-spacing: -0.02em;
}
.coex-brand-name {
  font-weight: 600;
  letter-spacing: -0.01em;
  font-size: 15px;
}
/* FIR-42 #207 — фирменный SVG-знак вместо inline-text .coex-brand-mark+name. */
.coex-brand-img {
  height: 28px;
  width: auto;
  display: block;
  user-select: none;
}
.coex-brand-img-auth {
  height: 36px;
}
.coex-nav-group-label {
  font-family: var(--mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-4);
  padding: 0 8px 6px;
}
.coex-nav {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.coex-nav li a {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px 8px;
  border-radius: var(--r);
  color: var(--ink-2);
  text-decoration: none;
  font-size: 13.5px;
  line-height: 1.2;
  cursor: pointer;
}
.coex-nav li a:hover { background: var(--bg-3); color: var(--ink); }
.coex-nav li.active > a {
  background: var(--bg-3);
  color: var(--ink);
  font-weight: 500;
}
.coex-nav li.active > a .ic { color: var(--accent); }
.coex-nav .ic {
  width: 16px; height: 16px;
  color: var(--ink-3);
  flex: 0 0 16px;
}

/* FIR-42 #243/#246/#260 — фикс наезжающих друг на друга sub-list items в
   sidebar /admin/?table=users (Все пользователи / Сотрудники / Посредники
   / Рефоводы / Клиенты / Рефералы). Раньше .sub-button без иконки имел
   меньшую высоту чем .nav-link с иконкой, и group-label «Доходы и расходы»
   следующего раздела наезжал на «Рефералы». Также Bootstrap collapse-
   обвертка иногда обрезала контент через overflow:hidden. */
.coex-nav.sub-list {
  gap: 4px;                 /* было 2px — слишком плотно */
  padding-block: 4px 8px;   /* воздух между последним sub-button и следующей группой */
  overflow: visible;        /* отменяем Bootstrap collapse cropping */
}
.coex-nav.sub-list li {
  margin: 0;
  padding: 0;
  list-style: none;
}
.coex-nav.sub-list li > a,
.coex-nav .sub-button {
  display: flex;
  align-items: center;
  min-height: 28px;          /* стабильная высота даже без иконки */
  padding: 6px 8px;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.collapse#rolesSubmenu,
.collapse#incomesSubmenu {
  overflow: visible !important;  /* Bootstrap по умолчанию hidden */
}
/* group-label следующей секции получает отбивку чтобы не наехать на
   последний sub-button предыдущей. */
.coex-nav-group-label + .coex-nav {
  margin-top: 2px;
}

/* Topbar */
.coex-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-bottom: 18px;
  margin-bottom: 24px;
  border-bottom: 1px solid var(--line);
}
.coex-crumbs {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.coex-crumbs .sep { color: var(--ink-4); }
.coex-crumbs .cur { color: var(--ink); }

/* FIR-42 #63/#98 — active-office indicator in operator topbar */
.coex-active-office {
  display: inline-flex;
  align-items: center;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-3);
  padding: 6px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bg-2);
  white-space: nowrap;
}
.coex-active-office strong { color: var(--ink); font-weight: 600; }
/* FIR-48 #2023 — индикатор может быть button (кликабельный) — нужен hover
   feedback, чтобы пользователь понял что элемент интерактивен. */
button.coex-active-office { transition: background .12s, border-color .12s; }
button.coex-active-office:hover {
  background: var(--bg-3, #f0f0f5);
  border-color: var(--accent, #5e6ad2) !important;
  color: var(--ink);
}
/* FIR-48 #15/#19 — кнопка-chip должна явно выглядеть кликабельной.
   Юзер не понимал что можно нажать → openед modal через chevron-▼,
   cursor:pointer на всей зоне, hover-effect усилен. #19 — усиливаем
   аффорданс: заполненный accent-фон + accent border, чтобы chip сразу
   читался как кнопка-переключатель «активный офис». */
.coex-active-office--clickable {
  cursor: pointer;
  user-select: none;
  background: rgba(94, 106, 210, 0.10);
  border-color: rgba(94, 106, 210, 0.45);
  color: var(--ink);
  transition: background .12s, border-color .12s, box-shadow .12s, transform .12s;
}
.coex-active-office--clickable:hover {
  background: rgba(94, 106, 210, 0.18);
  border-color: var(--accent, #5e6ad2);
  box-shadow: 0 2px 6px rgba(94, 106, 210, 0.22);
  transform: translateY(-1px);
}
.coex-active-office--clickable:active {
  transform: translateY(0);
  box-shadow: 0 0 0 2px rgba(94, 106, 210, 0.18);
}
.coex-active-office--clickable:focus-visible {
  outline: 2px solid var(--accent, #5e6ad2);
  outline-offset: 1px;
}
/* small chevron вариант — 12px вместо 16px */
.coex-active-office .ic.ic-xs {
  width: 12px;
  height: 12px;
}

/* FIR-42 #104 — kill the grey "placeholder bar" select2 paints inside a
   disabled multi-select. When disabled with no selection, select2 renders
   a faint pill that looks like a giant grey stripe; we just hide it. */
.coex-party-row .select2-selection--multiple[aria-disabled="true"] .select2-selection__choice,
.coex-party-row .select2-selection--multiple[aria-disabled="true"] .select2-selection__rendered::after {
  display: none !important;
}
.coex-party-row .select2-selection--multiple[aria-disabled="true"] {
  background-color: var(--bg-2);
  border-color: var(--line);
}

/* FIR-48 #11 — multi-select Посредник/Рефовод схлопывать в 1 строку.
   Раньше 2+ чипа разворачивали row в 2 строки, что ломало grid party-row.
   Теперь chips-контейнер ограничен 1 строкой с overflow:hidden и nowrap.
   При hover на cell показываем все имена через native title-tooltip
   (PHP проставляет data-coex-multi-title из selected option-ов).
   Скрытые чипы пользователь видит когда кликает по dropdown. */
.coex-party-row .select2-selection--multiple {
  min-height: 36px;
  max-height: 38px;
  overflow: hidden;
}
.coex-party-row .select2-selection--multiple .select2-selection__rendered {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  overflow: hidden;
  white-space: nowrap;
  padding-right: 4px;
}
.coex-party-row .select2-selection--multiple .select2-selection__choice {
  flex: 0 0 auto;
  max-width: 130px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* «…» индикатор когда чипы переполнили cell: добавляется JS-ом
   (см. scripts.js #11) на .select2-container с aria-overflowing=true */
.coex-party-row .select2-container[data-coex-overflow="1"]::after {
  content: "…";
  position: absolute;
  right: 28px;
  top: 50%;
  transform: translateY(-50%);
  background: linear-gradient(90deg, transparent 0%, #fff 30%);
  padding: 0 4px 0 18px;
  font-weight: 600;
  color: var(--ink-2);
  pointer-events: none;
  font-size: 14px;
}

/* FIR-42 #107 — "Итого получено: 100 000" wrapped to 3 lines because it
   lives inside a narrow col-2. Force single-line and let the small label
   overflow its parent column without wrapping. */
.get-total-amount,
.give-total-amount {
  white-space: nowrap;
  display: inline-block;
  overflow: visible;
}

/* FIR-42 #98 — square "Д" diagnostic button next to the user dropdown */
.coex-diag-btn {
  width: 36px;
  height: 36px;
  padding: 0;
  font-family: var(--mono);
  font-weight: 700;
  font-size: 14px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Page header */
.coex-page-title {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin-bottom: 6px;
}
.coex-page-title h1 {
  margin: 0;
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.015em;
}
.coex-page-title .meta {
  font-family: var(--mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-3);
}
.coex-page-sub {
  color: var(--ink-3);
  font-size: 13.5px;
  margin-bottom: 20px;
}

/* Search */
.coex-search {
  display: flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--bg);
  padding: 5px 10px;
  font-size: 13px;
  min-width: 240px;
  color: var(--ink-3);
}
.coex-search input {
  border: 0;
  outline: 0;
  font: inherit;
  color: var(--ink);
  width: 100%;
  background: transparent;
}
.coex-kbd {
  font-family: var(--mono);
  font-size: 11px;
  background: var(--bg-3);
  color: var(--ink-3);
  padding: 1px 5px;
  border-radius: 3px;
  border: 1px solid var(--line);
}

/* Toggle (Факт/Долг, Купил/Продал) */
.coex-toggle {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
}
.coex-toggle button {
  background: #fff;
  border: 0;
  padding: 6px 14px;
  font-family: var(--mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-2);
  cursor: pointer;
}
.coex-toggle button + button { border-left: 1px solid var(--line); }
.coex-toggle button.on { background: var(--ink); color: #fff; }
.coex-toggle button:hover:not(.on) { background: var(--bg-2); }

/* Status chips */
.coex-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 20px;
  padding: 0 8px;
  border-radius: var(--r-sm);
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  background: var(--bg-3);
  color: var(--ink-2);
  border: 1px solid var(--line);
  white-space: nowrap;
}
.coex-chip.fact {
  background: var(--accent-soft);
  color: #3b3da3;
  border-color: rgba(94, 106, 210, 0.25);
}
.coex-chip.debt {
  background: #fff7ed;
  color: #9a3412;
  border-color: #fed7aa;
}
.coex-chip.path {
  background: #fef9c3;
  color: #854d0e;
  border-color: #fde68a;
}
.coex-chip.ok {
  background: #ecfdf5;
  color: #047857;
  border-color: #a7f3d0;
}
.coex-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  display: inline-block;
}
.coex-dot.ok { background: var(--ok); }
.coex-dot.warn { background: var(--warn); }
.coex-dot.bad { background: var(--bad); }

/* Filter chip */
.coex-filters {
  display: flex;
  gap: 8px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-2);
  align-items: center;
  flex-wrap: wrap;
}
.coex-filter {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r);
  font-size: 12.5px;
  color: var(--ink-2);
  background: #fff;
}
.coex-filter strong { color: var(--ink); font-weight: 500; }
.coex-filter .x { color: var(--ink-4); font-size: 14px; line-height: 1; cursor: pointer; }
.coex-filters-right {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* KPI */
.coex-kpis {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin-bottom: 24px;
}
.coex-kpi {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 14px 16px;
  background: #fff;
}
.coex-kpi .k-label {
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-3);
  margin-bottom: 6px;
}
.coex-kpi .k-value {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
}
.coex-kpi .k-delta {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ok);
  margin-top: 4px;
}
.coex-kpi .k-delta.bad { color: var(--bad); }

/* Avatar */
.coex-avatar {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--bg-3);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--ink-2);
}
.coex-who {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* App layout */
.coex-app {
  display: grid;
  grid-template-columns: 232px 1fr;
  min-height: 100vh;
}
.coex-main {
  padding: 20px 28px 60px;
  min-width: 0;
}

/* Neutralise legacy theme-metis `.admin-sidebar`/`admin-main` rules that
   are leaking through. The legacy CSS sets the sidebar to position:fixed
   and adds margin-left to .admin-main which double-counts our grid column. */
.coex-app .admin-sidebar,
.coex-app .admin-sidebar.coex-sidebar {
  position: static !important;
  width: auto !important;
  height: auto !important;
  top: auto !important;
  left: auto !important;
}
.coex-app .admin-main,
.coex-app .admin-main.coex-main {
  margin-left: 0 !important;
  margin-top: 0 !important;
}
/* .sidebar-backdrop is a position-fixed overlay used only on mobile when the
   sidebar opens — but in the source it's a sibling of the sidebar inside our
   grid, so it consumes the second column. Force it out of the grid flow. */
.coex-app > .sidebar-backdrop {
  position: fixed !important;
  inset: 0 !important;
  pointer-events: none;
  display: none;
}

/* Auth (login page) */
.coex-auth {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-2);
  padding: 20px;
}
.coex-auth-card {
  width: 100%;
  max-width: 360px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 32px 28px;
}
.coex-auth-card .coex-brand {
  border-bottom: 0;
  padding: 0 0 18px;
  justify-content: center;
}
.coex-auth-card h2 {
  margin: 0 0 22px;
  font-size: 18px;
  text-align: center;
}
.coex-auth-card .form-control { margin-bottom: 10px; }
.coex-auth-card .btn { width: 100%; justify-content: center; padding: 9px 12px; }
.coex-auth-message {
  font-size: 13px;
  margin-top: 12px;
  text-align: center;
  min-height: 18px;
}
.coex-auth-message.bad { color: var(--bad); }
.coex-auth-message.ok { color: var(--ok); }

/* Responsive */
@media (max-width: 900px) {
  .coex-app { grid-template-columns: 1fr; }
  .coex-sidebar { min-width: 0; max-width: none; border-right: 0; border-bottom: 1px solid var(--line); }
  .coex-kpis { grid-template-columns: repeat(2, 1fr); }
}

/* Suppress conflicting Bootstrap classes used in legacy templates */
.text-primary { color: var(--accent) !important; }
.bg-white { background: var(--bg) !important; }
.border-bottom { border-bottom: 1px solid var(--line) !important; }

/* #16 — Quick-pick template buttons */
.coex-template-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.coex-template-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px;
  border: 1px solid var(--line-strong);
  background: #fff;
  border-radius: var(--r);
  font: 500 13.5px var(--sans);
  color: var(--ink);
  cursor: pointer;
  white-space: nowrap;
  transition: border-color .12s, background .12s;
}
.coex-template-btn .t-from,
.coex-template-btn .t-to {
  font-family: var(--mono);
  font-size: 12.5px;
  font-weight: 500;
}
.coex-template-btn .t-arrow {
  color: var(--ink-4);
  font-size: 13px;
}
.coex-template-btn:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.coex-template-btn.is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.coex-template-btn.is-active .t-arrow { color: rgba(255,255,255,0.7); }
.coex-template-more {
  margin-left: auto;
  background: transparent;
  border: 1px dashed var(--line-strong);
  color: var(--ink-3);
  padding: 7px 14px;
  border-radius: var(--r);
  font: 500 13px var(--sans);
  cursor: pointer;
}
.coex-template-more:hover { border-color: var(--accent); color: var(--accent); }

/* #30 — keep template buttons on one line; shrink on narrow */
.coex-template-row { row-gap: 6px; }
.coex-template-btn { padding: 6px 10px; font-size: 13px; }
.coex-template-btn .t-from,
.coex-template-btn .t-to { font-size: 11.5px; }

/* "Другое" custom picker — compact 3-col grid */
.coex-other-row {
  display: grid;
  grid-template-columns: 1fr auto 1fr auto;
  gap: 10px;
  align-items: end;
  padding: 12px 14px;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--r);
  max-width: 600px;
}
.coex-other-arrow {
  font-size: 18px;
  color: var(--ink-3);
  padding-bottom: 8px;
  font-family: var(--mono);
}

/* Remove "×" on repeatable blocks (#20) */
.duplicate-block {
  position: relative;
}
.duplicate-block .duplicate-block-remove {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #fff;
  border: 1px solid var(--line-strong);
  color: var(--ink-3);
  font-size: 14px;
  line-height: 1;
  font-family: var(--sans);
  text-indent: 0;
  z-index: 2;
  /* FIR-42 #341 — flex-shrink:0 + white-space:nowrap защищают «X Удалить»
     от схлопывания, если кнопку рендерим в потоке flex-row (а не absolute).
     Без них «X Удалить» обрезалась до «Удали» — flex сжимал auto-width-child. */
  flex-shrink: 0;
  white-space: nowrap;
}
/* FIR-43 #22 — в /operator/debt/ кнопка «X Удалить» wrap-ается в
   .d-flex.justify-content-end (in-flow), а не как absolute «×»-circle на
   углу. Возвращаем normal-button layout: auto-width, padding, без
   position:absolute. Иначе CSS выше схлопывает её в 22×22 кружок и
   текст «Удалить» уходит за пределы width=22 (rect width=22, content=24chars). */
.duplicate-block .d-flex .duplicate-block-remove,
.duplicate-block-get .d-flex .duplicate-block-remove,
.duplicate-block-give .d-flex .duplicate-block-remove {
  position: static !important;
  top: auto !important;
  right: auto !important;
  width: auto !important;
  height: auto !important;
  border-radius: 4px !important;
  padding: 2px 8px !important;
  background: transparent !important;
  border: none !important;
}
.duplicate-block .duplicate-block-remove:hover {
  background: var(--bad);
  color: #fff;
  border-color: var(--bad);
}
.duplicate-block.d-none .duplicate-block-remove { display: none; }

/* FIR-48 #24 — на /operator/debt/ кнопки «+ Добавить» (сидит в header
   fieldset) и «× Удалить» (сидит в активной карточке строки) рендерились
   в разных flex-row → визуально шли столбиком. Поднимаем wrapper кнопки
   «× Удалить» абсолютно в строку заголовка fieldset, чтобы получился один
   визуальный flex-ряд у правого края. Сдвигаем левее «+ Добавить» (она
   ≈6rem шириной) с небольшим зазором — overflow:visible у .duplicate-block
   уже выставлен правилом #341 ниже, обрезки нет. DOM не трогаем (любой
   перенос ломает .closest('.duplicate-block') в JS-обработчике 6997). */
/* designer review: position:relative на сами блоки → absolute-якорь
   внутри карточки (а не у body/ближайшего предка с позицией); :not(.d-none)
   → правило не цепляет hidden-template (.duplicate-block-*.d-none). */
form.debt .duplicate-block-get,
form.debt .duplicate-block-give {
  position: relative;
}
form.debt .duplicate-block-get:not(.d-none) > .d-flex.justify-content-end,
form.debt .duplicate-block-give:not(.d-none) > .d-flex.justify-content-end {
  position: absolute !important;
  top: -2.5rem;       /* mt-3 контейнера (1rem) + mt-4 header (1.5rem) */
  right: 7rem;        /* левее «+ Добавить» (~6rem) + зазор */
  margin: 0 !important;
  z-index: 3;
}

/* FIR-42 #341 — родительские контейнеры не должны клипать absolute-кнопку
   «Удалить», которая выступает на 8px за правую границу. Раньше row/col
   с Bootstrap overflow могли её обрезать. */
.duplicate-block,
.duplicate-container-get,
.duplicate-container-give,
.duplicate-container-get-more,
.duplicate-container-give-more {
  overflow: visible !important;
}

/* Operator form section headers — used pattern .fw-bold.text-success/danger/muted.fs-5
   Restyle them: same compact heading, with a 3px coloured bar on the left for semantic in/out */
.fw-bold.text-success.fs-5,
.fw-bold.text-danger.fs-5,
.fw-bold.text-muted.fs-5 {
  color: var(--ink) !important;
  font-family: var(--sans) !important;
  font-size: 14px !important;
  font-weight: 600 !important;
  letter-spacing: -0.005em;
  display: inline-flex !important;
  align-items: center;
  gap: 10px;
  padding-left: 0;
  line-height: 1.4;
}
.fw-bold.text-success.fs-5::before,
.fw-bold.text-danger.fs-5::before,
.fw-bold.text-muted.fs-5::before {
  content: '';
  width: 3px;
  height: 14px;
  border-radius: 2px;
  background: var(--ink-4);
  display: inline-block;
  flex-shrink: 0;
}
.fw-bold.text-success.fs-5::before { background: var(--ok); }
.fw-bold.text-danger.fs-5::before { background: var(--bad); }
.fw-bold.text-muted.fs-5::before { background: var(--ink-4); }

/* "Добавить" link in section headers (operator-accounting "Получили + Добавить") */
.fw-bold + .add-input,
a.add-input, .add-input {
  font-size: 13px;
  color: var(--accent);
  text-decoration: none;
  font-weight: 500;
}
.add-input:hover { color: var(--accent-hover); }

/* ---------- Legacy AJAX table tightening (kernel.php output) ---------- */
/* The dynamically loaded table renders "Name" + <small>ID: 123</small> on two
   lines per row. Make it one line, tighter padding, restyle badges. */

#data-table-wrp .card { border: 1px solid var(--line); border-radius: var(--r-lg); }
#data-table-wrp .card-header {
  padding: 10px 12px;
  background: transparent;
  border-bottom: 1px solid var(--line);
}
#data-table-wrp .table { font-size: 13px; }
#data-table-wrp .table > thead > tr > th,
#data-table-wrp .table thead th {
  padding: 8px 10px;
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-3);
  background: var(--bg-2);
  white-space: nowrap;
}
#data-table-wrp .table > tbody > tr > td {
  padding: 8px 10px;
  vertical-align: middle;
  line-height: 1.35;
}

/* FIR-42 #100/#124 + FIR-43 #6 — compact admin tables: 12px font, tight
   padding, nowrap cells. Allow horizontal scroll WHEN needed (so the
   Статус column from FIR-43 #6 and Должность from FIR-42 #124 can both
   be visible even on smaller screens), but the scrollbar is thin and
   only appears when the table actually overflows. Row click → edit. */
#data-table-wrp .table-responsive {
  overflow-x: auto;
  scrollbar-width: thin;
}
/* P2-8 — .card-body (flex-item в column-flex .card) по умолчанию имеет
   min-width:auto и потому НЕ сжимается ниже min-content своей таблицы.
   Из-за этого широкая таблица (Офисы: scrollWidth≈1269 при clientWidth≈1160)
   раздувала card-body → внутренний .table-responsive overflow-x:auto никогда
   не получал ограниченную ширину и не давал скролл — последние колонки
   (СТАТУС/Действия) уходили под правый край без скроллбара (потеря данных
   аудита). min-width:0 возвращает сжатие → .table-responsive начинает
   скроллиться. Скролл появляется только при реальном переполнении, узким
   таблицам (Страны/Города/Валюты) правило безвредно. */
#data-table-wrp .card-body { min-width: 0; }
#data-table-wrp .table-responsive::-webkit-scrollbar { height: 6px; }
#data-table-wrp .table-responsive::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 3px; }
#data-table-wrp .table { table-layout: auto; font-size: 12px; }
#data-table-wrp .table > tbody > tr > td,
#data-table-wrp .table > thead > tr > th { padding: 5px 6px; white-space: nowrap; }
#data-table-wrp .table-row { cursor: pointer; }
#data-table-wrp .table-row.table-row-even,
#data-table-wrp .table-row.table-row-odd { background: transparent; }
#data-table-wrp .table-row:hover > td { background: var(--bg-2); }

/* Name cell: name + ID inline */
/* FIR-42 #298 — раньше «Имя» и «ID: NN» рендерились в одну строку
   (display:inline). На длинных именах клиентов («Иванов Иван Иванович …»)
   ID-метка наезжала на соседнюю колонку или обрезалась с многоточием.
   ID переносится на следующую строчку под именем.
   FIR-42 #318 — раньше имя имело white-space:normal + word-break:break-word,
   и длинные системные ники («TestClient_BAD_1779294204955») рвались на 2
   строки → name(2) + ID(1) = 3 lines = 64px row, в то время как нормальные
   row-ы 47px. «Полетел стиль». Делаем имя single-line c ellipsis: row-height
   всегда = name(1) + ID(1) = ~47px. Hover в браузере покажет полное имя
   через native overflow tooltip; для UX-явного hint можно позже добавить
   data-bs-toggle="tooltip". */
#data-table-wrp .table .table-cell .fw-medium {
  display: block;
  font-weight: 500;
  color: var(--ink);
  /* FIR-42 #302 — раньше имя имело white-space:nowrap + ellipsis (см. #318).
     Юзер: «можно тут отцифровать чтобы переносы были нормальные» —
     длинные системные ники / составные имена обрезались многоточием и
     юзер не видел полное значение. Возвращаем wrap, но с break-word
     чтобы один длинный токен (TestClient_BAD_1779294204955) ломался по
     границе ширины cell-а вместо overflow-а в соседнюю колонку. */
  white-space: normal;
  word-break: break-word;
  overflow-wrap: anywhere;
  max-width: 100%;
}
#data-table-wrp .table .table-cell:has(.fw-medium) {
  min-width: 180px;
  max-width: 320px;
  white-space: normal;
  word-break: break-word;
  overflow-wrap: anywhere;
}
#data-table-wrp .table .table-cell .fw-medium + small,
#data-table-wrp .table .table-cell small.text-muted {
  display: block;
  margin-left: 0;
  margin-top: 2px;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-4);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 400;
}

/* Convert all bootstrap colored badges into our chip style */
#data-table-wrp .badge {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 8px;
  border-radius: var(--r-sm);
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
  border: 1px solid;
  line-height: 1;
}
#data-table-wrp .badge.bg-success { background: #ecfdf5 !important; color: #047857 !important; border-color: #a7f3d0; }
#data-table-wrp .badge.bg-secondary { background: var(--bg-3) !important; color: var(--ink-3) !important; border-color: var(--line); }
#data-table-wrp .badge.bg-danger { background: #fef2f2 !important; color: #991b1b !important; border-color: #fecaca; }
#data-table-wrp .badge.bg-warning { background: #fffbeb !important; color: #92400e !important; border-color: #fde68a; }
#data-table-wrp .badge.bg-primary { background: var(--accent-soft) !important; color: #3b3da3 !important; border-color: rgba(94, 106, 210, 0.25); }
#data-table-wrp .badge.bg-info { background: #ecfeff !important; color: #155e75 !important; border-color: #a5f3fc; }
#data-table-wrp .badge.bg-dark { background: var(--ink) !important; color: #fff !important; border-color: var(--ink); }

/* Telegram link */
#data-table-wrp td a[href^="https://t.me"] {
  color: var(--ink-2);
  text-decoration: none;
  font-family: var(--mono);
  font-size: 12.5px;
}
#data-table-wrp td a[href^="https://t.me"]:hover { color: var(--accent); }

/* Phone (looks like numbers in cells without class) — tabular */
#data-table-wrp td { font-variant-numeric: tabular-nums; }

/* Row action dropdown button — quieter */
#data-table-wrp .table-drop-btn {
  padding: 2px 6px;
  border: 1px solid var(--line);
  background: #fff;
  color: var(--ink-3);
  border-radius: var(--r-sm);
  box-shadow: none;
}
#data-table-wrp .table-drop-btn:hover { background: var(--bg-2); color: var(--ink); }
#data-table-wrp .table-drop-btn::after { display: none; }

/* Empty cell — visual placeholder so empty columns don't read as misalignment */
#data-table-wrp .table-cell:empty::before {
  content: "—";
  color: var(--ink-4);
  font-family: var(--mono);
  font-size: 12px;
}

/* Stock badges (Currencies table) */
#data-table-wrp .badge.stock-badge,
#data-table-wrp .stock-badge {
  background: var(--bg-3) !important;
  color: var(--ink-2) !important;
  border-color: var(--line) !important;
}

/* Search/Status/Role filter row inside the AJAX card */
#data-table-wrp .card-header .form-control,
#data-table-wrp .card-header .form-select {
  font-size: 13px;
  padding: 5px 10px;
  height: 32px;
}

/* Pagination footer */
#data-table-wrp .pagination .page-link {
  border: 1px solid var(--line);
  color: var(--ink-2);
  font-size: 13px;
}
#data-table-wrp .pagination .page-item.active .page-link {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* Ensure native <select> shows a clear chevron (no built-in arrow on Bootstrap form-select sometimes hidden) */
.form-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23737373' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") !important;
  background-repeat: no-repeat !important;
  background-position: right 10px center !important;
  background-size: 14px 14px !important;
  padding-right: 32px !important;
  appearance: none !important;
  -webkit-appearance: none !important;
  -moz-appearance: none !important;
}

/* FIR-42 #337 — Select2 ставит class `select2-hidden-accessible` на нативный
   <select>, прячет его (width:1px, clip rect 0). Но НАШИ глобальные rules
   `.modal .form-select { min-height: 36px }` + `.form-select { padding-right:
   32px !important; appearance: none !important; background-image: ... !important }`
   перебивают и оставляют native select видимым (368×36 у юзера). Native chevron
   рендерится поверх select2-wrapper, «+» button сидит на пути.

   Принудительно подавляем все наши rules для скрытых select2-инструментальных
   элементов — с !important и более высокой специфичностью (через
   :is/where + class chain).

   См. screenshot #337: select-стрелка чуть выше «+» button, потому что native
   select рисуется поверх квадрата с собственным background-image. */
select.select2-hidden-accessible,
.form-select.select2-hidden-accessible {
  width: 1px !important;
  height: 1px !important;
  min-width: 0 !important;
  min-height: 0 !important;
  max-width: 1px !important;
  max-height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  border: 0 !important;
  overflow: hidden !important;
  position: absolute !important;
  clip: rect(0, 0, 0, 0) !important;
  clip-path: inset(50%) !important;
  white-space: nowrap !important;
  background-image: none !important;
  appearance: none !important;
  -webkit-appearance: none !important;
  pointer-events: none !important;
}

/* Select2 single-select arrow — replace default purple/grey arrow */
.select2-container--default .select2-selection--single .select2-selection__arrow b {
  display: none !important;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
  width: 30px !important;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23737373' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") !important;
  background-repeat: no-repeat !important;
  background-position: center !important;
  background-size: 14px 14px !important;
}

/* Kill the absolutely-positioned bi-search icon that overlaps the input as a phantom square.
   We replace it with a clean inset lupa using the input's own background. */
#data-table-wrp .position-relative > .bi-search {
  display: none !important;
}
#data-table-wrp .position-relative > input[type="search"] {
  padding-left: 32px !important;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23737373' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E") !important;
  background-repeat: no-repeat !important;
  background-position: 9px center !important;
  background-size: 14px 14px !important;
}

/* Remove the blue/highlighted-row state on click — the hidden row-selection radio
   shouldn't drive any visual change, only :hover indicates row interactivity */
#data-table-wrp .table-row.active,
#data-table-wrp .table-row:has(input[name="row-selection"]:checked) {
  background: transparent !important;
}
#data-table-wrp .table-row.active > td,
#data-table-wrp .table-row:has(input[name="row-selection"]:checked) > td {
  background: transparent !important;
}

/* Truncated wallet/crypto address pattern: full text on .reveal-trigger click */
.addr-trunc { font-family: var(--mono); font-size: 12.5px; color: var(--ink); }
.addr-trunc .addr-eye {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px; height: 18px;
  margin-left: 4px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
  vertical-align: middle;
}
.addr-trunc .addr-eye:hover { color: var(--accent); }
.addr-trunc .addr-eye .bi { font-size: 14px; line-height: 1; }

/* Icon utility */
.ic {
  display: inline-block;
  width: 16px;
  height: 16px;
  vertical-align: middle;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.ic-sm { width: 14px; height: 14px; }
.ic-lg { width: 20px; height: 20px; }

/* FIR-42 #37 — box modal: drop inner scroll, let modal grow naturally */
#box-modal .modal-dialog-scrollable .modal-body {
  max-height: none;
  overflow-y: visible;
}

/* FIR-42 #39 — self-profile modal: compact 2-column form layout */
#self-profile-modal .modal-body .form-group { margin-bottom: 12px; }
#self-profile-modal .self-profile-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px 24px;
}
#self-profile-modal .self-profile-grid .form-group { margin-bottom: 0; }
#self-profile-modal .self-profile-pass-section {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--border, #e5e7eb);
}
@media (max-width: 575.98px) {
  #self-profile-modal .self-profile-grid { grid-template-columns: 1fr; }
}

/* FIR-42 #35 — office modal quick-add row for city/country */
/* FIR-42 #283 — «+ Новый» рядом с country/city в office-modal был
   ~75px (icon + текст «Новый»), отжирая у select-а место для
   «Россия». Прячем текст-метку — оставляем только «+» иконку
   (28×28 квадрат). title-tooltip от Bootstrap сохраняется,
   pointer accessibility сохраняется (button > i). */
/* FIR-48 #13 (финал) — «+» РОВНО по центру кнопки, детерминированно.
   Почему прошлые заходы не помогали: центрировали flex-КОНТЕНТ кнопки, а в нём
   рядом с иконкой невидимый текст «Новый» + у inline-варианта gap:6px +
   side-bearing глифа bi-plus-lg → «+» уезжал влево на ~3px; плюс два набора
   правил (28px и 36px) конфликтовали. Решение: один авторитетный селектор на
   ОБА варианта строки + пиннинг самого <i> абсолютно в центр — на центровку
   больше НЕ влияют ни сосед-текст, ни gap, ни метрики шрифта, ни конфликт. */
#office-modal .quick-add-btn {
  position: relative !important;
  flex: 0 0 auto;
  width: 36px !important;
  height: 36px !important;
  padding: 0 !important;
  gap: 0 !important;
  font-size: 0 !important;            /* прячет текст «Новый» */
  overflow: hidden;
}
#office-modal .quick-add-btn > i,
#office-modal .quick-add-btn > .bi {
  position: absolute !important;
  top: 50% !important;
  left: 50% !important;
  transform: translate(-50%, -50%) !important;
  margin: 0 !important;
  font-size: 16px !important;
  line-height: 1 !important;
}

#office-modal .quick-add-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
#office-modal .quick-add-row > select,
#office-modal .quick-add-row > .select2 {
  flex: 1 1 auto;
  min-width: 0;
}
#office-modal .quick-add-trigger {
  flex: 0 0 auto;
  white-space: nowrap;
  font-size: 12px;
  padding: 4px 10px;
  border-radius: 6px;
}
#office-modal .quick-add-form {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
}
#office-modal .quick-add-form .quick-add-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 32px;
  font-size: 13px;
}
#office-modal .quick-add-form .quick-add-save {
  background-color: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-size: 12px;
  padding: 4px 10px;
}
#office-modal .quick-add-form .quick-add-save:hover {
  background-color: var(--accent-hover);
  border-color: var(--accent-hover);
}
#office-modal .quick-add-form .quick-add-cancel {
  background-color: #e5e7eb;
  border-color: #e5e7eb;
  color: #374151;
  font-size: 12px;
  padding: 4px 10px;
}
#office-modal .quick-add-form .quick-add-cancel:hover {
  background-color: #d1d5db;
  border-color: #d1d5db;
}

/* FIR-42 #320 — те же правила для country-modal currency quick-add. */
#country-modal .quick-add-row .quick-add-btn {
  font-size: 0;
}
#country-modal .quick-add-row .quick-add-btn > i {
  font-size: 14px;
}
#country-modal .quick-add-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
#country-modal .quick-add-row > select,
#country-modal .quick-add-row > .select2 {
  flex: 1 1 auto;
  min-width: 0;
}
/* FIR-42 #337 — «+» button должна быть точно той же высоты, что select2-wrapper
   (36px), чтобы они визуально не «прыгали». Раньше height 32 (btn-sm дефолт) vs
   select2 36 → 2px разница, кажется что «+» сидит ниже chevron-а select-а. */
#country-modal .quick-add-trigger {
  flex: 0 0 auto;
  white-space: nowrap;
  font-size: 12px;
  padding: 0 10px;
  border-radius: 6px;
  height: 36px;
  min-width: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
#country-modal .quick-add-form {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
  flex-wrap: wrap;
}
#country-modal .quick-add-form .quick-add-input,
#country-modal .quick-add-form .quick-add-full-name {
  height: 32px;
  font-size: 13px;
}
/* FIR-42 #335 — раньше тут было `flex: 1 1 160px` потому что .quick-add-full-name
   был direct flex-item родителя .quick-add-form (row). После #332 input обёрнут
   в .quick-add-field { display: flex; flex-direction: column }, и flex: 1 1 160px
   на input-е в column-flex-контексте задаёт flex-basis = 160px ВЫСОТЫ — поле
   разрастается до 160px height вместо нормальных 32px. См. скрин #335.
   Flex теперь на wrapper-е (.quick-add-field--grow), input просто width: 100%. */
#country-modal .quick-add-form .quick-add-full-name {
  min-width: 0;
  width: 100%;
  height: 32px;
  flex: none;
}
/* FIR-48 #70 — серый × близ заголовка quick-add (вместо «Отмена»-кнопки).
   Кликнул → блок сворачивается, поля очищаются, плюсик возвращается. Никакого
   фиолетового «Сохранить» внутри: и валюту, и страну сохраняет нижняя «Сохранить»
   модалки. B&W театр — у × нет фона, hover — чернеет. position:absolute на правом
   верхнем углу .quick-add-form (parent → position:relative). */
#country-modal .quick-add-form {
  position: relative;
}
#country-modal .quick-add-form .quick-add-close-x {
  position: absolute;
  top: 0;
  right: 0;
  width: 20px;
  height: 20px;
  padding: 0;
  border: 0;
  background: transparent;
  color: #9ca3af;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  transition: color 0.12s ease;
}
#country-modal .quick-add-form .quick-add-close-x:hover,
#country-modal .quick-add-form .quick-add-close-x:focus {
  color: var(--ink);
  outline: none;
  background: transparent;
}
/* Inline-ошибка под ISO-полем (дубль и т.п.). Bootstrap invalid-feedback
   показывается только когда у соседнего .form-control есть .is-invalid;
   нам же нужно показывать программно — добавляем .quick-add-error.show. */
#country-modal .quick-add-form .quick-add-error {
  font-size: 11.5px;
  color: #dc2626;
  margin-top: 2px;
  display: none;
}
#country-modal .quick-add-form .quick-add-error.show {
  display: block;
}

/* FIR-42 #331 — country-modal layout: убираем пустые строки когда раскрыт
   quick-add «+ Новая валюта». До фикса: modal-form — 2-col grid (1fr 1fr),
   align-items: start. БВ-колонка с открытым quick-add разрастается вниз
   (ISO + Полное название + Фиат + Сохранить + Отмена wrap-аются в 4-5
   рядов), а «Название» слева остаётся высотой 36px → справа большая
   пустая полоса. Скрин #331.

   Fix:
   1. `:has(.quick-add-form:not(.d-none))` — row БВ расширяется на оба
      столбца grid'а когда quick-add открыт. Quick-add разворачивается
      горизонтально в одну строку, нижние поля Поддерж.валюты + Статус
      выравниваются ниже без gap-ов. Когда quick-add закрыт — обычное
      2-col поведение восстанавливается.
   2. Quick-add inputs внутри full-width row: ISO ширина 90px, тип 100px,
      полное название flex, кнопки 32px высоты. Всё в одну строку.

   :has() поддерживается в Chrome 105+ / Safari 15.4+ / FF 121+. На старых
   браузерах degrades gracefully — будет старое поведение с empty-row. */
@media (min-width: 768px) {
  /* БВ-row span-2 когда раскрыт quick-add */
  #country-modal .modal-form > .row.form-group:has(.quick-add-form:not(.d-none)) {
    grid-column: 1 / -1;
  }
  /* Поддерж. валюты тоже span-2 в этом сценарии — иначе одинокая клетка
     слева и пустота справа в ряду 3. С полной шириной select2-мультиселект
     получает больше места для чипов валют. */
  #country-modal .modal-form:has(.quick-add-form:not(.d-none)) > .row.form-group:has(#country-supported-currency-ids) {
    grid-column: 1 / -1;
  }
}
/* Когда БВ-row span-2 — quick-add встаёт в одну строку без wrap.
   Полное название занимает оставшееся место (flex: 1) */
/* FIR-42 #332 — quick-add-field обёртки: label + input стопкой,
   ряды flex aligned bottom. Каждое поле имеет видимый micro-label,
   чтобы пользователь понимал что вводит без placeholder-guessing. */
#country-modal .quick-add-form {
  flex-wrap: nowrap;
  align-items: flex-end;
  gap: 8px;
}
.quick-add-field {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 0 0 auto;
  min-width: 0;
}
.quick-add-field--grow {
  flex: 1 1 auto;
}
.quick-add-label {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-3);
  font-weight: 500;
  margin: 0;
  line-height: 1.1;
}
.quick-add-actions {
  display: flex;
  gap: 6px;
  align-items: center;
  flex: 0 0 auto;
}
/* Размеры внутри full-width БВ-row (когда quick-add открыт) */
#country-modal .modal-form > .row.form-group:has(.quick-add-form:not(.d-none)) .quick-add-form .quick-add-field:has(.quick-add-input) {
  flex: 0 0 110px;
}
#country-modal .modal-form > .row.form-group:has(.quick-add-form:not(.d-none)) .quick-add-form .quick-add-field:has(.quick-add-currency-type) {
  flex: 0 0 110px;
}
#country-modal .modal-form > .row.form-group:has(.quick-add-form:not(.d-none)) .quick-add-form .quick-add-field--grow {
  flex: 1 1 auto;
}
#country-modal .modal-form > .row.form-group:has(.quick-add-form:not(.d-none)) .quick-add-form .quick-add-input,
#country-modal .modal-form > .row.form-group:has(.quick-add-form:not(.d-none)) .quick-add-form .quick-add-full-name,
#country-modal .modal-form > .row.form-group:has(.quick-add-form:not(.d-none)) .quick-add-form .quick-add-currency-type {
  max-width: none;
  width: 100%;
  height: 32px;
}
/* FIR-48 #70 — раньше тут сидели .quick-add-save / .quick-add-cancel (height:32px),
   они теперь полностью удалены из DOM (сабмит — нижней кнопкой страны, отмена —
   серым × в правом верхнем углу .quick-add-form). Никаких inline-actions. */
/* Статус-row справа от Название (бывает скучно занимает половину пустотой,
   когда нет supported-валют) — компактим toggle. Без изменения markup-а. */
#country-modal .modal-form > .row.form-group:last-of-type .switch,
#country-modal .modal-form > .row.form-group:has(#country-status) .switch {
  flex: 0 0 auto;
}

/* ============================================================
   FIR-42 #56 / #67 — modal polish for office and user modals
   ------------------------------------------------------------
   Goal: kill the "wallet on two rows" problem, tighten the
   spacing, and standardise the "+ Новый" inline quick-add
   button across every modal that grows a related row.
   ============================================================ */

/* Tighten vertical rhythm in the redesigned office modal and any modal
   using inline quick-adds — drops blank space without crowding labels. */
#office-modal.office-modal-redesign .modal-body,
#user-modal .modal-body {
  padding-top: 14px;
  padding-bottom: 8px;
}
#office-modal.office-modal-redesign .form-group,
#user-modal .form-group {
  margin-bottom: 10px;
}
#office-modal.office-modal-redesign .form-control,
#office-modal.office-modal-redesign .form-select,
#user-modal .form-control,
#user-modal .form-select {
  min-height: 32px;
  font-size: 13.5px;
}
#office-modal.office-modal-redesign .form-label,
#user-modal .form-label {
  font-size: 13px;
  display: flex;
  align-items: center;
  min-height: 32px;
  margin-bottom: 0;
}

/* Inline quick-add row used in office and user modals.
   FIR-42 #77 — must stay on a single visual row even when the select is
   a multi-select that grows in height. Layout:
   [ select grows ][ "+ Новый" button hugs right ] — one row, no wrap. */
.quick-add-row--inline {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: nowrap;
  width: 100%;
}
/* #90 — wallet chip + "Новый" button MUST fit in one row. Shrink chip
   font + tighten paddings inside the multi-select container. */
.quick-add-row--inline .select2-container--default .select2-selection--multiple .select2-selection__choice {
  font-size: 11px !important;
  padding: 0 5px !important;
  margin: 1px 2px !important;
  line-height: 18px !important;
  max-width: 130px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.quick-add-row--inline .select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
  margin-right: 3px !important;
  font-size: 13px !important;
}
.quick-add-row--inline .select2-container--default .select2-selection--multiple {
  min-height: 36px !important;
  padding: 1px 4px !important;
  display: flex !important;
  align-items: center;
  flex-wrap: wrap;
}
/* #89 — kill phantom hit-zone between Select2 dropdown and chips. The
   gap is rendered by select2's __rendered <ul> with stray padding.
   Lock its bg and remove the hoverable strip. */
.quick-add-row--inline .select2-container--default .select2-selection--multiple .select2-selection__rendered {
  padding: 0 !important;
  margin: 0 !important;
  display: flex !important;
  flex-wrap: wrap;
  align-items: center;
}
.quick-add-row--inline > select,
.quick-add-row--inline > .select2,
.quick-add-row--inline > .select2-container {
  flex: 1 1 auto;
  min-width: 0;
  width: 100% !important; /* override select2 inline width */
  /* FIR-42 #204 — strict overflow gate: чипы НИКОГДА не должны заходить за
     правую границу select-container, и тем более под соседнюю кнопку «+Новый».
     overflow:hidden обрезает «хвост» chip-а, max-width:100% не даёт
     контейнеру расширяться сверх своего flex-allocation. */
  overflow: hidden;
  max-width: 100%;
}
/* FIR-42 #202 — чипы внутри inline-row выкладываются в одну строку с
   горизонтальным скроллом при переполнении (а не в 3 ряда под кнопкой).
   Если их много — пользователь скроллит горизонтально внутри select-а. */
.quick-add-row--inline .select2-container--default .select2-selection--multiple .select2-selection__rendered {
  flex-wrap: nowrap !important;
  overflow-x: auto !important;
  overflow-y: hidden !important;
  scrollbar-width: thin;
}
.quick-add-row--inline .select2-container--default .select2-selection--multiple .select2-selection__rendered::-webkit-scrollbar {
  height: 4px;
}
.quick-add-row--inline .select2-container--default .select2-selection--multiple .select2-selection__rendered::-webkit-scrollbar-thumb {
  background: var(--line);
  border-radius: 2px;
}
/* FIR-42 #72 — solid, fully-visible button matching the design system.
   Previously the button used pale gray fills (#f3f4f6 / #e5e7eb) that
   read as semi-transparent against the modal body. Switch to the ink
   palette: white bg + solid ink border + ink text → unambiguously visible. */
.quick-add-row--inline .quick-add-btn {
  flex: 0 0 auto;
  white-space: nowrap;
  font-size: 13px;
  font-weight: 500;
  padding: 6px 14px;
  border-radius: var(--r-lg);
  background-color: #ffffff !important;
  border: 1px solid var(--ink) !important;
  color: var(--ink) !important;
  opacity: 1;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  line-height: 1.2;
  height: 36px;
  align-self: center;
}
.quick-add-row--inline .quick-add-btn:hover,
.quick-add-row--inline .quick-add-btn:focus {
  background-color: var(--ink) !important;
  border-color: var(--ink) !important;
  color: #ffffff !important;
  opacity: 1;
}
.quick-add-row--inline .quick-add-btn .bi,
.quick-add-row--inline .quick-add-btn .quick-add-btn-label {
  color: inherit !important;
}
.quick-add-row--inline .quick-add-btn:focus {
  box-shadow: 0 0 0 3px rgba(10, 10, 10, 0.12);
  outline: none;
}
.quick-add-row--inline .quick-add-btn .bi {
  font-size: 12px;
}
/* FIR-42 #81 — defensively re-assert label visibility on the wallet quick-add
   button. Some Bootstrap/select2 cascades had collapsed the inline " Новый"
   text node to a 0-width / transparent state, making the button look like an
   empty bordered rectangle. Wrapping the word in a <span class="quick-add-btn-label">
   and pinning the colour + display below keeps the text on-screen regardless
   of the surrounding rules. */
.quick-add-row--inline .quick-add-btn .quick-add-btn-label {
  color: inherit;
  display: inline-block;
  font-size: inherit;
  font-weight: inherit;
  line-height: 1.2;
  margin-left: 4px;
  opacity: 1;
  visibility: visible;
  white-space: nowrap;
}
.quick-add-row--inline .quick-add-btn:hover .quick-add-btn-label,
.quick-add-row--inline .quick-add-btn:focus .quick-add-btn-label {
  color: inherit;
}

/* FIR-42 #82(b) — Примечание stays short; clamp the height to ~60px
   so it doesn't eat the modal. */
.user-description-short {
  max-height: 60px;
  min-height: 40px;
  resize: vertical;
}

/* FIR-42 #80 — compact delete modal: small dialog (480px max), no empty
   body padding waste. The .delete-modal-dialog class is added inline on
   the .modal-dialog so we can target without bleeding into other small
   modals. */
.delete-modal-dialog.modal-dialog {
  max-width: 440px !important;
}
/* FIR-48 #68 — kill the 2-col grid inherited from .modal-form on the
   delete-form. Delete-modal не содержит form-group полей — только
   single-column колонку «explainer + input» + footer. */
#delete-modal .modal-form {
  display: block;
}
#delete-modal .modal-form > .modal-footer {
  width: auto;
}
#delete-modal .modal-content {
  border-radius: 12px;
}
#delete-modal .modal-header {
  padding: 14px 18px 12px 18px;
  border-bottom: 1px solid var(--line);
}
#delete-modal .modal-header .modal-title {
  font-size: 15px;
  font-weight: 500;
  margin: 0;
}
/* #87 — kill the empty gap between header and footer; pull footer up tight. */
#delete-modal .modal-footer {
  padding: 12px 18px;
  border-top: 0;
  gap: 8px;
}
/* FIR-42 #318 — раньше тут стоял display:none (наследие #80, когда modal-body
   действительно был пустым padding-wrapper-ом). После #292 в modal-body живёт
   type-to-confirm input + explainer-фраза. display:none скрывал их полностью —
   user видел только заголовок «Удалить ... ?» и две кнопки, кнопка «Удалить»
   permanently disabled, ничего нельзя было удалить из справочников. Возвращаем
   нормальный padding, но компактный (12-14px), без «empty gap». */
#delete-modal .modal-body {
  padding: 16px 20px 18px 20px;
}
/* FIR-42 #335 — центрируем содержимое body: explainer-текст + фраза + input
   выровнены по центру dialog'а. Раньше всё прижато к левому краю с явно
   тесным wrap-ом текста (см. скрин #335: «Чтобы подтвердить\nудаление,\nвведите ниже\nфразу: удалить TC_...»
   на 4 строки в узком 440px dialog'е). Текст ровный, input центрирован,
   удобнее читается. */
#delete-modal .coex-delete-explainer {
  text-align: center;
  line-height: 1.5;
  margin-bottom: 12px !important;
}
#delete-modal .coex-delete-phrase {
  display: inline-block;
  margin-top: 4px;
}
#delete-modal .coex-delete-confirm-input {
  text-align: center;
  max-width: 320px;
  margin: 0 auto;
  display: block;
}
#delete-modal .coex-delete-mismatch {
  text-align: center;
  margin-top: 6px;
}

/* FIR-48 #68 — inline notice "запись активна" */
#delete-modal .coex-delete-active-alert {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 10px 12px;
  margin: 0 0 12px 0;
  border: 1px solid var(--ink-2);
  border-radius: var(--r);
  background: var(--bg-2);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.4;
  text-align: left;
}
#delete-modal .coex-delete-active-alert[hidden] {
  display: none;
}
#delete-modal .coex-delete-active-alert__icon {
  flex: 0 0 auto;
  font-size: 16px;
  line-height: 1.2;
  color: var(--ink-2);
}
#delete-modal .coex-delete-active-alert__text {
  flex: 1 1 auto;
  min-width: 0;
}

/* Make Select2 inside the inline row line up with the button height
   and never collapse below it. multi-select grows downward but the
   button stays centred — no wrap to a 2nd or 3rd line. */
.quick-add-row--inline .select2-container--default .select2-selection--single,
.quick-add-row--inline .select2-container--default .select2-selection--multiple {
  min-height: 36px;
}

/* ============================================================
   FIR-42 v4 fixes (##34b, 38, 40)
   ============================================================ */

/* #34b — role chips: stronger fills (was too washed out, especially
   "Сотрудник" which user called бледный) */
#data-table-wrp .badge.bg-warning {
  background: #fde68a !important;
  color: #78350f !important;
  border-color: #fbbf24 !important;
}
#data-table-wrp .badge.bg-danger {
  background: #fecaca !important;
  color: #7f1d1d !important;
  border-color: #f87171 !important;
}
#data-table-wrp .badge.bg-success {
  background: #bbf7d0 !important;
  color: #14532d !important;
  border-color: #4ade80 !important;
}
#data-table-wrp .badge.bg-primary {
  background: #c7d2fe !important;
  color: #312e81 !important;
  border-color: #818cf8 !important;
}
#data-table-wrp .badge.bg-info {
  background: #a5f3fc !important;
  color: #0e7490 !important;
  border-color: #22d3ee !important;
}

/* #40 — operator "Настроить" button — was bright indigo .btn-primary,
   user calls it «ужасный цвет». Demote to secondary outline. */
.switcher-button.btn.btn-primary,
label.switcher-button.btn-primary {
  background: #fff !important;
  border: 1px solid var(--line-strong) !important;
  color: var(--ink) !important;
  box-shadow: none !important;
}
.switcher-button.btn.btn-primary:hover,
label.switcher-button.btn-primary:hover {
  background: var(--bg-2) !important;
  border-color: var(--accent) !important;
  color: var(--accent) !important;
}
.switcher-button.btn.btn-primary i,
label.switcher-button.btn-primary i { color: inherit !important; }

/* #38 — global density: shave another ~25% off vertical paddings */
.coex-main { padding: 14px 22px 60px; }
.card-body { padding: 14px; }
.card-header { padding: 10px 14px; }
.coex-page-title h1 { font-size: 20px; }
.coex-page-title { margin-bottom: 4px; }
.coex-page-sub { font-size: 13px; margin-bottom: 14px; }
.coex-topbar { padding-bottom: 12px; margin-bottom: 16px; }
.coex-kpis { gap: 10px; margin-bottom: 16px; }
.coex-kpi { padding: 10px 14px; }
.coex-kpi .k-value { font-size: 19px; }
.coex-kpi .k-label { margin-bottom: 4px; }
.table-wrap { margin-bottom: 16px !important; }
/* FIR-42 #272 — выравниваем вертикальный ритм карточек на admin-balances /
   admin-debts. Раньше table-wrap'ы шли через inline margin-bottom:24px
   + ещё mb-3/mt-3 на чартах = неровные «дырки» между блоками. Унификация:
   .coex-card / .table-wrap = 16px стабильный gap. Все строки внутри
   per-office summary grid выровнены через align-items:stretch. */
.coex-card { margin-bottom: 16px; }
.coex-card + .coex-card { margin-top: 0 !important; }
.coex-app .row > [class*="col-"] > .table-wrap,
.coex-app .row > [class*="col-"] > .card { height: 100%; }
.coex-app .row.g-3.coex-stretch { align-items: stretch; }
/* Per-office summary card: убираем «провисание» когда секции разной
   высоты — нижние границы align. */
.coex-app .table-wrap > .coex-filters { padding: 10px 16px; }
.coex-app .table-wrap > .table-responsive > .table th,
.coex-app .table-wrap > .table-responsive > .table td { padding: 8px 12px; }
#data-table-wrp .table > thead > tr > th { padding: 7px 10px; }
#data-table-wrp .table > tbody > tr > td { padding: 7px 10px; }
/* FIR-42 #83 — density override: spacing via row-gap on parent grid, not
   margin-bottom on each row, so hover hit-zones don't bleed into the gap. */
.modal-form { row-gap: 7px; }
.modal-form > .row.form-group { margin-bottom: 0 !important; }
.modal-form .form-fields.card { padding: 10px 12px !important; margin: 4px 0 10px !important; }
.coex-template-row { gap: 6px; }
.coex-template-btn { padding: 5px 10px; }
.fw-bold.text-success.fs-5,
.fw-bold.text-danger.fs-5,
.fw-bold.text-muted.fs-5 { font-size: 13.5px !important; }
.coex-sidebar { padding: 14px 10px; gap: 12px; }
.coex-sidebar > div + div { margin-top: 2px; }
.coex-nav-group-label { padding: 0 8px 4px; }
.coex-nav li a { padding: 5px 8px; font-size: 13px; }

/* #53 — chevron direction reflects collapse state.
   - Submenu OPEN  (aria-expanded="true")  → arrow points UP  (click to collapse).
   - Submenu CLOSED (aria-expanded="false") → arrow points DOWN (click to expand).
   We ship a single chevron-down SVG and flip it via transform when open. Target
   only the trailing chevron (.ic-sm with margin-left:auto), not the leading
   row icon. */
/* No transition — theme-metis.css ships a broken `.fade` pattern that
   stalls Web Animations at progress=0; same hazard freezes a transitioned
   transform here. Snap instead. */
.coex-sidebar .coex-collapse-toggle .ic.ic-sm,
.coex-sidebar [data-bs-toggle="collapse"] .ic.ic-sm {
	transition: none !important;
	transform: rotate(0deg) !important;
}
.coex-sidebar .coex-collapse-toggle[aria-expanded="true"] .ic.ic-sm,
.coex-sidebar [data-bs-toggle="collapse"][aria-expanded="true"] .ic.ic-sm {
	transform: rotate(180deg) !important;
}

/* FIR-42 #62 — admin-permissions matrix (was inline in admin-permissions.php).
   Monochrome checkbox styling for the role × permission matrix. theme-metis.css
   ships an indigo .form-check-input:checked rule, so every selector here keeps
   the !important from the original inline block — removing it lets the theme
   recolour the checks. The rules cover base, hover, focus, checked, disabled,
   and disabled+checked states, plus a couple of layout helpers for the table. */
#perms-matrix .perm-toggle.form-check-input,
#perms-matrix .perm-toggle {
	width: 16px;
	height: 16px;
	background-color: #fff !important;
	border: 1.5px solid var(--ink-3) !important;
	border-radius: 3px;
	margin: 0;
	box-shadow: none !important;
	cursor: pointer;
}
#perms-matrix .perm-toggle:hover:not(:disabled) {
	border-color: var(--ink) !important;
}
#perms-matrix .perm-toggle:focus {
	outline: 2px solid var(--ink-3);
	outline-offset: 1px;
}
#perms-matrix .perm-toggle.form-check-input:checked,
#perms-matrix .perm-toggle:checked,
#perms-matrix input.form-check-input.perm-toggle:checked {
	background-color: var(--ink) !important;
	border-color: var(--ink) !important;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2.5' d='m3.5 8.5 3 3 6-7'/%3E%3C/svg%3E") !important;
}
#perms-matrix .perm-toggle:disabled {
	opacity: 0.5;
	cursor: not-allowed;
	background-color: var(--bg-2);
}
/* FIR-42 #328 — disabled-checked раньше был --ink-3 (серый), а обычный
   :checked — --ink (чёрный). Создавало визуальный микс: «Часть серой
   заливки, часть чёрной». Унифицируем — все checked одного цвета;
   disabled остаётся opacity:0.5 (см. выше) для визуального cue. */
#perms-matrix .perm-toggle:disabled:checked {
	background-color: var(--ink) !important;
	border-color: var(--ink) !important;
}
#perms-matrix th,
#perms-matrix td {
	vertical-align: middle;
}
#perms-matrix .perm-group-row td {
	padding: 8px 12px;
}

/* FIR-42 #79 — removed .operator-name-* rules. The per-user operator
   AJAX submenu (commit ed1529e, FIR-42 #75) was reverted; the sidebar
   now uses a static "Сотрудники" group covering the 4 employee-class
   roles, rendered server-side as regular .role-button items. */

/* #54 — sticky bulk-action bar that appears under the operations table when
   one or more rows are checked. Stays fixed to the bottom of the viewport so
   the action stays reachable while scrolling long lists. */
.ops-bulk-bar {
	position: fixed;
	left: 50%;
	bottom: 18px;
	transform: translateX(-50%);
	z-index: 1040;
	background: var(--ink, #111);
	color: #fff;
	padding: 10px 16px;
	border-radius: 999px;
	display: inline-flex;
	align-items: center;
	gap: 14px;
	font-size: 13px;
	box-shadow: 0 6px 24px rgba(0,0,0,0.18);
}
.ops-bulk-bar .btn { padding: 4px 12px; }

/* FIR-42 #78 — restore visible modals.
   theme-metis.css ships `.fade { transition: opacity .15s linear; }` plus
   `.fade:not(.show) { opacity:0 }` but no `.fade.show { opacity:1 }`. The
   missing rule plus a stale Web Animation in this bundle freezes the
   transition at progress=0 → modal sits in DOM at opacity:0 invisibly.
   Fix: kill the transition AND force opacity:1 with !important so neither
   theme-metis nor a stuck animation can override us. */
.modal.fade,
.fade {
	transition: none !important;
}
.modal.fade.show,
.fade.show {
	opacity: 1 !important;
}
.modal.fade:not(.show),
.fade:not(.show) {
	opacity: 0 !important;
}
.modal-backdrop.fade.show {
	opacity: var(--bs-backdrop-opacity, 0.5) !important;
}

/* FIR-42 #23 — compact 2-column layout for operator-accounting and operator-exchange.
   Получили + Отдали fieldsets float side-by-side; everything else spans full width.
   :has() supported in all evergreen browsers (Chromium 105+, Safari 15.4+, Firefox 121+). */
@media (min-width: 992px) {
	#main-form.accounting > .duplicate-wrapper,
	#main-form.exchange > .duplicate-wrapper {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: 14px;
		align-items: start;
	}
	/* Every direct child spans full width by default… */
	#main-form.accounting > .duplicate-wrapper > *,
	#main-form.exchange > .duplicate-wrapper > * {
		grid-column: 1 / -1;
		margin-top: 0 !important;
	}
	/* …except the Получили (text-success) and Отдали (text-danger) blocks. */
	#main-form.accounting > .duplicate-wrapper > fieldset:has(.fw-bold.text-success.fs-5),
	#main-form.exchange > .duplicate-wrapper > fieldset:has(.fw-bold.text-success.fs-5) {
		grid-column: 1 / 2;
	}
	#main-form.accounting > .duplicate-wrapper > fieldset:has(.fw-bold.text-danger.fs-5),
	#main-form.exchange > .duplicate-wrapper > fieldset:has(.fw-bold.text-danger.fs-5) {
		grid-column: 2 / 3;
	}
	/* Inner col-3 cells inside the narrower column stretch to fit. */
	#main-form.accounting .duplicate-block-get .row .col-3,
	#main-form.accounting .duplicate-block-give .row .col-3,
	#main-form.exchange .duplicate-block-get .row .col-3,
	#main-form.exchange .duplicate-block-give .row .col-3 {
		flex: 1 1 0;
		max-width: none;
	}
}

/* FIR-42 #22 — inline доход/расход reveal panel (vs. modal click-through). */
.income-front-inline,
.outcome-front-inline {
	background: var(--bg-2, #fafafa);
	border: 1px dashed var(--line-strong, #ddd);
	border-radius: var(--r, 6px);
	padding: 12px 14px;
	margin: 8px 12px 12px;
}
.income-front-inline.d-none,
.outcome-front-inline.d-none { display: none !important; }
/* FIR-51 #12 (баг 690) — inline-панель дохода/расхода на accounting/exchange:
   форма переезжает из модалки (scripts.js ~7194 inlineMode) ВМЕСТЕ с классом
   .modal-form, и ряд «Офис (col-6) + Тип кассы (col-6)» попадал под грид-правило
   `.modal-form > .row.form-group { grid-template-columns: 110px 1fr }` (~739
   и media ≥768px) → «Офис» зажимался в 110px label-колонку, select2 89px,
   текст «М…» вместо «МСК». Внутри inline-панелей возвращаем обычный
   bootstrap-row флоу (флекс), обе панели — income и outcome — одинаково. */
.income-front-inline .modal-form > .row.form-group,
.outcome-front-inline .modal-form > .row.form-group,
.income-front-inline .modal-form .row.form-group,
.outcome-front-inline .modal-form .row.form-group {
	display: flex !important;
	flex-wrap: wrap;
	grid-template-columns: none !important;
	overflow: visible;
}
/* Inline-панель шире модалки — 2-col grid самого .modal-form (media ≥768px,
   «compact admin modals») внутри панели не нужен: поля идут сверху вниз на
   всю ширину, как юзер видит панель дохода. */
@media (min-width: 768px) {
	.income-front-inline .modal-form,
	.outcome-front-inline .modal-form {
		display: block;
	}
}
/* FIR-51 Bundle E #2 — те же ряды «Офис (col-6) + Тип кассы (col-6)» в
   НАСТОЯЩИХ модалках income/outcome-front (operator-consult.php:1129/1201,
   operator-balancing.php:707; те же id живут в operator-accounting/exchange
   как модальный fallback) оставались под гридом
   `.modal-form > .row.form-group { 110px 1fr }` → «МСК» резалось в «М…».
   Тот же подход, что для inline-панелей выше (57397e3): возвращаем
   bootstrap-flex внутри этих модалок. */
#income-front-modal .modal-form > .row.form-group,
#outcome-front-modal .modal-form > .row.form-group,
#income-front-modal .modal-form .row.form-group,
#outcome-front-modal .modal-form .row.form-group {
	display: flex !important;
	flex-wrap: wrap;
	grid-template-columns: none !important;
	overflow: visible;
}
/* 2-col grid самого .modal-form (media ≥768px, «compact admin modals»)
   в этих модалках тоже не нужен: поля идут сверху вниз, как в инлайне. */
@media (min-width: 768px) {
	#income-front-modal .modal-form,
	#outcome-front-modal .modal-form {
		display: block;
	}
}
/* FIR-51 finisher #4 — модалка «Добавить долговую операцию»
   (operator-debt.php ~708, #debt-line-form внутри #debt-line-modal):
   ряды «Тип» (col-12) и «Касса (col-6) + Контрагент (col-6)» попадали под
   тот же грид `.modal-form > .row.form-group { 110px 1fr }` → select2
   зажимался, «МСК» резалось. Тот же подход, что Bundle E #2 выше:
   возвращаем bootstrap-flex внутри этой модалки. */
#debt-line-modal .modal-form > .row.form-group,
#debt-line-modal .modal-form .row.form-group {
	display: flex !important;
	flex-wrap: wrap;
	grid-template-columns: none !important;
	overflow: visible;
}
@media (min-width: 768px) {
	#debt-line-modal .modal-form {
		display: block;
	}
}
.income-front-inline .modal-footer,
.outcome-front-inline .modal-footer {
	border-top: 1px solid var(--line, #eee);
	padding-top: 10px;
	margin-top: 8px;
	border-bottom: 0;
}

/* FIR-42 #136 — красная подсветка незаполненных required-полей при попытке
   сохранить. Bootstrap .is-invalid дает border на нативном input/select;
   .coex-invalid-s2 подкрашивает обёртку select2-container, потому что
   сам native <select> у select2 скрыт display:none. */
.select2-container.coex-invalid-s2 .select2-selection {
	border-color: var(--bs-danger, #dc3545) !important;
	box-shadow: 0 0 0 0.15rem rgba(220, 53, 69, 0.18);
}
.coex-invalid:not(.select2-hidden-accessible) {
	border-color: var(--bs-danger, #dc3545) !important;
	box-shadow: 0 0 0 0.15rem rgba(220, 53, 69, 0.18);
}

/* FIR-43 #23 — те же подсветки через классы которые навешивает save.js
   pre-submit validator (consistent naming с jQuery-side). Дублируем
   правила для is-invalid-select2 чтобы select2-wrapped поля тоже горели. */
.select2-container.is-invalid-select2 .select2-selection,
.select2-container.is-invalid-select2 .select2-selection--multiple,
.select2-container.is-invalid-select2 .select2-selection--single {
	border-color: var(--bs-danger, #dc3545) !important;
	box-shadow: 0 0 0 0.15rem rgba(220, 53, 69, 0.18) !important;
}
select.is-invalid,
textarea.is-invalid {
	border-color: var(--bs-danger, #dc3545) !important;
	box-shadow: 0 0 0 0.15rem rgba(220, 53, 69, 0.18);
}

/* FIR-43 #49 — подсветка несовпадения сумм яркее (двух-сторонняя проверка
   суммы в Покупки/Продажи / Обмен). Раньше border был светло-розовый
   (rgba 0.18 = 18% alpha) — оператор глаза скользили мимо, и форма
   сохранялась с битым балансом. Теперь жирный 2px красный border с
   насыщенным glow + фоновая подсветка. Действует только на поля сумм
   приёма/выдачи (.get-to-amount / .give-to-amount) — на остальных
   required-полях сохраняется стандартная Bootstrap подсветка. */
/* FIR-43 #49 — «ярче красным»: жирнее border, насыщеннее заливка, сильнее
   glow. Цвет text-color затемнили до #5B0F0F для контраста на #FECACA
   фоне; font-weight 700 чтобы цифры читались как ошибка с первого
   взгляда. Pulse-анимация привлекает внимание сразу после save-attempt. */
.form-control.get-to-amount.is-invalid,
.form-control.give-to-amount.is-invalid,
input.get-to-amount.is-invalid,
input.give-to-amount.is-invalid {
	border: 2.5px solid #B91C1C !important;
	background-color: #FECACA !important;
	box-shadow: 0 0 0 0.28rem rgba(185, 28, 28, 0.45) !important;
	color: #5B0F0F !important;
	font-weight: 700;
	animation: coex-invalid-pulse 0.8s ease-in-out 2;
}
.form-control.get-to-amount.is-invalid:focus,
.form-control.give-to-amount.is-invalid:focus {
	border-color: #991B1B !important;
	box-shadow: 0 0 0 0.32rem rgba(153, 27, 27, 0.55) !important;
}
@keyframes coex-invalid-pulse {
	0%, 100% { box-shadow: 0 0 0 0.28rem rgba(185, 28, 28, 0.45); }
	50%      { box-shadow: 0 0 0 0.5rem  rgba(185, 28, 28, 0.7); }
}

/* FIR-43 #23 — общий ярче-красный для любых .is-invalid когда они отмечены
   серверной ошибкой (save.js навешивает is-invalid). Тонкий border мало
   заметен — увеличиваем до 2px + glow. Это базовый стиль, специфичные
   .get-to-amount / .give-to-amount выше его перекрывают (более интенсивно). */
.form-control.is-invalid,
input.is-invalid,
select.is-invalid,
textarea.is-invalid {
	border-width: 2px !important;
}

/* FIR-42 #151 — Получили / Отдали side-by-side, курс под ними.
   Бухгалтерская симметрия: in-side слева, out-side справа, на одной
   высоте; глаз воспринимает их как одну операцию с двумя сторонами.
   На мобилках (md и ниже) сворачивается в стек естественно через
   col-12. Ниже одна compact рабочая полоска курсов. */
.coex-exchange-row > [class*="col-"] > .fieldset-container {
	width: 100%;
}
.coex-exchange-row .float-none.w-100 {
	padding-left: 1rem;
	padding-right: 1rem;
}
.coex-rate-card {
	max-width: 920px;
	margin-left: auto;
	margin-right: auto;
}
.coex-rate-card .rate-course-header {
	font-variant: small-caps;
	letter-spacing: 0.03em;
}
/* Когда заголовок RUB → USDT — компактнее inputs (только курс). #108
   уже скрывает .rate из JS, не CSS, но добавим тонкую двух-колоночную
   подложку для случая когда видны все 4. */
.coex-rate-card .row.g-1 input[type="number"] {
	font-variant-numeric: tabular-nums;
}

/* FIR-42 #152 — chevron animation на collapse-кнопках. Bootstrap data-bs-toggle
   меняет aria-expanded; крутим chevron через CSS transform для визуальной
   обратной связи "развернуто/свернуто". UI-rule §7 state-transition. */
.coex-template-more .bi-chevron-down,
[data-bs-toggle="collapse"] .bi-chevron-down,
[data-bs-toggle="collapse"] .bi-chevron-right {
	transition: transform 0.2s ease;
}
.coex-template-more[aria-expanded="true"] .bi-chevron-down,
[data-bs-toggle="collapse"][aria-expanded="true"] .bi-chevron-down {
	transform: rotate(180deg);
}
[data-bs-toggle="collapse"][aria-expanded="true"] .bi-chevron-right {
	transform: rotate(90deg);
}

/* FIR-42 #151 — Долг нам/мы/Списать в 99% не используются. Прячем их за
   small toggle "+ Долг", раскрываем по клику. Сама структура (col-2/col-2/
   col-auto) остаётся неизменной для save.js, только display:none по
   умолчанию. JS добавляет .coex-debt-shown к .coex-debt-row на клике
   соседней кнопки .coex-debt-toggle. */
.coex-debt-row {
	display: none;
}
.coex-debt-row.coex-debt-shown {
	display: flex;
	gap: 0.5rem;
	align-items: flex-end;
	flex-wrap: wrap;
	margin-top: 0.25rem;
}
.coex-debt-toggle {
	font-size: 12px;
	color: var(--ink-3);
	background: transparent;
	border: 1px dashed var(--line);
	border-radius: var(--r-sm, 6px);
	padding: 2px 8px;
	cursor: pointer;
	transition: all 0.15s ease;
}
.coex-debt-toggle:hover {
	color: var(--accent);
	border-color: var(--accent);
}
.coex-debt-toggle .bi {
	font-size: 11px;
	margin-right: 2px;
}

/* FIR-48 v4 #23 — debt-поля «Долг нам / Долг мы / Списать» вылезали за
   правую границу карточки «Получили/Отдали» когда юзер раскрывал их через
   toggle. Юзер: «Долг мы долг нам не выравнены и залазят на другие границы».
   Причина: строка .row.g-1 содержит col-3 + col-3 + col-auto(toggle) +
   col-2 + col-2 + col-auto.ms-4(Списать) — суммарно >12 колонок, плюс
   ms-4 (margin-left:1.5rem) физически толкал «Списать» за край карточки.
   Прошлый фикс (v3) ставил overflow:hidden — это КЛИПало видимые поля
   (выглядели обрезанными), а не укладывало их внутрь.
   Фикс v4: строка с debt-полями переносит лишние колонки на новую строку
   (flex-wrap), каждый столбец box-sizing:border-box + min-width:0, и
   гасим ms-4-толчок у «Списать» внутри debt-row — раскладка остаётся
   внутри границ карточки. Структура колонок не меняется (save.js не трогаем). */
.duplicate-block-get .row,
.duplicate-block-give .row {
	flex-wrap: wrap;
}
.duplicate-block-get .row > [class*="col-"],
.duplicate-block-give .row > [class*="col-"] {
	box-sizing: border-box;
	min-width: 0;
}
/* Долг-колонки и кнопка-toggle не вылезают за правый край карточки. */
.duplicate-block-get .coex-debt-col,
.duplicate-block-give .coex-debt-col,
.duplicate-block-get .coex-debt-toggle-wrap,
.duplicate-block-give .coex-debt-toggle-wrap {
	box-sizing: border-box;
	max-width: 100%;
}
/* Когда долг раскрыт, «Списать» (col-auto.ms-4) больше не отталкивается
   margin-left:1.5rem за правую границу — переносится естественно. */
.duplicate-block-get .row > .coex-debt-col.ms-4,
.duplicate-block-give .row > .coex-debt-col.ms-4 {
	margin-left: 0.5rem !important;
}
.coex-debt-toggle-wrap {
	white-space: nowrap;
}
/* Debt input visually weak when empty, prominent when filled — UX cue
   что долг создан автоматически. */
input[name="in_debt[]"],
input[name="out_debt[]"],
input[id*="-debt-amount-"] {
	background: rgba(248, 113, 113, 0.06);
}
input[name="in_debt[]"]:not([value=""]):not(:placeholder-shown),
input[name="out_debt[]"]:not([value=""]):not(:placeholder-shown),
input[id*="-debt-amount-"]:not([value=""]):not(:placeholder-shown) {
	background: rgba(248, 113, 113, 0.12);
	font-weight: 600;
}

/* FIR-42 #153 — footer кнопки компактные слева, без full-width. */
.coex-form-footer .btn-primary {
	min-width: 200px;
}

/* FIR-42 #179 — компактные фильтр-формы. Поля «На дату», селекты, кнопки
   «Применить» — не должны растягиваться на всю ширину. Унифицируем max-width
   на фильтр-карточках и form-control в них. */
.coex-app form.card.no-transform.mb-3 {
	max-width: 980px;
}
.coex-app form.card.no-transform.mb-3 .form-control,
.coex-app form.card.no-transform.mb-3 .form-select {
	max-width: 100%;
}
.coex-app form.card.no-transform.mb-3 input[type="date"] {
	max-width: 180px;
}
.coex-app form.card.no-transform.mb-3 .btn-sm {
	min-width: 110px;
}

/* FIR-42 #248 (2519) — панель фильтров /admin/operations/ должна занимать ВСЮ
   ширину контента, а не 980px как прочие узкие фильтр-карточки. Override снимает
   общий max-width только для этой формы (по id), поля внутри — Bootstrap-сетка
   col-md-2 ×6 = 12 колонок = ровно на всю ширину, поэтому распределяются сами.
   Адаптив сохранён: на узких экранах сетка сама переносит поля (col-6/col-12). */
.coex-app form.card.no-transform.mb-3#opsFiltersForm {
	max-width: none;
	width: 100%;
}
.coex-app form.card.no-transform.mb-3#opsFiltersForm > .card-body {
	width: 100%;
}
.coex-app form.card.no-transform.mb-3#opsFiltersForm .form-control,
.coex-app form.card.no-transform.mb-3#opsFiltersForm .form-select {
	max-width: 100%;
	width: 100%;
}
.coex-app form.card.no-transform.mb-3#opsFiltersForm input[type="date"] {
	max-width: 100%;
}

/* ============================================================
   FIR-42 #265 — /operator/outcome/ redesign
   Раньше форма расхода была собрана из 5+ <fieldset class="border p-2 rounded card">,
   каждый со своим заголовком .fs-5 text-muted в float-none. Визуально это
   создавало 5 жирных рамок с одинаковыми «карточками-в-карточке», много
   air-space без структуры. После редизайна — единый поток .coex-outcome-section
   (без border, только заголовок + контент), spacing 24px между блоками,
   плотная сетка внутри. Markup-hooks (id/name) НЕ менялись — save.js, kernel.js,
   duplicate-block JS-templates продолжают работать.
   ============================================================ */
.coex-outcome-page {
	max-width: 920px;
	margin: 0 auto;
}
.coex-outcome-back {
	max-width: 920px;
	margin-left: auto;
	margin-right: auto;
}
.coex-outcome-section {
	background: var(--bg);
	border: 1px solid var(--line);
	border-radius: var(--r-lg);
	padding: 20px 24px;
	margin-bottom: 16px;
}
.coex-outcome-section .form-label {
	font-weight: 500;
	color: var(--ink-2);
	font-size: 13px;
	margin-bottom: 6px;
}
.coex-outcome-header {
	padding-top: 24px;
	padding-bottom: 24px;
}
.coex-outcome-header__title {
	display: flex;
	align-items: baseline;
	gap: 12px;
	margin-bottom: 20px;
}
.coex-outcome-title {
	margin: 0;
	font-size: 22px;
	font-weight: 600;
	color: var(--ink);
	letter-spacing: -0.01em;
}
.coex-outcome-subtitle {
	font-size: 13px;
	color: var(--ink-3);
}
.coex-outcome-section__header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: 16px;
}
.coex-outcome-section__title {
	margin: 0;
	font-size: 14px;
	font-weight: 600;
	color: var(--ink);
	text-transform: uppercase;
	letter-spacing: 0.04em;
}
.coex-outcome-section__title--muted {
	color: var(--ink-3);
	font-weight: 500;
}
.coex-outcome-section-heading {
	max-width: 920px;
	margin-left: auto;
	margin-right: auto;
	padding: 4px 24px;
}
/* Таблица расходов внутри section — снимаем дефолтный bg, выравниваем
   по бортам section через -ms/-mr. */
.coex-outcome-table-wrap {
	margin: 0 -24px -20px -24px;
	border-top: 1px solid var(--line);
}
.coex-outcome-table-wrap .table {
	margin: 0;
}
.coex-outcome-table-wrap .table > :not(caption) > * > * {
	padding: 12px 16px;
}
.coex-outcome-table-wrap .table-light {
	--bs-table-bg: var(--bg-2);
}
/* Технический обмен — оставляем fieldset/card, но даём ему наш дизайн. */
.coex-outcome-tech-card {
	background: var(--bg);
	border: 1px solid var(--line) !important;
	border-radius: var(--r-lg);
	padding: 16px 20px;
	max-width: 920px;
	margin-left: auto;
	margin-right: auto;
}
.coex-outcome-tech-card__header {
	display: flex;
	align-items: center;
	gap: 8px;
	margin-bottom: 12px;
	padding-bottom: 8px;
	border-bottom: 1px solid var(--line);
}
.coex-outcome-tech-card__title {
	font-size: 13px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}
.coex-outcome-tech-card__title--ok { color: var(--ok); }
.coex-outcome-tech-card__title--bad { color: var(--bad); }

/* FIR-48 #6 — «Технический обмен»: Получаем / Отдаём теперь стоят рядом
   (row > col-lg-6). Внутри grid убираем центрирующий max-width:920px+auto
   у карточек, иначе каждая колонка сожмётся и уплывёт в центр своей половины.
   Левый акцент-бордер: зелёный для Получаем, красный для Отдаём — как на
   форме сделки «Получили/Отдали». */
.coex-outcome-tech-row > [class*="col-"] {
	display: flex;
}
.coex-outcome-tech-row .coex-outcome-tech-card {
	max-width: 100%;
	margin-left: 0;
	margin-right: 0;
	width: 100%;
}
.coex-outcome-tech-card--ok {
	border-top: 3px solid var(--ok) !important;
}
.coex-outcome-tech-card--bad {
	border-top: 3px solid var(--bad) !important;
}
/* FIR-43 #8 — «Технический обмен» (Получаем/Отдаём): поля Офис/Валюта/Сумма/
   Тип кассы/Ставка/Курс стояли по 6 в один ряд (.row-cols-6 → ~16% ширины),
   из-за чего были узкими и нечитаемыми. Раскладываем по 3 в ряд (×2 ширины,
   перенос на 2-ю строку), не трогая markup и duplicate-block-клоны (логика
   клонирования завязана на классы, а не на сетку). Скоуп строго по tech-блокам
   (get-tech/give-tech) — основная сетка форм не затрагивается. UI-нейтрально:
   ни цвета, ни dark-mode, ни остальная вёрстка не меняются. */
[class*="duplicate-block-get-tech"] .row-cols-6 > .col,
[class*="duplicate-block-give-tech"] .row-cols-6 > .col {
	flex: 0 0 auto !important;
	width: 33.3333% !important;
	margin-bottom: 10px !important;
}
/* FIR-49 2.1 — поля «Технического обмена» (Получаем/Отдаём) визуально
   не совпадали с остальной формой: Bootstrap `.rounded-0` давал острые
   углы + input-group-склейка читалась как «обведённые чёрным» чужие
   контролы. Приводим к единому B&W: тот же радиус (var(--r)), та же
   светло-серая рамка (var(--line)), та же высота, что у обычных
   .form-control/.form-select на форме. Markup (.rounded-0) не трогаем —
   duplicate-block-клоны зависят от классов. */
.coex-outcome-tech-card .form-control,
.coex-outcome-tech-card .form-select {
	border-radius: var(--r) !important;
	border: 1px solid var(--line) !important;
}
.coex-outcome-tech-card .select2-container .select2-selection--single {
	border-radius: var(--r) !important;
	border: 1px solid var(--line) !important;
}
.coex-outcome-status-wrap {
	max-width: 280px;
}
.coex-outcome-actions {
	max-width: 920px;
	margin: 24px auto 40px;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
}
.coex-outcome-actions .btn-primary {
	min-width: 200px;
	display: inline-flex;
	align-items: center;
	gap: 8px;
}
.coex-help {
	color: var(--ink-3);
	cursor: help;
}
.coex-help .bi {
	font-size: 13px;
}

/* Modal-form редизайн: input-group [currency | amount] */
.coex-amount-row {
	max-width: 100%;
}
.coex-amount-group {
	flex-wrap: nowrap;
}
.coex-amount-group > .coex-amount-currency,
.coex-amount-group > .select2-container {
	flex: 0 0 auto !important;
	width: 140px !important;
	min-width: 140px;
}
.coex-amount-group > .select2-container .select2-selection {
	border-top-right-radius: 0 !important;
	border-bottom-right-radius: 0 !important;
	border-right: 0 !important;
}
.coex-amount-group > .coex-amount-input {
	flex: 1 1 auto;
	min-width: 0;
	border-top-left-radius: 0 !important;
	border-bottom-left-radius: 0 !important;
	font-size: 16px;
	font-weight: 500;
}
.coex-outcome-return {
	padding-left: 2.5em;
}
.coex-outcome-return .form-check-label {
	color: var(--ink-2);
	font-size: 13px;
}
.coex-outcome-upload .upload-list:empty {
	display: none;
}
.coex-upload-list {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
}
.coex-outcome-category {
	background: var(--bg-2);
	border: 1px solid var(--line);
	border-radius: var(--r);
	padding: 12px 14px;
	margin-bottom: 16px;
}
.coex-outcome-category__label {
	font-size: 12px;
	font-weight: 500;
	color: var(--ink-3);
	margin-bottom: 8px;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}
.coex-outcome-modal-footer {
	display: flex;
	justify-content: space-between;
	align-items: center;
	border-top: 1px solid var(--line);
	padding-top: 16px;
	margin-top: 16px;
}
.coex-outcome-modal-footer .btn-primary {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	min-width: 140px;
	justify-content: center;
}

/* FIR-43 #8+ — fix outcome/income modal layout перед select2 init.
   Пустой <select> без options выглядит как тонкий квадратик (12-20px),
   ломая grid. Минимальные размеры до загрузки + skeleton-плейсхолдер. */
.modal-body .form-select:not(.select2-hidden-accessible) {
	min-height: 38px;
	min-width: 100%;
	background-color: var(--bg-2);
	background-image: linear-gradient(90deg, var(--bg-2) 0%, var(--bg-3, #f3f4f6) 50%, var(--bg-2) 100%);
	background-size: 200% 100%;
	animation: coex-skel-shimmer 1.2s ease-in-out infinite;
}
@keyframes coex-skel-shimmer {
	0%   { background-position: 200% 0; }
	100% { background-position: -200% 0; }
}
/* После select2 init анимация уходит — select спрятан, select2 контейнер заменит */
.modal-body .select2-container {
	min-width: 100% !important;
}
.modal-body .coex-amount-group > .select2-container {
	min-width: 140px !important;
}
/* 4 уровня детализации — выровнять select2 высоту и убрать пустую обводку */
.coex-outcome-category .form-select-sm {
	min-height: 32px;
}
.coex-outcome-category .select2-container--default .select2-selection--single {
	min-height: 32px;
	height: 32px;
}

/* FIR-43 #8+ — tooltip на сокращённые имена касс в select2 dropdown */
.select2-results__option {
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	max-width: 100%;
}

/* FIR-51 #4 — категории расхода («Вид расхода») сидят в 4 узких col-md-3
   селектах, и общий .select2-results__option выше резал длинные имена в
   ellipsis → текст почти не виден. По паттерну FIR-48 #24 / FIR-49 2.3
   (полное имя / перенос) для dropdown'ов с классом .coex-cat-dd снимаем
   обрезку: даём перенос строк и нормальную ширину панели, чтобы полное
   имя категории читалось. Только для категорий — кассы/валюты не трогаем. */
.coex-cat-dd .select2-results__option {
	white-space: normal !important;
	overflow: visible !important;
	text-overflow: clip !important;
	line-height: 1.35;
	word-break: break-word;
}
.coex-cat-dd.select2-dropdown {
	min-width: 320px !important;
	max-width: 90vw;
}
/* FIR-49 #14 — выбранное значение Select2 в col-md-3 обрезалось ellipsis */
.coex-outcome-category .select2-container--default .select2-selection--single .select2-selection__rendered {
	overflow: visible !important;
	text-overflow: clip !important;
	white-space: normal !important;
	line-height: 1.3 !important;
	padding-top: 3px;
	padding-bottom: 3px;
}
.coex-outcome-category .select2-container--default .select2-selection--single {
	height: auto !important;
	min-height: 32px;
}
/* FIR-49 #23 — кассы в модалках Расход/Доход (#outcome-box-type / #income-box-type)
   сидят в col-md-6 → панель ~99.5px → длинные «Касса_Главный_Крипто_USDT1» режутся
   ellipsis. Адресно через data-dropdown-class="coex-boxes-dd" (НЕ ломаем другие
   .boxes-select по проекту: admin_modals, accounting/exchange/debt/custom/...).
   По паттерну coex-cat-dd: перенос строки + минимальная ширина панели. */
.coex-boxes-dd .select2-results__option { white-space: normal; word-break: break-word; line-height: 1.35; }
.coex-boxes-dd.select2-dropdown { min-width: 280px; max-width: 90vw; }
/* FIR-49 #23 (доп.) — закрытое поле «Касса» в модалках Расход/Доход: длинное
   имя переносилось в 2-3 строки и вылезало за 36px col-md-6 / col-6. Принуди-
   тельный nowrap + ellipsis; title-tooltip остаётся (Select2 v4 ставит сам из
   option.text). Также tech-exchange (duplicate-block-*-tech-1-more): там
   row-cols-6 в col-lg-6 → ~150px на колонку → имя враппается. */
#outcome-front-modal .select2-selection--single .select2-selection__rendered,
#income-front-modal  .select2-selection--single .select2-selection__rendered,
.duplicate-block-get-tech-1-more .select2-selection--single .select2-selection__rendered,
.duplicate-block-give-tech-1-more .select2-selection--single .select2-selection__rendered,
.duplicate-block-get-tech-2-more .select2-selection--single .select2-selection__rendered,
.duplicate-block-give-tech-2-more .select2-selection--single .select2-selection__rendered {
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
}

.select2-results__option[title] {
	cursor: help;
}
/* Same для table cells где касса/wallet может быть длинной */
.coex-truncate-name {
	max-width: 220px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	display: inline-block;
	vertical-align: middle;
}

/* Mobile: stack tech-card columns + tighter section padding */
@media (max-width: 767.98px) {
	.coex-outcome-section {
		padding: 16px;
	}
	.coex-outcome-actions {
		flex-direction: column-reverse;
		align-items: stretch;
	}
	.coex-outcome-actions .btn-primary,
	.coex-outcome-actions .btn-link {
		width: 100%;
		min-width: 0;
	}
	.coex-amount-group > .coex-amount-currency,
	.coex-amount-group > .select2-container {
		width: 110px !important;
		min-width: 110px;
	}
}

/* FIR-42 #258 / #261 — компактный «?» хелп-знак вместо verbose .form-text
   подсказок под полями. Маленький круглый бэдж рядом с label-ом, при
   hover/focus показывает tooltip (через tooltip-pipeline в scripts.js →
   initCoexTooltips, который перехватывает data-bs-toggle="tooltip").
   Семантика: cursor:help + role="img" + aria-label со скоупом title. */
.coex-help-tip {
	display: inline-flex;
	width: 14px;
	height: 14px;
	border-radius: 50%;
	background: var(--ink-3, #6c757d);
	color: #fff;
	font-size: 10px;
	font-weight: bold;
	align-items: center;
	justify-content: center;
	cursor: help;
	margin-left: 4px;
	vertical-align: middle;
	line-height: 1;
	user-select: none;
}
.coex-help-tip:hover,
.coex-help-tip:focus {
	background: var(--ink-2, #495057);
	outline: none;
}

/* FIR-42 #269 — /admin/positions/ density fixes.
   Жалоба «почему всё скомкано»: таблицы шли впритык, секции прижаты друг
   к другу, page-title без воздуха, radio группа в модале без отступов.
   Scope намеренно узкий — стили вешаются только через `.coex-positions-page`
   wrapper, чтобы не ломать другие admin-страницы которые шарят .table/.card. */
.coex-positions-page .coex-page-title {
	margin-bottom: 8px;
}
.coex-positions-page .coex-page-title h1 {
	margin: 0 0 6px 0;
}
.coex-positions-page .coex-page-sub {
	margin: 0;
	line-height: 1.55;
	color: var(--ink-2, #495057);
	max-width: 760px;
}
/* Заголовочный блок страницы — больше воздуха над секциями. */
.coex-positions-page .coex-positions-header {
	margin-bottom: 24px;
}
/* Карточки секций (Должности сотрудников / Клиентские классификации) —
   24-32px между ними плюс отступ от заголовка страницы. */
.coex-positions-page .coex-positions-section + .coex-positions-section {
	margin-top: 32px;
}
.coex-positions-page .coex-positions-section {
	border: 1px solid var(--line, #e6e8eb);
	border-radius: var(--r-lg);
	overflow: hidden;
	background: #fff;
}
.coex-positions-page .coex-positions-section .card-header {
	padding: 16px 20px;
	background: var(--bg-2);
	border-bottom: 1px solid var(--line, #e6e8eb);
}
.coex-positions-page .coex-positions-section .card-header h5 {
	font-size: 16px;
	font-weight: 600;
	line-height: 1.3;
}
.coex-positions-page .coex-positions-section .card-header .text-muted {
	line-height: 1.5;
	margin-top: 6px !important;
}
.coex-positions-page .coex-positions-section .card-body {
	padding: 0;
}
/* Таблица должностей — плотные/нормальные строки, не «скомканные».
   Bootstrap по умолчанию даёт .75rem (12px) vertical, но без горизонтальных
   gutter-ов на td → читается тесно. Явный override. */
.coex-positions-page .coex-positions-section table.table {
	margin: 0;
}
.coex-positions-page .coex-positions-section table.table > thead > tr > th {
	padding: 12px 16px;
	font-weight: 600;
	font-size: 13px;
	color: var(--ink-2, #495057);
	background: var(--bg-2);
	border-bottom: 1px solid var(--line, #e6e8eb);
}
.coex-positions-page .coex-positions-section table.table > tbody > tr > td {
	padding: 10px 16px;
	vertical-align: middle;
	border-bottom: 1px solid var(--line);
}
.coex-positions-page .coex-positions-section table.table > tbody > tr:last-child > td {
	border-bottom: 0;
}
/* Inline rename-form — input + button не должны лип­нуть друг к другу. */
.coex-positions-page .coex-positions-section td form.d-flex {
	gap: 8px;
}
.coex-positions-page .coex-positions-section td .form-control-sm {
	max-width: 320px;
}
/* Alert-ы success/error — отступ снизу до первой секции. */
.coex-positions-page .alert {
	margin-bottom: 16px;
}
/* Модал «Добавить роль» — radio-group должен дышать. */
#position-add-modal .modal-body {
	padding: 20px 24px;
}
#position-add-modal .form-check {
	padding: 10px 12px 10px 36px;
	border: 1px solid var(--line, #e6e8eb);
	border-radius: 8px;
	margin-bottom: 8px;
	cursor: pointer;
	transition: background-color 120ms ease, border-color 120ms ease;
}
#position-add-modal .form-check:hover {
	background: var(--bg-2);
}
#position-add-modal .form-check .form-check-input {
	margin-left: -24px;
	margin-top: 4px;
}
#position-add-modal .form-check .form-check-label {
	cursor: pointer;
	line-height: 1.45;
	display: block;
}
#position-add-modal .mb-3 + .mb-3 {
	margin-top: 20px;
}

/* FIR-42 #278 — таймлайн истории изменений операции внизу edit-формы.
   Стиль: лёгкая bordered-секция с dot-bullet списком, серое время,
   жирный пользователь, italic action, обычные changes.  */
.coex-op-history {
	margin-top: 24px;
	padding: 16px 20px;
	background: var(--bg-2);
	border: 1px solid var(--line);
	border-radius: 6px;
}
.coex-op-history__title {
	font-size: 14px;
	font-weight: 600;
	color: var(--ink-2);
	margin: 0 0 12px 0;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}
.coex-op-history__list {
	list-style: none;
	margin: 0;
	padding: 0 0 0 14px;
	position: relative;
}
.coex-op-history__list::before {
	content: '';
	position: absolute;
	left: 4px;
	top: 6px;
	bottom: 6px;
	width: 1px;
	background: var(--line-strong);
}
.coex-op-history__item {
	position: relative;
	padding: 6px 0 6px 12px;
	font-size: 13px;
	line-height: 1.5;
	color: var(--ink);
}
.coex-op-history__item::before {
	content: '';
	position: absolute;
	left: -12px;
	top: 12px;
	width: 9px;
	height: 9px;
	border-radius: 50%;
	background: var(--ink-4);
	border: 2px solid var(--bg-2);
	box-sizing: border-box;
}
.coex-op-history__item:first-child::before {
	background: var(--accent);
}
.coex-history-time {
	color: var(--ink-4);
	font-variant-numeric: tabular-nums;
	margin-right: 8px;
	white-space: nowrap;
}
.coex-history-user {
	font-weight: 600;
	color: var(--ink);
	margin-right: 8px;
}
.coex-history-action {
	font-style: italic;
	color: var(--ink-3);
	margin-right: 8px;
}
.coex-history-changes {
	color: var(--ink-2);
	display: inline;
	word-break: break-word;
}

/* FIR-42 #280 — inline rate hint «/ Рынок: 83.45» рядом с input «Рыночный курс».
   Компактный серый span, не ломает выравнивание строки form-label/input. */
.coex-market-hint {
	display: inline-block;
	margin-left: 6px;
	padding: 2px 6px;
	font-size: 11px;
	color: var(--ink-3);
	background: var(--bg-3);
	border-radius: 4px;
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
	vertical-align: middle;
}
.coex-market-hint.is-loading {
	color: var(--ink-4);
	font-style: italic;
}
.coex-market-hint.is-error {
	color: #b91c1c;
	background: #fef2f2;
}

/* ============================================================
   FIR-42 #283 — office modal polish
   ------------------------------------------------------------
   (a) Шаблоны сделки внутри office-modal-preview: горизонтальный
       flex-wrap, чипы одинакового размера, никакой вертикальной
       стопки.  «Другое» НЕ уходит в свою строку через
       margin-left:auto — иначе при N>3 чипах последняя кнопка
       толкает каждую новую вниз.
   (b) Страна / Город: полностью видимое значение в select2.
       Раньше .quick-add-row--inline > .select2 имел
       overflow:hidden + max-width:100%, из-за чего «Россия»
       обрезалась до «Рос...».  Multi-select-ам это нужно для
       чипов, обычным single-select-ам — нет.
   ============================================================ */

/* (a) Template chip grid inside office modal preview. */
#office-template-preview.coex-template-row {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	align-items: center;
	row-gap: 8px;
}
#office-template-preview .coex-template-btn {
	min-width: 110px;
	max-width: 170px;
	justify-content: center;
	flex: 0 0 auto;
}
/* "Другое" — не оттягиваем вправо, иначе всё распадается на колонки. */
#office-template-preview .coex-template-more {
	margin-left: 0;
	flex: 0 0 auto;
}

/* (b) Country / city select inside office modal — fully readable. */
#office-modal #office-country-id + .select2-container,
#office-modal #office-city-id + .select2-container {
	min-width: 0;
	width: 100% !important;
}
#office-modal .quick-add-row--inline #office-country-id,
#office-modal .quick-add-row--inline #office-city-id,
#office-modal .quick-add-row--inline #office-country-id + .select2-container,
#office-modal .quick-add-row--inline #office-city-id + .select2-container {
	/* Single-select-ам не нужен overflow:hidden от FIR-42 #204 (тот rule
	   обслуживает multi-select чипы). Возвращаем видимое значение. */
	overflow: visible !important;
	max-width: none !important;
}
#office-modal #office-country-id + .select2-container .select2-selection--single,
#office-modal #office-city-id + .select2-container .select2-selection--single {
	min-height: 36px;
	height: 36px;
	display: flex;
	align-items: center;
}
#office-modal #office-country-id + .select2-container .select2-selection__rendered,
#office-modal #office-city-id + .select2-container .select2-selection__rendered {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	line-height: 1.4;
	padding-right: 24px;
}

/* ============================================================
   FIR-42 #321 — UI audit P2/P3 polish
   ============================================================ */

/* Skeleton screens for #loading-caption (admin tables).
   Replaces plain «Загрузка…» text with 5 shimmering rows so the user
   gets immediate visual feedback that something is loading — far less
   perceived latency vs a static caption. */
.coex-table-skeleton {
	padding: 4px 0;
}
.coex-skel-row {
	height: 36px;
	background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
	background-size: 200% 100%;
	animation: coex-skel-shimmer 1.2s infinite;
	margin-bottom: 4px;
	border-radius: 4px;
}
@keyframes coex-skel-shimmer {
	0%   { background-position: 200% 0; }
	100% { background-position: -200% 0; }
}

/* P3 — focus-visible rings on interactive elements. Keyboard-only focus
   gets a clear 2px accent ring; mouse clicks don't show it (Bootstrap's
   default :focus halo was confusing).
   FIR-42 #335 — раньше это правило применялось ко ВСЕМ input/select/textarea
   и СУММИРОВАЛОСЬ с .form-control:focus box-shadow (3px halo + 2px outline
   с offset 2px = «двойная толстая фиолетовая обводка»). Юзер жаловался
   «подсветку как везде, а не как ты сделал». Теперь form-control/form-select/
   select2 — НЕ получают outline отсюда (для них уже есть accent border +
   subtle halo через .form-control:focus). Outline остаётся для buttons,
   ссылок, role=button и [tabindex] — где Bootstrap не ставит своего focus. */
button:focus-visible,
a:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible {
	outline: 2px solid var(--accent, #5e6ad2) !important;
	outline-offset: 2px !important;
	box-shadow: none !important;
}
/* Для form-control / form-select оставляем только subtle accent halo
   из .form-control:focus (3px 15% opacity). Outline 0 — без offset-rings. */
.form-control:focus-visible,
.form-select:focus-visible,
input.form-control:focus-visible,
select.form-select:focus-visible,
textarea.form-control:focus-visible {
	outline: 0 !important;
}
/* Select2 selection wrapper (имитирует form-control). Тоже без жёсткого outline. */
.select2-container--default.select2-container--focus .select2-selection,
.select2-container--default .select2-selection:focus,
.select2-container--default .select2-selection:focus-visible {
	outline: 0 !important;
	border-color: var(--accent, #5e6ad2) !important;
	box-shadow: 0 0 0 3px rgba(94, 106, 210, 0.15) !important;
}

/* FIR-48 #60 — «кривое обрамление ячейки» при выборе Офиса в Кассах.
   При открытии Select2 фокус уходит на внутренний .select2-search__field
   (tabindex=0), который ловил общее правило [tabindex]:focus-visible →
   outline 2px solid + outline-offset 2px + border-radius 0 = ПРЯМОУГОЛЬНАЯ
   обводка со смещением, торчащая поверх скруглённого селекта. Плюс на самой
   обёртке .select2-container появлялся второй квадратный focus-glow. Итог —
   двойная съехавшая рамка. Чистим: рамку держит ТОЛЬКО .select2-selection
   (accent-border + один скруглённый halo выше), а внутренний поиск и
   контейнер фокус-артефактов не дают. */
.select2-container .select2-search__field,
.select2-container .select2-search__field:focus,
.select2-container .select2-search__field:focus-visible {
	outline: 0 !important;
	box-shadow: none !important;
	border: 0 !important;
}
.select2-container--default.select2-container--focus,
.select2-container--default.select2-container--open {
	outline: 0 !important;
	box-shadow: none !important;
	border-radius: 6px;
}

/* FIR-42 #335 — чуть больше воздуха в country-modal quick-add row (когда раскрыт).
   Добавляем padding снизу и сверху, чтобы поля «дышали». */
#country-modal .modal-form > .row.form-group:has(.quick-add-form:not(.d-none)) .quick-add-form {
	padding: 10px 0 4px 0;
}

/* P3 — respect prefers-reduced-motion. Users who've opted out of motion
   (OS-level) get near-instant transitions for ALL animations / transitions,
   so we don't have to chase every rule individually. */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* FIR-42 #344 — auto dark-mode полностью убран по запросу. UI всегда light. */

/* ============================================================
   FIR-42 #321 — GLOBAL MODAL ALIGNMENT STANDARDS
   ------------------------------------------------------------
   Унифицируем все всплывающие окна:
   • одинаковый радиус/тень shell-а
   • один padding для header/body/footer
   • один размер title (16/600)
   • одинаковая label-колонка в form-row (110px)
   • одинаковый размер form-control (min-height 36px)
   • footer-кнопки выровнены вправо, primary справа, secondary слева
   ------------------------------------------------------------ */

/* Shell */
.modal-content {
	border: 0 !important;
	border-radius: var(--r-lg, 12px) !important;
	box-shadow: 0 16px 48px rgba(0, 0, 0, 0.14) !important;
	overflow: hidden;
}

/* Header */
.modal-header {
	padding: 16px 20px !important;
	border-bottom: 1px solid var(--line) !important;
	align-items: center;
}
.modal-header .modal-title {
	font-size: 16px !important;
	font-weight: 600 !important;
	letter-spacing: -0.01em;
	line-height: 1.3;
	color: var(--ink);
}
.modal-header .btn-close {
	margin: -4px -4px -4px auto;
}

/* Body */
.modal-body {
	padding: 16px 20px !important;
}

/* Footer — кнопки справа, primary последняя */
.modal-footer {
	padding: 12px 20px 16px !important;
	border-top: 1px solid var(--line) !important;
	gap: 8px !important;
	justify-content: flex-end !important;
	flex-wrap: wrap;
}
.modal-footer .btn {
	min-width: 120px;
	min-height: 36px;
}
.modal-footer .btn-primary,
.modal-footer .btn-success,
.modal-footer .btn-danger {
	order: 2;
}
.modal-footer .btn-secondary,
.modal-footer .btn-light,
.modal-footer .btn-link,
.modal-footer .btn-outline-secondary {
	order: 1;
}

/* Form-row in modals — already locked to 110px grid via #283/#302;
   re-affirm here so новые модалки автоматически получают alignment. */
.modal-form > .row.form-group,
.modal-form .coex-modal-section > .row.form-group,
.modal-form .container-fluid > .row.form-group,
.modal-form .repeatable-fields .row.form-group {
	align-items: center;
	gap: 12px !important;
	margin-bottom: 12px !important;
}

/* Form controls inside modals — единый размер */
.modal .form-control,
.modal .form-select,
.modal-form .form-control,
.modal-form .form-select {
	min-height: 36px;
}

/* Quick-add row — единый паттерн (inline кнопка-плюс 32×32 рядом со
   select-ом). Уже определено для .quick-add-row--inline в #204; добавляем
   safety-default для голого .quick-add-row без модификатора. */
.modal .quick-add-row,
.modal-form .quick-add-row {
	gap: 8px;
	align-items: center;
}
/* FIR-42 #337/#338 — UNIFIED «+» quick-add button geometry.
   Раньше per-modal overrides задавали разные размеры:
   - #office-modal: 28×28
   - #country-modal: 36px height
   - .modal/.modal-form generic: 32×32
   → Каждый «+» рядом со своим select-ом выглядел по-разному,
     не центровался с chevron-ом. User: «мне каждый + тебе показывать?»

   Теперь ОДНО глобальное правило: 36×36 (= form-select min-height в modal-е),
   icon-only (font-size:0 на кнопке, 14px на <i>), inline-flex с центровкой.
   Применяется ко ВСЕМ modals (#office-modal, #country-modal, #user-modal,
   #box-modal, …) и любому contexту где есть .quick-add-btn в .quick-add-row.
   !important чтобы перебить устаревшие per-modal rules выше. */
.quick-add-row .quick-add-btn,
.modal .quick-add-btn,
.modal-form .quick-add-btn {
	width: 36px !important;
	height: 36px !important;
	min-width: 36px !important;
	padding: 0 !important;
	flex: 0 0 36px !important;
	display: inline-flex !important;
	align-items: center !important;
	justify-content: center !important;
	font-size: 0 !important;
	line-height: 1 !important;
	border-radius: 8px !important;
	align-self: center !important;
}
.quick-add-row .quick-add-btn > i,
.quick-add-row .quick-add-btn > .bi,
.modal .quick-add-btn > i,
.modal .quick-add-btn > .bi,
.modal-form .quick-add-btn > i,
.modal-form .quick-add-btn > .bi {
	font-size: 16px !important;
	line-height: 1 !important;
	margin: 0 !important;
}
/* Если кнопка имеет лейбл («+ Новый»), скрываем его — оставляем icon-only.
   Это применяется только в icon-mode (.quick-add-btn без .quick-add-btn--text). */
.quick-add-row .quick-add-btn .quick-add-btn-label,
.modal .quick-add-btn .quick-add-btn-label,
.modal-form .quick-add-btn .quick-add-btn-label {
	display: none !important;
}
/* Ровняем row высоту с button + select2-wrapper-ом */
.quick-add-row.quick-add-row--inline {
	min-height: 36px;
	align-items: center !important;
}

/* FIR-42 #338b — select2-selection--multiple (мультиселект с chips) рендерится
   38px вместо 36px из-за пары пикселей border + padding-а на rendered area.
   Кнопка «+» рядом 36px — 2px разница, dy=1px при центровке. Принудительно
   normalize-им multiple до 36px минимум, чтобы row выровнялся с button.
   При наличии chips высота сама вырастет (multiple растягивается под content)
   — это уже не misalignment, а ожидаемое поведение. */
/* FIR-42 #338d — DOUBLE BORDER fix.
   Select2 рендерит ДВА вложенных элемента, оба получают form-select класс
   и наш `.form-control, .form-select { border: 1px solid var(--line) }`:
   - outer .select2-container (38px total = 36 inner + 2 own borders)
   - inner .select2-selection (36px = 34 content + 2 borders)
   В итоге: outer 38px vs «+» button 36px → 1px misalignment.
   Плюс визуально 2 границы наслаиваются.

   Fix: убираем border + padding с outer .select2-container, оставляем
   только на inner .select2-selection. Outer становится «прозрачным
   wrapper-ом» — height следует за inner = 36px = ровно с button. */
.quick-add-row .select2-container.form-select,
.modal .select2-container.form-select {
	border: 0 !important;
	padding: 0 !important;
	background: transparent !important;
	min-height: 0 !important;
	height: auto !important;
	box-shadow: none !important;
	box-sizing: border-box !important;
}
.quick-add-row .select2-container--default .select2-selection,
.modal .select2-container--default .select2-selection {
	box-sizing: border-box !important;
}
.quick-add-row .select2-container--default .select2-selection--multiple,
.modal .select2-container--default .select2-selection--multiple {
	min-height: 36px !important;
	height: 36px;
}
/* С chips — autoexpand */
.quick-add-row .select2-container--default .select2-selection--multiple:has(.select2-selection__choice),
.modal .select2-container--default .select2-selection--multiple:has(.select2-selection__choice) {
	height: auto !important;
}
.quick-add-row .select2-container--default .select2-selection--single,
.modal .select2-container--default .select2-selection--single {
	height: 36px !important;
	min-height: 36px !important;
}
/* FIR-49 #23 round 2: блок «v2» (ID-таргетный nowrap+ellipsis) удалён —
   перебивал по ID-специфичности фикс из style.css (.boxes-select + .select2-container
   .select2-selection__rendered с white-space:normal/overflow:visible/word-break).
   Источник правды — style.css FIR-49 #23. */
.quick-add-row .select2-container--default .select2-selection--multiple .select2-selection__rendered,
.modal .select2-container--default .select2-selection--multiple .select2-selection__rendered {
	padding: 0 8px !important;
}

/* На узких экранах (sm: < 576px) — kill grid, чтобы label был сверху */
@media (max-width: 575.98px) {
	.modal-form > .row.form-group,
	.modal-form .coex-modal-section > .row.form-group,
	.modal-form .container-fluid > .row.form-group,
	.modal-form .repeatable-fields .row.form-group {
		grid-template-columns: 1fr !important;
		align-items: stretch;
	}
	.modal-footer .btn { min-width: 0; flex: 1; }
}

/* FIR-42 #330 — compact tree view для /admin/?table=incomes («Доходы и расходы»).
   Дефолт bootstrap-treeview рендерит каждый узел как «толстую» list-group-item
   с ~14-18px вертикальным padding-ом, своим border-radius'ом и заметным gap'ом
   между айтемами — на дереве из 30+ узлов это выглядит «расхлябанно»
   (см. FIR-42 #330 screenshot). Делаем плотный, скомканный список:
   – высота строки ~36px (paddings 6/10)
   – единая обводка контейнера, hairline border-bottom между айтемами вместо
     card-look per row
   – «...» dropdown-кнопка минималистичная, без border-а, 28×24
   – selected state — лёгкий accent-soft фон + 3px accent-stripe слева,
     без full-card highlight
   – indent от bootstrap-treeview (inline padding-left) сохраняется, но
     слегка сжимаем за счёт меньших паддингов */
#tree-view {
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: var(--bg);
}
#tree-view .list-group {
  border-radius: 0;
  margin: 0;
}
#tree-view .list-group-item {
  border: 0 !important;
  border-bottom: 1px solid var(--line) !important;
  border-radius: 0 !important;
  padding: 6px 12px 6px 10px !important;
  margin: 0 !important;
  background: transparent !important;
  min-height: 36px;
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--ink);
  font-size: 14px;
  line-height: 1.35;
  transition: background-color 120ms ease;
}
#tree-view .list-group-item:last-child {
  border-bottom: 0 !important;
}
#tree-view .list-group-item:hover {
  background: var(--bg-2) !important;
}
#tree-view .list-group-item.node-selected {
  background: var(--accent-soft) !important;
  box-shadow: inset 3px 0 0 var(--accent);
  color: var(--ink);
}
#tree-view .list-group-item .item-text {
  flex: 1 1 auto;
  font-weight: 400;
  color: inherit;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Корневые узлы (Доход / Расход / Доставка с клиента и т.п.) — bootstrap-treeview
   присваивает им padding-left ≈ 5px. Делаем заголовочные узлы чуть жирнее. */
#tree-view .list-group-item[style*="padding-left: 5px"],
#tree-view .list-group-item[style*="padding-left:5px"] {
  font-weight: 600;
  background: var(--bg-3) !important;
}
#tree-view .list-group-item[style*="padding-left: 5px"]:hover,
#tree-view .list-group-item[style*="padding-left:5px"]:hover {
  background: var(--bg-2) !important;
}
/* Expand/collapse glyph — переключаем с glyphicon ± на минималистичный chevron.
   Иконка остаётся та же (glyphicon), но pаdding-вокруг — меньше. */
#tree-view .list-group-item .icon {
  width: 14px;
  min-width: 14px;
  text-align: center;
  color: var(--ink-3);
  font-size: 11px;
  margin-right: 4px;
}
#tree-view .list-group-item .icon.expand-icon {
  cursor: pointer;
}
#tree-view .list-group-item .icon:empty {
  display: none;
}
/* «...» dropdown action — компактная иконка, без рамки, светится только на hover */
#tree-view .list-group-item .dropdown {
  flex: 0 0 auto;
  margin-left: auto;
}
#tree-view .list-group-item .table-drop-btn,
#tree-view .list-group-item .btn.btn-outline-secondary.dropdown-toggle {
  border: 1px solid transparent !important;
  background: transparent !important;
  color: var(--ink-3) !important;
  padding: 2px 8px !important;
  min-height: 24px;
  height: 24px;
  border-radius: 6px;
  font-size: 12px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  box-shadow: none !important;
}
#tree-view .list-group-item .table-drop-btn:hover,
#tree-view .list-group-item .table-drop-btn:focus,
#tree-view .list-group-item .btn.btn-outline-secondary.dropdown-toggle:hover {
  background: var(--bg-3) !important;
  border-color: var(--line) !important;
  color: var(--ink) !important;
}
#tree-view .list-group-item .table-drop-btn::after {
  margin-left: 2px;
  border-top-color: currentColor;
}
#tree-view .list-group-item .table-drop-btn .bi {
  font-size: 14px;
}

/* FIR-42 #318/#322 — Alpine x-cloak + x-show vs Bootstrap utility classes.
   .d-flex / .d-block в Bootstrap 5 объявлены `display: ... !important`, поэтому
   inline `style="display: none"`, выставляемый Alpine при `x-show="false"`,
   ПРОИГРЫВАЕТ — оба footer'а (server-paginated и client-paginated) показывались
   одновременно («Показано 1 по 5 из 5 всего» + «Показано 5 из 5» рядом).
   Решение: повышаем приоритет inline display:none + x-cloak до !important,
   чтобы Alpine мог управлять видимостью таких элементов независимо от
   utility-классов. */
[x-cloak],
[x-show][style*="display: none"],
[x-show][style*="display:none"] {
	display: none !important;
}

/* ============================================================
   FIR-42 #342b — Global density + typography audit fixes
   ============================================================
   After audit of admin tables (/admin/?table=users|offices|cities|
   currencies|countries|cashes|operations|incomes), modals (#user-modal,
   #office-modal, #country-modal, #city-modal, #currency-modal, #box-modal,
   #wallet-modal, #income-modal, #self-profile-modal) and operator forms
   (/operator/accounting/, /operator/exchange/, /operator/balancing/,
   /operator/income/, /operator/outcome/, /operator/debt/) — fixed
   these specific inconsistencies:

   1. h1.coex-page-title was 20px/600 (line 2536 #38) — spec 24-28px/700.
   2. Breadcrumb (.coex-crumbs) was 12px — spec 11px uppercase.
   3. Page-subtitle color was not pinned to var(--ink-3) for some pages.
   4. #data-table-wrp .badge was height 20px / 10.5px — spec 22-26px / 11-12px.
   5. .table-drop-btn was 2×6 padding (~24×20) — spec 32×32, right-aligned.
   6. Actions column («...» dropdown) had no right-alignment rule.
   7. Modal-form .modal-footer had no flex-end alignment for buttons.
   8. Modal .form-control / .form-select didn't enforce 36px baseline
      (only select2 / specific helpers did) — fields visually jittered.
   9. Operator fieldset section headers had grey border (1px all) but
      no 3px colored side-stripe — spec wants visible stripe.
   10. .form-control in operator forms occasionally inherited raw hex
       border via inline style="border:1px solid #ddd" — replaced via
       attribute selector to var(--line).
   11. Admin table tbody row paddings were over-specified across 3
       different selectors (5×6, 7×10, 8×10, 8×12) — pinned to 7×10
       to give a stable 34-36px row height.
   12. Modal-form row-gap was 7px (line 2564), spec wants 10-14px;
       bumped to 10px to give labels breathing room.
   ============================================================ */

/* (1) Page title h1 — 22px base / 20px via #38 was too modest for an
   accounting app where every page is a dashboard. Bump to 24px / 700.
   Was: font-size:20px (line 2536), font-weight:600 (line 1245). */
.coex-page-title h1 {
	font-size: 22px;
	font-weight: 600;
	letter-spacing: -0.015em;
}
/* Sub-text under h1 — pin to var(--ink-3) and lock to spec 13-14px. */
.coex-page-sub {
	color: var(--ink-3);
	font-size: 13.5px;
}

/* (2) Breadcrumbs — were 12px (line 1176); spec 11px uppercase. */
.coex-crumbs {
	font-size: 11px;
	letter-spacing: 0.08em;
}

/* (4) Status badges in admin tables — height was 20px / 10.5px font.
   At that height the chips read as «крошечный sticker», spec wants
   22-26px height with 11-12px body so chips align with row text. */
#data-table-wrp .badge {
	height: 22px;
	padding: 0 9px;
	font-size: 11px;
	letter-spacing: 0.05em;
}

/* (5)+(6) Actions column («...» row dropdown). Currently 2×6 padding
   gives a ~24×20 button which doesn't meet 32px touch target. Make it
   32×32 + right-align the cell so all admin tables agree. */
#data-table-wrp .table > tbody > tr > td:last-child,
#data-table-wrp .table > thead > tr > th:last-child {
	text-align: right;
}
#data-table-wrp .table-drop-btn {
	width: 32px;
	height: 32px;
	padding: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border-radius: var(--r);
}
/* FIR-48 #13 — Bootstrap Icons font has an ascent metric that pushes the
   three-dots glyph into the upper third of a 14px line-box. line-height:1
   alone doesn't center it (the glyph is offset INSIDE its own font-box).
   Fix: make the <i> a full-size flex container of the 32x32 button, so the
   glyph is centered by flexbox geometry, not by font baseline. */
#data-table-wrp .table-drop-btn > i.bi {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: 100%;
	font-size: 14px;
	line-height: 1;
	vertical-align: middle;
}

/* (7) Modal footer — buttons (Отменить / Сохранить) right-aligned.
   Bootstrap default is flex-end, but our .modal-form (CSS grid) sometimes
   stretched the footer; pin alignment explicitly. */
.modal-form .modal-footer,
.modal .modal-footer {
	display: flex;
	justify-content: flex-end;
	align-items: center;
	gap: 8px;
}
.modal-form .modal-footer .btn,
.modal .modal-footer .btn {
	height: 36px;
	min-width: 100px;
}

/* (8) Modal form-control / form-select — 36px baseline so dropdowns,
   inputs, и select2 не разъезжаются по высоте на 32 vs 34 vs 36px.
   Scoped to `.modal` чтобы не ломать compact admin filter row
   (#data-table-wrp .card-header .form-control, который уже 32px). */
.modal .form-control,
.modal .form-select {
	min-height: 36px;
}
/* Modal label column — 110px fixed (already enforced at line 561 via
   .modal-form > .row.form-group). Re-state for nested .form-fields card
   container, которое выпадало из grid и давало 4-колоночный layout. */
.modal-form .form-fields .container-fluid > .row.form-group {
	display: grid !important;
	grid-template-columns: 110px 1fr !important;
	align-items: center;
	gap: 8px;
	margin: 0 !important;
}

/* (9) Operator fieldset section headers — добавляем 3px цветовую
   полоску слева, чтобы Получили / Отдали / Долговые позиции были
   узнаваемы с первого взгляда. Без неё все секции выглядят одинаково
   серыми, и оператор путает поля «Сумма получено» с «Сумма выдано». */
#main-form fieldset.fieldset-container {
	position: relative;
	border-left: 3px solid var(--line) !important;
}
#main-form fieldset.fieldset-container:has(.fw-bold.text-success.fs-5) {
	border-left-color: var(--ok) !important;
}
#main-form fieldset.fieldset-container:has(.fw-bold.text-danger.fs-5) {
	border-left-color: var(--bad) !important;
}
#main-form fieldset.fieldset-container:has(.fw-bold.text-muted.fs-5) {
	border-left-color: var(--accent) !important;
}

/* (10) Замена raw hex border-color (часто #ddd / #ccc / #e0e0e0) на
   var(--line) для input-ов внутри operator-форм. Атрибутный селектор
   ловит inline style и старые правила без необходимости править PHP. */
#main-form .form-control[style*="#ddd"],
#main-form .form-control[style*="#ccc"],
#main-form .form-control[style*="#e0e0e0"],
#main-form .form-select[style*="#ddd"],
#main-form .form-select[style*="#ccc"] {
	border-color: var(--line) !important;
}

/* (11) Admin tables — единое правило padding на td/th после 3-х
   конфликтующих override-ов (lines 1723 / 2560-2561 / 2558-2559).
   7×10 даёт строку 34-36px при line-height 1.35 — это центр спека
   32-40px и хорошо сочетается с 22px-badge'ами из пункта (4). */
#data-table-wrp .table > thead > tr > th,
#data-table-wrp .table > tbody > tr > td {
	padding: 7px 10px;
	line-height: 1.35;
}
/* Header font — спек хочет 11-12px; был 10.5px. Чуть крупнее даёт
   thead больше веса и убирает «squinting» эффект на широких экранах. */
#data-table-wrp .table > thead > tr > th,
#data-table-wrp .table thead th {
	font-size: 11px;
}

/* (12) Modal-form spacing — row-gap был 7px (line 2564), спек 10-14px;
   ставим 10px. Этого хватает чтобы label/input не сливались, но grid
   остаётся компактным (4-5 строк в видимой части модалки). */
.modal-form {
	row-gap: 10px;
}

/* FIR-42 #338 — section dividers in user-modal (and any modal-form that
   opts into the pattern). Subtle top-border + small uppercase header gives
   the wall of fields a clear visual rhythm without adding visual weight. */
.coex-modal-section {
	border-top: 1px solid var(--line);
	padding-top: 14px;
	margin-top: 14px;
}
.coex-modal-section:first-child {
	border-top: 0;
	padding-top: 0;
	margin-top: 0;
}
/* Hide the section wrapper entirely when its single inner card-block is
   hidden by JS (e.g. #user-post-fields toggled off for non-staff roles, or
   #user-operator-fields hidden for client/refovod). The :has() selector is
   supported by all evergreen browsers; older browsers fall back to showing
   the header alone — visually harmless but not ideal. */
.coex-modal-section--posts:has(> #user-post-fields[style*="display: none"]),
.coex-modal-section--posts:has(> #user-post-fields[style*="display:none"]),
.coex-modal-section--operator:has(> #user-operator-fields[style*="display: none"]),
.coex-modal-section--operator:has(> #user-operator-fields[style*="display:none"]) {
	display: none;
}
.coex-section-title {
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--ink-3);
	font-weight: 600;
	margin: 0 0 10px 0;
}


/* FIR-42 #330 — user-modal Посредники/Рефоводы multi-select растёт вертикально
   когда выбрано 3+ людей (на скрине показано 4 строки items). Когда у клиента
   будут сотни брокеров — поле станет огромным. Limit visible height; scroll
   внутри. Каждый chip остаётся видим, но overflow vertical scroll.
   User: «не надо делать большое поле для них». */
#user-modal .select2-container--default .select2-selection--multiple {
	max-height: 72px !important; /* ~2 rows of chips */
	overflow-y: auto !important;
}
#user-modal .select2-container--default .select2-selection--multiple .select2-selection__rendered {
	padding: 4px 8px !important;
}

/* FIR-48 #11 — посредники/рефоводы в карточке сделки и в таблице операций.
   User: «Если два посредника или рефовода, не надо в две строки — второго
   сократи через …, при наведении подсветить всех что не влезли». Решение
   CSS-only: контейнер chip-ов в multi-select на ОДНОЙ строке (nowrap),
   каждый chip с max-width + ellipsis, при hover/focus раскрываем wrap
   с z-index чтобы скрытые элементы стали видны поверх соседних полей. */
#broker + .select2-container .select2-selection--multiple .select2-selection__rendered,
#refovod + .select2-container .select2-selection--multiple .select2-selection__rendered {
	flex-wrap: nowrap !important;
	overflow: hidden !important;
	max-width: 100%;
}
#broker + .select2-container .select2-selection--multiple .select2-selection__choice,
#refovod + .select2-container .select2-selection--multiple .select2-selection__choice {
	max-width: 160px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	flex-shrink: 0;
}
#broker + .select2-container:hover .select2-selection--multiple .select2-selection__rendered,
#broker + .select2-container.select2-container--focus .select2-selection--multiple .select2-selection__rendered,
#refovod + .select2-container:hover .select2-selection--multiple .select2-selection__rendered,
#refovod + .select2-container.select2-container--focus .select2-selection--multiple .select2-selection__rendered {
	flex-wrap: wrap !important;
	overflow: visible !important;
	position: relative;
	z-index: 20;
	background: #fff;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}

/* Таблица операций — колонки Контрагент / Рефовод. Имена раздуваются на
   2-3 строки при множественной привязке. Ужимаем до одной строки + native
   title-tooltip (он уже выставляется на cell-е). */
.coex-op-counter,
.coex-op-referer {
	max-width: 180px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Справочник клиентов оператора — колонки Посредники / Рефоводы тоже
   могут содержать N имён через запятую. Та же ужимка + tooltip. */
.coex-clients-table td.coex-brokers-cell,
.coex-clients-table td.coex-refovods-cell {
	max-width: 220px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* FIR-48 #9/#10/#14/#15 deploy-marker rules — позволяют QA service
   detect-нуть применённые фиксы через document.styleSheets без auth.
   Селекторы deliberately specific, ничего не стилизуют, существуют
   только для self-test. */
.coex-office-multi { /* FIR-48 #22v3 — multi-select офис на /admin/boxes/ */ }
.fir48-allfilters-marker { display: none; }
.fir48-9-deploy-marker { display: none; }
.fir48-10-deploy-marker { display: none; }
.fir48-14-deploy-marker { display: none; }

/* FIR-48 #22 — «дизайн пользовательской таблицы»: модалка «Изменить
   пользователя» съезжала по трём причинам:
     (a) «+» рядом с «Крипто-кошелёк» уезжал за правую границу модала —
         coex-full-row (grid-column 1/-1) не получал min-width:0/overflow:hidden,
         поэтому quick-add-row--inline выкидывал кнопку наружу.
     (b) Кастомная роль «Отдел продаж» (создана через admin-positions)
         попадала как chip в user-role-ids multi-select. Без жёсткого
         overflow-x:hidden на selection-container chip визуально вылезал
         поверх соседних полей (включая textarea «Примечание к источнику»).
     (c) Cells «Посредники» / «Рефоводы» в coex-user-roles-row имели разную
         высоту, когда один select пустой, другой — с chip-ами. align-items
         у grid-row не выставлен явно, select2-selection minHeight тоже
         различался. Юзер: «съехал почему внизу вообще неясно».
   Фикс — три CSS-правила ниже. */
.modal-form .row.form-group.coex-full-row {
	min-width: 0 !important;
	overflow: hidden !important;
}
.modal-form .row.form-group.coex-full-row > .col,
.modal-form .row.form-group.coex-full-row > [class*="col-"] {
	min-width: 0;
	overflow: hidden;
}
.modal-form .row.form-group.coex-full-row .quick-add-row--inline {
	min-width: 0;
	width: 100%;
}
.modal-form .row.form-group.coex-full-row .quick-add-row--inline > select,
.modal-form .row.form-group.coex-full-row .quick-add-row--inline > .select2,
.modal-form .row.form-group.coex-full-row .quick-add-row--inline > .select2-container {
	flex: 1 1 0;
	min-width: 0;
	max-width: calc(100% - 110px); /* зарезервировать место под «+ Новый» */
}
.modal-form .row.form-group.coex-full-row .quick-add-row--inline .quick-add-btn {
	flex: 0 0 auto;
}

/* FIR-48 #13/#22 — quick-add «+» CLIPPED past modal right edge.
   Корень: на ≥768px `.modal-form > .row.form-group` становится grid-cell-ом
   с `overflow:hidden` (см. ~989). Select2 после init ставит inline
   `width: NNNpx` на свой .select2-container; даже с `width:100% !important`
   (правило ~2677) flex-basis:auto заставляет контейнер занять ВСЮ ширину
   cell-а, не оставляя места под кнопку «+». Кнопка вылезает за правый край
   и обрезается `overflow:hidden`-ом.

   Раньше это чинилось ТОЛЬКО для user-wallet row через `.coex-full-row`
   (~4709) с резервом `calc(100% - 110px)`. Но office-modal rows
   (Криптокошельки / Кассы / Страна / Город) — это обычные `.row.form-group`
   БЕЗ `.coex-full-row`, поэтому резерв не применялся и «+» обрезался.

   Fix: для ЛЮБОГО `.quick-add-row--inline` внутри `.modal-form` делаем
   select2-container/нативный select сжимаемым (flex:1 1 0; min-width:0)
   и резервируем место под «+» (44px = 36px кнопка + 8px gap). Кнопка
   `flex:0 0 auto` остаётся целиком внутри cell-а. */
.modal-form .quick-add-row--inline {
	min-width: 0;
	width: 100%;
}
.modal-form .quick-add-row--inline > select,
.modal-form .quick-add-row--inline > .select2,
.modal-form .quick-add-row--inline > .select2-container {
	flex: 1 1 0 !important;
	min-width: 0 !important;
	width: auto !important; /* перебить select2 inline px-width */
	max-width: calc(100% - 44px); /* зарезервировать место под «+» (36px) + gap (8px) */
}
.modal-form .quick-add-row--inline .quick-add-btn {
	flex: 0 0 36px !important;
}

/* (b) chip-ы в user-role-ids НЕ должны вылезать за правый край select-а.
   max-height:72px уже стоит выше (#330) — добавляем overflow-x:hidden
   и принудительный wrap чипов внутри (вертикальный, а не горизонтальный
   overflow), чтобы кастомные длинные имена ролей («Отдел продаж») не
   накладывались на соседние секции модала. */
#user-modal .roles-select + .select2-container .select2-selection--multiple,
#user-modal #user-role-ids + .select2-container .select2-selection--multiple {
	overflow-x: hidden !important;
	overflow-y: auto !important;
}
#user-modal .roles-select + .select2-container .select2-selection--multiple .select2-selection__rendered,
#user-modal #user-role-ids + .select2-container .select2-selection--multiple .select2-selection__rendered {
	flex-wrap: wrap !important;
	max-width: 100%;
}
#user-modal .roles-select + .select2-container .select2-selection--multiple .select2-selection__choice,
#user-modal #user-role-ids + .select2-container .select2-selection--multiple .select2-selection__choice {
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
/* (c) выравниваем cell-ы Посредники / Рефоводы по высоте — grid-row stretch,
   select2-selection одинаковый min-height. */
.coex-user-roles-row {
	align-items: stretch;
}
.coex-user-roles-cell {
	align-self: stretch;
}
.coex-user-roles-cell .select2,
.coex-user-roles-cell .select2-container {
	width: 100% !important;
}
.coex-user-roles-cell .select2-container--default .select2-selection--single,
.coex-user-roles-cell .select2-container--default .select2-selection--multiple {
	min-height: 38px !important;
}
.fir48-22-user-modal-marker { display: none; }

/* FIR-48 v3 #24 v4 — v3 не сработал: col-4 внутри #debt-line-modal не
   получает Bootstrap flex 0 0 33.333% (что-то выше в каскаде делает
   col-* flex: 1 1 auto). Здесь принудительно возвращаем grid
   первой строки и гарантируем читаемость опций Тип. */
#debt-line-modal .modal-body .row.form-group {
    width: 100% !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
}
#debt-line-modal .modal-body .row.form-group > .col-4 {
    flex: 0 0 33.3333% !important;
    max-width: 33.3333% !important;
    min-width: 0 !important;
}
#debt-line-modal .modal-body .col-4 > .select2,
#debt-line-modal .modal-body .col-4 > .select2-container {
    width: 100% !important;
    min-width: 0 !important;
}
#debt-line-modal #debt-line-type + .select2-container .select2-selection__rendered {
    overflow: visible;
    text-overflow: clip;
    white-space: nowrap;
    padding-right: 28px;
}
#debt-line-modal #debt-line-type + .select2-container .select2-dropdown {
    min-width: 160px !important;
    width: auto !important;
}
#debt-line-modal .select2-results__option {
    white-space: nowrap !important;
    text-overflow: clip !important;
    overflow: visible !important;
    padding: 6px 12px !important;
}

/* FIR-49 #32 — вторая строка модалки (Касса | Контрагент) рендерилась
   ~полширины модалки: у .col-6 без min-width:0 длинный текст в Select2 не
   даёт flex-item сжиматься, а сам .select2-container берёт inline-width
   из исходного <select> (общий initializeSelect2 не передаёт width:'100%').
   Зеркалим существующее правило для col-4: фиксируем 50/50 раскладку и
   принудительно тянем select2-container на всю ширину колонки. */
#debt-line-modal .modal-body .row.form-group > .col-6 {
    flex: 1 1 0 !important;
    max-width: 50% !important;
    min-width: 0 !important;
}
#debt-line-modal .modal-body .col-6 > .select2,
#debt-line-modal .modal-body .col-6 > .select2-container {
    width: 100% !important;
    max-width: 100% !important;
    min-width: 0 !important;
}
/* FIR-49 #32 v2 — РАУНД 2.
   ПРОБЛЕМА 1: `+ .select2-container` не давал ellipsis на КАССЕ — глобальный
   фикс из style.css:237 `.boxes-select + .select2-container .select2-selection__rendered`
   ставит white-space:normal !important и перебивал. Переписываем через РОДИТЕЛЯ
   .col-6 + поднимаем специфичность и !important на каждое свойство. Покрываем
   ОБА поля одной цепочкой (КАССА boxes-select + КОНТРАГЕНТ users-select).
   ПРОБЛЕМА 2: dropdown не парился внутри `.select2-container` (Select2 v4 кладёт
   его в dropdownParent — здесь .modal). Селектор через сиблинг просто не матчил.
   Адресуем через класс на самом dropdown'е: для КАССЫ уже coex-boxes-dd
   (min-width:280px в строке ~4036), для КОНТРАГЕНТА добавляем парный
   coex-debt-line-agent-dd через data-dropdown-class в шаблоне. */
#debt-line-modal .modal-body .row.form-group > .col-6 .select2-selection__rendered {
    white-space: nowrap !important;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
    padding-right: 28px !important;
    word-break: normal !important;
}
/* Dropdown панель «Контрагент» (зеркало .coex-boxes-dd для КАССЫ).
   Класс приклеивается к самому .select2-dropdown через dropdownCssClass
   (initializeSelect2 в scripts.js ~966), независимо от dropdownParent. */
.select2-dropdown.coex-debt-line-agent-dd {
    width: max-content !important;
    min-width: 240px !important;
    max-width: 90vw;
}
.select2-dropdown.coex-debt-line-agent-dd .select2-results__option {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.select2-dropdown.coex-debt-line-agent-dd .select2-results__options {
    overflow-x: auto;
}
/* ПРОБЛЕМА 3: контейнер `#additional-debt-line-fields` ужимался — страховка
   на 100% ширины модалки. Row-margins уже сброшены выше (.row.form-group). */
#debt-line-modal #additional-debt-line-fields {
    width: 100% !important;
}

/* FIR-48 #24 — «Тип долговой операции»: btn-group из 5 кнопок с длинными
   подписями обрезался/съезжал. Меняем на CSS-grid, равные колонки, перенос
   текста, активная radio-кнопка подсвечивается акцентом. */
.coex-app .debt-type-group {
    display: grid;
    grid-template-columns: repeat(5, minmax(140px, 1fr));
    gap: 6px;
    width: 100%;
}
.coex-app .debt-type-group .btn {
    white-space: normal;
    line-height: 1.15;
    min-height: 44px;
    padding: 8px 10px;
    font-size: 12px;
    font-weight: 500;
    border-radius: 6px;
    text-align: center;
}
/* Bootstrap btn-check pattern: активный radio через :checked + .btn,
   класс .active не выставляется, поэтому селектор отличается от шаблона
   дизайнера, но визуальный результат тот же. */
.coex-app .debt-type-group .btn-check:checked + .btn,
.coex-app .debt-type-group .btn.active {
    background: var(--accent);
    color: #fff;
    border-color: var(--accent);
}
@media (max-width: 1280px) {
    .coex-app .debt-type-group {
        grid-template-columns: repeat(3, 1fr);
        width: 100%;
    }
}

/* FIR-48 #18 — operator-accounting + другие операционные формы (кроме balancing):
   валютный select2 — самостоятельный pill (radius 6px по 4 углам), input «Сумма» — тоже pill,
   зазор 8px. Перебиваем FIR-42 #220 склейку из правил выше в этом же файле.
   Whitelist по data-type — balancing исключён, там склейка валюта+сумма по дизайну. */

form#main-form[data-type="accounting"] .coex-balance-row .input-group,
form#main-form[data-type="income"]     .coex-balance-row .input-group,
form#main-form[data-type="outcome"]    .coex-balance-row .input-group,
form#main-form[data-type="consult"]    .coex-balance-row .input-group,
form#main-form[data-type="custom"]     .coex-balance-row .input-group,
form#main-form[data-type="exchange"]   .coex-balance-row .input-group,
form#main-form[data-type="debt"]       .coex-balance-row .input-group {
  gap: 8px !important;
  flex-wrap: nowrap;
}

form#main-form[data-type="accounting"] .coex-balance-row .input-group > .select2-container .select2-selection,
form#main-form[data-type="income"]     .coex-balance-row .input-group > .select2-container .select2-selection,
form#main-form[data-type="outcome"]    .coex-balance-row .input-group > .select2-container .select2-selection,
form#main-form[data-type="consult"]    .coex-balance-row .input-group > .select2-container .select2-selection,
form#main-form[data-type="custom"]     .coex-balance-row .input-group > .select2-container .select2-selection,
form#main-form[data-type="exchange"]   .coex-balance-row .input-group > .select2-container .select2-selection,
form#main-form[data-type="debt"]       .coex-balance-row .input-group > .select2-container .select2-selection {
  border-radius: 6px !important;
  border: 1px solid var(--line) !important;
}

form#main-form[data-type="accounting"] .coex-balance-row .input-group > .select2-container--default.select2-container--focus .select2-selection,
form#main-form[data-type="income"]     .coex-balance-row .input-group > .select2-container--default.select2-container--focus .select2-selection,
form#main-form[data-type="outcome"]    .coex-balance-row .input-group > .select2-container--default.select2-container--focus .select2-selection,
form#main-form[data-type="consult"]    .coex-balance-row .input-group > .select2-container--default.select2-container--focus .select2-selection,
form#main-form[data-type="custom"]     .coex-balance-row .input-group > .select2-container--default.select2-container--focus .select2-selection,
form#main-form[data-type="exchange"]   .coex-balance-row .input-group > .select2-container--default.select2-container--focus .select2-selection,
form#main-form[data-type="debt"]       .coex-balance-row .input-group > .select2-container--default.select2-container--focus .select2-selection,
form#main-form[data-type="accounting"] .coex-balance-row .input-group > .select2-container--default.select2-container--open .select2-selection,
form#main-form[data-type="income"]     .coex-balance-row .input-group > .select2-container--default.select2-container--open .select2-selection,
form#main-form[data-type="outcome"]    .coex-balance-row .input-group > .select2-container--default.select2-container--open .select2-selection,
form#main-form[data-type="consult"]    .coex-balance-row .input-group > .select2-container--default.select2-container--open .select2-selection,
form#main-form[data-type="custom"]     .coex-balance-row .input-group > .select2-container--default.select2-container--open .select2-selection,
form#main-form[data-type="exchange"]   .coex-balance-row .input-group > .select2-container--default.select2-container--open .select2-selection,
form#main-form[data-type="debt"]       .coex-balance-row .input-group > .select2-container--default.select2-container--open .select2-selection {
  border-radius: 6px !important;
  border: 1px solid var(--accent) !important;
}

form#main-form[data-type="accounting"] .coex-balance-row .input-group > input.form-control,
form#main-form[data-type="income"]     .coex-balance-row .input-group > input.form-control,
form#main-form[data-type="outcome"]    .coex-balance-row .input-group > input.form-control,
form#main-form[data-type="consult"]    .coex-balance-row .input-group > input.form-control,
form#main-form[data-type="custom"]     .coex-balance-row .input-group > input.form-control,
form#main-form[data-type="exchange"]   .coex-balance-row .input-group > input.form-control,
form#main-form[data-type="debt"]       .coex-balance-row .input-group > input.form-control {
  border-radius: 6px !important;
  border: 1px solid var(--line) !important;
  margin-left: 0 !important;
}

/* FIR-55 #3 (баг 1147) — на accounting/consult/custom «Сумма к выдаче» лежит в
   .coex-balance-row .input-group, и правило выше (спец. 1,3,3) перебивало зелёную
   рамку сходящейся выдачи (grey var(--line)). Дублируем .is-valid-ветку с .is-valid
   в селекторе (спец. 1,4,3) → зелёная рамка снова выигрывает. Совпадает с exchange,
   где балансового wrapper'а нет и работала .coex-app .form-control.is-valid. */
form#main-form[data-type="accounting"] .coex-balance-row .input-group > input.form-control.is-valid,
form#main-form[data-type="income"]     .coex-balance-row .input-group > input.form-control.is-valid,
form#main-form[data-type="outcome"]    .coex-balance-row .input-group > input.form-control.is-valid,
form#main-form[data-type="consult"]    .coex-balance-row .input-group > input.form-control.is-valid,
form#main-form[data-type="custom"]     .coex-balance-row .input-group > input.form-control.is-valid,
form#main-form[data-type="exchange"]   .coex-balance-row .input-group > input.form-control.is-valid,
form#main-form[data-type="debt"]       .coex-balance-row .input-group > input.form-control.is-valid {
  border-color: var(--ok) !important;
}

/* FIR-48 #18 (2-й круг) — schлопнуть ширину .select2-container до contents,
   убрать унаследованный Bootstrap min-width:140px от .form-select и margin-left:-1px,
   чтобы реальный визуальный gap между chevron'ом валюты и полем «Сумма» был 8px,
   а не 41px (selection width 106px против контейнера 140px = 34px пустоты внутри). */
form#main-form[data-type="accounting"] .coex-balance-row .input-group > .select2-container,
form#main-form[data-type="income"]     .coex-balance-row .input-group > .select2-container,
form#main-form[data-type="outcome"]    .coex-balance-row .input-group > .select2-container,
form#main-form[data-type="consult"]    .coex-balance-row .input-group > .select2-container,
form#main-form[data-type="custom"]     .coex-balance-row .input-group > .select2-container,
form#main-form[data-type="exchange"]   .coex-balance-row .input-group > .select2-container,
form#main-form[data-type="debt"]       .coex-balance-row .input-group > .select2-container {
  width: auto !important;
  min-width: 0 !important;
  flex: 0 0 auto !important;
  margin-left: 0 !important;
}

/* =====================================================================
   FIR-48 #46 — column-toggler (pilot /admin/debts/) + op-meta header.
   ===================================================================== */
.coex-table-toolbar {
  display: flex;
  justify-content: flex-end;
  padding: 6px 8px 4px;
  position: relative;
  overflow: visible;
}

.coex-col-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  background: #fff;
  border: 1px solid var(--ink-6, #e6e6ea);
  border-radius: 6px;
  color: var(--ink-2, #333);
  cursor: pointer;
  padding: 0;
  transition: border-color .15s, color .15s;
}
.coex-col-toggle:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.coex-col-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.coex-col-toggle .ic,
.coex-col-toggle svg {
  width: 16px;
  height: 16px;
  stroke: currentColor;
  fill: none;
}

.coex-cols-pop {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 30;
  min-width: 220px;
  max-width: 260px;
  max-height: 60vh;
  overflow-y: auto;
  background: #fff;
  border: 1px solid var(--ink-6, #e6e6ea);
  border-radius: 8px;
  box-shadow: 0 6px 24px rgba(0,0,0,.08), 0 1px 2px rgba(0,0,0,.04);
  padding: 6px 0;
}
.coex-cols-pop[hidden] { display: none; }

.coex-cols-pop__head {
  padding: 8px 12px 6px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ink-3, #666);
  border-bottom: 1px solid var(--ink-6, #e6e6ea);
}
.coex-cols-pop__list {
  list-style: none;
  margin: 0;
  padding: 4px 0;
}
.coex-cols-pop__item {
  padding: 0;
  margin: 0;
}
.coex-cols-pop__item > label {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  font-size: 13px;
  cursor: pointer;
  margin: 0;
  width: 100%;
  user-select: none;
}
.coex-cols-pop__item > label:hover {
  background: rgba(94,106,210,.06);
}
.coex-cols-pop__item input[type="checkbox"] {
  accent-color: var(--accent);
  margin: 0;
  cursor: pointer;
}
.coex-cols-pop__item input[type="checkbox"]:disabled {
  cursor: not-allowed;
  opacity: .5;
}
.coex-cols-pop__foot {
  padding: 6px 12px 4px;
  border-top: 1px solid var(--ink-6, #e6e6ea);
  display: flex;
  justify-content: flex-end;
}
.coex-cols-pop__reset {
  background: none;
  border: 0;
  padding: 2px 0;
  font-size: 12px;
  color: var(--ink-3, #666);
  border-bottom: 1px dotted var(--ink-3, #666);
  cursor: pointer;
  line-height: 1.2;
}
.coex-cols-pop__reset:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

@keyframes coex-pop-shake {
  0%   { transform: translateX(0); }
  25%  { transform: translateX(-3px); }
  50%  { transform: translateX(3px); }
  75%  { transform: translateX(-2px); }
  100% { transform: translateX(0); }
}
.coex-pop-shake {
  animation: coex-pop-shake .25s ease-in-out;
}

/* op-meta header в операторских формах сделок (read-only). */
.coex-op-meta {
  font-size: 12px;
  color: var(--ink-3, #666);
  padding: 6px 0 10px;
  border-bottom: 1px solid var(--ink-6, #e6e6ea);
  margin-bottom: 12px;
  display: flex;
  gap: 8px;
  align-items: baseline;
  flex-wrap: wrap;
}
.coex-op-meta .lbl {
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: 10px;
  color: var(--ink-4, #999);
  margin-right: 2px;
}
.coex-op-meta .val {
  color: var(--ink-2, #333);
  font-variant-numeric: tabular-nums;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: inline-block;
  vertical-align: middle;
}
.coex-op-meta__sep {
  color: var(--ink-5, #bbb);
}
@media (max-width: 600px) {
  .coex-op-meta__sep { display: none; }
}

/* FIR-48 #68 — статус-тумблер (.switch + .slider.round) рендерился голым
   Bootstrap-квадратом: стилей самого переключателя в проекте не было.
   Делаем нормальный iOS-style toggle (офис/город/валюта/… — статус). */
.switch { position: relative; display: inline-block; width: 46px; height: 26px; cursor: pointer; margin: 0; }
.switch input[type="checkbox"] { position: absolute; opacity: 0; width: 0; height: 0; margin: 0; pointer-events: none; }
.switch .slider { position: absolute; inset: 0; background: var(--line, #d0d3e0); border-radius: 999px; transition: background .18s ease; }
.switch .slider::before { content: ""; position: absolute; height: 20px; width: 20px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: transform .18s ease; box-shadow: 0 1px 2px rgba(0,0,0,.25); }
.switch input:checked + .slider { background: var(--accent, #5e6ad2); }
.switch input:checked + .slider::before { transform: translateX(20px); }
.switch input:focus-visible + .slider { box-shadow: 0 0 0 3px rgba(94,106,210,.25); }

/* ─────────────────────────────────────────────────────────────────────────
   FIR-48 #68/#70 — ЕДИНЫЙ «+»: глиф ВСЕГДА строго по центру кнопки.
   Юзер (повторно): «+ должен быть всегда в центре». Корень регрессии: центровку
   add-кнопки задавали 6 разных областей (#office-modal, #country-modal,
   .quick-add-row--inline, .modal-form .quick-add-btn, .coex-full-row…), причём
   часть — через position:absolute + translate(-50%,-50%) на иконке. У Bootstrap
   Icons псевдоэлемент .bi::before имеет vertical-align:-.125em → глиф «+» съезжал
   вниз, по-разному в каждой модалке. Здесь ОДНО правило поверх всех: квадрат
   фикс-размера, «+» центрируется самим flex-боксом (надёжно), abs-позиционирование
   и icon-font-смещение погашены. Внешний вид (фон/рамка из .quick-add-row--inline)
   НЕ трогаем — только геометрия и центровка. Применяется во ВСЕХ модалках разом,
   чтобы «+» больше не расходился между офисом/страной/городом/юзером/валютой. */
.quick-add-btn,
.modal .quick-add-btn,
.modal-form .quick-add-btn,
#office-modal .quick-add-btn,
#country-modal .quick-add-btn,
.quick-add-row--inline .quick-add-btn {
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  width: 38px !important;
  height: 38px !important;
  min-width: 38px !important;
  flex: 0 0 38px !important;
  padding: 0 !important;
  gap: 0 !important;
  font-size: 0 !important;          /* прячет подпись «Новый/Новая» — остаётся только «+» */
  line-height: 1 !important;
  align-self: center !important;    /* по центру относительно select-а в строке */
  overflow: hidden;
}
.quick-add-btn > i,
.quick-add-btn > .bi,
.modal .quick-add-btn > i,
.modal .quick-add-btn > .bi,
.modal-form .quick-add-btn > i,
.modal-form .quick-add-btn > .bi,
#office-modal .quick-add-btn > i,
#office-modal .quick-add-btn > .bi,
#country-modal .quick-add-btn > i,
#country-modal .quick-add-btn > .bi,
.quick-add-row--inline .quick-add-btn > i,
.quick-add-row--inline .quick-add-btn > .bi {
  position: static !important;      /* убираем absolute — flex центрирует сам */
  transform: none !important;
  top: auto !important;
  left: auto !important;
  right: auto !important;
  bottom: auto !important;
  margin: 0 !important;
  padding: 0 !important;
  font-size: 17px !important;
  line-height: 1 !important;
  display: block !important;
}
/* Bootstrap Icons по умолчанию опускают глиф на vertical-align:-.125em —
   именно это и сдвигало «+» вниз от центра. Гасим. */
.quick-add-btn > i::before,
.quick-add-btn > .bi::before,
.modal-form .quick-add-btn > i::before,
#office-modal .quick-add-btn > i::before,
.quick-add-row--inline .quick-add-btn > i::before {
  vertical-align: middle !important;
}

/* FIR-48 #72 — упрощение модалки добавления офиса.
   Свёртка «Дополнительно» в ADD-режиме скрывает шаблоны / крипто / кассы /
   оборотку. В EDIT/SHOW режимах (класс coex-mode-edit / coex-mode-show на
   #office-modal) — раскрыта всегда, кнопка-тоггл скрыта (см. scripts.js
   show.bs.modal handler). */
#office-modal .coex-collapse-section { margin-top: 12px; border-top: 1px solid var(--line); padding-top: 12px; }
/* FIR-53 #3 — крипто/кассы/оборотка показываются инлайн (без collapse).
   Тонкий разделитель сверху + section-title отделяют их от блока выше. */
#office-modal .office-extra-section { margin-top: 16px; border-top: 1px solid var(--line); padding-top: 16px; }
#office-modal .office-extra-section > .coex-section-title { margin-bottom: 14px; }
#office-modal .coex-collapse-toggle { display: flex; align-items: center; gap: 8px; background: transparent; border: 0; padding: 8px 0; font-weight: 500; font-size: 14px; color: var(--ink); cursor: pointer; width: 100%; text-align: left; }
#office-modal .coex-collapse-toggle:hover { background: var(--bg-3); }
#office-modal .coex-collapse-hint { color: var(--ink-3); font-weight: 400; }
#office-modal .coex-collapse-chevron { transition: transform .2s ease; }
#office-modal .coex-collapse-toggle[aria-expanded="true"] .coex-collapse-chevron { transform: rotate(180deg); }
.coex-required { color: var(--bad); margin-left: 2px; font-weight: 500; }
#office-modal.coex-mode-edit #office-extra-section .coex-collapse-toggle,
#office-modal.coex-mode-show #office-extra-section .coex-collapse-toggle { display: none; }
#office-modal.coex-mode-edit #office-extra-body,
#office-modal.coex-mode-show #office-extra-body { display: block !important; height: auto !important; visibility: visible !important; }

/* ─────────────────────────────────────────────────────────────────────────
   FIR-48 — «строка словно без имени»: у поля с quick-add (Базовая валюта,
   Касса, Страна, Город) метка должна ИМЕНОВАТЬ строку ВЫБОРА (select + «+»),
   а не уезжать к центру колонки, когда снизу раскрыт блок «добавить новое».
   Прижимаем метку к верху → она всегда подписывает строку выбора. */
.modal-form .row.form-group:has(.quick-add-row--inline) > .form-label,
#country-modal .row.form-group:has(.quick-add-row--inline) > .form-label,
#office-modal .row.form-group:has(.quick-add-row--inline) > .form-label {
  align-self: flex-start !important;
  padding-top: 8px;
}
/* Подпись раскрытого блока «добавить новое» (валюта/касса/страна/город) */
.quick-add-cap {
  flex-basis: 100%; width: 100%; order: -1;
  font-size: 11px; font-weight: 500; color: var(--ink-2);
  margin: 0 0 6px; letter-spacing: .01em;
}

/* P3-10 — empty-state inline-таблиц форм (Доходы/Расходы на exchange/accounting,
   Долговые позиции на debt). Эти tbody на старте пустые (шапка без строк), JS
   вставляет <tr> через «+ Добавить». Через :empty показываем ненавязчивую
   подсказку прямо в пустом tbody; как только JS добавит первый <tr>, tbody
   перестаёт быть :empty → подсказка исчезает сама (ничего не ломает «+ Добавить»).
   Рендерим pseudo-row как block внутри tbody — table-fix-up браузера оставит
   текст внутри строки таблицы, занимая всю ширину. */
.income-table > tbody:empty::after,
.outcome-table > tbody:empty::after,
.debt-line-table > tbody:empty::after {
  content: "Нет позиций — нажмите + Добавить";
  display: block;
  padding: 16px 12px;
  text-align: center;
  color: var(--ink-3);
  font-size: 13px;
}
/* косметика exchange: пустой tbody без строк не давал нижней границы → «незамкнутый»
   контур таблицы. Лёгкая верхняя линия отделяет подсказку от шапки. */
.income-table > tbody:empty,
.outcome-table > tbody:empty,
.debt-line-table > tbody:empty {
  display: table-caption;
  caption-side: bottom;
  border-top: 1px solid var(--line, #e5e5e5);
}

/* FIR-43 #8 — визуально-выключённая обёртка Save в модалках Доход/Расход.
   coex-save-wrap.is-disabled навешивается coexIncomeOutcomeSaveGate, когда
   офис/валюта/касса не заполнены. opacity .5 + cursor not-allowed + блок
   pointer-events на дочерней кнопке (сам span ловит hover для tooltip). */
.coex-save-wrap.is-disabled {
  opacity: .5;
  cursor: not-allowed;
}
.coex-save-wrap.is-disabled > .btn,
.coex-save-wrap.is-disabled > .modal-save {
  pointer-events: none;
}

/* FIR-49 #21 — modal outcome: align amount input + clear category border + neutral switch */

/* 1. #outcome-amount → 36px / 14px / 400 как соседние Select2 */
#outcome-front-modal .coex-amount-group > .coex-amount-input {
  height: 36px;
  min-height: 36px;
  padding: 4px 10px;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.4;
}

/* 2. Согласование углов внутри input-group (Select2 слева — закруглён слева, input справа — закруглён справа) */
#outcome-front-modal .coex-amount-group > .select2-container .select2-selection {
  border-top-left-radius: 6px !important;
  border-bottom-left-radius: 6px !important;
  border-top-right-radius: 0 !important;
  border-bottom-right-radius: 0 !important;
}
#outcome-front-modal .coex-amount-group > .coex-amount-input {
  border-top-left-radius: 0 !important;
  border-bottom-left-radius: 0 !important;
  border-top-right-radius: 6px !important;
  border-bottom-right-radius: 6px !important;
}

/* 3. Снять чёрную обводку с блока «Вид расхода» */
#outcome-front-modal .coex-outcome-category {
  border: 0;
  background: transparent;
  padding: 0;
  margin-bottom: 0;
}

/* 4. Нейтральный switch до клика, акцент при :checked */
#outcome-front-modal .coex-outcome-return .form-check-input {
  background-color: #fff !important;
  border-color: var(--line) !important;
  box-shadow: none !important;
}
#outcome-front-modal .coex-outcome-return .form-check-input:checked {
  background-color: var(--accent) !important;
  border-color: var(--accent) !important;
}
#outcome-front-modal .coex-outcome-return .form-check-input:focus {
  box-shadow: 0 0 0 2px var(--accent-soft) !important;
  border-color: var(--accent) !important;
}

/* FIR-51 #6 — нейтральный hover для кликабельных строк income/outcome
   (категория без синего underline; клик по любой ячейке открывает модалку). */
.tr-edit:hover { background: rgba(0,0,0,.03); }
