/* Каркас «Пульса»: раскладка, сайдбар, карточки, заглушки.
   Все цвета и размеры — из tokens.css. */

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
}

body {
  font-family: var(--font-ui);
  font-size: var(--fs-body);
  line-height: 1.5;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--pulse); }
a:hover { color: var(--pulse-deep); }

/* --- Раскладка: сайдбар + контент --- */

/* dvh — чтобы на телефоне высоту не воровала съезжающая панель браузера
   (vh оставлен запасным вариантом для старых движков) */
.shell {
  display: grid;
  grid-template-columns: var(--side-w) 1fr;
  min-height: 100vh;
  min-height: 100dvh;
}

/* Сайдбар: тот же фон, что и страница, — единое пространство, граница едва заметна */
.side {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  padding: var(--sp-5) var(--sp-3);
  border-right: 1px solid var(--rule-soft);
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-3);
  text-decoration: none;
  color: var(--ink);
}

.brand-pulse {
  width: 44px;
  height: 20px;
  color: var(--pulse);
  flex: none;
}

.brand-name {
  font-size: var(--fs-h3);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.nav {
  display: flex;
  flex-direction: column;
  gap: 6px; /* воздух между плитками — макет 2026-08-14 */
  flex: 1;
}

.nav-group {
  font-size: var(--fs-caption);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-mute);
  padding: var(--sp-4) var(--sp-3) var(--sp-1);
}

.nav-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  min-height: 36px;
  border-radius: var(--r-ctl);
  color: var(--ink-soft);
  text-decoration: none;
  font-weight: 500;
}

a.nav-item:hover {
  color: var(--ink);
  background: var(--rule-soft);
}

.nav-item.is-active {
  color: var(--pulse);
  background: var(--pulse-wash);
}

.nav-item:focus-visible {
  outline: 2px solid var(--pulse);
  outline-offset: 1px;
}

/* Будущие инструменты: видно состав, но кликать нечего.
   Тише активных пунктов, но это всё-таки текст, а не прочерк, — --ink-mute,
   не --ink-ghost (иначе состав инструментов не прочитать). */
.nav-item.is-soon {
  color: var(--ink-mute);
  cursor: default;
  justify-content: space-between;
}

.nav-item.is-soon em {
  font-style: normal;
  font-size: var(--fs-caption);
  color: var(--ink-mute);
  border: 1px solid var(--rule-soft);
  border-radius: 999px;
  padding: 0 var(--sp-2);
  line-height: 18px;
}

.side-foot {
  font-size: var(--fs-caption);
  color: var(--ink-ghost);
  padding: 0 var(--sp-3);
}

/* --- Контентная область --- */

.main {
  padding: var(--sp-6) var(--sp-8) var(--sp-8);
  min-width: 0;
}

/* Раздел, где содержимое — одна большая таблица (ОПиУ-отчёт, ABC): экран
   отдаётся ей целиком. Ставит класс роутер (ROUTES → wide в app.js).
   Выбор Артёма 2026-08-12 из четырёх примеренных раскладок, вариант «В».

   Три вещи по порядку важности:
   1. Таблица тянется до низа окна ЦЕПОЧКОЙ ФЛЕКСОВ, а не формулой
      `max-height: calc(100vh − угаданное)`. Формула врёт при любой правке
      шапки, и именно из-за неё под таблицей оставалась пустая полоса,
      а подпись уезжала за нижний край. Здесь ничего угадывать не нужно:
      что осталось от окна — то и досталось таблице.
      `min-height: 0` обязателен ВСЕЙ цепочке: флекс-элемент по умолчанию
      не даёт сжать себя ниже содержимого, и без него скроллпорт вылезает
      за низ экрана вместо того, чтобы прокручиваться внутри.
   2. Заголовок раздела убран — он же подсвечен в сайдбаре, а ярус занимал.
      Плашка свежести остаётся и встаёт над правым краем тулбара, поэтому
      тулбару отдан правый отступ: иначе кнопки ABC налезут на неё.
   3. Карточка-обёртка отдаёт свои отступы таблице; скругление переезжает
      на сам скроллпорт, иначе углы станут прямыми.

   ⚠ Только шире 900px. Ниже сайдбар становится верхней полосой В ПОТОКЕ
   документа, и `height: 100vh` у .main дало бы полосу плюс целый экран —
   страница поехала бы вниз ровно там, где обещано, что не поедет. Узкий
   экран остаётся на прежней раскладке: это две широкие таблицы, их всё
   равно смотрят с большого монитора. */
@media (min-width: 901px) {
  .layout-wide .main {
    display: flex;
    flex-direction: column;
    height: 100vh;
    padding: var(--sp-4) var(--sp-5) 0;
  }

  .layout-wide .page-head {
    height: 0;
    margin: 0;
    align-items: flex-start;
    overflow: visible;
  }
  /* Заголовок уходит с глаз, но не из страницы: у ABC и ОПиУ он был
     единственным, и display:none оставлял разделы вообще без заголовков —
     переход по ним, которым пользуются программы чтения, там не работал
     (аудит 2026-08-13). Прячем тем же способом, что подписи колонок РНП. */
  .layout-wide .page-title {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .layout-wide .data-status {
    position: relative;
    top: 11px;
    z-index: 6;
  }

  .layout-wide .view {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  .layout-wide .view > .card {
    padding: 0;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  .layout-wide .toolbar {
    padding-right: 170px;
    margin-bottom: var(--sp-2);
  }
}

.page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-5);
}

.page-head-left {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-width: 0;
}

/* Свёрнутый сайдбар — полоска 56px: только логотип-пульс и иконки.
   С 2026-08-14 — по макету пользователя из Claude Design: полоска БЕЛАЯ
   (--card, читается колонкой на сером фоне, а не сливается с ним),
   56px, пункты — квадратные плитки 36×36 по центру, активный — плитка
   --pulse-wash. Полоска фиксирована и ПЛАВНО выезжает до полной ширины
   при наведении (класс side-peek из app.js) — поверх контента, страница
   не дёргается. Геометрия пунктов в обоих состояниях одна (иконки не
   прыгают), меняются только ширина панели и прозрачность подписей.
   ВАЖНО: fixed-сайдбар выпадает из грида, поэтому сетка в mini —
   одна колонка, а место под полоску даёт margin у .main (иначе контент
   сядет в 56px-колонку — уже наступали). */
.shell.side-mini { grid-template-columns: 1fr; }
.shell.side-mini .main { margin-left: 56px; }

.shell.side-mini .side {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: 56px;
  height: auto;
  padding: 14px 10px;
  background: var(--card);
  overflow: hidden;
  z-index: 60;
  transition: width 0.18s ease, box-shadow 0.18s ease;
}

/* Плитка 36×36: бок полоски 10px + паддинг пункта 9px центрируют
   иконку 18px ровно по оси полоски (10+9+9=28) */
.shell.side-mini .nav-item { padding-left: 9px; padding-right: 9px; }

.shell.side-mini.side-peek .side {
  width: var(--side-w);
  box-shadow: 10px 0 28px rgba(var(--ink-rgb), 0.10);
}

.shell.side-mini .brand { padding: var(--sp-1) 0; }
.shell.side-mini .brand-pulse { width: 36px; transition: width 0.18s ease; }
.shell.side-mini.side-peek .brand-pulse { width: 44px; }

/* Подписи не display:none (иначе не анимируются) — гаснут и не переносятся */
.brand-name,
.nav-item .label,
.nav-group,
.side-user-name,
.side-foot { white-space: nowrap; }

.shell.side-mini:not(.side-peek) .brand-name,
.shell.side-mini:not(.side-peek) .nav-item .label,
.shell.side-mini:not(.side-peek) .nav-group,
.shell.side-mini:not(.side-peek) .side-user-name,
.shell.side-mini:not(.side-peek) .side-foot {
  opacity: 0;
  visibility: hidden;
}

.brand-name, .nav-item .label, .nav-group, .side-user-name, .side-foot {
  transition: opacity 0.15s ease 0.04s, visibility 0.15s;
}

/* Подсписок инструментов РНП: в полоске спрятан, в развёрнутом — дерево */
.shell.side-mini:not(.side-peek) .nav-sub {
  opacity: 0;
  visibility: hidden;
  max-height: 0;
}

.nav-sub {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 200px;
  overflow: hidden;
  transition: opacity 0.15s ease 0.04s, max-height 0.18s ease, visibility 0.15s;
}

.nav-item-sub {
  min-height: 32px;
  font-weight: 400;
}

/* Отступ подпункта — то, чем видно, что тепловая и юнитка лежат ВНУТРИ РНП,
   а не стоят рядом с ним.
   ⚠️ Селектор длинный не для красоты: `.shell.side-mini .nav-item` выше
   задаёт плиточный паддинг 9px и тремя классами бьёт короткое
   `.nav-item-sub`. Класс `side-mini` висит на оболочке ВСЕГДА (в разметке
   намертво, JS его не снимает), поэтому короткая запись отступа не работает
   вообще — подпункты вставали вровень с родителем, и дерево читалось
   плоским списком (замечено 2026-08-14 после переделки сайдбара по макету).
   Отступ живёт только здесь, у самого длинного селектора: вторая копия
   покороче ничего не даёт и путает. */
.shell.side-mini.side-peek .nav-item-sub { padding-left: 25px; }

.nav-item-sub .ni { width: 16px; height: 16px; }

/* На подстранице РНП (тепловая, юнитка) родитель мягко подсвечен —
   в полоске виден только он */
.nav-item.is-sub-active { color: var(--pulse); }

/* Иконки пунктов меню — набор из макета 2026-08-14 (Claude Design):
   единая сетка viewBox 24, рисунок 18px в плитке 36×36.
   ⚠️ Толщина штриха задана в юнитах viewBox, поэтому она связана с сеткой:
   1.8 при viewBox 24 и рендере 18px = видимые 1.35px. Меняешь сетку
   иконки — пересчитывай, иначе один значок станет жирнее соседей. */
.ni {
  width: 18px;
  height: 18px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Пользователь внизу сайдбара */
.side-user {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0 var(--sp-3);
}
.side-user-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-caption);
  color: var(--ink-soft);
}
.side-logout { font-size: var(--fs-h4); }

.page-title {
  margin: 0;
  font-size: var(--fs-h2);
  font-weight: 600;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.data-status {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-caption);
  color: var(--ink-mute);
  white-space: nowrap;
}

.data-status-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ink-ghost);
}

.data-status-dot.is-ok { background: var(--gain); }
.data-status-dot.is-warn { background: var(--chart-2); }
.data-status-dot.is-stale { background: var(--loss); }

/* --- Карточки и сетка дашборда --- */

.card {
  background: var(--card);
  border-radius: var(--r-card);
  box-shadow: var(--lift);
  padding: var(--sp-4) var(--sp-5);
  min-width: 0;
}

.card-title {
  margin: 0 0 var(--sp-1);
  font-size: var(--fs-caption);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

.grid {
  display: grid;
  gap: var(--sp-4);
}

/* Ряд KPI: первая плитка — герой, шире остальных.
   Плиток пять: «Выкупы, шт» убрана 2026-08-10 (за один день выкупов почти
   не бывает — заказ едет к покупателю дни, см. home.js) */
.grid-kpi {
  grid-template-columns: 1.4fr repeat(4, 1fr);
  margin-bottom: var(--sp-4);
}

/* Почему плитки «сегодня» пустые. Стоит НАД рядом плиток: объяснение
   читается раньше прочерков, иначе оно уже не нужно. Охра, а не красный —
   это «посмотри», а не «сломалось» (разбор --warn в tokens.css).
   Появляется, только когда выгрузка правда отстала (home.js, renderLag). */
.dash-lag {
  margin: 0 0 var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-ctl);
  background: var(--warn-wash);
  color: var(--warn);
  font-size: 13px;
  line-height: 1.45;
}

/* Средний ряд: динамика доминирует */
.grid-mid {
  grid-template-columns: 2fr 1fr;
  margin-bottom: var(--sp-4);
}

.grid-bottom {
  grid-template-columns: 1fr 1fr;
}

/* --- KPI-плитка --- */

.kpi-value {
  font-size: var(--fs-value);
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
}

.kpi-value.is-empty { color: var(--ink-ghost); }

.kpi-note {
  font-size: var(--fs-caption);
  color: var(--ink-mute);
  margin-top: var(--sp-1);
}

/* День данных в заголовке плитки — не кричит, просто уточняет */
.kpi-when {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
}

/* Дельта к прошлому дню: цвет несёт только она (правило «стрелки, не заливки») */
.kpi-delta {
  font-size: 13px;
  font-weight: 500;
  margin-left: var(--sp-2);
  vertical-align: 3px;
  white-space: nowrap;
}

/* Справка «вчера: N» у плиток за сегодня (день неполный — стрелка врала бы) */
.kpi-prev {
  font-size: var(--fs-caption);
  font-weight: 400;
  color: var(--ink-mute);
  margin-left: var(--sp-2);
  vertical-align: 3px;
  white-space: nowrap;
}

/* Контейнеры графиков ECharts */
.chart-box {
  height: 260px;
  min-width: 0;
}

.chart-box-s { height: 200px; }

/* --- Заглушка блока: тихая пульс-линия + подпись --- */

.placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 120px;
  border-radius: var(--r-ctl);
  background: var(--well);
  color: var(--ink-mute);
  font-size: var(--fs-caption);
  text-align: center;
  padding: var(--sp-4);
}

.placeholder svg {
  width: 96px;
  height: 24px;
  color: var(--ink-ghost);
}

.placeholder.is-tall { min-height: 220px; }

/* --- Узкий экран: сайдбар становится верхней полосой --- */

@media (max-width: 900px) {
  .shell, .shell.side-mini { grid-template-columns: 1fr; }

  /* Нейтрализуем полоску и её плавный выезд: тут сайдбар — верхняя полоса.
     Прокручивается только список разделов; логотип и блок пользователя
     закреплены по краям, иначе «Выйти» уезжает за экран (аудит 2026-08-06). */
  .side,
  .shell.side-mini .side {
    position: static;
    width: auto;
    height: auto;
    flex-direction: row;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-2) var(--sp-4);
    border-right: 0;
    border-bottom: 1px solid var(--rule-soft);
    overflow: hidden;
    box-shadow: none;
  }

  /* ⚠️ Нейтрализация выше не срабатывала: `.shell.side-mini.side-peek .side`
     из базовых стилей — четыре класса против трёх, и он выигрывал по
     специфичности прямо внутри этого медиазапроса (медиазапрос
     специфичность не повышает). На айфоне класс `side-peek` появляется
     от первого же тапа: Safari шлёт по касанию mouseenter, а mouseleave
     не шлёт вовсе — снять его было некому. Верхняя полоса ужималась
     до 232px, разделы правее обрезались `overflow: hidden`, и меню
     выглядело нерабочим: тап не нажимался и никуда не вёл
     (найдено на айфоне 2026-08-13).
     Селектор здесь ТОТ ЖЕ, что в базовых стилях, — специфичность равная,
     и выигрывает он тем, что стоит ниже по файлу. Не переписывать его
     короче: `.side` (один класс) снова проиграет. */
  .shell.side-mini.side-peek .side {
    width: auto;
    box-shadow: none;
  }

  .brand { flex: none; }

  .shell.side-mini:not(.side-peek) .brand-name,
  .shell.side-mini:not(.side-peek) .nav-item .label {
    opacity: 1;
    visibility: visible;
  }

  .shell.side-mini:not(.side-peek) .nav-sub,
  .nav-sub {
    opacity: 1;
    visibility: visible;
    max-height: none;
    flex-direction: row;
    overflow: visible;
  }

  /* В верхней полосе подпункты — соседние кнопки в ряду, отступ дерева тут
     не значит ничего. Селектор ТОТ ЖЕ, что в базовых стилях: короче он
     проиграет по специфичности, а `side-peek` на айфоне остаётся висеть
     от первого тапа (см. разбор выше). */
  .nav-item-sub,
  .shell.side-mini.side-peek .nav-item-sub { padding-left: var(--sp-3); }

  .brand { padding: 0; }
  .shell.side-mini .brand-pulse { width: 44px; }

  .nav {
    flex-direction: row;
    align-items: center;
    gap: var(--sp-1);
    min-width: 0;
    overflow-x: auto;
    /* Растворяющийся правый край — единственный намёк, что список едет
       дальше: полосы прокрутки на телефоне не видно. В маске работает
       только альфа-канал, сам цвет ничего не красит. */
    mask-image: linear-gradient(to right, black calc(100% - 24px), transparent);
    scrollbar-width: none;
  }
  .nav::-webkit-scrollbar { display: none; }

  /* Хвостовой пробел ровно под растворяющийся край: докрутив до конца,
     последний пункт остаётся читаемым, а не тонет в градиенте */
  .nav::after {
    content: '';
    flex: none;
    width: 24px;
  }

  .nav-group { display: none; }
  .side-foot { display: none; }
  .nav-item { white-space: nowrap; }
  /* Возврат плиточного паддинга полоски: в верхней полосе пункты — строки.
     Селектор тот же, что в базовых стилях, — короче он проиграет. */
  .shell.side-mini .nav-item { padding-left: var(--sp-3); padding-right: var(--sp-3); }
  .nav-item.is-soon { display: none; }

  /* Имя и выход всегда на экране, у правого края полосы */
  .side-user {
    flex: none;
    padding: 0 0 0 var(--sp-3);
    border-left: 1px solid var(--rule-soft);
  }
  .side-user-name { max-width: 88px; }

  .main { padding: var(--sp-4); }
  .shell.side-mini .main { margin-left: 0; }

  .grid-kpi { grid-template-columns: 1fr 1fr; }
  .grid-mid, .grid-bottom { grid-template-columns: 1fr; }
}

/* --- Палец вместо мыши ---
   Условие по типу указателя, а не по ширине экрана: планшет с клавиатурой
   и ноутбук с сенсорным экраном — разные случаи. Меньше 44px палец не
   ловит: до правки кнопки тулбара были 33px, крестики — 18×21
   (аудит 2026-08-06). На мыши ничего не меняется. */
@media (pointer: coarse) {
  .btn,
  .seg-btn,
  .sort-btn,
  .nav-item,
  .picker-item,
  .picker-list-apply,
  .picker-save-list,
  .picker-reset,
  .draw-row {
    min-height: 44px;
  }

  .btn, .seg-btn { min-width: 44px; }

  .chip-x {
    min-width: 44px;
    min-height: 44px;
  }

  /* Ползунок остаётся 34×20 на вид, но ловит палец на 44px вокруг */
  .sw input { inset: -12px; }

  .ue td.is-edit input,
  .ue td.is-edit select { min-height: 44px; }
}

@media (prefers-reduced-motion: no-preference) {
  .nav-item { transition: background-color 140ms cubic-bezier(0.23, 1, 0.32, 1), color 140ms cubic-bezier(0.23, 1, 0.32, 1); }
}

/* Обещание из DESIGN.md: анимации выключаются, если система просит покоя.
   Раньше под запросом жила только подсветка меню, а выезд сайдбара,
   тумблеры и раскрытие подсписка двигались всегда (аудит 2026-08-06). */
@media (prefers-reduced-motion: reduce) {
  .shell.side-mini .side,
  .shell.side-mini .brand-pulse,
  .nav-sub,
  .brand-name,
  .nav-item .label,
  .nav-group,
  .side-user-name,
  .side-foot,
  .sw-track,
  .sw-thumb {
    transition: none;
  }
}

/* ===== РНП: панель управления и таблица раскладки А ===== */

.toolbar {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}

.toolbar-label {
  font-size: var(--fs-caption);
  color: var(--ink-mute);
}

.chips {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
  min-height: 32px;
}

.chip-id {
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  color: var(--ink-mute);
}

/* Номер карточки, нажав на который попадаешь на неё же на клиентском WB
   (просьба пользователя 2026-08-14). В покое ссылка молчит: цвет остаётся
   цветом метаданных, о нажимаемости говорит одна пунктирная подчёркивающая
   линия. Красить её в акцент нельзя — номер стоит в каждой строке списка,
   и два десятка малиновых чисел на экране перекричат сами цифры отчёта.
   `color: inherit` не мелочь: глобальное правило `a` красит ссылки
   в `--pulse`, и без него планка и список разошлись бы по цвету. */
.chip-link {
  color: inherit;
  text-decoration: underline dotted var(--ink-ghost);
  text-underline-offset: 2px;
  padding: 2px 4px;
  margin: -2px -4px;
  border-radius: 4px;
}

.chip-link:hover {
  color: var(--pulse);
  text-decoration: underline solid var(--pulse);
}

.chip-link:focus-visible {
  outline: 2px solid var(--pulse);
  outline-offset: 1px;
}

/* Крестик. Раньше был 16×21 — стандарт просит 24×24 и на мыши тоже,
   а не только под палец (WCAG 2.5.8, аудит 2026-08-13). Строки таблиц
   высотой 31–40px это принимают, не раздвигаясь: круг просто занимает
   уже отведённое место. */
.chip-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  min-height: 24px;
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  color: var(--ink-mute);
  cursor: pointer;
  border-radius: 50%;
}
.chip-x:hover { color: var(--loss); }

.btn {
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  background: var(--card);
  padding: 5px 12px;
  font: inherit;
  font-weight: 500;
  color: var(--ink-soft);
  cursor: pointer;
}
.btn:hover { background: var(--well); color: var(--ink); }
.btn:focus-visible { outline: 2px solid var(--pulse); outline-offset: 1px; }
/* Ссылка в виде кнопки (скачать файл, открыть таблицу) — без подчёркивания:
   она выглядит кнопкой, значит и вести себя должна как кнопка */
a.btn { text-decoration: none; }

/* Выпадающий выбор артикулов */

.picker { position: relative; display: inline-block; }

.picker-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 20;
  width: min(340px, calc(100vw - 48px));
  background: var(--card);
  border-radius: var(--r-card);
  box-shadow: var(--lift), 0 12px 28px rgba(var(--ink-rgb), 0.12);
  padding: var(--sp-2);
}

.is-hidden { display: none; }

.picker-search {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  background: var(--well);
  font: inherit;
  margin-bottom: var(--sp-2);
}
.picker-search:focus-visible { outline: 2px solid var(--pulse); outline-offset: 1px; }

.picker-list { max-height: 300px; overflow-y: auto; }

.picker-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 7px 10px;
  border-radius: var(--r-ctl);
  cursor: pointer;
}
.picker-item:hover { background: var(--well); }
.picker-item input { accent-color: var(--pulse); }
.picker-name { flex: 1; }

/* Кнопка выбора артикулов при включённом фильтре: видно и что фильтр
   активен, и сколько выбрано — чипы-простыню убрали (2026-08-06) */
.btn.is-filter-on {
  border-color: var(--pulse);
  color: var(--pulse);
  background: var(--pulse-wash);
  font-weight: 500;
}

/* Кнопка сброса фильтра в попапе */
.picker-reset {
  display: block;
  width: calc(100% - 16px);
  margin: 0 8px var(--sp-2);
  padding: 7px 10px;
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  background: none;
  font: inherit;
  font-size: var(--fs-caption);
  color: var(--ink-soft);
  cursor: pointer;
  text-align: center;
}

.picker-reset:hover {
  border-color: var(--pulse);
  color: var(--pulse);
}

.picker-reset.is-hidden { display: none; }

/* --- Тумблер-ползунок (панель «Вид», фильтр артикулов) --- */

.sw {
  position: relative;
  width: 34px;
  height: 20px;
  flex: none;
  display: inline-block;
}

.sw input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.sw-track {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: var(--ink-ghost);
  transition: background 0.15s ease;
  pointer-events: none;
}

.sw-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--card);
  box-shadow: 0 1px 2px rgba(var(--ink-rgb), 0.25);
  transition: transform 0.15s ease;
  pointer-events: none;
}

.sw input:checked ~ .sw-track { background: var(--pulse); }
.sw input:checked ~ .sw-thumb { transform: translateX(14px); }
.sw input:focus-visible ~ .sw-track {
  outline: 2px solid var(--pulse);
  outline-offset: 1px;
}

/* --- Списки артикулов в попапе выбора --- */

.picker-lists {
  border-bottom: 1px solid var(--rule-soft);
  padding: var(--sp-2) var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-2);
}

.picker-lists-title {
  font-size: var(--fs-caption);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-mute);
  padding: var(--sp-1) 10px var(--sp-2);
}

.picker-lists-empty { padding: 0 10px var(--sp-1); }

.picker-list-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.picker-list-apply {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  padding: 7px 10px;
  border: 0;
  border-radius: var(--r-ctl);
  background: none;
  font: inherit;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
}

.picker-list-apply:hover { background: var(--well); }

.picker-save-list {
  width: 100%;
  padding: 7px 10px;
  margin-top: var(--sp-1);
  border: 1px dashed var(--rule);
  border-radius: var(--r-ctl);
  background: none;
  font: inherit;
  font-size: var(--fs-caption);
  color: var(--ink-soft);
  cursor: pointer;
  text-align: left;
}

.picker-save-list:hover {
  border-color: var(--pulse);
  color: var(--pulse);
}

/* Переключатель периода */

.seg {
  display: inline-flex;
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  background: var(--card);
  overflow: hidden;
}

/* Соседние группы кнопок — в одной рамке: «дни/недели» и период про одно
   и то же (что показываем по горизонтали), поэтому и держатся вместе.
   Внутренняя граница между группами заметнее, чем между кнопками. */
.seg-pair {
  display: inline-flex;
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  background: var(--card);
  overflow: hidden;
}
.seg-pair > .seg { border: 0; border-radius: 0; }
.seg-pair > .seg + .seg { border-left: 1px solid var(--rule); }
.seg-pair > .seg-btn + .seg-btn { border-left: 1px solid var(--rule-soft); }

/* Выбор сортировки — только для узких экранов, где нет шапки списка */
.sort-mobile { display: none; }

.sort-mobile select {
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  background: var(--card);
  color: var(--ink-soft);
  font: inherit;
  padding: 5px 8px;
  cursor: pointer;
}
.sort-mobile select:focus-visible { outline: 2px solid var(--pulse); outline-offset: 1px; }

/* Кнопка-иконка внутри группы: квадратная, без подписи */
.seg-ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  padding: 6px 0;
}

.seg-btn {
  border: 0;
  background: none;
  padding: 6px 12px;
  font: inherit;
  color: var(--ink-soft);
  cursor: pointer;
}
.seg-btn + .seg-btn { border-left: 1px solid var(--rule-soft); }
.seg-btn.is-active { background: var(--pulse-wash); color: var(--pulse); font-weight: 500; }
.seg-btn:focus-visible { outline: 2px solid var(--pulse); outline-offset: -2px; }

/* Сводка и блоки артикулов */

/* Сводка РНП теснее общих плиток (макет 2026-08-14): зазор и отступы
   меньше, цифра 26px — пять плиток остаются одной строкой контекста,
   а не отдельным экраном. «Прибыль» — единственная цветная. */
.rnp-summary { grid-template-columns: repeat(5, 1fr); gap: var(--sp-2); margin-bottom: var(--sp-2); }
.rnp-summary .card { padding: var(--sp-3) var(--sp-4); }
.rnp-summary .kpi-value { font-size: 26px; letter-spacing: -0.01em; }
.kpi-value.is-gain { color: var(--gain); }
.kpi-value.is-loss { color: var(--loss); }
.kpi-unit { font-size: 18px; font-weight: 500; }

.chev { color: var(--ink-mute); flex: none; }

/* Мини-фото товара: в списке выбора артикулов и в липкой планке.
   Фон --well на случай прозрачных углов миниатюры WB. */
.ava {
  width: 24px;
  height: 32px;
  object-fit: cover;
  border-radius: 4px;
  background: var(--well);
  flex: none;
}

/* --- Дашборд: топ и антитоп артикулов по данным ABC ---
   Шесть карточек двумя группами. Цвет несёт только сумма прибыли — как
   у дельт плиток выше: заливать карточку целиком нечем, «лучший» и так
   стоит в группе «Лучшие». */

.dash-abc {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.abc-mini-title {
  font-size: var(--fs-caption);
  font-weight: 500;
  color: var(--ink-soft);
  margin-bottom: var(--sp-2);
}

/* Три карточки в ряд — сколько их и есть в группе. На узком экране ряд
   из трёх не помещается и распирал страницу вбок (375 → 613 px), поэтому
   там колонок две; горизонтальной прокрутки у дашборда быть не должно. */
.abc-mini-row-wrap {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-2);
}

@media (max-width: 900px) {
  .abc-mini-row-wrap { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.abc-mini {
  display: flex;
  gap: var(--sp-2);
  padding: var(--sp-2);
  border: 1px solid var(--rule-soft);
  border-radius: var(--r-ctl);
  color: inherit;
  text-decoration: none;
  transition: border-color 0.15s, background 0.15s;
}

.abc-mini:hover { border-color: var(--rule); background: var(--well); }

.abc-mini:focus-visible {
  outline: 2px solid var(--pulse);
  outline-offset: 1px;
}

.abc-mini-photo {
  width: 40px;
  height: 53px;
  object-fit: cover;
  border-radius: 4px;
  background: var(--well);
  flex: none;
}

.abc-mini-body { min-width: 0; flex: 1; }

.abc-mini-code {
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  color: var(--ink-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.abc-mini-warn { color: var(--warn); }

.abc-mini-profit {
  font-size: var(--fs-body);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  margin: 2px 0;
}

.abc-mini-profit.is-gain { color: var(--gain); }
.abc-mini-profit.is-loss { color: var(--loss); }

.abc-mini-row {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-2);
  font-size: var(--fs-caption);
  color: var(--ink-mute);
  /* Ни подпись, ни число не переносятся: на узкой карточке «ЧП/шт» рвался
     пополам, а «−1 193 ₽» уезжал на вторую строку и ряды разъезжались */
  white-space: nowrap;
}

.abc-mini-row b {
  font-weight: 500;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

/* --- Тепловая карта: таблица на базе .rnp, но ячейки несут заливку --- */

.heat .c-m {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.heat-name {
  display: inline-flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.heat-code {
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.heat td:not(.c-m) { text-align: right; }

/* Итоговая строка «Все артикулы» — суммы/агрегаты по каждому дню */
.heat-row-total td { font-weight: 600; }
.heat-row-total .c-m { background: var(--well); }
.heat-row-total td { border-bottom: 2px solid var(--rule); }

/* Вторая строка ячейки у «Маржа · ДРР»: лежит на залитой клетке,
   поэтому тише размером и весом, но не серым (правило «текст на цветной
   подложке» в DESIGN.md) */
.heat-cell-sub {
  display: block;
  font-size: var(--fs-caption);
  font-weight: 400;
  color: var(--ink-soft);
  line-height: 1.2;
}

.heat-note {
  margin: var(--sp-3) var(--sp-5) 0;
  font-size: var(--fs-caption);
  color: var(--ink-mute);
}

/* Сверка охвата финотчёта (ABC). В норме строка тихая и незаметная — она
   лишь подтверждает, что проверка есть. Красной становится только когда
   деньги реально потерялись: тревога точечная, как и везде (DESIGN.md). */
.abc-leak {
  color: var(--loss);
  background: var(--loss-wash);
  border-radius: var(--r-ctl);
  padding: var(--sp-2) var(--sp-3);
  margin-inline: var(--sp-5);
}

/* --- Липкая шапка раскрытого артикула: планка с названием и датами,
   появляется, когда шапка таблицы уезжает при прокрутке --- */

.rnp-sticky {
  position: fixed;
  top: 0;
  z-index: 40; /* ниже выезжающего сайдбара (60) */
  background: var(--card);
  box-shadow: var(--lift);
  border-radius: 0 0 var(--r-card) var(--r-card);
  overflow: hidden;
}

.rnp-sticky-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  border-bottom: 1px solid var(--rule-soft);
  font-size: 13px;
}

.rnp-sticky-title { font-weight: 600; }

.rnp-sticky-head .ava {
  width: 20px;
  height: 26px;
}

.rnp-sticky-scroll { overflow: hidden; }

/* --- Полноэкранный режим таблицы: прячем сайдбар и шапку --- */

.shell.is-full .side,
.shell.is-full .page-head { display: none; }

.shell.is-full {
  grid-template-columns: 1fr;
}

.shell.is-full .main { padding-top: var(--sp-3); }

/* --- Полоса дней. Внутри клетки заказы → прибыль → ДРР, даты — в шапке
   списка, один раз.

   Заливка по заказам убрана 2026-08-07 (вариант «A» из четырёх примерок
   на живом сайте): прямоугольник в каждой клетке перетягивал внимание на
   правую половину строки, а главное — итоги артикула слева. Ряд дней стал
   спокойным хвостом: цифра дня мельче и тише основных, убыточный день
   узнаётся красными цифрами, а не кантом и заливкой. Ценой этого спрос
   больше не читается «гистограммой» — только по числам. --- */

/* --- Список артикулов как таблица (2026-08-07, вариант «A» из трёх
   примерок). Раньше каждый артикул был отдельной карточкой со своими
   подписями и своим рядом дат — 22 копии одного и того же, отчего экран
   читался россыпью блоков. Теперь подписи и даты стоят ОДИН раз в шапке,
   а артикулы идут строками одной сетки: цифры выстраиваются в колонки. --- */

/* Без overflow: hidden — он ломает sticky у шапки списка (она бы уезжала
   вместе со страницей). Скругление углов держат сами края: шапка сверху,
   последняя строка снизу. */
.rnp-list { padding: 0; }
.rnp-list > *:last-child { border-radius: 0 0 var(--r-card) var(--r-card); }

/* Одна сетка на шапку и строки — иначе колонки разъедутся.
   Ширины с запасом под недельный режим: там в тех же колонках стоят
   суммы за 8–12 недель, и на прежних 82px «+1 245 678» налезало на
   соседа (2026-08-07). Правило: колонку меряем по самому длинному
   числу, которое в неё может прийти, а не по типичному. */
.rnp-head,
.rnp-line {
  display: grid;
  grid-template-columns:
    14px 38px minmax(168px, 1.1fr)
    72px 68px 104px 48px 176px
    minmax(0, 3.2fr) 80px;
  gap: var(--sp-3);
  align-items: center;
  padding: 0 var(--sp-4);
}

/* Окно целиком в прошлом (произвольные даты, 2026-08-10): текущего
   отрезка в нём нет, и блок «сегодня / эта неделя» показывал бы столбец
   прочерков под подписью «ещё идёт». Убираем его вместе с колонкой —
   пустая колонка врёт увереннее, чем её отсутствие. */
.rnp-list.is-past .rnp-head,
.rnp-list.is-past .rnp-line {
  grid-template-columns:
    14px 38px minmax(168px, 1.1fr)
    72px 68px 104px 48px
    minmax(0, 3.2fr) 80px;
}

.rnp-list.is-past .lh-now,
.rnp-list.is-past .line-now { display: none; }

/* Даты и подписи остаются на виду при прокрутке длинного списка —
   иначе колонки читать не по чему */
.rnp-head {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--card);
  border-radius: var(--r-card) var(--r-card) 0 0;
  border-bottom: 1px solid var(--rule);
  padding-top: var(--sp-2);
  padding-bottom: var(--sp-2);
  align-items: end;
}

.lh {
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-mute);
  white-space: nowrap;
}
.lh.is-num { text-align: right; }

/* Заголовок-сортировка: выглядит как подпись колонки, ведёт себя как
   кнопка. Активная колонка помечена цветом и стрелкой направления. */
.sort-btn {
  border: 0;
  padding: 0;
  background: none;
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
  white-space: nowrap;
}
/* Область попадания 24px по высоте (WCAG 2.5.8): сама подпись 15px,
   и растить её нельзя — шапка плотной таблицы раздвинулась бы на всех
   разделах. Поэтому растёт не кнопка, а невидимая площадка вокруг неё;
   вширь она не выходит за подпись, так что соседние колонки не задевает
   (аудит 2026-08-13). */
.sort-btn { position: relative; }
.sort-btn::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  min-width: 24px;
  height: 24px;
}
.sort-btn:hover { color: var(--ink); }
.sort-btn:focus-visible { outline: 2px solid var(--pulse); outline-offset: 2px; }
.sort-btn.is-on { color: var(--pulse); font-weight: 600; }
.sort-arr { margin-left: 2px; }

/* Подпись текущего отрезка: общий заголовок + три мини-подписи под ним */
.lh-now-cap {
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-mute);
  white-space: nowrap;
}
/* «день идёт» при подписи отрезка — слова, а не прочерк: тот же разбор,
   что строкой ниже, только сюда правка 2026-08-07 не дошла (аудит 2026-08-13) */
.lh-now-cap em {
  font-style: normal;
  text-transform: none;
  letter-spacing: 0;
  color: var(--ink-mute);
}
/* Это подписи колонок, а не прочерки: --ink-ghost давал 1.9:1 и они
   не читались (аудит 2026-08-07) */
.lh-now-cols {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: var(--sp-2);
  font-size: 10px;
  color: var(--ink-mute);
  text-align: right;
}

/* Ноутбук: восьми колонок слева и десяти дней одновременно не бывает.
   Первыми уходят заглушка плана и мини-график переходов — они полезны,
   но не для ежедневного чтения; дни возвращаются с четырёх до семи. */
@media (min-width: 901px) and (max-width: 1500px) {
  .rnp-head,
  .rnp-line {
    grid-template-columns:
      14px 38px minmax(140px, 1.1fr)
      72px 68px 104px 176px
      minmax(0, 3.2fr);
  }

  .rnp-list.is-past .rnp-head,
  .rnp-list.is-past .rnp-line {
    grid-template-columns:
      14px 38px minmax(140px, 1.1fr)
      72px 68px 104px
      minmax(0, 3.2fr);
  }

  .lh.is-plan,
  .lh.is-chart,
  .line-num.is-plan,
  .line-chart { display: none; }
}

/* --- Строка артикула --- */

.rnp-line {
  padding-top: 4px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--rule-soft);
  cursor: pointer;
  user-select: none;
}
.rnp-line:hover { background: var(--well); }
.rnp-line:focus-visible { outline: 2px solid var(--pulse); outline-offset: -2px; }
.rnp-line.is-open { background: var(--well); }
.rnp-list .rnp-line:last-child { border-bottom: 0; }

/* Компактная плотность — выбор пользователя 2026-08-14 (макет):
   фото ниже, строка на ~10px короче, на экран влезает больше артикулов */
.line-photo {
  width: 38px;
  height: 48px;
  border-radius: 4px;
  background: var(--well);
  overflow: hidden;
}
.line-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

.line-name { min-width: 0; }

.line-title {
  font-size: var(--fs-body);
  font-weight: 600;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Код, остаток и план выкупа — мелкой строкой: бейджам в плотной строке
   места нет, а знать их надо */
.line-meta {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-caption);
  color: var(--ink-mute);
  white-space: nowrap;
  overflow: hidden;
}
.meta-stock { font-variant-numeric: tabular-nums; }
.meta-stock.is-low { color: var(--loss); font-weight: 500; }

/* Иерархия итогов строки (макет 2026-08-14): Заказы 15px — главная цифра,
   Прибыль 14px, ДРР периода тише всех (13px, полужирный, вторичный цвет) —
   глаз сперва ловит объём и деньги, ДРР читается при разборе */
.line-num {
  text-align: right;
  font-size: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.line-num.is-profit { font-size: 14px; }
.line-num.is-quiet {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-soft);
}

/* Подпись при числе. На широком экране колонки подписаны шапкой, поэтому
   здесь она не нужна глазу — но нужна тем, кто слушает страницу: без неё
   строка звучит лентой цифр. Прячем визуально, а не от скринридера. */
.num-cap {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.line-num.is-gain { color: var(--gain); }
.line-num.is-loss { color: var(--loss); }
.line-num.is-dim { color: var(--ink-ghost); font-weight: 400; }

/* Погас сам прочерк, но не его подпись: на широком экране .num-cap
   спрятана визуально, а на телефоне она выходит к числу (см. правило
   в блоке max-width: 900px) — и там призрачный серый давал 1.7:1
   при обычном на вид тексте (аудит 2026-08-13). */
.line-num.is-dim > .num-cap { color: var(--ink-mute); }

/* Текущий отрезок — три числа на розовой подложке «сегодня».
   Между ними полноценный зазор: на «13 0,1% +3 640» четырёх пикселей
   не хватало и числа слипались в одно (2026-08-07). */
.line-now {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: var(--sp-2);
  background: var(--pulse-wash);
  border-radius: 5px;
  padding: 4px var(--sp-3);
}
.line-now .line-num { font-size: 13px; }

/* Плана ещё нет — прочерк того же цвета, что и «нет данных» */
.sum-todo { color: var(--ink-ghost); font-weight: 400; }

/* Мини-график отделён вертикалью, как ряд дней; цвет тише (макет 2026-08-14) */
.line-chart {
  color: var(--ink-mute);
  text-align: right;
  align-self: stretch;
  display: flex;
  flex-direction: column;
  justify-content: center;
  border-left: 1px solid var(--rule);
  padding-left: 10px;
}
.lh.is-chart { border-left: 1px solid var(--rule); padding-left: 10px; }
.sum-spark { display: block; margin-left: auto; }
.sum-note { font-size: 10px; color: var(--ink-mute); margin-top: 1px; }

/* --- Раскрытый артикул: таблица под своей строкой --- */

.rnp-open {
  border-bottom: 1px solid var(--rule);
  background: var(--card);
  padding-bottom: var(--sp-2);
}

/* Полоса живёт в ячейке общей сетки и занимает её целиком. Вид по макету
   2026-08-14: клетки без зазоров, между днями волосяные вертикали, числа
   прижаты ВПРАВО (как в таблице), клетки тянутся на всю ширину — лишние
   дни прячет container query, а не сплющивание. */
.rnp-strip {
  display: flex;
  min-width: 0;
  align-self: stretch;
}

.strip-days {
  display: flex;
  flex: 1;
  min-width: 0;
  gap: 0;
  border-left: 1px solid var(--rule);
}

.strip-col {
  display: flex;
  flex-direction: column;
  justify-content: center;
  flex: 1 0 56px;
  min-width: 0;
  text-align: right;
  border-left: 1px solid var(--rule-soft);
}
.strip-col:first-child { border-left: 0; }

.strip-date {
  font-size: 10px;
  letter-spacing: 0.02em;
  color: var(--ink-mute);
  white-space: nowrap;
  padding-right: var(--sp-2);
  height: 16px;
}

/* День недели при дате — читаемым серым, не призрачным: это подпись
   колонки, а не прочерк (правило контраста, tokens.css) */
.strip-dow { color: var(--ink-mute); font-weight: 400; }

.strip-col.is-today .strip-date { color: var(--pulse); font-weight: 600; }

.strip-cell {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  gap: 1px;
  padding: 2px var(--sp-2) 2px var(--sp-1);
  flex: 1;
}

.strip-cell > span {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* Иерархия клетки (макет 2026-08-14): заказы — чернилами и полужирно,
   маржа дня — мельче и тихим серым; убыток красит обе строки */
.strip-orders {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  line-height: 17px;
}

.strip-margin {
  font-size: 10.5px;
  font-weight: 500;
  color: var(--ink-mute);
  line-height: 13px;
}

.strip-cell .is-dim { color: var(--ink-ghost); font-weight: 400; }
.strip-cell .is-loss { color: var(--loss); }

/* Убыточный день: без заливки и канта сигналом остаются сами цифры */
.strip-cell.is-neg .strip-orders { color: var(--loss); }

/* Тесно — режем самые старые дни (они справа), свежие остаются.
   Пороги — по реальной ширине полосы (container query), а не окна:
   сайдбар и полноэкранный режим учитываются сами. Колонка 56px, зазоров
   нет. Шапка списка и строки считают одинаково: сетка у них общая. */
.rnp-strip { container-type: inline-size; }

/* В шапке даты прижаты к низу, как остальные подписи колонок */
.rnp-head .strip-col { justify-content: flex-end; }

@container (max-width: 559px) { .strip-days .strip-col:nth-child(n+10) { display: none; } }
@container (max-width: 503px) { .strip-days .strip-col:nth-child(n+9) { display: none; } }
@container (max-width: 447px) { .strip-days .strip-col:nth-child(n+8) { display: none; } }
@container (max-width: 391px) { .strip-days .strip-col:nth-child(n+7) { display: none; } }
@container (max-width: 335px) { .strip-days .strip-col:nth-child(n+6) { display: none; } }
@container (max-width: 279px) { .strip-days .strip-col:nth-child(n+5) { display: none; } }
@container (max-width: 223px) { .strip-days .strip-col:nth-child(n+4) { display: none; } }

/* Таблица: первая колонка и Σ закреплены, скролл по дням внутри карточки */

.rnp-scroll { overflow-x: auto; }

table.rnp {
  border-collapse: separate;
  border-spacing: 0;
  min-width: 100%;
  font-size: var(--fs-body);
  line-height: 1.35;
  font-variant-numeric: tabular-nums;
}

.rnp th, .rnp td {
  padding: 6px 10px;
  text-align: right;
  white-space: nowrap;
  border-bottom: 1px solid var(--rule-soft);
}

.rnp thead th {
  font-size: var(--fs-caption);
  font-weight: 500;
  color: var(--ink-mute);
  border-bottom: 1px solid var(--rule);
}

/* Ярусы строк: главное жирнее, производное тише и с отступом.
   Насмотрено на плотных аналитических таблицах: иерархия веса и цвета
   вместо равных строк, линии светлые, «пустые» значения гаснут. */

.rnp tr.t-hero td { font-weight: 600; }
.rnp tr.t-hero .c-m { color: var(--ink); }

.rnp tr.t-base .c-m { color: var(--ink-soft); }

.rnp tr.t-soft td {
  color: var(--ink-soft);
  padding-top: 4px;
  padding-bottom: 4px;
}
.rnp tr.t-soft .c-m {
  color: var(--ink-mute);
  padding-left: calc(var(--sp-5) + 12px);
}

/* Пустые значения не должны звенеть как данные */
.rnp td.is-dim { color: var(--ink-ghost); }
/* Клетка без заливки, но с настоящим нулём (тепловая карта): тише
   залитых соседей, но читается — см. разбор в heat.js */
.rnp td.is-zero { color: var(--ink-mute); }

/* Стрелки динамики к предыдущему дню (по мотивам truestats):
   цвет несут только они, фон ячеек остаётся тихим */
.rnp .arr { font-size: 11px; margin-left: 3px; }
/* Цвета стрелок динамики — общие (РНП, плитки дашборда) */
.arr-g { color: var(--gain); }
.arr-b { color: var(--loss); }
.arr-n { color: var(--ink-ghost); }

/* Колонка «Динамика»: мини-бары за период, хронологически слева направо */
.rnp .c-dyn { width: 64px; min-width: 64px; }
.rnp thead .c-dyn { text-align: right; }
.dyn {
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  gap: 1px;
  height: 18px;
}
.dyn span {
  flex: 1 1 2px;
  max-width: 4px;
  min-height: 1px;
  background: var(--ink-ghost);
  border-radius: 1px;
}

/* День недели в шапке дат — второй строкой, тихо.
   Тихо, но не призрачно: это подпись колонки, её читают
   (было --ink-ghost, 1,7:1 — аудит 2026-08-13). */
.rnp thead .dow {
  display: block;
  font-size: 10px;
  line-height: 1.2;
  color: var(--ink-mute);
  text-transform: lowercase;
}

/* Вести взгляд по 14 колонкам помогает подсветка строки */
.rnp tbody tr:not(.grp):hover td { background: var(--well); }
.rnp tbody tr:not(.grp):hover td.is-today { background: var(--pulse-wash); }

.rnp .c-m {
  position: sticky;
  left: 0;
  z-index: 2;
  width: 176px;
  min-width: 176px;
  background: var(--card);
  text-align: left;
  padding-left: var(--sp-5);
}

.rnp thead .c-m {
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--ink);
}

.rnp .c-t {
  position: sticky;
  left: 176px;
  z-index: 2;
  background: var(--card);
  border-right: 1px solid var(--rule);
  font-weight: 500;
}

.rnp .is-today { background: var(--pulse-wash); }

/* Заголовок группы — «полка»: фоновая полоса на всю ширину + разрыв сверху,
   чтобы секции читались даже при беглом прокручивании */
.rnp .grp td {
  cursor: pointer;
  user-select: none;
  background: var(--well);
  border-bottom: 0;
  border-top: 8px solid var(--card);
  padding-top: 5px;
  padding-bottom: 5px;
}

.rnp .grp .c-m {
  font-size: var(--fs-caption);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  background: var(--well);
}

.rnp tbody tr:last-child td { border-bottom: 0; }

/* Название блока — кнопка без вида кнопки: наследует «полку» целиком,
   но сворачивается с клавиатуры, а не только мышью */
.rnp .grp-btn {
  border: 0;
  padding: 0;
  background: none;
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}
.rnp .grp-btn:focus-visible { outline: 2px solid var(--pulse); outline-offset: 2px; }

.rnp .grp .grp-btn::before { content: '▾ '; color: var(--ink-ghost); }
.rnp tbody.is-closed tr:not(.grp) { display: none; }
.rnp tbody.is-closed .grp .grp-btn::before { content: '▸ '; }

/* --- Раскрытая таблица РНП, уплотнение по макету 2026-08-14 (.rnp-x).
   Модификатор, а не правка базового .rnp: на нём же живёт тепловая карта,
   и её плотность решается отдельно. Что здесь: кегль 13/12,5, колонка
   названий 208px с моношрифтом артикула в шапке, «Динамика» и «сегодня»
   закреплены вместе с названием и Σ (при прокрутке дней видна вся левая
   рамка чтения), «сегодня» — розовый чип, волосяные вертикали между
   днями, стрелка динамики в слоте фиксированной ширины, деньги со знаком
   ₽ в ячейке, «Прибыль» окрашена знаком. --- */

table.rnp-x { font-size: 12.5px; }
.rnp-x th, .rnp-x td {
  padding: 3px var(--sp-2);
  border-left: 1px solid var(--rule-soft);
}
.rnp-x .c-m, .rnp-x .c-t, .rnp-x .c-dyn { border-left: 0; }

/* «Динамика» обязана держать РОВНО свою ширину: она в закреплённой пачке,
   и офсет «сегодня» посчитан от неё. Без фиксированной ширины мини-баров
   ячейка расползается по max-content (14 баров шире, чем 8), и «сегодня»
   наезжает на бары. 60px делят между собой сколько угодно дней. */
.rnp-x .c-dyn { width: 76px; min-width: 76px; }
.rnp-x .dyn { width: 60px; margin-left: auto; }
.rnp-x tr.t-hero td { font-size: 13px; }
.rnp-x tr.t-soft td { padding-top: 3px; padding-bottom: 3px; }

.rnp-x .c-m { width: 208px; min-width: 208px; padding-left: var(--sp-4); }
.rnp-x tr.t-soft .c-m { padding-left: 32px; }
.rnp-x .c-t { left: 208px; width: 112px; min-width: 112px; }
.rnp-x .c-dyn {
  position: sticky;
  left: 320px;
  z-index: 2;
  background: var(--card);
}

/* «Сегодня» — закреплённая колонка-чип сразу за «Динамикой»: подложка
   непрозрачная (заливка поверх карточки), иначе при прокрутке дней под
   ней просвечивали бы чужие цифры */
.rnp-x th.is-today, .rnp-x td.is-today {
  position: sticky;
  left: 396px; /* 208 (название) + 112 (Σ) + 76 (Динамика) */
  z-index: 2;
  background: linear-gradient(var(--pulse-wash), var(--pulse-wash)), var(--card);
  border-left: 0;
}
.rnp-x thead th.is-today {
  color: var(--pulse);
  font-weight: 600;
  border-radius: 4px 4px 0 0;
}
.rnp-x tbody tr:not(.grp):hover td.is-today {
  background: linear-gradient(var(--pulse-wash), var(--pulse-wash)), var(--well);
}

.rnp-x thead th { font-size: 10px; }
.rnp-x thead .c-t, .rnp-x thead .c-dyn {
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.rnp-x thead .c-m {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 400;
  color: var(--ink-soft);
}
/* Дата и день недели — в одну строку, день недели читаемым серым */
.rnp-x thead .dow { display: inline; margin-left: 4px; font-size: 10px; }

/* Слот стрелки всегда одной ширины — числа в колонке стоят колонкой */
.rnp-x .arr {
  display: inline-block;
  width: 8px;
  margin-left: 2px;
  font-size: 9px;
  text-align: left;
}

/* Единственная строка с цветом по знаку — «Прибыль», как её итог в списке */
.rnp-x td.is-gain { color: var(--gain); }
.rnp-x td.is-loss { color: var(--loss); }

/* Полка группы: текст чернилами, разрыв между группами тоном подложки */
.rnp-x .grp td { border-top: 8px solid var(--paper); border-left: 0; }
.rnp-x .grp .c-m { color: var(--ink); }

/* Мини-бары «Динамики» — нейтральный тон графиков, не призрачный */
.rnp-x .dyn span { background: var(--chart-ghost); }

/* Подписи строк комментариев — тише, это служебные ряды */
.rnp-x .cmt-row .c-m { color: var(--ink-mute); }

/* --- Блок «Комментарии»: редактируемые ячейки-заметки (грид, как в
   Google-таблице: клик — выделить, двойной — редактировать, Ctrl+C/V —
   диапазоном). Логика — pages/rnp-comments.js. --- */

.rnp td.cmt {
  cursor: cell;
  text-align: left;
  vertical-align: top;
  position: relative; /* точка отсчёта для редактора поверх клетки */
  padding: 4px 6px;
}

/* «Сегодня» и в комментариях остаётся закреплённой колонкой. Правило выше
   идёт ПОЗЖЕ блока .rnp-x .is-today и с той же силой, поэтому сбивало ему
   sticky на relative — и left: 396px срабатывал как сдвиг вправо: клетка
   «сегодня» уезжала на две колонки от своей шапки (2026-08-15). Sticky
   так же годится редактору точкой отсчёта. */
.rnp-x td.cmt.is-today { position: sticky; }
.rnp td.cmt:focus { outline: none; } /* состояние показывает рамка выделения */

/* Внутренний блок держит ширину колонки: длинная заметка переносится и
   обрезается, а не растягивает столбец дат под собой */
.rnp td.cmt .cmt-in {
  min-width: 64px;
  max-width: 132px;
  min-height: 19px;
  max-height: 88px;
  overflow: hidden;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-size: 12px;
  line-height: 1.4;
  color: var(--ink-soft);
}

/* «Стратегия» — один текст на артикул, широкая ячейка на все дни */
.rnp td.cmt-strategy .cmt-in { max-width: 560px; }

.cmt-row .c-m { color: var(--ink-soft); }

/* Выделение: кольцо в каждой выбранной клетке, у якоря плотнее.
   Розовая подложка сильнее hover и «сегодня» — правило ниже возвращает её
   поверх подсветки строки при наведении */
.rnp td.cmt.is-sel {
  background: var(--pulse-wash);
  box-shadow: inset 0 0 0 1px var(--pulse);
}
.rnp td.cmt.is-anchor { box-shadow: inset 0 0 0 2px var(--pulse); }
.rnp tbody tr:not(.grp):hover td.cmt.is-sel { background: var(--pulse-wash); }

/* Редактор поверх клетки: пока печатаешь, таблица не раздвигается */
.cmt-editor {
  position: absolute;
  top: -1px;
  left: -1px;
  z-index: 5;
  padding: 5px 7px;
  border: 2px solid var(--pulse);
  border-radius: var(--r-ctl);
  background: var(--card);
  box-shadow: var(--lift);
  font: inherit;
  font-size: 12px;
  line-height: 1.4;
  color: var(--ink);
  resize: both;
}

.empty-note { color: var(--ink-mute); }

/* Хвост длинного журнала. Строки рисуются окном: две с половиной тысячи
   платежей разом давали 36 000 узлов и полторы секунды сборки (аудит
   2026-08-13). Здесь — чем досыпать и сколько строк из скольких на экране;
   размер порции и разбор — в pnl.js и selfbuy.js. */
.list-more {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--rule-soft);
}

/* Панель «Вид»: настройка строк таблицы (порядок + вкл/выкл) */

.toolbar-right {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

/* Тулбар РНП снова в одну строку (2026-08-11): пресеты и поля дат ушли
   в календарь-попап (.rng), от тесноты, ради которой заводили две строки
   (2026-08-10), осталась одна кнопка с текущим отрезком. */
.rnp-toolbar-line {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(var(--ink-rgb), 0.28);
}

.drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 41;
  width: min(360px, 92vw);
  display: flex;
  flex-direction: column;
  background: var(--card);
  box-shadow: var(--lift), -16px 0 40px rgba(var(--ink-rgb), 0.14);
  padding: var(--sp-4) var(--sp-4) var(--sp-3);
}

.drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--sp-2);
}

.drawer-title {
  margin: 0;
  font-size: var(--fs-h4);
  font-weight: 600;
}

.drawer-close { font-size: var(--fs-h3); }

.drawer-body {
  flex: 1;
  overflow-y: auto;
  margin: var(--sp-2) 0;
  border-top: 1px solid var(--rule-soft);
}

.drawer-foot {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--rule-soft);
}

.drawer-foot-gap { flex: 1; }

.drawer-reset { color: var(--ink-soft); }

.btn-primary {
  background: var(--pulse);
  border-color: var(--pulse);
  color: var(--on-pulse);
}
.btn-primary:hover { background: var(--pulse-deep); color: var(--on-pulse); }

.draw-group-title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-caption);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-mute);
  padding: var(--sp-3) var(--sp-2) var(--sp-1);
}
.draw-group.dragging { opacity: 0.45; }

/* Выключенный целиком блок: строки гаснут, но их тумблеры не сбрасываются */
.draw-group-name { flex: 1; }
.draw-group.is-off .draw-row { opacity: 0.4; }

.draw-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 5px var(--sp-2);
  border-radius: var(--r-ctl);
  background: var(--card);
}
.draw-row:hover { background: var(--well); }
.draw-row.dragging { opacity: 0.45; }
.draw-row input { accent-color: var(--pulse); }

.draw-label { flex: 1; }

.draw-switch {
  border: 1px solid var(--rule-soft);
  border-radius: var(--r-ctl);
  padding: var(--sp-2) var(--sp-2);
}

.handle {
  cursor: grab;
  color: var(--ink-ghost);
  user-select: none;
}

/* Админка */

.admin-card { padding: var(--sp-4) 0 var(--sp-4); }
.admin-card .ue-head { margin-bottom: var(--sp-3); }
.admin-card .ue { width: 100%; }
.ue-status.is-error { color: var(--loss); }

.admin-switch {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  cursor: pointer;
  color: var(--ink-soft);
}
.admin-switch input { accent-color: var(--pulse); }

.admin-actions { text-align: right; }
/* Крестик удаления аккаунта — тот же, что у строк журналов и списков РНП,
   и стоит после «Нового пароля», а не перед: сначала обычное действие. */
.admin-actions .chip-x { margin-left: var(--sp-2); vertical-align: middle; }

.admin-add {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-5) 0;
  border-top: 1px solid var(--rule-soft);
  margin-top: var(--sp-3);
}
.admin-add .auth-input { flex: 1 1 160px; width: auto; }

/* Страницы входа и первичной настройки */

.auth-page {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  min-height: 100dvh;
  padding: var(--sp-4);
}

.auth-card {
  width: min(360px, 100%);
  padding: var(--sp-8) var(--sp-6) var(--sp-6);
}

.auth-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  color: var(--pulse);
  margin-bottom: var(--sp-5);
}
.auth-brand .brand-pulse { width: 44px; height: 20px; }
.auth-title {
  font-size: var(--fs-h3);
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.01em;
}

.auth-note {
  margin: 0 0 var(--sp-4);
  color: var(--ink-soft);
  font-size: var(--fs-body);
}

.auth-label {
  display: block;
  font-size: var(--fs-caption);
  font-weight: 500;
  color: var(--ink-mute);
  margin: var(--sp-3) 0 var(--sp-1);
}

.auth-input {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  background: var(--well);
  font: inherit;
}
.auth-input:focus-visible { outline: 2px solid var(--pulse); outline-offset: 1px; }

.auth-error {
  margin: var(--sp-3) 0 0;
  color: var(--loss);
  font-size: var(--fs-body);
}

.auth-submit {
  width: 100%;
  margin-top: var(--sp-4);
  padding: 9px 12px;
}

@media (max-width: 900px) {
  .rnp-summary { grid-template-columns: 1fr 1fr; }
  .rnp .c-m { width: 132px; min-width: 132px; padding-left: var(--sp-4); }
  .rnp .c-t { left: 132px; }

  /* На телефоне закреплённых колонок только две: «Динамика» и «сегодня»
     вместе с названием и Σ съели бы весь экран. Ширина Σ снова по
     содержимому — 112px рядом со 132px названия слишком жирно. */
  .rnp-x .c-t { width: auto; min-width: 72px; }
  .rnp-x .c-dyn,
  .rnp-x th.is-today,
  .rnp-x td.is-today { position: static; left: auto; }
  /* Клетке комментария relative вернуть отдельно: редактор внутри неё
     считает координаты от неё же. Смещения при этом быть не должно —
     его снимает left: auto выше */
  .rnp-x td.cmt.is-today { position: relative; }

  /* На телефоне таблицей строку не удержать: сетка складывается в два
     ряда — сверху название и цифры, снизу дни во всю ширину.
     Шапку колонок прячем: подписи возвращаются к самим значениям. */
  .rnp-head { display: none; }

  .rnp-line {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2) var(--sp-3);
    padding: var(--sp-2) var(--sp-3);
  }
  .rnp-line > .line-photo { width: 40px; height: 52px; }
  /* базис маленький, иначе название требует свою ширину и уносит цифры
     на отдельную строку */
  .rnp-line > .line-name { flex: 1 1 90px; min-width: 0; }

  /* Под названием места на всё не хватает: номер карточки на телефоне
     нужен реже, чем остаток и план выкупа, — он и уходит первым */
  .line-meta { flex-wrap: wrap; row-gap: 0; }
  .line-meta .chip-id { display: none; }
  .rnp-line > .rnp-strip { flex: 1 0 100%; }

  /* План-заглушка, «сегодня» и спарклайн на телефоне не помещаются —
     они остаются на широком экране и в раскрытом артикуле */
  .rnp-line > .line-num.is-plan,
  .rnp-line > .line-now,
  .rnp-line > .line-chart { display: none; }

  .toolbar-right { flex-wrap: wrap; }

  /* Шапки списка тут нет, поэтому сортировка переезжает в тулбар,
     а подписи колонок — к самим числам */
  .sort-mobile {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: var(--fs-caption);
    color: var(--ink-mute);
  }

  /* Видимой становится только подпись при числе; «остаток» в мете
     остаётся служебной — там значение и так говорит за себя */
  .line-num > .num-cap {
    position: static;
    width: auto;
    height: auto;
    clip-path: none;
    display: block;
    font-size: 10px;
    font-weight: 400;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-mute);
  }
}

/* ===== Юнит-экономика: таблица с редактируемыми ячейками ===== */

.ue-card { padding: var(--sp-4) 0 var(--sp-2); }

.ue-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-3);
  padding: 0 var(--sp-5);
  margin-bottom: var(--sp-2);
}

.ue-status { font-size: var(--fs-caption); color: var(--gain); white-space: nowrap; }
.ue-status.is-error { color: var(--loss); }

/* Общая ставка налога — маленькое поле в шапке справочника.
   margin-left: auto прижимает его вправо (2026-08-10): раньше шапка была
   flex со space-between из трёх элементов, и поле вставало где придётся —
   на широком экране посередине пустоты, без опоры на край. */
.ue-tax {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin-left: auto;
  font-size: var(--fs-caption);
  color: var(--ink-soft);
  white-space: nowrap;
}

.ue-tax input {
  width: 52px;
  padding: 4px 8px;
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  background: var(--card);
  font: inherit;
  color: var(--ink);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Фокус у «тихих» полей — то же кольцо, что у остальных 24 контролов.
   Смена цвета рамки в 1px читалась заметно слабее (аудит 2026-08-13). */
.ue-tax input:focus-visible {
  outline: 2px solid var(--pulse);
  outline-offset: 1px;
  border-color: var(--pulse);
}

.ue-scroll { overflow-x: auto; }

table.ue {
  border-collapse: separate;
  border-spacing: 0;
  min-width: 100%;
  font-size: var(--fs-body);
  font-variant-numeric: tabular-nums;
}

.ue th, .ue td {
  border-bottom: 1px solid var(--rule-soft);
  white-space: nowrap;
  text-align: left;
}

.ue th {
  padding: 6px 10px;
  font-size: var(--fs-caption);
  font-weight: 500;
  color: var(--ink-mute);
}

.ue td { padding: 0; }
.ue td.is-auto { padding: 6px 10px; color: var(--ink-soft); }
.ue td.c-id { font-family: var(--font-mono); font-size: 13px; }
.ue th:first-child, .ue td:first-child { padding-left: var(--sp-5); }

/* Редактируемая ячейка: «тихий» инпут — граница видна только при наведении/фокусе */
.ue td.is-edit input {
  width: 100%;
  min-width: 96px;
  border: 1px solid transparent;
  border-radius: 0;
  background: none;
  font: inherit;
  color: var(--ink);
  padding: 6px 10px;
}

/* Текстовым колонкам — больше места: сезон (5), менеджер (6), ЮР лицо (7).
   Статус (4) — выпадающий список, ширина у него своя (см. select ниже). */
.ue td:nth-child(5) input,
.ue td:nth-child(6) input,
.ue td:nth-child(7) input { min-width: 136px; }
.ue td.is-edit input:hover { border-color: var(--rule); }
.ue td.is-edit input:focus-visible {
  outline: 2px solid var(--pulse);
  outline-offset: -2px;
  border-color: var(--pulse);
  background: var(--card);
}

.ue td.is-edit select {
  width: 100%;
  min-width: 120px;
  border: 1px solid transparent;
  border-radius: 0;
  background: none;
  font: inherit;
  color: var(--ink);
  padding: 6px 10px;
  cursor: pointer;
}
.ue td.is-edit select:hover { border-color: var(--rule); }
.ue td.is-edit select:focus-visible {
  outline: 2px solid var(--pulse);
  outline-offset: -2px;
  border-color: var(--pulse);
  background: var(--card);
}
.ue td.is-num input { text-align: right; }

.ue td.is-loss-wash { background: var(--loss-wash); }
.ue td.is-loss-wash input { color: var(--loss); font-weight: 500; }
.ue td.is-gain-wash { background: var(--gain-wash); }
.ue td.is-gain-wash input { color: var(--gain); font-weight: 500; }

/* --- ABC-анализ: широкая таблица группами колонок, как лист «🔍 ABC» --- */

/* Двухрядная шапка: ряд групп — «полки» (как заголовки блоков РНП),
   ряд колонок — обычные подписи. Границы групп несут вертикальные линии. */
.abc thead .abc-g th {
  text-align: center;
  background: var(--well);
  font-size: var(--fs-caption);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  border-bottom: 0;
}
.abc thead .abc-g .c-m { background: var(--card); }
.abc .gs { border-left: 1px solid var(--rule-soft); }
.abc thead .abc-g th.gs { border-left: 1px solid var(--rule); }

/* Третий ярус шапки — подблок внутри группы («Расходы по самовыкупам»
   внутри «Рекламы»). Появляется только когда его колонки видны; группы без
   подблока растянуты на оба ряда, поэтому полосы пустых ячеек тут нет.
   Подпись не капсом: ярус ниже группы и не должен спорить с ней за внимание. */
.abc thead .abc-sub th {
  padding-top: 0;
  font-size: 12px;
  text-transform: none;
  letter-spacing: 0;
}
.abc thead .abc-sub th.is-sub {
  color: var(--ink-soft);
  background: var(--card);
  box-shadow: inset 0 -1px 0 var(--rule);
}

/* Подсказка «как считается» — пунктир под подписью. У колонок она на кнопке
   сортировки (правило ниже), у групп и подблоков — на своём span. */
.abc thead .has-tip { border-bottom: 1px dashed var(--rule); cursor: help; }

/* Липкая шапка (2026-08-11). Таблице дан СВОЙ скроллпорт по высоте — без него
   sticky липнуть некуда: контейнер уже прокручивается по горизонтали, и
   вертикальный sticky считается от него, а не от страницы. Это та же ловушка,
   из-за которой в РНП шапку пришлось клонировать; здесь она решается дешевле,
   потому что таблица одна на весь экран. Заодно горизонтальная полоса всегда
   под рукой, а тулбар и Парето не уезжают. */
/* Только потолок, без min-height: при коротком списке (включён фильтр по
   классу) он оставлял бы под последней строкой пустую полосу. */
.abc-scroll {
  overflow: auto;
  max-height: calc(100vh - 232px);
}

/* Плотные строки (выбор Артёма 2026-08-12, вариант «Г»). У ABC 68 колонок,
   и это единственное, что реально борется с шириной. Кегль ниже 12px
   не опускать — контраст 4.5:1 ещё держится, но читаемость уже на грани.
   Замеры и причина — DESIGN.md, здесь копии чисел нет намеренно: она уже
   разошлась однажды (5566 против 5320, замерено до сужения первой колонки).
   Базовый отступ приходит от `.rnp th, .rnp td` — таблица размечена
   как `class="rnp abc"`. */
.abc th, .abc td { padding: 3px 8px; font-size: 12px; }

/* Раздел отдан таблице целиком: карточка без отступов, высота — остаток
   окна вместо формулы. Общая часть и почему только шире 900px —
   `.layout-wide` в начале файла. */
@media (min-width: 901px) {
  .layout-wide #abc-pareto { flex: none; }
  .layout-wide #abc-pareto > .card { padding: var(--sp-2) var(--sp-4); }
  .layout-wide #abc-data { flex: 1; min-height: 0; display: flex; }
  .layout-wide #abc-data > .card {
    padding: 0;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
  .layout-wide .abc-scroll {
    max-height: none;
    flex: 1;
    min-height: 0;
    border-radius: var(--r-card);
  }
}
.abc thead { position: sticky; top: 0; z-index: 3; }
/* Фон обязателен всем трём ярусам: под ними едут строки. */
.abc thead th { background: var(--card); }
.abc thead .abc-g th { background: var(--well); }
.abc thead .abc-sub th.is-sub { background: var(--card); }
/* Угол «Артикул» — на пересечении липкой шапки и липкой первой колонки,
   поэтому z-index выше обоих. */
.abc thead .c-m, .abc thead .abc-cat { z-index: 4; }

.abc .c-m { width: 200px; min-width: 200px; }

.abc .abc-cat {
  text-align: left;
  color: var(--ink-mute);
  font-size: 13px;
}

/* Паспорт артикула: фото + код + бейджи класса и статуса */
.abc-item { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.abc .ava { width: 26px; height: 34px; }
.abc-name { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.abc-code {
  font-family: var(--font-mono);
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.abc-meta { display: flex; align-items: center; gap: 6px; }

.abc-cls {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--well);
  color: var(--ink-soft);
}
.abc-cls.is-top { background: var(--gain-wash); color: var(--gain); }
.abc-cls.is-low { background: var(--loss-wash); color: var(--loss); }

.abc-status { font-size: 10px; }
.abc-status.is-loss-w { color: var(--loss); }
.abc-status.is-gain-w { color: var(--gain); }
.abc-nocost { font-size: 10px; color: var(--ink-mute); border-bottom: 1px dashed var(--rule); }

/* Итог сверху; убыток — красным только там, где минус означает беду */
.abc .abc-total td { background: var(--well); }
.abc td.is-loss { color: var(--loss); }

/* Артикулы без движения за период — видны, но не звенят */
.abc tr.is-idle td { color: var(--ink-mute); }
.abc tr.is-idle .ava { opacity: 0.55; }
.abc tr.is-idle .abc-code { color: var(--ink-mute); }

.abc tr.abc-un td { color: var(--ink-mute); }

/* Тулбар: период живёт в общем календаре (.rng), здесь — попап порогов */
.abc-thr { position: relative; display: inline-flex; }
.abc-thr > .seg-btn { border: 1px solid var(--rule); border-radius: var(--r-ctl); }
.abc-thr-pop.is-hidden { display: none; }
.abc-thr-pop {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  background: var(--card);
  border-radius: var(--r-card);
  box-shadow: var(--lift), 0 12px 28px rgba(var(--ink-rgb), 0.12);
  white-space: nowrap;
}
.abc-thr-pop label { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--ink-soft); }
.abc-thr-pop input {
  width: 64px;
  padding: 5px 8px;
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  font: inherit;
  text-align: right;
  color: var(--ink);
}
.abc-thr-pop input:focus-visible { outline: 2px solid var(--pulse); outline-offset: -1px; }
.abc-thr-foot { display: flex; justify-content: flex-end; gap: var(--sp-2); }
.abc-thr-foot .seg-btn { border: 1px solid var(--rule); border-radius: var(--r-ctl); }

/* Парето-полоса: тот случай, где заливка и есть смысл блока (правило
   тепловой карты) — интенсивность одного тона по классам, не три цвета */
.abc-pareto { margin-bottom: var(--sp-4); }
.abc-pareto-head {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  font-size: var(--fs-caption);
  color: var(--ink-mute);
  margin-bottom: var(--sp-4);
}
.abc-pareto-legend { display: inline-flex; gap: var(--sp-2); align-items: baseline; }
.abc-pareto-legend b {
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--ink-soft);
  margin-left: var(--sp-2);
}
.pareto-bar { position: relative; height: 18px; margin-top: 4px; }
.pareto-track {
  display: flex;
  height: 100%;
  border-radius: 4px;
  overflow: hidden;
  background: var(--well);
}
.pareto-seg { display: block; height: 100%; min-width: 2px; }
.pareto-seg + .pareto-seg { border-left: 1px solid var(--card); }
.pareto-seg.cls-a { background: rgba(var(--heat), 0.45); }
.pareto-seg.cls-b { background: rgba(var(--heat), 0.24); }
.pareto-seg.cls-c { background: rgba(var(--heat), 0.11); }
.pareto-mark {
  position: absolute;
  top: -3px;
  bottom: -3px;
  width: 0;
  border-left: 1px dashed rgba(var(--ink-rgb), 0.4);
}
.pareto-mark i {
  position: absolute;
  top: -14px;
  left: -9px;
  font-size: 10px;
  font-style: normal;
  color: var(--ink-mute);
}

/* Строка «Не разложено по артикулам»: сумма и состав дублируются в
   закреплённой колонке — их колонки (Маржа, Ч. прибыль) уезжают вправо,
   и без этого строка читалась бы как пустая */
.abc-un-name { display: block; }
.abc-un-sum {
  margin-left: 6px;
  font-weight: 500;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}
.abc-un-note {
  display: block;
  margin-top: 1px;
  font-size: 10px;
  color: var(--ink-mute);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- Фильтр по классу ABC: матрица 3×3 (выручка × маржа) ---
   Класс двухбуквенный, и это две независимые оси. Плоский список из девяти
   галочек прятал бы главное — несовпадения («выручки много, маржи нет»),
   поэтому выбор идёт по раскладу, где эти клетки видно глазами. */

.seg-btn.is-filter-on {
  border-color: var(--pulse);
  color: var(--pulse);
  background: var(--pulse-wash);
  font-weight: 500;
}

.abc-cls-pop { min-width: 210px; }

.abc-mx-cap {
  font-size: 10px;
  color: var(--ink-mute);
  margin-bottom: var(--sp-2);
  max-width: 190px;
  white-space: normal;
  line-height: 1.35;
}

.abc-mx {
  display: grid;
  grid-template-columns: 22px repeat(3, 46px);
  gap: 3px;
  align-items: stretch;
}

.abc-mx-corner { display: block; }

.abc-mx-h,
.abc-mx-c {
  border: 1px solid transparent;
  border-radius: var(--r-ctl);
  background: none;
  font: inherit;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  padding: 4px 0;
}

/* Заголовки строк/столбцов — буквы: тише клеток, но кликабельны
   (берут всю линию одним нажатием) */
.abc-mx-h {
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--ink-mute);
}
.abc-mx-h:hover { color: var(--ink); background: var(--well); }
.abc-mx-h.is-on { color: var(--pulse); }

/* Клетка — число артикулов в классе */
.abc-mx-c {
  background: var(--well);
  color: var(--ink-soft);
  font-weight: 500;
}
.abc-mx-c:hover:not(:disabled) { background: var(--rule); color: var(--ink); }
.abc-mx-c.is-on {
  background: var(--pulse-wash);
  border-color: var(--pulse);
  color: var(--pulse);
}

/* Пустой класс выбирать нечего — гаснет, как прочерк в таблице */
.abc-mx-c.is-empty {
  background: none;
  color: var(--ink-ghost);
  cursor: default;
}

.abc-mx-h:focus-visible,
.abc-mx-c:focus-visible { outline: 2px solid var(--pulse); outline-offset: -2px; }

/* Подпись при «Итого»: сколько артикулов в итоге и по какому отбору */
.abc-total-note {
  display: block;
  margin-top: 1px;
  font-size: 10px;
  font-weight: 400;
  color: var(--ink-mute);
}

/* Выключенная кнопка сегмента («Показать все», когда фильтр и так пуст):
   должна читаться как недоступная, а не как обычная */
.seg-btn:disabled {
  color: var(--ink-ghost);
  cursor: default;
}

/* Заголовок колонки с пояснением: пунктир снизу — единственный намёк,
   что у названия есть расшифровка по наведению (как «нет С/С» в строке) */
.sort-btn.has-tip { border-bottom: 1px dashed var(--rule); }

/* --- Колонка «Куда уходит рубль»: структура выручки полосой ---
   Тот же случай, что тепловая карта: цвет здесь не фон к цифрам, а
   единственное содержимое колонки. Стоит последней, чтобы не разрывать
   ряды чисел (просьба пользователя 2026-08-07). */

.abc .c-str {
  width: 200px;
  min-width: 200px;
  text-align: left;
  padding-left: var(--sp-3);
}
.abc thead .c-str { text-align: left; }

.str { position: relative; display: block; }

.str-bar {
  display: flex;
  height: 14px;
  border-radius: 3px;
  overflow: hidden;
  background: var(--well);
}

/* Разделяет сегменты, не сдвигая их: зазор через тень внутрь, а не gap —
   иначе проценты перестали бы сходиться с шириной */
.str-bar i {
  display: block;
  height: 100%;
  box-shadow: inset -1px 0 0 var(--card);
}
.str-bar i:last-child { box-shadow: none; }

/* Граница выручки: видна только там, где полоса за неё вышла */
.str-tick {
  position: absolute;
  top: -3px;
  bottom: -3px;
  width: 2px;
  background: var(--ink);
}

.abc tbody tr:hover .str-bar i { box-shadow: inset -1px 0 0 var(--well); }

/* Подвал таблицы — одна строка (2026-08-12, просьба Артёма): легенда полосы,
   слово «Методика» с пояснениями по наводке и чистая прибыль кабинета.
   Раньше под таблицей лежали три абзаца текста на ~90px — на экране, отданном
   таблице, они забирали её высоту, а читают их редко. Прибыль кабинета из
   этого текста ВЫНЕСЕНА наружу: это единственное место, где она вообще есть,
   и прятать факт за наводку нельзя — прячем объяснения, не данные. */
.abc-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-4);
  padding: var(--sp-2) var(--sp-5) var(--sp-3);
}
.abc-foot-profit {
  margin-left: auto;
  font-size: var(--fs-caption);
  color: var(--ink-mute);
}
.abc-foot-profit b { color: var(--ink); }

/* Пояснения по наводке — компонент общий, к ABC не привязан.
   Кнопка, а не span: до подсказки надо добираться и с клавиатуры, поэтому
   раскрытие держится на :focus-within, а не на одном :hover. Роль tooltip
   и aria-describedby, а НЕ aria-expanded: показ живёт в CSS, и атрибут
   состояния, который никто не переключает, врал бы скринридеру. */
.notepop { position: relative; display: inline-flex; }

.notepop-btn {
  padding: 0;
  border: 0;
  border-bottom: 1px dashed var(--rule);
  background: none;
  font: inherit;
  font-size: var(--fs-caption);
  color: var(--ink-soft);
  cursor: help;
}
.notepop-btn:hover {
  color: var(--pulse-deep);
  border-bottom-color: var(--pulse);
}
.notepop-btn:focus-visible {
  outline: 2px solid var(--pulse);
  outline-offset: 3px;
  border-radius: 3px;
}

/* Открывается ВВЕРХ: подвал таблицы и так у нижнего края окна */
.notepop-body {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 0;
  z-index: 60;
  width: max-content;
  max-width: min(720px, calc(100vw - 220px));
  padding: var(--sp-3) var(--sp-4);
  background: var(--card);
  border-radius: var(--r-card);
  box-shadow: 0 10px 28px rgba(var(--ink-rgb), 0.16), var(--lift);
  font-size: var(--fs-caption);
  line-height: 1.5;
  color: var(--ink-mute);
  opacity: 0;
  visibility: hidden;
  transform: translateY(4px);
  transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;
}
.notepop-body p { margin: 0; }
.notepop-body p + p { margin-top: var(--sp-2); }

.notepop:hover .notepop-body,
.notepop:focus-within .notepop-body {
  opacity: 1;
  visibility: visible;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .notepop-body { transition: none; }
}

/* Легенда полосы — под таблицей, рядом с остальными пояснениями */
.str-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-3);
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--ink-mute);
}
.str-legend span { display: inline-flex; align-items: center; gap: 5px; }
.str-legend i {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  display: block;
}

/* Хвост полосы за границей выручки — расходы, которые товар не окупил */
.str-over {
  position: absolute;
  right: 0;
  bottom: -3px;
  height: 2px;
  background: var(--loss);
  border-radius: 1px;
}

/* ===== Самовыкупы: журнал, грид ввода, массовая правка ===== */

.sb-card { padding: var(--sp-4) 0 var(--sp-2); }
.sb-pad { padding: 0 var(--sp-5) var(--sp-2); }
.sb-gap { flex: 1; }
.row-wrap { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }

.sb-sel {
  font: inherit;
  font-size: var(--fs-body);
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  padding: 4px 8px;
}
.btn-mini { padding: 4px 9px; font-size: var(--fs-caption); }

/* Сводка: та же типографика, что у плиток дашборда */
.sb-totals {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  flex-wrap: wrap;
  padding: 0 var(--sp-5) var(--sp-4);
}
.sb-totals .kpi { display: flex; flex-direction: column; gap: 1px; }
.sb-totals .kpi .l {
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.sb-totals .kpi .v {
  font-family: var(--font-mono);
  font-size: var(--fs-h3);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.sb-totals .kpi .v.is-bad { color: var(--loss); }

.sb-stat {
  font-size: var(--fs-caption);
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.sb-stat::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 2px;
  background: currentColor;
}
.sb-stat.is-buy { color: var(--gain); }
.sb-stat.is-ord { color: var(--pulse); }
.sb-stat.is-warn { color: var(--warn); }
.sb-stat.is-err { color: var(--loss); }

.sb-scroll { overflow: auto; max-height: 68vh; }

.sb-table { border-collapse: collapse; width: 100%; font-size: var(--fs-body); }
.sb-table th, .sb-table td {
  padding: 6px var(--sp-3);
  text-align: left;
  white-space: nowrap;
  border-bottom: 1px solid var(--rule-soft);
}
.sb-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--card);
  font-size: var(--fs-caption);
  font-weight: 500;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-mute);
  border-bottom: 1px solid var(--rule);
}
.sb-table tbody tr:hover { background: var(--well); }
.sb-table tbody tr.is-err { background: var(--loss-wash); }
.sb-table .is-num { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.sb-table .c-date, .sb-table .c-id { font-family: var(--font-mono); }
/* Номер выкупа — данные, а не прочерк: по нему ищут строку в гугл-таблице.
   Был --ink-ghost на 1704 строках при 1.9:1 (аудит 2026-08-13). */
.sb-table .sb-id { font-family: var(--font-mono); font-size: var(--fs-caption); color: var(--ink-mute); }
.sb-table .sb-q { max-width: 220px; overflow: hidden; text-overflow: ellipsis; color: var(--ink-soft); }
.sb-none { color: var(--ink-ghost); }
.sb-act { text-align: right; }
.sb-ok { color: var(--gain); }
.sb-warn { color: var(--warn); }
.sb-err { color: var(--loss); }

.sb-chip {
  font-size: 10.5px;
  padding: 1px 7px;
  border-radius: 999px;
  white-space: nowrap;
}
.sb-chip.is-ord { background: var(--pulse-wash); color: var(--pulse); }
.sb-chip.is-buy { background: var(--gain-wash); color: var(--gain); }
.sb-chip.is-bad { background: var(--loss-wash); color: var(--loss); }

.sb-foot {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5) var(--sp-2);
  border-top: 1px solid var(--rule-soft);
}

/* Журнал заперт: правки идут в гугл-таблице. Это «посмотри», а не ошибка,
   поэтому --warn пунктиром, как бейдж «не закрыт» в ОПиУ. */
.sb-locked {
  margin: 0 0 var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  border: 1px dashed var(--warn);
  border-radius: var(--r-card);
  background: var(--warn-wash);
  color: var(--ink-soft);
  font-size: var(--fs-caption);
  line-height: 1.45;
}

/* Ссылка на таблицу — прямо в окне: своей страницы настроек у раздела нет,
   а заводить её ради одного поля незачем */
.sb-link-form {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--sp-2) var(--sp-3);
  align-items: end;
  padding: var(--sp-3) var(--sp-5) var(--sp-4);
  border-top: 1px solid var(--rule-soft);
}
.sb-link-form label {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: var(--fs-caption);
  color: var(--ink-mute);
}
.sb-link-form input {
  padding: 7px var(--sp-3);
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  background: var(--well);
  font: inherit;
  font-size: var(--fs-body);
  color: var(--ink);
}
.sb-link-form input:focus-visible {
  outline: 2px solid var(--pulse);
  outline-offset: 1px;
  border-color: var(--pulse);
  background: var(--card);
}
.sb-link-form p { grid-column: 1 / -1; margin: 0; line-height: 1.45; }


/* Правка одной строки */
.sb-edit { width: min(440px, 100vw); }
.sb-edit-body { display: flex; flex-direction: column; gap: var(--sp-3); }
.sb-fld { display: flex; flex-direction: column; gap: 3px; }
.sb-fld > span { font-size: var(--fs-caption); color: var(--ink-mute); }
.sb-fld input, .sb-fld select {
  font: inherit;
  padding: 6px 9px;
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  background: var(--card);
  color: var(--ink);
}

.sb-flash {
  margin-bottom: var(--sp-3);
  padding: 8px var(--sp-4);
  border-radius: var(--r-ctl);
  background: var(--gain-wash);
  color: var(--gain);
  font-size: var(--fs-body);
}

/* Сверка загруженного файла: блоки «что изменится» и «что удалится» */
.sb-block { border-top: 1px solid var(--rule-soft); }
.sb-block-h {
  padding: var(--sp-3) var(--sp-5) var(--sp-2);
  font-size: var(--fs-caption);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.sb-block-h.sb-err { color: var(--loss); }
.sb-diff { display: inline-block; margin-right: var(--sp-3); white-space: nowrap; }
.sb-diff s { color: var(--ink-mute); }
.sb-diff b { font-weight: 500; }
.sb-table td.sb-q { white-space: normal; }

/* Окно «Файл таблицы»: скачать, загрузить, история версий */
/* .drawer-backdrop сам по себе не флекс — он подложка для выезжающей
   панели, которая позиционируется fixed. Окну нужен флекс, иначе оно
   ложится в левый верхний угол. */
/* z-index выше сайдбара (60): у подложки drawer'а он 40, и 64-пиксельная
   полоска сайдбара накрывала левый край окна — на узком экране оно выглядело
   сдвинутым, хотя было отцентровано. */
.sb-modal-back {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-5);
  z-index: 70;
}
/* Шапка окна: у .drawer-head своих отступов нет — он рассчитан на выезжающую
   панель с общим padding'ом, а у окна padding нулевой (иначе прокрутка тела
   отрезала бы края). Без этой строки заголовок лежал вплотную к краю. */
.sb-modal .drawer-head { padding: var(--sp-4) var(--sp-5) 0; }

/* Крестик окна — крупнее общего .chip-x: в модальном окне это единственный
   способ выйти мышью, и попадать в него должно быть легко. */
.sb-modal .drawer-close {
  font-size: 26px;
  line-height: 1;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: var(--r-ctl);
  margin: -6px -8px -6px 0;
}
.sb-modal .drawer-close:hover { background: var(--well); color: var(--loss); }

.sb-modal {
  background: var(--card);
  border-radius: var(--r-card);
  box-shadow: var(--lift), 0 24px 60px rgba(var(--ink-rgb), 0.18);
  width: min(920px, calc(100vw - 48px));
  max-height: calc(100vh - 64px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.sb-modal-body {
  padding: var(--sp-4) 0 var(--sp-2);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.sb-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
  padding: 0 var(--sp-5);
}
@media (max-width: 640px) { .sb-actions { grid-template-columns: 1fr; } }
.sb-action {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  text-align: left;
  padding: var(--sp-4);
  line-height: 1.4;
}
.sb-action b { font-size: var(--fs-h4); font-weight: 600; }
.sb-action .empty-note, .sb-action span { font-size: var(--fs-caption); }
.sb-action.btn-primary span { color: rgba(255, 255, 255, 0.85); }
a.sb-action { text-decoration: none; }
.sb-action:disabled { opacity: 0.5; cursor: not-allowed; }
/* Пояснение в окне — по тем же полям, что и кнопки над ним */
.pnl-modal-note { padding: 0 var(--sp-5); margin: 0; line-height: 1.5; }

.sb-versions { border-top: 1px solid var(--rule-soft); }
.sb-versions-h {
  padding: var(--sp-4) var(--sp-5) var(--sp-2);
  font-size: var(--fs-caption);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.sb-vchanges { font-family: var(--font-mono); white-space: nowrap; }
.sb-vchanges span { margin-right: 6px; }
.sb-act a.btn-mini { text-decoration: none; display: inline-block; }

/* Комментарий к версии — пишется в момент применения */
.sb-comment {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: var(--sp-3) var(--sp-5) 0;
}
.sb-comment > span:first-child { font-size: var(--fs-caption); color: var(--ink-mute); }
.sb-comment input {
  font: inherit;
  padding: 8px 11px;
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  background: var(--card);
  color: var(--ink);
  max-width: 640px;
}
.sb-comment input:focus { outline: 2px solid var(--pulse); outline-offset: 1px; }

/* ===== Выбор периода: одно окно-календарь (компонент _range.js) =====
   Кнопка с текущим отрезком + попап: слева месяцы вертикальной прокруткой,
   справа пресеты, поля дат и «Показать». Отрезок — полоса --pulse-wash,
   концы — заливка --pulse: те же роли цвета, что у «сегодня» и активных
   кнопок, календарь не заводит своей палитры. */

.rng { position: relative; display: inline-block; }

.rng-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-variant-numeric: tabular-nums;
}
.rng-btn svg { color: var(--ink-mute); flex: none; }

.rng-pop {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 45; /* выше липких шапок таблиц (40), ниже сайдбара (60) */
  display: flex;
  gap: var(--sp-4);
  padding: var(--sp-4);
  background: var(--card);
  border-radius: var(--r-card);
  box-shadow: var(--lift), 0 12px 28px rgba(var(--ink-rgb), 0.12);
}
/* Специфичность выше глобального .is-hidden: у .rng-pop свой display */
.rng-pop.is-hidden { display: none; }
.rng-pop.is-right { left: auto; right: 0; }

/* Календарь: месяцы столбиком, заголовок месяца липнет при прокрутке */
.rng-cal {
  width: 246px;
  max-height: 322px;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-right: var(--sp-1);
}
.rng-mon-t {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: var(--sp-1) var(--sp-1) 3px;
  background: var(--card);
  font-size: 13px;
  font-weight: 600;
}
.rng-grid { display: grid; grid-template-columns: repeat(7, 1fr); }
.rng-dow { padding-bottom: 2px; }
.rng-dow span {
  text-align: center;
  font-size: var(--fs-caption);
  color: var(--ink-mute);
}
.rng-d {
  position: relative;
  border: 0;
  background: none;
  font: inherit;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  height: 30px;
  border-radius: var(--r-ctl);
  cursor: pointer;
}
.rng-d:hover:not(:disabled) { background: var(--well); }
.rng-d:disabled { color: var(--ink-ghost); cursor: default; }
.rng-d:focus-visible { outline: 2px solid var(--pulse); outline-offset: -2px; }
/* Точка под сегодняшним числом — от него считаются пресеты */
.rng-d.is-today::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 3px;
  width: 4px;
  height: 4px;
  margin-left: -2px;
  border-radius: 50%;
  background: var(--pulse);
}
/* Полоса отрезка сплошная (без скруглений), концы — заливкой акцента */
.rng-d.is-in { background: var(--pulse-wash); border-radius: 0; }
.rng-d.is-in:hover:not(:disabled) { background: rgba(var(--pulse-rgb), 0.14); }
.rng-d.is-edge {
  background: var(--pulse);
  color: var(--on-pulse);
  border-radius: var(--r-ctl);
  font-weight: 500;
}
.rng-d.is-edge:hover:not(:disabled) { background: var(--pulse-deep); }
.rng-d.is-edge.is-today::after { background: var(--on-pulse); }

/* Правая колонка: пресеты, поля, кнопки */
.rng-side {
  width: 168px;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.rng-pres {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-bottom: var(--sp-1);
}
.rng-pre {
  border: 0;
  background: none;
  font: inherit;
  text-align: left;
  padding: 6px 10px;
  border-radius: var(--r-ctl);
  color: var(--ink-soft);
  cursor: pointer;
}
.rng-pre:hover { background: var(--well); color: var(--ink); }
.rng-pre.is-active { background: var(--pulse-wash); color: var(--pulse); font-weight: 500; }
.rng-pre:focus-visible { outline: 2px solid var(--pulse); outline-offset: -2px; }

.rng-f {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: var(--fs-caption);
  color: var(--ink-mute);
}
.rng-inp {
  font: inherit;
  font-variant-numeric: tabular-nums;
  width: 100%;
  padding: 6px 9px;
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  background: var(--well);
  color: var(--ink);
}
.rng-inp:focus-visible { outline: 2px solid var(--pulse); outline-offset: -1px; }
.rng-inp.is-invalid { border-color: var(--loss); outline-color: var(--loss); }

.rng-foot {
  margin-top: auto;
  display: flex;
  gap: var(--sp-2);
  padding-top: var(--sp-2);
}
.rng-foot .btn { flex: 1; text-align: center; }
.rng-apply:disabled { opacity: 0.45; cursor: default; }
.rng-apply:disabled:hover { background: var(--pulse); }

/* Пальцевые экраны: клетка держит правило 44px */
@media (pointer: coarse) {
  .rng-d { height: 44px; }
  .rng-cal { width: 288px; max-height: 356px; }
}

/* Узкий экран: колонки в столбик, попап не шире окна */
@media (max-width: 560px) {
  .rng-pop {
    flex-direction: column;
    width: min(320px, calc(100vw - 24px));
  }
  .rng-cal { width: 100%; max-height: 264px; }
  .rng-side { width: 100%; }
  .rng-pres { flex-direction: row; flex-wrap: wrap; }
}

/* ===== ОПиУ: месячный P&L =====
   Раскладка и палитра утверждены на мокапах 2026-08-11 (вариант «В3»):
   доля % второй строчкой под суммой, заливки строк — токены --pnl-*
   (дословно палитра референс-гугл-таблицы). Липкая шапка — тем же приёмом,
   что .abc-scroll: скролл-контейнер с max-height + sticky thead. */

/* Отступы карточки раздела: раньше стояли инлайном из pnl.js, но на отчёте
   их снимает layout-wide, а инлайн-стиль перебить нечем, кроме !important */
.pnl-card { padding: var(--sp-4) var(--sp-4) var(--sp-3); }

.pnl-scroll { overflow: auto; max-height: calc(100vh - 216px); }

/* Отчёт отдан таблице целиком (выбор Артёма 2026-08-12, вариант «В»);
   общая часть и почему только шире 900px — `.layout-wide` в начале файла.
   Журнал и настройки живут по своим адресам и этого не получают:
   там формы, а не одна таблица. */
@media (min-width: 901px) {
  .layout-wide #pnl-body {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
  .layout-wide .pnl-scroll {
    max-height: none;
    flex: 1;
    min-height: 0;
    border-radius: var(--r-card);
  }
}

.pnl {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  font-variant-numeric: tabular-nums;
}

.pnl th, .pnl td { padding: 6px 12px; white-space: nowrap; font-weight: 400; }

.pnl thead th {
  position: sticky;
  top: 0;
  background: var(--card);
  z-index: 20;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink-mute);
  text-align: right;
  border-bottom: 1px solid var(--rule);
  padding-bottom: 7px;
}

.pnl td {
  text-align: right;
  border-bottom: 1px solid var(--rule-soft);
  font-size: 13.5px;
  line-height: 1.25;
}

/* Первая колонка липкая; фон обязан совпадать с фоном строки, поэтому
   у каждой цветной строки ниже свой фон прописан и для первой ячейки */
.pnl td:first-child, .pnl thead th:first-child {
  position: sticky;
  left: 0;
  background: var(--card);
  z-index: 10;
  text-align: left;
  min-width: 265px;
  box-shadow: inset -1px 0 var(--rule-soft);
}
.pnl thead th:first-child { z-index: 25; }

.pnl-share { display: block; color: var(--ink-mute); font-size: 11px; line-height: 1.15; }
.pnl .is-gain { color: var(--gain); }
.pnl .is-ghost { color: var(--ink-ghost); }
/* Прочерк на цветной полосе. Заливки ОПиУ светлые, и призрачный серый
   на них растворяется совсем: 1.29:1 на розовой полке расходов, 1.18:1
   на серой «Маржинальности» (аудит 2026-08-13). Тёмная полоса —
   исключение: там тот же серый светлее фона и даёт 6.8:1 сам по себе. */
.pnl tr.r-shelf .is-ghost,
.pnl tr.r-loss .is-ghost,
.pnl tr.r-g1 .is-ghost,
.pnl tr.r-g2 .is-ghost,
.pnl tr.r-g3 .is-ghost,
.pnl tr.r-pct .is-ghost,
.pnl tr.r-peach .is-ghost { color: var(--ink-ghost-band); }

/* Бейдж «не закрыт» у текущего месяца в шапке */
.pnl-open-badge {
  display: block;
  font-size: 10px;
  font-weight: 400;
  color: var(--warn);
  border-bottom: 1px dashed var(--warn);
  cursor: help;
  width: fit-content;
  margin-left: auto;
}
/* Месяц, который ещё не наступил: тише прошедших, но это заголовок
   колонки (был --ink-ghost, 1.9:1 — аудит 2026-08-13) */
.pnl thead th.is-future { color: var(--ink-mute); }

/* Колонка «Итог за год» */
.pnl th.pnl-ytd, .pnl td.pnl-ytd { border-left: 2px solid var(--rule); }
.pnl td.pnl-ytd { background: rgba(var(--ink-rgb), 0.015); font-weight: 600; }

/* Недельные куски раскрытого месяца (2026-08-13). Ячейки недель отличает
   полупрозрачная плёнка ПОВЕРХ фона строки (background-image, не подмена
   background: фоны заняты палитрой --pnl-*); на тёмной строке выручки плёнка
   не видна — колонку там держат шапка и граница пачки. Конец пачки недель
   перед следующим месяцем — вертикаль потолще, как .gs в ABC. */
.pnl td.is-week, .pnl thead th.is-week {
  background-image: linear-gradient(rgba(var(--ink-rgb), 0.03), rgba(var(--ink-rgb), 0.03));
}
.pnl thead th.is-week { background-color: var(--well); font-weight: 500; }
.pnl th.is-wk-last, .pnl td.is-wk-last { border-right: 2px solid var(--rule); }
.pnl thead th.pnl-th-m { cursor: pointer; }
.pnl thead th.pnl-th-m.is-m-open { background-color: var(--well); }
.pnl-wk-sub {
  display: block;
  font-size: 10px;
  font-weight: 400;
  color: var(--ink-mute);
  line-height: 1.2;
}

/* Ярусы строк */
.pnl tr.r-hero td { font-weight: 600; font-size: 14px; }
.pnl tr.r-soft td, .pnl tr.r-soft td:first-child { color: var(--ink-soft); font-size: 12.5px; }
.pnl tr.r-shelf td, .pnl tr.r-shelf td:first-child { background: var(--well); font-weight: 600; }
.pnl tr.r-sub td { color: var(--ink-soft); font-size: 12.5px; border-bottom-style: dotted; }
.pnl tr.r-sub td:first-child { padding-left: 30px; color: var(--ink-soft); }
.pnl tr.r-sub td:first-child.is-deep { padding-left: 46px; }

/* Цветные строки (палитра референса, tokens.css --pnl-*). Селекторы включают
   первую ячейку: она липкая и несёт собственный фон. */
.pnl tr.r-dark td, .pnl tr.r-dark td:first-child {
  background: var(--pnl-dark);
  color: var(--pnl-on-dark);
  border-bottom-color: transparent;
}
.pnl tr.r-dark .pnl-share { color: var(--pnl-on-dark-soft); }
.pnl tr.r-loss td, .pnl tr.r-loss td:first-child { background: var(--pnl-loss); }
.pnl tr.r-g1 td, .pnl tr.r-g1 td:first-child { background: var(--pnl-g1); }
.pnl tr.r-g2 td, .pnl tr.r-g2 td:first-child { background: var(--pnl-g2); }
.pnl tr.r-g3 td, .pnl tr.r-g3 td:first-child { background: var(--pnl-g3); }
.pnl tr.r-pct td, .pnl tr.r-pct td:first-child { background: var(--pnl-pct); color: var(--ink); }
.pnl tr.r-peach td, .pnl tr.r-peach td:first-child { background: var(--pnl-peach); color: var(--ink); }
/* Доли на цветных заливках должны читаться чернилами, а не серым */
.pnl tr.r-loss .pnl-share, .pnl tr.r-g1 .pnl-share, .pnl tr.r-g2 .pnl-share,
.pnl tr.r-g3 .pnl-share, .pnl tr.r-pct .pnl-share, .pnl tr.r-peach .pnl-share {
  color: var(--ink-soft);
}

/* Раскрытия ▸/▾ */
.pnl .pnl-caret {
  display: inline-block;
  width: 14px;
  color: var(--ink-mute);
  cursor: pointer;
  user-select: none;
}
.pnl tr.r-dark .pnl-caret, .pnl tr.r-shelf .pnl-caret { color: inherit; }

/* Раскрывающаяся строка (2026-08-12): кликом ловится вся полоса — целиться
   в стрелку шириной 14px было мелко. Название при этом настоящая кнопка,
   иначе блок недостижим с клавиатуры (DESIGN.md → «Сворачивание — всегда
   кнопка»). Кнопка внешне неотличима от текста строки: она и есть текст. */
.pnl tr.is-open-row { cursor: pointer; }

.pnl-open-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  border: 0;
  padding: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
/* Раскрытие месяца — 17px в высоту; площадка попадания растёт до 24px,
   не трогая высоту шапки отчёта (WCAG 2.5.8, аудит 2026-08-13) */
.pnl-open-btn::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  min-width: 24px;
  height: 24px;
}
.pnl-open-btn:focus-visible {
  outline: 2px solid var(--pulse);
  outline-offset: 2px;
  border-radius: 4px;
}
/* Подсказка внутри кликабельной строки не должна обещать «только справка» */
.pnl-open-btn .has-tip { cursor: pointer; }

/* Подсветка наведения — тонкая плёнка поверх собственного фона строки:
   у полок он свой (розовый --pnl-loss), и подменять его нельзя.
   У первой ячейки к плёнке добавлена её же граница липкой колонки. */
.pnl tr.is-open-row:hover > td {
  box-shadow: inset 0 0 0 999px rgba(var(--ink-rgb), 0.04);
}
.pnl tr.is-open-row:hover > td:first-child {
  box-shadow: inset -1px 0 var(--rule-soft), inset 0 0 0 999px rgba(var(--ink-rgb), 0.04);
}

/* Подсказки-формулы: как в ABC — пунктир под подписью */
.pnl .has-tip { border-bottom: 1px dashed var(--rule); cursor: help; }
.pnl tr.r-dark .has-tip { border-bottom-color: var(--pnl-on-dark-soft); }

/* Строка сверки охвата и подписи под таблицей */
.pnl-foot { padding: 10px 4px 0; color: var(--ink-mute); font-size: 12px; }
.pnl-foot .is-ok { color: var(--gain); }
.pnl-foot .is-warn { color: var(--warn); }

/* --- Формы журнала и настроек --- */

.pnl-tabs { display: flex; gap: var(--sp-2); }

/* Валюта — настоящий сегментированный контрол: две кнопки в общей рамке.
   Без неё они читались как два отдельных слова рядом с полем. */
.pnl-seg {
  gap: 0;
  align-self: flex-start;   /* не растягиваться на всю ширину подписи */
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  overflow: hidden;
  background: var(--card);
}
.pnl-seg .seg-btn { padding: 6px 12px; }

.pnl-form {
  display: flex;
  gap: var(--sp-2);
  align-items: flex-end;
  flex-wrap: wrap;
  padding: var(--sp-3) 0 var(--sp-4);
}

.pnl-form label {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: var(--fs-caption);
  color: var(--ink-mute);
}

.pnl-form input, .pnl-form select {
  padding: 6px 9px;
  border: 1px solid var(--rule);
  border-radius: var(--r-ctl);
  background: var(--card);
  font: inherit;
  color: var(--ink);
  min-width: 0;
}
.pnl-form input:focus-visible, .pnl-form select:focus-visible {
  outline: 2px solid var(--pulse);
  outline-offset: 1px;
}
.pnl-form .w-date { width: 130px; }
.pnl-form .w-sum { width: 110px; }
.pnl-form .w-cat { width: 220px; }
.pnl-form .w-acc { width: 152px; }
.pnl-form .w-note { width: 240px; }
.pnl-form .w-url { width: min(420px, 60vw); }

/* Форма ввода — собранный блок, а не поля вразброс по белому (просьба
   2026-08-12 про статьи, распространено на все формы раздела: они одного
   рода). Плотнее и «мягче»: подложка --well, поля белые, углы карточные. */
.pnl-add {
  padding: var(--sp-3) var(--sp-4);
  background: var(--well);
  border-radius: var(--r-card);
}
.pnl-add + .pnl-hint { margin-top: var(--sp-2); }

/* Галочка стоит в строку с подписью, а не подписью сверху: у остальных полей
   подпись объясняет, что вводить, а здесь она и есть значение. */
.pnl-form .pnl-check {
  flex-direction: row;
  align-items: center;
  gap: var(--sp-2);
  padding-bottom: 6px;
  font-size: 13px;
  color: var(--ink-soft);
  cursor: pointer;
  white-space: nowrap;
}
.pnl-form .pnl-check input {
  width: 16px;
  height: 16px;
  accent-color: var(--pulse);
  cursor: pointer;
}

/* Подпись под формой: объяснение правила, а не подпись поля */
.pnl-hint { max-width: 760px; margin: var(--sp-2) 0 0; font-size: var(--fs-caption); line-height: 1.5; }

/* Настройки раздела: три блока в столбик, каждый со своей шапкой */
.pnl-set { display: flex; flex-direction: column; gap: var(--sp-6); padding-top: var(--sp-2); }
.pnl-set-h {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

/* Таблица журнала и статей — обычная плотная таблица */
.pnl-list { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; }
.pnl-list th {
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--ink-mute);
  text-align: left;
  padding: 4px 10px 6px;
  border-bottom: 1px solid var(--rule);
}
.pnl-list td { padding: 5px 10px; border-bottom: 1px solid var(--rule-soft); font-size: 13px; }
.pnl-list td.is-num, .pnl-list th.is-num { text-align: right; }
/* «Править» и «Удалить» в строке журнала: 21×20 и 16×20 не дотягивали
   до 24×24 (WCAG 2.5.8, аудит 2026-08-13). Строка журнала высотой 31px —
   квадрат помещается, ряд не растёт. */
.pnl-list .row-x,
.pnl-list .row-edit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: 0;
  background: none;
  color: var(--ink-mute);
  cursor: pointer;
  font: inherit;
  padding: 0;
}
.pnl-list .row-x:hover { color: var(--loss); }
.pnl-list .row-edit:hover { color: var(--pulse); }
.pnl-list tr.is-editing td { background: var(--pulse-wash); }
/* Статья вне P&L: в отчёте её нет вовсе, и в справочнике она должна читаться
   как выключенная, а не как обычная строка. Гасим, но не прячем — платежи по
   ней заводятся по-прежнему. */
.pnl-list tr.is-off td { opacity: 0.55; }
.pnl-list tr.is-off td:has(input[data-f="inPnl"]) { opacity: 1; }
.pnl-status { font-size: var(--fs-caption); color: var(--ink-mute); min-height: 16px; }
.pnl-status.is-error { color: var(--loss); }

/* Журнал длинный (тысячи строк) — прокручивается внутри карточки,
   шапка при этом липнет: иначе к сотой строке непонятно, где какая колонка */
.pnl-jscroll { max-height: calc(100vh - 330px); overflow: auto; }
/* Строка журнала — в одну строку: перенос в «Кабинете» и «Сумме» растягивал
   её на три яруса, и на экран влезало вчетверо меньше платежей. Ширину даёт
   горизонтальная прокрутка, она у контейнера уже есть. */
.pnl-jscroll th, .pnl-jscroll td { white-space: nowrap; }
.pnl-jscroll thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--card);
}
/* Приход в журнале — зелёным; расход остаётся чернилами. Красить обе стороны
   значило бы красить весь столбец: расходов там подавляющее большинство. */
.pnl-list .is-gain { color: var(--gain); }

/* Справочник статей: редактируемая таблица по образцу юнит-экономики —
   «тихие» инпуты, граница появляется при наведении и фокусе. До 2026-08-12
   поля здесь вообще не имели стилей и выглядели браузерными коробками. */
.pnl-cats-scroll { max-height: min(58vh, 640px); overflow: auto; }
.pnl-cats { table-layout: fixed; max-width: 940px; }
.pnl-cats thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--card);
}
.pnl-cats th, .pnl-cats td { padding: 2px 6px; }
.pnl-cats th { padding-bottom: 6px; }
.pnl-cats th:nth-child(1) { width: 34%; }
.pnl-cats th:nth-child(2) { width: 28%; }
.pnl-cats th:nth-child(3) { width: 104px; }
.pnl-cats th:nth-child(4) { width: 72px; }
.pnl-cats th:nth-child(5) { width: 84px; }
.pnl-cats th:nth-child(6) { width: 38px; }
.pnl-cats th.is-mid, .pnl-cats td.is-mid { text-align: center; }

.pnl-cats td input:not([type="checkbox"]) {
  width: 100%;
  padding: 5px 8px;
  border: 1px solid transparent;
  border-radius: var(--r-ctl);
  background: none;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
}
.pnl-cats td input:not([type="checkbox"]):hover { border-color: var(--rule); }
.pnl-cats td input:not([type="checkbox"]):focus-visible {
  outline: 2px solid var(--pulse);
  outline-offset: -2px;
  border-color: var(--pulse);
  background: var(--card);
}
.pnl-cats input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--pulse);
  cursor: pointer;
}

/* Узкий экран: первая колонка не должна съедать всю ширину — сузить
   и разрешить перенос длинных названий статей */
@media (max-width: 720px) {
  .pnl td:first-child, .pnl thead th:first-child { min-width: 158px; max-width: 190px; white-space: normal; }
  .pnl th, .pnl td { padding: 6px 8px; }

  /* Формы в столбик: заданные ширины полей (в ряду они держат ритм) на узком
     экране оставляли рваный правый край. Перечисляем классы ширин поимённо —
     у них та же специфичность, и общим правилом их не перебить. */
  .pnl-form label { flex: 1 1 100%; }
  .pnl-form .pnl-check { flex: 0 0 auto; }
  .pnl-form .w-date, .pnl-form .w-sum, .pnl-form .w-cat,
  .pnl-form .w-acc, .pnl-form .w-note, .pnl-form .w-url { width: 100%; }
  .pnl-jscroll { max-height: none; }
}

/* Строка с ошибкой в предпросмотре загруженного файла (журнал расходов).
   Классы .sb-* исторические — они обслуживают обе таблицы-журнала,
   самовыкупы и расходы ОПиУ: у них одинаковая работа файлом. */
.pnl-list tr.is-err td { background: var(--loss-wash); }
.pnl-list a.row-edit { text-decoration: none; }
