:root{--bg:#0f0d12;--panel:#17141b;--line:#2a2530;--txt:#e8e3ee;--dim:#8f88a0;
--acc:#c2185b;--acc2:#ff4081;--good:#3ddc84;--bad:#ff5c5c;
/* Поверхности поверх панели: шапка таблицы и поля ввода (panel2), всплывашки
   и чипы пресетов (panel3), разделитель строк таблицы (line2). До 16.09.2026
   эти три значения были рассыпаны шестнадцатью литералами по app.css
   и predict.css — правка темы требовала искать их поиском по файлам */
--panel2:#1e1a24;--panel3:#241f2b;--line2:#221e29;
/* Палитра кривых графика — единственное место, где она задана: сервер читает
   эти значения из файла (app.py:_series_colors), браузер — через
   getComputedStyle (app.js:PICKC). Прошлая палитра не проходила валидатор
   dataviz (все шесть тонов вне полосы светлоты L 0.48–0.67) и занимала
   статусные цвета: слот 1 был --good, слот 2 — акцентный --acc2, то есть
   «цвет серии» и «цвет хорошего» совпадали. Эти шесть проверены:
   node scripts/validate_palette.js "…" --mode dark --surface "#17141b"
   → полоса светлоты, цветность, CVD ΔE 8.4, нормальное зрение 19.3,
   контраст — ALL CHECKS PASS */
--s1:#3987e5;--s2:#d95926;--s3:#199e70;--s4:#c98500;--s5:#d55181;--s6:#008300}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--txt);
font:13px/1.45 -apple-system,Segoe UI,Roboto,sans-serif}
a{color:var(--acc2);text-decoration:none}a:hover{text-decoration:underline}
header{background:linear-gradient(90deg,#7b1236,#c2185b);padding:9px 16px;
display:flex;gap:18px;align-items:center;position:sticky;top:0;z-index:10}
header b{font-size:15px;letter-spacing:.5px}
main{padding:16px}
h1{font-size:19px;margin:0 0 4px}
.sub{color:var(--dim);margin-bottom:12px}
/* Мера строки. Абзац методики шёл во всю ширину окна — 1556 px, около 200
   символов в строке при читаемой норме 60–80, и глаз терял начало следующей */
p.sub,.note{max-width:78ch}
.note{background:#241a10;border:1px solid #5a4020;color:#e8c898;padding:8px 12px;
border-radius:8px;margin-bottom:14px;font-size:12px}
.card{background:var(--panel);border:1px solid var(--line);border-radius:8px;
padding:12px 14px;margin-bottom:14px}
.f{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end}
.f label{display:block;color:var(--dim);font-size:11px;text-transform:uppercase;
letter-spacing:.5px;margin-bottom:3px}
.grid{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:14px}
/* min-width считан по самой широкой плитке (профит со спарклайном): плитки
   разной ширины в одном ряду читаются как сбой вёрстки */
.kv{background:var(--panel);border:1px solid var(--line);border-radius:8px;
padding:8px 12px;min-width:128px}
.kv span{display:block;color:var(--dim);font-size:11px;text-transform:uppercase;
letter-spacing:.6px}
.kv b{font-size:17px;font-weight:600}
/* Иерархия плиток: ИТМ и ROI крупно (первая воспроизводима, вторая — главная
   результатная метрика), ABI и $/вход мелко. Тот же приём, каким в таблице
   разведены ИТМ и ROI: размер и яркость вместо порядка следования */
.kv.hi b{font-size:22px}
.kv.lo b{font-size:15px;color:#b9b2c6}
/* Дельта к предыдущему периоду той же длины: плитки перестали дословно
   повторять строку «Итого», видную на том же экране двенадцатью строками ниже */
.kv i{display:block;font-style:normal;font-size:11.5px;margin-top:1px}
.kv svg.spark{display:block;margin-top:3px}
table{border-collapse:collapse;width:auto;font-size:12.5px}
/* Прокрутка таблицы — внутри контейнера, и это не косметика. th{position:sticky}
   прилипает к ближайшему прокручиваемому родителю; при overflow-x:auto без
   ограничения высоты scrollHeight равен clientHeight, вертикальной прокрутки
   внутри нет, липнуть не к чему — и при прокрутке страницы шапка уезжала
   (замер: th.top = −288 px, числа 20 колонок без подписей) */
.scroll{overflow:auto;max-height:70vh;border:1px solid var(--line);
border-radius:8px;background:var(--panel)}
th{background:var(--panel2);color:var(--dim);text-align:left;padding:7px 10px;
position:sticky;top:0;z-index:2;white-space:nowrap;font-weight:600;overflow:hidden;
/* Не border-bottom: при border-collapse:collapse граница липкой ячейки уезжает
   вместе с содержимым таблицы, а внутренняя тень остаётся на месте */
box-shadow:inset 0 -1px 0 var(--line)}
/* Верхний ярус шапки — блоки колонок (Ключ · Объём · Результат · Качество ·
   Контекст). Высота фиксирована: второй ярус липнет ровно под неё */
tr.grp th{top:0;height:23px;line-height:15px;padding:3px 10px;text-align:center;
color:var(--txt);background:var(--panel3)}
tr.cols th{top:23px}
td{padding:6px 10px;border-bottom:1px solid var(--line2);white-space:nowrap;
max-width:460px;overflow:hidden;text-overflow:ellipsis}
/* Колонки ключа при горизонтальной прокрутке. Таблица шире контейнера
   (2058 px против 1587 в срезе «Кастомка»), и без закрепления, уехав вправо,
   теряешь, чья это строка. Фон обязателен: под липкой ячейкой идут строки.
   Смещение left приходит правилом на страницу (app.py:_pin_css): инлайновый
   стиль на каждой ячейке стоил 15 КБ хвоста строк в срезе «Кастомка» */
td.pin{position:sticky;z-index:1;background:var(--panel)}
th.pin{z-index:3}
/* Ячейка яруса блоков над колонками ключа: закреплена у левого края,
   ширину ей даёт colspan — она равна сумме закреплённых колонок */
th.gpin{position:sticky;left:0;z-index:3}
tr:hover td{background:#1c1822}
tr.tot td{font-weight:700;background:#221726}
.num{text-align:right;font-variant-numeric:tabular-nums}
th+th,td+td{border-left:1px solid #201c27}
.pos{color:var(--good)}.neg{color:var(--bad)}.dim{color:var(--dim)}
.sm{font-size:11px}
/* ИТМ — основная метрика таблицы, ROI рядом идёт классом dim. Вес задан
   размером и яркостью: ROI ячейки не воспроизводится (корреляция половин
   выборки 0.13–0.52), ИТМ воспроизводится (0.23–0.93) */
.big{font-size:14px;font-weight:600}
/* Тепловые карты: цвет ячейки приходит инлайном из _heat_color, здесь только
   геометрия. Ячейка узкая и по центру — карту читают глазами как решётку,
   а не как таблицу с числами по правому краю */
/* Ширина — во всю панель: карта читается как решётка, и узкий столбик
   ячеек у левого края при пустых двух третях экрана рядом не читается */
.heatmap{margin-bottom:10px;width:100%;max-width:1100px;table-layout:fixed}
.heatmap td.heat{text-align:center;padding:9px 8px;
font-variant-numeric:tabular-nums;font-weight:600}
.heatmap td.heat small{display:block;font-weight:400;color:var(--dim);font-size:10px}
.heatmap td.empty{color:#463f52;background:#181420}
.heatmap th{position:static;background:var(--panel2)}
.heatmap tbody th{text-align:right;font-weight:600;color:var(--txt);
overflow:hidden;text-overflow:ellipsis}
.heatmap thead th:first-child,.heatmap tbody th{width:150px;max-width:150px}
/* Таблицы вне контейнера .scroll: тревоги, «Куда смотреть сейчас», карты.
   Класс .tbl стоял в разметке с самого начала и нигде не был определён.
   Липкая шапка им не только не нужна, но и вредна: прокручиваемого родителя
   у них нет, и заголовки прилипали к окну, уезжая под шапку сайта */
.tbl{max-width:1100px}
.tbl th{position:static}
ul.flags{margin:0 0 12px;padding-left:18px;color:#e8c898;font-size:12px}
ul.flags li{margin-bottom:3px}
/* Лента тревог. Красная рамка — единственная на вкладке: это блок «посмотри
   сюда сейчас», и он должен отличаться от карточек и таблиц */
.alerts{border-color:#7a2a3c;background:#1b1319;border-left:3px solid var(--acc2)}
.alerts summary{cursor:pointer;font-weight:600;margin-bottom:8px;font-size:14px}
.alerts summary .bad,.alerts summary .ok{font-weight:700;margin-left:6px}
.alerts summary .ok{color:var(--good)}
.alerts table{margin-bottom:8px}
/* Тир под румом: одна просадка часто видна на двух уровнях, и вторая строка
   должна читаться как уточнение первой, а не как отдельная тревога */
.alerts tr.sub2 td{color:var(--dim);background:#181119}
.alerts tr.sub2 td.big{color:var(--txt)}
/* Панель «Куда смотреть сейчас» — списки с деньгами. Зелёная отбивка против
   красной у тревог: тревога говорит «сломалось», панель — «вот работа» */
.focus{border-left:3px solid var(--good)}
.focus summary{cursor:pointer;font-weight:600;font-size:14px;margin-bottom:8px}
.focus table{margin-bottom:8px}
/* Названия списков — обычным цветом текста: акцентный розовый читается как
   тревога, а это не тревога, а работа. Подчёркивание при наведении остаётся */
.focus td:first-child{font-weight:600}
.focus td a{color:var(--txt)}
.focus td.sm{color:#9d95ad;max-width:none;white-space:normal}
input,select,button{background:var(--panel2);color:var(--txt);border:1px solid var(--line);
border-radius:6px;padding:6px 9px;font:inherit}
select[multiple]{min-height:74px}
button{background:var(--acc);border-color:var(--acc);cursor:pointer;font-weight:600}
button:hover{background:var(--acc2)}
/* Фильтры-кнопки: значение видно на самой кнопке, панель раскрывается по клику */
.fbar{display:flex;flex-wrap:wrap;gap:7px;align-items:center}
.fchip{position:relative}
.fchip .fbtn{background:var(--panel2);border:1px solid var(--line);border-radius:16px;
padding:5px 12px;color:var(--dim);font-weight:500;white-space:nowrap;cursor:pointer}
.fchip .fbtn:hover{border-color:var(--acc2)}
.fchip .ft{color:var(--dim)}
.fchip .fbtn b{color:var(--txt);font-weight:600;margin-left:6px}
.fchip .fcar{color:var(--dim);margin-left:6px;font-size:10px}
.fchip.on .fbtn{background:#2a1020;border-color:var(--acc);color:var(--acc2)}
.fchip.on .ft{color:var(--acc2)}
.fchip.on .fbtn b{color:#fff}
.fpanel{display:none;position:absolute;top:calc(100% + 5px);left:0;z-index:30;
background:var(--panel);border:1px solid var(--line);border-radius:8px;
padding:10px;box-shadow:0 8px 24px #000a}
.fchip.open .fpanel{display:block}
.fchip.open .fbtn{border-color:var(--acc2)}
.frow{display:flex;gap:6px;align-items:center;margin-bottom:6px}
.frow label{color:var(--dim);font-size:11px;text-transform:uppercase;
letter-spacing:.5px;min-width:74px;margin:0}
.fck{display:block;padding:2px 0;color:var(--txt);text-transform:none;
font-size:12.5px;cursor:pointer;break-inside:avoid}
.fck input{margin-right:6px;vertical-align:-1px}
.fcols{column-gap:14px}
.fsep{border:0;border-top:1px solid var(--line);margin:6px 0}
.fpre{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px;padding-top:8px;
border-top:1px solid var(--line)}
.fpre a{background:var(--panel3);border-radius:10px;padding:2px 9px;font-size:11.5px;
color:var(--dim)}
.fpre a:hover{background:var(--acc);color:#fff;text-decoration:none}
.tabs{display:flex;gap:6px;margin-bottom:12px;flex-wrap:wrap;align-items:center}
.tabs a{background:var(--panel);border:1px solid var(--line);border-radius:6px;
padding:6px 12px;color:var(--txt)}
.tabs a.on{background:var(--acc);border-color:var(--acc);color:#fff}
/* Разделитель групп вкладок разрезов: базовые ключи фонда · измерения
   турнира · разбор. Одиннадцать кнопок в ряд читались как один список
   равнозначных вариантов, хотя это три разных вопроса */
.tabs .tsep{width:1px;height:20px;background:var(--line);margin:0 4px}
.chart{background:var(--panel);border:1px solid var(--line);border-radius:8px;
padding:10px;margin-top:14px;position:relative}
/* Подсказка курсора. position:absolute внутри .chart, потому что SVG тянется
   по ширине окна: в координатах viewBox подсказка уехала бы при любом
   масштабе. pointer-events:none обязателен — иначе она перехватывает
   mousemove у себя под курсором и начинает мигать. */
.chart .tip{position:absolute;display:none;pointer-events:none;z-index:5;
background:var(--panel3);border:1px solid var(--line);border-radius:6px;
padding:6px 9px;font-size:12px;line-height:1.5;white-space:nowrap;
box-shadow:0 4px 14px #0008}
.chart .tip b{color:#fff;font-weight:600}
.chart .tip .d{color:var(--dim)}
.chart svg.roll{cursor:crosshair}
/* Метки панелей сравнения — те же слоты серийной палитры, что у линий A и B
   на графике (app.py:COLOR_A/COLOR_B). Раньше это были --good и --acc2:
   «панель A» читалась цветом «хорошо», а «панель B» — цветом ссылки */
.pa{color:var(--s1);font-size:15px}.pb{color:var(--s2);font-size:15px}
h2.pan{font-size:15px;margin:20px 0 8px;text-transform:none;letter-spacing:0}
h2.pan small{color:var(--dim);font-weight:400;margin-left:8px;font-size:12px}
.tools{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px;align-items:center}
.tools a{background:var(--panel);border:1px solid var(--line);border-radius:6px;
padding:5px 11px;color:var(--txt);font-size:12px}
.tools a:hover{background:var(--panel3);text-decoration:none}
.tools span{color:var(--dim);font-size:11px;text-transform:uppercase;letter-spacing:.5px}
details>summary{cursor:pointer;color:var(--acc2);padding:7px 0;font-weight:600;
list-style:none}
details>summary::-webkit-details-marker{display:none}
details>summary::before{content:"▸ ";font-size:11px}
details[open]>summary::before{content:"▾ "}
th.s{cursor:pointer;user-select:none}
th.s:hover{color:var(--txt)}
th.s::after{content:"⇅";opacity:.3;margin-left:3px;font-size:9px}
th.s.asc::after{content:"↑";opacity:1;color:var(--acc2)}
th.s.desc::after{content:"↓";opacity:1;color:var(--acc2)}
.pager{display:flex;gap:4px;align-items:center;margin:8px 0 12px;flex-wrap:wrap}
.pager a{min-width:28px;text-align:center;padding:4px 7px;border:1px solid var(--line);
border-radius:6px;background:var(--panel);color:var(--txt);font-size:12px;cursor:pointer;
user-select:none}
.pager a:hover{background:var(--panel3);text-decoration:none}
.pager a.on{background:var(--acc2);border-color:var(--acc2);color:#fff}
.pager a.off{opacity:.3;cursor:default;pointer-events:none}
.pager span{color:var(--dim);font-size:12px;padding:0 4px}
.pager .cnt{margin-left:auto}
/* Выбор строк для графика. Левая граница красится цветом своей кривой через
   инлайновый style — так подсветка строки и линия на графике совпадают. */
tr.pick{cursor:pointer}
tr.pick:hover>td{background:var(--panel3)}
tr.pick.on>td{background:var(--panel3)}
tr.pick.on>td:first-child{box-shadow:inset 3px 0 0 var(--c,var(--acc2))}
.picked{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:8px 0 4px;
font-size:12px;color:var(--dim)}
.picked b{font-weight:600}
.picked a{color:var(--acc2);cursor:pointer}
.picked .warn{color:#ffb300}
/* Индикатор частичного обновления htmx. Раньше гасился весь #main на 0.7–2.5 с,
   и вместе с ним моргали фильтры и вкладки — то есть ровно те элементы, по
   которым в этот момент хочется щёлкнуть ещё раз. Теперь гаснут только данные
   (плитки и таблица), а ход запроса показывает узкая полоса под шапкой сайта */
#main.htmx-request .grid,#main.htmx-request .scroll{opacity:.45;
transition:opacity .1s ease}
#main.htmx-request::before{content:"";position:fixed;left:0;right:0;top:38px;
height:2px;z-index:20;background:linear-gradient(90deg,
transparent,var(--acc2),transparent);background-size:42% 100%;
background-repeat:no-repeat;animation:hxbar 1.1s linear infinite}
@keyframes hxbar{from{background-position:-42% 0}to{background-position:142% 0}}
/* ── Подсказки о данных ──
   Тот же приём, что на вкладке «Модель ROI»: текст лежит в data-help, всплывашка
   одна на страницу (#helptip) и позиционируется у курсора. Своя, а не title
   браузера: у title задержка около секунды, он не переносит строки по-русски
   и не даёт оформить заголовок колонки отдельно от описания. */
#helptip{position:fixed;z-index:60;pointer-events:none;opacity:0;
transition:opacity .08s ease;max-width:380px;background:var(--panel3);
border:1px solid var(--line);border-radius:7px;padding:8px 10px;font-size:12px;
line-height:1.5;box-shadow:0 8px 24px #000a}
#helptip .t{font-weight:600;color:#fff;margin-bottom:4px}
#helptip .h{color:var(--dim)}
[data-help]{cursor:help}
/* Значок ⓘ у заголовков: у сортируемых колонок ⇅ уже занял ::after, поэтому
   значок ставится перед текстом через ::before */
th[data-help]::before{content:"ⓘ";opacity:.45;margin-right:3px;font-size:.85em}
th[data-help]:hover::before{opacity:1;color:var(--acc2)}
.kv span[data-help]::after,h2[data-help]::after,.f label[data-help]::after,
summary[data-help]::after{
content:"ⓘ";opacity:.45;margin-left:4px;font-size:.9em}
/* Подсказка длиной в абзац (методика ленты тревог — 1061 символ) в 380 px
   выходила колонкой на пол-экрана */
#helptip{max-width:520px}

/* ── Узкое окно ──
   До 16.09.2026 в app.css не было ни одного медиазапроса. Ниже ~1100 px
   шестая плитка KPI уходила в свою строку сиротой, а ряд фильтров-чипов
   занимал три ряда вперемешку с вкладками разрезов. */
@media (max-width:1100px){
  main{padding:12px}
  .grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr))}
  .kv{min-width:0}
  .kv.hi b{font-size:19px}
  /* Таблица и без того шире окна — отдаём ей всю доступную высоту */
  .scroll{max-height:76vh}
  p.sub,.note{max-width:none}
}
