/* ===========================================================================
   Оформление сервиса. Один набор токенов, светлая и тёмная темы.
   Тёмная подбиралась отдельно, а не выворачиванием светлой наизнанку.
   =========================================================================== */

:root {
  color-scheme: light;
  --surface: #f9f9f9;
  --panel: #ffffff;
  --panel-2: #fcfcfc;
  --panel-3: #f0f0f0;
  --line: #e8e8e8;
  --line-strong: #cecece;
  /* Четыре уровня границ, как в ClickUp: слабая для разделителей строк и
     рамок чипов, основная для панелей, контрастная для полей, hover —
     только под курсором. Одной --line таблица выходит жёстче, чем нужно:
     каждая строка отчёркнута так же заметно, как край панели. */
  --line-low: #f0f0f0;
  --line-hover: #bbbbbb;
  --ink: #202020;
  /* Четыре уровня текста, и все четыре читаются. Проверено считалкой
     контраста на --panel, --panel-2 и --panel-3 в обеих темах: минимум
     4.5:1, как требует норма для мелкого кегля. До 13.11.2026 второй и
     третий уровни были светлее (#838383 — 3.8:1 на белом), и подписи,
     даты и счётчики на всех страницах читались через силу. */
  --ink-2: #4f4f4f;
  --ink-3: #666666;
  /* Плейсхолдер и выключенный текст: раньше оба брали --ink-3, и подсказка
     в пустом поле весила столько же, сколько значение в соседнем. */
  --ink-4: #757575;
  --ink-5: #bbbbbb;
  /* Акцент не задаётся прямо: его подставляет набор --a-l-* выбранного
     цвета (блок «акценты» ниже). Без выбора работает запасной лиловый. */
  --accent: var(--a-l, #3e63dd);
  --accent-hover: color-mix(in srgb, var(--accent) 86%, #000);
  --accent-soft: var(--a-l-soft, #f0f4ff);
  --accent-ink: #ffffff;
  --good: #18794e;
  --good-soft: #e7f6ee;
  --warn: #c62a2f;
  --warn-soft: #fdecec;
  /* Жёлтый ClickUp для приоритета High: единственный цвет, который не
     читается как опасность и при этом заметнее обычного. */
  --caution: #915930;
  --caution-soft: #fdf4e3;
  --info: #2a78d6;
  --info-soft: #e8f1fc;
  /* цвета данных: проверены валидатором палитры в обеих темах */
  --data-1: #2a78d6;
  --data-2: #eb6834;
  --data-3: #1baf7a;
  /* Стекло: панель просвечивает, под ней — мягкая заливка контейнера.
     Формула одна на обе темы: --panel в тёмной уже тёмный. */
  --glass: color-mix(in srgb, var(--panel) 70%, transparent);
  --glass-line: color-mix(in srgb, var(--line-strong) 45%, transparent);
  --shadow-sm: 0 1px 2px rgba(16, 24, 40, .05);
  --shadow-md: 0 6px 16px rgba(16, 24, 40, .08);
  --shadow-lg: 0 16px 40px rgba(16, 24, 40, .16);
  /* ----------------------------------------------------------- размеры
     Шкала кегля. До неё в файле жили девятнадцать разных размеров, среди
     них 10.5, 11.5, 12.5, 13.5 и 14.5 — половинные пиксели браузер
     округляет по-своему, и соседние подписи получались разного веса без
     всякой причины. Цвет здесь был системой, размер — нет; отсюда и
     бралось общее ощущение неаккуратности.
     Шаги мелкие намеренно: сервис плотный, и 13 / 14 / 15 — это три
     разные роли (строка таблицы, основной текст, заголовок панели),
     а не три оттенка одного. Размеры от темы не зависят, поэтому
     задаются один раз и в тёмных блоках не повторяются. */
  --fs-100: 10px;   /* инициалы в аватарах, числовые бейджи */
  --fs-200: 11px;   /* капс-группы, время, самые мелкие подписи */
  --fs-300: 12px;   /* вторичный текст, шапки колонок, чипы */
  --fs-400: 13px;   /* плотный основной: таблицы, кнопки, поля */
  --fs-500: 14px;   /* базовый текст страницы и h3 */
  --fs-600: 15px;   /* заголовок панели, h2, шапка канала */
  --fs-700: 16px;   /* крупный подзаголовок */
  --fs-800: 20px;   /* заголовок страницы, h1 */
  --fs-900: 26px;   /* число в карточке KPI */
  --fs-1000: 32px;  /* главное число дашборда */
  /* Шкала шага. Отступы и промежутки раньше брали каждое целое число от
     1 до 20 подряд: 3 и 4, 5 и 6, 7 и 9 стояли рядом в соседних правилах
     и ничем не отличались на глаз, зато ничто не вставало на общий ритм.
     Здесь шаг растёт заметно, поэтому расстояние снова что-то значит.
     Крупные величины (64px снизу страницы, высоты панелей) — это размеры
     каркаса, а не ритм, и на шкалу не переводятся. */
  --sp-1: 2px;
  --sp-2: 4px;
  --sp-3: 6px;
  --sp-4: 8px;
  --sp-5: 10px;
  --sp-6: 12px;
  --sp-7: 16px;
  --sp-8: 20px;
  --sp-9: 24px;
  --sp-10: 32px;
  --radius: 12px;
  --radius-sm: 8px;
  /* Третий шаг радиуса — чипы и мелкие кнопки. На 8px чип выглядит
     скруглённее, чем панель, в которой лежит. */
  --radius-xs: 6px;
  --sidebar: 256px;
  /* Свёрнутое меню — рельс 52px с отступами по 6px. */
  --sidebar-narrow: 64px;
  --rail: 52px;
  --gbar: 40px;
  /* Рамка окна, панель разделов и рабочее поле — три разные подложки,
     как в ClickUp: белая, #f9f9f9 и снова белая. */
  --frame: #ffffff;
  --side: #f9f9f9;
  --content: #ffffff;
  /* Подложка под курсором и у выбранного пункта: чёрный на 6%, а не
     отдельный серый — на любой из трёх подложек выходит верный тон. */
  --hover: rgba(0, 0, 0, .06);
  --hover-2: rgba(0, 0, 0, .1);
  /* Рельс красится в цвет выбранного акцента, затемнённый так же, как
     синий ClickUp: #3e63dd даёт #3451b2 сверху и #1f2d5c снизу. В тёмной
     теме рельс остаётся тем же — он тёмный в обеих. */
  --rail-top: color-mix(in srgb, var(--a-l, #3e63dd) 82%, #000);
  --rail-bottom: color-mix(in srgb, var(--a-l, #3e63dd) 45%, #000);
}

@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    color-scheme: dark;
    --surface: #0e1116;
    --panel: #161a21;
    --panel-2: #1b2029;
    --panel-3: #222833;
    --line: #272d39;
    --line-strong: #39414f;
    --line-low: #20252e;
    --line-hover: #4a5361;
    --ink: #e8ebf1;
    --ink-2: #a6afbd;
    --ink-3: #8e97a4;
    --ink-4: #7d8796;
    --ink-5: #454d59;
    --accent: var(--a-d, #8da4ef);
    --accent-hover: color-mix(in srgb, var(--accent) 86%, #fff);
    --accent-soft: var(--a-d-soft, #1b2447);
    --accent-ink: #15131f;
    --good: #199e70;
    --good-soft: #10261f;
    --warn: #e2703a;
    --warn-soft: #2a1a12;
    --caution: #e0a63a;
    --caution-soft: #2b2110;
    --info: #3987e5;
    --info-soft: #11213a;
    --data-1: #3987e5;
    --data-2: #d95926;
    --data-3: #199e70;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-md: 0 6px 16px rgba(0, 0, 0, .45);
    --frame: #0a0c10;
    --side: #12151b;
    --content: var(--surface);
    --hover: rgba(255, 255, 255, .07);
    --hover-2: rgba(255, 255, 255, .12);
    --shadow-lg: 0 16px 40px rgba(0, 0, 0, .6);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --surface: #0e1116;
  --panel: #161a21;
  --panel-2: #1b2029;
  --panel-3: #222833;
  --line: #272d39;
  --line-strong: #39414f;
  --line-low: #20252e;
  --line-hover: #4a5361;
  --ink: #e8ebf1;
  --ink-2: #a6afbd;
  --ink-3: #8e97a4;
  --ink-4: #7d8796;
  --ink-5: #454d59;
  --accent: var(--a-d, #8da4ef);
  --accent-hover: color-mix(in srgb, var(--accent) 86%, #fff);
  --accent-soft: var(--a-d-soft, #1b2447);
  --accent-ink: #15131f;
  --good: #199e70;
  --good-soft: #10261f;
  --warn: #e2703a;
  --warn-soft: #2a1a12;
  --caution: #e0a63a;
  --caution-soft: #2b2110;
  --info: #3987e5;
  --info-soft: #11213a;
  --data-1: #3987e5;
  --data-2: #d95926;
  --data-3: #199e70;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-md: 0 6px 16px rgba(0, 0, 0, .45);
  --frame: #0a0c10;
  --side: #12151b;
  --content: var(--surface);
  --hover: rgba(255, 255, 255, .07);
  --hover-2: rgba(255, 255, 255, .12);
  --shadow-lg: 0 16px 40px rgba(0, 0, 0, .6);
}

/* ----------------------------------------------------------------- акценты
   Цвет интерфейса выбирается в «Оформлении» и живёт в data-accent на <html>.
   Каждый набор задаёт две пары: --a-l для светлой темы, --a-d для тёмной.
   Тёмная не выворачивается из светлой — на тёмной подложке тот же тон
   выглядит грязным, поэтому он подобран отдельно и взят светлее.

   Все десять проверены на контраст в обеих темах: белый текст на акценте,
   акцент текстом на своей подложке и на панели — везде не ниже 4.5:1.
   Меняя цифру, прогоните проверку заново, иначе подпись на кнопке
   потеряется на фоне. */
:root[data-accent="black"]  { --a-l: #2f333a; --a-l-soft: #eceef1;
                              --a-d: #c6ccd6; --a-d-soft: #272b33; }
:root[data-accent="purple"] { --a-l: #5b4fd6; --a-l-soft: #eeecfc;
                              --a-d: #8b80f0; --a-d-soft: #241f3f; }
:root[data-accent="blue"]   { --a-l: #3e63dd; --a-l-soft: #f0f4ff;
                              --a-d: #8da4ef; --a-d-soft: #1b2447; }
:root[data-accent="pink"]   { --a-l: #c62a73; --a-l-soft: #fce8f1;
                              --a-d: #f075ac; --a-d-soft: #331022; }
:root[data-accent="violet"] { --a-l: #8b35d6; --a-l-soft: #f3e9fc;
                              --a-d: #c186f5; --a-d-soft: #2a1540; }
:root[data-accent="indigo"] { --a-l: #4a53d9; --a-l-soft: #e9ebfd;
                              --a-d: #8e97f7; --a-d-soft: #1b1f42; }
:root[data-accent="orange"] { --a-l: #a44a09; --a-l-soft: #fcefe4;
                              --a-d: #f0883d; --a-d-soft: #331c0d; }
:root[data-accent="teal"]   { --a-l: #0a6e68; --a-l-soft: #e3f3f2;
                              --a-d: #3ec4b4; --a-d-soft: #0c2a29; }
:root[data-accent="bronze"] { --a-l: #8a5c3e; --a-l-soft: #f5ebe4;
                              --a-d: #cb9a78; --a-d-soft: #2e2019; }
:root[data-accent="mint"]   { --a-l: #0b7149; --a-l-soft: #e6f5ee;
                              --a-d: #3ec98d; --a-d-soft: #0d2a1e; }

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font: 14px/1.55 -apple-system, system-ui, "Segoe UI Variable Text", "Segoe UI",
        Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;
  color: var(--ink);
  background: var(--frame);
  -webkit-font-smoothing: antialiased;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
h1 { font-size: var(--fs-800); line-height: 1.3; margin: 0; letter-spacing: -.01em; }
h2 { font-size: var(--fs-600); margin: var(--sp-9) 0 var(--sp-5); letter-spacing: -.005em; }
h3 { font-size: var(--fs-500); margin: var(--sp-7) 0 var(--sp-4); }
p { margin: 0 0 var(--sp-5); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

.icon { width: 17px; height: 17px; flex: 0 0 auto; stroke: currentColor; fill: none;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
/* Иконки ClickUp залитые, без обводки, и рендерятся в 16px при viewBox 24.
   Обводочные в мелком размере выглядят бледнее и ломают ритм строки. */
.icon.solid { fill: currentColor; stroke: none; }

/* ----------------------------------------------------------------- каркас */
/* Каркас снят с ClickUp (замер 14.11.2026, getComputedStyle):
   общая полоса 40px с поиском-пилюлей по центру; рельс модулей 52px
   с отступом 6px, градиент от #3451b2 к #1f2d5c, радиус 8; панель
   разделов на #f9f9f9 с пунктами 28px / 14px / радиус 7, активный —
   серая подложка 6%, а не акцент; рабочее поле белое.
   Рельс (64 с отступами) и панель (192) вместе дают прежние 256px:
   рабочему полю на окне 974px остаётся столько же, сколько было. */
.gbar {
  position: sticky; top: 0; z-index: 40; height: var(--gbar);
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: var(--sp-4);
  padding: 0 var(--sp-3); background: var(--frame);
}
.gbar-left, .gbar-right { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.gbar-right { justify-content: flex-end; }
.gbar .icon-btn { width: 28px; height: 28px; border-radius: var(--radius-xs); position: relative; }
.gbar .icon-btn .icon { width: 16px; height: 16px; }
.ws {
  display: inline-flex; align-items: center; gap: var(--sp-3); height: 28px; min-width: 0;
  padding: 0 var(--sp-4) 0 var(--sp-3); border-radius: var(--radius-xs);
  background: var(--hover); color: var(--ink); font-size: var(--fs-500); line-height: 16px;
}
.ws:hover { text-decoration: none; background: var(--hover-2); }
.ws b { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ws-mark {
  width: 18px; height: 18px; border-radius: 5px; flex: 0 0 auto;
  background: var(--accent); color: var(--accent-ink);
  display: grid; place-items: center; font-size: var(--fs-200); font-weight: 700;
}
.me-avatar {
  width: 24px; height: 24px; margin-left: var(--sp-2);
  background: var(--ink); color: var(--panel); font-size: var(--fs-200); cursor: default;
}

.shell { display: flex; min-height: calc(100vh - var(--gbar)); }

.sidebar {
  width: var(--sidebar); flex: 0 0 var(--sidebar); display: flex;
  position: sticky; top: var(--gbar); height: calc(100vh - var(--gbar)); z-index: 35;
}
.rail {
  width: var(--rail); flex: 0 0 var(--rail); margin: 0 6px 6px;
  display: flex; flex-direction: column; align-items: center; gap: 0;
  padding: var(--sp-2) 0 var(--sp-3); border-radius: var(--radius-sm); overflow: hidden auto;
  background: linear-gradient(var(--rail-top), var(--rail-bottom));
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -2px rgba(0, 0, 0, .1);
  scrollbar-width: none;
}
.rail a {
  display: flex; flex-direction: column; align-items: center; flex: 0 0 auto;
  width: 100%; padding: var(--sp-3) 0 var(--sp-2); color: #fff;
}
.rail a:hover { text-decoration: none; }
.rail-ic {
  width: 32px; height: 32px; border-radius: var(--radius-sm);
  display: grid; place-items: center; transition: background-color .12s ease;
}
.rail-ic .icon { width: 20px; height: 20px; }
.rail a:hover .rail-ic { background: rgba(255, 255, 255, .16); }
.rail a.on .rail-ic {
  background: #fff; color: var(--rail-top);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .1), 0 1px 2px -1px rgba(0, 0, 0, .1);
}
.rail-label { font-size: var(--fs-100); font-weight: 600; line-height: 16px; padding-top: 2px; }
.rail .rail-end { margin-top: auto; }

.side-panel {
  flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column;
  background: var(--side); border: 1px solid var(--line); border-bottom: none;
  border-radius: var(--radius-sm) 0 0 0;
}
.side-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  flex: 0 0 auto; min-height: 44px; padding: var(--sp-4) var(--sp-4) var(--sp-2) var(--sp-6);
}
.side-head b { font-size: var(--fs-700); font-weight: 600; line-height: 20px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.btn.create {
  height: 28px; padding: 0 var(--sp-4) 0 var(--sp-3); gap: var(--sp-2);
  font-size: var(--fs-500); font-weight: 500; line-height: 16px; border-radius: 7px;
}
.btn.create .icon { width: 16px; height: 16px; }

.side-panel nav { display: flex; flex-direction: column; gap: 2px; overflow-y: auto;
  padding: 0 var(--sp-4) var(--sp-8); }
.side-panel nav a {
  display: flex; align-items: center; gap: var(--sp-4); flex: 0 0 auto;
  height: 28px; padding: 0 var(--sp-4); border-radius: 7px;
  color: var(--ink); font-size: var(--fs-500); line-height: 28px; white-space: nowrap;
}
.side-panel nav a .icon { width: 16px; height: 16px; color: var(--ink-2); }
.side-panel nav a .label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.side-panel nav a:hover { background: var(--hover); text-decoration: none; }
.side-panel nav a.on { background: var(--hover); font-weight: 500; }
.side-panel nav a.on .icon { color: var(--ink); }
.nav-group {
  flex: 0 0 auto; height: 24px; display: flex; align-items: center;
  font-size: var(--fs-300); font-weight: 500; line-height: 16px; color: var(--ink-2);
  margin: var(--sp-6) 0 0 var(--sp-3);
}
.nav-group:first-child { margin-top: var(--sp-2); }

/* Свёрнутое меню — как в ClickUp: остаётся один рельс, панель разделов
   выезжает поверх страницы, когда курсор или фокус на рельсе. Так с
   рельса по-прежнему можно дойти до любого раздела, а не только до
   шести модулей. */
body.nav-narrow .sidebar { width: var(--sidebar-narrow); flex-basis: var(--sidebar-narrow); }
body.nav-narrow .side-panel {
  display: none; position: absolute; left: var(--sidebar-narrow); top: 0; bottom: 6px;
  width: 208px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
}
body.nav-narrow .sidebar:hover .side-panel,
body.nav-narrow .sidebar:focus-within .side-panel { display: flex; }

.avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: 0 0 auto;
  background: var(--accent-soft); color: var(--accent);
  display: grid; place-items: center; font-size: var(--fs-300); font-weight: 650;
}
.brand-mark {
  width: 28px; height: 28px; border-radius: 8px; flex: 0 0 auto;
  background: var(--accent); color: var(--accent-ink);
  display: grid; place-items: center; font-weight: 700; font-size: var(--fs-400);
}

.main {
  flex: 1; min-width: 0; display: flex; flex-direction: column;
  background: var(--content); border-top: 1px solid var(--line);
}
body.nav-narrow .main { border-left: 1px solid var(--line); border-radius: var(--radius-sm) 0 0 0; }
.icon-btn {
  display: inline-grid; place-items: center; width: 30px; height: 30px;
  border-radius: var(--radius-sm); border: 1px solid transparent;
  background: transparent; color: var(--ink-2); cursor: pointer; padding: 0;
}
.icon-btn:hover { background: var(--hover); color: var(--ink); border-color: transparent; }
/* Поиск — пилюля 28px по центру полосы: белая, без рамки, контур даёт
   тень в один пиксель. */
.search-trigger {
  display: flex; align-items: center; justify-content: flex-start; gap: var(--sp-2); width: 254px; max-width: 100%; height: 28px;
  padding: 0 var(--sp-4); border: none; border-radius: 999px;
  background: var(--panel); color: var(--ink-4); font-size: var(--fs-500); font-weight: 500;
  box-shadow: 0 0 1px rgba(0, 0, 0, .27), 0 1px 2px rgba(0, 0, 0, .055); cursor: pointer;
}
.search-trigger .icon { width: 16px; height: 16px; color: var(--ink-2); }
.search-trigger:hover { background: var(--panel); color: var(--ink-2); border: none;
  box-shadow: 0 0 1px rgba(0, 0, 0, .45), 0 1px 3px rgba(0, 0, 0, .1); }
.search-trigger kbd {
  font: inherit; font-size: var(--fs-300); font-weight: 400; color: var(--ink-4);
  border: none; padding: 0 var(--sp-2); background: none;
}
.content { padding: var(--sp-8) var(--sp-8) 64px; max-width: 1320px; width: 100%; }

/* ------------------------------------------------------------- компоненты */
.card, .panel {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: var(--sp-7) var(--sp-7); margin-bottom: var(--sp-6);
  box-shadow: var(--shadow-sm);
}
.panel-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-5); margin-bottom: var(--sp-6); }
/* Заголовок панели — h2: после h1 страницы h3 пропускал уровень, и
   читалка объявляла раздел не того порядка. Размер оставляем прежний,
   чтобы шапки панелей на всех страницах выглядели одинаково. */
.panel-head h2, .panel-head h3 { margin: 0; font-size: var(--fs-500); }
/* Подпись не переносилась и вылезала за панель: на аналитике «узкая полоса
   снизу — реклама того же дня» торчала наружу на 36px, а заголовок рядом
   ломался на три строки. Теперь ряд умеет переноситься: если подпись не
   встала рядом, она уходит на свою строку и прижимается вправо, а
   заголовку достаётся вся ширина и он перестаёт дробиться. */
.panel-head { flex-wrap: wrap; }
.panel-head > :first-child { min-width: 0; }
.panel-head .hint { white-space: nowrap; margin-left: auto; }
/* Ряд карточек. Минимальная ширина в minmax раньше считалась в пикселях
   (212px), и на рабочем окне 974px в контент влезали ровно три колонки:
   четыре KPI ложились 3 + 1, и под тремя карточками оставалась дыра во
   всю строку. Теперь минимум — это доля самого ряда, а не константа:
   ширина трека равна точной четверти (или половине), поэтому колонок
   всегда столько, сколько задано, без «почти влезло».
   auto-fit схлопывает пустые треки, так что одна карточка по-прежнему
   занимает всю ширину, а три — ровные трети. */
.cards {
  display: grid; gap: var(--sp-6); margin-bottom: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(calc((100% - 3 * var(--sp-6)) / 4), 1fr));
}
/* Ниже 1180px окна контент уже меньше 884px — четыре карточки по 212px
   в него не встают. Переходим на две колонки: четыре KPI дают ровный
   квадрат 2x2, восемь — 2x4. Порог взят по ширине контента, а не окна:
   окно минус сайдбар 256 и поля 44. */
@media (max-width: 1180px) {
  .cards { grid-template-columns: repeat(auto-fit, minmax(calc((100% - var(--sp-6)) / 2), 1fr)); }
  /* Нечётная карточка осталась бы одна в последнем ряду и опять оставила
     бы полряда пустым (так ведут себя трое на «Поставщиках»). Последняя
     в нечётном ряду растягивается на обе колонки — ряд закрыт. */
  .cards > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .cards { grid-template-columns: minmax(0, 1fr); }
}
/* min(320px, 100%), а не 320px: на телефоне контент шириной 343px, и
   колонка в 320 вроде бы влезает — но ребёнок сетки по умолчанию не
   сжимается уже своего содержимого, и панель «Заказы по дням» доходила
   до 491px, утаскивая вбок всю страницу. min-width:0 снимает этот
   запрет, min() даёт колонке честно стать уже порога. */
.grid-2 {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: var(--sp-6);
}
.grid-2 > * { min-width: 0; }

.kpi {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: var(--sp-6) var(--sp-7); box-shadow: var(--shadow-sm);
}
.kpi .k { font-size: var(--fs-300); color: var(--ink-3); display: flex; align-items: center; gap: var(--sp-3); }
.kpi .v { font-size: var(--fs-900); font-weight: 650; letter-spacing: -.02em; margin: var(--sp-3) 0 var(--sp-1); }
.kpi .s { font-size: var(--fs-300); color: var(--ink-3); }
.kpi.alert .v { color: var(--warn); }
.kpi.good .v { color: var(--good); }

table { width: 100%; border-collapse: collapse; background: var(--panel); }
table.list { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-sm); }
/* Широкая таблица (расчёт себестоимости) прокручивается вбок, а не вылезает
   за панель. Рамка уезжает на обёртку, иначе она обрезается при прокрутке. */
.table-scroll {
  overflow-x: auto; border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
/* Прозрачная: подложку даёт .table-scroll, и на ней же лежат тени по
   краям (блок «таблица уехала вбок» ниже). Непрозрачная таблица
   закрашивала их целиком — подсказка была в файле, но её никто не
   видел ни разу. */
.table-scroll > table.list {
  border: none; border-radius: 0; box-shadow: none; min-width: 100%;
  background: transparent;
}
.table-scroll th, .table-scroll td { white-space: nowrap; }
/* Длинные названия переносим и ограничиваем по ширине: иначе одна
   колонка с именем китайского завода в 60 символов растягивает таблицу
   на пол-экрана, и до правых колонок надо долго крутить. */
.table-scroll td.t-title { white-space: normal; min-width: 180px; max-width: 300px; }
/* Номер партии — код из десяти знаков, он не переносится и ему не нужны
   180 пикселей, заложенные под длинное название задачи. */
.table-scroll td.t-title.code { min-width: 0; max-width: none; white-space: nowrap; }
/* Название китайского завода в 60 символов нельзя ни пустить в строку
   (колонка на пол-экрана), ни перенести по словам (строка таблицы в семь
   этажей). Режем многоточием, целиком — в подсказке и в карточке.
   max-width на самой ячейке таблица игнорирует, поэтому ограничиваем
   содержимое. 230px ужато до 170 — названия всё равно обрезаются, а
   различаются они в первых полутора десятках знаков; эти шестьдесят
   пикселей — ровно то, чего не хватало «Плану прихода» у поставок,
   чтобы поместиться на рабочем окне. */
.table-scroll td.t-wrap > *, table.list td.t-wrap > * {
  display: block; max-width: 170px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
th, td { text-align: left; padding: var(--sp-5) var(--sp-6); border-bottom: 1px solid var(--line-low); font-size: var(--fs-500); vertical-align: middle; }
/* Заголовок колонки: 12px/500 обычным регистром и высотой 32, как в
   ClickUp. Капс с разрядкой в плотной таблице читается хуже — глаз
   спотыкается на каждой подписи, а их в строке до восьми. */
th {
  height: 32px; padding-top: 0; padding-bottom: 0;
  font-size: var(--fs-300); font-weight: 500; color: var(--ink-3);
  background: var(--panel-2); border-bottom-color: var(--line);
}
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--panel-2); }
/* Числовая ячейка. Без nowrap «5 733 885 ₽» переносилось так, что знак
   рубля уезжал на вторую строку, а строка таблицы вырастала вдвое —
   на аналитике ячейки доходили до 82px высоты. Сумма и процент — это
   одно слово, разрывать их нельзя. tabular-nums держит цифры в колонку,
   иначе разряды в соседних строках не совпадают по ширине. */
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* :first-of-type, а не :first-child: в строках с правкой форма лежит
   перед первой ячейкой (<form id> + td с form=...), и по :first-child
   правило не срабатывало совсем — поле имени схлопывалось в 26px. */
table.list td:first-of-type input[type="text"],
table.list td:first-of-type input:not([type]) { min-width: 150px; }
table.list input, table.list select, table.list textarea { margin-top: 0; }
table.list textarea { min-height: 54px; font-size: var(--fs-400); }

label { display: block; font-size: var(--fs-400); color: var(--ink-2); margin-bottom: var(--sp-6); }
input, select, textarea {
  /* Поле 34px и кнопка 32px с радиусом 6 — размеры ClickUp. Прежние 40px
     делали каждую форму и панель фильтров на четверть выше. */
  width: 100%; margin-top: var(--sp-2); padding: 5px var(--sp-5); font: inherit; font-size: var(--fs-500);
  color: var(--ink); background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius-xs);
}
input[type="color"] { padding: var(--sp-1); height: 34px; }
textarea { min-height: 120px; resize: vertical; }
input:hover, select:hover, textarea:hover { border-color: var(--line-hover); }
input::placeholder, textarea::placeholder { color: var(--ink-4); }
input:disabled, select:disabled, textarea:disabled { color: var(--ink-5); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
button, .btn {
  display: inline-flex; align-items: center; gap: var(--sp-3); justify-content: center;
  padding: var(--sp-2) var(--sp-5); font: inherit; font-size: var(--fs-500); font-weight: 500;
  color: var(--accent-ink); background: var(--accent); border: 1px solid var(--accent);
  border-radius: var(--radius-xs); cursor: pointer; white-space: nowrap;
}
button:hover, .btn:hover { background: var(--accent-hover); border-color: var(--accent-hover); text-decoration: none; }
.btn.ghost, button.ghost {
  background: var(--panel); color: var(--ink); border-color: var(--line); font-weight: 500;
}
.btn.ghost:hover, button.ghost:hover { background: var(--panel-3); border-color: var(--line-strong); }
.btn.small, button.small { padding: var(--sp-1) var(--sp-4); font-size: var(--fs-400); }
/* Длинная подпись переносится, а не вылезает за панель на узком экране. */
.btn.wrap, button.wrap { white-space: normal; text-align: center; max-width: 100%; }
.btn.danger { background: var(--warn); border-color: var(--warn); }
.row { display: flex; gap: var(--sp-6); flex-wrap: wrap; align-items: flex-end; }
.row > * { flex: 1; min-width: 150px; }
.row > .narrow { flex: 0 0 auto; min-width: 0; }
/* Поля под длинный текст растут вдвое быстрее соседей: иначе описание
   получает те же 150px, что и «Порядок», и содержимое не прочитать. */
.row > .wide { flex: 2 1 220px; }
form.inline { display: inline; }
fieldset { border: none; padding: 0; margin: 0; }

.flash {
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-6); border-radius: var(--radius-sm); margin-bottom: var(--sp-6); font-size: var(--fs-500);
}
.flash.warn { background: var(--warn-soft); color: var(--warn); }
.flash.ok { background: var(--good-soft); color: var(--good); }
.hint { color: var(--ink-3); font-size: var(--fs-400); }
.muted { color: var(--ink-3); }
.pill {
  display: inline-flex; align-items: center; gap: var(--sp-2); padding: var(--sp-1) var(--sp-4); border-radius: 999px;
  font-size: var(--fs-300); font-weight: 550; background: var(--panel-3); color: var(--ink-2);
}
.pill .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.pill.urgent, .pill.high { background: var(--warn-soft); color: var(--warn); }
.pill.ok { background: var(--good-soft); color: var(--good); }
.pill.accent { background: var(--accent-soft); color: var(--accent); }
.kpi .s.prop { font-size: var(--fs-600); color: var(--ink); margin-top: var(--sp-2); }
.overdue { color: var(--warn); font-weight: 600; }
.head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-6); margin-bottom: var(--sp-7); }
.head .hint { margin: var(--sp-2) 0 0; }
/* Блок заголовка держался за свою естественную ширину, и кнопкам справа
   не доставалось места: на товарах «Новый товар» срывался на вторую
   строку один, на оргструктуре — «Сотрудники». Теперь заголовок умеет
   сжиматься (подпись под ним переносится), и ряд кнопок остаётся целым.
   Название страницы при этом не дробим: это опора всей шапки. */
.head > :first-child { min-width: 0; flex: 0 1 auto; }
.head h1 { white-space: nowrap; }
.head > .narrow { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--sp-3); flex: 0 0 auto; }
.prose { max-width: 760px; }
.prose h2 { font-size: var(--fs-700); } .prose h3 { font-size: var(--fs-500); }
.prose ul, .prose ol { padding-left: var(--sp-8); }
.prose code { background: var(--panel-3); padding: var(--sp-1) var(--sp-2); border-radius: 5px; font-size: var(--fs-400); }
.prose blockquote { margin: 0 0 var(--sp-5); padding: var(--sp-4) var(--sp-6); background: var(--panel-2); border-left: 3px solid var(--line-strong); }
.tree { list-style: none; padding-left: 0; margin: 0; }
.tree ul { list-style: none; padding-left: var(--sp-8); border-left: 1px dashed var(--line-strong); margin: var(--sp-2) 0 var(--sp-2) var(--sp-3); }
.tree li { padding: var(--sp-1) 0; }
.empty {
  padding: 34px var(--sp-9); text-align: center; color: var(--ink-3);
  background: var(--panel); border: 1px dashed var(--line-strong); border-radius: var(--radius);
}
.empty .icon { width: 26px; height: 26px; stroke: var(--ink-3); margin-bottom: var(--sp-4); }
.empty-title { color: var(--ink); font-weight: 600; margin-bottom: var(--sp-2); }

/* --------------------------------------------------------- графики (бары) */
.bars { display: flex; flex-direction: column; gap: var(--sp-4); }
.bar-row { display: grid; grid-template-columns: 140px 1fr 44px; align-items: center; gap: var(--sp-5); }
.bar-label { display: flex; align-items: center; gap: var(--sp-3); font-size: var(--fs-400); color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.swatch { width: 9px; height: 9px; border-radius: 3px; background: var(--c, var(--data-1)); flex: 0 0 auto; }
.bar-track { height: 12px; background: var(--panel-3); border-radius: 3px; overflow: hidden; }
.bar-fill { display: block; height: 100%; background: var(--c, var(--data-1)); border-radius: 0 4px 4px 0; min-width: 2px; }
.bar-value { font-size: var(--fs-400); color: var(--ink); text-align: right; font-variant-numeric: tabular-nums; }
/* Денежные бары: справа не счётчик, а сумма — колонке нужно больше места. */
.bars.money .bar-row { grid-template-columns: 124px 1fr 96px; }
.bars.money .bar-value { white-space: nowrap; }
/* Две величины в одном баре: заказы сверху, реклама того же дня снизу. */
.bars.dual .bar-track { position: relative; height: 16px; }
.bars.dual .bar-fill { height: 9px; }
.bar-sub {
  position: absolute; left: 0; bottom: 0; height: 5px; display: block;
  background: var(--c, var(--data-2)); border-radius: 0 3px 3px 0; min-width: 2px;
}
.bar-label .muted { margin-left: var(--sp-3); font-size: var(--fs-300); }

/* ------------------------------------------------------- поиск по сервису */
.palette-wrap {
  position: fixed; inset: 0; z-index: 100; display: none;
  background: rgba(16, 24, 40, .45); padding: 12vh var(--sp-7) var(--sp-7);
}
.palette-wrap.open { display: block; }
.palette {
  max-width: 560px; margin: 0 auto; background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.palette input {
  margin: 0; border: none; border-bottom: 1px solid var(--line); border-radius: 0;
  padding: var(--sp-6) var(--sp-7); font-size: var(--fs-600); background: var(--panel);
}
.palette input:focus { box-shadow: none; border-color: var(--line); }
.palette-results { max-height: 52vh; overflow-y: auto; padding: var(--sp-3); }
.palette-group { font-size: var(--fs-200); text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-3); padding: var(--sp-4) var(--sp-5) var(--sp-2); font-weight: 600; }
.palette-item {
  display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-4) var(--sp-5);
  border-radius: var(--radius-sm); color: var(--ink); cursor: pointer; font-size: var(--fs-500);
}
.palette-item:hover, .palette-item.on { background: var(--accent-soft); color: var(--accent); text-decoration: none; }
.palette-item .muted { margin-left: auto; font-size: var(--fs-300); }
.palette-foot { border-top: 1px solid var(--line); padding: var(--sp-4) var(--sp-6); font-size: var(--fs-300); color: var(--ink-3); }

/* ---------------------------------------------------------- оформление
   Диалог «Тема и цвет». Устроен как палитра поиска: тот же затемнённый
   фон и та же карточка, чтобы оверлеи в сервисе выглядели одинаково. */
.modal-wrap {
  position: fixed; inset: 0; z-index: 110; display: none;
  background: rgba(16, 24, 40, .45); padding: 10vh var(--sp-7) var(--sp-7); overflow-y: auto;
}
.modal-wrap.open { display: block; }
.modal {
  max-width: 440px; margin: 0 auto; background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); padding: var(--sp-7) var(--sp-8) var(--sp-8);
}
.modal-head { display: flex; align-items: flex-start; gap: var(--sp-6); margin-bottom: var(--sp-2); }
.modal-head > div { flex: 1; min-width: 0; }
.modal-head b { font-size: var(--fs-600); }
.modal-head .icon-btn { font-size: var(--fs-800); line-height: 1; }
.modal-section {
  font-size: var(--fs-200); text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-3); font-weight: 600; margin: var(--sp-7) 0 var(--sp-4);
}

.theme-modes { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); }
.theme-mode {
  display: flex; flex-direction: column; align-items: stretch; gap: var(--sp-3);
  padding: var(--sp-3); background: var(--panel); border: 1.5px solid var(--line);
  border-radius: var(--radius-sm); cursor: pointer; color: var(--ink-2);
  font-size: var(--fs-300); font-weight: 500;
}
.theme-mode:hover { background: var(--panel); border-color: var(--line-strong); }
.theme-mode.on { border-color: var(--accent); color: var(--ink); }
.theme-mode-name { text-align: center; }
/* Миниатюра темы: слева «меню» с цветным квадратом, справа «строки».
   Цвета заданы числами, а не токенами: плитка светлой темы обязана
   остаться светлой, даже когда включена тёмная. */
.theme-prev {
  position: relative; display: block; height: 46px; border-radius: 6px;
  overflow: hidden; border: 1px solid var(--line);
  background: #ffffff;
}
.theme-prev i { position: absolute; display: block; }
.theme-prev i:first-child { left: 0; top: 0; bottom: 0; width: 30%; background: #eef0f4; }
.theme-prev i:last-child {
  left: 7%; top: 7px; width: 16%; height: 9px; border-radius: 3px;
  background: var(--accent);
}
.theme-prev::after {
  content: ""; position: absolute; left: 38%; right: 8%; top: 11px; height: 6px;
  border-radius: 3px; background: #dfe3ea;
  box-shadow: 0 13px 0 #e9ecf1, 0 26px 0 #e9ecf1;
}
.theme-prev.dark { background: #161a21; border-color: #272d39; }
.theme-prev.dark i:first-child { background: #1b2029; }
.theme-prev.dark::after { background: #2d3440; box-shadow: 0 13px 0 #232936, 0 26px 0 #232936; }
/* «Как в системе» — половина светлая, половина тёмная, как у ClickUp.
   Строки рисуются двумя частями: ::after до середины светлым, ::before
   после середины тёмным. Одним градиентом не обойтись — он считается от
   ширины самой полосы, а она начинается не от края плитки. */
.theme-prev.auto { background: linear-gradient(90deg, #ffffff 50%, #161a21 50%); }
.theme-prev.auto i:first-child { background: #eef0f4; }
.theme-prev.auto::after { left: 38%; right: 52%; background: #dfe3ea;
  box-shadow: 0 13px 0 #e9ecf1, 0 26px 0 #e9ecf1; }
.theme-prev.auto::before {
  content: ""; position: absolute; left: 54%; right: 8%; top: 11px; height: 6px;
  border-radius: 3px; background: #2d3440;
  box-shadow: 0 13px 0 #232936, 0 26px 0 #232936;
}

.accent-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-4); }
.accent-pick {
  display: flex; align-items: center; gap: var(--sp-4); justify-content: flex-start;
  padding: var(--sp-4) var(--sp-5); font-size: var(--fs-400); font-weight: 500;
  color: var(--ink-2); background: var(--panel);
  border: 1.5px solid var(--line); border-radius: var(--radius-sm); cursor: pointer;
  min-width: 0;
}
.accent-pick:hover { background: var(--panel-3); border-color: var(--line-strong); }
.accent-pick.on { border-color: var(--accent); color: var(--ink); background: var(--accent-soft); }
.accent-dot {
  width: 14px; height: 14px; border-radius: 4px; flex: 0 0 auto;
  background: var(--ink-3);
}
.accent-pick.on .accent-dot::after {
  content: "✓"; display: block; color: #fff; font-size: var(--fs-100); line-height: 14px;
  text-align: center; font-weight: 700;
}
.accent-dot[data-accent="black"] { background: #2f333a; }
.accent-dot[data-accent="purple"] { background: #5b4fd6; }
.accent-dot[data-accent="blue"] { background: #0f66b4; }
.accent-dot[data-accent="pink"] { background: #c62a73; }
.accent-dot[data-accent="violet"] { background: #8b35d6; }
.accent-dot[data-accent="indigo"] { background: #4a53d9; }
.accent-dot[data-accent="orange"] { background: #a44a09; }
.accent-dot[data-accent="teal"] { background: #0a6e68; }
.accent-dot[data-accent="bronze"] { background: #8a5c3e; }
.accent-dot[data-accent="mint"] { background: #0b7149; }

/* Точки в сетке цветов — не токены, а сами цвета: каждая обязана
   показывать свой цвет, а не выбранный сейчас. В тёмной теме берётся
   светлый вариант того же набора. */
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) .accent-dot[data-accent="black"] { background: #c6ccd6; }
  :root:where(:not([data-theme="light"])) .accent-dot[data-accent="purple"] { background: #8b80f0; }
  :root:where(:not([data-theme="light"])) .accent-dot[data-accent="blue"] { background: #55a9ef; }
  :root:where(:not([data-theme="light"])) .accent-dot[data-accent="pink"] { background: #f075ac; }
  :root:where(:not([data-theme="light"])) .accent-dot[data-accent="violet"] { background: #c186f5; }
  :root:where(:not([data-theme="light"])) .accent-dot[data-accent="indigo"] { background: #8e97f7; }
  :root:where(:not([data-theme="light"])) .accent-dot[data-accent="orange"] { background: #f0883d; }
  :root:where(:not([data-theme="light"])) .accent-dot[data-accent="teal"] { background: #3ec4b4; }
  :root:where(:not([data-theme="light"])) .accent-dot[data-accent="bronze"] { background: #cb9a78; }
  :root:where(:not([data-theme="light"])) .accent-dot[data-accent="mint"] { background: #3ec98d; }
}
:root[data-theme="dark"] .accent-dot[data-accent="black"] { background: #c6ccd6; }
:root[data-theme="dark"] .accent-dot[data-accent="purple"] { background: #8b80f0; }
:root[data-theme="dark"] .accent-dot[data-accent="blue"] { background: #8da4ef; }
:root[data-theme="dark"] .accent-dot[data-accent="pink"] { background: #f075ac; }
:root[data-theme="dark"] .accent-dot[data-accent="violet"] { background: #c186f5; }
:root[data-theme="dark"] .accent-dot[data-accent="indigo"] { background: #8e97f7; }
:root[data-theme="dark"] .accent-dot[data-accent="orange"] { background: #f0883d; }
:root[data-theme="dark"] .accent-dot[data-accent="teal"] { background: #3ec4b4; }
:root[data-theme="dark"] .accent-dot[data-accent="bronze"] { background: #cb9a78; }
:root[data-theme="dark"] .accent-dot[data-accent="mint"] { background: #3ec98d; }

/* --------------------------------------------------------------- вход */
.login-wrap { min-height: 100vh; display: grid; place-items: center; padding: var(--sp-8);
  background: radial-gradient(1200px 500px at 50% -10%, var(--accent-soft), var(--surface)), var(--surface); }
.login { width: 380px; }
.login h1 { font-size: var(--fs-800); margin-bottom: var(--sp-2); }
.login button { width: 100%; margin-top: var(--sp-2); }
.login .brand-mark { width: 36px; height: 36px; font-size: var(--fs-600); margin-bottom: var(--sp-6); }

/* =============================================================== трекер */
.space-tabs { display: flex; gap: var(--sp-1); flex-wrap: wrap; margin-bottom: var(--sp-5);
  border-bottom: 1px solid var(--line); padding-bottom: var(--sp-3); }
.space-tabs a {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-6); border-radius: var(--radius-sm); color: var(--ink-2); font-size: var(--fs-500);
}
.space-tabs a:hover { background: var(--panel-3); color: var(--ink); text-decoration: none; }
.space-tabs a.on { background: var(--accent-soft); color: var(--accent); font-weight: 600; }

/* Панель фильтров остальных разделов: товары, поставки, аналитика,
   управленка. У задач своя — .view-bar ниже. */
/* Сетка, а не flex-wrap: при переносе flex растягивал последний ряд, и
   «Показывать» в одиночку разъезжался на 483px против 187 у соседа
   сверху. В сетке колонки одни и те же во всех рядах, поэтому поля
   стоят друг под другом. Поиск занимает две колонки: в одну его
   подсказка не помещается. */
.toolbar {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: var(--sp-5) var(--sp-6); align-items: end;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: var(--sp-5) var(--sp-6); margin-bottom: var(--sp-7); box-shadow: var(--shadow-sm);
}
/* Поля панели фильтров брали ширину по содержимому: на поставках
   «Поставщик» разъезжался на 450px, а «Транспорт» рядом занимал 180,
   и ряды выходили рваной мозаикой. Общая основа выравнивает их в
   колонки, а растяжение добивает ряд до края, не оставляя дыр.
   Кнопки из этого ритма исключены — они живут по своей ширине. */
.toolbar .tool { margin: 0; font-size: var(--fs-300); min-width: 0; }
.toolbar .tool:has(input:not([type="checkbox"])) { grid-column: span 2; }
.toolbar > button, .toolbar > .btn { justify-self: start; align-self: end; }
.toolbar .tool select { min-width: 148px; padding: var(--sp-3) var(--sp-4); font-size: var(--fs-400); }

/* Вкладки видов и панель инструментов под ними — как в ClickUp: сначала
   выбираешь вид, потом настраиваешь его. Старый класс .toolbar не трогаем:
   он стоит ещё на десятке страниц (товары, поставки, управленка). */
.view-head { margin-bottom: var(--sp-7); }

/* Название пространства и ряд вкладок стоят в одной строке: заголовок
   слева, вкладки за ним, общая линия снизу. Отдельной строкой заголовок
   стоил 44px высоты, а на окне 974px шапка задач и так съедала почти
   половину экрана — первая задача начиналась на y=366 из 820. */
.view-top {
  display: flex; align-items: flex-end; gap: var(--sp-9); flex-wrap: wrap;
  border-bottom: 1px solid var(--line);
}
.space-title {
  font-size: var(--fs-800); font-weight: 600; letter-spacing: -.01em;
  margin: 0 0 var(--sp-3); flex: 0 0 auto;
}
/* Линия переехала на .view-top, иначе под вкладками их оказалось бы две. */
.view-top .view-tabs { border-bottom: none; flex: 1 1 auto; }

/* Ряд вкладок ClickUp: подписи 12/600, активная подчёркнута линией 2px
   цвета текста (не акцента), промежутки широкие, фона у вкладок нет. */
.view-tabs {
  display: flex; align-items: stretch; gap: var(--sp-8); flex-wrap: wrap;
  border-bottom: 1px solid var(--line);
}
.vtab-sep { width: 1px; background: var(--line); margin: var(--sp-3) 0; align-self: stretch; }
.vt-ico { width: 15px; height: 15px; }
.vt-chat { color: #7b68ee; }
.vt-list { color: #1090e0; }
.vt-board { color: #4a53d9; }
.vt-cal { color: #eb6834; }
/* Вкладка — кнопка формы и ссылка одновременно, поэтому сбрасываем всё,
   что им дают базовые стили button и a. */
.vtab, .view-tabs .dropdown > summary {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) 0 var(--sp-3); margin-bottom: -1px;
  background: none; border: none; border-bottom: 2px solid transparent;
  border-radius: 0; cursor: pointer;
  font-size: var(--fs-300); font-weight: 500; color: var(--ink-2);
}
.vtab:hover, .view-tabs .dropdown > summary:hover {
  color: var(--ink); text-decoration: none; border-bottom-color: var(--line-strong);
}
.vtab.on {
  color: var(--ink); font-weight: 600; border-bottom-color: var(--ink);
  background: none;
}
.vtab.on .vtab-ico { color: var(--ink); }
.vtab-more { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-bottom: var(--sp-6); }
.vtab-ico { font-size: var(--fs-400); color: var(--ink-3); line-height: 1; }
.vtab-mine { font-size: var(--fs-300); color: var(--ink-3); font-weight: 400; }
.vtab.on .vtab-mine { color: color-mix(in srgb, var(--accent) 70%, var(--ink-3)); }
.view-tabs .dropdown > summary { color: var(--ink-3); }
.view-tabs .dropdown[open] > summary { color: var(--accent); border-bottom-color: var(--accent); }
.vtab-new .dropdown-body { min-width: 272px; }
.vtab-new label { margin-bottom: var(--sp-5); }

/* Чат пространства встроен отдельным документом: у него свой js живых
   сообщений, перенести его в страницу задач одной разметкой нельзя. */
.space-chat {
  width: 100%; height: calc(100vh - 260px); min-height: 420px;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel);
}
.chat.bare { grid-template-columns: 1fr; }

/* Список: все группы в одной панели, как в ClickUp. Таблица внутри без
   своей рамки — рамка одна, у панели. */
.list-panel {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: var(--sp-4) 0; box-shadow: var(--shadow-sm);
}
.lg + .lg { margin-top: var(--sp-5); }
.lg-head { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-4) var(--sp-6) var(--sp-3); }
.list-panel table.list { border: none; border-radius: 0; box-shadow: none; }
.list-panel table.list th { background: none; }
/* Значок и название статуса в строке — тем же цветом, но подмешанным к
   основному тексту: чистый цвет статуса на панели не читается (жёлтый на
   белом — 2.2:1). Примесь работает в обе темы: в светлой --ink тёмный и
   цвет уходит вниз, в тёмной светлый и цвет уходит вверх, оттенок цел. */
.row-status {
  width: 16px; height: 16px; vertical-align: -3px; margin-right: var(--sp-3);
  color: color-mix(in srgb, var(--c, var(--ink-3)) 60%, var(--ink));
}
.cell-v { display: inline-flex; align-items: center; gap: var(--sp-2); }
.cell-v .icon { width: 14px; height: 14px; }
.cell-v.overdue { color: var(--warn); font-weight: 400; }
.cell-v.pri-urgent .icon { color: var(--warn); }
.cell-v.pri-high .icon { color: #ffc53d; }
.cell-v.pri-low .icon { color: var(--ink-5); }
.cell-v .cm-avatar { width: 20px; height: 20px; font-size: var(--fs-100); }
/* Пустая ячейка — бледная иконка поля, а не прочерк. */
.cell-empty { width: 16px; height: 16px; color: var(--ink-5); }
.cell-empty-dash { color: var(--ink-5); }

.view-bar {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-5) 0 0;
}
.view-bar-gap { flex: 1 1 auto; }
/* Подпись кнопки: «Группировка» серым, текущее значение — тёмным рядом.
   Так видно настройку, не открывая выпадашку. */
.view-bar .dropdown > summary {
  gap: var(--sp-3); font-size: var(--fs-300); line-height: 16px; padding: var(--sp-1) var(--sp-4);
  background: var(--panel); border-radius: var(--radius);
}
.view-bar .dropdown > summary b { color: var(--ink); font-weight: 600; }
.view-bar .dropdown > summary.live {
  border-color: var(--accent); color: var(--accent); background: var(--accent-soft);
}
.view-bar .dropdown > summary.live b { color: var(--accent); }
.view-bar .dropdown-body label { margin-bottom: var(--sp-5); }
.view-bar .dropdown-body label:last-of-type { margin-bottom: 0; }
/* Селект на всю ширину — только в узких выпадашках (группировка,
   сортировка). В широкой живёт конструктор фильтров: там в строке три
   поля рядом, и 100% растягивало каждое на всю панель, унося её за
   правый край экрана вместе со всей страницей. */
.view-bar .dropdown-body:not(.wide) select { min-width: 100%; }

.dropdown { position: relative; }
.dropdown > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: inline-flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-6); border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--panel); font-size: var(--fs-400); color: var(--ink-2);
}
.dropdown > summary::-webkit-details-marker { display: none; }
.dropdown > summary:hover { border-color: var(--line-strong); color: var(--ink); }
.dropdown[open] > summary { border-color: var(--accent); color: var(--accent); }
.dropdown-body {
  position: absolute; z-index: 25; top: calc(100% + 6px); left: 0; min-width: 244px;
  max-width: calc(100vw - 32px);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: var(--sp-6); box-shadow: var(--shadow-lg);
}
/* Класс вешает app.js, когда справа от кнопки не хватает места. */
.dropdown-body.flip { left: auto; right: 0; }
/* min-width сильнее max-width, поэтому на телефоне жёсткие 580px
   перевешивали ограничение по ширине окна и уносили панель за край. */
.dropdown-body.wide { min-width: min(580px, calc(100vw - 32px)); }
.dropdown-body.right { left: auto; right: 0; }
.check { display: flex; align-items: center; gap: var(--sp-4); font-size: var(--fs-500); color: var(--ink); margin-bottom: var(--sp-3); }
.check input { width: auto; margin: 0; }

.filter-row { display: flex; gap: var(--sp-3); align-items: center; margin-bottom: var(--sp-4); }
.filter-row select, .filter-row input { width: auto; min-width: 132px; margin: 0; padding: var(--sp-3) var(--sp-4); font-size: var(--fs-400); }
.filter-row .fv-holder select[multiple] { min-height: 64px; }

/* -------------------------------------------------------------- дашборды */
.board-tile { display: block; color: var(--ink); }
.board-tile:hover { text-decoration: none; border-color: var(--accent); }
.board-name { font-size: var(--fs-700); font-weight: 650; margin: var(--sp-3) 0 var(--sp-1); letter-spacing: -.01em; }
.tpl-grid .tpl { display: flex; flex-direction: column; gap: var(--sp-1); margin: 0; }
.tpl-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-5); }
.tpl-head b { font-size: var(--fs-600); }
/* Описание забирает лишнюю высоту на себя, поэтому поле «Название»,
   галочка и кнопка стоят в соседних карточках на одном уровне. Раньше
   у «Простого» описание было в строку, у «Руководителю» в две, и кнопки
   «Создать» расходились по высоте на 15px. */
.tpl-grid .tpl .hint { flex: 1 1 auto; }
.tpl .btn { align-self: flex-start; margin-top: var(--sp-2); }
.dash-bar { padding-top: 0; margin-bottom: var(--sp-6); }
.sep { border: none; border-top: 1px solid var(--line); margin: var(--sp-6) 0; }

/* Двенадцать колонок: карточка занимает --w из них и --h рядов по 96px.
   Свободная сетка с произвольными координатами выглядит так же, но
   требует разбора пересечений при каждом переносе — здесь карточки
   просто перетекают, а порядок задаётся перетаскиванием. */
.dash-grid {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--sp-6); align-items: start;
}
.dcard {
  grid-column: span var(--w, 6);
  min-height: calc(var(--h, 2) * 96px);
  display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: var(--sp-6) var(--sp-7); box-shadow: var(--shadow-sm);
  min-width: 0;
}
.dcard-head { display: flex; align-items: center; gap: var(--sp-4); margin-bottom: var(--sp-5); }
.dcard-head h2, .dcard-head h3 { margin: 0; font-size: var(--fs-500); flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dcard-head .hint { white-space: nowrap; }
.dcard-head .dropdown > summary { padding: var(--sp-1) var(--sp-4); font-size: var(--fs-400); }
.dcard-body { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; }
.dcard-body > .bars { justify-content: center; }

.dcard-number { font-size: var(--fs-1000); font-weight: 650; letter-spacing: -.02em; line-height: 1.1; }
.dcard-number.alert { color: var(--warn); }
.dcard-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-3); }
.dcard-list li {
  display: flex; align-items: center; gap: var(--sp-3); font-size: var(--fs-400); min-width: 0;
}
.dcard-list li > a {
  color: var(--ink); flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dcard-list li > a:hover { color: var(--accent); }
.dcard-list .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--c, var(--ink-3)); flex: 0 0 auto; }
.dcard-list .muted, .dcard-list .overdue { font-size: var(--fs-300); white-space: nowrap; }
.dcard-pair { display: flex; flex-wrap: wrap; gap: var(--sp-5); }
.dcard-mini {
  flex: 1 1 96px; min-width: 0; padding: var(--sp-4) var(--sp-5);
  background: var(--panel-2); border-radius: var(--radius-sm); color: var(--ink);
}
.dcard-mini:hover { text-decoration: none; background: var(--panel-3); }
.dcard-mini b { display: block; font-size: var(--fs-800); font-weight: 650; letter-spacing: -.01em; }
.dcard-mini span { font-size: var(--fs-300); color: var(--ink-3); }
.dcard-mini.alert b { color: var(--warn); }
.dcard .prose { max-width: none; font-size: var(--fs-500); }

/* Режим правки: заголовок становится ручкой переноса. */
.dash-grid.editing .dcard { border-style: dashed; border-color: var(--line-strong); }
.dash-grid.editing .dcard-head h2 { cursor: grab; }
.dcard.dragging { opacity: .35; }
.dcard.ghost {
  position: fixed; z-index: 100; pointer-events: none; opacity: .97;
  box-shadow: var(--shadow-lg); border-style: solid;
}
.dash-grid.editing.over { outline: 2px dashed var(--accent); outline-offset: 6px; border-radius: var(--radius); }
.kind-row { margin: 0; }
.kind-pick {
  display: block; width: 100%; text-align: left; padding: var(--sp-3) var(--sp-4);
  background: none; border: none; border-radius: var(--radius-sm); color: var(--ink);
  font-weight: 500;
}
.kind-pick:hover { background: var(--accent-soft); }
.kind-pick b { display: block; font-size: var(--fs-400); }
.kind-pick .hint { display: block; white-space: normal; font-size: var(--fs-300); }

/* На ноутбуке двенадцать колонок дают карточку в четверть шириной
   160px — в неё не влезает ни число с подписью, ни полоса. Ниже
   1100 сетка складывается вдвое, ниже 700 — в одну колонку. */
/* span не принимает calc() и min(), поэтому узкие ширины задаются
   отдельными правилами по data-w, а не пересчётом переменной. */
@media (max-width: 1100px) {
  .dash-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .dcard { grid-column: span 6; }
  .dcard[data-w="3"], .dcard[data-w="4"] { grid-column: span 3; }
}
@media (max-width: 700px) {
  .dash-grid { grid-template-columns: 1fr; }
  .dcard, .dcard[data-w="3"], .dcard[data-w="4"] { grid-column: span 1; }
}

/* ------------------------------------------------------------- календарь */
.cal-nav { display: flex; align-items: center; gap: var(--sp-2); }
.cal-nav .icon-btn { width: 28px; height: 28px; font-size: var(--fs-700); line-height: 1; }
.cal-title { font-size: var(--fs-500); min-width: 128px; text-align: center; }

.calendar { display: flex; gap: var(--sp-6); align-items: flex-start; }
.cal-grid {
  flex: 1; min-width: 0;
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  background: var(--line); gap: var(--sp-1);
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.cal-dow {
  background: var(--panel-2); padding: var(--sp-3) var(--sp-5);
  font-size: var(--fs-200); text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-3); font-weight: 600;
}
.cal-day {
  background: var(--panel); min-height: 108px; padding: var(--sp-2) var(--sp-3) var(--sp-3);
  display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0;
}
.cal-day.other { background: var(--panel-2); }
.cal-day.other .cal-date { color: var(--ink-3); }
.cal-day.weekend:not(.other) { background: color-mix(in srgb, var(--panel-2) 55%, var(--panel)); }
.cal-date { font-size: var(--fs-300); color: var(--ink-2); font-weight: 600; padding: var(--sp-1) var(--sp-1); }
.cal-date .muted { font-weight: 400; font-size: var(--fs-200); }
.cal-day.today .cal-date {
  background: var(--accent); color: var(--accent-ink);
  border-radius: 999px; width: 22px; height: 22px;
  display: grid; place-items: center; padding: 0;
}
/* Клетка не должна расти от числа задач: иначе одна занятая дата
   растягивает всю строку недели на пол-экрана. Лишнее прокручивается. */
.cal-drop { display: flex; flex-direction: column; gap: var(--sp-1); max-height: 132px; overflow-y: auto; }
/* Блок, а не flex: у flex-контейнера text-overflow не срабатывает, и
   длинное название обрезалось по краю клетки без многоточия. Точка
   статуса поэтому inline-block внутри строки. */
.cal-task {
  display: block; padding: var(--sp-1) var(--sp-3); border-radius: 5px;
  font-size: var(--fs-300); line-height: 1.5; color: var(--ink);
  background: var(--panel-3); cursor: grab;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cal-task:hover { text-decoration: none; background: var(--accent-soft); color: var(--accent); }
.cal-task .dot {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--c, var(--ink-3)); margin-right: var(--sp-2); vertical-align: middle;
}
.cal-task.overdue { color: var(--warn); font-weight: 600; }
.cal-task.drag { opacity: .4; }
.cal-task.ghost {
  position: fixed; z-index: 100; pointer-events: none; opacity: .97;
  box-shadow: var(--shadow-lg); background: var(--panel);
  border: 1px solid var(--line-strong);
}
.cal-drop.over { outline: 2px dashed var(--accent); outline-offset: -2px; border-radius: 5px; }
/* Поле «＋» показывается при наведении на клетку: тридцать пустых полей
   на месяц — это шум, из-за которого не видно самих задач. Там, где
   наведения нет (телефон, планшет), поле видно всегда. */
.cal-add { opacity: 0; transition: opacity .12s ease; }
.cal-day:hover .cal-add, .cal-add:focus-within { opacity: 1; }
@media (hover: none) {
  .cal-add { opacity: 1; }
}
.cal-add input {
  margin: 0; padding: var(--sp-1) var(--sp-3); font-size: var(--fs-300); border-color: transparent;
  background: transparent; color: var(--ink-3);
}
.cal-add input:hover { border-color: var(--line); background: var(--panel); }
.cal-add input:focus { color: var(--ink); background: var(--panel); }
/* «＋» здесь не подсказка, а подпись кнопки: читать её надо так же, как
   подпись задачи, поэтому ступень вверх — как в колонке доски. */
.cal-add input::placeholder { color: var(--ink-3); }

.cal-side { flex: 0 0 216px; display: flex; flex-direction: column; gap: var(--sp-6); }
.cal-side-group {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: var(--sp-5) var(--sp-6); box-shadow: var(--shadow-sm);
}
.cal-side-head {
  font-size: var(--fs-200); text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-3); font-weight: 600; margin-bottom: var(--sp-4);
}
.cal-side .cal-task { margin-bottom: var(--sp-2); }
.cal-side .hint { margin: 0; }

/* --------------------------------------------------------------- таблица */
.table-view td, .table-view th { padding: var(--sp-3) var(--sp-6); }
.table-view .c-pick { width: 34px; padding-right: 0; }
.table-view .c-pick input { width: auto; margin: 0; }
.table-view .c-num { width: 42px; color: var(--ink-3); font-size: var(--fs-300); font-variant-numeric: tabular-nums; }
.table-view tr.picked td { background: var(--accent-soft); }
.table-view tbody.group-row td {
  background: var(--panel-2); font-weight: 650; font-size: var(--fs-400);
  padding: var(--sp-3) var(--sp-6); white-space: nowrap;
}
.table-view tbody.group-row .dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: var(--c, var(--ink-3)); margin-right: var(--sp-3);
}
.table-view .table-add { padding: 0; }
.table-view .table-add input {
  margin: 0; border: none; border-radius: 0; background: transparent;
  color: var(--ink-3); padding: var(--sp-4) var(--sp-6);
}
.table-view .table-add input:focus { box-shadow: none; color: var(--ink); background: var(--panel-2); }

/* Панель массовых действий: всплывает снизу над содержимым, как в ClickUp.
   Внутри прокручиваемой страницы ей нужен свой слой — иначе её перекроет
   шапка таблицы при залипании. */
.bulk-bar {
  position: sticky; bottom: 14px; z-index: 28;
  display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap;
  margin: var(--sp-6) auto 0; width: fit-content; max-width: 100%;
  min-height: 48px; padding: var(--sp-4) var(--sp-6);
  background: var(--ink); color: var(--panel);
  border: 1px solid transparent; border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.bulk-bar.hidden { display: none; }
.bulk-bar b { font-size: var(--fs-400); white-space: nowrap; }
.bulk-bar select { width: auto; min-width: 128px; margin: 0; padding: var(--sp-2) var(--sp-4); font-size: var(--fs-400); }
/* На тёмной панели кнопка «Снять» должна быть прозрачной со светлой
   подписью — белая кнопка на тёмной плашке перетягивает внимание с
   «Применить». Селекты остаются светлыми: тёмный select на части систем
   рисует нечитаемый список вариантов. */
.bulk-bar .btn.ghost, .bulk-bar button.ghost {
  background: transparent; color: var(--panel);
  border-color: color-mix(in srgb, var(--panel) 28%, transparent);
}
.bulk-bar .btn.ghost:hover, .bulk-bar button.ghost:hover {
  background: color-mix(in srgb, var(--panel) 14%, transparent);
  border-color: color-mix(in srgb, var(--panel) 40%, transparent);
}

.group-head {
  display: flex; align-items: center; gap: var(--sp-4); margin: var(--sp-8) 0 var(--sp-4);
  font-size: var(--fs-500); font-weight: 650;
}
.group-head .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--c, var(--ink-3)); }
.group-head .muted { font-weight: 500; }
/* Колонка с названием — самая важная и самая широкая: в ClickUp на неё
   отведено 36% ширины таблицы против 14% на остальные. У нас она делила
   ширину со статусом поровну, названия ломались на пять строк, и строка
   вырастала со штатных 35px до 180. */
.tasks-list th:first-child, .tasks-list td.t-title { width: 36%; min-width: 140px; }
/* В раскладке «Список» у каждой группы своя <table>, и при table-layout:
   auto каждая считала ширины по своему содержимому: колонки соседних
   групп разъезжались на 54px на 974px и до 90px на 1440px — список
   выглядел кривым. Фиксированная раскладка заставляет все группы взять
   одни и те же доли: 36% под название, остаток поровну между прочими.
   Набор колонок у групп один и тот же, поэтому доли совпадают. */
.list-panel table.tasks-list { table-layout: fixed; }
/* Остальные колонки живут коротким содержимым («—», «Высокий», датой), и
   их ширину задаёт подпись в шапке, а не данные. Сжимаем им поля с 12 до
   8: тридцать два пикселя уходят колонке с названием, ради которой в
   таблицу и смотрят. */
.tasks-list th + th, .tasks-list td.t-title ~ td { padding-left: var(--sp-4); padding-right: var(--sp-4); }
.t-title a { font-weight: 500; color: var(--ink); }
.t-title a:hover { color: var(--accent); }
.chip {
  display: inline-flex; align-items: center; margin-left: var(--sp-3); padding: var(--sp-1) var(--sp-3); border-radius: 6px;
  font-size: var(--fs-300); background: var(--panel-3); color: var(--ink-2);
}
.card-meta .chip { background: var(--panel); border: 1px solid var(--line-low); }
.chip.warn { background: var(--warn-soft); color: var(--warn); }
.chip.overdue { background: var(--warn-soft); color: var(--warn); }
select.status-pick {
  width: auto; min-width: 88px; max-width: 100%; padding: var(--sp-2) var(--sp-3); font-size: var(--fs-400); margin: 0;
  border-color: color-mix(in srgb, var(--c, var(--line)) 45%, var(--line));
  color: color-mix(in srgb, var(--c, var(--ink)) 60%, var(--ink));
  background: var(--panel); font-weight: 600;
}

.board { display: flex; gap: var(--sp-4); overflow-x: auto; padding-bottom: var(--sp-6); align-items: flex-start; }
/* Колонка и её шапка подкрашены цветом статуса (8% и 12%), как в ClickUp:
   колонку узнаёшь боковым зрением, не читая заголовок. */
.board-col {
  flex: 0 0 264px; padding: var(--sp-4); border-radius: var(--radius);
  background: color-mix(in srgb, var(--c, var(--ink-3)) 8%, var(--panel-3));
}
.board-col-head {
  display: flex; align-items: center; gap: var(--sp-3); height: 40px;
  margin: -8px -8px var(--sp-4); padding: 0 var(--sp-5);
  border-radius: var(--radius) var(--radius) 0 0;
  background: color-mix(in srgb, var(--c, var(--ink-3)) 12%, transparent);
  font-size: var(--fs-400); font-weight: 650; color: var(--ink);
}
.board-col-head .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--c, var(--ink-3)); }
/* Чип статуса: залит цветом статуса, подпись капсом — как в ClickUp.
   У самой левой колонки («не начато») ClickUp вместо заливки даёт лёгкую
   подложку и тёмный текст, иначе светло-серый чип с белой подписью не
   читается.
   Подпись приходит в --c-ink: цвета статусов задаёт человек, и на светлых
   (жёлтый, мята, светло-серый) белый капс не читался — 2.2:1 на жёлтом.
   Сервер считает яркость цвета и подставляет белую или почти чёрную; сам
   цвет не трогаем, его же носят точка на доске и подложка колонки. */
.st-chip {
  display: inline-flex; align-items: center; gap: var(--sp-2); height: 20px;
  padding: var(--sp-1) var(--sp-3) var(--sp-1) var(--sp-2); border-radius: var(--radius-xs);
  background: var(--c, var(--ink-3)); color: var(--c-ink, #ffffff);
  font-size: var(--fs-300); font-weight: 500; line-height: 16px;
  text-transform: uppercase; white-space: nowrap;
}
.st-chip .icon { width: 14px; height: 14px; }
.st-chip.soft { background: rgba(0, 0, 0, .06); color: var(--ink); }
:root[data-theme="dark"] .st-chip.soft { background: rgba(255, 255, 255, .1); }
/* Колонка подкрашена цветом статуса, и подложка выходит светлее панели:
   на ней третий и четвёртый уровни текста уже не дотягивают до нормы
   (на серой колонке — 3.6:1). Внутри колонки поднимаем на ступень. */
.board-col-count { font-size: var(--fs-500); font-weight: 500; color: var(--ink-2); }
.board-add input::placeholder { color: var(--ink-2); }

/* Поля карточки: заполненное — чип с иконкой и значением, пустое — та же
   иконка в квадрате 24×24 без текста. ClickUp так уводит шум: видно, куда
   кликать, но доска не пестрит словом «не задано». */
.cm {
  display: inline-flex; align-items: center; gap: var(--sp-2); height: 24px; padding: 0 var(--sp-3);
  border: 1px solid var(--line-low); border-radius: var(--radius-xs);
  background: var(--panel); color: var(--ink-2); font-size: var(--fs-400); white-space: nowrap;
}
.cm .icon { width: 14px; height: 14px; }
.cm.empty { width: 24px; padding: 0; justify-content: center; color: var(--ink-4); }
.cm.due.overdue { color: var(--warn); }
.cm.due.overdue .icon { color: var(--warn); }
.cm.pri-urgent .icon { color: var(--warn); }
.cm.pri-high .icon { color: #ffc53d; }
.cm.pri-low .icon { color: var(--ink-5); }
.cm-avatar {
  width: 24px; height: 24px; border-radius: 50%; flex: 0 0 auto;
  background: #595d66; color: rgba(255, 255, 255, .9);
  display: grid; place-items: center; font-size: var(--fs-100); line-height: 1;
}
.card-desc-mark { display: block; margin-top: var(--sp-3); color: var(--ink-4); }
.board-drop { min-height: 40px; display: flex; flex-direction: column; gap: var(--sp-4); }
.board-drop.over { outline: 2px dashed var(--accent); outline-offset: 3px; border-radius: var(--radius-sm); }
/* Карточка без рамки, на двух тенях — контурной и мягкой, как в ClickUp.
   Рамка поверх подкрашенной колонки давала третью линию подряд: край
   колонки, рамка, тень. В тёмной теме тень не читается — там рамка нужна. */
.task-card {
  background: var(--panel); border: 1px solid transparent; border-radius: 10px;
  padding: var(--sp-5) var(--sp-5); margin: 0; cursor: grab; touch-action: none; user-select: none;
  box-shadow: 0 0 0 1px rgba(16, 24, 40, .07), 0 1px 2px rgba(16, 24, 40, .06);
}
.task-card:hover { box-shadow: 0 0 0 1px rgba(16, 24, 40, .1), 0 2px 5px rgba(16, 24, 40, .1); }
:root[data-theme="dark"] .task-card { border-color: var(--line); box-shadow: var(--shadow-sm); }
:root[data-theme="dark"] .task-card:hover { border-color: var(--line-strong); }
.task-card.dragging { opacity: .35; }
.task-card.ghost {
  position: fixed; z-index: 100; pointer-events: none; opacity: .97;
  box-shadow: var(--shadow-lg); transform: rotate(1.5deg);
}
body.dragging-now { cursor: grabbing; }
.task-card a { color: var(--ink); font-weight: 500; font-size: var(--fs-500); line-height: 20px; }
.card-meta { margin-top: var(--sp-4); display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.card-meta .chip { margin-left: 0; }
.card-field { margin-top: var(--sp-3); font-size: var(--fs-300); color: var(--ink-2); }
.board-add { margin-top: var(--sp-4); }
.board-add input { font-size: var(--fs-400); padding: var(--sp-3) var(--sp-4); background: transparent; border-style: dashed; }
.board-add input:focus { background: var(--panel); }
.hidden { display: none !important; }

.task-grid { display: grid; grid-template-columns: minmax(0, 1fr) 330px; gap: var(--sp-7); align-items: start; }
.field-row { display: flex; gap: var(--sp-5); align-items: center; padding: var(--sp-2) 0; font-size: var(--fs-500); }
.field-row .field-name { flex: 0 0 142px; color: var(--ink-3); font-size: var(--fs-400); }
.field-row .field-value { flex: 1; min-width: 0; }
.field-row input, .field-row select, .field-row textarea { margin: 0; }

/* --------------------------------------------------------- адаптивность */

/* --------------------------------------------------------------- мессенджер
   Две колонки: слева список чатов, справа переписка. Лента прокручивается
   внутри себя, а не страницей, иначе поле ввода уезжает за экран. */
.chat {
  display: grid; grid-template-columns: 76px 320px minmax(0, 1fr); gap: var(--sp-5);
  height: calc(100vh - 150px); min-height: 440px;
  /* Под стеклянными панелями нужна подложка, иначе размывать нечего.
     Заливка еле видна и проступает в зазорах между колонками. */
  background:
    radial-gradient(90% 70% at 6% 0%, color-mix(in srgb, var(--accent) 9%, transparent), transparent 62%),
    radial-gradient(80% 60% at 100% 100%, color-mix(in srgb, var(--info) 7%, transparent), transparent 58%);
  border-radius: var(--radius);
}
/* Ветка — ещё одна колонка справа. В доке (embed) полосы папок нет, в
   режиме bare (чат во вкладке задач) нет и списка. */
.chat.with-thread { grid-template-columns: 76px 320px minmax(0, 1fr) 380px; }
.chat.embed { grid-template-columns: 240px minmax(0, 1fr); }
.chat.embed.with-thread { grid-template-columns: 240px minmax(0, 1fr) 340px; }
/* bare — это чат во вкладке задач: ни полосы папок, ни списка, одна
   лента во всю ширину рамки. Правило идёт после embed и с тремя
   классами, иначе список-невидимка съедал 240px, а переписка уезжала
   в узкую колонку. */
.chat.bare, .chat.embed.bare { grid-template-columns: minmax(0, 1fr); }
.chat.bare.with-thread, .chat.embed.bare.with-thread {
  grid-template-columns: minmax(0, 1fr) 380px;
}
/* Полосу папок прячем вместе со списком: одна кнопка — одно действие. */
.chat.side-off .chat-rail { display: none; }
.chat-thread {
  display: flex; flex-direction: column; min-width: 0;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-sm); overflow: hidden;
}
.thread-head {
  display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-5) var(--sp-6);
  border-bottom: 1px solid var(--line);
}
.thread-head .spacer { flex: 1 1 auto; }
.thread-log { flex: 1 1 auto; overflow-y: auto; padding: var(--sp-6); }
.thread-count {
  font-size: var(--fs-300); color: var(--ink-3); margin: var(--sp-5) 0 var(--sp-3);
  padding-bottom: var(--sp-3); border-bottom: 1px solid var(--line-low);
}
.thread-compose {
  display: flex; gap: var(--sp-4); align-items: flex-end;
  padding: var(--sp-5) var(--sp-6); border-top: 1px solid var(--line);
}
.thread-compose textarea { margin: 0; min-height: 46px; }

/* Строка ветки под сообщением: аватар, число ответов, время последнего —
   открывает ветку, как «1 reply» в ClickUp. */
.thread-line {
  display: inline-flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-3);
  padding: var(--sp-1) var(--sp-4) var(--sp-1) var(--sp-1); border-radius: 999px;
  font-size: var(--fs-400); color: var(--accent-text, var(--accent));
}
.thread-line:hover { background: var(--panel-2); text-decoration: none; }
.thread-line .avatar.small { width: 20px; height: 20px; font-size: var(--fs-100); }
.thread-line .muted { color: var(--ink-3); font-weight: 400; }

/* Панель действий над сообщением: в покое скрыта, всплывает под курсором
   у правого края — ровно как в ClickUp. */
.msg-acts {
  position: absolute; top: -10px; right: 6px; z-index: 5;
  display: none; align-items: center; gap: var(--sp-1);
  padding: var(--sp-1); background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
}
.chat-msg:hover .msg-acts, .msg-acts:focus-within { display: flex; }
.msg-act {
  display: inline-grid; place-items: center; width: 26px; height: 26px;
  padding: 0; border: none; border-radius: var(--radius-xs);
  background: none; color: var(--ink-2); cursor: pointer;
  font-size: var(--fs-500); line-height: 1; list-style: none;
}
.msg-act:hover { background: var(--panel-3); color: var(--ink); text-decoration: none; }
.msg-act .icon { width: 15px; height: 15px; }
.msg-act-more { position: relative; }
.msg-act-more > summary::-webkit-details-marker { display: none; }
/* --------------------------------------------- полоса папок и список чатов
   Раскладка повторяет мессенджеры: папки узкой колонкой, чаты строками
   с аватаром, последней репликой и временем, переписка справа. */
.chat-rail {
  /* overflow здесь видимый: иначе колонка срезает выпадашку «новая
     папка», как это уже было с формой опроса. Прокручивается внутренний
     список вкладок, а не сама полоса.
     z-index обязателен: backdrop-filter у соседнего списка заводит свой
     контекст наложения, и стеклянная панель закрывала собой форму
     новой папки, как бы высоко та ни лежала внутри полосы. */
  position: relative; z-index: 2;
  display: flex; flex-direction: column; gap: var(--sp-2); overflow: visible;
  padding: var(--sp-4) var(--sp-2);
  background: var(--glass); backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid var(--glass-line); border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
.rail-tabs {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--sp-2);
}
.rail-tab {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: var(--sp-3) 2px; border-radius: var(--radius-sm);
  color: var(--ink-3); font-size: var(--fs-200); text-align: center;
}
.rail-tab:hover { background: var(--panel-3); color: var(--ink-2); text-decoration: none; }
.rail-tab.on { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.rail-ico {
  position: relative; font-size: 17px; line-height: 1;
  display: grid; place-items: center; width: 24px; height: 24px;
}
.rail-ico .icon { width: 19px; height: 19px; }
.rail-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rail-dot {
  position: absolute; top: -6px; left: 11px; min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 8px; background: var(--accent); color: var(--accent-ink);
  font-size: var(--fs-100); font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
}
.rail-add { margin-top: auto; padding-top: var(--sp-3); }
/* Кружок под размер аватаров в списке, значок по центру: прежний «＋»
   был знаком полной ширины и в прямоугольной рамке стоял криво. */
.rail-add > summary {
  display: grid; place-items: center; width: 32px; height: 32px; margin: 0 auto;
  list-style: none; cursor: pointer;
  border: 1px dashed var(--line-strong); border-radius: 50%;
  color: var(--ink-3);
}
.rail-add > summary .icon { width: 15px; height: 15px; stroke-width: 2; }
.rail-add > summary::-webkit-details-marker { display: none; }
.rail-add > summary:hover { color: var(--accent); border-color: var(--accent); }
.rail-add .dropdown-body { left: 0; min-width: 264px; }

.chat-side {
  position: relative; z-index: 2;
  /* Колонка, из которой сейчас раскрыта выпадашка, поднимается над
     соседней: стеклянные панели — каждая со своим слоем, и фиксированный
     порядок всегда прятал меню то слева, то справа. */
  display: flex; flex-direction: column; min-width: 0;
  background: var(--glass); backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid var(--glass-line); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); overflow: visible;
}
.chat-rail:has(details[open]), .chat-side:has(details[open]) { z-index: 6; }
.chat-side-head {
  display: flex; align-items: center; gap: var(--sp-3); flex: 0 0 auto;
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
}
.chat-side-head b { font-size: var(--fs-700); letter-spacing: -.01em; }
.chat-side-head .spacer { flex: 1 1 auto; }
.chat-add > summary { list-style: none; cursor: pointer; }
.chat-add > summary::-webkit-details-marker { display: none; }
.chat-add-body { min-width: 300px; max-height: 60vh; overflow-y: auto; }
.chat-add-group {
  font-size: var(--fs-200); text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-3); font-weight: 600; margin: var(--sp-6) 0 var(--sp-2);
}
.chat-add-group:first-child { margin-top: 0; }
.new-members {
  margin: var(--sp-4) 0; max-height: 168px; overflow-y: auto;
  padding: var(--sp-3) var(--sp-4); border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.new-members-head { font-size: var(--fs-300); color: var(--ink-2); margin-bottom: var(--sp-3); }
.new-members .hint { margin: var(--sp-3) 0 0; }

.chat-list { flex: 1 1 auto; overflow-y: auto; padding: 0 var(--sp-3) var(--sp-4); }
.chat-group {
  font-size: var(--fs-200); text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-3); font-weight: 600; padding: var(--sp-5) var(--sp-4) var(--sp-2);
}
.chat-item {
  display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-sm); color: var(--ink); font-size: var(--fs-500);
}
.chat-item:hover { background: var(--panel-3); text-decoration: none; color: var(--ink); }
.chat-item.on { background: var(--accent-soft); }
/* Та же причина: акцентная подложка светлее панели, и время под ней
   теряется. Строка и так выделена заливкой — ступень вверх не мешает. */
.chat-item.on .chat-when { color: var(--ink-3); }
.chat-item.on .chat-name { color: var(--accent); }
.chat-list .chat-ava { width: 40px; height: 40px; border-radius: 50%; font-size: var(--fs-600); }
.chat-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.chat-line { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.chat-name {
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-weight: 600;
}
.chat-name .muted { font-size: var(--fs-300); font-weight: 400; }
.chat-when {
  flex: 0 0 auto; font-size: var(--fs-200); color: var(--ink-4);
  font-variant-numeric: tabular-nums;
}
/* Превью тише имени — так и задумано. Раньше здесь стоял --ink-2: --ink-3
   на мелком кегле не дотягивал до нормы. Теперь дотягивает. */
.chat-last {
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-size: var(--fs-300); color: var(--ink-3);
}
/* Чат с непрочитанными виден сразу: имя темнее и жирнее, время акцентом. */
.chat-item.unread .chat-name { font-weight: 700; }
.chat-item.unread .chat-when { color: var(--accent); font-weight: 600; }
.chat-item.flat { padding: var(--sp-2) var(--sp-3); font-size: var(--fs-400); }
.chat-empty { padding: var(--sp-4) var(--sp-5); }
.chat-hash { color: var(--ink-3); font-weight: 600; }
.chat-item.on .chat-hash { color: var(--accent); }
.chat-badge {
  flex: 0 0 auto; min-width: 19px; height: 19px; padding: 0 var(--sp-2);
  border-radius: 10px; background: var(--accent); color: var(--accent-ink);
  font-size: var(--fs-300); font-weight: 700; display: inline-flex;
  align-items: center; justify-content: center;
}
.avatar.small { width: 22px; height: 22px; font-size: var(--fs-200); flex: 0 0 auto; }

.chat-main {
  display: flex; flex-direction: column; min-width: 0;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-sm); overflow: hidden;
}
.chat-head {
  /* Прижимаем всё влево, а кнопки отодвигаем margin'ом: со
     space-between на узком окне аватар уезжал к правому краю, а
     название с кнопками сыпалось на три строки. */
  display: flex; align-items: center; justify-content: flex-start;
  flex-wrap: wrap; gap: var(--sp-5);
  padding: var(--sp-6) var(--sp-7); border-bottom: 1px solid var(--line); background: var(--panel-2);
}
.chat-head b { font-size: var(--fs-600); }
.chat-head-actions { display: flex; gap: var(--sp-3); flex: 0 0 auto; margin-left: auto; }
/* Под шапкой канала две колонки: слева закладки, справа переписка. */
.chat-body-row { display: flex; flex: 1 1 auto; min-height: 0; }
.chat-stream { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
.chat-marks {
  flex: 0 0 212px; width: 212px; overflow-y: auto;
  padding: var(--sp-6) var(--sp-5); border-right: 1px solid var(--line); background: var(--panel-2);
}
.marks-head {
  font-size: var(--fs-200); font-weight: 600; text-transform: uppercase;
  letter-spacing: .04em; color: var(--ink-3); margin-bottom: var(--sp-4); padding: 0 var(--sp-2);
}
.marks-empty { font-size: var(--fs-300); margin: 0 var(--sp-2) var(--sp-5); }
.mark { position: relative; margin-bottom: var(--sp-2); }
.mark-link, .mark-note {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-8) var(--sp-3) var(--sp-4); border-radius: var(--radius-xs);
  font-size: var(--fs-400); color: var(--ink); text-decoration: none;
}
.mark-link:hover { background: var(--panel-3); text-decoration: none; }
.mark-note { display: block; background: var(--panel); border: 1px solid var(--line-low); }
.mark-note b { display: block; font-weight: 600; }
.mark-note p { margin: var(--sp-1) 0 0; font-size: var(--fs-300); color: var(--ink-2); }
.mark-emoji { flex: 0 0 auto; margin-right: var(--sp-2); }
.mark-title { overflow: hidden; text-overflow: ellipsis; }
/* Крестик виден только под курсором: панель не пестрит кнопками. */
.mark-del { position: absolute; top: 5px; right: 2px; opacity: 0; }
.mark:hover .mark-del, .mark-del:focus-within { opacity: 1; }
.mark-del button {
  width: 20px; height: 20px; padding: 0; border: none; border-radius: var(--radius-xs);
  background: none; color: var(--ink-3); cursor: pointer; font-size: var(--fs-300); line-height: 1;
}
.mark-del button:hover { background: var(--panel-3); color: var(--warn); }
.marks-add { margin-top: var(--sp-4); }
.marks-add > summary {
  padding: var(--sp-3) var(--sp-4); border: 1px dashed var(--line-strong); border-radius: var(--radius-xs);
  background: none; font-size: var(--fs-400); color: var(--ink-2); justify-content: center;
}
.marks-add > summary:hover { border-color: var(--accent); color: var(--accent); }
.marks-add .dropdown-body { left: 0; min-width: 280px; }
/* На узком окне колонка закладок съела бы ленту — прячем её. Порог
   считаем по ленте, а не по окну: из ширины окна сначала вычитается
   сайдбар 256 и поля 44, потом список каналов 248 и его отступ 14, и
   только остаток достаётся ленте. При старых 900px на окне 974 лента
   получала 248px — закладки её и съедали, ровно как обещал комментарий. */
@media (max-width: 1260px) { .chat-marks { display: none; } }

/* Выпадашка открывается вниз, а форма опроса висит у самого поля ввода,
   под которым до низа окна ничего нет: панель раскрывалась за краем, и
   со стороны выглядело, будто кнопка не работает. Класс вешает app.js,
   когда снизу не хватает места, а сверху — хватает. */
.dropdown-body.drop-up { top: auto; bottom: calc(100% + 6px); }


/* Свёрнутые колонки чата. Список каналов — колонка сетки, закладки —
   колонка внутри ленты, поэтому прячутся они по-разному. */
.chat-head-panels { display: flex; gap: var(--sp-2); flex: 0 0 auto; }
.chat-head-panels .icon-btn[aria-pressed="false"] { color: var(--ink-3); }
.chat-head-panels .icon-btn[aria-pressed="false"] .icon { opacity: .6; }
.chat.side-off { grid-template-columns: 1fr; }
.chat.side-off.with-thread { grid-template-columns: 1fr 380px; }
.chat.side-off .chat-side { display: none; }
.chat.marks-off .chat-marks { display: none; }
/* Ниже 1260px закладок нет и так — кнопка, которая ничего не меняет,
   только сбивает с толку. */
@media (max-width: 1260px) { .chat-head-panels [data-chat-panel="marks"] { display: none; } }

.chat-log { flex: 1 1 auto; overflow-y: auto; padding: var(--sp-6) var(--sp-7); }
.chat-more { text-align: center; margin-bottom: var(--sp-6); }
.chat-day { text-align: center; margin: var(--sp-6) 0 var(--sp-5); position: relative; }
.chat-day::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 1px;
  background: var(--line);
}
.chat-day span {
  position: relative; background: var(--panel); padding: 0 var(--sp-5);
  font-size: var(--fs-300); color: var(--ink-3);
}
.chat-msg { padding: var(--sp-1) 0 var(--sp-2); position: relative; }
.chat-msg.joined { padding-top: 0; }
.chat-msg:hover { background: var(--panel-2); border-radius: var(--radius-sm); }
.chat-msg-head { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-1); }
.chat-msg-head b { font-size: var(--fs-500); }
.chat-time { font-size: var(--fs-300); color: var(--ink-3); }
.chat-body { padding-left: var(--sp-10); font-size: var(--fs-500); color: var(--ink); }
.chat-body p { margin: 0 0 var(--sp-2); }
.chat-body p:last-child { margin-bottom: 0; }
.chat-body ul, .chat-body ol { margin: var(--sp-2) 0; padding-left: var(--sp-8); }
.chat-edited { font-size: var(--fs-200); color: var(--ink-3); margin-left: var(--sp-2); }
.mention {
  background: var(--accent-soft); color: var(--accent);
  border-radius: 4px; padding: 0 var(--sp-1); font-weight: 600;
}
.chat-tools {
  position: absolute; top: 2px; right: 6px; display: none; gap: var(--sp-2);
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius-sm); padding: var(--sp-1);
}
.chat-msg:hover .chat-tools { display: flex; }
.chat-tools button { padding: var(--sp-1) var(--sp-3); font-size: var(--fs-300); }
.chat-edit { margin: var(--sp-3) 0 var(--sp-1) var(--sp-10); display: flex; gap: var(--sp-3); align-items: flex-start; }
.chat-edit textarea { flex: 1 1 auto; margin: 0; min-height: 52px; }
.chat-empty { padding: var(--sp-10) 0; text-align: center; }

/* Композер: вкладки сверху, поле и ряд инструментов в одной рамке, как в
   ClickUp. Рамка одна — у коробки, у самого поля её нет, иначе выходит
   рамка в рамке. */
.chat-compose { padding: var(--sp-5) var(--sp-6) var(--sp-6); border-top: 1px solid var(--line); }
.compose-tabs { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.ctab {
  display: inline-flex; align-items: center; gap: var(--sp-3); height: 28px; padding: 0 var(--sp-5);
  border: 1px solid transparent; border-radius: var(--radius-xs);
  background: none; font-size: var(--fs-400); font-weight: 500; color: var(--ink-2); cursor: pointer;
}
.ctab .icon { width: 14px; height: 14px; }
.ctab:hover { background: var(--panel-3); color: var(--ink); }
.ctab.on {
  background: var(--panel); border-color: var(--line); color: var(--ink);
  box-shadow: var(--shadow-sm);
}
.compose-box {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
.compose-box:focus-within { border-color: var(--line-hover); }
.compose-main { display: block; margin: 0; padding: var(--sp-4) var(--sp-5) 0; }
.post-fields {
  display: flex; align-items: center; gap: var(--sp-5); flex-wrap: wrap;
  padding-bottom: var(--sp-4); margin-bottom: var(--sp-3); border-bottom: 1px solid var(--line-low);
}
.post-type {
  display: inline-flex; align-items: center; gap: var(--sp-3); margin: 0;
  font-size: var(--fs-400); color: var(--ink-2); white-space: nowrap;
}
.post-type select { width: auto; margin: 0; padding: var(--sp-2) var(--sp-4); font-size: var(--fs-400); }
#postTitle {
  flex: 1 1 200px; margin: 0; border: none; background: none;
  padding: var(--sp-1) 0; font-size: var(--fs-600); font-weight: 600;
}
#postTitle:focus { box-shadow: none; outline: none; }
.chat-input-wrap { flex: 1 1 auto; position: relative; min-width: 0; }
.chat-compose textarea {
  margin: 0; min-height: 40px; max-height: 180px; resize: none; width: 100%;
  border: none; background: none; padding: var(--sp-2) 0;
}
.chat-compose textarea:focus { box-shadow: none; outline: none; }
.compose-tools { display: flex; align-items: center; gap: var(--sp-1); padding: var(--sp-2) var(--sp-4) var(--sp-4); }
.ctool {
  display: inline-grid; place-items: center; width: 28px; height: 28px; padding: 0;
  border: none; border-radius: var(--radius-xs); background: none; color: var(--ink-2);
  cursor: pointer; font-size: var(--fs-500); line-height: 1; list-style: none;
}
.ctool:hover { background: var(--panel-3); color: var(--ink); }
.ctool .icon { width: 16px; height: 16px; }
.ctool::-webkit-details-marker { display: none; }
.ctool-sep { width: 1px; height: 18px; background: var(--line); margin: 0 var(--sp-3); }
.ctool-gap { flex: 1 1 auto; }
.compose-send { height: 28px; padding: 0 var(--sp-6); font-size: var(--fs-400); }
.compose-hint { margin-top: var(--sp-3); text-align: right; font-size: var(--fs-300); color: var(--ink-4); }

/* Меню команд по «/»: всплывает над полем, две группы с подписями,
   выбранный пункт подсвечен — как у ClickUp по слэшу. */
.slash-menu {
  position: absolute; left: 0; bottom: calc(100% + 8px); z-index: 30;
  width: min(420px, 100%); max-height: 320px; overflow-y: auto; padding: var(--sp-3);
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.slash-group {
  padding: var(--sp-4) var(--sp-4) var(--sp-2); font-size: var(--fs-200); font-weight: 600;
  text-transform: uppercase; letter-spacing: .04em; color: var(--ink-3);
}
.slash-item {
  display: flex; align-items: center; gap: var(--sp-5); width: 100%;
  padding: var(--sp-3) var(--sp-4); border: none; border-radius: var(--radius-xs);
  background: none; color: var(--ink); cursor: pointer; text-align: left;
  font-size: var(--fs-500); line-height: 18px;
}
.slash-item:hover, .slash-item.on { background: var(--panel-3); }
.slash-mark {
  flex: 0 0 auto; display: grid; place-items: center;
  width: 26px; height: 26px; border: 1px solid var(--line-low);
  border-radius: var(--radius-xs); background: var(--panel-2);
  font-size: var(--fs-200); font-weight: 600; color: var(--ink-2);
}
.slash-name { flex: 0 0 auto; font-weight: 500; }
.slash-hint {
  flex: 1 1 auto; text-align: right; font-size: var(--fs-300); color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Пункт чек-листа в отрендеренном сообщении — без точки списка. */
li.md-check { list-style: none; margin-left: -18px; }
.chat-body pre, .prose pre {
  margin: var(--sp-3) 0; padding: var(--sp-5) var(--sp-6); overflow-x: auto;
  background: var(--panel-3); border-radius: var(--radius-sm);
  font-size: var(--fs-400); line-height: 1.5;
}
.chat-body pre code, .prose pre code { background: none; padding: 0; }

/* Объявление в ленте — карточка с видом и заголовком, чтобы его читали, а
   не проматывали вместе с болтовнёй. */
.post-card {
  /* Объявление отличает подпись сверху, а не цветная полоса слева:
     трёхпиксельная кромка на карточке — самый заметный штамп. */
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: var(--sp-5) var(--sp-6); margin-top: var(--sp-2);
  background: var(--panel-2);
}
.post-card-kind {
  display: flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-300); font-weight: 600; color: var(--accent);
  text-transform: uppercase; letter-spacing: .02em;
}
.post-card h4 { margin: var(--sp-2) 0 var(--sp-3); font-size: var(--fs-700); font-weight: 600; }
.chat-suggest {
  position: absolute; left: 0; bottom: calc(100% + 6px); z-index: 20;
  min-width: 220px; background: var(--panel); border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); padding: var(--sp-2);
}
.chat-suggest-item {
  display: block; width: 100%; text-align: left; background: none; border: none;
  color: var(--ink); font-weight: 500; padding: var(--sp-3) var(--sp-4); border-radius: 6px;
}
.chat-suggest-item:hover, .chat-suggest-item.on {
  background: var(--accent-soft); color: var(--accent); border-color: transparent;
}
/* Счётчик непрочитанных в боковом меню. */
.nav-badge {
  margin-left: auto; min-width: 19px; height: 19px; padding: 0 var(--sp-2);
  border-radius: 10px; background: var(--accent); color: var(--accent-ink);
  font-size: var(--fs-300); font-weight: 700; display: inline-flex;
  align-items: center; justify-content: center; flex: 0 0 auto;
}
.nav-badge.mention { background: var(--warn); }
/* Значок на кнопке чатов в верхней полосе — маленький, в углу. */
.gbar .nav-badge {
  position: absolute; top: -3px; right: -4px; min-width: 15px; height: 15px;
  padding: 0 var(--sp-1); font-size: var(--fs-100);
}

/* ----------------------------------------------------------------- файлы
   Картинки показываем сразу, остальное — строкой с именем и размером. */
.files { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: var(--sp-3); }
.file-row {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--panel-2); font-size: var(--fs-400); max-width: 460px;
}
.file-row .icon { width: 16px; height: 16px; color: var(--ink-3); flex: 0 0 auto; }
.file-row a { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-row .muted { flex: 0 0 auto; font-size: var(--fs-300); }
.file-row form.inline button { padding: var(--sp-1) var(--sp-3); font-size: var(--fs-300); }
.file-image { margin: 0; max-width: 360px; }
.file-image img {
  display: block; max-width: 100%; max-height: 320px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--panel-2);
}
.file-image figcaption {
  display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-2); font-size: var(--fs-300);
}
.file-image figcaption a { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-image figcaption form.inline button { padding: var(--sp-1) var(--sp-3); font-size: var(--fs-300); }

/* Выбранное к отправке — чипсы над полем ввода. */
.chat-picked { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.picked-file {
  display: inline-flex; align-items: center; gap: var(--sp-3); padding: var(--sp-1) var(--sp-2) var(--sp-1) var(--sp-4);
  border: 1px solid var(--line-strong); border-radius: 999px;
  background: var(--panel); font-size: var(--fs-300); max-width: 260px;
}
.picked-file > span {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.picked-file button {
  background: none; border: none; color: var(--ink-3); padding: 0 var(--sp-2);
  font-size: var(--fs-500); line-height: 1; cursor: pointer;
}
.picked-file button:hover { background: none; color: var(--warn); }

/* Куда бросать файл. */
.chat-main.drop-here { outline: 2px dashed var(--accent); outline-offset: -4px; }
.chat-compose .icon-btn { flex: 0 0 auto; height: 38px; width: 38px; }

/* --------------------------------------------- панель чатов справа
   Внутри — обычная страница чата в iframe: разметка одна на оба режима. */
.chat-dock {
  position: fixed; top: 0; right: 0; bottom: 0; width: 420px; z-index: 60;
  display: flex; flex-direction: column;
  background: var(--panel); border-left: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
}
.chat-dock-head {
  display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-5) var(--sp-6);
  border-bottom: 1px solid var(--line); background: var(--panel-2); flex: 0 0 auto;
}
.chat-dock-head .spacer { flex: 1 1 auto; }
.chat-dock iframe { flex: 1 1 auto; width: 100%; border: none; background: var(--surface); }
body.dock-open .content { padding-right: 436px; }
body.chat-embed { background: var(--surface); }
body.chat-embed .flash { margin: var(--sp-5); }

/* Встроенный режим: список и переписка по очереди, а не рядом.
   Ширина здесь 420px — это телефонная ширина, но высота полная, поэтому
   список остаётся вертикальным, а вбок не должно уезжать ничего. */
.chat.embed {
  grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr);
  height: 100vh; gap: 0; padding: 0;
}
.chat.embed .chat-side,
.chat.embed .chat-main { border-radius: 0; border: none; box-shadow: none; }
.chat.embed .chat-side { border-bottom: 1px solid var(--line); }
.chat.embed .chat-new-body { max-height: 220px; }
.chat.embed .chat-side { max-height: 40vh; overflow-x: hidden; }
.chat.embed .chat-folders { flex-wrap: wrap; }
.chat.embed .chat-main { min-height: 0; }
/* Поле ввода делит строку с тремя кнопками и остаётся шириной 183px —
   подсказка переносится на вторую строку и обрезается. В панели кнопки
   уходят под поле, и строка ввода снова одна. */
.chat.embed .compose-main { flex-wrap: wrap; }
.chat.embed .chat-input-wrap { flex: 1 1 100%; }
.chat.embed .chat-compose textarea { min-height: 44px; }

/* Выпадашки привязаны к своей кнопке, и в панели шириной 420px им
   некуда раскрыться: с right: 0 они уезжают за левый край, с left: 0 —
   за правый. Внутри iframe fixed считается от самой панели, поэтому
   здесь они раскрываются во всю её ширину. */
.chat.embed .folder-new .dropdown-body,
.chat.embed .chat-head .dropdown-body,
.chat.embed .emoji-panel,
.chat.embed .poll-new .dropdown-body {
  position: fixed; left: 12px; right: 12px; width: auto;
  min-width: 0; max-width: none; max-height: 56vh; overflow-y: auto;
}
.chat.embed .folder-new .dropdown-body,
.chat.embed .chat-head .dropdown-body { top: 52px; bottom: auto; }
.chat.embed .emoji-panel,
.chat.embed .poll-new .dropdown-body { bottom: 84px; top: auto; }
/* Форме опроса 56vh мало: в рамке высотой 420px это 234px при нужных
   317, и половина уезжала под край. Отдаём ей всё место над полем
   ввода. */
.chat.embed .poll-new .dropdown-body { max-height: calc(100vh - 100px); }
/* Палитра реакций раскрывается от самого сообщения, а не от кнопки «+»:
   у кнопки справа всего пара десятков пикселей, и палитра уезжает. */
.chat.embed .reaction-add { position: static; }
.chat.embed .reaction-add .dropdown-body {
  left: 12px; right: 12px; width: auto; flex-wrap: wrap;
}

/* Папки как вкладки над списком чатов. */
.chat-folders {
  display: flex; flex-wrap: wrap; gap: var(--sp-2); padding: 0 var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line); margin-bottom: var(--sp-3);
}
.folder-tab {
  padding: var(--sp-2) var(--sp-4); border-radius: 999px; font-size: var(--fs-400);
  color: var(--ink-2); background: var(--panel-3); white-space: nowrap;
}
.folder-tab:hover { text-decoration: none; color: var(--ink); }
.folder-tab.on { background: var(--accent); color: var(--accent-ink); }
.folder-tab .muted { color: inherit; opacity: .75; }
.folder-new > summary {
  cursor: pointer; list-style: none; padding: var(--sp-2) var(--sp-5); border-radius: 999px;
  background: var(--panel-3); color: var(--ink-2); font-size: var(--fs-400);
}
.folder-new > summary::-webkit-details-marker { display: none; }
.folder-new { position: relative; }
.folder-new .dropdown-body {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 30; width: 230px;
  background: var(--panel); border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); padding: var(--sp-5);
}

/* Кружок чата: картинка, эмодзи, буква или решётка. */
.chat-ava {
  width: 26px; height: 26px; border-radius: 8px; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--fs-500); overflow: hidden; background: var(--panel-3); color: var(--ink-2);
}
.chat-ava img { width: 100%; height: 100%; object-fit: cover; }
.chat-ava.letter { background: var(--accent-soft); color: var(--accent); font-weight: 700; font-size: var(--fs-300); }
.chat-ava.hash { font-weight: 700; }
.chat-head .chat-ava { width: 32px; height: 32px; font-size: var(--fs-700); }
.chat-head-text { flex: 1 1 120px; min-width: 0; }
.chat-badge.mention { background: var(--warn); }

/* Реакции под сообщением. */
.reactions { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); align-items: center; }
.reaction {
  background: var(--panel-3); border: 1px solid transparent; color: var(--ink);
  border-radius: 999px; padding: var(--sp-1) var(--sp-4); font-size: var(--fs-400); font-weight: 500;
}
.reaction:hover { background: var(--panel-3); border-color: var(--line-strong); }
.reaction.mine { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.reaction[disabled] { opacity: .7; cursor: default; }
.reaction-add { position: relative; }
.reaction-add > summary {
  cursor: pointer; list-style: none; width: 22px; height: 22px; border-radius: 999px;
  background: var(--panel-3); color: var(--ink-3); font-size: var(--fs-400);
  display: inline-flex; align-items: center; justify-content: center;
}
.reaction-add > summary::-webkit-details-marker { display: none; }
.reaction-add .dropdown-body {
  position: absolute; bottom: calc(100% + 5px); left: 0; z-index: 25;
  display: flex; gap: var(--sp-1); padding: var(--sp-2);
  background: var(--panel); border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
}

/* Выбор смайлика и значка канала. */
.emoji-panel {
  position: absolute; bottom: calc(100% + 8px); right: 0; z-index: 30;
  width: 300px; max-height: 280px; overflow-y: auto; padding: var(--sp-4);
  background: var(--panel); border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
}
.emoji-group {
  font-size: var(--fs-200); text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-3); font-weight: 600; padding: var(--sp-3) var(--sp-1) var(--sp-2);
}
.emoji-grid { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.emoji-pick {
  background: none; border: 1px solid transparent; font-size: var(--fs-700); line-height: 1;
  padding: var(--sp-2); border-radius: 6px; cursor: pointer; color: inherit;
}
.emoji-pick:hover { background: var(--panel-3); border-color: var(--line); }
.emoji-pick.on { background: var(--accent-soft); border-color: var(--accent); }

/* Голосование. */
.poll {
  margin-top: var(--sp-4); padding: var(--sp-5) var(--sp-6); border: 1px solid var(--line);
  border-radius: var(--radius-sm); background: var(--panel-2); max-width: 460px;
}
.poll-head { display: flex; flex-direction: column; gap: var(--sp-1); margin-bottom: var(--sp-4); }
.poll-option {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center;
  gap: var(--sp-4); margin: 0 0 var(--sp-3); padding: var(--sp-2) var(--sp-3); border-radius: 6px; cursor: pointer;
}
.poll-option:hover { background: var(--panel-3); }
.poll-option.chosen { background: var(--accent-soft); }
.poll-option input { width: auto; margin: 0; }
.poll-text { font-size: var(--fs-500); }
.poll-bar {
  grid-column: 2 / 3; height: 5px; border-radius: 3px; background: var(--panel-3);
  overflow: hidden; display: block;
}
.poll-bar > span { display: block; height: 100%; background: var(--accent); }
.poll-share { font-size: var(--fs-300); color: var(--ink-3); font-variant-numeric: tabular-nums; }
.poll-who { font-size: var(--fs-300); color: var(--ink-3); margin: -3px 0 var(--sp-3) var(--sp-10); }
.poll-foot { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; margin-top: var(--sp-4); }
/* Якорь формы опроса — не кнопка, а сам композер: 300px влево от
   кнопки не помещаются в колонку ленты и срезаются её краем. От
   композера форма раскрывается вверх на всю его ширину. */
.chat-compose { position: relative; }
.poll-new { position: static; flex: 0 0 auto; }
.poll-new > summary {
  cursor: pointer; list-style: none; padding: var(--sp-4) var(--sp-6); font-size: var(--fs-500);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--panel); color: var(--ink);
}
.poll-new > summary::-webkit-details-marker { display: none; }
/* Подвал формы опроса прилипает к низу панели: когда места мало и
   форма прокручивается, кнопка «Создать опрос» остаётся на виду. */
.poll-new-foot {
  position: sticky; bottom: calc(var(--sp-6) * -1); z-index: 1;
  margin: var(--sp-5) calc(var(--sp-6) * -1) calc(var(--sp-6) * -1);
  padding: var(--sp-4) var(--sp-6);
  background: var(--panel); border-top: 1px solid var(--line-low);
}
.poll-new .dropdown-body {
  /* top: auto обязателен. Общее правило .dropdown-body ставит top, а
     здесь стоял только bottom — заданы оба края, и высоту брал на себя
     браузер: форма сплющивалась в полоску 26px у нижнего края.
     Предельную высоту ставит app.js по свободному месту сверху. */
  position: absolute; top: auto; bottom: calc(100% + 8px);
  left: var(--sp-6); right: var(--sp-6); width: auto;
  z-index: 30; min-width: 0; max-width: none; overflow-y: auto;
  background: var(--panel); border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); padding: var(--sp-6);
}

/* ------------------------------------------------------------ управленка
   Широкая таблица с колонками-периодами: строки статей, выделенные
   заголовки разделов и жирный итог внизу. */
table.list.fin td:first-of-type { min-width: 240px; }
.fin-section td { background: var(--panel-2); font-weight: 600; }
.fin-section td:first-child { text-transform: uppercase; font-size: var(--fs-300); letter-spacing: .03em; }
.fin-article { padding-left: var(--sp-8) !important; }
.fin-sign {
  display: inline-block; width: 14px; font-weight: 700; color: var(--ink-3);
}
.fin-sign.income { color: var(--good); }
.fin-sign.expense { color: var(--warn); }
.fin-total td { background: var(--panel-3); font-size: var(--fs-500); }
table.list.fin th .hint { font-weight: 400; text-transform: none; letter-spacing: 0; }

@media (max-width: 1100px) { .task-grid { grid-template-columns: 1fr; } }
/* Календарь: боковая полоса уезжает под сетку. Рядом с ней на рабочем
   окне ноутбука на клетку остаётся 55 пикселей, и от названия задачи
   видно две буквы — сетке нужна вся ширина. */
@media (max-width: 1100px) {
  .calendar { flex-direction: column; }
  .cal-side {
    flex: none; width: 100%;
    display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  }
}
/* Тот же счёт: список каналов ужимается, когда контента под чат меньше
   примерно 980px, то есть окна — меньше 1280. */
@media (max-width: 1280px) {
  /* Колонок теперь три: правило на две роняло переписку под список. */
  .chat { grid-template-columns: 60px 248px minmax(0, 1fr); }
  .chat.with-thread { grid-template-columns: 60px 248px minmax(0, 1fr) 300px; }
  .chat.embed { grid-template-columns: 208px minmax(0, 1fr); }
  .chat.embed.with-thread { grid-template-columns: 208px minmax(0, 1fr) 300px; }
  .chat.bare, .chat.embed.bare { grid-template-columns: minmax(0, 1fr); }
  .chat.bare.with-thread, .chat.embed.bare.with-thread {
    grid-template-columns: minmax(0, 1fr) 300px;
  }
}
@media (max-width: 900px) {
  /* Ниже 900px панель разделов сворачивается сама — так же, как по
     кнопке: остаётся рельс, панель выезжает под курсором. */
  :root { --sidebar: var(--sidebar-narrow); }
  .side-panel {
    display: none; position: absolute; left: var(--sidebar-narrow); top: 0; bottom: 6px;
    width: 208px; border: 1px solid var(--line); border-radius: var(--radius-sm);
    box-shadow: var(--shadow-lg);
  }
  .sidebar:hover .side-panel, .sidebar:focus-within .side-panel { display: flex; }
  .main { border-left: 1px solid var(--line); border-radius: var(--radius-sm) 0 0 0; }
  .search-trigger { width: 200px; }
  .content { padding: var(--sp-7) var(--sp-7) 56px; }
}

/* --------------------------------------------------------------- путь партии
   Восемь шагов от заказа до склада. Были восемь одинаковых карточек в
   сетке: порядок читался только слева направо, а что путь пройден до
   «В пути» — ниоткуда; карточка текущего шага держалась на цветной
   полосе слева в два пикселя, самом заметном штампе машинной вёрстки.
   Теперь шаги стоят на дорожке: отрезок позади пройденного шага
   сплошной и тёмный, впереди — бледный, точка пройденного залита
   цветом статуса, будущего — пустая, текущего — в кольце своего цвета.
   Кнопка «отметить» остаётся у каждого шага (вернуться назад тоже
   надо), но заметная только у следующего: это то действие, ради
   которого сюда и заходят. */
.flow { display: flex; flex-wrap: wrap; row-gap: var(--sp-7); }
.flow-step {
  flex: 1 1 144px; min-width: 136px; position: relative;
  display: flex; flex-direction: column; gap: var(--sp-1);
  padding: 2px var(--sp-5) 0 0;
}
/* Отрезок дорожки: от своей точки до точки следующего шага. */
.flow-step::before {
  content: ""; position: absolute; z-index: 0;
  left: 5px; right: -5px; top: 6px; height: 2px; background: var(--line);
}
.flow-step:last-child::before { display: none; }
.flow-step.done::before { background: var(--line-hover); }
.flow-step .dot {
  position: relative; z-index: 1; width: 10px; height: 10px; border-radius: 50%;
  background: var(--panel); box-shadow: inset 0 0 0 2px var(--line-strong);
}
.flow-step .flow-title { font-size: var(--fs-400); font-weight: 600; color: var(--ink-2); }
.flow-step .flow-date { font-size: var(--fs-300); color: var(--ink-3); font-variant-numeric: tabular-nums; }
.flow-step form.inline { margin-top: var(--sp-2); }
.flow-step form.inline button { padding: var(--sp-1) var(--sp-3); font-size: var(--fs-300); }
.flow-step.done .dot { background: var(--c); box-shadow: none; }
/* Пройденное — история: оно читается, но не спорит с текущим шагом.
   Раньше названия пройденных шагов были той же плотности, что текущий,
   и «где мы сейчас» приходилось искать по рамке. */
.flow-step.done .flow-title { color: var(--ink-2); }
.flow-step.on .dot {
  background: var(--c); box-shadow: 0 0 0 4px color-mix(in srgb, var(--c) 24%, transparent);
}
.flow-step.on .flow-title { color: var(--ink); font-weight: 700; font-size: var(--fs-500); }
.flow-step.on .flow-date { color: var(--ink-2); }
/* Непройденное гасим цветом, а не прозрачностью: opacity .66 на тексте
   второго уровня давала 4.1:1 — ниже нормы, и заодно глушила кнопку,
   которую потом приходилось высветлять обратно. */
.flow-step.next .flow-title { color: var(--ink-3); }
/* Следующий шаг — с настоящей кнопкой: это то действие, ради которого
   сюда заходят. У остальных кнопка остаётся тихой. */
.flow-step.on + .flow-step .flow-title { color: var(--ink-2); }
.flow-step.on + .flow-step form.inline button {
  background: var(--accent); border-color: var(--accent);
  color: var(--accent-ink); font-weight: 600;
}
/* form.inline задаёт display: inline и перебивает одиночный класс —
   черта рисовалась бы вокруг кнопки, а не поперёк панели. */
form.inline.flow-cancel {
  display: block; margin-top: var(--sp-7); padding-top: var(--sp-6);
  border-top: 1px solid var(--line);
}
.flow-step.done form.inline button,
.flow-step.next form.inline button { color: var(--ink-3); }

@media (max-width: 600px) {
  /* На телефоне рельс и панель не помещаются: разделы встают одной
     прокручиваемой строкой иконок под верхней полосой. */
  .shell { flex-direction: column; }
  .sidebar, body.nav-narrow .sidebar {
    width: auto; flex-basis: auto; height: auto; position: sticky; top: var(--gbar);
    border-bottom: 1px solid var(--line); background: var(--side);
  }
  .rail, .side-head, .nav-group { display: none; }
  .side-panel, body.nav-narrow .side-panel {
    display: flex; position: static; width: auto; flex: 1 1 auto;
    border: none; border-radius: 0; box-shadow: none;
  }
  .side-panel nav { flex-direction: row; overflow-x: auto; gap: var(--sp-1); padding: var(--sp-2) var(--sp-4); }
  .side-panel nav a { height: 36px; padding: 0 var(--sp-5); }
  .side-panel nav a .label {
    position: absolute; width: 1px; height: 1px; margin: -1px;
    overflow: hidden; clip-path: inset(50%);
  }
  .side-panel nav a .icon { width: 18px; height: 18px; }
  .main, body.nav-narrow .main { border-left: none; border-radius: 0; }
  .gbar { grid-template-columns: auto 1fr auto; }
  .gbar .icon-btn[aria-label="Свернуть меню"], .gbar .ws b { display: none; }
  .search-trigger { width: 100%; }
  .search-trigger kbd { display: none; }
  .head { flex-wrap: wrap; }
  /* Ряд кнопок шапки не сжимается (flex: 0 0 auto — так его закрепили,
     чтобы на рабочей ширине кнопка не срывалась на вторую строку).
     На телефоне это выносило «Новый товар» на 540px при окне 375, и вся
     страница ехала вбок. Здесь ряду дают всю ширину: кнопки переносятся
     между собой, а не выталкивают страницу. */
  .head > .narrow { flex: 1 1 100%; min-width: 0; justify-content: flex-start; }
  /* Выпадашка висит над страницей и отсчитывается от своей кнопки. На
     телефоне ей негде висеть: конструктор фильтров задач шириной 343px
     от кнопки на x=104 уходит правым краем на 447 при окне 375, а
     перевернуть его влево мешает тот же край с другой стороны (об этом
     есть разбор в app.js). Раскрываем панель прямо в потоке, во всю
     ширину строки — вверх ничего не наезжает, и некуда вылезать. */
  .dropdown[open] > .dropdown-body {
    position: static; width: 100%; min-width: 0; max-width: none;
    margin-top: var(--sp-3); box-shadow: none; background: var(--panel-2);
  }
  .view-bar .dropdown[open], .tb-side .dropdown[open] { flex: 1 1 100%; }
  /* Строка условия — «поле / сравнение / значение» в ряд, каждое не уже
     132px: 400px с промежутками, и ни панель, ни страница в 375 уже не
     становятся. На телефоне ставим условия в столбец. */
  .filter-row { flex-wrap: wrap; }
  .filter-row select, .filter-row input { flex: 1 1 100%; min-width: 0; }
  .bar-row { grid-template-columns: 104px 1fr 34px; }
  table.list { display: block; overflow-x: auto; }
  .grid-2 { grid-template-columns: 1fr; }
  /* На телефоне подпись панели уходит под заголовок, а не рвёт его пополам. */
  .panel-head { flex-wrap: wrap; }
  .panel-head h2, .panel-head h3 { flex: 1 0 100%; }
  .panel-head .hint { white-space: normal; }
  .flow-step { flex: 1 1 100%; flex-direction: row; align-items: center; gap: var(--sp-4); }
  .flow-step .flow-title { flex: 1 1 auto; }
  /* Телефон: список чатов ложится полосой над перепиской. Панель справа
     (.embed) такая же узкая, но высокая, и полоса ей не годится — там
     список остаётся вертикальным, иначе каналы уезжают за край. */
  .chat:not(.embed) { grid-template-columns: 1fr; height: auto; }
  .chat:not(.embed) .chat-side {
    flex-direction: row; overflow-x: auto; gap: var(--sp-3); align-items: center;
  }
  .chat:not(.embed) .chat-side-head,
  .chat:not(.embed) .chat-group { display: none; }
  .chat:not(.embed) .chat-item { flex: 0 0 auto; }
  /* Без этого блок папок — гибкий ребёнок строки — сжимается в ноль, и
     вкладок «Все» и «Непрочитанные» на экране просто нет. */
  .chat:not(.embed) .chat-folders {
    flex: 0 0 auto; flex-wrap: nowrap; border-bottom: none; margin: 0; padding: 0 var(--sp-1);
  }
  .chat:not(.embed) .chat-new {
    position: relative; margin: 0; border-top: none; padding-top: 0; flex: 0 0 auto;
  }
  /* Выпадашка считается от самого details, а не от страницы, иначе она
     встаёт по координате строки и уходит за правый край. */
  .chat:not(.embed) .chat-new-body {
    position: absolute; left: 0; top: calc(100% + 4px); z-index: 30;
    width: 260px; max-width: calc(100vw - 32px); background: var(--panel);
    border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
    box-shadow: var(--shadow-lg); padding: var(--sp-5); }
  .chat:not(.embed) .chat-main { height: calc(100vh - 230px); min-height: 380px; }
  .chat-tools { display: flex; position: static; margin-left: var(--sp-10); margin-top: var(--sp-2); }
  /* Шапка канала на телефоне складывается: кнопки под названием. */
  .chat-head-text { flex: 1 0 100%; }
  .chat-dock { width: 100%; }
  body.dock-open .content { padding-right: var(--sp-7); }
  .emoji-panel { width: calc(100vw - 48px); right: auto; left: 0; }
  /* На телефоне строка ввода не влезает в один ряд — опрос уходит вниз. */
  .chat-compose { flex-wrap: wrap; }
  .compose-main { flex: 1 1 100%; }
}

/* ===========================================================================
   Отклик интерфейса.

   До этого места в файле было ровно два перехода: ширина меню и кнопка
   «＋» в календаре. Всё остальное — кнопки, строки таблиц, пункты меню,
   поля — меняло вид мгновенно. На глаз это читается не как «быстро», а
   как «дёрнулось»: нет доли секунды, за которую видно, что состояние
   поменялось именно под курсором, а не само по себе.

   Числа взяты короткие. 140ms — курсор уже на месте, подсветка только
   догоняет; 90ms на нажатие — отпускание должно быть быстрее наведения,
   иначе кнопка «залипает». Длиннее 200ms в рабочем инструменте мешает:
   по этим строкам ходят весь день.
   =========================================================================== */
button, .btn, .icon-btn, .sidebar nav a, .vtab, .chip, .pill,
.search-trigger, .palette-item, summary {
  transition: background-color .14s ease, border-color .14s ease,
              color .14s ease, box-shadow .14s ease;
}
tbody tr { transition: background-color .1s ease; }
input, select, textarea {
  transition: border-color .14s ease, box-shadow .14s ease;
}

/* Нажатие. Кнопка без него не отличает «навёл» от «кликнул», и на
   медленном ответе сервера непонятно, дошёл ли клик вообще. Сдвиг на
   полпикселя не двигает соседей: transform не влияет на раскладку. */
button:active, .btn:active, .icon-btn:active {
  transform: translateY(.5px);
  transition-duration: .09s;
}

/* Выделение текста красим в акцент: по умолчанию браузер берёт свой
   синий, и в бронзовой или мятной теме он выглядит чужим. */
::selection { background: color-mix(in srgb, var(--accent) 24%, transparent); }

/* Полоса прокрутки в тёмной теме по умолчанию остаётся светлой на
   Windows и в Linux — яркая белая линия вдоль тёмной панели. */
* { scrollbar-color: var(--line-hover) transparent; scrollbar-width: thin; }

/* Галочки, переключатели и ползунки браузер красит своим синим — он не
   менялся от выбора акцента, и в мятной или бронзовой теме десяток
   синих галочек в списке сотрудников выдавал, что до них не дошли руки.
   Курсор в поле — там же: по умолчанию чёрный, в тёмной теме его почти
   не видно на тёмной панели. */
input, select, textarea, progress { accent-color: var(--accent); }
input, textarea { caret-color: var(--accent); }

/* --------------------------------------------------- таблица уехала вбок
   Широкая таблица лежит в .table-scroll и прокручивается вбок. Узнать об
   этом было неоткуда: на окне 974px у товаров за правым краем остаются
   три колонки, и ничто на это не указывает — таблица просто обрывается
   ровно по границе панели, как будто там её конец.

   Две тени по краям, приклеенные к содержимому. Приём известный: пара
   градиентов с background-attachment: local «уезжает» вместе с
   содержимым и прячется, как только докрутил до края, а пара с
   attachment: scroll стоит на месте и эти тени закрывает. Ноль скрипта,
   и состояние всегда верное — браузер считает его сам при прокрутке. */
.table-scroll {
  background:
    linear-gradient(to right, var(--panel) 30%, transparent) left   / 28px 100% no-repeat local,
    linear-gradient(to left,  var(--panel) 30%, transparent) right  / 28px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%,
      color-mix(in srgb, var(--ink) 28%, transparent), transparent) left  / 16px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%,
      color-mix(in srgb, var(--ink) 28%, transparent), transparent) right / 16px 100% no-repeat scroll;
  background-color: var(--panel);
}

/* --------------------------------------------------------------- движение
   Системная настройка «меньше движения» — это не вкус, а здоровье:
   вестибулярные расстройства и мигрень. Переходы выше короткие, но
   правило обязано быть, иначе ни один из них не выключить. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  button:active, .btn:active, .icon-btn:active { transform: none; }
}

/* ===========================================================================
   Свёрнутая панель фильтров.

   На товарах панель занимала 261px: восемь полей в три колонки плюс
   кнопка. Вместе с шапкой и четырьмя карточками KPI первая строка
   таблицы начиналась на y=701 при окне 820 — то есть до данных, ради
   которых страницу и открыли, оставалось 119px, одна строка с хвостом.
   А меняют в этих полях обычно одно, и то не каждый раз.

   Свёрнутая панель оставляет на виду то, чем пользуются: поиск, кнопку
   и выпадашку колонок. Остальные поля уходят под «Фильтры», а те из
   них, что сейчас выбраны, видны чипами рядом — свёрнутость не должна
   прятать, что выборка уже сужена. Это тот же порядок, что на задачах
   («Группировка · Сортировка · Колонки · Фильтры»), только собранный
   из полей, которые на этих страницах уже есть.

   Фильтром считается поле с пустым вариантом («все», «любой») — оно
   сужает выборку. Сортировка, группировка и «показывать» пустого
   варианта не имеют: это настройка вида, она не прячется в счётчик.
   =========================================================================== */
.toolbar > .tb-bar {
  grid-column: 1 / -1;
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-4);
}
.tb-bar > .tool { margin: 0; flex: 1 1 240px; min-width: 180px; }
/* Подпись «Поиск» над полем в одну строку с кнопками не нужна: плашка
   сама говорит, что это поиск. Высота ряда падает с 56px до 34px. */
.tb-bar > .tool { font-size: 0; }
.tb-bar > .tool > input { margin-top: 0; font-size: var(--fs-500); }
/* Правая половина строки: всё, чем меняют выборку. margin-left:auto
   прижимает её вправо, а при переносе она уезжает вниз целиком. */
.tb-side {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-4);
  margin-left: auto;
}

/* Кнопка-переключатель. Ведёт себя как .btn.ghost.small, но со счётчиком
   и галочкой-стрелкой, поэтому своя. */
.tb-toggle {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5); font-size: var(--fs-400); font-weight: 500;
  color: var(--ink); background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius-sm); cursor: pointer; white-space: nowrap;
}
.tb-toggle:hover { background: var(--panel-3); border-color: var(--line-strong); }
.tb-toggle[aria-expanded="true"] {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent);
}
.tb-toggle .icon { width: 15px; height: 15px; }
.tb-count {
  min-width: 17px; height: 17px; padding: 0 var(--sp-2); border-radius: 999px;
  background: var(--accent); color: var(--accent-ink);
  font-size: var(--fs-200); font-weight: 650; line-height: 17px; text-align: center;
}
.tb-toggle[aria-expanded="true"] .tb-count { background: var(--accent); color: var(--accent-ink); }

/* Чип выбранного фильтра. Крестик — кнопка внутри кнопки нельзя, поэтому
   чип это span, а снимается фильтр крестиком-кнопкой. */
.tb-chip {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-4); border-radius: var(--radius-xs);
  background: var(--accent-soft); color: var(--accent);
  font-size: var(--fs-300); font-weight: 500; max-width: 240px;
}
.tb-chip > b { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-chip > span { color: color-mix(in srgb, var(--accent) 70%, var(--ink-3)); flex: 0 0 auto; }
.tb-chip-x {
  display: inline-grid; place-items: center; width: 16px; height: 16px; flex: 0 0 auto;
  padding: 0; border: none; border-radius: 4px; background: none;
  color: inherit; font-size: var(--fs-400); line-height: 1; cursor: pointer;
}
.tb-chip-x:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); color: inherit; }
.tb-reset {
  background: none; border: none; padding: var(--sp-2) var(--sp-3); color: var(--ink-3);
  font-size: var(--fs-300); font-weight: 500; cursor: pointer; border-radius: var(--radius-xs);
}
.tb-reset:hover { background: var(--panel-3); color: var(--ink); }

/* Свёрнутое состояние: поля-селекты и всё, что не перенесли в строку,
   не показываем. display:none у поля формы не мешает ему отправиться —
   значения сохраняются, выборка не слетает. */
.toolbar.folded > :not(.tb-bar) { display: none; }
/* Развёрнутая панель отделяет строку от полей, иначе поиск и «Категория»
   стоят вплотную и читаются одним рядом. */
.toolbar:not(.folded) > .tb-bar {
  padding-bottom: var(--sp-5); margin-bottom: var(--sp-1);
  border-bottom: 1px solid var(--line-low);
}

/* --------------------------------------------------- сообщение и ожидание */
/* Крестик у флеша. Цвет не задаём: сообщение само красит себя в зелёный
   или красный, и крестик должен быть того же тона, иначе он читается
   отдельной кнопкой, а не частью плашки. */
.flash-note { position: relative; padding-right: 34px; }
.flash-x {
  position: absolute; top: 50%; right: var(--sp-3); transform: translateY(-50%);
  display: grid; place-items: center; width: 22px; height: 22px; padding: 0;
  background: none; border: none; border-radius: var(--radius-xs);
  color: inherit; font-size: var(--fs-700); line-height: 1; cursor: pointer; opacity: .6;
}
.flash-x:hover { background: color-mix(in srgb, currentColor 14%, transparent); opacity: 1; }
.flash-x:active { transform: translateY(-50%); }

/* Полоска ожидания. Поверх всего, включая шапку (30) и диалоги (110):
   уход на другую страницу важнее того, что сейчас открыто. */
.load-bar {
  position: fixed; top: 0; left: 0; height: 2px; width: 0;
  background: var(--accent); z-index: 120;
  transition: width 2.4s cubic-bezier(.1, .7, .3, 1);
}
.load-bar.go { width: 80%; }

/* Кнопка ждёт ответа. Кружок приписывается к подписи, поэтому ширина
   кнопки меняется на 22px и один раз — подмена текста двигала бы её
   на каждом нажатии и на разную величину. */
button.is-busy, .btn.is-busy { opacity: .75; cursor: progress; }
button.is-busy::after, .btn.is-busy::after {
  content: ""; width: 13px; height: 13px; flex: 0 0 auto;
  border: 2px solid color-mix(in srgb, currentColor 30%, transparent);
  border-top-color: currentColor; border-radius: 50%;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(1turn); } }
@media (prefers-reduced-motion: reduce) {
  /* Ползущую полосу убираем, но знак «идёт запрос» оставляем: без него
     непонятно, дошло ли нажатие. */
  .load-bar { width: 100%; opacity: .5; transition: none; }
}

/* ------------------------------------------------------- шпаргалка клавиш */
.palette-foot { display: flex; align-items: center; gap: var(--sp-5); }
.palette-keys {
  margin-left: auto; display: inline-flex; align-items: center; gap: var(--sp-3);
  background: none; border: none; padding: 0;
  color: var(--ink-3); font-size: var(--fs-300); font-weight: 500; cursor: pointer;
}
.palette-keys:hover { background: none; color: var(--ink); }
/* Описание рядом с клавишей, а не под ней: так колонка клавиш читается
   сверху вниз одним столбцом, и глаз не ищет, к чему относится подпись. */
.keys { display: grid; grid-template-columns: auto 1fr; gap: var(--sp-3) var(--sp-7); margin: 0 0 var(--sp-5); }
.keys dt { display: flex; align-items: center; gap: var(--sp-2); justify-self: start; }
.keys dd { margin: 0; font-size: var(--fs-400); color: var(--ink-2); align-self: center; }
.keys dt .muted { font-size: var(--fs-300); }
kbd {
  display: inline-grid; place-items: center; min-width: 20px; height: 20px; padding: 0 var(--sp-3);
  font: inherit; font-size: var(--fs-200); font-weight: 600; color: var(--ink-2);
  background: var(--panel-2); border: 1px solid var(--line-strong);
  border-bottom-width: 2px; border-radius: var(--radius-xs);
}
.modal-section kbd { vertical-align: 1px; text-transform: none; letter-spacing: 0; }

/* ===========================================================================
   Мессенджер как в ClickUp (замер 14.11.2026 с живого канала General).
   Что перенесено:
   — списка чатов отдельной колонкой нет: каналы и личные стоят в общей
     боковой панели, группами «Каналы» и «Личные», переписка занимает всё
     рабочее поле без рамки и полей;
   — закладки — полоса пилюль под шапкой, а не колонка слева;
   — день — пилюля по центру линии;
   — сообщение: аватар 32px слева, имя и время в одну строку, текст под
     именем; подсветка под курсором идёт от края до края;
   — строка ветки привязана к аватару уголком.
   Док справа (embed) и телефон остаются со своим списком: там общей
   боковой панели рядом нет.
   =========================================================================== */

/* ------------------------------------------ каналы в боковой панели */
.nav-hash {
  width: 16px; height: 16px; flex: 0 0 16px; display: grid; place-items: center;
  color: var(--ink-2); font-size: var(--fs-500); font-weight: 500; line-height: 1;
}
.nav-ava {
  width: 18px; height: 18px; flex: 0 0 18px; margin: 0 -1px; border-radius: 50%;
  display: grid; place-items: center; background: var(--ink); color: var(--panel);
  font-size: var(--fs-100); font-weight: 600; line-height: 1;
}
.side-panel nav a.unread .label { font-weight: 600; }
.side-panel nav a.on-soft { font-weight: 500; }
.side-panel nav a.nav-add, .side-panel nav a.nav-add .nav-hash { color: var(--ink-3); }
.side-panel nav a.nav-add:hover, .side-panel nav a.nav-add:hover .nav-hash { color: var(--ink); }
.nav-count { margin-left: auto; font-size: var(--fs-300); color: var(--ink-3); }
.side-panel .nav-badge { min-width: 16px; height: 16px; padding: 0 var(--sp-2); font-size: var(--fs-100); }
.side-panel .nav-badge + .nav-badge { margin-left: 0; }

@media (max-width: 600px) { .nav-chat { display: none !important; } }

@media (min-width: 601px) {
  /* Переписка во всё рабочее поле: ни полей страницы, ни рамки. */
  .content:has(> .chat:not(.embed)) { padding: 0; max-width: none; }
  .chat:not(.embed) {
    grid-template-columns: minmax(0, 1fr); gap: 0; background: none; border-radius: 0;
    height: calc(100vh - var(--gbar) - 1px); min-height: 420px;
  }
  .chat:not(.embed).with-thread { grid-template-columns: minmax(0, 1fr) 340px; }
  .chat:not(.embed) > .chat-rail, .chat:not(.embed) > .chat-side { display: none; }
  .chat:not(.embed) > .chat-main, .chat:not(.embed) > .chat-thread {
    border: none; border-radius: 0; box-shadow: none;
  }
  .chat:not(.embed) > .chat-thread { border-left: 1px solid var(--line); }
  .chat:not(.embed) [data-chat-panel="side"] { display: none; }
}

/* ------------------------------------------------------- шапка канала */
.chat-head {
  /* Перенос оставлен: при открытой ветке и в доке шапка узкая, и кнопки
     уходят на вторую строку, а не наезжают на название. */
  flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); min-height: 48px;
  padding: var(--sp-4) var(--sp-7); background: var(--panel); border-bottom: 1px solid var(--line);
}
.chat-head b { font-size: var(--fs-500); font-weight: 600; line-height: 16px; }
.chat-head .hint { font-size: var(--fs-300); line-height: 16px; margin: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-head-text { min-width: 0; flex: 1 1 120px; }
.chat-head-actions { flex: 0 1 auto; min-width: 0; flex-wrap: wrap; justify-content: flex-end; }
.chat-head .chat-ava { width: 28px; height: 28px; flex: 0 0 28px; border-radius: var(--radius-xs); font-size: var(--fs-500); }
/* Действия шапки — тихие текстовые кнопки, как Integrate и Ask: рамка
   и заливка появляются только под курсором. */
.chat-head-actions { gap: var(--sp-1); align-items: center; }
.chat-head-actions .btn.ghost, .chat-head-actions .dropdown > summary {
  height: 28px; padding: 0 var(--sp-4); border: 1px solid transparent; border-radius: var(--radius-xs);
  background: none; color: var(--ink-2); font-size: var(--fs-400); font-weight: 400;
}
.chat-head-actions .btn.ghost:hover, .chat-head-actions .dropdown > summary:hover,
.chat-head-actions .dropdown[open] > summary {
  background: var(--hover); color: var(--ink); border-color: transparent;
}
.chat-head-actions .chat-new > summary { width: 28px; padding: 0; justify-content: center; }
.chat-head-actions .chat-new > summary .icon { width: 14px; height: 14px; }
.folders-new { margin-top: var(--sp-5); padding-top: var(--sp-5); border-top: 1px solid var(--line-low); }
.folders-new:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.empty .chat-new { margin-top: var(--sp-5); display: inline-block; text-align: left; }

/* ------------------------------------------------------ полоса закладок */
.chat-body-row { flex-direction: column; }
.chat-marks {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3);
  flex: 0 0 auto; width: auto; overflow: visible;
  padding: var(--sp-4) var(--sp-7); border-right: none; background: none;
}
.chat.embed .chat-marks { display: none; }
.chat-head-panels [data-chat-panel="marks"] { display: inline-grid; }
.chat.embed .chat-head-panels [data-chat-panel="marks"] { display: none; }
.marks-head, .marks-empty { display: none; }
.mark { margin: 0; min-width: 0; }
.mark-link, .mark-note, .marks-add > summary {
  display: inline-flex; align-items: center; gap: var(--sp-2); height: 24px; max-width: 240px;
  padding: 0 var(--sp-4); border: 1px solid var(--line); border-radius: 12px;
  background: var(--panel); color: var(--ink-2); font-size: var(--fs-300); font-weight: 500;
  white-space: nowrap;
}
.mark-link:hover, .mark-note:hover, .marks-add > summary:hover {
  background: var(--panel-2); border-color: var(--line-strong); color: var(--ink);
}
.mark-note b { display: inline-flex; align-items: center; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; }
.mark-note p { display: none; }
.mark-emoji { margin-right: var(--sp-1); }
.mark-del { top: 2px; right: 3px; }
.mark-del button { background: var(--panel); border-radius: 50%; }
.marks-add { margin: 0; }
.marks-add > summary { border-style: solid; }

/* ---------------------------------------------------------------- лента */
#chatLog, .thread-log { padding: var(--sp-5) 0; }
#chatLog > .chat-more, #chatLog > .chat-empty, .thread-log > .thread-count { margin-left: var(--sp-7); margin-right: var(--sp-7); }
.chat-day { margin: var(--sp-6) 0 var(--sp-5); }
.chat-day span {
  display: inline-block; padding: var(--sp-1) var(--sp-5); border: 1px solid var(--line);
  border-radius: 999px; color: var(--ink); font-size: var(--fs-300); font-weight: 500; line-height: 16px;
}
.chat-msg { padding: var(--sp-3) var(--sp-7) var(--sp-3) 56px; }
.chat-msg:hover { border-radius: 0; }
.chat-msg-head { gap: var(--sp-3); margin-bottom: 0; line-height: 20px; }
.chat-msg-head b { font-size: var(--fs-500); font-weight: 600; }
.chat-msg-head .avatar.small {
  position: absolute; left: var(--sp-7); top: var(--sp-3); width: 32px; height: 32px;
  background: var(--ink); color: var(--panel); font-size: var(--fs-400); font-weight: 600;
}
.chat-body { padding-left: 0; line-height: 20px; }
.chat-edit { margin-left: 0; }
.msg-acts { right: var(--sp-7); }
/* Строка ветки: уголок от аватара к ответам. */
.thread-line { position: relative; color: var(--ink-2); margin-top: var(--sp-4); }
.thread-line b { font-weight: 500; }
.thread-line:hover b { color: var(--accent); }
.thread-line::before {
  content: ""; position: absolute; left: -25px; bottom: 50%; width: 21px; height: 20px;
  border: solid var(--line-strong); border-width: 0 0 1px 1px; border-bottom-left-radius: 10px;
  pointer-events: none;
}
.thread-line .avatar.small { background: var(--ink); color: var(--panel); }
.reaction { height: 28px; padding: 0 var(--sp-4); background: var(--panel); border-color: var(--line); }
.reaction.mine { border-color: color-mix(in srgb, var(--accent) 55%, transparent); }
.reaction-add > summary { width: 28px; height: 28px; background: none; border: 1px solid var(--line); }

/* -------------------------------------------------------------- композер */
.chat-compose { padding: var(--sp-4) var(--sp-7) var(--sp-5); border-top: none; }
.compose-box { border-radius: var(--radius-sm); box-shadow: none; }
.compose-box:focus-within { border-color: var(--accent); }
.compose-tools { flex-wrap: wrap; row-gap: var(--sp-2); }
.compose-tabs { flex-wrap: wrap; }

/* ===========================================================================
   Пространства и списки как в ClickUp.
   В боковой панели — дерево: пространство (квадрат своего цвета с буквой),
   под ним списки-проекты со значком и числом открытых задач. «＋» у
   пространства виден под курсором и раскрывает поле для нового списка.
   На странице задач — строка «где мы»: пространство / список, 14px/600,
   как заголовок расположения в ClickUp; ряд вкладок под ней.
   =========================================================================== */
.sp-ava {
  width: 18px; height: 18px; flex: 0 0 18px; margin: 0 -1px; border-radius: 5px;
  display: grid; place-items: center; background: var(--c, #64748b); color: #fff;
  font-size: var(--fs-100); font-weight: 700; line-height: 1;
}
.nav-group-act { justify-content: space-between; padding-right: var(--sp-1); }
.nav-plus, .nav-new > summary {
  width: 20px; height: 20px; flex: 0 0 20px; border-radius: 5px; display: grid; place-items: center;
  color: var(--ink-3); cursor: pointer; list-style: none;
}
.side-panel nav a.nav-plus { height: 20px; padding: 0; }
.side-panel nav a.nav-plus .icon, .nav-new > summary .icon { width: 14px; height: 14px; color: inherit; }
.nav-plus:hover, .nav-new > summary:hover { background: var(--hover-2); color: var(--ink); }
.nav-space { position: relative; flex: 0 0 auto; }
/* Место под «＋» есть только когда он виден: иначе длинное название
   пространства обрезалось бы на 24px раньше без всякой причины. */
.nav-space:hover > a, .nav-space:focus-within > a, .nav-space:has(.nav-new[open]) > a { padding-right: 28px; }
.nav-new > summary { position: absolute; top: 4px; right: 4px; opacity: 0; }
.nav-new > summary::-webkit-details-marker { display: none; }
.nav-space:hover .nav-new > summary, .nav-new > summary:focus-visible,
.nav-new[open] > summary { opacity: 1; }
.nav-new form { margin: 2px 0 2px 24px; }
.nav-new input { margin: 0; height: 28px; padding: 0 var(--sp-4); font-size: var(--fs-400); border-radius: 7px; }
.side-panel nav a.nav-list { padding-left: var(--sp-9); }
.side-panel nav a.nav-list .icon { width: 14px; height: 14px; color: var(--ink-3); }
.side-panel nav a.nav-list.on .icon { color: var(--ink); }
@media (max-width: 600px) { .nav-space, .nav-list, .nav-group-act { display: none !important; } }
/* Вкладки пространств на странице задач остались для телефона: там
   дерева в панели нет. На большом экране дерево их заменяет. */
@media (min-width: 601px) { .space-tabs { display: none; } }

.loc { display: flex; align-items: center; gap: var(--sp-3); min-height: 28px; margin-bottom: var(--sp-3); min-width: 0; }
.loc .sp-ava { width: 20px; height: 20px; flex-basis: 20px; margin: 0; font-size: var(--fs-200); }
.loc .space-title {
  font-size: var(--fs-500); font-weight: 600; line-height: 16px; letter-spacing: 0; margin: 0;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.loc-up { font-size: var(--fs-500); line-height: 16px; color: var(--ink-2); white-space: nowrap; }
.loc-up:hover { color: var(--ink); text-decoration: none; }
.loc-sep { color: var(--ink-5); }
.loc-count { font-size: var(--fs-300); color: var(--ink-3); font-variant-numeric: tabular-nums; }
.loc-more > summary {
  width: 24px; height: 24px; padding: 0; justify-content: center; border-color: transparent;
  background: none; border-radius: var(--radius-xs); color: var(--ink-3); font-weight: 700; letter-spacing: 1px;
}
.loc-more > summary:hover, .loc-more[open] > summary { background: var(--hover); color: var(--ink); border-color: transparent; }
.loc-more .dropdown-body { min-width: 260px; }
.loc-danger { margin-top: var(--sp-5); padding-top: var(--sp-5); border-top: 1px solid var(--line-low); }
.view-top { gap: var(--sp-7); }
/* Подпись списка у задачи — тихая, с рамкой: это адрес, а не метка. */
.chip-list { background: none; border: 1px solid var(--line); color: var(--ink-3); }
.chip-list:hover { color: var(--ink); border-color: var(--line-strong); text-decoration: none; }

/* ===========================================================================
   Папки, несколько исполнителей, зависимости — по ClickUp.
   =========================================================================== */
/* Папка в дереве: на уровень глубже пространства, списки в ней — ещё на
   один. Значок папки залитый, серый, как у ClickUp. */
.side-panel nav .nav-folder > a { padding-left: var(--sp-9); }
.side-panel nav .nav-folder > a .icon { width: 14px; height: 14px; color: var(--ink-3); }
.side-panel nav .nav-folder > a.on .icon { color: var(--ink); }
.side-panel nav a.nav-list.nav-deep { padding-left: 40px; }
.nav-folder .nav-new form { margin-left: 40px; }
.nav-new-acts { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); }
.nav-new-acts button { flex: 1 1 0; height: 24px; padding: 0 var(--sp-3); font-size: var(--fs-300); }

/* Аватары внахлёст: у каждого обводка цветом подложки, чтобы круги
   читались по отдельности. */
.ava-stack { display: inline-flex; align-items: center; }
.ava-stack .cm-avatar { box-shadow: 0 0 0 2px var(--panel); }
.ava-stack .cm-avatar + .cm-avatar { margin-left: -6px; }
.ava-stack .cm-avatar.more { background: var(--panel-3); color: var(--ink-2); font-size: 9px; }

/* Выбор исполнителей: кнопка выглядит как поле, внутри — галочки. */
.fld { display: block; font-size: var(--fs-400); color: var(--ink-2); margin-bottom: var(--sp-6); }
.people-pick { display: block; margin-top: var(--sp-2); }
.field-row .people-pick { margin-top: 0; }
.people-pick > summary {
  display: flex; width: 100%; min-height: 34px; padding: 5px var(--sp-5);
  border-radius: var(--radius-xs); font-size: var(--fs-500); color: var(--ink);
}
.people-pick-val { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.people-pick .dropdown-body { min-width: 100%; max-height: 260px; overflow-y: auto; padding: var(--sp-4) var(--sp-5); }
.people-pick .dropdown-body .check { margin-bottom: 0; padding: var(--sp-2) 0; }

/* Пометки в строке задачи: «ждёт» — предупреждением, «держит» — тихо. */
.chip-wait { gap: var(--sp-1); background: var(--warn-soft); color: var(--warn); }
.chip-wait .icon { width: 12px; height: 12px; }
.chip-hold { background: none; border: 1px solid var(--line); color: var(--ink-3); }
.flash.dep-note { background: var(--warn-soft); color: var(--warn); flex-wrap: wrap; }
.flash.dep-note .icon { width: 16px; height: 16px; }
.flash.dep-note a { color: inherit; text-decoration: underline; }

.dep-group + .dep-group { margin-top: var(--sp-5); }
.dep-title { font-size: var(--fs-300); font-weight: 500; color: var(--ink-3); margin-bottom: var(--sp-2); }
.dep-row { display: flex; align-items: center; gap: var(--sp-4); min-height: 32px; padding: 0 var(--sp-2);
  border-radius: var(--radius-xs); }
.dep-row:hover { background: var(--panel-2); }
.dep-row > a { flex: 1 1 auto; min-width: 0; color: var(--ink); font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dep-row.closed > a { color: var(--ink-3); text-decoration: line-through; }
.dep-del button {
  width: 22px; height: 22px; padding: 0; border: none; border-radius: var(--radius-xs);
  background: none; color: var(--ink-3); font-size: var(--fs-300);
}
.dep-del button:hover { background: var(--panel-3); color: var(--warn); }
.dep-add { display: flex; gap: var(--sp-3); align-items: center; flex-wrap: wrap;
  margin-top: var(--sp-5); padding-top: var(--sp-5); border-top: 1px solid var(--line-low); }
.deps > .hint + .dep-add { border-top: none; padding-top: 0; }
.dep-add select { width: auto; flex: 0 0 auto; margin: 0; }
.dep-add input { flex: 1 1 180px; min-width: 0; margin: 0; }
/* Статус в строке списка занимает свою ячейку, а не 88px минимум: с
   шестью колонками на окне 974px он наезжал на исполнителя. */
.tasks-list select.status-pick { min-width: 0; width: 100%; }

/* ===========================================================================
   Сквозная связь задач с товарами и поставками.
   =========================================================================== */
/* Ссылка на объект: тихая, с рамкой и значком — её видно, но с метками
   и статусом она не спорит. */
.chip-obj { gap: var(--sp-1); background: none; border: 1px solid var(--line); color: var(--ink-2); }
.chip-obj .icon { width: 12px; height: 12px; }
a.chip-obj:hover { color: var(--accent); border-color: var(--accent); text-decoration: none; }
/* Выход на площадку: карточка WB или Ozon в новой вкладке. */
.chip-out { background: var(--accent-soft); color: var(--accent); font-weight: 500; }
.chip-out:hover { text-decoration: none; background: color-mix(in srgb, var(--accent) 16%, var(--panel)); }
.chip-out.off { background: var(--panel-3); color: var(--ink-3); }
.link-row .link-ico { width: 16px; height: 16px; flex: 0 0 16px; color: var(--ink-3); }
.link-row > a b { font-weight: 600; }
.link-row > a { font-weight: 400; }
.link-row .chip, .link-row .pill { flex: 0 0 auto; margin-left: 0; }
.link-note { display: flex; align-items: center; gap: var(--sp-3); margin: 0 0 var(--sp-6);
  padding: var(--sp-3) var(--sp-5); border-radius: var(--radius-xs); background: var(--accent-soft);
  font-size: var(--fs-400); color: var(--ink-2); }
.link-note .icon { width: 16px; height: 16px; color: var(--accent); }

/* Задачи в карточке товара и партии: строки, а не таблица — название
   занимает всё свободное место, статус и срок прижаты вправо. */
.obj-tasks { display: flex; flex-direction: column; }
.obj-task {
  display: flex; align-items: center; gap: var(--sp-4); min-height: 36px; padding: 0 var(--sp-3);
  border-bottom: 1px solid var(--line-low); color: var(--ink); font-size: var(--fs-500);
}
.obj-task:last-child { border-bottom: none; }
.obj-task:hover { background: var(--panel-2); text-decoration: none; }
.obj-task:hover .obj-task-title { color: var(--accent); }
.obj-task-title { flex: 1 1 auto; min-width: 0; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.obj-task .pill, .obj-task .chip { flex: 0 0 auto; margin-left: 0; }
.obj-task.closed .obj-task-title { color: var(--ink-3); text-decoration: line-through; }
.obj-task.quiet .obj-task-title { font-weight: 400; color: var(--ink-2); }
.obj-mentioned { margin-top: var(--sp-6); padding-top: var(--sp-5); border-top: 1px solid var(--line-low); }
.panel-head .btn.small .icon { width: 14px; height: 14px; }
/* Колонки карточки задачи могут сжиматься уже своего содержимого: длинное
   название поставщика в строке связи иначе раздвигало колонку и уводило
   всю страницу вбок. */
.task-grid > * { min-width: 0; }

/* ===========================================================================
   Карточка товара как база знаний и база файлов.
   Разделы идут один под другим; сверху липкая строка с оглавлением и
   кнопкой «Вид». Пустых разделов на странице нет — они перечислены
   одной строкой «Не заполнено».
   =========================================================================== */
.psec-bar {
  position: sticky; top: var(--gbar); z-index: 20; display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--sp-3) var(--sp-5); margin: 0 calc(var(--sp-8) * -1) var(--sp-6); padding: var(--sp-3) var(--sp-8);
  background: var(--content); border-bottom: 1px solid var(--line);
}
.psec-nav { display: flex; gap: var(--sp-1); flex: 1 1 auto; min-width: 0; overflow-x: auto; scrollbar-width: none; }
.psec-nav a {
  flex: 0 0 auto; height: 24px; padding: 0 var(--sp-4); border-radius: var(--radius-xs);
  display: inline-flex; align-items: center; font-size: var(--fs-300); font-weight: 500; color: var(--ink-2);
}
.psec-nav a:hover { background: var(--hover); color: var(--ink); text-decoration: none; }
.psec-view > summary { height: 24px; padding: 0 var(--sp-4); font-size: var(--fs-300); border-radius: 12px; }
.psec-view .dropdown-body { min-width: 250px; max-height: 60vh; overflow-y: auto; }
.psec-empty { flex: 1 0 100%; font-size: var(--fs-300); color: var(--ink-3); }
.psec { scroll-margin-top: calc(var(--gbar) + 56px); }
.psec .panel-head h2 { font-size: var(--fs-600); }
.psec .prose { max-width: none; }
.proj-panel { margin-top: calc(var(--sp-3) * -1); }
.chip.kind-kit { background: var(--accent-soft); color: var(--accent); }
.chip.kind-component { background: var(--panel-3); color: var(--ink-2); }

/* Характеристики: группы в две колонки, строки только заполненные. */
.spec-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); gap: var(--sp-5) var(--sp-9); }
.spec-group { min-width: 0; }
.spec-group .field-row { padding: var(--sp-1) 0; border-bottom: 1px solid var(--line-low); }
.spec-group .field-row:last-child { border-bottom: none; }

/* Набор: строка комплектующего раскрывается и показывает данные его
   карточки — ничего не копируется. */
.kit-row { border-bottom: 1px solid var(--line-low); }
.kit-row > summary {
  display: flex; align-items: center; gap: var(--sp-5); min-height: 36px; padding: 0 var(--sp-3);
  cursor: pointer; list-style: none; border-radius: var(--radius-xs);
}
.kit-row > summary::-webkit-details-marker { display: none; }
.kit-row > summary::before { content: "›"; color: var(--ink-3); width: 10px; transition: transform .12s ease; }
.kit-row[open] > summary::before { transform: rotate(90deg); }
.kit-row > summary:hover { background: var(--panel-2); }
.kit-sku { flex: 0 0 auto; font-weight: 600; font-size: var(--fs-400); font-variant-numeric: tabular-nums; }
.kit-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kit-qty, .kit-cost { flex: 0 0 auto; font-size: var(--fs-400); color: var(--ink-2); font-variant-numeric: tabular-nums; }
.kit-body { padding: var(--sp-4) var(--sp-3) var(--sp-6) var(--sp-9); }
.kit-files, .kit-acts { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-5); }
.kit-files .chip, .doc-files .chip { margin-left: 0; max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Фото и макеты плиткой. */
.media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: var(--sp-5); }
.media-tile {
  display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: var(--radius-sm);
  overflow: hidden; background: var(--panel-2); color: var(--ink-2);
}
.media-tile:hover { border-color: var(--line-hover); text-decoration: none; }
.media-tile img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; display: block; background: var(--panel-3); }
.media-file { aspect-ratio: 3 / 4; display: grid; place-items: center; gap: var(--sp-3); padding: var(--sp-4);
  font-size: var(--fs-300); text-align: center; word-break: break-word; }
.media-cap { padding: var(--sp-2) var(--sp-4); font-size: var(--fs-300);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.doc-row { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-4) 0; border-bottom: 1px solid var(--line-low); }
.doc-row:last-of-type { border-bottom: none; }
.doc-main { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
.doc-main .chip { margin-left: 0; }
.doc-files { display: flex; flex-wrap: wrap; gap: var(--sp-3); }

/* Вопросы и отзывы: вопрос, под ним ответ с отступом. */
.qa { padding: var(--sp-4) 0; border-bottom: 1px solid var(--line-low); }
.qa-q { font-weight: 500; display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-3); }
.qa-q .hint { font-weight: 400; font-size: var(--fs-300); }
.qa-stars { color: #d97706; letter-spacing: 1px; font-size: var(--fs-400); }
.qa-a { margin-top: var(--sp-2); padding: var(--sp-3) var(--sp-5); border-radius: var(--radius-xs);
  background: var(--panel-2); color: var(--ink); white-space: pre-line; }
.qa-edit, .qa-add { margin-top: var(--sp-3); }
.qa-edit > summary, .qa-add > summary { cursor: pointer; font-size: var(--fs-300); color: var(--ink-3); list-style: none; }
.qa-edit > summary::-webkit-details-marker, .qa-add > summary::-webkit-details-marker { display: none; }
.qa-edit > summary:hover, .qa-add > summary:hover { color: var(--accent); }
.qa-add > summary { font-size: var(--fs-400); color: var(--ink-2); font-weight: 500; padding: var(--sp-2) 0; }
.qa-edit form, .qa-add form { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-3); margin-top: var(--sp-3); }
.qa-edit textarea, .qa-add textarea { min-height: 56px; margin: 0; }
.qa-edit form .row, .qa-edit form > label { width: 100%; margin-bottom: 0; }
.qa-rate { display: inline-flex; align-items: center; gap: var(--sp-3); margin: 0; }
.qa-rate select { width: auto; margin: 0; }

/* Версии: строка версии раскрывается таблицей «было — стало». */
.ver { border-bottom: 1px solid var(--line-low); }
.ver > summary { display: flex; align-items: center; gap: var(--sp-5); min-height: 34px; cursor: pointer; list-style: none;
  font-size: var(--fs-400); }
.ver > summary::-webkit-details-marker { display: none; }
.ver-num { flex: 0 0 auto; min-width: 30px; font-weight: 600; color: var(--ink); }
.ver-when, .ver-who { flex: 0 0 auto; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.ver-note { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink-2); }
.ver .chip { margin-left: 0; flex: 0 0 auto; }
.ver-table { margin: var(--sp-2) 0 var(--sp-5); border: 1px solid var(--line-low); }
.ver-table td { font-size: var(--fs-400); vertical-align: top; }
.ver-was { color: var(--ink-3); text-decoration: line-through; }
.ver-now { color: var(--good); }

.lib-filter { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; margin-bottom: var(--sp-6); }
.lib-filter input { flex: 1 1 220px; margin: 0; }
.lib-filter select { flex: 0 0 auto; width: auto; margin: 0; }
.lib-item .doc-row { padding-top: 0; }
.lib-note { margin: 0; }
.access-table .acc-col { text-align: center; width: 120px; white-space: normal; }
.access-table input { width: auto; margin: 0; }
/* Название товара бывает длинным: в карточке оно переносится, а не
   уезжает под кнопки. */
.head-wrap { align-items: flex-start; }
.head-wrap h1 { white-space: normal; overflow-wrap: anywhere; }

/* ===========================================================================
   Представления базы данных: панель фильтров и таблица (app/dataview.py).
   =========================================================================== */
.dv-bar { padding: 0 0 var(--sp-5); }
.dv-q { flex: 0 1 200px; min-width: 120px; height: 26px; margin: 0; padding: 0 var(--sp-4);
  font-size: var(--fs-300); border-radius: 12px; }
.dv-cols { max-height: 60vh; overflow-y: auto; }
.dv-total { white-space: nowrap; font-variant-numeric: tabular-nums; }
.dv-bar .filter-row { display: flex; gap: var(--sp-3); align-items: flex-start; margin-bottom: var(--sp-3); }
.dv-bar .filter-row select, .dv-bar .filter-row input { margin: 0; flex: 1 1 132px; min-width: 0; }
.dv-bar .filter-row select[multiple] { padding: var(--sp-1); height: auto; }
.dv-bar .filter-row .btn { flex: 0 0 auto; height: 34px; }
.dv-table td { white-space: nowrap; max-width: 320px; overflow: hidden; text-overflow: ellipsis; }
.dv-table td.dv-wide { white-space: normal; min-width: 240px; max-width: 420px; }
.dv-table td .chip { margin-left: 0; margin-right: var(--sp-1); }
.dv-table tr.dv-group td { background: var(--panel-2); padding-top: var(--sp-4); padding-bottom: var(--sp-4);
  border-bottom: 1px solid var(--line); font-size: var(--fs-400); }
.dv-table tr.dv-group:hover { background: var(--panel-2); }
@media (max-width: 600px) { .dv-bar .filter-row { flex-wrap: wrap; } }
.dv-table td.dv-main a { font-weight: 500; color: var(--ink); }
.dv-table td.dv-main a:hover { color: var(--accent); }
.dv-table td.dv-main.dv-wide a { font-weight: 400; }
.dv-group-title { margin: var(--sp-7) 0 var(--sp-4); font-size: var(--fs-500); }
.lib-tiles { margin-bottom: var(--sp-6); }
.lib-tiles .media-cap.hint { padding-top: 0; }

/* Сохранённые виды в панели раздела. */
.dv-saved .dropdown-body { min-width: 280px; }
.dv-saved-row { display: flex; align-items: center; gap: var(--sp-3); min-height: 30px; }
.dv-saved-row a { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--ink); font-weight: 500; }
.dv-saved-row a.on { color: var(--accent); }
.dv-saved-new { margin-top: var(--sp-5); padding-top: var(--sp-5); border-top: 1px solid var(--line-low); }
.dv-saved-new input[name=name] { margin: 0 0 var(--sp-3); }
