/* SellProf styles.css — дизайн-система поверх Tailwind CDN.
   Токены — CSS-переменные (:root свет / html.dark тьма), компоненты ссылаются
   на них и переключают тему сами, без дублирующих dark:-правил. Tailwind
   darkMode:'class' (tailwind-config.js): существующие dark:-утилиты работают
   по .dark на <html> (ставит theme-init.js). Сборочного шага нет — здесь
   обычный CSS (никакого @apply). */

/* ── Шрифты (self-hosted, /static/fonts) ─────────────────────────────────────
   Inter — переменный woff2, сабсеты по unicode-range (лат + кириллица), тело/UI/
   таблицы. Manrope — переменный ttf, дисплейная гарнитура (крупные числа KPI,
   заголовки). Обе — OFL (см. fonts/OFL-*.txt). font-display:swap — без блокировки. */
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url('/static/fonts/inter-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url('/static/fonts/inter-cyrillic-ext.woff2') format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url('/static/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url('/static/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Manrope'; font-style: normal; font-weight: 200 800; font-display: swap;
  src: url('/static/fonts/Manrope-var.ttf') format('truetype');
}

/* ── Токены темы ─────────────────────────────────────────────────────────── */
:root {
  --sp-bg: #f4f6f9;            /* фон приложения — прохладный светлый */
  --sp-surface: #ffffff;       /* карточки/панели */
  --sp-surface-2: #f1f4f8;     /* вставки, чипы, чётные строки */
  --sp-surface-3: #e7ecf3;     /* hover-вставки */
  --sp-border: #e5e9f0;        /* волосяная граница */
  --sp-border-strong: #d3dae4;
  --sp-ink: #161a22;           /* основной текст */
  --sp-ink-2: #545c6b;         /* вторичный */
  --sp-ink-3: #8b93a3;         /* приглушённый */

  --sp-brand: #6366f1;
  --sp-brand-strong: #4f46e5;
  --sp-brand-hover: #4338ca;
  --sp-brand-ink: #4f46e5;     /* бренд как текст на светлом */
  --sp-brand-tint: #eef1ff;    /* мягкая бренд-подложка */
  --sp-param-bg: #e7f0ec;      /* пилюли-параметры (размер/рост): шалфейно-мятный */
  --sp-param-ink: #3d6b58;     /* текст параметров: 5.5:1 на подложке */
  --sp-accent: #0d9488;        /* бирюза как текст/акцент на светлом */
  --sp-accent-mark: #14b8a6;   /* бирюза для графики */

  --sp-profit: #059669; --sp-profit-bg: #ecfdf5; --sp-profit-border: #a7f3d0;
  --sp-loss: #e11d48;   --sp-loss-bg: #fff1f2;   --sp-loss-border: #fecdd3;
  /* Пастель динамики (дельты/стрелки в таблицах): семантический цвет,
     разбавленный чернилами — тише основных сумм, смысл тот же (запрос
     владельца 2026-09-09). Считается от --sp-profit/loss → в тьме
     адаптируется сама. */
  --sp-delta-up: color-mix(in srgb, var(--sp-profit) 75%, var(--sp-ink-3));
  --sp-delta-down: color-mix(in srgb, var(--sp-loss) 70%, var(--sp-ink-3));
  /* Hover строки таблицы — едва заметный: ~3.5% чернил (≈ #f7f8fa на
     белом, спектр #F4F7F6/#F8FAFC): строка выделяется, текст читается
     без напряжения (запрос владельца 2026-09-09). */
  --sp-row-hover: rgba(22,26,34,0.035);
  /* Solid-эквивалент --sp-row-hover для sticky-колонок (ОПиУ-шторка):
     translucent-подсветка на sticky «Месяце» просвечивает дни под ним. */
  --sp-row-hover-mix: 3.5%;
  --sp-warn: #b45309;   --sp-warn-bg: #fffbeb;   --sp-warn-border: #fde68a;
  --sp-info: #0369a1;   --sp-info-bg: #eff6ff;   --sp-info-border: #bfdbfe;

  --sp-ring: rgba(99,102,241,0.45);
  --sp-shadow-1: 0 1px 3px rgba(16,24,40,0.05), 0 8px 22px -10px rgba(16,24,40,0.10);
  --sp-shadow-menu: 0 8px 30px -6px rgba(16,24,40,0.18), 0 2px 8px -3px rgba(16,24,40,0.10);

  /* графика (uPlot/SVG) */
  --sp-grid: #eceff4; --sp-axis: #8b93a3; --sp-tick: #545c6b;
  --sp-tooltip-bg: #1c2230; --sp-tooltip-ink: #eef1f6;
  --sp-track: #e7ecf3; --sp-thumb: #cbd3df;
}
/* Ночь 2026-09-14 — перекомпоновка по DeepSeek Harness (решение владельца:
   прежний фон #0a0c11 был «слишком чёрным»). Взята тональная композиция DSH:
   почти нейтральные серые (синий ±1–2 канала, не «синий в синем»), равномерные
   ступени возвышения bg → surface → surface-2 → surface-3, волосяные границы —
   белая альфа вместо серых линий, текст до почти-белого. Фирменное индиго и
   семантика profit/loss/warn/info — родные, не переезжают. */
html.dark {
  --sp-bg: #151517;            /* холст — тон DSH bg-base */
  --sp-surface: #232324;       /* карточки/панели — ступень DSH layer-1 */
  --sp-surface-2: #2c2c2e;     /* вставки, чипы, чётные строки — layer-2 */
  --sp-surface-3: #353638;     /* hover-вставки — layer-3 */
  --sp-border: rgba(255,255,255,0.08);        /* DSH: белая альфа вместо серых линий */
  --sp-border-strong: rgba(255,255,255,0.16);
  --sp-ink: #f9fafb;           /* почти белый */
  --sp-ink-2: #cfd3d6;         /* вторичный */
  --sp-ink-3: #90939a;         /* приглушённый; ≥4.5:1 на surface-2 */

  --sp-brand: #818cf8;
  --sp-brand-strong: #6366f1;
  --sp-brand-hover: #4f46e5;
  --sp-brand-ink: #a5b4fc;
  --sp-brand-tint: rgba(99,102,241,0.14);
  --sp-param-bg: rgba(148,180,158,0.12); /* пилюли-параметры: шалфей */
  --sp-param-ink: #9fc4af;
  --sp-accent: #2dd4bf;
  --sp-accent-mark: #2dd4bf;

  --sp-profit: #34d399; --sp-profit-bg: rgba(16,185,129,0.12); --sp-profit-border: rgba(16,185,129,0.30);
  --sp-loss: #fb7185;   --sp-loss-bg: rgba(244,63,94,0.13);   --sp-loss-border: rgba(244,63,94,0.32);
  --sp-row-hover: rgba(255,255,255,0.06);
  /* Белая альфа — приём DSH (их interactive-hover 8%); у нас 6%: на плотных
     таблицах даёт ровно следующую ступень элевации (surface-3), не «кричит». */
  --sp-row-hover-mix: 6%;
  --sp-warn: #fbbf24;   --sp-warn-bg: rgba(245,158,11,0.12);  --sp-warn-border: rgba(245,158,11,0.30);
  --sp-info: #7dd3fc;   --sp-info-bg: rgba(56,189,248,0.12);  --sp-info-border: rgba(56,189,248,0.30);

  --sp-ring: rgba(129,140,248,0.55);
  --sp-shadow-1: 0 1px 2px rgba(0,0,0,0.28), 0 10px 28px -12px rgba(0,0,0,0.45);
  --sp-shadow-menu: 0 10px 34px -6px rgba(0,0,0,0.5), 0 2px 8px -3px rgba(0,0,0,0.35);

  --sp-grid: #2d2d30; --sp-axis: #7e8187; --sp-tick: #a8abb1;
  --sp-tooltip-bg: #43454a; --sp-tooltip-ink: #f9fafb;
  /* Тултип в тьме — серая элевация DSH (их tooltip-bg), не инверсия:
     та же логика «слой выше — светлее», что и у поверхностей. */
  --sp-track: #2c2c2e; --sp-thumb: #45464a;
}

/* ── База ────────────────────────────────────────────────────────────────── */
body {
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;
  background: var(--sp-bg); color: var(--sp-ink);
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  /* clip (не hidden): не роняет position:sticky, но гасит горизонтальный
     выступ full-bleed-панели Финотчёта (100vw включает ширину скроллбара). */
  overflow-x: clip;
}
::selection { background: rgba(99,102,241,0.22); }
a:focus-visible, button:focus-visible, select:focus-visible, input:focus-visible,
textarea:focus-visible, [tabindex]:focus-visible, .sp-btn:focus-visible, .sp-icon-btn:focus-visible {
  outline: 2px solid var(--sp-ring); outline-offset: 2px; border-radius: 8px;
}
/* Скроллбар в тон теме (webkit + firefox) */
* { scrollbar-color: var(--sp-thumb) transparent; }
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-thumb { background: var(--sp-thumb); border-radius: 9999px; border: 3px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: var(--sp-border-strong); background-clip: content-box; }
::-webkit-scrollbar-track { background: transparent; }

/* ── HTMX индикаторы ─────────────────────────────────────────────────────── */
.htmx-indicator { opacity: 0; transition: opacity 200ms; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }

/* ── Числа: табличные цифры Inter (финансы не «пляшут»; премиальнее моно) ─── */
.tnum { font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1, 'ss01' 1; }

/* ── Карточки / панели ───────────────────────────────────────────────────── */
.sp-card {
  background: var(--sp-surface); border: 1px solid var(--sp-border);
  border-radius: 14px; box-shadow: var(--sp-shadow-1);
}
.sp-panel { background: var(--sp-surface); border: 1px solid var(--sp-border); border-radius: 14px; }
.sp-inset { background: var(--sp-surface-2); border: 1px solid var(--sp-border); border-radius: 12px; }
/* Кликабельная КАРТОЧКА-ссылка (целый бокс: хелп, плитки навигации,
   карточки отчётов): лёгкий подъём + бренд-граница. На СТРОКАХ внутри
   карточки-списка запрещён — рамка/тень рисуются прямоугольником внутри
   .sp-card, а translateY сдвигает соседние строки; строкам — .sp-row-link. */
.sp-card-link { transition: border-color .16s, box-shadow .16s, transform .16s; }
.sp-card-link:hover {
  border-color: var(--sp-brand); transform: translateY(-1px);
  box-shadow: 0 4px 14px -3px rgba(99,102,241,0.28), var(--sp-shadow-1);
}
/* Строка-ссылка внутри карточки-списка (виджет внимания дашборда, модалка
   «Показать все», центр уведомлений): канонический ховер строки таблицы
   (--sp-row-hover, решение владельца 2026-09-09) + тональная кромка слева
   в цвет сигнала — тот же язык, что state-кромка KPI-плиток (.sp-stat::before).
   Наведение отвечает на два вопроса сразу: «строка кликабельна» и «какой
   это сигнал» — без подъёма, теней и сдвига соседей (0 layout shift). */
.sp-row-link {
  cursor: pointer; /* класс вешается только на интерактивные строки */
  transition: background-color .16s ease, box-shadow .16s ease;
  --sp-edge: var(--sp-warn);
}
.sp-row-link:hover {
  background: var(--sp-row-hover);
  box-shadow: inset 2px 0 0 var(--sp-edge);
}
.sp-row-link[data-tone="loss"]    { --sp-edge: var(--sp-loss); }
.sp-row-link[data-tone="info"]    { --sp-edge: var(--sp-info); }
.sp-row-link[data-tone="profit"]  { --sp-edge: var(--sp-profit); }
.sp-row-link[data-tone="brand"]   { --sp-edge: var(--sp-brand); }
.sp-row-link[data-tone="neutral"] { --sp-edge: var(--sp-border-strong); }
/* Тихое действие строки («Скрыть») проявляется на ховере строки:
   обнаружимость без постоянного шума (resting = прежний ink-3). */
.sp-row-act { color: var(--sp-ink-3); transition: color .16s; }
.sp-row-link:hover .sp-row-act { color: var(--sp-ink); }
.sp-divider { height: 1px; background: var(--sp-border); border: 0; }

/* ── KPI-плитка (сигнатурный элемент: подсветка критических изменений) ────── */
/* Без overflow:hidden: чип магнита спарклайна («день · значение») выходит
   за границу плитки и не должен обрезаться рамкой (ревью владельца
   2026-09-27); угол state-полосы (::before) скруглён взамен обрезки. */
.sp-stat {
  position: relative;
  background: var(--sp-surface); border: 1px solid var(--sp-border);
  border-radius: 14px; padding: 14px 16px; box-shadow: var(--sp-shadow-1);
}
.sp-stat-label { font-size: 12px; font-weight: 500; color: var(--sp-ink-3); display: flex; align-items: center; gap: 6px; }
.sp-stat-value {
  font-family: 'Manrope', 'Inter', system-ui, sans-serif;
  font-weight: 700; font-size: 1.6rem; line-height: 1.15; letter-spacing: -0.015em;
  color: var(--sp-ink); font-variant-numeric: tabular-nums; margin-top: 3px;
}
.sp-stat-foot { margin-top: 6px; min-height: 22px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.sp-stat-reason { font-size: 11.5px; line-height: 1.35; color: var(--sp-ink-2); margin-top: 7px; }
/* Состояния: цветная кромка слева + подложка + смысловой цвет причины */
.sp-stat::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  border-radius: 13px 0 0 13px; /* повторяет радиус плитки (14 − 1px рамки) */
  background: transparent; transition: background .2s;
}
/* Neutral-состояние (волна «фейковых нулей» P1-4/P1-5): «нет данных» и
   «нет мнения» — спокойный серый, не зелёный (пустой Status ≠ good). */
.sp-stat[data-state="neutral"] { background: var(--sp-surface-2); border-color: var(--sp-border); }
.sp-stat[data-state="neutral"]::before { background: var(--sp-border-strong); }
.sp-stat[data-state="good"]::before { background: var(--sp-profit); }
.sp-stat[data-state="warn"] { background: var(--sp-warn-bg); border-color: var(--sp-warn-border); }
.sp-stat[data-state="warn"]::before { background: var(--sp-warn); }
.sp-stat[data-state="warn"] .sp-stat-reason { color: var(--sp-warn); }
.sp-stat[data-state="critical"] { background: var(--sp-loss-bg); border-color: var(--sp-loss-border); }
.sp-stat[data-state="critical"]::before { background: var(--sp-loss); }
.sp-stat[data-state="critical"] .sp-stat-reason { color: var(--sp-loss); font-weight: 500; }
.sp-stat[data-state="critical"] .sp-stat-flag { animation: sp-breathe 2.4s ease-in-out infinite; }

/* ── KPI-радар дашборда (план 2026-09-26-dashboard-kpi-radar.md):
     герои шире, спарклайн-фон, дельта в подвале, клик-плитки ── */
/* Шапка плитки — size-контейнер: по её ширине бейдж «предварительно»
   решает, помещается ли текст (см. @container у .sp-stat-tag). Контейнер —
   именно шапка, НЕ плитка: contain:layout делал бы плитку stacking
   context, и чип магнита прятался бы под соседнюю плитку. */
.sp-stat-head { container-type: inline-size; display: flex; align-items: center; gap: 6px; min-width: 0; }
.sp-stat-ico { display: inline-flex; width: 15px; height: 15px; flex: none; color: var(--sp-ink-3); }
.sp-stat-ico svg { width: 100%; height: 100%; }
.sp-stat-hero .sp-stat-ico { color: var(--sp-brand); }
.sp-stat-hero .sp-stat-label { color: var(--sp-ink-2); }
.sp-stat-hero .sp-stat-value { font-size: 1.9rem; }
.sp-stat-spark {
  position: absolute; right: 14px; bottom: 12px; width: 44%; max-width: 150px;
  color: var(--sp-brand); pointer-events: auto; z-index: 0;
}
/* Приглушение тренда — на SVG, не на боксе: точка/чип магнита (решение
   владельца 2026-09-26) поверх тренда идут в полную силу.
   pointer-events:auto — магнит ловит hover; контент плитки (z-index:1)
   перехватывает указатель там, где лежит текст.
   Бренд на ВСЕХ плитках (решение владельца 2026-09-27): канал «сейчас» —
   цветная линия, «было» — серый пунктир (sp-spark-ghost), без вариантов
   серый-на-серый у узких плиток. */
.sp-stat-spark > svg { opacity: .5; }
.sp-stat-hero .sp-stat-spark > svg { opacity: .55; }
/* Призрак прошлого окна: фикс-серый НЕ от currentColor (иначе у узких
   плиток обе линии серые), плотность ~0.4 итоговая (.8 внутри svg .5) —
   был 0.35×0.5≈0.17, «практически не видна» (ревью владельца). */
.sp-spark-ghost { stroke: var(--sp-ink-3); opacity: .8; }
/* Спарк — ФОН: positioned-элемент рисуется выше потока, поднимаем
   контент плитки явно (head/value/foot) */
.sp-stat-head, .sp-stat-value, .sp-stat-foot { position: relative; z-index: 1; }
/* Активный магнит поднимается над контентом плитки — чип читается */
.sp-stat-spark:hover { z-index: 2; }
/* Точка магнита: DOM-оверлей (SVG-круг при preserveAspectRatio=none
   сплющился бы); display в классе нет — скрытие через атрибут [hidden] */
.sp-spark-pt {
  position: absolute; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; transform: translate(-50%, -50%);
  box-shadow: 0 0 0 1.5px var(--sp-surface); pointer-events: none;
}
/* Чип магнита «день · значение» + вторая строка «прошлый день ·
   значение» (серым, мельче — объясняет серый пунктир спарка).
   Строки — div без author-display: скрытие через [hidden] работает.
   transform чипа — из JS (центр / прижатие к краям плитки).
   z-index 5 — чип читается ПОВЕРХ соседних ячеек таблиц: чип вылетает
   за границы td спарка (центрирован на точке), а positioned-ячейки
   каркаса (#pnl-table thead th z2, замороженный угол z3) иначе рисуются
   поверх него — замер 2026-09-28 (замечание владельца). */
.sp-spark-chip {
  position: absolute; bottom: calc(100% + 6px); left: 50%; z-index: 5;
  white-space: nowrap; font-size: 11px; line-height: 1.3;
  padding: 3px 7px; border-radius: 6px; pointer-events: none;
  background: var(--sp-surface); border: 1px solid var(--sp-border);
  color: var(--sp-ink); box-shadow: var(--sp-shadow-1);
  font-variant-numeric: tabular-nums;
}
.sp-spark-chip-prev { font-size: 10px; color: var(--sp-ink-3); margin-top: 1px; }
/* Δ-строка чипа (универсальный магнит, charts.js): цвет ТОЛЬКО по знаку —
   канон Δ-цветов (fin-delta). Ведёт таблица ОПиУ и шторка дней. */
.sp-spark-chip-up { font-size: 10px; margin-top: 1px; color: var(--sp-delta-up); }
.sp-spark-chip-down { font-size: 10px; margin-top: 1px; color: var(--sp-delta-down); }
/* Клик-плитка: рецепт ховера .sp-card-link (:176), без новых теней.
   z-index обязателен: transform ховера создаёт stacking context, и без
   подъёма чип магнита лёг бы ПОД соседнюю плитку справа (порядок DOM). */
.sp-stat-link { cursor: pointer; }
.sp-stat-link:hover, .sp-stat-link:focus-visible {
  border-color: var(--sp-brand); transform: translateY(-1px); z-index: 3;
  box-shadow: 0 4px 14px -3px rgba(99,102,241,0.28), var(--sp-shadow-1);
}
/* «Предварительно»: тихий контурный чип вместо тоновой плашки.
   Если в шапке плитки тексту тесно (контейнер < 220px — тексту нужно
   215px: лейбл 105 + зазор 6 + чип 104, замер 2026-09-27), чип
   сворачивается в иконку ⓘ — В СТРОКЕ лейбла у правого края; адрес,
   тултип и aria-label — прежние. Когда не влезает и ⓘ (лейбл 105 +
   6 + 18 = 129px — узкая плитка на 1280), иконка уходит под строку
   лейбла, к правому краю строки значения. */
.sp-stat-tag {
  display: inline-flex; align-items: center; font-size: 10.5px; font-weight: 600;
  color: var(--sp-ink-3); border: 1px solid var(--sp-border); background: transparent;
  padding: 1px 7px; border-radius: 9999px; white-space: nowrap; text-decoration: none;
}
.sp-stat-tag:hover { border-color: var(--sp-brand); color: var(--sp-brand-ink); }
.sp-stat-tag-ico { display: none; width: 14px; height: 14px; }
@container (max-width: 219px) {
  .sp-stat-tag-text { display: none; }
  .sp-stat-tag-ico { display: inline-flex; }
  .sp-stat-tag { background: transparent; border: 0; padding: 0; border-radius: 0; }
}
@container (max-width: 133px) {
  .sp-stat-tag { position: absolute; top: calc(100% + 5px); right: -14px; }
}
/* Подсветка карточки графика после клика по плитке */
.sp-chart-flash { animation: sp-chart-flash 1.6s ease-out 1; }
@keyframes sp-chart-flash {
  0% { border-color: var(--sp-brand); box-shadow: 0 0 0 3px var(--sp-ring), var(--sp-shadow-1); }
}
@media (prefers-reduced-motion: reduce) {
  .sp-chart-flash { animation: none; }
}

/* ── Дельта-пилюля (рост/падение) ────────────────────────────────────────── */
.sp-delta {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums;
  padding: 1px 7px 1px 5px; border-radius: 9999px; line-height: 1.5;
}
.sp-delta::before { font-size: 10px; }
.sp-delta[data-dir="up"]   { color: var(--sp-profit); background: var(--sp-profit-bg); }
.sp-delta[data-dir="up"]::before   { content: '▲'; }
.sp-delta[data-dir="down"] { color: var(--sp-loss);   background: var(--sp-loss-bg); }
.sp-delta[data-dir="down"]::before { content: '▼'; }
.sp-delta[data-dir="flat"] { color: var(--sp-ink-3);  background: var(--sp-surface-2); }
.sp-delta[data-dir="flat"]::before { content: '→'; }
/* tone переопределяет цвет (напр. рост возвратов — это плохо) */
.sp-delta[data-tone="loss"]   { color: var(--sp-loss);   background: var(--sp-loss-bg); }
.sp-delta[data-tone="profit"] { color: var(--sp-profit); background: var(--sp-profit-bg); }
.sp-delta[data-tone="muted"]  { color: var(--sp-ink-3);  background: var(--sp-surface-2); }

/* ── Бейджи (статусы, %-метки в таблицах) ────────────────────────────────── */
.sp-badge {
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
  font-size: 11.5px; font-weight: 600; line-height: 1.5;
  padding: 2px 9px; border-radius: 9999px; border: 1px solid transparent;
}
.sp-badge[data-tone="neutral"] { color: var(--sp-ink-2); background: var(--sp-surface-2); border-color: var(--sp-border); }
.sp-badge[data-tone="brand"]   { color: var(--sp-brand-ink); background: var(--sp-brand-tint); border-color: transparent; }
.sp-badge[data-tone="profit"]  { color: var(--sp-profit); background: var(--sp-profit-bg); border-color: var(--sp-profit-border); }
.sp-badge[data-tone="loss"]    { color: var(--sp-loss); background: var(--sp-loss-bg); border-color: var(--sp-loss-border); }
.sp-badge[data-tone="warn"]    { color: var(--sp-warn); background: var(--sp-warn-bg); border-color: var(--sp-warn-border); }
.sp-badge[data-tone="info"]    { color: var(--sp-info); background: var(--sp-info-bg); border-color: var(--sp-info-border); }

/* ── Кнопки ──────────────────────────────────────────────────────────────── */
.sp-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  font-weight: 600; font-size: 0.875rem; line-height: 1.2; white-space: nowrap;
  padding: 0.55rem 0.95rem; border-radius: 10px; border: 1px solid transparent;
  cursor: pointer; transition: background .15s, border-color .15s, color .15s, box-shadow .15s, transform .05s;
  -webkit-user-select: none; user-select: none;
}
.sp-btn:active { transform: translateY(0.5px); }
.sp-btn[disabled], .sp-btn:disabled { opacity: 0.55; cursor: not-allowed; }
.sp-btn-sm { padding: 0.35rem 0.7rem; font-size: 0.8125rem; border-radius: 9px; }
.sp-btn-primary { background: var(--sp-brand-strong); color: #fff; box-shadow: 0 1px 2px rgba(79,70,229,0.35); }
.sp-btn-primary:hover { background: var(--sp-brand-hover); }
.sp-btn-secondary { background: var(--sp-surface); color: var(--sp-ink); border-color: var(--sp-border-strong); }
.sp-btn-secondary:hover { background: var(--sp-surface-2); border-color: var(--sp-brand); color: var(--sp-brand-ink); }
.sp-btn-ghost { background: transparent; color: var(--sp-ink-2); }
.sp-btn-ghost:hover { background: var(--sp-surface-2); color: var(--sp-ink); }
.sp-btn-danger { background: transparent; color: var(--sp-loss); border-color: var(--sp-loss-border); }
.sp-btn-danger:hover { background: var(--sp-loss-bg); }
/* sp-btn-loss — сплошная критическая кнопка (действие диалога подтверждения
   на удаление/перезапись). Текст инвертируется по теме: белый на #e11d48 в
   свету (4.6:1), тёмный на светло-розовом #fb7185 в темноте (7:1). */
.sp-btn-loss { background: var(--sp-loss); color: #fff; box-shadow: 0 1px 2px rgba(225,29,72,0.35); }
.sp-btn-loss:hover { filter: brightness(0.94); }
html.dark .sp-btn-loss { color: #17171a; }
html.dark .sp-btn-loss:hover { filter: brightness(1.05); }

/* Иконочная кнопка (действия в шапке) */
.sp-icon-btn {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 10px; border: 1px solid transparent;
  color: var(--sp-ink-2); background: transparent; cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.sp-icon-btn:hover { background: var(--sp-surface-2); color: var(--sp-ink); border-color: var(--sp-border); }
.sp-icon-btn svg { width: 19px; height: 19px; }
/* Точка-индикатор непрочитанного (уведомления) */
.sp-icon-btn[data-dot="1"]::after {
  content: ''; position: absolute; top: 8px; right: 9px; width: 7px; height: 7px;
  border-radius: 50%; background: var(--sp-loss); border: 2px solid var(--sp-surface);
}
/* В шапке иконки-кнопки компактнее (сжатый хедер), вне шапки — базовые 38px */
.sp-header .sp-icon-btn { width: 34px; height: 34px; }
.sp-header .sp-icon-btn svg { width: 17px; height: 17px; }
.sp-header .sp-icon-btn[data-dot="1"]::after { top: 6px; right: 8px; }
/* Компактный вариант внутри панелей/поповеров (шапка центра уведомлений):
   базовые 38px в меню слишком крупны. Двойной класс — перебить
   .sp-header .sp-icon-btn (панель живёт внутри шапки), порядок в файле
   решает при равной специфичности. */
.sp-icon-btn.sp-icon-btn-sm { width: 30px; height: 30px; border-radius: 9px; }
.sp-icon-btn.sp-icon-btn-sm svg { width: 16px; height: 16px; }

/* ── Сегмент-контрол / плотность / мини-табы ─────────────────────────────── */
.sp-seg { display: inline-flex; gap: 2px; padding: 3px; border-radius: 11px;
  background: var(--sp-surface-2); border: 1px solid var(--sp-border); }
.sp-seg > button, .sp-seg > a {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  padding: 0.35rem 0.72rem; border-radius: 8px; font-size: 0.8125rem; font-weight: 500;
  color: var(--sp-ink-2); background: transparent; border: 0; transition: background .15s, color .15s;
}
.sp-seg > button:hover, .sp-seg > a:hover { color: var(--sp-ink); }
.sp-seg > .is-active, .sp-seg > [aria-selected="true"], .sp-seg > [aria-pressed="true"] {
  background: var(--sp-surface); color: var(--sp-ink); box-shadow: 0 1px 2px rgba(16,24,40,0.10);
}

/* ── Общий пикер периода (34-dates §4/§5, волна G1) ───────────────────────
   Разметка — define period_picker (layout.html), поведение — sp-period.js.
   Пресеты — sp-seg выше, даты — sp-input; здесь только состояние ошибки
   инверсии (у поля, §5 4.1) — цвета несут --sp-* токены. */
.sp-input.is-invalid { border-color: var(--sp-loss); }
.sp-period-error { white-space: nowrap; }

/* ── Чипы (пресеты фильтров, теги) ───────────────────────────────────────── */
.sp-chip {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  padding: 0.3rem 0.7rem; border-radius: 9999px; font-size: 0.8125rem; font-weight: 500;
  color: var(--sp-ink-2); background: var(--sp-surface); border: 1px solid var(--sp-border);
  transition: border-color .15s, color .15s, background .15s;
}
.sp-chip:hover { border-color: var(--sp-brand); color: var(--sp-brand-ink); }
.sp-chip[data-active="1"], .sp-chip.is-active {
  color: var(--sp-brand-ink); background: var(--sp-brand-tint); border-color: transparent;
}
/* Пресеты Мониторинга (бриф владельца 2026-09-26): чипы в ЕДИНОМ
   нейтральном стиле — цветовой смысл несёт маленькая точка-индикатор
   перед счётчиком (красная = нужно вмешательство, янтарная = проверь;
   data-hot ставит серверный рендер пресет-чипов rnp.html). Хаос цветных плашек
   разной длины разгружает верх экрана. */
.sp-chip[data-hot="loss"], .sp-chip[data-hot="warn"] { color: var(--sp-ink-2); border-color: var(--sp-border); }
.sp-chip[data-hot]::before {
  content: ""; width: 6px; height: 6px; border-radius: 9999px;
  background: var(--sp-loss); flex: none;
}
.sp-chip[data-hot="warn"]::before { background: var(--sp-warn); }
/* Неактивные пресеты — текст без плашки (бриф владельца 2026-09-26 №2):
   подложка и рамка — только у активного чипа; так «Все» не спорит с
   остальными, а фокус ведёт активный фильтр. */
#rnp-presets .sp-chip:not(.is-active) { background: transparent; border-color: transparent; }
#rnp-presets .sp-chip:not(.is-active):hover { background: var(--sp-surface-2); color: var(--sp-ink); }
.sp-chip-add { border-style: dashed; color: var(--sp-ink-3); }

/* ── Поля ввода / селекты ────────────────────────────────────────────────── */
.sp-input, .sp-select {
  font-size: 0.875rem; color: var(--sp-ink); line-height: 1.4;
  background: var(--sp-surface); border: 1px solid var(--sp-border-strong);
  border-radius: 10px; padding: 0.5rem 0.7rem; transition: border-color .15s, box-shadow .15s;
}
.sp-input::placeholder { color: var(--sp-ink-3); }
.sp-input:focus, .sp-select:focus { outline: none; border-color: var(--sp-brand); box-shadow: 0 0 0 3px var(--sp-ring); }

/* ⚠ ИНВАРИАНТ (решение владельца 2026-09-05): НИ ОДНО числовое поле ввода
   в проекте не имеет нативных стрелок-спиннеров — они мешают и ломают вид.
   Правило глобальное: любые новые input[type="number"] подхватываются сами,
   заводить поля со спиннерами нельзя (клавиатурные ↑/↓ продолжают работать).
   См. AGENTS.md «Кодстайл» и рецепт input в DESIGN.md. */
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* Компактный ввод внутри ячеек таблиц (inline-edit): меньше паддинг/радиус. */
.sp-input-sm { padding: 0.25rem 0.5rem; font-size: 0.8125rem; border-radius: 8px; }

/* Тихий фидбек сохранения ценовых ячеек «Ввода» (спека 17 §4.1, G24;
   17:9 — значок сохранения, «сохранено» плавно гаснет): краткая зелёная
   обводка ячейки на ~1.5с, ставит/снимает app.js (htmx:afterRequest).
   Тоста на каждую строку нет; ошибка — тост с серверным текстом. */
.sp-cell-saved { border-color: var(--sp-profit) !important; box-shadow: 0 0 0 1.5px var(--sp-profit-border); transition: box-shadow .4s ease, border-color .4s ease; }

/* ── Режим чтения реестра «Себестоимость и маркировка» (ревью владельца
   2026-09-07): инпут по умолчанию — тихий текст без рамки и фона (сотни
   одинаковых серых боксов давали «зебру» и визуальный шум); рамка и фон
   проявляются на hover, фокус — бренд-акцент. Радиус строгий b2b — 5px.
   Скоуп — класс .sp-inputs-quiet на таблице, другие реестры не задеты.
   width:auto — таблица жмётся по контенту (ревью 2, «эффект разлетающихся
/* Ширина — 100% (решение владельца 2026-09-07, приёмка в контексте
   полной страницы: сжатие по контенту ломало консистентность сетки —
   таблица «сиротливо» прижималась влево, правая половина экрана
   пустовала; surplus отдаётся колонке «Товар»). */
.sp-inputs-quiet .sp-input {
  border-color: transparent; background: transparent;
  border-radius: 5px; box-shadow: none;
}
.sp-inputs-quiet .sp-input:hover {
  border-color: var(--sp-border-strong); background: var(--sp-surface);
}
.sp-inputs-quiet .sp-input:focus {
  border-color: var(--sp-brand); background: var(--sp-surface);
  box-shadow: 0 0 0 3px var(--sp-ring);
}
/* Явный override цены размера — акцент на отклонении от наследования:
   полужирный, бренд-чернила и мягкий бренд-тинт фона (аналитик сразу
   видит размеры с индивидуальной ценой). */
.sp-inputs-quiet .sp-input.sp-size-ovr {
  font-weight: 600; color: var(--sp-brand-ink); background: var(--sp-brand-tint);
}
.sp-inputs-quiet .sp-input.sp-size-ovr:hover,
.sp-inputs-quiet .sp-input.sp-size-ovr:focus { background: var(--sp-surface); }
/* Размерные строки-потомки: лёгкий фон + левый цветной маркер
   вложенности (3px, бренд) на первой колонке — блок читается как
   «содержимое товара выше», а не отдельная таблица. */
.sp-sizes-row > td { background: var(--sp-surface-2); }
.sp-sizes-row > td:first-child { border-left: 3px solid var(--sp-brand); }


.sp-select {
  padding-right: 2rem; -webkit-appearance: none; -moz-appearance: none; appearance: none; 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='%238b93a3' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat; background-position: right 0.55rem center; background-size: 1.05rem;
}
.sp-label { display: block; font-size: 12px; font-weight: 600; color: var(--sp-ink-2); margin-bottom: 5px; }
.sp-link { color: var(--sp-brand-ink); font-weight: 500; }
.sp-link:hover { text-decoration: underline; text-underline-offset: 2px; }

/* ── Панель инструментов подвкладки (ввод → товары): слева тихие
   действия, справа контекст (тултип + счётчик SKU). Компактный ритм
   принятого варианта «Тишина сверху» (live-сессия 2026-09-04). ── */
.sp-tab-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 8px 12px; flex-wrap: wrap; margin-bottom: 10px; }
.sp-tab-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.sp-tab-actions svg { display: block; }

/* ── Тихая форма настроек: секция = заголовок + резюме + строки «метка — поле» ──
   Каждая секция — самостоятельная hx-форма с автосохранением (паттерн порогов
   ДРР); строки держат метку и управление на одной линии, подробности — в
   тултипе data-tip, дефолт — в подписи. Только токены, без новых цветов. */
.sp-setting { padding-top: 1.125rem; margin-top: 1.125rem; border-top: 1px solid var(--sp-border); }
.sp-setting:first-child { padding-top: 0; margin-top: 0; border-top: 0; }
.sp-setting-head { display: flex; align-items: center; gap: 8px; }
.sp-setting-title { font-size: 0.875rem; font-weight: 700; color: var(--sp-ink); }
.sp-setting-summary { margin-top: 3px; margin-bottom: 4px; font-size: 12px; line-height: 1.5; color: var(--sp-ink-3); }
.sp-setting-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 6px 0; }
.sp-setting-name { min-width: 0; }
.sp-setting-label { display: block; font-size: 13px; font-weight: 500; color: var(--sp-ink); cursor: pointer; }
.sp-setting-hint { display: block; margin-top: 1px; font-size: 12px; line-height: 1.45; color: var(--sp-ink-3); }
.sp-setting-row .sp-input, .sp-setting-row .sp-select { flex-shrink: 0; }
.sp-setting-err { display: block; margin-top: 6px; font-size: 12px; color: var(--sp-loss); }

/* ── Шапка / навигация ───────────────────────────────────────────────────── */
/* Каркас-оболочка (шапка/навигация/рабочая область/футер): контент = 90%
   ширины экрана — отступы по 5% слева и справа на любом размере (адаптивно,
   проценты). Заменяет прежний жёсткий cap 1400px. */
.sp-shell { width: 90%; margin-inline: auto; }
.sp-header {
  background: var(--sp-surface);
  background: color-mix(in srgb, var(--sp-surface) 88%, transparent);
  border-bottom: 1px solid var(--sp-border);
  -webkit-backdrop-filter: saturate(1.4) blur(10px);
  backdrop-filter: saturate(1.4) blur(10px);
}
.sp-logo-mark {
  display: inline-flex; height: 30px; width: 30px; flex-shrink: 0;
  align-items: center; justify-content: center; border-radius: 10px;
  background: linear-gradient(135deg, var(--sp-brand), var(--sp-accent));
  box-shadow: 0 4px 12px -3px color-mix(in srgb, var(--sp-brand) 55%, transparent);
}
.sp-logo-mark svg { width: 17px; height: 17px; }
.sp-wordmark { font-family: 'Manrope', 'Inter', sans-serif; font-size: 17px; font-weight: 800; letter-spacing: -0.02em; color: var(--sp-ink); line-height: 1; }
.sp-wordmark b { color: var(--sp-brand-ink); font-weight: 800; }

.sp-nav { background: var(--sp-surface); border-bottom: 1px solid var(--sp-border); }
.sp-nav-link {
  display: inline-flex; align-items: center; gap: 7px; padding: 6px 12px;
  font-size: 14px; font-weight: 500; white-space: nowrap; color: var(--sp-ink-2);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color .15s, border-color .15s;
}
.sp-nav-link svg { width: 16px; height: 16px; opacity: .7; }
.sp-nav-link:hover { color: var(--sp-ink); border-color: var(--sp-border-strong); }
.sp-nav-link[aria-current="page"] { color: var(--sp-brand-ink); border-color: var(--sp-brand); }
.sp-nav-link[aria-current="page"] svg { opacity: 1; }

/* ── Вкладки в карточке (inputs/tracking/settings): подчёркивание бренд-цветом ── */
/* Компактная геометрия полос вкладок (решение владельца 2026-09-29
   «ужать шапку и вкладки»): вертикальный паддинг 6px (было 8px) — ряд
   ~35px вместо ~39px при тех же пропорциях к 50px-шапке (layout.html). */
.sp-tab {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 14px; font-size: 0.875rem; font-weight: 500; white-space: nowrap;
  border-bottom: 2px solid transparent; margin-bottom: -1px; color: var(--sp-ink-3);
  transition: color .14s, border-color .14s;
  /* hx-get-ссылки без href: без pointer браузер рисует I-beam и выделяет текст */
  cursor: pointer; user-select: none;
}
.sp-tab:hover { color: var(--sp-ink); border-bottom-color: var(--sp-border-strong); }
.sp-tab.is-active, .sp-tab[aria-selected="true"] { color: var(--sp-brand-ink); border-bottom-color: var(--sp-brand); }
/* Иконка под-вкладки (tab_icon в layout.html): небольшая, слева от названия */
.sp-tab svg { width: 14px; height: 14px; flex-shrink: 0; opacity: .6; transition: opacity .14s; }
.sp-tab:hover svg { opacity: .85; }
.sp-tab.is-active svg, .sp-tab[aria-selected="true"] svg { opacity: 1; }

/* «?»-справка в правом краю полосы под-вкладок (layout.html tabstrip_help):
   ростом с ряд — align-self:stretch, высоту задаёт самая высокая вкладка —
   глиф по центру, ритм ховера ровно как у .sp-tab (цвет + нижняя черта).
   Описание вкладки живёт в data-tip, тултип открывается ВНИЗ
   (data-tip-below, ui.js). margin-left:auto прижимает к правому краю. */
.sp-tab-help {
  align-self: stretch; width: 38px; margin-left: auto; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  color: var(--sp-ink-3); cursor: help; user-select: none;
  transition: color .14s, border-color .14s;
}
.sp-tab-help svg { width: 18px; height: 18px; opacity: .6; transition: opacity .14s; }
.sp-tab-help:hover { color: var(--sp-ink); border-bottom-color: var(--sp-border-strong); }
.sp-tab-help:hover svg { opacity: .85; }

/* Кликабельные строки таблиц отслеживания: ховер-подсветка (inline-стиль :hover не выразить). */
.sp-row-hover { cursor: pointer; transition: background-color .12s; }
.sp-row-hover:hover > td { background: var(--sp-surface-2); }

/* Иконка-кнопка в тексте (копирование КИЗ и т.п.): приглушённая, бренд при наведении. */
.sp-icon-muted { color: var(--sp-ink-3); transition: color .14s; }
.sp-icon-muted:hover { color: var(--sp-brand-ink); }

/* help_i — кнопка «?» справки у заголовков карточек ({{define "help_i"}},
   layout.html): тот же глиф help-circle, что у sp-tab-help. Приглушённая,
   но читаемая (ink-3 на 14px-заголовке), бренд при наведении, курсор help;
   фокус-ринг даёт общий button:focus-visible. Плотно к заголовку —
   подсказка относится к нему, а не к карточке целиком. */
.help-i { display: inline-flex; align-items: center; justify-content: center;
          width: 18px; height: 18px; padding: 0; border: 0; border-radius: 6px;
          background: transparent; color: var(--sp-ink-3); cursor: help;
          transition: color .14s; }
.help-i svg { width: 15px; height: 15px; }
.help-i:hover { color: var(--sp-brand-ink); }

/* Переключатель темы: показываем солнце в тёмной теме, месяц — в светлой. */
.sp-i-sun { display: none; }
html.dark .sp-i-sun { display: block; }
html.dark .sp-i-moon { display: none; }

.sp-empty-ico {
  display: inline-flex; height: 44px; width: 44px; align-items: center; justify-content: center;
  border-radius: 12px; background: var(--sp-surface-3); color: var(--sp-ink-3);
}

/* ── Плашки-уведомления (ошибки/внимание в формах и на страницах) ─────────── */
.sp-alert { border-radius: 10px; padding: 0.6rem 0.8rem; font-size: 0.875rem; border: 1px solid; line-height: 1.45; }
.sp-alert[data-tone="loss"]   { background: var(--sp-loss-bg);   border-color: var(--sp-loss-border);   color: var(--sp-loss); }
.sp-alert[data-tone="warn"]   { background: var(--sp-warn-bg);   border-color: var(--sp-warn-border);   color: var(--sp-warn); }
.sp-alert[data-tone="info"]   { background: var(--sp-info-bg);   border-color: var(--sp-info-border);   color: var(--sp-info); }
.sp-alert[data-tone="profit"] { background: var(--sp-profit-bg); border-color: var(--sp-profit-border); color: var(--sp-profit); }
.sp-field-err { display: block; margin-top: 4px; font-size: 12px; color: var(--sp-loss); }

/* Иконка функции/отчёта (карточки на дашборде и в справке). */
.sp-feat-ico {
  display: inline-flex; height: 40px; width: 40px; flex-shrink: 0;
  align-items: center; justify-content: center; border-radius: 11px;
  background: var(--sp-brand-tint); color: var(--sp-brand-ink);
}
.sp-feat-ico svg { width: 20px; height: 20px; }

/* ── Меню/выпадашки (шапка: уведомления; дропдауны отчётов) ─────────────── */
.sp-menu {
  background: var(--sp-surface); border: 1px solid var(--sp-border);
  border-radius: 14px; box-shadow: var(--sp-shadow-menu); padding: 6px;
}

/* ── Селектор кабинета шапки: кастомный дропдаун (layout, data-menu).
   Триггер — на базе .sp-input; пункты — .sp-option; заметка «i» — только
   у кабинета с ситуацией (решение владельца 2026-09-24: имя в списке
   ЧИСТОЕ, лимиты/ошибки — иконкой и тултипом, НЕ в названии; 25 §4.3).
   Типографика пунктов — тише базового .sp-option (13px/500, без болда —
   правка владельца 2026-09-25: «большой шрифт, то ли жирный»); выбранный
   — подсветкой фона, не весом текста. ── */
.sp-cab-trigger { display: flex; align-items: center; justify-content: space-between; gap: 8px; text-align: left; cursor: pointer;
  /* Фиксированная ширина (владелец, 2026-09-27): ширина триггера задаётся
     самым длинным именем кабинета (sizer в лейбле), а не выбранным пунктом —
     «Все кабинеты» не сжимает кнопку. Кап в символах шрифта кнопки
     (0.875rem): длиннее 40ch — троеточие, меньше — не сжимается. */
  max-width: 40ch; }
/* Невидимый sizer внутри лейбла: block+height:0 не добавляет высоты,
   visibility:hidden не видно, но его max-content (самое длинное имя)
   задаёт preferred-ширину лейбла → триггера. */
.sp-cab-sizer { display: block; height: 0; overflow: hidden; visibility: hidden; white-space: nowrap; pointer-events: none; }
/* Имя на кнопке: flex-ребёнок сжимается до ширины кнопки с троеточием —
   без min-width:0 flex не сжимает контент (min-width:auto) и длинное имя
   распирало триггер. */
.sp-cab-trigger .truncate { min-width: 0; flex: 1 1 auto; }
.sp-cab-chevron { width: 1rem; height: 1rem; color: var(--sp-ink-3); transition: transform .15s; }
[data-menu][data-open] .sp-cab-chevron { transform: rotate(180deg); }
/* Специфичность 0-2-0: базовый .sp-option (block, 16px-паддинги) объявлен
   ниже и при равной специфичности перебивал flex-строку — имя и «i»
   разъезжались на две строки (дефект владельца 2026-09-25). */
.sp-option.sp-cab-option { display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; text-align: left; padding: 7px 10px; border-radius: 8px;
  font-size: 0.8125rem; font-weight: 500; color: var(--sp-ink); }
.sp-cab-option .truncate { min-width: 0; flex: 1 1 auto; }
.sp-cab-option[aria-selected="true"] { background: var(--sp-brand-tint); color: var(--sp-brand-ink); }
/* Зазор между пунктами панели (панель нельзя делать flex-контейнером:
   display-класс на [hidden]-панели делает её видимой всегда). */
.sp-cab-option + .sp-cab-option { margin-top: 2px; }
.sp-cab-note { display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; flex-shrink: 0; border-radius: 9999px; color: var(--sp-warn); cursor: help; }
.sp-cab-note svg { width: 14px; height: 14px; display: block; }

/* Опция автокомплита (живой поиск товара): двустрочная, hover/active подсветка.
   Активную (стрелками) подсвечивает JS инлайновым background. */
.sp-option { display: block; width: 100%; text-align: left; padding: 8px 16px;
  background: transparent; border: 0; cursor: pointer; transition: background .12s; }
.sp-option:hover { background: var(--sp-surface-2); }
.sp-option-title { font-size: 0.875rem; color: var(--sp-ink); }
.sp-option-meta { font-size: 0.75rem; color: var(--sp-ink-3); }

/* ── Скелетон-загрузка (shimmer) ─────────────────────────────────────────── */
.sp-skeleton { position: relative; overflow: hidden; background: var(--sp-surface-2); border-radius: 9px; }
.sp-skeleton::after {
  content: ''; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.55), transparent);
  animation: sp-shimmer 1.5s infinite;
}
html.dark .sp-skeleton::after { background: linear-gradient(90deg, transparent, rgba(255,255,255,0.08), transparent); }
@keyframes sp-shimmer { 100% { transform: translateX(100%); } }
@keyframes sp-breathe { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }

/* ── Progressive Loading (волна 2026-09-10, design.md §3/§5): размерные
   модификаторы ПОВЕРХ .sp-skeleton выше (база с шиммером; тёмная тема и
   reduced-motion уже покрыты базой). Ширины — хвосты Tailwind (w-2/3…). */
.sp-skel-line  { height: 11px; }                     /* строка текста  */
.sp-skel-value { height: 28px; border-radius: 8px; } /* число в sp-stat */
.sp-skel-pill  { height: 18px; width: 64px; border-radius: 999px; }
.sp-skel-cell  { height: 12px; }                     /* ячейка таблицы */
.sp-skel-dot   { flex: none; width: 22px; height: 22px; border-radius: 50%; }
/* «График»: 10 мягких баров разной высоты — абстрактная заготовка
   диаграммы; сами бары — та же .sp-skeleton (шиммер общий). */
.sp-skel-bars { display: flex; align-items: flex-end; gap: 6px; height: 100%; }
.sp-skel-bars > .sp-skeleton { flex: 1 1 0; border-radius: 6px 6px 2px 2px; }
.sp-skel-bars > .sp-skeleton:nth-child(10n+1) { height: 34%; }
.sp-skel-bars > .sp-skeleton:nth-child(10n+2) { height: 58%; }
.sp-skel-bars > .sp-skeleton:nth-child(10n+3) { height: 42%; }
.sp-skel-bars > .sp-skeleton:nth-child(10n+4) { height: 74%; }
.sp-skel-bars > .sp-skeleton:nth-child(10n+5) { height: 50%; }
.sp-skel-bars > .sp-skeleton:nth-child(10n+6) { height: 66%; }
.sp-skel-bars > .sp-skeleton:nth-child(10n+7) { height: 38%; }
.sp-skel-bars > .sp-skeleton:nth-child(10n+8) { height: 82%; }
.sp-skel-bars > .sp-skeleton:nth-child(10n+9) { height: 46%; }
.sp-skel-bars > .sp-skeleton:nth-child(10n+10) { height: 62%; }

/* Честная заглушка внутри карточки графика, когда серий нет или все
   значения нулевые (rnp.js): вместо голых осей — по центру, тихо. */
.sp-chart-empty { display: flex; align-items: center; justify-content: center;
  height: 100%; font-size: 12.5px; color: var(--sp-ink-3); }
/* Подпись НАД силуэтом скелетона графика (внутри .h-48 flex-col). */
.sp-chart-empty-label { height: auto; flex: none; }

/* Скелетон-силуэт графика (референс владельца: серый «горный» график
   вместо пустых осей/голого текста): два мягких area-слоя на тематных
   поверхностях, дыхание вместо шиммера (sp-breathe уже в системе). */
.sp-skel-chart { position: relative; flex: 1 1 auto; min-height: 0;
  overflow: hidden; border-radius: 8px; }
.sp-skel-chart-svg { position: absolute; inset: 0; width: 100%; height: 100%;
  animation: sp-breathe 2.4s ease-in-out infinite; }

/* Заметка зоны «Загружаем финансы · запись в БД» (§4): спиннер
   переиспользует .sync-spin — анимация и reduced-motion уже там. */
.sp-zone-note { display: flex; align-items: center; gap: 8px;
  margin: 2px 0 10px; font-size: 12.5px; color: var(--sp-ink-3); }
.sp-zone-spin { width: 14px; height: 14px; flex: none; fill: none; stroke: var(--sp-brand); }

/* Тихий пульс числа при обновлении зоны (решение владельца 2026-09-27
   вместо бейджа «Обновляем…»): бренд-тинт гаснет к обычному цвету за
   время tween'а «старое → новое». Класс вешает/снимает только
   progzone.js; reduced-motion дублирует JS-гвард tween'а. */
.sp-num-tween { animation: sp-num-pulse 0.7s ease-out; }
@keyframes sp-num-pulse {
  0% { color: var(--sp-brand); }
  100% { color: inherit; }
}
@media (prefers-reduced-motion: reduce) { .sp-num-tween { animation: none; } }

/* First-sync пилюля (§9.1): лёгкий бренд-тинт поверх info-подложки —
   только токены, обе темы; hex-значений сознательно нет. */
.sync-pill[data-first-sync] { color: var(--sp-brand);
  background: color-mix(in srgb, var(--sp-brand) 10%, transparent);
  border-color: color-mix(in srgb, var(--sp-brand) 30%, transparent); }

/* ── HTML-таблицы (ОПиУ, юнит и пр.) ─────────────────────────────────────── */
.sp-table { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
.sp-table thead th {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--sp-ink-3); text-align: left; padding: 9px 12px;
  border-bottom: 1px solid var(--sp-border); background: var(--sp-surface);
}
.sp-table tbody td { padding: 9px 12px; border-bottom: 1px solid var(--sp-border); color: var(--sp-ink); }
.sp-table tbody tr:hover td { background: var(--sp-surface-2); }
.sp-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.sp-table tfoot td { padding: 10px 12px; border-top: 2px solid var(--sp-border-strong); font-weight: 700; }
.sp-table-sticky thead th { position: sticky; top: 0; z-index: 1; }

/* Универсальные поиск и сортировка таблиц (sp-table.js): opt-in —
   data-sortable на таблице, data-key на сортируемых th, data-table-search
   на поле поиска. Остальные sp-table не затронуты.
   Одна стрелка на таблицу (решение владельца 2026-09-28, план
   docs/plans/2026-09-28-table-unification-plan.md, R2): подсказка ↕ в
   каждом заголовке убрана — брендовая ↑/↓ рисуется ТОЛЬКО у сортируемого
   сейчас столбца (sp-sorted-asc/-desc ниже). */
.sp-table th[data-key] {
  cursor: pointer; user-select: none; white-space: nowrap;
  transition: background-color 120ms ease, color 120ms ease;
}
.sp-table th[data-key]:hover { color: var(--sp-ink-2); }
.sp-table th[data-key].sp-sorted-asc::after { content: '↑'; opacity: 1; color: var(--sp-brand); }
.sp-table th[data-key].sp-sorted-desc::after { content: '↓'; opacity: 1; color: var(--sp-brand); }
.sp-table th[data-key].sp-sorted-asc,
.sp-table th[data-key].sp-sorted-desc { background: var(--sp-surface-2); color: var(--sp-ink-2); }
.sp-table tbody tr { transition: background-color 120ms ease; }
.sp-table tr[hidden] { display: none; }
/* Плюс-строка создания первой строкой таблицы (restock): строка-кнопка
   «＋ Новый артикул», пунктир-разделитель читается как «вставка над
   данными». pinned-поведение (вне поиска/сортировки/пагинации) даёт
   tr[data-table-pin] в sp-table.js; раскрытие инлайн-формы — restock.js. */
.sp-table .sp-add-row td { padding: 5px 12px; border-bottom: 1px dashed var(--sp-border-strong); }
.sp-add-row-btn {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.875rem; font-weight: 500; color: var(--sp-ink-2);
  padding: 4px 8px; border-radius: 8px;
  transition: color 120ms ease, background-color 120ms ease;
}
.sp-add-row-btn svg { color: var(--sp-ink-3); transition: color 120ms ease; }
.sp-add-row-btn:hover { color: var(--sp-ink); background: var(--sp-surface-3); }
.sp-add-row-btn:hover svg { color: var(--sp-brand); }
/* Поиск в шапке таблицы (решение владельца 2026-09-28, план
   docs/plans/2026-09-28-table-unification-plan.md, R1): поле поиска живёт
   в свободном месте ячейки первого столбца, а не в тулбаре. Разметка:
     <th data-key="…"><div class="sp-th-head"><span>Товар</span>
       <span class="sp-th-search-box"><svg/><input data-table-search="#id"></span></div></th>
   Работают оба движка: и клиентский sp-table.js, и серверный
   sp-table-server.js (поиск делегируется на document). */
.sp-table th .sp-th-head { display: flex; align-items: center; gap: 8px; }
.sp-table th .sp-th-head > span:first-child { flex: none; }
.sp-th-search-box { position: relative; flex: 0 1 240px; min-width: 110px; }
.sp-th-search-box svg {
  position: absolute; left: 7px; top: 50%; transform: translateY(-50%);
  color: var(--sp-ink-3); pointer-events: none;
}
.sp-th-search-box input {
  width: 100%; padding: 3px 8px 3px 25px; font-size: 12px; line-height: 1.4;
  text-transform: none; letter-spacing: normal;
  color: var(--sp-ink-2); background: var(--sp-surface-2);
  border: 1px solid transparent; border-radius: 7px;
  outline: none; transition: border-color 120ms ease, background-color 120ms ease;
}
.sp-th-search-box input:focus { border-color: color-mix(in srgb, var(--sp-brand) 45%, transparent); background: var(--sp-surface); color: var(--sp-ink); }
/* Стрелка сортировки в шапке с поиском (фикс 2026-09-28): стрелка —
   ::after самого th, а после блочного flex-ряда .sp-th-head inline-контент
   переносится на новую строку — стрелка «съезжала» под подпись столбца
   («Подмены и неверные вложения», скрин владельца). Для заголовков с
   .sp-th-head стрелку рисует СЛОТ после подписи, ПЕРЕД полем поиска;
   место под стрелку зарезервировано всегда — переключение сортировки
   не двигает input. th::after таких заголовков заглушён через :has —
   без этого вторая стрелка осталась бы под рядом. Правило одно на все
   таблицы sp-table, оба движка (класс sp-sorted-* ставят и
   sp-table.js, и sp-table-server.js, и серверный рендер). */
.sp-table th[data-key] .sp-th-head > span:first-child::after {
  content: ''; display: inline-block; width: 12px; text-align: center;
}
.sp-table th[data-key].sp-sorted-asc .sp-th-head > span:first-child::after { content: '↑'; color: var(--sp-brand); }
.sp-table th[data-key].sp-sorted-desc .sp-th-head > span:first-child::after { content: '↓'; color: var(--sp-brand); }
.sp-table th[data-key]:has(.sp-th-head).sp-sorted-asc::after,
.sp-table th[data-key]:has(.sp-th-head).sp-sorted-desc::after { content: none; }
.sp-table-search { position: relative; }
.sp-table-search svg {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  color: var(--sp-ink-3); pointer-events: none;
}
.sp-table-search .sp-input { padding-left: 31px; width: 270px; max-width: 62vw; }
/* Пейджер sp-table.js — визуальный клон футера пагинации tracking: слева
   счётчик, справа окно кнопок (sp-btn-sm; активная — sp-btn-primary). */
.sp-pager {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px 12px; flex-wrap: wrap; padding: 10px 2px 2px;
  color: var(--sp-ink-3); font-size: 0.875rem;
}
.sp-pager-pages { display: flex; gap: 4px; flex-wrap: wrap; }
/* Компактные строки табличных реестров (opt-in .sp-table-compact):
   плотный вертикальный ритм — паттерн «реестр», а не «карточки».
   Первый пользователь — «Ввод → Себестоимость и маркировка». */
.sp-table-compact tbody td { padding-top: 5px; padding-bottom: 5px; }

/* ── Пилюли колонки «Товар» — три визуальные группы (решение владельца
   2026-09-07, план docs/plans/2026-09-07-pill-visual-hierarchy.md):
   sp-pill-id — идентификаторы (баркод/nmID/КИЗ/ID поставок и кампаний),
   бренд-тинт; sp-pill-param — параметры (размер/рост), шалфей;
   sp-cell-text — второстепенные описания (название/предмет/бренд/
   кабинет) — обычный текст без капсулы. База = только капсула и
   типографика, цвет живёт в группах; 12px и 2px 8px — канон компактных
   меток (основной текст таблиц 14px). Клик — значение в буфер
   (data-action="copy", app.js: тост «Скопировано»), тултип называет
   свойство, показ — обрезка 50 символов (pillMaxRunes, sku_cell.go).
   Зелёную семантику прибыли (#ecfdf5/#059669) для параметров НЕ
   занимать (Semantic Colors Rule, DESIGN.md). ── */
.sp-pill {
  display: inline-flex; align-items: center; max-width: 100%;
  font-family: inherit; font-size: 12px; font-weight: 500; line-height: 1.4;
  white-space: nowrap; padding: 2px 8px; border-radius: 9999px;
  border: 1px solid transparent; cursor: copy; text-align: left;
  overflow: hidden; text-overflow: ellipsis;
  appearance: none; -webkit-appearance: none;
  transition: color 120ms ease, background-color 120ms ease, border-color 120ms ease, transform 60ms ease;
}
.sp-pill-id { color: var(--sp-brand-ink); background: var(--sp-brand-tint); }
.sp-pill-id:hover { background: var(--sp-surface); border-color: var(--sp-border-strong); }
.sp-pill-param { color: var(--sp-param-ink); background: var(--sp-param-bg); }
.sp-pill-param:hover { background: var(--sp-surface); border-color: var(--sp-border-strong); }
.sp-pill:active { transform: scale(0.97); }
/* Removable-чип привязки строки поставки к исходному артикулу (волна
   «Поставка по исходным артикулам», запрос владельца 2026-09-26: ✕ вне
   пилюли был слишком мелким и терялся). Код + ✕ в ОДНОЙ пилюле;
   бренд-точка — маркер «строка привязана» (язык чипов-точек); кнопка —
   круглая зона 20px (закон Фиттса), ховеры пилюли и кнопки —
   color-mix от бренд-токенов (обе темы бесплатны). cursor: default —
   чип не копируется, в отличие от sp-pill. */
.sp-article-chip { gap: 2px; padding: 3px 4px 3px 10px; cursor: default; }
.sp-article-chip:hover { background: var(--sp-brand-tint); border-color: var(--sp-brand-ink); }
.sp-article-chip-dot {
  width: 6px; height: 6px; flex-shrink: 0; border-radius: 9999px;
  background: var(--sp-brand-ink); opacity: 0.55;
}
.sp-article-clear {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; flex-shrink: 0;
  border-radius: 9999px; color: var(--sp-brand-ink); opacity: 0.72;
  appearance: none; background: transparent; border: none; cursor: pointer;
  transition: opacity 120ms ease, background-color 120ms ease, transform 60ms ease;
}
.sp-article-clear:hover { opacity: 1; background: color-mix(in srgb, var(--sp-brand-ink) 16%, transparent); }
.sp-article-clear:active { transform: scale(0.94); }
/* Артикул — якорь строки: ОБЫЧНЫЙ ТЕКСТ, не пилюля (решение владельца
   2026-09-06): капсула и фон у имени убраны, осталась только функция
   копирования (клик — Full в буфер). Потолок 34ch: 50 рун (pillMaxRunes)
   не должны раздувать колонку «Товар» — эллипсис на месте. */
.sp-pill-name {
  font-size: 12px; font-weight: 600; color: var(--sp-ink);
  padding: 0; background: transparent; border: none; max-width: 34ch;
}
.sp-pill-name:hover { color: var(--sp-brand-ink); background: transparent; border-color: transparent; }
.sp-pill-name:active { transform: none; }
/* Артикул-якорь как ССЫЛКА на «Досье товара» (sku_cell Href, запрос
   владельца 2026-09-09): вид «обычного текста» тот же, подчёркивания
   нет — курсор-указатель и бренд при наведении (уже в .sp-pill-name:hover). */
a.sp-pill { text-decoration: none; cursor: pointer; }
/* Второстепенные описания (название/предмет/бренд/кабинет): обычный
   текст, НЕ пилюля (решение владельца 2026-09-07) — без фона, рамки и
   капсулы; копирование по клику и тултип сохранены. */
.sp-cell-text {
  background: transparent; border: none; padding: 0;
  font-size: 12px; font-weight: 500; color: var(--sp-ink-2);
}
.sp-cell-text:hover { color: var(--sp-ink); border-color: transparent; }
.sp-cell-text:active { transform: none; }
/* Разделитель «·» между текстовыми описаниями ОДНОЙ строки (ставит JS,
   app.js: pillTextSeparators — меряет offsetTop; перенесённые на новую
   строку элементы остаются без точки). Жирнее текста, цвет приглушённый. */
.sp-cell-sep { color: var(--sp-ink-3); font-weight: 700; margin: 0 5px; user-select: none; }
/* Баркод — моно-стек tailwind (мелкое отличие «номерного» свойства) */
.sp-pill-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; letter-spacing: 0.01em; }
/* Пилюля-действие «скрыть/показать» (замена «удалить»): иконка-глаз,
   тихая до наведения, тултип — data-tip. */
.sp-pill-action { padding: 2.5px 6px; color: var(--sp-ink-3); background: transparent; cursor: pointer; }
.sp-pill-action:hover { color: var(--sp-ink); background: var(--sp-surface-2); border-color: var(--sp-border); }
.sp-pill-action svg { display: block; }
/* Метка «удалена в WB» (надгробие карточки): тихая, НЕ копируется —
   только поясняет, почему строка уехала в нижнюю группу. */
.sp-pill-del { color: var(--sp-loss); background: var(--sp-loss-bg); border-color: var(--sp-loss-border); cursor: help; }
/* Строка скрытого SKU («тонущая»): приглушена целиком, при наведении
   оживает — поля и кнопка «Показать» остаются рабочими. */
.sp-row-hidden td { opacity: 0.55; transition: opacity 120ms ease; }
.sp-row-hidden:hover td { opacity: 1; }
/* Делитель группы «Скрытые»: тихая метка-счётчик, читается как секция,
   а не строка данных (sp-table.js держит её вне поиска/сортировки). */
tr[data-table-divider] > td { padding-top: 16px; padding-bottom: 4px; border-bottom: 1px solid var(--sp-border); }
.sp-hidden-label { font-size: 11px; font-weight: 600; color: var(--sp-ink-3); letter-spacing: 0.02em; }


/* Плотность таблиц (тумблер ставит data-density на контейнере) */
[data-density="compact"] .sp-table thead th,
[data-density="compact"] .sp-table tbody td { padding-top: 4px; padding-bottom: 4px; }

/* ── Плотный пивот ОПиУ (месяцы/дни): компактная сетка «замороженный столбец
      + строки-итоги» в тон токенам. Ячейки-паддинги задаёт разметка. ─────── */
.sp-pivot { width: 100%; border-collapse: collapse; }
.sp-pivot thead th {
  background: var(--sp-surface-2); color: var(--sp-ink-3);
  font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em;
}
.sp-pivot tbody tr { border-top: 1px solid var(--sp-border); }
.sp-pivot tbody td { color: var(--sp-ink); }
.sp-pivot tbody tr:hover td, .sp-pivot tbody tr:hover .pv-sticky { background: var(--sp-surface-2); }
/* Замороженный первый столбец (метрика) */
.sp-pivot .pv-sticky { position: sticky; left: 0; z-index: 5; background: var(--sp-surface); }
.sp-pivot thead .pv-sticky { z-index: 15; background: var(--sp-surface-2); }
/* Точка-аномалия (скачок статьи к прошлому месяцу): SSR-ячейки ОПиУ
   (шаблон pnl_cell) и легенда в шапке карточки. Вариант .sp-pivot .pv-anom
   удалён (мёртвый после сноса SSR: sp-pivot живёт только в drawer-таблице,
   где pv-anom нет). */
.fin-panel .pv-anom { display: inline-block; width: 6px; height: 6px; border-radius: 9999px; background: var(--sp-warn); vertical-align: middle; margin-left: 2px; }

/* ── Пивот ОПиУ: единая таблица с drill-down по дням (редизайн 2026-08) ──── */
/* Строка-заголовок секции: не сворачивается, метка прилипает слева */
.sp-pivot tr.pv-section td {
  background: var(--sp-surface-2); color: var(--sp-ink-3);
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em;
  padding: 7px 16px;
}
.sp-pivot .pv-section-label { position: sticky; left: 16px; display: inline-block; }
/* Волосяная граница справа прилипшего столбца «Метрика» */
.sp-pivot .pv-sticky { border-right: 1px solid var(--sp-border); }
/* ── ОПиУ: СЕРВЕРНАЯ таблица #pnl-table (план «ОПиУ → единый движок
   таблиц» 2026-09-28; Tabulator снесён): каркас #fin-table/#rnp-matrix —
   плотность 44px, липкая шапка, замороженный угол «Метрика», Δ-чипы
   cstack, ховер колонки = ховеру строки (bindColHover pnl-table.js).
   DnD/ресайз колонок — сознательно НЕТ (решение владельца 2026-09-28). ── */
#pnl-table { width: max-content; min-width: 100%; border-collapse: separate; border-spacing: 0; }
#pnl-table th, #pnl-table td {
  border-bottom: 1px solid var(--sp-border); border-right: 1px solid var(--sp-border);
  padding: 4px 10px; white-space: nowrap;
}
/* Шапка — «нейтральный гребень» (тот же, что у #fin-table/#rnp-matrix);
   липнет к скролл-обёртке — вертикаль внутри панели, канон Мониторинга. */
#pnl-table thead th {
  position: sticky; top: 0; z-index: 2; background: var(--sp-surface-2);
  font-size: 11px; font-weight: 600; color: var(--sp-ink-2);
  text-align: center; transition: background-color .12s ease;
}
#pnl-table thead th.num { text-align: right; }
#pnl-table thead tr:last-child th { border-bottom: 1px solid var(--sp-border-strong); }
#pnl-table-wrap { max-height: calc(100vh - 15rem); }
/* Три строки cstack умещаются в 44px только с малыми паддингами и
   межстрочным 1.15 (замер 2026-09-11; скоуплен таблицей ОПиУ). */
#pnl-table .cstack, #pnl-table .cstack-main, #pnl-table .cstack-sub { line-height: 1.15; }
#pnl-table tbody tr { height: 44px; }
#pnl-table td.num, #pnl-table th.num { text-align: right; font-variant-numeric: tabular-nums; }
#pnl-table .pnl-month-head, #pnl-table td[data-col^="m"] { min-width: 96px; }
#pnl-table th[data-col="year"], #pnl-table td[data-col="year"] { min-width: 104px; }
#pnl-table tbody tr:hover td { background: color-mix(in srgb, var(--sp-ink) var(--sp-row-hover-mix), var(--sp-surface)); }
/* Ховер колонки под курсором шапки — ТА ЖЕ формула, что у #fin-table
   td.col-hover (бриф владельца 2026-09-27; слой — inset box-shadow НАД
   фоном ячейки: не затирается фоном/хavadocом строки). */
#pnl-table td.col-hover {
  box-shadow: inset 0 0 0 9999px color-mix(in srgb, var(--sp-ink) var(--sp-row-hover-mix), var(--sp-surface));
}
/* Замороженный угол «Метрика» (th в шапке и в строках scope=row):
   тень «слой над данными» — канон #rnp-matrix td.fin-sku. */
#pnl-table th.fin-corner { left: 0; z-index: 3; text-align: left; min-width: 260px; }
#pnl-table tbody th.fin-corner {
  position: sticky; z-index: 1; background: var(--sp-surface);
  box-shadow: 6px 0 8px -6px rgba(16, 24, 40, 0.22);
}
html.dark #pnl-table tbody th.fin-corner { box-shadow: 6px 0 8px -6px rgba(0, 0, 0, 0.5); }
/* Секция — полоса тинта tone (группировка строк «Доходы/Расходы/…»,
   канон прежних этажей B1/B2 «ОПиУ 2.0»); фолбэк без tone — surface-2.
   Ярлык живёт в замороженном углу строки. */
#pnl-table tr.pv-section { height: 30px; }
#pnl-table tr.pv-section th, #pnl-table tr.pv-section td { background: var(--sp-surface-2); }
#pnl-table tr.pv-section[data-tone="income"] th,
#pnl-table tr.pv-section[data-tone="income"] td { background: color-mix(in srgb, var(--sp-delta-up) 7%, var(--sp-surface)); }
#pnl-table tr.pv-section[data-tone="expense"] th,
#pnl-table tr.pv-section[data-tone="expense"] td { background: color-mix(in srgb, var(--sp-ink) 4%, var(--sp-surface)); }
#pnl-table tr.pv-section[data-tone="summary"] th,
#pnl-table tr.pv-section[data-tone="summary"] td { background: var(--sp-brand-tint); }
#pnl-table .pv-section-label { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; color: var(--sp-ink-2); }
/* Клик по всему столбцу месяца → шторка (решение владельца 2026-09-11):
   курсор-хенд на шапке и ячейках месяца; кнопка месяца — стиль ниже. */
#pnl-table th[data-col^="m"], #pnl-table td[data-col^="m"] { cursor: pointer; }
/* Колонка «График»: универсальный спарклайн spCharts (движок мини-
   графиков дашборда) в цвете бренда; контейнер data-spark —
   position:relative: точка и чип магнита абсолютные В ЕГО координатах. */
#pnl-table .pnl-spark-head, #pnl-table .pnl-spark-cell { min-width: 170px; }
#pnl-table .pnl-spark-cell { color: var(--sp-brand); }
#pnl-table .pnl-spark-cell [data-spark] { width: 100%; position: relative; }
/* Плотная типографика числовых колонок (канон прежних колонок ОПиУ):
   значение 12px, Δ/«% выр.» 10px — три строки cstack в 44px. */
#pnl-table td.num .cstack-main { font-size: 12px; }
#pnl-table td.num .cstack-sub { font-size: 10px; }
/* Метрика: nowrap + ellipsis, полное название — в data-tip угла */
.pnl-metric { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Кнопка месяца в шапке колонки (SSR + is-active от pnl-days.js) */
.pnl-month-btn {
  display: inline-flex; align-items: center; padding: 3px 8px;
  border: 1px solid transparent; border-radius: 8px; background: transparent;
  color: var(--sp-ink-2); cursor: pointer; font: inherit;
  transition: background .12s, color .12s;
}
.pnl-month-btn:hover { background: var(--sp-surface-3); color: var(--sp-ink); }
.pnl-month-btn:focus-visible { outline: 2px solid var(--sp-ring); outline-offset: 1px; }
.pnl-month-btn.is-active { background: var(--sp-brand-tint); color: var(--sp-brand-ink); }
/* ── Дневная шторка ОПиУ .pnl-side (волна «ОПиУ 2.0», фаза C): fixed
   панель справа + скрим, монтируются в body (pnl-days.js). z: скрим 60,
   панель 70 — выше поповеров проекта (.fin-pop 30, .g-pop 50+); тултипы
   #global-tip — выше панели. Только токены --sp-*. ── */
.pnl-side-root { position: fixed; inset: 0; z-index: 60; pointer-events: none; }
.pnl-side-scrim {
  position: absolute; inset: 0; pointer-events: auto;
  background: color-mix(in srgb, var(--sp-ink) 32%, transparent);
  opacity: 0; transition: opacity 240ms ease;
}
.pnl-side-root.is-open .pnl-side-scrim { opacity: 1; }
.pnl-side {
  position: fixed; top: 0; right: 0; height: 100dvh;
  /* Шире по решению владельца 2026-09-11 (было clamp(440px,36vw,720px)).
     Колонка «График» главной таблицы повторяет эту формулу в px —
     sideW() pnl-table.js (синхронно вручную). */
  width: clamp(560px, 44vw, 880px); z-index: 70;
  display: flex; flex-direction: column; pointer-events: auto;
  background: var(--sp-surface);
  border-left: 1px solid var(--sp-border);
  box-shadow: var(--sp-shadow-menu);
  transform: translateX(100%); visibility: hidden;
  transition: transform 240ms ease, visibility 0s linear 240ms;
}
.pnl-side-root.is-open .pnl-side {
  transform: translateX(0); visibility: visible;
  transition: transform 240ms ease;
}
@media (prefers-reduced-motion: reduce) {
  .pnl-side, .pnl-side-root.is-open .pnl-side,
  .pnl-side-scrim, .pnl-side-root.is-open .pnl-side-scrim,
  .pnl-side-body { transition: none; }
}
/* Шапка: месяц, сегмент-переключатель [📈 Графики | 📋 Таблица], ✕ */
.pnl-side-head {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 14px; border-bottom: 1px solid var(--sp-border);
}
.pnl-side-title { font-weight: 600; font-size: 13px; color: var(--sp-ink); white-space: nowrap; }
.pnl-side-tabs {
  display: inline-flex; gap: 2px; margin-left: auto; padding: 2px;
  background: var(--sp-surface-2); border: 1px solid var(--sp-border); border-radius: 9px;
}
.pnl-side-tab {
  border: 0; background: transparent; cursor: pointer; font: inherit;
  font-size: 12px; color: var(--sp-ink-2); padding: 3px 10px; border-radius: 7px;
  transition: background .12s, color .12s;
}
.pnl-side-tab:hover { color: var(--sp-ink); }
.pnl-side-tab:focus-visible { outline: 2px solid var(--sp-ring); outline-offset: 1px; }
.pnl-side-tab[aria-selected="true"] { background: var(--sp-surface); color: var(--sp-brand-ink); font-weight: 600; }
.pnl-side-close {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; flex: none;
  border: 1px solid var(--sp-border); border-radius: 8px;
  background: var(--sp-surface); color: var(--sp-ink-3); cursor: pointer;
  transition: background .12s, color .12s;
}
.pnl-side-close:hover { background: var(--sp-surface-3); color: var(--sp-ink); }
.pnl-side-close:focus-visible { outline: 2px solid var(--sp-ring); outline-offset: 1px; }
.pnl-side-close svg { width: 12px; height: 12px; }
/* Контент — единственный скроллящийся регион панели (обе прокрутки;
   страница не скроллится). Fade переключения режимов (150мс) ставит
   pnl-days.js инлайном; reduced-motion глушится выше. */
.pnl-side-body { flex: 1; min-height: 0; overflow: auto; transition: opacity 150ms ease; overscroll-behavior: contain; }
/* Подвал: сверка «Σ дней = месячному итогу» (тултип pnl.days.sum_match)
   + выручка месяца из ctx. Диагностическая подпись, НЕ вычисление. */
.pnl-side-foot {
  display: flex; align-items: center; gap: 12px;
  padding: 7px 14px; border-top: 1px solid var(--sp-border);
  font-size: 11.5px; color: var(--sp-ink-3);
}
.pnl-side-foot-sum { cursor: help; }
.pnl-side-rev { margin-left: auto; color: var(--sp-ink-2); white-space: nowrap; }
.pnl-side-msg {
  padding: 24px 16px; display: flex; flex-direction: column;
  gap: 10px; align-items: flex-start; font-size: 13px; color: var(--sp-ink-2);
}
/* ── Режим «Графики»: лента секций (тинт tone — как этажи таблицы)
   и метрик-виджетов: слева имя+итог месяца+Δ (из ctx), справа спарклайн. ── */
.pnl-days-band {
  position: sticky; top: 0; z-index: 3;
  padding: 5px 14px; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.07em; color: var(--sp-ink-2);
  background: var(--sp-surface-2);
}
.pnl-days-band[data-tone="income"]  { background: color-mix(in srgb, var(--sp-delta-up) 7%, var(--sp-surface)); }
.pnl-days-band[data-tone="expense"] { background: color-mix(in srgb, var(--sp-ink) 4%, var(--sp-surface)); }
.pnl-days-band[data-tone="summary"] { background: var(--sp-brand-tint); }
.pnl-days-widget {
  display: flex; align-items: center; gap: 10px;
  min-height: 44px; padding: 6px 14px;
  border-bottom: 1px solid var(--sp-surface-2);
}
.pnl-days-widget:hover { background: var(--sp-row-hover); }
.pnl-days-winfo { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.pnl-days-wname { font-size: 12px; color: var(--sp-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pnl-days-wsub { display: flex; gap: 8px; font-size: 11px; color: var(--sp-ink-2); }
/* Универсальный спарклайн виджета (spCharts, движок плиток дашборда):
   бренд-цвет линии (tiles-канон); position:relative — точка и чип магнита
   абсолютные В КООРДИНАТАХ спарка, не панели (иначе чип улетает). */
.pnl-days-wspark { flex: none; line-height: 0; position: relative; color: var(--sp-brand); }
.pnl-days-spark { display: block; overflow: visible; }
/* Тултип дня — вид эталонного #global-tip; fixed у курсора (z выше панели) */
.pnl-days-daytip {
  position: fixed; z-index: 80; pointer-events: none;
  background: var(--sp-tooltip-bg); color: var(--sp-tooltip-ink);
  max-width: 320px; width: max-content; padding: 6px 9px; border-radius: 8px;
  font-size: 12px; line-height: 1.45; box-shadow: var(--sp-shadow-menu);
  white-space: nowrap;
}
/* ── Режим «Таблица» — ТРАНСПОНИРОВАНО (решение владельца 2026-09-11):
   метрики строками, время колонками: «Метрика» | «Месяц» | 01…31.
   Sticky слева — «Метрика» (190px) и «Месяц» (за ней), sticky сверху —
   шапка дней. Ширина 190 синхронна sticky-отступам «Месяц» (left:190). ── */
.pnl-days-ttable {
  border-collapse: separate; border-spacing: 0;
  width: max-content; min-width: 100%; font-size: 11px;
}
.pnl-days-ttable th, .pnl-days-ttable td { box-sizing: border-box; font-variant-numeric: tabular-nums; }
.pnl-days-metriccol {
  position: sticky; left: 0; z-index: 2;
  width: 190px; min-width: 190px; max-width: 190px;
  background: var(--sp-surface); color: var(--sp-ink);
  text-align: left; font-weight: 500; padding: 0 8px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pnl-days-colhead {
  position: sticky; top: 0; z-index: 3; height: 30px;
  width: 76px; min-width: 76px; max-width: 76px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  text-align: right; font-weight: 600; color: var(--sp-ink-2);
  background: var(--sp-surface-2); padding: 0 6px;
}
/* Угол (th с обоими классами) матчит и .pnl-days-metriccol, и идущую
   позже .pnl-days-colhead (76px) — пин держит угол = 190px (метрика),
   z 5 — выше «Месяца» (4) и шапки дней (3). */
th.pnl-days-metriccol.pnl-days-colhead {
  z-index: 5; text-align: left;
  width: 190px; min-width: 190px; max-width: 190px;
}
/* «Месяц» — итог из ctx: sticky слева ЗА метрикой (left = ширина метрики). */
.pnl-days-monthhead { left: 190px; z-index: 4; }
td.pnl-days-monthcell {
  position: sticky; left: 190px; z-index: 2;
  background: var(--sp-surface); font-weight: 600;
}
.pnl-days-ttable tbody th, .pnl-days-ttable tbody td {
  height: 26px; padding: 0 6px; text-align: right; white-space: nowrap;
  border-bottom: 1px solid var(--sp-surface-2);
}
/* Hover sticky-колонок — ТОЛЬКО непрозрачный фон (раунд 2): translucent
   --sp-row-hover на sticky «Месяце» просвечивает прокрученные под ним дни
   («месяц сливается с днём», баг приёмки 2026-09-11). Solid-эквивалент —
   color-mix c --sp-ink: light 3.5% ≈ rgba(22,26,34,.035), dark 6%. */
td.pnl-days-monthcell:hover,
.pnl-days-ttable tbody tr:hover td.pnl-days-monthcell {
  background: color-mix(in srgb, var(--sp-ink) var(--sp-row-hover-mix), var(--sp-surface));
}
.pnl-days-ttable tbody tr:hover td:not(.pnl-days-monthcell) { background: var(--sp-row-hover); }
/* Имя статьи — слева (раунд 2): text-align:right правила tbody th/td —
   для цифр дней, а статья выравнивается как в главной таблице ОПиУ. */
.pnl-days-ttable tbody th.pnl-days-metriccol { text-align: left; }
/* Полоса секции — как .pnl-days-band режима «Графики» (тинт tone).
   Название группы — В ПЕРВОМ столбце (раунд 5): раньше был один colspan-th
   с text-align:left, который перебивался .pnl-days-ttable tbody th
   (text-align:right, специфичность выше) — группа уезжала к последнему дню.
   Теперь title — отдельная sticky-ячейка 190px (= колонке «Метрика»),
   добор th до конца строки несёт только тинт. */
.pnl-days-ttable th.pnl-days-band-cell {
  position: sticky; left: 0; z-index: 2;
  width: 190px; min-width: 190px; max-width: 190px;
  text-align: left; padding: 0 8px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pnl-days-band-row th {
  height: 26px; font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.07em; color: var(--sp-ink-2);
  background: var(--sp-surface-2);
  border-bottom: 1px solid var(--sp-border);
}
.pnl-days-band-row[data-tone="income"] th  { background: color-mix(in srgb, var(--sp-delta-up) 7%, var(--sp-surface)); }
.pnl-days-band-row[data-tone="expense"] th { background: color-mix(in srgb, var(--sp-ink) 4%, var(--sp-surface)); }
.pnl-days-band-row[data-tone="summary"] th { background: var(--sp-brand-tint); }

/* ── Мини-графики (спарклайны) ───────────────────────────────────────────── */
.sp-spark { display: inline-block; vertical-align: middle; line-height: 0; }
.sp-spark svg { display: block; overflow: visible; }

/* ── Flagged-строки (РНП: quality_flag) ──────────────────────────────────── */
.flagged { border-left: 3px solid var(--sp-warn); background-color: var(--sp-warn-bg); }

/* ── Статус-бейдж кабинета: [data-status=active|error|stale|running|first_sync|throttled|needs_key|warn|unknown]
   warn — только сводный бейдж «Состояния данных» (states.html, 23:35):
   частичный сбой групп — «внимание», кабинет жив. ── */
.badge-status {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 11px; border-radius: 9999px; border: 1px solid var(--sp-border);
  font-size: 12px; line-height: 1.5; white-space: nowrap;
  color: var(--sp-ink-2); background: var(--sp-surface-2);
}
.badge-status::before { content: ''; width: 8px; height: 8px; border-radius: 50%; background: var(--sp-ink-3); }
.badge-status-at { opacity: 0.75; font-weight: 400; }
.badge-status[data-status="active"]    { color: var(--sp-profit); border-color: var(--sp-profit-border); background: var(--sp-profit-bg); }
.badge-status[data-status="active"]::before    { background: #10b981; }
.badge-status[data-status="error"]      { color: var(--sp-loss); border-color: var(--sp-loss-border); background: var(--sp-loss-bg); }
.badge-status[data-status="error"]::before      { background: #ef4444; }
/* «Данные устарели» (П4 §9.1 стр.4) — warn-тон, мягче ошибки */
.badge-status[data-status="stale"]      { color: var(--sp-warn); border-color: var(--sp-warn-border); background: var(--sp-warn-bg); }
.badge-status[data-status="stale"]::before      { background: #f59e0b; }
/* Идёт синхронизация / первая загрузка — брендовый живой тон */
.badge-status[data-status="running"]    { color: var(--sp-brand-strong); border-color: var(--sp-border); background: var(--sp-surface-2); }
.badge-status[data-status="running"]::before    { background: var(--sp-brand-strong); }
.badge-status[data-status="first_sync"] { color: var(--sp-brand-strong); border-color: var(--sp-border); background: var(--sp-surface-2); }
.badge-status[data-status="first_sync"]::before { background: var(--sp-brand-strong); }
.badge-status[data-status="throttled"] { color: var(--sp-warn); border-color: var(--sp-warn-border); background: var(--sp-warn-bg); }
.badge-status[data-status="throttled"]::before { background: #f59e0b; }
/* needs_key («Требует новый ключ», №18): loss-тон — без нового ключа синк не возобновится */
.badge-status[data-status="needs_key"] { color: var(--sp-loss); border-color: var(--sp-loss-border); background: var(--sp-loss-bg); }
.badge-status[data-status="needs_key"]::before { background: #ef4444; }
/* Частичный сбой групп — сводка «Состояния данных» (23:35, 27-sync §4.9):
   жёлтый «внимание» (кабинет жив, часть групп не грузится); случай «не
   работает ни одна группа» уносит тон error. */
.badge-status[data-status="warn"] { color: var(--sp-warn); border-color: var(--sp-warn-border); background: var(--sp-warn-bg); }
.badge-status[data-status="warn"]::before { background: #f59e0b; }
.badge-status[data-status="unknown"]   { color: var(--sp-ink-3); }

/* ── «Живой» бейдж шапки (решение владельца 2026-09-26, направление B
   «Живой сигнал», волна impeccable animate+delight+overdrive): по
   умолчанию видна только цветная точка-капсула; ховер/фокус раскрывают
   подпись. КЛИК по носителю (tabindex) защёлкивает раскрытие через
   :focus-within до клика в другом месте/увода фокуса — осознанный
   механизм-пин (решение владельца 2026-09-26 на сводном бейдже
   «Состояния данных»: «кликнул — зафиксировалось, кликнул рядом —
   пропало»), НЕ баг — не «чинить». Геометрия — grid 0fr→1fr с одиночным clip-потомком (fold):
   текст не прыгает, width из JS не меряется; в старых движках без
   анимируемых fr-треков раскрытие мгновенное (progressive enhancement).
   Форма — идеальный круг 22px (правка владельца «пропорционально
   круглый»: фикс-высота + паддинг 6px), вход — плавный ease-in-out
   320мс («поплавнее»), выход короче — 180мс. Модификатор ставит
   ТОЛЬКО шапка (layout.html): пилюли кабинетов /settings остаются
   полными капсулами. ──────────────────── */
.badge-status-dot { height: 22px; padding: 0 6px; gap: 0; cursor: default;
                    /* Круг (решение владельца 2026-09-26 «пропорционально
                       круглый»): высота ФИКСИРОВАНА, иначе строчный бокс
                       fold'а делает капсулу овальной (было 18×26);
                       ширина = паддинг 6×2 + точка 8 + кромка 2 = 22px.
                       Ширина всегда content-driven (паддинг + grid) —
                       оба состояния интерполируются без прыжка. */
                    transition: padding .18s ease, gap .18s ease; }
.badge-status-dot .badge-status-body { display: grid; grid-template-columns: 0fr;
                                       transition: grid-template-columns .18s ease; }
.badge-status-dot .badge-status-fold { min-width: 0; overflow: hidden; }
.badge-status-dot:hover,
.badge-status-dot:focus-visible,
.badge-status-dot:focus-within { padding: 0 11px; gap: 6px;
                    /* Плавный вход (решение владельца 2026-09-26 «появлялся
                       поплавнее»): ease-in-out 320мс — мягкий старт вместо
                       щелчка прежнего ease-out 220мс; выход короче
                       (180мс), но тоже без рывка. */
                    transition: padding .32s cubic-bezier(.65, 0, .35, 1), gap .32s cubic-bezier(.65, 0, .35, 1); }
.badge-status-dot:hover .badge-status-body,
.badge-status-dot:focus-visible .badge-status-body,
.badge-status-dot:focus-within .badge-status-body { grid-template-columns: 1fr;
                    transition: grid-template-columns .32s cubic-bezier(.65, 0, .35, 1); }
/* Сигналы точки — из словаря системы: «дыхание» критичной KPI-плитки
   (sp-breathe) у ошибки и просроченного ключа; радар-кольцо тенью самой
   точки (currentColor, color-mix) у идущей синхронизации — кольцо всегда
   центрировано на точке, раскрытие капсулы его не смещает. */
.badge-status-dot[data-status="error"]::before,
.badge-status-dot[data-status="needs_key"]::before { animation: sp-breathe 2.4s ease-in-out infinite; }
.badge-status-dot[data-status="running"]::before,
.badge-status-dot[data-status="first_sync"]::before { animation: badge-radar 2s ease-out infinite; }
@keyframes badge-radar {
  0%        { box-shadow: 0 0 0 0 color-mix(in srgb, currentColor 45%, transparent); }
  75%, 100% { box-shadow: 0 0 0 7px transparent; }
}
/* Разовая вспышка при СМЕНЕ статуса (live-патч app.js вешает .badge-flash
   только на реальное изменение data-status): микроподъём всей капсулы от
   точки, transform — раскладку не двигает. */
.badge-status-dot.badge-flash { animation: badge-bloom .5s cubic-bezier(.16, 1, .3, 1); transform-origin: left center; }
@keyframes badge-bloom { 0% { transform: scale(1); } 35% { transform: scale(1.045); } 100% { transform: scale(1); } }
/* Точка-СЫЛКА (переиспользование dot-механики интерактивным носителем;
   2026-09-27: бейдж-переключатель «Без себестоимости: N из M» на
   «Себестоимости и маркировке» — <a href>): клик ведёт на фильтр,
   курсор pointer вместо дефолтного cursor:default точки. */
.badge-status-dot[href] { cursor: pointer; }

/* Сводный бейдж «Состояния данных» (badge-status-sum, states.html,
   решение владельца 2026-09-26): механика раскрытия шапочного
   .badge-status-dot (точка → капсула по ховеру/фокусу) БЕЗ «живых»
   циклов — «не пульсирует»: модификатор глушит дыхание/радар точки при
   любом data-status. Специфичность равна правилам циклов выше — решает
   порядок файла (как в reduced-motion-блоке ниже). Носитель не несёт
   [data-cabinet-status]: renderBadge (app.js) не должен переписывать
   сводку кадром шапки. */
.badge-status.badge-status-sum::before { animation: none; }
/* Сводный бейдж «Состояния данных» стоит в ЛЕВОЙ группе тулбара рядом
   со счётчиком (решение владельца 2026-09-29 — «по аналогии со вкладкой
   Себестоимость и маркировка»; supersede «прижат к правому краю,
   row-reverse» 2026-09-26). Обычный порядок row, точка слева: левый
   край группы зафиксирован контейнером, капсула растёт ВПРАВО — точка
   неподвижна при раскрытии, фликер «наведение/схлопывание» (инцидент
   2026-09-26, он же требовал row-reverse на правом краю) невозможен.
   Правило оставлено явным, чтобы возврат row-reverse не случился по
   памяти о правом крае. */
.badge-status.badge-status-sum { flex-direction: row; }

/* ── Единый бейдж пробелов данных (gaps_badge, layout.html; запрос
   владельца 2026-09-26 — унификация пробелов между вкладками): язык
   шапочного бейджа (раскрытие капсулы grid 0fr→1fr) в КЛИКАБЕЛЬНОЙ
   роли — вместо точки-кружка иконка ⚠, курсор-указатель (аффорданс
   клика), клик открывает поповер .sp-gaps-pop на общем слое data-menu
   (ui.js). Бейдж — статичный вердикт: пульсов НЕТ ни в каком тоне —
   пульсация остаётся привилегией живых сигналов шапки. ── */
.badge-status-gap { cursor: pointer; }
.badge-status-gap::before { content: none; }
.badge-status-gap .sp-gaps-ico { width: 13px; height: 13px; flex: none; }
.badge-status-gap, .badge-status-gap::before { animation: none; }

/* Поповер пробелов: компактная таблица-справка, единая для Финотчёта /
   ОПиУ / Мониторинга / досье товара — один шрифт и одна сетка вместо
   прежних свёрток на всю ширину карточки (разный шрифт и размер были
   сутью жалобы владельца). */
.sp-gaps-pop { width: 40rem; max-width: calc(100vw - 1.5rem); padding: 12px 14px; overflow-x: auto; }
.sp-gaps-head { font-size: 13px; font-weight: 600; color: var(--sp-ink); }
.sp-gaps-sub { font-size: 12px; color: var(--sp-ink-3); margin: 2px 0 8px; }
.sp-gaps-section { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--sp-ink-3); margin: 10px 0 4px; }
.sp-gaps-table { width: 100%; min-width: 560px; border-collapse: collapse; font-size: 12px; }
.sp-gaps-table th { text-align: left; font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;
                    color: var(--sp-ink-3); padding: 4px 10px 4px 0; white-space: nowrap; }
.sp-gaps-table td { padding: 6px 10px 6px 0; border-top: 1px solid var(--sp-border); vertical-align: top; color: var(--sp-ink-2); }
.sp-gaps-table td:first-child, .sp-gaps-table th:first-child { padding-left: 0; }
.sp-gaps-sev { white-space: nowrap; font-weight: 500; color: var(--sp-ink); }
.sp-gaps-sev-info { opacity: 0.7; }

/* ── Toast (разметку строит ui.js) ───────────────────────────────────────── */
@keyframes toast-in  { from { transform: translateX(120%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes toast-out { from { transform: translateX(0); opacity: 1; } to { transform: translateX(120%); opacity: 0; } }
@keyframes toast-progress { from { transform: scaleX(1); } to { transform: scaleX(0); } }
.toast-item { animation: toast-in 0.34s cubic-bezier(0.21, 1.02, 0.73, 1) both; will-change: transform, opacity; }
.toast-item.leaving { animation: toast-out 0.28s ease-in both; }
.toast-progress { transform-origin: left center; animation-name: toast-progress; animation-timing-function: linear; animation-fill-mode: forwards; }
.toast-item:hover .toast-progress { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .toast-item, .toast-item.leaving { animation-duration: 0.01ms !important; }
  .toast-progress { display: none; }
  .sync-spin { animation-duration: 0.01ms !important; }
  .sp-skeleton::after { animation: none; }
  .sp-skel-chart-svg { animation: none; }
  .sp-stat[data-state="critical"] .sp-stat-flag { animation: none; }
  .sp-card-link:hover { transform: none; }
  /* «Живой» бейдж шапки: раскрытие мгновенное (состояние читаемо),
     циклы (дыхание/радар) и вспышка смены — выключены */
  .badge-status-dot, .badge-status-dot .badge-status-body { transition: none; }
  .badge-status-dot[data-status="error"]::before,
  .badge-status-dot[data-status="needs_key"]::before,
  .badge-status-dot[data-status="running"]::before,
  .badge-status-dot[data-status="first_sync"]::before,
  .badge-status-dot.badge-flash { animation: none; }
  #global-tip { transition: none; }
}

/* ── Confirm-диалог (разметку строит sp-confirm.js; замена нативного confirm) ──
   Авторский момент — вход карточки: подъём 8px + scale 0.97→1 на expo-out,
   подложка просто проявляется. Уход — короткий, вдвое быстрее входа. */
.sp-confirm { display: flex; }
.sp-confirm[hidden] { display: none; }
.sp-confirm-backdrop { background: rgba(15,18,26,0.45); animation: sp-fade-in 0.18s ease-out both; }
html.dark .sp-confirm-backdrop { background: rgba(0,0,0,0.5); }
.sp-confirm-card {
  background: var(--sp-surface); border: 1px solid var(--sp-border);
  border-radius: 14px; box-shadow: var(--sp-shadow-menu);
  animation: sp-confirm-in 0.22s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.sp-confirm.leaving .sp-confirm-backdrop { animation: sp-fade-out 0.12s ease-in both; }
.sp-confirm.leaving .sp-confirm-card { animation: sp-confirm-out 0.12s ease-in both; }
@keyframes sp-fade-in   { from { opacity: 0; } }
@keyframes sp-fade-out  { to { opacity: 0; } }
@keyframes sp-confirm-in  { from { opacity: 0; transform: translateY(8px) scale(0.97); } }
@keyframes sp-confirm-out { to   { opacity: 0; transform: translateY(4px) scale(0.98); } }
.sp-confirm-icon { width: 2.5rem; height: 2.5rem; border-radius: 50%; flex-shrink: 0;
                   display: flex; align-items: center; justify-content: center; }
.sp-confirm-icon svg { width: 1.25rem; height: 1.25rem; }
.sp-confirm-icon-loss { background: var(--sp-loss-bg); color: var(--sp-loss); }
.sp-confirm-icon-warn { background: var(--sp-warn-bg); color: var(--sp-warn); }
.sp-confirm-title { font-size: 0.9375rem; font-weight: 600; line-height: 1.35; color: var(--sp-ink); }
.sp-confirm-detail { margin-top: 0.375rem; font-size: 0.875rem; line-height: 1.5;
                     color: var(--sp-ink-2); overflow-wrap: break-word; }
@media (prefers-reduced-motion: reduce) {
  .sp-confirm-backdrop, .sp-confirm-card,
  .sp-confirm.leaving .sp-confirm-backdrop, .sp-confirm.leaving .sp-confirm-card {
    animation-duration: 0.01ms !important;
  }
}

/* ── Tooltip (.tip с вложенным .tip-text) ────────────────────────────────── */
.tip { display: inline-flex; align-items: center; justify-content: center;
       width: 16px; height: 16px; margin-left: 4px; border-radius: 50%;
       background: var(--sp-surface-3); color: var(--sp-ink-2); font-size: 11px; cursor: help; vertical-align: middle; }
.tip-text { display: none; }
/* «?»-курсор — только у справки: иконка «Справка» в шапке и кружки-подсказки
   .tip (они сами нарисованы вопросом). Остальным data-tip-элементам
   (действия: тема/настройки/уведомления, бейджи) курсор не меняем —
   тултип показывается, указатель остаётся обычным. */
.sp-icon-btn[href^="/help"] { cursor: help; }
#global-tip { visibility: hidden; opacity: 0; transform: translateY(3px);
              transition: opacity 156ms ease, transform 156ms cubic-bezier(.16, 1, .3, 1);
              position: fixed; top: 0; left: 0; z-index: 100;
              /* z 100: выше дневной шторки ОПиУ (.pnl-side, z 70) и
                 rnp-geo-pop (90) — тултип по канону поверх всего */
              max-width: 320px; width: max-content; padding: 9px 12px; border-radius: 9px;
              background: var(--sp-tooltip-bg); color: var(--sp-tooltip-ink);
              font-size: 12px; line-height: 1.5; font-weight: normal;
              box-shadow: var(--sp-shadow-menu); pointer-events: none; white-space: pre-line; }
#global-tip.sp-tip-open { visibility: visible; opacity: 1; transform: none; }
/* Универсальная база форматирования (волна 2026-09-26 «живой бейдж +
   база тултипов», решение владельца): заголовок — data-tip-title носителя;
   строки — текст с \n рендерится построчно (ui.js renderTipContent).
   Контракт для точечных правок контента: одна сущность = одна строка,
   пустые строки схлопываются, « · »-простыни внутри строки не разводятся. */
#global-tip .sp-tip-title { display: block; font-weight: 600; margin-bottom: 3px; }
#global-tip .sp-tip-line { display: block; }

/* ── Индикатор синхронизации (шапка, разметку ведёт layout.html) ─────────── */
.sync-pill { display: inline-flex; align-items: center; gap: 6px; padding: 3px 11px;
             border-radius: 9999px; font-size: 12px; font-weight: 500; max-width: 360px;
             color: var(--sp-info); background: var(--sp-info-bg); border: 1px solid var(--sp-info-border); }
.sync-pill[hidden] { display: none; }
.sync-pill [data-sync-indicator-text] { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sync-spin { width: 13px; height: 13px; flex-shrink: 0; animation: sync-rotate 0.9s linear infinite; }
@keyframes sync-rotate { to { transform: rotate(360deg); } }
.sync-pill[data-state="done"]  { color: var(--sp-profit); background: var(--sp-profit-bg); border-color: var(--sp-profit-border); }
.sync-pill[data-state="done"] .sync-spin  { animation: none; }
.sync-pill[data-state="error"] { color: var(--sp-loss); background: var(--sp-loss-bg); border-color: var(--sp-loss-border); }
/* error НЕ останавливает вращение (решение владельца 2026-09-26: «висит
   на одном месте» читалось как зависание): красный тон = «есть ошибка»,
   вращение = «работа продолжается» — остальные задачи прогона живые. */
.sync-pill[data-state="error"] .sync-spin { animation: sync-rotate 0.9s linear infinite; }
/* degraded — состояние ТРАНСПОРТА live_updates (П4 §9.2): нейтрально,
   не влияет на статусы данных/синка; fallback-поллинг уже работает */
.sync-pill[data-state="degraded"] { color: var(--sp-ink-2); background: var(--sp-surface-2); border-color: var(--sp-border); }
.sync-pill[data-state="degraded"] .sync-spin { animation: none; }
/* Свёрнутая синх-пилюля шапки (решение владельца 2026-09-28): по
   умолчанию виден только синий спиннер-кружок, ховер/фокус раскрывают
   капсулу с подписью — та же механика grid 0fr→1fr, что у
   .badge-status-dot (layout.html, «живой бейдж»): fold = grid-контейнер,
   текстовый span — clip-потомок с min-width:0 (overflow/ellipsis уже в
   базовой .sync-pill-строке выше). Спиннер не прячется никогда —
   вращение и есть свёрнутый сигнал. */
.sync-pill-dot { height: 22px; padding: 0 4px; gap: 0;
                 transition: padding .18s ease, gap .18s ease; }
.sync-pill-dot .sync-pill-fold { display: grid; grid-template-columns: 0fr; min-width: 0;
                                 transition: grid-template-columns .18s ease; }
.sync-pill-dot .sync-pill-fold > [data-sync-indicator-text] { min-width: 0; }
.sync-pill-dot:hover,
.sync-pill-dot:focus-visible { padding: 0 11px; gap: 6px;
                 transition: padding .32s cubic-bezier(.65, 0, .35, 1), gap .32s cubic-bezier(.65, 0, .35, 1); }
.sync-pill-dot:hover .sync-pill-fold,
.sync-pill-dot:focus-visible .sync-pill-fold { grid-template-columns: 1fr;
                 transition: grid-template-columns .32s cubic-bezier(.65, 0, .35, 1); }

/* Строчный live-индикатор «Данных» (states-live.js, 23 §3): этап идущей
   задачи ПОВЕРХ ячейки статуса; предыдущий итог строки (data-row-done)
   НЕ прячется, а приглушается (states-dim — решение владельца 2026-09-26:
   «всё обнуляется в загрузку» читалось как потеря статуса) — по завершении
   его сменяет свежий «ок»/«ошибка» свапом карточки. */
.states-live { display: inline-flex; align-items: center; gap: 6px;
               color: var(--sp-brand-strong); font-size: 0.8125rem; }
.states-live[hidden] { display: none; }
.states-live .sync-spin { width: 12px; height: 12px; }
tr[data-live] td { background: var(--sp-surface-2); }
[data-row-done].states-dim { opacity: 0.45; }
@media (prefers-reduced-motion: reduce) {
  .states-live .sync-spin { animation-duration: 0.01ms !important; }
}

/* ── Пилюля «Джем» (шапка: активная подписка WB выбранного кабинета;
   статус — jam_pill.go, tooltip через data-tip/#global-tip) ─────────────── */
.sp-jam-pill { display: inline-flex; align-items: center; gap: 5px; padding: 3px 11px;
               border-radius: 9999px; font-size: 12px; font-weight: 600; color: #fff;
               background: linear-gradient(135deg, #d946ef 0%, #8b5cf6 100%);
               white-space: nowrap; cursor: default; }
.sp-jam-pill svg { width: 12px; height: 12px; flex-shrink: 0; }

/* ── Модалка: scroll-lock страницы при открытии ──────────────────────────── */
body.modal-open { overflow: hidden; }

/* Открытая модалка — flex-оверлей: карточка строго по центру экрана
   (items-center/justify-center в разметке работают только при flex;
   кейс владельца 2026-08-25: модалки прижимались влево-вверх). */
#modal:not(.hidden) { display: flex; }

/* ── Горизонтальные скролл-меню без полосы прокрутки ─────────────────────── */
.scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; }
.scrollbar-hide::-webkit-scrollbar { display: none; }

/* ── Финотчёт/Мониторинг: единый full-bleed каркас таблиц ────────────────── */
/* Панель на всю ширину экрана: выходим из .sp-shell (90%); в отличие от
   сырого 100vw (выезжает под скроллбар) оставляем 16px отступа от краёв
   вьюпорта — рецепт Мониторинга, распространён на обе таблицы
   (унификация 2026-09-09). body{overflow-x:clip} гасит выступ. */
.fin-bleed { width: auto; margin-inline: calc((100% - 100vw) / 2 + 16px); }
.fin-panel {
  background: var(--sp-surface);
  /* Единая карточка таблицы (запрос владельца 2026-09-26: «в финочете
     должна быть такая же таблица, как в мониторинге» — скругление 14px,
     как у .sp-card Мониторинга/ОПиУ; раньше Финотчёт был квадратной
     полосой с границами только сверху/снизу). */
  border: 1px solid var(--sp-border);
  border-radius: 14px;
  box-shadow: var(--sp-shadow-1);
  /* Внутренний inset: контент не прилегает к краям экрана (фото/артикулы
     в frozen-колонке иначе «съедаются»), скролл-контейнер таблицы —
     внутри паддинга, горизонтальный скролл не ломается. */
  padding-inline: 14px;
}

/* Тулбар: итоги периода слева, пресеты и «Настройки таблицы» справа
   (6px + 14px панели = 20px до контента) */
.fin-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 8px 20px; padding: 9px 6px;
  border-bottom: 1px solid var(--sp-border);
}
/* Полоса фильтров над таблицей (Финотчёт — поиск SKU, Мониторинг —
   та же рецептура): компактные контролы (4px по вертикали, 12.5px
   шрифт — канон шапки таблиц 2026-09-09), один ряд, ровный инсет
   6px + 14px панели = 20px. */
.fin-filterrow {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  padding: 7px 6px; border-bottom: 1px solid var(--sp-border);
}
.fin-filterrow .sp-input, .fin-filterrow .sp-select {
  padding-top: 4px; padding-bottom: 4px; font-size: 12.5px; border-radius: 8px;
}
.fin-filterrow .sp-select {
  padding-right: 1.7rem; background-position: right 0.45rem center; background-size: 0.95rem;
}
.fin-filterrow .sp-table-search .sp-input { padding-left: 31px; width: 15rem; max-width: 60vw; }
.fin-totals { display: flex; align-items: baseline; flex-wrap: wrap; gap: 3px 22px; }
/* Статусные капсулы (⚠ «Пробелы данных» + «Сверка с ОПиУ») — плотная
   группа: у капсул нет текстовой базовой линии, а 22px-ритм полосы
   итогов между ними читался как разрыв (замечание владельца
   2026-09-27) — внутренний зазор 8px. По высоте строки группа
   центрируется (align-self), как бывшие прямые дети с тем же правилом:
   baseline-выравнивание строки итогов сажало ⚠ и пилюлю ниже текста
   (замер владельца 2026-09-26). */
.fin-total-badges { display: inline-flex; align-items: center; gap: 8px; align-self: center; }
.fin-total { display: inline-flex; align-items: baseline; gap: 7px; white-space: nowrap; }
.fin-total-label {
  font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--sp-ink-3);
}
.fin-total b { font-size: 13.5px; font-weight: 700; color: var(--sp-ink); font-variant-numeric: tabular-nums; }
/* Тихая под-строка итога (разрез FBS/FBW выручки, 2026-09-23) */
.fin-total-sub { font-size: 11px; font-weight: 500; color: var(--sp-ink-3); font-variant-numeric: tabular-nums; }

/* Ячейки и строки: плотная «газета данных» */
.fin-cell { font-size: 12.5px; line-height: 1.3; font-variant-numeric: tabular-nums; }
/* Доля от выручки — тихий элемент cstack-sub (типографику и цвет даёт
   .cstack-sub); прячется вместе с дельтами при включённой тепловой карте. */
/* Дельта-динамика (стрелки/проценты): на шаг меньше основных сумм,
   пастельные тона (--sp-delta-up/down) — показатели динамики не спорят
   с деньгами (запрос владельца 2026-09-09). Цвет ставит finance.js. */
.fin-delta { font-size: 9.5px; font-weight: 500; font-variant-numeric: tabular-nums; }
/* SKU-ячейка Tabulator-таблиц (Финотчет + Мониторинг — один скин
   .fin-panel) на пилюлях, канон «Себестоимости и маркировки» (sku_cell):
   строка-якорь — артикул (ССЫЛКА на досье, a.sp-pill) + nmID пилюлей;
   тексты (предмет/название/бренд) — вторая строка с «·», клик копирует.
   Пилюли на шаг компактнее канона 12px: строки таблиц плотнее реестров,
   высота строки не растёт (запрос владельца 2026-09-09). */
.sku-pill-line, .sku-pill-meta {
  display: flex; align-items: center; min-width: 0;
  overflow: hidden; white-space: nowrap;
  /* 10.5/1.3: контейнеры наследуют у ячейки Tabulator 14px/21px —
     разделитель «·» раздувал строку меты до 21px и выталкивал
     трёхстрочную ячейку за высоту строки (замер 2026-09-09) */
  font-size: 10.5px; line-height: 1.3;
}
.sku-pill-line { gap: 5px; }
.sku-pill-meta .sp-cell-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.fin-panel .sp-pill { font-size: 10.5px; line-height: 1.25; padding: 0 7px; }
.fin-panel .sp-pill-name { font-size: 11px; line-height: 1.3; max-width: 28ch; }
/* line-height 1.3 обязателен: у кнопок нормальный (~1.5 у Inter) раздувает
   строку текстов на ~2px и выталкивает трёхстрочную ячейку за высоту строки */
.fin-panel .sp-cell-text { font-size: 10.5px; line-height: 1.3; }
.fin-flag-dot {
  display: inline-block; width: 6px; height: 6px; border-radius: 9999px;
  background: var(--sp-warn); margin-right: 6px; vertical-align: 1px;
}
/* Точка аномалий строки Финотчёта — КНОПКА (хвост GAP-04/2, канон
   04 §11: у popover'а причин есть «Открыть операции»): клик открывает
   drawer исключённых операций SKU; сброс кнопочных дефолтов спэна. */
button.fin-flag-dot { padding: 0; border: none; cursor: pointer; }
button.fin-flag-dot:hover { transform: scale(1.45); }
/* Легенда живёт в футере таблицы одной строкой */
.fin-legend-inline { font-size: 11px; color: var(--sp-ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 1500px) { .fin-legend-inline { display: none; } }


/* ── Тонированные группы шапки (бриф владельца 2026-09-26 «чуть-чуть
   красок в рамках разумного»): палитра --gt по data-tone — Деньги/
   прибыль зелёный, Остатки сине-серый, Реклама янтарная, Воронка
   нейтральный подъём. Писатель атрибута — SSR-шапка матрицы
   (rnp_matrix_cells.go rnpGroupTone, фаза C «Один движок таблиц»);
   Tabulator-потребители (.tabulator-col-group) снесены вместе с
   paintGroupTones, палитру берёт #rnp-matrix th.fin-group-th (ниже). */
[data-tone="money"] { --gt: var(--sp-profit); }
[data-tone="stock"] { --gt: var(--sp-info); }
[data-tone="ads"] { --gt: var(--sp-warn); }
[data-tone="funnel"] { --gt: var(--sp-ink-2); }

/* Тепловая карта: ячейка несёт --hp (доля от лидера, 0..100) и --ht
   (токен цвета); насыщенность = hp × --heat-k контейнера. Смена режима —
   одно свойство на #fin-table-wrap, мгновенно и без JS-обходов. */
#fin-table-wrap { --heat-k: 0; }

/* Футер: счётчик + легенда + пагинация-капсулы (6px + 14px панели = 20px) */
.fin-foot {
  display: flex; align-items: center; gap: 14px;
  padding: 6px 6px; border-top: 1px solid var(--sp-border); background: var(--sp-surface);
}

/* Полоса «Нулевой SKU» под таблицей: деньги, которые нельзя отнести к
   одному товару (нераспределённые услуги WB) — вне таблицы, видны, но
   не соревнуются с товарами за внимание (запрос владельца 2026-09-05). */
.fin-zero {
  display: flex; align-items: baseline; gap: 3px 16px;
  padding: 5px 6px; border-top: 1px solid var(--sp-border);
  background: var(--sp-surface-2);
  font-size: 11.5px; color: var(--sp-ink-3);
  white-space: nowrap; overflow-x: auto; scrollbar-width: thin;
}
.fin-zero-label { font-weight: 600; color: var(--sp-ink-2); flex-shrink: 0; }
.fin-zero-chip { display: inline-flex; align-items: baseline; gap: 5px; }
.fin-zero-chip b { font-weight: 600; color: var(--sp-ink-2); font-variant-numeric: tabular-nums; }

/* Кнопка-значение drill-down ячейки Финотчёта (drawer «статья →
   операции», GAP-04/23): наследует типографику ячейки; аффорданс —
   пунктирное подчёркивание на hover, без визуального шума таблицы. */
.fin-ops-btn {
  font: inherit; color: inherit; background: none; border: 0; padding: 0;
  cursor: pointer; font-variant-numeric: inherit; text-align: inherit;
}
.fin-ops-btn:hover { text-decoration: underline; text-decoration-style: dashed; text-underline-offset: 3px; }
.fin-ops-btn:focus-visible { outline: 2px solid var(--sp-primary); outline-offset: 1px; border-radius: 4px; }

/* DnD th-каркаса (sp-th-dnd) — перенесено из CSSOM-фолбэка, фаза
   харденинга 2026-09-27: классы-индикаторы — те же имена, что ставил
   sp-col-dnd (его Tabulator-вариант .tabulator-col.sp-coldnd-*
   демонтирован в фазе C «Один движок таблиц»);
   здесь — серверный каркас th[data-col-dnd] (сегодня #fin-table),
   JS только переключает классы. */
th.sp-coldnd-src { opacity: 0.45; cursor: grabbing; }
th.sp-coldnd-before { box-shadow: inset 3px 0 0 0 var(--sp-brand); }
th.sp-coldnd-after { box-shadow: inset -3px 0 0 0 var(--sp-brand); }

/* ── Финотчёт: СЕРВЕРНАЯ таблица #fin-table (каркас П6, волна «поиск
   SKU + чип „Выборка" P12»): заменяет Tabulator-кокпит. Двухъярусная
   липкая шапка (группы + колонки), замороженная SKU-колонка слева,
   тепловая карта на тех же CSS-переменных (--hp/--ht × --heat-k). */
#fin-table { width: max-content; min-width: 100%; border-collapse: separate; border-spacing: 0; }
#fin-table th, #fin-table td { border-bottom: 1px solid var(--sp-border); }
/* Шапка — ТОТ ЖЕ «нейтральный гребень», что у матрицы Мониторинга
   (запрос владельца 2026-09-26 «таблица Финотчёта = таблица
   Мониторинга»): фон surface-2, листья ink-2 по центру над числами;
   отсортированная колонка — акцент бренда (см. ниже). */
#fin-table thead th {
  position: sticky; z-index: 2; background: var(--sp-surface-2);
  font-size: 11px; font-weight: 600; color: var(--sp-ink-2);
  padding: 4px 10px; white-space: nowrap; text-align: center;
  transition: background-color .12s ease;
}
#fin-table thead tr:last-child th { border-bottom: 1px solid var(--sp-border-strong); }
/* Ховер заголовка (бриф 2026-09-26): лёгкий подъём над гребнем. */
#fin-table thead th:hover { background: color-mix(in srgb, var(--sp-ink) 4%, var(--sp-surface-2)); }
/* Курсоры шапки (бриф владельца 2026-09-28): группы и заголовки колонок
   перетаскиваются между собой (sp-th-dnd) — курсор grab как аффорданс;
   у листа остаётся и сортировка по клику (тихий ↕ ниже). */
#fin-table thead th[data-col],
#fin-table thead th.fin-group-th { cursor: grab; }
/* Подсветка родительской группы при наведении на заголовок её колонки
   (класс вешает bindColHover finance.js) — та же слабая заливка, что у
   собственного ховера; селектор с двумя классами перебивает тонировку
   .fin-group-th[data-group]. */
#fin-table thead th.fin-group-th.fin-group-hover {
  background: color-mix(in srgb, var(--sp-ink) 4%, var(--sp-surface-2));
}
/* Группа (верхний ярус): чернильный капс, усиленный разделитель между
   смысловыми блоками + тонированная плашка с верхней кромкой цвета
   группы (та же семантика, что у матрицы Мониторинга). */
#fin-table th.fin-group-th {
  text-align: center; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--sp-ink); font-weight: 700;
  border-right: 1px solid var(--sp-border-strong);
}
#fin-table th.fin-group-th[data-group] {
  background: color-mix(in srgb, var(--gt, transparent) 9%, var(--sp-surface-2));
  box-shadow: inset 0 3px 0 0 color-mix(in srgb, var(--gt, transparent) 75%, transparent);
  /* Боковые кромки группы — в цвете группы (бриф 2026-09-26 №5:
     «продлите линии по краям»); без тона — обычный усиленный разрез. */
  border-left: 1px solid color-mix(in srgb, var(--gt, transparent) 35%, var(--sp-border-strong));
  border-right: 1px solid color-mix(in srgb, var(--gt, transparent) 35%, var(--sp-border-strong));
}
#fin-table thead th.fin-group-th:hover {
  background: color-mix(in srgb, var(--sp-ink) 4%, var(--sp-surface-2));
}
/* Палитра групп: деньги и прибыль — зелёный, реклама — янтарная,
   склад — сине-серый; услуги/себестоимость/налог — нейтральный гребень. */
#fin-table th.fin-group-th[data-group="sales"] { --gt: var(--sp-profit); }
#fin-table th.fin-group-th[data-group="profit"] { --gt: var(--sp-profit); }
#fin-table th.fin-group-th[data-group="ads"] { --gt: var(--sp-warn); }
#fin-table th.fin-group-th[data-group="stock"] { --gt: var(--sp-info); }
/* Отсортированная колонка (бриф 2026-09-26): брендовая стрелка на едва
   заметной плашке, заголовок ярче неактивных. */
#fin-table thead th.sp-sorted-asc,
#fin-table thead th.sp-sorted-desc {
  color: var(--sp-ink);
  background: color-mix(in srgb, var(--sp-brand) 8%, var(--sp-surface-2));
}
/* Липкая шапка — ВНУТРИ скролл-контейнера #fin-table-wrap: обёртка
   обязана быть scroll-контейнером (горизонтальный скролл широких
   колонок), поэтому window-sticky на ней невозможен (любой предок с
   overflow:auto перехватывает якорь position:sticky — шапка «умирала»:
   стояла на месте и уезжала со страницей). Канон — внутренний
   viewport-скролл, как у таблиц tracking: max-height на обёртке,
   ярусы шапки якорятся к ней (top от 0, не от --sp-sticky-top —
   эту переменную на странице Финотчёта никто не считает). */
#fin-table-wrap { max-height: calc(100vh - 15rem); }
/* Компактность шапки (канон Мониторинга, план «Один движок таблиц» §3,
   мини-этап после фазы B): паддинги ярусов 4px, но ПЕРВЫЙ ярус прижат
   к ровно 30px — нижний ярус липнет top:30px, якорь обязан совпадать
   с фактической высотой яруса (box-sizing: border-box → ровно 30px
   с рамкой), иначе при прокрутке листьевые th уезжают под группы. */
#fin-table thead tr:first-child th { top: 0; height: 30px; }
#fin-table thead tr:nth-child(2) th { top: 30px; }
#fin-table td { border-right: 1px solid var(--sp-border); }
/* Разрез между смысловыми группами колонок в теле — усиленная линия
   (первый столбец каждой группы; бриф владельца 2026-09-26). */
#fin-table td.group-start { border-left: 1px solid var(--sp-border-strong); }
/* Ховер столбца при наведении на его заголовок (бриф 2026-09-26):
   бледная брендовая вуаль ПОВЕРХ фона ячейки. Слой — inset box-shadow,
   НЕ background-image: тень рисуется НАД фоном элемента, поэтому её не
   могут затереть background-ШОРТХЭНДЫ других правил на той же ячейке.
   Дефект (замечание владельца 2026-09-26): вуаль через background-image
   сбрасывалась правилом #fin-table td.fin-heat { background: color-mix }
   (ниже по файлу, та же специфичность, шортхэнд обнуляет background-image)
   и ховером строки tr:hover td — столбец подсвечивался только на ячейках
   БЕЗ теплового Style (нули и «шум» <4% от лидера, finHeatStyle), т.е.
   подсветка шла за данными, а не за геометрией колонки. Контент ячейки
   (значение/дельта-чип) остаётся поверх вуали; конфликтов box-shadow с
   другими правилами на td[data-col] нет (flagged-тень — только на
   td:first-child SKU-угла, он без data-col).
   Заливка = ховер строки (бриф владельца 2026-09-27): та же формула
   color-mix(ink × --sp-row-hover-mix, surface), что у tr:hover td, —
   прежняя брендовая 5% отличалась от подсветки строки. */
#fin-table td.col-hover {
  box-shadow: inset 0 0 0 9999px color-mix(in srgb, var(--sp-ink) var(--sp-row-hover-mix), var(--sp-surface));
}
/* SKU-колонка: заморожена слева (заголовок — выше обычных th). */
#fin-table th.fin-corner {
  left: 0; z-index: 3; text-align: left; min-width: 220px;
}
#fin-table td.fin-sku {
  position: sticky; left: 0; z-index: 1; background: var(--sp-surface);
  min-width: 220px; max-width: 360px;
  /* Компактность (канон Мониторинга): фото 32×38 + 2×3px = ровно 44px —
     ряд с фото не выше ряда без (общие 4px дали бы 46px и ломали сетку). */
  padding-top: 3px; padding-bottom: 3px;
}
#fin-table tbody tr:hover td { background: color-mix(in srgb, var(--sp-ink) var(--sp-row-hover-mix), var(--sp-surface)); }
/* Компактность строк = канон Мониторинга (план «Один движок таблиц» §3,
   открытый пункт «Компактность Финотчёта», мини-этап после фазы B,
   БЕЗ смены движка): строка 44px — Excel-компакт (исторический rowHeight: 44
   клиентской таблицы; live-вариант 2026-09-07: 52→44); вертикальные
   паддинги ячеек 4px — дефолт ячейки Tabulator (tabulator.min.css,
   .tabulator-cell { padding: 4px }). Высоту SSR-строки держит height
   на tr (в табличной раскладке это минимум), контент центрирует дефолт
   table-cell: строка Финотчёта той же плотности, что ряд матрицы
   Мониторинга. .cstack не перекалиброван: главная + производная
   (≈29px контента при fin-cell 12.5px) умещаются в 44px. */
#fin-table tbody tr { height: 44px; }
#fin-table td { padding: 4px 10px; white-space: nowrap; }
#fin-table td.num { text-align: right; font-variant-numeric: tabular-nums; }
#fin-table th[data-unit="rub"] { min-width: 96px; }
#fin-table th[data-unit]:not([data-unit="rub"]) { min-width: 78px; }
/* Тепловая карта — те же переменные, что в Tabulator-версии:
   насыщенность = --hp × --heat-k контейнера; режим off/soft/bold —
   одно свойство на #fin-table-wrap. */
#fin-table td.fin-heat {
  background: color-mix(in srgb, var(--ht) calc(var(--hp, 0) * var(--heat-k) * 1%), transparent);
}
/* При включённой карте дельты и % от выручки прячутся (04:96) —
   ячейка «тихая»; чипы дельт вставляет finance.js, прячет CSS. */
#fin-table-wrap.fin-heat-on .fin-share,
#fin-table-wrap.fin-heat-on .fin-delta { display: none; }
/* Аномалии: кромка строки + подсветка колонки отклонений. */
#fin-table tr.fin-flagged-row td:first-child { box-shadow: inset 2px 0 0 var(--sp-warn); }
#fin-table .flagged-col { background: color-mix(in srgb, var(--sp-warn) 7%, transparent); }
#fin-table tbody tr:hover .flagged-col { background: color-mix(in srgb, var(--sp-warn) 10%, transparent); }
/* Скрытая настройками колонка (fin:prefs → finance.js). */
#fin-table .sp-col-hidden { display: none; }
/* Футер-итог: sticky снизу, тихий фон; высота 30px — канон calcs-строки
   «Итог выборки» Мониторинга (.fin-panel .tabulator-calcs-holder
   .tabulator-row { min-height: 30px }, выше по файлу). */
#fin-table tfoot td {
  position: sticky; bottom: 0; background: var(--sp-surface-2); height: 30px;
  font-weight: 600; color: var(--sp-ink-2); border-top: 1px solid var(--sp-border-strong);
}

/* ── Мониторинг: СЕРВЕРНАЯ таблица #rnp-matrix (фаза C2 волны
   «Один движок таблиц»): матрица Мониторинга на каркасе #fin-table.
   Плотность = канон Мониторинга (строка 44px, паддинги 4px),
   двухъярусная липкая шапка (top: 0/30px), тепловая карта на тех же
   --hp/--ht × --heat-k обёртки, тон групп — глобальная палитра
   [data-tone] (--gt) выше по файлу. Добавляются ТОЛЬКО правила,
   которых у каркаса нет (id-scoped). */
#rnp-matrix { width: max-content; min-width: 100%; border-collapse: separate; border-spacing: 0; }
#rnp-matrix th, #rnp-matrix td { border-bottom: 1px solid var(--sp-border); }
/* Шапка — тот же «нейтральный гребень», что у #fin-table (канон
   2026-09-26 «таблица Финотчёта = таблица Мониторинга»). */
#rnp-matrix thead th {
  position: sticky; z-index: 2; background: var(--sp-surface-2);
  font-size: 11px; font-weight: 600; color: var(--sp-ink-2);
  padding: 4px 10px; white-space: nowrap; text-align: center;
  transition: background-color .12s ease;
}
#rnp-matrix thead tr:last-child th { border-bottom: 1px solid var(--sp-border-strong); }
#rnp-matrix thead th:hover { background: color-mix(in srgb, var(--sp-ink) 4%, var(--sp-surface-2)); }
/* Курсоры шапки и подсветка родительской группы — те же правила, что у
   #fin-table выше (бриф владельца 2026-09-28, универсальная таблица). */
#rnp-matrix thead th[data-col],
#rnp-matrix thead th.fin-group-th { cursor: grab; }
#rnp-matrix thead th.fin-group-th.fin-group-hover {
  background: color-mix(in srgb, var(--sp-ink) 4%, var(--sp-surface-2));
}
/* Группа (верхний ярус): капс + тонированная плашка с верхней кромкой
   цвета группы (палитра --gt — глобальные [data-tone] правила). */
#rnp-matrix th.fin-group-th {
  text-align: center; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--sp-ink); font-weight: 700;
  border-right: 1px solid var(--sp-border-strong);
}
#rnp-matrix th.fin-group-th[data-group] {
  background: color-mix(in srgb, var(--gt, transparent) 9%, var(--sp-surface-2));
  box-shadow: inset 0 3px 0 0 color-mix(in srgb, var(--gt, transparent) 75%, transparent);
  border-left: 1px solid color-mix(in srgb, var(--gt, transparent) 35%, var(--sp-border-strong));
  border-right: 1px solid color-mix(in srgb, var(--gt, transparent) 35%, var(--sp-border-strong));
}
/* Отсортированная колонка: брендовая плашка (та же семантика, что у
   #fin-table; стрелка ↑/↓ — общие правила .sp-table по sp-sorted-*). */
#rnp-matrix thead th.sp-sorted-asc,
#rnp-matrix thead th.sp-sorted-desc {
  color: var(--sp-ink);
  background: color-mix(in srgb, var(--sp-brand) 8%, var(--sp-surface-2));
}
#rnp-matrix thead th[data-key]:not(.sp-sorted-asc):not(.sp-sorted-desc):hover::after {
  content: '↕'; opacity: 0.45; color: var(--sp-ink-3);
}
/* Скролл-обёртка: вертикаль — внутри панели, шапка липнет к ней. */
#rnp-matrix-scroll { max-height: calc(100vh - 15rem); }
#rnp-matrix thead tr:first-child th { top: 0; height: 30px; }
#rnp-matrix thead tr:nth-child(2) th { top: 30px; }
#rnp-matrix td { border-right: 1px solid var(--sp-border); padding: 4px 10px; white-space: nowrap; }
#rnp-matrix td.num { text-align: right; font-variant-numeric: tabular-nums; }
#rnp-matrix th[data-unit="rub"] { min-width: 96px; }
#rnp-matrix th[data-unit]:not([data-unit="rub"]) { min-width: 78px; }
/* Усиленный разрез между смысловыми группами колонок в теле. */
#rnp-matrix td.group-start { border-left: 1px solid var(--sp-border-strong); }
#rnp-matrix tbody tr { height: 44px; }
#rnp-matrix tbody tr:hover td { background: color-mix(in srgb, var(--sp-ink) var(--sp-row-hover-mix), var(--sp-surface)); }
/* Ховер столбца при наведении на его заголовок (бриф владельца
   2026-09-27): колонка подсвечивается ТАК ЖЕ, как строка — та же
   формула заливки, тот же inset box-shadow-слой, что у #fin-table
   td.col-hover (слой над фоном не затирается теплом/фоном ячейки;
   SKU-угол и группы без data-col не участвуют; проводка —
   bindColHover в rnp-matrix.js, зеркально finance.js). */
#rnp-matrix td.col-hover {
  box-shadow: inset 0 0 0 9999px color-mix(in srgb, var(--sp-ink) var(--sp-row-hover-mix), var(--sp-surface));
}
/* SKU-угол: заморожен слева; фото 32×38 + 2×3px = ровно 44px (канон
   компактности Финотчёта, тот же бюджет). */
#rnp-matrix th.fin-corner { left: 0; z-index: 3; text-align: left; min-width: 300px; }
#rnp-matrix td.fin-sku {
  position: sticky; left: 0; z-index: 1; background: var(--sp-surface);
  padding-top: 3px; padding-bottom: 3px;
  box-shadow: 6px 0 8px -6px rgba(16, 24, 40, 0.22);
  /* Аффорданс детализации (бриф владельца 2026-09-28): клик по пустому
     месту SKU-ячейки открывает follow-строку с графиком; пилюли внутри
     держат свои курсоры (ссылки/копирование). */
  cursor: pointer;
}
html.dark #rnp-matrix td.fin-sku { box-shadow: 6px 0 8px -6px rgba(0, 0, 0, 0.5); }
/* Тепловая карта — те же переменные, что в Tabulator-версии;
   производные cstack-sub при включённой карте прячутся, Δ-чипы
   остаются ПОВЕРХ теплофона всегда (Q41, 06:51). */
#rnp-matrix td.fin-heat {
  background: color-mix(in srgb, var(--ht) calc(var(--hp, 0) * var(--heat-k) * 1%), transparent);
}
#rnp-matrix-wrap { --heat-k: 0; }
#rnp-matrix-wrap.fin-heat-on #rnp-matrix .cstack-sub { display: none; }
/* Убыточная строка — кромка слева (как flagged у Финотчёта): box-shadow
   ОБЪЕДИНЯЕТСЯ с правой отбивкой замороженного угла (td:first-child —
   та же .fin-sku), иначе loss-правило целиком перебивало её тень. */
#rnp-matrix tbody tr.rnp-loss-row td:first-child {
  box-shadow: inset 2px 0 0 var(--sp-loss), 6px 0 8px -6px rgba(16, 24, 40, 0.22);
}
html.dark #rnp-matrix tbody tr.rnp-loss-row td:first-child {
  box-shadow: inset 2px 0 0 var(--sp-loss), 6px 0 8px -6px rgba(0, 0, 0, 0.5);
}
/* Скрытая настройками колонка (rnp:prefs → rnp-matrix.js). */
#rnp-matrix .sp-col-hidden { display: none; }
/* Drawer строки: follow-тр с detail-контентом (rnp-matrix.js). */
#rnp-matrix tr.rnp-detail-row > td { padding: 0; border-right: 0; }
/* Сетка графиков шторки (T2 волны «Мониторинг: один вид», 2026-09-28):
   2 ряда × 4 колонки; ячейки БЕЗ рамок/подложек — sp-card не применять,
   фон общий с шторкой, разделение только gap. Обёртка со скроллом:
   min-width сетки не распирает td шторки при скрытых колонках матрицы —
   скроллится сама шторка, table-layout матрицы не прыгает. Легенда —
   НЕ fin-legend-inline (у него nowrap+ellipsis и display:none ≤1500px):
   это единственный объяснительный текст серий, виден всегда. */
.rnp-detail-grid-scroll { overflow-x: auto; }
.rnp-detail-grid {
  display: grid; grid-template-columns: repeat(4, minmax(230px, 1fr));
  gap: 10px; min-width: 950px;
}
/* Узкое окно: 2 колонки/4 ряда — осознанное отклонение от «2 строк»
   брифа ради читаемости (план §7-T2, приёмка §9 п.4). */
@media (max-width: 1100px) {
  .rnp-detail-grid { grid-template-columns: repeat(2, minmax(230px, 1fr)); }
}
.rnp-detail-cell-title { font-size: 11px; color: var(--sp-ink-3); margin-bottom: 2px; }
.rnp-detail-legend {
  font-size: 11px; color: var(--sp-ink-3);
  white-space: normal; overflow: visible; align-self: start;
}
/* Итог выборки: sticky снизу, 30px — канон calcs-строки Мониторинга. */
#rnp-matrix tfoot td {
  position: sticky; bottom: 0; background: var(--sp-surface-2); height: 30px;
  font-weight: 600; color: var(--sp-ink-2); border-top: 1px solid var(--sp-border-strong);
}
.fin-pager { display: flex; align-items: center; gap: 3px; }
.fin-pager .tabulator-page {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 26px; height: 26px; padding: 0 6px;
  color: var(--sp-ink-2); background: var(--sp-surface);
  border: 1px solid var(--sp-border); border-radius: 8px;
  font-size: 12px; font-variant-numeric: tabular-nums; cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.fin-pager .tabulator-page:hover { background: var(--sp-surface-3); }
.fin-pager .tabulator-page.active { color: #fff; background: var(--sp-brand-strong); border-color: var(--sp-brand-strong); }
.fin-pager .tabulator-page[disabled] { opacity: 0.45; cursor: default; }
.fin-pager .tabulator-page svg { width: 12px; height: 12px; }

/* Поповер «Настройки таблицы» */
.fin-pop {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 30;
  width: 384px; max-width: calc(100vw - 24px);
  max-height: min(72vh, 640px); overflow-y: auto;
  background: var(--sp-surface); border: 1px solid var(--sp-border);
  border-radius: 14px; box-shadow: var(--sp-shadow-menu);
}
.fin-pop-head {
  position: sticky; top: 0; z-index: 1;
  display: flex; align-items: center; justify-content: space-between;
  padding: 9px 14px; border-bottom: 1px solid var(--sp-border);
  font-size: 13.5px; font-weight: 700; color: var(--sp-ink); background: var(--sp-surface);
}
.fin-pop-body { padding: 2px 14px 8px; }
.fin-pop-sec { padding: 12px 0; border-top: 1px solid var(--sp-border); }
.fin-pop-sec:first-child { border-top: 0; }
.fin-pop-title {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--sp-ink-3); margin-bottom: 8px;
}
.fin-pop-hint { margin-top: 8px; font-size: 11.5px; line-height: 1.5; color: var(--sp-ink-3); }
.fin-pop-foot {
  padding: 8px 14px; border-top: 1px solid var(--sp-border);
  font-size: 11px; color: var(--sp-ink-3);
}
.fin-pop input[type="checkbox"] { accent-color: var(--sp-brand-strong); width: 14px; height: 14px; cursor: pointer; flex-shrink: 0; }

/* Группы колонок в поповере: native <details> без JS-раскрытия */
.fin-groups { display: flex; flex-direction: column; gap: 4px; }
.fin-group { border: 1px solid var(--sp-border); border-radius: 10px; overflow: hidden; }
.fin-group summary {
  list-style: none; display: flex; align-items: center; justify-content: space-between;
  gap: 8px; padding: 7px 10px; cursor: pointer; background: var(--sp-surface);
  transition: background .12s;
}
.fin-group summary::-webkit-details-marker { display: none; }
.fin-group summary:hover { background: var(--sp-surface-2); }
.fin-group-head { display: flex; align-items: center; gap: 8px; font-size: 12.5px; font-weight: 600; color: var(--sp-ink); min-width: 0; }
.fin-group-count { font-size: 11px; color: var(--sp-ink-3); font-variant-numeric: tabular-nums; flex-shrink: 0; }
.fin-group-cols {
  padding: 4px 10px 8px; border-top: 1px solid var(--sp-border);
  display: flex; flex-direction: column; gap: 1px; background: var(--sp-surface);
}
.fin-group-col {
  display: flex; align-items: center; gap: 8px; padding: 3px 2px;
  font-size: 12.5px; color: var(--sp-ink-2); cursor: pointer; border-radius: 6px;
}
.fin-group-col:hover { color: var(--sp-ink); }
.fin-group-col span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── Графики (uPlot): в тон токенам, компактная легенда, аккуратный курсор ── */
.uplot, .uplot * { box-sizing: border-box; }
.uplot { font-family: Inter, system-ui, sans-serif; width: 100%; }
.u-title { font: 700 13px Manrope, Inter, sans-serif; color: var(--sp-ink-2); }
.u-legend { display: flex; flex-wrap: wrap; align-items: center;
  gap: 2px 18px; font-size: 12px; color: var(--sp-ink-3);
  margin: 8px 0 2px; text-align: left; }
.u-legend .u-series { display: inline-flex; align-items: center; padding: 1px 0; cursor: pointer; }
.u-legend .u-series > * { display: inline-flex; align-items: center; }
.u-legend .u-marker { width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; }
/* Маркер «оценки» (пунктирная серия) — контурный и рваный: факт и оценка
   не должны выглядеть одинаковыми квадратиками (ревью владельца
   2026-09-26). currentColor = цвет серии, который uPlot ставит строке. */
.u-legend .u-series.sp-ser-dash .u-marker {
  background: transparent !important;
  border: 2px dashed currentColor;
}
.u-legend .u-label { font-weight: 500; color: var(--sp-ink-2); }
.u-legend .u-value { margin-left: 6px; font-weight: 600; color: var(--sp-ink); font-variant-numeric: tabular-nums; }
.u-legend .u-off .u-label, .u-legend .u-off .u-value { opacity: .4; }
.u-cursor-x, .u-cursor-y { border-color: var(--sp-border-strong) !important; }
/* Кольцо точки курсора гасим ЯВНО: дефолт живёт в uplot.min.css (не в
   этом файле), и оно перекрывало линию ±5px — читалось как «пробел» в
   графике при наведении (жалоба владельца 2026-09-26). Точка 5.5px
   садится прямо на линию; позицию дублирует вертикальный кроссхэйр. */
.u-cursor-pt { box-shadow: none; }
/* Скрытая серия (значение только в легенде) не должна и курсорную
   точку рисовать — гасим её точку по классу серии. */
.u-cursor-pt.sp-ser-hidden { display: none; }
/* Столбцы заказов: курсорная точка сажается на вершину столбца и даётся
   с ободком поверхности (по просьбе владельца — «точка на каждом
   столбце при наведении»); стиль точки строит фабрика в charts.js. */
/* ── Тултип-чип графиков «Динамики» (решение владельца 2026-09-27):
   нижняя строка легенды снесена — день и значения серий показывает чип
   возле курсора, визуальный язык — как у чипа магнита спарклайна. В
   покое чипа нет; позицию и содержимое строит charts.js (tipCursor). */
.sp-chart-tip {
  position: absolute; z-index: 6; pointer-events: none;
  min-width: 118px; max-width: 240px; padding: 7px 10px 8px;
  background: var(--sp-surface);
  border: 1px solid var(--sp-border-strong);
  border-radius: 10px;
  box-shadow: 0 6px 20px rgba(15, 23, 42, .14);
  font-size: 12px; line-height: 1.35; color: var(--sp-ink);
}
.sp-chart-tip[hidden] { display: none; }
.sp-chart-tip-date { font-weight: 600; color: var(--sp-ink-2);
  font-size: 11px; margin-bottom: 3px; }
.sp-chart-tip-row { display: flex; align-items: center; gap: 6px; margin-top: 2px; }
.sp-chart-tip-m { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.sp-chart-tip-m-dash { background: transparent !important;
  border: 2px dashed; }
.sp-chart-tip-label { color: var(--sp-ink-2); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sp-chart-tip-val { margin-left: auto; font-weight: 600;
  font-variant-numeric: tabular-nums; white-space: nowrap; }
/* ── «Текущий месяц»: пара шкал «Цель + Сравнение» (решение владельца
   2026-09-27) ── */
.sp-mhead, .sp-mrow { display: grid;
  grid-template-columns: minmax(170px, 230px) minmax(150px, 190px) 72px minmax(200px, 1fr);
  gap: 12px; align-items: center; padding: 9px 10px; }
.sp-mhead { padding: 6px 10px 2px; }
.sp-mh { font: 600 11px Inter, sans-serif; text-transform: uppercase;
  letter-spacing: .04em; color: var(--sp-ink-3); text-align: right;
  white-space: nowrap; }
.sp-mh-left { text-align: left; }
.sp-mrow { border-top: 1px solid var(--sp-border); }
.sp-mrow-label { color: var(--sp-ink); font-size: 13.5px; }
.sp-mrow-note { display: block; font-size: 11px; color: var(--sp-ink-3);
  margin-top: 2px; cursor: help; }
.sp-mrow-fact { display: block; font-family: Manrope, Inter, sans-serif;
  font-weight: 700; font-size: 15px; color: var(--sp-ink);
  font-variant-numeric: tabular-nums; line-height: 1.2; }
.sp-mrow-fore { display: block; font-size: 11.5px; color: var(--sp-ink-3);
  font-variant-numeric: tabular-nums; margin-top: 2px; cursor: help; }
.sp-mrow-planned { display: block; font-size: 11px; color: var(--sp-ink-3);
  margin-top: 2px; cursor: help; }
.sp-mrow-scales { display: flex; flex-direction: column; gap: 5px; }
.sp-mrow-scaleline { display: flex; align-items: center; gap: 8px; }
.sp-mrow-scale { position: relative; flex: 1; height: 14px; border-radius: 7px;
  background: var(--sp-surface-2); overflow: visible; }
/* База-оценка (план не задан): штриховка ТОЛЬКО в незаполненном хвосте
   шкалы — там, где факт не дошёл (решение владельца 2026-09-27: ≈-маркер
   неорганичен, штриховка по всему треку — шум; left задаёт шаблон от
   края заливки). */
.sp-mrow-tail { position: absolute; top: 0; bottom: 0; right: 0;
  border-radius: 0 7px 7px 0;
  background: repeating-linear-gradient(135deg, transparent 0 4px, var(--sp-border) 4px 8px); }
/* Перевыполнение/«на цели» — заливка зелёным тоном: успех, а не конец
   шкалы (кламп 100% больше не прячет перевыполнение — чип рядом). */
.sp-mrow-scale.over .sp-mrow-fill {
  background: linear-gradient(90deg, rgba(16,185,129,0.35), rgba(16,185,129,0.75)); }
.sp-mrow-fill { position: absolute; top: 0; bottom: 0; left: 0;
  border-radius: 7px;
  background: linear-gradient(90deg, rgba(129,140,248,0.28), rgba(129,140,248,0.60)); }
.sp-mrow-mark { position: absolute; top: -3px; bottom: -3px; width: 2px;
  border-radius: 1px; background: var(--sp-ink-3); cursor: help; }
/* Риса «сегодня» — календарный ориентир: доля прошедших дней месяца. */
.sp-mrow-today { position: absolute; top: -3px; bottom: -3px; width: 2px;
  border-radius: 1px; background: var(--sp-ink-2); cursor: help; }
/* Отрицательный факт — красный штрих от левого края: знак не молчит. */
.sp-mrow-negmark { position: absolute; left: 0; top: -3px; bottom: -3px;
  width: 3px; border-radius: 1px; background: var(--sp-loss); cursor: help; }
.sp-mrow-chip { font: 600 10.5px Inter, sans-serif; color: var(--sp-ink-2);
  white-space: nowrap; font-variant-numeric: tabular-nums; cursor: help; }
.sp-mrow-chip.over { color: var(--sp-profit); }
/* Нижняя шкала сравнения: трек на общем фоне (сегменты не «висят в
   воздухе» — ревью владельца 2026-09-27), ось-ноль по центру видимая,
   полутрек = ±50% Δ. */
.sp-mrow-dbarline { display: flex; align-items: center; height: 14px; }
.sp-mrow-dbarline .sp-mrow-note { margin: 0; }
.sp-mrow-dbar { position: relative; flex: 1; height: 14px;
  background: var(--sp-surface-2); border-radius: 7px; }
.sp-mrow-dbar-axis { position: absolute; left: 50%; top: -3px; bottom: -3px;
  width: 1px; background: var(--sp-ink-3); }
.sp-mrow-dbar-seg { position: absolute; top: 3px; bottom: 3px; left: 50%;
  border-radius: 0 7px 7px 0;
  background: linear-gradient(90deg, rgba(16,185,129,0.40), rgba(16,185,129,0.80)); }
.sp-mrow-dbar.neg .sp-mrow-dbar-seg { left: auto; right: 50%;
  border-radius: 7px 0 0 7px;
  background: linear-gradient(270deg, rgba(225,29,72,0.35), rgba(225,29,72,0.80)); }
.sp-mrow-none { font-size: 12px; color: var(--sp-ink-3); }
.sp-mrow-delta { text-align: right; }
.sp-delta-pill { display: inline-block; font-size: 11.5px; font-weight: 600;
  padding: 1px 8px; border-radius: 9999px; white-space: nowrap;
  font-variant-numeric: tabular-nums; }
.sp-delta-pill.down { color: var(--sp-delta-down); background: var(--sp-loss-bg); }
.sp-delta-pill.up { color: var(--sp-delta-up); background: var(--sp-profit-bg); }
.sp-delta-pill.flat { color: var(--sp-ink-3); background: var(--sp-surface-2); }
/* Недели: data bars заливкой ячейки + hover строки. */
.sp-wtable tbody tr { transition: background 120ms; }
.sp-wtable tbody tr:hover { background: var(--sp-row-hover); }
/* Появление графика (charts.js вешает .sp-chart-in на обёртку при первом
   монтировании): полотно «прочерчивается» слева направо — один авторский
   жест, не декор; перетема и повторная инициализация не переигрывают. */
.sp-chart-in .uplot { animation: sp-chart-sweep .7s cubic-bezier(.16, 1, .3, 1) both; }
@keyframes sp-chart-sweep {
  from { clip-path: inset(0 100% 0 0); opacity: .35; }
  60% { opacity: 1; }
  to { clip-path: inset(0 0 0 0); opacity: 1; }
}
/* Пульс последней точки спарклайна KPI-плиток — «живой» сигнал тренда. */
.sp-spark-dot { animation: sp-spark-pulse 2.4s ease-in-out infinite; }
@keyframes sp-spark-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .5; } }
@media (prefers-reduced-motion: reduce) {
  .sp-chart-in .uplot, .sp-spark-dot { animation: none; }
}
/* высота-обёртка графика: чтобы SSR-скелет не прыгал до отрисовки */
.sp-chart { width: 100%; position: relative; }

/* ── Мобильный баннер: скрыт на desktop, v1 без адаптива ─────────────────── */
.mobile-banner { display: none; }
@media (max-width: 1023px) { .mobile-banner { display: flex; } main { display: none; } }

/* ── Печать: без шапки/меню/модалок, A4 landscape ────────────────────────── */
@media print {
  header, nav, .no-print, #modal, #global-tip, .mobile-banner, footer { display: none !important; }
  main { max-width: 100% !important; padding: 0 !important; margin: 0 !important; }
  .fin-bleed { width: auto !important; margin: 0 !important; }
  body { background: #fff !important; color: #000 !important; }
  @page { size: A4 landscape; margin: 1cm; }
  thead { display: table-header-group; }
  tfoot { display: table-footer-group; }
  tr, .print-row { page-break-inside: avoid; }
  table { width: 100% !important; font-size: 9pt !important; }
  .text-red-600, .text-rose-600, .sp-loss { color: #000 !important; }
  a { color: #000 !important; text-decoration: none !important; }
}

/* ═══ Матрица портфеля и вид «По дням» (Пульс, редизайн 2026-08) ═══ */
/* Базовая таблица #rnp-tabulator (Tabulator-вариант матрицы) демонтирована
   вместе с матрицей — фаза C «Один движок таблиц» (SSR-каркас #rnp-matrix). */

/* SKU-ячейка (SSR-матрица + клиентские виды «По дням»/карточки):
   канон Финотчёта — фото 32×38 (+2 рамки) + 2×3px = ровно 44px.
   Прежний бюджет 52px и фото 38×44 (сжатие 2026-09-09, Tabulator)
   демонтированы решением владельца 2026-09-27 «сделай высоту»:
   SSR-ячейка матрицы = fin_sku_pills 1:1 (два ряда пилюль, полный
   титул в тултипе), строка матрицы — 44px канона; отдельный
   name-ряд (.rnp-sku-name) демонтирован за нехваткой бюджета. */
.rnp-sku-cell { display: flex; gap: 8px; align-items: center; }
.rnp-sku-cell img, .rnp-sku-ph { flex: none; width: 32px; height: 38px; object-fit: cover;
  border-radius: 6px; background: var(--sp-surface-2); border: 1px solid var(--sp-border); }
.rnp-sku-main { min-width: 0; display: flex; flex-direction: column; }
.rnp-sku-link { color: inherit; text-decoration: none; }
.rnp-sku-link:hover { color: var(--sp-brand-ink); text-decoration: underline; }
/* Бейджи в строке артикула (ABC, Критично/Внимание, сверка) —
   компактные: полноразмерный .sp-badge раздувает строку и выталкивает
   контент за высоту строки таблицы */
.rnp-sku-badges .sp-badge { font-size: 10px; padding: 0.5px 6px; line-height: 1.3; white-space: nowrap; }
.rnp-sku-badges { display: inline-flex; gap: 4px; margin-left: auto; flex: none; }

/* Многострочная ячейка данных (Финотчёт + Пульс, 2026-09-05): главное
   значение на первой строке, производные (шт, %, разборы) — мелкой
   тихой строкой ниже. Колонка узкая, шапка короче, ячейки обеих
   таблиц унифицированы. Стек прижат вправо — как числа колонки. */
.cstack { display: inline-flex; flex-direction: column; align-items: flex-end; gap: 1px;
  max-width: 100%; vertical-align: middle; }
/* Левый вариант стека — текстовые колонки (заявленный артикул подмен,
   2026-09-06): главная строка + производная прижаты влево, как текст */
.cstack-l { align-items: flex-start; }
.cstack-main { line-height: 1.2; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cstack-sub { font-size: 10.5px; line-height: 1.25; color: var(--sp-ink-3);
  font-variant-numeric: tabular-nums; white-space: nowrap;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; }

/* Подмены/неверные вложения (2026-09-06): бэдж-причина — кнопка-фильтр
   (клик — показать только эту причину, повторный — сброс), активный
   отмечен обводкой бренда */
.ded-filter { cursor: pointer; font-family: inherit; }
.ded-filter:focus-visible { outline: 2px solid var(--sp-brand); outline-offset: 1px; }
.ded-filter[data-active] { outline: 2px solid var(--sp-brand); outline-offset: 1px; }
.rnp-c-cell { white-space: nowrap; }

/* Копирование NMID — цель ≥28×28 (WCAG 2.5.8), иконка 14px */
.sp-copy-btn { display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 8px; color: var(--sp-ink-2);
  background: transparent; border: 0; cursor: pointer; }
.sp-copy-btn:hover { background: var(--sp-surface-2); color: var(--sp-ink); }
.sp-copy-btn svg { width: 14px; height: 14px; }

/* Спарклайн тренда */
.rnp-spark { display: block; }
.rnp-spark-col { vertical-align: middle; }

/* ── Строка контролов Мониторинга (запрос владельца 2026-09-26: верх
   таблицы «не органично расставлен»): бывшие ДВЕ коробки над панелью —
   ряд «SKU (N) + вид» и отдельная карточка «поиск + Категория + Бренд +
   ABC» — схлопнуты в ОДИН ряд на холсте (без собственной карточки:
   единственная «коробка» страницы — панель таблицы). При скролле ряд
   НЕ липнет (уточнение владельца 2026-09-09: «не должно ничего
   захватываться, кроме хедера таблицы»); липнут только заголовки
   колонок матрицы, сразу под навигацией (--sp-sticky-top = низ .sp-nav).
   Контролы — компактный канон 2026-09-09:
   4px по вертикали, 12.5px шрифт. */
.rnp-controls {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 6px 8px; margin-bottom: 6px;
}
.rnp-controls .sp-input, .rnp-controls .sp-select {
  padding-top: 4px; padding-bottom: 4px; font-size: 12.5px; border-radius: 8px;
}
.rnp-controls .sp-select {
  padding-right: 1.7rem; background-position: right 0.45rem center; background-size: 0.95rem;
}
.rnp-controls form { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; min-width: 0; }
/* Sticky-заголовки колонок матрицы: липнут сразу под навигацией.
   top = --sp-sticky-top (низ .sp-nav) МИНУС 1px:
   при дробных координатах (масштаб ОС 125% и т.п.) округление оставляло
   субпиксельную щель между навигацией и шапкой, в которой мелькали
   строки таблицы («прозрачная линия с точками», запрос владельца
   2026-09-09). Перекрытие вверх на 1px щель закрывает; навигация
   (z-30) рисуется ПОВЕРХ шапки (z-24) — её край не пострадает.
   Панель фильтров выше не липнет. У корня .tabulator стоит
   overflow:hidden (tabulator.min.css) — это делает его скролл-
   контейнером и роняет position:sticky у потомков. Переопределяем на
   clip: отсечение то же, скролл-контейнера нет — sticky работает
   относительно окна (fallback hidden для старых браузеров: sticky
   просто не включится, вид не ломается). */
/* Селекты #rnp-filterbar выбраны — видно, какой фильтр активен. */
.rnp-controls .sp-select[data-active] {
  border-color: var(--sp-brand); color: var(--sp-brand-ink);
  background-color: var(--sp-brand-tint);
}

/* Частичная шапка дня ОПиУ-шторки (pnl-days.js, режим «Таблица»):
   «◐» — WB ещё формирует отчёт за дату / дыра синка (тултип шапки
   различает). rnp-половина общего селектора и весь блок вида
   «По дням» (селекторы .rnp-days и .rnp-d-*) снесены 2026-09-28
   (T2 волны «Мониторинг: один вид»). */
.pnl-days-ttable thead th.sp-day-partial { color: var(--sp-warn); }

/* ── Линия расходов и налогов (.tl-*; план expenses_tax_timeline §8) ──────
   Сетка месяцев и дорожки-интервалы: ширина сегмента = flex:var(--m)
   (m = месяцев в сегменте), граница интервалов = граница сегментов.
   Мобильный: горизонтальный скролл .tl, метка дорожки прилипает слева. */
.tl { display: flex; flex-direction: column; gap: 10px; overflow-x: auto;
  padding-bottom: 4px; }
.tl [x-cloak] { display: none; }
.tl-head { margin-bottom: 2px; }
.tl-page { display: flex; flex-direction: column; gap: 4px;
  min-width: calc(var(--tl-m, 18) * 52px + 96px); }
.tl-row { display: flex; align-items: stretch; }
.tl-row-label { flex: 0 0 96px; position: sticky; left: 0; z-index: 2;
  background: var(--sp-surface); color: var(--sp-ink-2); font-size: 11px;
  font-weight: 600; display: flex; align-items: center; padding-right: 8px;
  overflow: hidden; white-space: nowrap; }
.tl-months { border-bottom: 1px solid var(--sp-border); }
.tl-month { flex: 1; min-width: 0; text-align: center; color: var(--sp-ink-3);
  font-size: 10.5px; line-height: 1.5; display: flex; flex-direction: column; }
.tl-month .tl-year { color: var(--sp-ink-2); font-weight: 700; }
.tl-month.tl-now { color: var(--sp-brand); font-weight: 700; }
.tl-seg { position: relative; min-width: 0; min-height: 26px; display: flex; cursor: pointer;
  align-items: center; justify-content: center; overflow: hidden;
  border-radius: 6px; margin-right: 2px; background: var(--sp-surface-2);
  border: 1px solid var(--sp-border); }
.tl-seg:last-child { margin-right: 0; }
.tl-seg-label { font-size: 10.5px; color: var(--sp-ink); padding: 0 4px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tl-seg-tax { background: var(--sp-brand-tint); border-color: var(--sp-brand); }
.tl-seg-gap { background: transparent; border-style: dashed; }
.tl-seg-none { border-style: dashed; background: transparent;
  color: var(--sp-ink-3); font-size: 11px; text-align: center; }
.tl-seg-open::after { content: "▶"; position: absolute; right: 2px; top: 50%;
  transform: translateY(-50%); font-size: 9px; color: var(--sp-ink-2); }
.tl-seg-notch { position: absolute; top: 0; bottom: 0; width: 0;
  border-left: 2px dashed var(--sp-warn); transform: translateX(-1px); }
.tl-seg-handle { position: absolute; left: 0; top: 50%;
  transform: translate(-50%, -50%); z-index: 3; width: 18px; height: 18px;
  border-radius: 50%; border: 1px solid var(--sp-border-strong);
  background: var(--sp-surface); color: var(--sp-ink-2); font-size: 10px;
  line-height: 1; cursor: pointer; display: flex; align-items: center;
  justify-content: center; padding: 0; }
.tl-seg-handle:hover { background: var(--sp-brand-tint); color: var(--sp-ink);
  border-color: var(--sp-brand); }
/* Hover-приглушение соседних сегментов дорожки */
.tl-row:has(.tl-seg:hover) .tl-seg:not(:hover) { opacity: .35; }
/* Дозагрузка влево */
.tl-older { align-self: flex-start; margin: 0 0 2px 96px; font-size: 11px;
  color: var(--sp-ink-2); background: var(--sp-surface-2);
  border: 1px solid var(--sp-border); border-radius: 999px; padding: 2px 10px;
  cursor: pointer; }
.tl-older:hover { background: var(--sp-brand-tint); color: var(--sp-ink); }
.tl-older-none { margin-left: 96px; font-size: 11px; color: var(--sp-ink-3); }
/* Тултип сегмента (Alpine x-show; липнет к левому краю дорожек) */
.tl-tip { position: sticky; left: 96px; display: flex; flex-direction: column;
  gap: 1px; margin-top: 6px; padding: 6px 10px; border-radius: 8px;
  background: var(--sp-tooltip-bg); color: var(--sp-tooltip-ink);
  font-size: 12px; line-height: 1.45; max-width: 320px; pointer-events: none; }
@media (max-width: 640px) {
  .tl-row-label { flex-basis: 72px; }
  .tl-page { min-width: calc(var(--tl-m, 18) * 52px + 72px); }
  .tl-older, .tl-older-none { margin-left: 72px; }
  .tl-tip { left: 72px; }
}

/* Будущие профили налога (за правым краем окна): чип-план (UX F4) */
.tl-seg-future {
  display: inline-flex; align-items: center; padding: 0 8px; margin-left: 6px;
  border: 1px dashed var(--sp-border-strong); border-radius: 9999px;
  font-size: 11px; color: var(--sp-ink-2); background: var(--sp-surface-2);
  white-space: nowrap; flex: none; align-self: center;
}

/* ── Календарь денег v1 (.sp-cal-v1) — принятый live-вариант c7e4cebb
   (density=airy, hatch=true; параметры запечены). Разметка:
   templates/pages/inputs/calendar_v1.html; проводка данных — этап 2
   docs/plans/expenses_tax_gantt.md (D2/D5). ── */
.sp-cal-v1 { font:400 14px/1.5 Inter,system-ui,sans-serif; color:var(--sp-ink); }
.sp-cal-v1 .cnum { font-family:Manrope,Inter,sans-serif; font-variant-numeric:tabular-nums; }
.sp-cal-v1 .cal-card { background:var(--sp-surface); border:1px solid var(--sp-border); border-radius:14px; box-shadow:var(--sp-shadow-1); overflow:hidden; }
.sp-cal-v1 .cal-head { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:12px; padding:14px 18px; border-bottom:1px solid var(--sp-border); }
.sp-cal-v1 .cal-head h2 { font:700 18px/1.3 Manrope,Inter,sans-serif; letter-spacing:-0.01em; margin:0; color:var(--sp-ink); }
.sp-cal-v1 .cal-head p { margin:2px 0 0; font-size:12.5px; color:var(--sp-ink-2); }
.sp-cal-v1 .cal-year { display:flex; align-items:center; gap:8px; font:600 12px Manrope,Inter,sans-serif; color:var(--sp-ink-2); }
.sp-cal-v1 .cal-year b { padding:4px 12px; border-radius:999px; background:var(--sp-brand-tint); color:var(--sp-brand-ink); }
.sp-cal-v1 .cal-scroll { overflow-x:auto; }
/* Этап 2 (D5): окно может быть >12 мес (год регистрации + планы) —
   число колонок задаёт --cal-cols на .cal-inner (calendar.html). */
.sp-cal-v1 .cal-inner { min-width:calc(118px + var(--cal-cols,12) * 72px); }
.sp-cal-v1 .row { display:grid; grid-template-columns:118px repeat(var(--cal-cols,12),minmax(48px,1fr)); align-items:stretch; }
.sp-cal-v1 .row + .row { border-top:1px solid var(--sp-border); }
/* D3 v2 «месяц = атомарная ячейка»: все дети строки — в одну
   грид-строку; визуал (сегменты/точки/штрих/ghost) не ловит указатель —
   клики и hover живут на ячейках-оверлеях .cell поверх. */
.sp-cal-v1 .row > * { grid-row:1; }
.sp-cal-v1 .seg, .sp-cal-v1 .dots, .sp-cal-v1 .hatch, .sp-cal-v1 .now-col { pointer-events:none; }
.sp-cal-v1 .lbl { display:flex; align-items:center; padding:0 12px; font-size:12px; font-weight:600; color:var(--sp-ink-2); border-right:1px solid var(--sp-border); }
.sp-cal-v1 .m { padding:7px 4px 5px; text-align:center; font:600 10.5px Inter,sans-serif; letter-spacing:.05em; text-transform:uppercase; color:var(--sp-ink-3); }
.sp-cal-v1 .m-now { background:var(--sp-brand); color:#fff; border-radius:0 0 6px 6px; margin:0 4px; }
.sp-cal-v1 .seg { grid-column:9 / span 5; display:flex; align-items:center; gap:6px; margin:5px 4px; padding:0 10px; min-height:34px; border-radius:8px; font-size:12px; font-weight:600; }
.sp-cal-v1 .seg .sub { font-weight:400; color:inherit; opacity:.75; }
.sp-cal-v1 .seg-tax { background:var(--sp-brand-tint); color:var(--sp-brand-ink); }
.sp-cal-v1 .seg-rule { background:var(--sp-surface-3); color:var(--sp-ink); }
/* ghost в одну строку с многоточием (compact-фикс со стенда). */
.sp-cal-v1 .seg-past { grid-column:2 / span 7; display:block; line-height:34px; background:var(--sp-surface-2); color:var(--sp-ink-3); font-weight:400; font-size:11.5px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.sp-cal-v1 .seg-open { border-radius:8px 0 0 8px; margin-right:0; }
.sp-cal-v1 .seg-plan { background:var(--sp-surface); border:1.5px dashed var(--sp-brand); color:var(--sp-brand-ink); }
.sp-cal-v1 .hatch { grid-column:10 / span 4; margin:5px 0 5px 4px; border-radius:8px; background:repeating-linear-gradient(135deg,transparent 0 7px,var(--sp-surface-2) 7px 8px); }
.sp-cal-v1 .dots { grid-column:9 / span 5; display:flex; align-items:center; gap:6px; margin:5px 4px; padding:0 10px; min-height:34px; font-size:12px; color:var(--sp-ink-2); }
.sp-cal-v1 .dot { width:9px; height:9px; border-radius:999px; background:var(--sp-accent-mark); flex:none; }
.sp-cal-v1 .cal-foot { display:flex; align-items:center; gap:8px; padding:10px 18px; border-top:1px solid var(--sp-border); font-size:12px; color:var(--sp-ink-3); }
.sp-cal-v1 .cal-foot svg { flex:none; }

/* ── Календарь денег v2 — production (этап 2, D3/D5; окно = годы,
   ячейки-оверлеи, модалка добавления/изменения). Разметка: calendar.html
   / calendar_modal.html. ── */
.sp-cal-v1 .m .yy { display:block; font-size:9px; letter-spacing:.02em; text-transform:none; color:var(--sp-ink-3); }
.sp-cal-v1 .m.m-now .yy { color:rgba(255,255,255,.85); }
.sp-cal-v1 .seg-label { font-size:12px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* Ячейка-оверлей месяца: hover = округлая подсветка брендом. */
.sp-cal-v1 .cell { margin:5px 4px; min-height:34px; padding:0; border:0; background:transparent; border-radius:8px; cursor:pointer; }
.sp-cal-v1 .cell:hover, .sp-cal-v1 .cell:focus-visible { background:var(--sp-brand-tint); box-shadow:inset 0 0 0 1.5px var(--sp-brand); }
.sp-cal-v1 .cell-idle { cursor:default; }
.sp-cal-v1 .now-col { margin:5px 2px; border-radius:6px; background:var(--sp-brand-tint); opacity:.4; }
.sp-cal-v1 .cal > .tl-older { align-self:auto; margin:8px 0 0 18px; }
.sp-cal-v1 .cal > .tl-older-none { margin:8px 0 0 18px; }
.sp-cal-v1 dialog.cal-dialog { border:0; padding:0; border-radius:14px; box-shadow:var(--sp-shadow-1); width:min(480px,92vw); color:var(--sp-ink); }
.sp-cal-v1 .cal-dialog-head { display:flex; align-items:center; justify-content:space-between; padding:14px 18px 0; }
.sp-cal-v1 .cal-dialog-head h3 { margin:0; font:700 16px/1.3 Manrope,Inter,sans-serif; }
.sp-cal-v1 .cal-dialog-x { border:0; background:var(--sp-surface-2); color:var(--sp-ink-2); width:26px; height:26px; border-radius:999px; cursor:pointer; }
.sp-cal-v1 .cal-type { display:grid; grid-template-columns:1fr 1fr; gap:8px; padding:12px 18px 0; }
.sp-cal-v1 .cal-type-card { display:flex; flex-direction:column; gap:2px; padding:10px 12px; border:1px solid var(--sp-border); border-radius:10px; cursor:pointer; font-size:12px; color:var(--sp-ink-2); }
.sp-cal-v1 .cal-type-card:has(input:checked) { border-color:var(--sp-brand); background:var(--sp-brand-tint); color:var(--sp-brand-ink); }
.sp-cal-v1 .cal-type-card b { font-size:13px; }
.sp-cal-v1 .cal-dialog-form { padding:12px 18px 16px; display:flex; flex-direction:column; gap:10px; }
.sp-cal-v1 .cal-dialog-row { display:grid; grid-template-columns:repeat(auto-fit,minmax(120px,1fr)); gap:8px; }
.sp-cal-v1 .cal-hint { display:block; font-size:11px; color:var(--sp-ink-3); }
.sp-cal-v1 .cal-dialog-actions { display:flex; flex-wrap:wrap; gap:8px; }
.sp-cal-v1 dialog.cal-dialog::backdrop { background:rgba(15,23,42,.45); }

/* ── Гант «Расходы и налоги» (ред. 4, expenses-gantt-model) ───────────── */

/* Панель вкладки на всю ширину экрана (fin-bleed, как у Финотчёта):
   карточка-обёртка inputs.html для money нейтрализуется, пока активна
   эта вкладка (чистый CSS, без JS — инвариант CSP). */
body:has(#inputs-money) .sp-card:has(#inputs-tab-content) {
  background: transparent; border: 0; box-shadow: none;
  border-radius: 0; overflow: visible;
}
body:has(#inputs-money) #inputs-tab-content { padding: 0; }

.g-panel {
  background: var(--sp-surface); border: 1px solid var(--sp-border);
  border-radius: 14px; box-shadow: var(--sp-shadow-1);
  padding: .85rem 1rem 1rem;
}
.g-intro { display: flex; flex-direction: column; gap: .15rem; margin-bottom: .7rem; }

.g-wrap { --g-lab: 190px; --g-colmin: 64px; display: flex; flex-direction: column; gap: .8rem; }
.g-summary { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
.g-pill {
  display: inline-block; padding: .18rem .65rem; border-radius: 999px;
  font-size: .78rem; font-weight: 700;
  background: var(--sp-profit-bg); color: var(--sp-profit);
  border: 1px solid var(--sp-profit-border);
}
.g-scope { font-size: .72rem; font-weight: 600; color: var(--sp-ink-2);
  padding: .14rem .55rem; border-radius: 999px;
  background: var(--sp-surface-2); border: 1px solid var(--sp-border);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 16rem; }
.g-thresh { font-size: .72rem; font-weight: 600; color: var(--sp-warn);
  padding: .14rem .55rem; border-radius: 999px; white-space: nowrap;
  background: color-mix(in srgb, var(--sp-warn) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--sp-warn) 38%, transparent); }
.g-zoom { display: inline-flex; align-items: center; gap: 3px; }
.g-zoom .text-xs { margin-right: 4px; }
.g-zoom-btn { width: 26px; height: 26px; border-radius: 8px; cursor: pointer;
  border: 1px solid var(--sp-border); background: var(--sp-surface);
  color: var(--sp-ink-2); font-size: .9rem; font-weight: 700; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center; }
.g-zoom-btn:hover:not(:disabled) { border-color: var(--sp-brand);
  color: var(--sp-brand-ink); background: var(--sp-brand-tint); }
.g-zoom-btn:disabled { opacity: .4; cursor: default; }
.g-scroll {
  overflow-x: auto; border: 1px solid var(--sp-border); border-radius: 12px;
  background: var(--sp-surface); box-shadow: var(--sp-shadow-1);
  scrollbar-width: none; -ms-overflow-style: none; /* нативный спрятан —
    вместо него тонкий .g-scrollbar правее колонки подписей (ред. 5.2) */
}
.g-scroll::-webkit-scrollbar { display: none; }
.g-scrollbar { position: relative; height: 11px; margin-left: var(--g-lab);
  margin-top: -5px; /* вплотную: гасим flex-gap .g-wrap (ред. 5.3) */
  border-radius: 999px; user-select: none; touch-action: none; cursor: default;
  background: color-mix(in srgb, var(--sp-border) 40%, transparent); }
.g-scrollbar-thumb { position: absolute; top: 0; bottom: 0; left: 0;
  min-width: 44px; border-radius: 999px;
  background: color-mix(in srgb, var(--sp-ink-3) 38%, transparent); }
.g-scrollbar-thumb:hover { background: color-mix(in srgb, var(--sp-ink-3) 58%, transparent); }
.g-scrollbar.g-scrollbar-drag .g-scrollbar-thumb {
  background: color-mix(in srgb, var(--sp-ink-3) 62%, transparent); }
/* Строки Ганта — flex (НЕ grid): sticky-метка должна прилипать на всю
   ширину прокрутки. У flex-item containing block — весь контейнер, у
   grid-item — только его grid-область (= собственная колонка 190px), где
   sticky двигаться некуда: в Firefox метка прокручивалась вместе с
   контентом (дефект владельца 2026-09-25). Span 1/-1 поверх трека тоже не
   годится — Firefox рисовал трек поверх метки. Flex: метка и трек —
   отдельные элементы без наложений, sticky работает во всех движках. */
.g-grid { display: flex; width: max-content; min-width: 100%; }
.g-lab {
  position: sticky; left: 0; z-index: 6;
  flex: 0 0 var(--g-lab);
  display: flex; align-items: center;
  font-size: .78rem; font-weight: 600; color: var(--sp-ink-2);
  padding: 0 .6rem 0 .8rem; height: 2.4rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  background: var(--sp-surface); border-right: 1px solid var(--sp-border);
}
.g-lab-head { z-index: 8; height: 1.8rem; align-items: center; font-weight: 600; }
.g-lab-years { height: 1.2rem; }
.g-row { border-top: 1px solid var(--sp-border); }
.g-row:hover .g-lab { color: var(--sp-ink); background: var(--sp-surface-2); }
.g-row:hover .g-track { background: color-mix(in srgb, var(--sp-brand) 3%, transparent); }

/* Шапка: годовые блоки — ТОЛЬКО фон; подписи месяцев лежат в той же
   сетке, что ячейки данных (одинаковые minmax-колонки без инсетов) —
   иначе даты съезжают к концу года (дефект приёмки 2026-09-05).
   ⚠ Специфичность .g-track.g-*: голый .g-headtrack/.g-yearstrack
   перебивался поздним .g-track { min-height: 2.4rem } — ряды шапки
   и годов росли до 38px, sticky-лейблы (28.8/19.2px) становились
   короче ряда, и при скролле низ серого годового блока и подпись
   года наезжали на колонку подписей (дефект приёмки 2026-09-06). */
.g-track.g-headtrack { min-height: 1.8rem; }
.g-ycell { pointer-events: none; z-index: 0; margin: 2px; border-radius: 10px;
  background: var(--sp-surface-2); border: 1px solid var(--sp-border); }
.g-m {
  z-index: 1; grid-row: 1;
  font-size: .72rem; color: var(--sp-ink-3); text-align: center;
  height: 1.8rem; line-height: 1.8rem;
  border-radius: 7px; min-width: 0; overflow: hidden;
}
.g-m-now { color: var(--sp-ink); font-weight: 700; background: var(--sp-brand-tint);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sp-accent-mark) 45%, transparent); }
.g-years { margin-top: 2px; }
.g-track.g-yearstrack { min-height: 1.2rem; }
.g-yearname {
  margin: 0 2px; border-radius: 8px; text-align: center;
  font-size: .64rem; font-weight: 800; color: var(--sp-ink-3); line-height: 1.4;
}

.g-track { position: relative; display: grid; flex: 1 0 auto;
  grid-template-columns: repeat(var(--g-cols, 13), minmax(var(--g-colmin), 1fr)); min-height: 2.4rem; }
.g-track > * { grid-row: 1; }
/* Серый блок ТЕКУЩЕГО года в треке (решение владельца 2026-09-06:
   в 2027 блок переедет на 2027, 2026 станет обычным — gYearFrames). */
.g-yband { pointer-events: none; z-index: 0; margin: 2px; border-radius: 10px;
  background: color-mix(in srgb, var(--sp-surface-3) 60%, transparent); }
.g-hatch { pointer-events: none; z-index: 0;
  background: repeating-linear-gradient(45deg, transparent 0 6px,
    var(--sp-surface-3) 6px 9px); }
.g-nowbg { pointer-events: none; z-index: 0;
  background: color-mix(in srgb, var(--sp-accent) 7%, transparent);
  border-right: 2px dashed var(--sp-accent-mark); }
.g-ghost { pointer-events: none; z-index: 1; display: flex; align-items: center;
  padding-left: .55rem; font-size: .72rem; color: var(--sp-ink-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Диапазоны: без теней — смежные полосы не отбрасывают «белый шов»
   друг на друга (ред. 4); стык показывает явный разделитель .g-div. */
.g-seg { z-index: 2; position: relative; display: flex; align-items: center;
  margin: .3rem 0; border-radius: 8px; padding: 0 .45rem; overflow: hidden;
  font-size: .72rem; font-weight: 700; color: #fff; min-height: 1.55rem; }
.g-rule { background: var(--sp-ink-2); }
.g-tax-usn_income { background: var(--sp-profit); }
.g-tax-usn_income_expenses { background: var(--sp-info); }
.g-tax-npd { background: var(--sp-brand); }
.g-plan { background: transparent; border: 1.5px dashed currentColor; color: inherit;
  box-shadow: none; }
.g-plan.g-rule { color: var(--sp-ink-2); border-color: var(--sp-ink-2); }
.g-plan.g-tax-usn_income { color: var(--sp-profit); }
.g-plan.g-tax-usn_income_expenses { color: var(--sp-info); }
.g-plan.g-tax-npd { color: var(--sp-brand); }
/* Тьма: solid-полосы не инвертируются механически. Светлые семантики
   (#34d399 и т.п.) как ЗАЛИВКА с белым текстом резали глаз и не читались
   (контраст белого по #34d399 ≈ 2:1); g-rule = --sp-ink-2 в тьме почти
   белый — полосы «светились». Замена: глубокая тональная заливка (микс
   семантики с поверхностью, все пары ≥4.5:1) + текст в цвет режима;
   расходным полосам — спокойный серый элевации (решение владельца
   2026-09-24). Светлая тема без изменений. */
/* :not(.g-plan): специфичность html.dark (0-2-1) перебивала бы
   .g-plan { background: transparent } — пунктир-план должен остаться
   БЕЗ заливки, как в светлой теме (приёмка 2026-09-25). */
html.dark .g-rule:not(.g-plan) { background: color-mix(in srgb, var(--sp-ink-2) 26%, var(--sp-surface-3)); }
html.dark .g-tax-usn_income:not(.g-plan) { background: color-mix(in srgb, var(--sp-profit) 24%, var(--sp-surface)); color: var(--sp-profit); }
html.dark .g-tax-usn_income_expenses:not(.g-plan) { background: color-mix(in srgb, var(--sp-info) 24%, var(--sp-surface)); color: var(--sp-info); }
html.dark .g-tax-npd:not(.g-plan) { background: color-mix(in srgb, var(--sp-brand) 24%, var(--sp-surface)); color: var(--sp-brand-ink); }
.g-seg-txt { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
/* Комментарий диапазона (решение владельца 2026-09-06): живёт только
   внутри полосы, мелким шрифтом; название строки — в первом столбце. */
.g-seg-note { font-size: .6rem; font-weight: 500; opacity: .85;
  margin-left: .4rem; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; min-width: 0; }
.g-inf { margin-left: .3rem; font-weight: 800; }

.g-div { position: absolute; right: 0; top: .15rem; bottom: .15rem; width: 5px;
  cursor: col-resize; z-index: 4; border-radius: 4px;
  background: var(--sp-surface); opacity: .9; }
.g-div:hover, .g-div.g-div-active { background: var(--sp-accent-mark); opacity: 1; }
body.g-dragging { cursor: col-resize; user-select: none; }

/* Строка «Разовые» (ред. 5): месяц разбит на дневные ячейки; траты
   дня — мягкая жёлтая полоска на позиции дня (не бросается в глаза). */
.g-evmonth { position: relative; display: flex; z-index: 1;
  margin: .3rem 0; border-radius: 7px; overflow: hidden;
  transition: background-color .12s ease, box-shadow .12s ease; }
/* Наведение на день «Разовых»: весь блок месяца слегка подсвечен
   (владелец, 2026-09-06), внутри — магнит полоски по дням как был. */
.g-evmonth.g-evmonth-hi { background: color-mix(in srgb, var(--sp-warn) 5%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sp-warn) 26%, transparent); }
.g-dayc { flex: 1 1 0; min-width: 0; cursor: pointer; }
.g-dayc:hover { background: color-mix(in srgb, var(--sp-warn) 24%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sp-warn) 45%, transparent); }
.g-daybar { position: absolute; bottom: 4px; height: 52%; border-radius: 3px;
  z-index: 1; pointer-events: none;
  background: color-mix(in srgb, var(--sp-warn) 34%, var(--sp-surface));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sp-warn) 50%, transparent);
  transition: height .12s ease, background-color .12s ease, box-shadow .12s ease; }
/* Ближайшая трата в ±7 дней от курсора — «магнитится» (gantt.js) */
.g-daybar.g-daybar-near { height: 82%; border-radius: 4px;
  background: color-mix(in srgb, var(--sp-warn) 66%, var(--sp-surface));
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--sp-warn) 80%, transparent); }
.g-dayc.g-dayc-hot { background: color-mix(in srgb, var(--sp-warn) 12%, transparent); }
.g-evsum { position: absolute; right: 4px; top: 2px; z-index: 2;
  font-size: .62rem; font-weight: 800; pointer-events: none;
  color: color-mix(in srgb, var(--sp-warn) 60%, var(--sp-ink-2)); }

.g-cell { z-index: 5; cursor: pointer; position: relative; border-radius: 8px; }
/* Ховер ячейки минимальный (решение владельца 2026-09-06): акцент
   уходит на полосу диапазона под ячейкой (.g-seg.g-hi, gantt.js). */
.g-cell:hover { box-shadow: inset 0 0 0 1px
  color-mix(in srgb, var(--sp-ring) 45%, transparent);
  background: color-mix(in srgb, var(--sp-brand) 3%, transparent); }
/* Месяц со взносами — визуальный маркер на дорожке (18:31/спека §6:
   «одного tooltip недостаточно»): спокойная чёрточка в нижней трети
   ячейки строки «Взносы»; сумма месяца — в tooltip. */
.g-contrib-mark { position: absolute; left: 50%; bottom: 16%;
  width: 30%; height: 10%; transform: translateX(-50%); border-radius: 3px;
  pointer-events: none;
  background: color-mix(in srgb, var(--sp-info) 55%, var(--sp-surface));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sp-info) 65%, transparent); }
.g-seg { transition: filter .12s ease, background-color .12s ease,
  box-shadow .12s ease, transform .12s ease; }
/* Наведение на месяц диапазона: полоса заметно «поднимается» —
   внутреннее кольцо, лёгкий подъём и мягкая тень. Живёт только в
   ховере: в покое теней нет (ред. 4 — смежные полосы без швов). */
.g-seg.g-hi {
  filter: brightness(1.1) saturate(1.22);
  transform: translateY(-1px);
  z-index: 3;
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, #fff 55%, transparent),
    0 3px 10px -3px color-mix(in srgb, var(--sp-ink) 32%, transparent);
}
.g-seg.g-plan.g-hi { filter: none; border-style: solid;
  background: color-mix(in srgb, currentColor 10%, transparent);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, currentColor 60%, transparent),
    0 3px 10px -3px color-mix(in srgb, currentColor 35%, transparent); }
@media (prefers-reduced-motion: reduce) { .g-seg.g-hi { transform: none; } }
.g-manual::after { content: ""; position: absolute; right: 3px; top: 3px;
  width: .4rem; height: .4rem; border-radius: 999px; background: var(--sp-warn); }

/* Пустая строка «+ Добавить расход» после «Разовые» (ред. 4). */
.g-addrow { border-top: 1px solid var(--sp-border); }
/* Черновая строка (ред. 5.3): редактируется название и комментарий;
   клик по месяцу создаёт диапазон; без диапазона не сохраняется. */
.g-draft { border-top: 1px dashed var(--sp-border); }
.g-draft-lab { flex-direction: row; align-items: center; gap: .35rem; padding-right: .3rem; }
.g-draft-fields { display: flex; flex-direction: column; gap: .12rem; flex: 1; min-width: 0; }
.g-draft-fields input { width: 100%; font-size: .74rem; padding: .18rem .35rem;
  border: 1px solid var(--sp-border); border-radius: 6px;
  background: var(--sp-surface); color: var(--sp-ink); }
.g-draft-fields input:focus { outline: 2px solid var(--sp-ring); outline-offset: 1px; }
.g-draft-x { border: 0; background: transparent; cursor: pointer;
  color: var(--sp-ink-3); font-size: .72rem; padding: .2rem .3rem; border-radius: 6px; }
.g-draft-x:hover { color: var(--sp-loss); background: var(--sp-surface-2); }
.g-draft .g-cell { background: color-mix(in srgb, var(--sp-brand) 4%, transparent); }
/* Ховер полупрозрачный: opaque --sp-brand-tint (#eef1ff) перекрывал
   текст-подсказку «кликните по месяцу начала…» под ячейками
   (дефект приёмки 2026-09-06). */
.g-draft .g-cell:hover { background: color-mix(in srgb, var(--sp-brand) 9%, transparent); }
.g-add { flex: 1 0 auto; margin: 4px; min-height: 2rem;
  border: 1.5px dashed var(--sp-border); border-radius: 9px;
  background: transparent; color: var(--sp-ink-3);
  font-size: .76rem; font-weight: 600; cursor: pointer; }
.g-add:hover { border-color: var(--sp-brand); color: var(--sp-brand-ink);
  background: var(--sp-brand-tint); }

/* поповер месяца: компактный (ред. 4), открытие только по клику */
.g-pop { position: absolute; z-index: 50; }
.g-pop-card { background: var(--sp-surface); border: 1px solid var(--sp-border);
  border-radius: 12px; box-shadow: var(--sp-shadow-menu);
  padding: .6rem .7rem; display: flex; flex-direction: column; gap: .45rem;
  max-height: 80vh; overflow-y: auto; }
.g-pop-h { display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  font-size: .78rem; font-weight: 800; color: var(--sp-ink); }
.g-pop-ht { display: inline-flex; align-items: center; gap: .4rem; min-width: 0; }
/* Варнинг «исторический период» живёт ТОЛЬКО тултипом у «i» в шапке
   (решение владельца 2026-09-25): баннер из тела формы убран; warn-тон
   иконки — единственный оставшийся на лице сигнал вниманию. */
.g-pop-h .g-pop-warn-i { flex: none; background: color-mix(in srgb, var(--sp-warn) 16%, transparent);
  color: var(--sp-warn); font-weight: 700; }
.g-pop-x { border: 0; background: transparent; cursor: pointer;
  color: var(--sp-ink-3); font-size: .72rem; line-height: 1;
  padding: .2rem .3rem; border-radius: 6px; }
.g-pop-x:hover { color: var(--sp-ink); background: var(--sp-surface-2); }
.g-err { color: var(--sp-loss); font-size: .75rem; white-space: pre-line; }
.g-hint { font-size: .68rem; color: var(--sp-ink-3); margin: 0; }
.g-pop-form { display: flex; flex-direction: column; gap: .4rem; }
.g-f { display: flex; flex-direction: column; gap: .15rem;
  font-size: .7rem; color: var(--sp-ink-3); min-width: 0; }
.g-f input, .g-f select { font-size: .84rem; padding: .28rem .4rem;
  border: 1px solid var(--sp-border); border-radius: 7px;
  background: var(--sp-surface); color: var(--sp-ink); width: 100%; }
.g-f input:focus, .g-f select:focus { outline: 2px solid var(--sp-ring); outline-offset: 1px; }
/* Month Picker полей «С месяца»/«По месяц» (решение владельца
   2026-09-08; портал 2026-09-09): иконка-календарь у поля открывает
   панель выбора как ОТДЕЛЬНЫЙ СЛОЙ — .g-cal живёт в body с
   position:fixed (gantt.js), z-index над .g-pop (50): перекрывает
   поповер, НЕ растягивая его карточку (инлайн-панель раздувала высоту
   .g-pop-card, а absolute обрезался бы её overflow). Токены проекта. */
.g-mwrap { display: flex; align-items: center; gap: .25rem; flex-wrap: wrap; }
.g-mwrap input { flex: 1 1 4.5rem; min-width: 0; width: auto; }
.g-cal-btn { display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; flex: 0 0 26px; border-radius: 7px; cursor: pointer;
  border: 1px solid var(--sp-border); background: var(--sp-surface); color: var(--sp-ink-2); }
.g-cal-btn:hover { color: var(--sp-ink); background: var(--sp-surface-2); }
.g-cal { position: fixed; z-index: 60; width: 224px;
  border: 1px solid var(--sp-border); border-radius: 8px;
  padding: .35rem; background: var(--sp-surface);
  box-shadow: var(--sp-shadow-menu); }
.g-cal-h { display: flex; align-items: center; justify-content: space-between;
  gap: .3rem; margin-bottom: .3rem; font-size: .74rem; font-weight: 700; color: var(--sp-ink); }
.g-cal-nav { border: 0; background: transparent; cursor: pointer; color: var(--sp-ink-3);
  font-size: .8rem; line-height: 1; padding: .15rem .45rem; border-radius: 6px; }
.g-cal-nav:hover { color: var(--sp-ink); background: var(--sp-surface-2); }
.g-cal-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: .2rem; }
.g-cal-m { font-size: .7rem; padding: .22rem 0; border: 1px solid var(--sp-border);
  border-radius: 6px; background: var(--sp-surface); color: var(--sp-ink-2); cursor: pointer; }
.g-cal-m:hover:not(:disabled) { color: var(--sp-ink); background: var(--sp-surface-2); }
.g-cal-m:disabled { opacity: .4; cursor: not-allowed; }
.g-cal-m.g-cal-sel { background: var(--sp-surface-2); color: var(--sp-ink); font-weight: 700; }
/* Ряд «поле + тултип-кружок ?» в лейблах поповера (ред. 9). */
.g-labrow { display: flex; align-items: center; gap: .3rem; }
.g-labrow input, .g-labrow select { flex: 1 1 auto; min-width: 0; }
/* Ряд «текст лейбла + тултип-кружок» (2026-09-27, выравнивание i-иконок
   по замечанию владельца): .g-f — flex-колонка, голый текст + .tip в ней
   становились ДВУМЯ строками (иконка «падала» между лейблом и полем);
   .g-labhead склеивает текст и кружок в одну строку — как у «?» в
   .g-labrow. Отступ кружка даёт его собственный margin-left. */
.g-labhead { display: flex; align-items: center; gap: .3rem; }
.g-2col { display: grid; grid-template-columns: 1fr 1fr; gap: .4rem; }
.g-chk { display: flex; align-items: center; gap: .35rem;
  font-size: .74rem; color: var(--sp-ink-2); cursor: pointer; }
.g-chk input[type="checkbox"] { accent-color: var(--sp-brand-strong);
  width: 14px; height: 14px; flex: none; cursor: pointer; }
.g-pop-actions { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }
/* Кнопки сохранения — вправо (решение владельца 2026-09-06: формы
   поповеров уходят только по явной кнопке «Добавить»/«Сохранить»,
   прижатой к правому нижнему углу). */
.g-pop-actions.g-end { justify-content: flex-end; }
.g-danger { color: var(--sp-loss); }
/* Иконочная кнопка-корзина (ред. 5): крупная, нейтральная, краснеет
   только при наведении — вместо красного эмодзи 🗑. */
.g-iconbtn { display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 8px; cursor: pointer;
  border: 1px solid var(--sp-border); background: var(--sp-surface);
  color: var(--sp-ink-2); }
.g-iconbtn:hover { color: var(--sp-loss);
  border-color: color-mix(in srgb, var(--sp-loss) 45%, var(--sp-border));
  background: color-mix(in srgb, var(--sp-loss) 8%, var(--sp-surface)); }
.g-quiet { font-size: .72rem; }
.g-ev { border-top: 1px dashed var(--sp-border); padding-top: .4rem; }
/* Свернутый список трат дня (ред. 5.1): скрыт по умолчанию, раскрывается
   кликом по summary или наведением (gantt.js). */
.g-evlist { font-size: .72rem; }
.g-evlist summary { cursor: pointer; color: var(--sp-ink-2); font-weight: 700;
  padding: .25rem .35rem; border-radius: 7px; user-select: none;
  border-top: 1px dashed var(--sp-border); list-style: none; }
.g-evlist summary::-webkit-details-marker { display: none; }
.g-evlist summary::before { content: "▸ "; }
.g-evlist[open] summary::before { content: "▾ "; }
.g-evlist summary:hover { color: var(--sp-ink); background: var(--sp-surface-2); }
.g-evlist-body { display: flex; flex-direction: column; gap: .4rem;
  padding-top: .4rem; border-top: 1px dashed var(--sp-border); }
.g-evitem { position: relative; padding-right: 34px; border-bottom: 1px dashed var(--sp-border); padding-bottom: .35rem; }
.g-evitem:last-child { border-bottom: 0; padding-bottom: 0; }
.g-evdel { position: absolute; right: 0; top: 0; }

/* Свёрнутая строка траты месяца (решение владельца 2026-09-27): список
   виден целиком однострочниками «дата · статья · сумма», форма правки —
   в раскрытии ПО ОДНОЙ (аккордеон gantt.js) — поповер не раздувается.
   .g-evfold снимает правочный отступ .g-evitem: корзина переехала внутрь
   раскрытия. */
.g-evfold { padding-right: 0; }
.g-evline { display: flex; align-items: baseline; gap: .45rem; width: 100%;
  border: 0; background: transparent; border-radius: 7px; cursor: pointer;
  font: inherit; font-size: .72rem; padding: .24rem .35rem; text-align: left;
  color: var(--sp-ink-2); transition: background-color .12s ease, color .12s ease; }
.g-evline:hover { background: color-mix(in srgb, var(--sp-warn) 9%, transparent);
  color: var(--sp-ink); }
.g-evline-date { flex: 0 0 auto; color: var(--sp-ink-3);
  font-variant-numeric: tabular-nums; }
.g-evline-kind { flex: 1 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.g-evline-sum { flex: 0 0 auto; font-weight: 600; color: var(--sp-ink);
  font-variant-numeric: tabular-nums; }
.g-evline-car { flex: 0 0 auto; color: var(--sp-ink-3);
  transition: transform 120ms ease; }
.g-evfold.g-ev-open .g-evline-car { transform: rotate(90deg); }
.g-evbody { padding-top: .2rem; }
/* Клик по месяцу строки «Разовые» (пустое место/счётчик «×N») открывает
   все траты месяца — тот же поповер, что у дней. */
.g-evmonth[data-pop] { cursor: pointer; }

/* Разовые траты «рядом» в поповере дня (±7 дней — радиус магнита,
   gantt.js): клик по строке открывает поповер дня той траты. */
.g-near { display: flex; flex-direction: column; gap: 2px;
  border-top: 1px dashed var(--sp-border); padding-top: .4rem; }
.g-near-h { font-size: .66rem; font-weight: 800; color: var(--sp-ink-3);
  text-transform: uppercase; letter-spacing: .05em; padding: 0 .35rem .15rem; }
.g-near-item { display: flex; align-items: baseline; gap: .45rem; width: 100%;
  border: 0; background: transparent; border-radius: 7px; cursor: pointer;
  font-size: .74rem; padding: .24rem .35rem; text-align: left;
  color: var(--sp-ink-2); transition: background-color .12s ease, color .12s ease; }
.g-near-item:hover { background: color-mix(in srgb, var(--sp-warn) 9%, transparent);
  color: var(--sp-ink); }
.g-near-d { font-weight: 700; color: var(--sp-ink); min-width: 3.1rem; }
.g-near-k { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.g-near-s { color: var(--sp-ink-3); font-size: .68rem; max-width: 8.5rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.g-near-a { font-weight: 700; font-variant-numeric: tabular-nums; }

/* модалка создания удалена (ред. 8, решение владельца 2026-09-06):
   создание — только поповером, .g-dlg больше нет */
.hidden { display: none; }

/* ══ Мониторинг: сводка «P&L-лента» (rnp.html, редизайн 2026-09-07,
   live-вариант 1, accent=25%, разделители вкл — решения владельца).
   5 секций по бизнес-цепочке: Объём → Доходы → Маркетинг → Итог →
   Снабжение; метка 10px → главное число Manrope 17px → суб-метрики
   11px. Токены — обе темы автоматически; Δ — капсулы data-tone
   (семантика: падение ДРР = good). */
.rnp-sum { padding: 7px 14px 8px 16px; }
.rnp-sum-strip { display: flex; align-items: stretch; flex-wrap: wrap; row-gap: 8px; }
.rnp-sum-lane { display: flex; flex-direction: column; gap: 3px; padding: 2px 20px; min-width: 0; }
.rnp-sum-lane:first-child { padding-left: 0; }
.rnp-sum-lane:last-child { padding-right: 0; }
.rnp-sum-lane + .rnp-sum-lane { border-left: 1px solid var(--sp-border); }
.rnp-sum-label { font: 600 10px/1.4 "Inter", system-ui, sans-serif; letter-spacing: .06em; text-transform: uppercase; color: var(--sp-ink-3); }
.rnp-sum-main { font-family: "Manrope", "Inter", system-ui, sans-serif; font-weight: 700; font-size: 17px; line-height: 1.15; letter-spacing: -0.01em; color: var(--sp-ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
.rnp-sum-main[data-sign="minus"] { color: var(--sp-loss); }
.rnp-sum-est { font: 600 9px/1 "Inter", system-ui, sans-serif; font-style: normal; color: var(--sp-ink-3); margin-left: 3px; vertical-align: 4px; }
.rnp-sum-subs { display: flex; flex-wrap: wrap; align-items: center; gap: 3px 10px; font-size: 11px; line-height: 1.4; color: var(--sp-ink-2); font-variant-numeric: tabular-nums; }
.rnp-sum-subs em { font-style: normal; color: var(--sp-ink-3); }
.rnp-sum-d { font-weight: 600; font-size: 10.5px; line-height: 1.4; padding: 1px 7px; border-radius: 9999px; white-space: nowrap; }
.rnp-sum-d[data-tone="good"] { color: var(--sp-profit); background: var(--sp-profit-bg); }
.rnp-sum-d[data-tone="bad"] { color: var(--sp-loss); background: var(--sp-loss-bg); }

/* ══ Мониторинг: скин матрицы УНИФИЦИРОВАН с Финотчётом (2026-09-09):
   шапка «Индиго-гребень», сетка 70% и hover --sp-row-hover переехали
   в общий скоуп .fin-panel. Здесь остаются только специфичные вещи:
   переменная тепловой карты (аффорданс Tabulator-перетаскивания снесён
   демонтажем матрицы — фаза C «Один движок таблиц»). */
#rnp-matrix-wrap { --heat-k: 0; }

/* ══ Чек-лист (волна A0, §7.2–7.3 плана checklist_feature_plan.md):
   дневная матрица «день × колонки» в языке Мониторинга. Тон ячейки
   решает СЕРВЕР (heat.go → cl-good|neutral|warn|bad|none), CSS только
   красит: мягкая подложка color-mix токена по образцу .fin-heat,
   значение остаётся чернильным. Сплошные заливки референса запрещены.
   cl-none (нет оценки) — без заливки. */
#unit-checklist td.cl-good    { background: color-mix(in srgb, var(--sp-profit) 22%, transparent); }
#unit-checklist td.cl-neutral { background: color-mix(in srgb, var(--sp-surface-3) 45%, transparent); }
#unit-checklist td.cl-warn    { background: color-mix(in srgb, var(--sp-warn) 26%, transparent); }
#unit-checklist td.cl-bad     { background: color-mix(in srgb, var(--sp-loss) 24%, transparent); }

/* Активный сигнал: подсветка затронутых колонок матрицы (чип полосы
   «Требует внимания» / «В чек-лист с фильтром колонки»). */
#unit-checklist .is-flagged {
  outline: 2px solid var(--sp-brand);
  outline-offset: -2px;
  border-radius: 3px;
}

/* Sticky-колонка дат: позиция/фон/z-index — inline в шаблоне (A0-08),
   здесь только тень-край по образцу .rnp-d-meta, чтобы скролл читался. */
#unit-checklist .cl-date-col { box-shadow: 6px 0 8px -6px rgba(16, 24, 40, 0.22); }
html.dark #unit-checklist .cl-date-col { box-shadow: 6px 0 8px -6px rgba(0, 0, 0, 0.5); }

/* Дата-ссылка поповера дня (клик по дате = кнопка «+» рядом). */
.cl-day-link {
  cursor: pointer;
  text-decoration: underline dotted;
  text-decoration-color: transparent;
  text-underline-offset: 2px;
}
.cl-day-link:hover { text-decoration-color: var(--sp-ink-3); }

/* Точка-маркер: день с записями журнала / тон чипа сигнала (индига = нейтраль). */
.cl-dot {
  display: inline-block; width: 6px; height: 6px; flex: none;
  border-radius: 9999px; background: var(--sp-brand);
}
.cl-dot[data-tone="loss"] { background: var(--sp-loss); }
.cl-dot[data-tone="warn"] { background: var(--sp-warn); }

/* Δ% к предыдущему дню под значением ячейки (E.1, G6): цвет ТОЛЬКО по
   знаку — канон Δ-цветов fin-delta (--sp-delta-up/down); направление
   «хорошо/плохо» остаётся тепловой заливке значения (cl-*). */
.cl-delta { margin-top: 1px; white-space: nowrap; }
.cl-delta[data-tone="good"] { color: var(--sp-delta-up); }
.cl-delta[data-tone="bad"]  { color: var(--sp-delta-down); }

/* Свёрнутая секция: подколонки прячет unit_checklist.js (data-cl-sec по
   data-collapsed бэнда), colspan бэнда сжат до 1; стрелка показывает
   направление разворота. */
.cl-collapsed { display: none; }
#unit-checklist [data-cl-section][data-collapsed="true"] [data-cl-toggle] { transform: rotate(-90deg); }

/* Ошибка сохранения записи журнала: ответ при hx-swap="none" не
   свапается — текст кладёт unit_checklist.js (htmx:responseError). */
.cl-form-err { color: var(--sp-loss); font-size: 11.5px; }

/* ── «География спроса»: визуальная ячейка + поповер (волна 2026-09-09) ── */
.rnp-geo { display: flex; flex-direction: column; gap: 2px; text-align: left; min-width: 0; }
.rnp-geo-bar { display: flex; gap: 1px; height: 4px; border-radius: 2px; overflow: hidden; background: var(--sp-surface-3); }
/* Гео-бары ячейки — брендовая лесенка рангов (решение владельца
   2026-09-26: цвет данным-визуализации возвращён, де-синизация осталась
   на хроме таблицы — шапка-гребень, метки сводки). */
.rnp-geo-seg { flex-basis: 0; min-width: 0; height: 100%; }
.rnp-geo-seg[data-rank="1"] { background: var(--sp-brand-strong); }
.rnp-geo-seg[data-rank="2"] { background: var(--sp-brand-strong); opacity: .66; }
.rnp-geo-seg[data-rank="3"] { background: var(--sp-brand-strong); opacity: .42; }
.rnp-geo-seg[data-rank="rest"] { background: var(--sp-ink-3); opacity: .35; }
.rnp-geo-line { font-size: 12px; line-height: 1.15; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
.rnp-geo-cov { font-size: 10.5px; line-height: 1.15; color: var(--sp-ink-3); }
.rnp-geo-sep { color: var(--sp-ink-3); margin: 0 5px; }
.rnp-geo-trigger { cursor: pointer; border-radius: 4px; }
.rnp-geo-trigger:focus-visible { outline: 2px solid var(--sp-brand-strong); outline-offset: 2px; }
/* Поповер полного разбора */
.rnp-geo-pop { position: fixed; z-index: 90; width: 264px; max-height: min(70vh, 480px); overflow-y: auto;
  background: var(--sp-surface); border: 1px solid var(--sp-border); border-radius: 14px;
  box-shadow: var(--sp-shadow-menu); padding: 12px 14px; color: var(--sp-ink);
  font-size: 12px; line-height: 1.35; }
.rnp-geo-pop[hidden] { display: none; }
.rnp-geo-pop-title { font-size: 13px; font-weight: 600; }
.rnp-geo-pop-sub { margin-top: 3px; font-size: 11px; color: var(--sp-ink-2); }
.rnp-geo-pop .rnp-geo-bar { height: 4px; margin: 10px 0 8px; }
.rnp-geo-row { display: grid; grid-template-columns: 90px 1fr auto auto; gap: 8px; align-items: center; padding: 4px 0; }
.rnp-geo-row-name { font-weight: 600; }
.rnp-geo-row-track { display: block; height: 4px; border-radius: 2px; background: var(--sp-surface-3); overflow: hidden; }
.rnp-geo-row-bar { display: block; height: 100%; min-width: 4px; border-radius: 2px; background: var(--sp-brand-strong); opacity: .8; }
.rnp-geo-row-count { font-variant-numeric: tabular-nums; color: var(--sp-ink-2); text-align: right; min-width: 24px; }
.rnp-geo-row-pct { font-variant-numeric: tabular-nums; font-weight: 700; min-width: 38px; text-align: right; }
.rnp-geo-row-undef { border-top: 1px dashed var(--sp-border); margin-top: 6px; padding-top: 7px; }
/* «Не определён» шире округов (слово «определён» = 86px @ 12px/600) —
   переносим на 2 строки ЧИСТО: колонка 90px держит «определён» без
   подрезки треком, компактный интерлиньяж держит блок собранным. */
.rnp-geo-row-undef .rnp-geo-row-name { line-height: 1.2; }
.rnp-geo-row-undef .rnp-geo-row-bar { background: var(--sp-ink-3); opacity: .55; }
.rnp-geo-total { border-top: 1px solid var(--sp-border); margin-top: 7px; padding-top: 7px;
  display: flex; justify-content: space-between; font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; }
.rnp-geo-pop[data-pinned="1"] { border-color: var(--sp-brand-strong); }

/* ── Микрофидбек копирования (план П6 §2.5): бабл «ID скопирован» у места
   клика вместо глобального тоста. Абсолютный к документу, по центру над
   элементом; auto-hide в app.js (copyFeedback). ── */
.sp-copy-bubble { position: absolute; z-index: 90; transform: translate(-50%, -100%);
  background: var(--sp-ink); color: var(--sp-bg); font-size: 11px; font-weight: 600;
  line-height: 1; padding: 6px 9px; border-radius: 999px; pointer-events: none;
  white-space: nowrap; box-shadow: 0 2px 8px rgba(0,0,0,.18); }
.sp-copy-bubble::after { content: ''; position: absolute; left: 50%; top: 100%;
  transform: translateX(-50%); border: 4px solid transparent; border-top-color: var(--sp-ink); }
.sp-copy-bubble-err { background: var(--sp-loss); }
.sp-copy-bubble-err::after { border-top-color: var(--sp-loss); }

/* ── Центр уведомлений: «очистить все» — улёт строк (решение владельца
   2026-09-26). Строки панели волной улетают вправо (animation-delay
   ставит app.js, 35 мс на строку). Сдвиг короткий и затухающий — за
   границы скролл-контейнера панели не выходим, иначе мигнул бы
   горизонтальный скроллбар (overflow-y:auto делает overflow-x авто). ── */
@keyframes sp-notify-sweep {
  from { opacity: 1; transform: translateX(0); }
  to   { opacity: 0; transform: translateX(56px); }
}
.sp-notify-sweep {
  animation: sp-notify-sweep 320ms cubic-bezier(0.55, 0, 0.85, 0.45) both;
  pointer-events: none; /* строки уже удалены на сервере — клики мимо */
}
@media (prefers-reduced-motion: reduce) {
  .sp-notify-sweep { animation-duration: 0.01ms; animation-delay: 0ms; }
}
