/* ==========================================================================
   LUMO / ui — рабочие компоненты страниц админки.
   --------------------------------------------------------------------------
   Один словарь на все разделы: страница, панель, кнопка, поле, фильтр,
   таблица, статус, пустое состояние, загрузка. Раньше каждый экран
   доопределял своё в pages/*.css поверх ui-components/ui-workspace — отсюда
   и брались расхождения («сохранить» выглядела по-разному на трёх экранах).

   Здесь же живут классы, которые страницы не пишут в разметке, а создаёт их
   JavaScript (мультиселект `.ms*`, сегменты `.scope-tab`, `.empty`,
   `.loading`, `.err`, `.kv`). Их имена трогать нельзя: на них завязано
   36 тысяч строк рабочего кода страниц. Меняется вид, не контракт.
   ========================================================================== */

/* ---------------- 1. Страница ---------------- */
.lm-page{ max-width: var(--lm-page-max); margin: 0 auto; padding: 16px 20px 40px; }
.lm-page__head{
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  flex-wrap: wrap; margin-bottom: 14px;
}
.lm-page__titles{ min-width: 0; }
.lm-page__sub{ margin-top: 4px; font-size: var(--lm-text-md); color: var(--lm-muted); max-width: 78ch; }
.lm-page__actions{ display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.lm-section{
  background: var(--lm-surface);
  border: 1px solid var(--lm-border);
  border-radius: var(--lm-radius-md);
}
.lm-section + .lm-section{ margin-top: 12px; }
.lm-section__head{
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  padding: 12px 14px;
  border-bottom: 1px solid var(--lm-border-soft);
}
.lm-section__title{ font-size: var(--lm-text-lg); font-weight: 640; }
.lm-section__sub{ font-size: var(--lm-text-sm); color: var(--lm-muted); margin-top: 2px; }
.lm-section__body{ padding: 12px 14px; }
.lm-section__body--flush{ padding: 0; }

/* ---------------- Ряд секций ----------------
   Сетка из секций одной высоты. Соседям обнуляется margin-top: правило
   `.lm-section + .lm-section` рассчитано на поток, а внутри сетки оно
   сдвигало вторую колонку вниз — на «Базе данных» блоки выглядели
   съехавшими друг относительно друга. */
.lm-bento{ display: grid; gap: 12px; }
.lm-bento > .lm-section + .lm-section{ margin-top: 0; }
.lm-bento--2{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
.lm-bento--3{ grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 1023px){
  .lm-bento--2, .lm-bento--3{ grid-template-columns: 1fr; }
}


/* ---------------- 1a. Рабочая раскладка «панель + область» ----------------
   Слева узкая колонка с настройками (фильтры рассылки, параметры отчёта),
   справа то, с чем работают. Не «рейл фильтров» из старой системы: колонка
   липкая и остаётся на виду, пока листаешь список. */
.lm-split{ display: grid; grid-template-columns: minmax(0, 340px) minmax(0, 1fr); gap: 12px; align-items: start; }
.lm-split__side{ position: sticky; top: calc(var(--lm-bar-h) + 12px); display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.lm-split__main{ min-width: 0; }
@media (max-width: 1099px){
  .lm-split{ grid-template-columns: 1fr; }
  .lm-split__side{ position: static; }
}

/* ---------------- 2. Кнопки ---------------- */
.lm-btn{
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  min-height: 34px; padding: 0 13px; border-radius: var(--lm-radius-sm);
  border: 1px solid var(--lm-border); background: var(--lm-surface);
  font-size: 13px; font-weight: 620; color: var(--lm-text); white-space: nowrap;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease, transform .12s ease;
}
.lm-btn:hover{ background: var(--lm-surface-3); border-color: color-mix(in srgb, var(--lm-accent) 34%, var(--lm-border)); }
.lm-btn:active{ transform: translateY(1px); }
.lm-btn[disabled], .lm-btn.is-disabled{
  opacity: .55; cursor: not-allowed; transform: none;
  background: var(--lm-surface-2); border-color: var(--lm-border-soft); color: var(--lm-muted-2);
}
.lm-btn svg{ width: 16px; height: 16px; }
.lm-btn--primary{ background: var(--lm-accent); border-color: var(--lm-accent); color: var(--lm-accent-text); }
.lm-btn--primary:hover{ background: var(--lm-accent-hover); border-color: var(--lm-accent-hover); }
.lm-btn--danger{ background: var(--lm-surface); border-color: color-mix(in srgb, var(--lm-danger) 45%, var(--lm-border)); color: var(--lm-danger); }
.lm-btn--danger:hover{ background: var(--lm-danger-soft); border-color: var(--lm-danger); }
.lm-btn--ghost{ background: transparent; border-color: transparent; color: var(--lm-muted); }
.lm-btn--ghost:hover{ background: var(--lm-surface-3); color: var(--lm-text); border-color: transparent; }
.lm-btn--sm{ min-height: 28px; padding: 0 9px; font-size: var(--lm-text-sm); border-radius: var(--lm-radius-xs); }
.lm-btn--icon{ width: 34px; padding: 0; }
.lm-btn--icon.lm-btn--sm{ width: 28px; }
.lm-btn.is-loading{ position: relative; color: transparent; pointer-events: none; }
.lm-btn.is-loading::after{
  content: ""; position: absolute; width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid color-mix(in srgb, currentColor 30%, transparent);
  border-top-color: var(--lm-accent);
  animation: lm-spin .7s linear infinite;
}
.lm-btn--primary.is-loading::after{ border-top-color: #fff; border-color: rgba(255,255,255,.35); border-top-color: #fff; }
@keyframes lm-spin{ to{ transform: rotate(360deg); } }

.lm-link{ color: var(--lm-accent); font-weight: 620; }
.lm-link:hover{ text-decoration: underline; text-underline-offset: 3px; }
.lm-link.is-danger{ color: var(--lm-danger); }


/* ---------------- 2a. Мост для кнопок, которые рисует JS ----------------
   Скрипты страниц (промо, заказы, маршруты, реестр) вставляют разметку
   строками и пишут туда старые классы `mp-btn`. Переписывать 4 тысячи строк
   рабочего JS ради имени класса незачем — здесь они получают вид системной
   кнопки. Правило уходит, когда эти скрипты будут переписаны. */
.lm .mp-btn{
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  min-height: 34px; padding: 0 13px; border-radius: var(--lm-radius-sm);
  border: 1px solid var(--lm-border); background: var(--lm-surface);
  font-size: 13px; font-weight: 620; color: var(--lm-text); white-space: nowrap; cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.lm .mp-btn:hover{ background: var(--lm-surface-3); border-color: color-mix(in srgb, var(--lm-accent) 34%, var(--lm-border)); }
.lm .mp-btn[disabled]{ opacity: .55; cursor: not-allowed; }
.lm .mp-btn--primary{ background: var(--lm-accent); border-color: var(--lm-accent); color: var(--lm-accent-text); }
.lm .mp-btn--primary:hover{ background: var(--lm-accent-hover); border-color: var(--lm-accent-hover); }
.lm .mp-btn--danger{ color: var(--lm-danger); border-color: color-mix(in srgb, var(--lm-danger) 45%, var(--lm-border)); }
.lm .mp-btn--danger:hover{ background: var(--lm-danger-soft); border-color: var(--lm-danger); }
.lm .mp-btn--ghost{ background: transparent; border-color: transparent; color: var(--lm-muted); }
.lm .mp-btn--ghost:hover{ background: var(--lm-surface-3); color: var(--lm-text); }
.lm .mp-btn--sm{ min-height: 28px; padding: 0 9px; font-size: var(--lm-text-sm); border-radius: var(--lm-radius-xs); }
.lm .mp-input{
  min-height: 34px; padding: 6px 10px;
  border-radius: var(--lm-radius-sm); border: 1px solid var(--lm-border);
  background: var(--lm-surface-2); color: var(--lm-text); font-size: 13px;
}
.lm .mp-input:focus{
  outline: none; background: var(--lm-surface); border-color: var(--lm-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--lm-accent) 18%, transparent);
}
.lm .muted{ color: var(--lm-muted); }

/* ---------------- 3. Поля и фильтры ---------------- */
.lm-toolbar{
  display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap;
  padding: 11px 12px; margin-bottom: 12px;
  background: var(--lm-surface); border: 1px solid var(--lm-border); border-radius: var(--lm-radius-md);
}
.lm-toolbar__spacer{ flex: 1 1 auto; }
.lm-toolbar__note{ font-size: var(--lm-text-sm); color: var(--lm-muted); }
/* Группа кнопок; --end прижимает её к правому краю (подвалы модалок). */
.lm-btnrow{ display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.lm-btnrow--end{ margin-left: auto; }

.lm-field{ display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.lm-field--grow{ flex: 1 1 190px; }
/* Поле с выпадающим фильтром: не ужимается до нечитаемого, но и не тянется
   на всю строку — иначе шесть фильтров расползаются по трём рядам. */
.lm-field--ms{ flex: 1 1 190px; min-width: 178px; max-width: 250px; }
.lm-label{ font-size: var(--lm-text-xs); font-weight: 650; color: var(--lm-muted); }

.lm-input, .lm-select, .lm-textarea{
  min-height: 34px; padding: 6px 10px;
  border-radius: var(--lm-radius-sm); border: 1px solid var(--lm-border);
  background: var(--lm-surface-2); color: var(--lm-text);
  font-size: 13px;
  transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease;
}
.lm-input:hover, .lm-select:hover, .lm-textarea:hover{ border-color: color-mix(in srgb, var(--lm-accent) 30%, var(--lm-border)); }
.lm-input:focus, .lm-select:focus, .lm-textarea:focus{
  outline: none; background: var(--lm-surface);
  border-color: var(--lm-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--lm-accent) 18%, transparent);
}
.lm-input::placeholder, .lm-textarea::placeholder{ color: var(--lm-muted-2); }
.lm-input[disabled], .lm-select[disabled], .lm-textarea[disabled]{ opacity: .6; cursor: not-allowed; }
.lm-textarea{ min-height: 96px; resize: vertical; }
/* Стрелку рисует сам select фоновой картинкой: обёртка .lm-select-wrap есть
   не везде, и без неё список выглядел как обычное поле ввода — на «Отчётах за
   день» и «Покрытии» по нему было не понять, что он раскрывается. */
.lm-select{
  appearance: none; padding-right: 28px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5 6 8l3.5-3.5' fill='none' stroke='%23808ba1' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 9px center; background-size: 12px 12px;
}
.lm-select-wrap{ position: relative; display: inline-flex; }
/* Обёртка осталась ради выравнивания в строке; вторую стрелку не рисуем. */
.lm-input--sm, .lm-select--sm{ min-height: 28px; font-size: var(--lm-text-sm); }
.lm-input[type="date"]{ min-width: 138px; }
.lm-input[type="search"]::-webkit-search-cancel-button{ filter: grayscale(1) opacity(.6); }

/* ---------------- Выпадающий фильтр (мультиселект) ----------------
   На страницах живут ДВА движка с разной разметкой: «homegrown» (сам .ms —
   это контрол: reports_today, users, shops) и «кнопочный» (.ms > .ms-btn:
   tasks, visit_alerts, statistics). Оба рисует JS страниц, менять разметку
   нельзя — поэтому единый вид собран здесь, из общих правил для панели и
   строк плюс два разных селектора для самого контрола.

   Что было не так до 19.08: панель наследовала ширину поля (в тулбаре это
   ~120px), из-за чего «Выполнена» превращалась в «Выполне…», а внутри
   появлялись горизонтальные полосы прокрутки — в каждом фильтре и в каждой
   модалке. Теперь панель шире поля и никогда не прокручивается вбок. */

.lm .ms{ position: relative; display: block; min-width: 0; }

/* Контрол: homegrown-вариант (.ms без кнопки внутри) и кнопочный (.ms-btn). */
.lm .ms:not(:has(.ms-btn)),
.lm .ms .ms-btn{
  display: flex; align-items: center; gap: 8px;
  width: 100%; min-height: 34px; padding: 6px 30px 6px 10px;
  border-radius: var(--lm-radius-sm); border: 1px solid var(--lm-border);
  background: var(--lm-surface-2); color: var(--lm-text);
  font-size: 13px; text-align: left; cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease;
}
.lm .ms:not(:has(.ms-btn)):hover,
.lm .ms .ms-btn:hover{ border-color: color-mix(in srgb, var(--lm-accent) 32%, var(--lm-border)); }
.lm .ms.open:not(:has(.ms-btn)),
.lm .ms.open .ms-btn{
  background: var(--lm-surface); border-color: var(--lm-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--lm-accent) 16%, transparent);
}
.lm .ms-value{
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Шеврон: у обоих движков свой элемент, но выглядит одинаково и стоит в поле. */
.lm .ms-caret, .lm .ms-chev{
  position: absolute; right: 11px; top: 50%; transform: translateY(-50%);
  width: 9px; height: 9px; color: transparent; font-size: 0; pointer-events: none;
}
.lm .ms-caret::after, .lm .ms-chev::after{
  content: ""; position: absolute; inset: 0 0 auto 0;
  width: 7px; height: 7px; margin: 0 auto;
  border-right: 1.8px solid var(--lm-muted); border-bottom: 1.8px solid var(--lm-muted);
  transform: rotate(45deg) translate(-1px, -1px);
  transition: transform var(--lm-dur) var(--lm-ease);
}
.lm .ms.open .ms-caret::after, .lm .ms.open .ms-chev::after{
  transform: rotate(225deg) translate(-2px, -2px);
  border-color: var(--lm-accent);
}

/* Панель: шире поля, с собственной шириной и без горизонтальной прокрутки. */
.lm .ms-panel{
  display: none;
  position: absolute; z-index: 60; top: calc(100% + 5px); left: 0;
  min-width: max(100%, 264px); max-width: min(400px, calc(100vw - 32px));
  padding: 6px;
  border-radius: var(--lm-radius-md); border: 1px solid var(--lm-border);
  background: var(--lm-surface); box-shadow: var(--lm-shadow-panel);
  overflow: hidden;
}
.lm .ms.open .ms-panel{ display: block; }
.lm .ms.up .ms-panel, .lm .ms.dropup .ms-panel, .lm .ms.open-up .ms-panel{ top: auto; bottom: calc(100% + 5px); }

.lm .ms-search{
  width: 100%; min-height: 32px; margin-bottom: 6px; padding: 6px 10px;
  border-radius: var(--lm-radius-sm); border: 1px solid var(--lm-border);
  background: var(--lm-surface-2); color: var(--lm-text); font-size: 13px;
}
.lm .ms-search:focus{
  outline: none; background: var(--lm-surface); border-color: var(--lm-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--lm-accent) 16%, transparent);
}

/* Список: прокрутка только вертикальная, строки не обрезаются на полуслове. */
.lm .ms-list,
.lm .ms-panel > .ms-row:first-of-type{ margin-top: 0; }
.lm .ms-list{ max-height: 260px; overflow-y: auto; overflow-x: hidden; }
.lm .ms-panel:not(:has(.ms-list)){ max-height: 320px; overflow-y: auto; overflow-x: hidden; }
.lm .ms-row, .lm .ms-item{
  display: flex; align-items: center; gap: 9px;
  min-height: 32px; padding: 5px 9px; border-radius: var(--lm-radius-xs);
  font-size: 13px; color: var(--lm-text); cursor: pointer;
}
.lm .ms-row:hover, .lm .ms-item:hover{ background: var(--lm-surface-3); }
.lm .ms-row input[type="checkbox"], .lm .ms-item input[type="checkbox"], .lm .ms-item input{
  width: 16px; height: 16px; accent-color: var(--lm-accent); flex: 0 0 auto; margin: 0;
}
.lm .ms-row .t, .lm .ms-text{
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lm .ms-empty{ padding: 14px 10px; color: var(--lm-muted-2); font-size: 13px; text-align: center; }

/* Действия панели: «Все» и «Сброс» одной высоты с полями. */
.lm .ms-actions{
  display: flex; gap: 6px; margin-top: 6px; padding-top: 6px;
  border-top: 1px solid var(--lm-border-soft);
}
.lm .ms-all, .lm .ms-none{
  flex: 1 1 auto; min-height: 30px; padding: 0 10px;
  border-radius: var(--lm-radius-sm); border: 1px solid var(--lm-border);
  background: var(--lm-surface-2); color: var(--lm-muted);
  font-size: var(--lm-text-sm); font-weight: 620;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.lm .ms-all:hover, .lm .ms-none:hover{
  color: var(--lm-text); border-color: color-mix(in srgb, var(--lm-accent) 34%, var(--lm-border));
}

/* Панель-«портал»: два движка (admin_products и static/multiselect.js на
   аналитике) выносят её прямо в body, чтобы модалка или скролл-контейнер не
   обрезали список. Тогда 100% — это ширина страницы, поэтому ширину задаём
   фиксированную, а координаты ставит сам JS. */
body.lm > .ms-panel{
  min-width: 240px; max-width: min(420px, calc(100vw - 24px));
  z-index: 4200;
}
body.lm > .ms-panel[data-portal="1"], body.lm > .ms-panel.ms-open{ display: block; }

/* Строка списка у портального движка: чекбокс, текст и счётчик в одной линии. */
.lm .ms-line{ display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1 1 auto; }
.lm .ms-item.is-archived{ opacity: .6; }
.lm .ms-item-badge{
  flex: 0 0 auto; min-width: 20px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  height: 18px; border-radius: var(--lm-radius-pill);
  background: var(--lm-surface-3); border: 1px solid var(--lm-border-soft);
  color: var(--lm-muted); font-size: 10.5px; font-weight: 700;
}

/* Подложка, по клику в которую панель закрывается, и блокировка прокрутки. */
.ms-backdrop{ position: fixed; inset: 0; z-index: 50; display: none; background: transparent; }
.ms-backdrop.show{ display: block; }
body.ms-lock{ overflow: hidden; }

/* Счётчик выбранного рядом с подписью фильтра: «•» пока пусто, число когда
   что-то выбрано (текст ставит JS страницы). */
.lm .ava-dot{
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px; margin-left: 4px;
  border-radius: var(--lm-radius-pill);
  background: var(--lm-surface-3); border: 1px solid var(--lm-border-soft);
  color: var(--lm-muted-2); font-size: 10.5px; font-weight: 700; line-height: 1;
  vertical-align: middle;
}

@media (max-width: 640px){
  .lm .ms-panel{ min-width: 100%; max-width: calc(100vw - 24px); }
}

/* Сегменты (вкладки-переключатели): классы создаёт JS страниц. */
.lm .crm-segmented, .lm .scope-tabs{
  display: inline-flex; gap: 3px; padding: 3px; flex-wrap: wrap;
  background: var(--lm-surface-3); border: 1px solid var(--lm-border-soft); border-radius: var(--lm-radius-md);
}
.lm .scope-tab, .lm .crm-segmented__btn{
  min-height: 28px; padding: 0 11px; border-radius: var(--lm-radius-sm); border: 0;
  background: transparent; color: var(--lm-muted);
  font-size: var(--lm-text-sm); font-weight: 620; white-space: nowrap;
  transition: background-color .15s ease, color .15s ease, box-shadow .15s ease;
}
.lm .scope-tab:hover, .lm .crm-segmented__btn:hover{ color: var(--lm-text); }
.lm .scope-tab.is-active, .lm .crm-segmented__btn.is-active,
.lm .scope-tab[aria-pressed="true"], .lm .crm-segmented__btn[aria-pressed="true"]{
  background: var(--lm-surface); color: var(--lm-text); box-shadow: var(--lm-shadow-btn);
}

/* ---------------- 3a. Полоса показателей ----------------
   Цифры, по которым читают состояние раздела. Намеренно мелкие: это строка
   над рабочей областью, а не витрина — на 1366×768 она не должна отодвигать
   данные за нижний край. */
.lm-stats{
  display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); gap: 8px;
  margin-bottom: 12px;
}
.lm-stat{
  display: flex; flex-direction: column; gap: 1px;
  padding: 9px 12px; border-radius: var(--lm-radius-md);
  background: var(--lm-surface); border: 1px solid var(--lm-border);
}
.lm-stat__val{ font-size: 17px; font-weight: 700; letter-spacing: -.015em; line-height: 1.2; font-variant-numeric: tabular-nums; }
.lm-stat__lab{ color: var(--lm-muted); font-size: var(--lm-text-xs); line-height: 1.3; }
.lm-stat--crit .lm-stat__val{ color: var(--lm-danger); }
.lm-stat--warn .lm-stat__val{ color: var(--lm-warn); }
.lm-stat--ok .lm-stat__val{ color: var(--lm-ok); }

/* ---------------- 3b. Вкладки разделов страницы ----------------
   Крупный переключатель содержимого страницы (Справочник / Загрузка /
   Журнал). Отличается от сегментов: это навигация по режимам, а не фильтр. */
.lm-tabs{ display: flex; gap: 2px; flex-wrap: wrap; margin-bottom: 12px; border-bottom: 1px solid var(--lm-border); }
.lm-tab{
  position: relative;
  min-height: 36px; padding: 0 14px;
  font-size: var(--lm-text-md); font-weight: 620; color: var(--lm-muted);
  transition: color .15s ease, background-color .15s ease;
  border-radius: var(--lm-radius-sm) var(--lm-radius-sm) 0 0;
}
.lm-tab:hover{ color: var(--lm-text); background: var(--lm-surface-2); }
.lm-tab.is-active{ color: var(--lm-accent); }
.lm-tab.is-active::after{
  content: ""; position: absolute; left: 10px; right: 10px; bottom: -1px; height: 2px;
  background: var(--lm-accent); border-radius: 2px 2px 0 0;
}


/* Строка с вкладками и содержимое активной вкладки. Раньше эти две строки
   лежали копиями в восьми постраничных файлах. */
.lm-tabs-row{ margin-bottom: 4px; }
.lm-pane{ padding: 14px 16px; }
.lm-pane[hidden]{ display: none; }

/* ---------------- 3c. Сворачиваемый блок ----------------
   Панель, которую можно убрать с глаз (фильтры отчёта, настройки рассылки).
   Класс is-folded ставит lumo-shell.js по кнопке [data-fold-toggle]. */
.lm-fold__head{
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 14px; border-bottom: 1px solid var(--lm-border-soft);
}
.lm-fold__title{ font-size: var(--lm-text-lg); font-weight: 640; }
.lm-fold__spacer{ flex: 1 1 auto; }
.lm-fold__toggle{
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: var(--lm-radius-sm);
  color: var(--lm-muted);
  transition: background-color .15s ease, color .15s ease, transform .2s var(--lm-ease);
}
.lm-fold__toggle:hover{ background: var(--lm-surface-3); color: var(--lm-text); }
.lm-fold__toggle svg{ width: 18px; height: 18px; }
.lm-fold.is-folded .lm-fold__toggle{ transform: rotate(-90deg); }
.lm-fold__body{ padding: 12px 14px; display: flex; flex-direction: column; gap: 12px; }
.lm-fold.is-folded .lm-fold__body{ display: none; }
.lm-divider{ height: 1px; background: var(--lm-border-soft); }
.lm-hint{ font-size: var(--lm-text-xs); color: var(--lm-muted); line-height: 1.45; }
.lm-check-row{ display: inline-flex; align-items: center; gap: 7px; font-size: 13px; color: var(--lm-muted); }
.lm-check-row input{ width: 15px; height: 15px; accent-color: var(--lm-accent); }
.lm-label-row{ display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.lm-tabs--sm .lm-tab{ min-height: 30px; padding: 0 11px; font-size: var(--lm-text-sm); }

/* ---------------- 3d. Зона перетаскивания файла ----------------
   Один вид на все загрузки: справочники, карта, промо, заказы. */
.lm-drop{
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  padding: 18px; text-align: center; cursor: pointer;
  border: 1px dashed var(--lm-border); border-radius: var(--lm-radius-md);
  background: var(--lm-surface-2); color: var(--lm-text);
  transition: border-color .16s ease, background-color .16s ease;
}
.lm-drop:hover, .lm-drop.over, .lm-drop:focus-visible{
  border-color: var(--lm-accent); background: var(--lm-accent-soft); outline: none;
}
.lm-drop svg{ width: 22px; height: 22px; color: var(--lm-muted-2); }
.lm-drop:hover svg, .lm-drop.over svg{ color: var(--lm-accent); }
.lm-drop__big{ font-size: 13px; font-weight: 640; }
.lm-drop__small{ font-size: var(--lm-text-xs); color: var(--lm-muted); }
.lm-drop__file{
  margin-top: 6px; max-width: 100%;
  padding: 3px 10px; border-radius: var(--lm-radius-pill);
  font-size: var(--lm-text-xs); font-weight: 650;
  color: var(--lm-accent); background: var(--lm-accent-soft);
  border: 1px solid color-mix(in srgb, var(--lm-accent) 35%, var(--lm-border));
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------------- 4. Таблицы ---------------- */
.lm-table-wrap{ overflow-x: auto; }
.lm-table{ width: 100%; font-size: 13px; }
.lm-table thead th{
  /* top: 0, а не высота шапки. Таблица лежит внутри .lm-table-wrap с
     overflow, поэтому липкость считается от этого контейнера, а не от окна:
     со значением var(--lm-bar-h) строка заголовков отступала вниз на высоту
     шапки и вставала под первой строкой данных — «съехавший заголовок» в
     истории загрузок, нормативах и отпусках. */
  position: sticky; top: 0; z-index: 2;
  text-align: left; padding: 10px 12px;
  background: var(--lm-surface-2); color: var(--lm-muted);
  font-size: var(--lm-text-xs); font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  border-bottom: 1px solid var(--lm-border);
  white-space: nowrap;
}
.lm-table tbody td{ padding: 10px 12px; border-bottom: 1px solid var(--lm-border-soft); vertical-align: middle; }
.lm-table tbody tr:last-child td{ border-bottom: 0; }
.lm-table tbody tr:hover td{ background: var(--lm-surface-2); }
.lm-table tbody tr.is-clickable{ cursor: pointer; }
.lm-table td.is-num, .lm-table th.is-num{ text-align: right; font-variant-numeric: tabular-nums; }


/* ---------------- 4a. Панель выделения ----------------
   Появляется над списком, когда отметили строки: сколько выбрано и что с
   этим можно сделать. Класс is-on ставит JS страницы (каталог ТТ,
   номенклатура из заказов), поэтому по умолчанию панель скрыта. */
.lm-selbar{
  display: none; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 12px; padding: 9px 12px;
  border-radius: var(--lm-radius-md);
  background: var(--lm-accent-soft);
  border: 1px solid color-mix(in srgb, var(--lm-accent) 30%, transparent);
  font-size: 13px;
}
.lm-selbar.is-on{ display: flex; }
.lm-selbar b{ font-weight: 700; color: var(--lm-accent); }

/* ---------------- 5. Статусы и метки ---------------- */
.lm-badge{
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 22px; padding: 0 9px; border-radius: var(--lm-radius-pill);
  font-size: var(--lm-text-xs); font-weight: 650;
  background: var(--lm-surface-3); color: var(--lm-muted); border: 1px solid var(--lm-border-soft);
}
.lm-badge--ok{ background: var(--lm-ok-soft); color: var(--lm-ok); border-color: color-mix(in srgb, var(--lm-ok) 32%, transparent); }
.lm-badge--warn{ background: var(--lm-warn-soft); color: var(--lm-warn); border-color: color-mix(in srgb, var(--lm-warn) 32%, transparent); }
.lm-badge--crit{ background: var(--lm-danger-soft); color: var(--lm-danger); border-color: color-mix(in srgb, var(--lm-danger) 32%, transparent); }
.lm-badge--info{ background: var(--lm-info-soft); color: var(--lm-info); border-color: color-mix(in srgb, var(--lm-info) 32%, transparent); }

.lm-state{ display: inline-flex; align-items: center; gap: 6px; font-size: var(--lm-text-sm); font-weight: 620; }
.lm-state::before{ content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.lm-state--ok{ color: var(--lm-ok); }
.lm-state--warn{ color: var(--lm-warn); }
.lm-state--crit{ color: var(--lm-danger); }
.lm-state--muted{ color: var(--lm-muted-2); }

.lm .kv{ display: grid; grid-template-columns: minmax(120px, auto) 1fr; gap: 4px 12px; font-size: 13px; }
.lm .kv > dt, .lm .kv__k{ color: var(--lm-muted); }
.lm .kv > dd, .lm .kv__v{ margin: 0; color: var(--lm-text); font-weight: 580; }

/* ---------------- 6. Состояния: пусто, загрузка, ошибка ---------------- */
.lm-empty, .lm .empty{
  padding: 34px 20px 38px; text-align: center; color: var(--lm-muted); font-size: 13px;
}
.lm-empty__title, .lm .empty b{ display: block; font-size: var(--lm-text-lg); font-weight: 620; color: var(--lm-text); margin-bottom: 5px; }
.lm-empty__hint{ max-width: 52ch; margin: 0 auto; }
.lm-empty__actions{ margin-top: 14px; display: flex; gap: 8px; justify-content: center; }

.lm .loading{ padding: 26px 20px; text-align: center; color: var(--lm-muted); font-size: 13px; }
.lm .err{
  padding: 12px 14px; border-radius: var(--lm-radius-md);
  background: var(--lm-danger-soft); color: var(--lm-danger);
  border: 1px solid color-mix(in srgb, var(--lm-danger) 30%, transparent);
  font-size: 13px; font-weight: 580;
}

.lm-skeleton{
  border-radius: var(--lm-radius-sm);
  background: linear-gradient(90deg,
    var(--lm-surface-3) 0%,
    color-mix(in srgb, var(--lm-surface-3) 55%, var(--lm-surface)) 50%,
    var(--lm-surface-3) 100%);
  background-size: 200% 100%;
  animation: lm-shimmer 1.2s linear infinite;
}
.lm-skeleton--row{ height: 44px; margin-bottom: 6px; }
@keyframes lm-shimmer{ from{ background-position: 200% 0; } to{ background-position: -200% 0; } }

.lm-note{
  padding: 10px 12px; border-radius: var(--lm-radius-md);
  background: var(--lm-surface-2); border: 1px solid var(--lm-border-soft);
  font-size: var(--lm-text-sm); color: var(--lm-muted);
}

/* ---------------- 6a. Формы внутри модалок ----------------
   Имена .field/.label/.input/.hint/.grid2/.modal-section/.row/.divider
   пришли из старой разметки и остаются: их пишет и читает JS страниц
   (admin_users, admin_shops, admin_products). Скоуп .ui-modal не даёт этим
   очень общим именам разъехаться по остальной странице. */
.lm .ui-modal .modal-section + .modal-section{ margin-top: 14px; }
.lm .ui-modal .modal-section__title{
  font-size: var(--lm-text-xs); font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--lm-muted-2); margin-bottom: 9px;
}
.lm .ui-modal .grid2{ display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.lm .ui-modal .field{ display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.lm .ui-modal .label{ font-size: var(--lm-text-xs); font-weight: 650; color: var(--lm-muted); }
.lm .ui-modal .input,
.lm .ui-modal .inp{
  width: 100%; min-height: 34px; padding: 6px 10px;
  border-radius: var(--lm-radius-sm); border: 1px solid var(--lm-border);
  background: var(--lm-surface-2); color: var(--lm-text); font-size: 13px;
  transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease;
}
.lm .ui-modal .input:focus,
.lm .ui-modal .inp:focus{
  outline: none; background: var(--lm-surface); border-color: var(--lm-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--lm-accent) 18%, transparent);
}
.lm .ui-modal .input[disabled],
.lm .ui-modal .inp[disabled]{ opacity: .6; cursor: not-allowed; }
.lm .ui-modal textarea.inp,
.lm .ui-modal textarea.input{ min-height: 96px; resize: vertical; line-height: 1.5; }
.lm .ui-modal .hint{ font-size: var(--lm-text-xs); color: var(--lm-muted); line-height: 1.45; }
.lm .ui-modal .divider{ height: 1px; background: var(--lm-border-soft); margin: 14px 0; }
.lm .ui-modal .row{
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  padding: 11px 12px; border-radius: var(--lm-radius-md);
  border: 1px solid var(--lm-border); background: var(--lm-surface-2);
}
.lm .ui-modal .row-title{ font-size: 13px; font-weight: 650; }
.lm .ui-modal .row-sub{ font-size: var(--lm-text-sm); color: var(--lm-muted); margin-top: 2px; }
.lm .ui-modal .filters{ display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.lm .ui-modal .search{ display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.lm .ui-modal .search .input{ flex: 1 1 auto; }
.lm .ui-modal .pill{
  display: inline-flex; align-items: center; gap: 5px;
  min-height: 26px; padding: 0 10px; border-radius: var(--lm-radius-pill);
  background: var(--lm-surface-3); border: 1px solid var(--lm-border-soft);
  font-size: var(--lm-text-xs); font-weight: 650; color: var(--lm-muted); white-space: nowrap;
}
/* Старые кнопки в подвалах модалок: класс .btn ещё живёт в разметке и в JS. */
.lm .ui-modal .btn{
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  min-height: 34px; padding: 0 13px; border-radius: var(--lm-radius-sm);
  border: 1px solid var(--lm-border); background: var(--lm-surface);
  font-size: 13px; font-weight: 620; color: var(--lm-text);
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.lm .ui-modal .btn:hover{ background: var(--lm-surface-3); border-color: color-mix(in srgb, var(--lm-accent) 34%, var(--lm-border)); }
.lm .ui-modal .btn[disabled]{ opacity: .55; cursor: not-allowed; }
.lm .ui-modal .btn.primary{ background: var(--lm-accent); border-color: var(--lm-accent); color: var(--lm-accent-text); }
.lm .ui-modal .btn.primary:hover{ background: var(--lm-accent-hover); border-color: var(--lm-accent-hover); }
.lm .ui-modal .btn.danger{ color: var(--lm-danger); border-color: color-mix(in srgb, var(--lm-danger) 45%, var(--lm-border)); }
.lm .ui-modal .btn.danger:hover{ background: var(--lm-danger-soft); border-color: var(--lm-danger); }

/* ---------------- 6b. Тост ---------------- */
.lm .toast{
  position: fixed; left: 50%; bottom: 24px; z-index: 1800;
  transform: translate(-50%, 12px);
  max-width: min(440px, calc(100vw - 32px));
  padding: 10px 16px; border-radius: var(--lm-radius-md);
  background: var(--lm-chassis); color: var(--lm-chassis-text);
  font-size: 13px; font-weight: 600;
  box-shadow: var(--lm-shadow-panel);
  opacity: 0; pointer-events: none;
  transition: opacity .16s ease, transform .2s var(--lm-ease);
}
.lm .toast.show{ opacity: 1; transform: translate(-50%, 0); }
/* Цвет рамки по исходу операции: класс ставит JS страниц (promo, push, карта). */
.lm .toast--ok{ border: 1px solid color-mix(in srgb, var(--lm-ok) 50%, transparent); }
.lm .toast--error{ border: 1px solid color-mix(in srgb, var(--lm-danger) 60%, transparent); }

/* ---------------- 6c. Сортируемые заголовки ----------------
   Класс .th-sort и стрелку .sort-ico ставит JS страниц. */
.lm .th-sort{ cursor: pointer; user-select: none; }
.lm .th-sort:hover{ color: var(--lm-text); }
.lm .sort-ico{ display: inline-block; width: 9px; margin-left: 5px; opacity: .45; font-size: 9px; }
.lm .sort-ico::after{ content: "↕"; }
/* Направление сортировки JS кладёт атрибутом data-dir на <th> (admin_users.js). */
.lm .th-sort[data-dir="asc"], .lm .th-sort[data-dir="desc"]{ color: var(--lm-accent); }
.lm .th-sort[data-dir="asc"] .sort-ico, .lm .th-sort[data-dir="desc"] .sort-ico{ opacity: 1; }
.lm .th-sort[data-dir="asc"] .sort-ico::after{ content: "↑"; }
.lm .th-sort[data-dir="desc"] .sort-ico::after{ content: "↓"; }


/* ---------------- 6d. Загрузка файла и предпросмотр ----------------
   Одинаковый узел на пяти экранах: промо, заказы, маршруты, реестр и
   справочник ТТ. Слева зона перетаскивания и форма, справа разбор файла:
   плитки итогов, предупреждения и таблица предпросмотра. Имена классов
   (.promo-*) пришли с первой такой страницы и остаются — их пишет JS
   каждого модуля, в том числе строит плитки .promo-stat. */
/* Ширина ограничена: на широком мониторе узел растягивался на 1400px и
   правая колонка выглядела пустой панелью во весь экран. */
.lm .promo-upload{ display: grid; grid-template-columns: minmax(0, 360px) minmax(0, 1fr); gap: 12px; align-items: start; max-width: 1180px; }
.lm .promo-upload__side{ display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.lm .promo-upload__main{ min-width: 0; }

.lm .promo-dropzone{
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; padding: 22px 18px; text-align: center; cursor: pointer;
  border: 1px dashed var(--lm-border); border-radius: var(--lm-radius-md);
  background: var(--lm-surface-2); color: var(--lm-text);
  transition: border-color .16s ease, background-color .16s ease;
}
.lm .promo-dropzone:hover, .lm .promo-dropzone:focus-visible{
  border-color: var(--lm-accent); background: var(--lm-accent-soft); outline: none;
}
.lm .promo-dropzone.is-dragover{ border-color: var(--lm-accent); background: var(--lm-accent-soft); }
.lm .promo-dropzone.is-busy{ opacity: .6; pointer-events: none; }
.lm .promo-dropzone__icon{
  display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; margin-bottom: 2px;
  border-radius: var(--lm-radius-md);
  background: var(--lm-accent-soft); color: var(--lm-accent);
}
.lm .promo-dropzone__icon svg{ width: 20px; height: 20px; }
.lm .promo-dropzone__title{ font-size: var(--lm-text-md); font-weight: 650; }
.lm .promo-dropzone__hint{ color: var(--lm-muted); font-size: var(--lm-text-sm); }

.lm .promo-form{ display: flex; flex-direction: column; gap: 10px; }
.lm .promo-side-note{ font-size: var(--lm-text-sm); color: var(--lm-muted); line-height: 1.5; }

/* Пустое состояние справа, пока файл не загрузили. */
.lm .promo-empty{
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; padding: 40px 24px; text-align: center; min-height: 100%;
  border: 1px solid var(--lm-border); border-radius: var(--lm-radius-md); background: var(--lm-surface);
}
.lm .promo-empty__icon{
  display: flex; align-items: center; justify-content: center;
  width: 52px; height: 52px; margin-bottom: 4px;
  border-radius: var(--lm-radius-lg); background: var(--lm-surface-3); color: var(--lm-muted-2);
}
.lm .promo-empty__icon svg{ width: 24px; height: 24px; }
.lm .promo-empty__title{ font-size: var(--lm-text-lg); font-weight: 650; }
.lm .promo-empty__text{ color: var(--lm-muted); font-size: 13px; line-height: 1.55; max-width: 52ch; }

/* Разбор загруженного файла. */
.lm .promo-preview{
  display: flex; flex-direction: column; gap: 12px;
  padding: 14px 16px; border: 1px solid var(--lm-border); border-radius: var(--lm-radius-md);
  background: var(--lm-surface);
}
.lm .promo-preview__head{ display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.lm .promo-preview__actions{ display: flex; gap: 8px; flex-wrap: wrap; }
.lm .promo-preview__table{ max-height: 460px; overflow: auto; }

.lm .promo-stats{ display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); gap: 8px; }
.lm .promo-stat{
  display: flex; flex-direction: column; gap: 1px;
  padding: 9px 12px; border-radius: var(--lm-radius-md);
  border: 1px solid var(--lm-border); background: var(--lm-surface-2);
}
.lm .promo-stat b, .lm .promo-stat__num{
  font-size: 17px; font-weight: 700; letter-spacing: -.015em; line-height: 1.2;
  font-variant-numeric: tabular-nums;
}
.lm .promo-stat span, .lm .promo-stat__lab{ color: var(--lm-muted); font-size: var(--lm-text-xs); line-height: 1.3; }
.lm .promo-stat--good{ border-color: color-mix(in srgb, var(--lm-ok) 34%, var(--lm-border)); background: var(--lm-ok-soft); }
.lm .promo-stat--good b, .lm .promo-stat--good .promo-stat__num{ color: var(--lm-ok); }
.lm .promo-stat--warn{ border-color: color-mix(in srgb, var(--lm-warn) 34%, var(--lm-border)); background: var(--lm-warn-soft); }
.lm .promo-stat--warn b, .lm .promo-stat--warn .promo-stat__num{ color: var(--lm-warn); }
.lm .promo-stat--danger{ border-color: color-mix(in srgb, var(--lm-danger) 34%, var(--lm-border)); background: var(--lm-danger-soft); }
.lm .promo-stat--danger b, .lm .promo-stat--danger .promo-stat__num{ color: var(--lm-danger); }

@media (max-width: 1099px){
  .lm .promo-upload{ grid-template-columns: 1fr; }
}


/* Статус загрузки и предупреждения разбора — общий язык всех загрузочных
   страниц (промо, заказы, маршруты, реестр). */
.lm .promo-status{
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 22px; padding: 0 10px; border-radius: var(--lm-radius-pill);
  font-size: var(--lm-text-xs); font-weight: 650;
  border: 1px solid var(--lm-border-soft); background: var(--lm-surface-3); color: var(--lm-muted);
}
.lm .promo-status::before{ content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.lm .promo-status--applied, .lm .promo-status--confirmed{
  color: var(--lm-ok); background: var(--lm-ok-soft); border-color: color-mix(in srgb, var(--lm-ok) 32%, transparent);
}
.lm .promo-status--draft, .lm .promo-status--suggested{
  color: var(--lm-accent); background: var(--lm-accent-soft); border-color: color-mix(in srgb, var(--lm-accent) 32%, transparent);
}
.lm .promo-status--rolled_back, .lm .promo-status--rejected{ color: var(--lm-muted-2); }
.lm .promo-status--none{
  color: var(--lm-danger); background: var(--lm-danger-soft); border-color: color-mix(in srgb, var(--lm-danger) 32%, transparent);
}

.lm .promo-warnings{
  padding: 10px 12px; border-radius: var(--lm-radius-md);
  background: var(--lm-warn-soft); border: 1px solid color-mix(in srgb, var(--lm-warn) 30%, transparent);
  color: var(--lm-text); font-size: 13px;
}
.lm .promo-warnings__title{ font-weight: 650; color: var(--lm-warn); margin-bottom: 4px; }
.lm .promo-warnings ul, .lm .promo-warnings__list{ margin: 0; padding-left: 18px; line-height: 1.55; }
.lm .promo-table td, .lm .promo-table th{ font-size: 13px; vertical-align: top; }
.lm .promo-table .row-warn td{ background: var(--lm-warn-soft); }

/* ---------------- 7. Пагинация ---------------- */
.lm-pager{ display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 14px; flex-wrap: wrap; }
.lm-pager__info{ font-size: var(--lm-text-sm); color: var(--lm-muted); }
.lm-pager__nav{ display: flex; align-items: center; gap: 4px; }

@media (max-width: 1099px){
  .lm-page{ padding: 14px 12px 32px; }
  .lm-table thead th{ top: 0; }
}
