/* ============================================================================
   СИСТЕМА УПРАВЛЕНИЯ — визуальный язык «Ink & Signal»
   ----------------------------------------------------------------------------
   Три слоя токенов: примитивы → семантика → компоненты.
   Менять палитру только в слоях 1–2, по месту не переопределять.
   ============================================================================ */

/* ---------------------------------------------------------------------------
   СЛОЙ 1. ПРИМИТИВЫ — сырые значения, без смысла
   --------------------------------------------------------------------------- */
:root {
  /* нейтральные: тёплая бумага, а не холодный серый — от этого весь характер */
  --n-0:   #ffffff;
  --n-25:  #faf9f6;
  --n-50:  #f4f3ef;
  --n-100: #edece6;
  --n-150: #e4e2da;
  --n-200: #d8d5cb;
  --n-300: #bdb9ad;
  --n-400: #8e8b81;
  --n-500: #6c6a63;
  --n-600: #4d4c47;
  --n-700: #33332f;
  --n-800: #1f1f1d;
  --n-850: #17171a;
  --n-900: #111114;
  --n-950: #0a0a0c;

  /* графит для рельса и тёмной темы — чуть синее нейтралей, чтобы не «грязнил» */
  --g-900: #0b0c0f;
  --g-850: #101114;
  --g-800: #16181c;
  --g-750: #1c1f24;
  --g-700: #24272d;
  --g-600: #31353d;
  --g-500: #4a4f59;
  --g-400: #767c88;
  --g-300: #9aa0aa;
  --g-200: #c3c7cf;
  --g-100: #e3e5e9;

  /* сигнальный ирис — единственный «фирменный» цвет */
  --iris-100: #eceafb;
  --iris-200: #d6d2f6;
  --iris-400: #7c74e8;
  --iris-500: #5b53d3;
  --iris-600: #4a42bf;
  --iris-700: #3b3499;
  --iris-dim:  #221f45;

  /* статусные */
  --green-500: #1f8f5a;  --green-400: #45c088;  --green-tint: #e4f4ea;  --green-dim: #0f2a1e;
  --amber-500: #b06b12;  --amber-400: #e0a137;  --amber-tint: #f8efdd;  --amber-dim: #2c2110;
  --red-500:   #c3382e;  --red-400:   #ee6a5f;  --red-tint:   #fbe8e6;  --red-dim:   #2e1614;
  /* бирюза — только сообщения: не путается ни с ирисом, ни со сроками */
  --teal-500:  #0d7f8c;  --teal-400:  #38c6d6;  --teal-tint:  #dcf3f6;  --teal-dim:  #072a30;

  /* шаг сетки — плотный дашборд */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 20px; --s-6: 24px; --s-8: 32px; --s-10: 40px; --s-12: 48px;

  /* радиусы — намеренно тесные, «крупные скругления» и есть шаблонность */
  --r-xs: 5px; --r-sm: 7px; --r: 9px; --r-md: 12px; --r-lg: 16px; --r-pill: 999px;
  /* совместимость со старой разметкой */
  --r-lg-legacy: 16px;

  --font-sans: 'Onest', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;

  --ease: cubic-bezier(.2,.8,.3,1);
  --ease-out: cubic-bezier(.16,1,.3,1);
  --dur: .16s;
}

/* ---------------------------------------------------------------------------
   СЛОЙ 2. СЕМАНТИКА — светлая тема
   --------------------------------------------------------------------------- */
:root {
  --bg: var(--n-50);
  --surface: var(--n-0);
  --surface-2: var(--n-50);
  --surface-3: var(--n-100);
  --border: var(--n-150);
  --border-strong: var(--n-200);
  --text: var(--n-850);
  --muted: var(--n-500);
  --faint: var(--n-400);

  --accent: var(--iris-500);
  --accent-hover: var(--iris-600);
  --accent-soft: var(--iris-100);
  --accent-line: var(--iris-200);

  --dark: var(--n-850);          /* «инверсная» поверхность: primary-кнопка, монограмма */
  --on-dark: var(--n-0);

  --ok: var(--green-500);      --ok-soft: var(--green-tint);
  --warn: var(--amber-500);    --warn-soft: var(--amber-tint);
  --danger: var(--red-500);    --danger-soft: var(--red-tint);
  /* Тревожный цвет под коротким именем: в разметке уже писали var(--bad), а
     переменной не было, и красные точки в гейте оставались бесцветными. */
  --bad: var(--danger);
  --msg: var(--teal-500);      --msg-soft: var(--teal-tint);
  --msg-line: color-mix(in srgb, var(--teal-500) 32%, transparent);

  /* плоские поверхности живут на волосяных линиях, тени — только у оверлеев */
  --shadow: none;
  --shadow-raise: 0 1px 2px rgba(20,18,12,.05), 0 8px 24px -12px rgba(20,18,12,.14);
  --shadow-lg: 0 24px 60px -12px rgba(18,16,12,.28), 0 4px 12px rgba(18,16,12,.10);
  --scrim: rgba(24,22,18,.42);

  --focus-ring:
    0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent),
    0 0 16px -3px color-mix(in srgb, var(--accent) 55%, transparent);

  --canvas-tint: none;
  color-scheme: light;
}

/* ---------------------------------------------------------------------------
   СЛОЙ 2. СЕМАНТИКА — тёмная тема
   --------------------------------------------------------------------------- */
[data-theme="dark"] {
  --bg: var(--g-900);
  --surface: var(--g-850);
  --surface-2: var(--g-800);
  --surface-3: var(--g-750);
  --border: var(--g-700);
  --border-strong: var(--g-600);
  --text: #e8e9ec;
  --muted: var(--g-300);
  --faint: var(--g-400);

  --accent: var(--iris-400);
  --accent-hover: #918af0;
  --accent-soft: var(--iris-dim);
  --accent-line: #3a3470;

  --dark: #eceef1;
  --on-dark: var(--g-900);

  --ok: var(--green-400);      --ok-soft: var(--green-dim);
  --warn: var(--amber-400);    --warn-soft: var(--amber-dim);
  --danger: var(--red-400);    --danger-soft: var(--red-dim);
  --bad: var(--danger);
  --msg: var(--teal-400);      --msg-soft: var(--teal-dim);
  --msg-line: color-mix(in srgb, var(--teal-400) 34%, transparent);

  --shadow: none;
  --shadow-raise: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px -12px rgba(0,0,0,.6);
  --shadow-lg: 0 28px 70px -14px rgba(0,0,0,.72), 0 4px 14px rgba(0,0,0,.5);
  --scrim: rgba(4,5,7,.62);

  --focus-ring:
    0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent),
    0 0 20px -3px color-mix(in srgb, var(--accent) 65%, transparent);

  --canvas-tint: radial-gradient(900px 420px at 22% -8%, rgba(124,116,232,.07), transparent 62%);
  color-scheme: dark;
}

/* Боковой рельс тёмный в обеих темах — это главный признак «продукта», а не админки */
:root, [data-theme="dark"] {
  --rail-bg: var(--g-900);
  --rail-surface: var(--g-800);
  --rail-border: rgba(255,255,255,.07);
  --rail-text: var(--g-200);
  --rail-muted: var(--g-400);
  --rail-active-bg: var(--g-750);
  --rail-active-text: #ffffff;
}

/* ---------------------------------------------------------------------------
   СЛОЙ 3. БАЗА
   --------------------------------------------------------------------------- */
* { margin: 0; padding: 0; box-sizing: border-box; }

/* Страница — приложение, а не документ: «оттягивание» за край (резиновая
   прокрутка macOS) показывало фон под страницей, и над тёмным меню на миг
   появлялась светлая полоса, будто вёрстка поехала. */
html { background: var(--bg); overscroll-behavior: none; height: 100%; }

body {
  font-family: var(--font-sans);
  background: var(--bg);
  background-image: var(--canvas-tint);
  background-attachment: fixed;
  overscroll-behavior: none;
  min-height: 100%;
  color: var(--text);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: 'ss01' 1, 'cv01' 1;
}
input, select, textarea, button { font-family: inherit; }

/* Атрибут hidden должен работать: у .field свой display, и он его перебивал —
   из-за этого «Дни недели» показывались при ежедневном повторе. */
[hidden] { display: none !important; }

::selection { background: var(--accent); color: #fff; }

/* Скроллбары — деталь, по которой отличают продукт от вёрстки «по умолчанию» */
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--border-strong); border-radius: var(--r-pill);
  border: 3px solid transparent; background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--faint); background-clip: content-box; }

/* Микро-подпись: моноширинный верхний регистр. Задаёт «технический» тон всей системе */
.eyebrow, .nav-label, thead th, .group-head h3, .stat .label, .kpi .t, .build {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .09em;
  text-transform: uppercase;
  font-weight: 500;
}

/* Все числа — табличным моноширинным. Колонки выравниваются сами */
.num, .value, .money, .kpi .n, .hero .side .n, .cell-money, .cell-sum,
.stat .value, .legend .item b, .check-line .n, .count, .hero-day .ring .val {
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   ВХОД
   --------------------------------------------------------------------------- */
.auth-wrap {
  min-height: 100vh; display: grid; place-items: center; padding: var(--s-6);
  background:
    radial-gradient(680px 340px at 50% -10%, var(--accent-soft), transparent 70%),
    var(--bg);
}
.auth-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--shadow-raise); padding: var(--s-8) var(--s-8) var(--s-6);
  width: 100%; max-width: 372px; position: relative; overflow: hidden;
}
.auth-card::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
}
.auth-mark {
  width: 38px; height: 38px; border-radius: 10px; background: var(--accent); color: #fff;
  display: grid; place-items: center; font-weight: 700; font-size: 17px; letter-spacing: -.02em;
  margin-bottom: var(--s-5); box-shadow: inset 0 1px 0 rgba(255,255,255,.22);
}
.auth-card h1 { font-size: 21px; font-weight: 700; letter-spacing: -.03em; margin-bottom: var(--s-1); }
.auth-card .sub { color: var(--muted); font-size: 13px; margin-bottom: var(--s-5); line-height: 1.5; }

/* ---------------------------------------------------------------------------
   КАРКАС
   --------------------------------------------------------------------------- */
.layout { display: flex; min-height: 100vh; }

/* Фон меню тянется на всю высоту страницы, а прилипает только содержимое.
   Раньше липким был сам блок с height:100vh — и на длинных страницах его
   тёмная полоса заканчивалась раньше конца документа: под меню вылезала
   светлая полоска, будто вёрстка поехала. */
.sidebar {
  width: 236px; flex-shrink: 0;
  background: var(--rail-bg); color: var(--rail-text);
  border-right: 1px solid var(--rail-border);
  align-self: stretch;
}
.sidebar > .rail {
  position: sticky; top: 0; height: 100vh;
  padding: var(--s-4) var(--s-3) var(--s-3);
  display: flex; flex-direction: column; gap: 1px;
}

.brand { display: flex; align-items: center; gap: 10px; padding: var(--s-1) var(--s-2) var(--s-5); }
.brand .logo {
  width: 30px; height: 30px; border-radius: 8px; flex-shrink: 0;
  background: var(--accent); color: #fff;
  display: grid; place-items: center; font-weight: 700; font-size: 14px;
  letter-spacing: -.02em; position: relative;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.22);
}
[data-theme="dark"] .brand .logo { background: var(--accent); color: #fff; }
.brand .logo::after {
  content: ''; position: absolute; right: -2px; bottom: -2px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--green-400); border: 2px solid var(--rail-bg);
}
.brand .name {
  font-size: 13px; font-weight: 650; letter-spacing: -.01em; color: #fff; line-height: 1.25;
}
.brand .who { font-size: 11px; color: var(--rail-muted); margin-top: 1px; }

.nav-label { color: var(--g-500); padding: var(--s-4) var(--s-2) var(--s-2); }

.nav-item {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: var(--r-sm); cursor: pointer;
  color: var(--rail-muted); font-size: 13px; font-weight: 500;
  transition: background var(--dur), color var(--dur); user-select: none;
}
.nav-item:hover { background: rgba(255,255,255,.045); color: var(--rail-text); }
.nav-item.active { background: var(--rail-active-bg); color: var(--rail-active-text); font-weight: 600; }
.nav-item.active::before {
  content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 3px; height: 16px; border-radius: 0 3px 3px 0; background: var(--accent);
}
.nav-item.active svg { color: var(--accent); }
.nav-item.disabled { opacity: .38; cursor: default; }
.nav-item.disabled:hover { background: transparent; color: var(--rail-muted); }
.nav-item svg { width: 16px; height: 16px; flex-shrink: 0; }

/* Только пометка «скоро» в меню: класс .soon занят ещё и тегом срока задачи */
.nav-item .soon {
  margin-left: auto; font-family: var(--font-mono); font-size: 9px;
  letter-spacing: .06em; text-transform: uppercase; color: var(--g-400);
  border: 1px solid var(--g-600); padding: 2px 5px; border-radius: var(--r-xs);
}
/* Счётчик моих задач в меню: спокойный кружок, красный — когда что-то горит */
.nav-item .nav-count {
  margin-left: auto; min-width: 20px; padding: 1px 6px; border-radius: 999px;
  font-family: var(--font-mono); font-size: 11px; line-height: 16px; text-align: center;
  background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent-line);
}
.nav-item .nav-count.alarm {
  background: var(--danger-soft); color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 30%, transparent);
}
.nav-item .nav-count.none { display: none; }

/* Список разделов прокручивается сам, а логотип и карточка профиля остаются на
   месте. Без этого высота рельса упиралась в экран: разделов стало десять, и на
   невысоком окне нижние просто уезжали за край — пункт есть, а нажать нельзя.
   Полосу прокрутки прячем: она тут появлялась бы поверх названий. */
.nav-scroll {
  flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden;
  display: flex; flex-direction: column; gap: 1px;
  scrollbar-width: none;
}
.nav-scroll::-webkit-scrollbar { width: 0; height: 0; }

.sidebar-foot { margin-top: auto; border-top: 1px solid var(--rail-border); padding-top: var(--s-2); }
.sidebar-foot .nav-item { font-size: 12.5px; }

/* Свой профиль правится оттуда, где человек себя видит: карточка внизу рельса.
   Раньше вход в правку был спрятан на вкладке «Все задачи» — найти невозможно. */
.me {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; margin-bottom: var(--s-1);
  border-radius: var(--r-sm); cursor: pointer; user-select: none;
  transition: background var(--dur);
}
.me:hover { background: rgba(255,255,255,.055); }
.me-text { min-width: 0; flex: 1; }
.me-name {
  font-size: 12.5px; font-weight: 600; color: #fff; line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.me-post {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .03em; text-transform: uppercase;
  color: var(--g-400); margin-top: 3px; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.me-edit { flex-shrink: 0; color: var(--g-500); opacity: 0; transition: opacity var(--dur), color var(--dur); }
.me-edit svg { width: 15px; height: 15px; display: block; }
.me:hover .me-edit { opacity: 1; color: #fff; }
@media (hover: none) { .me-edit { opacity: .7; } }

/* --- рабочая область --- */
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  padding: var(--s-6) var(--s-8) var(--s-5);
  display: flex; align-items: flex-start; gap: var(--s-4); flex-wrap: wrap;
}
.topbar .eyebrow { color: var(--faint); margin-bottom: 6px; }
.topbar h1 { font-size: 26px; font-weight: 700; letter-spacing: -.035em; line-height: 1.1; }
.topbar .sub { color: var(--muted); font-size: 13px; margin-top: 6px; max-width: 62ch; }
.topbar .spacer { flex: 1; }
.top-actions { display: flex; gap: 6px; flex-wrap: wrap; padding-top: 2px; }
/* Кнопка сообщений. Пока новых нет — обычная кнопка и без числа; как только
   появились, она перекрашивается в бирюзовый и мягко пульсирует. Резкое
   моргание отвлекает от работы и через минуту начинает раздражать. */
.btn.btn-msg { gap: 7px; }
.btn.btn-msg svg { width: 16px; height: 16px; }
.btn.btn-msg .msg-count { display: none; }
.btn.btn-msg.has-new {
  background: var(--msg-soft); color: var(--msg); border-color: var(--msg-line); font-weight: 650;
  animation: msg-glow 2s var(--ease) infinite;
}
.btn.btn-msg.has-new .msg-count {
  display: inline-block; min-width: 18px; padding: 0 5px; border-radius: 999px;
  background: var(--msg); color: var(--surface); font-family: var(--font-mono);
  font-size: 11px; line-height: 17px; text-align: center; font-weight: 700;
}
/* Фильтр сводки: период и площадка в одной строке над цифрами */
.fin-filter {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px;
}
.fin-filter select { width: auto; min-width: 150px; }

/* Плашки «на что смотреть». Появляются только когда есть что делать: блок,
   который горит всегда, перестают читать целиком. */
.hl-row {
  display: grid; gap: 10px; margin-bottom: 16px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.hl {
  padding: 12px 14px; border-radius: var(--r-md); border: 1px solid var(--line);
  background: var(--surface); border-left-width: 3px;
}
.hl-title { font-weight: 650; font-size: 14px; margin-bottom: 3px; }
.hl-text { font-size: 12.5px; color: var(--muted); line-height: 1.45; }
.hl-bad { border-left-color: var(--danger); background: var(--danger-soft); }
.hl-bad .hl-title { color: var(--danger); }
.hl-warn { border-left-color: var(--warn); background: var(--warn-soft); }
.hl-warn .hl-title { color: var(--warn); }
.hl-info { border-left-color: var(--c2); }
.hl[data-go-tab]:hover { border-color: var(--line-strong, var(--faint)); }

/* ОСТАТОК ДЕНЕГ ВО ВРЕМЕНИ.
   Одна величина — одна шкала: проблема разного масштаба прихода и расхода здесь
   отсутствует по устройству, а не решается подбором. */
.bc { --bc: var(--mc-in); }
.bc-plot { position: relative; height: 190px; }
.bc-svg { width: 100%; height: 190px; display: block; }

/* Сетка уходит на задний план: она нужна для чтения величин, а не для показа */
.bc-grid {
  stroke: var(--line); stroke-width: 1; opacity: .55;
  vector-effect: non-scaling-stroke;
}
.bc-g1 { stop-color: var(--bc); stop-opacity: .28; }
.bc-g2 { stop-color: var(--bc); stop-opacity: 0; }
.bc-area { fill: url(#bcFill); stroke: none; }
/* Часть площади ниже нуля — это долг, а не «низ графика» */
.bc-area-bad { fill: color-mix(in srgb, var(--danger) 22%, transparent); stroke: none; }
.bc-zero {
  stroke: var(--danger); stroke-width: 1; stroke-dasharray: 4 4; opacity: .7;
  vector-effect: non-scaling-stroke;
}
/* Будущее на приглушённой подложке: план не должен выглядеть как факт */
.bc-future { fill: var(--surface-2); opacity: .5; }
.bc-line {
  fill: none; stroke: var(--bc); stroke-width: 2.2;
  stroke-linejoin: round; stroke-linecap: round;
  vector-effect: non-scaling-stroke;   /* растяжение по ширине иначе раздувает линию */
}
.bc-plan { stroke: var(--muted); stroke-width: 2; stroke-dasharray: 5 5; }

/* Подписи величин — внутри поля, у самой сетки */
.bc-levels { position: absolute; inset: 0; pointer-events: none; }
/* Подписи стоят в собственном поле слева, а не поверх заливки: ярлык с фоном
   пробивал в площади дыру и читался как часть данных */
.bc-level {
  position: absolute; left: 0; width: 58px; text-align: right;
  transform: translateY(-50%);
  font-size: 10.5px; color: var(--faint); font-family: var(--font-mono);
}

/* Сегодняшняя точка и сумма рядом: главный ответ не надо искать глазами */
.bc-dot-now {
  position: absolute; width: 9px; height: 9px; border-radius: 50%;
  background: var(--bc); box-shadow: 0 0 0 3px var(--surface);
  transform: translate(-50%, -50%); pointer-events: none;
}
/* Конец прогноза: без точки пунктир выглядит обрезанным краем поля */
.bc-dot-end {
  position: absolute; width: 7px; height: 7px; border-radius: 50%;
  background: var(--muted); box-shadow: 0 0 0 3px var(--surface);
  transform: translate(-50%, -50%); pointer-events: none;
}
.bc-now-val {
  position: absolute; transform: translate(-100%, -180%); padding-right: 12px;
  font-size: 12px; font-weight: 650; color: var(--text);
  white-space: nowrap; pointer-events: none;
}

/* Курсор и карточка при наведении */
.bc-cursor { position: absolute; top: 0; bottom: 0; pointer-events: none; }
.bc-cursor i {
  position: absolute; top: 0; bottom: 0; left: 0; width: 1px;
  background: color-mix(in srgb, var(--bc) 55%, transparent);
}
.bc-cursor b {
  position: absolute; left: 0; width: 9px; height: 9px; border-radius: 50%;
  background: var(--bc); box-shadow: 0 0 0 3px var(--surface);
  transform: translate(-50%, -50%);
}
.bc-cursor b.plan { background: var(--muted); }
/* Карточка на подложке surface-2: на тёмной теме тени отключены, и на одном
   цвете с панелью она читалась как текст, случайно попавший на график */
.bc-tip {
  position: absolute; top: 6px; pointer-events: none; z-index: 2;
  background: var(--surface-2); border: 1px solid var(--line-strong, var(--line));
  border-radius: var(--r-sm); padding: 6px 10px; box-shadow: var(--shadow);
  display: flex; flex-direction: column; gap: 1px; white-space: nowrap;
}
.bc-tip b { font-size: 13.5px; font-family: var(--font-mono); }
.bc-tip span { font-size: 11px; color: var(--faint); }

/* Ось дат и подвал */
.bc-x { position: relative; height: 16px; margin-top: 4px; }
.bc-x span {
  position: absolute; transform: translateX(-50%);
  font-size: 10.5px; color: var(--faint); font-family: var(--font-mono);
}
.bc-foot {
  display: flex; align-items: center; gap: 16px;
  margin-top: 10px; font-size: 12px; color: var(--muted);
}
.bc-key {
  display: inline-block; width: 14px; height: 2.5px; border-radius: 2px;
  background: var(--bc); vertical-align: middle; margin-right: 6px;
}
.bc-key.plan { background: var(--muted); }
.bc-warn { color: var(--danger); font-weight: 600; }

/* Значок предстоящих платежей. Янтарный, пока просто предстоят, и красный с
   пульсом, когда дата прошла: разные новости должны выглядеть по-разному. */
.btn.btn-pay {
  gap: 7px; background: var(--warn-soft); color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 30%, transparent); font-weight: 650;
}
.btn.btn-pay svg { width: 16px; height: 16px; }
.btn.btn-pay .pay-count {
  display: inline-block; min-width: 18px; padding: 0 5px; border-radius: 999px;
  background: var(--warn); color: var(--surface); font-family: var(--font-mono);
  font-size: 11px; line-height: 17px; text-align: center; font-weight: 700;
}
.btn.btn-pay.is-late {
  background: var(--danger-soft); color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 32%, transparent);
  animation: pay-glow 2s var(--ease) infinite;
}
.btn.btn-pay.is-late .pay-count { background: var(--danger); }
@keyframes pay-glow {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--danger) 45%, transparent); }
  50% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--danger) 0%, transparent); }
}

/* Список платежей в панели из шапки */
.pay-list { display: flex; flex-direction: column; gap: 2px; }
.pay-item {
  display: flex; align-items: center; gap: 12px; padding: 10px 12px;
  border-radius: var(--r-sm); border: 1px solid transparent;
}
.pay-item:hover { background: var(--surface-2); }
.pay-item.is-now { border-color: color-mix(in srgb, var(--warn) 30%, transparent); }
.pay-item.is-late { border-color: color-mix(in srgb, var(--danger) 32%, transparent); }
.pay-when {
  flex: none; width: 108px; font-size: 12px; color: var(--faint);
  font-family: var(--font-mono);
}
.pay-item.is-late .pay-when { color: var(--danger); }
.pay-item.is-now .pay-when { color: var(--warn); }
.pay-main { flex: 1; min-width: 0; }
.pay-sum { flex: none; font-weight: 650; font-family: var(--font-mono); }

@keyframes msg-glow {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--msg) 45%, transparent); }
  60%      { box-shadow: 0 0 0 7px color-mix(in srgb, var(--msg) 0%, transparent); }
}
/* Кому анимация мешает — системная настройка сильнее любой нашей задумки */
@media (prefers-reduced-motion: reduce) {
  .btn.btn-msg.has-new, .tag.unread, .btn.btn-pay.is-late { animation: none; }
}

/* Задача с непрочитанным сообщением — видно прямо в списке, не наводя мышь */
.task-card.has-msg { border-color: var(--msg-line); }
.task-card.has-msg::after {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--msg); border-radius: var(--r) 0 0 var(--r);
}

/* Панель сообщений */
.msg-list { display: flex; flex-direction: column; gap: 2px; }
.msg-item {
  padding: 11px 12px; border: 1px solid var(--border); border-radius: var(--r);
  cursor: pointer; background: var(--surface); transition: border-color var(--dur), background var(--dur);
}
.msg-item:hover { border-color: var(--msg-line); background: var(--msg-soft); }
/* Новость о сроках проекта — не переписка, поэтому и выглядит иначе */
.msg-item.is-launch { border-left: 3px solid var(--warn); }
.msg-item.is-launch .msg-who { color: var(--warn); }
/* Срок уехал ближе — это хорошая новость, и выглядеть тревожно она не должна */
.msg-item.is-launch.is-good { border-left-color: var(--ok); }
.msg-item.is-launch.is-good .msg-who { color: var(--ok); }
.msg-top { display: flex; align-items: center; gap: 8px; font-size: 12px; }
.msg-who { font-weight: 650; color: var(--text); }
.msg-task { color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 320px; }
.msg-when { font-family: var(--font-mono); font-size: 11px; color: var(--faint); }
/* Закрытую задачу в разделе уже не найти — говорим об этом прямо в строке */
.msg-closed {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); border: 1px solid var(--border); border-radius: var(--r-xs); padding: 1px 5px;
}
.msg-n {
  min-width: 18px; padding: 0 5px; border-radius: 999px; background: var(--msg); color: var(--surface);
  font-family: var(--font-mono); font-size: 10.5px; line-height: 16px; text-align: center; font-weight: 700;
}
.msg-text { margin-top: 4px; font-size: 13px; color: var(--muted); }

.tabs {
  display: flex; gap: var(--s-5); padding: 0 var(--s-8);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 30;
  overflow-x: auto; scrollbar-width: none;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(180%) blur(10px);
  -webkit-backdrop-filter: saturate(180%) blur(10px);
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  padding: 11px 0 12px; cursor: pointer; color: var(--muted); font-size: 13.5px;
  font-weight: 500; border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color var(--dur), border-color var(--dur); white-space: nowrap;
}
.tab:hover { color: var(--text); }
.tab.active { color: var(--text); border-bottom-color: var(--accent); font-weight: 650; }
/* Число у вкладки: сколько задач в ней ждёт действия. Ноль не рисуем вовсе */
.tab-count {
  display: inline-block; min-width: 18px; padding: 0 5px; margin-left: 2px;
  border-radius: 999px; font-family: var(--font-mono); font-size: 10.5px;
  line-height: 16px; text-align: center; vertical-align: 1px; font-weight: 600;
  background: var(--surface-2); color: var(--muted); border: 1px solid var(--border);
}
.tab.active .tab-count { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }
.tab-count.alarm {
  background: var(--danger-soft); color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 30%, transparent);
}

.content { padding: var(--s-6) var(--s-8) var(--s-12); flex: 1; }
.view { display: none; }
.view.active { display: block; }

/* ---------------------------------------------------------------------------
   ПОЛОСА ПОКАЗАТЕЛЕЙ — единый блок с волосяными перегородками,
   а не россыпь карточек с тенями
   --------------------------------------------------------------------------- */
.stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(172px, 1fr));
  gap: 1px; margin-bottom: var(--s-4);
  background: var(--border); border: 1px solid var(--border);
  border-radius: var(--r-md); overflow: hidden;
}
.stat { background: var(--surface); padding: 13px var(--s-4) 14px; min-width: 0; }
.stat .label { color: var(--faint); display: block; }
.stat .value {
  font-family: var(--font-mono); font-size: 21px; font-weight: 500; margin-top: 8px;
  letter-spacing: -.045em; word-spacing: -.2em; line-height: 1.15;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.stat .value small {
  font-family: var(--font-sans); font-size: 12.5px; font-weight: 500;
  color: var(--faint); letter-spacing: 0; word-spacing: normal;
}
.stat .sub { font-size: 12px; color: var(--faint); margin-top: 5px; }
.stat .sub b { font-weight: 650; }
.stat.accent .value { color: var(--accent); }
.stat.warn  .value { color: var(--warn); }
.stat.danger .value { color: var(--danger); }

/* ---------------------------------------------------------------------------
   ПАНЕЛИ
   --------------------------------------------------------------------------- */
.panel {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); margin-bottom: var(--s-4); overflow: hidden;
}
.panel-head {
  padding: 13px var(--s-4); display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  border-bottom: 1px solid var(--border);
}
.panel-head h2 { font-size: 14px; font-weight: 650; letter-spacing: -.015em; }
.panel-head .spacer { flex: 1; }
.panel-body { padding: var(--s-4); }
.panel > .panel-head:last-child { border-bottom: none; }
/* заголовок секции, вынесенный из панели (закрытые поставки) */
.panel-head[style*="padding-left:0"] { border-bottom: none; background: transparent; }

/* ---------------------------------------------------------------------------
   ТАБЛИЦЫ
   --------------------------------------------------------------------------- */
.table-scroll { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13.5px; table-layout: auto; }
thead th {
  text-align: left; padding: 9px 10px; color: var(--faint);
  border-bottom: 1px solid var(--border);
  background: var(--surface-2); white-space: nowrap;
  position: sticky; top: 0; z-index: 2;
}
thead th.num { text-align: right; }
tbody td {
  padding: 10px; border-bottom: 1px solid var(--border);
  vertical-align: middle; position: relative;
}
tbody tr:last-child td { border-bottom: none; }
tbody td:first-child { color: var(--text); }
tbody tr.hoverable { cursor: pointer; }
tbody tr.hoverable:hover td { background: var(--surface-2); }
tbody tr.hoverable:hover td:first-child::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 2px; background: var(--accent);
}
tfoot td {
  padding: 11px 10px; border-top: 1px solid var(--border-strong);
  font-weight: 650; background: var(--surface-2);
}
.num { text-align: right; white-space: nowrap; }
tbody td.num, tfoot td.num {
  font-family: var(--font-mono); font-size: 12.5px;
  letter-spacing: -.02em; word-spacing: -.18em;
}
td.num .btn { font-family: var(--font-sans); font-size: 12.5px; letter-spacing: 0; word-spacing: normal; }
.strong { font-weight: 600; }
.dim { color: var(--muted); }
.faint { color: var(--faint); }
.nowrap { white-space: nowrap; }
/* Что именно поменяли в документе — под строкой журнала, приглушённо: главное
   там кто и что сделал, подробности читают только когда пошли разбираться. */
.audit-diff { margin-top: 4px; color: var(--text); font-size: 12.5px; line-height: 1.55;
  padding-left: 10px; border-left: 2px solid var(--line); }
.cell-money { font-family: var(--font-mono); font-size: 12.5px; letter-spacing: -.02em; }

.prod-cell { display: flex; align-items: center; gap: 11px; min-width: 200px; }
.thumb, .thumb-ph {
  width: 34px; height: 34px; border-radius: var(--r-sm); flex-shrink: 0;
  background: var(--surface-2); border: 1px solid var(--border);
  transition: border-color var(--dur);
}
.thumb { object-fit: cover; }
.thumb-ph {
  display: grid; place-items: center; font-size: 13px; font-weight: 650; color: var(--faint);
}
tbody tr.hoverable:hover .thumb, tbody tr.hoverable:hover .thumb-ph { border-color: var(--accent); }

/* ---------------------------------------------------------------------------
   ФОРМЫ
   --------------------------------------------------------------------------- */
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--s-3); }
.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.field label { font-size: 12px; color: var(--muted); font-weight: 500; }

input, select, textarea {
  background: var(--surface); border: 1px solid var(--border-strong); color: var(--text);
  padding: 8px 11px; border-radius: var(--r-sm); font-size: 13.5px; width: 100%; outline: none;
  transition: border-color var(--dur), box-shadow var(--dur), background var(--dur);
}
[data-theme="dark"] input, [data-theme="dark"] select, [data-theme="dark"] textarea {
  background-color: var(--surface-2);
}
input:hover, select:hover, textarea:hover { border-color: var(--faint); }
input:focus, select:focus, textarea:focus {
  border-color: var(--accent); box-shadow: var(--focus-ring); background-color: var(--surface);
}
input::placeholder, textarea::placeholder { color: var(--faint); }
select { appearance: none; background-image: none; cursor: pointer; padding-right: 26px; }
input[type="date"] {
  font-family: var(--font-mono); font-size: 12.5px; padding-right: 30px; cursor: pointer;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238e8b81' stroke-width='1.8'><rect x='3' y='5' width='18' height='16' rx='3'/><path d='M8 3v4M16 3v4M3 10h18'/></svg>");
  background-repeat: no-repeat; background-position: right 9px center; background-size: 15px;
}
[data-theme="dark"] input[type="date"] {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23767c88' stroke-width='1.8'><rect x='3' y='5' width='18' height='16' rx='3'/><path d='M8 3v4M16 3v4M3 10h18'/></svg>");
}
input[type="date"]::-webkit-calendar-picker-indicator { display: none; }
.toolbar input[type="date"] { min-width: 148px; }
input[type="number"] { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
/* Цифры моноширинные, а подсказка — обычным: моноширинная не влезала в узкую колонку */
input[type="number"]::placeholder { font-family: var(--font-sans); }
/* Флажки и переключатели ширину полей не наследуют: общее правило выше даёт
   input ширину 100%, и флажок растягивался на всё поле — форма разъезжалась
   (скриншот Дмитрия 07.09.2026). Размер задаём здесь, а не в каждом месте
   по отдельности, как делали раньше. */
input[type="checkbox"], input[type="radio"] {
  accent-color: var(--accent);
  width: 15px; min-width: 15px; height: 15px;
  padding: 0; margin: 0; flex: none; cursor: pointer;
}

.lines { border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; margin-top: 6px; }
.line-head, .line {
  display: grid; gap: var(--s-2); padding: 9px var(--s-3); align-items: center;
  grid-template-columns: minmax(0,1fr) 96px 116px 100px 34px;
}
.line-head {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--faint); background: var(--surface-2); border-bottom: 1px solid var(--border); font-weight: 500;
}
.line { border-bottom: 1px solid var(--border); }
.line:last-child { border-bottom: none; }
.line:hover { background: var(--surface-2); }
.line .cell-sum {
  font-family: var(--font-mono); font-size: 12px; text-align: right; color: var(--muted);
}

/* ---------------------------------------------------------------------------
   КНОПКИ
   --------------------------------------------------------------------------- */
a.btn { text-decoration: none; }
.btn {
  background: var(--surface); border: 1px solid var(--border-strong); color: var(--text);
  padding: 8px 13px; border-radius: var(--r-sm); font-size: 13px; font-weight: 500; cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  transition: background var(--dur), border-color var(--dur), color var(--dur), transform .08s;
}
.btn:hover { background: var(--surface-2); border-color: var(--faint); }
.btn:active { transform: translateY(1px); }
.btn svg { width: 14px; height: 14px; }
/* Неактивная кнопка выглядит выключенной, а не «сломанной главной»:
   гасим заливку и вес, оставляем ровный контур — так видно, что действие
   пока недоступно, но кнопка на месте и ждёт. */
.btn:disabled,
.btn-primary:disabled {
  background: var(--surface-2); border-color: var(--border);
  color: var(--faint); font-weight: 500; opacity: 1; cursor: default; box-shadow: none;
}
.btn:disabled:hover,
.btn-primary:disabled:hover {
  background: var(--surface-2); border-color: var(--border); color: var(--faint);
}

.btn-primary {
  background: var(--dark); border-color: var(--dark); color: var(--on-dark); font-weight: 600;
}
[data-theme="dark"] .btn-primary { background: var(--dark); border-color: var(--dark); color: var(--on-dark); }
.btn-primary:hover { background: var(--n-700); border-color: var(--n-700); }
[data-theme="dark"] .btn-primary:hover { background: #fff; border-color: #fff; }

/* Тёмная тема красит главную кнопку белым, поэтому выключенное состояние
   описываем и здесь — иначе неактивная кнопка светится как активная. */
[data-theme="dark"] .btn-primary:disabled,
[data-theme="dark"] .btn-primary:disabled:hover,
[data-theme="dark"] .btn:disabled,
[data-theme="dark"] .btn:disabled:hover {
  background: transparent; border-color: var(--border);
  color: var(--faint); font-weight: 500; box-shadow: none;
}

.btn-sm { padding: 5px 10px; font-size: 12.5px; border-radius: var(--r-xs); }
.btn-ghost { border-color: transparent; background: transparent; color: var(--muted); }
.btn-ghost:hover { background: var(--surface-2); border-color: transparent; color: var(--text); }
.btn-danger { color: var(--danger); }
.btn-danger:hover { border-color: var(--danger); background: var(--danger-soft); color: var(--danger); }

/* ---------------------------------------------------------------------------
   БЕЙДЖИ И ЧИПЫ
   --------------------------------------------------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 7px; border-radius: var(--r-xs);
  font-size: 11.5px; font-weight: 600; white-space: nowrap; line-height: 1.5;
  border: 1px solid transparent;
}
.badge-in       { background: var(--ok-soft);     color: var(--ok);     border-color: color-mix(in srgb, var(--ok) 22%, transparent); }
.badge-move     { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }
.badge-writeoff { background: var(--danger-soft); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 22%, transparent); }
.badge-count    { background: var(--warn-soft);   color: var(--warn);   border-color: color-mix(in srgb, var(--warn) 22%, transparent); }
/* Продажа — не потеря: цвет спокойный, как у прихода, чтобы в списке документов
   она не читалась наравне со списанием. */
.badge-sale     { background: var(--ok-soft);     color: var(--ok);     border-color: color-mix(in srgb, var(--ok) 22%, transparent); }
.badge-zero     { background: var(--danger-soft); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 22%, transparent); }
.badge-low      { background: var(--warn-soft);   color: var(--warn);   border-color: color-mix(in srgb, var(--warn) 22%, transparent); }
.badge-muted    { background: var(--surface-2);   color: var(--muted);  border-color: var(--border); }

.chip {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px;
  border-radius: var(--r-pill); background: var(--surface-2); border: 1px solid var(--border);
  font-size: 12px; color: var(--muted); white-space: nowrap;
}
.chip b { color: var(--text); font-weight: 650; font-variant-numeric: tabular-nums; }

/* Чип-ссылка: ведёт наружу (папка проекта на Диске), поэтому ведёт себя как
   кнопка — подсвечивается под курсором, а не выглядит мёртвой подписью. */
.chip-link {
  text-decoration: none; cursor: pointer;
  transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.chip-link:hover {
  color: var(--text); border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: color-mix(in srgb, var(--accent) 10%, var(--surface-2));
}

/* ---------------------------------------------------------------------------
   ПАНЕЛЬ ФИЛЬТРОВ
   --------------------------------------------------------------------------- */
.toolbar {
  display: flex; gap: 6px; flex-wrap: wrap; align-items: center; margin-bottom: var(--s-3);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--s-2) 10px;
}
.toolbar input:not([type="checkbox"]), .toolbar select { width: auto; min-width: 130px; }
.toolbar input[type="checkbox"] { width: 15px; min-width: 15px; height: 15px; margin: 0; cursor: pointer; }
.toolbar label { white-space: nowrap; }

.switch {
  display: flex; gap: 2px; background: var(--surface-2); padding: 2px;
  border-radius: var(--r-sm); border: 1px solid var(--border);
}
.switch button {
  border: none; background: transparent; padding: 5px 11px; border-radius: var(--r-xs);
  font-size: 12.5px; color: var(--muted); cursor: pointer; font-weight: 500;
  transition: background var(--dur), color var(--dur);
}
.switch button:hover { color: var(--text); }
.switch button.on { background: var(--surface); color: var(--text); font-weight: 600; box-shadow: var(--shadow-raise); }
[data-theme="dark"] .switch button.on { background: var(--surface-3); }

[data-theme="dark"] .panel,
[data-theme="dark"] .hero,
[data-theme="dark"] .hero-day,
[data-theme="dark"] .stats,
[data-theme="dark"] .toolbar,
[data-theme="dark"] .modal { box-shadow: inset 0 1px 0 rgba(255,255,255,.035); }

/* ---------------------------------------------------------------------------
   ПРОЧИЕ БЛОКИ
   --------------------------------------------------------------------------- */
.cell-reason { max-width: 165px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.note {
  position: relative;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r); padding: 11px 14px 11px 41px;
  font-size: 13px; color: var(--muted); margin-bottom: var(--s-4); line-height: 1.55;
}
.note b { color: var(--text); font-weight: 600; }
/* Знак вместо цветной полосы: смысл виден и без цвета.
   Иконка позиционируется абсолютно — во flex-контейнере <b> внутри текста
   стал бы отдельной колонкой и разорвал абзац. */
.note::before {
  content: ''; position: absolute; left: 13px; top: 12px;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--accent-soft)
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235b53d3' stroke-width='2.6' stroke-linecap='round'><path d='M12 11v6M12 7.2v.1'/></svg>")
    center / 12px no-repeat;
}
[data-theme="dark"] .note::before {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237c74e8' stroke-width='2.6' stroke-linecap='round'><path d='M12 11v6M12 7.2v.1'/></svg>");
}
.note-warn { border-color: color-mix(in srgb, var(--warn) 30%, transparent); background: var(--warn-soft); }
.note-warn::before {
  background-color: color-mix(in srgb, var(--warn) 22%, transparent);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23b06b12' stroke-width='2.6' stroke-linecap='round'><path d='M12 7v6M12 16.8v.1'/></svg>");
}
[data-theme="dark"] .note-warn::before {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23e0a137' stroke-width='2.6' stroke-linecap='round'><path d='M12 7v6M12 16.8v.1'/></svg>");
}
.note-ok { border-color: color-mix(in srgb, var(--ok) 30%, transparent); background: var(--ok-soft); }
.note-ok::before {
  background-color: color-mix(in srgb, var(--ok) 22%, transparent);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231f8f5a' stroke-width='2.8' stroke-linecap='round' stroke-linejoin='round'><path d='M20 6L9 17l-5-5'/></svg>");
}
[data-theme="dark"] .note-ok::before {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2345c088' stroke-width='2.8' stroke-linecap='round' stroke-linejoin='round'><path d='M20 6L9 17l-5-5'/></svg>");
}

.section-title { font-size: 14px; font-weight: 650; margin: var(--s-1) 0 var(--s-3); letter-spacing: -.015em; }

.empty { padding: var(--s-12) var(--s-5); text-align: center; color: var(--muted); }
.empty .icon {
  width: 42px; height: 42px; margin: 0 auto var(--s-3); border-radius: var(--r);
  background: var(--surface-2); border: 1px solid var(--border);
  display: grid; place-items: center; color: var(--faint);
}
.empty .icon svg { width: 20px; height: 20px; }
.empty .big { font-size: 15px; color: var(--text); font-weight: 650; margin-bottom: 5px; letter-spacing: -.015em; }
.empty .hint { font-size: 13px; max-width: 400px; margin: 0 auto; line-height: 1.6; }

.detail-row td { background: var(--surface-2); font-size: 13px; }
.detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--s-2) var(--s-5); }

.upload-box {
  border: 1px dashed var(--border-strong); border-radius: var(--r); padding: var(--s-3);
  display: flex; align-items: center; gap: var(--s-3); cursor: pointer;
  transition: border-color var(--dur), background var(--dur);
}
.upload-box:hover { border-color: var(--accent); background: var(--accent-soft); }
.upload-box img { width: 42px; height: 42px; border-radius: var(--r-sm); object-fit: cover; }

/* ---------------------------------------------------------------------------
   КАЛЕНДАРЬ
   --------------------------------------------------------------------------- */
.cal {
  position: fixed; z-index: 120; width: 268px; padding: 10px;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r-md); box-shadow: var(--shadow-lg);
  animation: pop .14s var(--ease-out);
}
.cal-head { display: flex; align-items: center; gap: 4px; margin-bottom: 8px; }
.cal-title {
  flex: 1; text-align: center; font-size: 13px; font-weight: 650; letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
}
.cal-nav {
  width: 26px; height: 26px; display: grid; place-items: center; flex-shrink: 0;
  border: 1px solid transparent; background: transparent; border-radius: var(--r-xs);
  color: var(--muted); cursor: pointer; transition: background var(--dur), color var(--dur);
}
.cal-nav:hover { background: var(--surface-2); color: var(--text); }
.cal-nav svg { width: 15px; height: 15px; }

.cal-wd, .cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal-wd span {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--faint); text-align: center; padding-bottom: 5px;
}
.cal-day {
  height: 32px; border: 1px solid transparent; background: transparent; border-radius: var(--r-xs);
  font-family: var(--font-mono); font-size: 12.5px; font-variant-numeric: tabular-nums;
  color: var(--text); cursor: pointer; transition: background var(--dur), color var(--dur);
}
.cal-day:hover { background: var(--surface-2); }
/* выходные приглушены — так месяц читается структурой, а не сплошной сеткой */
.cal-wd span:nth-child(n+6),
.cal-grid .cal-day:nth-child(7n+6),
.cal-grid .cal-day:nth-child(7n) { color: var(--muted); }
.cal-grid .cal-day.out:nth-child(7n+6),
.cal-grid .cal-day.out:nth-child(7n) { color: var(--faint); }
.cal-day.sel, .cal-grid .cal-day.sel:nth-child(7n+6), .cal-grid .cal-day.sel:nth-child(7n) { color: #fff; }
.cal-day.out { color: var(--faint); opacity: .5; }
.cal-day.now { border-color: var(--border-strong); font-weight: 600; }
.cal-day.sel { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
.cal-day.sel:hover { background: var(--accent); }

.cal-foot {
  display: flex; gap: 6px; align-items: center;
  margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--border);
}
.cal-foot .spacer { flex: 1; }
.cal-foot button {
  border: 1px solid transparent; background: transparent; color: var(--muted);
  font-size: 12px; padding: 4px 9px; border-radius: var(--r-xs); cursor: pointer;
  transition: background var(--dur), color var(--dur);
}
.cal-foot button:hover { background: var(--surface-2); color: var(--text); }

/* ---------------------------------------------------------------------------
   ОВЕРЛЕИ
   --------------------------------------------------------------------------- */
#loadbar {
  position: fixed; top: 0; left: 0; height: 2px; width: 0; z-index: 200;
  background: var(--accent); transition: width .25s ease, opacity .3s;
  box-shadow: 0 0 10px var(--accent);
}

#toast { position: fixed; right: var(--s-6); bottom: var(--s-6); z-index: 90; display: flex; flex-direction: column; gap: var(--s-2); }
.toast {
  display: flex; align-items: flex-start; gap: 10px;
  background: var(--g-850); color: #eceef1; border: 1px solid var(--g-700);
  padding: 11px 14px; border-radius: var(--r); font-size: 13px; max-width: 380px;
  box-shadow: var(--shadow-lg); line-height: 1.5;
}
.toast-icon {
  flex-shrink: 0; width: 20px; height: 20px; border-radius: 50%; margin-top: 1px;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--green-400) 20%, transparent); color: var(--green-400);
}
.toast-icon svg { width: 12px; height: 12px; }
.toast.error .toast-icon {
  background: color-mix(in srgb, var(--red-400) 22%, transparent); color: var(--red-400);
}

.modal-bg {
  position: fixed; inset: 0; background: var(--scrim); z-index: 80;
  display: flex; align-items: center; justify-content: center; padding: var(--s-6);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
.modal {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  width: 100%; max-width: 780px; max-height: 88vh;
  display: flex; flex-direction: column; box-shadow: var(--shadow-lg); overflow: hidden;
}
.modal.wide { max-width: 960px; }
.modal-head {
  padding: var(--s-4) var(--s-5); display: flex; align-items: center; gap: var(--s-3);
  border-bottom: 1px solid var(--border);
}
.modal-head h3 { font-size: 15.5px; font-weight: 650; letter-spacing: -.02em; }
.modal-head .spacer { flex: 1; }
.modal-body { padding: var(--s-5) var(--s-5) var(--s-6); overflow: auto; }
.modal-foot {
  padding: var(--s-3) var(--s-5); border-top: 1px solid var(--border);
  display: flex; gap: var(--s-2); align-items: center; background: var(--surface-2);
}
.modal-foot .spacer { flex: 1; }
.micro {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .09em;
  text-transform: uppercase; font-weight: 500; color: var(--faint);
}

/* ---------------------------------------------------------------------------
   ОСТАТКИ: главный экран
   --------------------------------------------------------------------------- */
.hero {
  position: relative; overflow: hidden;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--s-6) var(--s-6) var(--s-5); margin-bottom: var(--s-4);
}
.hero::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 100%;
  background: radial-gradient(620px 200px at 0% 0%, var(--accent-soft), transparent 68%);
  opacity: .7; pointer-events: none;
}
.hero > * { position: relative; }
.hero-top { display: flex; align-items: flex-end; gap: var(--s-8); flex-wrap: wrap; margin-bottom: var(--s-5); }
.hero .money {
  font-family: var(--font-mono); font-size: 40px; font-weight: 600;
  letter-spacing: -.045em; word-spacing: -.22em; line-height: 1;
}
.hero .cap {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--faint); margin-top: 9px; font-weight: 500;
}
.hero .side { display: flex; gap: 0; flex-wrap: wrap; margin-left: auto; }
.hero .side > div { padding: 0 var(--s-5); border-left: 1px solid var(--border); }
.hero .side > div:first-child { border-left: none; padding-left: 0; }
.hero .side .n {
  font-family: var(--font-mono); font-size: 20px; font-weight: 500;
  letter-spacing: -.04em; word-spacing: -.2em; line-height: 1.2;
}
.hero .side .cap { margin-top: 5px; }

.distbar {
  display: flex; height: 10px; border-radius: var(--r-xs); overflow: hidden;
  background: var(--surface-3); box-shadow: inset 0 0 0 1px rgba(0,0,0,.05);
}
.distbar i { display: block; height: 100%; transition: width .3s var(--ease-out); }

.legend { display: flex; flex-wrap: wrap; gap: 7px var(--s-5); margin-top: var(--s-4); }
.legend .item { display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--muted); }
.legend .dot { width: 8px; height: 8px; border-radius: 2px; flex-shrink: 0; }
.legend .item b { color: var(--text); font-weight: 650; }
.legend .item.off { opacity: .35; }

.minibar {
  display: flex; height: 5px; border-radius: var(--r-pill); overflow: hidden;
  background: var(--surface-3); min-width: 88px;
}
.minibar i { display: block; height: 100%; }

/* ---------------------------------------------------------------------------
   ЗАДАЧИ: шапка дня
   --------------------------------------------------------------------------- */
.hero-day {
  position: relative; overflow: hidden;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--s-5) var(--s-6); margin-bottom: var(--s-6);
  display: flex; align-items: center; gap: var(--s-6); flex-wrap: wrap;
}
.hero-day::before {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(700px 240px at 88% -40%, var(--accent-soft), transparent 62%);
  pointer-events: none;
}
[data-theme="dark"] .hero-day::before { opacity: .8; }
.hero-day > * { position: relative; }
.hero-day .ring { position: relative; width: 92px; height: 92px; flex-shrink: 0; }
.hero-day .ring svg { transform: rotate(-90deg); }
.hero-day .ring circle:first-child { stroke: var(--surface-3); }
.hero-day .ring .val {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 17px; font-weight: 600; letter-spacing: -.04em;
}
.hero-day .who-day { display: flex; align-items: center; gap: 13px; }
.hero-day .greet { font-size: 20px; font-weight: 700; letter-spacing: -.03em; }
.hero-day .post {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--faint); margin-top: 4px; font-weight: 500;
}
.hero-day .who-day .date { margin-top: 7px; }
.hero-day .date { font-size: 13px; color: var(--muted); margin-top: 4px; }
.hero-day .kpis { display: flex; gap: 1px; flex-wrap: wrap; margin-left: auto;
  border: 1px solid var(--border); background: var(--border); border-radius: var(--r); overflow: hidden; }
.kpi { min-width: 104px; padding: 10px 14px 11px; background: var(--surface); }
.kpi .n { font-family: var(--font-mono); font-size: 20px; font-weight: 500; letter-spacing: -.04em; line-height: 1.15; }
.kpi .t { color: var(--faint); margin-top: 4px; display: block; }
.kpi.alarm { background: var(--danger-soft); } .kpi.alarm .n { color: var(--danger); }
.kpi.warn  { background: var(--warn-soft); }   .kpi.warn .n  { color: var(--warn); }
.kpi.ok .n { color: var(--ok); }
/* Мелкая строка под подписью: «сегодня» — новость дня, «всего» — итог работы */
.kpi .sub { margin-top: 3px; font-family: var(--font-mono); font-size: 10px; color: var(--faint); }
.kpi-link { cursor: pointer; transition: background var(--dur); }
.kpi-link:hover { background: var(--surface-2); }

/* ---------------------------------------------------------------------------
   ЗАДАЧИ: сетка и карточки
   --------------------------------------------------------------------------- */
.task-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: var(--s-3); margin-bottom: var(--s-6); }

.task-card {
  position: relative; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--s-4) var(--s-4) 13px;
  cursor: pointer; overflow: hidden; isolation: isolate;
  transition: border-color var(--dur), box-shadow var(--dur), transform var(--dur) var(--ease-out);
  display: flex; flex-direction: column;
}
.task-card .task-foot { margin-top: auto; }
/* Карточки в ряду делят общую сетку строк: название, исполнитель, прогресс,
   подвал встают на одну высоту у всех соседей. Без этого длинное название
   переносилось на третью строку и в соседней карточке разделитель с подвалом
   оказывались заметно выше — выглядело как разная вёрстка у одинаковых задач.
   Прижатие подвала книзу такую разницу не убирает: оно выравнивает низ, а
   расходятся середины. */
@supports (grid-template-rows: subgrid) {
  .task-grid { grid-auto-rows: min-content; }
  .task-card { display: grid; grid-template-rows: subgrid; grid-row: span 4; align-content: start; }
  .task-card .task-foot { margin-top: 0; align-self: end; }
  /* Пустая полоса прогресса у задач без чек-листа место не занимает. */
  .task-card .check-line:empty { margin: 0; min-height: 0; }
}
/* Состояние читается подложкой и рамкой, а не цветной полосой слева: полоса
   кодировала смысл одним лишь цветом и вдобавок дублировала чип важности. */
.task-card:hover { transform: translateY(-2px); border-color: var(--border-strong); box-shadow: var(--shadow-raise); }
/* Просрочка помечается одной красной меткой «просрочено на N дн», а не всей
   карточкой. Залитая карточка кричала на весь экран: когда просрочено пять
   задач из семи, красным становится вся доска, и различить, что именно горит,
   уже нельзя — тревога перестаёт работать ровно там, где она нужнее всего.
   Метка внутри карточки заметна не хуже, а взгляд ведёт к сроку, а не к фону. */
.task-card.is-review::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(105deg, var(--warn-soft), transparent 62%);
}
/* Закрытые задачи приглушены, но читаемы: на вкладке «Поставил я» по ним
   разбирают историю, а не просто скользят взглядом. */
.task-card.is-done { opacity: .72; }
.task-card.is-done:hover { opacity: 1; }
.task-card.is-done .task-title { text-decoration: line-through; color: var(--muted); }

.task-head { display: flex; align-items: flex-start; gap: var(--s-2); }
.task-title { font-weight: 650; font-size: 14.5px; line-height: 1.35; letter-spacing: -.015em; flex: 1; }
/* Номер задачи перед названием: им её называют в переписке и по нему открывают
   в боте. Приглушён и моноширинный — чтобы читался как метка, а не спорил с
   названием за внимание. */
/* Значок площадки. Скруглением и размером подгоняем любой файл: логотипы
   маркетплейсов бывают и квадратные, и с полями — в строке они должны стоять
   одинаково, а не прыгать. */
.plat-ico {
  width: 16px; height: 16px; border-radius: 4px; object-fit: contain;
  vertical-align: -3px; margin-right: 5px; flex: none;
}
.plat-ico + .plat-ico { margin-left: -2px; }

.task-no {
  font: 500 12px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--muted); margin-right: 7px; letter-spacing: 0;
  vertical-align: 1px; user-select: all;
}
.task-card.is-done .task-no { text-decoration: none; }

.pill {
  display: inline-flex; align-items: center; gap: 5px; flex-shrink: 0;
  padding: 3px 9px; border-radius: var(--r-xs); font-size: 11.5px; font-weight: 600;
  background: var(--surface-2); color: var(--muted); border: 1px solid var(--border);
}
.pill .dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
.pill.s-in_progress { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }
/* вернули на доработку — формально «в работе», но это не рядовая работа */
.pill.s-rework { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 30%, transparent); }
.pill.s-review { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 22%, transparent); }
.pill.s-done { background: var(--ok-soft); color: var(--ok); border-color: color-mix(in srgb, var(--ok) 22%, transparent); }
.pill.s-blocked { background: var(--danger-soft); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 22%, transparent); }

/* --- важность задачи --------------------------------------------------------
   Один визуальный словарь на все места: точка задаёт цвет, форма — степень.
   Срочно — залитая точка с ореолом, обычно — залитая, потом — полая. */
.prio-dot {
  width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
  background: var(--accent); box-shadow: 0 0 0 3px transparent;
}
.prio-dot[data-p="high"]   { background: var(--danger); box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 20%, transparent); }
.prio-dot[data-p="normal"] { background: var(--accent); }
.prio-dot[data-p="low"]    { background: transparent; box-shadow: inset 0 0 0 1.5px var(--faint); }

.prio {
  display: inline-flex; align-items: center; gap: 6px; padding: 3px 9px;
  border-radius: var(--r-xs); font-size: 11.5px; font-weight: 600; white-space: nowrap;
  background: var(--surface-2); color: var(--muted); border: 1px solid var(--border);
}
.prio[data-p="high"] {
  background: var(--danger-soft); color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 22%, transparent);
}
.prio[data-p="normal"] { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }

/* Переключатель важности в форме: три варианта — выбор кнопками, не списком */
.seg {
  display: flex; gap: 2px; padding: 2px;
  background: var(--surface-2); border: 1px solid var(--border-strong); border-radius: var(--r-sm);
}
.seg-btn {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  border: none; background: transparent; padding: 7px 8px; border-radius: var(--r-xs);
  font-size: 12.5px; font-weight: 500; color: var(--muted); cursor: pointer; white-space: nowrap;
  min-width: 0;
  transition: background var(--dur), color var(--dur);
}
.seg-btn:hover { color: var(--text); }
.seg-btn.on { background: var(--surface); color: var(--text); font-weight: 600; box-shadow: var(--shadow-raise); }
[data-theme="dark"] .seg-btn.on { background: var(--surface-3); }

.task-row { display: flex; align-items: center; gap: var(--s-2); margin-top: 11px; flex-wrap: wrap; }
.ava {
  width: 24px; height: 24px; border-radius: var(--r-xs); display: grid; place-items: center;
  font-size: 10px; font-weight: 700; color: #fff; flex-shrink: 0; letter-spacing: .01em;
  overflow: hidden;
}
img.ava { object-fit: cover; }
.ava-lg { width: 46px; height: 46px; border-radius: 12px; font-size: 17px; }
.ava-sm { width: 20px; height: 20px; font-size: 8.5px; }
.ava-xs { width: 17px; height: 17px; font-size: 7.5px; border-radius: 4px; }

/* --- карточки сотрудников на вкладке «Все задачи» --- */
.people {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(232px, 1fr));
  gap: 1px; margin-bottom: var(--s-4);
  background: var(--border); border: 1px solid var(--border);
  border-radius: var(--r-md); overflow: hidden;
}
.person { background: var(--surface); padding: 14px var(--s-4); min-width: 0; }
/* Ячейка расчёта в списке юнитки: по ней открывают карточку */
td.clickable { cursor: pointer; }
td.clickable:hover { background: var(--surface-2); }

.person.clickable { cursor: pointer; transition: background var(--dur); }
.person.clickable:hover { background: var(--surface-2); }
.person-top { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.person-name { font-size: 13.5px; font-weight: 650; letter-spacing: -.01em; }
.person-role {
  font-size: 11.5px; color: var(--faint); margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.person .edit {
  margin-left: auto; opacity: 0; color: var(--faint);
  transition: opacity var(--dur), color var(--dur);
}
.person .edit svg { width: 15px; height: 15px; display: block; }
.person.clickable:hover .edit { opacity: 1; color: var(--accent); }
@media (hover: none) { .person .edit { opacity: .6; } }

/* Разбивка по стадиям: цифра над подписью, разделены волосяными линиями */
.stages { display: flex; }
.stages > div {
  flex: 1; min-width: 0; padding-left: 10px; border-left: 1px solid var(--border);
}
.stages > div:first-child { padding-left: 0; border-left: none; }
.stages .n {
  font-family: var(--font-mono); font-size: 17px; font-weight: 500;
  letter-spacing: -.04em; line-height: 1.1; font-variant-numeric: tabular-nums;
}
.stages .t {
  font-family: var(--font-mono); font-size: 9px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--faint); margin-top: 4px; font-weight: 500;
}
.stages .n.zero { color: var(--faint); opacity: .55; }
.stages .n.alarm { color: var(--danger); }
.stages .n.warn { color: var(--warn); }
.stages .n.ok { color: var(--ok); }
.stages .n.go { color: var(--accent); }
.who { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--text); font-weight: 550; }

.tag {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 8px; border-radius: var(--r-xs);
  font-size: 11.5px; background: var(--surface-2); color: var(--muted); white-space: nowrap;
  border: 1px solid var(--border);
}
.tag svg { width: 12px; height: 12px; }
.tag.late { background: var(--danger-soft); color: var(--danger); font-weight: 600; border-color: color-mix(in srgb, var(--danger) 22%, transparent); }
.tag.soon { background: var(--warn-soft); color: var(--warn); font-weight: 600; border-color: color-mix(in srgb, var(--warn) 22%, transparent); }
.tag.flag { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 22%, transparent); }
/* Непрочитанные сообщения в обсуждении задачи. Цвет отдельный — бирюзовый:
   срок, важность и статус уже заняли жёлтый, красный и ирис */
.tag.unread {
  background: var(--msg-soft); color: var(--msg); font-weight: 650;
  border-color: var(--msg-line);
  animation: msg-pulse 1.9s var(--ease) infinite;
}
@keyframes msg-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--msg) 40%, transparent); }
  55%      { box-shadow: 0 0 0 5px color-mix(in srgb, var(--msg) 0%, transparent); }
}
/* Сдвиг даты выхода запуска — заметно, но не как авария */
.tag.shift { background: var(--warn-soft); color: var(--warn); font-weight: 600; border-color: color-mix(in srgb, var(--warn) 22%, transparent); }

.check-line { display: flex; align-items: center; gap: var(--s-2); margin-top: 12px; }
.check-line .n { font-family: var(--font-mono); font-size: 10.5px; color: var(--faint); }

.progress { height: 5px; border-radius: var(--r-pill); background: var(--surface-3); overflow: hidden; flex: 1; min-width: 60px; }
.progress span { display: block; height: 100%; background: var(--accent); border-radius: var(--r-pill); transition: width .3s var(--ease-out); }
.progress.full span { background: var(--ok); }

/* Подвал прижат к низу карточки через margin-top:auto — из-за этого собственный
   верхний отступ у него всегда нулевой. Поэтому зазор до разделителя задаём
   отступом самого подвала, а линию рисуем внутри: тогда она не липнет
   к аватарке и тегу срока, какой бы короткой ни была карточка. */
.task-foot {
  position: relative;
  display: flex; align-items: center; gap: 7px; padding-top: 25px;
  font-size: 11.5px; color: var(--muted); flex-wrap: wrap;
}
.task-foot::before {
  content: ''; position: absolute; left: 0; right: 0; top: 15px;
  height: 1px; background: var(--border);
}
.task-actions { display: flex; gap: 5px; margin-left: auto; opacity: 0; transform: translateY(2px); transition: opacity .15s, transform .15s; }
.task-card:hover .task-actions { opacity: 1; transform: none; }
@media (hover: none) { .task-actions { opacity: 1; transform: none; } }

.add-card {
  border: 1px dashed var(--border-strong); border-radius: var(--r-md); background: transparent;
  display: grid; place-items: center; min-height: 124px; cursor: pointer; color: var(--muted);
  font-size: 13px; transition: border-color var(--dur), color var(--dur), background var(--dur);
}
.add-card:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }

.group-head { display: flex; align-items: center; gap: 10px; margin: 0 0 var(--s-3); }
.group-head h3 { color: var(--muted); font-weight: 600; }
.group-head .count {
  font-family: var(--font-mono); background: var(--surface-2); color: var(--muted);
  border: 1px solid var(--border); border-radius: var(--r-xs);
  padding: 0 6px; font-size: 11px; font-weight: 500;
}
.group-head .rule { flex: 1; height: 1px; background: var(--border); }
.group-head.alarm h3 { color: var(--danger); }
.group-head.alarm .count { color: var(--danger); background: var(--danger-soft); border-color: color-mix(in srgb, var(--danger) 22%, transparent); }

.task-top .badge { flex-shrink: 0; margin-top: 1px; }

/* ---------------------------------------------------------------------------
   ФОКУС И ДВИЖЕНИЕ
   --------------------------------------------------------------------------- */
/* Фокус — мягкое свечение по форме элемента. Жёсткий outline с отступом
   ложился поверх акцентной рамки поля и давал двойную обводку. */
:focus { outline: none; }
:focus-visible { outline: none; box-shadow: var(--focus-ring); }
input:focus-visible, select:focus-visible, textarea:focus-visible { border-color: var(--accent); }

.view.active { animation: fade .2s var(--ease-out); }
@keyframes fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

.modal { animation: pop .18s var(--ease-out); }
@keyframes pop { from { opacity: 0; transform: scale(.985) translateY(8px); } to { opacity: 1; transform: none; } }
.modal-bg { animation: fade .14s ease; }
.toast { animation: slide .22s var(--ease-out); }
@keyframes slide { from { opacity: 0; transform: translateX(16px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  .task-card:hover { transform: none; }
}

/* ---------------------------------------------------------------------------
   УЗКИЕ ЭКРАНЫ
   --------------------------------------------------------------------------- */
@media (max-width: 1100px) {
  .topbar, .tabs, .content { padding-left: var(--s-5); padding-right: var(--s-5); }
}

@media (max-width: 900px) {
  .layout { flex-direction: column; }
  /* На узком экране меню становится верхней полосой: липнет уже сам блок,
     а внутренний рельс перестаёт быть колонкой во всю высоту. */
  .sidebar {
    width: 100%; align-self: auto; position: sticky; top: 0; z-index: 40;
    border-right: none; border-bottom: 1px solid var(--rail-border);
  }
  .sidebar > .rail {
    position: static; height: auto;
    flex-direction: row; align-items: center;
    overflow-x: auto; gap: 4px; padding: var(--s-2) var(--s-3);
  }
  /* На узком экране рельс становится горизонтальной полосой — значит и список
     разделов должен ехать вбок, а не вниз. */
  .nav-scroll { flex-direction: row; overflow-x: auto; overflow-y: hidden; flex: 1; }
  .brand { padding: 0 var(--s-3) 0 var(--s-1); }
  .brand .who { display: none; }
  .nav-label { display: none; }
  .me { padding: 6px; margin: 0; }
  .me-text, .me-edit { display: none; }
  .sidebar-foot { margin: 0 0 0 auto; border: none; padding: 0; display: flex; gap: 2px; }
  .nav-item span:not(.soon) { display: none; }
  .nav-item.active::before { display: none; }
  .nav-item.active { background: var(--rail-active-bg); }
  .tabs { position: static; backdrop-filter: none; background: transparent; }
  .topbar { padding-top: var(--s-5); padding-bottom: var(--s-4); }
  .topbar h1 { font-size: 22px; }
  .task-grid { grid-template-columns: 1fr; }
  .hero .side { margin-left: 0; }
  .hero .side > div:first-child { padding-left: 0; }
  .hero .money { font-size: 32px; }
  .hero-day .kpis { margin-left: 0; }
}

@media (max-width: 560px) {
  .topbar, .tabs, .content { padding-left: var(--s-4); padding-right: var(--s-4); }
  .stats { grid-template-columns: 1fr 1fr; }
  .hero .side > div { padding: 0 var(--s-4); }
}

/* ---------------------------------------------------------------------------
   ЮНИТ-ЭКОНОМИКА
   --------------------------------------------------------------------------- */

/* Разложение цены: строки читаются сверху вниз, как убывающая сумма */
table.waterfall tbody td { padding: 9px 12px; }
table.waterfall tbody td:first-child { font-size: 13px; }
table.waterfall .wf-base td { font-weight: 650; background: var(--surface-2); }
table.waterfall .wf-base td.num { font-size: 15px; }
table.waterfall .wf-dim td { color: var(--faint); }
table.waterfall .wf-fee td.num { color: var(--muted); }
table.waterfall .wf-total td { font-weight: 650; border-top: 1px solid var(--border-strong); }
table.waterfall .wf-total + .wf-total td { border-top: none; }
table.waterfall tbody td.num {
  font-family: var(--font-mono); font-size: 13px;
  letter-spacing: -.02em; word-spacing: -.18em;
}

/* Плановая цена — та, по которой реально продаём: колонку обводим целиком,
   чтобы глаз находил её сразу, не считая столбцы. */
table.waterfall th.plan,
table.waterfall tbody td.plan,
table.waterfall .wf-base td.plan {
  background: color-mix(in srgb, var(--accent) 7%, var(--surface));
  border-left: 1px solid var(--accent-line);
  border-right: 1px solid var(--accent-line);
}
table.waterfall thead tr:first-child th.plan { border-top: 1px solid var(--accent-line); }
table.waterfall thead tr.head-note th.plan { border-bottom-color: var(--accent-line); }
table.waterfall tbody tr:last-child td.plan { border-bottom: 1px solid var(--accent-line); }

/* Итог красится по смыслу: убыток, на грани, рабочая маржа */
.good { color: var(--ok); }
.warn { color: var(--warn); }
.bad { color: var(--danger); }
td.good, td.warn, td.bad { font-weight: 650; }

/* В своде две площадки рядом — разделяем их вертикальной линией */
thead th[colspan] { text-align: center; border-left: 1px solid var(--border); }
thead th[colspan]:first-of-type { border-left: none; }

/* Подсказки по категориям: их тысячи, выбираем поиском */
.cat-hits {
  position: absolute; z-index: 40; margin-top: 4px; max-height: 260px; overflow: auto;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r); box-shadow: var(--shadow-lg); min-width: 320px;
}
.cat-hit {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px 12px; cursor: pointer; border-bottom: 1px solid var(--border);
}
.cat-hit:last-child { border-bottom: none; }
.cat-hit:hover { background: var(--surface-2); }
.field { position: relative; }

/* Кнопка «показать все» под длинной таблицей */
tr.more-row td {
  padding: 6px 10px; text-align: center; background: var(--surface-2);
  border-top: 1px solid var(--border);
}
tr.more-row .btn { color: var(--accent); }
tr.more-row .btn:hover { background: var(--accent-soft); }

/* Ввод для расчёта: три блока рядом, на узком экране — в столбик */
.unit-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
  gap: var(--s-3); align-items: start;
}
.unit-grid .panel { margin-bottom: 0; }

/* Скидка сценария правится прямо в шапке колонки */
.sc-disc {
  display: flex; align-items: center; justify-content: flex-end; gap: 4px;
  margin-top: 4px; font-weight: 400; color: var(--faint);
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .04em;
}
.sc-disc input {
  width: 46px; padding: 2px 5px; text-align: right;
  font-family: var(--font-mono); font-size: 11px; border-radius: var(--r-xs);
}

/* Ставка, заданная руками, должна бросаться в глаза: иначе расчёт врёт молча */
.manual-rate {
  display: flex; align-items: center; gap: 10px; margin-top: 12px;
  padding: 9px 12px; border-radius: var(--r);
  background: var(--warn-soft); border: 1px solid color-mix(in srgb, var(--warn) 26%, transparent);
  font-size: 13px;
}
.manual-rate b { color: var(--warn); }
.manual-rate .btn { margin-left: auto; flex-shrink: 0; }

/* Маршрут Ozon: откуда и куда едет посылка. Названия кластеров длинные
   («Москва, МО и Дальние регионы»), поэтому оба поля идут на всю ширину
   панели друг под другом, а стрелка между ними показывает направление. */
.route {
  padding: 12px; border-radius: var(--r);
  background: var(--surface-2); border: 1px solid var(--border);
}
.route .field + .route-arrow { margin: 4px 0 2px; }
.route-arrow { color: var(--faint); font-size: 13px; line-height: 1; }
.route-note { margin-top: 10px; font-size: 11.5px; line-height: 1.55; }
.route-note b { color: var(--text); font-family: var(--font-mono); }

/* Подпись под шапкой таблицы: по какой цене посчитаны цифры.
   Верхняя строка шапки лишается нижней линии, чтобы две строки читались как одна. */
thead tr.head-note th {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--faint); font-weight: 500; text-align: center;
  padding: 7px 10px 9px; border-bottom: 1px solid var(--border);
}
thead tr:has(+ tr.head-note) th { border-bottom: none; padding-bottom: 4px; }
thead tr.head-note th:empty { border-left: none; }

/* ---------------------------------------------------------------------------
   ЗАПУСКИ ТОВАРОВ
   Этапы идут параллельно, поэтому вместо линейки — дорожки: в каждой свой
   ряд плиток, и по цвету видно, что закрыто, что в работе, что ждёт очереди.
   --------------------------------------------------------------------------- */

/* Загрузка по этапам */
/* Этапов может быть больше десятка — без прокрутки колонки просто уезжали
   бы за край без следа. Прокрутка — подстраховка, основной случай закрывает
   перенос подписи ниже. */
.funnel { display: flex; align-items: flex-end; gap: 8px; overflow-x: auto; padding-bottom: 2px; }
.funnel-col { flex: 1 1 64px; min-width: 64px; display: flex; flex-direction: column; align-items: center; gap: 7px; }
.funnel-stack {
  display: flex; flex-direction: column; justify-content: flex-end; gap: 2px;
  width: 100%; max-width: 92px; height: 56px;
}
.funnel-bar {
  border-radius: 4px; display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 600; color: #fff;
}
.funnel-bar.work { background: var(--warn); }
.funnel-bar.done { background: var(--accent); }
/* Класс называется none, а не empty: глобальный .empty — это пустое состояние
   раздела с большим паддингом, и столбик воронки от него раздувался. */
.funnel-bar.none { height: 4px; background: var(--surface-3); }
/* Высота держится под две строки всегда, даже у короткой подписи в одну
   строку — иначе колонки становятся разной высоты и прямоугольники,
   выровненные по низу всего блока, съезжают друг относительно друга. */
.funnel-name { font-size: 10.5px; color: var(--faint); text-align: center; line-height: 1.25; min-height: 26px; }

/* Дорожки этапов */
.lanes { display: flex; flex-direction: column; gap: 6px; margin: 10px 0 4px; }
.lane { display: flex; align-items: center; gap: 10px; }
.lane-name {
  width: 74px; flex-shrink: 0; text-align: right;
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--faint);
}
.lane-row { display: flex; gap: 6px; flex: 1; flex-wrap: wrap; }
/* Компактный вид для ленты: в списке важно «где стоим», подробности — в карточке */
.lanes-sm .st { padding: 6px 10px; }
.lanes-sm .st-sub { margin-top: 1px; font-size: 10px; }

.st {
  flex: 0 0 196px; padding: 7px 10px 8px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface); transition: border-color .15s ease, background .15s ease, transform .12s ease;
}
[data-stage].st { cursor: pointer; }
[data-stage].st:hover { border-color: var(--accent); transform: translateY(-1px); }
.st-top { display: flex; align-items: center; gap: 7px; }
.st-mark {
  width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0;
  background: var(--surface-3); border: 1.5px solid var(--border-strong);
}
.st-title { font-size: 12.5px; font-weight: 600; }
.st-sub { font-size: 10.5px; color: var(--faint); margin-top: 3px; margin-left: 16px; }
.st-bar {
  height: 3px; border-radius: 2px; background: var(--surface-3);
  margin: 6px 0 0 16px; overflow: hidden;
}
.st-bar i { display: block; height: 100%; background: var(--accent); }

/* Готово */
.st-done { background: color-mix(in srgb, var(--accent) 8%, var(--surface)); border-color: color-mix(in srgb, var(--accent) 30%, transparent); }
.st-done .st-mark { background: var(--accent); border-color: var(--accent); }
.st-done .st-title { color: var(--muted); }

/* В работе */
.st-work { border-color: var(--accent); }
.st-work .st-mark {
  background: var(--surface); border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent);
}
.st-work .st-sub { color: var(--muted); }

/* Взяли раньше очереди — не ошибка, но пометить надо */
.st-early { border-color: color-mix(in srgb, var(--warn) 45%, transparent); }
.st-early .st-mark { border-color: var(--warn); box-shadow: 0 0 0 3px color-mix(in srgb, var(--warn) 18%, transparent); }

/* Выбранный этап: его чек-лист открыт ниже */
/* Этап стоит: не «медленно», а «не идёт» — поэтому красный, а не жёлтый */
.st-blocked { border-color: var(--danger); background: color-mix(in srgb, var(--danger) 7%, var(--surface)); }
.st-blocked .st-mark { border-color: var(--danger); background: color-mix(in srgb, var(--danger) 30%, transparent); }
.st-blocked .st-sub { color: var(--danger); }
.row-blocked td { background: color-mix(in srgb, var(--danger) 5%, transparent); }
/* Метка «из какого запуска задача»: выделяем, чтобы три одинаковых названия
   в списке различались с одного взгляда */
.tag.src-tag { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }
/* Завершённый запуск: строка живёт, но уже не требует внимания */
.row-done td { opacity: .62; }
/* Название запуска со стрелкой: длинное имя переносится по словам, а стрелка
   остаётся на своей строке слева. Инлайновой кнопкой её утаскивало в перенос */
.lc-name { display: flex; align-items: flex-start; gap: 8px; min-width: 200px; }
.lc-name > span { min-width: 0; }
.lc-toggle { padding: 0 6px; font-family: var(--font-mono); flex: none; }
.lc-toggle.on { color: var(--accent); border-color: var(--accent-line); }
.lc-lanes-row > td { padding: 4px 12px 14px; background: var(--surface-2); }

.st-focus { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 35%, transparent); }

/* Не требуется: этап есть, но в этом запуске не проходится */
.st-skip { opacity: .5; border-style: dashed; }
.st-skip .st-title { text-decoration: line-through; color: var(--faint); }

/* Кому поручено — аватар прямо на плитке */
.st-who { margin-left: auto; display: inline-flex; }
.st-who.bad { box-shadow: 0 0 0 2px var(--danger); border-radius: 5px; }

/* Ждёт очереди / можно начинать */
.st-idle { background: transparent; border-style: dashed; }
.st-ready { border-color: var(--border-strong); }
.st-ready .st-title { color: var(--text); }
.st-idle:not(.st-ready) .st-title { color: var(--faint); }

.ready-chip { border-color: color-mix(in srgb, var(--accent) 35%, transparent); color: var(--accent); }
.warn-chip { border-color: color-mix(in srgb, var(--warn) 40%, transparent); color: var(--warn); }
.ok-chip { border-color: color-mix(in srgb, var(--ok) 40%, transparent); color: var(--ok); }
/* возврат на доработку — состояние тревожнее ожидания, поэтому красный */
.bad-chip { border-color: color-mix(in srgb, var(--danger) 45%, transparent); color: var(--danger); }

/* Карточка запуска в ленте */
.lc { padding: 14px 16px 12px; }
.lc-late { border-left: 3px solid var(--danger); }
.lc-done { opacity: .72; }
.lc-top { display: flex; align-items: center; gap: 12px; cursor: pointer; }
.lc-img { width: 44px; height: 44px; border-radius: var(--r-sm); object-fit: cover; flex-shrink: 0; }
.lc-name { font-weight: 650; font-size: 15px; }
.lc-name .lc-art { font-weight: 400; font-size: 10.5px; }
.lc-meta { display: flex; gap: 6px; align-items: center; margin-top: 5px; flex-wrap: wrap; }
.lc-right { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.lc-owner { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--muted); }
.lc-date { font-family: var(--font-mono); font-size: 11.5px; color: var(--muted); }
.lc-date.bad { color: var(--danger); font-weight: 600; }
.lc-date.warn { color: var(--warn); font-weight: 600; }
.lc-date.ok { color: var(--ok); }
.lc-foot {
  display: flex; align-items: center; gap: 6px; margin-top: 10px; flex-wrap: wrap;
  border-top: 1px solid var(--border); padding-top: 10px; font-size: 12.5px;
}

/* Действия в строке запуска: папка проекта рядом с «Открыть». Иконка без
   подписи — в строке нет места на слова, а смысл держит подсказка.
   Flex живёт на внутреннем блоке, а не на самой ячейке: у td с display:flex
   пропадает фон строки, и справа оставалась белая заплата. */
.lc-actions { display: flex; align-items: center; gap: 6px; justify-content: flex-end; }
.lc-folder {
  text-decoration: none; padding-inline: 8px; line-height: 1;
  display: inline-flex; align-items: center; color: var(--muted);
}
.lc-folder:hover { color: var(--text); }
.lc-folder svg { width: 15px; height: 15px; }
.chip-link svg { width: 14px; height: 14px; flex: none; }

/* Этап и его исполнитель — одно целое, переносим только между парами */
.lc-work { white-space: nowrap; }

/* Строка «стоит: …» — предупреждение, а не простыня: коротко, в одну-две
   строки, полный текст причин показывает подсказка. */
.lc-stopped { font-size: 11.5px; color: var(--danger); margin-top: 3px; cursor: help; }
.lc-stopped .lc-who { color: color-mix(in srgb, var(--danger) 70%, var(--muted)); }
.lc-stuck { font-size: 11.5px; color: var(--warn); margin-top: 3px; }
.lc-stuck .lc-who { color: color-mix(in srgb, var(--warn) 70%, var(--muted)); }

/* Имя исполнителя рядом с названием этапа. Без своего стиля оно вставало
   впритык — читалось как «Бриф на контентДмитрий». */
.lc-who {
  margin-left: 5px; color: var(--muted); font-size: 11.5px;
}
.lc-who::before { content: '· '; }

/* Полоска прогресса в списке */
.mini-bar {
  width: 64px; height: 4px; border-radius: 2px; background: var(--surface-3);
  overflow: hidden; display: inline-block; vertical-align: middle;
}
.mini-bar i { display: block; height: 100%; background: var(--accent); }
tr.row-late td:first-child { box-shadow: inset 3px 0 0 var(--danger); }

/* Карточка запуска в окне */
.lm-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
/* Строка под дорожкой: слева подсказка, справа кнопки настройки —
   раньше кнопки терялись в тексте и их не находили */
.lm-hint { font-size: 11.5px; margin: 6px 0 0 84px; display: flex; align-items: center; gap: 8px; }
.lm-grid { display: grid; grid-template-columns: 1.35fr 1fr; gap: 12px; margin-top: 12px; align-items: start; }
.lm-check { display: flex; flex-direction: column; gap: 2px; }
.check-row {
  display: flex; align-items: center; gap: 9px; padding: 7px 8px;
  border-radius: var(--r-sm); font-size: 13.5px; cursor: pointer;
}
/* Без этого глобальное input { width: 100% } растягивает флажок на всю строку,
   и текст пункта уезжает к правому краю. */
.check-row input[type="checkbox"] {
  width: 15px; min-width: 15px; height: 15px; margin: 0; flex-shrink: 0; cursor: pointer;
}
.check-row span { flex: 1; }
.check-row:hover { background: var(--surface-2); }
.check-row.is-done span { color: var(--faint); text-decoration: line-through; }
.lm-addrow { display: flex; gap: 6px; margin-top: 10px; }
.lm-addrow input { flex: 1; }
.lm-stage-actions {
  display: flex; gap: 6px; margin-top: 12px; border-top: 1px solid var(--border);
  padding-top: 12px; flex-wrap: wrap; align-items: center;
}
.assigned-box {
  display: flex; align-items: center; gap: 10px; flex: 1 1 100%;
  padding: 8px 10px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--border); font-size: 12.5px;
}
.assigned-box > div { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.assigned-box .btn { margin-left: auto; }
.stage-note { flex: 1 1 100%; font-size: 11.5px; line-height: 1.5; margin-top: 2px; }
.eco-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.eco-cell { padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--r-sm); }
.eco-plat { font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--faint); }
.eco-main { font-family: var(--font-mono); font-size: 22px; font-weight: 600; margin-top: 4px; }
.eco-sub { font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.eco-warn { font-size: 11px; color: var(--warn); margin-top: 4px; }
.lm-stock { font-size: 14px; }
.lm-places { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.lm-feed { display: flex; flex-direction: column; gap: 6px; }
.feed-row { display: flex; gap: 10px; font-size: 12.5px; color: var(--muted); }
.feed-date { font-family: var(--font-mono); font-size: 11px; color: var(--faint); min-width: 74px; }

@media (max-width: 1100px) {
  .lm-grid { grid-template-columns: 1fr; }
  .lane { align-items: flex-start; }
  .lane-name { width: 60px; }
}

/* Чек-лист этапа только показывает состояние: отмечают его в задаче */
.check-row.is-static { cursor: default; }
.check-row.is-static:hover { background: transparent; }
.check-row.is-static input { cursor: default; }

/* Акции: выбор товаров и таблица расчёта */
.pr-pick {
  max-height: 260px; overflow: auto; border: 1px solid var(--border);
  border-radius: var(--r); padding: 4px 8px;
}
table.promo-table input[type="number"] { text-align: right; }
table.promo-table thead tr.head-note th { text-transform: none; letter-spacing: 0; font-size: 10.5px; }
.promo-foot { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* Акция: «было» и «станет» разделены фоном, чтобы читались как два расчёта */
table.promo-table th.was, table.promo-table td.was { background: var(--surface-2); }
table.promo-table th.now, table.promo-table td.now {
  background: color-mix(in srgb, var(--accent) 5%, var(--surface));
}
table.promo-table th.was:first-of-type, table.promo-table td.was:first-of-type { border-left: 1px solid var(--border); }
table.promo-table th.now, table.promo-table td.now { border-left: 1px solid var(--border); }

/* Решение по товару в акции: две короткие кнопки, состояние читается цветом */
.dec-btns { display: inline-flex; gap: 3px; }
.dec {
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--muted);
  border-radius: var(--r-xs); padding: 3px 9px; font-size: 12px; cursor: pointer;
  font-family: var(--font-sans); transition: all var(--dur);
}
.dec:hover { color: var(--text); border-color: var(--text); }
.dec.on-in { background: var(--ok); border-color: var(--ok); color: #fff; font-weight: 600; }
.dec.on-out { background: var(--surface-3); border-color: var(--border-strong); color: var(--text); font-weight: 600; }

/* Обработанная акция уходит в архивный вид: её уже не трогают */
tr.row-archived td { opacity: .55; }
tr.row-archived:hover td { opacity: .8; }
/* Утверждённые цифры: не поле, а значение — их вносят в кабинет как есть */
.frozen { font-family: var(--font-mono); font-size: 13px; color: var(--text); }

/* ---------------------------------------------------------------------------
   КОНКУРЕНТЫ
   Ряд читают глазами сверху вниз: дешёвый первый, наша строка подсвечена.
   Поэтому строка — не ячейки таблицы, а карточка с фото и крупной ценой.
   --------------------------------------------------------------------------- */

.rv-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
.rv-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 14px; cursor: pointer; transition: border-color var(--dur), transform var(--dur) var(--ease-out);
}
.rv-card:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.rv-card.alarm { border-color: color-mix(in srgb, var(--danger) 32%, var(--border)); }
.rv-card-top { display: flex; gap: 12px; align-items: flex-start; }
.rv-card-top img { width: 52px; height: 68px; object-fit: cover; border-radius: var(--r-sm); border: 1px solid var(--border); }
.rv-noimg {
  display: flex; align-items: center; justify-content: center; color: var(--faint);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm);
  width: 52px; height: 68px;
}
.rv-noimg svg { width: 20px; height: 20px; }
.rv-name { font-weight: 650; font-size: 13.5px; line-height: 1.3; }
.rv-plat { font-family: var(--font-mono); font-size: 11px; color: var(--faint); margin-top: 4px; }
.rv-nums { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 12px; }
.rv-nums .n { font-family: var(--font-mono); font-size: 15px; font-weight: 500; letter-spacing: -.03em; }
.rv-nums .n.bad { color: var(--danger); } .rv-nums .n.good { color: var(--ok); }
.rv-nums .t {
  font-family: var(--font-mono); font-size: 9px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--faint); margin-top: 2px;
}
.rv-sigs { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 11px; }
.rv-sig { font-size: 11px; padding: 2px 7px; border-radius: var(--r-xs); border: 1px solid var(--border); }
.rv-sig.bad { background: var(--danger-soft); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 22%, transparent); }
.rv-sig.warn { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 22%, transparent); }
.rv-sig.good { background: var(--ok-soft); color: var(--ok); border-color: color-mix(in srgb, var(--ok) 22%, transparent); }
.rv-when { font-family: var(--font-mono); font-size: 10.5px; color: var(--faint); margin-top: 10px; }

/* окно ряда */
/* Шапка ряда: чипы, кнопки и время сбора. Переносим строкой — без wrap при
   нехватке ширины flex сжимает элементы, и «5 мин назад» ломается по одному
   слову в строку, а чипы обрезаются на середине даты. */
.rv-head {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  margin-bottom: 14px;
}
.rv-head .chip, .rv-head .faint { white-space: nowrap; }
/* Распорка работает, только пока строка одна: после переноса она бы утащила
   хвост на отдельную строку и оставила пустоту. */
.rv-head .spacer { flex: 1 1 auto; min-width: 0; }
.rv-signals { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.rv-signal {
  display: flex; gap: 9px; align-items: center; padding: 9px 12px;
  border: 1px solid var(--border); border-radius: var(--r); background: var(--surface);
}
.rv-signal .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--muted); }
/* Плашка растёт по содержимому, но не шире четверти окна — текст переносится,
   а не обрубается: обрубок посреди слова читается хуже длинной строки. */
.rv-signal { min-width: 0; max-width: min(420px, 100%); align-items: flex-start; }
.rv-signal .dot { margin-top: 5px; }
.rv-signal b, .rv-signal .t { overflow-wrap: anywhere; }
.rv-signal .t { font-size: 12px; color: var(--muted); margin-top: 2px; }
.rv-signal.bad { background: var(--danger-soft); border-color: color-mix(in srgb, var(--danger) 22%, transparent); }
.rv-signal.bad .dot { background: var(--danger); }
.rv-signal.warn { background: var(--warn-soft); border-color: color-mix(in srgb, var(--warn) 22%, transparent); }
.rv-signal.warn .dot { background: var(--warn); }
.rv-signal.good { background: var(--ok-soft); border-color: color-mix(in srgb, var(--ok) 22%, transparent); }
.rv-signal.good .dot { background: var(--ok); }

/* Ширины колонок приходят из кода (их набор настраивается), поэтому здесь
   только общие правила. Таблица шире экрана не ломается, а прокручивается:
   колонок стало под два десятка, и при сжатии они наезжали друг на друга. */
.rv-scroll { overflow-x: auto; padding-bottom: 4px; }
.rv-th, .rv-row { display: grid; gap: 9px; min-width: max-content; }
.rv-th > div, .rv-row > div { min-width: 0; }
.rv-th { align-items: end; }
/* Ячейки выравниваем по верхнему краю: у разных участников подписей разное
   количество, и при выравнивании по центру числа в строке плясали. */
.rv-row { align-items: start; }
/* Первые строки ячеек — одной высоты, иначе шрифты разного размера съезжают
   по вертикали и «ровно по верху» видно только в разметке, а не глазом. */
.rv-row .rv-place, .rv-row .rv-price, .rv-row .rv-num,
.rv-row .rv-rate, .rv-row .rv-ctr { line-height: 21px; }
/* Движение цены за сутки: вниз — зелёным (конкурент давит), вверх — красным */
.rv-move { font-family: var(--font-mono); font-size: 13px; }
.rv-move.down { color: var(--ok); }
.rv-move.up { color: var(--danger); }
.rv-move.flat { color: var(--faint); font-size: 10.5px; }

/* Прирост отзывов за сутки — живой признак, что карточку покупают */
.rv-fbup { color: var(--ok); font-weight: 600; }
/* Соинвест: сколько за скидку доплачивает Ozon, а не мы */
.rv-coinvest {
  display: flex; gap: 18px; flex-wrap: wrap; align-items: baseline;
  margin: 10px 0 2px; padding: 10px 12px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
}
.rv-coinvest .lbl { font-family: var(--font-mono); font-size: 9px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--faint); display: block; margin-bottom: 3px; }
.rv-coinvest .val { font-size: 15px; font-weight: 600; }
.rv-coinvest .val small { font-size: 11px; font-weight: 400; color: var(--faint); margin-left: 5px; }
/* День, которого нет: Ozon скрыл остаток — не ноль продаж, а незнание */
.rv-hidden { color: var(--faint); }
.rv-th {
  padding: 0 12px 7px; font-family: var(--font-mono); font-size: 9px;
  letter-spacing: .07em; text-transform: uppercase; color: var(--faint);
}
.rv-row {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
  padding: 10px 12px; margin-bottom: 7px;
}
/* Наша строка: её ищут глазами первой */
.rv-row.mine { border-color: var(--accent-line); background: color-mix(in srgb, var(--accent-soft) 55%, var(--surface)); }
/* Данные старше суток — по ним нельзя принимать решение */
.rv-row.stale { opacity: .6; }
.rv-place { font-family: var(--font-mono); font-size: 14px; color: var(--faint); text-align: center; }
.rv-row.mine .rv-place { color: var(--accent); font-weight: 700; }
.rv-ph { width: 52px; height: 68px; object-fit: cover; border-radius: var(--r-sm); border: 1px solid var(--border); }
.rv-title { font-weight: 600; font-size: 13px; line-height: 1.3; }
.rv-me {
  background: var(--accent); color: #fff; font-size: 10px; padding: 1px 6px;
  border-radius: var(--r-xs); margin-right: 6px; vertical-align: 1px;
}
.rv-sub { font-family: var(--font-mono); font-size: 10.5px; color: var(--faint); margin-top: 3px; }
.rv-cat {
  display: inline-block; font-size: 10.5px; color: var(--muted); background: var(--surface-2);
  border: 1px solid var(--border); border-radius: var(--r-xs); padding: 1px 6px; margin-top: 4px;
}
.rv-cat.promo { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 22%, transparent); }
.rv-price { font-family: var(--font-mono); font-size: 16px; font-weight: 600; letter-spacing: -.03em; }
.rv-old { font-family: var(--font-mono); font-size: 10.5px; color: var(--faint); text-decoration: line-through; }
.rv-delta { font-size: 11px; margin-top: 3px; font-weight: 600; }
.rv-delta.bad { color: var(--danger); } .rv-delta.good { color: var(--ok); }
.rv-delta.flat { color: var(--faint); font-weight: 500; }
.rv-rate { font-family: var(--font-mono); font-size: 13px; }
.rv-rate.good { color: var(--ok); } .rv-rate.bad { color: var(--danger); }
.rv-arrow { font-weight: 700; }
.rv-fb { font-family: var(--font-mono); font-size: 10.5px; color: var(--faint); margin-top: 3px; }
.rv-num { font-family: var(--font-mono); font-size: 14px; }
.rv-num small { display: block; font-family: var(--font-sans); font-size: 10px; color: var(--faint); margin-top: 2px; }
/* Месячный итог — вспомогательная строка, не спорит с главным числом */
.rv-num small.rv-month { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--line); opacity: .85; }
.rv-ctr { font-family: var(--font-mono); font-size: 13px; cursor: pointer; }
.rv-ctr small { display: block; font-family: var(--font-sans); font-size: 9.5px; color: var(--faint); margin-top: 2px; }
.rv-ctr.empty { color: var(--faint); font-size: 11.5px; border-bottom: 1px dashed var(--border-strong); display: inline-block; }
.rv-ctr:hover { color: var(--accent); }
.rv-foot { font-family: var(--font-mono); font-size: 10.5px; color: var(--faint); margin-top: 14px; }

/* Площадки внутри карточки товара: WB и Ozon — два лица одного товара,
   поэтому они лежат в одной карточке, а не двумя отдельными. */
.rv-side {
  margin-top: 10px; padding: 10px 11px; border: 1px solid var(--border);
  border-radius: var(--r); cursor: pointer; background: var(--surface-2);
  transition: border-color var(--dur), background var(--dur);
}
.rv-side:hover { border-color: var(--accent-line); background: var(--surface); }
.rv-side.alarm { border-color: color-mix(in srgb, var(--danger) 30%, var(--border)); }
.rv-side-head { display: flex; align-items: center; gap: 7px; margin-bottom: 8px; }
.rv-side-name { font-size: 12.5px; font-weight: 600; }
.rv-badge {
  font-family: var(--font-mono); font-size: 9.5px; font-weight: 700; letter-spacing: .04em;
  padding: 2px 5px; border-radius: var(--r-xs); color: #fff;
}
.rv-badge.wb { background: #7c2dbb; }
.rv-badge.ozon { background: #0069ff; }
.rv-side .rv-nums { margin-top: 0; }
.rv-side .rv-sigs { margin-top: 9px; }

/* Правила повторяющейся задачи: строгая по умолчанию, но строгость настраивается */
.rec-opts { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }
.rec-opts label {
  display: flex; gap: 9px; align-items: flex-start; cursor: pointer;
  font-size: 13px; line-height: 1.4;
}
.rec-opts input { width: 16px; height: 16px; margin-top: 1px; flex: none; }
.rec-opts b { font-weight: 600; }
.rec-rules { font-size: 11.5px; color: var(--faint); margin-top: 4px; }

/* Ссылки задачи: регламент, таблица, папка с макетами */
.lnk-row { display: grid; grid-template-columns: 1fr 1.6fr 32px; gap: 8px; margin-bottom: 6px; }
.lnk-row .lnk-del { color: var(--faint); }
.lnk-row .lnk-del:hover { color: var(--danger); }
.task-links { display: flex; gap: 8px; flex-wrap: wrap; margin: 16px 0 4px; }
.task-links a { text-decoration: none; }
.task-links a svg { width: 14px; height: 14px; }

/* ---------------------------- график цен ---------------------------- */

.ch-tabs { display: flex; gap: 6px; align-items: center; margin-bottom: 10px; }
.ch { width: 100%; height: auto; display: block; }
.ch-grid { stroke: var(--border); stroke-width: 1; }
.ch-ylab { fill: var(--faint); font-family: var(--font-mono); font-size: 10px; text-anchor: end; }
.ch-xlab { fill: var(--faint); font-family: var(--font-mono); font-size: 9.5px; text-anchor: middle; }
.ch-legs { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 4px 12px; margin-top: 12px; }
.ch-leg {
  display: flex; align-items: center; gap: 7px; font-size: 12px; cursor: pointer;
  background: none; border: 1px solid transparent; border-radius: var(--r-sm);
  padding: 5px 8px; text-align: left; color: inherit; font-family: inherit;
}
.ch-leg:hover { border-color: var(--border); background: var(--surface); }
/* Выключенный участник: приглушён, но остаётся на виду — его можно вернуть */
.ch-leg.off { opacity: .45; }
.ch-leg.off b { text-decoration: line-through; }
.ch-leg.mine b { color: var(--accent); }
.ch-leg b { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 140px; }
.ch-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; border: 1px solid transparent; }

/* Подсказка под курсором: цены всех участников за один день */
.ch-wrap { position: relative; }
.ch-cursor { stroke: var(--border-strong); stroke-width: 1; stroke-dasharray: 3 3; }
.ch-tip {
  position: absolute; top: 8px; pointer-events: none; z-index: 3;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r-sm); padding: 8px 10px; box-shadow: var(--shadow, 0 6px 20px rgba(0,0,0,.18));
  min-width: 190px;
}
.ch-tip-day { font-family: var(--font-mono); font-size: 10px; color: var(--faint);
  text-transform: uppercase; letter-spacing: .06em; margin-bottom: 5px; }
.ch-tip-row { display: flex; align-items: center; gap: 6px; font-size: 12px; line-height: 1.7; }
.ch-tip-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 110px; }
.ch-tip-row b { font-family: var(--font-mono); }
.ch-now { font-family: var(--font-mono); }
.ch-down { color: var(--ok); font-size: 11px; }
.ch-up { color: var(--danger); font-size: 11px; }
/* Выбранный период на графике */
.btn.btn-on { background: var(--accent); color: var(--on-dark); border-color: var(--accent); }
/* С чем сравнивали предыдущее значение — иначе стрелка ни о чём */
.rv-wasline { font-family: var(--font-sans); font-size: 9.5px; color: var(--faint); margin-top: 1px; }

/* -------------------- фильтры списка запусков -------------------- */

.lc-filters {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-bottom: 12px; padding: 10px 12px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
}
.lc-f-group { display: flex; gap: 6px; flex-wrap: wrap; }
/* Выбранный фильтр — залитый, как активная вкладка: их может быть три сразу,
   и глазом должно быть видно, что именно сейчас включено. */
.lc-f.on { background: var(--accent); color: var(--on-dark); border-color: var(--accent); }
.lc-f:disabled { opacity: .4; cursor: default; }
.lc-f-n {
  font-family: var(--font-mono); font-size: 10px; margin-left: 5px; opacity: .65;
}
.lc-f-sel {
  height: 30px; padding: 0 8px; font-size: 12.5px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); color: inherit;
}

/* ======================== главный экран ======================== */

.home-bar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-bottom: 14px; padding: 10px 12px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
}
.home-ranges { display: flex; gap: 6px; flex-wrap: wrap; }
.home-r.on { background: var(--accent); color: var(--on-dark); border-color: var(--accent); }
.home-dates { display: flex; align-items: center; gap: 6px; }
.home-dates input[type="date"] {
  height: 30px; padding: 0 8px; font-size: 12.5px; color: inherit;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface-2);
}

/* Площадки — друг под другом: внутри каждой своя сетка плашек, и делить
   ширину пополам значит зажать их до нечитаемого. */
/* ── Общая выручка в заказах: первая цифра экрана ──────────────────────── */

.tsum {
  position: relative;
  margin-bottom: 12px;
  padding: 18px 20px 16px;
  border-radius: var(--r-lg, 14px);
  border: 1px solid color-mix(in srgb, var(--planet) 30%, var(--line));
  background:
    radial-gradient(120% 140% at 92% 0%, color-mix(in srgb, var(--planet) 16%, transparent), transparent 62%),
    var(--card);
  overflow: hidden;
}
.tsum::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px;
  background: linear-gradient(180deg, var(--planet), color-mix(in srgb, var(--planet) 30%, transparent));
}
.tsum .planet-dot { top: 16px; right: 18px; width: 22px; height: 22px; }

.tsum-label {
  font-size: 12.5px; letter-spacing: .02em;
  color: color-mix(in srgb, var(--planet) 58%, var(--muted));
}
.tsum-value {
  font-size: 34px; font-weight: 650; line-height: 1.1; margin-top: 2px;
  font-variant-numeric: tabular-nums;
}
.tsum-sub { font-size: 12.5px; color: var(--muted); margin-top: 1px; }

/* Полоса вклада площадок: тот же факт, что проценты, но читается сразу */
.tsum-bar {
  display: flex; gap: 2px; height: 5px; margin: 11px 0 8px;
  border-radius: 3px; overflow: hidden;
}
.tsum-seg { height: 100%; border-radius: 3px; }
.tsum-seg.tsum-ozon { background: #3b82c4; }
.tsum-seg.tsum-wb { background: #a855c4; }

.tsum-parts { display: flex; flex-wrap: wrap; gap: 14px; font-size: 12.5px; }
.tsum-part { color: var(--muted); }
.tsum-part b { color: var(--fg); font-variant-numeric: tabular-nums; }
.tsum-part::before {
  content: ""; display: inline-block; width: 7px; height: 7px;
  border-radius: 50%; margin-right: 6px; vertical-align: 1px;
}
.tsum-part.tsum-ozon::before { background: #3b82c4; }
.tsum-part.tsum-wb::before { background: #a855c4; }

.tsum-warn { margin-top: 8px; font-size: 12px; color: var(--warn, #b8860b); }

@media (max-width: 640px) {
  .tsum-value { font-size: 28px; }
}

.home-grid { display: grid; gap: 12px; margin-bottom: 12px; }
.home-two {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
}

/* Карточка приподнимается при наведении — так видно, что она живая и на неё
   можно нажать там, где внутри есть переходы. */
.home-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
  padding: 16px; transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.home-card:hover {
  transform: translateY(-2px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-raise);
}
.home-card.off { opacity: .75; }

.hc-head { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; }
.hc-head h3 { margin: 0; font-size: 15px; }
.hc-empty { padding: 18px 0; font-size: 13px; }

.hc-main { display: flex; align-items: center; gap: 16px; margin-bottom: 14px; }
.hc-money { flex: 1; min-width: 0; }
.hc-label {
  font-family: var(--font-mono); font-size: 9px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 4px;
}
.hc-big {
  font-family: var(--font-mono); font-size: 26px; font-weight: 700; letter-spacing: -.02em;
  line-height: 1.1;
}
.hc-sub { font-size: 11.5px; color: var(--faint); margin-top: 3px; }

.hc-rows { display: flex; flex-direction: column; gap: 1px; }
.hc-row {
  position: relative; display: flex; align-items: center; gap: 8px;
  padding: 7px 8px; border-radius: var(--r-sm); font-size: 12.5px;
  transition: background .15s ease;
}
.hc-row:hover { background: var(--surface-2); }
.hc-row span:first-child { flex: 1; color: var(--muted); }
.hc-row b { font-family: var(--font-mono); font-weight: 600; }
.hc-row b.bad { color: var(--danger); }
.hc-row.sub { font-size: 11.5px; color: var(--faint); padding-top: 3px; padding-bottom: 3px; }
.hc-row.sub span:first-child { padding-left: 10px; }
.hc-share {
  position: absolute; left: 8px; right: 8px; bottom: 2px; height: 2px;
  border-radius: 2px; background: var(--border);
}
.hc-share::after {
  content: ''; display: block; height: 100%; width: var(--w);
  border-radius: 2px; background: var(--accent); opacity: .55;
  transition: width .5s ease;
}
.hc-foot { font-size: 11px; margin-top: 12px; }

/* ================= блок площадки: плашки показателей ================= */

.pcard {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
  padding: 16px; overflow: hidden;
}
.pcard.off { opacity: .7; }
.pcard-head { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.pcard-head h3 { margin: 0; font-size: 16px; letter-spacing: -.01em; }
.pcard-empty { padding: 22px 0; font-size: 13px; }

/* Значок площадки: цвет самой площадки, но приглушённый под нашу палитру */
/* Логотип площадки — настоящий, из public/img. Раньше здесь стояли буквы «WB»
   и «OZ» на цветном квадрате: свои цвета, свои скругления, ни на что не
   похоже. Значок узнаётся мгновенно, буквы приходится читать. */
.pcard-logo {
  width: 30px; height: 30px; border-radius: 9px; flex: 0 0 auto;
  object-fit: contain;
}

.tiles {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}

/* Плашка показателя. Появляется с лёгкой задержкой по очереди — экран
   собирается на глазах, а не возникает целиком. */
.tile {
  position: relative; overflow: hidden;
  padding: 14px; border-radius: var(--r); border: 1px solid var(--border);
  background: var(--surface-2);
  transition: transform .2s cubic-bezier(.2,.7,.3,1), border-color .2s ease, box-shadow .2s ease;
  animation: tile-in .45s cubic-bezier(.2,.7,.3,1) backwards;
  animation-delay: calc(var(--i, 0) * 60ms);
}
@keyframes tile-in {
  from { opacity: 0; transform: translateY(10px) scale(.98); }
  to { opacity: 1; transform: none; }
}
.tile:hover {
  transform: translateY(-3px);
  border-color: var(--accent-line);
  box-shadow: var(--shadow-raise);
}
.tile.wide { grid-column: span 2; }
@media (max-width: 760px) { .tile.wide { grid-column: span 1; } }

/* Цветная подсветка слева и мягкий градиент — по смыслу показателя */
.tile::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--border-strong); opacity: .5; transition: opacity .2s ease;
}
.tile:hover::before { opacity: 1; }
.tile.t-accent::before { background: var(--accent); }
.tile.t-ok::before { background: var(--ok); }
.tile.t-warn::before { background: var(--warn); }
.tile.t-bad::before { background: var(--danger); }
.tile.t-accent { background: linear-gradient(160deg, var(--accent-soft), var(--surface-2) 70%); }
.tile.t-ok { background: linear-gradient(160deg, var(--ok-soft), var(--surface-2) 70%); }
.tile.t-warn { background: linear-gradient(160deg, var(--warn-soft), var(--surface-2) 70%); }
.tile.t-bad { background: linear-gradient(160deg, var(--danger-soft), var(--surface-2) 70%); }
.tile.t-muted { opacity: .6; }

.tile-top { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.tile-label {
  flex: 1; font-family: var(--font-mono); font-size: 9px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--faint);
}
.tile-badge {
  font-family: var(--font-mono); font-size: 10px; font-weight: 600;
  padding: 2px 7px; border-radius: 20px;
  background: var(--surface); border: 1px solid var(--border);
}
.tile-value {
  font-family: var(--font-mono); font-size: 24px; font-weight: 700;
  letter-spacing: -.03em; line-height: 1.05; position: relative; z-index: 1;
  white-space: nowrap;
}
.tile.wide .tile-value { font-size: 30px; }
/* Подпись под цифрой — одна короткая строка, а не перечисление. Всё, что
   длиннее, уезжает в раскрывающийся состав: мелкий текст в несколько статей
   читается как каша и обесценивает саму цифру. */
.tile-sub {
  font-size: 12px; color: var(--muted); margin-top: 6px;
  position: relative; z-index: 1;
}

/* ------- состав показателя, раскрывается по наведению ------- */

.tile.has-details { cursor: default; }
.tile-more {
  font-size: 10px; color: var(--faint); transition: transform .2s ease, color .2s ease;
}
.tile.has-details:hover .tile-more { transform: rotate(180deg); color: var(--accent); }

.tile-details {
  position: relative; z-index: 1;
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .28s cubic-bezier(.2,.7,.3,1), margin-top .28s ease;
  margin-top: 0;
}
.tile.has-details:hover .tile-details { grid-template-rows: 1fr; margin-top: 10px; }
.tile-dinner { overflow: hidden; min-height: 0; }
.tile-drow {
  display: flex; align-items: baseline; gap: 8px;
  padding: 4px 0; font-size: 12px; border-top: 1px solid var(--border);
}
.tile-drow:first-child { border-top: 0; }
.tile-drow span { flex: 1; color: var(--muted); }
.tile-drow b { font-family: var(--font-mono); font-weight: 600; white-space: nowrap; }
/* Вычитаемое в составе — приглушённым: это не самостоятельная цифра,
   а слагаемое, из которого получился итог наверху. */
.tile-drow.minus b { color: var(--danger); }

/* Кольцо в углу плашки, поверх фона */
/* ------- кольцо показателя -------
   Имя mring, а не ring: .ring в проекте уже занято кольцом в шапке задач,
   и общие правила превращали эти круги в чёрные пятна. */
.mring { width: 64px; height: 64px; flex: 0 0 auto; overflow: visible; }
.mring circle { fill: none; }
.mring-bg { stroke: var(--border); stroke-width: 6; }
.mring-fg {
  stroke: var(--accent); stroke-width: 6; stroke-linecap: round;
  transform: rotate(-90deg); transform-origin: 32px 32px;
  transition: stroke-dashoffset .8s cubic-bezier(.2, .7, .3, 1);
}
.mring.ok .mring-fg { stroke: var(--ok); }
.mring.warn .mring-fg { stroke: var(--warn); }
.mring.bad .mring-fg { stroke: var(--danger); }
.mring-txt {
  fill: var(--text); stroke: none; font-family: var(--font-mono);
  font-size: 15px; font-weight: 700; text-anchor: middle;
}

/* Полоса доли под цифрой — вместо кольца в углу: не спорит с числом за место
   и показывает честное значение, без растягивания шкалы «чтобы было видно». */
/* Кнопка-разбор на плитке: ведёт к подробностям, но не спорит с цифрой.
   Видна всегда — прятать её до наведения значит спрятать и саму возможность. */
.tile-act {
  margin-top: 8px; padding: 3px 9px;
  font-size: 11.5px; font-family: inherit;
  color: var(--muted); background: transparent;
  border: 1px solid var(--line); border-radius: 999px;
  cursor: pointer; transition: color .12s, border-color .12s, background .12s;
}
.tile-act:hover { color: var(--fg); border-color: var(--fg-3, var(--muted)); background: var(--surface-2); }
.tile-act:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.tile-bar {
  position: relative; z-index: 1; height: 3px; margin-top: 10px;
  border-radius: 3px; background: var(--border); overflow: hidden;
}
.tile-bar i {
  display: block; height: 100%; border-radius: 3px; background: var(--accent);
  transform-origin: left; animation: bar-in .7s cubic-bezier(.2,.7,.3,1) backwards;
  animation-delay: calc(var(--i, 0) * 60ms + 120ms);
}
@keyframes bar-in { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.tile.t-ok .tile-bar i { background: var(--ok); }
.tile.t-warn .tile-bar i { background: var(--warn); }
.tile.t-bad .tile-bar i { background: var(--danger); }

/* Мини-график лежит по нижнему краю широкой плашки */
.spark { position: absolute; left: 0; right: 0; bottom: 0; width: 100%; height: 40px; opacity: .5; }
.spark-line { fill: none; stroke: var(--accent); stroke-width: 1.6; vector-effect: non-scaling-stroke; }
.spark-fill { fill: var(--accent); opacity: .12; }

/* ------- список запусков на главной ------- */

.hl-list { display: flex; flex-direction: column; gap: 8px; }
.hl-item {
  display: block; width: 100%; text-align: left; cursor: pointer;
  padding: 9px 10px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); color: inherit; font: inherit;
  transition: border-color .15s ease, transform .15s ease;
}
.hl-item:hover { border-color: var(--accent); transform: translateX(2px); }
.hl-item.late { border-left: 3px solid var(--danger); }
.hl-item.blocked { border-left: 3px solid var(--warn); }
.hl-top { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; }
.hl-name { flex: 1; font-weight: 600; font-size: 13px; }
.hl-pct { font-family: var(--font-mono); font-size: 12px; color: var(--muted); }
.hl-bar { height: 4px; border-radius: 3px; background: var(--border); overflow: hidden; }
.hl-bar i { display: block; height: 100%; background: var(--accent); transition: width .6s ease; }
.hl-sub { font-size: 11px; margin-top: 5px; }

/* ------- скелет главного экрана на время загрузки ------- */

.home-skeleton { display: grid; gap: 12px; }
.sk-tile {
  padding: 14px; border-radius: var(--r); border: 1px solid var(--border);
  background: var(--surface-2); min-height: 96px;
}
.sk-tile.wide { grid-column: span 2; }
@media (max-width: 760px) { .sk-tile.wide { grid-column: span 1; } }
.sk-dot { width: 30px; height: 30px; border-radius: 9px; }
.sk-line { height: 10px; border-radius: 5px; margin-bottom: 10px; }
.sk-line.xs { width: 40%; height: 8px; }
.sk-line.sm { width: 55%; height: 8px; }
.sk-line.md { width: 130px; height: 14px; margin-bottom: 0; }
.sk-line.lg { width: 75%; height: 22px; }
/* Мягкое мерцание: показывает, что идёт работа, и не мельтешит */
.sk-dot, .sk-line {
  background: linear-gradient(90deg, var(--border) 25%, var(--surface-3) 50%, var(--border) 75%);
  background-size: 200% 100%;
  animation: sk-shine 1.4s ease-in-out infinite;
}
@keyframes sk-shine {
  from { background-position: 200% 0; }
  to { background-position: -200% 0; }
}

/* ---------------------------------------------------------------------------
   МАТЕРИАЛЫ И ДОСТУПЫ
   Карточками, а не таблицей: у записей разный состав — у регламента ссылка,
   у доступа логин с паролем, — и в таблице половина ячеек пустовала бы.
   --------------------------------------------------------------------------- */
.kb-grid {
  display: grid; gap: var(--s-3);
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.kb-card {
  border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--s-3) var(--s-4) var(--s-3); background: var(--surface);
  display: flex; flex-direction: column; gap: 6px;
  transition: border-color var(--dur) var(--ease);
}
.kb-card:hover { border-color: var(--border-strong); }
.kb-top { display: flex; align-items: center; gap: 6px; }
.kb-title { font-size: 14.5px; font-weight: 620; letter-spacing: -.01em; }
.kb-title a { color: var(--text); text-decoration: none; }
.kb-title a:hover { color: var(--accent); }
.kb-note { font-size: 12.5px; color: var(--muted); }
.kb-foot { font-size: 11.5px; }
.kb-foot a { color: var(--muted); }
/* Логин и пароль — моноширинным: их читают по символам и копируют */
.kb-row { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.kb-val {
  font-family: var(--font-mono); font-size: 12.5px; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: var(--r-xs); padding: 2px 7px;
  user-select: all;
}

/* Компактные поля в шапке панели: поиск и фильтр рядом с заголовком */
.input-sm {
  height: 30px; padding: 0 9px; font-size: 13px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface); color: var(--text);
}
.input-sm:focus { outline: none; border-color: var(--accent); }

/* Ссылка на вход в сервис: показываем домен, а не полный адрес — «mpstats.io»
   читается с одного взгляда, а простыня с параметрами только мешает. */
.kb-open {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12.5px; color: var(--accent); text-decoration: none;
  border: 1px solid var(--accent-line); border-radius: var(--r-xs);
  padding: 2px 8px; background: var(--accent-soft);
}
.kb-open:hover { border-color: var(--accent); }
.kb-open svg { width: 12px; height: 12px; }
.kb-host { font-size: 11.5px; margin-top: -2px; }
.kb-title svg { width: 12px; height: 12px; vertical-align: -1px; opacity: .5; }

/* Строка карточки площадки в товаре: площадка, артикул, статус, удаление */
.art-row {
  display: grid; grid-template-columns: 96px 1fr 130px 34px;
  gap: var(--s-2); align-items: center; margin-bottom: 6px;
}
.art-row input, .art-row select { height: 34px; }

/* Артикул карточки в строке запуска: второй строкой под названием товара.
   Рядом с названием он съедал ширину колонки, и название переносилось. */
.lc-name-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.lc-art {
  font-family: var(--font-mono); font-size: 10.5px; color: var(--faint);
  white-space: nowrap; align-self: flex-start; letter-spacing: .01em;
}

/* Этикетка в строке карточки товара: у каждого артикула свой штрихкод */
.art-row { grid-template-columns: 96px 1fr 130px 118px 34px; }
.art-label { display: flex; align-items: center; }
.art-label-add, .art-label-x {
  border: 1px dashed var(--border-strong); background: transparent; cursor: pointer;
  color: var(--muted); border-radius: var(--r-xs); font-size: 12px; padding: 4px 8px;
  display: inline-flex; align-items: center; gap: 4px;
}
.art-label-add:hover { border-color: var(--accent); color: var(--accent); }
.art-label-add svg { width: 12px; height: 12px; }
.art-label-link {
  display: inline-flex; align-items: center; gap: 4px; font-size: 12px;
  color: var(--accent); text-decoration: none;
}
.art-label-link svg { width: 13px; height: 13px; }
.art-label-x { border-style: solid; padding: 3px 6px; margin-left: 4px; }

/* Модель под названием товара: различает похожие позиции в списке */
.prod-model { font-size: 11.5px; color: var(--faint); font-family: var(--font-mono); }

/* Состав поставки: свёрнут по умолчанию, раскрывается кнопкой в шапке.
   При нескольких поставках развёрнутые списки занимают весь экран. */
.supply-card .supply-body { display: none; }
.supply-card.on .supply-body { display: block; }
.supply-card .sup-toggle { padding: 2px 7px; font-size: 12px; line-height: 1; }
/* Комментарий под шапкой поставки. Отрицательного отступа тут быть не должно:
   когда кнопки в шапке переносятся на вторую строку, текст заезжает под них и
   попадает прямо на разделительную линию. */
.supply-note {
  padding: 10px var(--s-5) var(--s-3); font-size: 12.5px;
}
/* Кнопки действий держим одной группой: иначе «оформить приёмку» остаётся в
   строке, а «списать как потерю» уезжает вниз и висит сама по себе. */
.sup-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* Заявки площадки: строка на поставку. Подробности раскрываются кликом —
   поставок мало, и карточка на каждую занимала бы весь экран впустую.
   Таблица плотная намеренно: её читают глазами по колонкам, а не изучают. */
.sup-bar { flex-wrap: wrap; gap: 8px; }
.sup-date { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--muted); }
.sup-date input { padding: 4px 8px; font-size: 12.5px; }

.oz-table { font-size: 13px; }
.oz-table th { font-size: 11px; letter-spacing: .02em; white-space: nowrap; }
.oz-table td { padding-top: 7px; padding-bottom: 7px; }
.oz-table th.num, .oz-table td.num { width: 1%; white-space: nowrap; font-variant-numeric: tabular-nums; }
.oz-table tbody tr.oz-row { cursor: pointer; }
.oz-table tbody tr.oz-row:hover { background: var(--surface-2); }
.oz-table tbody tr.oz-row.on > td { border-bottom: none; }
.oz-table tbody tr.oz-row.gap > td:nth-child(2) { box-shadow: inset 2px 0 0 var(--danger); }
/* Кнопка раскрытия: маленькая стрелка терялась, и было непонятно, что строку
   вообще можно открыть. Даём ей размер настоящей кнопки. */
.oz-arrow { text-align: center; padding-right: 0 !important; width: 34px; }
.oz-chevron {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: var(--r-xs); font-size: 12px;
  color: var(--muted); background: var(--surface-2); border: 1px solid var(--border);
}
.oz-row:hover .oz-chevron { color: var(--text); border-color: var(--border-strong); }
.oz-row.on .oz-chevron { color: var(--text); background: var(--surface-3); }
.oz-warn { color: var(--danger); font-size: 11.5px; }

/* Развоз по кластерам под строкой товара: куда именно поехали эти штуки */
.oz-clusters { display: flex; flex-wrap: wrap; gap: 3px 10px; margin-top: 3px; }
.oz-clusters span { font-size: 11px; color: var(--muted); }
.oz-clusters b { color: var(--text); font-weight: 600; }

.oz-items tfoot td {
  border-top: 1px solid var(--border-strong); border-bottom: none;
  padding-top: 8px; font-weight: 600;
}

.oz-detail > td { padding: 0 0 12px !important; }
.oz-meta {
  display: flex; flex-wrap: wrap; gap: 2px 14px; font-size: 11.5px;
  color: var(--muted); padding: 0 0 8px;
}
/* Состав поставки — это таблица, и читается она по колонкам. Без линеек
   строки сливаются: глаз теряет, к какому товару относится число. */
/* Таблица состава лежит внутри ячейки внешней таблицы, а ячейка растягивается
   под содержимое — поэтому overflow и max-width на обёртке не работают: вместо
   прокрутки вширь ехала вся страница. Лечится жёсткой раскладкой колонок:
   ширины считаются от родителя, содержимое переносится внутри своей колонки. */
.oz-items-wrap { max-width: 100%; }
.oz-items { width: 100%; table-layout: fixed; border-collapse: collapse; }
.oz-items th {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .03em; color: var(--muted);
  font-weight: 500; text-align: left; padding: 0 16px 8px 0;
  border: none; border-bottom: 1px solid var(--border-strong);
}
.oz-items th.num, .oz-items td.num { text-align: right; font-variant-numeric: tabular-nums; }
.oz-items td {
  padding: 10px 16px 10px 0; font-size: 12.5px; vertical-align: middle;
  border: none; border-bottom: 1px solid var(--border);
}
.oz-items tbody tr:last-child td { border-bottom: none; }
.oz-items tbody tr:hover td { background: var(--surface-2); }
/* Колонка с количеством отделена от описательной части — там начинаются числа.
   Литраж остаётся при товаре: это его свойство, а не результат поставки. */
.oz-items th:nth-child(5), .oz-items td:nth-child(5) { border-left: 1px solid var(--border); padding-left: 12px; }
/* Картинка товара и название не должны слипаться: миниатюре нужен свой
   отступ, иначе строка читается как одно пятно. */
.oz-items th:first-child, .oz-items td:first-child { width: 4%; padding-right: 12px; }
/* Числа держим узкими и рядом: растянутые на всю ширину, они перестают
   читаться как один ряд — глаз не связывает товар с его количеством. */
/* Доли, а не жёсткие пиксели: колонки делят ширину пропорционально и не
   перерастают карточку. Раньше название забирало весь остаток, и между ним и
   артикулом зияла пустая полоса в пол-экрана. Сумма долей — ровно 100%. */
/* Семь числовых колонок по 8,5% плюс картинка, название и артикул — ровно
   сотня. Считать надо буквально: доли в сумме больше ста растягивают таблицу
   за край родителя, и правый столбец с ценой обрезается. */
.oz-items th.num, .oz-items td.num { width: 8.5%; white-space: nowrap; }
.oz-items th:nth-child(2), .oz-items td:nth-child(2) { width: 23%; }
.oz-items th:nth-child(3), .oz-items td:nth-child(3) { width: 13.5%; }
.oz-items td:nth-child(2), .oz-items td:nth-child(3) { overflow-wrap: anywhere; }
.oz-items th:last-child, .oz-items td:last-child { padding-right: 4px; }
/* Разворот прижимался к самому краю карточки — даём ему поля, как у таблицы */
.oz-detail > td:last-child { padding-right: 16px !important; }
/* Заголовки числовых колонок длиннее самих чисел — даём им переноситься,
   иначе «Цена в кабинете» распирает колонку и ломает раскладку. */
.oz-items th.num { white-space: normal; }
.oz-actions { display: flex; gap: 8px; margin-top: 10px; }
.thumb-sm { width: 26px; height: 26px; border-radius: 5px; object-fit: cover; }

/* Ряд конкурентов: кнопки в конце строки и подсветка ключей, где карточка
   держится только рекламой — такие места нельзя повторить без бюджета. */
.rv-tools { display: flex; gap: 4px; align-items: center; justify-content: flex-end; }
.rv-tools .btn { padding: 4px 7px; }
.rv-tools .btn svg { width: 15px; height: 15px; display: block; }
tr.kw-paid td:first-child { color: var(--warn); }
/* Движение позиции. Вверх по списку — хорошо, вниз — плохо; у цен наоборот,
   поэтому классы здесь свои. */
.kw-move { font-size: 12.5px; color: var(--muted); white-space: nowrap; }
.kw-move.better { color: var(--ok); font-weight: 600; }
.kw-move.worse { color: var(--danger); font-weight: 600; }

/* Заголовки колонок раскрашены по тому, как часто приходят цифры: одни
   обновляются сами каждые полчаса, другие — раз в неделю, когда загрузят
   отчёт. Без этой подсказки «показы 25» и «цена 4257» читаются как одинаково
   свежие, хотя между ними неделя разницы. */
.rv-th .th-live { color: var(--accent); }
.rv-th .th-weekly { color: var(--warn); }
/* Памятка к цветам заголовков. Квадратик + подпись: круглая точка рядом с
   текстом читается как маркер списка, а квадрат — как образец цвета. */
.rv-legend {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  font-size: 11.5px; color: var(--muted); margin: 2px 0 8px;
}
.rv-legend b { display: inline-flex; align-items: center; gap: 5px; font-weight: 500; }
.rv-legend i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.rv-legend i.th-live { background: var(--accent); }
.rv-legend i.th-weekly { background: var(--warn); }

/* Цена со скидкой кошелька: её видит покупатель, поэтому она стоит под
   основной, но не спорит с ней размером — основная нужна для расчётов, эта
   для сравнения с конкурентами. */
.rv-wallet { font-size: 11.5px; color: var(--ok); font-weight: 600; margin-top: 1px; }

/* «Закончился» у конкурента — не ошибка данных, а новость: его покупатели
   идут к тем, у кого товар есть. Поэтому пометка заметная, а не серая. */
.rv-soldout {
  display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: .02em;
  color: var(--ok); background: color-mix(in srgb, var(--ok) 12%, transparent);
  border-radius: 4px; padding: 1px 6px; margin-bottom: 3px;
}

/* ============================ обсуждение в задаче ============================

   Раньше это была лента одинаковых серых строк: реплики людей и отметки системы
   выглядели одинаково, и разговор терялся среди «взял в работу». Теперь это
   переписка — как в мессенджере, к которому все привыкли.

   Блок вынесен на отдельную подложку и обведён рамкой: обсуждение должно быть
   видно сразу, не разглядывая. Пузыри разделяют говорящих без чтения подписей —
   свои справа, чужие слева. Системные события ужаты в тонкую строку по центру:
   они не разговор, а пометки на полях.
*/
.chat {
  margin-top: 20px;
  border: 1px solid var(--border-strong);
  border-radius: 14px;
  background: var(--surface-2);
  overflow: hidden;
}
.chat-head {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 14px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.chat-title { font-weight: 650; font-size: 13.5px; letter-spacing: -.01em; }

.chat-feed {
  max-height: 340px; overflow: auto;
  padding: 14px 14px 6px;
  display: flex; flex-direction: column; gap: 8px;
}
.chat-empty {
  color: var(--muted); font-size: 13px; line-height: 1.6;
  padding: 18px 10px; text-align: center;
}

/* дата отдельной строкой: обсуждение живёт неделями */
.chat-day { display: flex; justify-content: center; margin: 6px 0 2px; }
.chat-day span {
  font-size: 11.5px; color: var(--muted);
  background: var(--surface-3); border-radius: 999px; padding: 3px 10px;
}

.chat-row { display: flex; gap: 8px; align-items: flex-end; max-width: 100%; }
.chat-row.mine { flex-direction: row-reverse; }

.chat-ava {
  width: 26px; height: 26px; flex: none;
  border-radius: 50%;
  background: var(--surface-3); color: var(--muted);
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 650;
}

.chat-bubble {
  max-width: min(72%, 560px);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px 14px 14px 4px;
  padding: 8px 11px 6px;
  position: relative;
}
/* Своё сообщение — акцентной заливкой: в переписке важно мгновенно отличать,
   где твоя реплика, а где чужая. */
.chat-row.mine .chat-bubble {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  border-radius: 14px 14px 4px 14px;
}
.chat-who { font-size: 12px; font-weight: 650; color: var(--accent); margin-bottom: 2px; }
.chat-text { font-size: 13.5px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
.chat-at { font-size: 11px; color: var(--faint); text-align: right; margin-top: 2px; }

/* отметки системы: тонкой строкой, не мешаются с разговором */
.chat-sys {
  align-self: center; text-align: center;
  font-size: 12px; color: var(--muted);
  padding: 2px 4px; max-width: 90%;
}
.chat-sys-at { color: var(--faint); margin-left: 6px; }

.chat-write {
  display: flex; gap: 8px;
  padding: 10px 12px;
  background: var(--surface);
  border-top: 1px solid var(--border);
}
.chat-write input { flex: 1; }

@media (max-width: 640px) {
  .chat-bubble { max-width: 86%; }
  .chat-feed { max-height: 260px; }
}

/* вложения в обсуждении */
.chat-img { display: block; margin-bottom: 6px; border-radius: 10px; overflow: hidden; }
.chat-img img { display: block; max-width: 100%; max-height: 240px; object-fit: cover; }
.chat-file {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 9px; margin-bottom: 6px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--surface-2); color: var(--text); text-decoration: none;
}
.chat-file:hover { border-color: var(--accent-line); background: var(--accent-soft); }
.chat-file-ico { width: 20px; height: 20px; flex: none; color: var(--muted); }
.chat-file-ico svg { width: 100%; height: 100%; }
.chat-file-body { display: flex; flex-direction: column; min-width: 0; }
.chat-file-name {
  font-size: 13px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 320px;
}
.chat-file-size { font-size: 11.5px; color: var(--faint); }

/* выбранные, но ещё не отправленные */
.chat-attached { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 12px; }
.chat-attached:not(:empty) { padding: 10px 12px 0; }
.chat-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12.5px; padding: 4px 8px;
  background: var(--surface-3); border-radius: 999px;
}
.chat-chip.busy { opacity: .6; }
.chat-chip button {
  border: 0; background: none; cursor: pointer;
  color: var(--muted); font-size: 15px; line-height: 1; padding: 0;
}
.chat-chip button:hover { color: var(--danger); }

.chat-clip {
  display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; flex: none;
  border: 1px solid var(--border); border-radius: 9px;
  color: var(--muted); cursor: pointer;
}
.chat-clip:hover { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }
.chat-clip svg { width: 18px; height: 18px; }
.pcard-note {
  margin: 0 14px 10px; padding: 8px 11px;
  border: 1px solid var(--border); border-left: 3px solid var(--warn, var(--accent));
  border-radius: 8px; font-size: 12px; line-height: 1.5;
}
.rv-cat.gone {
  color: var(--danger); border-color: var(--danger-line, var(--border));
  background: var(--danger-soft, transparent);
}
.chat-to {
  padding: 8px 14px 10px;
  font-size: 12px; color: var(--faint);
  border-top: 1px solid var(--border);
}
.chat-to-off { text-decoration: underline dotted; text-underline-offset: 2px; }
.chat-file.expired { opacity: .65; cursor: default; }
.chat-file.expired:hover { border-color: var(--border); background: var(--surface-2); }

/* ============================ заметки ============================

   Плитками, как в блокноте на телефоне: видно начало текста, и нужную находишь
   глазами, не открывая каждую. Закреплённые выделены полосой слева — иначе в
   сетке они ничем не отличаются от соседей.
*/
.note-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}
.note-card {
  display: flex; flex-direction: column; gap: 7px;
  min-height: 140px; padding: 14px 15px;
  text-align: left; font: inherit; color: inherit; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
}
.note-card:hover { border-color: var(--border-strong); background: var(--surface); }
.note-card.pinned { border-left: 3px solid var(--accent); }

.note-head { display: flex; align-items: flex-start; gap: 8px; }
.note-title {
  font-weight: 650; font-size: 14px; line-height: 1.35; letter-spacing: -.01em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.note-pin { color: var(--accent); flex: none; }
.note-pin svg { width: 15px; height: 15px; }
.note-body {
  flex: 1; font-size: 13px; line-height: 1.5; color: var(--muted);
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
.note-foot { display: flex; align-items: center; gap: 8px; font-size: 11.5px; flex-wrap: wrap; }
.note-share {
  color: var(--accent); background: var(--accent-soft);
  border-radius: 999px; padding: 2px 8px;
}

/* окно заметки */
.note-editor { display: flex; flex-direction: column; gap: 10px; }
.note-title-input {
  font-size: 17px; font-weight: 650; letter-spacing: -.015em;
  border: 0; border-bottom: 1px solid var(--border); border-radius: 0; padding: 4px 2px;
}
.note-title-input:focus { box-shadow: none; border-bottom-color: var(--accent); }
.note-text {
  min-height: 320px; resize: vertical;
  font-size: 14px; line-height: 1.65;
  border: 0; padding: 4px 2px;
}
.note-text:focus { box-shadow: none; }
.note-status { font-size: 12px; min-height: 16px; }

.note-share-box { display: flex; flex-direction: column; gap: 10px; }
.note-people {
  display: flex; flex-wrap: wrap; gap: 8px;
  padding: 10px; background: var(--surface-2); border-radius: 10px;
}
.note-person {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; padding: 4px 10px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 999px;
  cursor: pointer;
}

/* Новое сообщение появляется, а не возникает: короткое движение снизу вверх
   объясняет глазу, что произошло, — это и есть разница между «отправилось» и
   «страница моргнула». */
@keyframes chat-appear {
  from { opacity: 0; transform: translateY(8px) scale(.98); }
  to   { opacity: 1; transform: none; }
}
.chat-row.appear .chat-bubble { animation: chat-appear .22s ease-out; }

@media (prefers-reduced-motion: reduce) {
  .chat-row.appear .chat-bubble { animation: none; }
}

/* Приглашение обновиться после выкладки. Внизу справа, поверх всего, но не
   перекрывая работу: человек дочитает и нажмёт, когда будет готов. */
.newver {
  position: fixed; right: 20px; bottom: 20px; z-index: 200;
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: 12px; box-shadow: var(--shadow-lg);
  font-size: 13.5px;
}
@media (max-width: 640px) {
  .newver { left: 12px; right: 12px; bottom: 12px; justify-content: space-between; }
}
/* Пузырь, который ещё уходит на сервер: чуть бледнее, чтобы было видно разницу
   между «написал» и «отправлено». */
.chat-row.sending .chat-bubble { opacity: .6; }

/* Финансы: две колонки на широком экране, одна на узком */
.fin-cols { display: grid; gap: 14px; grid-template-columns: 1fr 1fr; align-items: start; }
@media (max-width: 900px) { .fin-cols { grid-template-columns: 1fr; } }

/* Деньги запуска: план против факта */
.lm-money-top { display: flex; justify-content: space-between; align-items: flex-end; gap: 12px; }
.lm-bar { height: 6px; border-radius: 999px; background: var(--surface-3); margin: 10px 0 12px; overflow: hidden; }
.lm-bar-fill { height: 100%; background: var(--accent); border-radius: 999px; }
.lm-bar-fill.over { background: var(--danger); }
.lm-money-table { width: 100%; font-size: 13px; }
.lm-money-table td { padding: 4px 0; }

/* Календарь платежей. Просроченный платёж и остаток, ушедший в минус, — два
   места, где цвет несёт смысл: разрыв должен быть виден раньше, чем его
   прочитают глазами по цифрам. */
.row-overdue td { background: var(--danger-soft); }
.num-bad { color: var(--danger); }

/* ================= Календарь платежей =================
   Сетка месяца вместо списка: глазами видно не «когда что», а «где густо».
   Цвет здесь несёт смысл и только его: красное — деньги ушли в минус или
   платёж просрочен, зелёное — приход. Всё остальное нейтрально, иначе пёстрая
   сетка перестаёт читаться. */
.cal-head {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px;
  margin-bottom: 6px;
}
.cal-head div {
  font-size: 11px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted); text-align: center; padding: 2px 0;
}
/* minmax(0,1fr), а не 1fr: иначе длинное название платежа задаёт колонке
   минимальную ширину, и седьмой день недели уезжает за край панели. */
.cal-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; }
.cal-cell {
  min-height: 96px; min-width: 0; border: 1px solid var(--border); border-radius: 10px;
  padding: 6px 7px; background: var(--surface);
  display: flex; flex-direction: column; gap: 4px;
}
/* Дни соседних месяцев показываем, чтобы недели не рвались, но приглушаем */
.cal-cell.cal-out { background: transparent; border-color: transparent; }
.cal-cell.cal-out .cal-date { color: var(--faint); }
.cal-cell.cal-today { border-color: var(--accent); }
/* День, в который прогноз ушёл в минус */
.cal-cell.cal-gap { background: var(--danger-soft); border-color: color-mix(in srgb, var(--danger) 35%, transparent); }
.cal-date { font-size: 12px; color: var(--muted); font-weight: 600; }
.cal-cell.cal-today .cal-date { color: var(--accent); }
.cal-item {
  font-size: 11.5px; line-height: 1.25; border-radius: 6px; padding: 3px 5px;
  background: var(--surface-2); border: 1px solid var(--border);
  cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.cal-item:hover { border-color: var(--accent); }
.cal-item .cal-sum { font-weight: 650; }
.cal-item.cal-in { background: var(--ok-soft); border-color: color-mix(in srgb, var(--ok) 28%, transparent); }
.cal-item.cal-overdue { background: var(--danger-soft); border-color: color-mix(in srgb, var(--danger) 30%, transparent); }
/* Будущий повтор — тот же платёж, которого ещё не было: тише остальных */
.cal-item.cal-virtual { opacity: .62; border-style: dashed; }
.cal-more { font-size: 11px; color: var(--muted); cursor: pointer; }
.cal-left { margin-top: auto; font-size: 11px; color: var(--faint); text-align: right; }
.cal-left.bad { color: var(--danger); font-weight: 650; }
@media (max-width: 900px) {
  .cal-cell { min-height: 74px; }
  .cal-item { font-size: 10.5px; }
}

/* Кнопка «убрать из ряда» — незаметна, пока не наводишь на строку: удаление
   не то действие, которое должно стоять на виду и звать нажать. */
.rv-row { position: relative; }

/* Строка карточки в форме сравнения: поле, галочка «наша», кнопка убрать.
   Галочка одна на всё сравнение — две своих карточки означали бы, что место
   по цене считать не от чего. */
.rv-line { display: flex; gap: 8px; align-items: center; margin-bottom: 6px; }
.rv-line-sku { flex: 1 1 auto; min-width: 0; }
.rv-line-mine {
  display: flex; gap: 6px; align-items: center; cursor: pointer;
  font-size: 13px; color: var(--muted); white-space: nowrap;
  padding: 0 10px; border: 1px solid var(--border); border-radius: 8px;
  height: 38px; flex: none;
}
.rv-line-mine input { width: 15px; height: 15px; }
.rv-line-mine:has(input:checked) { color: var(--accent); border-color: var(--accent); }
.rv-line-del { flex: none; }

/* Строка запуска в финансах: бейдж площадки перед названием. Цвет площадки
   узнаётся быстрее, чем читается слово, — глаз находит нужную строку сразу. */
.fl-name { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.fl-name .rv-badge { flex: none; }
/* Логотип площадки — тот же файл, что на главной: узнаётся мгновенно, читать
   ничего не надо. */
.fl-logo { flex: none; border-radius: 5px; display: block; }

/* ============ График движения денег ============
   Цвета проверены валидатором на различимость при дальтонизме и на контраст с
   подложкой — в каждой теме свои шаги, а не осветление светлых: зелёный 400
   выпадал из полосы яркости на тёмном фоне.

   Столбики — обычные блоки: растянутый SVG искажает скругления, превращая их
   в капсулы, а библиотеку графиков в проект без зависимостей тянуть незачем. */
:root {
  --mc-in: #1f8f5a;    /* приход */
  --mc-out: #5b53d3;   /* расход */
}
[data-theme="dark"] {
  --mc-in: #34a873;
  --mc-out: #7c74e8;
}
.mc-wrap { padding: 2px 0 0; }
.mc-plot {
  display: flex; align-items: stretch; gap: 2px;   /* 2px зазор между столбиками */
  position: relative;
}
/* Нулевая линия проходит по стыку верхней и нижней половин */
.mc-plot::before {
  content: ''; position: absolute; left: 0; right: 0; top: var(--mc-up);
  border-top: 1px solid var(--border);
}
.mc-col {
  flex: 1 1 0; min-width: 0; display: flex; flex-direction: column;
  cursor: default;
}
.mc-up { display: flex; align-items: flex-end; }
.mc-down { display: flex; align-items: flex-start; }
.mc-up i, .mc-down i { display: block; width: 100%; }
.mc-in { background: var(--mc-in); border-radius: 3px 3px 0 0; }
.mc-out { background: var(--mc-out); border-radius: 0 0 3px 3px; }
.mc-col:hover .mc-in, .mc-col:hover .mc-out { filter: brightness(1.25); }
.mc-tick {
  font-family: var(--font-mono); font-size: 10px; color: var(--faint);
  text-align: center; height: 16px; line-height: 16px;
  overflow: hidden; white-space: nowrap;
}
.mc-legend {
  display: flex; gap: 14px; align-items: center; margin-top: 8px;
  font-size: 12px; color: var(--muted);
}
.mc-legend span { display: flex; gap: 6px; align-items: center; }
.mc-legend .spacer { flex: 1; }
.mc-dot { width: 9px; height: 9px; border-radius: 2px; display: inline-block; }
.mc-dot.in { background: var(--mc-in); }
.mc-dot.out { background: var(--mc-out); }

/* Полоса доли в таблице статей: сама строка и есть шкала — отдельная колонка
   с процентом рядом с полосой дублировала бы одно и то же дважды. */
.cat-bar { height: 4px; border-radius: 999px; background: var(--surface-3); margin-top: 6px; }
.cat-bar i { display: block; height: 100%; border-radius: 999px; background: var(--mc-out); }

/* ============ Категориальные цвета финансов ============
   Четыре оттенка в фиксированном порядке, прогнанные валидатором в обеих темах:
   различимы при дальтонизме и контрастны к подложке. Больше не берём — пятый
   цвет из этой палитры уже сливался с зелёным даже при обычном зрении.

   Цвет назначается по СМЫСЛУ, а не по порядку в списке: у счёта — по виду,
   у платежа — по группе статьи. Иначе он перекрашивался бы при добавлении
   новой записи и перестал бы что-либо значить. */
:root {
  --c1: #1f8f5a;   /* зелёный */
  --c2: #5b53d3;   /* фиолетовый */
  --c3: #b06b12;   /* янтарный */
  --c4: #0e8fa0;   /* бирюзовый */
}
[data-theme="dark"] {
  --c1: #34a873;
  --c2: #7c74e8;
  --c3: #bd821f;
  --c4: #0fa3ba;
}

/* Полоска слева у счёта: вид счёта узнаётся до чтения подписи */
.acc-row { position: relative; }
.acc-mark {
  display: inline-block; width: 3px; height: 26px; border-radius: 2px;
  margin-right: 10px; vertical-align: middle; flex: none;
}
.acc-mark.bank { background: var(--c2); }
.acc-mark.card { background: var(--c4); }
.acc-mark.cash { background: var(--c3); }
.acc-mark.platform { background: var(--c1); }
/* Товар — те же цвета мест, но полоска полая: деньги и товар различаются формой,
   а не оттенком. Оттенков на всё уже не хватает, да и разница тут важнее
   принадлежности к месту. */
.acc-mark.stock { background: none; box-shadow: inset 0 0 0 1.5px var(--c2); }
.acc-mark.stock.own { box-shadow: inset 0 0 0 1.5px var(--c1); }
.acc-mark.stock.transit { box-shadow: inset 0 0 0 1.5px var(--c3); }
.acc-mark.stock.marketplace { box-shadow: inset 0 0 0 1.5px var(--c4); }
.acc-cell { display: flex; align-items: center; }

/* Плашка платежа в календаре: цвет по группе статьи. Приход остаётся зелёным
   всегда — это не «одна из категорий», а другое направление денег. */
.cal-item.g-tovar { border-left: 3px solid var(--c2); }
.cal-item.g-promo { border-left: 3px solid var(--c3); }
.cal-item.g-company { border-left: 3px solid var(--c4); }
.cal-item.g-platform { border-left: 3px solid var(--c1); }

/* ---------------------------------------------------------------------------
   ОТЗЫВЫ И ВОПРОСЫ
   Карточка вместо строки таблицы: отзыв — это текст, который надо прочитать,
   а не число, которое надо сравнить.
   --------------------------------------------------------------------------- */
.rv-list { display: flex; flex-direction: column; gap: 12px; }
.rv-card {
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface); padding: 14px 16px;
}
/* Плохая оценка помечается полосой слева: в списке видно, куда смотреть */
.rv-card.is-bad { border-left: 3px solid var(--danger); }
/* Ответ уже отправлен: карточка приглушена, чтобы взгляд шёл к неотвеченным. */
.rv-card.is-done { border-left: 3px solid var(--ok); opacity: .78; }
.rv-card.is-done:hover { opacity: 1; }
.rv-sent {
  margin-top: 8px; padding: 8px 10px; border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--muted); font-size: 13px; line-height: 1.5;
}
.rv-head { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.rv-img {
  width: 42px; height: 42px; object-fit: cover; border-radius: var(--r-sm);
  background: var(--surface-2); flex: none;
}
.rv-mini {
  width: 30px; height: 30px; object-fit: cover; border-radius: 6px;
  background: var(--surface-2); margin-right: 10px; flex: none;
}
.rv-about { flex: 1; min-width: 0; }
.rv-rate { font-size: 14px; letter-spacing: 1px; color: var(--warn); white-space: nowrap; }
.rv-rate.bad { color: var(--danger); }
.rv-when { font-size: 12px; white-space: nowrap; }
.rv-text { font-size: 13.5px; line-height: 1.55; margin-bottom: 8px; }
.rv-part { margin-bottom: 4px; }
.rv-part b { font-weight: 650; }
.rv-answer { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }
.rv-answer textarea { width: 100%; resize: vertical; font-size: 13.5px; }
.rv-actions { display: flex; align-items: center; gap: 8px; margin-top: 8px; flex-wrap: wrap; }

/* Наш опубликованный ответ — отдельным блоком, визуально «ниже» отзыва:
   это уже сделанная работа, а не поле для ввода. */
.rv-ours {
  margin-top: 10px; padding: 10px 12px; border-radius: var(--r-sm);
  background: var(--surface-2); font-size: 13px; line-height: 1.5;
}
.rv-ours-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; font-size: 12px; }
.tag.tag-bad { background: var(--danger-soft); color: var(--danger); }
/* Состояние ответа: зелёное — стоит в кабинете, жёлтое — в пути. */
.tag.tag-ok { background: var(--ok-soft); color: var(--ok); font-weight: 600;
  border-color: color-mix(in srgb, var(--ok) 22%, transparent); }
.tag.tag-wait { background: var(--warn-soft); color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 22%, transparent); }

/* Выбор оценок: несколько сразу — «покажи всё, что 1, 2 и 3» */
.stars-row { display: flex; gap: 4px; }
.star-btn {
  padding: 5px 10px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--muted); font-size: 12.5px; cursor: pointer;
  font-family: inherit;
}
.star-btn:hover { border-color: var(--faint); }
.star-btn.on {
  background: var(--warn-soft); color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 40%, transparent); font-weight: 650;
}
.rev-filters { margin-bottom: 14px; }
.rev-filters input[type="date"] { width: auto; }
/* Число в кнопке состояния: сколько там записей при текущих фильтрах */
.switch button b { margin-left: 6px; font-family: var(--font-mono); font-size: 11.5px; opacity: .75; }

/* Заметка к отзыву: наша внутренняя, в кабинет не уходит */
.rv-note { margin-top: 10px; }
.rv-note-head { display: flex; align-items: center; gap: 8px; }
.rv-note-text {
  margin-top: 6px; padding: 8px 10px; border-radius: var(--r-sm);
  background: var(--surface-2); font-size: 12.5px; line-height: 1.5; color: var(--muted);
}
.tag.tag-watch { background: var(--warn-soft); color: var(--warn); }
/* Оценка изменилась после наших переговоров — главная хорошая новость раздела */
.rv-changed {
  margin-top: 10px; padding: 9px 12px; border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--mc-in) 12%, transparent);
  color: var(--mc-in); font-size: 13px;
}

/* Отзыв исчез из кабинета: не ошибка сбора, а действие покупателя */
.rv-gone {
  margin-top: 10px; padding: 9px 12px; border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--muted); font-size: 13px;
}

/* Памятка: заголовок пункта редактируется прямо в строке */
.note-title { font-weight: 650; font-size: 14px; border: 1px solid transparent; background: transparent; }
.note-title:focus { border-color: var(--line); background: var(--surface); }

/* ---------------------------------------------------------------------------
   ДИНАМИКА ТОВАРОВ — карта дней
   --------------------------------------------------------------------------- */

.tr-controls { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; margin-bottom: 14px; }
/* Прокрутка внутри блока, а не всей страницей: на месяце и двух таблица иначе
   растягивает панель и уезжает за край экрана вместе с ней.
   `min-width: 0` обязателен — без него флекс-родитель разрешает содержимому
   раздуть колонку, и `overflow` не срабатывает. */
/* Контейнер сжимается по таблице: иначе за короткой таблицей тянется пустая
   полоса прокрутки, и поле справа выглядит разным на разных периодах. */
.tr-scroll { overflow-x: auto; width: max-content; max-width: 100%;
  min-width: 0; padding-bottom: 6px; }
.tr-scroll::-webkit-scrollbar { height: 10px; }
.tr-scroll::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: var(--r-pill); }
.tr-scroll::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }
.tr-scroll::-webkit-scrollbar-track { background: transparent; }

.tr-map {
  /* БЕЗ ЩЕЛЕЙ МЕЖДУ ЯЧЕЙКАМИ.
     При `border-spacing` между ячейками остаются настоящие дырки, и сквозь них
     при прокрутке просвечивает то, что проезжает под закреплённой колонкой с
     названием: выглядит так, будто содержимое наезжает на имена. Зазор между
     клетками теперь рисуем прозрачной рамкой внутри самой клетки — щелей нет,
     а промежутки на вид те же. */
  border-collapse: separate; border-spacing: 0; font-size: 12px;
  /* Жёсткая сетка: иначе браузер растягивает колонки под длину числа, и клетки
     получаются разной ширины — карта перестаёт читаться как карта. */
  table-layout: fixed;
  /* Ширина строго по содержимому. Любое растягивание браузер раздаёт всем
     колонкам, даже с заданной шириной: на широком экране клетка на двух
     неделях вырастала до 82 пикселей при 44 на двух месяцах. Проверено
     замером `tests/замер-карты.js` — без него это не видно, на узком окне
     таблица и так шире экрана. */
  width: max-content;
}
.tr-map th { font-weight: 500; color: var(--muted); font-size: 10.5px; padding: 0 0 4px;
  font-family: var(--font-mono); text-align: center; }
.tr-map th.tr-weekend { color: var(--faint); }
/* Название прилипает к левому краю: на двух месяцах строка уезжает вправо, и
   без этого непонятно, чей это ряд. */
/* Тень у правого края закреплённой колонки — признак того, что слева есть ещё
   данные и они уехали под названия. Без неё прокрученная таблица выглядит так,
   будто за первые дни цифр просто нет: 06.09.2026 из-за этого Дмитрий увидел
   в шапке 10 заказов, а по видимым столбцам насчитал 7. */
.tr-map .tr-name { position: sticky; left: 0; z-index: 1; background: var(--surface);
  box-shadow: 6px 0 8px -8px rgba(0, 0, 0, .55);
  /* Ширина жёсткая: от метрики она зависеть не должна, иначе при переключении
     список товаров прыгает вместе с таблицей. */
  width: 300px; min-width: 300px; max-width: 300px;
  overflow: hidden; white-space: nowrap; padding-right: 10px; font-size: 12.5px; }
.tr-map tbody .tr-name { display: flex; align-items: center; gap: 6px; height: 38px; }
/* ИМЯ, МЕТКА И АРТИКУЛ — В ОДНУ СТРОКУ.
   Двухстрочная подпись задавала высоту всей строки таблицы, и клетки
   вытягивались в прямоугольники: строку тянет самая высокая ячейка. Плюс метка
   распродажи обрезалась вместе с длинным названием. Теперь метка идёт первой и
   не сжимается, имя ужимается, артикул держится справа. */
.tr-map .tr-name { line-height: 1; }
.tr-map .tr-name .tag-sale { flex: 0 0 auto; }
.tr-map .tr-name .tr-nm { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
.tr-map .tr-name .tr-art { flex: 0 0 auto; color: var(--muted); font-size: 11px;
  font-variant-numeric: tabular-nums; }
.tr-map .tr-name > * { vertical-align: middle; }
.tr-map .tr-total { font-family: var(--font-mono); color: var(--muted); padding-left: 8px;
  text-align: right; width: 74px; min-width: 74px; }

.tr-map .tr-fill { padding: 0; border: 0; background: transparent; width: 100%; }

/* ОДИН РАЗМЕР НА ВСЕ МЕТРИКИ.
   Раньше у денег и процентов клетки были шире, чем у штук: при переключении
   метрики вся таблица дёргалась, а колонка с названием меняла ширину. Теперь
   размер один и рассчитан на самое длинное значение — «20,4» тысячи или
   «13,25» процента. */
.tr-cell, .tr-map th:not(.tr-name) {
  width: 44px; min-width: 44px; max-width: 44px;
}
.tr-cell {
  /* Высота равна ширине: клетка должна быть квадратом, иначе карта читается
     как таблица чисел, а не как плитка. Меняете ширину — меняйте и высоту.
     Рамка прозрачная: она и создаёт промежуток между клетками, при этом сама
     ячейка остаётся сплошной и ничего сквозь неё не видно. */
  height: 44px; border: 2px solid transparent; background-clip: padding-box;
  text-align: center; border-radius: 8px;
  font-family: var(--font-mono); font-size: 11px; cursor: default;
  overflow: hidden; white-space: nowrap;
  transition: transform var(--dur) var(--ease-out);
}
/* У денег и процентов значение длиннее — уменьшаем шрифт, но НЕ размер клетки:
   таблица не должна перестраиваться при переключении метрики. */
.tr-map.is-money .tr-cell, .tr-map.is-percent .tr-cell { font-size: 10px; letter-spacing: -.02em; }
.tr-cell:hover { transform: scale(1.12); }

/* Семь ступеней вместо плавной заливки: глаз сравнивает уровни, а не оттенки.
   Середина намеренно нейтральная — «как обычно» не должно бросаться в глаза. */
.tr-none  { background: transparent; }
.tr-zero  { background: var(--surface-2); color: var(--faint); }
.tr-flat  { background: var(--surface-3); color: var(--muted); }
.tr-bad1  { background: color-mix(in srgb, var(--danger) 18%, var(--surface-2)); color: var(--text); }
.tr-bad2  { background: color-mix(in srgb, var(--danger) 42%, var(--surface-2)); color: #fff; }
.tr-bad3  { background: color-mix(in srgb, var(--danger) 72%, var(--surface-2)); color: #fff; }
.tr-ok1   { background: color-mix(in srgb, var(--ok) 18%, var(--surface-2)); color: var(--text); }
.tr-ok2   { background: color-mix(in srgb, var(--ok) 42%, var(--surface-2)); color: #fff; }
.tr-ok3   { background: color-mix(in srgb, var(--ok) 72%, var(--surface-2)); color: #fff; }

.tr-legend { display: flex; align-items: center; gap: 6px; margin-top: 14px; font-size: 12px; }
.tr-legend i { display: inline-block; width: 22px; height: 14px; border-radius: 4px; }

/* Карточка одного товара: метрики строками, дни столбцами. */
.tr-prod .tr-name { width: 200px; min-width: 200px; max-width: 200px; }
/* В карточке товара в одной таблице соседствуют штуки, проценты и рубли —
   ширина у всех одна, иначе строки разъезжаются между собой. */
.tr-prod .tr-cell, .tr-prod th:not(.tr-name) { width: 56px; min-width: 56px; max-width: 56px; }
/* Высота задана жёстко на все ячейки строки, а не только на клетки: строку
   растягивает самая высокая ячейка в ней, и раньше это делали подписи слева. */
.tr-prod tbody td, .tr-prod tbody th {
  height: 28px; line-height: 28px; padding-top: 0; padding-bottom: 0;
  overflow: hidden; white-space: nowrap;
}
.tr-prod .tr-cell { font-size: 10.5px; }
.tr-prod tr.is-sub .tr-name { padding-left: 14px; color: var(--muted); font-size: 12px; }
.tr-flag { color: var(--accent); font-style: normal; margin-left: 2px; }

.tr-event-add { display: flex; gap: 8px; align-items: center; margin-bottom: 14px; flex-wrap: wrap; }
.tr-event-add input[type=text] { flex: 1; min-width: 260px; }

.tr-events { display: flex; flex-direction: column; gap: 2px; }
.tr-event {
  display: flex; align-items: center; gap: 9px; padding: 8px 10px;
  border-radius: var(--r-sm); font-size: 13px;
}
.tr-event:nth-child(odd) { background: var(--surface-2); }
.tr-event-date { font-family: var(--font-mono); font-size: 11.5px; color: var(--muted); white-space: nowrap; }
.tr-event-text { min-width: 0; }

/* ── Флажки на записях ──────────────────────────────────────────────────────
   Пометка для глаза: смысл цвета назначает человек, система в него не лезет.

   Первая попытка была слишком деликатной — кружки с прозрачностью .28 на
   тёмной теме слились с фоном, и Дмитрий спросил, как их вообще ставить.
   Поэтому теперь они видны всегда: цветная обводка и лёгкая заливка. */

.tr-flags { display: flex; gap: 5px; flex: none; margin-right: 2px; }
.tr-flag {
  width: 15px; height: 15px; padding: 0; border-radius: 50%;
  border: 2px solid currentColor; background: currentColor;
  cursor: pointer; opacity: .55;
  transition: opacity .12s, transform .12s, box-shadow .12s;
}
.tr-event:hover .tr-flag { opacity: .8; }
.tr-flag:hover { opacity: 1; transform: scale(1.2); }
.tr-flag:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.tr-flag-green { color: #3f9c53; }
.tr-flag-yellow { color: #cc9a2e; }
.tr-flag-red { color: #c0503f; }

/* Поставленный флажок — с кольцом вокруг: видно, какой именно выбран */
.tr-flag.on { opacity: 1; }
.tr-flag-green.on { box-shadow: 0 0 0 3px rgba(63, 156, 83, .3); }
.tr-flag-yellow.on { box-shadow: 0 0 0 3px rgba(204, 154, 46, .3); }
.tr-flag-red.on { box-shadow: 0 0 0 3px rgba(192, 80, 63, .3); }

/* Помеченная запись подсвечена полосой слева — видно, не вглядываясь */
.tr-event.flag-green,
.tr-event.flag-yellow,
.tr-event.flag-red { box-shadow: inset 3px 0 0 var(--flag); }
.tr-event.flag-green { --flag: #3f9c53; background: color-mix(in srgb, #3f9c53 7%, transparent); }
.tr-event.flag-yellow { --flag: #cc9a2e; background: color-mix(in srgb, #cc9a2e 8%, transparent); }
.tr-event.flag-red { --flag: #c0503f; background: color-mix(in srgb, #c0503f 8%, transparent); }

[data-theme="dark"] .tr-event.flag-green { background: color-mix(in srgb, #3f9c53 12%, transparent); }
[data-theme="dark"] .tr-event.flag-yellow { background: color-mix(in srgb, #cc9a2e 12%, transparent); }
[data-theme="dark"] .tr-event.flag-red { background: color-mix(in srgb, #c0503f 12%, transparent); }

/* Всё по товару — на одном экране: слева выбор, справа цифры и записи. */
.tr-layout { display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: var(--s-3); align-items: start; }
.tr-side {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
  overflow: hidden; position: sticky; top: var(--s-4);
}
.tr-side-head {
  padding: 11px var(--s-4); font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--faint); border-bottom: 1px solid var(--border);
}
.tr-side-item { padding: 9px var(--s-4); cursor: pointer; border-bottom: 1px solid var(--border-soft, var(--border)); }
.tr-side-item:last-child { border-bottom: none; }
.tr-side-item:hover { background: var(--surface-2); }
.tr-side-item.on { background: var(--surface-3); box-shadow: inset 3px 0 0 var(--accent); }
.tr-side-name { font-size: 13px; font-weight: 550; line-height: 1.3; }
.tr-side-sub { font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.tr-main { min-width: 0; }

@media (max-width: 1100px) {
  .tr-layout { grid-template-columns: 1fr; }
  .tr-side { position: static; }
}

/* День, в который что-то делали, должен бросаться в глаза: по нему читают
   причину скачка. Мелкая точка сбоку для этого не годится. */
.tr-prod th.has-event { color: var(--accent); font-weight: 700; }
.tr-prod th.has-event .tr-flag {
  display: block; height: 3px; margin: 3px 2px 0;
  background: var(--accent); border-radius: 2px;
}
.tr-prod .tr-cell.in-event { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 45%, transparent); }

.tr-side-head { display: flex; align-items: center; gap: 6px; }
.tr-side-item { display: flex; align-items: center; gap: 9px; }
.tr-side-item.is-off { opacity: .45; }
.tr-side-item input[type=checkbox] { width: 15px; height: 15px; flex: none; }
.tr-side-foot { padding: 9px var(--s-4); font-size: 11.5px; border-top: 1px solid var(--border); }

/* Пометка «цифра неполная»: лучше видимый вопрос, чем тихое умолчание. */
.tr-warn {
  display: inline-block; width: 13px; height: 13px; line-height: 13px; text-align: center;
  border-radius: 50%; background: var(--warn-soft); color: var(--warn);
  font-size: 10px; font-style: normal; font-weight: 700; cursor: help;
}

/* Карточка в распродаже: её цифры нельзя мерить меркой новинок. */
.tag.tag-sale { background: var(--warn-soft); color: var(--warn); font-size: 10.5px; padding: 1px 6px; }

/* Расхождения сверки: заметно, но без паники — это повод разобраться. */
.checkup-bad {
  padding: 12px 14px; border-radius: var(--r-sm);
  background: var(--danger-soft); border: 1px solid color-mix(in srgb, var(--danger) 25%, transparent);
  font-size: 13px;
}
.checkup-list { margin-top: 6px; display: flex; flex-direction: column; gap: 3px; }

/* Значок площадки рядом с названием: видно, откуда цифры, без чтения подписи. */
.tr-side-name .plat-ico, .tr-map .tr-name .plat-ico { vertical-align: -2px; margin-right: 1px; }
.switch button .plat-ico { vertical-align: -2px; margin-right: 3px; }
.tr-prod h2 .plat-ico, .panel-head h2 .plat-ico { vertical-align: -3px; margin-right: 4px; }

/* История операций финансов: кто, когда, что изменил. */
.flog { display: flex; flex-direction: column; }
.flog-row { display: flex; gap: 14px; padding: 10px 2px; border-bottom: 1px solid var(--border); }
.flog-row:last-child { border-bottom: none; }
.flog-when { width: 76px; flex: none; font-family: var(--font-mono); font-size: 11.5px; line-height: 1.5; }
.flog-body { min-width: 0; flex: 1; }
.flog-head { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; font-size: 13px; }
/* Действия системы приглушены: их много, и они не требуют внимания. */
.flog-sys { color: var(--muted); }
.flog-changes { margin-top: 5px; display: flex; flex-direction: column; gap: 2px; font-size: 12.5px; }
.flog-changes s { color: var(--muted); }
.flog-title { font-variant-numeric: tabular-nums; }
.flog-parts { margin-top: 3px; font-size: 12.5px; color: var(--muted); }

/* ВЕРТИКАЛЬНОЙ ПРОКРУТКИ У КАРТЫ НЕТ — И НЕ НАДО.
   Пробовали ограничить высоту и закрепить шапку с датами: вместе с закреплённой
   слева колонкой названий это дало наложение слоёв, из-за которого содержимое
   просвечивало под именами и «прыгало» при прокрутке. На вкладке «По товару»
   такой таблицы нет, и там всё спокойно — карта устроена так же: прокрутка
   только горизонтальная, по вертикали листается вся страница. */

/* Край закреплённой колонки обозначаем линией: при прокрутке должно быть видно,
   где заканчивается список товаров и начинаются дни. */
.tr-map .tr-name { box-shadow: 1px 0 0 var(--border); }

/* Колонка товара повторяет список на вкладке по товару — те же классы, та же
   метка распродажи. Отдельная вёрстка распирала колонку и ломала таблицу. */
.tr-map .tr-name .tr-side-name { white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; }
.tr-map .tr-name .tr-side-sub { font-variant-numeric: tabular-nums; }
.tr-map tr.is-off { opacity: .45; }
.tr-map .tr-pick { position: sticky; left: 0; z-index: 2; background: var(--surface);
  padding: 0 6px; }

/* Разбивка остатка Ozon по карточкам: значок рядом с числом. */
.stock-split { display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; border-radius: 50%; font-size: 10px; font-weight: 600;
  color: var(--muted); border: 1px solid var(--border); cursor: help;
  vertical-align: 1px; margin-left: 3px; }
.stock-split:hover { color: var(--text); border-color: currentColor; }

/* Список товаров у карты дней свой не нужен: состав берётся с вкладки «По
   товару». Освободившаяся ширина уходит клеткам — они становятся квадратными,
   а не приплюснутыми. */
.tr-side-item.is-off { opacity: .5; }

/* Лицо на шаге, который ещё не начали: человек за ним закреплён, но работа не
   идёт. Приглушаем, чтобы не путать с тем, у кого шаг уже в руках, — и всё же
   показываем: до этой правки было не видно, кто отвечает за будущий шаг. */
.st-who-soon { opacity: .5; filter: saturate(.7); }
.st-done .st-who-soon, .st-skip .st-who-soon { display: none; }

/* ── График рекламы ───────────────────────────────────────────────────────
   Столбики по дням рисуем разметкой, без библиотек: в проекте нет ни одной
   зависимости, и заводить их ради графика незачем. */
.ads-chart {
  display: flex; align-items: flex-end; gap: 6px;
  height: 190px; padding: 8px 0 0; overflow-x: auto;
}
.ads-bar {
  flex: 0 0 var(--w, 64px); min-width: 42px; height: 100%;
  display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 4px;
}
.ads-bar-v {
  font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums;
  white-space: nowrap; height: 14px;
}
.ads-bar-fill {
  width: 100%; border-radius: 4px 4px 2px 2px; min-height: 2px;
  background: var(--accent, var(--text)); opacity: .82;
  transition: opacity var(--dur);
}
.ads-bar:hover .ads-bar-fill { opacity: 1; }
.ads-bar-d {
  font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* Пустой день на графике: не «ноль», а «данных нет». Полоска во всю высоту,
   почти прозрачная — видно, что день в периоде есть, а расхода в нём не было. */
.ads-bar-fill.empty {
  background: repeating-linear-gradient(180deg,
    var(--border) 0 3px, transparent 3px 7px);
  opacity: .5;
}

/* ── Дневник товара в разделе рекламы ─────────────────────────────────────
   Причины рядом с цифрами: график говорит, что случилось, запись — почему. */
.ads-diary { display: flex; flex-direction: column; }
.ads-diary-row {
  display: flex; gap: 14px; padding: 10px 0; border-top: 1px solid var(--border);
}
.ads-diary-row:first-child { border-top: 0; padding-top: 0; }
.ads-diary-date {
  flex: 0 0 76px; font-family: var(--font-mono); font-size: 12.5px; color: var(--muted);
  font-variant-numeric: tabular-nums; padding-top: 1px;
}
.ads-diary-body { flex: 1; min-width: 0; font-size: 13.5px; }
.ads-diary-ev { margin-top: 3px; }
.tag-kind {
  display: inline-block; font: 600 10px/1 var(--font-mono); letter-spacing: .05em;
  padding: 3px 6px; border-radius: 4px; margin-right: 6px;
  background: var(--surface-2); color: var(--muted); vertical-align: 1px;
}
.tag-kind.kind-ads { background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent); }

/* ══ Планеты в разделе «Реклама» ═══════════════════════════════════════════
   Раздел ведёт агент Марс, и космос здесь работает на дело: у каждой плашки
   свой цвет и свой шарик, и через неделю «расход» узнаётся боковым зрением
   быстрее, чем читается подпись. Планеты идут по порядку от Солнца — тогда
   и порядок плашек перестаёт выглядеть случайным.

   Цвет держим приглушённым: он трогает фон и метку, но не само число.
   Цифру читают, а не рассматривают. */
.planet-tile {
  position: relative; overflow: hidden;
  background:
    radial-gradient(120% 90% at 100% 0%, color-mix(in srgb, var(--planet) 12%, transparent), transparent 62%),
    var(--surface);
}
[data-theme="dark"] .planet-tile {
  background:
    radial-gradient(120% 90% at 100% 0%, color-mix(in srgb, var(--planet) 20%, transparent), transparent 62%),
    var(--surface);
}
.planet-tile .label { color: color-mix(in srgb, var(--planet) 58%, var(--muted)); }
[data-theme="dark"] .planet-tile .label { color: color-mix(in srgb, var(--planet) 62%, var(--muted)); }

.planet-dot {
  position: absolute; top: 11px; right: 12px;
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--planet-fill, var(--planet));
  box-shadow: inset -3px -2px 5px rgba(0, 0, 0, .42), 0 1px 4px color-mix(in srgb, var(--planet) 45%, transparent);
}
.planet-dot::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle at 30% 26%, rgba(255, 255, 255, .38), transparent 52%);
}

/* Меркурий — серый, побитый кратерами */
.p-mercury { --planet: #8b8178; }
.p-mercury .planet-dot {
  --planet-fill: radial-gradient(circle at 34% 30%, #a89c91, #7d7269 60%, #574f49 100%);
}
/* Венера — плотная кремовая облачность */
.p-venus { --planet: #d1a24e; }
.p-venus .planet-dot {
  --planet-fill: radial-gradient(circle at 32% 28%, #f0d197, #c08f3e 62%, #8a5f22 100%);
}
/* Земля — океаны и материки */
.p-earth { --planet: #3b82c4; }
.p-earth .planet-dot {
  --planet-fill:
    radial-gradient(circle at 62% 62%, #4e9b62 0 26%, transparent 27%),
    radial-gradient(circle at 30% 38%, #57a86c 0 18%, transparent 19%),
    radial-gradient(circle at 34% 30%, #63a9dd, #2f6fae 60%, #1d4470 100%);
}
/* Марс — ржавая пыль, цвет самого агента */
.p-mars { --planet: #c2603c; }
.p-mars .planet-dot {
  --planet-fill:
    radial-gradient(circle at 62% 40%, #a44a2c 0 22%, transparent 23%),
    radial-gradient(circle at 34% 30%, #d97b4e, #b4512c 55%, #7d3018 100%);
}
/* Юпитер — полосы и красное пятно */
.p-jupiter { --planet: #c08a55; }
.p-jupiter .planet-dot {
  --planet-fill:
    radial-gradient(circle at 66% 58%, #a8482f 0 15%, transparent 16%),
    repeating-linear-gradient(180deg, #d8a878 0 3px, #b98753 3px 5px, #caa06b 5px 8px);
}
/* Сатурн — бледный шар; кольцо рисуем отдельно */
.p-saturn { --planet: #cbb27a; }
.p-saturn .planet-dot {
  --planet-fill: radial-gradient(circle at 32% 28%, #e6d5a4, #c2a86f 60%, #8d7845 100%);
}
.p-saturn .planet-dot::before {
  content: ""; position: absolute; left: -7px; right: -7px; top: 45%;
  height: 3px; border-radius: 50%;
  border: 1px solid color-mix(in srgb, #d8c48f 78%, transparent);
  transform: rotate(-18deg);
}

/* ── Товары в форме акции ─────────────────────────────────────────────────
   Артикул рядом с названием: у товара их бывает несколько — основной и
   распродажный, — и по одному названию менеджер не понимает, какой считает. */
.pf-prod-name { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.pf-arts { display: flex; flex-wrap: wrap; gap: 6px; }
.pf-art { display: inline-flex; align-items: center; gap: 5px; }
.pf-art-code {
  font-family: var(--font-mono); font-size: 11.5px; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.tag-main { background: color-mix(in srgb, var(--ok, #2f7d5f) 14%, transparent); color: var(--ok, #2f7d5f); }
.tag-sale { background: color-mix(in srgb, var(--warn, #b8763a) 16%, transparent); color: var(--warn, #b8763a); }

/* ── Сигналы раздела рекламы ──────────────────────────────────────────────
   Не «плохо», а «столько стоит»: цифра, которую можно проверить делением,
   заставляет что-то сделать, а оценка «высокий ДРР» — нет. */
.ads-signals { display: flex; flex-direction: column; }
.ads-sig {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 12px 0; border-top: 1px solid var(--border);
}
.ads-sig:first-child { border-top: 0; padding-top: 0; }
.ads-sig-pr {
  font: 600 10px/1 var(--font-mono); letter-spacing: .06em; padding: 4px 6px;
  border-radius: 4px; white-space: nowrap; background: var(--surface-2); color: var(--muted);
}
.ads-sig.p1 .ads-sig-pr { background: color-mix(in srgb, var(--bad) 16%, transparent); color: var(--bad); }
.ads-sig.p2 .ads-sig-pr { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }
.ads-sig-body { flex: 1; min-width: 0; }
.ads-sig-money {
  text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums;
  display: flex; flex-direction: column; gap: 2px; font-size: 13.5px;
}
.ads-sig-money .faint { font-size: 11.5px; }

.gate-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 6px;
  background: var(--muted); vertical-align: 1px;
}
.gate-dot.ok { background: var(--ok); }
.gate-dot.bad { background: var(--bad); }
.gate-dot.unk { background: var(--muted); opacity: .5; }

/* ── Агент Марс ───────────────────────────────────────────────────────────
   Отдельным лицом и своим цветом: видно, где говорит модель, а где считает
   система. Слова агента и цифры раздела не должны читаться как одно и то же. */
.mars {
  --mars: #c2603c;
  border: 1px solid color-mix(in srgb, var(--mars) 34%, var(--border));
  border-radius: var(--r-md); background: var(--surface); margin: 16px 0 4px; overflow: hidden;
}
[data-theme="dark"] .mars { --mars: #e08a63; }
.mars-head { display: flex; gap: 13px; align-items: center; padding: 14px 16px; }
.mars-planet {
  width: 46px; height: 46px; border-radius: 50%; flex: 0 0 46px; position: relative;
  background:
    radial-gradient(circle at 32% 26%, #e8a077 0 8%, transparent 9%),
    radial-gradient(circle at 64% 40%, #a44a2c 0 11%, transparent 12%),
    radial-gradient(circle at 44% 66%, #9c4527 0 14%, transparent 15%),
    radial-gradient(circle at 22% 58%, #b85733 0 9%, transparent 10%),
    radial-gradient(circle at 30% 28%, #d97b4e, #b4512c 52%, #7d3018 100%);
  box-shadow: inset -6px -5px 11px rgba(0, 0, 0, .45), 0 2px 9px rgba(140, 60, 30, .26);
}
.mars-planet::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle at 30% 24%, rgba(255, 220, 190, .32), transparent 46%);
}
.mars-name { font-weight: 650; font-size: 15px; display: flex; align-items: center; gap: 8px; }
.mars-badge {
  font: 600 10px/1 var(--font-mono); letter-spacing: .07em; text-transform: uppercase;
  background: color-mix(in srgb, var(--mars) 15%, transparent); color: var(--mars);
  padding: 4px 7px; border-radius: 5px;
}
.mars-body { padding: 0 16px 6px; font-size: 14px; line-height: 1.6; }
.mars-body p { margin: 0 0 11px; }
.mars-ask { display: flex; gap: 8px; padding: 10px 16px 12px; border-top: 1px solid var(--border); }
.mars-ask input { flex: 1; }
.mars-hints { display: flex; gap: 6px; flex-wrap: wrap; padding: 0 16px 14px; }
.mars-hint {
  border: 1px dashed var(--border-strong); background: transparent; border-radius: 99px;
  padding: 4px 11px; font-size: 12px; color: var(--muted); cursor: pointer;
}
.mars-hint:hover { color: var(--text); border-color: var(--mars); }

/* Модель товара рядом с названием: у Дмитрия на складе две разные модели с
   одинаковым названием («Мультипекарь 3 в 1» — p. 1-3 и SL-206), и по одному
   названию менеджер их не различает. */
.pf-model {
  font-family: var(--font-mono); font-size: 11px; color: var(--muted);
  background: var(--surface-2); padding: 2px 6px; border-radius: 4px; margin-left: 6px;
}

/* Крупная денежная плашка: цена и соинвест в карточке кампании.
   Три числа в ряд, третье выделено — оно и есть ответ на вопрос
   «сколько за нас доплачивает площадка». */
.hero-money {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.hero-money-cell { background: var(--surface); padding: 20px 22px; }
.hero-money-cell.is-accent { background: color-mix(in srgb, var(--accent) 8%, var(--surface)); }
.hero-money-label {
  font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 8px;
}
.hero-money-value {
  font-size: 34px; font-weight: 650; line-height: 1.1;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.hero-money-cell.is-accent .hero-money-value { color: var(--accent); }
.hero-money-note { margin-top: 6px; font-size: 13px; color: var(--muted); }
@media (max-width: 700px) { .hero-money-value { font-size: 27px; } }

/* Поставки: карточки кластеров — то, что переносят в кабинет по одной.
   Каждая карточка это одна заявка, поэтому граница у неё жёсткая. */
.sup-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 12px;
}
.sup-card {
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
  padding: 14px 16px;
}
.sup-card-head {
  display: flex; align-items: baseline; gap: 10px;
  padding-bottom: 8px; margin-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
.sup-card-name { font-weight: 650; }
.sup-card-qty {
  margin-left: auto; font-variant-numeric: tabular-nums;
  color: var(--accent); font-weight: 650;
}
.sup-row {
  display: flex; gap: 10px; padding: 4px 0;
  font-size: 14px; color: var(--ink-2, inherit);
}
.sup-row-qty {
  margin-left: auto; font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* Меркурий — планета поставок. Тот же блок, что у Марса, но своя внешность:
   два агента рядом не должны выглядеть одинаково, иначе человек путает, кто
   из них о чём говорит. Меркурий серо-стальной и щербатый — как оригинал. */
.mars.is-mercury .mars-planet {
  background:
    radial-gradient(circle at 30% 24%, #cfd3d6 0 7%, transparent 8%),
    radial-gradient(circle at 62% 38%, #7d858b 0 10%, transparent 11%),
    radial-gradient(circle at 40% 62%, #6d757b 0 13%, transparent 14%),
    radial-gradient(circle at 24% 56%, #939ba1 0 8%, transparent 9%),
    radial-gradient(circle at 70% 68%, #838b91 0 6%, transparent 7%),
    radial-gradient(circle at 30% 28%, #b6bcc1, #8b9299 52%, #565d63 100%);
  box-shadow: inset -6px -5px 11px rgba(0, 0, 0, .5), 0 2px 9px rgba(90, 100, 110, .28);
}
.mars.is-mercury .mars-planet::after {
  background: radial-gradient(circle at 30% 24%, rgba(255, 255, 255, .28), transparent 46%);
}

/* ── Поставки: расчёт по шагам ───────────────────────────────────────────────
   Вкладка «Почему столько». Шаги нумерованы намеренно: это не украшение, а
   порядок вычисления — каждый следующий опирается на предыдущий. Ключевой шаг
   (тот, что решил исход) подсвечен, чтобы не читать все шесть подряд. */
.why-box { display: flex; flex-direction: column; gap: 2px; }
.why-step {
  display: flex; gap: 13px; align-items: flex-start;
  padding: 13px 15px; border: 1px solid var(--line); border-radius: var(--r-2);
  background: var(--surface);
}
.why-step + .why-step { margin-top: 6px; }
.why-step.is-key {
  border-color: color-mix(in srgb, var(--warn) 34%, transparent);
  background: var(--warn-soft);
}
.why-num {
  flex: none; width: 25px; height: 25px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent);
  font-size: 12.5px; font-weight: 600; font-variant-numeric: tabular-nums;
}
.why-step.is-key .why-num { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }
.why-step code {
  background: var(--surface-2); padding: 1px 6px; border-radius: 4px;
  font-size: 12.5px; white-space: nowrap;
}

/* ── Пояснение к плашкам рекламы ────────────────────────────────────────────
   Показатели рекламы WB непривычные: платят за показы, деньги в сомах, часть
   расхода бонусами. Дмитрий 14.09.2026 сказал прямо: «не все данные понимаю
   на плашках». Поэтому под ними идёт разбор словами — не подсказкой при
   наведении, которую надо искать, а текстом, который видно сразу. */

.ads-legend {
  margin-top: 12px; padding: 12px 14px;
  border: 1px solid var(--line); border-radius: var(--r-md, 10px);
  background: var(--surface-2);
  font-size: 12.5px; line-height: 1.55; color: var(--muted);
  display: flex; flex-direction: column; gap: 5px;
}
.ads-legend > b { color: var(--fg); font-size: 13px; margin-bottom: 2px; }
.ads-legend b { color: var(--fg); }
.ads-legend i { font-style: normal; text-decoration: underline; text-underline-offset: 2px; }

/* Пометка «цифра посчитана оценкой»: тот же значок, но другого цвета и знаком
   ≈ вместо «!». Восклицательный знак читается как ошибка, а здесь не ошибка —
   здесь честная прикидка там, где кабинет не дал точной цифры. */
.tr-warn.is-est { color: var(--warn, #cc9a2e); border-color: currentColor; }

/* Подпись «откуда взялась цифра» есть у каждой строки — значит она должна
   быть незаметной, пока её не ищут. Оговорка и оценка остаются жёлтыми:
   к ним внимание нужно. */
.tr-warn.is-info {
  background: var(--bg-soft, rgba(127, 127, 127, .12));
  color: var(--muted, #8a8f98);
  font-weight: 600;
}
.tr-name:hover .tr-warn.is-info { color: var(--text, inherit); }

/* ── Поисковые запросы рекламы WB ───────────────────────────────────────────
   Уровень, на котором правят ставки. Строка раскрывается: под ней история,
   которую система пишет сама, и заметки человека. */

.wq-table tbody tr.wq-row { cursor: pointer; }
.wq-table tbody tr.wq-row:hover { background: var(--surface-2); }

/* Исключённая фраза не удалена — она справка, и должна быть тише остальных */
.wq-row.is-off { opacity: .55; }
/* Тратит и не приносит — красная полоса слева, видно не вглядываясь */
.wq-row.is-waste td:first-child { box-shadow: inset 3px 0 0 #c0503f; }

.wq-has-note { margin-left: 6px; color: var(--accent); font-size: 12px; }

.wq-detail > td { background: var(--surface-2); padding: 12px 14px; }
.wq-panes { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; }
@media (max-width: 900px) { .wq-panes { grid-template-columns: 1fr; } }
.wq-pane h4.micro { margin: 0 0 8px; }

.wq-ev {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 0; font-size: 12.5px;
  border-bottom: 1px solid var(--line);
}
.wq-ev:last-child { border-bottom: 0; }

.wq-note-add { display: flex; gap: 6px; margin-bottom: 8px; }
.wq-note-add input { flex: 1; min-width: 0; }

.wq-note {
  display: flex; align-items: baseline; gap: 8px;
  padding: 5px 0; font-size: 12.5px;
  border-bottom: 1px solid var(--line);
}
.wq-note:last-child { border-bottom: 0; }

/* Последнее изменение по фразе — под её названием, чтобы свежая правка была
   видна без раскрытия. Остальная история прячется за призывом нажать. */
.wq-last { font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.wq-more { color: var(--accent); margin-left: 4px; }
.wq-row:hover .wq-more { text-decoration: underline; }

/* Раскрытие кампании: значок ▸/▾ у названия */
.ads-camp-row { cursor: pointer; }
.ads-camp-row:hover { background: var(--surface-2); }
.camp-open { color: var(--muted); font-size: 11px; margin-left: 4px; }
.ads-camp-queries > td { background: var(--surface-2); padding: 14px 16px; }

/* Пояснение к меткам фраз: показываем прямо под таблицей, а не подсказкой при
   наведении. Красная полоса без объяснения читается как «что-то сломалось». */
.wq-legend {
  margin-top: 12px; padding: 11px 13px;
  border: 1px solid var(--line); border-radius: var(--r-md, 10px);
  background: var(--card);
  font-size: 12px; line-height: 1.5; color: var(--muted);
  display: flex; flex-direction: column; gap: 5px;
}
.wq-legend > b { color: var(--fg); font-size: 12.5px; margin-bottom: 2px; }
.wq-legend b { color: var(--fg); }
.wq-mark {
  display: inline-block; width: 3px; height: 12px;
  margin-right: 7px; vertical-align: -1px; border-radius: 2px;
}
.wq-mark-waste { background: #c0503f; }

/* Что было перед правкой ставки: цифры, по которым принимали решение.
   Отдельной строкой под событием и тише его — это контекст, а не само событие. */
.wq-ev { flex-direction: column; align-items: flex-start; gap: 2px; }
.wq-ev-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.wq-ev-before { font-size: 11.5px; color: var(--muted); padding-left: 2px; }
.wq-ev-before b { color: var(--fg); font-weight: 600; }

/* ── Соинвест по часам ──────────────────────────────────────────────────────
   Тепловая карта скидки, которую Ozon даёт из своего кармана. Цвет здесь — от
   абсолютной величины, а не от отличия к своей норме: 50% соинвеста это повод
   поднять цену независимо от того, было ли так вчера. Поэтому своя шкала, а не
   общая с картой дней.

   Оттенок один, меняется густота: карта должна читаться как рельеф, а не как
   светофор — плохих и хороших значений тут нет, есть большие и малые. */

.co-map .tr-cell { font-family: var(--font-mono); text-align: center; }

.co-0 { color: var(--faint); }
.co-1 { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.co-2 { background: color-mix(in srgb, var(--accent) 20%, transparent); }
.co-3 { background: color-mix(in srgb, var(--accent) 34%, transparent); color: var(--text); }
.co-4 { background: color-mix(in srgb, var(--accent) 50%, transparent); color: var(--text); }
.co-5 { background: color-mix(in srgb, var(--accent) 68%, transparent); color: var(--text);
  font-weight: 600; }

/* День, внутри которого соинвест гулял больше чем на 8 пунктов: среднее по
   такому дню обманчиво, и его стоит раскрыть. Рамка, а не цвет — цвет уже
   занят величиной. */
.co-jumpy { box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--warn) 70%, transparent); }

/* Строка товара кликабельна целиком, кроме самих клеток: по ним читают цифру
   и наводят подсказку, а не сворачивают строку. */
.co-row { cursor: pointer; }
.co-row:hover .tr-name { color: var(--text); }
.co-row.is-open .tr-name { font-weight: 600; }
.co-caret { display: inline-block; width: 14px; color: var(--muted); font-size: 10px; }

.co-detail > td { padding: 0 0 14px; }
.co-hours { padding: 10px 12px 12px; border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--muted) 7%, transparent); }
.co-hours-table { border-collapse: separate; border-spacing: 2px; font-size: 11px;
  table-layout: fixed; width: max-content; }
.co-hours-table th { font-weight: 500; color: var(--muted); font-size: 10px;
  font-family: var(--font-mono); text-align: center; padding: 0 0 3px; width: 30px; }
.co-hours-table td.tr-cell { width: 30px; height: 22px; border-radius: 3px; }
.co-hours-table .co-day { color: var(--muted); font-size: 11px; white-space: nowrap;
  padding-right: 8px; text-align: right; width: auto; }

/* Ночные часы: сборщик там ходит реже, и пустая клетка значит «не смотрели»,
   а не «соинвеста не было». Приглушаем, чтобы взгляд не искал в них смысл. */
.co-night { opacity: .55; }

/* Замер, где витрина оказалась дороже кабинета: две цены сняты в разные
   моменты. Не ошибка расчёта и не находка — просто данные разъехались.
   Показываем штриховкой: видно, что клетка есть, но в среднее не идёт. */
.co-suspect {
  background: repeating-linear-gradient(45deg,
    transparent, transparent 3px,
    color-mix(in srgb, var(--muted) 18%, transparent) 3px,
    color-mix(in srgb, var(--muted) 18%, transparent) 6px);
  color: var(--faint);
}
