/* ТАБЛО · тёмная тема по эталону design/mockup.html.
   Значения цветов, размеров и длительностей — из мокапа, не из головы.
   Pico.css больше не используется: эталон самодостаточен, а два набора
   правил друг под другом — это спор селекторов на каждой странице. */

:root {
  --bg: #0E1218;
  --surface: #171C26;
  --surface-2: #1D2331;
  --line: #262E3C;
  --line-strong: #333C4D;
  --text: #E9EDF3;
  --text-dim: #949EB0;
  --text-faint: #646E80;

  --bad:  #C97A72;
  --good: #79A894;
  --warn: #BFA167;

  /* Акцент раздела: ДРР по умолчанию, остальные через data-section. */
  --accent: #6FB3C4;
  --accent-dim: #2A5C68;

  --wb-fuchsia: #E8148F;
  --wb-violet: #7B2FBE;
}

/* Акцент привязан к ГРУППЕ меню, не к блоку (решение 13.08.2026): цвет
   означает «где я нахожусь». «Реклама» живёт на акценте по умолчанию
   (голубой ДРР), у остальных групп свой приглушённый цвет в духе эталона. */
body[data-section="tasks"] { --accent: #C4899E; --accent-dim: #6B4351; }  /* Задачи · пыльная роза */
body[data-section="sklad"] { --accent: #9A8FCB; --accent-dim: #4A3F78; }  /* Склад · фиолетовый (был у Остатков) */
body[data-section="tovar"] { --accent: #7FB49B; --accent-dim: #33604F; }  /* Товар · шалфей (был у Поставок) */
body[data-section="rynok"] { --accent: #C4A56E; --accent-dim: #6B5630; }  /* Рынок · золото (был у Цен) */
body[data-section="system"] { --accent: #8A98AB; --accent-dim: #414B59; } /* Служебное · сталь */

* { box-sizing: border-box; }

body {
  margin: 0; background: var(--bg); color: var(--text);
  font: 400 14px/1.5 -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); }
h2, h3, h4 { font-weight: 500; }

/* ── Каркас ─────────────────────────────────────────────────────────── */

.app { position: relative; display: grid; grid-template-columns: 214px 1fr; min-height: 100vh; }

.side { position: relative; z-index: 2; background: var(--surface); border-right: 1px solid var(--line); padding: 22px 0; }
body[data-section="home"] .side {
  background: color-mix(in srgb, var(--surface) 86%, transparent);
  backdrop-filter: blur(7px);
}

/* Вывеска. Знак и слово — один объект, по нему проходит полоса.
   Свечение НЕ обрезается (Etap_interfeys_pravki §1.1): отсвет рисуется за
   границей блока, поэтому overflow у самой вывески visible с запасом поля,
   а прячется только бегущая полоса — в собственном клип-контейнере.
   Проверка: надпись светится на фоне одинаково со всех четырёх сторон. */
.lock {
  position: relative; display: block; text-align: center;
  padding: 16px 20px 10px; overflow: visible;
}
.lockclip { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.lockword {
  display: inline-block;
  font-size: 27px; font-weight: 500; letter-spacing: .2em;
  color: #fff; will-change: text-shadow;
  text-shadow:
    0 0 5px #fff, 0 0 13px var(--wb-fuchsia), 0 0 26px var(--wb-fuchsia),
    0 0 50px var(--wb-violet), 0 0 84px var(--wb-violet);
  animation: sign 8s infinite;
}
@keyframes sign {
  0%, 18%, 20.2%, 22%, 24.2%, 61%, 63.2%, 100% {
    text-shadow: 0 0 5px #fff, 0 0 13px var(--wb-fuchsia), 0 0 26px var(--wb-fuchsia),
                 0 0 50px var(--wb-violet), 0 0 84px var(--wb-violet);
    color: #fff;
  }
  19%, 21%, 23%, 62% {
    text-shadow: 0 0 4px rgba(255,255,255,.3), 0 0 10px rgba(232,20,143,.4);
    color: #E9D3E4;
  }
}
.scanline {
  position: absolute; left: 24px; right: 24px; top: 12px; height: 2px;
  background: linear-gradient(90deg, transparent, var(--wb-fuchsia), transparent);
  opacity: .75; filter: blur(.4px);
  animation: scanpass 5.5s cubic-bezier(.45,0,.55,1) infinite;
}
@keyframes scanpass {
  0%, 68% { transform: translateY(-4px); opacity: 0 }
  72% { opacity: .8 }
  96% { transform: translateY(34px); opacity: .8 }
  100% { transform: translateY(38px); opacity: 0 }
}

.tagline { padding: 0 20px 22px; font-size: 10.5px; letter-spacing: .18em; color: var(--text-faint); text-transform: uppercase; }

.side nav a {
  display: block; padding: 7px 20px; color: var(--text-dim); text-decoration: none;
  font-size: 13.5px; border-left: 2px solid transparent;
  transition: color .18s ease, background .18s ease, border-color .18s ease, padding-left .18s ease;
}
.side nav a:hover {
  color: var(--text); background: rgba(255,255,255,.025); padding-left: 24px;
  text-shadow: 0 0 9px color-mix(in srgb, var(--accent) 55%, transparent);
}
.side nav a.on {
  color: var(--text); border-left-color: var(--accent);
  background: linear-gradient(90deg, color-mix(in srgb, var(--accent) 13%, transparent), transparent 70%);
}
.grp { padding: 15px 20px 5px; font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-faint); }

.sidebar-user { padding: 16px 20px 0; font-size: 11.5px; color: var(--text-faint); line-height: 1.5; word-break: break-all; }
.side form { padding: 8px 20px 0; }
.side select { width: 100%; }
.account-single { padding: 8px 20px 0; font-size: 13px; color: var(--text-dim); }

.main { position: relative; z-index: 1; padding: 22px 26px 60px; min-width: 0; }

/* Заголовок раздела: единственный неон внутри страницы. */
.head { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; }
h1, .main > h2:first-child {
  margin: 0; font-size: 24px; font-weight: 500; letter-spacing: .02em; color: #fff;
  text-shadow: 0 0 4px rgba(255,255,255,.8), 0 0 12px var(--accent),
               0 0 30px color-mix(in srgb, var(--accent) 62%, transparent),
               0 0 62px color-mix(in srgb, var(--accent) 28%, transparent);
  animation: rise .5s cubic-bezier(.2,.7,.3,1) both;
}
.sub { color: var(--text-dim); font-size: 13px; animation: rise .5s .06s cubic-bezier(.2,.7,.3,1) both; }

.rule { position: relative; height: 1px; margin: 13px 0 18px; background: var(--line); overflow: hidden; }
.rule::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  transform: translateX(-100%); animation: sweep 3.4s ease-in-out infinite;
}
@keyframes sweep { 0% { transform: translateX(-100%) } 55%,100% { transform: translateX(100%) } }

@keyframes rise { from { opacity: 0; transform: translateY(6px) } to { opacity: 1; transform: none } }

/* ── Формы и фильтры ────────────────────────────────────────────────── */

form.filters, .filters { display: flex; gap: 8px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 16px; }
form.filters label { margin: 0; display: flex; flex-direction: column; gap: 3px; font-size: 11.5px; color: var(--text-dim); }

select, input, textarea, button {
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--line-strong); border-radius: 6px;
  padding: 6px 10px; font: inherit; font-size: 13px;
  transition: border-color .16s, background .16s, transform .1s;
}
select:hover, input:hover, button:hover { border-color: var(--accent-dim); }
select:focus, input:focus, textarea:focus { outline: none; border-color: var(--accent); }
input[type="checkbox"] { width: 15px; height: 15px; accent-color: var(--accent); padding: 0; }
button { cursor: pointer; }
button:active { transform: scale(.985); }
button.go, a.go, button[type="submit"]:not(.secondary):not(.outline) {
  background: color-mix(in srgb, var(--accent) 15%, var(--surface-2));
  border-color: var(--accent-dim);
}
button.go:hover, a.go:hover, button[type="submit"]:not(.secondary):not(.outline):hover {
  background: color-mix(in srgb, var(--accent) 25%, var(--surface-2));
  /* Неон под курсором — свечение, не мерцание. */
  box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 28%, transparent);
}
/* Ссылка-кнопка (выгрузка): выглядит и стоит как кнопка. */
a.go {
  display: inline-block; padding: 6px 10px; border: 1px solid var(--accent-dim);
  border-radius: 6px; color: var(--text); text-decoration: none; font-size: 13px;
}
button:disabled { opacity: .45; cursor: not-allowed; }
label { font-size: 12px; color: var(--text-dim); }

.checkbox-inline { display: flex; flex-direction: row !important; align-items: center; gap: 6px; }

.form-error { color: var(--bad); font-size: 13px; }

/* ── Карточки ───────────────────────────────────────────────────────── */

.cards, .stat-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-bottom: 20px; }
.card, .stat-card {
  position: relative; overflow: hidden; display: block; text-decoration: none; color: var(--text);
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px;
  animation: rise .5s cubic-bezier(.2,.7,.3,1) both;
  transition: border-color .2s, transform .2s;
}
.card:nth-child(1), .stat-card:nth-child(1) { animation-delay: .04s }
.card:nth-child(2), .stat-card:nth-child(2) { animation-delay: .09s }
.card:nth-child(3), .stat-card:nth-child(3) { animation-delay: .14s }
.card:nth-child(4), .stat-card:nth-child(4) { animation-delay: .19s }
.card:hover, .stat-card:hover { border-color: var(--line-strong); transform: translateY(-1px); }
.card::before, .stat-card::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  opacity: 0; transition: opacity .3s;
}
.card:hover::before, .stat-card:hover::before { opacity: .8; }
.card .lbl, .stat-card .muted { font-size: 11.5px; color: var(--text-dim); letter-spacing: .03em; }
.card .val, .stat-card .value { font-size: 24px; font-weight: 500; margin-top: 4px; font-variant-numeric: tabular-nums; }
/* Пара «вчера / месяц» в одной карточке (§2.2): месяц мельче и тусклее,
   слеш совсем тихий — вчера остаётся главным числом. */
.card .val .val-sep { margin: 0 6px; color: var(--text-faint); font-weight: 400; }
.card .val .val-month { font-size: 16px; color: var(--text-dim); font-weight: 400; }
.card .delta, .stat-card small { font-size: 12px; margin-top: 2px; font-variant-numeric: tabular-nums; color: var(--text-dim); display: block; }

.mini { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 14px 0 4px; }
.mini .card .val, .mini .stat-card .value { font-size: 19px; }

/* ── Таблица — главный компонент ────────────────────────────────────── */

.tblwrap, .table-scroll {
  border: 1px solid var(--line); border-radius: 10px; overflow: auto;
  max-height: 74vh; background: var(--surface);
}
table { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 12.5px; }
thead th {
  position: sticky; top: 0; z-index: 2; background: var(--surface-2); color: var(--text-dim);
  font-weight: 400; text-align: right; white-space: nowrap; padding: 8px 10px;
  border-bottom: 1px solid var(--line-strong); font-size: 11px; letter-spacing: .04em;
}
thead th:first-child { text-align: left; position: sticky; left: 0; z-index: 3; }
tbody td {
  padding: 5px 10px; text-align: right; white-space: nowrap;
  border-bottom: 1px solid rgba(255,255,255,.035);
  font-variant-numeric: tabular-nums;
}
tbody td:first-child { text-align: left; position: sticky; left: 0; background: var(--surface); z-index: 1; border-right: 1px solid var(--line); }
td.num, th.num { text-align: right; }

/* Каскад «выкладывания» строк: идёт по первым ~15 строкам и укладывается в
   полсекунды НЕЗАВИСИМО от их числа — у строк дальше пятнадцатой задержки
   нет, они появляются сразу (на боевом кабинете в 300 строк линейный шаг
   дал бы семь секунд сборки). Кривая мягче исходной, суммарная задержка не
   выросла. Отсчёт чисел на карточках — другой жест, его это не касается. */
tbody tr { animation: rowin .44s cubic-bezier(.22,.61,.36,1) both; }
tbody tr:nth-child(1){animation-delay:.03s}  tbody tr:nth-child(2){animation-delay:.07s}
tbody tr:nth-child(3){animation-delay:.11s}  tbody tr:nth-child(4){animation-delay:.15s}
tbody tr:nth-child(5){animation-delay:.19s}  tbody tr:nth-child(6){animation-delay:.24s}
tbody tr:nth-child(7){animation-delay:.28s}  tbody tr:nth-child(8){animation-delay:.32s}
tbody tr:nth-child(9){animation-delay:.36s}  tbody tr:nth-child(10){animation-delay:.40s}
tbody tr:nth-child(11){animation-delay:.43s} tbody tr:nth-child(12){animation-delay:.45s}
tbody tr:nth-child(13){animation-delay:.47s} tbody tr:nth-child(14){animation-delay:.49s}
tbody tr:nth-child(15){animation-delay:.50s}
@keyframes rowin { from { opacity: 0; transform: translateY(4px) } to { opacity: 1; transform: none } }
@media (prefers-reduced-motion: reduce) {
  tbody tr { animation: none; }
}

/* Приглушённая неоновая подсветка под курсором: строка слегка загорается
   акцентом раздела. Без мерцания — только transition; системный курсор не
   заменяется (своя картинка отобрала бы текстовую балку и палец).
   Это вариант А, выбранный заказчиком 14.08.2026; вариант Б — свечение,
   следующее за курсором на Главной, — снят целиком (CSS и JS). */
tbody tr td { transition: background .14s, box-shadow .14s; }
tbody tr:hover td { background: color-mix(in srgb, var(--accent) 5%, rgba(255,255,255,.015)); }
tbody tr:hover td:first-child {
  background: color-mix(in srgb, var(--accent) 7%, var(--surface-2));
  box-shadow: inset 2px 0 0 var(--accent-dim);
}

/* Склейка — строка-подытог; состав сворачивается кликом (app.js). */
tr.row-group td, tr.grp td { background: var(--surface-2); font-weight: 500; }
tr.row-group td:first-child, tr.grp td:first-child { background: var(--surface-2); cursor: pointer; }
tr.row-group td:first-child::before { content: "▾ "; color: var(--text-faint); font-size: 10px; }
tr.row-group.folded td:first-child::before { content: "▸ "; }
tr.in-group.hidden { display: none; }

tr.row-total td, tr.tot td {
  background: color-mix(in srgb, var(--accent) 7%, var(--surface-2));
  font-weight: 500; border-top: 1px solid var(--line-strong);
}
tr.row-total td:first-child, tr.tot td:first-child { background: color-mix(in srgb, var(--accent) 7%, var(--surface-2)); }

td.over, td.goal-bad  { color: var(--bad); background: rgba(201,122,114,.07); }
td.under, td.goal-good { color: var(--good); }
td.cell-alert { color: var(--bad); font-weight: 700; }
.dim, .muted { color: var(--text-dim); }
small.muted, .text-faint { color: var(--text-faint); }
.cell-indent { padding-left: 1.6rem; }

/* Чекбоксы кабинетов в панели управления (приглашение и список). */
.acct-checks { border: 0; padding: 0; margin: 0; }
.acct-checks legend { font-size: 11.5px; color: var(--text-dim); letter-spacing: .03em; }
.check-inline {
  display: inline-flex; align-items: center; gap: 5px; margin-right: 12px;
  font-size: 12.5px; white-space: nowrap; cursor: pointer;
}
.check-inline input[type="checkbox"] { margin: 0; }

.pill, small.badge {
  display: inline-block; padding: 1px 6px; border-radius: 4px; font-size: 10.5px;
  letter-spacing: .04em; border: 0; margin-left: 3px;
}
.pill.fbo, small.badge.fbo { background: rgba(79,191,212,.12); color: #8FD6E4; }
.pill.fbs, small.badge.fbs { background: rgba(155,133,222,.14); color: #BFB0EE; }

/* Подсветка пересчитанной ячейки: волна слева направо задаётся задержкой из app.js. */
.flash { animation: flash 1.1s ease-out; }
@keyframes flash {
  0% { background: color-mix(in srgb, var(--accent) 26%, transparent); }
  100% { background: transparent; }
}

.note { margin-top: 14px; font-size: 12px; color: var(--text-dim); }

/* ── Панели, статусы, строка состояния ──────────────────────────────── */

.panel, article {
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  border: 1px solid var(--line); border-radius: 10px; padding: 14px 16px;
  backdrop-filter: blur(3px); margin: 0 0 12px;
}
.panel h3, article h3, article h4 { margin: 0 0 10px; font-size: 13px; font-weight: 500; color: var(--text-dim); letter-spacing: .03em; }
/* Название и число читаются одной строкой (§2.3): раньше между ними лежала
   полполосы пустоты (space-between на всю ширину панели), и глаз не
   связывал строку с числом. Число идёт сразу за названием с воздухом. */
.panel .row {
  display: flex; justify-content: flex-start; align-items: baseline; gap: 18px;
  padding: 4px 0; font-size: 13px; border-bottom: 1px solid rgba(255,255,255,.04);
  font-variant-numeric: tabular-nums;
}
.panel .row span:first-child { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.panel .row span:last-child { white-space: nowrap; }
.panel .row:last-child { border-bottom: 0; }

.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
/* Высота панели считается по содержимому (правки 14.08 §5–6): без
   align-items grid тянул обе панели ряда до самой высокой, и «Мои задачи» с
   одной задачей занимали столько же, сколько заняли бы восемь. Пустое
   состояние — одна строка, панель схлопывается до неё. */
.home-grid { display: grid; grid-template-columns: 1.4fr 1fr; gap: 12px; margin-top: 12px; align-items: start; }
.panel > p.muted { margin: 2px 0 0; }
/* Списки Главной («Мои задачи», «Худшие SKU», «Ближе к нулю») не тянутся во
   всю ширину колонки (правки 14.08 §7): содержимого там на полширины, и
   пустота справа мешала глазу связать название с числом. Панель обнимает
   содержимое, потолок — ширина колонки. */
.panel-fit { width: fit-content; min-width: 300px; max-width: 100%; }

.st { display: flex; align-items: center; gap: 8px; padding: 5px 0; font-size: 12.5px; border-bottom: 1px solid rgba(255,255,255,.04); }
.st:last-child { border-bottom: 0; }
.st b { font-weight: 400; color: var(--text-dim); margin-left: auto; font-variant-numeric: tabular-nums; }
.led { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.led.ok { background: var(--good); box-shadow: 0 0 7px var(--good); }
.led.warn { background: var(--warn); box-shadow: 0 0 7px var(--warn); }
.led.bad { background: var(--bad); box-shadow: 0 0 7px var(--bad); }
.led.run { background: var(--accent); box-shadow: 0 0 7px var(--accent); animation: pulse 1.6s ease-in-out infinite; }
@keyframes pulse { 0%,100% { opacity: .35 } 50% { opacity: 1 } }

.strip {
  display: flex; align-items: center; gap: 10px; margin-top: 14px; padding: 9px 14px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  font-size: 12.5px; color: var(--text-dim);
}
.strip .right { margin-left: auto; }

/* Спарклайн ДРР по дням: высота столбика — SVG-атрибут, не inline-стиль. */
.spark { display: flex; align-items: flex-end; gap: 4px; height: 92px; margin-top: 6px; }
.spark svg { width: 100%; height: 100%; }
.spark rect { fill: color-mix(in srgb, var(--accent) 42%, transparent); transform-origin: bottom; animation: sprout .7s cubic-bezier(.2,.7,.3,1) both; }
.spark rect.hot { fill: color-mix(in srgb, var(--bad) 55%, transparent); }
@keyframes sprout { from { transform: scaleY(0); opacity: 0 } to { transform: scaleY(1); opacity: 1 } }
.spark-x { display: flex; justify-content: space-between; font-size: 10.5px; color: var(--text-faint); margin-top: 5px; }

/* ── Уведомления и служебные блоки ──────────────────────────────────── */

.notice {
  padding: .6rem .9rem; border-radius: 0 7px 7px 0; font-size: 12.5px;
  background: color-mix(in srgb, var(--accent) 9%, transparent);
  border-left: 3px solid var(--accent); color: var(--text-dim); margin-bottom: 12px;
}
.notice-warn { border-left-color: var(--warn); background: color-mix(in srgb, var(--warn) 9%, transparent); }

.badge-ok { color: var(--good); }
.badge-error { color: var(--bad); }
.badge-warn { color: var(--warn); }
.badge-unset { color: var(--text-faint); }

tr.status-failed  { background: rgba(201,122,114,.06); }
tr.status-partial { background: rgba(191,161,103,.08); }
tr.status-skipped { color: var(--text-faint); }

.error-detail { white-space: pre-wrap; word-break: break-word; max-width: 60ch; font-size: .85em; }

.progress-block { border-left: 3px solid var(--accent); padding-left: .9rem; margin-bottom: 14px; }

.day-marks summary { cursor: pointer; color: var(--text-dim); font-size: 12.5px; }
.day-list { list-style: none; padding-left: 0; display: flex; flex-wrap: wrap; gap: .4rem 1.2rem; }
.day-list li { font-size: .9em; }
.day-label { font-weight: 600; margin-right: .3rem; }
.day-missing { color: var(--bad); }
.day-partial { color: var(--warn); }
.day-loaded  { color: var(--text-faint); }

.two-buttons { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: 1rem; }

.history-split { display: grid; grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); gap: 1.2rem; align-items: start; }

svg.chart { width: 100%; height: auto; }
.chart-bar  { fill: var(--accent); opacity: .55; }
.chart-bar:hover { opacity: .85; }
.chart-line { fill: none; stroke: var(--bad); stroke-width: 2; }
.chart-dot  { fill: var(--bad); }
.chart-goal { stroke: var(--good); stroke-width: 1.5; stroke-dasharray: 6 4; }

.tabs { display: flex; gap: .5rem; border-bottom: 1px solid var(--line); margin-bottom: 1rem; }
.tabs a { padding: .5rem .75rem; text-decoration: none; color: var(--text-dim); }
.tabs a:hover { color: var(--text); }
.tabs a.active { border-bottom: 2px solid var(--accent); color: var(--text); }

.tag { display: inline-block; padding: 1px 6px; border-radius: 4px; font-size: 10.5px; background: rgba(255,255,255,.055); color: var(--text-dim); margin-right: 3px; }

.placeholder-box {
  padding: 2rem; text-align: center; color: var(--text-faint);
  border: 1px dashed var(--line-strong); border-radius: 10px;
}

/* Индикатор загрузки htmx: появляется через 300 мс, не сразу — мигание на
   быстрых запросах создаёт ощущение тормозов там, где их нет. */
.htmx-indicator { opacity: 0; transition: opacity .15s ease-in .3s; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }
.loading-bar {
  display: inline-block; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid var(--line-strong); border-top-color: var(--accent);
  animation: spinback .8s linear infinite; vertical-align: -2px;
}
@keyframes spinback { to { transform: rotate(360deg) } }

/* ── Экран входа ────────────────────────────────────────────────────── */

.auth-page {
  position: relative; min-height: 100vh; display: flex;
  align-items: center; justify-content: center; overflow: hidden;
}

.auth-card {
  position: relative; width: 372px; padding: 34px 32px 28px;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  border: 1px solid var(--line); border-radius: 14px;
  backdrop-filter: blur(10px);
  animation: rise .55s cubic-bezier(.2,.7,.3,1) both;
}
.auth-card .lock { padding: 0 0 6px; display: block; text-align: center; }
.auth-card .lockword { font-size: 34px; letter-spacing: .24em; }
.auth-card .scanline { left: 0; right: 0; }
.auth-card .tagline { padding: 0 0 26px; text-align: center; }
.auth-card label { display: block; font-size: 12px; color: var(--text-dim); margin: 0 0 5px; letter-spacing: .02em; }
.auth-card input { width: 100%; margin-bottom: 15px; padding: 9px 11px; font-size: 14px; }
.auth-card input:focus { box-shadow: 0 0 0 3px color-mix(in srgb, var(--wb-violet) 22%, transparent); }
.auth-card button[type="submit"], .auth-card .enter {
  width: 100%; margin-top: 6px; padding: 10px; font-size: 14px; color: #fff;
  background: color-mix(in srgb, var(--wb-violet) 40%, var(--surface-2));
  border-color: color-mix(in srgb, var(--wb-fuchsia) 45%, transparent);
  transition: background .2s, box-shadow .2s;
}
.auth-card button[type="submit"]:hover {
  background: color-mix(in srgb, var(--wb-violet) 58%, var(--surface-2));
  box-shadow: 0 0 18px color-mix(in srgb, var(--wb-fuchsia) 35%, transparent);
}
.auth-card .forgot { display: block; text-align: center; margin-top: 14px; font-size: 12.5px; color: var(--text-dim); text-decoration: none; }
.auth-card .forgot:hover { color: var(--text); }
.auth-card .foot { margin-top: 20px; padding-top: 14px; border-top: 1px solid var(--line); font-size: 11.5px; color: var(--text-faint); text-align: center; }

/* ── Фон Главной ────────────────────────────────────────────────────── */

/* Фон покрывает ВСЮ область контента при любой высоте страницы и при
   прокрутке (Etap_interfeys_pravki §2.1, третье возвращение претензии —
   пункт приёмки). Прежде контейнер был жёстко 820px с маской-затуханием
   на всём фоне: ниже него фон «заканчивался». Теперь тянется сетка и
   виньетка, а картина-svg остаётся верхней и гаснет своей маской. */
.bg { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
.main > *:not(.bg) { position: relative; z-index: 1; }

.bg .layer { position: absolute; inset: 0; transition: transform .5s cubic-bezier(.2,.7,.3,1); }
.bg .layer-art {
  bottom: auto; height: 820px;
  mask-image: linear-gradient(#000 55%, transparent);
  -webkit-mask-image: linear-gradient(#000 55%, transparent);
}

.bg .hgrid {
  position: absolute; inset: -40%;
  background-image:
    linear-gradient(color-mix(in srgb, var(--accent) 22%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--accent) 22%, transparent) 1px, transparent 1px);
  background-size: 46px 46px; opacity: .07;
  transform: perspective(560px) rotateX(58deg);
  animation: drift 34s linear infinite;
}
@keyframes drift { from { background-position: 0 0 } to { background-position: 0 460px } }

.bg .glow {
  position: absolute; width: 520px; height: 300px; left: 8%; top: -60px;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 26%, transparent), transparent);
  filter: blur(28px); opacity: .5;
  animation: float 26s ease-in-out infinite alternate;
}
@keyframes float { from { transform: translate(0,0) } to { transform: translate(240px, 40px) } }

.bg svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.bg .ln { fill: none; stroke: var(--accent); stroke-width: 1.5; opacity: .15; }
.bg .ln-f { opacity: .085; stroke-width: 1.2; }
.bg .ln2 { fill: none; stroke: var(--accent); stroke-width: 2; opacity: .55;
  stroke-dasharray: 240 3000; animation: trace 12s linear infinite; }
.bg .ln3 { fill: none; stroke: var(--accent); stroke-width: 1.6; opacity: .4;
  stroke-dasharray: 150 2600; animation: trace 17s linear infinite 2s; }
@keyframes trace { from { stroke-dashoffset: 3240 } to { stroke-dashoffset: 0 } }

.bg .bar { fill: var(--accent); opacity: .1; animation: grow 9s ease-in-out infinite alternate; transform-origin: bottom; }
.bg .bar:nth-of-type(2n) { animation-duration: 11s; }
.bg .bar:nth-of-type(3n) { animation-duration: 13s; }
@keyframes grow { from { transform: scaleY(.55) } to { transform: scaleY(1) } }

.bg .ring { fill: none; stroke: var(--accent); stroke-width: 8; opacity: .12;
  stroke-dasharray: 210 340; stroke-linecap: round; transform-origin: center;
  animation: spin 44s linear infinite; }
.bg .ring2 { stroke-width: 3; opacity: .2; stroke-dasharray: 60 400; animation-duration: 28s; animation-direction: reverse; }
@keyframes spin { to { transform: rotate(360deg) } }

.bg .glyph {
  fill: none; stroke: var(--accent); stroke-width: 1.6; opacity: .07;
  font: 500 210px/1 -apple-system, "Segoe UI", sans-serif;
  animation: sway 30s ease-in-out infinite alternate;
}
.bg .glyph-b { font-size: 150px; opacity: .055; animation-duration: 38s; animation-direction: alternate-reverse; }
.bg .glyph-c { font-size: 110px; }
@keyframes sway { from { transform: translate(0,0) } to { transform: translate(26px,-14px) } }

.bg .runner { fill: var(--accent); opacity: .85; filter: drop-shadow(0 0 8px var(--accent)); }
.bg .runner-b { opacity: .45; }

.bg .dot { fill: var(--accent); opacity: .35; animation: blip 5s ease-in-out infinite; }
.bg .dot:nth-of-type(2n) { animation-delay: 1.6s } .bg .dot:nth-of-type(3n) { animation-delay: 3.1s }
@keyframes blip { 0%,100% { opacity: .12; r: 2.5 } 50% { opacity: .5; r: 4 } }

.vignette { position: absolute; inset: 0; background: radial-gradient(120% 90% at 50% 20%, transparent 40%, var(--bg) 100%); }
.fade { mask-image: linear-gradient(#000 35%, transparent); -webkit-mask-image: linear-gradient(#000 35%, transparent); }

/* ── Телефон ────────────────────────────────────────────────────────── */
/* Ниже 600 точек — карточки и заглушки; от 600 планшет получает полный
   интерфейс лентой и масштабом (см. «Планшет вертикально» ниже). */

@media (max-width: 599px) {
  .app { grid-template-columns: 1fr; }
  .side { position: static; border-right: 0; border-bottom: 1px solid var(--line); padding: 12px 0 8px; }
  .main { padding: 14px 12px 40px; }

  /* Меню — горизонтальная лента, а не столбец на весь экран: до содержимого
     не должно быть страницы прокрутки. Группы-заголовки в ленте не нужны. */
  .side .lockword { font-size: 20px; }
  .side .tagline { padding-bottom: 8px; }
  .side nav { display: flex; overflow-x: auto; gap: 2px; padding: 0 8px; -webkit-overflow-scrolling: touch; }
  .side nav .grp { display: none; }
  .side nav a {
    white-space: nowrap; padding: 6px 10px; border-left: 0;
    border-bottom: 2px solid transparent; border-radius: 6px 6px 0 0;
  }
  .side nav a.on { border-bottom-color: var(--accent); background: none; }
  .side nav a:hover { padding-left: 10px; }
  .sidebar-user { display: none; }
  .side > form[action="/logout"] { position: absolute; top: 12px; right: 10px; padding: 0; }
  .side > form button { padding: 4px 9px; font-size: 12px; }
  .side .account-switcher, .side .account-single { padding: 4px 8px 6px; }
  .cards, .stat-cards, .mini { grid-template-columns: 1fr 1fr; }
  .grid, .home-grid { grid-template-columns: 1fr; }

  /* Остатки и Главная — читаемы. Остальные разделы честно говорят,
     что рассчитаны на компьютер, вместо сломанной таблицы. */
  body:not([data-section="home"]):not([data-section="sklad"]) .tblwrap,
  body:not([data-section="home"]):not([data-section="sklad"]) .table-scroll,
  body:not([data-section="home"]):not([data-section="sklad"]) .cards,
  body:not([data-section="home"]):not([data-section="sklad"]) .two-buttons { display: none; }
  body:not([data-section="home"]):not([data-section="sklad"]) .narrow-note { display: block; }

  /* Остатки: таблица превращается в карточки. SKU крупно, показатели ОДНОЙ
     строкой с переносом (постановка §6) — карточка на два-три ряда, а не
     столбец из шести строк. */
  body[data-section="sklad"] .table-scroll, body[data-section="sklad"] .tblwrap { border: 0; background: none; overflow: visible; max-height: none; }
  body[data-section="sklad"] table, body[data-section="sklad"] tbody { display: block; }
  body[data-section="sklad"] thead { display: none; }
  body[data-section="sklad"] tbody tr {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 1px 14px;
    background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
    margin-bottom: 8px; padding: 9px 12px;
  }
  body[data-section="sklad"] tbody td { display: inline; border: 0; padding: 0; white-space: normal; position: static; text-align: left; background: none; }
  body[data-section="sklad"] tbody td:first-child { flex: 1 1 100%; border-right: 0; }
  body[data-section="sklad"] tbody td[data-l]::before { content: attr(data-l) " "; color: var(--text-faint); font-size: 10.5px; }
  /* SKU крупно, служебные номера спрятаны, название одной строкой с
     многоточием — ничего не обрубается переносом посреди баркода. */
  body[data-section="sklad"] tbody td:first-child a { font-size: 14.5px; font-weight: 500; }
  body[data-section="sklad"] .ids { display: none; }
  body[data-section="sklad"] .title-line {
    display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; max-width: 100%;
  }
  /* Подытог склейки и итог: имя и доступный остаток, без простыни чисел. */
  body[data-section="sklad"] tr.row-group td[data-l]:not(:nth-child(2)),
  body[data-section="sklad"] tr.row-total td[data-l]:not(:nth-child(2)) { display: none; }
  /* Фильтры в два столбца — а не башней на пол-экрана. */
  form.filters { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  form.filters a.go, form.filters button { grid-column: span 2; }
}
.narrow-note { display: none; padding: 2rem 1rem; text-align: center; color: var(--text-dim); }

/* Если в системе отключены анимации — портал их не показывает. */
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ── Масштаб под экран ───────────────────────────────────────────────
   Эталон — design/mockup.html, блок с тем же названием; значения оттуда.

   На ноутбуке и планшете тот же интерфейс, что на ПК, только мельче:
   масштабируется всё сразу через zoom, а не полсотни размеров по
   отдельности. Правка любого элемента дальше не требует помнить про
   ноутбуки: он уедет вместе с остальными.

   Ступени ВНИЗ — списком через запятую, это ИЛИ: срабатывает та, где не
   хватает любой из сторон, решает более тесная. У ноутбуков узкое место —
   высота, а не ширина: 1366×768 по ширине просторен, а строк видно шесть.

   Ниже 600 точек вступает телефонная вёрстка (карточки), там
   масштабированием уже не обойтись.

   Проверочные точки: 1920×1080 → 1 · 1512×982 → .90 · 1440×900 → .85 ·
   1366×768 → .80 · 1024×768 (iPad mini) → .75 · 810×1080 (iPad
   вертикально) → .70. */
:root { --ui-zoom: 1; }

@media (max-width: 1780px), (max-height: 1000px) { :root { --ui-zoom: .95; } }
@media (max-width: 1600px), (max-height:  920px) { :root { --ui-zoom: .90; } }
@media (max-width: 1440px), (max-height:  860px) { :root { --ui-zoom: .85; } }
@media (max-width: 1300px), (max-height:  800px) { :root { --ui-zoom: .80; } }
@media (max-width: 1150px), (max-height:  740px) { :root { --ui-zoom: .75; } }
@media (max-width: 1000px), (max-height:  680px) { :root { --ui-zoom: .70; } }

/* min-height делится на масштаб: zoom уменьшает и вычисленную высоту,
   и без деления внизу осталась бы полоса фона в четверть экрана. */
.app { zoom: var(--ui-zoom); min-height: calc(100vh / var(--ui-zoom)); }

/* Вверх лестница тоже идёт: на 2К и 4К масштаб 1 оставляет мелкий текст
   и почти тысячу точек пустого поля. Лишняя ширина уходит в размер, а не
   в растягивание колонок: числа уехали бы от подписей, и глаз перестал бы
   связывать строку с колонкой.

   Условия через «and», а не через запятую: увеличивать можно, только
   когда просторно по обеим сторонам. Ультраширокий 2560×1080 крупным
   шрифтом получил бы четыре видимые строки.

   Проверочные точки: 2560×1440 → 1.10 · 3840×2160 → 1.25. Ступень 4К
   живьём НЕ проверена — таких экранов у команды нет (13.08.2026);
   оставлена на вырост, считать её увиденной нельзя (CLAUDE.md,
   «Не проверено»). */
@media (min-width: 2200px) and (min-height: 1200px) { :root { --ui-zoom: 1.10; } }
@media (min-width: 2900px) and (min-height: 1500px) { :root { --ui-zoom: 1.25; } }

/* Ограничения ширины контента ЗДЕСЬ НЕТ, и это решение, а не упущение.

   Предел (max-width на .main со ступенями 2200/2900) вводился, чтобы таблица
   не растягивалась на весь монитор, и снят в эталоне 13.08.2026 (коммит
   21ca108) после проверки на живом портале; в портал правка доехала 14.08.
   Причина: .main несёт не только таблицу, но и анимированный фон Главной и
   полосу под заголовком раздела. Предел резал их вместе с содержимым: фон
   обрывался на середине монитора, и экран читался как обрезанный.

   Если на 2К таблица окажется слишком разреженной, ограничивать надо ширину
   КОЛОНОК, а не страницы: тогда фон остаётся во всю ширину, а числа не
   разъезжаются. */

/* ── Планшет вертикально ──────────────────────────────────────────────
   Горизонтальный планшет (от 1000 точек) обходится одним масштабом:
   1024×768 → .75, полный интерфейс помещается целиком.

   С вертикальным так не выходит: на 768 точках после боковой панели
   остаётся около 550, а в таблице ДРР четырнадцать колонок — масштабом
   это .55, текст в семь пикселей. Уменьшать до нечитаемости хуже, чем
   изменить раскладку.

   Поэтому вертикально боковое меню превращается в горизонтальную ленту
   (тот же приём, что на телефоне), масштаб остаётся читаемым .85, и вся
   ширина уходит таблице. Первая колонка липкая (это глобальное правило
   таблиц) — уехав вправо, видно, о каком товаре строка. */
@media (min-width: 600px) and (max-width: 999px) {
  :root { --ui-zoom: .85; }

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

  .side {
    border-right: 0; border-bottom: 1px solid var(--line);
    padding: 10px 0 0;
    display: flex; align-items: center; gap: 14px;
    overflow-x: auto; white-space: nowrap;
  }
  .side .tagline { display: none; }
  .side .lock { flex: 0 0 auto; padding-left: 14px; }
  .side nav { display: flex; align-items: center; gap: 2px; }
  .side .grp {
    padding: 0 6px 0 12px; border-left: 1px solid var(--line);
    margin-left: 6px;
  }
  .side nav a { padding: 8px 10px; border-left: 0; border-bottom: 2px solid transparent; }
  .side nav a:hover { padding-left: 10px; }
  .side nav a.on { border-bottom-color: var(--accent); background: none; }

  .main { padding: 14px 14px 40px; }
  .cards, .stat-cards, .mini { grid-template-columns: repeat(2, 1fr); }
  .grid, .home-grid { grid-template-columns: 1fr; }

  /* Портальные элементы панели, которых в эталоне нет: в ленте им нужна
     компактная форма — как на телефоне. */
  .sidebar-user { display: none; }
  .side .account-switcher, .side .account-single { flex: 0 0 auto; padding: 0 0 0 6px; }
  .side > form[action="/logout"] { flex: 0 0 auto; margin-left: auto; padding: 0 10px 0 0; }
  .side > form button { padding: 4px 9px; font-size: 12px; }
}

/* Ниже 600 точек масштаб не применяется: телефонная вёрстка (карточки,
   заглушки) уже рассчитана на узкий экран, и лестница вниз ужала бы её до
   нечитаемости. В эталоне этого правила нет — там нет телефонной вёрстки;
   стоит оно после лестницы, иначе её ступень .70 победила бы по порядку. */
@media (max-width: 599px) { :root { --ui-zoom: 1; } }

/* ===== Задачи (доска) — перенос из эталона design/mockup.html ===== */
.head-actions { margin-left: auto; }
.tabs .tabs-right { margin-left: auto; display: flex; gap: .5rem; }

.stickbar { display: flex; gap: 6px; align-items: center; margin-bottom: 14px; flex-wrap: wrap; }
.stickbar .chip {
  display: flex; align-items: center; gap: 5px; padding: 4px 9px; font-size: 12px;
  background: var(--surface-2); border: 1px solid var(--line-strong); border-radius: 20px;
  color: var(--text-dim); cursor: pointer; text-decoration: none;
  transition: border-color .16s, color .16s;
}
.stickbar .chip:hover, .stickbar .chip.on { color: var(--text); border-color: var(--accent); }
.stickbar .stickbar-right { margin-left: auto; }

.board { display: grid; grid-template-columns: repeat(4, 1fr); gap: 11px; align-items: start; }
.bcol {
  background: color-mix(in srgb, var(--surface) 80%, transparent);
  border: 1px solid var(--line); border-radius: 12px; padding: 11px 10px 14px;
  min-height: 220px; transition: border-color .2s, background .2s;
}
.bcol h4 {
  margin: 0 0 10px; padding: 0 3px; font-size: 11.5px; font-weight: 400;
  letter-spacing: .07em; text-transform: uppercase; color: var(--text-dim);
  display: flex; justify-content: space-between;
}
.bcol h4 b { font-weight: 400; color: var(--text-faint); }

.tcard {
  display: block; text-decoration: none; color: var(--text);
  position: relative; background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 9px; padding: 10px 11px 9px; margin-bottom: 8px; cursor: default;
  animation: rise .4s cubic-bezier(.2,.7,.3,1) both;
  transition: transform .18s cubic-bezier(.2,.7,.3,1), box-shadow .18s, border-color .18s;
}
.tcard:hover { transform: translateY(-2px); border-color: var(--line-strong); box-shadow: 0 6px 18px rgba(0,0,0,.35); }
.sticker {
  position: absolute; top: -9px; right: -6px;
  width: 27px; height: 27px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-size: 14px;
  background: var(--surface); border: 1px solid var(--line-strong);
  transform: rotate(9deg); box-shadow: 0 3px 8px rgba(0,0,0,.4);
  transition: transform .2s;
}
.tcard:hover .sticker { transform: rotate(-6deg) scale(1.12); }
.tcard-status { margin-top: 8px; }
.tcard-status select { width: 100%; font-size: 11.5px; padding: 3px 6px; }

.tcard .t { font-size: 13px; line-height: 1.35; margin-bottom: 7px; padding-right: 20px; }
.tcard .meta { display: flex; align-items: center; gap: 7px; font-size: 11px; color: var(--text-dim); }
.who {
  width: 20px; height: 20px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: 9.5px; letter-spacing: .02em;
  background: color-mix(in srgb, var(--accent) 26%, var(--surface));
  color: var(--text);
}
.due.late { color: var(--bad); }
.eye { margin-left: auto; font-size: 10.5px; color: var(--text-faint); }
.acc { font-size: 10.5px; padding: 1px 6px; border-radius: 4px; background: rgba(255,255,255,.05); color: var(--text-dim); }

/* Форма задачи */
.task-form { max-width: 720px; display: flex; flex-direction: column; gap: 10px; }
.task-form .form-row { display: flex; gap: 12px; flex-wrap: wrap; }
.task-form .form-row label { flex: 1 1 180px; }

@media (max-width: 1023px) {
  .board { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 599px) {
  .board { grid-template-columns: 1fr; }
}

/* ===== Номенклатура — перенос из эталона ===== */
.thumb {
  width: 30px; height: 38px; border-radius: 4px; flex: none; object-fit: cover;
  background: linear-gradient(160deg, var(--surface-2), var(--line-strong));
  display: inline-block; border: 0;
}
.nom { display: flex; align-items: center; gap: 9px; }
.nom .nm { line-height: 1.2; }
.nom .nm b { display: block; font-weight: 400; font-size: 10.5px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.tag { display: inline-block; padding: 1px 6px; border-radius: 4px; font-size: 10.5px; background: rgba(255,255,255,.055); color: var(--text-dim); margin-right: 3px; }

.product-card { display: flex; gap: 22px; align-items: flex-start; flex-wrap: wrap; }
.product-photo {
  width: 246px; max-width: 40vw; border-radius: 8px; border: 1px solid var(--line);
  background: linear-gradient(160deg, var(--surface-2), var(--line-strong));
}
.product-photo-empty { height: 328px; display: flex; align-items: center; justify-content: center; }
.product-props { max-width: 640px; flex: 1 1 320px; }
.product-props td:first-child { width: 180px; }

/* ===== Товарная матрица — перенос из эталона ===== */
.mgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(232px, 1fr)); gap: 11px; }
.mcard {
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  border: 1px solid var(--line); border-radius: 11px; padding: 13px 14px 12px;
  animation: rise .45s cubic-bezier(.2,.7,.3,1) both;
  transition: border-color .2s, transform .2s;
}
.mcard:hover { border-color: var(--line-strong); transform: translateY(-2px); }
.mcard h4 { margin: 0 0 3px; font-size: 14px; font-weight: 500; }
.mcard .sub2 { font-size: 11.5px; color: var(--text-dim); margin-bottom: 10px; }
.mcard .row2 { display: flex; justify-content: space-between; font-size: 12px; padding: 3px 0; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.mcard .row2 b { font-weight: 400; color: var(--text); }
.mcard .note2 { margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--line); font-size: 11.5px; color: var(--text-faint); line-height: 1.4; }
.mcard .becomes { width: 100%; margin-top: 6px; font-size: 12px; padding: 5px; }
.becomes-form { margin-top: 10px; }
.becomes-form select { width: 100%; font-size: 12px; }
.mcard-edit { margin-top: 8px; }
.mcard-edit summary { cursor: pointer; font-size: 11.5px; }
.matrix-new { margin-bottom: 16px; }
.matrix-new summary { cursor: pointer; display: inline-block; }

.stage { display: inline-flex; align-items: center; gap: 5px; font-size: 10.5px; letter-spacing: .04em;
  padding: 2px 8px; border-radius: 20px; text-transform: uppercase; margin-bottom: 6px; }
.stage i { width: 5px; height: 5px; border-radius: 50%; background: currentColor; font-style: normal; }
.st-idea { background: rgba(255,255,255,.05); color: var(--text-faint); }
.st-ok   { background: color-mix(in srgb, var(--accent) 13%, transparent); color: var(--accent); }
.st-prod { background: color-mix(in srgb, var(--warn) 13%, transparent); color: var(--warn); }
.st-out  { background: color-mix(in srgb, var(--good) 13%, transparent); color: var(--good); }
.mcard.released { opacity: .55; }  /* архив: в эталоне inline-style, но CSP без инлайна */

/* ===== Календарь поставок — перенос из эталона ===== */
.calhead { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; flex-wrap: wrap; }
.calhead .m { font-size: 15px; }
.calhead-new { margin-left: auto; }
.calhead-new summary { cursor: pointer; display: inline-block; }
.cal { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.cal .dow { font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--text-faint); padding: 0 4px 4px; }
.day {
  min-height: 92px; background: color-mix(in srgb, var(--surface) 78%, transparent);
  border: 1px solid var(--line); border-radius: 9px; padding: 6px 6px 7px;
  transition: border-color .18s, background .18s;
}
.day:hover { border-color: var(--line-strong); }
.day.out { opacity: .32; }
.day.today { border-color: var(--accent); }
.day .n { font-size: 11.5px; color: var(--text-dim); font-variant-numeric: tabular-nums; display: flex; justify-content: space-between; }
.day.today .n { color: var(--accent); }

.sup {
  display: block; width: 100%; text-align: left; margin-top: 5px; padding: 4px 6px;
  font-size: 11px; line-height: 1.25; border-radius: 6px; cursor: pointer;
  border: 1px solid transparent; background: rgba(255,255,255,.045); color: var(--text);
  transition: transform .15s, border-color .15s, background .15s;
}
.sup:hover { transform: translateX(2px); border-color: var(--accent); background: rgba(255,255,255,.07); }
.sup b { display: block; font-weight: 400; color: var(--text-dim); font-size: 10px; }
.sup.plan { border-left: 3px solid var(--text-faint); border-radius: 0 6px 6px 0; }
.sup.way  { border-left: 3px solid var(--warn); border-radius: 0 6px 6px 0; }
.sup.done { border-left: 3px solid var(--good); border-radius: 0 6px 6px 0; }
span.sup { cursor: default; }
span.sup:hover { transform: none; border-color: transparent; border-left-color: var(--warn); }
span.sup.done:hover { border-left-color: var(--good); }

/* До нажатия на плашку панель не существует для глаза (§5.1): visibility
   прячет её даже там, где fixed-позиционирование сломано или стили панели
   не догрузились — именно так карточка оказалась «в потоке страницы». */
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: 470px; max-width: 92vw; z-index: 40;
  background: var(--surface); border-left: 1px solid var(--line-strong);
  padding: 22px 24px; overflow: auto;
  visibility: hidden;
  transform: translateX(100%);
  transition: transform .32s cubic-bezier(.2,.8,.3,1), visibility 0s linear .32s;
  box-shadow: -18px 0 44px rgba(0,0,0,.45);
}
body[data-drawer="1"] .drawer {
  visibility: visible; transform: none;
  transition: transform .32s cubic-bezier(.2,.8,.3,1), visibility 0s;
}
.drawer h3 { margin: 0 0 3px; font-size: 17px; font-weight: 500; }
.drawer .cap { color: var(--text-dim); font-size: 12.5px; margin-bottom: 16px; }
.drawer .close { position: absolute; top: 16px; right: 18px; padding: 3px 9px; }
.drawer table { font-size: 12px; margin-bottom: 16px; }
.drawer .sum { border-top: 1px solid var(--line); padding-top: 12px; }
.drawer .sum .r { display: flex; justify-content: space-between; padding: 3px 0; font-size: 13px; font-variant-numeric: tabular-nums; }
.drawer .sum .r span:first-child { color: var(--text-dim); }
.drawer .warnbox {
  margin-top: 16px; padding: 9px 11px; font-size: 12px; line-height: 1.45;
  background: color-mix(in srgb, var(--warn) 9%, transparent);
  border-left: 3px solid var(--warn); border-radius: 0 7px 7px 0; color: var(--text-dim);
}

/* ===== Сверка план/факт приёмки (§5.4) ===== */
/* Совпавшие строки не подсвечиваются вовсе — иначе подсветка перестаёт
   что-либо значить. Излишек — такое же расхождение, как недостача: цвета
   разные, но оба тревожные, зелёного здесь нет. */
tr.recon-short td, tr.recon-missing td { background: rgba(201, 122, 114, .08); }
tr.recon-short td.num:last-child, tr.recon-missing td.num:last-child { color: var(--bad); }
tr.recon-over td, tr.recon-extra td { background: rgba(191, 161, 103, .10); }
tr.recon-over td.num:last-child, tr.recon-extra td.num:last-child { color: var(--warn); }
.notice.recon-ok { border-left: 3px solid var(--good); color: var(--text-dim); }

.drawer-actions { display: flex; gap: 8px; margin: 4px 0 12px; flex-wrap: wrap; }
.qty-input { width: 90px; text-align: right; }

/* ===== Экран входа (Etap_interfeys_pravki §1) ===== */

/* §1.2 Вывеска зажигается: сначала темно, две неуверенные вспышки вразнобой,
   затем ровное свечение. Укладывается в ~1.7 секунды — дольше раздражает при
   каждом входе. Дальше подхватывает штатное мерцание sign. */
@keyframes ignite {
  0%, 9%   { color: #3B3140; text-shadow: none; }
  11%      { color: #E9D3E4; text-shadow: 0 0 4px rgba(255,255,255,.4), 0 0 12px rgba(232,20,143,.5); }
  14%, 27% { color: #3B3140; text-shadow: none; }
  30%      { color: #fff;
             text-shadow: 0 0 5px #fff, 0 0 13px var(--wb-fuchsia), 0 0 26px var(--wb-fuchsia),
                          0 0 50px var(--wb-violet), 0 0 84px var(--wb-violet); }
  34%, 46% { color: #4A3A48; text-shadow: 0 0 3px rgba(232,20,143,.25); }
  52%, 100% { color: #fff;
             text-shadow: 0 0 5px #fff, 0 0 13px var(--wb-fuchsia), 0 0 26px var(--wb-fuchsia),
                          0 0 50px var(--wb-violet), 0 0 84px var(--wb-violet); }
}
.auth-card .lockword-ignite {
  animation: ignite 1.7s linear both, sign 8s 1.7s infinite;
}
@media (prefers-reduced-motion: reduce) {
  /* Без мерцания: надпись сразу горит ровно (базовый text-shadow lockword). */
  .auth-card .lockword-ignite { animation: none; }
}

/* §1.3 Карточка входа: крупнее, по центру, контур подсвечен неоном в цвет
   логотипа. Единственный экран, который человек видит до входа, — он не
   должен выглядеть служебным. */
.auth-card {
  width: 424px; padding: 42px 40px 32px;
  border-color: color-mix(in srgb, var(--wb-violet) 55%, var(--line));
  box-shadow:
    0 0 22px color-mix(in srgb, var(--wb-violet) 30%, transparent),
    0 0 64px color-mix(in srgb, var(--wb-fuchsia) 12%, transparent),
    inset 0 0 22px color-mix(in srgb, var(--wb-violet) 8%, transparent);
}

/* §1.4 Фон входа — тот же, что на Главной, но еле различимый: фон не должен
   спорить с формой. Слои переиспользуются из partial_home_bg, обёртка глушит. */
.auth-page .auth-bgwrap { position: absolute; inset: 0; opacity: .45; }
.auth-page .auth-bgwrap .bg { position: absolute; inset: 0; }
.auth-page .authvg { position: absolute; inset: 0;
  background: radial-gradient(110% 80% at 50% 45%, transparent 30%, var(--bg) 100%); }
