/* LinesERP — оформление. Набор тем, мобильная раскладка.

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

:root {

  /* Шкала кегля — из tokens.css редизайна (владелец, 27 сентября 2026):
     11 · 12,5 · 14 · 15 · 18 · 22 · 32 px. Там она в пикселях, здесь та же
     в rem: крупность интерфейса ниже меняет html font-size, и шкала в
     пикселях перестала бы её слушаться. До редизайна была 13–28 с основой
     15 и правилом «только целые пиксели»; 12,5 — единственная дробная,
     ТЗ её держит ради плотных таблиц. */
  --t-2xs: .6875rem;   /* 11px — счётчики; в tokens.css ступени мельче xs нет */
  --t-xs:  .6875rem;   /* 11px — мета, вторичные подписи */
  --t-sm:  .78125rem;  /* 12,5px — плотные таблицы, подписи полей */
  --t-base:.875rem;    /* 14px — основной текст интерфейса */
  --t-md:  .9375rem;   /* 15px — заголовки карточек, крупные значения */
  --t-lg:  1.125rem;   /* 18px — заголовки разделов */
  --t-xl:  1.375rem;   /* 22px — заголовок внутреннего экрана */
  --t-2xl: 2rem;       /* 32px — заголовок главной */

  /* Моноширинный при том же кегле читается мельче: у IBM Plex Mono уже очко
     и шире межбуквенное. Размерным надписям — дате, проценту, длительности —
     даём ступень сверху, иначе в карточках они выглядят набранными для мыши,
     а не для глаза. */
  --t-mono: .78125rem; /* 12,5px */

  /* Кегль поля ввода на сенсорном экране. Не ступень шкалы, а порог Safari:
     поле мельче 16 пикселей он при касании увеличивает вместе со всей
     страницей, и после ввода человек остаётся в приближенном экране,
     из которого надо выбираться щипком. Поэтому число в пикселях, а не
     в rem: порог меряется пикселями, крупность интерфейса его не двигает. */
  --t-field: 16px;

  /* Шкала отступов, шаг 4px. Всё расстояние в интерфейсе берётся отсюда,
     иначе колонки соседних блоков не встают на общую линию. */
  --s-05: 2px;  --s-1: 4px;  --s-2: 8px;   --s-3: 12px;
  --s-4:  16px; --s-5: 24px; --s-6: 32px;  --s-7: 48px;

  /* Одна шкала формы на всё приложение. Правило: метки и мелкие плашки — sm,
     кнопки, поля и карточки — базовый, панели и окна — lg, пилюли — полный. */
  /* Ширина боковой колонки: по ней же выравнивается начало разделов в шапке.
     248px держит «Реконструкция особняка на Пречистенке» в две строки без
     многоточия на первом же слове */
  --side-w: 248px;
  /* Ширина колонки текста в базе знаний: строка длиннее читается тяжело,
     а инструкцию читают глазами, а не пролистывают */
  --kb-line: 760px;
  /* Кружок хода задачи. Один размер на главную, «Мои задачи» и канбан:
     это одна и та же кнопка, и разъезжаться по экранам ей нельзя.
     26px против прежних 22: в 22 кружок читался как значок при названии,
     а он — мишень, по которой задачу закрывают, не открывая. */
  --step-size: 26px;
  /* Радиусы — из tokens.css (--r-sm … --r-xl) под прежними именами */
  --radius-sm:   8px;
  --radius:      12px;
  --radius-lg:   18px;
  --radius-xl:   24px;   /* полотно страницы */
  --radius-full: 999px;

  --font: 'Onest', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  /* Цифры (номера проектов, сроки, счётчики) — нашим шрифтом с цифрами
     одной ширины, а не моноширинным: владелец, 30.09.2026 — «уродско
     выглядят моноширинные цифры». Настоящий моноширинный остался только
     для кода — --code */
  --mono: var(--font);
  --code: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  /* Имена шрифтов из tokens.css — на наши (ТЗ, раздел 7: шрифты боевые).
     Там они Golos, Geologica и JetBrains Mono с Google Fonts, которых у нас
     нет, и тот, кто звал --f-ui (генерация), получал системный шрифт. */
  --f-ui: var(--font);
  --f-head: var(--font);
  --f-mono: var(--mono);

  /* Одна кривая на все переходы: интерфейс должен ощущаться цельным */
  --ease: cubic-bezier(.4, 0, .2, 1);
  --fast: .14s var(--ease);
}

/* ── Цвет: фон × акцент × сторона света ──────────────────────────────────
   С 27 сентября 2026 (редизайн) ручных тем нет. Цвет строится в OKLCH
   в public/tokens.css — копии lines-erp-redesign/handoff/tokens.css, где
   и правится: светлость всех ступеней задаёт сторона света (data-scheme),
   фон (data-bg) и акцент (data-acc) дают только оттенок и насыщенность.
   Поэтому контраст одинаков при любом из 84 сочетаний — проверяет
   handoff/check-contrast.mjs и test/themes.test.js.

   Лестница та же, что была: фон → полотно-остров → карточка, в новых
   именах --base → --island → --solid; --well — утопленное.

   Ниже — прежние имена, псевдонимами новых. Переименовывать их по всему
   коду незачем: их тысячи, и разница только в имени. Стоит этот блок
   после tokens.css и с той же силой селектора, поэтому два имени, которые
   там значат другое, здесь побеждают:
     --canvas       у нас полотно-остров, в tokens.css — полупрозрачная заливка;
     --accent-text  у нас подпись НА акценте, в tokens.css — акцент для текста.

   Селектор — атрибут, а не :root: сочетание можно поставить на любой
   узел, и на этом держатся образцы в «Оформлении». */
[data-bg] {
  --bg: var(--base);
  --surface: var(--solid);
  --raised: var(--solid);
  --canvas: var(--island);
  --surface-2: var(--well);
  /* На ступень глубже колонки: полоса прокрутки, выбранное в утопленном */
  --surface-3: color-mix(in oklab, var(--well), var(--ink) 7%);
  --border: var(--line);
  --border-strong: var(--line-2);
  --text: var(--ink);
  --text-dim: var(--ink-2);
  --text-faint: var(--ink-3);

  --accent-text: var(--accent-ink);
  --accent-ring: color-mix(in srgb, var(--accent) 22%, transparent);
  /* Наведение на сплошное (кнопка, чип на подложке карточки): та же
     прозрачная --hover, но уже смешанная с --solid — под кнопкой бывает
     что угодно, а тон под мышью должен выйти одним на любом фоне */
  --hover-solid: color-mix(in srgb, var(--ink) 6%, var(--solid));
  /* Плоский акцент: градиент внутри кнопки редизайн убрал */
  --accent-grad: none;
  /* Акцент ТЕКСТОМ — ссылка, выбранное, счёт. В tokens.css это
     --accent-text (= --accent-hover), но у нас то имя занято подписью НА
     акценте, поэтому своё. Сам --accent (L .52) проходит 4,5 только на
     карточке: на фоне страницы 4,0, на утопленном 3,7 (сверка с ТЗ,
     28 сентября 2026) — текстом он не пишется. */
  --accent-fg: var(--accent-hover);

  /* Просрочка всегда красная (владелец, 3 сентября 2026) — теперь это
     просто --late: в новой модели он и так ни у какого акцента не отнят */
  --critical: var(--late);
  --critical-soft: var(--late-soft);
  --overdue: var(--late);
  --overdue-soft: var(--late-soft);

  --bar: color-mix(in oklab, var(--accent) 80%, var(--solid));
  --bar-done: var(--accent-hover);
  --summary: var(--ink-2);
  --milestone: var(--warn);
  --off: var(--well);
  --off-holiday: var(--late-soft);
  --today: var(--late);

  --shadow-xs: var(--sh-1);
  --shadow: var(--sh-1);
  --shadow-md: var(--sh-2);
  --shadow-lg: var(--sh-3);

  /* Подсветка фона — одна, слабая, от акцента (ТЗ, раздел 3). На досках
     её нет: цветное свечение вокруг рендера меняет восприятие его цвета */
  --bg-grad: radial-gradient(90% 65% at 8% -12%,
    color-mix(in srgb, var(--accent) calc(var(--glow) * .6), transparent) 0%, transparent 58%);
}
/* Сторона света отдельно от темы: браузеру — какие рисовать поля ввода
   и полосы прокрутки, приложению — на что опираться там, где важно не
   «какая тема», а «светло или темно» */
[data-scheme='light'] { color-scheme: light; }
[data-scheme='dark']  { color-scheme: dark; }

/* Статус ТЕКСТОМ (сверка с ТЗ, 28 сентября 2026). Ступени --late, --warn,
   --ok из tokens.css ТЗ проверяет только на карточке (4,6–5,1), а в портале
   ими пишут и на фоне страницы, на утопленной колонке канбана, под мышью
   и на своей же мягкой подложке (плашка «Ждёт» на --warn-soft) — там
   светлая сторона давала 3,1–4,4. Для текста светлая ступень темнее на
   семь-восемь сотых: 4,5 и выше на любой поверхности и любом из шести
   фонов. Заливки, точки и полосы остаются на прежних ступенях. На тёмной
   стороне статусы и так светлые и проходят везде — там это те же цвета.
   Проверяет test/themes.test.js. */
[data-scheme='light'] {
  --late-fg: oklch(.48 .17 27);
  --warn-fg: oklch(.47 .12 70);
  --ok-fg:   oklch(.47 .12 150);
}
[data-scheme='dark'] {
  --late-fg: var(--late);
  --warn-fg: var(--warn);
  --ok-fg:   var(--ok);
}

/* ── Крупность интерфейса ────────────────────────────────────────────────
   Весь текст задан в rem, поэтому масштаб меняется здесь одной строкой.
   На большом мониторе интерфейс крупнее, на телефоне чуть мельче:
   расстояние до экрана разное. */
html { font-size: 16px; }

* { box-sizing: border-box; }
/* Атрибут hidden должен работать и на кнопках: у них свой display,
   который иначе перебивает правило браузера */
[hidden] { display: none !important; }
html, body, #root { height: 100%; }
body {
  margin: 0;
  font-family: var(--font);
  /* Цифры одной ширины везде: сроки и номера стоят столбиком и не пляшут —
     раньше это давал моноширинный шрифт */
  font-variant-numeric: tabular-nums;
  font-size: var(--t-base);
  line-height: 1.5;
  color: var(--text);
  /* Свечение из верхнего угла — то, за счёт чего экран перестаёт быть
     равномерной заливкой. Оно закреплено (fixed) и не едет при прокрутке:
     ползущее пятно за текстом читается как дефект отрисовки. Держать его
     едва заметным обязательно — фон под текстом не должен быть событием. */
  background: var(--bg);
  background-image: var(--bg-grad);
  background-attachment: fixed;
  background-repeat: no-repeat;
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: 'cv02', 'cv03', 'cv04', 'tnum';
  overscroll-behavior: none;
  position: fixed; inset: 0;      /* никакой прокрутки самой страницы */
  width: 100%;
}

/* Заголовки плотнее текста: так выстраивается иерархия без лишних размеров */
h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: -.021em; line-height: 1.25; }
h1 { font-size: var(--t-2xl); }
h2 { font-size: var(--t-lg); }
h3 { font-size: var(--t-md); }
a { color: var(--accent-fg); text-decoration: none; }
a:hover:where([data-hover="mouse"] *) { text-decoration: underline; }
input, select, textarea, button { font: inherit; color: inherit; }
code { font-family: var(--code); font-size: .92em; }

/* Кольцо фокуса одно на всё приложение — видно, куда попала клавиатура */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-sm); }

::selection { background: var(--accent-soft); color: var(--accent-fg); }

/* Полосы прокрутки: тонкие, проявляются при наведении */
/* Полосы прокрутки: тонкие, проявляются при наведении.
   
   Тонкость задаётся двумя разными способами, и это не перестраховка.
   `scrollbar-width` — стандартное свойство, но в Chrome оно СИЛЬНЕЕ правил
   `::-webkit-scrollbar-*`: как только оно задано, весь набор веб-китовых
   правил ниже перестаёт применяться целиком. Мы этого не знали и полдня
   правили дорожку, которая ни на что не влияла: полоса выходила 12 пикселей
   вместо просимых 10, со стрелками на концах и без отступов.
   
   Поэтому стандартное свойство включается только там, где веб-китовых
   псевдоэлементов нет вовсе, — то есть в Firefox. Chrome и Safari получают
   правила ниже и вместе с ними отступ от скруглённых углов полотна. */
@supports not selector(::-webkit-scrollbar) {
  * { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--border-strong); border-radius: var(--radius-full);
  border: 3px solid transparent; background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover:where([data-hover="mouse"] *) { background: var(--text-faint); background-clip: content-box; }
/* Кнопки-стрелки на концах полосы. Их рисует система, и в нашем интерфейсе
   их не нажимают ни разу: листают колесом и перетаскиванием. Зато они
   занимают концы дорожки — и отступ, который отводит полосу от скруглённого
   угла, до неё не доходил. */
::-webkit-scrollbar-button { display: none; width: 0; height: 0; }

/* Полотно-остров скруглено на 18 пикселей, и полоса прокрутки шла по самому
   его краю: сверху и снизу она входила прямо в закругление, и между дугой
   рамки и прямым столбиком полосы оставался клин — угол выглядел срезанным.
   Отводим дорожку от концов ровно на радиус: полоса начинается там, где
   закругление заканчивается. */
.main::-webkit-scrollbar-track { margin: var(--radius-xl) 0; }

/* В колонках (левая колонка разделов, сводка «Сегодня») ползунок — только
   под мышью: вечная черта у края узкой колонки читалась рамкой, а листают
   там редко (владелец, 28 сентября 2026: «пройтись по верху колонки»).
   Прозрачным делаем сам ползунок, а не `scrollbar-width` — см. выше, почему
   в Chrome его трогать нельзя */
.side::-webkit-scrollbar-thumb, .svodka__body::-webkit-scrollbar-thumb { background-color: transparent; }
.side:hover:where([data-hover="mouse"] *)::-webkit-scrollbar-thumb, .svodka__body:hover:where([data-hover="mouse"] *)::-webkit-scrollbar-thumb { background-color: var(--border-strong); }
@supports not selector(::-webkit-scrollbar) {
  .side, .svodka__body { scrollbar-color: transparent transparent; }
  .side:hover:where([data-hover="mouse"] *), .svodka__body:hover:where([data-hover="mouse"] *) { scrollbar-color: var(--border-strong) transparent; }
}

/* ── Элементы управления ─────────────────────────────────────────────────── */

/* Кнопка — пилюлей на сплошной подложке (редизайн, 27 сентября 2026):
   та же форма, что у кнопок новых экранов и у поиска в шапке */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  height: 36px; padding: 0 var(--s-4); border-radius: var(--radius-full);
  border: 1px solid var(--line); background: var(--solid);
  cursor: pointer; white-space: nowrap; font-weight: 500; font-size: var(--t-sm);
  color: var(--text); box-shadow: var(--shadow-xs);
  transition: background var(--fast), border-color var(--fast),
              box-shadow var(--fast), transform .08s var(--ease);
  -webkit-tap-highlight-color: transparent;
  /* Наведение — токенами, а не отдельным :hover у каждого вида кнопки.
     До 30 сентября 2026 у каждого вида было своё правило наведения, а ниже
     по файлу общее `.btn:hover` («Наведение — одной подложкой») с той же
     силой селектора стояло позже и перебивало их все. Главная кнопка под
     мышью становилась почти белой при белой подписи (контраст 1,14), на
     тёмной стороне — тёмно-серой при тёмной подписи (1,29): владелец
     назвал это «смешением тем». Теперь правило наведения одно, а вид
     кнопки меняет только то, ЧЕМ подсвечивать, — перебить нечему. */
  --btn-hover-bg: var(--hover-solid);
  --btn-hover-line: var(--line-2);
}
.btn:hover:where([data-hover="mouse"] *) { background: var(--btn-hover-bg); border-color: var(--btn-hover-line); }
.btn:active { transform: scale(.97); }
.btn:disabled { opacity: .45; cursor: default; transform: none; box-shadow: none; }

/* Главная кнопка плоская (редизайн): блик внутри снят, --accent-grad
   пуст — оставлен для прежних правил, которые его зовут. */
.btn--primary {
  background: var(--accent); background-image: var(--accent-grad);
  border-color: var(--accent); color: var(--accent-text);
  box-shadow: var(--shadow-xs);
  --btn-hover-bg: var(--accent-hover); --btn-hover-line: var(--accent-hover);
}
.btn--primary:hover:where([data-hover="mouse"] *) { background-image: none; }
.btn--ghost {
  border-color: transparent; background: transparent; box-shadow: none;
  --btn-hover-bg: var(--hover); --btn-hover-line: transparent;
}
.btn--danger { color: var(--late-fg); --btn-hover-bg: var(--critical-soft); --btn-hover-line: var(--critical); }
.btn--sm { height: 30px; padding: 0 var(--s-3); font-size: var(--t-sm); }
/* Большая кнопка — «Установить на Windows / Mac»: одна на окно, её нажимают все */
.btn--lg { height: var(--s-7); padding: 0 var(--s-5); font-size: var(--t-md); }
.btn--icon { width: 36px; padding: 0; }
.btn--sm.btn--icon { width: 30px; }

.field { display: block; margin-bottom: var(--s-4); }
.field__label {
  display: block; font-size: var(--t-sm); color: var(--text-dim);
  margin-bottom: var(--s-2); font-weight: 500;
}
.input, .select, .textarea {
  width: 100%; height: 38px; padding: 0 var(--s-3);
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface); outline: none; color: var(--text);
  transition: border-color var(--fast), box-shadow var(--fast);
}
.input::placeholder, .textarea::placeholder { color: var(--text-faint); }
.input:hover:where([data-hover="mouse"] *), .select:hover:where([data-hover="mouse"] *), .textarea:hover:where([data-hover="mouse"] *) { border-color: var(--text-faint); }
.textarea { height: auto; padding: var(--s-3) var(--s-3); min-height: 80px; resize: vertical; line-height: 1.55; }
/* Список задач: строк сразу десять, чтобы вставленное было видно целиком,
   а не в щель на три строки. Межстрочный интервал плотнее обычного текста:
   здесь не абзац, а перечень, и строки читаются как ряд. */
.spisok__text { min-height: 210px; line-height: 1.45; }
.input:focus, .select:focus, .textarea:focus {
  border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring);
}
.input:disabled, .select:disabled, .textarea:disabled {
  background: var(--surface-2); color: var(--text-dim); cursor: default;
}
/* На сенсорном экране — телефон и iPad — всякое поле не мельче порога
   Safari (см. --t-field). Правило общее и с `!important` нарочно: поля
   в приложении набраны десятком разных кеглей под свои места (название
   доски 14, поиск в ассетах 15, ячейка таблицы 13), и перебивать каждое
   поштучно значит пропустить половину — а пропущенное поле увеличивает
   страницу при первом же касании. Мышь ни при чём: там поля остаются
   своего кегля.

   Правимые блоки (`contenteditable`) сюда не входят: в базе знаний это
   заголовки крупнее порога, а на доске — надпись, чей кегль задаёт масштаб
   холста. Абзацу базы знаний порог выставлен отдельно, у его правил. */
@media (pointer: coarse) {
  input:not([type='checkbox']):not([type='radio']):not([type='range']):not([type='file']):not([type='color']):not([type='button']):not([type='submit']),
  textarea, select {
    font-size: var(--t-field) !important;
  }
}
/* Стрелка выпадающего списка рисуется фоном: свой значок вместо системного */
/* Стрелка — тот же шеврон, что у .caret и в наборе значков (сверка экранов,
   28 сентября 2026): был залитый треугольник из двух градиентов, а у
   `select.input` — системная стрелка, своя в каждом браузере. Серый штриха
   один на обе стороны света: фон маской не красится, а средний серый
   читается и на светлом поле, и на тёмном. */
.select, select.input {
  appearance: none; -webkit-appearance: none; padding-right: var(--s-6); cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a8f98' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-position: right var(--s-3) center;
  background-size: var(--s-4) var(--s-4); background-repeat: no-repeat;
}
.row { display: flex; gap: var(--s-3); }
.row > * { flex: 1; min-width: 0; }
/* Кнопка в ряду не растягивается: «Сохранить» и «Добавить» во всю ширину
   читались полосой, а не кнопкой (сверка экранов, 28 сентября 2026). */
.row > .btn { flex: none; }
/* Ряд «поля + действия» (админка: офисы, разделы витрины): кнопки стоят
   на линии полей, а не ниже их на отбивку `.field`, и не тянутся. */
.row--end { align-items: flex-end; }
.row--end > :not(.field) {
  flex: none; margin-bottom: var(--s-4); display: flex; gap: var(--s-2); align-items: center;
}

.chip {
  display: inline-flex; align-items: center; gap: var(--s-1); height: 24px; padding: 0 var(--s-3);
  border-radius: var(--radius-full); font-size: var(--t-sm); font-weight: 500;
  background: var(--grey-soft); color: var(--text-dim); border: 1px solid transparent;
  white-space: nowrap;
}
.chip--org { background: var(--accent-soft); color: var(--accent-fg); }
.chip--ok { background: var(--ok-soft); color: var(--ok-fg); }
.chip--warn { background: var(--warn-soft); color: var(--warn-fg); }
/* Просрочка — один и тот же знак во всех местах: на главной, в списке
   проектов, в загрузке людей и в поиске. Раньше тот же факт бывал и серой
   строкой меты, и красной датой, и не показывался вовсе. */
.chip--overdue { font-weight: 600; }
.chip--xs { height: 20px; padding: 0 var(--s-2); font-size: var(--t-2xs); }
.peoplemeta { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.chip--danger { background: var(--critical-soft); color: var(--late-fg); }

.note { font-size: var(--t-sm); color: var(--text-dim); line-height: 1.55; }
/* Тихая ссылка внутри окна: «Все настройки проекта» и подобное — выход туда,
   где то же дело делают подробнее. Кнопкой её рисовать нельзя: в окне уже
   стоят «Отмена» и «Сохранить», и третья кнопка спорила бы с ними за то,
   чем окно заканчивается. Ссылка не спорит — она в стороне. */
.linkbtn {
  background: none; border: none; padding: 0; font: inherit;
  font-size: var(--t-sm); color: var(--text-dim); cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.linkbtn:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); }
.error {
  background: var(--critical-soft); color: var(--late-fg);
  padding: var(--s-3) var(--s-3); border-radius: var(--radius-sm); font-size: var(--t-base);
  margin-bottom: var(--s-3); border: 1px solid transparent;
}
.empty { text-align: center; padding: var(--s-7) var(--s-5); color: var(--text-dim); }
.empty h3 { margin-bottom: var(--s-2); color: var(--text); }

/* Карточка — сплошная, без рамки (редизайн): от фона её отделяют тон
   и тень, а не линия. И шапка без черты — части разделяет воздух. */
.card {
  background: var(--solid); border: none;
  border-radius: var(--radius-lg); box-shadow: var(--sh-1);
}
/* Список прямо на полотне: рамка вокруг него на том же цвете ничего не отделяет,
   а только добавляет ещё одну коробку. Строки разделяет волосяная линия. */
.card--plain {
  background: transparent; border: none; box-shadow: none; border-radius: 0;
}
.card + .card { margin-top: var(--s-4); }
/* В сетке карточки разделяет gap, а отступ соседа их сдвигал: вторая
   карточка «Стройки» стояла на шестнадцать точек ниже первой. */
.cardsgrid > .card + .card { margin-top: 0; }
.card__head {
  padding: var(--s-4) var(--s-4) var(--s-2);
  display: flex; align-items: center; gap: var(--s-3);
}
.card__body { padding: var(--s-4); }
/* Телефон: шапка карточки переносится, а поле поиска в ней встаёт своей
   строкой во всю ширину. В строку «Сотрудники · 8 человек · поиск ·
   + Сотрудник» на 375 точках помещалось всё, кроме самого поиска — его
   сжимало до квадратика в 26 точек, — а «+ Сотрудник» уезжал за край,
   и страница листалась вбок. */
@media (max-width: 760px) {
  .card__head { flex-wrap: wrap; row-gap: var(--s-2); padding: var(--s-3); }
  .card__head > .input { order: 10; flex: 1 1 100%; max-width: none !important; }
  /* «8 человек» не рвётся на две строки в одну цифру и одно слово */
  .card__head > .note { white-space: nowrap; }
}

/* Вкладки — пилюлей, как «События · Отпуска» и «Мои · Поручил» редизайна
   (27 сентября 2026): подложка утоплена, выбранная — сплошной плашкой.
   До редизайна была полоса во всю ширину с подчёркиванием под активной. */
.tabs {
  display: flex; gap: var(--s-05); padding: var(--s-05);
  width: fit-content; max-width: 100%;
  background: var(--sunken); border-radius: var(--radius-full);
  box-shadow: inset 0 0 0 .5px var(--line);
  margin-bottom: var(--s-4);
  /* Вкладки листаются вбок, если их много */
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  display: inline-flex; align-items: center; flex: none;
  height: 30px; padding: 0 var(--s-3); border: none; background: none; cursor: pointer;
  border-radius: var(--radius-full);
  color: var(--text-dim); font-weight: 500; font-size: var(--t-sm);
  white-space: nowrap;
  transition: color var(--fast), background var(--fast);
}
.tab:hover:where([data-hover="mouse"] *) { color: var(--text); }
.tab.is-active { color: var(--text); background: var(--solid); box-shadow: var(--sh-1); }
/* Число рядом с названием вкладки: сколько там строк, видно не заходя */
.tab__n {
  margin-left: var(--s-2); color: var(--text-faint); font-size: var(--t-xs);
  font-variant-numeric: tabular-nums;
}
/* Вкладка, которую видит не каждый: точка слева говорит «это ваши права»,
   а не «так у всех». Слов не пишем — они заняли бы полполосы. */


.table { width: 100%; border-collapse: collapse; font-size: var(--t-base); font-variant-numeric: tabular-nums; }
.table th {
  text-align: left; font-weight: 500; color: var(--text-dim); font-size: var(--t-xs);
  text-transform: uppercase; font-family: var(--mono); letter-spacing: .06em;
  padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--border); white-space: nowrap;
}
.table td { padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--border); vertical-align: middle; }
/* Числа в таблицах — по правому краю и моноширинные: только так разряды
   встают друг под друга и суммы можно сравнить глазом. Разметка помечает
   такие ячейки классом num. */
.table th.num, .table td.num {
  text-align: right;
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  letter-spacing: -.01em; white-space: nowrap;
}
.table th.num { font-family: inherit; }
.table tr:last-child td { border-bottom: none; }
.table tbody tr { transition: background var(--fast); }
.table tbody tr:hover:where([data-hover="mouse"] *) td { background: var(--hover); }
.table__actions { display: flex; gap: var(--s-2); justify-content: flex-end; }

/* ── Каркас приложения ───────────────────────────────────────────────────── */

/* Высота ровно по экрану, с учётом «чёлки» и полосы жестов на айфоне.
   Без этого в ярлыке с рабочего стола низ уезжает под системную полосу,
   а страница начинает пружинить вместо прокрутки. */
.app {
  display: flex; flex-direction: column;
  /* body закреплён (position: fixed; inset: 0), поэтому 100% — это ровно
     видимая область. -webkit-fill-available здесь давал неверную высоту. */
  height: 100%;
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
  overflow: hidden;
}

.topbar {
  display: flex; align-items: center; gap: var(--s-3);
  height: 60px; padding: 0 var(--s-5); flex: none;
  /* Шапка лежит на общем фоне без заливки и линии: заливка с бортиком делала
     из неё полку, а из навигации — колонку. Границы рисует не линия, а воздух. */
  background: transparent;
}
/* Логотип занимает ровно ширину боковой колонки: разделы в шапке начинаются
   там же, где начинается полотно с содержимым, и экран не режется вертикалью
   посередине пустого места */
.topbar__brand {
  display: flex; align-items: center; gap: var(--s-2);
  font-weight: 600; letter-spacing: -.02em; font-size: var(--t-md);
  flex: 0 0 calc(var(--side-w) - var(--s-5) - var(--s-3)); min-width: 0;
}
/* Логотип бюро вместо набранного имени. Маской, а не картинкой: так знак
   красится currentColor и одинаково жив во всех шести темах — иначе пришлось
   бы держать чёрный файл и белый и переключать их темой.

   Квадратного знака рядом больше нет: либо знак с набранным именем, либо
   логотип — вместе это две подписи об одном. Логотип поэтому крупнее, чем
   был в паре со знаком: он теперь один держит левый край шапки.
   Высота долей кегля, а не ступенью шкалы: это доля кегля, а не размер. */
.brand__name {
  display: block; height: .95em; aspect-ratio: var(--brand-logo-ar, 10 / 1);
  background-color: currentColor;
  -webkit-mask: var(--brand-logo) no-repeat center / contain;
  mask: var(--brand-logo) no-repeat center / contain;
}
/* Без логотипа — имя набором: тем же цветом, чуть плотнее обычного текста. */
.brand__name--text {
  display: inline-block; height: auto; aspect-ratio: auto; background: none;
  -webkit-mask: none; mask: none;
  font-weight: 600; letter-spacing: .01em; white-space: nowrap;
}
/* Знак «Стадии»: три линии убывающей толщины — концепция, проект, рабочая
   документация.

   В шапке и на входе он больше не рисуется: у бюро там логотип, а знак
   с логотипом рядом — две подписи об одном. Правило оставлено намеренно,
   а не забыто: знак живёт в иконках приложения, и другому бюро, которому
   логотипа взять неоткуда, шапка со знаком и набранным именем вернётся
   одной строкой в `brandName()`. Пропорции взяты из мелкого построения знака (32px и меньше),
   а не из крупного: у крупного тонкая линия на 26 пикселях пропадает совсем.
   В долях стороны: поле 22%, длина штриха 56%, толщины 16 / 8,5 / 4,5%.

   Красится темой. Плитка — акцент, штрихи — цвет подписи на акценте, то есть
   ровно та пара, что уже проверена на контраст в каждой из шестнадцати тем.
   Знак получается самым ярким предметом в шапке — так и задумано: это
   единственное место, где цвет темы стоит в полную силу и ничего не значит,
   кроме «вот приложение». */
.topbar__logo {
  width: 26px; height: 26px; border-radius: 5.7px; flex: none;
  background-color: var(--accent);
  /* Три штриха — тремя слоями заливки, а не псевдоэлементами: их и нужно три,
     а псевдоэлементов у узла два. Размеры в пикселях, а не в долях: проценты
     в background-position считаются от разницы размеров, и штрих уезжает
     тем сильнее, чем он тоньше. Знак везде 26 пикселей, так что это точно.
     Доли построения: поле 22%, длина 56%, толщины 16 / 8,5 / 4,5%. */
  background-image:
    linear-gradient(var(--accent-text), var(--accent-text)),
    linear-gradient(var(--accent-text), var(--accent-text)),
    linear-gradient(var(--accent-text), var(--accent-text));
  background-repeat: no-repeat;
  background-size: 14.6px 4.2px, 14.6px 2.2px, 14.6px 1.2px;
  background-position: 5.7px 6.1px, 5.7px 13.4px, 5.7px 18.7px;
  box-shadow: 0 1px 3px var(--accent-ring);
}
.topbar__spacer { flex: 1; }
.topbar__title { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar__user { display: flex; align-items: center; gap: var(--s-2); }
.avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  display: grid; place-items: center; font-size: var(--t-xs); font-weight: 600;
  background: var(--accent-soft); color: var(--accent-fg);
  letter-spacing: .01em;
}
/* Цифра на красном — цветом карточки, а не белым: на тёмной стороне
   --late светлый, и белая цифра на нём не читалась */
.badge {
  min-width: 18px; height: 18px; padding: 0 var(--s-1); border-radius: var(--radius);
  background: var(--critical); color: var(--solid); font-size: var(--t-2xs); font-weight: 600;
  display: inline-grid; place-items: center; line-height: 1;
}
/* Кружок, а не пилюля: число непросмотренных — это счётчик, и у счётчика
   во всём приложении круглая форма. Пилюлей набраны метки со словом. */
.badge--krug { border-radius: var(--radius-full); padding: 0 5px; }
/* Метка словом, а не числом: она стоит в строке и должна читаться */
/* Метки словом — мягкой пилюлей статуса, как в макете («Ожидание оплаты»):
   на янтаре тёмной стороны текст цвета чернил не читался */
.badge--bad, .badge--warn { height: auto; padding: var(--s-05) var(--s-2); font-weight: 500; border-radius: var(--radius-full); }
.badge--bad { background: var(--late-soft); color: var(--late-fg); }
.badge--warn { background: var(--warn-soft); color: var(--warn-fg); }

.main {
  flex: 1; min-height: 0; overflow: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  /* Содержимое — отдельное полотно, лежащее на фоне приложения. Скругление и
     зазор по краям делают то, что раньше делала граница у навигации.
     Заливка — своя, --canvas: полотно и лежащая на нём карточка не могут
     быть одного цвета, иначе карточки на нём не видно (см. раздел тем). */
  background: var(--canvas);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  margin: 0 var(--s-5) var(--s-5) 0;
}
.page {
  max-width: min(1440px, 100%); margin: 0 auto;
  /* предел ширины держит строку читаемой; холсты снимают его через .page--wide */
  /* Поле сверху срезано на пятую часть: над названием проекта стояла пустая
     полоса в треть высоты шапки, а под ней сразу начинается работа. На
     широком экране это 27 пикселей вместо 35 — заметно, но не в упор. */
  padding: clamp(20px, 1.9vw, 32px) clamp(20px, 2.2vw, 36px) var(--s-7);
}
/* Экран с доской: гант, канбан и таблица — холсты, им нужен весь монитор.
   Ограничивать их шириной колонки текста значит терять недели на шкале. */
.page--wide { max-width: 100%; }
/* Настройки — у левого края, а не посередине: «Профиль» шире остальных
   вкладок (1180 против 860), и страница по центру дёргала заголовок на
   130 точек при каждом переключении (сверка 28 сентября 2026) */
.page--nastroyki { margin-left: 0; }

/* Свернул колонку — получил ширину.
   Предел в 1440 держит строку читаемой, и убирать его совсем нельзя: список
   во всю ширину большого монитора читается хуже, а не лучше. Но человек,
   свернувший колонку, сделал это ради места, и не дать ему ничего — значит
   не выполнить того, о чём он попросил. Ступень одна и небольшая. */
.shell:has(.side.is-folded) .page,
.shell:has(.side--bare) .page { max-width: min(1680px, 100%); }
/* …но не холстам. Ступень выше придумана для страницы с текстом; для доски
   и справочника она не прибавка, а отнятие: у них предела нет вовсе, и
   правило про свёрнутую колонку возвращало им 1680 — то есть раздел без
   левой колонки оказывался уже, чем такой же с колонкой. */
.shell:has(.side.is-folded) .page--wide,
.shell:has(.side--bare) .page--wide { max-width: 100%; }
.shell:has(.side.is-folded) .page--roomy,
.shell:has(.side--bare) .page--roomy { max-width: min(1760px, 100%); }
.shell:has(.side.is-folded) .page--home,
.shell:has(.side--bare) .page--home { max-width: min(1920px, 100%); }

/* Главная: список работы плюс колонка заметок в 316 точек.
   Предел в 1440 придуман для строки текста, а здесь его делят надвое — и на
   широком мониторе список задач оставался в тысяче точек, канбан ужимался
   до четырёх узких колонок с прокруткой вбок, а справа от заметок стояло
   пустое поле в треть экрана. Ступень поднята ровно настолько, чтобы
   заметки остались на месте, а работе досталось освободившееся. */
.page--home { max-width: min(1920px, 100%); }

/* Экраны, где содержимое — сетка карточек, а не текст.
   Предел в 1440 придуман для строки: она читается тем хуже, чем длиннее.
   Сетке он ни к чему — от лишней ширины в ней появляется ещё один столбец,
   то есть ещё три проекта на виду. Но и совсем без предела нельзя: на очень
   широком мониторе ряд из шести карточек глазом уже не охватывается. */
.page--roomy { max-width: min(1760px, 100%); }

/* Возврат к списку — стрелкой в самом заголовке, а не отдельной строкой крошек:
   раздел и так подсвечен в навигации, дублировать его строкой нечем оправдать */
.backbtn {
  width: 30px; height: 30px; flex: none; display: grid; place-items: center;
  border: none; background: none; cursor: pointer; border-radius: var(--radius-full);
  color: var(--text-faint); font-size: var(--t-lg); font-family: inherit;
  transition: background var(--fast), color var(--fast);
}
.backbtn:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }

/* Команда проекта в шапке: аватары стопкой и вход в состав. Держим её на виду,
   потому что без людей в проекте задачу не на кого назначить. */
/* Люди и «плюс» — в одной рамке: раньше плюс стоял отдельной кнопкой рядом
   с обведённым рядом лиц, и было непонятно, к чему он относится. Теперь он
   выглядит как следующий по счёту человек, которого ещё нет. */
.teamwrap {
  display: inline-flex; align-items: center; gap: var(--s-1); flex: none;
  height: 40px; padding: 0 var(--s-2); border-radius: var(--radius-full);
  border: 1px solid var(--border); background: none;
  transition: border-color var(--fast);
}
.teamwrap:hover:where([data-hover="mouse"] *) { border-color: var(--border-strong); }
/* Отдельная кнопка «плюс»: показывает, кого можно добавить, и добавляет
   одним нажатием — раньше за этим открывалось окно с двумя списками */
/* Тот же круг, что у лиц: «плюс» читается как следующий человек */
.teamadd {
  width: 34px; height: 34px; border-radius: 50%; flex: none;
  border: 1px dashed var(--border-strong); background: none; cursor: pointer;
  color: var(--text-dim); font-size: var(--t-lg); line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  margin-left: var(--s-1);
  transition: border-color var(--fast), color var(--fast);
}
.teamadd:hover:where([data-hover="mouse"] *), .teamadd.is-open { border-color: var(--accent); color: var(--accent-fg); }
.teambtn {
  display: inline-flex; align-items: center; flex: none;
  height: 34px; padding: 0; border: none; background: none; cursor: pointer;
  color: var(--text-dim); font-family: inherit; font-size: var(--t-sm);
  transition: color var(--fast);
}
.teambtn:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); }
/* До шести человек лица стоят в ряд и не перекрываются: так видно, кто
   в проекте, не открывая ничего. Дальше ряд занял бы полшапки — лица
   наезжают друг на друга, а хвост сворачивается в «+N». */
.teambtn .avatar { margin-left: var(--s-1); border: 2px solid var(--surface); }
.teambtn.is-dense .avatar { margin-left: -8px; }
.teambtn .avatar:first-child { margin-left: 0; }
.avatar--team { width: 34px; height: 34px; font-size: var(--t-xs); }
.teambtn__rest {
  font-size: var(--t-2xs); color: var(--text-faint); margin-left: var(--s-1); font-weight: 600;
}
.teambtn__add { margin-left: var(--s-2); font-weight: 600; }

/* Окно новой задачи: узкое, полей ровно столько, сколько нужно на входе */
.modal--task { max-width: 420px; width: min(420px, calc(100vw - 32px)); }
/* Поле не распирает окно.

   На айфоне окно новой задачи уезжало правым краем за экран: у поля с датой
   в Safari своя наименьшая ширина, и оно раздвигало окно изнутри вместо
   того, чтобы ужаться. Проверить это в настольном браузере нельзя — там
   дата рисуется иначе, — поэтому правило поставлено на все поля разом:
   ширина по месту, а не по прихоти поля. */
.modal input, .modal select, .modal textarea {
  max-width: 100%; min-width: 0; box-sizing: border-box;
}
.modal input[type="date"] { -webkit-appearance: none; appearance: none; }
.modal__body { overflow-x: hidden; }

/* Отбивка под шапкой — на ступень меньше: вместе с урезанным полем сверху
   это отдаёт работе почти строку экрана, а ритма листа не ломает. */
.page__head { display: flex; align-items: center; gap: var(--s-2); margin-bottom: var(--s-3); flex-wrap: wrap; }
/* Заголовок не растягивается на всю полосу: иначе всё, что стоит следом,
   уезжает к правому краю и перестаёт читаться вместе с названием */
.page__head h1 { min-width: 0; }
.page__head h1.page__title { flex: none; }
.page__head > .spacer { flex: 1; }
/* Правая часть шапки проекта переносится целиком, а не по кнопке: длинные
   названия разделов («Задачи по комплектации») забирают ширину, и раньше
   на вторую строку уезжала одна шестерёнка */
/* Прижата вправо своим полем, а не распоркой: с распоркой при переносе она
   съедала остаток первой строки, и группа начинала вторую от левого края —
   как будто это ещё одна строка содержимого, а не правый угол шапки */
.page__head-right {
  display: flex; align-items: center; gap: var(--s-2); flex: none; margin-left: auto;
}
/* Плашка-кнопка: выглядит как метка, но по ней есть выбор */
.chip--act { cursor: pointer; border: none; font: inherit; font-weight: 600; }
/* Тихая плашка: состояние дел, а не выделенная метка — без жирного и заливки */
.chip--quiet {
  background: none; color: var(--text-dim); font-weight: 400;
  border: 1px solid var(--border);
}
.chip--quiet:hover:where([data-hover="mouse"] *) { border-color: var(--border-strong); color: var(--text); }
/* Наведение — налётом --hover поверх любой заливки плашки: прежний
   brightness(.96) на тёмной стороне был не виден вовсе (сверка экранов,
   28 сентября 2026) */
.chip--act:hover:where([data-hover="mouse"] *) { box-shadow: inset 0 0 0 100vmax var(--hover); }

/* ── Вход ────────────────────────────────────────────────────────────────── */

.auth { min-height: 100dvh; display: grid; place-items: center; padding: var(--s-5); }
.auth__box { width: 100%; max-width: 380px; }
/* Обёртка логотипа и формы — во всю ширину колонки: в сетке с place-items
   она сжималась по содержимому, и форма входа выходила в 264 точки с
   полями вплотную к краю карточки (сверка экранов, 28 сентября 2026) */
.auth > * { width: min(100%, 380px); }
.auth .card__body { padding: var(--s-5); }
.auth__logo { display: flex; align-items: center; gap: var(--s-3); justify-content: center; margin-bottom: var(--s-5); font-size: var(--t-lg); font-weight: 600; }
/* На входе логотип крупнее, чем в шапке: там он метка рядом с разделами,
   а здесь единственное, что есть на экране до ввода пароля. Тонкие штрихи
   «MATTER» на невысоком кегле выцветают в полпикселя — экрану нужно дать
   им высоту, благо место на этой странице есть. */
.auth__logo .brand__name { height: .95em; }
.auth__switch { text-align: center; margin-top: var(--s-4); font-size: var(--t-base); color: var(--text-dim); }
.auth__switch button { background: none; border: none; color: var(--accent-fg); cursor: pointer; padding: 0; font-weight: 500; }

/* ── Список досок ────────────────────────────────────────────────────────── */

/* Карточки покрупнее: при 268px на широком экране получалось четыре узких
   колонки, и пары проектов не хватало, чтобы ряд выглядел заполненным */
.boards { display: grid; gap: var(--s-3); grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); }
.bcard {
  /* Колонкой, чтобы подвал с метками прижимался к низу: иначе карточки в ряду
     разной высоты и нижний край получается рваным */
  display: flex; flex-direction: column; text-align: left; width: 100%; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: var(--s-4); box-shadow: var(--shadow-xs); color: var(--text);
  transition: border-color var(--fast), box-shadow var(--fast), transform var(--fast);
}
.bcard:hover:where([data-hover="mouse"] *) { border-color: var(--border-strong); box-shadow: var(--shadow-md); }
.bcard__title { font-weight: 600; margin-bottom: var(--s-1); }
.bcard__meta {
  font-size: var(--t-sm); color: var(--text-dim); margin-bottom: var(--s-2);
  font-family: var(--mono); font-variant-numeric: tabular-nums;
}
/* Описание режется по строкам, а не по символам: обрыв приходится на границу
   слова, а карточки в ряду получают одинаковую высоту */
.bcard__desc {
  font-size: var(--t-sm); color: var(--text-dim); line-height: 1.45;
  margin-bottom: var(--s-3);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.bcard__foot { display: flex; gap: var(--s-2); flex-wrap: wrap; align-items: center; margin-top: auto; }
.group-title { margin: var(--s-5) 0 var(--s-3); display: flex; align-items: center; gap: var(--s-2); }
.group-title h2 { font-size: var(--t-md); }
.group-title .note { font-weight: 400; }

/* ── Экран доски ─────────────────────────────────────────────────────────── */

.board { display: flex; flex-direction: column; height: 100%; min-height: 0; }
/* Панель переносится на вторую строку, а не уезжает вбок: уехавшие кнопки
   просто исчезали с глаз — на 800 точках за краем оставался и переключатель
   вида, и отбор по типам. */
.board__bar {
  display: flex; align-items: center; gap: var(--s-2); padding: var(--s-3) var(--s-4); flex: none;
  background: var(--surface); border-bottom: 1px solid var(--border);
  flex-wrap: wrap; row-gap: var(--s-2);
}
.board__bar::-webkit-scrollbar { display: none; }
.board__bar > * { flex: none; }
.board__bar .spacer { flex: 1 1 auto; min-width: 4px; }
/* Органы диаграммы — второй строкой панели, а не в общем ряду с видами.

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

   Своей коробки у строки нет: черта под панелью просто съезжает ниже, когда
   строка приходит. Рамка вокруг рамки ничего не отделяет, а панель на экране
   должна читаться одна — просто в две строки. */
.board__bar:has(+ .board__bar--gantt:not([hidden])) {
  border-bottom: none; padding-bottom: 0;
}
.board--embed .board__bar--gantt { border-top: none; border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
.board--embed .board__bar:has(+ .board__bar--gantt:not([hidden])) {
  border-bottom: none; border-radius: var(--radius-lg) var(--radius-lg) 0 0; margin-bottom: 0;
}
/* Переключатель — пилюлей, как .seg--pill редизайна: подложка утоплена,
   выбранное — сплошной плашкой */
.seg {
  display: inline-flex; gap: var(--s-05); padding: var(--s-05);
  background: var(--sunken); border-radius: var(--radius-full);
  box-shadow: inset 0 0 0 .5px var(--line);
}
.seg button {
  height: 28px; padding: 0 var(--s-3); flex: none; border: none; background: none;
  border-radius: var(--radius-full); cursor: pointer; color: var(--text-dim);
  font-size: var(--t-sm); font-weight: 500; white-space: nowrap;
  transition: background var(--fast), color var(--fast);
}
.seg button:hover:where([data-hover="mouse"] *) { color: var(--text); }
.seg button.is-active {
  background: var(--solid); color: var(--text); font-weight: 500;
  box-shadow: var(--sh-1);
}

/* Отмена и повтор тем же островком, что и масштаб: две стрелки, и гаснут,
   когда отменять нечего. Погашенная кнопка здесь честнее спрятанной —
   человек, ищущий отмену, должен видеть, где она живёт, и до первой правки
   тоже. */
.seg--undo button {
  padding: 0 var(--s-2); display: inline-flex; align-items: center; justify-content: center;
}
.undoarrow { display: inline-flex; align-items: center; }
.seg button:disabled { opacity: .4; cursor: default; }
.seg button:disabled:hover:where([data-hover="mouse"] *) { color: var(--text-dim); }

/* ── Диаграмма ───────────────────────────────────────────────────────────── */

/* --gantt-step — шаг вложенности строк. Его читает и скрипт: линия «куда
   упадёт» при перетаскивании стоит на том же отступе, что и сама строка. */
.gantt {
  position: relative; flex: 1; min-height: 0; background: var(--surface);
  --gantt-step: var(--s-5);
}
.gantt__scroll { position: absolute; inset: 0; overflow: auto; overscroll-behavior: contain; }
/* Дорожка полосы прокрутки видна целиком. Общая дорожка приложения
   прозрачна, и у диаграммы от горизонтальной полосы оставался один бегунок:
   он висел под куском шкалы и читался полосой, которая кончается посреди
   экрана, — непонятно было, что даты тянутся дальше. */
.gantt__scroll::-webkit-scrollbar-track { background: var(--surface-2); }
.gantt__scroll::-webkit-scrollbar-corner { background: var(--surface-2); }
.gantt__inner {
  display: grid;
  grid-template-columns: var(--left-w) var(--chart-w);
  grid-template-rows: auto 1fr;
  width: max-content; min-width: 100%; min-height: 100%;
}
.gantt__corner {
  position: sticky; left: 0; top: 0; z-index: 5;
  background: var(--surface); border-right: 1px solid var(--border-strong);
  border-bottom: 1px solid var(--border-strong);
}
.gantt__headright {
  position: sticky; top: 0; z-index: 3;
  background: var(--surface); border-bottom: 1px solid var(--border-strong);
}
.gantt__left {
  position: sticky; left: 0; z-index: 2; overflow: visible;
  background: var(--surface); border-right: 1px solid var(--border-strong);
}
.gantt__right { position: relative; }
.gantt.is-dragging { cursor: grabbing; user-select: none; }
.gantt.is-dragging .gantt__scroll { scroll-behavior: auto; }

.gantt__headtitle {
  height: 100%; display: flex; align-items: flex-end; padding: 0 var(--s-3) var(--s-2);
  font-size: var(--t-sm); font-weight: 600; color: var(--text-dim);
  gap: var(--s-2);
}
.gantt__headtitle-name { flex: 1; min-width: 0; }
/* Подпись над числами: раньше над ними стояло слово «Задача» */
.gantt__headtitle-dur { flex: none; font-size: var(--t-2xs); color: var(--text-faint); }
.ghead { position: relative; height: 52px; }
.ghead__row { position: absolute; left: 0; right: 0; }
.ghead__row--major { top: 0; height: 26px; }
.ghead__row--minor { top: 26px; height: 26px; }
.ghead__cell {
  position: absolute; top: 0; height: 26px; display: flex; align-items: center;
  font-size: var(--t-sm); font-weight: 600; color: var(--text);
  border-left: 1px solid var(--border); overflow: hidden; white-space: nowrap;
}
.ghead__label { padding-left: var(--s-2); will-change: transform; }
.ghead__day {
  position: absolute; top: 0; height: 26px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  border-left: 1px solid var(--border); font-size: var(--t-2xs); color: var(--text-dim);
  overflow: hidden;
}
/* Выходные — вполсилы: заливка сплошным --off читалась тяжёлыми серыми
   столбами поперёк графика и спорила с полосами. Выходной — фон, а не
   содержание: его достаточно отличить, а не заметить первым. */
.ghead__day.is-off {
  background: color-mix(in srgb, var(--off) 55%, transparent); color: var(--text-faint);
}
/* Подпись на акценте — --accent-text (светлая на светлой стороне, тёмная
   на тёмной), а не белая: на тёмной стороне акцент светлый */
.ghead__day.is-today { background: var(--accent); color: var(--accent-text); font-weight: 600; }
.ghead__day.is-today .ghead__dwd { color: color-mix(in srgb, var(--accent-text) 80%, transparent); }
.ghead__dnum { font-size: var(--t-xs); line-height: 1.05; color: var(--text); font-weight: 500; }
.ghead__day.is-off .ghead__dnum { color: var(--text-faint); }
.ghead__day.is-today .ghead__dnum { color: inherit; }
.ghead__dwd { font-size: var(--t-2xs); line-height: 1.1; text-transform: uppercase; letter-spacing: .02em; }

.grow {
  display: flex; align-items: center; gap: var(--s-05); height: var(--row-h);
  padding-left: calc(var(--s-2) + var(--depth) * var(--gantt-step)); padding-right: var(--s-1);
  border-bottom: 1px solid var(--border); cursor: pointer;
  -webkit-tap-highlight-color: transparent; position: relative;
  transition: background var(--fast);
}
/* Полоска слева у строки — одна на все виды: та же толщина, та же высота,
   тот же зазор. Отличается только цвет, и он тот же, что у полосы на шкале.
   Раньше у каждой был свой ореол тенью, а цвет этапа был вписан числом —
   на тёмной теме полоски этапов пропадали, и ряд читался неровным. */
.grow__color {
  width: 3px; height: 60%; border-radius: var(--radius-full); flex: none;
  margin-right: var(--s-1); background: var(--bar);
}
.grow__color.is-sum { background: var(--summary); }
.grow__color.is-ms { background: var(--milestone); }
.grow__more {
  width: 22px; height: 22px; flex: none; border-radius: var(--radius-full);
  display: grid; place-items: center; color: var(--text-faint);
  opacity: 0; transition: opacity .1s, background .1s;
}
.grow__more svg { pointer-events: none; }
.grow:hover:where([data-hover="mouse"] *) .grow__more, .grow.is-selected .grow__more { opacity: 1; }
.grow__more:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }
.grow__input {
  width: 100%; height: 24px; padding: 0 var(--s-1); font-size: var(--t-base);
  border: 1px solid var(--accent); border-radius: var(--radius-sm); background: var(--surface);
  outline: none; box-shadow: 0 0 0 3px var(--accent-soft);
}
.gantt.is-rowdrag { cursor: grabbing; user-select: none; }
.gantt.is-rowdrag .grow { cursor: grabbing; }
.grow.is-ghost { opacity: .4; }
.gantt__dropline {
  position: absolute; height: 2px; right: 6px; z-index: 6; pointer-events: none;
  background: var(--accent); border-radius: var(--radius-sm);
}
.gantt__dropline::before {
  content: ''; position: absolute; left: -4px; top: -3px;
  width: 8px; height: 8px; border-radius: 50%; background: var(--accent);
}
/* Подсказка «куда попадёт»: иначе непонятно, станет задача подзадачей или нет */
.gantt__dropline::after {
  content: attr(data-hint); position: absolute; left: 10px; top: -9px;
  background: var(--accent); color: var(--accent-text); font-size: var(--t-2xs); font-weight: 500;
  padding: var(--s-05) var(--s-2); border-radius: var(--radius-full); white-space: nowrap;
}
.grow:hover:where([data-hover="mouse"] *) { background: var(--hover); }
/* Выбранная строка помечается полосой слева: заливка одна на всю ширину
   спорит с цветными метками задач */
.grow.is-selected { background: var(--accent-soft); }
.grow.is-selected::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--accent);
}
.grow__twist {
  width: 17px; flex: none; text-align: center; color: var(--text-faint); font-size: var(--t-2xs);
}
/* Стрелка свёртки — i-chevron-down набора маской, свёрнутая — повёрнута */
.grow__twist.is-active {
  cursor: pointer; color: var(--text-dim); font-size: 0; align-self: stretch;
  background: currentColor;
  -webkit-mask: var(--chevron) center / var(--s-3) no-repeat;
  mask: var(--chevron) center / var(--s-3) no-repeat;
  transition: transform var(--fast);
}
.grow__twist.is-folded { transform: rotate(-90deg); }
.grow__text { flex: 1; min-width: 0; }
/* Кегль названия — переменной: по нему же считается высота двух строк
   у стройки, и на телефоне, где кегль меньше, они не разойдутся. */
.gantt { --grow-name: var(--t-base); }
.grow__name {
  font-size: var(--grow-name); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.25;
}
.grow.is-summary .grow__name { font-weight: 600; }
/* Название в одну строку (умолчание диаграммы) — с многоточием, полное
   в подсказке: высота строки 34, и второй ряд кегля 15 в неё не влезает.
   У стройки и у задач проекта (.gantt--twoline) — две строки с переносом,
   третья и дальше — многоточием: названия длинные, и в одну строку
   не помещалась большая их часть (владелец, 23.09.2026). Высоту строки под две строки выбирает
   gantt.js (`nameLines`), и шкала справа идёт тем же шагом.
   Дата под названием остаётся, пока есть место: поле текста ровно в две
   строки названия, и если название заняло обе, дата уходит за край —
   срок и так виден полосой справа, а название видно только здесь. */
.gantt--twoline .grow__text {
  max-height: calc(var(--grow-name) * 1.25 * 2); overflow: hidden;
}
.gantt--twoline .grow__name {
  white-space: normal; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
}
/* Дата — тем же плотным шагом: с межстрочным 1.5 от тела страницы она
   вылезала за край поля на полпикселя и срезалась под короткими названиями */
.gantt--twoline .grow__meta { line-height: 1.25; }
/* Название и кружки исполнителей в одну строку: название ужимается, кружки — нет */
.grow__nameline { display: flex; align-items: center; gap: var(--s-1); min-width: 0; }
.grow__nameline .grow__name { min-width: 0; }
/* Кружки исполнителей отодвинуты от названия: четырёх пикселей общего зазора
   не хватало, и две буквы в кружке читались продолжением слова — «Обмерный
   планАВ». Между названием и людьми нужна пауза, внутри группы — нет. */
.grow__who { display: flex; gap: var(--s-05); flex: none; margin-left: var(--s-2); }
.grow__dot {
  width: 17px; height: 17px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--t-2xs); font-weight: 600; letter-spacing: .2px;
  background: var(--accent-soft); color: var(--accent-fg);
  border: 1px solid var(--border);
}
.grow__dot--rest { background: var(--surface-2); color: var(--text-dim); }
.grow__meta { font-size: var(--t-2xs); color: var(--text-dim); white-space: nowrap; }
.grow__right { display: flex; gap: var(--s-2); align-items: center; flex: none; }
.grow__dur { font-size: var(--t-2xs); color: var(--text-faint); white-space: nowrap; }
.grow__pct { font-size: var(--t-2xs); color: var(--ok-fg); font-weight: 600; }

.gchart { display: block; }
/* Выходные вполсилы — почему, написано у шапки (.ghead__day.is-off) */
.gchart .off { fill: var(--off); fill-opacity: .5; }
.gchart .off--holiday { fill: var(--off-holiday); fill-opacity: .7; }
.gchart .gridline { stroke: var(--border); stroke-width: 1; opacity: .55; }
.gchart .gridline--month { stroke: var(--border-strong); opacity: .9; }
.gchart .gridline--row { stroke: var(--border); opacity: .8; }
.gchart .todayline { stroke: var(--today); stroke-width: 2; stroke-dasharray: 4 3; opacity: .85; }

.bar__body { fill: var(--bar); }
.bar__done { fill: var(--bar-done); }
.bar__done--tinted { filter: brightness(.68) saturate(1.15); }
.bar.is-critical .bar__body { fill: var(--critical); }
.bar.is-critical .bar__done { filter: brightness(.75); }
.bar.is-conflict .bar__body { stroke: var(--warn); stroke-width: 2; stroke-dasharray: 3 2; }
.bar.is-selected .bar__body { stroke: var(--text); stroke-width: 2; }
.bar .summary { fill: var(--summary); }
.bar .milestone { fill: var(--milestone); stroke: var(--surface); stroke-width: 1.5; }
.bar .baseline { fill: var(--text-faint); opacity: .45; }
/* Подпись печатается поверх сетки дней, и на плотном графике читались плохо
   обе. Обводка цветом полотна отделяет буквы от линий, не добавляя плашки. */
.bar__label {
  fill: var(--text-dim); font-size: var(--t-xs); font-family: var(--font);
  pointer-events: none;
  stroke: var(--surface); stroke-width: 3px; paint-order: stroke fill;
}
/* Подпись внутри полосы — когда справа край холста, а полоса длинная.
   Обводка цветом полотна здесь ни к чему: буквы лежат на заливке. */
.bar__label--in { fill: var(--accent-text); stroke: none; font-weight: 500; }
/* Подпись вехи — ромб сам по себе ничего не сообщает */
.bar__label--ms { fill: var(--text); font-weight: 600; font-size: var(--t-xs); }
.bar__grip { fill: transparent; cursor: ew-resize; }
.bar__link { fill: var(--surface); stroke: var(--border-strong); stroke-width: 1.5; cursor: crosshair; opacity: 0; }
.bar:hover:where([data-hover="mouse"] *) .bar__link { opacity: 1; }
.bar:hover:where([data-hover="mouse"] *) .bar__body { filter: brightness(1.08); }
.gantt__right .bar { cursor: pointer; }

.link { fill: none; stroke: var(--text-faint); stroke-width: 1.4; opacity: .8; }
.link--critical { stroke: var(--critical); opacity: 1; stroke-width: 1.8; }
.arrowhead { fill: var(--text-faint); }
.arrowhead--crit { fill: var(--critical); }
.ghostlink { stroke: var(--accent); stroke-width: 2; stroke-dasharray: 4 3; }

/* Граница между колонкой задач и диаграммой — её тянут мышью или пальцем */
.gantt__resizer {
  position: absolute; top: 0; bottom: 0; width: 7px; z-index: 6;
  cursor: col-resize; touch-action: none;
  -webkit-tap-highlight-color: transparent;
}
.gantt__resizer::before {
  content: ''; position: absolute; left: 2px; top: 0; bottom: 0; width: 3px;
  background: transparent; transition: background .12s;
}
.gantt__resizer:hover:where([data-hover="mouse"] *)::before { background: var(--accent); }
.gantt.is-resizing { user-select: none; cursor: col-resize; }
.gantt.is-resizing .gantt__resizer::before { background: var(--accent); }
/* Маленькая «ручка» посередине — чтобы границу вообще заметили */
.gantt__resizer::after {
  content: ''; position: absolute; left: 0; top: 50%; margin-top: -14px;
  width: 7px; height: 28px; border-radius: var(--radius-sm);
  background: var(--border-strong); opacity: 0; transition: opacity .12s;
}
.gantt__resizer:hover:where([data-hover="mouse"] *)::after, .gantt.is-resizing .gantt__resizer::after { opacity: 1; }

.gantt__tip {
  position: absolute; z-index: 20; pointer-events: none; max-width: 300px;
  background: var(--text); color: var(--bg); padding: var(--s-2) var(--s-3);
  border-radius: var(--radius-sm); font-size: var(--t-sm); line-height: 1.45;
  box-shadow: var(--shadow-lg);
}
/* В тёмной теме подсказка не инвертируется: светлая плашка резала бы глаз.
   Поднятая поверхность темы годится на все три тёмных — раньше цвет был
   вписан числом и «Графит» получал бы синеватую плашку. */
[data-scheme='dark'] .gantt__tip { background: var(--surface-3); color: var(--text); }

/* ── Панель задачи ───────────────────────────────────────────────────────── */

.sheet-backdrop {
  position: fixed; inset: 0; background: rgba(12, 15, 20, .35);
  z-index: 40; animation: fade .15s ease;
}
@keyframes fade { from { opacity: 0 } }
/* ── Стекло ───────────────────────────────────────────────────────────────
   Только у плавающего над содержимым: меню, палитра поиска, боковой лист.
   Под ним страница видна размыто, поэтому слой читается как лежащий сверху,
   а не как ещё одна плоскость. Настройка «Без стекла» (data-glass="off")
   возвращает сплошную заливку. */
[data-glass='panels'] .menupop,
[data-glass='panels'] .palette,
[data-glass='panels'] .sheet,
[data-glass='panels'] .datepop,
[data-glass='panels'] .kbpop,
[data-glass='panels'] .postpick,
[data-glass='panels'] .modal--pop,
[data-glass='panels'] .tbulk,
[data-glass='panels'] .diskpick.is-on,
[data-glass='panels'] .dxfv__tools {
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border-color: var(--edge-2);
  box-shadow: var(--in), var(--sh-3);
}
/* Боковой лист плавает у правого края с полем и скруглением, как в макете
   (редизайн): это слой поверх страницы, а не приставленная к краю колонка.
   На телефоне — снизу, во всю ширину (правило ниже, в @media). */
.sheet {
  position: fixed; z-index: 41; background: var(--solid);
  display: flex; flex-direction: column; overflow: hidden;
  right: var(--s-3); top: var(--s-3); bottom: var(--s-3); width: min(420px, calc(100% - var(--s-5)));
  border-radius: var(--radius-xl); box-shadow: var(--sh-3);
  animation: slide-in .18s ease;
}
@keyframes slide-in { from { transform: translateX(24px); opacity: .5 } }
.sheet__head {
  display: flex; align-items: center; gap: var(--s-3); padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--border); flex: none;
}
.sheet__head h3 { flex: 1; min-width: 0; }
/* Имя задачи — заголовок панели, а не первое поле формы. Правится по месту:
   поле без рамки, которое становится полем при наведении и фокусе. */
.sheet__ident { flex: 1; min-width: 0; }
.sheet__kind {
  font-size: var(--t-2xs); text-transform: uppercase; font-family: var(--mono); letter-spacing: .08em;
  font-weight: 500; color: var(--text-faint); margin-bottom: var(--s-05);
}
.sheet__ident .input {
  height: auto; padding: var(--s-05) var(--s-1); margin-left: calc(-1 * var(--s-1));
  font-size: var(--t-lg); font-weight: 600; line-height: 1.25;
  border-color: transparent; background: none;
}
.sheet__ident .input:hover:where([data-hover="mouse"] *):not(:disabled) { border-color: var(--border); }
.sheet__ident .input:focus { border-color: var(--accent); background: var(--surface); }

.sheet__body { flex: 1; overflow: auto; padding: var(--s-4); }
.sheet__bits { display: flex; gap: var(--s-1); flex-wrap: wrap; margin-bottom: var(--s-4); }

/* Раздел панели: подпись и содержимое. Разделяет воздух и волосяная линия
   сверху — двадцать полей подряд без групп читались как анкета. */
.sheet__group { margin-top: var(--s-5); }
.sheet__grouphead {
  font-size: var(--t-2xs); text-transform: uppercase; font-family: var(--mono); letter-spacing: .08em;
  font-weight: 500; color: var(--text-faint); margin-bottom: var(--s-3);
  padding-top: var(--s-4); border-top: 1px solid var(--border);
}
/* Свёрнутый раздел: то, что заводят один раз, не занимает свиток каждый раз */
.fold { margin-top: var(--s-4); border-top: 1px solid var(--border); padding-top: var(--s-3); }
.fold > summary {
  cursor: pointer; list-style: none; display: flex; align-items: center; gap: var(--s-2);
  font-size: var(--t-2xs); text-transform: uppercase; font-family: var(--mono); letter-spacing: .08em;
  font-weight: 500; color: var(--text-faint); padding: var(--s-1) 0;
  border-radius: var(--radius-sm);
}
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::before {
  content: ''; transform: rotate(-90deg); transition: transform var(--fast);
  color: var(--text-faint);
}
.fold[open] > summary::before { transform: none; }
.fold > summary:hover:where([data-hover="mouse"] *) { color: var(--text-dim); }
.fold[open] > summary { margin-bottom: var(--s-3); }
/* Тихая гармошка внутри окна («Настроить вручную»): без черты сверху и без
   подписи вразрядку — это пояснение, а не раздел формы. Стрелка — та же
   маска --chevron, а не системный треугольник. */
.fold.fold--tiho { margin-top: 0; border-top: none; padding-top: 0; }
.fold.fold--tiho > summary {
  display: inline-flex; font-size: var(--t-sm); text-transform: none; font-family: var(--font);
  letter-spacing: 0; font-weight: 400; color: var(--text-dim);
}
.fold.fold--tiho > summary:hover:where([data-hover="mouse"] *) { color: var(--text); }
/* Флажок с подписью в строку — их в панели несколько */
.field--check {
  display: flex; gap: var(--s-2); align-items: center;
  font-size: var(--t-sm); color: var(--text-dim);
}
.field--check input { flex: none; }
.sheet__foot {
  padding: var(--s-3) var(--s-4); border-top: 1px solid var(--border);
  display: flex; gap: var(--s-2); flex: none; align-items: center;
}
.sheet__status { font-size: var(--t-sm); color: var(--text-dim); transition: color .15s; }
.sheet__status.is-ok { color: var(--ok-fg); }
.sheet__status.is-error { color: var(--late-fg); }
.sheet__grip { display: none; }

.modal-backdrop {
  position: fixed; inset: 0; background: rgba(9, 9, 11, .45);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  z-index: 50; display: grid; place-items: center; padding: var(--s-4);
  animation: fade-in .12s var(--ease);
}
.modal {
  background: var(--solid); border-radius: var(--radius-lg); box-shadow: var(--sh-3);
  width: min(460px, 100%); max-height: 88dvh; display: flex; flex-direction: column;
  animation: modal-in .16s var(--ease);
}
@keyframes fade-in { from { opacity: 0 } }
@keyframes modal-in { from { opacity: 0; transform: translateY(8px) scale(.98) } }
/* Окно без черт под шапкой и над подвалом — как карточка редизайна */
.modal__head { padding: var(--s-4) var(--s-5) var(--s-2); display: flex; gap: var(--s-3); align-items: center; }
.modal__head h3 { flex: 1; }
.modal__body { padding: var(--s-2) var(--s-5) var(--s-4); overflow: auto; }
.modal__foot { padding: var(--s-2) var(--s-5) var(--s-5); display: flex; gap: var(--s-2); justify-content: flex-end; }

/* Сообщение сверху: снизу на телефоне полоса разделов, а на компьютере в тот
   угол никто не смотрит. Сверху же взгляд и так бывает — там заголовок. */
.toast {
  position: fixed; left: 50%; top: calc(12px + env(safe-area-inset-top));
  transform: translateX(-50%);
  display: flex; align-items: center; gap: var(--s-3);
  background: var(--text); color: var(--bg); padding: var(--s-3) var(--s-4);
  border-radius: var(--radius-full);
  font-size: var(--t-base); z-index: 90; box-shadow: var(--shadow-lg);
  animation: toast-in .18s var(--ease);
  max-width: calc(100% - 32px); text-align: center;
}
@keyframes toast-in { from { opacity: 0; transform: translate(-50%, -10px) } }
.toast--error { background: var(--critical); color: var(--solid); }
/* «Отменить» — тише самого сообщения: она предлагает откат, а не действие.
   Тёмная кнопка на подсказке тянула бы внимание сильнее, чем сам текст. */
.toast__act {
  border: 1px solid currentColor; background: none; cursor: pointer;
  font: inherit; font-size: var(--t-xs); font-weight: 500;
  color: inherit; opacity: .6; padding: 1px var(--s-2);
  border-radius: var(--radius-full); margin-left: var(--s-2);
}
.toast__act:hover:where([data-hover="mouse"] *) { opacity: 1; }
.toast__act:disabled { cursor: default; opacity: .4; }

/* Ход долгой работы (`ходРаботы` в app.js): как тост, но стоит до конца и
   ниже тостов, чтобы сообщение по ходу дела его не закрывало. */
.hod-raboty {
  position: fixed; left: 50%; top: calc(var(--s-7) + var(--s-5) + env(safe-area-inset-top));
  transform: translateX(-50%);
  display: flex; align-items: center; gap: var(--s-3);
  background: var(--text); color: var(--bg); padding: var(--s-2) var(--s-4);
  border-radius: var(--radius-full); font-size: var(--t-sm);
  z-index: 89; box-shadow: var(--shadow-lg);
  max-width: calc(100% - var(--s-6)); white-space: nowrap;
}
.hod-raboty__tekst { overflow: hidden; text-overflow: ellipsis; }
.hod-raboty__polosa {
  flex: none; width: calc(var(--s-7) + var(--s-6)); height: var(--s-1);
  border-radius: var(--radius-full); background: color-mix(in srgb, var(--bg) 25%, transparent);
  overflow: hidden;
}
.hod-raboty__dolya { display: block; height: 100%; width: 0; background: var(--bg); transition: width .2s var(--ease); }
@media (max-width: 480px) {
  .hod-raboty { gap: var(--s-2); padding: var(--s-2) var(--s-3); }
  .hod-raboty__polosa { width: var(--s-6); }
}

/* Подсказка при наведении. Своя, а не браузерная: та всплывает через секунду
   с лишним — за это время уже нажимают наугад. */
.tip {
  position: fixed; z-index: 95; pointer-events: none;
  background: var(--text); color: var(--bg);
  padding: var(--s-1) var(--s-3); border-radius: var(--radius);
  font-size: var(--t-xs); line-height: 1.4; max-width: 260px;
  box-shadow: var(--shadow-md); animation: fade-in .1s var(--ease);
}

.linkrow, .assignrow {
  display: flex; align-items: center; gap: var(--s-2); padding: var(--s-2) 0;
  border-bottom: 1px solid var(--border); font-size: var(--t-base);
}
.linkrow:last-child, .assignrow:last-child { border-bottom: none; }
/* Строка переносится, а не распирает экран: в «Справочники → Календарь»
   дата, плашка «Праздник», название и «Убрать» на телефоне в строку не
   помещались, и страница листалась вбок на полторы сотни точек. Кнопка
   при переносе прижимается вправо своим полем. */
.assignrow { flex-wrap: wrap; }
/* Основа в восемь букв, а не ноль: с нулевой пояснение не уходило на
   новую строку, а сжималось в три точки, и его текст, вылезая, всё равно
   раздвигал страницу вбок. */
.assignrow > .note { flex: 1 1 8em; min-width: 0; overflow-wrap: anywhere; }
.assignrow > .btn:last-child { margin-left: auto; }
.linkrow__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.progress-wrap { display: flex; align-items: center; gap: var(--s-3); }
.progress-wrap input[type=range] { flex: 1; accent-color: var(--accent); }
.progress-wrap span { width: 42px; text-align: right; font-variant-numeric: tabular-nums; }

.legend { display: flex; gap: var(--s-4); flex-wrap: wrap; font-size: var(--t-sm); color: var(--text-dim); padding: var(--s-2) var(--s-3); }
.legend i { display: inline-block; width: 12px; height: 8px; border-radius: var(--radius-sm); margin-right: var(--s-1); vertical-align: middle; }


/* Файлы на карточке задачи. Строкой, а не плиткой: их обычно два-три,
   и важнее имя, чем вид. */
.tfile { display: flex; align-items: center; gap: var(--s-2); padding: var(--s-1) 0; }
.tfile__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tfile__size { flex: none; }
/* Куда ронять файл на карточке. Своя зона, а не вся карточка: на карточке
   роняют и на чек-лист, и на описание, и попасть «вообще в задачу» нельзя. */
.tfiles__drop {
  display: flex; align-items: center; gap: var(--s-2);
  margin-top: var(--s-2); padding: var(--s-2);
  border: 1px dashed var(--border); border-radius: var(--radius);
  transition: border-color var(--fast), background var(--fast);
}
.tfiles__drop.is-dropping { border-color: var(--accent); background: var(--accent-soft); }

/* ── Диск ─────────────────────────────────────────────────────────────────── */

/* Корень диска — карточки папок, а не строки списка: их немного, и это выбор
   места, куда идти, а не перечень содержимого. */
.diskgroup__title {
  font-size: var(--t-base); font-weight: 600; color: var(--text-dim);
  margin: 0 0 var(--s-2);
}
.diskgrid { display: grid; gap: var(--s-2); grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }

/* ── Верхний уровень диска: плитки с лицом ───────────────────────────────────
   Диск бюро состоит из проектов, и узнают их в лицо. Семь одинаковых серых
   прямоугольников различались только подписью — чтобы попасть в нужный,
   приходилось читать все. */
.disktiles {
  display: grid; gap: var(--s-2); margin-bottom: var(--s-5);
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.disktile {
  display: flex; align-items: center; gap: var(--s-3); text-align: left;
  padding: var(--s-2); cursor: pointer; font: inherit; color: var(--text);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  transition: border-color var(--fast), box-shadow var(--fast);
}
.disktile:hover:where([data-hover="mouse"] *) { border-color: var(--border-strong); box-shadow: var(--shadow-xs); }
/* Лицо квадратное и заметное: по нему и узнают. Меньше — снова читаешь
   подписи, больше — плитка превращается в карточку проекта, а это диск. */
.disktile__face {
  flex: none; width: 52px; height: 52px; border-radius: var(--radius);
  display: grid; place-items: center; overflow: hidden;
  background: var(--surface-2); color: var(--text-dim);
}
.disktile__cover { width: 100%; height: 100%; display: block; }
.disktile__cover img, .disktile__cover svg { width: 100%; height: 100%; object-fit: cover; object-position: center center; display: block; }
.disktile__body { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.disktile__name {
  font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Своя папка — не проект: значок крупнее и приглушён, чтобы плитка читалась
   как своё место, а не как ещё один объект бюро. */
.disktile--моя .disktile__face { color: var(--text-faint); }
.disktile--моя .diskico svg { width: 26px; height: 26px; }
/* Корзина строкой под проектами: заходят туда реже всего, и работой она
   не является — незачем стоять вровень с проектами. */
.disktrash, .diskinstall {
  /* Кнопка, а не div: с неё в корзину попадают с клавиатуры. Но кнопка
     центрирует текст и рисует свою рамку — снимаем и то и другое, иначе
     строка не похожа на строку. */
  /* Черты сверху нет (сверка 28 сентября 2026): волосяная линия со
     скруглёнными концами читалась обрезком рамки. Строка отделена воздухом,
     подложка — по наведению, пилюлей, как у строк колонки. */
  display: inline-flex; width: auto; max-width: 100%;
  background: none; border: none; font: inherit; color: var(--text-dim);
  text-align: left; border-radius: var(--radius-full);
  padding: var(--s-2) var(--s-4) var(--s-2) var(--s-3);
}
.disktrash:hover:where([data-hover="mouse"] *), .diskinstall:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }
.disktrash .diskrow__icon, .diskinstall .diskrow__icon { min-width: 0; display: inline-flex; }
/* Подпись сразу за именем, а не у правого края: строка одна, и разгонять
   два слова по разным концам экрана незачем. */
.disktrash .diskrow__name, .diskinstall .diskrow__name { flex: none; }
.disktrash .diskrow__meta, .diskinstall .diskrow__meta { flex: 1; }
/* «Диск на компьютере» — под корзиной, той же тихой строкой (О3, 1.10.2026) */
.diskinstall { display: flex; width: max-content; margin-top: var(--s-2); }

/* ── Папка плиткой ───────────────────────────────────────────────────────────
   У картинки видно картинку, а не имя `IMG_4821.jpg`, по которому не отличить
   фасад от санузла. Ширина 150 — на ней читается имя файла в две строки
   и виден сам снимок; меньше — снимок превращается в марку. */
.disktilegrid {
  display: grid; gap: var(--s-2); padding: var(--s-2);
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.diskfile {
  display: flex; flex-direction: column; align-items: stretch; gap: var(--s-1);
  padding: var(--s-2); cursor: pointer; font: inherit; color: var(--text);
  background: none; border: 1px solid transparent; border-radius: var(--radius);
  text-align: left; min-width: 0;
}
.diskfile:hover:where([data-hover="mouse"] *) { border-color: var(--border); background: var(--hover); }
/* Квадратное место под картинку: у файлов разной высоты плитки прыгали бы
   строками, и сетка переставала читаться сеткой. */
.diskfile__pic {
  aspect-ratio: 1; display: grid; place-items: center; overflow: hidden;
  border-radius: var(--radius-sm); background: var(--surface-2); color: var(--text-dim);
}
.diskfile__pic.is-photo { background: var(--well); }
/* Снимок целиком, а не обрезанный под квадрат: вертикальный кадр терял
   верх и низ (владелец, 16 сентября 2026). Место остаётся квадратным,
   чтобы сетка не прыгала; поля — цветом подложки. */
.diskfile__pic img { width: 100%; height: 100%; object-fit: contain; display: block; }
/* Плитка в корзине — не кнопка (у неё свои кнопки под снимком), а щелчок
   по снимку открывает галерею. */
.diskfile--корзина { cursor: default; }
.diskfile--корзина .diskfile__pic.is-photo { cursor: zoom-in; }
.diskfile--корзина .diskrow__act { justify-content: flex-start; margin-top: var(--s-1); }
/* Имя в две строки и обрезка многоточием: у файлов бюро имена длинные,
   и в одну строку от них остаётся «План_1_эт…». */
.diskfile__name {
  font-size: var(--t-sm); line-height: 1.25;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; word-break: break-word;
}
.diskfile__size { font-size: var(--t-2xs); }
/* Папка плиткой — значок крупнее и на своей подложке: в сетке из снимков
   папку надо отличать не читая подпись. */
.diskfile--папка .diskfile__pic { background: var(--well); }
.diskfile--папка .diskico svg { width: 34px; height: 34px; }
/* Отмеченная плитка: заливка и рамка акцентом. Галочки в углу нет намеренно
   — в сетке из снимков она села бы поверх картинки, а отметку и так видно. */
.diskfile.is-picked {
  border-color: var(--accent); background: var(--accent-soft);
}
/* Рамка выделения. Поверх всего и мимо указателя: она рисуется, пока тянут,
   и перехватывать нажатия ей нечем. */
.diskramka {
  position: fixed; z-index: 60; pointer-events: none;
  border: 1px solid var(--accent); background: var(--accent-soft);
  opacity: .55; border-radius: 2px;
}
/* Сетка не выделяет текст, пока по ней тянут рамку: иначе вместе с файлами
   выделяются их подписи, и на экране получается каша. */
.disktilegrid { user-select: none; }

/* ── Папка таблицей ──────────────────────────────────────────────────────────
   Как в проводнике: имя, формат, вес, когда положили. Списком видно имя
   и вес, и этого хватает, пока в папке десяток файлов; когда их сотня,
   разбирают по столбцам — сортируя по дате или отделяя чертежи от снимков. */
.disktablewrap { overflow-x: auto; }
.disktable { width: 100%; }
.disktable__name { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
.disktable__fmt { width: 90px; white-space: nowrap; }
.disktable__size { width: 110px; white-space: nowrap; text-align: right; }
.disktable__when { width: 130px; white-space: nowrap; }
.disktable__act { width: 44px; text-align: right; }
.disktable tr.is-click { cursor: pointer; }
.disktable tr.is-picked td { background: var(--accent-soft); }

/* Файл, к которому пришли по внутренней ссылке: подсвечивается и гаснет.
   Держаться подсветка не должна — через минуту она читается как состояние
   файла, а это была навигация. */
.is-hailed { animation: hail 2.5s var(--ease); }
@keyframes hail {
  0%, 60% { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent); }
  100% { background: transparent; box-shadow: none; }
}
/* Ярлык на папку в задаче: кнопка, а не ссылка — папка открывается внутри
   приложения, и «открыть в новой вкладке» ей ни к чему. */
/* Имя файла — кнопка, а не ссылка: файл теперь открывается окном просмотра,
   а не переходом по адресу. Выглядеть при этом должно ровно как прежде:
   человек различает не разметку, а то, что подчёркивается под курсором. */
button.tfile__name {
  background: none; border: none; padding: 0; font: inherit; cursor: pointer;
  color: var(--accent-fg); text-align: left;
}
button.tfile__name:hover:where([data-hover="mouse"] *) { text-decoration: underline; }

.tfile__papka {
  background: none; border: none; padding: 0; font: inherit; cursor: pointer;
  color: var(--accent-fg); text-align: left;
}
.tfile__papka:hover:where([data-hover="mouse"] *) { text-decoration: underline; }

/* Два поля в строку в админке: «сколько» и «как долго» — одна настройка
   с двух сторон, и разводить их по разным строкам значило бы разделить
   то, что решают вместе. */
.admgrid2 {
  display: grid; gap: var(--s-3);
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}

/* ── Версии файла ────────────────────────────────────────────────────────────
   Нынешний файл сверху и отдельно: он не версия, он файл. Ниже — чем он был
   раньше, от свежего к старому. */
.versrow {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-2) 0; border-top: 1px solid var(--border);
}
.versrow--now {
  border-top: none; border-bottom: 1px solid var(--border-strong);
  margin-bottom: var(--s-2); padding-top: 0;
}
.versrow__n { flex: none; width: 54px; }
.versrow--now .versrow__n { color: var(--accent-fg); font-weight: 600; }
.versrow__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.versrow__when { flex: none; }
.versrow__skolko { margin: var(--s-3) 0 0; }
/* Имя версии — рядом с именем файла, акцентом: её назвали, чтобы найти */
.versrow__label { margin-left: var(--s-2); font-size: var(--t-xs); color: var(--accent-fg); }

/* Значки диска: одна плотность со значками видов, цвет — текущий. */
.diskico { display: inline-grid; place-items: center; color: var(--text-dim); }
.diskico svg { display: block; }
.diskcard {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-05);
  text-align: left; cursor: pointer;
  padding: var(--s-3); border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); color: var(--text); font: inherit;
  transition: border-color var(--fast), box-shadow var(--fast);
}
.diskcard:hover:where([data-hover="mouse"] *) { border-color: var(--border-strong); box-shadow: var(--shadow-xs); }
.diskcard__name { font-weight: 500; }

/* Путь до папки. Без него в дереве не понять, где стоишь, а «назад» отвечает
   только на один шаг из десяти. */
.diskpath {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1);
  margin-bottom: var(--s-3); font-size: var(--t-sm);
}
.diskpath__step {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--accent-fg); font: inherit;
}
.diskpath__step.is-here { color: var(--text-dim); cursor: default; }
.diskpath__sep { color: var(--text-faint); }

.diskrow {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) var(--s-3); border-bottom: 1px solid var(--border);
}
.diskrow:last-child { border-bottom: none; }
.diskrow--act { cursor: pointer; }
.diskrow--act:hover:where([data-hover="mouse"] *) { background: var(--hover); }
/* Тип файла тремя буквами вместо значка: «PDF» и «CAD» читаются с одного
   взгляда, а картинка формата — нет. Мелко и жирно: 600 на таком кегле
   не читается, тут нужен 700 (см. docs/ОБЛИК-И-ШКАЛЫ.md). */
.diskrow__icon, .tfile__icon {
  flex: none; min-width: 34px;
  font-size: var(--t-2xs); font-weight: 700; letter-spacing: .04em;
  color: var(--text-faint);
}
.diskrow__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.diskrow__meta { flex: none; }
.diskrow__act { display: flex; gap: var(--s-1); flex: none; }

/* ── Список папки: столбцы «Кто · Когда · Размер» (владелец, 1.10.2026) ──────
   «Список» и «Таблица» стали одним видом. Строка — сетка: отметка, метка
   расширения, имя, кто, когда, вес, «⋯»; заголовок столбца нажимается
   и сортирует. Галочка — при наведении и у отмеченных, как в почте:
   постоянная колонка квадратиков ничего не говорит, пока ничего не отмечено.
   На телефоне столбцы уходят, имя — в две строки, под ним «вес · когда». */
.dlist { padding: 0; overflow: hidden; }
.dlist__head, .dlrow {
  display: grid; align-items: center; column-gap: var(--s-3);
  grid-template-columns: var(--s-4) calc(var(--s-6) + var(--s-2)) minmax(0, 1fr)
    minmax(8rem, 12rem) 8rem 6rem calc(var(--s-6) + var(--s-1));
}
.dlist__head {
  padding: var(--s-2) var(--s-3); border-bottom: 1px solid var(--line);
  font-family: var(--mono); font-size: var(--t-xs); font-weight: 500;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3);
}
.dlist__col {
  justify-self: start; display: inline-flex; align-items: center; gap: var(--s-1);
  padding: var(--s-05) 0; border: none; background: none; cursor: pointer;
  font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit;
}
.dlist__col:hover:where([data-hover="mouse"] *), .dlist__col.is-on { color: var(--ink); }
.dlist__col.dlist__r { justify-self: end; }
.dlist__arrow { font-family: inherit; }
.dlrow { padding: var(--s-2) var(--s-3); }
.dlrow__pick { display: flex; align-items: center; }
.dlrow__pick .diskrow__pick { opacity: 0; transition: opacity var(--fast); }
.dlrow:hover:where([data-hover="mouse"] *) .diskrow__pick, .dlrow.is-picked .diskrow__pick,
.dlrow .diskrow__pick:checked, .dlrow .diskrow__pick:focus-visible { opacity: 1; }
.dlrow__ext.dfile__ext { position: static; justify-self: start; min-width: calc(var(--s-6) + var(--s-2)); text-align: center; }
.dlrow__ext.dfile__ext--folder { background: none; color: var(--ink-3); display: inline-flex; justify-content: center; padding: 0; }
.dlrow__name { min-width: 0; display: flex; flex-direction: column; gap: var(--s-05); }
.dlrow__nm { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dlrow__sub { display: none; font-size: var(--t-xs); color: var(--ink-3); }
.dlrow__who { display: flex; align-items: center; gap: var(--s-2); min-width: 0; font-size: var(--t-sm); color: var(--ink-2); }
.dlrow__whon { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dlrow__when, .dlrow__size { font-size: var(--t-sm); color: var(--ink-2); white-space: nowrap; font-variant-numeric: tabular-nums; }
.dlrow__size { text-align: right; }
/* У папки вместо веса — «3 папки · 12 файлов»: в столбце размера оно
   длиннее числа, поэтому занимает и «Кто», и «Когда» */
.dlrow--folder .dlrow__size { grid-column: 4 / 7; text-align: left; color: var(--ink-3); }
.dlrow--folder .dlrow__who, .dlrow--folder .dlrow__when { display: none; }
.dempty p { margin: 0; }
/* Находки поиска на полотне (Д5): та же строка списка, путь — нажимаемый,
   совпадение — мягким акцентом, у найденного по содержимому — отрывок */
.dnahodki mark, .dnahodka__otryvok mark { background: var(--accent-soft); color: inherit; border-radius: var(--radius-sm); padding: 0; }
.dnahodka__put {
  align-self: flex-start; max-width: 100%; padding: 0; border: none; background: none; cursor: pointer;
  font: inherit; font-size: var(--t-xs); color: var(--ink-3); text-align: left;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dnahodka__put:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); text-decoration: underline; }
.dnahodka__otryvok { font-size: var(--t-xs); color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dnahodki__rody { margin-bottom: var(--s-3); }
.dnahodki .dlrow--folder .dlrow__size { display: none; }
@media (max-width: 760px) {
  .dlist__head { display: none; }
  .dlrow {
    grid-template-columns: calc(var(--s-6) + var(--s-2)) minmax(0, 1fr) auto;
    padding: var(--s-2) var(--s-2) var(--s-2) var(--s-3); align-items: start;
  }
  .dlrow__pick, .dlrow__who, .dlrow__when, .dlrow__size { display: none; }
  .dlrow--folder .dlrow__size { display: none; }
  .dlrow__ext.dfile__ext { margin-top: var(--s-05); }
  /* Имя целиком, до двух строк: по хвосту имени и отличают один файл от
     другого (разбор 30.09.2026: видно было 14 знаков) */
  .dlrow__nm {
    white-space: normal; overflow-wrap: anywhere; line-height: 1.3;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  }
  .dlrow__sub { display: block; }
  .dlrow .diskrow__act { align-self: center; }
}

/* ── Диск по макету редизайна (27 сентября 2026) ─────────────────────────────
   Раскладка из lines-erp-redesign/portal.html, «Диск»: у заголовка — сколько
   занято и главные действия («+ Папка», «Загрузить»); строкой ниже — путь
   и вид словами; дальше сетка плиток прямо на фоне, у каждой своё лицо —
   снимок, лист PDF или знак рода, — формат меткой в углу, под ним имя
   и «кто · сколько · когда». Последней — приёмная плитка. */
.page--disk .page__head.dhead {
  border-bottom: none; padding-bottom: 0; margin-bottom: var(--s-4);
  align-items: flex-end;
}
.dhead__t { display: flex; flex-direction: column; gap: var(--s-1); min-width: 0; }
.dhead__row { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
.dhead__row h1 { min-width: 0; overflow-wrap: anywhere; }
.dhead__sub { font-size: var(--t-sm); color: var(--ink-3); }
.dhead .page__head-right .btn { display: inline-flex; align-items: center; gap: var(--s-1); }

.dbar {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  margin-bottom: var(--s-4);
}
.dbar__sp { flex: 1; }
.dbar .diskpath { margin-bottom: 0; gap: var(--s-1); }
/* Путь тихий, где стоим — чёрным: как в макете, крошки — подпись, а не ссылки
   в строке текста */
.dbar .diskpath__step { color: var(--ink-3); }
.dbar .diskpath__step:hover:where([data-hover="mouse"] *) { color: var(--ink); }
.dbar .diskpath__step.is-here { color: var(--ink); font-weight: 500; }
.dbar .diskpath__sep { display: inline-flex; color: var(--ink-3); }

/* Вид словами — пилюлей, как переключатели макета */
.dseg { border-radius: var(--radius-full); background: var(--sunken); box-shadow: inset 0 0 0 1px var(--line); }
.dseg button { border-radius: var(--radius-full); }
.dseg button.is-active { background: var(--solid); box-shadow: var(--sh-1); }

/* Просторные плитки файлов: лист и имя читаются без плотной россыпи. */
.dgrid {
  display: grid; gap: var(--s-3);
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  user-select: none;
}
.page--disk .dgrid + .diskgroup__title,
.page--disk .dgrid + .card + .diskgroup__title { margin-top: var(--s-5); }
.page--disk .dgrid + .disktrash { margin-top: var(--s-5); }
/* Папки и проекты — просторными плашками (владелец 1.10.2026): обложка 56,
   номер столбцом, имя до двух строк и «3 папки · 12 файлов». На телефоне —
   одна под другой. Отменяет «диск на
   телефоне — плитками по две» сверки 28 сентября, как 30 сентября — у проектов */
.dchips {
  display: grid; gap: var(--s-3); user-select: none;
  grid-template-columns: repeat(auto-fill, minmax(min(22rem, 100%), 1fr));
}
.dchip {
  display: flex; align-items: center; gap: var(--s-3); min-width: 0;
  padding: var(--s-3) var(--s-4); border: none; border-radius: var(--radius);
  background: var(--solid); box-shadow: var(--sh-1); cursor: pointer;
  font: inherit; color: var(--ink); text-align: left; transition: box-shadow var(--fast);
}
.dchip:hover:where([data-hover="mouse"] *) { box-shadow: var(--sh-2); }
.dchip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.dchip.is-picked { background: var(--accent-soft); box-shadow: inset 0 0 0 1.5px var(--accent); }
.dchip__face {
  flex: none; width: calc(var(--s-7) + var(--s-2)); height: calc(var(--s-7) + var(--s-2));
  border-radius: var(--radius-sm); overflow: hidden; display: grid; place-items: center;
  background: var(--well); color: var(--ink-3);
}
.dchip__face .dfile__cover, .dchip__face .dfile__cover img, .dchip__face .dfile__cover svg { width: 100%; height: 100%; }
.dchip__face > svg, .dchip__face > .ic, .dchip__face > .ic svg { width: 28px; height: 28px; }
.dchip__num { flex: none; min-width: 3.4em; font-size: var(--t-base); color: var(--ink-3); font-variant-numeric: tabular-nums; }
.dchip__t { min-width: 0; display: flex; flex-direction: column; gap: var(--s-1); }
.dchip__nm { font-size: var(--t-md); font-weight: 500; overflow: hidden; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.dchip__mt { font-size: var(--t-sm); color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.page--disk .dchips { margin-bottom: var(--s-5); }
.page--disk .dchips + .disktrash { margin-top: 0; }
/* Корзина строкой внизу — для узкого экрана, где колонки нет. Есть
   колонка — корзина уже в ней, второй раз её не показываем */
@media (min-width: 1101px) { .shell:has(.side .disktree) .disktrash { display: none; } }
.dfile {
  display: flex; flex-direction: column; align-items: stretch; gap: var(--s-2); min-width: 0;
  padding: var(--s-3); border: none; border-radius: var(--radius-lg);
  background: var(--solid); box-shadow: var(--sh-1);
  font: inherit; color: var(--ink); text-align: left; cursor: pointer;
  transition: box-shadow var(--fast);
}
/* Под мышью — только тень: плитка не подпрыгивает (владелец, 1.10.2026,
   «без прыжков при наведении»; разбор диска 30.09 — сдвиг был 1 точка) */
.dfile:hover:where([data-hover="mouse"] *) { box-shadow: var(--sh-2); }
.dfile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Отмеченная плитка — обводкой акцентом и его заливкой: галочки в углу нет
   намеренно, в сетке из снимков она села бы поверх картинки */
.dfile.is-picked { background: var(--accent-soft); box-shadow: 0 0 0 2px var(--accent), var(--sh-1); }

/* Лицо: 4:3, как лист и кадр. Снимок — целиком, а не обрезанный (владелец,
   16 сентября 2026: вертикальный кадр терял верх и низ); обложка проекта —
   во всё лицо, она и нарисована под обрезку */
.dfile__th {
  position: relative; aspect-ratio: 4 / 3; overflow: hidden;
  display: grid; place-items: center; border-radius: var(--radius);
  background: var(--sunken); color: var(--ink-3);
}
.dfile__th > img { width: 100%; height: 100%; display: block; object-fit: contain; }
.dfile__th.is-photo { background: var(--well); }
.dfile__th.is-sheet { background: var(--well); }
.dfile__th.is-sheet > img { object-fit: contain; }
.dfile__cover { width: 100%; height: 100%; display: block; }
.dfile__cover img, .dfile__cover svg { width: 100%; height: 100%; display: block; object-fit: cover; }
/* Заглушки по роду, пока нет картинки. Лист PDF — клеткой, как бумага
   чертежа; чертёж CAD — на акценте; папка — знаком акцентом */
.dfile__th--pdf {
  background:
    linear-gradient(var(--line) 1px, transparent 1px) 0 0 / var(--s-3) var(--s-3),
    linear-gradient(90deg, var(--line) 1px, transparent 1px) 0 0 / var(--s-3) var(--s-3),
    var(--solid);
}
.dfile__th--cad { background: var(--accent-soft); color: var(--accent-fg); }
.dfile__th--folder, .dfile__th--photos { color: var(--accent-fg); }
/* Формат — меткой в углу лица: «PDF» и «DWG» читаются с одного взгляда.
   Мелко и жирно: 600 на таком кегле не читается, нужен 700 */
.dfile__ext {
  position: absolute; left: var(--s-2); bottom: var(--s-2);
  padding: var(--s-05) var(--s-2); border-radius: var(--radius-sm);
  font-family: var(--mono); font-size: var(--t-2xs); font-weight: 700; letter-spacing: .04em;
  line-height: 1.4; color: var(--accent-ink); background: var(--ink-3);
}
.dfile__ext--pdf { background: var(--late); }
.dfile__ext--cad, .dfile__ext--doc, .dfile__ext--prog { background: var(--accent); }
.dfile__ext--xls { background: var(--ok); }
.dfile__ext--zip { background: var(--warn); }
.dfile__ext--img { background: var(--ink); color: var(--solid); }
/* Имя в две строки: у файлов бюро имена длинные, и в одну строку от них
   остаётся «План_1_эт…» */
.dfile__nm {
  padding: 0 var(--s-1); font-size: var(--t-sm); font-weight: 500; line-height: 1.25;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; word-break: break-word;
}
.dfile__mt {
  display: flex; align-items: center; gap: var(--s-2); min-width: 0;
  padding: 0 var(--s-1) var(--s-1); font-size: var(--t-xs); color: var(--ink-3);
}
.dfile__who { display: inline-flex; flex: none; }
.dfile__who:empty { display: none; }
.dfile__mtt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Плитка в корзине — не кнопка: у неё свои «Вернуть» и «✕» */
.dfile--корзина { cursor: default; }
.dfile--корзина:hover:where([data-hover="mouse"] *) { transform: none; }
.dfile--корзина .dfile__th.is-photo { cursor: zoom-in; }
.dfile--корзина .diskrow__act { padding: 0 var(--s-1) var(--s-1); }

/* Дерево в колонке диска: треугольник раскрытия и сама папка — две кнопки
   в одной строке. Уровень вложенности — отступом по шагу шкалы */
.dtrow {
  display: flex; align-items: center; gap: 0; border-radius: var(--radius);
  padding-left: calc(var(--s-3) * var(--d, 0));
  transition: background var(--fast);
}
.dtrow:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.dtrow.is-active { background: var(--surface); box-shadow: var(--shadow-xs); }
.dtrow__tw {
  flex: none; width: var(--s-5); align-self: stretch;
  display: grid; place-items: center; padding: 0;
  border: none; background: none; color: var(--text-faint); cursor: pointer;
  border-radius: var(--radius-sm);
}
.dtrow__tw:hover:where([data-hover="mouse"] *) { color: var(--text); }
.dtrow__tw .ic { transform: rotate(-90deg); transition: transform var(--fast); }
.dtrow__tw.is-open .ic { transform: none; }
.dtrow__go {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-2) var(--s-2) var(--s-2) 0;
  border: none; background: none; cursor: pointer; text-align: left;
  font: inherit; font-size: var(--t-sm); color: var(--text-dim);
}
.dtrow:hover:where([data-hover="mouse"] *) .dtrow__go, .dtrow.is-active .dtrow__go { color: var(--text); }
.dtrow.is-active .dtrow__go { font-weight: 600; }
.dtrow__ic { flex: none; display: inline-flex; color: var(--text-faint); }
.dtrow.is-active .dtrow__ic { color: var(--accent-fg); }
.dtrow__main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s-05); }
.dtrow__name {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere; line-height: 1.25;
}
.dtrow--note { padding: var(--s-1) 0 var(--s-1) calc(var(--s-5) + var(--s-3) * var(--d, 0)); font-size: var(--t-xs); }
.dtrow--note:hover:where([data-hover="mouse"] *) { background: none; }
.side__list.disktree .siderow .dtrow__ic { margin-left: calc(var(--s-5) - var(--s-3)); }
/* Место перед именем — одной ширины у значка, номера и пустого: имена
   встают на одну линию (аудит 30.09.2026, «лесенка»). Ширина — колонка
   номера вида «192-1» мелким кеглем, значок в ней слева; номер длиннее
   не режется, а раздвигает свою строку */
.disktree .dtrow__lead { flex: none; width: calc(var(--s-6) + var(--s-2)); min-width: calc(var(--s-6) + var(--s-2)); font-size: var(--t-xs); }
.disktree .dtrow__lead.siderow__code { width: auto; white-space: nowrap; }
.disktree > .side__group:empty { padding: 0; margin: var(--s-2) var(--s-3); border-top: 1px solid var(--line); }

@media (max-width: 760px) {
  .dgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2); }
  .dhead .page__head-right { margin-left: 0; }
  /* Без колонки, плитками по две (владелец, 27 сентября 2026). Обложки
     папок и проектов — ниже: в 4:3 две плитки занимали полэкрана, и корень
     не помещался. Снимки и листы остаются 4:3 — их смотрят целиком */
  .dgrid .dfile__th:not(.is-photo):not(.is-sheet) { aspect-ratio: 16 / 9; }
  .dfile { padding: var(--s-1); gap: var(--s-1); }
  .dfile__nm { font-size: var(--t-sm); }
}

/* Кнопка «С диска» в панели инструментов редактора досок. Своей краски
   у неё нет намеренно: она склонирована с соседней кнопки Excalidraw и
   носит его же вид — так она не читается заплаткой ни в одной теме.
   Здесь только то, чего у клона быть не может, — курсор. */
.wbdisk__tool { cursor: pointer; }

/* Выбор картинки: то же дерево, что в разделе «Диск», но в окне.
   Имя не `diskpick` — оно уже занято полоской отметок в самом разделе.
   Высота ограничена, чтобы окно не выросло длиннее экрана на папке
   с сотней снимков. */
.pickimg__body { max-height: min(60vh, 520px); overflow: auto; padding: var(--s-2); }
.pickimg__row { width: 100%; text-align: left; background: none; border: 0;
                color: inherit; font: inherit; cursor: pointer;
                border-radius: var(--radius-sm); border-bottom: none; padding: var(--s-2) var(--s-3); }
.pickimg__row:hover:where([data-hover="mouse"] *) { background: var(--hover); }
/* Значок папки — в цвете акцента, в клетке той же ширины, что трёхбуквенный
   тип файла: колонка имён стоит ровно и у папок, и у файлов */
.pickimg__folder { color: var(--accent-fg); display: grid; place-items: center; }
.pickimg__folder svg { display: block; }
.pickimg__chev { flex: none; display: inline-flex; color: var(--text-faint); padding-left: var(--s-2); }
/* Путь в окне — своей строкой под заголовком, с полями окна */
.modal > .diskpath { padding: var(--s-2) var(--s-4) 0; }

/* Ссылки наружу. Выдача сверху, выданные списком под ней: сначала отвечаем
   на «дай ссылку», потом на «а что я уже раздал». */
.sharenew { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.sharelist { margin-top: var(--s-3); border-top: 1px solid var(--border); }
.sharerow {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-2) 0; border-bottom: 1px solid var(--border);
}
.sharerow:last-child { border-bottom: none; }
.sharerow__main { flex: 1; min-width: 0; }
/* Мёртвая ссылка остаётся в списке: она след того, что файл уходил наружу.
   Но читается вполсилы — живые важнее. */
.sharerow.is-off .sharerow__main { color: var(--text-faint); }

/* Снимки объекта — сеткой по дням съёмки. В эту папку заходят посмотреть,
   и список имён на вопрос «что там» не отвечает вовсе. */
.photoday {
  margin: var(--s-4) 0 var(--s-2); font-size: var(--t-base); font-weight: 600;
}
.photoday:first-child { margin-top: 0; }
.photogrid {
  display: grid; gap: var(--s-1);
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
}
/* Снимки лежат рядами одной высоты, а ширина у каждого своя — по его
   пропорциям. До этого сетка резала всё в квадраты: вертикальный кадр
   терял верх и низ, панорама — бока, и по превью нельзя было понять, что
   на снимке (владелец, 16 сентября 2026). Высота ряда задана токеном ниже:
   в окне выбора картинки для доски и в папке снимков она одна и та же. */
.photogrid { display: flex; flex-wrap: wrap; gap: var(--s-1); --tile-h: 168px; }
.phototile {
  height: var(--tile-h); flex: 0 0 auto; max-width: 100%;
  padding: 0; border: none; cursor: pointer;
  border-radius: var(--radius-sm); overflow: hidden;
  background: var(--surface-2);
}
/* Пока миниатюра не приехала, плитка держит место по известным
   пропорциям (aspect-ratio ставит разметка); без них — квадрат. */
.phototile:not(:has(img)) { aspect-ratio: var(--tile-ar, 1); }
.phototile img { height: 100%; width: auto; max-width: 100%; object-fit: contain; display: block; }
.phototile.is-picked { outline: 3px solid var(--accent); outline-offset: -3px; }
.phototile.is-picked img { opacity: .75; }

.phototile:hover:where([data-hover="mouse"] *) { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Страница во всю высоту полотна. Нужна там, где на страницу роняют файлы:
   приёмная область иначе кончается вместе с содержимым, и человек, целящийся
   в пустое место ниже списка, промахивается мимо неё. */
.page--tall { min-height: 100%; }

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

   Внизу, а не вверху: там её не перепутать с шапкой папки, а рука с мышью
   и так внизу — отметив файлы, до неё ближе всего. */
.diskpick { display: none; }
.diskpick.is-on {
  display: flex; align-items: center; gap: var(--s-2);
  position: fixed; z-index: 40;
  left: 50%; transform: translateX(-50%);
  bottom: calc(var(--s-5) + env(safe-area-inset-bottom));
  max-width: min(880px, calc(100vw - 2 * var(--s-4)));
  padding: var(--s-2) var(--s-3);
  background: var(--raised); border: 1px solid var(--border-strong);
  border-radius: var(--radius-full); box-shadow: var(--shadow-lg);
  font-size: var(--t-sm);
  animation: pick-in .14s var(--ease);
}
/* Своя анимация, а не общая `modal-in`: та двигает `transform`, а он здесь
   занят центровкой — полоска уехала бы вбок. */
@keyframes pick-in { from { opacity: 0; transform: translateX(-50%) translateY(10px) } }
/* Кнопки в полоске круглее обычного: полоска — пилюля, и прямые углы
   внутри неё читаются как чужая деталь. */
.diskpick .btn { border-radius: var(--radius-full); white-space: nowrap; }
/* Счёт не переносится: «Отмечено 4 файла» в две строки распирает пилюлю
   по высоте и она перестаёт быть полоской. */
.diskpick > span { white-space: nowrap; flex: none; }
.diskpick .topbar__spacer { display: none; }

@media (max-width: 760px) {
  /* Над нижней полосой разделов, а не под ней. */
  .diskpick.is-on {
    bottom: calc(64px + var(--s-3) + env(safe-area-inset-bottom));
    max-width: calc(100vw - 2 * var(--s-3));
    overflow-x: auto; justify-content: flex-start;
  }
}
.diskrow__pick { flex: none; margin: 0; cursor: pointer; }

/* Ход загрузки. Класть полгигабайта в тишину — значит смотреть
   на неподвижный экран и гадать, идёт оно вообще или встало. */
.diskupload { display: grid; gap: var(--s-1); margin-bottom: var(--s-2); }
.diskprogress {
  display: flex; align-items: center; gap: var(--s-3);
  font-size: var(--t-sm); color: var(--text-dim);
}
.diskprogress__name { flex: none; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.diskprogress__bar { flex: 1; height: 4px; border-radius: var(--radius-full); background: var(--surface-2); overflow: hidden; }
.diskprogress__bar i { display: block; height: 100%; width: 0; background: var(--accent); transition: width .2s; }

/* Дела с архивами — плашкой внизу справа, на всё приложение.
   Сжатие идёт минутами, а человек тем временем ходит по диску: ход должен
   быть виден там, куда он ушёл, а не только в папке, где нажал. */
.arhdela {
  position: fixed; right: var(--s-4); bottom: var(--s-4); z-index: 60;
  width: min(380px, calc(100% - 2 * var(--s-4)));
  display: grid; gap: var(--s-2);
}
.arhdelo {
  display: grid; gap: var(--s-1); padding: var(--s-3);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  font-size: var(--t-sm);
}
.arhdelo__head { display: flex; align-items: center; gap: var(--s-2); }
.arhdelo__name { flex: 1; min-width: 0; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.arhdelo__note { overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; }
.arhdelo .diskprogress__bar { display: block; flex: none; }
.arhdelo.is-error .arhdelo__note { color: var(--late-fg); }
.arhdelo > .btn { justify-self: start; }
@media (max-width: 760px) {
  /* Над полосой разделов, во всю ширину: справа в углу палец её не достанет */
  .arhdela { left: var(--s-3); right: var(--s-3); width: auto; bottom: var(--в-низ-меню, var(--s-3)); }
}

/* Окно архива: дерево того, что внутри, до распаковки. Строки — как
   в списке папки, отступ ступени — токеном, по уровню вложенности. */
.arhv { display: flex; flex-direction: column; min-height: 100%; }
.arhv__head { padding: var(--s-3) var(--s-4) var(--s-2); }
.arhv__warn { margin: 0 var(--s-4) var(--s-2); }
.arhv__list { flex: 1; padding: 0 var(--s-2) var(--s-3); }
.arhv__row {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-1) var(--s-2);
  padding-left: calc(var(--s-2) + var(--arhv-level, 0) * var(--s-5));
  border-radius: var(--radius); cursor: pointer; min-height: 36px;
}
.arhv__row:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.arhv__row.is-off { cursor: default; color: var(--text-dim); }
.arhv__fold {
  flex: none; width: var(--s-5); height: var(--s-5); padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: none; color: var(--text-dim); cursor: pointer;
  /* Значок «chevron» смотрит влево (он же «назад»): закрытая папка —
     стрелкой вправо, открытая — вниз */
  transform: rotate(180deg); transition: transform .15s;
}
.arhv__row.is-open .arhv__fold { transform: rotate(-90deg); }
span.arhv__fold { transform: none; }
.arhv__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.arhv__size, .arhv__when { flex: none; white-space: nowrap; font-variant-numeric: tabular-nums; }
.arhv__size { min-width: 72px; text-align: right; }
.arhv__when { min-width: 72px; }
.arhv__dl { flex: none; min-width: 76px; }
.arhv__foot {
  position: sticky; bottom: 0; display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--s-2); padding: var(--s-3) var(--s-4);
  background: var(--surface); border-top: 1px solid var(--border);
}
.arhv__foot:empty { display: none; }
.arhv__btns { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-left: auto; }
.arhv__foot > .btn:first-of-type { margin-left: auto; }
.arhv__pic { display: flex; align-items: center; justify-content: center; min-height: 100%; padding: var(--s-4); }
.arhv__pic img { max-width: 100%; max-height: 80vh; object-fit: contain; }
@media (max-width: 760px) {
  /* На телефоне дата и «Скачать» не помещаются рядом с именем — уходят;
     скачать одну вещь можно из её окна */
  .arhv__when, .arhv__dl { display: none; }
  .arhv__row { padding-left: calc(var(--s-1) + var(--arhv-level, 0) * var(--s-4)); }
}

/* Список папок нового проекта. Высота своя: общее правило полей ставит
   всем 38 точек, и атрибут `rows` её не перебивает. */
.diskskeleton {
  height: auto; min-height: 200px; padding: var(--s-2) var(--s-3);
  resize: vertical; line-height: 1.6;
}

/* Куда ронять файл. Подсвечиваем весь раздел, а не узкую полоску: попасть
   в полоску — занятие для меткого, а не для занятого. */
.page.is-dropping { outline: 2px dashed var(--accent); outline-offset: -6px; border-radius: var(--radius-lg); }
/* Диск: вместо пунктира — вся папка под мягким акцентом и слово, куда лягут
   файлы (владелец, 1.10.2026: приёмной плитки больше нет, пунктиров тоже) */
.page--disk { position: relative; }
.page--disk.is-dropping { outline: none; }
.page--disk.is-dropping::after {
  content: attr(data-drop); position: absolute; inset: 0; z-index: 5; pointer-events: none;
  display: grid; place-items: center; border-radius: var(--radius-xl);
  background: color-mix(in srgb, var(--accent-soft) 82%, transparent);
  box-shadow: inset 0 0 0 2px var(--accent);
  font-size: var(--t-lg); font-weight: 600; color: var(--accent-fg);
}

/* ── Мобильная раскладка ─────────────────────────────────────────────────── */

@media (max-width: 760px) {
  .topbar { height: 50px; padding: 0 var(--s-3); gap: var(--s-1); flex: none; }
  .topbar .topbar__hide { display: none; }
  .topbar__title { font-size: var(--t-base); max-width: 34vw; }
  /* Шаг вложенности на телефоне короче: колонка задач там в полэкрана */
  .gantt { --gantt-step: var(--s-3); --grow-name: var(--t-sm); }
  .grow__meta { font-size: var(--t-2xs); }
  .ghead__day { font-size: var(--t-2xs); }
  /* Прятали имя, когда рядом оставался квадратный знак. Знака больше нет,
     и спрятать логотип значит оставить шапку без левого края и без кнопки
     «на главную» — эта область кликабельна. Поэтому не прячем, а уменьшаем. */
  .topbar__brand .brand__name { height: .8em; }
  .page { padding: var(--s-4) var(--s-3) 60px; }
  .boards { grid-template-columns: 1fr; }
  .sheet {
    left: 0; right: 0; top: auto; bottom: 0; width: 100%;
    max-height: min(86dvh, calc(100dvh - 40px));
    border-radius: var(--radius-lg) var(--radius-lg) 0 0; border-left: none;
    padding-bottom: env(safe-area-inset-bottom);
    animation: slide-up .2s ease;
  }
  @keyframes slide-up { from { transform: translateY(100%) } }
  .sheet__grip {
    display: block; width: 38px; height: 4px; border-radius: var(--radius-sm);
    background: var(--border-strong); margin: var(--s-2) auto 0; flex: none;
  }
  .sheet__body { padding: var(--s-4); }
  /* Таблица шире экрана листается вбок, и об этом надо сказать: на телефоне
     от месяца видно четырнадцать дней из тридцати одного, а край обрезан
     ровно по границе ячейки и выглядит концом таблицы, а не обрывом.

     Тень у правого края — приём с двумя слоями фона: слой `local` едет вместе
     с содержимым и закрывает тень, когда доехали до конца, слой `scroll`
     стоит на месте. Обработчик прокрутки для этого не нужен. */
  .table--wide {
    display: block; overflow-x: auto; white-space: nowrap;
    background:
      linear-gradient(to left, var(--surface), transparent) right center / 20px 100% no-repeat local,
      radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, .13), transparent)
        right center / 10px 100% no-repeat scroll;
  }
  .board__bar {
    padding: var(--s-2) var(--s-3); flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .board__bar::-webkit-scrollbar { display: none; }
  .board__bar > * { flex: none; }
  .board__bar .spacer { display: none; }
  .btn { height: 38px; }
  .seg button { height: 36px; }
}

@media (pointer: coarse) {
  .bar__grip, .bar__link { display: none; }
  /* На телефоне границу надо ещё суметь поймать пальцем */
  .gantt__resizer { width: 20px; margin-left: -7px; }
  .gantt__resizer::after {
    opacity: 1; left: 5px; width: 9px; height: 34px; margin-top: -17px;
    background: var(--border-strong);
    box-shadow: 0 0 0 2px var(--surface);
  }
  .grow__more { opacity: 1; width: 26px; height: 26px; }
  .grow { padding-right: var(--s-2); }
}

@media print {
  .topbar, .board__bar, .sheet, .modal-backdrop { display: none !important; }
  .gantt__scroll { position: static; overflow: visible; }
}

/* ── Палитра цветов ──────────────────────────────────────────────────────── */
/* Ряд кружков цвета. Имя .palette занято окном поиска по ⌘K - если назвать
   так же, правила окна перебьют этот ряд и кружки встанут столбиком. */
.swatchrow { display: flex; gap: var(--s-2); flex-wrap: wrap; }
.swatch {
  width: 28px; height: 28px; border-radius: 50%; cursor: pointer; flex: none;
  border: 2px solid transparent; box-shadow: inset 0 0 0 1px rgba(0,0,0,.12);
  transition: transform .08s; padding: 0;
}
.swatch:hover:where([data-hover="mouse"] *) { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--border-strong); }
.swatch.is-active { border-color: var(--text); }
.swatch--none { background: var(--surface-2); position: relative; }
.swatch--none::after {
  content: ''; position: absolute; inset: 6px 3px; border-top: 2px solid var(--critical);
  transform: rotate(-45deg); transform-origin: center;
}

/* ── Канбан ──────────────────────────────────────────────────────────────── */

.kanban {
  display: flex; gap: var(--s-3); align-items: flex-start;
  overflow-x: auto; overflow-y: hidden; padding: var(--s-05) var(--s-05) var(--s-3);
  -webkit-overflow-scrolling: touch;
}
/* Что доска листается вбок, ниоткуда не следовало: последняя колонка просто
   обрывалась краем. Тень у края появляется, только когда есть куда листать. */
.kanwrap { position: relative; }
.kanwrap::after {
  content: ''; position: absolute; top: 0; bottom: var(--s-3); right: 0; width: 40px;
  pointer-events: none; opacity: 0; transition: opacity var(--fast);
  background: linear-gradient(to right, transparent, var(--bg));
}
.kanwrap.has-more::after { opacity: 1; }
/* Колонка не сжимается ниже читаемой ширины: при группировке по исполнителю их
   бывает полтора десятка, и раньше они превращались в полоски. Что не влезло —
   листается вбок полосой самого канбана. Своей вертикальной прокрутки у колонки
   нет: вертикаль всегда одна, общая прокрутка содержимого. */
.kcol {
  /* Одинаковая ширина у всех: пустая «Готово» растягивалась наравне с полными,
     а при семи этапах комплектации колонки расходились по ширине содержимого.
     Но ширина эта не постоянная: пока колонки помещаются, они делят полосу
     поровну и занимают её целиком. Четыре колонки по 272 пикселя на большом
     мониторе стояли в левой половине, а справа оставалось пустое поле. */
  flex: 1 1 272px; min-width: 272px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius); display: flex; flex-direction: column;
}
.kcol.is-over { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.kcol__head {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-3) var(--s-3); border-bottom: 1px solid var(--border);
}
.kcol__dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
/* Лицо в заголовке колонки — когда колонка это человек. Кружок цвета
   там не значит ничего: цвет у всех людей одинаковый, а различать их
   надо с одного взгляда. */
.kcol__face { flex: none; }
.kcol__name { font-size: var(--t-base); font-weight: 600; flex: 1; min-width: 0; }
.kcol__name--two { line-height: 1.2; }
/* Подпись под именем: в «Планировании» это загрузка человека. Тише имени
   и мельче — это уточнение к нему, а не вторая строка заголовка. */
.kcol__note {
  font-size: var(--t-2xs); font-weight: 500; color: var(--text-faint);
  margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kcol__note.is-over { color: var(--late-fg); }
/* Полоса загрузки под заголовком колонки — в «Загрузке». Синее — до полной
   недели, красный хвост — перебор; при переборе полоса сжата так, что
   граница полной недели стоит там, где кончается синее. */
.kcol__bar {
  display: flex; height: 4px; margin: var(--s-2) var(--s-3) 0;
  border-radius: var(--radius-full); background: var(--border); overflow: hidden;
}
.kcol__barfill { height: 100%; background: var(--accent); }
.kcol__barfill--over { background: var(--late); }
/* Часы человека на задаче — моноширинно, как срок рядом */
.kcard__hours {
  font-family: var(--mono); font-size: var(--t-mono); font-variant-numeric: tabular-nums;
  color: var(--text-dim); font-weight: 500;
}
.kcol__count {
  font-size: var(--t-xs); color: var(--text-dim); background: var(--surface);
  border-radius: var(--radius-full); padding: var(--s-05) var(--s-2); border: 1px solid var(--border);
}
/* Пустая колонка тоже должна быть крупной мишенью для перетаскивания */
.kcol__body { padding: var(--s-2); display: flex; flex-direction: column; gap: var(--s-2);
  min-height: 180px; }
.kcol__empty { font-size: var(--t-sm); color: var(--text-faint); text-align: center; padding: var(--s-4) 0; }

/* Карточка задачи. Главное на ней — название, поэтому оно набрано весом, а всё
   остальное приглушено. До этого было наоборот: название шло обычным
   начертанием, а вокруг него горели цветные плашки метки, приоритета, звёзд и
   процента — и глазу не за что было зацепиться. */
/* Рамка ровная со всех сторон.
   
   Слева стояла жирная полоса цвета задачи — наследство диаграммы Ганта, где
   цветом различают полосы. На карточках она делала список пёстрым: у каждой
   строки свой цвет, и по нему ничего не читалось, потому что задавать этот
   цвет в интерфейсе уже негде — палитра из карточки задачи убрана, а данные
   с ней остались от старых задач и от песочницы. Знак, который нельзя ни
   поставить, ни объяснить, — это не знак, а рябь.
   
   Цвет остаётся там, где он что-то значит: на полосах диаграммы. */
.kcard {
  background: var(--raised); border: 1px solid var(--border);
  border-radius: var(--radius); padding: var(--s-3); cursor: pointer;
  box-shadow: var(--shadow-xs); transition: transform .1s, box-shadow .1s, border-color var(--fast);
}
.kcard:hover:where([data-hover="mouse"] *) {
  box-shadow: var(--shadow-md);
  border-color: var(--border-strong);
}
.kcard.is-dragging { opacity: .35; }
/* Копия карточки, которая едет за курсором или пальцем */
.kcard--ghost {
  position: fixed; z-index: 60; pointer-events: none; margin: 0;
  box-shadow: var(--shadow-lg); transform: rotate(1.5deg);
  opacity: .95;
}
/* Палец по карточке тянет её вбок, а вверх-вниз по-прежнему листает колонку */
.kcard { touch-action: pan-y; }
.kcard__stage { font-size: var(--t-2xs); color: var(--text-faint); margin-bottom: var(--s-1); }
/* Название и кнопка хода — в одну строку, кнопка не сжимается.
   Кружок выше строки текста, поэтому название опускается на полразницы:
   в одну строку оно встаёт ровно по центру кружка, в несколько — кружок
   приходится на середину первой строки, а не на середину всего абзаца.
   Держать их по верхнему краю было нельзя: кружок крупнее, и текст рядом
   с ним всплывал. */
.kcard__title { display: flex; align-items: flex-start; gap: var(--s-2); }
.kcard__title .kcard__name {
  flex: 1; min-width: 0;
  /* Полразницы между кружком хода и строкой названия: так они совмещаются
     серединами. Кегль здесь тот же, что у `.kcard__name` ниже, — разъедутся
     они, и название снова всплывёт над кружком. */
  margin-top: calc((var(--step-size) - var(--t-base) * 1.35) / 2);
}

/* Кружок статуса задачи — «как в Linear» (30 сентября 2026, вариант 2
   макета). Индикатор, а не шаг: цвет всегда от колонки (--st-color),
   заполнение — по ходу цепочки колонок (src/shared/krug.js). Нажатие
   открывает меню колонок общим menuButton. До 30.09 здесь был .stepbtn —
   шаг на колонку вперёд каждым нажатием. */
.krug {
  flex: none; width: var(--step-size); height: var(--step-size); padding: 0;
  border: none; background: none; cursor: pointer; border-radius: var(--radius-full);
  display: grid; place-items: center; position: relative;
  color: var(--st-color, var(--text-faint));
  transition: background var(--fast), transform var(--fast);
}
/* Значок тянется за кнопкой: размер задан токеном --step-size, а не в разметке */
.krug > .krug__ic, .krug__ic > svg { width: 100%; height: 100%; display: block; }
.krug__ic { color: var(--st-color, var(--text-faint)); display: grid; place-items: center; }
.krug:hover:where([data-hover="mouse"] *), .krug.is-open { background: var(--hover); }
.krug:active { transform: scale(.94); }
.krug:disabled { opacity: .5; cursor: default; }
/* Только показать — у чужой задачи без права её вести */
.krug.is-ro { cursor: default; }
.krug.is-ro:hover:where([data-hover="mouse"] *) { background: none; }
/* Галочка готовой вырезана цветом подложки: в меню подложка — само меню */
.menupop { --krug-cut: var(--surface); }

/* Пункты меню колонок: значок ступени слева, пометка справа */
.menupop .menurow--krug { gap: var(--s-2); padding: var(--s-2) var(--s-2); }
.menurow--krug .krug__ic { width: var(--s-5); height: var(--s-5); flex: none; }
.menurow--krug .krug__ic > svg { width: 18px; height: 18px; }
.menurow--krug .krug__ic--plain { color: var(--ink-3); }
.menurow__hint { flex: none; margin-left: var(--s-2); font-size: var(--t-xs); font-weight: 400; color: var(--ink-3); white-space: nowrap; }
.menupop .menurow--krug.is-next { background: var(--accent-soft); }
.menupop .menurow--krug.is-next:hover:where([data-hover="mouse"] *):not(:disabled),
.menupop .menurow--krug.is-next:focus-visible { background: color-mix(in srgb, var(--accent-soft), var(--ink) 6%); }
.menurow--krug.is-next .menurow__hint { color: var(--accent-fg); font-weight: 500; }
.menurow--krug.is-current { color: var(--ink-2); }
.menupop .menurow--krug:focus-visible { outline: none; background: var(--hover); }
/* Палец: пункт меню колонок — 44 точки в высоту на любом сенсорном экране,
   а не только на узком (планшет) */
@media (pointer: coarse) {
  .menupop .menurow--krug { min-height: 44px; }
}

/* Плашка «Статус» на странице задачи: кружок вместо точки */
.tpill--status .krug__ic { width: 16px; height: 16px; flex: none; }
.tpill--status .krug__ic > svg { width: 16px; height: 16px; }

/* Пустая карточка «новая задача»: та же форма, но пунктиром */
.kcard--add {
  display: flex; align-items: center; justify-content: center; gap: var(--s-2);
  background: none; border: 1px dashed var(--border-strong); border-left-width: 1px;
  border-radius: var(--radius); min-height: 96px; cursor: pointer;
  color: var(--text-faint); font-family: inherit; font-size: var(--t-base); font-weight: 500;
  box-shadow: none; transition: border-color var(--fast), color var(--fast), background var(--fast);
}
.kcard--add:hover:where([data-hover="mouse"] *) {
  border-color: var(--accent); color: var(--accent-fg);
  background: var(--accent-soft); transform: none;
}
.kcard--add__plus { font-size: var(--t-lg); line-height: 1; }

/* Настройки списка «Моя работа»: порядок и группы */
.seg--home button { height: 26px; font-size: var(--t-sm); padding: 0 var(--s-2); }
.hblock__head .seg--home { flex: none; }
/* Подпись группы: тише заголовка раздела, но заметнее строки задачи */
.hgroup {
  display: flex; align-items: center; gap: var(--s-2);
  font-size: var(--t-2xs); text-transform: uppercase; font-family: var(--mono); letter-spacing: .08em;
  font-weight: 500; color: var(--text-faint);
  margin: var(--s-5) 0 var(--s-3);
}
.hgroup:first-child { margin-top: 0; }
.hgroup__n {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  letter-spacing: 0; color: var(--text-faint); opacity: .8;
}
/* «Показать все» — под списком */
.hblock__all {
  margin-top: var(--s-4); border: none; background: none; cursor: pointer;
  font-family: inherit; font-size: var(--t-sm); font-weight: 500; color: var(--text-dim);
  padding: var(--s-2) 0;
}
.hblock__all:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); }

/* Перетаскивание карточки: своя рука, приподнятая копия под курсором и
   подсветка того места, куда карточка встанет */
.kcard--free.is-draggable { cursor: grab; }
.kcard--free.is-draggable:active { cursor: grabbing; }
.kcard--free.is-dragging { opacity: .3; }
/* Место приземления — черта между карточками, а не подсветка соседа:
   карточку кладут МЕЖДУ задачами, а не «в» задачу */
.cardsgrid--home.is-reordering { position: relative; }
.kcard--free.is-insert-before,
.kcard--free.is-insert-after { position: relative; }
.kcard--free.is-insert-before::before,
.kcard--free.is-insert-after::after {
  content: ''; position: absolute; top: -2px; bottom: -2px; width: 3px;
  border-radius: var(--radius-full); background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}
.kcard--free.is-insert-before::before { left: calc(-1 * var(--s-2) / 2 - 1px); }
.kcard--free.is-insert-after::after { right: calc(-1 * var(--s-2) / 2 - 1px); }
/* Название в карточке — до трёх строк: длинное имя не должно ни ломать сетку,
   ни обрываться на первом слове */
/* Название задачи — 15-м и весом 500. Найдено с трёх заходов.

   Сначала оно шло вровень с подписями вокруг и терялось среди них. Тогда
   его подняли до 17 и 600 — и оно стало крупнее всего на экране: в колонке
   помещалось четыре карточки вместо пяти, а в списке строка задачи весила
   больше заголовка раздела над ней. Опустили до 14 и 400, как обычный
   текст, — стало тихо: название перестало собирать взгляд первым, хотя
   ради него карточку и открывают.

   Середина: кегль основного текста (15) и вес органов управления (500).
   Ни одной новой ступени сверх тех, что в приложении уже есть, — а от
   подписей вокруг, набранных 12-м и тише цветом, отличается и тем, и
   другим сразу. */
.kcard__name {
  font-size: var(--t-base); line-height: 1.35; font-weight: 500;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
/* Точка «новая или изменена после вашего просмотра» — внутри строки
   названия, а не в углу карточки: в углу у канбана стоят меню и срок,
   и точка спорила бы с ними. Цвет тот же, что у красного кружка слева:
   это одна новость. */
.kcard__fresh {
  /* Отступы сверху и снизу равны по самим буквам: без обрезки строки
     шрифта над «new» оставалось больше воздуха, чем под ним */
  display: inline-block; margin-left: var(--s-2); padding: var(--s-1) var(--s-1);
  vertical-align: .15em; line-height: 1; text-box: trim-both ex alphabetic;
  font-size: var(--t-2xs); font-weight: 600; letter-spacing: .02em;
  border-radius: var(--radius-sm); background: var(--critical); color: #fff;
}
/* Огонёк просрочки и подсветка карточки: видно, не читая */
/* Огонёк приоритета — в бледном кружке.
   
   Голый значок в строке терялся: он единственный говорит «раньше остального»,
   а весил столько же, сколько любая из меток рядом. Кружок даёт ему поле —
   знак перестаёт спорить с соседями за место и ловится боковым зрением.
   
   Диаметр ровно как у кружка хода (--step-size): строку названия держит
   именно он, и огонёк вписывается в готовую высоту, ничего не раздвигая.
   Слева круг действия, справа круг важности, одного размера — строка
   получает две опоры вместо одной опоры и одного пятна.
   
   Заливка считается от цвета ступени приоритета и полотна карточки, а не
   написана числом: у шкалы может быть сколько угодно ступеней своих цветов,
   и каждая должна лечь на любую из шестнадцати тем. Доля та же, что у
   стикеров, — ровно столько краски, чтобы кружок читался подложкой, а не
   меткой. */
.kcard__hot {
  flex: none; width: var(--step-size); height: var(--step-size);
  border-radius: 50%; display: grid; place-items: center;
  font-size: var(--t-base); line-height: 1;
  background: color-mix(in srgb, var(--prio-color, var(--critical)) 16%, var(--raised));
}
/* Две записи одного срока: полная и короткая. Короткая живёт только
   в строках на телефоне, всё остальное время её нет. */
.kcard__date-brief { display: none; }
/* Просрочка — рамкой, а не заливкой.
   Заливка была верной, пока просроченных было одна-две: красная строка среди
   белых сразу видна. Но их бывает шесть из девяти — и тогда красным залит
   весь список, читается он как экран аварии, а невыделенной оказывается
   как раз работа, которая идёт по плану. Рамка говорит то же самое и не
   перекрашивает страницу: цвет просрочки остаётся у даты и у огонька.

   Цвет этот — не общий красный, а свой у каждой темы (`--overdue`).
   Красный годится не всякой палитре: в розовых он тонет, в тёплых спорит
   со всем сразу. К тому же красным в приложении говорят «опасно» —
   про удаление и ошибку, — а просрочка не опасность, а состояние работы.
   Решение владельца 3 сентября 2026. */
.kcard.is-hot { border-color: var(--overdue); }
.kcard.is-hot:hover:where([data-hover="mouse"] *) { border-color: var(--overdue); box-shadow: var(--shadow-md); }
/* Подвал карточки — по правому краю: срок, счёт по чек-листу, статус, лица.
   
   То же самое и в том же месте, что в строке списка на главной, где эта
   группа стоит справа от меток. Одно приложение — одно правило: слева то,
   что про саму задачу (название и метки), справа то, что про её ход (когда
   и у кого). Пока подвал карточки жался влево, одна и та же задача
   в колонке и в строке читалась по-разному, и взгляд каждый раз заново искал,
   где смотреть срок. */
.kcard__meta {
  display: flex; align-items: center; gap: var(--s-2); margin-top: var(--s-3);
  flex-wrap: wrap; justify-content: flex-end;
}
/* Огонёк приоритета стоит в подвале первым и распоркой отжимает от себя
   всё остальное: подвал прижат вправо, а важность — в левый угол. У названия
   он раньше забирал ширину в каждой из трёх строк, а на карточке это
   несколько слов, которых не видно. */
.kcard__meta > .kcard__hot:first-child,
.kcard__meta > .kcard__hotbtn:first-child { margin-right: auto; }
/* Завести задачу прямо в колонке. В покое почти не видно — проявляется,
   когда мышь над колонкой: постоянная кнопка в каждой колонке превратила бы
   доску в панель кнопок. */
/* Видна всегда, только приглушена: она проявлялась при наведении на колонку,
   а на сенсорном экране наведения нет — и завести задачу в колонке было
   нельзя вовсе */
.kcol__add {
  border: 1px dashed var(--border); border-radius: var(--radius);
  padding: var(--s-2) var(--s-3); font-size: var(--t-sm); color: var(--text-faint);
  cursor: pointer; text-align: center; transition: color var(--fast), border-color var(--fast);
  margin-top: var(--s-1); opacity: .7;
}
.kcol:hover:where([data-hover="mouse"] *) .kcol__add { opacity: 1; }
.kcol .kcol__add:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); border-color: var(--accent); opacity: 1; }

/* Цифры одной ширины везде, где их читают колонкой: иначе даты «пляшут»
   и список перестаёт читаться сверху вниз */
.kcard__date { font-size: var(--t-2xs); color: var(--text-dim); font-variant-numeric: tabular-nums; }
/* Просрочка — цветом, и только им.
   Красным, полужирным и моноширинным разом срок кричал громче названия
   задачи, хотя сам по себе он новость только тем, что просрочен. Про то же
   говорит и красная обводка карточки — три знака об одном. */
.kcard__date.is-late { color: var(--late-fg); }
/* Сегодня — словом и акцентом (владелец, 1.10.2026): на сегодня — не тревога,
   но и не рядовая дата. Просрочка своим правилом сильнее */
.kcard__date.is-today, .trow__due .kcard__date.is-today { color: var(--accent-fg); font-weight: 500; }
/* Срок — кнопка, а не подпись: нажатие открывает календарь прямо на карточке.
   В покое выглядит текстом, чтобы не превращать карточку в панель кнопок. */
.kcard__date-btn {
  font: inherit; color: inherit; background: none; border: none; cursor: pointer;
  padding: 1px var(--s-1); margin: -1px calc(var(--s-1) * -1);
  border-radius: var(--radius-sm); transition: background var(--fast), color var(--fast);
}
.kcard__date-btn:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }
/* Просроченный срок под мышью — на своей красноватой подложке, а не на общей
   серой: серая ложится поверх подсветки строки, и на тёмной стороне красная
   дата падала до 4,2 (разбор наведения, 30 сентября 2026) */
.kcard__date.is-late .kcard__date-btn:hover:where([data-hover="mouse"] *) { color: var(--late-fg); background: var(--late-soft); }
.kcard__date-input {
  font: inherit; font-family: var(--mono); color: var(--text);
  border: 1px solid var(--accent); border-radius: var(--radius-sm);
  padding: 0 var(--s-1); background: var(--surface); max-width: 140px;
}
.kcard__pct { font-size: var(--t-2xs); color: var(--ok-fg); font-weight: 600; }
.kcard__flag {
  font-size: var(--t-2xs); color: var(--warn-fg); border: 1px solid var(--warn);
  border-radius: var(--radius-full); padding: 0 var(--s-2);
}
.kcard__who { display: flex; gap: var(--s-05); margin-left: auto; }
.kcard__dot {
  /* Кружки были 19 пикселей: две буквы в них читались с трудом, а именно
     по ним на доске и узнают, чья это задача */
  width: 24px; height: 24px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--t-2xs); font-weight: 600;
  background: var(--accent-soft); color: var(--accent-fg); border: 1px solid var(--border);
}
.kcard__dot--rest { background: var(--surface-2); color: var(--text-dim); }
/* Статус прямо на карточке: та же плашка, но нажимается. Цветная точка слева
   берётся из цвета колонки — так статус узнаётся до чтения слова. */
.kcard__status {
  display: inline-flex; align-items: center; gap: var(--s-2);
  height: 24px; padding: 0 var(--s-2) 0 var(--s-3); border-radius: var(--radius-full);
  background: var(--surface-2); color: var(--text-dim); border: 1px solid transparent;
  font-size: var(--t-2xs); font-weight: 600; font-family: inherit; cursor: pointer;
  transition: border-color var(--fast), color var(--fast);
}
.kcard__status::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--st-color, var(--text-faint));
}
.kcard__status:hover:where([data-hover="mouse"] *), .kcard__status.is-open {
  border-color: var(--border-strong); color: var(--text);
}

@media (max-width: 760px) {
  .kcol { flex-basis: 78vw; max-width: 78vw; max-height: none; }
}

/* ── Чек-лист и обсуждение в карточке задачи ─────────────────────────────── */

.ckbar { height: 5px; border-radius: var(--radius-sm); background: var(--surface-2); overflow: hidden; margin-bottom: var(--s-3); }
.ckbar__fill { height: 100%; background: var(--ok); transition: width .2s; }
.ckrow {
  display: flex; align-items: center; gap: var(--s-3); padding: var(--s-2) 0;
  border-bottom: 1px solid var(--border); font-size: var(--t-base);
}
.ckrow:last-of-type { border-bottom: none; }
.ckrow.is-done span { color: var(--text-faint); text-decoration: line-through; }

/* Флажок чек-листа — свой, а не системный.
   
   Системный флажок рисует операционная система: на Windows это синий
   квадратик с чужим скруглением и чужим синим, на маке — свой, и оба
   не имеют отношения ни к одной из шестнадцати наших тем. В строке,
   где всё остальное собрано из наших токенов, он читался деталью
   от другого приложения.
   
   Форма — кружок, как у кнопки хода задачи: чек-лист и есть та же работа,
   только помельче, и отмечают её тем же движением. Галочка внутри нарисована
   двумя линиями через clip-path — так она масштабируется и красится цветом
   темы, в отличие от шрифтовой «✓», которая в каждом шрифте своя. */
.ckrow input[type='checkbox'] {
  appearance: none; -webkit-appearance: none; margin: 0; flex: none;
  width: 20px; height: 20px; border-radius: 50%;
  border: 1.5px solid var(--border-strong); background: var(--raised);
  cursor: pointer; position: relative;
  transition: background var(--fast), border-color var(--fast);
}
.ckrow input[type='checkbox']:hover:where([data-hover="mouse"] *):not(:disabled) { border-color: var(--ok); }
.ckrow input[type='checkbox']:checked {
  background: var(--ok); border-color: var(--ok);
}
.ckrow input[type='checkbox']:checked::after {
  content: ''; position: absolute; left: 4.5px; top: 5.5px;
  width: 9px; height: 5px;
  border-left: 2px solid var(--raised); border-bottom: 2px solid var(--raised);
  transform: rotate(-45deg);
}
.ckrow input[type='checkbox']:disabled { cursor: default; opacity: .55; }

.cmt { display: flex; gap: var(--s-2); padding: var(--s-2) 0; border-bottom: 1px solid var(--border); }
/* Поле ответа стоит на той же линии, что и чужие реплики: видно, что пишешь
   в ту же ленту, а не заполняешь форму под ней */
.cmt--new { border-bottom: none; padding-top: var(--s-3); align-items: flex-start; position: relative; }
.cmt__input { min-height: 38px; resize: none; overflow: hidden; }
.cmt__foot { display: flex; align-items: center; gap: var(--s-3); margin-top: var(--s-2); }
.cmt:last-of-type { border-bottom: none; }
.cmt__head { display: flex; gap: var(--s-2); align-items: baseline; font-size: var(--t-sm); }
.cmt__body { font-size: var(--t-base); white-space: pre-wrap; word-break: break-word; margin-top: var(--s-05); }
/* @упоминание в тексте — как ссылка, но не кликается: адресат его и так
   уже получил окликом, вести здесь больше некуда */
.cmt__body .mention { color: var(--accent-fg); font-weight: 600; }

/* Подсказка людей по «@» — плавает под полем ввода, а не сдвигает разметку:
   список меняется на каждую букву, и прыгающая под ним лента мешала бы
   целиться в строку курсором. */
.mention-pop {
  position: absolute; left: 0; right: 0; bottom: 100%; margin-bottom: var(--s-1);
  background: var(--solid); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-md); max-height: 220px; overflow: auto; z-index: 20;
}
.mention-pop__row {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-2) var(--s-3); cursor: pointer; font-size: var(--t-sm);
}
.mention-pop__row.is-sel, .mention-pop__row:hover:where([data-hover="mouse"] *) { background: var(--accent-soft); }

/* ── Ресурсы и показатели ────────────────────────────────────────────────── */

/* «Загрузка», прогноз на шесть недель: строка — человек, клетка — неделя.
   Сетка, а не таблица: первая колонка тянется под имя, недели делят
   остаток поровну — и клетки соседних строк стоят ровно друг под другом. */
.planfc {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-xs);
  overflow-x: auto; padding: var(--s-2) 0;
}
.planfc__grid {
  display: grid; align-items: center; min-width: 640px;
  grid-template-columns: minmax(180px, 1.6fr) repeat(var(--planfc-n, 6), minmax(64px, 1fr)) minmax(64px, .8fr);
}
.planfc__hd {
  display: flex; flex-direction: column; align-items: center; gap: var(--s-05);
  padding: var(--s-2) var(--s-1); font-size: var(--t-xs); color: var(--text-faint);
  font-family: var(--mono); font-variant-numeric: tabular-nums;
}
.planfc__hd b { font-weight: 500; color: var(--text-dim); font-family: var(--font); }
.planfc__hd--who { align-items: flex-start; padding-left: var(--s-4); font-family: var(--font); }
/* Текущая неделя помечена акцентом в шапке: от неё и читают вправо */
.planfc__hd.is-now, .planfc__hd.is-now b { color: var(--accent-fg); }
.planfc__who {
  display: flex; align-items: center; gap: var(--s-2); min-width: 0;
  padding: var(--s-1) var(--s-3) var(--s-1) var(--s-4); font-size: var(--t-base);
}
.planfc__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.planfc__cell { padding: var(--s-1); display: flex; }
.planfc__cell b {
  flex: 1; text-align: center; padding: var(--s-2) 0; border-radius: var(--radius-sm);
  font-family: var(--mono); font-size: var(--t-mono); font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.planfc__cell--free b { background: var(--ok-soft); color: var(--ok-fg); }
.planfc__cell--mid b { background: var(--accent-soft); color: var(--accent-fg); }
.planfc__cell--over b { background: var(--late-soft); color: var(--late-fg); font-weight: 600; }
/* Пустая неделя — едва заметной подложкой, а не обведённой клеткой: рамки на белом
   читались сеткой старой таблицы (сверка экранов, 28 сентября 2026) */
.planfc__cell--zero b { color: var(--text-faint); background: var(--hover); }
.planfc__avg {
  text-align: center; font-family: var(--mono); font-size: var(--t-mono);
  color: var(--text-dim); font-variant-numeric: tabular-nums;
}
/* Легенда под прогнозом: квадратик того же цвета, что клетка */
.planleg {
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); margin-top: var(--s-3);
  font-size: var(--t-sm); color: var(--text-dim);
}
.planleg span { display: inline-flex; align-items: center; gap: var(--s-2); }
.planleg__sw { width: 14px; height: 14px; border-radius: var(--radius-sm); display: inline-block; }
.planleg__sw.planfc__cell--free { background: var(--ok-soft); }
.planleg__sw.planfc__cell--mid { background: var(--accent-soft); }
.planleg__sw.planfc__cell--over { background: var(--late-soft); }
.planleg__sw.planfc__cell--zero { background: var(--hover); }
/* На телефоне имя уже: недели важнее, а имя дочитывается по лицу */
@media (max-width: 700px) {
  .planfc__grid { grid-template-columns: minmax(130px, 1fr) repeat(var(--planfc-n, 6), minmax(56px, 1fr)) minmax(56px, .8fr); }
}

/* Вкладки внутри шапки страницы: рядом с заголовком, а не полосой под ним.
   Полоса под заголовком отделяла бы шапку от содержимого лишней чертой —
   здесь под шапкой сразу колонки, и вторая горизонталь только шумит. */
.tabs--inline {
  margin-bottom: 0; margin-left: var(--s-3); overflow: visible;
}

/* «Загрузка», часы по проектам: строка — проект, полоса — его часы.
   Строка раскрывается канбаном проекта по людям — тем, что до редизайна
   было разрезом «по проектам». Отрезки полосы — люди, одним цветом:
   своего цвета у человека нет, и различает их подпись с лицом под полосой. */
.planpr { display: flex; flex-direction: column; gap: var(--s-2); }
.planpr__bar { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; margin-bottom: var(--s-1); }
.planpr__row {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-xs);
}
.planpr__sum {
  display: grid; grid-template-columns: minmax(200px, 1.2fr) 2fr 64px;
  align-items: center; gap: var(--s-2) var(--s-4);
  padding: var(--s-3) var(--s-4); cursor: pointer; list-style: none;
}
.planpr__sum::-webkit-details-marker { display: none; }
.planpr__name { display: flex; align-items: baseline; gap: var(--s-2); min-width: 0; }
.planpr__name::before {
  content: '▸'; color: var(--text-faint); font-size: var(--t-sm);
  transition: transform var(--fast); display: inline-block;
}
.planpr__row[open] .planpr__name::before { transform: rotate(90deg); }
.planpr__code {
  font-family: var(--mono); font-size: var(--t-mono); color: var(--text-dim); flex: none;
}
.planpr__title {
  font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.planpr__meta { font-size: var(--t-xs); color: var(--text-faint); flex: none; }
.planpr__track { height: 10px; border-radius: var(--radius-full); background: var(--surface-2); overflow: hidden; }
.planpr__fill { display: flex; gap: var(--s-05); height: 100%; }
.planpr__fill i { display: block; height: 100%; background: var(--accent); flex-basis: 0; min-width: 2px; }
.planpr__h {
  text-align: right; font-family: var(--mono); font-size: var(--t-mono);
  font-weight: 600; font-variant-numeric: tabular-nums;
}
/* Чьи часы — второй строкой под полосой, лицом и числом */
.planpr__who {
  grid-column: 2 / -1; display: flex; flex-wrap: wrap; gap: var(--s-1) var(--s-3);
  font-size: var(--t-sm); color: var(--text-dim);
}
.planpr__person { display: inline-flex; align-items: center; gap: var(--s-1); }
.planpr__person b {
  font-weight: 500; font-family: var(--mono); font-size: var(--t-mono); color: var(--text);
}
.planpr__open { padding: 0 var(--s-4) var(--s-2); }
.planpr__kan { padding: 0 var(--s-2) var(--s-3); }
/* Неделя «Загрузки»: колонки людей стоят на линии заголовка страницы, а не
   на поле холста правее его (сверка экранов, 28 сентября 2026) */
.kanban-host.planweek { padding-left: 0; padding-right: 0; }
@media (max-width: 700px) {
  .planpr__sum { grid-template-columns: 1fr auto; }
  .planpr__track { grid-column: 1 / -1; grid-row: 2; }
  .planpr__who { grid-column: 1 / -1; }
}

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: var(--s-3); }
.tile {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: var(--s-4) var(--s-4); box-shadow: var(--shadow);
}
/* Плитка внутри карточки — утопленная, без своей тени: карточка в карточке
   читалась двумя этажами (Диск → Хранилище). */
.card .tile { background: var(--well); box-shadow: none; }
/* Число и подпись плитки не ломаются: «100 МБ» и «Память свободно» в узкой
   плитке «Сервера» уезжали на две строки, и ряд плиток прыгал по высоте */
.tiles { grid-template-columns: repeat(auto-fit, minmax(156px, 1fr)); }
.tile__num { white-space: nowrap; }
.tile__num { font-size: var(--t-2xl); font-weight: 600; line-height: 1.1; letter-spacing: -.02em; }

/* ── Файлы, история, уведомления ─────────────────────────────────────────── */

.filerow {
  display: flex; align-items: center; gap: var(--s-2); padding: var(--s-2) 0;
  border-bottom: 1px solid var(--border); font-size: var(--t-base);
}
.filerow:last-of-type { border-bottom: none; }
.filerow__icon {
  flex: none; font-size: var(--t-2xs); font-weight: 700; letter-spacing: .3px;
  background: var(--accent-soft); color: var(--accent-fg);
  border-radius: var(--radius-sm); padding: var(--s-1) var(--s-1); min-width: 38px; text-align: center;
}
.filerow__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.histrow {
  display: flex; gap: var(--s-2); padding: var(--s-1) 0; font-size: var(--t-sm);
  border-bottom: 1px solid var(--border);
}
.histrow:last-of-type { border-bottom: none; }

/* Уведомления — всплывающей панелью под колокольчиком, как в макете
   (27 сентября 2026): стеклом, без затемнения страницы. Строки — без черт,
   непрочитанное — точкой акцента слева, а не полосой по краю. */
.modal-backdrop--pop {
  background: transparent; -webkit-backdrop-filter: none; backdrop-filter: none;
  place-items: start end; padding: calc(56px + var(--s-3) * 2 + env(safe-area-inset-top)) var(--s-5) var(--s-5);
}
.modal--pop { width: min(400px, 100%); max-height: min(600px, 100%); border-radius: var(--radius-xl); }
.modal--pop .modal__head { padding: var(--s-3) var(--s-3) var(--s-2) var(--s-4); }
.modal--pop .modal__head h3 { font-size: var(--t-md); }
.modal--pop .modal__body { padding: 0 var(--s-2) var(--s-2); }
@media (max-width: 760px) {
  .modal-backdrop--pop { place-items: start stretch; padding: calc(50px + env(safe-area-inset-top)) var(--s-2) var(--s-2); }
  .modal--pop { width: 100%; }
}
.notifday {
  padding: var(--s-2) var(--s-2) var(--s-1); font-size: var(--t-xs); font-weight: 500;
  color: var(--ink-3); text-transform: uppercase; font-family: var(--mono); letter-spacing: .08em;
}
.notif {
  position: relative; display: flex; gap: var(--s-3); padding: var(--s-2) var(--s-2) var(--s-2) var(--s-5);
  border-radius: var(--radius);
}
.notif[style*='pointer']:hover:where([data-hover="mouse"] *) { background: var(--hover); }
/* Значок вида слева, как у рядов сводки; непрочитанное — точкой на нём */
.notif { padding: var(--s-2); }
.notif__ic {
  position: relative; flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: var(--radius-full);
  background: var(--well); color: var(--ink-2);
}
.notif.is-new .notif__ic { background: var(--accent-soft); color: var(--accent-fg); }
.notif__ic.is-late { background: var(--late-soft); color: var(--late-fg); }
.notif.is-new .notif__ic::after {
  content: ''; position: absolute; top: -1px; right: -1px;
  width: var(--s-2); height: var(--s-2); border-radius: var(--radius-full);
  background: var(--accent); box-shadow: 0 0 0 2px var(--solid);
}
.notif__txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.notif__title { font-weight: 500; }
.notif:not(.is-new) .notif__title { color: var(--ink-2); }
.notif__list { display: flex; flex-direction: column; gap: 2px; font-size: var(--t-sm); color: var(--ink-2); }
.notif__sub { margin-top: var(--s-1); font-weight: 600; color: var(--ink); }
.notif__sub:first-child { margin-top: 0; }
.notif__li { padding-left: var(--s-3); position: relative; }
.notif__li::before { content: '·'; position: absolute; left: var(--s-1); color: var(--ink-3); }
.notif__more { color: var(--ink-3); }
.notif__more::before { content: none; }
/* Полоса — общая оформленная (::-webkit-scrollbar выше); scrollbar-width в Chrome её бы отключил */
.notif__empty { padding: var(--s-4) var(--s-2); color: var(--ink-3); }

/* ── Редактор колонок ────────────────────────────────────────────────────── */

.modal--wide { max-width: 560px; }
.colrow { display: flex; gap: var(--s-2); align-items: center; margin-bottom: var(--s-2); }
.colrow .input { flex: 1; min-width: 0; }
.coldot {
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  border: 2px solid var(--surface); box-shadow: 0 0 0 1px var(--border-strong);
  cursor: pointer; padding: 0;
}
.select--sm { height: 30px; font-size: var(--t-base); width: auto; min-width: 165px; padding: 0 var(--s-5) 0 var(--s-2);
  /* Стрелка — по середине высоты: смещение на 13 точек вниз осталось от
     прежней стрелки из двух слоёв и роняло нынешнюю ниже текста */
  background-position: right var(--s-2) center; }

/* ── Меню для узкого экрана ──────────────────────────────────────────────── */

.topbar__menu { display: none; }
.menurow {
  display: flex; align-items: center; gap: var(--s-3); width: 100%;
  padding: var(--s-3) var(--s-1); border: none; background: none; cursor: pointer;
  border-bottom: 1px solid var(--border); font-size: var(--t-md);
}
.menurow:last-of-type { border-bottom: none; }
/* Список выбора в окне: те же строки, что в меню, но с прокруткой — людей
   в бюро может быть и тридцать, а окно выше экрана не растёт */
.choicelist { margin-top: var(--s-2); max-height: 46vh; overflow-y: auto; }
/* Поле «Кому» в окне новой задачи: кнопка во всю ширину, как было у списка,
   но с лицом внутри */
.ktobtn { width: 100%; justify-content: flex-start; height: 38px; }
.ktobtn__in { display: flex; align-items: center; gap: var(--s-2); width: 100%; }
.ktobtn__in .caret { margin-left: auto; }
/* Имена выбранных перечисляются подряд, и втроём они кнопку не помещаются.
   Обрезаем многоточием: полный список видно в самом меню, а кнопка должна
   остаться одной строкой — иначе поле прыгает по высоте при каждой галочке. */
.ktobtn__txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.choicelist .menurow:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.menurow:active { background: var(--surface-2); }

/* Меню у кнопки. Внутри те же .menurow, что и в модалках, но без разделителей
   на каждой строке: в коротком списке хайрлайн под каждым пунктом — шум. */
.menupop {
  position: fixed; z-index: 60; min-width: 208px; max-width: 280px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  padding: var(--s-1); overflow: hidden;
  /* Долистал до конца — страница под меню не едет следом: иначе прокрутка
     уходила окну, и меню закрывалось (24 сентября 2026) */
  overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
}
/* На телефоне меню разворачивается во всю ширину — ширину ему ставит
   разметка, а предел в 280 точек мешал бы. Прижатое к правому краю, оно
   занимало две трети экрана и читалось как выехавшая сбоку панель. */
@media (max-width: 520px) {
  .menupop { max-width: none; }
}
/* Кто вошёл — подпись в шапке меню, а не пункт: нажимать на неё нечего */
.menupop__me {
  padding: var(--s-2) var(--s-3) var(--s-3);
  font-size: var(--t-base); font-weight: 500; color: var(--text);
}
.menupop .menurow {
  border-bottom: none; border-radius: var(--radius-sm);
  padding: var(--s-2) var(--s-3); font-size: var(--t-base);
}
.menupop .menurow:hover:where([data-hover="mouse"] *):not(:disabled) { background: var(--hover); }
.menupop .menurow:disabled { opacity: .45; cursor: default; }
.menupop .menurow.is-active { color: var(--accent-fg); font-weight: 600; }
/* Значок пункта — тихим тоном, подпись остаётся главной; опасное — красным
   вместе со значком (меню файла диска, аудит 30.09.2026) */
.menurow__ic { flex: none; display: inline-flex; color: var(--ink-3); }
.menupop .menurow:has(.menurow__ic) { gap: var(--s-2); }
.menupop .menurow.is-danger, .menupop .menurow.is-danger .menurow__ic { color: var(--late-fg); }
.menupop__sep { height: 1px; background: var(--border); margin: var(--s-1) 0; }
.btn.is-open { background: var(--surface-3); }

/* Разделитель групп в панели инструментов: он объясняет, что кнопки рядом
   делают разное, дешевле любой подписи */
.bar__sep { width: 1px; align-self: stretch; margin: var(--s-1) var(--s-1); background: var(--border); flex: none; }

@media (max-width: 760px) {
  .topbar__menu { display: inline-flex; }
  .topbar__user .btn { display: none; }        /* «Выйти» переехало в меню */
  .modal { max-height: calc(100dvh - 32px); }
  .modal__body { max-height: 66dvh; overflow: auto; -webkit-overflow-scrolling: touch; }
  .select--sm { min-width: 140px; }
}

/* ── ERP: проекты, отпуска, лёгкая версия ─────────────────────────────────── */

/* Полоса готовности на карточке доски в проекте */
.progressline {
  height: 4px; border-radius: var(--radius-sm); background: var(--surface-2);
  margin: var(--s-2) 0 var(--s-05); overflow: hidden;
}
.progressline__fill { height: 100%; background: var(--ok); border-radius: var(--radius-sm); }


/* Строка исполнителя в настройках лёгкой версии */
.perfrow { display: flex; gap: var(--s-2); align-items: center; margin-bottom: var(--s-2); flex-wrap: wrap; }
.perfrow .input { flex: 1; min-width: 150px; }

/* ── Боковая навигация ───────────────────────────────────────────────────── */
/* Инструменты слева и всегда на виду: человек не ищет, куда нажать, а видит
   весь набор сразу — как в Basecamp. Топбар остаётся под поиск и профиль. */

.shell { display: flex; flex: 1; min-height: 0; }

/* Разделы строкой в шапке. Полоса внизу (.nav) — только для телефона, на
   компьютере её нет: те же пять кнопок дважды на экране не нужны. */
.topnav { display: flex; align-items: center; gap: var(--s-05); min-width: 0; }
/* Орган управления — --t-sm и 500, как кнопка, сегмент, поиск и метки
   (макет: .topnav, .btn, .seg, .chip, .search — всё 12,5). До сверки
   с ТЗ (28 сентября 2026) полоса и кнопки были 14 рядом с сегментом
   и поиском в 12,5 на той же строке. */
.topnav .navitem { width: auto; padding: var(--s-2) var(--s-3); font-size: var(--t-sm);
  /* Зазор 12px был рассчитан на значок перед подписью; в верхней полосе значка
     нет, и между словом и кружком счётчика висела дыра (владелец, 30.09.2026) */
  gap: var(--s-1); }
.topnav .navitem__icon { display: none; }
.nav { display: none; }

/* Боковая колонка — контекст, а не разделы: список проектов и тот, где мы.

   Выравнивание идёт по тексту, а не по подложке строки. Подложка — то, что
   видно при наведении, — на общей линии стоять не должна: она шире текста
   на свои поля и уводит сами названия вправо. Раньше на линии логотипа
   (24, поле шапки) стоял её край, а текст уезжал на 36; теперь на линии
   логотипа текст, а подложка торчит левее, на 12. Названиям проектов
   достались освободившиеся 12 точек ширины — в узкой колонке это строка
   переноса. */
.side {
  width: var(--side-w); flex: none; display: flex; flex-direction: column; gap: var(--s-1);
  padding: var(--s-2) var(--s-3) var(--s-4) var(--s-3); overflow-y: auto;
  transition: width var(--fast);
}
/* Складка колонки: знак в строке заголовка, у правого края — у той границы,
   которую он и двигает. Своей строкой он отодвигал «Проекты» вниз, и над
   списком висело пустое поле. */
.side__fold {
  flex: none; width: 26px; height: 26px; margin-right: calc(-1 * var(--s-2));
  display: grid; place-items: center;
  border: none; border-radius: var(--radius-sm); background: none;
  color: var(--text-faint); cursor: pointer;
  transition: background var(--fast), color var(--fast);
}
.side__fold:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }
.side__fold.is-folded .ic { transform: rotate(180deg); }
/* Свёрнутая колонка — полоса со знаком, а не пустое место: колонка,
   пропавшая без следа, не сообщает, чем её вернуть.

   Ширина полосы ровно 24 точки — там, где стояли названия проектов
   (поле колонки 12 плюс поле строки 12). Край полотна встаёт на ту же
   вертикаль, что и текст в развёрнутой колонке, и логотип над ним:
   складка двигает содержимое, но не сбивает общую линию приложения. */
.side.is-folded, .side--bare {
  width: calc(var(--s-3) * 2); padding-left: 0; padding-right: 0;
}
/* Колонки нет — нет и складки: складывать нечего. Полоса остаётся,
   чтобы край полотна стоял на общей вертикали приложения. */
.side--bare { overflow: hidden; }
/* От свёрнутой колонки остаётся строка заголовка, а от неё — одна складка:
   сам заголовок в 24 точки не поместится, а знак поместится. */
.side.is-folded > *:not(.side__head) { display: none; }
.side.is-folded .side__head { padding: 0; }
.side.is-folded .side__head > *:not(.side__fold) { display: none; }
.side.is-folded .side__fold {
  width: calc(var(--s-3) * 2); height: calc(var(--s-3) * 2); margin-right: 0;
}
/* Поле здесь равно полю строки проекта: заголовок колонки и названия под ним
   набраны текстом и стоят на одной вертикали */
.side__head { display: flex; align-items: center; gap: var(--s-2); padding: 0 var(--s-3); }
.side__title {
  flex: 1; font-size: var(--t-2xs); font-weight: 500; letter-spacing: .08em;
  text-transform: uppercase; font-family: var(--mono); color: var(--text-faint); padding: var(--s-2) 0;
}
.side__list { display: flex; flex-direction: column; gap: 1px; }
.siderow {
  display: flex; align-items: center; gap: var(--s-2); width: 100%;
  padding: var(--s-2) var(--s-3); border: none; border-radius: var(--radius); cursor: pointer;
  background: none; color: var(--text-dim); font: inherit; font-size: var(--t-sm);
  text-align: left; transition: background var(--fast), color var(--fast);
}
.siderow:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }
.siderow.is-active {
  background: var(--surface); color: var(--text); font-weight: 600; box-shadow: var(--shadow-xs);
}
/* Разделы открытого проекта: те же строки, только с отступом и тише —
   это его внутренности, а не соседи по списку. Полоски готовности у них
   нет: раздел не «сделан на 40%». */
.siderow--sub {
  padding-left: var(--s-5); font-size: var(--t-sm); color: var(--text-faint);
  min-height: 30px;
}
/* Открытый раздел помечен чертой слева, а не той же приподнятой пилюлей,
   что и проект над ним. Пилюля означает «вот где вы» на верхнем уровне;
   когда она стояла и на проекте, и на его разделе, две одинаковые заливки
   подряд читались как два равных пункта, и было непонятно, что во что
   вложено. Черта говорит то же самое, но тише и на своём уровне. */
.siderow--sub.is-active {
  font-weight: 500; color: var(--text); background: none; box-shadow: none;
  position: relative;
}
.siderow--sub.is-active::before {
  content: ''; position: absolute; left: var(--s-3); top: 6px; bottom: 6px;
  width: 2px; border-radius: 1px; background: var(--accent);
}
.siderow--sub:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.siderow__main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.siderow__name {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere; line-height: 1.25;
}
.siderow__prog { height: 2px; border-radius: var(--radius-full); background: var(--border); overflow: hidden; }
/* У общего проекта компании это не шкала, а просто черта: тише обычной,
   чтобы её не читали как «ничего не сделано» */
.siderow__prog.is-plain { background: var(--border); opacity: .55; }
.siderow__done { display: block; height: 100%; background: var(--ok); border-radius: inherit; }
/* Красный кружок у проекта — сколько в нём задач, которые человека
   касаются и которых он ещё не открывал.

   Просрочки здесь нет и не было с тех пор, как её убрали: красное число
   у названия читается как «непрочитанное», что бы в него ни клали, — и
   когда там стояла просрочка, читали именно так. Теперь оно и значит
   непросмотренное, а просрочка помечена огоньком на карточках задач,
   то есть там, где с ней и работают. */
.siderow > .badge { flex: none; }
/* Нить внутри проекта: этап и задача, на которой мы стоим. Волосяная линия
   слева показывает, что это ветка активной строки, а не соседний проект */
.sidetrail {
  display: flex; flex-direction: column; gap: 1px;
  margin: var(--s-1) 0 var(--s-2) calc(var(--s-3) + var(--s-1));
  border-left: 1px solid var(--border);
}
.sidetrail__row {
  border: none; background: none; cursor: pointer; text-align: left; font: inherit;
  font-size: var(--t-xs); color: var(--text-faint); border-radius: var(--radius-sm);
  padding: var(--s-1) var(--s-2);
  padding-left: calc(var(--s-3) + var(--trail-depth, 0) * 10px);
  transition: background var(--fast), color var(--fast);
}
.sidetrail__row:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text-dim); }
.sidetrail__name {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere; line-height: 1.3;
}
/* Та, на которой стоим: курсора-руки нет — идти некуда, мы уже здесь */
.sidetrail__row.is-here { color: var(--text); font-weight: 600; cursor: default; }
.sidetrail__row.is-here:hover:where([data-hover="mouse"] *) { background: none; color: var(--text); }
.sidetrail__row--root { color: var(--text-dim); }

/* Узкий экран: контекст уступает место содержимому */
.side__spacer { flex: 1; min-height: var(--s-5); }
.roundbtn .badge { position: absolute; top: -2px; right: -2px; }
/* Точка «внутри есть новое» — на гамбургере и на «Ещё» телефона, за
   которыми спрятаны разделы со счётчиками (аудит 30.09.2026) */
.navdot {
  position: absolute; top: 0; right: 0; width: 8px; height: 8px;
  border-radius: var(--radius-full); background: var(--critical);
  box-shadow: 0 0 0 2px var(--surface); pointer-events: none;
}
.roundbtn--menu { position: relative; }
.roundbtn--menu .navdot { top: 4px; right: 4px; }
.navitem--more .navitem__icon { position: relative; }
/* Ячейка значка во всю ширину вкладки — точку ставим от середины, у значка */
.navitem--more .navitem__icon .navdot { top: var(--s-1); right: auto; left: calc(50% + var(--s-2)); }
.menurow__badge { flex: none; margin-left: var(--s-2); }

@media (max-width: 1100px) {
  .side { display: none; }
  /* Колонки нет — выравнивать не подо что, логотип занимает своё */
  .topbar__brand { flex: none; }
}
.navitem {
  display: flex; align-items: center; gap: var(--s-3); width: 100%;
  padding: var(--s-2) var(--s-3); border: none; border-radius: var(--radius); cursor: pointer;
  background: none; color: var(--text-dim); font-size: var(--t-base); font-weight: 500;
  text-align: left; font-family: inherit;
  transition: background var(--fast), color var(--fast), box-shadow var(--fast);
}
.navitem:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }
/* Внешний раздел («Генерация») — ссылка, а не кнопка: без подчёркивания, в остальном тот же пункт */
a.navitem { text-decoration: none; box-sizing: border-box; }
/* Выбранный раздел приподнят карточкой того же цвета, что и полотно справа:
   видно, что содержимое — продолжение этой строки, а не соседняя колонка */
.navitem.is-active {
  background: var(--surface); color: var(--text); font-weight: 600;
  box-shadow: var(--shadow-xs);
}
.navitem__icon { width: 17px; text-align: center; flex: none; font-size: var(--t-md); }
.navitem__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.navitem .badge { flex: none; }

/* Три круглые кнопки в шапке и внизу колонки: поиск, уведомления, аватарка —
   и тема, настройки, админка. Одинаковый размер и форма: это один ряд
   инструментов, а не набор разных вещей. */
.roundbtn {
  width: 36px; height: 36px; flex: none; display: grid; place-items: center;
  border: none; border-radius: 50%; background: var(--surface-2); color: var(--text-dim);
  cursor: pointer; font-size: var(--t-md); font-family: inherit; position: relative;
  transition: background var(--fast), color var(--fast);
}
.roundbtn:hover:where([data-hover="mouse"] *) { background: var(--surface-3, var(--surface)); color: var(--text); }
.roundbtn.is-open, .roundbtn.is-active { background: var(--surface); color: var(--text); box-shadow: var(--shadow-xs); }
a.roundbtn { text-decoration: none; }
.roundbtn--sm { width: 32px; height: 32px; font-size: var(--t-base); }

/* Аватарка — крайняя справа и без подложки: это лицо, а не кнопка */
.profilebtn {
  padding: 0; border: none; background: none; cursor: pointer; flex: none;
  border-radius: 50%; line-height: 0;
}
.profilebtn.is-open { box-shadow: 0 0 0 2px var(--accent); }
/* Портрет — ростом с соседние круглые кнопки (36): мелкий, 28, он читался
   меньше колокольчика и лиц на доске (владелец, 28 сентября 2026) */
/* 30.09.2026: портрет 36 с кольцом 1px снаружи выходил 38 и, залитый фото
   до края, читался крупнее колокольчика — владелец просил «такой же». Фото
   32, кольцо внутрь: на глаз он теперь ростом с круглую кнопку 36 */
.topbar .profilebtn .avatar { width: 32px; height: 32px; font-size: var(--t-sm); box-shadow: inset 0 0 0 1px var(--line); }
/* Круглые кнопки — плашки, а не текст, и левым краем встают на линию плашек,
   то есть на край подложки строки, а не на линию названий */
.side__tools { display: flex; align-items: center; gap: var(--s-1); padding: var(--s-2) var(--s-2) 0 0; }

/* Поиск в шапке: узкая кнопка, разворачивается в палитру по ⌘K */
.searchbtn {
  display: flex; align-items: center; gap: var(--s-2); height: 34px; padding: 0 var(--s-3);
  border: 1px solid var(--border); border-radius: var(--radius-full); background: var(--surface-2);
  color: var(--text-dim); font-size: var(--t-base); cursor: pointer; min-width: 210px;
  font-family: inherit; transition: background var(--fast), border-color var(--fast);
}
.searchbtn:hover:where([data-hover="mouse"] *) { background: var(--surface); border-color: var(--border-strong); }
.searchbtn kbd {
  margin-left: auto; font-size: var(--t-2xs); font-family: inherit; color: var(--text-faint);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: var(--s-05) var(--s-2); line-height: 1;
}

/* ── Палитра поиска ──────────────────────────────────────────────────────── */

.palette {
  /* Шире: на широком экране окно занимало треть, а длинные названия при этом
     обрезались — место было, им просто не пользовались */
  width: min(720px, calc(100vw - 28px)); max-height: 70vh;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column; overflow: hidden;
}
/* Отбор по виду и подсказка клавиш: стрелки работали, но узнать об этом
   было неоткуда */
.palette__kinds {
  display: flex; gap: var(--s-1); padding: var(--s-2) var(--s-3);
  border-bottom: 1px solid var(--border); flex-wrap: wrap;
}
.palette__kind {
  border: none; background: none; cursor: pointer; font: inherit;
  font-size: var(--t-xs); color: var(--text-dim);
  padding: var(--s-1) var(--s-2); border-radius: var(--radius-sm);
}
.palette__kind:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }
.palette__kind.is-active { background: var(--accent-soft); color: var(--accent-fg); font-weight: 600; }

.palette__hint {
  display: flex; gap: var(--s-4); padding: var(--s-2) var(--s-4);
  border-top: 1px solid var(--border); background: var(--surface-2);
  font-size: var(--t-2xs); color: var(--text-faint); flex-wrap: wrap;
}
.palette__hint kbd {
  font-family: var(--mono); font-size: 10px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 0 4px; margin-right: 2px;
}

/* Найденное подсвечено: иначе совпадение ищут в каждой строке заново */
.palette__hit {
  background: var(--warn-soft); color: inherit; border-radius: 2px;
  padding: 0 1px; font-weight: 600;
}
/* Проект различает восемь одинаковых названий — он не подпись, а метка */
.palette__sub {
  flex: none; font-size: var(--t-xs); color: var(--text-dim);
  background: var(--surface-2); border-radius: var(--radius-sm);
  padding: 1px var(--s-2); max-width: 40%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.palette__input {
  height: 50px; border: none; border-bottom: 1px solid var(--border);
  background: none; color: var(--text); font-size: var(--t-md); padding: 0 var(--s-4);
  outline: none; font-family: inherit; width: 100%;
}
.palette__list { overflow: auto; padding: var(--s-2); }
.palette__group {
  font-size: var(--t-xs); color: var(--text-faint); text-transform: uppercase; font-family: var(--mono); font-weight: 500;
  letter-spacing: .08em; padding: var(--s-2) var(--s-3) var(--s-1);
}
.palette__row {
  display: flex; align-items: center; gap: var(--s-2); width: 100%;
  padding: var(--s-2) var(--s-3); border: none; border-radius: var(--radius-sm); background: none;
  color: var(--text); font-size: var(--t-base); cursor: pointer; text-align: left;
  font-family: inherit;
}
.palette__row.is-cursor { background: var(--accent-soft); color: var(--accent-fg); }
.palette__main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
/* Строка поиска: срок и статус под названием — видно, что с задачей, не открывая */
.palette__state { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.palette__state .note { font-size: var(--t-xs); }
.palette__state .note.is-done { text-decoration: line-through; opacity: .7; }
.palette__row small { color: var(--text-faint); font-size: var(--t-sm); margin-left: auto; flex: none; }
.palette__icon { width: 16px; display: inline-flex; justify-content: center; flex: none; opacity: .7; }
.palette__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── Главная: сегодня ────────────────────────────────────────────────────── */

/* Между «Моими задачами», «Поручил» и «Наблюдаю» было 48 точек — ступень,
   которой отбивают разделы документа, а это соседние списки одного экрана.
   Вдвое меньше: разница между ними и так видна заголовком. */
.home { display: flex; flex-direction: column; gap: var(--s-5); }
/* Колонок на главной ровно две: работа и заметки. Раньше короткие списки под
   «Моей работой» вставали ещё одной парой, и экран разрезался на три полосы. */
.hblock__head {
  /* По центру, а не по базовой линии: у кнопок со значками базовой линии нет,
     и переключатель вида съезжал вверх относительно соседей.
     Высота задана жёстко и совпадает с высотой шапки правой колонки —
     иначе «Моя работа» и «Объявления» стоят на разных базовых линиях:
     слева заголовок центрируется в полосе с кнопками, справа — в полосе
     из одного текста. */
  display: flex; align-items: center; gap: var(--s-2) var(--s-3);
  margin-bottom: var(--s-5);
  min-height: 30px; flex-wrap: wrap;
}
/* Органы управления списком — одной группой: по отдельности последняя кнопка
   срывалась на вторую строку и висела там сиротой */
.hblock__tools { display: flex; align-items: center; gap: var(--s-2); flex: none; }
/* Пара кнопок-отборов. Воздух между ними задан здесь: правило ниже даёт его
   только прямым детям заголовка, а эта пара лежит внутри группы инструментов,
   и кнопки стояли впритык, читаясь одной длинной клавишей. */
.hblock__otbor { display: inline-flex; align-items: center; gap: var(--s-2); }

/* Порядок, группировка и «…» — три отдельные кнопки, между ними нужен воздух */
.hblock__head > span { display: inline-flex; align-items: center; gap: var(--s-2); }
.hblock__head > .spacer { flex: 1 1 auto; min-width: var(--s-3); }
/* Треугольник у кнопки-списка: видно, что по ней есть выбор */
.menulabel { display: inline-flex; align-items: center; gap: var(--s-2); }
/* Подпись бывает двух длин — «По сроку» и «Срок», — и показывается одна.
   Какая, решает измерение шапки, а не порог по ширине окна: порог читался
   один раз при отрисовке и с тех пор врал, а помещается строка или нет,
   зависит ещё и от длины заголовка, от счётчика просрочки и от того,
   доехал ли шрифт. Тот же приём, что у переключателя разделов доски. */
.menulabel__short { display: none; }
.hblock__head.is-tight .menulabel__full { display: none; }
.hblock__head.is-tight .menulabel__short { display: inline; }
/* Шапка меряется на мгновение: перенос запрещаем и смотрим, вылезает ли
   содержимое за ширину. Видимого мигания нет — между добавлением класса
   и снятием браузер не перерисовывает. */
.hblock__head.is-measuring { flex-wrap: nowrap; overflow: hidden; }
/* Треугольник был в девять точек — на экране читался как пылинка, и понять,
   что у кнопки есть выбор, было нельзя */
/* Стрелка выпадения — значок i-chevron-down набора, маской: буква «▾»
   в каждом шрифте своего роста и веса и в ряд со значками не вставала.
   Текст «▾» в разметке остаётся — для чтения с экрана, но не рисуется. */
.caret, .fold > summary::before {
  display: inline-block; flex: none; width: var(--s-3); height: var(--s-3);
  font-size: 0; line-height: 0; opacity: .7; vertical-align: middle;
  background: currentColor;
  -webkit-mask: var(--chevron) center / contain no-repeat;
  mask: var(--chevron) center / contain no-repeat;
}
/* Стрелка, вложенная в подпись («Любой сегмент ⌄», «Сортировка: по сроку ⌄»),
   не прилипает к последней букве: зазора flex-ряда внутри подписи нет */
span > .caret:last-child { margin-left: var(--s-1); }
:root {
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}
/* Заголовок не сжимается: иначе на телефоне «Моя работа» ломается на две
   строки, чтобы уступить место счётчику и ссылке. Уступает как раз ссылка. */
.hblock__head h2 { flex: none; }
/* Заголовок блока — обычный заголовок, а не мелкая подпись вразрядку.
   Прописные в 11px подряд над каждым разделом читаются как оформление, а не
   как навигация: глаз их пропускает и внутри страницы теряется структура. */
.hblock__head h2 {
  font-size: var(--t-md); font-weight: 600; color: var(--text);
  letter-spacing: -.01em;
}
.hblock__head .chip { flex: none; }
/* Сколько всего задач и сколько из них горит — тихой строкой у заголовка:
   по восьми карточкам не понять, все они или это верхушка тридцати */
/* Счётчик и просрочка — одна тихая строка одного кегля. Раньше это были три
   разных размера подряд: заголовок, подпись и красная плашка мельче подписи,
   и шапка читалась как набор разнородных наклеек. */
.hblock__count {
  display: inline-flex; align-items: baseline; gap: var(--s-3); flex: none;
  font-size: var(--t-sm); color: var(--text-faint);
}
.hblock__count .is-overdue { color: var(--late-fg); font-weight: 600; }
/* Отметка «смотрю глазами сотрудника»: без неё непонятно, почему половина
   кнопок пропала. Нажатие возвращает свои права. */
.chip--asuser { cursor: pointer; border: none; font: inherit; font-weight: 600; }

/* Значок в кнопке: буква «плюс» смотрелась мельче самой кнопки */
.plusicon { display: inline-grid; place-items: center; }
.plusicon svg { display: block; }
.hblock__more {
  margin-left: auto; font-size: var(--t-sm); color: var(--text-dim);
  background: none; border: none; cursor: pointer; font-family: inherit;
  font-weight: 500; transition: color var(--fast);
}
.hblock__more:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); }

.hrow {
  display: flex; align-items: center; gap: var(--s-3); width: 100%;
  padding: var(--s-3) var(--s-3); border: none; border-bottom: 1px solid var(--border);
  background: none; color: var(--text); font-size: var(--t-base); cursor: pointer;
  text-align: left; font-family: inherit;
  border-radius: var(--radius);
}
.hrow:last-child { border-bottom: none; }
.hrow:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.hrow:first-child { border-top-left-radius: var(--radius-lg); border-top-right-radius: var(--radius-lg); }
.hrow__dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
/* Название задачи важнее пути к ней: сжимаем путь, а не имя */
.hrow__name { flex: 0 1 auto; min-width: 90px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hrow__where {
  color: var(--text-faint); font-size: var(--t-sm); flex: 1 1 auto;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hrow__right { margin-left: auto; flex: none; font-size: var(--t-sm); color: var(--text-dim); }
.hrow__right.is-over { color: var(--late-fg); }
.hrow__acts { margin-left: auto; display: flex; gap: var(--s-2); flex: none; }

/* Строка, по которой принимают решение, не обрезается: утверждать отпуск,
   не видя ни имени целиком, ни дат, нельзя. Переносится вместо многоточия. */
.hrow--decision { flex-wrap: wrap; align-items: baseline; }
.hrow--decision .hrow__name,
.hrow--decision .hrow__where {
  overflow: visible; text-overflow: clip; white-space: normal;
}
.hrow--decision .hrow__name { flex: 0 1 auto; font-weight: 500; }
.hrow--decision .hrow__where { flex: 0 1 auto; font-variant-numeric: tabular-nums; }

/* Лента: кто что сделал */
.feed { display: flex; flex-direction: column; gap: var(--s-05); }
/* Заголовок дня: без него вчерашнее и сегодняшнее выглядели случившимися
   разом — у всех строк только время, без даты */
.feed__day {
  font-size: var(--t-2xs); text-transform: uppercase; font-family: var(--mono); letter-spacing: .08em;
  font-weight: 500; color: var(--text-faint);
  margin: var(--s-3) 0 var(--s-1); padding: 0 var(--s-05);
}
.feed__day:first-child { margin-top: 0; }
.feedrow {
  display: flex; align-items: center; gap: var(--s-2); padding: var(--s-2) var(--s-05);
  font-size: var(--t-base); color: var(--text-dim); cursor: pointer;
  background: none; border: none; text-align: left; width: 100%; font-family: inherit;
}
.feedrow:hover:where([data-hover="mouse"] *) { color: var(--text); }
.feedrow__ava {
  width: 24px; height: 24px; border-radius: 50%; flex: none;
  display: grid; place-items: center; overflow: hidden;
  background: var(--surface-2); color: var(--text-dim);
}
.feedrow__ava img { width: 100%; height: 100%; object-fit: cover; object-position: center center; display: block; }
.feedrow__text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.feedrow__time { flex: none; color: var(--text-faint); font-size: var(--t-sm); }

/* Полоса прогресса проекта */
.prog {
  height: 6px; border-radius: var(--radius-full); background: var(--surface-3);
  overflow: hidden; display: flex; flex: none;
}
.prog__done { background: var(--ok); flex: none; transition: width .3s var(--ease); }
.prog__over { background: var(--critical); flex: none; }
.projrow {
  display: flex; align-items: center; gap: var(--s-3); width: 100%;
  padding: var(--s-3) var(--s-3); border: none; border-bottom: 1px solid var(--border);
  background: none; color: var(--text); font-size: var(--t-base); cursor: pointer;
  text-align: left; font-family: inherit;
  border-radius: var(--radius);
}
.projrow:last-child { border-bottom: none; }
.projrow:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.projrow:last-child { border-bottom: none; }
.projrow__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.projrow .prog { width: 84px; }

/* Хлебные крошки на доске и в проекте */
.crumbs {
  display: flex; align-items: center; gap: var(--s-1); font-size: var(--t-sm);
  color: var(--text-faint); margin-bottom: var(--s-2); flex-wrap: wrap;
}
.crumbs button {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--text-dim); font-size: inherit; font-family: inherit;
}
.crumbs button:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); text-decoration: underline; }
.crumbs__sep { opacity: .5; }
.crumbs__cur { color: var(--text-dim); }

/* Уведомления, сгруппированные по дню — см. .modal--pop выше */

/* Узкий экран: полоса разделов внизу ужимается до значков.

   Правила писались, когда навигация была колонкой слева, и адресовались
   всякому `.navitem` — а он теперь и в шапке. Между 761 и 900 точками
   выходило так: подписи в шапке спрятаны этим блоком, значки — правилом
   `.topnav .navitem__icon`, и в полосе стояли восемь пустых квадратиков.
   Поэтому здесь всё привязано к `.nav`: это про нижнюю полосу и только
   про неё. Шапка на тесном экране складывается в гамбургер — см. `is-tight`. */
@media (max-width: 900px) {
  .nav { width: 56px; padding: var(--s-3) var(--s-2); }
  .nav .navitem { justify-content: center; padding: var(--s-2) 0; position: relative; }
  .nav .navitem__label { display: none; }
  .nav .navitem .badge { position: absolute; transform: translate(13px, -11px); }
  .searchbtn { min-width: 0; }
  .searchbtn span, .searchbtn kbd { display: none; }
}

@media (max-width: 760px) {
  /* На телефоне навигация уезжает вниз — большим пальцем удобнее */
  .shell { flex-direction: column; }
  /* На телефоне разделы — полосой внизу, под большим пальцем; строка в шапке
     на 375px не помещается и уводит бренд с поиском за край */
  /* Высота полосы объявлена числом и стоит здесь одна на всех.
     Раньше высота получалась сама — из значка, подписи и полей, — а место
     под неё на странице было забито отдельным числом. Сошлось 82 против 78,
     и две строки внизу проекта навсегда остались под полосой: долистать
     до конца можно, а достать их нельзя. Теперь оба места считаются
     от одной величины и разойтись не могут. */
  /* На корне, а не на .shell: меню Ватмана лежит в body, вне оболочки, и
     листом снизу накрывало полосу разделов (24 сентября 2026) */
  :root, .shell { --nav-h: 82px; }
  :root { --в-низ-меню: calc(var(--nav-h) + env(safe-area-inset-bottom) + var(--s-2)); }
  .nav {
    display: flex; width: 100%; flex-direction: row; border-right: none;
    border-top: 1px solid var(--border); padding: var(--s-2) var(--s-1);
    background: var(--surface); flex: none;
    gap: 0; overflow-x: auto;
    height: calc(var(--nav-h) + env(safe-area-inset-bottom));
    padding-bottom: calc(6px + env(safe-area-inset-bottom));
  }
  .topnav { display: none; }
  .nav .navitem.is-active { box-shadow: none; background: var(--accent-soft); color: var(--accent-fg); }
  .nav .navitem { flex: 1; flex-direction: column; gap: var(--s-1); padding: var(--s-2) var(--s-05); font-size: var(--t-2xs); }
  .nav .navitem__icon { font-size: var(--t-lg); }
  /* Через `.nav`, а не голым классом: блок на 900 точках прячет подписи
     тем же путём, и голое правило проиграло бы ему весом — на телефоне
     под значками осталась бы пустота. */
  .nav .navitem__label { display: block; font-size: var(--t-2xs); text-align: center; }
  .nav .navitem .badge { position: absolute; transform: translate(12px, -4px); }
  /* Пятая вкладка «Ещё» — не переход, а меню, поэтому она кнопка, а не
     navitem: содержимое приходится обернуть, чтобы значок и подпись встали
     столбиком, как у соседей. Полоса не листается вбок — пять вкладок
     делят ширину поровну и всегда на месте. */
  .nav { overflow-x: visible; }
  .navitem--more { flex: 1; padding: var(--s-2) var(--s-05); }
  .navitem--more .navitem__in {
    display: flex; flex-direction: column; align-items: center; gap: var(--s-1);
  }
  /* Заголовок и правая часть делят первую строку, разделы уходят под них */
  .page__head-right { order: 2; }
  /* Правая часть шапки не шире экрана. У проекта в ней пять предметов —
     заметки, стройка, лица команды, отбор и «…», — и на 375 точках «…»
     уезжал за правый край, а страница начинала листаться вбок. Ужимается
     она за счёт лиц команды: их на телефоне три, и они наезжают друг
     на друга (см. teamButton), а крайний запас — обрезка ряда лиц. */
  .page__head-right { flex: 0 1 auto; min-width: 0; max-width: 100%; gap: var(--s-1); }
  .page__head-right .teambtn { min-width: 0; overflow: hidden; }
  /* Кнопка закреплённого на телефоне начинает вторую строку шапки, а не
     стоит за названием: отступ от названия ей там не нужен, а трёх точек
     не хватало, чтобы на 360 точках правая часть встала с ней в одну строку. */
  .page__head .zakrepbtn { margin-left: 0; }
  .teambtn .avatar:not(:first-child),
  .teambtn.is-dense .avatar:not(:first-child) { margin-left: calc(-1 * var(--s-3)); }

  /* На телефоне разделы уже внизу — вторые двери в них из шапки убираем:
     значок базы знаний повторял пункт «Ещё → База знаний», а меню аватарки
     повторяло всё «Ещё» целиком. Наверху остаются поиск и колокольчик —
     то, чего в полосе разделов нет. */
  .topbar .roundbtn--kb, .topbar .profilebtn, .topbar .roundbtn--ai, .topbar .roundbtn--zoom { display: none; }
  /* На телефоне остров не нужен: экран и так узкий, поля съедают содержимое */
  .main { order: 1; margin: 0; border: none; border-radius: 0; }
  .topbar { padding: 0 var(--s-3); height: 56px; }
  .palette { width: calc(100vw - 20px); max-height: 74vh; }
  /* На телефоне путь к задаче не помещается — остаётся имя и срок */
  .hrow__where { display: none; }
  .hrow { padding: var(--s-3) var(--s-3); gap: var(--s-2); }
  .hrow__name { flex: 1; }
  /* Строка решения — «отпуск такого-то, ждёт бухгалтера, оформить». На
     широком экране это одна строка; на телефоне она переносилась по частям,
     и каждая вставала своей строкой: кружок отдельно, имя отдельно, плашка
     отдельно, кнопки отдельно — четыре строки и две пустые полосы между
     ними. Собираем в столбец сами: имя, под ним даты с плашкой, снизу
     кнопки. Кружок в столбце не нужен вовсе — он метил строку в списке,
     а здесь строка одна. */
  .hrow--decision {
    display: grid; grid-template-columns: 1fr; gap: var(--s-1);
    align-items: start; padding: var(--s-3);
  }
  .hrow--decision .hrow__dot { display: none; }
  .hrow--decision .hrow__where { display: inline; }
  .hrow--decision .hrow__name { font-size: var(--t-base); }
  .hrow--decision .hrow__acts { margin: var(--s-1) 0 0; justify-content: flex-start; }
  /* Даты и плашка «ждёт бухгалтера» — одной строкой под именем */
  .hrow--decision .chip { justify-self: start; }

  /* Колонка по человеку — по содержимому, а не в 180 точек.

     Высота задана ради перетаскивания: пустая колонка должна быть мишенью,
     в которую можно попасть мышью. На телефоне не перетаскивают вовсе,
     а колонки идут одна под другой — и пустая занимала треть экрана
     надписью «Пусто». Три свободных человека — и до занятого не долистать. */
  .kcol__body { min-height: 0; }
  .kcol__empty { padding: var(--s-2) 0; }
  .kcol { min-width: 0; }
  /* Слева вровень с заголовком раздела: своё поле у строки сдвигало имя
     на дюжину точек вправо, и «Отпуска на оформлении» с «Виктор Шутка»
     стояли на разных вертикалях — на узком экране это видно сразу. */
  .hrow--decision { padding-left: 0; padding-right: 0; }

  /* Между работой и заметками — 24 точки вместо 48.

     На широком экране это два столбца рядом, и зазор между ними разводит
     их по горизонтали. На телефоне столбец один, и тот же зазор становится
     пустой полосой в полсотни точек поперёк экрана — между «Оформить»
     и «Объявлениями» висела дыра, за которой не видно, что там дальше. */
  /* Вес поднят нарочно: общее правило .homewrap объявлено ниже по файлу,
     и при равной силе побеждало бы оно. */
  .page--home .homewrap { gap: var(--s-5); }
  .projrow { padding: var(--s-3) var(--s-3); }
  .projrow .prog { width: 54px; }
}

/* Участник команды проекта */
.teamchip {
  display: flex; align-items: center; gap: var(--s-2);
  border: 1px solid var(--border); border-radius: var(--radius-full);
  padding: var(--s-1) var(--s-3) var(--s-1) var(--s-1); font-size: var(--t-sm);
}
.teamchip__x {
  border: none; background: none; cursor: pointer; padding: 0 var(--s-05);
  color: var(--text-faint); font-size: var(--t-sm); line-height: 1;
}
.teamchip__x:hover:where([data-hover="mouse"] *) { color: var(--late-fg); }

/* ── Служебное → Обновление ──────────────────────────────────────────────
   Журнал — как в терминале, но своим шрифтом: строки из четырёхсот точек
   не должны растягивать страницу, поэтому переносятся по любому знаку. */
.obn__btns { display: flex; gap: var(--s-2); flex-wrap: wrap; }
.obn__commit { display: flex; align-items: baseline; gap: var(--s-2); flex-wrap: wrap; }
.obn__state { margin-bottom: var(--s-3); display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
/* «Служебное → Модули»: галочка, имя с описанием, что требует, почему
   выключен. Выключенная строка тише — видно, что есть, но не работает. */
.moduli td { vertical-align: top; }
.moduli__pick { width: 1%; }
.moduli__name { font-weight: 500; }
.moduli tr.is-off .moduli__name { color: var(--text-dim); }
.moduli__warn { margin-top: var(--s-1); font-size: var(--t-sm); color: var(--warn-fg); }
.obn__log {
  margin: 0; padding: var(--s-3); max-height: 420px; overflow: auto;
  font-family: var(--mono); font-size: var(--t-mono); line-height: 1.5;
  white-space: pre-wrap; word-break: break-all;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--text-dim);
}
.obn__badge {
  display: inline-block; padding: var(--s-05) var(--s-2); border-radius: var(--radius-full);
  font-size: var(--t-2xs); font-weight: 600; background: var(--surface); color: var(--text);
}
.obn__badge--идёт { background: var(--warn-soft); color: var(--warn-fg); }
.obn__badge--готово { background: var(--ok-soft); color: var(--ok-fg); }
.obn__badge--ошибка, .obn__badge--брошено { background: var(--critical-soft); color: var(--late-fg); }

/* Полоса нагрузки по минутам на вкладке «Сервер» */
.spark {
  display: flex; align-items: flex-end; gap: var(--s-05);
  height: 90px; padding: var(--s-1) 0; overflow: hidden;
}
.spark__bar { flex: 1; min-width: 2px; background: var(--accent-soft); border-radius: 1px; }
.spark__bar.is-slow { background: var(--warn); }
.spark__bar.is-error { background: var(--critical); }

/* ── Переключатель вида задач: канбан / гант / список ────────────────────── */

.viewseg button {
  display: grid; place-items: center; width: 34px;
}
.viewseg__icon { display: grid; place-items: center; }
.viewseg__icon svg { display: block; }

/* ── Метки на карточках задач: проект, этаж, помещение, тип ──────────────── */

.kcard__tags { display: flex; flex-wrap: wrap; gap: var(--s-1); margin-top: var(--s-2); }
/* Приглашений «+ Тип», «+ Этаж», «+ Помещение» на карточке нет — ни в покое,
   ни на наведении (владелец, 30 сентября 2026: «карточки прыгают»).

   С 4 сентября они приходили на наведении и раздвигали карточку: ряд,
   которого не было, вставал под названием, карточка росла, соседи в сетке
   съезжали — мышь шла по списку, и карточки дёргались одна за другой.
   Наведение на карточке меняет только тень и рамку. Тип, этаж и помещение
   ставят в самой задаче: там они стоят своей строкой и никуда не прыгают. */
.kcard .ktag--pusto, .kcard__tags--pusto { display: none; }
/* Пустое место вместо метки — приглашение его заполнить: пунктирная плашка
   «+ Проект» или «+ Этаж» прямо на карточке */
.ktag--put {
  border: 1px dashed var(--border-strong); background: none; color: var(--text-faint);
  cursor: pointer; font: inherit; font-size: var(--t-2xs); line-height: 1;
  padding: var(--s-1) var(--s-2); border-radius: var(--radius-full);
}
.ktag--put:hover:where([data-hover="mouse"] *) { border-color: var(--accent); color: var(--accent-fg); background: var(--accent-soft); }
/* Ярлык задачи — проект, этаж, помещение, тип.
   
   Один вид на всё приложение: и в списке на главной, и на карточке в доске
   проекта. Пока он задавался в каждом месте своим, одна и та же метка
   выглядела в двух списках по-разному, и глаз каждый раз заново решал,
   одно ли это и то же.

   Тринадцать пикселей — середина между двумя размерами, которые тут были.
   Нажимаемый ярлык шёл пятнадцатью (см. `.ktag--act` ниже), ненажимаемый —
   двенадцатью, и в одном списке «170 Дом в Козино» выглядел крупно,
   а этажом ниже точно такой же — мелко. Пятнадцать — это кегль названия,
   с ним ярлык спорит за внимание; двенадцать на второй строке уже не
   читаются, а вглядываться в метку никто не станет.

   На две ступени мельче названия, и это главное в нём. Ярлык отвечает
   на вопрос «какая это задача», а название — на вопрос «что делать»;
   когда они одного веса, строка читается как два заголовка подряд,
   и взгляд спотыкается о метку раньше, чем о дело. */
.ktag {
  font-size: var(--t-xs); line-height: 1.4; padding: 2px var(--s-2);
  border-radius: var(--radius-full);
  background: var(--surface-2); color: var(--text-dim); white-space: nowrap;
  max-width: 190px; overflow: hidden; text-overflow: ellipsis;
}
/* Акцент на собственной мягкой заливке не дотягивал до порога: берём
   затемнённый вариант, цвет остаётся тем же по смыслу */
.ktag--project { background: var(--accent-soft); color: var(--accent-hover); font-weight: 600; }
/* «Без проекта» на карточке доски — тихо, без подложки: держит строку,
   чтобы название стояло вровень с соседями, но не спорит с плашками проектов */
.ktag--none { background: none; padding-left: 0; color: var(--ink-3); }
/* Этаж — той же заливкой, что помещение. Он стоял на --surface-3, самой
   тёмной ступени набора, и на карточке оказывался темнее всего остального:
   среди светлых меток одна тёмная читалась как выделенная, хотя этаж ничем
   не важнее помещения рядом. */
.ktag--floor { background: var(--surface-2); color: var(--text-dim); }
/* Зелёный в приложении означает «готово» — помещению он не принадлежит */
.ktag--room { background: var(--surface-2); color: var(--text-dim); }
/* Тип задачи — единственный ярлык, чей цвет задаёт человек: у каждого проекта
   свой набор типов и своя палитра. Отсюда и беда: цвет выбирают по вкусу,
   а читать его приходится тринадцатым кеглем на собственной бледной заливке.
   Измерение по всем шестнадцати темам дало 3,93 — ниже порога 4,5, при котором
   мелкий текст считается читаемым, и одинаково ниже везде.

   Цвет не подменяется: тип узнают именно по нему. Он подтягивается к тексту
   темы — в светлой темнеет, в тёмной светлеет, оставаясь тем же по тону.
   Заливка при этом чуть гуще: разводить их только цветом текста значило бы
   сильно менять оттенок, а так хватает малого сдвига с обеих сторон. */
.ktag--type {
  background: color-mix(in srgb, var(--ktag-color, #64748b) 18%, transparent);
  color: color-mix(in srgb, var(--ktag-color, #64748b) 58%, var(--text));
  font-weight: 600;
}

/* Сложность — справочная величина. Янтарным она кричала наравне с «Горит»,
   хотя ничего срочного не сообщает */

.kcard__prio {
  font-size: var(--t-2xs); line-height: 1; padding: var(--s-1) var(--s-2); border-radius: var(--radius-full); font-weight: 700;
  background: color-mix(in srgb, var(--prio-color, #e05555) 14%, transparent);
  color: var(--prio-color, #e05555);
}

/* Аватарка внутри кружка исполнителя */
/* Инициалы — рисунком во всю ширину кружка. Кегль здесь больше ничего не
   решает: буквы вписаны в систему координат SVG и уменьшаются вместе с ним.
   До этого они набирались текстом, кегль задавался в rem и про размер кружка
   не знал — на узком экране и при крупном системном шрифте две буквы вылезали
   за край заливки. */
.kcard__dot > svg, .avatar > svg, .tlist__ava > svg, .grow__dot > svg,
.feedrow__ava > svg { width: 100%; height: 100%; display: block; }
/* Кружок с фотографией: заливка и рамка убираются, снимок обрезается
   по кругу. Перечислены все места, где кружок бывает, — диаграмма в том
   числе: пока её не было в списке, фотография в ней ложилась квадратом
   поверх заливки. */
.kcard__dot.has-img, .avatar.has-img, .grow__dot.has-img {
  overflow: hidden; padding: 0;
}
.grow__dot.has-img { background: none; border-color: transparent; }
.kcard__dot img, .avatar img, .tlist__ava img, .grow__dot img {
  width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block;
}
.avatar--sm { width: 22px; height: 22px; font-size: var(--t-2xs); }
.avatar--big { width: 72px; height: 72px; font-size: var(--t-2xl); }
.avaprev { flex: none; }

/* ── Список задач таблицей ───────────────────────────────────────────────── */

.tlist { overflow-x: auto; }
.tlist__table { width: 100%; border-collapse: collapse; font-size: var(--t-base); }
.tlist__table th {
  text-align: left; font-size: var(--t-xs); font-weight: 500; color: var(--text-faint);
  text-transform: uppercase; font-family: var(--mono); letter-spacing: .06em;
  padding: var(--s-2) var(--s-3); border-bottom: 1px solid var(--border-strong);
  white-space: nowrap; position: sticky; top: 0; background: var(--bg); z-index: 1;
}
.tlist__table td {
  padding: var(--s-2) var(--s-3); border-bottom: 1px solid var(--border); vertical-align: middle;
  white-space: nowrap;
}
.tlist__row { cursor: pointer; }
.tlist__row:hover:where([data-hover="mouse"] *) td { background: var(--hover); }
.tlist__stage { cursor: pointer; background: var(--surface-2); }
.tlist__stage .tlist__name { font-weight: 600; }
.tlist__name { white-space: normal; min-width: 220px; }
/* Номер задачи в таблице. Моноширинный и приглушённый: колонка «№» стоит
   слева от имени, читают её глазами по вертикали — при одинаковой ширине
   знаков четыре кода подряд сравниваются мгновенно, а пропорциональным
   шрифтом их пришлось бы вычитывать. Цветом не спорит с названием: номер
   ищут, когда он нужен, а нужен он редко. */
.tlist__num {
  font-family: var(--mono); font-size: var(--t-mono); color: var(--text-faint);
  width: 1%; white-space: nowrap;
}
.tlist__dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  margin-right: var(--s-2); vertical-align: 1px;
}
.tlist__flag {
  font-size: var(--t-2xs); color: var(--warn-fg); border: 1px solid var(--warn);
  border-radius: var(--radius-full); padding: 0 var(--s-2); margin-left: var(--s-2);
}
.tlist__room { color: var(--text-dim); }
.tlist__status {
  font-size: var(--t-xs); padding: var(--s-1) var(--s-2); border-radius: var(--radius-full); font-weight: 600;
  background: color-mix(in srgb, var(--st-color, #94a3b8) 14%, transparent);
  color: var(--st-color, #94a3b8);
}
.tlist__date { color: var(--text-dim); }
.tlist__date.is-late { color: var(--late-fg); font-weight: 600; }
.tlist__who { display: flex; gap: var(--s-05); }
.tlist__ava {
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--t-2xs); font-weight: 600;
  background: var(--accent-soft); color: var(--accent-fg); border: 1px solid var(--border);
}
.tlist__ava.has-img { overflow: hidden; }
.tlist__more { font-size: var(--t-xs); color: var(--text-dim); align-self: center; }
.tlist__empty { text-align: center; color: var(--text-faint); padding: var(--s-5) 0 !important; }

/* Стили звёзд сложности убраны вместе с самой оценкой (27 августа 2026):
   .starrow, .starbtn, .kcard__stars, .tlist__stars, .tpill--stars. Поле
   в базе и ручка PATCH на месте — см. starsNode в kanban.js.

/* ── Закреплённое на странице проекта ────────────────────────────────────── */

/* Закреплённое: описание проекта, доска в Miro, папка с обмерами, договор,
   памятка команде. Стеной карточек это занимало 145px над задачами — ради
   ссылки с подписью. Теперь строка: значок, название, подпись — в одну высоту. */
/* Закреплённое: плашки одной ширины, но ряд не растягивается. Две штуки
   на всю строку выглядели как незаполненная таблица; теперь они просто
   стоят слева, а свободное место остаётся свободным. */
/* Ширина плашки убывает плавно, а не ступенями.
   Было: ровно 236px, а на 1100 точках — сразу 190. Между этими двумя
   значениями ряд не сужался вовсе, а копил пустое место справа, пока
   очередная плашка не срывалась на вторую строку целиком; на 1100 всё
   разом худело на четверть. Теперь ширина считается от ширины окна и едет
   вместе с ним — ряд теряет плашку не рывком, а по мере того, как ей
   действительно перестаёт хватать места.

   Не `1fr`: плашки не растягиваются на всю строку. Две штуки во всю ширину
   выглядели незаполненной таблицей — свободное место остаётся свободным. */
.pnotes {
  display: grid; gap: var(--s-2); margin-bottom: var(--s-4);
  grid-template-columns: repeat(auto-fill, minmax(0, clamp(168px, 19vw, 236px)));
  align-items: stretch;
}
/* «ещё 4» и «Свернуть» в ряду закреплённого и дедлайнов.
   Не кнопка и не плашка: тихая подпись, которую нажимают. Выглядеть как
   заметка ей нельзя — она не содержимое ряда, а способ показать остальное;
   выглядеть как кнопка тоже: тогда она перетянет внимание с того, ради
   чего ряд и стоит. */
.foldmore {
  background: none; border: none; padding: 0 var(--s-2); cursor: pointer;
  font: inherit; font-size: var(--t-xs); color: var(--text-faint);
  align-self: center; justify-self: start; white-space: nowrap;
  transition: color var(--fast);
}
.foldmore:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); }
.pnote {
  border-radius: var(--radius-lg); padding: var(--s-2) var(--s-3) var(--s-2) var(--s-2);
  font-size: var(--t-sm); border: 1px solid transparent;
  display: flex; align-items: flex-start; gap: var(--s-2);
  min-height: 34px; min-width: 0; width: 100%;
  transition: border-color var(--fast), box-shadow var(--fast);
}
/* Описание проекта: две строки текста без подписи над ними */
.pnote:hover:where([data-hover="mouse"] *) { border-color: rgba(0, 0, 0, .12); box-shadow: var(--shadow-xs); }
[data-scheme='dark'] .pnote:hover:where([data-hover="mouse"] *) { border-color: rgba(255, 255, 255, .16); }
.pnote__open {
  display: inline-flex; align-items: flex-start; gap: var(--s-2); min-width: 0;
  color: inherit; text-decoration: none; font: inherit; cursor: pointer;
  background: none; border: none; padding: 0; text-align: left;
}
.pnote__open:hover:where([data-hover="mouse"] *) { text-decoration: none; }
.pnote__text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
/* Текст идёт под заголовком и занимает до двух строк: в одну строку
   помещалась половина фразы, и закреплённое нельзя было прочитать */
.pnote__body {
  min-width: 0; overflow: hidden; font-size: var(--t-xs);
  line-height: 1.35; display: -webkit-box; -webkit-line-clamp: 2;
  -webkit-box-orient: vertical; overflow-wrap: anywhere;
}
/* Описание проекта — единственная плашка без заголовка: строка названия
   у неё свободна, значит текста помещается на строку больше. Правило стоит
   после общего намеренно: раньше оно шло выше и общие две строки его
   перебивали — описание обрезалось там, где обрезаться было незачем. */
.pnote__body--lead {
  -webkit-line-clamp: 3; opacity: 1; color: var(--text);
}
button.pnote { font: inherit; cursor: pointer; text-align: left; }
/* Описание проекта — такая же плашка, только шире: одной строкой над задачами
   его переставали замечать, а в настройках оно и вовсе никому не попадалось */
/* Заголовок «О проекте» набран как у остальных плашек: крупнее он читался
   как заголовок раздела, хотя это такая же закреплённая карточка */
.pnote--about { max-width: 460px; }
.pnote--about .pnote__title { font-size: var(--t-base); font-weight: 600; }
/* «+ Заметка» — по размеру слова, а не во всю плашку.
   Раньше она занимала полный столбец сетки и была самым крупным предметом
   в ряду: пустая пунктирная коробка шириной с заметку, но без единого слова
   о проекте. Чем уже экран, тем дороже это место — и тем очевиднее, что
   на нём полезнее стоять настоящей заметке.
   Теперь кнопка сжимается по содержимому и прижата к началу своего столбца,
   а когда ряд перестаёт помещаться в строку, `foldRow` прячет её первой:
   у неё больше нет `data-keep`. Действие при этом не пропадает — «Заметка»
   лежит в меню «…» в шапке проекта. */
.pnote--add {
  background: none; border: 1px dashed var(--border-strong); color: var(--text-dim);
  cursor: pointer; font-family: inherit; gap: var(--s-2);
  display: inline-flex; align-items: center; justify-content: center;
  width: auto; min-width: 0; justify-self: start; padding: 0 var(--s-3);
  white-space: nowrap;
}
/* Плюс стоял выше подписи: у знака своя высота строки, и он всплывал.
   Здесь он выровнен по центру кнопки, как и слово рядом. */
.pnote__plus { display: inline-flex; align-items: center; line-height: 1; font-size: var(--t-md); }
.pnote--add:hover:where([data-hover="mouse"] *) { border-color: var(--accent); color: var(--accent-fg); box-shadow: none; }
/* Цвет стикера считается от полотна темы, а не написан числом.
   Раньше светлая половина держала готовые пастели (#fef9c3, #dbeafe): они
   не знали ни одной из тем, лежали на «Бумаге» тем же холодным жёлтым, что
   и на «Дне», и в тихом интерфейсе горели ярче всего остального на экране.
   Тёмная половина уже считалась подмешиванием — теперь так считаются обе,
   и краски ровно столько, чтобы отличить одну бумажку от другой.

     --pnote-hue   краска стикера; светлым темам — насыщенная (500),
                   тёмным — светлая (400): на тёмном экране густая краска
                   уходит в грязь, на светлом бледная не читается;
     --pnote-tint  сколько краски в заливке — доля от полотна;
     --pnote-ink   сколько краски в подписи. На светлом подпись остаётся
                   тёмной и лишь окрашивается, на тёмном — наоборот. */
:root { --pnote-tint: 16%; --pnote-ink: 42%; }
[data-scheme='dark'] { --pnote-tint: 14%; --pnote-ink: 70%; }

.pnote--yellow, .pnote--lime, .pnote--green, .pnote--teal, .pnote--blue,
.pnote--purple, .pnote--pink, .pnote--red, .pnote--orange,
.stick--yellow, .stick--lime, .stick--green, .stick--teal, .stick--blue,
.stick--purple, .stick--pink, .stick--red, .stick--orange {
  background: color-mix(in srgb, var(--pnote-hue) var(--pnote-tint), var(--raised));
  color: color-mix(in srgb, var(--pnote-hue) var(--pnote-ink), var(--text));
}

.pnote--yellow, .stick--yellow { --pnote-hue: #eab308; }
.pnote--lime, .stick--lime   { --pnote-hue: #84cc16; }
.pnote--green, .stick--green  { --pnote-hue: #22c55e; }
.pnote--teal, .stick--teal   { --pnote-hue: #14b8a6; }
.pnote--blue, .stick--blue   { --pnote-hue: #3b82f6; }
.pnote--purple, .stick--purple { --pnote-hue: #8b5cf6; }
.pnote--pink, .stick--pink   { --pnote-hue: #ec4899; }
.pnote--red, .stick--red    { --pnote-hue: #ef4444; }
.pnote--orange, .stick--orange { --pnote-hue: #f97316; }

[data-scheme='dark'] .pnote--yellow, [data-scheme='dark'] .stick--yellow { --pnote-hue: #facc15; }
[data-scheme='dark'] .pnote--lime, [data-scheme='dark'] .stick--lime   { --pnote-hue: #a3e635; }
[data-scheme='dark'] .pnote--green, [data-scheme='dark'] .stick--green  { --pnote-hue: #4ade80; }
[data-scheme='dark'] .pnote--teal, [data-scheme='dark'] .stick--teal   { --pnote-hue: #2dd4bf; }
[data-scheme='dark'] .pnote--blue, [data-scheme='dark'] .stick--blue   { --pnote-hue: #60a5fa; }
[data-scheme='dark'] .pnote--purple, [data-scheme='dark'] .stick--purple { --pnote-hue: #a78bfa; }
[data-scheme='dark'] .pnote--pink, [data-scheme='dark'] .stick--pink   { --pnote-hue: #f472b6; }
[data-scheme='dark'] .pnote--red, [data-scheme='dark'] .stick--red    { --pnote-hue: #f87171; }
[data-scheme='dark'] .pnote--orange, [data-scheme='dark'] .stick--orange { --pnote-hue: #fb923c; }

/* Серый — не краска, а её отсутствие: берётся прямо у темы */
.pnote--gray, .stick--gray { background: var(--surface-2); color: var(--text); }
.pnote__head { display: inline-flex; align-items: center; gap: var(--s-2); min-width: 0; }
.pnote__title {
  font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  line-height: 1.3;
}
/* Закреплённое целиком — в окне чтения: переносы автора сохраняем */
.pinread { white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.55; }
.pnote__badge {
  width: 20px; height: 20px; border-radius: var(--radius-sm); flex: none;
  display: grid; place-items: center; font-size: var(--t-xs); font-weight: 700;
}
.pnote__badge--plain { background: transparent; font-size: var(--t-base); }
/* Место под карандаш и крестик отведено всегда, меняется только видимость:
   пока ширина росла по наведению, плашка раздвигалась под курсором и вся
   строка закреплённого перекладывалась заново — соседи прыгали, а последний
   мог уехать на другую строку. */
.pnote__act {
  border: none; background: none; cursor: pointer; color: inherit; flex: none;
  opacity: 0; width: 20px; height: 20px; overflow: hidden; display: inline-grid; place-items: center;
  font-size: var(--t-sm); padding: 0; border-radius: var(--radius-sm);
  transition: opacity var(--fast), background var(--fast);
}
.pnote:hover:where([data-hover="mouse"] *) .pnote__act, .pnote:focus-within .pnote__act { opacity: .55; }
.pnote__act:hover:where([data-hover="mouse"] *) { opacity: 1 !important; background: rgba(0, 0, 0, .07); }
/* На сенсорном экране наведения не бывает — правка и открепление видны сразу */
@media (hover: none) {
  .pnote__act { opacity: .5; }
}

/* Цвета стикеров в палитре выбора */
.swatch--note-yellow { background: #fde047; }
.swatch--note-green  { background: #86efac; }
.swatch--note-blue   { background: #93c5fd; }
.swatch--note-pink   { background: #f9a8d4; }
.swatch--note-gray   { background: #d4d4d8; }
.swatch--note-orange { background: #fdba74; }
.swatch--note-red    { background: #fca5a5; }
.swatch--note-purple { background: #c4b5fd; }
.swatch--note-teal   { background: #5eead4; }
.swatch--note-lime   { background: #bef264; }

/* ── Доска, встроенная в страницу проекта ────────────────────────────────── */

.projboard { margin-bottom: var(--s-2); }
/* Внутри страницы проекта у панели и полосы дедлайнов своих полей быть
   не должно: они складывались с полями страницы, и доска с дедлайнами
   стояли с лишним отступом справа от всего остального. */
.projboard .duebar { padding-left: 0; padding-right: 0; }
/* Между закреплённым и дедлайнами воздуха было в две ступени шкалы —
   слишком много для соседних полос одного экрана. Оставили полторы. */
.projboard .duebar { padding-top: var(--s-2); }
/* Колонки стояли на 18 точек внутрь от панели над ними: 16 давало поле
   холста, 2 — сам канбан. Вертикальные края всего на экране совпадали,
   а доска — единственное, ради чего сюда заходят, — стояла с уступом.
   Поле холста снято; двойка канбану нужна (это он прокручивается вбок,
   и без неё срезает тень и рамку выделения у крайних карточек), поэтому
   она гасится отрицательным полем — содержимое встаёт вровень, а место
   под тень остаётся. */
.projboard .board__canvas { padding-left: 0; padding-right: 0; }
.projboard .kanban { margin-left: -2px; margin-right: -2px; }
/* Встроенная в проект доска. Высоту задаёт содержимое, окно ограничивает
   сверху: раньше высота всегда бралась от окна, и на графике из трёх задач под
   последней строкой оставалось пустое поле с прокруткой. Рамки и заливки нет —
   доска лежит прямо на полотне страницы. */
.board--embed {
  height: auto; min-height: 0;
  --board-cap: clamp(420px, calc(100dvh - 300px), 1080px);
  border: none; border-radius: 0; background: transparent;
  display: flex; flex-direction: column;
}

/* Строка умолчания: название, переключатель, счёт кого достанет.
   Счёт стоит справа и тише всего — он не орган управления, а последствие
   того, что стоит слева от него. */
.umolrow {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) 0; border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.umolrow:last-child { border-bottom: none; }
.umolrow__name { flex: 1 1 200px; min-width: 0; font-size: var(--t-sm); }
.umolrow__n { flex: 0 0 auto; text-align: right; min-width: 160px; }
@media (max-width: 700px) {
  .umolrow__name { flex-basis: 100%; }
  .umolrow__n { min-width: 0; }
}

/* ── Строки редакторов структуры (этажи, помещения, типы, приоритеты) ────── */

.structrow { display: flex; gap: var(--s-2); align-items: center; margin-bottom: var(--s-2); }
/* Строка типа задачи: имя сверху, оттенки метки под ним отдельным рядом */
.structrow--type { flex-wrap: wrap; margin-bottom: var(--s-4); }
.swatchrow--tag { flex-basis: 100%; gap: var(--s-1); }
.swatchrow--tag .swatch { width: 20px; height: 20px; }
.structrow .input { flex: 1; }
/* Пара стрелок «выше — ниже» вплотную друг к другу: это один орган из двух
   половин, а не две отдельные кнопки. Между ними и «убрать» — обычный зазор
   строки: убрать и переставить путать нельзя. */
.structrow__move { display: inline-flex; gap: 2px; flex: none; }
.structrow__move .btn { width: 26px; padding: 0; font-size: var(--t-sm); }
.structrow__move .btn:disabled { opacity: .3; }
/* Строка этапа комплектации: название и подсказка — разной длины текст,
   поэтому и места им нужно разное; оттенки уезжают под них своим рядом */
.structrow--stage .stage__name { flex: 1 1 150px; min-width: 130px; }
.structrow--stage .stage__hint { flex: 2 1 240px; min-width: 160px; }
.structrow--stage { padding-bottom: var(--s-2); border-bottom: 1px solid var(--border); }
.colorpick {
  width: 34px; height: 34px; padding: var(--s-05); border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--surface); cursor: pointer; flex: none;
}
.modal--wide { max-width: 640px; width: min(640px, calc(100vw - 32px)); }

/* Срок, которого нет. Не красный и не чёрный: «без срока» — не беда
   и не обещание, а отсутствие обещания. Тише всего остального в строке. */
.kcard__date.is-none, .kcard__date.is-none .kcard__date-btn { color: var(--text-faint); }

/* ── Узловые точки закупки: план и факт по каждой ────────────────────────── */

.proctochki { display: grid; gap: var(--s-2); }
.proctochki__head, .proctochki__row {
  display: grid; grid-template-columns: 1fr 150px 150px 90px;
  gap: var(--s-2); align-items: center;
}
.proctochki__head {
  font-size: var(--t-2xs); text-transform: uppercase; font-family: var(--mono); letter-spacing: .08em;
  font-weight: 500; color: var(--text-faint);
}
.proctochki__name { font-size: var(--t-sm); color: var(--text-dim); }
/* Отставание: «+3 дня» красным, «в срок» — тише всего. Знак важнее числа,
   поэтому он стоит первым и не отрывается от него переносом. */
.procdelta { font-size: var(--t-xs); font-weight: 600; white-space: nowrap; }
.procdelta.is-late { color: var(--late-fg); }
.procdelta.is-early { color: var(--ok, var(--text-dim)); }
.procdelta.is-ok { color: var(--text-faint); font-weight: 500; }
@media (max-width: 700px) {
  /* Четыре колонки в телефон не влезают: подпись встаёт своей строкой,
     под ней план и факт рядом — так их и сравнивают. */
  .proctochki__head { display: none; }
  .proctochki__row { grid-template-columns: 1fr 1fr; grid-auto-rows: auto; }
  .proctochki__name { grid-column: 1 / -1; font-weight: 600; color: var(--text); }
  .proctochki__delta { grid-column: 1 / -1; }
}

/* Та же задача без срока на диаграмме: полоса контуром, а не заливкой.
   Даты под ней есть — иначе ей негде стоять, — но они не обещание. */
.bar.is-nodate .bar__body {
  fill: none; stroke: var(--border-strong); stroke-width: 1.5; stroke-dasharray: 4 3;
}
.bar.is-nodate .bar__done { opacity: .35; }
.bar.is-nodate .bar__label { opacity: .7; }

/* Окно заведения задачи: галочка строкой и складка «Подробности».
   Окно открывают десятки раз в день, и всё, что нужно не каждый раз,
   лежит закрытым — иначе четыре поля превращаются в анкету на восемь. */
.checkline {
  display: flex; align-items: center; gap: var(--s-2);
  font-size: var(--t-sm); color: var(--text-dim);
  margin: calc(-1 * var(--s-2)) 0 var(--s-3); cursor: pointer;
}
.checkline input { margin: 0; }
.newtask__more { margin-top: var(--s-2); }
.newtask__more > summary {
  cursor: pointer; font-size: var(--t-sm); color: var(--text-dim);
  padding: var(--s-2) 0; user-select: none;
}
.newtask__more > summary:hover:where([data-hover="mouse"] *) { color: var(--text); }
.newtask__more[open] > summary { margin-bottom: var(--s-2); }

/* Переключатель разделов проекта живёт слева, вплотную к кнопке добавления,
   и прилипать к правому краю ему незачем — правило ниже писано для
   переключателя вида, который стоит в конце полосы. */
.board__bar .seg--razdel { position: static; box-shadow: none; outline: none; }
/* Значок и подпись рядом: одними значками этот ряд путали с переключателем
   вида, который стоит в той же полосе такими же квадратиками.
   width: auto обязателен — у `.viewseg button` ширина задана в 34 точки под
   один значок, и подпись вылезала из кнопки на соседнюю. */
.seg--razdel button {
  display: inline-flex; align-items: center; gap: var(--s-2);
  width: auto; padding: 0 var(--s-3);
}
.seg--razdel .seg__txt { white-space: nowrap; }
/* Подпись бывает двух длин, и показывается одна. Полная — «Задачи
   по проекту», «График закупок»; короткая — «Задачи», «Закупки».
   Совсем убирать подпись, как было раньше, нельзя: разделов стало три,
   и по одному значку «комплектация» от «закупок» не отличить. */
.seg--razdel .seg__txt--short { display: none; }
@media (max-width: 900px) {
  .seg--razdel .seg__txt--full { display: none; }
  .seg--razdel .seg__txt--short { display: inline; }
}
/* Короткая подпись включается не только шириной окна, но и теснотой самой
   панели: у проекта с комплектацией в ней стоят три раздела, кнопка
   добавления, отбор, четыре вида и «…», и на 1280 точках всё это уже
   не помещалось в строку даже со свёрнутым отбором. Ставит класс
   `подогнать` в app.js — измерением, а не порогом: пороги здесь врут,
   потому что ширина зависит ещё и от того, открыта ли левая колонка. */
.board__bar.is-tight .seg--razdel .seg__txt--full { display: none; }
.board__bar.is-tight .seg--razdel .seg__txt--short { display: inline; }

/* Переключатель вида не должен уезжать при прокрутке панели инструментов:
   в режиме ганта кнопок много, а переключиться обратно нужно всегда */
.board__bar .viewseg {
  position: sticky; right: 0; z-index: 2;
  box-shadow: -10px 0 10px -6px var(--surface), -1px 0 0 var(--surface);
  outline: 4px solid var(--surface);
}

/* Комплектация: архивные позиции приглушены */
.table tr.is-archived td { opacity: .45; }

/* ── Карточки задач вне канбана: главная, «Мои задачи» ───────────────────── */

.cardsgrid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--s-3);
}
.cardsgrid--home { grid-template-columns: repeat(auto-fill, minmax(265px, 1fr)); align-items: stretch; }
/* Ровный ряд: карточка не ниже трёх строк названия плюс метки и срок */
.cardsgrid--home .kcard--free { min-height: 132px; }

/* Тот же список строками: карточка растягивается на всю ширину и складывается
   в одну линию — название слева, метки следом, срок и статус у правого края.
   Задач видно вдвое больше, а содержимое то же самое. */
.cardsgrid--home.is-rows { grid-template-columns: 1fr; gap: var(--s-2); }
/* Строка в две линии: сверху название во всю ширину, снизу метки и срок.
   В одну линию метки начинали обрезаться на первом же длинном названии, а их
   там до пяти — проект, этаж, помещение, тип, приоритет. Высота одинаковая у
   всех строк: разнобой в списке читается хуже, чем лишний воздух. */
.is-rows .kcard--free {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: 'title title' 'tags meta';
  align-items: center; gap: var(--s-1) var(--s-3);
  padding: var(--s-3) var(--s-4); min-height: 74px; min-width: 0;
}
.is-rows .kcard__title { grid-area: title; align-items: center; min-width: 0; }
/* Строка всегда одна и уже выровнена по центру — полразницы здесь сдвинули бы
   название вниз относительно кружка вместо того, чтобы совместить их */
.is-rows .kcard__title .kcard__name { margin-top: 0; }
/* Название в строке обрезается многоточием, а не обрубается на середине
   буквы. display:-webkit-box из общей карточки здесь мешает: в сафари
   с ним многоточие не рисуется вовсе, и на айфоне название просто обрывалось. */
.is-rows .kcard__name {
  display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.is-rows .kcard__stage { display: none; }
/* Метки второй строки начинаются там же, где название, а не под кружком.
   Название сдвинуто кружком хода, метки — нет, и вторая строка уезжала
   влево, ломая левый край карточки. Отступ ровно на кружок с зазором и
   только там, где кружок есть: в «Поручил» и «Наблюдаю» его нет, и сдвигать
   нечего. */
.is-rows .kcard--free:has(.krug) .kcard__tags {
  padding-left: calc(var(--step-size) + var(--s-2));
}
/* Метки в строке: раньше они жались в один ряд и обрезались все разом —
   первым же уезжал проект, а он-то и различает одинаковые названия.
   Теперь ряд переносится, проект не сжимается, а лишние метки уходят
   за край по одной, начиная с наименее важной. */
.is-rows .kcard__tags {
  grid-area: tags; margin-top: 0; min-width: 0; flex-wrap: wrap; overflow: hidden;
  /* Ровно два ряда: метка 22, зазор 4, значит 22 + 4 + 22 = 48.
     Прежние 34 показывали первый ряд и двенадцать точек второго — метки
     резались пополам, и полоска чужих букв под строкой читалась поломкой,
     а не «дальше есть ещё». Резать теперь можно только по границе ряда. */
  max-height: 48px;
}
.is-rows .ktag--project { flex: none; max-width: none; }
.is-rows .kcard--free .kcard__meta {
  grid-area: meta; margin: 0; padding-top: 0; flex-wrap: nowrap;
}
/* Лица в строке крупнее, чем в карточке: строка 78 пикселей высотой, и всю
   её вторую половину занимал кружок в 22 — ровно столько, сколько он сам
   и задавал. Инициалы в нём читались только вблизи, а по ним в этом списке
   и узнают, чья задача. 28 — ступень, на которой две буквы видно с рабочего
   расстояния, и она всё ещё меньше кружка хода: главное в строке — действие,
   а не лицо.

   В режиме карточек кружок остаётся мелким: там своё лицо у каждой карточки,
   и крупные кружки превратили бы сетку в ряд портретов. */
.is-rows .kcard__who .avatar { width: 28px; height: 28px; }
.is-rows .kcard__who .avatar + .avatar { margin-left: -8px; }
.is-rows .kcard__who-n { font-size: var(--t-xs); }
.is-rows .kcard--add { min-height: 0; padding: var(--s-3); }
/* Черта приземления при перетаскивании ложится поперёк, а не вдоль */
.is-rows .kcard--free.is-insert-before::before,
.is-rows .kcard--free.is-insert-after::after {
  left: 0; right: 0; width: auto; height: 3px; top: auto; bottom: auto;
}
.is-rows .kcard--free.is-insert-before::before { top: calc(-1 * var(--s-1) - 1px); }
.is-rows .kcard--free.is-insert-after::after { bottom: calc(-1 * var(--s-1) - 1px); }
@media (max-width: 760px) {
  /* На телефоне метки и срок встают друг под друга: на две колонки места нет */
  .is-rows .kcard--free {
    grid-template-columns: minmax(0, 1fr); grid-template-areas: 'title' 'tags' 'meta';
  }
  .is-rows .kcard--free .kcard__meta { justify-content: flex-start; }
}
.kcard--free {
  width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer;
  display: flex; flex-direction: column; gap: var(--s-05);
}
.kcard--free .kcard__meta { margin-top: auto; padding-top: var(--s-2); }

/* ── Задачи прямо на странице проекта, без «рамки отдельной доски» ───────── */

/* Панель с видами и отборами — своей полосой на подложке: так видно, что это
   органы управления доской, а не ещё один ряд содержимого.
   Полей у неё какое-то время не было вовсе, и синяя «+ Задача» упиралась
   в край полосы — кнопка на подложке без поля слева выглядит обрубленной.
   Поля возвращены внутрь полосы: наружу она по-прежнему встаёт вровень
   с закреплённым и дедлайнами, а кнопкам есть куда дышать. */
/* С редизайна (сверка облика, 27 сентября 2026) — сплошной плашкой с тенью,
   а не рамкой по фону: как карточки вокруг */
.board--embed .board__bar {
  padding: var(--s-2) var(--s-3);
  background: var(--solid); border: 1px solid transparent; box-shadow: var(--sh-1);
  border-radius: var(--radius-lg); margin-bottom: var(--s-2);
}
.projboard { margin-bottom: 0; }

/* ── Интерактивность: нажатия и наведения ощущаются живыми ──────────────── */

.btn { transition: background var(--fast), border-color var(--fast), transform var(--fast), box-shadow var(--fast); }
.btn:active { transform: translateY(1px); }
.btn--primary:hover:where([data-hover="mouse"] *) { box-shadow: 0 4px 14px var(--accent-ring); }
.kcard--free:hover:where([data-hover="mouse"] *) { box-shadow: var(--shadow-md); border-color: var(--border-strong); }
.pnote { transition: transform var(--fast), box-shadow var(--fast); }
.pnote:hover:where([data-hover="mouse"] *) { box-shadow: var(--shadow-md); filter: brightness(.985); }
.teamchip { transition: border-color var(--fast), box-shadow var(--fast); }
.teamchip:hover:where([data-hover="mouse"] *) { border-color: var(--border-strong); box-shadow: var(--shadow-xs); }
.tab:hover:where([data-hover="mouse"] *) { color: var(--text); }
.tlist__row td { transition: background var(--fast); }
.feedrow { transition: background var(--fast); }

/* Видимый фокус с клавиатуры — доступность без охоты за элементами */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-sm); }
.kcard:focus-visible, .kcard--free:focus-visible { outline-offset: 0; }
/* Кнопка сохранения профиля не уезжает за край длинной формы */
.profsave {
  position: sticky; bottom: 0; padding: var(--s-3) 0 0;
  background: linear-gradient(to bottom, transparent, var(--surface) 40%);
}
/* На компьютере полотно прокручивается с полем снизу (--s-5), и прилипшая
   кнопка вставала над ним: поля формы выглядывали из-под «Сохранить»
   полосой в 24 точки. Подложка кнопки уходит в это поле (сверка
   28 сентября 2026). */
@media (min-width: 761px) {
  .profsave { bottom: calc(-1 * var(--s-5)); padding-bottom: var(--s-5); margin-bottom: calc(-1 * var(--s-3)); }
}

/* Полосы-разделители в админке: настройки шли одним столбцом от важного
   до косметики */
.adminband {
  display: flex; align-items: baseline; gap: var(--s-3);
  margin: var(--s-6) 0 var(--s-3); padding-bottom: var(--s-2);
  border-bottom: 1px solid var(--border);
}
.adminband:first-child { margin-top: 0; }
.adminband h2 { margin: 0; font-size: var(--t-md); }

/* Полоса действий над несколькими задачами: появляется, только когда что-то
   отмечено — постоянная панель занимала бы место ради недельного случая */
.tbulk {
  position: sticky; bottom: var(--s-3); z-index: 5;
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  margin-top: var(--s-3); padding: var(--s-2) var(--s-3);
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius); box-shadow: var(--shadow-md);
}
.tbulk__n { font-weight: 600; font-size: var(--t-sm); margin-right: var(--s-2); }
/* Телефон: обе липкие полосы — «Сохранить» профиля и действия над
   отмеченными задачами — липнут над полосой разделов, а не к краю окна.
   У края их накрывала полоса разделов: кнопка «Сохранить» длинной формы
   профиля стояла под вкладками, и нажать её было нельзя, пока не
   долистаешь до самого конца. */
@media (max-width: 760px) {
  .profsave { bottom: calc(var(--nav-h, 82px) + env(safe-area-inset-bottom)); }
  .tbulk { bottom: calc(var(--nav-h, 82px) + var(--s-3) + env(safe-area-inset-bottom)); }
}
.tlist__pick { width: 32px; text-align: center; }
.tlist__pick input { cursor: pointer; }

/* Перетаскивание строк таблицы: на двадцати людях стрелками не наездишься */
.draghandle { cursor: grab; color: var(--text-faint); user-select: none; font-size: var(--t-sm); }
.draghandle:active { cursor: grabbing; }
tr.is-drop td { box-shadow: inset 0 2px 0 var(--accent); }

a.btn { text-decoration: none; display: inline-flex; align-items: center; }

/* ── Система направления «Полночь. Лазурь» ───────────────────────────────
   Архитектурная нотка живёт не в картинках, а в наборе правил: числа
   моноширинные, как размерные надписи на листе; подписи разделов идут
   в разрядку, как в штампе чертежа; форма скруглений одна на всё. */

/* Одна шкала формы. С редизайна (27 сентября 2026) кнопки, метки,
   карточки, окна и боковой лист скругляются у себя, по tokens.css: кнопки
   и метки — пилюлей, карточки и окна — --radius-lg, лист — --radius-xl.
   Прежде здесь всё сводилось к --radius, и это правило, стоящее ниже по
   файлу, перебивало даже скругление листа на телефоне (только верх). */
.bcard, .kcard, .kcard--free, .input, .select, .textarea,
.kcol, .softcard { border-radius: var(--radius); }
.ktag, .kcard__prio, .tlist__status { border-radius: var(--radius-sm); }

/* Подписи — как надписи в штампе листа. Заголовков разделов здесь нет:
   когда заголовок блока набран так же, как подпись поля, между ними нет
   разницы по весу и структура страницы перестаёт читаться. Приём остаётся
   на том, что он и подписывает: колонки, шапки таблиц, поля форм. */
/* (Подписи чисел отпуска, `.vstat__label`, — в modules/schedule/styles.css.) */
.kcol__name, .tlist__table th, .field__label {
  text-transform: uppercase;
  letter-spacing: .1em;
  font-size: var(--t-2xs);
  font-weight: 600;
}
/* Подпись прописью одна на портал (сверка с ТЗ, 28 сентября 2026): как
   .eyebrow, шапка таблицы и заголовок группы макета — IBM Plex Mono 500,
   --t-xs, разрядка .08em, у шапки таблицы .06em. До сверки их было девять
   видов: Onest 600 с разрядкой .1em, .06em, .04em — и в одной карточке
   профиля «СТАТУС» стоял моноширинным, а «ИМЯ» под ним — рубленым. */
.tlist__table th, .field__label { font-family: var(--mono); font-weight: 500; letter-spacing: .08em; }
.tlist__table th { letter-spacing: .06em; }

/* Числа — размерные надписи: моноширинные, выровненные по разрядам.

   Крупные значения графика работы (`.vstat__value`) сюда не входят: им нужна
   моноширинность, но не этот кегль. Пока они стояли в общем списке, правило
   ниже по файлу перебивало их собственные 28 пикселей на 13 — «сделать
   информацию про отпуск крупнее» было записано в стилях и не работало
   ни дня. Семейство и выключку они получают отдельной строкой — с 24 сентября
   2026 в modules/schedule/styles.css. */
.kcard__date, .tlist__date, .kcard__pct,
.hrow__right, .feedrow__time, .softcard__ver {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-mono);
  letter-spacing: -.01em;
}
/* Срок на карточке — на ступень мельче остальных размерных надписей.

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

   Правило стоит после общего, а не рядом с остальными про срок: там оно
   объявлено выше по файлу и общее его перебивало — размер оставался прежним,
   а я считал, что уменьшил. */
.kcard__date { font-size: var(--t-2xs); }
/* Предлог при сроке — подпись, а не кнопка. Пропорциональным шрифтом:
   моноширинный нужен цифрам, чтобы столбец дат стоял ровно, а слову «до»
   он придаёт вид кода. */
.kcard__date-lead {
  font-family: var(--font); color: var(--text-faint); margin-right: 4px;
}
.kcard__date.is-late .kcard__date-lead { color: var(--late-fg); }

.kcard { padding: var(--s-3) var(--s-3); }
/* Тот же кегль и то же начертание, что и выше: правило стоит ниже
   и перебивало бы их. Интерлиньяж 1.35 совпадает с расчётом отступа
   в `.kcard__title .kcard__name`, которым название совмещают с кружком хода. */
.kcard__name { font-size: var(--t-base); line-height: 1.35; font-weight: 500; }
/* Колонка канбана — неглубокий жёлоб под полотном, а не отдельная плита.

   Она была залита --surface-2, а это ступень, придуманная для полей ввода
   и шапок таблиц: между колонкой и лежащей на ней карточкой набегало до
   1,52 раза по светлоте (Periwinkle), и доска читалась не как лист с
   карточками, а как ряд серых плит, на которых что-то белеет.

   Теперь у колонки свой токен --well: ступень вниз от полотна (1,06–1,08),
   карточка — ступень вверх (1,07). Между колонкой и карточкой выходит
   1,14–1,16 во всех шестнадцати темах.

   Глубину жёлоба подбирали дважды. Сперва взяли 1,05 — и колонка слилась
   с полотном: доска стала ровным листом, на котором карточки висят сами
   по себе. 1,08 читается выемкой, но не плитой. У «Дня» и нескольких
   тёмных тем жёлоб упирается в цвет фона приложения — это не совпадение,
   а предел: глубже в этих палитрах просто нет места, и колонка оказывается
   ровно тем же тоном, что фон за островом. Выглядит как отверстие в листе,
   и это верно по смыслу. */
.kcol { background: var(--well); border: none; }
.kcol__body { gap: var(--s-2); }

/* Под шапкой страницы черты нет (редизайн: иерархия тоном и воздухом, а не
   линиями) — как у «Задач», «Проектов» и «Команды». До 27 сентября 2026
   здесь была «модульная линия», и экраны старого вида отличались ею. */
.page__head { padding-bottom: var(--s-2); }
.page__head h1 { font-weight: 600; letter-spacing: -.025em; }

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

/* ── Выбор значка заметки ────────────────────────────────────────────────── */

.iconpick {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: var(--s-2);
}
.iconpick__item {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-2) var(--s-2); border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); color: var(--text); cursor: pointer;
  font-size: var(--t-sm); text-align: left; min-width: 0;
  transition: border-color var(--fast), background var(--fast);
}
.iconpick__item span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.iconpick__item:hover:where([data-hover="mouse"] *) { border-color: var(--border-strong); }
.iconpick__item.is-active { border-color: var(--accent); background: var(--accent-soft); }
.iconpick__item .pnote__badge { flex: none; }
/* Знаки сервисов — плитками в одну клетку: подпись у каждого занимала строку
   ради того, что и так узнаётся. Первый, «по ссылке», подписан — он объясняет,
   почему значок иногда меняется сам. */
.iconpick { grid-template-columns: repeat(auto-fill, minmax(44px, 1fr)); }
.iconpick__item--auto { grid-column: span 3; }
.iconpick__item--mark { justify-content: center; padding: var(--s-2); }
.pnote__badge--mark { background: none; padding: 0; overflow: hidden; border-radius: var(--radius-sm); }
.pnote__badge--mark svg,
.pnote__badge--mark img { width: 100%; height: 100%; display: block; object-fit: contain; }


/* ── Адаптивность: от телефона до большого монитора ──────────────────────── */

/* Полосе прокрутки вбок место только там, где вкладок и вправду много:
   колонки канбана сжимаются до минимума раньше, чем появится полоса. */
.kanban { scrollbar-width: thin; }
.kanban::-webkit-scrollbar { height: 8px; }
.kanban::-webkit-scrollbar-thumb {
  background: var(--border-strong); border-radius: var(--radius-sm);
}
.kanban::-webkit-scrollbar-track { background: transparent; }

/* Холсты доски: диаграмма, канбан и таблица. На отдельном экране доски они
   тянутся во всю высоту окна, внутри проекта — по содержимому (см. ниже). */
.board__canvas { flex: 1; min-height: 0; position: relative; }
.kanban-host, .list-host { overflow: auto; padding: var(--s-4); }

.board--embed .board__canvas { flex: none; }
/* Шапка со шкалой плюс строки, но не выше отведённого. Высоту считает скрипт
   по остатку окна: пока у страницы и у диаграммы были свои полосы прокрутки,
   колесо мыши работало то на одну, то на другую. */
.board--embed .gantt {
  /* Полоса прокрутки лежит поверх содержимого и накрывала последнюю строку:
     на графике из одной задачи она закрывала её наполовину, и прочесть было
     нечего. Поэтому её рост прибавлен к высоте, а совсем короткому графику
     задан низ — шапка и две строки, чтобы задача не жалась к краям. */
  height: min(var(--board-cap),
              max(148px, calc(52px + var(--rows, 6) * var(--row-h, 34px) + 15px)));
}
/* Диаграмма во весь экран: с ней работают подолгу, и остальной интерфейс
   в это время только отнимает высоту */
.board--full {
  position: fixed; inset: 0; z-index: 60; margin: 0; border-radius: 0;
  background: var(--surface); display: flex; flex-direction: column;
  padding-top: env(safe-area-inset-top);
}
.board--full .board__bar { flex: none; }
.board--full .board__canvas { flex: 1; min-height: 0; }
.board--full .gantt { height: 100%; max-height: none; }
body.has-boardfull { overflow: hidden; }

/* Типы задач словами: их у проекта три-четыре, место в панели есть, а под
   воронкой приходилось открывать список даже затем, чтобы посмотреть,
   включён ли отбор */
.typebar { display: flex; align-items: center; gap: var(--s-1); flex-wrap: wrap; min-width: 0; }
.typechip {
  display: inline-flex; align-items: center; gap: var(--s-2);
  height: 30px; padding: 0 var(--s-3); border-radius: var(--radius-full);
  border: 1px solid transparent; background: none; cursor: pointer;
  font: inherit; font-size: var(--t-sm); font-weight: 500; color: var(--text-dim); white-space: nowrap;
  transition: background var(--fast), color var(--fast);
}
.typechip:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }
.typechip__dot {
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--type-color, var(--text-faint));
}
.typechip.is-on {
  background: color-mix(in srgb, var(--type-color, var(--accent)) 16%, transparent);
  color: var(--text); font-weight: 600;
}
.typechip.is-on:first-child { background: var(--surface-3); }
/* Выбранный чип под мышью — своим цветом погуще, а не общей серой
   подложкой: общее `.typechip:hover` ниже по файлу стоит позже и с той же
   силой, и выбранный тип под мышью переставал выглядеть выбранным */
.typechip.is-on:hover:where([data-hover="mouse"] *) { background: color-mix(in srgb, var(--type-color, var(--accent)) 24%, transparent); }
.typechip.is-on:first-child:hover:where([data-hover="mouse"] *) { background: color-mix(in oklab, var(--surface-3), var(--ink) 6%); }
/* Свёрнутый отбор: воронка, название выбранного типа и треугольник.
   Показывается вместо ряда слов, когда ряд перестаёт помещаться в строку
   панели, — см. `подогнать` в app.js.

   Включённый отбор красится общим правилом `.btn.is-on` — тем же, что
   у «показать закрытые» и у прочих выключателей: свёрнутый отбор обязан
   говорить, что часть задач сейчас скрыта, и говорит он это так же, как
   все остальные включённые кнопки приложения. */
.typepick { display: inline-flex; align-items: center; gap: var(--s-2); }
/* Панель меряется на мгновение: перенос запрещаем и смотрим, вылезает ли
   содержимое за ширину. Видимого мигания нет — между добавлением класса
   и снятием браузер не перерисовывает. */
.board__bar.is-measuring { flex-wrap: nowrap; overflow: hidden; }
/* Канбан и список тянутся по содержимому: вертикаль листает страница целиком.
   Ограничение по высоте оставлено только диаграмме — ей нужна своя область с
   закреплённой шкалой. Полоса прокрутки вбок остаётся у самого канбана. */
.board--flow .kanban-host, .board--flow .list-host { overflow: visible; max-height: none; }
.board--flow .board__canvas { flex: none; }
.board--flow { height: auto; }

/* Планшет и узкий ноутбук: карточек в ряд меньше, колонки уже */
@media (max-width: 1100px) {
  .kcol { min-width: 200px; }
  .cardsgrid { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); }
  /* Правила для `.pnotes` здесь больше нет: ширина плашки считается
     от ширины окна и сужается плавно, без ступени на 1100 точках. */
}

/* Большой монитор: шире контейнер, крупнее карточки, больше воздуха */
@media (min-width: 1700px) {
  .cardsgrid { grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); }
  .board--embed { --board-cap: clamp(520px, calc(100dvh - 280px), 1240px); }
}

/* Телефон: колонка канбана почти во весь экран, таблицы листаются, ничего
   не вылезает за край страницы */
@media (max-width: 760px) {
  .kcol { flex: 0 0 82vw; min-width: 0; max-width: 82vw; max-height: none; }
  .board--embed { --board-cap: clamp(380px, calc(100dvh - 300px), 900px); }
  .cardsgrid, .cardsgrid--home { grid-template-columns: 1fr; }
  .pnotes { grid-template-columns: 1fr; }
  .row { flex-direction: column; gap: 0; }
  /* В столбце `flex: 1` у детей значит нулевую основу по высоте: кнопки
     в ряду («Изменить…», «Сохранить» в реквизитах компании) сплющивало
     до 23 точек и до нуля — текст вылезал за рамку, а нажать было некуда.
     В столбце ребёнку растягиваться не во что, он берёт свою высоту. */
  .row > * { flex: none; }
  .row > .btn + .btn { margin-top: var(--s-2); }
  .verdict, .system { grid-template-columns: 1fr; }
  .iconpick { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
  .tlist { margin: 0 -12px; padding: 0 var(--s-3); }
}

/* Ничто не имеет права раздвигать страницу вбок: длинные ссылки в заметках,
   широкие таблицы и подписи переносятся или прокручиваются внутри себя */
body { overflow-x: hidden; }
.main { max-width: 100%; }   /* предел ширины .page задан выше и не снимается */
.softcard__desc, .feedrow__text { overflow-wrap: anywhere; }


/* ── Телефон: экран проекта ──────────────────────────────────────────────
   Заголовок, заметки и панель инструментов рассчитаны на широкий экран.
   На узком они съедали всю высоту до задач, ради которых экран и открывают.
   Блок держим в конце файла: он правит то, что объявлено выше. */
@media (max-width: 760px) {
  .page--wide { padding-left: var(--s-3); padding-right: var(--s-3); }
  /* Заголовок проекта: 23px на 375px давал перенос на две-три строки */
  /* Только у проекта, диска и доски: там в заголовке имя, и оно бывает
     длинным. Раздел («Поставщики», «Загрузка») пишется тем же кеглем, что
     остальные разделы на телефоне, — с 18 он выглядел подписью. */
  /* Заголовок раздела на телефоне — --t-xl, а не 32: «Отпуска и отсутствия»
     шло в две строки и съедало сотню точек первого экрана (владелец,
     1 октября 2026, по аудиту) */
  .page__head h1 { font-size: var(--t-xl); }
  :is(.prj-page, .page--disk, .page--wb) .page__head h1 { font-size: var(--t-lg); }
  .page__head { gap: var(--s-2); margin-bottom: var(--s-3); }

  /* Закреплённое листается вбок: столбиком оно отодвигало задачи за экран —
     четыре заметки давали семьсот пикселей до первой задачи, а за задачами
     в проект и заходят.

     Полоса задаётся сеткой, а не flex: `.pnotes` — это grid, и `flex-wrap`
     на нём не значит ничего. Правило с `flex-wrap` здесь и стояло, столбик
     держался соседним `grid-template-columns: 1fr`, и вбок ничего
     не листалось. Проверять такое надо снимком, а не чтением.

     Поля наружу и обратно внутрь — чтобы полоса начиналась и обрывалась
     у самого края экрана, а не в рамке поля страницы: обрыв у края и есть
     то, что говорит «здесь листается». */
  .pnotes {
    grid-auto-flow: column; grid-template-columns: none;
    /* Ровно 68vw, а не minmax(0, 68vw): с нулевым минимумом столбцы
       ужимались под ширину экрана вместо того, чтобы выехать за него,
       и от заметки оставался один значок. */
    grid-auto-columns: 68vw;
    overflow-x: auto;
    margin: 0 calc(-1 * var(--s-3)) var(--s-3);
    padding: 0 var(--s-3) var(--s-1);
    scrollbar-width: none;
  }
  .pnotes::-webkit-scrollbar { display: none; }
  /* На узком заголовок занимает свою строку целиком, а статус и шестерёнка
     встают под ним парой. Иначе статус помещался рядом с названием, а
     шестерёнку выбрасывало на третью строку в одиночестве. */
  .page--wide .page__head .spacer { display: none; }
  .page__head { row-gap: var(--s-2); }
  /* Место под кнопку «назад» — до 48 точек, а не ровно 30: на диске она
     круглая, 42, и с прежними 38 заголовок не помещался рядом с ней —
     стрелка стояла одна на строке, заголовок под ней, и шапка папки
     занимала четыре ряда до первого файла. */
  .page--wide .page__head h1 { flex: 1 1 calc(100% - var(--s-7) - var(--s-2)); }

  /* Панель инструментов — ровно две строки, и обе осмысленные.
     
     Переносится, а не листается вбок: на 375px в строку помещалось полторы
     кнопки, а приклеенный к правому краю переключатель вида наезжал на то,
     что под ним. Но простого переноса не хватило — панель расползалась
     на четыре ряда: «+ Задача» одна, отборы одни, переключатель один
     и «…» один. Четыре ряда по одному предмету читаются не как панель,
     а как обломки вёрстки.
     
     Теперь порядок задан: сверху то, чем распоряжаются, — завести задачу,
     сменить вид, открыть «ещё»; снизу отдельной строкой отборы, которые
     листаются вбок, потому что типов бывает пять и в ширину они не влезут
     никогда. */
  .board__bar {
    flex-wrap: wrap; overflow-x: visible;
    padding-top: var(--s-2); padding-bottom: var(--s-2); gap: var(--s-2);
    align-items: center;
  }
  /* «+ Задача» тянется и выталкивает остальное первой строки вправо.
     Исключение из соседнего правила прописано явно: у `.btn--primary`
     и `.btn` одинаковая сила, и без :not() побеждало бы то, что ниже
     по файлу, — то есть порядок задавался бы случайно. */
  /* Разделы проекта — первой строкой во всю ширину.

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

     Три кнопки делят ширину поровну: подписи у них короткие («Задачи ·
     Комплектация · Закупки»), и ряд равных кнопок читается переключателем
     сразу, без вглядывания. */
  .board__bar > .seg--razdel { order: 0; flex: 1 0 100%; }
  .board__bar > .seg--razdel button { flex: 1 1 0; justify-content: center; }
  .board__bar > .btn--primary { order: 1; flex: 1 1 auto; }
  .board__bar > .seg:not(.seg--razdel),
  .board__bar > .btn:not(.btn--primary) { order: 2; flex: none; }
  /* Отборы — своей строкой во всю ширину, листаются вбок */
  .board__bar > .typebar {
    order: 9; flex: 1 0 100%; flex-wrap: nowrap; overflow-x: auto;
    scrollbar-width: none; padding-bottom: 2px;
  }
  .board__bar > .typebar::-webkit-scrollbar { display: none; }
  .board__bar > .typebar > * { flex: none; }
  .board__bar .spacer { display: none; }
  .board__bar .viewseg {
    position: static; margin-left: auto;
    box-shadow: none; outline: none;
  }
  .board__bar .bar__sep { display: none; }
  .board--embed { --board-cap: clamp(360px, calc(100dvh - 240px), 900px); }

  /* Цели нажатия. Палец не мышь: всё, что нажимается, должно быть не меньше
     44px по обеим сторонам. Кнопки честно подрастают, а хлебная крошка
     добирает зону невидимой подложкой — иначе строка над заголовком
     раздувается вдвое ради ссылки в одно слово. */
  .board__bar .btn,
  .board__bar .seg button,
  .viewseg button,
  .searchbtn,
  .topbar button,
  .tab {
    min-height: 44px;
  }
  .board__bar .btn, .viewseg button, .topbar button { min-width: 44px; }
  .crumbs button { position: relative; }
  .crumbs button::after {
    content: ''; position: absolute; left: 0; right: 0;
    top: 50%; height: 44px; transform: translateY(-50%);
  }
}

/* ── Рабочий экран: задачи и стопка заметок рядом ────────────────────────── */
/* На широком мониторе справа от задач остаётся пустое поле — туда и уходят
   объявления и записки. На узком колонка встаёт под задачами: сначала работа. */
.homewrap { display: grid; gap: var(--s-7); align-items: start; }
@media (min-width: 1240px) {
  /* Слева работа и под ней лента, справа во всю высоту — заметки */
  .homewrap {
    grid-template-columns: minmax(0, 1fr) 316px;
    grid-template-areas: 'work rail' 'feed rail';
  }
  /* Свёрнутая правая колонка — полоса со знаком, как и левая: колонка,
     пропавшая без следа, не сообщает, чем её вернуть. */
  .homewrap.is-railfolded { grid-template-columns: minmax(0, 1fr) 26px; }
  .homewrap > .home { grid-area: work; }
  .homewrap > .rail { grid-area: rail; }
  .homewrap > .homefeed { grid-area: feed; }
}
.homefeed { min-width: 0; }
/* Колонка задач — полноправный элемент сетки: без min-width её содержимое
   (карточки в три ряда) распирает колонку и наезжает на заметки */
.homewrap > .home { min-width: 0; }
.home > * { min-width: 0; }
/* Таблица «моей работы»: то же самое строками со столбцами.
   Строки живые: кружок хода, статус, срок и лица работают так же, как
   на карточке. В задачу ведут название и проект — не вся строка целиком,
   иначе нажать на что-то внутри неё было бы нельзя. */
.htbl { background: var(--surface); border-radius: var(--radius); overflow: hidden; }
.htbl__row { transition: background var(--fast); }
.htbl__row:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.htbl__row:last-child td { border-bottom: none; }
.htbl__cell { cursor: pointer; }
.htbl__name { font-weight: 500; }
.htbl__dim { color: var(--text-dim); }
/* Столбец хода узкий: в нём один кружок или одна плашка */
.htbl__step { width: 1%; white-space: nowrap; padding-right: 0; }
.htbl__due { white-space: nowrap; }
/* Просроченный срок — цветом, как везде в приложении */
.htbl td.is-late { color: var(--late-fg); font-weight: 500; }
.htbl__who { width: 1%; white-space: nowrap; }
.htbl__who .avatar { margin-left: -6px; }
.htbl__who .avatar:first-child { margin-left: 0; }

.rail { display: flex; flex-direction: column; gap: var(--s-3); min-width: 0; }
/* Складка правой колонки — та же, что у левой, и по той же причине: кому
   объявления и записки сейчас не нужны, тот убирает их и остаётся с одной
   работой. Знак стоит в строке первого заголовка, у правого края — своей
   строкой он держал пустое поле над колонкой, которую сворачивают ради места. */
.rail__fold {
  margin-left: auto; flex: none; width: 26px; height: 26px;
  display: grid; place-items: center;
  border: none; border-radius: var(--radius-sm); background: none;
  color: var(--text-faint); cursor: pointer;
  transition: background var(--fast), color var(--fast);
}
.rail__fold:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }
/* Развёрнутая колонка складывается вправо, свёрнутая раскрывается влево */
.rail__fold .ic { transform: rotate(180deg); }
.rail__fold.is-folded .ic { transform: none; }
/* От свёрнутой колонки остаётся первая строка заголовка, а от неё — складка */
.rail.is-folded > *:not(.rail__head) { display: none; }
.rail.is-folded .rail__head:not(:has(.rail__fold)) { display: none; }
.rail.is-folded .rail__head { margin: 0; }
.rail.is-folded .rail__head > *:not(.rail__fold) { display: none; }
.rail.is-folded .rail__fold { margin-left: 0; }
/* Та же полоса, что у «Моей работы»: одна высота, одно выравнивание,
   один кегль заголовка — тогда базовые линии сходятся сами */
/* Между подписью раздела и его содержимым нужен воздух: вплотную заголовок
   читался как первая строка списка. На телефоне поле ужимается ниже. */
.rail__head {
  display: flex; align-items: center; gap: var(--s-3);
  min-height: 30px; margin: var(--s-5) 0 var(--s-3);
}
.rail__head:first-child { margin-top: 0; }
.rail__head h2 {
  font-size: var(--t-md); font-weight: 600; color: var(--text); letter-spacing: -.01em;
}
.sticks { display: flex; flex-direction: column; gap: var(--s-2); }
/* В офисах бумажки лежат рядом, а не столбиком: там их бывает много,
   а колонка в узкой правой полосе — это про рабочий экран */
.sticks--wide {
  flex-direction: row; flex-wrap: wrap; align-items: flex-start;
}
.sticks--wide .stick { width: 240px; }
.stick { position: relative; }
/* Ссылка и удаление — значками в углу бумажки, по наведению */
.stick__acts { position: absolute; top: var(--s-1); right: var(--s-1); display: flex; gap: 2px; }
.stick__act {
  border: none; background: none; cursor: pointer; color: inherit;
  width: 22px; height: 22px; padding: 0; border-radius: var(--radius-sm);
  font-size: var(--t-2xs); opacity: 0; transition: opacity var(--fast), background var(--fast);
}
.stick:hover:where([data-hover="mouse"] *) .stick__act, .stick:focus-within .stick__act { opacity: .6; }
.stick__act:hover:where([data-hover="mouse"] *) { opacity: 1; background: rgba(0, 0, 0, .08); }
@media (hover: none) { .stick__act { opacity: .5; } }
.stick__link {
  display: block; margin-top: var(--s-2); font-size: var(--t-2xs);
  color: inherit; opacity: .75; text-decoration: underline; word-break: break-all;
}
.stick__url {
  width: 100%; margin-top: var(--s-2); font: inherit; font-size: var(--t-sm);
  border: none; border-bottom: 1px solid currentColor; background: none;
  color: inherit; padding: 2px 0;
}
.stick__url:focus { outline: none; }

/* Стикер: бумажка, а не карточка — без рамки, с мягким углом и своей краской */
.stick {
  border-radius: var(--radius-lg); padding: var(--s-3) var(--s-4);
  font-size: var(--t-base); line-height: 1.45; text-align: left;
  border: 1px solid transparent; box-shadow: var(--shadow-xs);
  transition: transform var(--fast), box-shadow var(--fast);
}
.stick[tabindex]:hover:where([data-hover="mouse"] *) { box-shadow: var(--shadow-md); cursor: text; }
/* Длинная заметка не должна растягивать колонку на два экрана: показываем
   первые строки, остальное листается внутри самой бумажки */
.stick__body { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 15em; overflow: auto; }
.stick__input { max-height: 22em; overflow-y: auto; }
.stick__who { font-size: var(--t-2xs); opacity: .7; margin-top: var(--s-2); }
.stick__input {
  min-height: 96px;
  width: 100%; border: none; background: none; color: inherit;
  font: inherit; line-height: 1.45; resize: none; outline: none; padding: 0;
  overflow: hidden;
}
.stick__colors { display: flex; gap: var(--s-1); margin-top: var(--s-2); }
.stick__colors .swatch { width: 18px; height: 18px; }
.stick.is-editing { box-shadow: var(--shadow-md); }
.stick--add {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  border: 1px dashed var(--border-strong); background: none; color: var(--text-faint);
  cursor: pointer; font: inherit; font-size: var(--t-sm); padding: var(--s-3) var(--s-4);
  box-shadow: none;
}
.stick--add:hover:where([data-hover="mouse"] *) { border-color: var(--accent); color: var(--accent-fg); }
/* Краски заметок — там же, где краски объявлений: это один набор бумажек,
   и разъезжаться им нельзя. См. «Цвет стикера» выше. */

/* Описание проекта строкой под названием: два ряда, дальше многоточие —
   развёрнутый текст живёт в настройках проекта, здесь он для узнавания */
.page__lead {
  color: var(--text-dim); font-size: var(--t-base); line-height: 1.5;
  margin: calc(-1 * var(--s-2)) 0 var(--s-4); max-width: 76ch;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* Состав команды проекта — раскрывается из стопки аватаров в шапке */
.teampop { min-width: 264px; padding: var(--s-2); }
.teampop__head {
  font-size: var(--t-2xs); font-weight: 500; letter-spacing: .08em; text-transform: uppercase; font-family: var(--mono);
  color: var(--text-faint); padding: var(--s-2) var(--s-3) var(--s-2);
}
.teampop__row {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) var(--s-3); border-radius: var(--radius-sm);
}
.teampop__row:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.teampop__who { flex: 1; min-width: 0; font-size: var(--t-base); }
.teampop__who .note { font-size: var(--t-xs); }
.teampop__who > div { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.teampop__x {
  flex: none; border: none; background: none; cursor: pointer; color: var(--text-faint);
  font-size: var(--t-sm); padding: var(--s-1); border-radius: var(--radius-sm); opacity: 0;
}
.teampop__row:hover:where([data-hover="mouse"] *) .teampop__x { opacity: 1; }
/* На сенсорном — телефон, iPad — наведения нет, и крестик «убрать из
   проекта» оставался невидимым навсегда: нажать можно, догадаться нельзя.
   Видны сразу, но тихо. (То же у «…» в дереве базы знаний — в её модуле.) */
@media (hover: none) {
  .teampop__x { opacity: .6; }
}
.teampop__x:hover:where([data-hover="mouse"] *) { color: var(--late-fg); background: var(--critical-soft); }
.teampop__add { margin-top: var(--s-1); border-top: 1px solid var(--border); border-radius: 0; }

/* ── Карточка проекта ────────────────────────────────────────────────────── */
/* Ряды одинаковой высоты: имя со статусом, две строки описания, полоса с
   числами, внизу лица команды. Пустое описание держит своё место — иначе
   соседние карточки разъезжаются и сетка перестаёт читаться рядами. */
/* Сетка проектов: четыре в ряд на большом мониторе, три на обычном, два на
   узком, один на телефоне. Раньше стояло auto-fill от 320px — и на широком
   экране получалось четыре узких столбца, в которых название проекта вроде
   «Реконструкция особняка на Пречистенке» переносилось трижды. Число колонок
   задано ступенями, а не подбором: так карточка на каждой ширине остаётся
   той величины, на которую рассчитано её содержимое. */
/* Три карточки в ряду, не четыре. На карточке теперь обложка слева от
   названия и ряд кнопок в подвале — в четверти ширины они не помещались
   и вставали в две строки каждый, отчего сетка теряла ряды. */
/* Число столбцов считает сама сетка, а не ступени по ширине экрана.
   Ступеней было три — 3, 2 и 1 столбец, — и между ними карточка оказывалась
   то просторной, то такой, что в неё не помещались ни название, ни кнопки
   разделов: «189 Скандинавия» читалось как «18 9…», а «Комплектация»
   обрезалась краем. Минимум в 340 точек — это ширина, на которой карточка
   ещё работает; сколько таких влезло, столько и столбцов. */
.projgrid {
  display: grid; gap: var(--s-4);
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
}
@media (max-width: 400px) { .projgrid { grid-template-columns: 1fr; } }
.projcard {
  display: grid; grid-template-rows: 1fr auto; gap: var(--s-3);
  text-align: left; font: inherit; cursor: pointer;
  /* Карточка лежит на полотне и обязана быть светлее его — как карточка
     задачи. См. --canvas / --raised в разделе тем. */
  background: var(--raised); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: var(--s-5);
  transition: border-color var(--fast), box-shadow var(--fast), transform var(--fast);
}
.projcard:hover:where([data-hover="mouse"] *) {
  border-color: var(--border-strong); box-shadow: var(--shadow-md);
}
/* Общий проект компании отличается не цветом, а тоном: он подложен на
   ступень ниже остальных карточек — той же краской, что колонки.

   Прежде он красился акцентом, и это было слишком: акцент в приложении
   означает «нажми меня», а карточка компании ничем не важнее соседних —
   она просто одна такая и стоит первой. Цветное пятно на весь ряд забирало
   внимание, которое нужно проектам.

   Правится в одном месте на все темы: каждая тема задаёт свой --surface-2,
   и карточка сама встаёт в тон той теме, что сейчас на экране. */
.projcard--company { border-color: var(--border-strong); background: var(--surface-2); }
.projcard--company:hover:where([data-hover="mouse"] *) { border-color: var(--text-faint); }
/* Обложка слева, справа от неё столбцом имя и описание. Без переноса:
   описание должно стоять рядом с картинкой, а не под ней. */
.projcard__top { display: flex; align-items: flex-start; gap: var(--s-4); }
.projcard__head { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s-2); }
.projcard__line { display: flex; align-items: flex-start; gap: var(--s-2); flex-wrap: wrap; }
/* Обложка проекта: квадрат слева от названия, в высоту имени с описанием.
   Не круг — круг в приложении означает человека, и проект в кружке читался
   бы сотрудником. Скруглён так же, как карточка задачи.

   Размер — 88 точек: обложка в 44 была ровно значком, а по значку объект
   не узнать. Проект узнают по картинке быстрее, чем по названию: «та самая
   квартира с эркером» вспоминается раньше, чем «Мойка, 12». */
.projcard__cover {
  flex: none; width: 88px; height: 88px; border-radius: var(--radius);
  overflow: hidden; display: grid; place-items: center;
  background: var(--surface); color: var(--text-faint);
}
.projcard__cover img { width: 100%; height: 100%; object-fit: cover; object-position: center center; display: block; }
.projcard__cover.is-empty { border: 1px solid var(--border); }
.projcard__cover svg { width: 60%; height: 60%; }
/* Та же обложка в настройках проекта — крупнее, чтобы было видно, что
   именно встанет на карточку после обрезки по центру. */
.projcard__cover--big { width: 96px; height: 96px; border-radius: var(--radius-lg); }
/* Название не ужимается ниже читаемого: рядом с ним в строке стоит плашка
   («Общий», «На паузе»), и с `min-width: 0` она забирала всё — от «189
   Скандинавия» оставалось «18 9…», а перенос по любому месту рвал число
   пополам. Теперь имя держит больше половины строки, а плашке, если ей
   не хватило, строка достаётся своя. */
.projcard__name {
  flex: 1 1 auto; min-width: 60%;
  font-size: var(--t-md); font-weight: 600; line-height: 1.3;
  color: var(--text); overflow-wrap: break-word;
  text-align: left; font-family: inherit; background: none; border: 0; padding: 0;
  cursor: pointer;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.projcard__top .chip { flex: none; }
.projcard__desc {
  color: var(--text-dim); font-size: var(--t-sm); line-height: 1.45; min-height: 2.9em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* Счёт задач — третьей строкой в том же столбце, что имя и описание,
   то есть справа от обложки. Своей строкой во всю ширину он оставлял
   слева пустой квадрат в размер обложки. */
.projcard__nums {
  display: flex; align-items: baseline; gap: var(--s-3); flex-wrap: wrap;
  font-size: var(--t-sm); color: var(--text-dim); margin-top: auto;
}
.projcard__late { color: var(--late-fg); font-weight: 600; }
/* Подвал переносится, а не вылезает. Лица, «Задачи» и «Комплектация»
   в одну строку на узкой карточке не помещались, и всё лишнее уезжало
   за её край — вместе с ним появлялась полоса прокрутки у всей страницы.
   Не влезло — кнопки уходят строкой ниже и остаются прижатыми вправо. */
.projcard__foot {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  border-top: 1px solid var(--border); padding-top: var(--s-3);
}
/* Лица не растягивают подвал и не наезжают на подпись: ряд занимает столько,
   сколько занимает, а лишнее уходит под обрез. Без overflow отрицательные
   поля аватарок выносили их поверх соседнего текста. */
.projcard__faces {
  display: flex; align-items: center; gap: 3px; flex: 1 1 auto;
  min-width: 0; overflow: hidden;
}
.projcard__faces .avatar { border: 2px solid var(--raised); margin-left: -6px; }
.projcard__faces .avatar:first-child { margin-left: 0; }
/* Кнопки разделов: с карточки чаще идут не «в проект вообще», а в задачи
   или в комплектацию. Прижаты вправо, лица занимают остальное. */
.projcard__go { flex: none; display: flex; gap: var(--s-2); margin-left: auto; }
@media (max-width: 760px) {
  /* Число колонок задано ступенями выше — здесь только то, что от них
     не зависит. Прежняя строка «в один столбец» ломала вторую ступень:
     между 640 и 760 должно оставаться два столбца. */
  /* В один столбец выравнивать нечего — пустое описание просто уходит */
  .projcard__desc { min-height: 0; }
  .projcard__desc:empty { display: none; }
  /* На телефоне обложка мельче: карточка здесь во всю ширину экрана,
     описание получает строку целиком, и картинка в 88 точек отодвигала бы
     его вниз, съедая половину видимой карточки. */
  .projcard__cover { width: 56px; height: 56px; }
  .projcard__top { gap: var(--s-3); }
  /* Поля в размер экрана: на телефоне карточка занимает всю ширину, и
     двадцатипиксельные поля с обеих сторон съедали десятую часть строки. */
  .projcard { padding: var(--s-4); gap: var(--s-2); }
}

/* Сводный график планирования: высота по числу строк, но не выше экрана */
.planchart {
  position: relative; height: clamp(320px, calc(100dvh - 320px), 900px);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); overflow: hidden;
}

/* ── Экран задачи ────────────────────────────────────────────────────────── */
/* Та же карточка, что и в панели сбоку, но на полотне страницы: своей прокрутки
   нет — листает страница, как и везде. Ширина ограничена: поля в строку на
   весь монитор читать невозможно. */
/* Ширины своей у страницы задачи больше нет — она такая же, как у главной
   и у списка проектов. Была уже: сперва 880, потом 1000 при общих 1440,
   и переход из списка в задачу выглядел как переход в другое приложение —
   полотно вдруг сужалось. Длинная строка в описании читается хуже узкой,
   это правда, но за неё платили тем, что на широком экране справа от задачи
   лежало пустое поле в треть монитора. */
.page--task { position: relative; }

/* Перенос файлов: цель — вся страница, а не кнопка «Добавить файл». Целиться
   в кнопку с файлом в руке неудобно, да и не всякий догадается, что можно.
   Страницу не заслоняем: рамка по краю и подсказка внизу экрана — содержимое
   должно остаться видно, чтобы было понятно, куда именно кладёшь. */
.taskdrop { display: none; }
.page--task.is-drop {
  outline: 2px dashed var(--accent); outline-offset: var(--s-3);
  border-radius: var(--radius-lg);
}
.page--task.is-drop .taskdrop {
  display: block; position: fixed; left: 50%; bottom: var(--s-6);
  transform: translateX(-50%); z-index: 60; pointer-events: none;
  background: var(--accent); color: var(--accent-text); font-weight: 600;
  font-size: var(--t-sm); padding: var(--s-2) var(--s-4);
  border-radius: var(--radius-full); box-shadow: var(--shadow-md);
}
/* ── Экран задачи: две колонки ───────────────────────────────────────────
   23 сентября 2026, разбор владельца: «весь интерфейс выглядит максимально
   убого». Свойства задачи стояли россыпью пунктирных пилюль в три ряда,
   подписи капсом мешались со значениями, пустые разделы рисовались
   пунктирными коробками во всю ширину. Глазу не за что было зацепиться.

   Теперь как в трекерах, к которым привыкли: слева то, что читают
   и пишут, — название, описание, чек-лист, файлы, обсуждение; справа узкая
   колонка свойств строками «подпись — значение». Ширину колонки считает
   сама страница (container query): полотну её задаёт ещё и левая колонка
   приложения, открыта она или свёрнута, и порог по окну врал бы. */
.page--task { container-type: inline-size; }

/* Шапка — одна тихая строка: стрелка назад, путь, справа ход по списку
   и «…». Название в ней больше не стоит — оно над содержимым. */
.tview__bar {
  display: flex; align-items: center; gap: var(--s-2);
  margin-bottom: var(--s-4); min-height: 32px;
}
.tview__bar .crumbs { margin: 0; min-width: 0; }
.tview__bar > .spacer { flex: 1; }
.tview__bar .sheet__status { font-size: var(--t-xs); white-space: nowrap; }

.tview {
  display: grid; align-items: start;
  grid-template-columns: minmax(0, 1fr) 288px;
  grid-template-areas: 'title side' 'main side';
  grid-template-rows: auto 1fr;
  column-gap: var(--s-7); row-gap: var(--s-4);
}
.tview__title { grid-area: title; min-width: 0; }
.tview__main { grid-area: main; min-width: 0; }
/* Колонка свойств держится на экране, пока листают описание: статус
   и сроки спрашивают чаще всего, и искать их прокруткой вверх незачем.
   Линия слева — единственная рамка на экране: она отделяет свойства от
   записки, не заключая ни то ни другое в коробку. */
.tview__side {
  grid-area: side; position: sticky; top: var(--s-4); min-width: 0;
  padding-left: var(--s-5); border-left: 1px solid var(--border);
}
/* Род задачи над названием — только когда это не просто задача */
.tview__kind {
  font-size: var(--t-xs); font-weight: 500; color: var(--text-faint);
  margin-bottom: var(--s-1);
}
/* Название правится на месте. Поле без рамки, пока его не трогают, и
   сдвинуто влево на своё поле — на общую вертикаль встаёт текст, а не
   подложка (docs/ОБЛИК-И-ШКАЛЫ.md, «Выравнивание — по тексту»). */
.tview__title .input {
  display: block; width: calc(100% + 2 * var(--s-2));
  margin-left: calc(-1 * var(--s-2));
  height: auto; padding: var(--s-1) var(--s-2);
  font-size: var(--t-2xl); font-weight: 600; line-height: 1.25;
  letter-spacing: -.015em;
  border-color: transparent; background: transparent;
  resize: none; overflow: hidden; font-family: inherit;
}
.tview__title .input:hover:where([data-hover="mouse"] *):not(:disabled) { border-color: var(--border); background: var(--surface); }
.tview__title .input:focus { border-color: var(--accent); background: var(--surface); }
.tview__title .input:disabled { color: var(--text); opacity: 1; }

/* Узкое полотно: одна колонка. Свойства встают между названием
   и описанием компактным блоком на утопленной подложке — отдельно
   от записки, но без рамки. */
@container (max-width: 760px) {
  .tview {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: 'title' 'side' 'main';
    grid-template-rows: auto;
  }
  .tview__side {
    position: static; border-left: 0;
    padding: var(--s-2) var(--s-3) var(--s-2) var(--s-4);
    background: var(--well); border-radius: var(--radius-lg);
  }
  .tview__title .input { font-size: var(--t-xl); }
  .taskstep__at { display: none; }
}
@container (max-width: 460px) {
  /* Путь переносится на свою строку под стрелкой и действиями: иначе
     на телефоне ему оставалась щель в полтораста точек */
  .tview__bar { flex-wrap: wrap; row-gap: var(--s-1); }
  .tview__bar .crumbs { order: 5; flex-basis: 100%; }
  .tview__bar .sheet__status { display: none; }
}

/* ── Колонка свойств ─────────────────────────────────────────────────────── */
.tprops { display: flex; flex-direction: column; gap: var(--s-05); }
.tprop {
  display: grid; grid-template-columns: calc(2 * var(--s-7)) minmax(0, 1fr);
  column-gap: var(--s-3); align-items: start;
}
.tprop__label {
  display: flex; align-items: center; min-height: 30px;
  font-size: var(--t-sm); color: var(--text-dim);
}
/* Значения сдвинуты влево на поле плашки: текст значения встаёт на одну
   вертикаль, а подложка при наведении выступает левее, как и положено фону */
.tprop__value {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--s-1);
  min-width: 0; margin-left: calc(-1 * var(--s-2));
}
/* Люди — по человеку в строке, кнопки «добавить» — общей строкой под ними */
.tprop--people .tprop__value { flex-direction: column; align-items: flex-start; }
.tprop__adds { display: flex; flex-wrap: wrap; gap: 0 var(--s-1); }
.tprop__faint, .tprop__late, .tprop__link { padding: 0 var(--s-2); }
.tprop__faint { font-size: var(--t-sm); color: var(--text-faint); line-height: 30px; }
.tprop__late { font-size: var(--t-xs); font-weight: 600; color: var(--late-fg); }
/* «Убрать срок» — своей строкой под датами, тихой ссылкой */
.tprop__link {
  flex-basis: 100%; text-align: left; background: none; border: 0; cursor: pointer;
  font: inherit; font-size: var(--t-xs); color: var(--text-faint);
  padding-top: var(--s-05); padding-bottom: var(--s-1);
}
.tprop__link:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); text-decoration: underline; }
/* Черта между группами: состояние, люди, где и что */
.tprops__gap { border-top: 1px solid var(--border); margin: var(--s-2) 0; }
.tprops__note {
  font-size: var(--t-xs); color: var(--text-dim); line-height: 1.45;
  background: var(--surface-2); border-radius: var(--radius);
  padding: var(--s-2) var(--s-3); margin-bottom: var(--s-3);
}
@container (max-width: 760px) {
  .tprops__note { background: var(--surface); }
}

/* Плашки в колонке свойств — строкой текста, без заливки и пунктира.
   Подложка приходит под курсором: этого хватает, чтобы понять, что
   значение нажимается, а в покое колонка читается ровным столбцом. */
.tprops .tpill {
  height: 30px; max-width: 100%; padding: 0 var(--s-2);
  background: transparent; border: 0; border-radius: var(--radius-sm);
  color: var(--text); font-weight: 400;
}
.tprops .tpill--act:hover:where([data-hover="mouse"] *), .tprops .tpill--act.is-open { background: var(--hover); color: var(--text); }
.tprops .tpill--status { font-weight: 500; }
.tprops .tpill--project { color: var(--accent-fg); font-weight: 500; }
.tprops .tpill--project.tpill--act:hover:where([data-hover="mouse"] *) { background: var(--accent-soft); color: var(--accent-hover); }
.tprops .tpill--type, .tprops .tpill--prio { color: var(--tpill-color, var(--text)); font-weight: 500; }
.tprops .tpill--type.tpill--act:hover:where([data-hover="mouse"] *), .tprops .tpill--prio.tpill--act:hover:where([data-hover="mouse"] *) {
  background: color-mix(in srgb, var(--tpill-color, #64748b) 14%, transparent);
}
.tprops .tpill--put, .tprops .tpill--add { color: var(--text-faint); }
.tprops .tpill--put:hover:where([data-hover="mouse"] *), .tprops .tpill--add:hover:where([data-hover="mouse"] *) { color: var(--text-dim); }
.tprops .tpill--late { color: var(--late-fg); font-weight: 600; }
.tprops .tpill--late.tpill--act:hover:where([data-hover="mouse"] *) { background: var(--overdue-soft); color: var(--late-fg); }
.tprops .tpill--who { padding-left: var(--s-1); }
.tprops .tpill--who .avatar { width: 22px; height: 22px; }
/* Предлоги у сроков — строчными, вплотную к своей дате: «с 24 сентября» */
.tprops .tmeta__pair { gap: 0; }
.tprops .tpill__lead--pre {
  margin: 0; padding-left: var(--s-2);
  font-size: var(--t-sm); text-transform: none; font-family: var(--font); letter-spacing: 0;
}
.tprops .tmeta__pair .tpill { padding: 0 var(--s-1); }

/* ── Содержимое: разделы без коробок ─────────────────────────────────────── */
.tbody { display: flex; flex-direction: column; }
.tbody__main { min-width: 0; display: flex; flex-direction: column; gap: var(--s-5); }
.tbody__rest { margin-top: var(--s-5); }
.tbody__rest .progress-wrap .ckbar { flex: 1; margin: 0; }
.tbody__rest .tsec { margin-top: var(--s-5); }
.tsec { min-width: 0; }

/* Заголовок раздела — обычным регистром и весом заголовка. Мелкая
   прописная с чертой под ней делала «Описание» такой же подписью, как
   «Поставил» в свойствах, и иерархии между ними не было. */
.tsec__head {
  display: flex; align-items: baseline; gap: var(--s-2);
  font-size: var(--t-base); font-weight: 600; color: var(--text);
  margin-bottom: var(--s-2);
}
.tsec__count { font-size: var(--t-sm); font-weight: 400; color: var(--text-faint); font-variant-numeric: tabular-nums; }
/* Два сложенных раздела подряд — две строки списка, а не два раздела:
   зазор между ними как между пунктами */
.tsec--fold + .tsec--fold { margin-top: calc(-1 * var(--s-4)); }

/* Тихая строка «+ действие»: пустой раздел, новый пункт, файл.
   Без рамки — плюс и бледный текст говорят «сюда можно добавить», не
   перекрикивая написанное. Сдвинута влево на своё поле: плюс встаёт
   на вертикаль текста. */
.tadd {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: var(--s-1) var(--s-2); margin-left: calc(-1 * var(--s-2));
  background: none; border: 0; border-radius: var(--radius-sm); cursor: pointer;
  font: inherit; font-size: var(--t-sm); color: var(--text-faint); text-align: left;
  transition: color var(--fast), background var(--fast);
}
.tadd:hover:where([data-hover="mouse"] *) { color: var(--text); background: var(--hover); }
/* Плюс шириной с флажок чек-листа: новый пункт встаёт в столбик с прежними */
.tadd__plus {
  display: inline-flex; justify-content: center; width: 20px; flex: none;
  font-size: var(--t-md); line-height: 1;
}
/* Строка ввода нового пункта — та же строка списка, что и пункты */
.tadd--row {
  display: flex; width: 100%; margin-left: 0; padding: var(--s-2) 0;
  gap: var(--s-3); cursor: text;
}
.tadd--row:hover:where([data-hover="mouse"] *) { background: none; }
.tadd--row:focus-within .tadd__plus { color: var(--accent-fg); }
.tadd__input {
  flex: 1; min-width: 0; padding: 0; border: 0; outline: none; background: transparent;
  font: inherit; font-size: var(--t-base); color: var(--text);
}
.tadd__input::placeholder { color: var(--text-faint); }

/* Описание — поле, похожее на поле: тонкая рамка говорит, что сюда пишут,
   а подсказка в пустом — что именно. Без рамки оно читалось просто текстом,
   и было непонятно, что его можно править. Кто править не может, видит
   текст без рамки: поле, в которое нельзя писать, звало бы напрасно. */
.tbody__main .textarea.tnotes {
  border-color: var(--border); background: transparent;
  padding: var(--s-3); border-radius: var(--radius); line-height: 1.6;
}
.tbody__main .textarea.tnotes:hover:where([data-hover="mouse"] *):not(:disabled) { border-color: var(--border-strong); background: transparent; }
.tbody__main .textarea.tnotes:focus { border-color: var(--accent); background: var(--surface); }
.tbody__main .textarea.tnotes:disabled {
  border-color: transparent; padding-left: 0; padding-right: 0; color: var(--text); opacity: 1;
}

/* Чек-лист и файлы на экране задачи — без черт между строками:
   разделяет воздух, а крестик приходит под курсором */
.tview .ckbar { height: 4px; margin-bottom: var(--s-2); }
.tview .ckrow { border-bottom: 0; padding: var(--s-1) 0; }
@media (hover: hover) {
  .tview .ckrow > .btn, .tview .tfile > .btn { opacity: 0; transition: opacity var(--fast); }
  .tview .ckrow:hover:where([data-hover="mouse"] *) > .btn, .tview .tfile:hover:where([data-hover="mouse"] *) > .btn,
  .tview .ckrow > .btn:focus-visible, .tview .tfile > .btn:focus-visible { opacity: 1; }
}

/* Строка «Загрузить файл · С диска» — без рамки в покое. Пунктир приходит,
   только когда над ней держат файл: тогда и надо видеть, куда он упадёт. */
.tview .tfiles__drop {
  gap: var(--s-1); margin: var(--s-1) 0 0 calc(-1 * var(--s-2));
  padding: var(--s-05) 0; border: 1px dashed transparent;
}
.tview .tfiles__drop .tadd { margin-left: 0; }
.tview .tfiles__drop.is-dropping { border-color: var(--accent); background: var(--accent-soft); }
.tfiles__hint { font-size: var(--t-xs); margin-left: var(--s-1); }

/* Разговор о задаче: строка с объяснением и кнопкой в чат */
.ttalk {
  display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap;
  padding: var(--s-3) var(--s-4); background: var(--surface-2); border-radius: var(--radius);
}
.ttalk__txt { flex: 1 1 200px; min-width: 0; font-size: var(--t-sm); }

/* Складки экрана задачи — «История изменений», «Прежнее обсуждение»,
   «Служебное» — обычным регистром, тихим цветом, без черты сверху.
   Мелкая прописная здесь была третьим видом подписи на одном экране. */
.fold.tfold { border-top: 0; margin-top: 0; padding-top: 0; }
.fold.tfold > summary {
  font-size: var(--t-sm); font-weight: 500; text-transform: none; font-family: var(--font); letter-spacing: 0;
  color: var(--text-dim);
}
.fold.tfold > summary:hover:where([data-hover="mouse"] *) { color: var(--text); }
.tfold:not([hidden]) + .tfold { margin-top: calc(-1 * var(--s-3)); }

/* Переход к соседней задаче: разбирая этап, после каждой возвращались
   в список. Счёт между стрелками говорит, что это ход по списку. */
.taskstep { display: flex; align-items: center; gap: var(--s-1); flex: none; }
.taskstep button:disabled { opacity: .35; cursor: default; }
.taskstep__at {
  font-size: var(--t-xs); color: var(--text-faint); white-space: nowrap;
  font-variant-numeric: tabular-nums; padding: 0 var(--s-1);
}

/* Поле, которое растёт по тексту: уголок растягивания предлагал работу,
   которой быть не должно — заметка сама знает, сколько ей места */
.textarea--grow { resize: none; overflow: hidden; }
/* Поля на странице задачи — без рамок, пока их не трогают: страница должна
   читаться как записка, а не как анкета. Рамка появляется под курсором —
   этого хватает, чтобы понять, что текст правится. */
.tbody__main .textarea, .tbody__main .input {
  background: transparent; border-color: transparent;
}
.tbody__main .textarea:hover:where([data-hover="mouse"] *):not(:disabled),
.tbody__main .input:hover:where([data-hover="mouse"] *):not(:disabled) { border-color: var(--border); background: var(--surface); }
.tbody__main .textarea:focus, .tbody__main .input:focus {
  border-color: var(--accent); background: var(--surface);
}
/* Высоту теперь считает содержимое: коробка в сто шестнадцать пикселей
   стояла и под одной строкой, и под пустотой, читаясь как форма */
.textarea--lead { min-height: 0; }

/* ── Метки задачи ────────────────────────────────────────────────────────── */
/* Основа плашки значения. На экране задачи она живёт в колонке свойств
   и там переодета строкой текста (.tprops .tpill выше); здесь то, что
   общее: высота, выравнивание, огонёк, точка статуса, меню по нажатию. */
.tpill {
  display: inline-flex; align-items: center; height: 30px; padding: 0 var(--s-3);
  border: 1px solid transparent; border-radius: var(--radius-full);
  background: var(--surface-2); color: var(--text-dim);
  font-size: var(--t-sm); font-weight: 500; white-space: nowrap;
  max-width: 260px; box-shadow: none;
}
.tpill__in { display: inline-flex; align-items: center; gap: var(--s-2); min-width: 0; }
.tpill__txt { overflow: hidden; text-overflow: ellipsis; display: inline-flex;
  align-items: center; gap: 5px; }
/* Огонёк важности на плашке задачи — тот же знак, что на карточке, только
   меньше: там он стоит в кружке отдельно, здесь идёт перед словом. */
.tpill__hot { font-size: var(--t-sm); line-height: 1; flex: none; }
/* Погасший: важность не поднята, но поднять её можно. Тот же приём, что
   у огонька на карточке, — знак остаётся на месте и не заводит новый ряд. */
.tpill__hot--off { color: var(--ink-3); }
/* Молния набора, а не эмодзи 🔥 (сверка с ТЗ, 28 сентября 2026): на
   карточке она уже была молнией, а в листе задачи стоял огонёк — один
   знак важности в двух видах. Цвет — от плашки, то есть ступени. */
.tpill__hot { display: inline-grid; place-items: center; }
.tpill__hot .ic, .tpill__hot svg { display: block; }
.tpill__dot {
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--tpill-color, var(--text-faint));
}
.tpill--act { cursor: pointer; transition: background var(--fast), color var(--fast); }
.tpill--act:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }
.tpill--act.is-open { background: var(--surface-3); color: var(--text); }
.tpill--act:active { transform: scale(.97); }

.tpill--status { font-weight: 600; color: var(--text); }
.tpill--project { background: var(--accent-soft); color: var(--accent-hover); font-weight: 600; }
.tpill--project.tpill--act:hover:where([data-hover="mouse"] *) { background: var(--accent-soft); color: var(--accent-fg); }
.tpill--floor { background: var(--surface-3); }
.tpill--type, .tpill--prio {
  background: color-mix(in srgb, var(--tpill-color, #64748b) 14%, transparent);
  color: var(--tpill-color, #64748b); font-weight: 600;
}
.tpill--type.tpill--act:hover:where([data-hover="mouse"] *), .tpill--prio.tpill--act:hover:where([data-hover="mouse"] *) {
  background: color-mix(in srgb, var(--tpill-color, #64748b) 22%, transparent);
  color: var(--tpill-color, #64748b);
}
.tpill--date { background: transparent; border-color: var(--border); }
.tpill--date.tpill--act:hover:where([data-hover="mouse"] *) { background: var(--hover); border-color: var(--border-strong); }
.tpill--late { color: var(--late-fg); border-color: var(--overdue); font-weight: 600; }
.tpill--late.tpill--act:hover:where([data-hover="mouse"] *) { background: var(--overdue-soft); color: var(--late-fg); }
.tpill--who { padding-left: var(--s-1); }
.tpill--who .avatar { width: 22px; height: 22px; font-size: var(--t-2xs); }
/* Незаполненное — бледным текстом, без пунктира: пунктирная рамка у каждой
   пустой метки складывалась в узор, который читался громче значений */
.tpill--put, .tpill--add { background: transparent; color: var(--text-faint); }
.tpill--put:hover:where([data-hover="mouse"] *), .tpill--add:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text-dim); }

/* ── Наш календарь вместо системного ─────────────────────────────────────── */
.datepop {
  position: fixed; z-index: 60; padding: var(--s-3);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
  animation: fade-in .1s var(--ease);
}
.datepop__head { display: flex; align-items: center; gap: var(--s-2); margin-bottom: var(--s-2); }
.datepop__month {
  flex: 1; text-align: center; font-weight: 600; font-size: var(--t-sm);
}
.datepop__nav {
  width: 26px; height: 26px; border: none; background: transparent; cursor: pointer;
  border-radius: var(--radius-full); color: var(--text-dim);
  display: inline-grid; place-items: center; padding: 0;
}
.datepop__nav:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }
.datepop__grid { display: grid; grid-template-columns: repeat(7, 32px); gap: 2px; }
.datepop__wd {
  display: grid; place-items: center; height: 22px;
  font-size: var(--t-2xs); color: var(--text-faint); text-transform: uppercase;
}
.dateday {
  height: 30px; border: none; background: transparent; cursor: pointer;
  border-radius: var(--radius-full); color: var(--text); font-size: var(--t-sm);
  font-variant-numeric: tabular-nums; transition: background var(--fast);
}
.dateday:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.dateday.is-out { color: var(--text-faint); opacity: .55; }
.dateday.is-off { color: var(--text-faint); background: var(--off); }
.dateday.is-off:hover:where([data-hover="mouse"] *) { background: color-mix(in srgb, var(--ink) 7%, var(--well)); }
.dateday.is-today { box-shadow: inset 0 0 0 1.5px var(--today); font-weight: 600; }
.dateday.is-sel { background: var(--accent); color: var(--accent-text); font-weight: 600; }
.dateday.is-sel:hover:where([data-hover="mouse"] *) { background: var(--accent-hover); }
.datepop__foot {
  display: flex; gap: var(--s-1); margin-top: var(--s-2);
  padding-top: var(--s-2); border-top: 1px solid var(--border);
}

@media (max-width: 760px) {
  .tpill { max-width: 100%; }
}

/* Номер задачи — последней ступенью крошек. Кнопка, но не выглядит
   кнопкой: она копирует ссылку, а звать к себе ей незачем. Подчёркивание
   при наведении говорит, что нажать можно, ровно в тот момент, когда об
   этом спрашивают. Селектор через .crumbs: общее правило кнопок крошек
   иначе перебило бы моноширинный шрифт. */
.crumbs .tasknum {
  flex: none; padding: 0 var(--s-05);
  font-family: var(--mono); font-size: var(--t-mono); color: var(--text-faint);
}
.crumbs .tasknum:hover:where([data-hover="mouse"] *) { color: var(--text-dim); }

/* ── Карточка коллеги в разделе «Команда» ────────────────────────────────── */
/* Человек, почта и одна строка состояния: на месте он сегодня или нет.
   Ничего больше здесь не нужно — за задачами идут в проект, за отпуском в табель. */
.pcard {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: var(--s-4);
  display: flex; flex-direction: column; gap: var(--s-3); align-items: flex-start;
}
.pcard__top { display: flex; align-items: center; gap: var(--s-4); min-width: 0; }
/* «в отпуске до 28.08.2026» — плашка длинная, и в узкой карточке (четыре
   в ряд) она распирала верх наружу вместе с именем. Пусть переносится. */
.pcard__top .chip { display: inline-flex; white-space: normal; }
.pcard__name { font-weight: 600; font-size: var(--t-base); }
.pcard__mail {
  display: block; font-size: var(--t-sm); color: var(--text-dim);
  text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Заголовок колонки — кнопка: по нему открывается полный список проектов */
.side__title--act {
  background: none; border: none; cursor: pointer; width: 100%; text-align: left;
  font: inherit; font-size: var(--t-2xs); font-weight: 500; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-faint); padding: var(--s-2) 0;
  transition: color var(--fast);
}
.side__title--act:hover:where([data-hover="mouse"] *) { color: var(--text-dim); }

/* Значки приложения: свой контур вместо эмодзи. Эмодзи на маке выглядят
   прилично, а на windows и android — как попало, разного веса и размера,
   и в одном ряду не стоят. */
.ic { display: inline-flex; align-items: center; justify-content: center; flex: none; }
.ic svg { display: block; }
.navitem__icon .ic svg { width: 18px; height: 18px; }

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

/* Плашка песочницы: спокойная, но заметная. Человек по ссылке должен сразу
   понять, что всё здесь ненастоящее и сломать он ничего не может. */
.sandbox {
  display: inline-flex; align-items: center; gap: var(--s-2); flex: none;
  height: 32px; padding: 0 var(--s-2) 0 var(--s-3); border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--warn, #e0932a) 14%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--warn, #e0932a) 35%, transparent);
  font-size: var(--t-2xs); color: var(--text);
}
.sandbox__dot {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--warn, #e0932a);
}
.sandbox__text { display: flex; gap: var(--s-2); align-items: baseline; white-space: nowrap; }
.sandbox__text span { color: var(--text-dim); }
.sandbox__reset {
  border: none; background: none; cursor: pointer; font: inherit; font-weight: 600;
  color: var(--accent-fg); padding: 0 var(--s-2); border-radius: var(--radius-sm);
}
.sandbox__reset:hover:where([data-hover="mouse"] *) { background: var(--hover); }
/* На узком экране остаётся только слово и кнопка: объяснение вытесняло
   разделы из полосы */
/* Резервный сервер — та же плашка, цветом сведений, а не предупреждения */
.sandbox--zerkalo { background: color-mix(in srgb, var(--accent) 12%, var(--surface));
  border-color: color-mix(in srgb, var(--accent) 35%, transparent); }
.sandbox--zerkalo .sandbox__dot { background: var(--accent); }
@media (max-width: 1400px) { .sandbox__text span { display: none; } }
@media (max-width: 900px) { .sandbox__text b { display: none; } }

/* Скрытый текст — как в телеграме: текст размыт и присыпан мелкими точками,
   которые медленно плывут. Чёрный прямоугольник кричал «здесь что-то есть»
   и выглядел дырой в тексте; размытое пятно читается как текст, который
   просто не разобрать. Защиты тут нет — строка лежит в базе как есть; это
   про то, чтобы пароль от общего сервиса не читался через плечо. */
.spoiler {
  cursor: pointer; user-select: none; border-radius: var(--radius-sm);
  padding: 0 1px;
  /* Сам текст невидим, но оставляет размытый след — форма слов сохраняется */
  color: transparent;
  text-shadow: 0 0 5px var(--text);
  background-image:
    radial-gradient(circle at 1px 1px, currentColor .8px, transparent .9px),
    radial-gradient(circle at 3px 4px, currentColor .6px, transparent .7px);
  background-size: 6px 6px, 8px 7px;
  background-position: 0 0, 2px 1px;
  animation: spoiler-drift 9s linear infinite;
  transition: text-shadow var(--fast), color var(--fast);
}
.spoiler * { color: inherit; text-shadow: inherit; }
@keyframes spoiler-drift {
  to { background-position: 24px 12px, 26px 15px; }
}
.spoiler.is-open {
  color: inherit; text-shadow: none; background-image: none;
  animation: none; cursor: auto; user-select: text;
  background-color: var(--surface-2);
}
.spoiler.is-open * { color: inherit; text-shadow: none; }
@media (prefers-reduced-motion: reduce) { .spoiler { animation: none; } }

/* Ширину страница задачи берёт общую — см. .page--task выше. */
/* Подпись перед исполнителями: без неё аватарки читались как «кто-то» */
.tpill__lead {
  font-size: var(--t-2xs); color: var(--text-faint);
  text-transform: uppercase; font-family: var(--mono); font-weight: 500; letter-spacing: .08em; margin-left: var(--s-2);
}
/* Предлог перед датой — та же подпись, что «Поставил» и «Делает», но вплотную
   к своей кнопке: «с» и дата читаются вместе, а с общим отступом слева предлог
   отрывался от даты и прилипал к предыдущей плашке */
.tpill__lead--pre { margin-left: 0; margin-right: calc(-1 * var(--s-1)); }
/* Подпись со своим значением. Переносится парой: по отдельности на телефоне
   выходило «ПРОСРОЧЕНА С» в конце строки и «3 августа» в начале следующей —
   подпись без числа и число без подписи. Внутри пары переносов нет,
   между парами есть. */
.tmeta__pair { display: inline-flex; align-items: center; gap: var(--s-2); }
.tmeta__pair .tpill__lead { margin-left: 0; }
/* Длинное имя задачи не должно распирать меню на весь экран */
.menupop { max-width: min(420px, calc(100vw - 32px)); }
.menurow { text-align: left; overflow-wrap: anywhere; }

.pcard__mail:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); text-decoration: underline; }
/* Карточка человека отвечает на вопрос «к кому идти»: должность, город,
   чем поможет и как связаться. Строки набраны парами «что — значение»,
   чтобы карточка читалась сверху вниз, а не расползалась абзацем. */
/* Карточек в ряд — сколько задано в админке, но не в ущерб читаемости:
   ширина колонки считается точно под нужное число, а если она уходит ниже
   210 пикселей, браузер сам ставит в ряд меньше. Так одно и то же правило
   даёт «четыре в ряд» на большом экране и одну на телефоне. */
/* Отбор людей по имени и умению */
.teamfind { max-width: 360px; margin-bottom: var(--s-3); }
.softfilter { display: flex; gap: var(--s-2); flex-wrap: wrap; margin-bottom: var(--s-4); }
.softtag {
  border: 1px solid var(--border); background: var(--surface); cursor: pointer;
  font: inherit; font-size: var(--t-xs); color: var(--text-dim);
  padding: var(--s-1) var(--s-3); border-radius: var(--radius-full);
  transition: border-color var(--fast), color var(--fast), background var(--fast);
}
.softtag:hover:where([data-hover="mouse"] *) { border-color: var(--border-strong); color: var(--text); }
.softtag.is-active { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-fg); font-weight: 600; }
.softtag--flat { cursor: default; background: var(--surface-2); border-color: transparent; }

/* Должность — подпись, а не ссылка: акцент — для того, что нажимается
   и выбрано (ТЗ, раздел 1: «один акцент»; макет — --ink-2) */
.pcard__post { font-size: var(--t-sm); color: var(--ink-2); }
.pcard__about { font-size: var(--t-sm); color: var(--text-dim); line-height: 1.45; }
/* Подписи и значения — двумя столбцами: «день рождения» длиннее прочих
   подписей и сдвигал своё значение с общей вертикали (сверка 28 сентября 2026) */
.pcard__lines {
  display: grid; grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--s-1) var(--s-3); align-items: baseline; width: 100%; font-size: var(--t-sm);
}
.pcard__line { display: contents; }
.pcard__k {
  flex: none; min-width: 62px; font-size: var(--t-2xs); color: var(--text-faint);
  text-transform: uppercase; font-family: var(--mono); font-weight: 500; letter-spacing: .08em;
}
.pcard__v { color: var(--text); text-decoration: none; word-break: break-word; min-width: 0; }
a.pcard__v:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); text-decoration: underline; }
.pcard__soft { font-size: var(--t-sm); color: var(--text-dim); white-space: pre-line; }
/* Город под должностью: раньше он жил внутри плашки «на месте · Москва»,
   и чтобы узнать, где человек, приходилось читать очевидное «на месте» */
.pcard__where { font-size: var(--t-xs); color: var(--text-faint); margin-top: var(--s-05); }
/* «Чем помогает» — в две строки: у одного строка, у другого пять, и ряд
   карточек выходил рваным */
.pcard__helps {
  font-size: var(--t-sm); color: var(--text-dim); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.pcard__hobby { font-size: var(--t-sm); color: var(--text-faint); font-style: italic; }


/* Включённый фильтр видно по акценту: иначе непонятно, почему задач мало */
.select.is-on {
  border-color: var(--accent); color: var(--accent-fg); font-weight: 600;
  background-color: var(--accent-soft);
}
/* То же самое для кнопки-воронки: значок без подписи обязан показывать,
   что отбор включён, иначе половина задач пропадает без объяснения */
.btn.is-on {
  border-color: var(--accent); color: var(--accent-fg);
  background-color: var(--accent-soft); position: relative;
  /* Под мышью включённая воронка остаётся включённой: подложка чуть
     гуще своей, а не серая общая */
  --btn-hover-bg: color-mix(in oklab, var(--accent-soft), var(--ink) 6%);
  --btn-hover-line: var(--accent);
}
.btn.is-on::after {
  content: ''; position: absolute; top: 3px; right: 3px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 0 2px var(--surface);
}

/* ── Телефон: переосмысление ─────────────────────────────────────────────────
   Раздел держим последним: он правит то, что объявлено выше для широкого
   экрана. Правил здесь три.

   Первое: листает сама страница, а не рамка внутри неё. Приложение было
   закреплено по краям окна (body: position fixed), и содержимое ездило внутри
   своей коробки. На телефоне это стоит дорого: браузер не прячет адресную
   строку, потому что страница «не листается», прокрутка теряет инерцию,
   а вложенные полосы спорят друг с другом.

   Второе: палец не мышь. Карточка берётся долгим нажатием (это в скрипте),
   всё нажимаемое — не меньше 44 пикселей, наведения нет вовсе.

   Третье: на 375 точках дорога каждая строка. Карточки не держат общую
   высоту, вид «строками» становится настоящим списком в одну линию. */

@media (max-width: 760px) {
  html, body, #root { height: auto; }
  body { position: static; inset: auto; overflow-x: hidden; overscroll-behavior: auto; }
  .app { height: auto; min-height: 100dvh; overflow: visible; padding-bottom: 0; }
  .shell { display: block; flex: none; min-height: 0; }
  .main {
    overflow: visible; min-height: 0; overscroll-behavior: auto;
    margin: 0; border: none; border-radius: 0;
  }
  /* Полотно — до низа экрана и на короткой странице. Обычным блоком оно
     кончалось там, где кончалось содержимое, и ниже проступал фон
     приложения другого тона: у «Графиков стройки», пустых «Поставщиков»
     и «Обучения» полэкрана делила ровная черта, похожая на недогруженный
     раздел. Колонкой растягивается только в высоту — ширина и прокрутка
     страницы остаются прежними. */
  .shell { display: flex; flex-direction: column; flex: 1 0 auto; }
  .main { flex: 1 0 auto; }
  /* Шапка и разделы остаются на месте: до поиска и до «Проектов» рука
     дотягивается на любом месте списка */
  .topbar {
    position: sticky; top: 0; z-index: 30; background: var(--bg);
    padding-left: max(var(--s-3), env(safe-area-inset-left));
    padding-right: max(var(--s-3), env(safe-area-inset-right));
  }
  .nav {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
    padding-left: max(var(--s-1), env(safe-area-inset-left));
    padding-right: max(var(--s-1), env(safe-area-inset-right));
    box-shadow: 0 -1px 0 var(--border);
  }
  /* Под полосой разделов должно оставаться место — иначе последняя задача
     прячется под неё, и до неё не долистать. Высота полосы взята из её же
     объявления, а не переписана числом: расходились они молча. Сверх неё —
     ещё полполосы воздуха, чтобы последняя строка не липла к вкладкам. */
  .page {
    padding-left: max(var(--s-3), env(safe-area-inset-left));
    padding-right: max(var(--s-3), env(safe-area-inset-right));
    padding-bottom: calc(var(--nav-h, 82px) + var(--s-4) + env(safe-area-inset-bottom));
  }

  /* Карточка по содержимому, а не по общей высоте: ровный низ нужен сетке
     в три столбца, а в один столбец он оборачивался пустотой в пол-экрана */
  .cardsgrid--home .kcard--free { min-height: 0; }
  .kcard--free { gap: var(--s-1); }
  .kcard--free .kcard__meta { padding-top: var(--s-1); }

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

     Раскладка взята с компьютера намеренно, а не сведена к телефонной:
     один и тот же список не должен на разных экранах отвечать на разные
     вопросы. Метки — проект, этаж, помещение, тип — это и есть ответ
     на «что за задача»; без них три «Обмерных плана» из трёх проектов
     выглядят одинаково.

     Разница с компьютером только в ширине, и она разрешается сама:
     ряд меток переносится и обрезается по высоте одной строки — лишнее
     уходит за край по одной метке, начиная с наименее важной. Проект
     не сжимается никогда, он объявлен нерастяжимым выше по файлу.

     Срок при этом остаётся короткой записью («03.08», не «до 3 августа»):
     на второй строке он делит место с метками, и полная подпись съедала бы
     их все. */
  .cardsgrid--home.is-rows { gap: var(--s-1); }
  .is-rows .kcard--free {
    display: grid; align-items: center;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: 'title title' 'tags meta';
    column-gap: var(--s-2); row-gap: var(--s-1);
    min-height: 64px; padding: var(--s-2) var(--s-3);
  }
  .is-rows .kcard__title { grid-area: title; min-width: 0; }
  .is-rows .kcard__stage { display: none; }
  /* Ровно одна строка меток, и обрез по ней точный.

     Высота плашки задана числом, а высота ряда равна ей: иначе от второй,
     перенесённой строки оставалась снизу видимая полоска — серые огрызки
     под метками, которые читались как поломка вёрстки. Пока высота плашки
     складывалась из кегля и полей, совпадение этих двух чисел было делом
     случая. */
  .is-rows .kcard__tags {
    grid-area: tags; display: flex; margin: 0; gap: var(--s-1);
    flex-wrap: wrap; overflow: hidden; max-height: 22px; min-width: 0;
  }
  /* Кегль и поля у ярлыка общие — они заданы в `.ktag` один раз на всё
     приложение. Здесь только высота: ряд обрезается ровно по ней, и число
     должно совпасть с настоящей высотой плашки. */
  .is-rows .kcard__tags > * {
    max-width: 100%; height: 22px; display: inline-flex; align-items: center;
  }
  /* «+ Этаж», «+ Помещение», «+ Тип» — приглашения заполнить, а не сведения
     о задаче. В строке на телефоне метки не нажимаются (нажимается сама
     строка), так что приглашение никуда не ведёт, а место у настоящих
     меток отнимает. На карточках и на большом экране остаются. */
  .is-rows .kcard__tags .ktag--pusto { display: none; }
  .is-rows .kcard__meta {
    grid-area: meta; margin: 0; padding: 0; gap: var(--s-2);
    justify-content: flex-end; flex-wrap: nowrap;
  }
  /* Срок покороче: полная подпись съедала половину строки, и от названия
     оставалось восемь букв — три задачи подряд читались одинаково */
  .is-rows .kcard__date-long { display: none; }
  .is-rows .kcard__date-brief { display: inline; }
  .is-rows .kcard__pct { display: none; }
  .is-rows .kcard--add { min-height: 52px; }

  /* Заголовок раздела и его кнопки — одной строкой */
  .hblock__head { gap: var(--s-1); margin-bottom: var(--s-3); }
  /* На телефоне подпись порядка всегда короткая: шапку там не меряют —
     у неё своя раскладка, — а «По сроку» рядом с заголовком и «+» не
     помещается ни при какой ширине телефона. */
  .menulabel__full { display: none; }
  .menulabel__short { display: inline; }
  /* Три заголовка на главной — «Мои задачи», «Поручил», «Наблюдаю» —
     набраны одинаково. На большом экране «Мои задачи» крупнее: своя работа
     главная, чужая стоит под ней. На телефоне эта разница не работает:
     заголовки идут не рядом, а один под другим через экран прокрутки,
     сравнить их не с чем, и разный кегль читается не как старшинство,
     а как разнобой.
     Вес селектора поднят нарочно: правило `.fold--home > summary` объявлено
     ниже по файлу, и при равной силе побеждало бы оно — кегль задавался бы
     тем, что стоит дальше, а не тем, что относится к телефону. */
  .hblock__head h2,
  .fold.fold--home > summary { font-size: var(--t-base); }
  /* Между разделами — s-3 вместо s-5. На большом экране 24 пикселя отделяют
     раздел от раздела; на телефоне, где всё и так идёт в один столбец,
     они превращают одну страницу в три, между которыми надо ехать. */
  .fold--home { margin-top: var(--s-3); }
  /* От счёта задач остаётся одно число: «Мои задачи 9», «Поручил 12».

     «9 всего · 6 просрочено» — это полстроки на экране в 390 точек, а под
     ним сразу идёт список, где просроченное и так обведено красным. Число
     же нужно: у свёрнутого «Поручил» оно единственное, что говорит, есть
     ли там что-нибудь.

     Слово «всего» и просрочка убираются видом, а не разметкой: при повороте
     телефона строка должна меняться сама, а не ждать перерисовки списка.

     Число остаётся в одной строке с заголовком — на отдельную его выносить
     незачем, оно короткое.

     «Плюс» уходит к правому краю. На телефоне у него нет подписи — это
     просто синий квадрат, — и вплотную к заголовку он читался частью
     заголовка. У края он читается кнопкой раздела, как в любом приложении
     на этом же телефоне. */
  .hblock__count-w, .hblock__count .is-overdue { display: none; }
  .hblock__count { gap: 0; }
  /* Кнопка встаёт за распоркой по порядку, а не по автоматическому полю.
     `margin-left: auto` здесь не работает: свободное место в гибкой строке
     сперва раздаётся растущим элементам и только потом автополям, а распорка
     растущая — она забирала всё, и поле вычислялось в нуль. Распорку при
     этом трогать нельзя: в других разделах шапки она разводит заголовок
     и органы, у которых своей кнопки нет. */
  .hblock__head > .btn--primary { order: 3; }
  .hblock__head > .hblock__tools { order: 4; }
  /* То же и в свёрнутых разделах: у «Поручил» и «Наблюдаю» заголовок — это
     summary, а не .hblock__head, и правило выше их не касалось. Кнопка
     оставалась там, где стояла, — вплотную к числу, и строка читалась
     как «Поручил 11+ Задача». */
  .fold--home > summary > .btn--primary { order: 3; }
  .fold--home > summary > .hblock__tools,
  .fold--home > summary > span:last-child { order: 4; }
  /* Строка «Поручил 12 · + · просроченные · Кто делает ▾ · ▸» на 375 точках
     была шире экрана на одиннадцать точек, на 360 — на двадцать шесть:
     стрелка складки обрезалась правым краем наполовину. Уступает отбор
     «Кто делает»: подпись у него на телефоне короткая, «Кто», а имя
     выбранного человека ужимается многоточием (стрелка меню остаётся),
     и распорка может сойтись в ноль. */
  .fold--home > summary > .spacer { min-width: 0; }
  .fold--home > summary .hblock__otbor { min-width: 0; flex: 0 1 auto; }
  .hblock__otbor .btn { min-width: 0; max-width: 100%; }
  .hblock__otbor .menulabel { min-width: 0; }
  .hblock__otbor .menulabel__text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* Плитки обзора демо — в два столбца, а не потоком. Потоком они вставали
     как придётся: одна на строке, вторая на строке, две в ряд — четыре
     плитки одного веса выглядели обломками разной длины. */

  /* Окно вылезает снизу листом, а не висит посреди экрана: до кнопок ближе,
     на клавиатуре не подпрыгивает */
  .modal-backdrop { place-items: end center; padding: 0; }
  .modal {
    width: 100%; max-width: 100%; border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    max-height: 92dvh; animation: slide-up .18s var(--ease);
  }
  .modal__foot { padding-bottom: calc(var(--s-4) + env(safe-area-inset-bottom)); }
  .modal__foot .btn { flex: 1; min-height: 44px; }

  /* Правила, прятавшего ряд разрезов канбана, здесь больше нет: разрез
     переехал в меню «…» на любой ширине, и прятать стало нечего. */

  /* Метки задачи и кнопки в меню — под палец */
  .tpill { height: 34px; }
  .menurow { min-height: 44px; }
  .roundbtn { width: 42px; height: 42px; }

}

/* Карточка, поднятая долгим нажатием: видно, что она «взята» и следующее
   движение пальца потащит её, а не пролистает список */
/* Закрытая задача уходит из списка не рывком: успевает быть увиденной */
.kcard--free.is-leaving {
  opacity: 0; transform: scale(.97);
  transition: opacity .2s var(--ease), transform .2s var(--ease);
  pointer-events: none;
}

.kcard.is-lifted, .kcard--free.is-lifted {
  transform: scale(1.03); box-shadow: var(--shadow-md);
  transition: transform .12s var(--ease), box-shadow .12s var(--ease);
}

/* ── Дедлайны ────────────────────────────────────────────────────────────────
   Даты, к которым что-то сдаётся: согласование, выезд, отправка в печать.
   Раньше они лежали карточками в колонках канбана и назывались вехами —
   слово из графиков работ, которое человеку со стороны не говорит ничего,
   а карточка среди задач выглядела задачей, которую нельзя взять в работу.
   Теперь это отдельная полоса под задачами; на диаграмме они и так видны
   ромбами на своей линии, там полосы нет. */
/* Всё в одну строку: заголовок, сами даты и «+». Дедлайнов на проект
   немного — три-четыре, — и отдельная строка под заголовок «ДЕДЛАЙНЫ»
   стоила больше места, чем сами дедлайны под ней. */
.duebar {
  padding: var(--s-4) var(--s-4) var(--s-2);
  display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap;
}
/* Комплектация свою полосу дедлайнов строит сама и лежит вне .projboard —
   поля ей нужны ровно те же, что задаёт `.projboard .duebar`, иначе при
   переходе «Задачи → График закупок» полоса, панель и всё под ними съезжают
   на восемь точек вниз. Стоять правило должно ниже базового: вес у них
   одинаковый, и решает порядок. */
.duebar--flush { padding: var(--s-2) 0; }
.duebar__head {
  display: flex; align-items: center; gap: var(--s-2); flex: none;
  font-size: var(--t-2xs); text-transform: uppercase; font-family: var(--mono); letter-spacing: .08em;
  font-weight: 500; color: var(--text-faint);
}
.duebar__n {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}
.duebar__row {
  display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center;
  /* Основа 0, а не auto: с auto ряд заявлял ширину своего содержимого,
     не влезал рядом с заголовком и целиком уезжал на вторую строку —
     ровно то, от чего мы уходили. Переносятся пусть сами даты внутри. */
  flex: 1 1 0; min-width: 0;
}
/* Полоса дедлайнов — одна строка, и место в ней делится между тремя-четырьмя
   датами. Ширина ограничена жёстче прежнего: длинное имя уходит под обрез,
   целиком оно есть во всплывающей и в самой задаче. */
.duechip {
  display: inline-flex; align-items: center; gap: var(--s-2); max-width: 260px;
  height: 32px; padding: 0 var(--s-3); border-radius: var(--radius-full);
  border: 1px solid var(--border); background: var(--raised);
  font: inherit; font-size: var(--t-sm); color: var(--text); cursor: pointer;
  transition: border-color var(--fast), box-shadow var(--fast);
}
.duechip:hover:where([data-hover="mouse"] *) { border-color: var(--border-strong); box-shadow: var(--shadow-xs); }
.duechip__date {
  font-variant-numeric: tabular-nums; font-weight: 600; color: var(--text-dim); flex: none;
}
.duechip__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* Прошедший срок — тем же цветом, что и просроченная задача */
.duechip.is-late { border-color: var(--overdue); background: var(--overdue-soft); }
.duechip.is-late .duechip__date { color: var(--late-fg); }
/* «Добавить дедлайн» — один знак в той же круглой рамке, что у дедлайнов
   рядом: круг, а не пилюля, потому что внутри одна буква и растягивать её
   не во что. Пунктир говорит «здесь пока пусто», как у пустой карточки
   задачи, — форма общая на всё приложение. */
.duechip--add {
  border-style: dashed; color: var(--text-faint);
  width: 32px; padding: 0; justify-content: center; flex: none;
  font-size: var(--t-md); line-height: 1;
}
.duechip--add:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); border-color: var(--accent); }

/* ── Сводка «Что смотрят» в админке ───────────────────────────────────────
   Полоски, а не цифры столбцом: у списка из сорока строк вопрос не «сколько
   именно», а «что заметно больше остального», и на это отвечает длина,
   а не число. Число стоит рядом для тех случаев, когда всё-таки нужно точно. */
.statlist { display: flex; flex-direction: column; gap: var(--s-1); }
.statrow {
  display: grid; grid-template-columns: minmax(0, 1fr) 3fr 56px 40px;
  align-items: center; gap: var(--s-3); font-size: var(--t-sm);
}
.statrow__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.statrow__bar { height: 8px; border-radius: var(--radius-full); background: var(--well); }
.statrow__fill {
  display: block; height: 100%; border-radius: var(--radius-full);
  background: var(--accent); min-width: 2px;
}
.statrow__n, .statrow__people {
  font-variant-numeric: tabular-nums; text-align: right; color: var(--text-dim);
}
/* Сколько человек — тише числа нажатий: это уточнение, а не главное */
.statrow__people { color: var(--text-faint); font-size: var(--t-xs); }
/* Тема, которую сейчас не носит никто: ради этой строки раздел и заводили */
.table tr.is-cold td { color: var(--text-faint); }
.table tr.is-cold td:first-child { font-style: italic; }

/* ── Выбор оформления ─────────────────────────────────────────────────────
   Два вопроса подряд: когда какая тема и какие именно. Режимы — плитки,
   темы — образцы: то же приложение в миниатюре, фон, полотно, пилюля
   раздела, строки текста.

   Внутри образца стоит своя `data-theme`, поэтому картинка красится сама:
   ни одного цвета числом, добавили тему — образец появился вместе с ней.
   Штрихи внутри картинки заданы пикселями — это рисунок, а не вёрстка,
   и на общую сетку отступов он не встаёт. */

.modes { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s-2); }
@media (max-width: 460px) { .modes { grid-template-columns: 1fr; } }
/* Выбор из трёх — тремя столбцами, а не двумя с сиротой.
   В сетке на две колонки третья плитка вставала одна во втором ряду и была
   вдвое уже соседок: читалось это как «эта чем-то отличается», хотя три
   состояния здесь равноправны. Порог 900 — плитка с подписью в два слова
   уже трёх столбцов не выдерживает и переносит слова по одному. */
.modes--3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 900px) { .modes--3 { grid-template-columns: 1fr; } }
.mode {
  display: flex; flex-direction: column; gap: var(--s-05); text-align: left;
  padding: var(--s-3); border-radius: var(--radius); cursor: pointer;
  /* Утопленной плиткой без рамки, а не карточкой в рамке на карточке
     (сверка 28 сентября 2026); выбранная — кольцом акцента, как образцы
     фона и кнопки акцента ниже */
  border: 1px solid transparent; background: var(--sunken); color: var(--text);
  transition: border-color var(--fast), background var(--fast), box-shadow var(--fast);
}
.mode:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.mode.is-active { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); background: var(--accent-soft); }
.mode__name { font-weight: 600; }
.mode.is-active .mode__name { color: var(--accent-fg); }
.mode__note { font-size: var(--t-xs); color: var(--text-dim); line-height: 1.4; }

.thms { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--s-2); }
.thm {
  display: flex; flex-direction: column; gap: var(--s-1); text-align: left;
  padding: var(--s-1); border-radius: var(--radius-lg); cursor: pointer;
  border: 1px solid transparent; background: none; color: var(--text);
  transition: border-color var(--fast), box-shadow var(--fast);
}
.thm:hover:where([data-hover="mouse"] *) { background: var(--hover); }
/* Обводка выбранного рисуется на кнопке, а не на картинке: на картинке лежит
   чужая тема, и обводка взяла бы её акцент вместо нашего */
.thm.is-active { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.thm__name { font-size: var(--t-sm); font-weight: 600; padding: 0 var(--s-1); }
.thm.is-active .thm__name { color: var(--accent-fg); }
.thm__note {
  font-size: var(--t-xs); color: var(--text-dim); line-height: 1.35;
  padding: 0 var(--s-1) var(--s-1);
}

.thm__pic {
  display: flex; gap: 4px; padding: 6px; aspect-ratio: 16 / 10; overflow: hidden;
  border-radius: var(--radius); background: var(--bg); border: 1px solid var(--border);
}
.thm__nav { flex: 0 0 28%; display: flex; flex-direction: column; gap: 4px; }
.thm__pill { height: 8px; border-radius: var(--radius-full); background: var(--surface); box-shadow: var(--shadow-xs); }
.thm__item { height: 5px; border-radius: var(--radius-full); background: var(--surface-3); }
.thm__page {
  flex: 1; display: flex; flex-direction: column; gap: 5px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
}
.thm__bar { height: 7px; width: 58%; border-radius: var(--radius-full); background: var(--accent); }
.thm__line { height: 4px; border-radius: var(--radius-full); background: var(--text-dim); opacity: .5; }
.thm__line--short { width: 62%; }

/* Сторона света в «Оформлении»: фон образцами, акцент и готовые сочетания
   кнопками с кружком. Кружок несёт своё сочетание атрибутами, кнопка —
   нет: иначе кнопка тёмной стороны на светлой странице взяла бы светлый
   текст и пропала. */
.vid { margin-top: var(--s-5); display: flex; flex-direction: column; gap: var(--s-2); }
.vid__head { margin: 0; font-size: var(--t-md); font-weight: 600; }
.vid .field__label { margin-top: var(--s-2); }
.thms--fon { grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); }
.vybor { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.vybor__btn {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: var(--s-1) var(--s-3) var(--s-1) var(--s-1);
  border: 1px solid var(--border); border-radius: var(--radius-full);
  background: var(--surface); color: var(--text);
  font: inherit; font-size: var(--t-sm); cursor: pointer;
}
.vybor__btn:hover:where([data-hover="mouse"] *) { border-color: var(--border-strong); }
.vybor__btn.is-active { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.vybor__akcent, .vybor__preset {
  flex: none; width: 22px; height: 22px; border-radius: var(--radius-full);
  box-shadow: inset 0 0 0 1px var(--line-2);
}
.vybor__akcent { background: var(--accent); box-shadow: none; }
/* Готовое сочетание — фон и акцент пополам */
.vybor__preset { background: linear-gradient(135deg, var(--base) 50%, var(--accent) 50%); }
/* База знаний — модуль с 24 сентября 2026: её стили в modules/kb/styles.css,
   подключаются только у включённого модуля. Здесь остался токен --kb-line:
   им же меряют узкие страницы (.page--narrow). */

/* ── Комплектация ─────────────────────────────────────────────────────────
   Раздел отвечает на один вопрос — успеваем ли к монтажу, — и всё заметное
   здесь про срок оплаты: он горит красным, он же ромбом на диаграмме.
   Доска переиспользует колонки и карточки канбана: две разные доски в одном
   приложении читались бы как две разные программы. */

/* Панель графика закупок повторяет панель задач до пикселя: обе половины
   комплектации — один раздел, и переключение между ними не должно двигать
   ни кнопку добавления, ни всё, что под ней. Раньше у графика панель была
   без подложки и с другими полями, и страница при переходе заметно ехала. */
.procbar {
  display: flex; align-items: center; gap: var(--s-2);
  flex-wrap: wrap; row-gap: var(--s-2);
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--border); border-radius: var(--radius);
  margin-bottom: var(--s-2);
}
.procbar__left, .procbar__right {
  display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap;
}


.chip--late {
  background: var(--critical-soft); color: var(--late-fg); font-weight: 600;
}

/* ── Карточка позиции ── */

.proccard.is-late { box-shadow: inset 3px 0 0 var(--critical), var(--shadow-xs); }
.proccard.is-soon { box-shadow: inset 3px 0 0 var(--warn), var(--shadow-xs); }

.procdate {
  font-size: var(--t-xs); font-weight: 600; color: var(--text-dim);
  padding: var(--s-05) var(--s-2); border-radius: var(--radius-sm);
  background: var(--surface-2); white-space: nowrap;
}
.procdate.is-late { background: var(--critical-soft); color: var(--late-fg); }
.procdate.is-soon { background: var(--warn-soft); color: var(--warn-fg); }
.procdate.is-blank { background: none; color: var(--text-faint); font-weight: 500; }
.procmoney {
  font-family: var(--mono); font-size: var(--t-mono); color: var(--text-dim);
  white-space: nowrap;
}

/* ── График закупок (этапы 5–6 переработки, вариант D) ──
   Строка — позиция: отрезки между точками (ожидание, производство,
   доставка, монтаж), ромбы точек (пустой — план, залитый — факт), подпись
   у следующей точки. Примерная дата «≈» — бледно и пунктиром. Таблица слева
   прилипает при прокрутке вбок, шкала — при прокрутке вниз. Деньги — только
   в режиме «Оплаты». Цвета отрезков — те же, что были у диаграммы поставки. */

.pgbar { margin-bottom: var(--s-2); }
.pgbar .spacer, .pglegend .spacer, .pgsum .spacer { flex: 1 1 auto; min-width: var(--s-1); }
.pgbar .procbar__left { gap: var(--s-2) var(--s-3); }
.pgtview { display: inline-flex; align-items: center; gap: var(--s-2); }
.pgtview__k { font-size: var(--t-sm); color: var(--text-faint); }
.pgtview .select--sm { min-width: 150px; }
.pgcount { display: inline-flex; gap: var(--s-3); font-size: var(--t-sm); color: var(--text-faint); white-space: nowrap; }
.pgcount__hot { color: var(--late-fg); font-weight: 600; }

.pg {
  --seg-wait: color-mix(in oklab, var(--ink) 16%, var(--solid));
  --seg-make: #2e9e83; --seg-ship: #3b62d9; --seg-mount: #7c5cd6;
  --pg-build: color-mix(in oklab, var(--ink) 40%, var(--solid));
  --pg-build-soft: color-mix(in oklab, var(--ink) 9%, var(--solid));
  --pg-line: color-mix(in oklab, var(--ink) 6%, var(--solid));
  display: flex; flex-direction: column; min-width: 0; position: relative; overflow: hidden;
}
.pg__scroll { overflow: auto; overscroll-behavior: contain; position: relative; min-height: 0; }
.pg__inner { position: relative; min-width: 100%; }

.pg__head {
  position: sticky; top: 0; z-index: 6; display: flex; height: 46px;
  background: var(--solid); border-bottom: 1px solid var(--border);
}
.pg__hleft {
  position: sticky; left: 0; z-index: 7; display: flex; flex: none; width: var(--left-w);
  background: var(--solid); border-right: 1px solid var(--border);
}
.pg__hc {
  display: flex; align-items: flex-end; padding: 0 0 var(--s-2) var(--s-3); flex: none;
  font-size: var(--t-2xs); letter-spacing: .05em; text-transform: uppercase; color: var(--text-faint);
  white-space: nowrap; overflow: hidden;
}
.pg__hc.is-num { justify-content: flex-end; padding-right: var(--s-3); }
.pg__hc.is-date, .pg__c.is-date { padding-left: var(--s-2); letter-spacing: .02em; }
.pg__scale { position: relative; flex: none; height: 100%; }
.pg__month {
  position: absolute; top: 4px; height: 16px; border-left: 1px solid var(--border-strong);
  font-size: var(--t-xs); font-weight: 600; color: var(--text-dim); white-space: nowrap; overflow: hidden;
}
.pg__month span { padding-left: var(--s-2); }
.pg__tick {
  position: absolute; bottom: 5px; font-size: var(--t-2xs); color: var(--text-faint);
  transform: translateX(3px); white-space: nowrap;
}
.pg__tick.is-day { transform: none; text-align: center; bottom: 2px; line-height: 1.05; }
.pg__tick.is-day small { display: block; font-size: 9px; text-transform: uppercase; }
.pg__tick.is-off { color: color-mix(in oklab, var(--text-faint) 60%, var(--solid)); }
.pg__todaylbl {
  position: absolute; bottom: 3px; transform: translateX(-50%); z-index: 1;
  background: var(--late); color: var(--solid); font-size: var(--t-2xs); line-height: 1;
  padding: 3px var(--s-1); border-radius: var(--radius-sm); white-space: nowrap;
}

.pg__grid {
  position: absolute; top: 46px; bottom: 0; left: var(--left-w); pointer-events: none; z-index: 0;
}
.pg__grid i { position: absolute; top: 0; bottom: 0; width: 1px; }
.pg__wk { background: var(--pg-line); }
.pg__mo { background: var(--border); }
.pg__off { background: color-mix(in oklab, var(--ink) 3%, transparent); width: auto !important; }
.pg__grid--over { z-index: 2; }
.pg__today { width: 0 !important; border-left: 1.5px solid var(--late); }
.pg__cross { display: none; width: 0 !important; border-left: 1px solid var(--accent); }

.pg__rows { position: relative; }
.pg__row { display: flex; height: var(--row-h); border-bottom: 1px solid var(--pg-line); position: relative; cursor: pointer; }
.pg__row--build { height: var(--build-h); cursor: default; border-bottom: none; }
.pg__left {
  position: sticky; left: 0; z-index: 3; display: flex; flex: none; width: var(--left-w);
  background: var(--solid); border-right: 1px solid var(--border);
}
.pg__rows .pg__left, .pg__grp { z-index: 4; }
.pg__row:hover:where([data-hover="mouse"] *) .pg__left,
.pg__row:hover:where([data-hover="mouse"] *) .pg__lane { background-color: color-mix(in oklab, var(--ink) 2.5%, transparent); }
.pg__row:hover:where([data-hover="mouse"] *) .pg__left { background-color: color-mix(in oklab, var(--ink) 2.5%, var(--solid)); }
.pg__row.is-sel .pg__left { background: var(--accent-soft); }
.pg__row.is-sel .pg__lane { background: color-mix(in oklab, var(--accent-soft) 55%, transparent); }
.pg__row.is-new .pg__left { animation: pgnew 1.6s var(--ease); }
@keyframes pgnew { from { background: var(--accent-soft); } }
.pg__row.is-moving { opacity: .4; }
.pg__row.is-drop-before { box-shadow: inset 0 2px 0 var(--accent); }
.pg__row.is-drop-after { box-shadow: inset 0 -2px 0 var(--accent); }
.pg__c {
  display: flex; align-items: center; flex: none; min-width: 0; padding: 0 0 0 var(--s-3);
  font-size: var(--t-sm); white-space: nowrap; overflow: hidden;
}
.pg__c.is-num { justify-content: flex-end; padding-right: var(--s-3); font-variant-numeric: tabular-nums; }
.pg__c--faint { color: var(--text-faint); font-size: var(--t-xs); }
.pg__c--name { gap: var(--s-1); }
.pg__nm { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.pg__name { font-weight: 500; font-size: var(--t-sm); color: var(--text); overflow: hidden; text-overflow: ellipsis; }
.pg__sub { font-size: var(--t-2xs); color: var(--text-faint); overflow: hidden; text-overflow: ellipsis; }
.pg__row.is-hot .pg__name { color: var(--late-fg); }
.pg__grip { cursor: grab; color: var(--text-faint); display: inline-flex; flex: none; }
.pg__faint { color: var(--text-faint); }
.pg__paid { color: var(--ok-fg); }
.pg__next { display: inline-flex; gap: var(--s-1); align-items: baseline; font-size: var(--t-sm); }
.pg__next b { font-weight: 500; }
.pg__next span { color: var(--text-dim); font-variant-numeric: tabular-nums; }
.pg__next.is-late b, .pg__next.is-late span { color: var(--late-fg); }
.pg__next.is-soon b { color: var(--warn-fg); }
.pg__next.is-approx b { color: var(--text-faint); font-weight: 500; border-bottom: 1px dashed var(--text-faint); }
.pg__date { font-size: var(--t-sm); line-height: 1.15; font-variant-numeric: tabular-nums; }
.pg__date small { display: block; font-size: var(--t-2xs); color: var(--text-faint); }
.pg__date.is-fact { color: var(--ok-fg); }
.pg__date.is-late { color: var(--late-fg); }
.pg__date.is-approx { color: var(--text-dim); }

.pg__lane { position: relative; flex: none; overflow: hidden; }
.pg__seg {
  position: absolute; top: 50%; height: 8px; margin-top: -4px; border-radius: 4px; z-index: 1;
  background: var(--seg-wait);
}
.pg__seg.is-make { background: var(--seg-make); }
.pg__seg.is-ship { background: var(--seg-ship); }
.pg__seg.is-mount { background: var(--seg-mount); }
.pg__seg.is-span { height: 12px; margin-top: -6px; border-radius: 3px; }
.pg__seg.is-done { opacity: .45; }
.pg__seg.is-approx, .pg__lane.is-approx .pg__seg { opacity: .38; }
.pg__seg:not(.is-done) { cursor: ew-resize; }
.pg__pt {
  position: absolute; top: 50%; width: 11px; height: 11px; margin: -5.5px 0 0 -5.5px; z-index: 2;
  transform: rotate(45deg); background: var(--solid); border: 2px solid var(--text-dim); border-radius: 2px;
}
.pg__pt.is-fact { background: var(--text-dim); }
.pg__pt.is-approx { border-style: dashed; opacity: .75; }
.pg__pt.is-late { border-color: var(--late); background: var(--late-soft); }
.pg__pt.is-soon { border-color: var(--warn); }
.pg__pt.is-next { box-shadow: 0 0 0 3px var(--accent-ring); }
.pg__pt.is-drag { cursor: ew-resize; }
.pg__pt.is-drag:hover:where([data-hover="mouse"] *) { transform: rotate(45deg) scale(1.25); }
.pg__lbl {
  position: absolute; top: 50%; z-index: 3; transform: translate(10px, -50%); pointer-events: none;
  font-size: var(--t-2xs); line-height: 16px; color: var(--text-dim); white-space: nowrap;
  background: color-mix(in oklab, var(--solid) 92%, transparent); padding: 0 var(--s-1); border-radius: var(--radius-sm);
}
.pg__lbl.is-left { transform: translate(calc(-100% - 10px), -50%); }
.pg__lbl.is-late { color: var(--late-fg); font-weight: 500; }
.pg__need { position: absolute; top: 3px; bottom: 3px; width: 0; border-left: 2px dashed var(--pg-build); z-index: 1; }
.pg__need.is-late { border-color: var(--late); }
.pg__dep { position: absolute; top: 0; bottom: 0; width: 0; border-left: 1px dotted var(--pg-build); z-index: 0; }

.pg__grp {
  display: flex; align-items: center; gap: var(--s-2); height: 24px; padding: 0 var(--s-3);
  position: sticky; left: 0; width: max-content; min-width: 100%;
  font-size: var(--t-2xs); color: var(--text-faint); border-bottom: 1px solid var(--border);
  background: var(--canvas);
}
.pg__grpt { display: inline-flex; align-items: center; gap: var(--s-1); text-transform: uppercase; letter-spacing: .05em; }
.pg__bbar {
  position: absolute; top: 50%; height: calc(var(--build-h) - 5px); transform: translateY(-50%);
  border-radius: var(--radius-sm); background: var(--pg-build-soft); border: 1px solid color-mix(in oklab, var(--ink) 18%, var(--solid));
  font-size: var(--t-2xs); line-height: calc(var(--build-h) - 7px); padding: 0 var(--s-1); color: var(--text-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; z-index: 1;
}
.pg__bbar.is-done { opacity: .6; }
.pg__bbar.is-now { background: color-mix(in oklab, var(--ink) 15%, var(--solid)); }
.pg__bbar.is-dep { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-fg); }

.pg__coin {
  position: absolute; top: 50%; width: 16px; height: 16px; margin: -8px 0 0 -8px; z-index: 2;
  border-radius: 50%; background: var(--solid); border: 2px solid var(--warn); color: var(--warn-fg);
  font-size: 9px; font-weight: 700; display: grid; place-items: center; line-height: 1;
}
.pg__coin.is-paid { background: var(--ok); border-color: var(--ok); color: var(--solid); }
.pg__coin.is-late { border-color: var(--late); color: var(--late-fg); background: var(--late-soft); }
.pg__coin.is-approx { border-style: dashed; opacity: .75; }
.pg__coin.is-sm { width: 13px; height: 13px; margin: 0 0 0 -6.5px; top: 2px; font-size: 7.5px; border-width: 1.5px; }
.pg__coin.is-static { position: static; display: inline-grid; margin: 0 var(--s-1) 0 0; vertical-align: middle; }
.pg__coinlbl {
  position: absolute; top: 50%; transform: translateY(-50%); padding-left: 11px; z-index: 1;
  font-size: var(--t-2xs); color: var(--text-dim); white-space: nowrap; pointer-events: none;
}
.pg__coinlbl.is-paid { color: var(--ok-fg); }
.pg__coinlbl.is-late { color: var(--late-fg); }
.pg__life { position: absolute; top: 50%; height: 4px; margin-top: -2px; border-radius: 2px; background: var(--pg-line); }
.pg__ghost {
  position: absolute; top: 50%; width: 7px; height: 7px; margin: -3.5px 0 0 -3.5px;
  transform: rotate(45deg); background: var(--text-faint); opacity: .35; border-radius: 1px;
}

.pg__empty { padding: var(--s-5) var(--s-4); font-size: var(--t-sm); color: var(--text-dim); position: sticky; left: 0; max-width: 760px; }

.pgtip {
  position: absolute; z-index: 20; display: none; pointer-events: none; max-width: 420px;
  background: var(--ink); color: var(--solid); font-size: var(--t-xs); line-height: 1.45;
  border-radius: var(--radius-sm); padding: var(--s-2) var(--s-2); box-shadow: var(--sh-3);
  white-space: normal;
}
.pgtip.is-on { display: none; }
.pgtip b { font-weight: 600; }

/* Быстрый ввод — строкой под последней позицией */
.pgadd {
  display: flex; align-items: center; gap: var(--s-2); min-height: 44px; padding: var(--s-1) var(--s-3);
  border-top: 1px solid var(--border); background: var(--canvas); overflow: hidden; flex: none;
}
.pgadd__plus { color: var(--text-faint); display: inline-flex; }
.pgadd .input { height: 30px; font-size: var(--t-sm); }
.pgadd__name { width: 270px; flex: 0 1 270px; min-width: 150px; }
.pgadd__tpl { max-width: 240px; min-width: 0; flex: 0 1 240px; font-size: var(--t-sm); }
.pgadd__sup { width: 170px; flex: 0 1 170px; min-width: 110px; }
.pgadd__plan {
  height: 30px; padding: 0 var(--s-2); border-radius: var(--radius-sm); flex: none; cursor: pointer;
  border: 1px dashed var(--border-strong); background: var(--solid); color: var(--text-dim); font-size: var(--t-sm);
}
.pgadd__plan.is-on { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-fg); }
.pgadd__enter { font-size: var(--t-2xs); color: var(--text-faint); flex: none; }
.pgadd__hint { font-size: var(--t-xs); color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }

/* «Оплаты»: платежи по неделям и сводка — внизу графика */
.pgcash { display: flex; height: 46px; border-top: 1px solid var(--border); flex: none; }
.pgcash__k {
  flex: none; display: flex; align-items: center; padding-left: var(--s-3);
  font-size: var(--t-xs); color: var(--text-faint); border-right: 1px solid var(--border);
}
.pgcash__clip { flex: 1; min-width: 0; overflow: hidden; position: relative; }
.pgcash__lane { position: absolute; top: 0; bottom: 0; left: 0; }
.pgcash__bar { position: absolute; bottom: 4px; border-radius: 2px 2px 0 0; background: color-mix(in oklab, var(--warn) 35%, var(--solid)); }
.pgcash__bar.is-paid { background: color-mix(in oklab, var(--ok) 45%, var(--solid)); }
.pgcash__lbl { position: absolute; transform: translateX(-50%); font-size: 9.5px; color: var(--text-dim); white-space: nowrap; }
.pgsum {
  display: flex; align-items: center; gap: var(--s-4); padding: var(--s-2) var(--s-3); flex: none;
  border-top: 1px solid var(--border); font-size: var(--t-sm); white-space: nowrap; overflow: hidden;
}
.pgsum__k { color: var(--text-faint); margin-right: var(--s-1); }
.pgsum b { font-weight: 600; font-variant-numeric: tabular-nums; }
.pgsum__nx { display: inline-flex; gap: var(--s-3); color: var(--text-dim); overflow: hidden; }

/* «Экспорт в PDF» комплектации (этап 7): слева параметры, справа первый лист */
.modal.pgpdf { width: min(700px, 100%); }
.pgpdf__body { display: flex; gap: var(--s-4); align-items: stretch; }
.pgpdf__opts { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s-3); }
.pgpdf__fld { display: flex; flex-direction: column; gap: var(--s-1); }
.pgpdf__fld .field__label { margin: 0; }
.pgpdf__fld .seg { align-self: flex-start; }
.pgpdf__what { display: flex; flex-direction: column; gap: var(--s-1); }
.pgpdf__radio { display: flex; align-items: baseline; gap: var(--s-2); font-size: var(--t-sm); cursor: pointer; min-width: 0; }
.pgpdf__radio input { flex: none; margin: 0; transform: translateY(2px); }
.pgpdf__name { flex: none; }
.pgpdf__hint { color: var(--text-faint); font-size: var(--t-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.pgpdf__note { margin: 0; padding: var(--s-2) var(--s-3); border-radius: var(--radius-sm);
  background: color-mix(in oklab, var(--ink) 4%, var(--solid)); }
.pgpdf__prev { flex: none; width: 316px; min-height: 316px; display: grid; place-items: center;
  border-radius: var(--radius); background: color-mix(in oklab, var(--ink) 5%, var(--solid)); }
.pgpdf__sheet { line-height: 0; box-shadow: 0 1px 4px rgba(0, 0, 0, .18); }
.pgpdf__sheet svg { display: block; }
.pgpdf__count { align-self: center; font-size: var(--t-xs); color: var(--text-faint); }
@media (max-width: 720px) {
  .pgpdf__body { flex-direction: column; }
  .pgpdf__prev { width: auto; min-height: 0; padding: var(--s-3); }
}

.pglegend {
  display: flex; align-items: center; gap: var(--s-3); padding: var(--s-2) var(--s-3); flex: none;
  border-top: 1px solid var(--border); font-size: var(--t-2xs); color: var(--text-faint); white-space: nowrap;
}
.pglegend__items {
  display: flex; align-items: center; gap: var(--s-3); flex: 1 1 auto; min-width: 0;
  overflow: hidden; mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
}
.pglegend__ctl { display: flex; align-items: center; gap: var(--s-2); flex: none; }
.pglegend__i { display: inline-flex; align-items: center; gap: var(--s-1); }
.pglegend__i > i { display: inline-block; flex: none; }
.pglegend__seg { width: 14px; height: 7px; border-radius: 3px; background: var(--seg-wait); }
.pglegend__seg.is-make { background: var(--seg-make); }
.pglegend__seg.is-ship { background: var(--seg-ship); }
.pglegend__seg.is-mount { background: var(--seg-mount); }
.pglegend__pt { width: 8px; height: 8px; transform: rotate(45deg); border: 2px solid var(--text-dim); background: var(--solid); border-radius: 2px; }
.pglegend__pt.is-fact { background: var(--text-dim); }
.pglegend__pt.is-approx { border-style: dashed; opacity: .75; }
.pglegend__need { width: 0; height: 12px; border-left: 2px dashed var(--pg-build); }
.pglegend__build { width: 14px; height: 8px; border-radius: 2px; background: var(--pg-build-soft); border: 1px solid color-mix(in oklab, var(--ink) 18%, var(--solid)); }
.pglegend__link {
  border: none; background: none; padding: 0; cursor: pointer; font: inherit; color: var(--text-dim);
}
.pglegend__link:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); }
.pglegend .seg button { height: 24px; font-size: var(--t-2xs); padding: 0 var(--s-2); }
.pglegend .btn--sm { height: 26px; font-size: var(--t-xs); }
.pglegend .btn--sm.is-chosen { background: var(--accent-soft); color: var(--accent-fg); }

@media (max-width: 760px) {
  .pgadd { flex-wrap: wrap; }
  .pgadd__name, .pgadd__tpl, .pgadd__sup { flex: 1 1 100%; max-width: none; width: auto; }
  .pgadd__hint { display: none; }
}


/* ── Окно позиции ── */

/* Бумаги лота: КП, счёт, накладная приходят по очереди */
.procdocs { display: flex; flex-direction: column; gap: var(--s-2); align-items: flex-start; }
.procdoc { display: flex; gap: var(--s-2); width: 100%; }
.procdoc input:first-child { flex: 0 0 34%; }
.procdoc input:nth-child(2) { flex: 1; min-width: 0; }

.procgrid { display: grid; gap: var(--s-3); }
.procgrid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.procgrid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.procdatewrap { display: grid; }
/* Число и счёт дней стоят вместе: «45» без «кал./раб.» ничего не значит */
.procdur { display: flex; gap: var(--s-1); }
.procdur input { min-width: 0; }
.procdur__unit { flex: none; width: 64px; padding-inline: var(--s-2); }

.modal__sub {
  margin: var(--s-5) 0 var(--s-2); font-size: var(--t-2xs); font-weight: 500;
  text-transform: uppercase; font-family: var(--mono); letter-spacing: .08em; color: var(--text-faint);
}
.field__note { display: block; margin-top: var(--s-1); }

/* Расчёт: то, ради чего окно и открывают. Меняешь срок поставки — видно,
   как уезжает день оплаты, и не надо ничего сохранять, чтобы это увидеть. */
.proccalc {
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-5);
  margin-top: var(--s-3); padding: var(--s-3) var(--s-4);
  background: var(--surface-2); border-radius: var(--radius);
}
.proccalc__step { display: flex; flex-direction: column; gap: var(--s-05); }
.proccalc__label {
  font-size: var(--t-2xs); text-transform: uppercase; font-family: var(--mono); letter-spacing: .08em;
  font-weight: 500; color: var(--text-faint);
}
.proccalc__value { font-size: var(--t-sm); font-weight: 600; color: var(--text); }
.proccalc__step.is-key .proccalc__value { color: var(--accent-fg); }
.proccalc__step.is-soon .proccalc__value { color: var(--warn-fg); }
.proccalc__step.is-late .proccalc__value { color: var(--late-fg); }
.proccalc__warn {
  flex-basis: 100%; font-size: var(--t-xs); color: var(--late-fg);
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-1);
}

@media (max-width: 760px) {
  .procgrid--2, .procgrid--4 { grid-template-columns: minmax(0, 1fr); }
}

/* События чата проекта в настройках проекта — сеткой галочек. Список
   людей телеграма в админке — в modules/telegram/styles.css. */
.tgevents { display: flex; flex-direction: column; gap: var(--s-1); }
.tgevents { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
/* Мелкий переключатель: три коротких слова, а не три кнопки в полный рост */
.seg--sm button { padding: 3px var(--s-2); font-size: var(--t-2xs); }

/* Ключ доступа: его надо выделить и скопировать, поэтому он набран
   моноширинным и переносится, а не уезжает за край окна. */
.tokenbox {
  margin: 0 0 var(--s-2); padding: var(--s-3);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: var(--mono); font-size: var(--t-xs); line-height: 1.5;
  white-space: pre-wrap; word-break: break-all; user-select: all;
}
.tokenbox--conf { word-break: normal; max-height: 260px; overflow: auto; }

/* «Подключить Клода» — первая карточка профиля: заметная, но не крикливая.
   Полоса акцента слева отличает её от анкеты ниже, кнопка — справа, как
   действие, а не как поле формы. */
.klod-karta__telo { display: flex; gap: var(--s-4); align-items: center; }
.klod-karta__tekst { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s-1); }
.klod-karta__zag { font-size: var(--t-lg); font-weight: 600; letter-spacing: -.021em; }
@media (max-width: 600px) {
  .klod-karta__telo { flex-direction: column; align-items: stretch; }
}
.klod-shagi { margin: 0 0 var(--s-3); padding-left: var(--s-5); display: grid; gap: var(--s-2); }
/* Справка по разделам: две колонки на широком экране, одна на узком */
.klod-razdely { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--s-4); }
/* Утопленной плиткой без рамки: рамка вокруг блока внутри карточки — это
   карточка в карточке (сверка 28 сентября 2026) */
.klod-razdel { padding: var(--s-3) var(--s-4); border-radius: var(--radius); background: var(--sunken); }
.klod-razdel h3 { margin: 0 0 var(--s-2); font-size: var(--t-base); }
.klod-razdel p { margin: 0 0 var(--s-2); font-size: var(--t-sm); color: var(--text-dim); }
.klod-frazy { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--s-1); font-size: var(--t-sm); }
.klod-frazy li { font-style: italic; }

/* ── Потянуть, чтобы обновить ─────────────────────────────────────────────
   Значок висит над содержимым и едет за пальцем. Только на телефоне: на
   компьютере есть F5, а перехватывать колесо мыши незачем.

   overscroll-behavior на странице обязателен. Без него Chrome на андроиде
   показывает поверх нашего свой значок обновления и перезагружает вкладку
   целиком — то есть заново качает приложение вместо того, чтобы перерисовать
   экран. Два значка на один жест человек читает как поломку. */
body { overscroll-behavior-y: contain; }

.ptr {
  position: fixed; top: 0; left: 50%; z-index: 60;
  transform: translate(-50%, 0);
  width: var(--s-6); height: var(--s-6);
  margin-top: calc(var(--s-5) * -1);
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-full);
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--shadow-md);
  pointer-events: none;
}
.ptr.is-hiding { transition: transform .2s ease, opacity .2s ease; opacity: 0; }
.ptr__spin {
  width: var(--s-4); height: var(--s-4);
  border: 2px solid var(--border-strong);
  border-top-color: var(--accent);
  border-radius: var(--radius-full);
  /* Пока тянут — стрелка стоит: крутиться ей не с чего, ничего ещё не
     происходит. Довели до порога — значок окрашивается, и по нему видно,
     что отпускать можно */
  opacity: .55;
}
.ptr.is-ready .ptr__spin { opacity: 1; }
.ptr.is-spin .ptr__spin { animation: ptr-spin .7s linear infinite; }
@keyframes ptr-spin { to { transform: rotate(360deg); } }

/* Кому анимация мешает — тому её и не надо */
@media (prefers-reduced-motion: reduce) {
  .ptr.is-spin .ptr__spin { animation: none; }
  .ptr.is-hiding { transition: none; }
}

/* ── Лента проекта: сложенный раздел, а не приписка ────────────────────────
   Обычная складка (.fold) набрана мелкой прописной — так подписана «История
   изменений» внутри задачи, и там это верно: служебная строка. Лента же
   заменяет собой раздел с заголовком, и если оставить ей тот же кегль,
   свёрнутая она читается как служебная строка и её перестают замечать. */
.fold--feed { border-top: none; margin-top: var(--s-5); padding-top: 0; }
/* «Поручил» и «Наблюдаю» на главной. Заголовок крупнее панельного: это
   раздел страницы, а не складка внутри карточки, — но тише «Моих задач»:
   своя работа остаётся главной, чужая стоит под ней и ждёт, когда её
   откроют. Счётчик и пояснение — в той же строке, чтобы по закрытому
   блоку было видно, есть ли там что-нибудь. */
/* Отступ между блоками — s-5, а не s-6: 32 пикселя разрывали главную на
   три отдельных экрана, между которыми нужно ехать глазами. Это части
   одного списка дел, а не разные страницы. */
.fold--home { border-top: none; margin-top: var(--s-5); padding-top: 0; }
/* По базовой линии, а не по центру: заголовок 17px, счётчик и пояснение
   мельче, и при выравнивании по центру мелкое всплывало над словом.
   Одна ось у всех трёх — это то, что читается как одна строка. */
.fold--home > summary {
  align-items: baseline;
  font-size: var(--t-md); text-transform: none; font-family: var(--font); letter-spacing: -.01em;
  color: var(--text); font-weight: 600;
}
/* Распорка в шапке складки растягивается — как в шапке «Моих задач».
   Правила для неё тут не было вовсе, и отборы «Поручил» стояли вплотную
   к заголовку, а у «Моих задач» — у правого края. Три заголовка одного
   экрана, и органы у них в разных местах. */
.fold--home > summary > .spacer { flex: 1 1 auto; min-width: var(--s-3); }
/* Стрелка складки уехала из-под заголовка к правому краю.
   Слева она стояла первой в строке и сдвигала заголовок «Поручил» на
   полсантиметра вправо — в ряду с «Моими задачами», у которых складки нет,
   три заголовка одного экрана начинались от двух разных линий. Справа она
   в этот ряд не вмешивается вовсе.
   ::after, а не ::before: он идёт последним среди детей строки, то есть
   правее и счётчика, и кнопки, и отборов. */
.fold--home > summary::before { display: none; }
.fold--home > summary::after {
  content: '▸'; align-self: center; flex: none; order: 99;
  display: grid; place-items: center; width: 28px; height: 28px;
  font-size: var(--t-base); line-height: 1; color: var(--text-faint);
  border-radius: var(--radius); background: var(--surface-2);
  transition: transform var(--fast), color var(--fast), background var(--fast);
}
.fold--home[open] > summary::after { transform: rotate(90deg); }
.fold--home > summary:hover:where([data-hover="mouse"] *)::after { color: var(--text); background: var(--hover); }
/* Счёт задач в заголовке — тот же .hblock__count, что у «Моих задач»:
   «12 всего · 3 просрочено». Сперва здесь стояло голое число, да ещё и
   моноширинным шрифтом от подписи группы, и три заголовка на одном экране
   считали задачи тремя разными способами.
   
   Вес обычный: жирная цифра рядом с жирным словом читается как второе слово.
   Точка перед пояснением — иначе «Поручил 12 что я поставил другим»
   складывается в одну фразу, где число оказывается частью предложения. */
.fold--home > summary .hblock__count { font-weight: 400; letter-spacing: 0; }
.fold--home > summary .note { font-weight: 400; letter-spacing: 0; }
.fold--home > summary:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); }
.fold--home[open] > summary { margin-bottom: var(--s-3); }

/* Состояние и исполнители на карточке — только в «Поручил» и «Наблюдаю».
   Статус тихой плашкой с точкой цвета колонки: это справка, а не орган
   управления, и выглядеть как кнопка он не должен. */
.kcard__status {
  display: inline-flex; align-items: center; gap: var(--s-1);
  font-size: var(--t-2xs); color: var(--text-dim); white-space: nowrap;
}
.kcard__status::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--st-color, var(--text-faint));
}
/* Обёртка вокруг плашки статуса: нажатие меняет статус.
   Кнопка ничего не рисует — вид остаётся у самой плашки, иначе в строке
   появился бы второй прямоугольник вокруг первого. */
.kcard__statusbtn {
  border: none; background: none; padding: 0; margin: 0; font: inherit;
  color: inherit; cursor: pointer; display: inline-flex; align-items: center;
  flex: none; border-radius: var(--radius-full);
  transition: opacity var(--fast);
}
.kcard__statusbtn:hover:where([data-hover="mouse"] *) .kcard__status,
.kcard__statusbtn.is-open .kcard__status { color: var(--text); }

/* Лица стопкой, как в шапке проекта: до трёх, дальше «+N» */
.kcard__who { display: inline-flex; align-items: center; flex: none; }
.kcard__who .avatar { margin-left: -6px; border: 2px solid var(--raised); }
.kcard__who .avatar:first-child { margin-left: 0; }
.kcard__who-n { font-size: var(--t-2xs); color: var(--text-faint); margin-left: var(--s-1); }

/* Кнопки прямо на карточке: исполнитель, приоритет, сложность. Выглядят как
   были — заливки и рамки нет, — но нажимаются. Кнопка, которая выглядит как
   кнопка, среди меток превратила бы карточку в панель управления; здесь
   достаточно, чтобы под курсором знак оживал. */
/* Метка-кнопка и срок-кнопка на карточке в колонке: выглядят как метка,
   но по ним меняется значение. Заливки и рамки кнопки нет намеренно —
   карточка не должна превращаться в панель управления; достаточно, чтобы
   знак оживал под курсором. */
/* Только семейство, а не `font: inherit`.

   Сокращение `font` сбрасывает разом всё — и кегль в том числе, на кегль
   родителя. Правило стоит ниже `.ktag`, и нажимаемый ярлык оказывался
   на две ступени крупнее ненажимаемого: одна и та же метка в одной строке
   имела два разных размера, смотря можно ли её поменять. */
.ktag--act { cursor: pointer; font-family: inherit; border: none; }
.ktag--act:hover:where([data-hover="mouse"] *) { filter: brightness(.95); }
.kcard__date--act {
  background: none; border: none; padding: 0; font: inherit; color: inherit;
  cursor: pointer; border-radius: var(--radius-sm);
}
.kcard__date--act:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); }
.kcard__whobtn, .kcard__hotbtn {
  border: none; background: none; padding: 0; margin: 0; font: inherit;
  color: inherit; cursor: pointer; border-radius: var(--radius-sm);
  display: inline-flex; align-items: center; flex: none;
  transition: opacity var(--fast), transform var(--fast);
}
.kcard__whobtn:hover:where([data-hover="mouse"] *), .kcard__hotbtn:hover:where([data-hover="mouse"] *) { transform: scale(1.08); }
.kcard__whobtn.is-open, .kcard__hotbtn.is-open { transform: scale(1.08); }
/* Погасший огонёк: приоритета нет, но поднять его можно. Виден только
   при наведении на карточку — иначе серый огонёк стоял бы на каждой строке
   и означал ничего. Кружка под ним нет: пустое место не подсвечивают. */
.kcard__hot--off {
  opacity: 0; filter: grayscale(1); background: none;
  transition: opacity var(--fast);
}
.kcard--free:hover:where([data-hover="mouse"] *) .kcard__hot--off, .kcard__hotbtn.is-open .kcard__hot--off { opacity: .45; }
.kcard__hot--off:hover:where([data-hover="mouse"] *) { opacity: .8 !important; }

/* Кнопка «обсудить в чате» — вместо поля обсуждения в задаче. Кнопка, а не
   ссылка строкой: это выход в другую программу, и выглядеть он должен как
   действие. Название чата рядом и тише — по нему видно, куда именно ведёт. */
.talkbtn { display: inline-flex; align-items: center; gap: var(--s-2); text-decoration: none; }
.talkbtn:hover:where([data-hover="mouse"] *) { border-color: var(--accent); color: var(--accent-fg); }
.fold--feed > summary {
  font-size: var(--t-lg); font-weight: 600; color: var(--text);
  text-transform: none; font-family: var(--font); letter-spacing: normal;
}
.fold--feed > summary::before { font-size: var(--t-md); color: var(--text-dim); }
.fold--feed > summary .note { text-transform: none; font-family: var(--font); letter-spacing: normal; font-weight: 400; }

/* ── Под палец ────────────────────────────────────────────────────────────
   Блок стоит последним намеренно. Правила здесь перебивают размеры, заданные
   выше по файлу, а сила у них та же — значит решает порядок. Стоял он в
   середине, и `.pnote__act { width: 18px }` из раздела закреплённого спокойно
   его отменял: значок оставался восемнадцатипиксельным, а я считал, что
   починил. Проверка нажатием это и вскрыла.

   Всё внутри — только для сенсорных указателей. Мышь попадает и в двадцать
   два пикселя, а невидимые зоны на десктопе перехватывали бы наведение
   у соседей. */
@media (pointer: coarse) {
  /* Зона нажатия у мелких органов — невидимой подложкой, а не размером.
     
     Палец накрывает круг около сорока четырёх пикселей, а кружок хода
     у нас двадцать шесть, срок — двадцать два в высоту, значок на заметке —
     восемнадцать. Промах по такой цели стоит дорого: рядом с кружком хода
     лежит сама карточка, и мимо кнопки «закрыть» открывается задача.
     
     Раздувать их нельзя: строка задачи держится на том, что органы в ней
     мелкие и не спорят с названием. Поэтому растёт не сам знак, а его
     зона: псевдоэлемент по центру, ровно 44 на 44, невидимый и не мешающий
     соседям, потому что вынесен из потока.
     
     Только на сенсорных: мышь попадает и в двадцать два пикселя, а лишние
     невидимые квадраты на десктопе перехватывали бы наведение. */
  /* Вторая строка списка — 24 сентября 2026, проход по всему порталу
     на телефоне: отборы по типу над канбаном (30 точек), узкие квадратные
     кнопки в шапках разделов (30 в ширину), номер задачи и шаги пути
     на диске (по 20), плашка статуса в карточке. Все они стоят с запасом
     места вокруг, и подложка соседей не накрывает. */
  .krug, .kcard__whobtn, .kcard__hotbtn, .kcard__date-btn,
  .pnote__act, .stick__act, .backbtn, .teamadd,
  .kcard__tags .ktag--act, .kcard__tags .ktag--put,
  .typechip, .btn--sm.btn--icon, .tasknum, .diskpath__step,
  .kcard__statusbtn, .softtag {
    position: relative;
  }
  .krug:not(.is-ro)::after, .kcard__whobtn::after, .kcard__hotbtn::after,
  .kcard__date-btn::after, .pnote__act::after, .stick__act::after,
  .backbtn::after, .teamadd::after,
  .kcard__tags .ktag--act::after, .kcard__tags .ktag--put::after,
  .typechip::after, .btn--sm.btn--icon::after, .tasknum::after,
  .diskpath__step::after, .kcard__statusbtn::after, .softtag::after {
    content: ''; position: absolute; top: 50%; left: 50%;
    width: 100%; height: 100%; min-width: 44px; min-height: 44px;
    transform: translate(-50%, -50%);
  }
  /* Флажки — единственное, что приходится растить по-настоящему: у них
     нет своего содержимого, и невидимая подложка не даёт им веса на глаз.
     Тринадцать пикселей — это системный флажок, каким его рисует Windows. */
  input[type='checkbox']:not(.ckrow input) { width: 22px; height: 22px; }

  /* Значки на заметке растут по-настоящему: они стоят в углу карточки,
     соседей рядом нет, и подложка им не поможет — она перекрыла бы вторую
     такую же кнопку в двух пикселях от первой. */
  .pnote__act, .stick__act { width: 32px; height: 32px; }

  /* В строке списка нажимается сама строка, а органы в ней — нет.
     
     Строка высотой 56 пикселей вмещает кружок хода, метку проекта, срок,
     огонёк и лицо. Развести их под палец нельзя: сорок четыре пикселя
     на каждый — это двести двадцать, вчетверо больше самой строки, и зоны
     перекрыли бы друг друга. Проверка нажатием это и показала: палец
     попадает в соседа.
     
     Поэтому на сенсорном строка ведёт себя как строка: нажатие открывает
     задачу, а срок, приоритет, исполнителя и метки правят внутри неё, где
     под каждый орган есть место. Кружок хода — исключение: закрыть задачу
     одним касанием и есть то, ради чего список открывают.
     
     pointer-events: none, а не скрытие: знаки продолжают сообщать — виден
     и срок, и приоритет, и кто делает. Нажатие просто проходит сквозь них
     к карточке. */
  .is-rows .kcard__hotbtn, .is-rows .kcard__whobtn,
  .is-rows .kcard__date-btn, .is-rows .kcard__tags .ktag--act,
  .is-rows .kcard__tags .ktag--put { pointer-events: none; }
}

/* Ещё две цели, до которых палец не дотягивался. Обе — на сенсорном экране;
   на мыши они в добавке не нуждаются и её не получают.

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

   Кнопки разделов на карточке проекта — тридцать восемь пикселей: палец
   попадает, но запаса нет. Соседей сверху и снизу у них нет — только край
   карточки, — поэтому здесь можно и нужно поставить полные сорок четыре. */
@media (pointer: coarse) {
  .crumbs button { padding: var(--s-2) 0; }
  /* «Зарегистрироваться» и «Забыли пароль?» под формой входа — строчки
     текста по 23 точки. Растут по высоте тем же приёмом, что и крошки:
     соседей сверху и снизу у них нет. */
  .auth__switch button { padding: var(--s-2) 0; }
  /* Малый выпадающий список (порядок в ассетах, срок в «Служебном») —
     той же высоты, что поле и кнопка на телефоне: в 30 точках палец
     попадал в соседний отбор. */
  .select--sm { height: 38px; }
  .projcard__go .btn { min-height: 44px; }
}

/* Закрытая задача на доске: видна, но приглушена.

   Она показывается только при включённом «показать закрытые» и стоит
   вперемешку с живыми — в своей колонке. Без пометки её не отличить,
   а спутать закрытую с работой, которую ещё делать, дорого. Приглушение,
   а не перечёркивание: перечёркнутый текст в списке из десяти карточек
   читается хуже, чем не читается вовсе. */
.kcard--zakryta { opacity: .55; }
.kcard--zakryta:hover:where([data-hover="mouse"] *) { opacity: .8; }
.kcard--zakryta .kcard__name { text-decoration: none; }

/* ── Динозаврик ──────────────────────────────────────────────────────────────
   Игра рисуется на холсте, и оттуда же берёт цвета темы, — стилей ей нужно
   ровно два: чтобы холст растягивался по ширине окна и чтобы точки остались
   точками. Сглаживание здесь враг: браузер по умолчанию размывает картинку
   при растяжении, и пиксельный ящер превращается в мыло. */
.dino__body { padding: 0; }
.dino__canvas {
  display: block; width: 100%; height: auto;
  image-rendering: pixelated;
  border-radius: var(--radius);
  /* Палец на телефоне не должен листать страницу, пока им же прыгают */
  touch-action: none;
  cursor: pointer;
}
/* Подпись в шапке окна на узком экране уезжает: там и без неё понятно,
   а «пробел» на телефоне всё равно негде нажать */
@media (max-width: 760px) {
  .dino .modal__head .note { display: none; }
}

/* Таблица рекордов динозаврика. Показывается вместо холста, в том же окне:
   отдельное окно поверх окна ради двадцати строк — это уже не игра, а
   интерфейс. Кнопка в подвале переключает туда и обратно. */
.dino__board { padding: var(--s-4); min-height: 176px; }
.dino__table { width: 100%; }
.dino__table td, .dino__table th { vertical-align: middle; }
/* Место: медали первым трём, дальше просто число. Ряд из двадцати кружочков
   превратил бы таблицу в ёлку, а «7» и так говорит всё, что нужно. */
.dino__place { font-size: var(--t-md); text-align: center; }
.dino__who { display: inline-flex; align-items: center; gap: var(--s-2); min-width: 0; }
/* Очки моноширинные и с ведущими нулями — как счётчик в самой игре:
   цифры не пляшут, и столбец читается сверху вниз одним взглядом */
.dino__score {
  text-align: right; font-family: var(--mono); font-size: var(--t-mono);
  font-variant-numeric: tabular-nums;
}
/* Своя строка подсвечена: в таблице на двадцать фамилий себя ищут первым делом */
.dino__table tr.is-me { background: var(--accent-soft); }
.dino__table tr.is-me td { font-weight: 600; }

/* ── Whiteboard: доски для рисования ──────────────────────────────────────── */

/* Сетка досок. Карточка — миниатюра и подпись под ней: доску узнают по тому,
   что на ней нарисовано, а название придумывают на бегу. */
/* Карточка шире, чем была (240): доску узнают по миниатюре, а на узкой
   не разобрать, что нарисовано (владелец, 22 сентября 2026 — «превью надо
   пошире»). На ширину экрана в ряд по-прежнему встаёт столько, сколько
   влезет. */
.wbgrid {
  display: grid; gap: var(--s-4);
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
}
.wbcard {
  display: flex; flex-direction: column; cursor: pointer; overflow: hidden;
  background: var(--raised); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: calc(var(--s-1) + var(--s-05));
  transition: border-color var(--fast), box-shadow var(--fast);
}
/* Без подъёма — только тень (то же правило, что у плиток диска) */
.wbcard:hover:where([data-hover="mouse"] *) { border-color: var(--border-strong); box-shadow: var(--shadow-md); }
/* Холст доски Ватмана — фон страницы (--base) с четвертью насыщенности:
   почти серый, но в тоне темы. Та же формула, что у редактора
   (Vatman, editor/oformlenie.js, ДОЛЯ_ОТТЕНКА), и редактор берёт цвет
   отсюда, если он есть, — холст и карточки превью совпадают на любой
   теме. Определён там же, где --base (у [data-bg]), чтобы считаться от
   тех же ступеней светлоты и тона. */
:root { --board-canvas: var(--base); }
[data-bg] { --board-canvas: oklch(var(--Lb) calc(var(--bc) * var(--cf) * .25) var(--bh)); }
/* Миниатюра всегда одной высоты: иначе ряд карточек идёт лесенкой и сетка
   перестаёт читаться рядами. Картинка вписывается целиком, а не обрезается
   по центру — на доске важен угол, где что-то нарисовано. */
.wbcard__img {
  /* 150, а не 200 (Б1, 1.10.2026): у пустой доски миниатюра — точечное поле,
     и 200 точек ничего не говорили; на 2560 в ряд встаёт пять досок */
  display: block; width: 100%; height: 150px; object-fit: contain;
  /* Миниатюра — утопленным полем в точку, как холст доски, с полем
     карточки вокруг (макет редизайна, «Доски»; сверка 28 сентября 2026).
     Была заливкой карточки с чертой снизу: пустая доска читалась пустой
     карточкой, а черта — рамкой внутри рамки. */
  border-radius: var(--radius);
  /* Поле — цвет холста доски текущей темы (владелец, 29 сентября 2026):
     превью прозрачное, и под ним то же, что под фигурами на самой доске, —
     светлое или тёмное, меняется вместе с темой. Точки — как на холсте. */
  background: var(--board-canvas) radial-gradient(var(--line) 1px, transparent 1.3px) 0 0 / var(--s-3) var(--s-3);
}
.wbcard__img--empty { display: grid; place-items: center; color: var(--text-faint); }
.wbcard__foot { display: flex; align-items: flex-start; gap: var(--s-2); padding: var(--s-2) var(--s-2) var(--s-1); }
.wbcard__main { flex: 1; min-width: 0; }
/* Название — в две строки: доски зовут «Фасад со стороны двора, вариант 3»,
   и в одну строку от такого названия оставалось начало (владелец,
   22 сентября 2026). Больше двух строк не даём: подпись под миниатюрой
   не должна расти выше самой миниатюры. */
.wbcard__name {
  font-size: var(--t-base); font-weight: 600; overflow: hidden;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  line-clamp: 2; overflow-wrap: anywhere;
}
/* Проект — плашкой над названием, а не серой припиской под ним: список досок
   разбирают по объектам, и ответ на этот вопрос не должен стоять третьим
   по счёту. Плашка та же, что на карточке задачи. */
.wbcard__tags { display: flex; margin-bottom: var(--s-1); }
.wbcard__note {
  font-size: var(--t-2xs); color: var(--text-faint); margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Заголовок группы внутри стопки. Мельче заголовка стопки («Общие доски»):
   стопка отвечает, кто это видит, а группа — по какому это объекту, и
   одинаковым весом они спорили бы за старшинство. */
.wbgroup {
  display: flex; align-items: baseline; gap: var(--s-2);
  margin: var(--s-4) 0 var(--s-2);
}
.wbgroup h3 { font-size: var(--t-base); }
.wbgroup .note { font-size: var(--t-2xs); color: var(--text-faint); }
/* Кто и когда правил — «Ольга · вчера»; кто в доске сейчас — зелёным с точкой
   (Б3, 1.10.2026). Зелёный здесь значит «идёт»: других зелёных меток на
   карточке доски нет, и спутать не с чем. */
.wbnote--live, .wblist__who.is-live { color: var(--ok-fg); font-weight: 500; }
.wbnote--live::before, .wblist__who.is-live::before {
  content: ''; display: inline-block; width: 6px; height: 6px; margin-right: var(--s-1);
  border-radius: 50%; background: var(--ok); vertical-align: middle;
}
/* Пустая стопка — строкой (Б5) */
.wbempty { margin: 0 0 var(--s-4); font-size: var(--t-sm); color: var(--ink-3); }
.wbhead__live { font-size: var(--t-sm); margin-left: var(--s-2); }
/* «+ Доска» в шапке раздела (О3, 1.10.2026); на телефоне — одним плюсом,
   как «+ Проект»: подпись уводила кнопку на свою строку */
.wbadd { gap: var(--s-1); }
@media (max-width: 760px) {
  .wbadd { width: 36px; padding: 0; flex: none; }
  .wbadd__t { display: none; }
  /* Плюс — на строке заголовка, справа, как у «Проектов»; вид — строкой ниже */
  .wbhead { flex-wrap: wrap; align-items: center; }
  .wbhead h1 { flex: 1; min-width: 0; }
  .wbhead .spacer { display: none; }
  .wbhead .wbadd { order: 1; }
  .wbhead .seg { order: 2; }
}
/* Колонка досок: код проекта перед именем и число досок справа — как
   у отборов в макете. «Сейчас работают» с живыми досками — зелёным. */
/* Номер проекта — тем же шрифтом, что название, цифрами одной ширины, и
   колонкой постоянной ширины: моноширинный номер разной длины сдвигал
   каждое название на свою линию (владелец, 28 сентября 2026) */
.siderow__code {
  flex: none; min-width: 3.4em; font-size: var(--t-sm); color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.siderow__count {
  flex: none; font-family: var(--mono); font-size: var(--t-xs); color: var(--text-faint);
  font-variant-numeric: tabular-nums; font-weight: 500;
}
.siderow__count.is-live { color: var(--ok-fg); font-weight: 600; }
.wbcard__more { flex: none; opacity: 0; transition: opacity var(--fast); }
/* Доски списком — одна карточка со строками через черту и столбцами
   «Проект · Кто правил · Когда» (Б6, 1.10.2026), как список диска; прежде
   каждая строка была своей плашкой с тенью. На телефоне — всегда списком
   (Б1): миниатюра 44, имя, под ним «186 · Ольга · вчера». */
.wblist { background: var(--solid); border-radius: var(--radius-lg); box-shadow: var(--sh-1); overflow: hidden; margin-bottom: var(--s-4); }
.wblist__head, .wblist__row {
  display: grid; align-items: center; column-gap: var(--s-3);
  grid-template-columns: calc(var(--s-6) + var(--s-3)) minmax(0, 1.4fr) minmax(0, 1fr) 11rem 9rem calc(2 * var(--s-6) + var(--s-2));
  padding: var(--s-2) var(--s-3);
}
.wblist--bezproekta .wblist__head, .wblist--bezproekta .wblist__row {
  grid-template-columns: calc(var(--s-6) + var(--s-3)) minmax(0, 1fr) 11rem 9rem calc(2 * var(--s-6) + var(--s-2));
}
.wblist__head {
  border-bottom: 1px solid var(--line);
  font-family: var(--mono); font-size: var(--t-xs); font-weight: 500;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3);
}
.wblist__row { border-bottom: 1px solid var(--line); cursor: pointer; transition: background var(--fast); }
.wblist__row:last-child { border-bottom: none; }
.wblist__row:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.wblist__pic {
  width: calc(var(--s-6) + var(--s-3)); height: var(--s-6); border-radius: var(--radius-sm); object-fit: cover;
  background: var(--board-canvas) radial-gradient(var(--line) 1px, transparent 1.3px) 0 0 / var(--s-2) var(--s-2);
}
.wblist__pic--empty { display: grid; place-items: center; color: var(--ink-3); }
.wblist__name { min-width: 0; display: flex; flex-direction: column; gap: var(--s-05); }
.wblist__title { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wblist__sub { display: none; font-size: var(--t-xs); color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wblist__proj { min-width: 0; font-size: var(--t-sm); color: var(--accent-fg); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wblist__proj.is-none { color: var(--ink-3); font-weight: 400; }
.wblist__who, .wblist__when { min-width: 0; font-size: var(--t-sm); color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wblist__row .wbcard__more { opacity: 0; }
.wblist__row:hover:where([data-hover="mouse"] *) .wbcard__more, .wblist__row .wbcard__more.is-open { opacity: 1; }
@media (max-width: 760px) {
  .wblist__head { display: none; }
  .wblist__head, .wblist__row, .wblist--bezproekta .wblist__row {
    grid-template-columns: var(--s-7) minmax(0, 1fr) auto;
  }
  .wblist__pic { width: var(--s-7); height: var(--s-7); border-radius: var(--radius); }
  .wblist__proj, .wblist__who, .wblist__when { display: none; }
  .wblist__sub { display: block; }
  .wblist__title { font-size: var(--t-md); }
  .wblist__row .wbcard__more { opacity: .6; }
}
.wbcard:hover:where([data-hover="mouse"] *) .wbcard__more { opacity: 1; }
/* Под пальцем наведения нет — кнопка видна всегда */
@media (hover: none) { .wbcard__more { opacity: .6; } }

/* Сама доска: холст во всё, что осталось от экрана. Поля вокруг него —
   чистая потеря: рисуют на всём, что дают. */
.page--wb {
  display: flex; flex-direction: column; height: 100%;
  padding: var(--s-3) var(--s-3) var(--s-3);
}
/* Всё, что было шапкой, лежит на самом холсте двумя островками: слева
   у гамбургера редактора, справа в углу. Отдельная строка сверху съедала
   полсотни точек высоты у того, ради чего на доску и заходят.

   Островки — в ключе самого редактора: у него всё, что лежит на холсте,
   живёт в белых прямоугольниках с тенью. Наше должно читаться как часть
   его, а не как приклеенное сверху. */
.wb__wrap { position: relative; flex: 1; min-height: 360px; display: flex; }
.wb__over {
  position: absolute; top: var(--s-3); z-index: 4;
  display: flex; align-items: center; gap: var(--s-2);
  /* Оба островка одной высоты: они стоят на одной строке по краям холста,
     и разная высота читается как перекос, а не как замысел. */
  height: 40px; box-sizing: border-box;
  padding: 0 var(--s-2);
  overflow: hidden;
  background: var(--raised); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-md);
}
/* Слева — после панели инструментов редактора: она стоит столбцом
   у левого края, в var(--s-3) от угла, и занимает 44 точки.

   Верх холста теперь свободен целиком: инструменты ушли столбцом влево,
   свойства — колонкой вправо, и посередине никого нет. Прежние границы
   (`50% - 360px`) считались от горизонтальной панели, которая стояла
   посередине сверху, — её больше нет, а островок из-за неё жался до 390
   точек и съедал название доски до «Моя дос». Осталось одно настоящее
   условие: два островка не должны встретиться посередине. */
.wb__over--left {
  /* От края на столько же, на сколько панель инструментов редактора
     (0.375rem в форке): владелец 15 сентября 2026 — «выровнять, чтобы
     расстояние от левого края до панели и до заголовка было одинаковым».
     Панель сама начинается ниже островка, верх свободен. */
  left: calc(1rem + 0.375rem); /* 1rem — внутренний отступ самого редактора */
  min-width: 0; max-width: calc(50% - 40px);
}
.wb__over--right { right: var(--s-3); max-width: calc(50% - 40px); }
/* Узкий экран: редактор уводит инструменты вниз, и верхняя строка свободна
   целиком — тесниться больше не перед кем. */
@media (max-width: 860px) {
  .wb__over--left { max-width: calc(100% - 96px); }
  .wb__over--right { max-width: 40%; }
}
/* «Ко всем доскам» — одна из главных кнопок: крупнее и в полный цвет */
.wb__back { flex: none; width: 34px; height: 34px; color: var(--text); }
.wb__back svg { display: block; }
.wb__nastr svg { display: block; }

/* Название правится на месте, а не в окне: поле без рамки, пока в него
   не встали, — заголовок, который оказался вводом. */
.wb__title {
  /* Имени доски место не уступают: оно и есть ответ на вопрос «что это».
     Прежде поле сжималось до шестидесяти точек, и «Моя доска» превращалась
     в «Моя дос». Теперь ужимаются ярлыки справа от него — их узнают,
     а не читают. */
  width: min(320px, 26vw); min-width: 150px; flex: 0 1 auto; height: 26px;
  padding: 0 var(--s-2);
  /* Мельче заголовка страницы: на холсте название — не заголовок, а метка;
     читают его раз, а место оно занимает всё время. */
  font-size: var(--t-sm); font-weight: 600;
  border-color: transparent; background: transparent;
  /* Не влезло (на телефоне поле узкое) — многоточие, а не обрыв на букве
     (аудит 30.09.2026: «Концепция гостин» без знака, что имя длиннее) */
  text-overflow: ellipsis;
}
.wb__title:hover:where([data-hover="mouse"] *) { border-color: var(--border); }
/* Гость доски по ссылке (/v/<ключ>): название — надпись, а не поле, править
   его нечем. Ширину берёт по тексту, длинное — многоточием. */
.wb__title--static {
  display: inline-flex; align-items: center; width: auto; max-width: min(360px, 40vw);
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis; border: 1px solid transparent;
}
.wb__title--static:hover:where([data-hover="mouse"] *) { border-color: transparent; }
/* Имя бюро — метка, а не ссылка: портал этому человеку не открыт.
   Отделено чертой от названия доски, чтобы не читалось его частью. */
.wb__brand {
  display: inline-flex; align-items: center; flex: none; height: 24px;
  padding-right: var(--s-2); border-right: 1px solid var(--border);
  font-size: var(--t-sm); color: var(--text);
}
.wb__share, .wb__disk-add { flex: none; gap: var(--s-1); }
/* Ярлык проекта уступает место первым — многоточием. На iPad в альбомной
   ориентации (1024 точки) островок упирался в свою предельную ширину,
   и «Поделиться» обрезался его краем на полслова. */
.wb__proj { display: flex; flex: 0 1 auto; min-width: 0; }
.wb__proj .btn { min-width: 0; max-width: 100%; }
.wb__proj .btn > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Стрелка выбора проекта — с зазором от имени и не уходит под многоточие:
   вплотную «Садовой⌄» читалась одним словом (сверка 28 сентября 2026) */
.wb__proj .btn > span { display: inline-flex; align-items: center; gap: var(--s-1); }
.wb__proj-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Значок «Поделиться»/«Диск» — только для телефона, где слову нет места */
.wb__share .ic, .wb__disk-add .ic { display: none; }
/* «Поделиться» доской (29 сентября 2026) — плашкой под кнопкой, как в
   Miro: сверху ссылка для своих, ниже гость без входа одной строкой
   с переключателем. Плавает над холстом — значит, стекло, как у меню. */
.wbshare-pop {
  position: fixed; z-index: 45; width: 380px; box-sizing: border-box; /* под окнами вопросов (50) */
  padding: var(--s-3); overflow-y: auto; overscroll-behavior: contain;
  background: var(--solid); border: 1px solid var(--line);
  border-radius: var(--radius-lg); box-shadow: var(--sh-3);
  animation: fade-in .12s var(--ease);
}
[data-glass='panels'] .wbshare-pop {
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border-color: var(--edge-2); box-shadow: var(--in), var(--sh-3);
}
.wbshare-modal { width: min(420px, 100%); }
.wbshare { display: flex; flex-direction: column; gap: var(--s-2); font-size: var(--t-sm); color: var(--ink); }
.wbshare__copy { width: 100%; justify-content: center; gap: var(--s-2); }
.wbshare__who { color: var(--ink-3); text-align: center; margin-top: calc(-1 * var(--s-1)); }
.wbshare__sep { height: 1px; background: var(--line); margin: var(--s-1) 0; }
.wbshare__guest { display: flex; flex-direction: column; gap: var(--s-2); }
.wbshare__row { display: flex; align-items: center; gap: var(--s-2); }
.wbshare__label { flex: 1; min-width: 0; display: flex; flex-direction: column; font-weight: 600; font-size: var(--t-base); }
.wbshare__state { font-weight: 400; font-size: var(--t-xs); color: var(--ink-3); }
.wbshare__term { width: auto; flex: none; height: 28px; padding: 0 var(--s-2); font-size: var(--t-sm); }
.wbshare__hint { color: var(--ink-3); font-size: var(--t-xs); }
/* Переключатель: дорожка с кружком, включён — цветом акцента */
.wbshare__sw {
  flex: none; position: relative; width: 36px; height: 20px; padding: 0; cursor: pointer;
  border: none; border-radius: var(--radius-full); background: var(--line-2);
  transition: background var(--fast);
}
.wbshare__sw.is-on { background: var(--accent); }
.wbshare__sw:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.wbshare__knob {
  position: absolute; top: var(--s-05); left: var(--s-05); width: 16px; height: 16px;
  border-radius: var(--radius-full); background: #fff; box-shadow: var(--sh-1);
  transition: transform var(--fast);
}
.wbshare__sw.is-on .wbshare__knob { transform: translateX(16px); }
.wbshare__url { display: flex; gap: var(--s-1); align-items: center; }
.wbshare__url .input { flex: 1; min-width: 0; height: 32px; font-family: var(--mono); font-size: var(--t-xs); }
.wbshare__url .btn { flex: none; width: 32px; height: 32px; padding: 0; justify-content: center; }
.wbshare__acts { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s-1) var(--s-2); }
.wbshare__act {
  border: none; background: none; padding: var(--s-1) 0; cursor: pointer;
  font: inherit; font-size: var(--t-sm); color: var(--accent-fg);
}
.wbshare__act:hover:where([data-hover="mouse"] *) { text-decoration: underline; }
.wbshare__act--danger { color: var(--late-fg); margin-left: auto; }
/* Телефон: «Выключить» переносился второй строкой, а выключает ссылку и
   переключатель над ним — на узком экране хватит его одного */
@media (max-width: 520px) { .wbshare__act--danger { display: none; } }
/* Область для заказчика (28 сентября 2026). У гостя в островке — метка
   «Можно править» (у ссылки на просмотр «Только просмотр» пишет сам Ватман)
   и кнопка со своим именем: им его видят те, кто сейчас в области. */
.wb__access {
  display: inline-flex; align-items: center; flex: none; height: 24px; padding: 0 var(--s-2);
  border-radius: var(--radius-full); font-size: var(--t-xs); font-weight: 600;
  color: var(--accent-fg); background: var(--accent-soft); white-space: nowrap;
}
.wb__who { flex: 0 1 auto; min-width: 0; max-width: 12em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Окно «Для заказчика»: две ссылки разделами, у каждой свой срок */
.zak__intro { margin: 0 0 var(--s-2); }
.zak__sec { display: flex; flex-direction: column; gap: var(--s-2); padding: var(--s-3) 0; border-top: 1px solid var(--line); }
.zak__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-2); font-weight: 600; font-size: var(--t-md); }
.zak__head .note { font-weight: 400; font-size: var(--t-sm); }
.zak__row { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
.zak__row .btn { flex: none; }
.zak__url { flex: 1 1 14em; min-width: 0; font-family: var(--mono); font-size: var(--t-sm); }
.zak__srok { width: auto; flex: none; }
.zak__stop { margin-right: auto; }
/* Держит ширину: «правится» и «сохранено в 12:40» разной длины, и без
   этого правая полка дёргалась при каждом сохранении */
.wb__saved { font-size: var(--t-2xs); color: var(--text-faint); white-space: nowrap; min-width: 7.5em; text-align: right; }
/* Кто сейчас на доске — лицами в углу холста. Курсоры соседей рисует сам
   редактор; эта строка отвечает на вопрос «я тут один?», не глядя на холст.
   Лицо общее для всего приложения, обводка — цвет курсора этого человека. */
.wb__people { display: flex; align-items: center; gap: var(--s-1); }
.wb__face { flex: none; }
/* Никаких рамок вокруг холста. Их было три слоя: скруглённое полотно
   приложения, поле страницы внутри него и своя рамка у самого холста —
   и всё это отъедало место у того, ради чего сюда заходят. Осталась одна
   полоска под шапкой, которая отделяет доску от приложения. */
.wb__canvas { flex: 1; min-height: 0; overflow: hidden; }
.shell:has(.page--wb) .main {
  margin: 0; border: none; border-radius: 0;
  border-top: 1px solid var(--border);
}
/* И боковая колонка на доске не нужна: в свёрнутом виде она пустая, а
   двадцать четыре точки слева от холста — это те самые поля, от которых
   мы здесь и уходили. Кнопки, что в ней живут, все есть в верхней полосе. */
.shell:has(.page--wb) .side { display: none; }
/* Полотно на доске не прокручивается: прокрутку делает сам холст. Без этого
   при неудачном округлении вылезала полоса прокрутки — синяя черта во всю
   ширину под доской, которую принимали за элемент интерфейса. */
.shell:has(.page--wb) .main { overflow: hidden; }
.page--wb { padding: 0; }
/* Редактор рисует себя сам и лезет во всю высоту родителя */
.wb__canvas .excalidraw { height: 100%; }




/* Сводка «Планирования»: одна строка над колонками. Не плитки — плитки
   просят места и веса, которых у сводки нет: её читают на бегу, по дороге
   к колонкам, ради которых сюда и заходят. */
.plansv {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--s-2);
  font-size: var(--t-sm); color: var(--text-dim); margin-bottom: var(--s-3);
}
.plansv__item b { font-weight: 600; color: var(--text); }
.plansv__item.is-bad b { color: var(--late-fg); }
.plansv__item.is-good b { color: var(--ok-fg); }
.plansv__item.is-warn b { color: var(--warn-fg); }
.plansv__sep { color: var(--text-faint); }
.plansv__quiet { color: var(--text-faint); }
/* Какая неделя — первым словом строки: часы в колонках без неё не про что */
.plansv__week { color: var(--text); font-weight: 500; }

/* Гамбургер разделов: показывается, только когда полоса не влезла.
   Ширину не угадываем числом — у бюро разделов может быть шесть, а может
   десять; меряет сама шапка, см. `подогнатьПолосуРазделов`. */
.roundbtn--menu { display: none; }
.topbar.is-tight .topnav { display: none; }
.topbar.is-tight .roundbtn--menu { display: grid; }
/* На телефоне разделы стоят полосой внизу, и гамбургер в шапке был бы
   третьей дверью в одно и то же место */
@media (max-width: 760px) { .roundbtn--menu { display: none !important; } }

/* ── Поставщики ──────────────────────────────────────────────────────────── */
/* Стили справочника переехали в modules/suppliers/styles.css (24 сентября
   2026). Здесь — то, чем пользуются и другие экраны. */

/* Полоса с процентами вместо трёх точек. Точки не отличают «идёт» от
   «встало»; полоса отвечает на оба вопроса сразу и говорит, сколько ещё. */
.progress { max-width: 420px; margin: var(--s-7) auto; }
.progress__head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: var(--s-2);
}
.progress__what { font-size: var(--t-sm); color: var(--text-dim); }
.progress__pct {
  font-size: var(--t-sm); font-variant-numeric: tabular-nums; color: var(--text);
}
.progress__track {
  height: 4px; border-radius: 999px; background: var(--surface-2); overflow: hidden;
}
.progress__bar {
  height: 100%; width: 0; border-radius: 999px; background: var(--accent);
  transition: width .12s linear;
}
/* Длина ответа неизвестна — полоса бегает сама, чтобы было видно: идёт */
.progress.is-vague .progress__bar {
  width: 35%; animation: progress-run 1.1s ease-in-out infinite;
}
@keyframes progress-run {
  0% { margin-left: -35%; } 100% { margin-left: 100%; }
}

.pageicon { display: block; line-height: 0; }
/* Выбор поставщика поиском: списком шестьсот строк не выбирают */
.pickbox { max-height: 320px; overflow-y: auto; margin-top: var(--s-3); }
.pickbox__row {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-2);
  width: 100%; text-align: left; padding: var(--s-2); border: none; background: none;
  cursor: pointer; border-radius: var(--radius-sm); font: inherit;
}
.pickbox__row:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.typechip--more { border-style: dashed; color: var(--text-dim); }


/* Окно выбора строками (откуда взять файл и т.п.): у каждой пояснение под
   заголовком. Не кнопками в ряд — у способов разная цена и разный смысл,
   и выбирают их, прочитав, а не ткнув в ближайшую. */
.vygruz { display: flex; flex-direction: column; gap: var(--s-1); }
.vygruz__row {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: var(--s-2) var(--s-3); height: auto; text-align: left;
}
.vygruz__row:disabled { opacity: .5; cursor: default; }
.vygruz__name { font-weight: 500; }
.vygruz__note { font-size: var(--t-xs); }


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

/* До 900 точек островки перестают быть островками и становятся шапкой доски.
   Порог не с потолка: слева стоят стрелка, имя и ярлык проекта — около 440
   точек, справа цвет, сетка, выгрузка, лица и отметка — около 300, да поля.
   Ниже этого они встречаются посередине: на планшете в 768 ярлык проекта
   обрезался, а правый островок наезжал на левый. */
@media (max-width: 900px) {
  /* Сеткой, а не рядами с переносом: у переноса высота рядов делится поровну,
     и шапка забирала себе полэкрана. Сетка говорит прямо — шапке по
     содержимому, холсту всё остальное. */
  .wb__wrap {
    display: grid; min-height: 0;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: 'слева справа' 'холст холст';
  }
  .wb__over {
    position: static; height: auto; min-height: 40px;
    padding: var(--s-1) var(--s-2);
    /* Фон светлый, а не прозрачный: доска всегда в светлой теме, и текст
       здесь тёмный. Сквозь прозрачную шапку в тёмной теме портала
       просвечивал тёмный фон приложения, и «← Название» читалось тёмным
       по тёмному (владелец, 21 сентября 2026, с телефона). */
    background: var(--surface); box-shadow: none; border-radius: 0;
    /* Полоска под шапкой — та же, что отделяет доску от приложения на большом
       экране. Без неё имя доски висит прямо над холстом и читается надписью
       на нём. */
    border: none; border-bottom: 1px solid var(--border);
  }
  .wb__over--left {
    grid-area: слева; min-width: 0; max-width: none;
    padding-left: max(var(--s-2), env(safe-area-inset-left));
  }
  .wb__over--right {
    grid-area: справа; max-width: none;
    padding-right: max(var(--s-2), env(safe-area-inset-right));
  }
  .wb__canvas { grid-area: холст; min-height: 0; }
  /* Имя доски занимает всё, что осталось от строки: выбирать ему ширину
     числом на такой ширине нечем. */
  .wb__title { width: auto; min-width: 0; flex: 1 1 auto; }
  /* Отметка сохранения ужимается многоточием, а не обрубается краем экрана.
     Она бывает и длинной — «страница 12 из 40…», «не сохранилось», — а места
     в строке ровно столько, сколько осталось от имени доски. */
  .wb__saved {
    flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  }
}

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

   Без этого доска складывалась в 360 точек: `.shell` на телефоне — обычный
   блок, `flex: 1` в нём ничего не растягивает, и от холста оставалась его
   наименьшая высота, то есть треть экрана. */
@media (max-width: 760px) {
  /* Страницу под доской запираем совсем. Одного `overflow: hidden` у
     приложения мало: страница по-прежнему остаётся тем, что браузер считает
     своим, и жест, начатый мимо холста — по шапке доски, по логотипу, по
     полосе разделов, — достаётся ему. Доска оттягивается вниз, а следом за
     оттяжкой идёт «потянуть, чтобы обновить»: страница перезагружается прямо
     посреди рисования, и всё, что было на экране, сбрасывается.

     Сам холст от этого защищён — у него `touch-action: none`, и жест по нему
     редактор забирает себе. Незащищено было всё остальное.

     Способ тот же, каким приложение живёт на большом экране: тело закреплено
     по краям окна (`position: fixed; inset: 0`), и прокручивать снаружи
     нечего. `overscroll-behavior: none` добавлено рядом — оно снимает
     и оттяжку, и обновление там, где закрепления мало. */
  /* Признак — класс на корне (его ставит app.js при переходе на доску),
     а не `:has()` в стилях: `:has()` есть не во всяком телефонном браузере,
     а это ровно тот случай, где проверить нечем, а ошибка стоит
     перезагрузки посреди рисования. */
  .доска-целиком { height: 100%; overflow: hidden; overscroll-behavior: none; }
  .доска-целиком body {
    position: fixed; inset: 0; height: auto;
    overflow: hidden; overscroll-behavior: none;
  }
  /* Высоту надо провести до самого приложения: общее телефонное правило
     ставит `#root` в `height: auto`, и `100%` у приложения не от чего было
     считать — оно съёживалось до высоты шапки, а холст обращался в ноль. */
  .доска-целиком #root { height: 100%; }
  /* 100% от закреплённого тела — это ровно видимая область. `100dvh` здесь
     хуже: он меняется, когда браузер прячет адресную строку, и холст
     подрагивает высотой при каждом таком движении. `min-height` снимаем
     тем же движением: он остался от общего правила и был больше высоты. */
  .доска-целиком .app { height: 100%; min-height: 0; overflow: hidden; }
  .доска-целиком .shell { display: flex; flex: 1; min-height: 0; }
  .доска-целиком .main { overflow: hidden; }
  /* Шапка доски жест браузеру тоже не отдаёт: тянут чаще всего именно
     за неё — она у верхнего края, где и начинается «потянуть, чтобы
     обновить». Холст от этого защищён сам, у него своё `touch-action`. */
  .wb__over { touch-action: none; }
  /* Шапка доски на 375 точках: стрелка, меню, название, проект и
     «Поделиться» делили строку так, что названию оставалось две буквы —
     «Пр» вместо «Проба копий». Имя доски — ответ на вопрос «где я»,
     поэтому уступают соседи: «Поделиться» становится значком, а ярлык
     проекта ужимается многоточием (выбор проекта при этом весь на месте). */
  .wb__share, .wb__disk-add { width: 40px; height: 40px; padding: 0; justify-content: center; }
  .wb__share .ic, .wb__disk-add .ic { display: block; }
  .wb__share-t { display: none; }
  .wb__title { min-width: 88px; height: 40px; }
  .wb__proj { max-width: 38%; }
  .wb__proj .btn { height: 40px; }
  .wb__back, .wb__menu { width: 40px; height: 40px; }
  /* И весь холст Ватмана с его панелями: у самого холста `touch-action`
     свой, а панели инструментов внизу — обычные блоки, и жест, начатый
     с них, уходил браузеру: доска оттягивалась и перезагружалась
     (владелец, 21 сентября 2026, с телефона). Списки внутри, которым
     нужна прокрутка, ставят себе `touch-action: pan-y` сами. */
  .wb__canvas--vatman { touch-action: none; overscroll-behavior: none; }
  /* Поля у доски не нужны вовсе — рисуют до края, — а снизу оставляем ровно
     полосу разделов: она закреплена поверх и иначе накрыла бы холст. */
  .page--wb {
    padding: 0 0 calc(var(--nav-h, 82px) + env(safe-area-inset-bottom)) 0;
  }
  /* У гостя доски по ссылке полосы разделов нет — и место под неё не нужно */
  .page--wb.page--guest { padding-bottom: env(safe-area-inset-bottom); }
  /* Доска раздела «Доски» — во весь экран (Б10, 1.10.2026): шапки портала
     и полосы разделов нет, холст от плашки доски до низа экрана; назад —
     стрелкой на плашке. Признак `доска-без-рамки` ставит app.js */
  .доска-без-рамки .topbar, .доска-без-рамки .nav { display: none; }
  .доска-без-рамки .page--wb { padding: env(safe-area-inset-top) 0 env(safe-area-inset-bottom) 0; }
}

/* ── Выбор поставщика в позиции закупок ──────────────────────────────────────
   Подсказки из справочника прямо под полем, а не отдельным окном: поставщика
   набирают по ходу правки лота, и уводить человека в модальное окно ради
   одной строки — это лишний заход туда и обратно. */
.postpick__box { position: relative; }
.postpick {
  position: absolute; left: 0; right: 0; top: calc(100% + 2px); z-index: 20;
  max-height: 240px; overflow-y: auto;
  display: flex; flex-direction: column;
  background: var(--solid);
  border-radius: var(--radius-lg); box-shadow: var(--sh-2); padding: var(--s-1);
}
.postpick__row {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-2);
  padding: var(--s-2) var(--s-3); min-height: 36px;
  text-align: left; background: none; border: none; cursor: pointer; border-radius: var(--radius-sm);
  color: var(--text); font: inherit;
}
.postpick__row:hover:where([data-hover="mouse"] *), .postpick__row:focus-visible { background: var(--hover); }
/* Связь со справочником — не предупреждение, а подтверждение: цветом
   акцента, а не тревоги. Без связи пояснение остаётся приглушённым:
   набрать своими словами можно, это не ошибка. */
.postpick__есть { color: var(--accent-fg); }
/* Поставщик из справочника в строке лота: подчёркивание только при наведении —
   в таблице десяток строк, и десяток подчёркиваний читаются как рябь. */
.procsup { color: inherit; text-decoration: none; }
.procsup:hover:where([data-hover="mouse"] *) { color: var(--accent-fg); text-decoration: underline; }

/* Окно «где лежит файл»: имя крупнее пути — спрашивают про файл, а путь
   это ответ. */
.gdefile__name { font-weight: 600; margin: 0 0 var(--s-1); word-break: break-word; }
/* Пояснение про место в окне выбора страниц — отделено чертой: это не ещё
   один способ положить документ, а замечание про все три. */
.gdefile__note {
  margin: var(--s-2) 0 0; padding-top: var(--s-2);
  border-top: 1px solid var(--border);
}



/* ── Просмотр файла с диска ───────────────────────────────────────────────────

   Окно почти во весь экран, а не карточка посередине. Смотрят здесь чертёж
   и смету, то есть то, что мелким читать нельзя: карточка на 460 пикселей
   годится для вопроса «удалить?», а не для листа А1.

   Поверх страницы, а не отдельным адресом: посмотрел и вернулся в ту же
   папку, к тому же месту в списке. Отдельная страница файла заставляла бы
   искать это место заново. */
.smotr {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(0, 0, 0, .62);
  display: flex; padding: var(--s-4);
  animation: fade-in .14s var(--ease);
}
.smotr__win {
  background: var(--solid);
  border-radius: var(--radius-xl); box-shadow: var(--sh-3);
  margin: auto; width: min(1180px, 100%); height: 100%;
  display: flex; flex-direction: column; overflow: hidden;
}
.smotr__head {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-3) var(--s-3) var(--s-4);
  flex: none;
}
/* Имя жмётся, кнопки — нет: длинное имя не должно выдавливать «Закрыть». */
.smotr__name {
  font-size: var(--t-md); font-weight: 600;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.smotr__ves { flex: none; }
.smotr__act { margin-left: auto; display: flex; gap: var(--s-2); flex: none; }
/* Соседние файлы папки: ‹ 2 из 5 › — слева от имени (Д16, 1.10.2026) */
.smotr__nav { display: flex; align-items: center; gap: var(--s-1); flex: none; }
.smotr__schet { min-width: 5.5ch; text-align: center; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* «лист 2 из 3» — плашкой у низа окна, пока листают PDF; стекло, как всё плавающее */
.smotr__list-n {
  position: sticky; bottom: var(--s-3); width: max-content; margin: calc(-1 * var(--s-7)) auto var(--s-3);
  padding: var(--s-1) var(--s-3); border-radius: var(--radius-full);
  background: var(--glass-strong); backdrop-filter: var(--blur); -webkit-backdrop-filter: var(--blur);
  box-shadow: var(--sh-2); font-size: var(--t-sm); color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.smotr__pravit { align-self: center; color: var(--warn-fg); white-space: nowrap; }

/* Окно программы (ShelestPDF, NOPS, Tertsia, редактор документов) — во весь
   экран, поверх всего: редактору нужно место, а не рамка просмотрщика.
   Своей шапки у окна нет (владелец 14 сентября 2026): «Ссылка», «Закрыть»,
   состояние и кружки «кто в файле» рисует программа в своей шапке, см.
   public/programma.js. */
.programma {
  position: fixed; inset: 0; z-index: 90;
  background: var(--surface);
  display: flex; flex-direction: column;
  animation: fade-in .14s var(--ease);
}
.programma__frame { flex: 1; min-height: 0; width: 100%; border: 0; background: #fff; }
/* Окна портала, открытые из программы, — поверх её окна, а не под ним.
   Имя нового файла, «откуда взять картинку», «куда положить экспорт» —
   всё это `.modal-backdrop` с z-index 50, а окно программы стоит на 90:
   14 сентября 2026 плюсик в Tertsia молча открывал окно имени ПОД
   программой, и снаружи казалось, что ничего не произошло. Всплывашки —
   ещё выше: ошибка «не удалось положить» должна быть видна и над окном. */
.programma ~ .modal-backdrop { z-index: 91; }
.programma ~ .toast { z-index: 92; }
.smotr__body {
  flex: 1; min-height: 0; overflow: auto; -webkit-overflow-scrolling: touch;
  background: var(--solid);
}
/* Черты под шапкой нет, как у окна (сверка 28 сентября 2026): листы PDF
   и снимки лежат на утопленной подложке, она и отделяет их от шапки. */
.smotr__body:has(> .smotr__pdf) { background: var(--well); }

/* Страницы PDF — столбиком, каждая своим листом на подложке. Тень и белый
   фон намеренно: без них лист сливается с полотном, и на многостраничном
   документе не видно, где кончается одна страница и начинается другая. */
.smotr__pdf {
  display: flex; flex-direction: column; align-items: center;
  gap: var(--s-4); padding: var(--s-4);
}
.smotr__list {
  display: block; max-width: 100%; height: auto;
  background: #fff; border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
}

/* Текст — моноширинным и с сохранением переносов: в csv и логах вся
   осмысленность в том, где кончается строка. */
.smotr__text {
  margin: 0; padding: var(--s-4);
  font-family: var(--mono); font-size: var(--t-mono); line-height: 1.55;
  white-space: pre-wrap; word-break: break-word; color: var(--text);
}
.smotr__more { padding: 0 var(--s-4) var(--s-4); }
/* Старый документ Тетради — страницей сервера в песочнице; лист белый, как бумага */
/* Отрывок находки по содержимому в поиске диска: совпадение — фоном, цвет текста тот же */
.siderow__snippet { white-space: normal; }
.siderow__snippet mark { background: var(--accent-soft); color: inherit; border-radius: var(--radius-sm); }
.smotr__tetrad { display: block; width: 100%; height: 100%; border: 0; background: #fff; }

.smotr__video { display: block; width: 100%; height: 100%; background: #000; }
.smotr__audio { display: block; width: min(560px, 100%); margin: var(--s-6) auto; }

/* Нечего показать — говорим это посередине пустого окна, а не строкой
   в углу: это и есть весь ответ на нажатие. */
.smotr__net {
  max-width: 460px; margin: auto; padding: var(--s-6) var(--s-4);
  text-align: center; height: 100%;
  display: flex; flex-direction: column; justify-content: center; gap: var(--s-3);
}
.smotr__net h3 { margin: 0; font-size: var(--t-lg); }
.smotr__net p { margin: 0; }
.smotr__btns {
  display: flex; gap: var(--s-2); justify-content: center; margin-top: var(--s-2);
}

@media (max-width: 760px) {
  /* На телефоне окно во весь экран без полей: полтора сантиметра поля по
     краю — это полтора сантиметра, которых не хватает чертежу. */
  .smotr { padding: 0; }
  .smotr__win { border: 0; border-radius: 0; width: 100%; }
  .smotr__head { padding: var(--s-2) var(--s-2) var(--s-2) var(--s-3); }
  .smotr__ves { display: none; }
  .smotr__pdf { padding: var(--s-2); gap: var(--s-2); }
  .smotr__btns { flex-direction: column; }
}

/* Разделы админки кнопкой — только там, где нет левой колонки.
   Колонка пропадает ниже 1100 точек, и вместе с ней пропадала вся навигация
   по админке: человек оставался в том разделе, в который вошёл. */
.admnav { display: none; margin-left: auto; }
.admnav__label { display: inline-flex; align-items: center; gap: var(--s-1); }
/* Шеврон общий на всё приложение и смотрит влево; здесь он говорит
   «раскроется вниз» — поворачиваем, а не заводим второй значок. */
.admnav__label .ic { transform: rotate(-90deg); }
@media (max-width: 1100px) {
  .admnav { display: inline-flex; }
}
/* На телефоне кнопки нет: там у админки есть свой первый экран со списком
   разделов и строка «‹ Администрирование» над каждым из них. Две двери
   в одно место на узком экране — это не запас, а лишний предмет в шапке. */
@media (max-width: 760px) {
  .admnav { display: none; }
}

/* ── Админка на телефоне: сначала разделы, потом экраны раздела ─────────────

   Разделы стоят в левой колонке, а её ниже 1100 точек нет. Ниже 760 нет
   и места под кнопку с меню — зато есть привычка: настройки телефона
   устроены ровно так же, списком с пояснениями, и объяснять этот экран
   не приходится.

   Что показать, решает ширина экрана, а не проверка в коде: страница
   рисуется целиком — и список разделов, и сам раздел, — а видно из них
   то, что уместно. Телефон поворачивают, и ответ должен меняться вместе
   с ним, а не при следующей перерисовке. */
.admlist { display: none; flex-direction: column; }
.admback { display: none; }
@media (max-width: 760px) {
  /* Корень админки — только список разделов. Всё прочее на нём есть
     в разметке, но не на экране: страница раздела откроется следующим
     нажатием, и печатать её под списком незачем. */
  .page--admroot .admlist { display: flex; }
  .page--admroot > *:not(.admlist) { display: none; }
  /* Дорога назад. Стрелка со словом: одна стрелка в углу не говорит, куда
     ведёт, а «Администрирование» говорит. */
  .admback {
    display: inline-flex; align-items: center; gap: var(--s-1);
    margin-bottom: var(--s-2); padding: var(--s-2) 0;
    border: none; background: none; cursor: pointer;
    color: var(--text-dim); font: inherit; font-size: var(--t-sm); font-weight: 500;
  }
  .admback:hover:where([data-hover="mouse"] *) { color: var(--text); }
}
.admlist__row {
  display: flex; align-items: center; gap: var(--s-3); width: 100%;
  padding: var(--s-3) 0; border: none; border-bottom: 1px solid var(--border);
  background: none; cursor: pointer; color: var(--text); font: inherit;
  text-align: left;
}
.admlist__row:last-child { border-bottom: none; }
.admlist__main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s-05); }
.admlist__name { font-size: var(--t-base); font-weight: 500; }
/* Пояснение отвечает на «мне сюда?» до нажатия — иначе разделы приходится
   перебирать по одному, а их восемь. */
.admlist__note { font-size: var(--t-xs); color: var(--text-dim); line-height: 1.35; }
/* Шеврон общий на всё приложение и смотрит влево; здесь он говорит
   «откроется дальше» — поворачиваем, а не заводим второй значок. */
.admlist__go { flex: none; display: inline-flex; color: var(--text-faint); }
.admlist__go .ic { transform: rotate(180deg); }

/* ── Администрирование по макету редизайна (27 сентября 2026) ─────────────────
   Раскладка прежняя — разделы в колонке, экраны раздела вкладками (решение
   4 сентября 2026); по макету — значки у разделов, карточки без черты под
   шапкой и с воздухом по краям, люди строками, выключатели у модулей. */
.siderow__ic, .admlist__ic { flex: none; display: inline-flex; color: var(--text-faint); }
.siderow.is-active .siderow__ic { color: var(--accent-fg); }
.admlist__ic { color: var(--accent-fg); }

.page--admin .card { border: none; background: var(--solid); box-shadow: var(--sh-1); }
.page--admin .card__head { border-bottom: none; padding: var(--s-4) var(--s-5) var(--s-2); }
.page--admin .card__head h2 { font-size: var(--t-lg); }
.page--admin .card__body { padding: var(--s-2) var(--s-5) var(--s-5); }
@media (max-width: 760px) {
  .page--admin .card__head { padding: var(--s-3) var(--s-3) var(--s-2); }
  .page--admin .card__body { padding: var(--s-2) var(--s-3) var(--s-3); }
}
/* Таблица прямо в карточке админки («Состав», «Не в компании»): крайние
   ячейки — на поле карточки, чтобы имя стояло под заголовком, а не на
   восемь точек левее; последний столбец — действия — прижат вправо
   (сверка экранов, 28 сентября 2026). */
.page--admin .card > .table--wide :is(th, td):first-child,
.page--admin .card > .table :is(th, td):first-child { padding-left: var(--s-5); }
.page--admin .card > .table--wide :is(th, td):last-child,
.page--admin .card > .table :is(th, td):last-child { padding-right: var(--s-5); text-align: right; }
.page--admin .card > :is(.table, .table--wide):last-child { margin-bottom: var(--s-2); }
@media (max-width: 760px) {
  .page--admin .card > .table--wide :is(th, td):first-child,
  .page--admin .card > .table :is(th, td):first-child { padding-left: var(--s-3); }
  .page--admin .card > .table--wide :is(th, td):last-child,
  .page--admin .card > .table :is(th, td):last-child { padding-right: var(--s-3); }
}

/* Люди строками: аватар, имя, под ним почта; справа роль и действия.
   Заявка на вход — подсвеченной строкой: она ждёт решения */
.admppl { display: flex; flex-direction: column; padding: 0 var(--s-5) var(--s-2); }
.admppl__row {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) 0; border-top: 1px solid var(--line);
}
.admppl__row:first-child { border-top: none; }
.admppl__row.is-drop { box-shadow: inset 0 2px 0 var(--accent); }
.admppl__row--wait {
  border-top: none; border-radius: var(--radius);
  padding: var(--s-3); background: var(--warn-soft);
}
.admppl__row--wait + .admppl__row--wait { margin-top: var(--s-2); }
.admppl__main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s-05); }
.admppl__name { font-weight: 500; }
.admppl__main .note { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.admppl__row--gone .admppl__name { color: var(--text-dim); }
.admppl__tags { flex: none; display: flex; align-items: center; gap: var(--s-2); }
.admppl__act { flex: none; display: flex; align-items: center; gap: var(--s-1); }
.admppl__none { padding: var(--s-3) 0; }
@media (max-width: 760px) {
  .admppl { padding: 0 var(--s-3) var(--s-2); }
  .admppl__row { flex-wrap: wrap; row-gap: var(--s-2); }
  .admppl__main { flex-basis: 60%; }
  .admppl__tags { order: 5; }
  .admppl__act { order: 6; margin-left: auto; }
}

/* Модули — строками с выключателем справа */
.moduli { display: flex; flex-direction: column; }
.moduli__row {
  display: flex; align-items: center; gap: var(--s-4);
  padding: var(--s-3) 0; border-top: 1px solid var(--line);
}
.moduli__row:first-child { border-top: none; }
.moduli__main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s-05); }
.moduli__row.is-off .moduli__name { color: var(--text-dim); }

/* Выключатель — галочка, нарисованная переключателем */
.tog {
  -webkit-appearance: none; appearance: none; flex: none; margin: 0; position: relative;
  width: calc(var(--s-6) + var(--s-3)); height: calc(var(--s-5) + var(--s-05));
  border-radius: var(--radius-full); background: var(--line-2); cursor: pointer;
  transition: background var(--fast);
}
.tog::after {
  content: ''; position: absolute; left: var(--s-05); top: var(--s-05);
  width: calc(var(--s-5) - var(--s-05)); height: calc(var(--s-5) - var(--s-05));
  border-radius: var(--radius-full); background: var(--solid); box-shadow: var(--sh-1);
  transition: transform var(--fast);
}
.tog:checked { background: var(--accent); }
.tog:checked::after { transform: translateX(calc(var(--s-4) + var(--s-05))); background: var(--accent-ink); }
.tog:disabled { opacity: .5; cursor: default; }
.tog:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

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

   Считает это вёрстка, а не код: окно тянут и телефон поворачивают, и
   ответ должен меняться вместе с ними, а не при следующей перерисовке. */
.shell:has(.side--разделы:not(.is-folded)) .tabs--разделы { display: none; }
/* Селектор повторён слово в слово: `:has()` весит столько же, сколько самый
   тяжёлый его довод, и «просто .side--разделы» проиграл бы правилу выше
   по весу, а не по порядку — полоса осталась бы спрятанной и на телефоне. */
@media (max-width: 1100px) {
  .shell:has(.side--разделы:not(.is-folded)) .tabs--разделы { display: flex; }
}

/* Полоса страниц раздела над полотном — «Ресурсы», «Проекты» (28 сентября
   2026): тот же список, что в колонке, для экранов, где колонки нет. Ядро
   ставит её первой в полотно, страницу раздела рисует модуль под ней —
   поэтому у полосы поле страницы сверху и по бокам, а зазор до страницы
   один, а не два. */
.page--polosa { padding-bottom: 0; }
.page--polosa .tabs { margin-bottom: 0; }
.page--polosa + .page { padding-top: var(--s-4); }
/* Полоса спрятана — колонка раздела на месте (шире 1100): у страницы
   обычное поле сверху, как у всех. Иначе заголовок «Проектов» и «Ресурсов»
   вставал на 11 точек выше «Досок» и «Диска», и шапка прыгала при
   переходе между разделами (аудит 30.09.2026). Селектор — тот же, что
   прячет полосу выше. */
@media (min-width: 1101px) {
  .shell:has(.side--разделы:not(.is-folded)) .page--polosa + .page { padding-top: clamp(20px, 1.9vw, 32px); }
}

/* Шапка раздела с подписью под заголовком («Проекты», «Задачи»): кнопка
   справа — на средней линии заголовка, а не у низа подписи. Правило
   «одна строка шапки — одна средняя линия» (ОБЛИК-И-ШКАЛЫ, «Вертикальный
   ритм»); «+ Проект» стоял ниже середины «Проектов» (аудит 30.09.2026).
   Заголовок 32 × 1,05 = 34 точки, кнопка 36 — встают вровень верхом. */
@media (min-width: 761px) {
  .prj-head > .btn, .tasks__head > .btn { align-self: flex-start; }
}

/* Колонка «Ресурсов»: строки со значком, как у админки; вложенное (виды
   и категории ассетов) — по линии текста строки над ним, а не левее его:
   `--sub-in` — поле строки, значок 18 и зазор, ступень глубже — ещё --s-4.
   Черта открытого вложенного — у его собственного края. */
.side--resursy { --sub-in: calc(var(--s-6) + var(--s-1) + var(--s-05)); }
.side--resursy .siderow--sub { --in: var(--sub-in); padding-left: var(--in); }
.side--resursy .siderow--l2 { --in: calc(var(--sub-in) + var(--s-4)); }
.side--resursy .siderow--l3 { --in: calc(var(--sub-in) + 2 * var(--s-4)); }
.side--resursy .siderow--l4 { --in: calc(var(--sub-in) + 3 * var(--s-4)); }
.side--resursy .siderow--sub.is-active::before { left: calc(var(--in) - var(--s-2)); }
/* Навигатор открытого раздела — своим блоком под разделами (resursy.js):
   уже не под строкой, поэтому без отступа под её значок; черта сверху
   отделяет «что есть» от «где я» */
.side--resursy .side__group--vlozheno { margin-top: var(--s-2); border-top: 1px solid var(--line); }
.side--resursy .side__list--vlozheno { --sub-in: var(--s-3); }
.side--resursy .side__list--vlozheno .mdlside__search { padding-left: var(--s-2); padding-right: var(--s-2); }
/* «Все ресурсы» — путь на обзор, чуть отступя от разделов */
.side--resursy .siderow--obzor { margin-bottom: var(--s-1); }

/* Overview of «Ресурсы» (/resources, 7 Oct 2026): big cards, one per
   section of the column; the grid takes the width, like app tiles. */
.resobzor__grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
  gap: var(--s-4);
}
.rescard {
  position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-3);
  min-height: 168px; min-width: 0; padding: var(--s-5); text-align: left;
  background: var(--surface); border: 1px solid transparent; border-radius: var(--radius-lg);
  box-shadow: var(--shadow); color: var(--text); font: inherit; cursor: pointer;
  transition: box-shadow var(--fast), border-color var(--fast);
}
.rescard:hover:where([data-hover="mouse"] *) {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); box-shadow: var(--shadow-md);
}
.rescard:active { box-shadow: var(--shadow-xs); }
.rescard__icon {
  flex: none; display: grid; place-items: center; width: 56px; height: 56px; border-radius: var(--radius);
  background: var(--accent-soft); color: var(--accent-fg);
}
.rescard__text { display: flex; flex-direction: column; gap: var(--s-1); min-width: 0; }
.rescard__name { font-size: var(--t-lg); font-weight: 600; }
.rescard__desc { font-size: var(--t-sm); color: var(--text-dim); line-height: 1.35; }
.rescard__count {
  position: absolute; top: var(--s-5); right: var(--s-5);
  font-size: var(--t-xl); font-weight: 600; color: var(--text-dim);
}
@media (max-width: 560px) {
  .rescard { min-height: 0; flex-direction: row; align-items: center; padding: var(--s-3) var(--s-4); }
  .rescard__icon { width: 40px; height: 40px; }
  .rescard__name { font-size: var(--t-md); }
  .rescard__count { position: static; margin-left: auto; font-size: var(--t-md); }
}

/* Полоса вкладок листается — и это должно быть видно.
   Растворяем содержимое у того края, куда можно уехать. Маской по самой
   полосе: подложка внутри прокручиваемого блока уехала бы вместе
   с вкладками, а маска считается по коробке и стоит на месте. */
.tabs.есть-справа {
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 36px), transparent);
  mask-image: linear-gradient(90deg, #000 calc(100% - 36px), transparent);
}
.tabs.есть-слева {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 36px);
  mask-image: linear-gradient(90deg, transparent, #000 36px);
}
.tabs.есть-слева.есть-справа {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 36px,
    #000 calc(100% - 36px), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 36px,
    #000 calc(100% - 36px), transparent);
}

/* ── Таблица из книги Excel ──────────────────────────────────────────────────

   Буквы столбцов и номера строк, как в самом Excel: первую строку за
   заголовок не выдаём — в сметах бюро сверху шапка на три строки, и «шапка
   таблицы» из неё сбивает с толку сильнее, чем помогает. */
.xlsv { padding: var(--s-3); }
/* Полоса листов не уезжает вверх вместе с таблицей: на листе три тысячи
   строк, и вернуться к выбору листа иначе можно только прокруткой обратно. */
.smotr__body > .tabs {
  position: sticky; top: var(--s-2); z-index: 2;
  margin: var(--s-2) var(--s-3) 0;
}
.xlsv__table {
  border-collapse: collapse; font-size: var(--t-sm);
  font-variant-numeric: tabular-nums;
}
.xlsv__table th, .xlsv__table td {
  border: 1px solid var(--border);
  padding: var(--s-1) var(--s-2);
  max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.xlsv__table th {
  position: sticky; top: 0; z-index: 1;
  background: var(--surface-2, var(--raised)); color: var(--text-dim);
  font-weight: 500; font-size: var(--t-xs);
}
.xlsv__num {
  position: sticky; left: 0; z-index: 1;
  background: var(--surface-2, var(--raised)); color: var(--text-faint);
  font-size: var(--t-xs); text-align: right;
}
.xlsv__table th.xlsv__num { z-index: 3; }
.xlsv__ch { text-align: right; }

/* ── Документ Word ───────────────────────────────────────────────────────────

   Колонка текста, а не во всю ширину окна: строка длиннее семидесяти знаков
   читается тяжело, а документ именно читают. Ширина та же, что у базы
   знаний, — это один и тот же род чтения. */
.docv {
  max-width: var(--kb-line); margin: 0 auto;
  padding: var(--s-5) var(--s-4); font-size: var(--t-base); line-height: 1.6;
}
.docv h2 { font-size: var(--t-xl); margin: var(--s-5) 0 var(--s-2); }
.docv h3 { font-size: var(--t-lg); margin: var(--s-5) 0 var(--s-2); }
.docv h4, .docv h5 { font-size: var(--t-md); margin: var(--s-4) 0 var(--s-2); }
.docv p { margin: 0 0 var(--s-3); }
.docv ul { margin: 0 0 var(--s-3); padding-left: var(--s-5); }
.docv li { margin-bottom: var(--s-1); }
.docv li p { margin: 0; }
.docv__pic { display: block; max-width: 100%; height: auto; margin: var(--s-3) 0; }
.docv__table {
  border-collapse: collapse; width: 100%; margin: 0 0 var(--s-4);
  font-size: var(--t-sm);
}
.docv__table td {
  border: 1px solid var(--border); padding: var(--s-2); vertical-align: top;
}

/* ── Проект NOPS ─────────────────────────────────────────────────────────── */
.nopsv { padding: var(--s-4); text-align: center; }
.nopsv__pic {
  max-width: 100%; height: auto; background: #fff;
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
}
.nopsv .note { margin-top: var(--s-3); }

@media (max-width: 760px) {
  .docv { padding: var(--s-4) var(--s-3); }
  .xlsv { padding: var(--s-2); }
}

/* Портрет с меткой: человек смотрит глазами обычного сотрудника.
   Кнопка-глаз, которая раньше об этом говорила, убрана, а сказать надо:
   в этом режиме половина кнопок пропадает, и без знака это читается как
   поломка, а не как «вы сами так попросили». */
.profilebtn.is-asuser { position: relative; }
.profilebtn.is-asuser::after {
  content: ''; position: absolute; right: -1px; bottom: -1px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--bg);
}

/* ── Чертёж DXF ──────────────────────────────────────────────────────────────

   Холст во всё окно: чертёж смотрят целиком, а потом всматриваются в угол.
   Колесо приближает к курсору, перетаскивание двигает — как в любой
   программе, где есть чертёж. */
.dxfv { position: relative; width: 100%; height: 100%; }
.dxfv__canvas { display: block; width: 100%; height: 100%; cursor: grab; touch-action: none; }
.dxfv__canvas:active { cursor: grabbing; }
.dxfv__tools {
  position: absolute; left: var(--s-3); bottom: var(--s-3);
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  background: var(--raised); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
}

/* Поиск по файлам — в колонке диска, над списком папок.
   Отдельной строкой, а не внутри списка: он не пункт списка, а вопрос
   к нему, и уезжать вместе с прокруткой ему нельзя. */
.side__search { padding: 0 var(--s-2) var(--s-2); }
.side__search .input { width: 100%; }
/* Путь под именем: «Визуализации» есть в каждом проекте, и без пути
   и закреп, и находка отвечают не на тот вопрос. */
.siderow__note {
  display: block; font-size: var(--t-2xs); color: var(--text-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Закреп отличается булавкой слева: черта у края колонки читалась плохо —
   её принимали за подсветку выбранного пункта. */
.siderow--zakrep .siderow__pin {
  flex: none; display: inline-flex; margin-right: var(--s-1);
  color: var(--text-faint);
}
.siderow--zakrep.is-active .siderow__pin { color: inherit; }
.siderow--nahodka { align-items: flex-start; }

/* ── Диск колонками, как в Finder ────────────────────────────────────────────

   Столбец на каждый шаг пути. Прокрутка вбок, а не перенос: дорога — это
   ряд, и перенос её на вторую строку разрушил бы сам смысл вида. */
.kolonki {
  display: flex; gap: 0; overflow-x: auto; overflow-y: hidden;
  /* Сплошная карточка без рамки, как плитки и таблица диска (сверка
     28 сентября 2026); столбцы делит волосяная черта, шапку — воздух. */
  border-radius: var(--radius-lg); box-shadow: var(--sh-1);
  background: var(--solid); height: 60vh; min-height: 320px;
}
.kolonka {
  flex: none; width: 260px; min-width: 200px;
  display: flex; flex-direction: column; min-height: 0;
  border-right: 1px solid var(--hair);
}
/* Последний столбец — открытая папка — забирает остаток полосы: при одном-
   двух столбцах полоса шириной ~800, а имя файла резалось на 230 точках
   (аудит 30.09.2026). Столбцов много — он по-прежнему 260 и листается. */
.kolonka:last-child { border-right: none; flex: 1 0 260px; }
/* Имя столбца — над ним, а не строкой внутри: строка внутри читалась бы
   как ещё один пункт, по которому можно щёлкнуть. */
.kolonka__head {
  flex: none; padding: var(--s-2) var(--s-3);
  font-size: var(--t-2xs); text-transform: uppercase; font-family: var(--mono); font-weight: 500; letter-spacing: .08em;
  color: var(--text-faint); padding-top: var(--s-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kolonka__body { flex: 1; min-height: 0; overflow-y: auto; padding: var(--s-1); }
.kolrow {
  display: flex; align-items: center; gap: var(--s-2); width: 100%;
  padding: var(--s-1) var(--s-2); border: none; background: none; cursor: pointer;
  border-radius: var(--radius-sm); color: var(--text); font: inherit;
  font-size: var(--t-sm); text-align: left;
}
.kolrow:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.kolrow.is-active { background: var(--accent-soft); color: var(--accent-fg); }
/* Отмеченный рамкой файл — тем же цветом, что и в списке: отметка одна
   на все виды, и выглядеть она должна одинаково. */
.kolrow.is-picked { background: var(--accent-soft); box-shadow: inset 2px 0 0 var(--accent); }
/* Значок строки: у папки рисунок, у файла ярлычок формата словом («ФАЙЛ»,
   «CAD»). Ширина под слово, а не под рисунок: в 18 точек «ФАЙЛ» не влезал
   и наезжал на имя. */
.kolrow__ic {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px;
  font-size: var(--t-2xs); font-weight: 700; letter-spacing: .04em;
  color: var(--text-faint);
}
.kolrow__ic .diskico { width: 18px; height: 18px; }
.kolrow__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kolrow__more { flex: none; display: inline-flex; color: var(--text-faint); }
/* Колонка просмотра выбранного файла — как в Finder (Д11, 1.10.2026):
   та же плитка, что в виде «Плитка», крупно, и под ней действия */
.kolonka--prosmotr { flex: 1 0 300px; }
.kolprosmotr { display: flex; flex-direction: column; gap: var(--s-3); padding: var(--s-3); }
.kolprosmotr .dfile { width: min(100%, 420px); cursor: default; box-shadow: none; background: none; padding: 0; }
.kolprosmotr .dfile:hover:where([data-hover="mouse"] *) { box-shadow: none; }
.kolprosmotr .dfile__nm { -webkit-line-clamp: 3; font-size: var(--t-base); }
.kolprosmotr__act { display: flex; flex-wrap: wrap; gap: var(--s-2); }

@media (max-width: 760px) {
  /* На телефоне столбец один в экран: два по 260 точек не помещаются,
     а половина столбца хуже, чем его отсутствие. */
  .kolonki { height: 70vh; }
  .kolonka { width: 82vw; }
}

/* ── Презентация колодой ─────────────────────────────────────────────────────

   Карточка на слайд, сверху вниз. Не «как в PowerPoint»: раскладку слайда
   мы не повторяем, а показываем то, ради чего презентацию открывают
   с диска, — что на слайде и в каком он порядке. */
.pptv {
  max-width: 900px; margin: 0 auto; padding: var(--s-4);
  display: flex; flex-direction: column; gap: var(--s-4);
}
.pptv__slide {
  position: relative; display: flex; gap: var(--s-4); align-items: flex-start;
  background: var(--raised); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: var(--s-4) var(--s-4) var(--s-4) var(--s-6);
}
/* Номер слайда — на поле слева, а не в тексте: он служебный, но без него
   не сказать «посмотри на третьем». */
.pptv__n { position: absolute; left: var(--s-3); top: var(--s-4); }
.pptv__text { flex: 1; min-width: 0; }
.pptv__text h3 { margin: 0 0 var(--s-2); font-size: var(--t-md); }
.pptv__text p { margin: 0 0 var(--s-1); font-size: var(--t-sm); color: var(--text-dim); }
.pptv__pics { flex: none; width: 40%; display: flex; flex-direction: column; gap: var(--s-2); }
.pptv__pics img {
  width: 100%; height: auto; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: #fff;
}

@media (max-width: 760px) {
  .pptv__slide { flex-direction: column; padding-left: var(--s-4); }
  .pptv__n { position: static; }
  .pptv__pics { width: 100%; }
}

/* Подзаголовок внутри колонки: «Ближайшие сроки», «Дни рождения».
   Тише имени раздела наверху и с воздухом сверху — иначе два списка подряд
   читаются как один длинный. */
.side__group {
  padding: var(--s-3) var(--s-3) var(--s-1);
  font-size: var(--t-2xs); font-weight: 500; letter-spacing: .08em;
  text-transform: uppercase; font-family: var(--mono); color: var(--text-faint);
}
.side__list > .side__group:first-child { padding-top: var(--s-1); }
/* Строка, по которой не нажимают: она сообщает, а не ведёт. */
.siderow--tih { cursor: default; }
.siderow--tih:hover:where([data-hover="mouse"] *) { background: none; }

/* Свой набор тем для телефона — с отбивкой слева, чтобы было видно, что он
   подчинён галочке над ним, а не третий сам по себе. */
.tema-tel {
  margin-top: var(--s-2); padding-left: var(--s-4);
  border-left: 2px solid var(--border);
}
/* Кнопка «свернуть закреплённое» — сразу за названием проекта, через
   небольшой промежуток. Не в правой группе: она про то, что видно прямо
   под ней, и рука идёт к ней от заголовка, а не через весь экран. */
.zakrepbtn { margin-left: var(--s-2); flex: none; }

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

   Имя своё, а не `diskcard`: под тем именем уже живёт карточка объекта
   на диске, и приписанный к ней `display: flex` однажды разложил папку
   в один столбец — плитки схлопнулись, строки сжались по содержимому. */
.diskpole {
  min-height: 70vh;
  /* Текст на диске не выделяется вовсе — как в проводнике. Рамку тянут
     отовсюду, в том числе прямо с имени файла, и выделение текста тут
     не второй способ работы, а помеха: оно перехватывало протяжку. */
  user-select: none;
}
/* Пока тянут рамку, ничего не выделяется текстом: иначе протяжка попутно
   подсвечивает синим полоску отметок, крошки и заголовок — они лежат выше
   карточки, а рамку тянут как раз снизу вверх. */
body.tyanem-ramku, body.tyanem-ramku * { user-select: none; }

/* Отмеченная папка — тем же, чем отмеченный файл: одна отметка на всё,
   и выглядеть она должна одинаково, в какой бы строке ни стояла. */
.diskrow.is-picked, .diskfile.is-picked { background: var(--accent-soft); }
.diskrow.is-picked { box-shadow: inset 2px 0 0 var(--accent); }


/* Раздел в шапке гостевой страницы (оболочкаГостя в app.js — график
   стройки по ссылке): стили самого графика — в modules/builds/styles.css. */
.navitem.is-static { cursor: default; background: none; }
.navitem.is-static:hover:where([data-hover="mouse"] *) { background: none; }

/* ── Доска в цвете портала ────────────────────────────────────────────────
   До 27 сентября 2026 доска и всё вокруг холста были всегда светлыми
   (владелец, 15 сентября: тёмная тема Excalidraw инвертировала фотографии).
   Ватман после редизайна берёт цвет у портала сам — атрибуты data-scheme,
   data-bg, data-acc на <html> — и картинок не трогает: на тёмной стороне
   темнеют только заливки фигур на экране, документ и экспорт прежние
   (docs/ВАТМАН-В-ПОРТАЛЕ.md). Поэтому своей светлой палитры у доски больше нет. */

/* «3D-модели» (.mdl*) с 24 сентября 2026 — в modules/models/styles.css,
   подключаются только у включённого модуля. */

/* Генерация (.page--aigen, .aigen__frame) с 24 сентября 2026 — в
   modules/aigen/styles.css, подключается только у включённого модуля. */

/* «Редактировать в NOPS» в панели галереи: у PhotoSwipe кнопки значками,
   а эта словами — значок тут не объяснит, куда уедет снимок. */
.pswp__button--текстом {
  width: auto !important; padding: 0 var(--s-3); font: inherit; font-size: var(--t-sm);
  color: #fff; white-space: nowrap;
}


/* ── Запертые настройки (админка) ────────────────────────────────────────────
   Подключение, ключи, адреса: задаются один раз, ошибка ломает всё разом.
   Блок свёрнут и стоит последним, поля заперты fieldset'ом, открывает их
   «Изменить…» с подтверждением (app.js, запертыеНастройки). */
.zamok { margin-top: var(--s-4); }
.zamok > summary { cursor: pointer; list-style: none; display: flex; align-items: center; gap: var(--s-2); }
.zamok > summary::-webkit-details-marker { display: none; }
.zamok > summary h2 { margin: 0; }
.zamok > summary > svg { color: var(--text-faint); flex: none; transition: color var(--fast); }
/* Свёрнутый замок отвечает на наведение: замок темнеет (сверка экранов,
   28 сентября 2026) */
.zamok > summary:hover:where([data-hover="mouse"] *) > svg { color: var(--ink); }
/* Выбор режима строкой («Всем сотрудникам», «Только выбранным») — строка
   целиком нажимается, и наведение это показывает подложкой */
.page--admin label.ckrow {
  margin: 0 calc(-1 * var(--s-2)); padding-left: var(--s-2); padding-right: var(--s-2);
  border-radius: var(--radius-sm); cursor: pointer; transition: background var(--fast);
}
.page--admin label.ckrow:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.zamok__svodka { margin-left: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.zamok__predupr { background: var(--warn-soft); border-radius: var(--radius); padding: var(--s-2) var(--s-3); margin-bottom: var(--s-3); font-size: var(--t-sm); }
.zamok__polya { border: 0; padding: 0; margin: 0; min-width: 0; }
.zamok__polya:disabled .input { opacity: .7; cursor: not-allowed; }

/* Место в бакете и на сервере: строка, полоса доли, размер */
.mesto__h { font-size: var(--t-base); margin: 0 0 var(--s-2); }
.mesto td { vertical-align: middle; }
.mesto__polosa { width: 30%; }
.mesto__polosa span { display: block; height: var(--s-2); border-radius: var(--radius-full); background: var(--accent); }

/* Окно сотрудника: блокировка и выход — отдельной полосой под чертой,
   чтобы не стоять вплотную к полям, которые правят каждый раз */
.userdlg__dostup { margin-top: var(--s-5); padding-top: var(--s-3); border-top: 1px solid var(--border); }

/* «Права в проектах»: на широком — таблица (право × уровень), на телефоне
   четыре столбца не влезали — право строкой, уровни под ним строкой
   отметок-пилюль с подписью (владелец, 29 сентября 2026) */
.pravatab td.pravatab__lvl { text-align: center; }
.pravatab__lvl label { display: inline-flex; align-items: center; gap: var(--s-1); cursor: pointer; }
.pravatab__rol { display: none; }
@media (max-width: 760px) {
  .pravatab thead { display: none; }
  .pravatab, .pravatab tbody { display: block; }
  .pravatab tr {
    display: flex; flex-wrap: wrap; gap: var(--s-1) var(--s-2);
    padding: var(--s-3) 0; border-bottom: 1px solid var(--hair);
  }
  .pravatab tr:last-child { border-bottom: none; }
  .pravatab td { display: block; padding: 0; border: none; white-space: normal; }
  .pravatab td.pravatab__cap { flex: 1 0 100%; margin-bottom: var(--s-1); }
  .pravatab__rol { display: inline; }
  .pravatab__lvl label {
    min-height: 32px; padding: 0 var(--s-3) 0 var(--s-2); border-radius: var(--radius-full);
    background: var(--well); font-size: var(--t-sm);
  }
  .pravatab__lvl label:hover:where([data-hover="mouse"] *) { background: var(--hover); }
  .pravatab__lvl label:has(input:checked) { background: var(--accent-soft); color: var(--accent-fg); }
  fieldset:disabled .pravatab__lvl label { cursor: default; }
}

/* Распорка внутри карточки. Общего правила у `.spacer` нет — у каждой
   полосы своё, — и в карточках админки (шапка «Сотрудники», «Журнал»,
   карточки программ) она не раздвигала ничего: «+ Сотрудник» и
   «Сохранить» липли к соседям посреди строки вместо правого края. */
.card .spacer { flex: 1 1 auto; }

/* ── Главная: поле бюро и сводка «Сегодня» ───────────────────────────────────
   С редизайна (27 сентября 2026) главная — доска Ватмана во весь экран
   (каркас .page--wb) и сводка поверх неё. Сводка — интерфейс, а не часть
   поля: не масштабируется и не уезжает вместе с холстом. Плавает над полем,
   поэтому стеклянная (ТЗ, раздел 3); без стекла — сплошная. */
.page--pole { position: relative; }
.pole__pole { flex: 1; min-height: 0; display: flex; }

.svodka {
  position: absolute; z-index: 5; display: flex; flex-direction: column;
  background: var(--solid); color: var(--ink);
  border-radius: var(--radius-lg); box-shadow: var(--sh-2);
  font-size: var(--t-sm);
}
[data-glass='panels'] .svodka {
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  box-shadow: var(--in), var(--sh-2);
}
.svodka--left { top: var(--s-3); left: var(--s-3); bottom: var(--s-3); width: 320px; }
.svodka--top { top: var(--s-3); left: var(--s-3); right: var(--s-3); max-height: 46%; }
.svodka--folded { top: var(--s-3); left: var(--s-3); background: none; box-shadow: none; }
[data-glass='panels'] .svodka--folded { background: none; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }

.svodka__plashka {
  display: inline-flex; align-items: center; gap: var(--s-1);
  height: 40px; padding: 0 var(--s-4); border: none; cursor: pointer;
  border-radius: var(--radius-full); font: inherit; font-size: var(--t-sm); color: var(--ink);
  background: var(--solid); box-shadow: var(--sh-2);
}
[data-glass='panels'] .svodka__plashka {
  background: var(--glass-strong); -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  box-shadow: var(--in), var(--sh-2);
}

.svodka__head {
  display: flex; align-items: flex-start; gap: var(--s-2);
  padding: var(--s-4) var(--s-3) var(--s-2) var(--s-4); flex: none;
}
.svodka__title { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.svodka__head h2 { margin: 0; font-size: var(--t-xl); font-weight: 600; letter-spacing: -0.01em; line-height: 1.15; }
.svodka__head .svodka__date { font-size: var(--t-xs); color: var(--ink-3); }
.svodka__head .svodka__btn { align-self: flex-start; }
.svodka__date { color: var(--ink-3); }
.svodka__sp { flex: 1; }
.svodka__btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0; border: none; border-radius: var(--radius-full);
  background: transparent; color: var(--ink-2); cursor: pointer; align-self: center;
}
.svodka__btn:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--ink); }

.svodka__body {
  flex: 1; min-height: 0; overflow: auto; padding: 0 var(--s-2) var(--s-3);
}
.svodka--top .svodka__body {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(260px, 1fr); gap: var(--s-3);
  overflow-x: auto; overflow-y: auto;
}
.svodka__group { padding: var(--s-2) 0; }
.svodka__group + .svodka__group { border-top: 1px solid var(--hair); }
.svodka--top .svodka__group + .svodka__group { border-top: none; }
.svodka__label {
  padding: var(--s-1) var(--s-2); font-size: var(--t-xs); font-weight: 500;
  color: var(--ink-3); text-transform: uppercase; font-family: var(--mono); letter-spacing: .08em;
}
.svodka__row, .svodka__proj, .svodka__trow {
  display: flex; align-items: center; gap: var(--s-3); width: 100%;
  padding: var(--s-2); border: none; border-radius: var(--radius);
  background: none; color: inherit; font: inherit; text-align: left; text-decoration: none;
}
.svodka__row.is-link, .svodka__proj { cursor: pointer; }
.svodka__row.is-link:hover:where([data-hover="mouse"] *), .svodka__proj:hover:where([data-hover="mouse"] *) { background: var(--hover); }
/* Круглые значки — одинаковые у всех рядов (ТЗ) */
.svodka__ic {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: var(--radius-full);
  background: var(--accent-soft); color: var(--accent-fg);
}
.svodka__ic.is-late { background: var(--late-soft); color: var(--late-fg); }
.svodka__txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.svodka__main { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svodka__main .code { font-variant-numeric: tabular-nums; color: var(--ink-3); font-weight: 400; }
.svodka__note { font-size: var(--t-xs); color: var(--ink-3); }
.is-late { color: var(--late-fg); }
.svodka__note.is-late { color: var(--late-fg); }
.svodka__count {
  flex: none; min-width: 24px; padding: 0 var(--s-2); height: 22px; line-height: 22px;
  border-radius: var(--radius-full); background: var(--well); text-align: center;
  font-family: var(--mono); font-size: var(--t-xs); font-variant-numeric: tabular-nums;
}
.svodka__faces { display: inline-flex; flex: none; }
.svodka__face {
  width: 24px; height: 24px; border-radius: var(--radius-full); overflow: hidden; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--well); color: var(--ink-2); font-size: var(--t-xs); font-weight: 600;
  box-shadow: 0 0 0 2px var(--solid);
}
.svodka__faces .svodka__face + .svodka__face { margin-left: -6px; }
.svodka__face img { width: 100%; height: 100%; object-fit: cover; object-position: center center; display: block; }
.svodka__trow .svodka__face { width: 30px; height: 30px; box-shadow: none; }

.svodka__empty { padding: var(--s-2); color: var(--ink-3); }

.svodka__thumb {
  flex: none; width: 36px; height: 36px; border-radius: var(--radius-sm); overflow: hidden;
  object-fit: cover; background: var(--well); display: block;
}
.svodka__thumb svg { width: 100%; height: 100%; display: block; }
/* Дорожка стадий — готовность проекта полосой */
.svodka__track { display: block; height: 4px; margin-top: var(--s-1); border-radius: var(--radius-full); background: var(--well); overflow: hidden; }
.svodka__track i { display: block; height: 100%; background: var(--accent); }
.svodka__due { flex: none; font-size: var(--t-xs); color: var(--ink-2); font-family: var(--mono); }
.svodka__due.is-late { color: var(--late-fg); }

/* Боковой лист пошире — для задачи */
.sheet--wide { width: min(640px, calc(100% - var(--s-5))); }
/* Лист задачи: экран задачи внутри, своя строка с путём и шагами — шапка
   листа ему не нужна, кроме крестика */
.sheet--task { width: min(760px, calc(100% - var(--s-5))); }
@media (max-width: 760px) {
  .sheet--wide, .sheet--task { width: 100%; }
}
.sheet--task .sheet__head { position: absolute; top: var(--s-2); right: var(--s-2); padding: 0; border: none; z-index: 2; }
.sheet--task .sheet__ident { display: none; }
.sheet--task .sheet__body { padding: var(--s-4) var(--s-5); }
.page--sheet { padding: 0; max-width: none; }
.page--sheet .tview__bar { padding-right: var(--s-7); }

/* Заголовок яруса в меню «Ещё»: «Управление» с замком (ТЗ, раздел 4) */
.menupop__group {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-1) var(--s-3) 0; font-size: var(--t-xs); font-weight: 600;
  color: var(--ink-3);
}
.menupop__group .note { font-weight: 400; }


/* Телефон: сводка — лентой сверху, поле под ней. Колонкой слева на узком
   экране она закрыла бы всё поле */
@media (max-width: 760px) {
  .svodka--left, .svodka--top { left: var(--s-2); right: var(--s-2); top: var(--s-2); bottom: auto; width: auto; max-height: 55%; }
  .svodka--top .svodka__body { display: block; }
}


/* ── Каркас по макету редизайна (27 сентября 2026) ───────────────────────────
   Общей колонки проектов нет; у раздела, которому колонка нужна (диск, доски,
   админка, команда, настройки, календарь, проект), она — карточкой на фоне
   рядом с содержимым. «Острова» у содержимого тоже нет: страница лежит прямо
   на фоне, а карточки на ней — сплошные (--solid). Логотип больше не держит
   ширину колонки — её нет. */
.shell { padding: 0 var(--s-5) var(--s-5); gap: var(--s-4); }
.side--bare { display: none; }
.main { background: transparent; border: none; border-radius: 0; margin: 0; }
.side:not(.side--bare) {
  align-self: flex-start; max-height: 100%;
  background: var(--solid); border-radius: var(--radius-lg); box-shadow: var(--sh-1);
  padding: var(--s-3) var(--s-2) var(--s-3);
  margin-top: var(--s-5);
}
.topbar__brand { flex: 0 0 auto; margin-right: var(--s-4); }
/* Доска и главная — во весь экран, без полей каркаса */
.shell:has(.page--wb) { padding: 0; gap: 0; }

.topsearch {
  display: inline-flex; align-items: center; gap: var(--s-2);
  height: 36px; min-width: 240px; padding: 0 var(--s-2) 0 var(--s-3);
  border: 1px solid var(--line); border-radius: var(--radius-full);
  background: var(--solid); color: var(--ink-3); font: inherit; font-size: var(--t-sm);
  cursor: pointer; transition: border-color var(--fast);
}
.topsearch:hover:where([data-hover="mouse"] *) { border-color: var(--line-2); color: var(--ink-2); }
.topsearch__t { flex: 1; text-align: left; }
.topsearch__k {
  font-family: var(--mono); font-size: var(--t-xs); color: var(--ink-3);
  padding: 1px var(--s-2); border-radius: var(--radius-sm); background: var(--well);
}
@media (max-width: 1100px) {
  .topsearch { min-width: 0; width: 36px; padding: 0; justify-content: center; }
  .topsearch__t, .topsearch__k { display: none; }
}
/* Разделам не хватает места — поиск лупой, прежде чем прятать полосу
   (`подогнатьПолосуРазделов`) */
.topbar.is-snug .topsearch { min-width: 0; width: 36px; padding: 0; justify-content: center; }
.topbar.is-snug .topsearch__t, .topbar.is-snug .topsearch__k { display: none; }
@media (max-width: 760px) {
  .shell { padding: 0; gap: 0; }
}

/* ── Шапка плашкой (владелец, 27 сентября 2026) ──────────────────────────────
   Отдельная плавающая плашка со скруглением, как в макете: страница
   прокручивается под ней, поэтому у шапки — стекло (на панелях). Место под
   ней держит поле сверху у содержимого и у колонки раздела. Доска и главная
   начинаются под плашкой, чтобы та не закрывала верх холста. На телефоне
   шапка прежняя — строкой. */
@media (min-width: 761px) {
  .app { position: relative; }
  .topbar {
    position: absolute; z-index: 30;
    top: calc(env(safe-area-inset-top) + var(--s-3));
    left: var(--s-5); right: var(--s-5);
    height: 56px;
    /* Поле по макету: справа портрет 36 стоит на (56 − 36) / 2 от края — столько
       же, сколько сверху и снизу, и скругление обходит его ровно; слева то же
       поле плюс свой отступ логотипа (владелец, 28 сентября 2026) */
    padding: 0 calc((56px - 36px) / 2);
    /* Справа — портрет 32: поле до края то же, что над ним и под ним */
    padding-right: calc((56px - 32px) / 2);
    background: var(--solid); border-radius: var(--radius-xl); box-shadow: var(--sh-2);
  }
  [data-glass='panels'] .topbar {
    background: var(--glass-strong);
    -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
    box-shadow: var(--in), var(--sh-2);
  }
  /* Прокрутка — у края окна, а не в поле каркаса: иначе полоса стояла
     серой чертой в 24 точках от края, под концом плашки, и низ страницы
     обрезался тем же полем (владелец, 27 сентября 2026, скриншот диска).
     Поле каркаса справа и снизу теперь внутри прокрутки. */
  .shell { padding-top: 0; padding-right: 0; padding-bottom: 0; }
  .main { padding-top: calc(56px + var(--s-3) * 2); padding-right: var(--s-5); padding-bottom: var(--s-5); }
  .side:not(.side--bare) { margin-bottom: var(--s-5); }
  .side:not(.side--bare) {
    margin-top: calc(56px + var(--s-3) * 2 + var(--s-5)); max-height: calc(100% - 56px - var(--s-3) * 2 - var(--s-5) * 2); /* и снизу — тот же отступ, что сверху */
  }
  /* Доска и главная — под плашкой, во весь экран: холст уходит под стекло,
     а не начинается серой полосой под ним (владелец, 27 сентября 2026,
     скриншот главной). Ниже плашки встаёт только оснастка: островки доски,
     сводка и панели редактора (последним — через поля Ватмана, app.js). */
  .shell:has(.page--wb) .main { padding: 0; border-top: none; }
  .page--wb { --plashka: calc(env(safe-area-inset-top) + 56px + var(--s-3)); }
  .page--wb .wb__over { top: calc(var(--plashka) + var(--s-3)); }
  /* До 900 островки — строкой сетки над холстом (position: static), и top
     на них не действует: строка вставала под шапку-плашку. Место под
     плашку держит сама сетка */
  @media (max-width: 900px) {
    .page--wb .wb__wrap { padding-top: calc(var(--plashka) + var(--s-3)); }
    .page--wb .ватман .в-панель.в-люди { top: var(--s-3); }
  }
  /* Края плашки доски — по краям шапки-плашки, а не в 12 точках от окна:
     две пилюли одна над другой с разным отступом читались съехавшими */
  /* По центру плашка простояла один день (4 октября 2026) — владелец
     вернул её налево, над боковой панелью доски */
  .page--wb .wb__over--left { left: var(--s-5); }
  .page--wb .wb__over--right { right: var(--s-5); }
  /* Кто на доске — та же правая линия, что у шапки-плашки над ней: в 12
     точках от окна она выступала за край шапки (владелец, 28.09.2026) */
  .page--wb .ватман .в-панель.в-люди { right: calc(var(--s-5) + var(--в-справа, 0px)); top: calc(var(--plashka) + var(--s-3)); }
  .page--pole .svodka--left, .page--pole .svodka--top, .page--pole .svodka--folded { top: calc(var(--plashka) + var(--s-3)); left: var(--s-5); }
  .page--pole .svodka--right, .page--pole .svodka--right-folded { top: calc(var(--plashka) + var(--s-3)); right: var(--s-5); }
  .page--pole .svodka--top { right: var(--s-5); }
}

/* ── Бюро: области ───────────────────────────────────────────────────────── */
.byuro { display: grid; gap: var(--s-4); grid-template-columns: repeat(auto-fill, minmax(min(340px, 100%), 1fr)); align-items: start; }
.byuro__area { background: var(--solid); border-radius: var(--radius-lg); box-shadow: var(--sh-1); padding: var(--s-3); display: flex; flex-direction: column; gap: var(--s-1); }
.byuro__head { display: flex; align-items: center; gap: var(--s-2); padding: 0 var(--s-1) var(--s-2); }
.byuro__head h2 { margin: 0; font-size: var(--t-md); font-weight: 600; }
.byuro__count { font-family: var(--mono); font-size: var(--t-xs); color: var(--ink-3); }
.byuro__list { display: flex; flex-direction: column; }
.byuro__task { display: flex; align-items: center; gap: var(--s-2); padding: var(--s-2); border-radius: var(--radius); color: inherit; text-decoration: none; }
.byuro__task:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.byuro__dot { flex: none; width: 10px; height: 10px; border-radius: var(--radius-full); }
.byuro__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.byuro__due { flex: none; font-family: var(--mono); font-size: var(--t-xs); color: var(--ink-3); }
.byuro__due.is-late { color: var(--late-fg); }
.byuro__who { display: inline-flex; flex: none; }
.byuro__who .svodka__face + .svodka__face { margin-left: -6px; }
.byuro__empty { padding: var(--s-2); color: var(--ink-3); font-size: var(--t-sm); }

/* ── Задачи (/tasks) по макету редизайна (27 сентября 2026) ─────────────────
   Один список на сплошной карточке, разбитый по сроку; вкладки «Мои ·
   Поручил · Наблюдаю» и «Список / Канбан» — пилюлями в строке над ним.
   Правой колонки нет: заметки — листом справа. Страница лежит на фоне,
   как весь каркас. */
/* На больших экранах — во всю доступную ширину: сетка карточек сама
   прибавляет столбцы, а справа не остаётся трети пустого экрана (владелец,
   29 сентября 2026). Не шире 1600: строка списка длиннее уже теряется глазом */
.page--tasks { max-width: min(1600px, 100%); display: flex; flex-direction: column; gap: var(--s-5); }
.tasks__head { display: flex; align-items: flex-end; gap: var(--s-3); flex-wrap: wrap; }
.tasks__head > .spacer, .tasks__bar > .spacer { flex: 1; }
.tasks__title h1 { font-size: var(--t-2xl); line-height: 1.05; letter-spacing: -.025em; }
.tasks__sub { margin-top: var(--s-2); color: var(--ink-3); font-size: var(--t-sm); }
.tasks__sub .is-late { color: var(--late-fg); }
.tasks__head .btn--primary { display: inline-flex; align-items: center; gap: var(--s-2); border-radius: var(--radius-full); }
.tasks__bar { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; margin-top: calc(-1 * var(--s-2)); }
.tasks__right { display: flex; align-items: center; gap: var(--s-2); margin-left: auto; }
.tasks__tools { display: flex; align-items: center; gap: var(--s-2); }
.tasks__tools .btn { border-radius: var(--radius-full); }

/* Сегмент-пилюля: подложка утоплена, выбранное — сплошной плашкой */
.seg--pill {
  padding: var(--s-05); gap: var(--s-05); border-radius: var(--radius-full);
  background: var(--sunken); box-shadow: inset 0 0 0 .5px var(--line);
}
.seg--pill button {
  height: 30px; padding: 0 var(--s-3); border-radius: var(--radius-full);
  display: inline-flex; align-items: center; gap: var(--s-2);
  color: var(--ink-2); font-weight: 500;
}
.seg--pill button.is-active { background: var(--solid); color: var(--ink); font-weight: 500; box-shadow: var(--sh-1); }
/* Счёт тише подписи только на сплошной плашке выбранного: на утопленной
   подложке --ink-3 даёт 4,4 (сверка с ТЗ, 28 сентября 2026) — там счёт
   цветом подписи, отличает его моноширинный шрифт */
.seg__n { font-family: var(--mono); font-size: var(--t-xs); color: inherit; }
.is-active > .seg__n, [aria-pressed="true"] > .seg__n { color: var(--ink-3); }

.tlist { background: var(--solid); border-radius: var(--radius-xl); box-shadow: var(--sh-1); overflow: hidden; }
.tlist--empty { padding: var(--s-6) var(--s-5); color: var(--ink-3); text-align: center; }
.tlist__grp {
  padding: var(--s-4) var(--s-4) var(--s-2);
  font: 500 var(--t-xs)/1 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
}
.tlist__grp.is-late { color: var(--late-fg); }
/* Столбцы строки ставятся по порядку, а спрятанные места не занимают:
   на телефоне из строки уходят статус и лица, и сетка сама сжимается */
.trow {
  display: grid; grid-template-columns: var(--step-size) minmax(0, 1fr);
  grid-auto-flow: column; grid-auto-columns: auto;
  gap: var(--s-3); align-items: center;
  padding: var(--s-3) var(--s-4); border-top: 1px solid var(--line);
  cursor: pointer; touch-action: pan-y; transition: background var(--fast), opacity .2s;
}
.tlist__grp + .trow, .tlist > .trow:first-child { border-top: 0; }
.trow:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.trow.is-done .trow__name { color: var(--ink-3); text-decoration: line-through; text-decoration-color: var(--line-2); }
.trow.is-leaving { opacity: 0; }
.trow.is-dragging { opacity: .4; }
.trow.is-insert-before { box-shadow: inset 0 2px 0 var(--accent); }
.trow.is-insert-after { box-shadow: inset 0 -2px 0 var(--accent); }
.trow__nostep { width: var(--step-size); }
.trow__main { min-width: 0; }
.trow__name {
  font-weight: 500; font-size: var(--t-base); color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.trow__meta {
  display: flex; align-items: center; gap: var(--s-2); margin-top: var(--s-05);
  font-size: var(--t-xs); color: var(--ink-3); min-width: 0; overflow: hidden; white-space: nowrap;
}
.trow__code {
  font: 500 var(--t-xs)/1.5 var(--font); font-variant-numeric: tabular-nums; color: var(--ink-2); white-space: nowrap;
  padding: 0 var(--s-2); border-radius: var(--radius-sm); background: var(--grey-soft);
  border: none; flex: none; max-width: 22ch; overflow: hidden; text-overflow: ellipsis;
}
button.trow__code { cursor: pointer; }
button.trow__code:hover:where([data-hover="mouse"] *) { color: var(--ink); background: var(--hover); }
/* Не --accent-text: у нас это подпись НА акценте (белая), а не акцент для текста */
.trow__code--bureau { font-family: var(--font); background: var(--accent-soft); color: var(--accent-hover); }
.trow__type { overflow: hidden; text-overflow: ellipsis; }
.trow__prio {
  font: 600 var(--t-xs)/1 var(--mono); letter-spacing: .06em; text-transform: uppercase;
  /* Цвет ступени задаёт человек (#e05555 и подобные) — для текста он
     подмешивается к --ink: оттенок тот же, 4,5 держится на любой стороне */
  color: color-mix(in oklab, var(--c, var(--late-fg)) 72%, var(--ink)); flex: none;
}
.trow__chk { font-family: var(--mono); flex: none; }
.trow__st .kcard__status {
  height: 22px; padding: 0 var(--s-2); gap: var(--s-1); border: none; font-weight: 500; font-size: var(--t-xs);
  background: color-mix(in srgb, var(--st-color, var(--ink-3)) 14%, transparent);
  color: color-mix(in srgb, var(--st-color, var(--ink-3)) 70%, var(--ink));
}
.trow__st .kcard__status::before { width: 6px; height: 6px; }
.trow__st .kcard__statusbtn { padding: 0; background: none; border: none; }
.trow__who .kcard__who { margin: 0; }
.trow__who .kcard__who .avatar { border-color: var(--solid); }
.trow__who .kcard__whobtn { padding: 0; background: none; border: none; }
.trow__due { min-width: 62px; display: flex; justify-content: flex-end; }
.trow__due .kcard__date { font-family: var(--mono); font-size: var(--t-sm); color: var(--ink-2); }
.trow__due .kcard__date-lead, .trow__due .kcard__date-long { display: none; }
.trow__due .kcard__date-brief { display: inline; }
.trow__due .kcard__date.is-late { color: var(--late-fg); }

.page--tasks .kanwrap { margin: 0; }
.page--tasks .kcol { background: var(--well); }
.tasks__extras { display: flex; flex-direction: column; gap: var(--s-5); }
.tasks__extras:empty { display: none; }
.tasks__extra .card { background: var(--solid); box-shadow: var(--sh-1); border-radius: var(--radius-xl); overflow: hidden; }

@media (max-width: 760px) {
  .page--tasks { gap: var(--s-4); }
  .tasks__title h1 { font-size: var(--t-xl); }
  .tasks__bar { margin-top: 0; }
  .tasks__right { margin-left: 0; width: 100%; }
  .tasks__right > .seg { margin-left: auto; }
  /* Листается пальцем, полосы не видно: под пилюлями она читалась
     лишней чертой (как у `.tabs`) */
  .tasks__tabs { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
  .tasks__tabs::-webkit-scrollbar { display: none; }
  .tasks__tools { order: 3; }
  .tasks__order .menulabel__text { max-width: 12ch; overflow: hidden; text-overflow: ellipsis; }
  .tlist { border-radius: var(--radius-lg); }
  .trow { padding: var(--s-3); gap: var(--s-2); }
  .trow__who, .trow__nostep { display: none; }
  /* На узком экране название — в две строки: одной оставалось восемь букв */
  .trow__name {
    white-space: normal; display: -webkit-box; -webkit-box-orient: vertical;
    -webkit-line-clamp: 2; line-clamp: 2;
  }
  .trow__due { min-width: 0; }
}


/* ── «Задачи»: полоса, виды, карточка (редизайн 30 сентября 2026) ──────────
   По макету «Виды задач» с решениями владельца. Классы свои (zd*), а не
   .kcard/.trow: у тех за полгода набралось по файлу больше сотни правил
   (наведение с приглашениями, красная рамка просрочки, узкие варианты), и
   новая карточка унаследовала бы их вместе с прыжками на наведении.
   .trow остаётся колонке «Сегодня» на главной. */
.tasks__add { flex: none; }
/* Черта между своими вкладками и «Командой»: та — про чужие задачи */
.tasks__div { flex: none; align-self: center; width: 1px; height: 16px; margin: 0 var(--s-1); background: var(--line-2); }
.tasks__mface { width: 18px; height: 18px; flex: none; display: inline-grid; place-items: center; color: var(--ink-2); }
.tasks__mface svg { width: 18px; height: 18px; display: block; }
/* «По людям» там, где он ни к чему, — виден, но притушен; подсказка
   объясняет почему (нажатие — тоже) */
.viewseg button.is-off { opacity: .4; cursor: default; }
.viewseg button.is-off:hover:where([data-hover="mouse"] *) { background: none; }
/* Колонки — во всю ширину страницы, доска листается вбок */
.page--tasks.is-columns { max-width: none; }

.zdlst { display: flex; flex-direction: column; gap: var(--s-5); }
.zdisl { background: var(--solid); border-radius: var(--radius-xl); box-shadow: var(--sh-1); overflow: hidden; }
.zdgrp {
  display: flex; gap: var(--s-2); padding: var(--s-4) var(--s-4) var(--s-2);
  font: 500 var(--t-xs)/1 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
}
.zdgrp.is-late { color: var(--late-fg); }
.zdgrp--bare { padding: 0 var(--s-1); }
.zdsec { display: flex; flex-direction: column; gap: var(--s-3); min-width: 0; }
.zdsec__h { display: flex; align-items: center; gap: var(--s-2); margin: 0; font-size: var(--t-md); font-weight: 600; }
.zdsec__n { font: 400 var(--t-xs)/1 var(--mono); color: var(--ink-3); }
.zdsec__late { font-size: var(--t-xs); font-weight: 400; color: var(--late-fg); }

/* Подписи строки и карточки — без своего наведения: нажимается целое */
.zdpj {
  display: inline-flex; align-items: baseline; gap: var(--s-1); flex: none; max-width: 100%;
  padding: 0 var(--s-2); border-radius: var(--radius-sm); background: var(--grey-soft); color: var(--ink-2);
  font: 500 var(--t-xs)/1.6 var(--font); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.zdpj b { font: 500 var(--t-xs)/1.6 var(--mono); color: var(--ink); }
.zdpj--b { background: var(--accent-soft); color: var(--accent-hover); }
.zdtag { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.zdrole { flex: none; padding: 0 var(--s-2); border: 1px solid var(--line); border-radius: var(--radius-full); font-size: var(--t-xs); line-height: 1.5; color: var(--ink-3); }
.zdbolt { display: inline-flex; flex: none; color: color-mix(in oklab, var(--prio, var(--late-fg)) 72%, var(--ink)); }
.zdbolt svg { display: block; }
.zddue { font: 400 var(--t-sm)/1 var(--mono); white-space: nowrap; color: var(--ink-2); }
.zddue.is-late { color: var(--late-fg); }
.zddue.is-none { color: var(--ink-3); }
.zdchk { display: inline-flex; align-items: center; gap: var(--s-1); flex: none; font: 400 var(--t-xs)/1 var(--mono); color: var(--ink-3); }
.zdchk__ic, .zdchk__ic svg { display: block; }
.zdchk.is-full { color: var(--ok-fg); }
.zdbar { width: 36px; height: 4px; border-radius: var(--radius-full); background: var(--grey-soft); overflow: hidden; flex: none; }
.zdbar i { display: block; height: 100%; border-radius: var(--radius-full); background: var(--accent); }
.zdchk.is-full .zdbar i { background: var(--ok); }
.zdwho { display: inline-flex; align-items: center; flex: none; }
.zdwho .avatar { box-shadow: 0 0 0 2px var(--solid); }
.zdwho .avatar + .avatar { margin-left: calc(-1 * var(--s-1) - var(--s-05)); }
.zdwho__n { margin-left: var(--s-1); font-size: var(--t-xs); color: var(--ink-3); }
/* Срок, лица и молния меняются прямо со строки и карточки (владелец,
   30.09.2026). Кнопка занимает ровно место подписи: отступ под подложку
   возвращён отрицательным полем, рамки нет ни в покое, ни на наведении —
   меняется только фон, соседи не двигаются (замер: 0 px). */
.zdact {
  display: inline-flex; align-items: center; flex: none;
  padding: var(--s-05) var(--s-1); margin: calc(-1 * var(--s-05)) calc(-1 * var(--s-1));
  border: 0; border-radius: var(--radius-sm); background: none; color: inherit; font: inherit;
  cursor: pointer; transition: background var(--fast);
}
.zdact:hover:where([data-hover="mouse"] *), .zdact.is-open { background: var(--hover); }
.zdact:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
.zddue.zdact.is-late:hover:where([data-hover="mouse"] *) { background: var(--late-soft); }
/* Добавить второго в колонке человека: пустое место под лицо — кружком того
   же размера, что портрет, чтобы подвал не менял высоту */
.zdwho__plus { width: 22px; height: 22px; flex: none; display: inline-grid; place-items: center; border-radius: var(--radius-full); border: 1px dashed var(--line-2); color: var(--ink-3); }
.zdwho__plus .ic, .zdwho__plus svg { display: block; }
.zdbolt.is-off { color: var(--ink-3); opacity: .45; }
.zdact:hover:where([data-hover="mouse"] *) .zdbolt.is-off { opacity: .8; }

/* ── Строка списка: столбцы справа выровнены по всему списку ── */
.zdrow {
  position: relative; display: grid; align-items: center; gap: var(--s-3);
  grid-template-columns: var(--step-size) minmax(0, 1fr) 52px 16px 72px 64px;
  padding: var(--s-2) var(--s-4); min-height: 56px; border-top: 1px solid var(--line);
  cursor: pointer; touch-action: pan-y; transition: background var(--fast), opacity .2s;
}
.zdisl > .zdrow:first-child, .zdgrp + .zdrow { border-top: 0; }
.zdrow:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.zdrow:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.zdrow.is-done .zdrow__name { color: var(--ink-3); text-decoration: line-through; text-decoration-color: var(--line-2); }
.zdrow.is-leaving, .zdcard.is-leaving { opacity: 0; }
.zdrow.is-dragging { opacity: .4; }
.zdrow.is-insert-before { box-shadow: inset 0 2px 0 var(--accent); }
.zdrow.is-insert-after { box-shadow: inset 0 -2px 0 var(--accent); }
.zdrow__nostep { width: var(--step-size); }
.zdrow__main { min-width: 0; }
.zdrow__name { font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.zdrow__meta {
  display: flex; align-items: center; gap: var(--s-2); margin-top: var(--s-05); min-width: 0;
  overflow: hidden; white-space: nowrap; font-size: var(--t-xs); color: var(--ink-3);
}
.zdrow__ph { display: none; }
.zdrow__who, .zdrow__due { display: flex; justify-content: flex-end; }

/* ── Карточка: в ряду одной высоты, подвал прижат к низу ── */
.zdgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--s-3); align-items: stretch; }
.zdcard {
  position: relative; display: flex; flex-direction: column; gap: var(--s-2); min-width: 0;
  padding: var(--s-3); background: var(--solid); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--sh-1); cursor: pointer; touch-action: pan-y;
  /* Наведение — только тень и рамка: ни размеров, ни отступов, ни новых меток */
  transition: box-shadow var(--fast), border-color var(--fast), opacity .2s;
}
.zdcard:hover:where([data-hover="mouse"] *) { border-color: var(--line-2); box-shadow: var(--sh-2); }
.zdcard:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.zdcard.is-dragging { opacity: .35; }
.zdcard.is-lifted { box-shadow: var(--sh-3); }
.zdcard.is-insert-before { box-shadow: -3px 0 0 var(--accent), var(--sh-1); }
.zdcard.is-insert-after { box-shadow: 3px 0 0 var(--accent), var(--sh-1); }
.zdcol .zdcard.is-insert-before { box-shadow: 0 -3px 0 var(--accent), var(--sh-1); }
.zdcol .zdcard.is-insert-after { box-shadow: 0 3px 0 var(--accent), var(--sh-1); }
.zdcard__top { display: flex; align-items: flex-start; gap: var(--s-2); }
.zdcard__name {
  flex: 1; min-width: 0; font-weight: 500; line-height: 1.35;
  margin-top: calc((var(--step-size) - var(--t-base) * 1.35) / 2);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden;
}
.zdcard.is-done .zdcard__name { color: var(--ink-3); text-decoration: line-through; text-decoration-color: var(--line-2); }
.zdcard__tags, .zdcard__foot { display: flex; align-items: center; gap: var(--s-1) var(--s-2); padding-left: calc(var(--step-size) + var(--s-2)); min-width: 0; }
.zdcard__tags { flex-wrap: wrap; font-size: var(--t-xs); color: var(--ink-3); }
.zdcard__foot { margin-top: auto; min-height: 24px; }
.zdcard__sp { flex: 1; }

/* ── Колонки: жёлоб без рамки, высота карточки — по содержимому ── */
.zdkb { display: flex; gap: var(--s-3); align-items: flex-start; overflow-x: auto; padding-bottom: var(--s-2); scroll-snap-type: x proximity; }
.zdcol {
  flex: 1 0 240px; min-width: 240px; max-width: 360px; display: flex; flex-direction: column; gap: var(--s-2);
  padding: var(--s-2); border-radius: var(--radius-lg); background: var(--sunken); scroll-snap-align: start;
  transition: background var(--fast), box-shadow var(--fast);
}
.zdcol.is-over { background: var(--accent-soft); box-shadow: inset 0 0 0 1.5px var(--accent); }
.zdcol__h { display: flex; align-items: center; gap: var(--s-2); min-height: 32px; padding: var(--s-1); }
.zdcol__h .krug { --step-size: 22px; }
.zdcol__name { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: var(--s-2); font-weight: 600; white-space: nowrap; overflow: hidden; }
.zdcol__name b { font: 500 var(--t-sm)/1 var(--mono); }
.zdcol__name span { overflow: hidden; text-overflow: ellipsis; }
.zdcol__n { font: 400 var(--t-xs)/1 var(--mono); color: var(--ink-3); }
.zdcol__late { font-size: var(--t-xs); color: var(--late-fg); white-space: nowrap; }
.zdcol__body { display: flex; flex-direction: column; gap: var(--s-2); min-height: 48px; }
/* «+ Поручить» внизу колонки человека — тихой строкой, как «+ Задача» у
   колонки канбана: видна всегда, под мышью только подложка */
.zdcol__add {
  display: flex; align-items: center; gap: var(--s-1); width: 100%; min-height: 32px;
  padding: 0 var(--s-2); border: 0; border-radius: var(--radius); background: none;
  color: var(--ink-3); font: 500 var(--t-sm)/1 var(--font); cursor: pointer; transition: background var(--fast), color var(--fast);
}
.zdcol__add:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--ink); }
.zdcol__empty { display: flex; flex-direction: column; align-items: center; gap: var(--s-2); padding: var(--s-4) var(--s-2); color: var(--ink-3); font-size: var(--t-sm); text-align: center; }
.zdcol .zdcard { padding: var(--s-2) var(--s-3) var(--s-3) var(--s-2); }
.zdcol .zdcard__tags, .zdcol .zdcard__foot { padding-left: 0; }

@media (max-width: 760px) {
  /* «+ Задача» — круглой кнопкой на том же месте */
  .tasks__add { width: 40px; height: 40px; padding: 0; justify-content: center; }
  /* Кнопка — в строке заголовка справа, а не под ним: шапка не переносится */
  .tasks__head { flex-wrap: nowrap; align-items: flex-start; }
  .tasks__title { min-width: 0; }
  /* Инструменты (кто делает, порядок, виды) — к правому краю, лишнее — на
     следующую строку, а не за край экрана */
  .tasks__right { flex-wrap: wrap; justify-content: flex-end; }
  .tasks__right .tasks__tools { order: 0; flex-wrap: wrap; justify-content: flex-end; }
  .tasks__right > .seg { margin-left: 0; }
  .tasks__add .tasks__addt { display: none; }
  .zdisl { border-radius: var(--radius-lg); }
  .zdrow { grid-template-columns: var(--step-size) minmax(0, 1fr) auto; gap: var(--s-2); padding: var(--s-3); }
  .zdrow__chk, .zdrow__prio, .zdrow__who { display: none; }
  .zdrow__ph { display: inline-flex; }
  .zdrow__name { white-space: normal; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; }
  .zdrow__meta { flex-wrap: wrap; row-gap: var(--s-1); }
  .zdrow__meta > * { flex: none; }
  /* Колонки листаются пальцем по одной */
  .zdkb { scroll-snap-type: x mandatory; }
  .zdcol { flex: 0 0 86%; min-width: 0; max-width: none; }
}


/* ── Профиль по макету редизайна (27 сентября 2026) ──────────────────────────
   Слева — карточка человека, прилипает при прокрутке; справа — карточки
   того, что правится редко. На узком экране — одной колонкой. */
.prof { display: grid; grid-template-columns: 320px minmax(0, 1fr); gap: var(--s-5); align-items: start; }
.prof__card {
  position: sticky; top: 0;
  display: flex; flex-direction: column; gap: var(--s-3);
  padding: var(--s-5); border-radius: var(--radius-xl);
  background: var(--solid); box-shadow: var(--sh-1);
}
.prof__secs { display: flex; flex-direction: column; gap: var(--s-4); min-width: 0; }
.prof__secs > * + * { margin-top: 0; }
.prof__secs .card, .prof__secs > div > .card { border-radius: var(--radius-xl); background: var(--solid); box-shadow: var(--sh-1); border-color: transparent; margin: 0; }
.prof__who { display: flex; align-items: center; gap: var(--s-4); }
.prof__name { font-size: var(--t-xl); font-weight: 600; line-height: 1.15; letter-spacing: -.015em; }
.prof__role { margin-top: var(--s-1); font-size: var(--t-sm); color: var(--ink-3); }
.prof__lab {
  margin-top: var(--s-1);
  font: 500 var(--t-xs)/1 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
}
.prof__hint { font-size: var(--t-xs); color: var(--ink-3); margin-top: calc(-1 * var(--s-1)); }
.prof__status { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.prof__chip {
  display: inline-flex; align-items: center; gap: var(--s-2);
  height: 30px; padding: 0 var(--s-3); border: none; border-radius: var(--radius-full);
  background: var(--well); color: var(--ink-2); font: inherit; font-size: var(--t-xs); font-weight: 500;
  cursor: pointer; transition: background var(--fast), color var(--fast);
}
.prof__chip::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--c); }
.prof__chip:hover:where([data-hover="mouse"] *) { color: var(--ink); }
.prof__chip[aria-pressed="true"] { background: var(--ink); color: var(--solid); }
.prof__ct { display: flex; flex-direction: column; gap: var(--s-2); font-size: var(--t-sm); }
.prof__ct a { display: flex; align-items: center; gap: var(--s-3); color: var(--ink-2); text-decoration: none; min-width: 0; overflow-wrap: anywhere; }
.prof__ct a:hover:where([data-hover="mouse"] *) { color: var(--accent-hover); }
.prof__ct .ic { color: var(--ink-3); flex: none; }
.prof__card > .btn { margin-top: var(--s-2); align-self: flex-start; border-radius: var(--radius-full); }

.prof__keys { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-2) var(--s-5); }
.prof__keys > div {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  padding: var(--s-2) 0; border-bottom: 1px solid var(--line); font-size: var(--t-sm);
}
.prof__keys kbd {
  font-family: var(--mono); font-size: var(--t-xs); color: var(--ink-2); white-space: nowrap;
  padding: var(--s-05) var(--s-2); border-radius: var(--radius-sm); background: var(--well);
  box-shadow: inset 0 -1px 0 var(--line-2);
}
.prof__dev { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-2) 0; }
.prof__dev + .prof__dev { border-top: 1px solid var(--line); }
.prof__devic {
  width: 36px; height: 36px; border-radius: var(--radius); flex: none;
  display: grid; place-items: center; background: var(--well); color: var(--ink-2);
}
.prof__devtx { flex: 1; min-width: 0; font-size: var(--t-sm); }

/* Статус дня плашкой: в профиле, в «Команде», у устройства «сейчас» */
.daystat {
  display: inline-flex; align-items: center; gap: var(--s-1); height: 22px; padding: 0 var(--s-2);
  border-radius: var(--radius-full); font-size: var(--t-xs); font-weight: 500; white-space: nowrap;
  background: color-mix(in srgb, var(--c) 14%, transparent);
  color: color-mix(in srgb, var(--c) 70%, var(--ink));
}
.daystat::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--c); }
.pcard__state { align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.pcard__doing { font-size: var(--t-sm); color: var(--ink-2); }

@media (max-width: 1100px) {
  .prof { grid-template-columns: 1fr; }
  .prof__card { position: static; }
}
@media (max-width: 760px) {
  .prof__card { padding: var(--s-4); border-radius: var(--radius-lg); }
  .prof__keys { grid-template-columns: 1fr; }
}

/* ── Плашка доски по редизайну (27 сентября 2026) ────────────────────────────
   Та же стеклянная пилюля, что панели Ватмана под ней: плавает над холстом,
   поэтому стекло (на панелях). Кнопки — круглые, как у редактора; проект и
   «Поделиться» — мягкими пилюлями, а не кнопками в рамке. Стоит в том же
   отступе от края, что и панели редактора. */
.wb__over {
  height: 44px; padding: 0 var(--s-1); gap: var(--s-1);
  background: var(--solid); border: none; border-radius: var(--radius-full); box-shadow: var(--sh-2);
}
[data-glass='panels'] .wb__over {
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  box-shadow: var(--in), var(--sh-2);
}
.wb__over--left { left: var(--s-3); }
.wb__back, .wb__menu, .wb__over .backbtn {
  width: 36px; height: 36px; border-radius: var(--radius-full); color: var(--ink-2);
}
.wb__back:hover:where([data-hover="mouse"] *), .wb__menu:hover:where([data-hover="mouse"] *), .wb__over .backbtn:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--ink); }
.wb__title { height: 32px; border-radius: var(--radius-full); padding: 0 var(--s-3); color: var(--ink); }
.wb__title:hover:where([data-hover="mouse"] *) { border-color: transparent; background: var(--hover); }
.wb__title:focus { background: var(--solid); border-color: var(--line-2); }
.wb__over .btn {
  height: 32px; border: none; border-radius: var(--radius-full);
  background: var(--sunken); color: var(--ink-2); box-shadow: none; font-weight: 500;
}
.wb__over .btn:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--ink); }
.wb__brand { border-right-color: var(--line); padding-left: var(--s-2); }

/* ── Карточки старого вида — сплошными, без рамки (сверка облика, 27 сентября
   2026). Карточка на фоне отделяется тоном --solid и тенью, как карточки
   «Проектов» и «Задач» редизайна; обводка у них осталась от «полотна-острова»,
   где карточка лежала на той же заливке. Рамка прозрачная, а не снятая —
   размеры карточек не меняются. Подсвеченные состояния (просрочка, выбор)
   задают цвет рамки своими правилами и по-прежнему видны. */
.bcard, .kcard, .planfc, .planpr__row, .tile, .projcard, .planchart, .pcard, .wbcard {
  border-color: transparent; background: var(--solid); box-shadow: var(--sh-1);
}
.bcard:hover:where([data-hover="mouse"] *), .kcard:hover:where([data-hover="mouse"] *), .projcard:hover:where([data-hover="mouse"] *), .wbcard:hover:where([data-hover="mouse"] *) {
  border-color: transparent; box-shadow: var(--sh-2);
}
.teamchip { border-color: transparent; background: var(--grey-soft); }

/* Поля поиска — пилюлей, как поиск в шапке: так в макете сделаны только
   поиск и отборы, остальные поля ввода — со скруглением карточки
   (27 сентября 2026, решение по сверке облика) */
input[type='search'].input, input[type='search'].kbside__search { border-radius: var(--radius-full); padding-left: var(--s-3); }

/* ── Лист задачи по макету (владелец, 28 сентября 2026: «страница задачи
   отвратительно выглядит») ─────────────────────────────────────────────────
   Сплошной, а не стеклом: сквозь большой лист с текстом стекло показывало
   строки списка под ним, и всё читалось кашей. Под плашкой шапки, а не
   поверх неё. Внутри — как в макете: название во всю ширину, слева то,
   что читают и пишут, справа узкая колонка свойств подписями над
   значениями; серого блока свойств сверху больше нет. */
.sheet--task, [data-glass='panels'] .sheet--task {
  background: var(--solid); -webkit-backdrop-filter: none; backdrop-filter: none;
  box-shadow: var(--sh-3);
}
.sheet-backdrop { background: color-mix(in oklab, black 18%, transparent); }
@media (min-width: 761px) {
  .sheet--task { top: calc(env(safe-area-inset-top) + 56px + var(--s-3) * 2); }
}
.sheet--task .sheet__body { padding: var(--s-4) var(--s-5) var(--s-6); }
.sheet--task .tview__bar { margin-bottom: var(--s-3); }
/* Строка пути со стрелками «пред./след.» и «…» прилипает к верху листа:
   прокрутил к обсуждению — и остался один крестик, к соседней задаче не
   перейти (обход 28 сентября 2026). Подложка — цветом листа, крестик
   (`.sheet__head`, z-index 2) остаётся поверх */
.sheet--task .tview__bar {
  position: sticky; top: calc(-1 * var(--s-4)); z-index: 1;
  margin-top: calc(-1 * var(--s-4)); padding-top: var(--s-4); padding-bottom: var(--s-2);
  background: var(--solid);
}
@container (min-width: 520px) {
  .sheet--task .tview {
    grid-template-columns: minmax(0, 1fr) 216px;
    grid-template-areas: 'title title' 'main side';
    grid-template-rows: auto 1fr;
    column-gap: var(--s-6); row-gap: var(--s-3);
  }
  .sheet--task .tview__side {
    position: sticky; top: 0; padding: 0; border: 0; border-radius: 0; background: none;
  }
  .sheet--task .tprop { grid-template-columns: minmax(0, 1fr); }
  .sheet--task .tprop__label { min-height: 0; margin-top: var(--s-2); font-size: var(--t-xs); color: var(--ink-3); }
  .sheet--task .tprops__gap { margin: var(--s-2) 0 0; border-color: var(--hair); }
  .sheet--task .tview__title .input { font-size: var(--t-xl); }
}
/* Описание — на утопленной подложке, без рамки: поле видно, а лист не
   расчерчен коробками */
.sheet--task .tbody__main .textarea.tnotes { border-color: transparent; background: var(--well); border-radius: var(--radius-lg); }
.sheet--task .tbody__main .textarea.tnotes:hover:where([data-hover="mouse"] *):not(:disabled) { border-color: transparent; background: var(--hover); }
.sheet--task .tbody__main .textarea.tnotes:focus { border-color: var(--accent); background: var(--solid); }
.sheet--task .tbody__main .textarea.tnotes:disabled { background: transparent; }
/* ── Карточки задач — один свежий вид (сверка экранов, 28 сентября 2026) ────
   По логике макета редизайна: колонка — утопленный жёлоб без рамки и без
   черты под шапкой, счёт — тихой моноширинной цифрой; карточка — сплошная,
   тень вместо рамки, под мышью приподнимается; снизу срок, приоритет и лица
   внахлёст. Просрочка по-прежнему рамкой (решение 3 сентября 2026), только
   мягче: полная красная обводка на каждой второй карточке кричала громче
   названий. Правила стоят в конце файла и перебивают прежние слои. */
.kcol { border: none; border-radius: var(--radius-lg); background: var(--well); }
.kcol.is-over { box-shadow: inset 0 0 0 2px var(--accent); }
.kcol__head { border-bottom: none; padding: var(--s-3) var(--s-3) var(--s-1) var(--s-4); }
.kcol__count {
  border: none; background: none; padding: 0;
  font-family: var(--mono); font-size: var(--t-xs); color: var(--ink-3);
}
.kcol__body { padding: var(--s-2); }
.kcol__empty { color: var(--ink-3); }
/* «+ Задача» в колонке — тихой строкой, а не пунктирной коробкой */
.kcol__add, .kcol .kcol__add {
  border: none; border-radius: var(--radius); background: none; opacity: 1;
  padding: var(--s-2) var(--s-3); text-align: left; font-weight: 500; color: var(--ink-3);
  transition: background var(--fast), color var(--fast);
}
.kcol .kcol__add:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--ink); }

.kcard {
  border-color: transparent; background: var(--solid); box-shadow: var(--sh-1);
  transition: transform var(--fast), box-shadow var(--fast), border-color var(--fast);
}
.kcard:hover:where([data-hover="mouse"] *), .kcard--free:hover:where([data-hover="mouse"] *) { border-color: transparent; box-shadow: var(--sh-2); transform: translateY(-1px); }
.kcard.is-dragging, .kcard--ghost { transform: none; }
.kcard.is-hot, .kcard.is-hot:hover:where([data-hover="mouse"] *) { border-color: color-mix(in srgb, var(--late) 55%, transparent); }
.kcard__stage { font-size: var(--t-xs); color: var(--ink-3); }
.kcard__meta { gap: var(--s-2); }
/* Срок словами — пропорциональным шрифтом: моноширинный нужен столбцу цифр,
   а «до 29 сентября» в нём расползалось по буквам. Цифры табличные. */
.kcard .kcard__date { font-family: var(--font); font-size: var(--t-xs); color: var(--ink-3); letter-spacing: 0; }
.kcard .kcard__date-lead { color: var(--ink-3); margin-right: var(--s-1); }
.kcard .kcard__date.is-late, .kcard .kcard__date.is-late .kcard__date-lead { color: var(--late-fg); }
.kcard__date-btn:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--ink); }
.kcard__pct { font-family: var(--mono); font-size: var(--t-xs); font-weight: 500; color: var(--ink-3); }
.kcard__flag {
  border: none; background: var(--warn-soft); color: var(--warn-fg);
  font-size: var(--t-xs); font-weight: 500; line-height: 20px; padding: 0 var(--s-2);
}
/* Приоритет — молнией из общего набора цвета ступени шкалы */
.kcard__hot {
  color: var(--prio-color, var(--late));
  background: color-mix(in srgb, var(--prio-color, var(--late)) 14%, transparent);
}
.kcard__hot > svg, .kcard__hot .ic, .kcard__hot .ic > svg { display: block; }
.kcard__hot--off { color: var(--ink-3); background: none; filter: none; }
/* Лица — внахлёст с кольцом цвета карточки; ничья задача — пунктирный кружок */
.kcard__who .avatar, .kcard__who .kcard__dot { border: 2px solid var(--solid); }
.kcard__dot--rest {
  background: var(--grey-soft); color: var(--ink-3);
  font-family: var(--mono); font-size: var(--t-xs); font-weight: 500;
}

/* Список задач проекта — тем же видом, что список на «Задачах» (.tlist):
   одна сплошная карточка, строки через волосяную черту, подсветка строки
   под мышью. До этого каждая строка была отдельной карточкой с тенью, и
   один и тот же список в проекте и в разделе читался двумя поколениями. */
.cardsgrid.is-rows {
  gap: 0; background: var(--solid); border-radius: var(--radius-xl);
  box-shadow: var(--sh-1); overflow: hidden;
}
.is-rows .kcard--free, .is-rows .kcard--free:hover:where([data-hover="mouse"] *) {
  border: none; border-radius: 0; box-shadow: none; transform: none;
}
.is-rows .kcard--free {
  background: none; border-top: 1px solid var(--line); min-height: 0;
  padding: var(--s-3) var(--s-4); transition: background var(--fast);
}
.is-rows .kcard--free:first-child { border-top: none; }
.is-rows .kcard--free:hover:where([data-hover="mouse"] *) { background: var(--hover); border-top: 1px solid var(--line); }
.is-rows .kcard--free:first-child:hover:where([data-hover="mouse"] *) { border-top: none; }
/* Просрочка в строке — чертой слева, а не рамкой вокруг: рамка вокруг
   строки внутри карточки читалась ещё одной карточкой */
.is-rows .kcard--free.is-hot, .is-rows .kcard--free.is-hot:hover:where([data-hover="mouse"] *) { box-shadow: inset 3px 0 0 var(--late); }
/* Срок в строке — коротко цифрами у правого края, как на «Задачах» */
.is-rows .kcard__date { font-family: var(--mono); font-size: var(--t-sm); color: var(--ink-2); }
.is-rows .kcard__date.is-late { color: var(--late-fg); }
.is-rows .kcard__date-lead, .is-rows .kcard__date-long { display: none; }
.is-rows .kcard__date-brief { display: inline; }
.is-rows .kcard__date.is-none .kcard__date-brief { font-family: var(--font); color: var(--ink-3); }
/* Этаж и помещение — прозрачной подложкой от текста (--grey-soft), как код
   проекта в строке: заливка --well на тёмной стороне темнее карточки, и
   метки читались дырами в ней */
.ktag--floor, .ktag--room { background: var(--grey-soft); color: var(--ink-2); }

/* ── Диаграмма (сверка экранов, 28 сентября 2026) ──────────────────────────
   Выходные — лёгкой вуалью от цвета текста, а не заливкой жёлоба: на шкале
   «месяц» они стояли штрихкодом серых столбов через весь график, а на тёмной
   стороне ещё и темнее фона. Вуаль от --ink одинаково тиха на обеих сторонах.
   Сегодняшняя клетка шапки — мягким акцентом, а не сплошной плашкой: в виде
   «месяц» она красила целый месяц синим блоком. Строка под мышью — --hover,
   как строки списков. */
.gchart .off { fill: var(--ink); fill-opacity: .04; }
.gchart .off--holiday { fill: var(--late); fill-opacity: .08; }
.ghead__day.is-off { background: color-mix(in srgb, var(--ink) 4%, transparent); }
.ghead__day.is-today { background: var(--accent-soft); color: var(--accent-fg); }
.ghead__day.is-today .ghead__dwd { color: var(--accent-fg); }
.grow:hover:where([data-hover="mouse"] *) { background: var(--hover); }

/* ── Бюро (сверка экранов, 28 сентября 2026) ─────────────────────────────── */
.byuro__top { margin-bottom: var(--s-5); }
.byuro__top .btn { border-radius: var(--radius-full); display: inline-flex; align-items: center; gap: var(--s-2); }
.byuro__head .spacer { flex: 1; }
.byuro__head h2 { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.byuro__task { transition: background var(--fast); }

/* ── Наведение — одной подложкой (сверка экранов, 28 сентября 2026) ─────────
   Строки, пункты меню и кнопки подсвечивались --surface-2, а это --well —
   ступень ВНИЗ от карточки. На светлой стороне разница не видна, а на тёмной
   строка под мышью темнела и проваливалась в дыру. Подсветка — --hover
   (прозрачная подложка от цвета текста): светлее на тёмной, темнее на
   светлой, одинаково заметна на любом фоне. Кнопка — та же подложка поверх
   своей сплошной заливки — токеном --btn-hover-bg в правиле `.btn` выше:
   здесь стояло своё `.btn:hover` и перебивало главную и «опасную» кнопки
   (разбор 30 сентября 2026). */
.table tbody tr:hover:where([data-hover="mouse"] *) td, .tlist__row:hover:where([data-hover="mouse"] *) td { background: var(--hover); }
.menupop .menurow:hover:where([data-hover="mouse"] *):not(:disabled), .choicelist .menurow:hover:where([data-hover="mouse"] *),
.siderow:hover:where([data-hover="mouse"] *), .siderow--sub:hover:where([data-hover="mouse"] *), .sidetrail__row:hover:where([data-hover="mouse"] *), .teampop__row:hover:where([data-hover="mouse"] *),
.hrow:hover:where([data-hover="mouse"] *), .projrow:hover:where([data-hover="mouse"] *), .dateday:hover:where([data-hover="mouse"] *), .backbtn:hover:where([data-hover="mouse"] *), .typechip:hover:where([data-hover="mouse"] *),
.side__fold:hover:where([data-hover="mouse"] *), .palette__kind:hover:where([data-hover="mouse"] *), .datepop__nav:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.roundbtn:hover:where([data-hover="mouse"] *) { background: color-mix(in srgb, var(--ink) 8%, var(--solid)); }
/* Вкладки, сегменты и чипы отбора — «Мои · Поручил · Наблюдаю», полосы
   страниц разделов, переключатели вида (владелец, 30 сентября 2026: «при
   наведении меняется только цвет текста, нет интерактивности»). Невыбранный
   пункт под мышью получает ту же мягкую подложку, что строки и кнопки,
   с тем же переходом --fast (он объявлен у самих .seg button и .tab).
   Выбранный не трогаем — у него своя сплошная плашка. Меняется только
   фон: размеры и жирность остаются, соседи не сдвигаются. */
.seg button:not(.is-active):not([aria-pressed="true"]):not(:disabled):hover:where([data-hover="mouse"] *),
.tab:not(.is-active):hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }
/* Счёт на подложке темнеет вместе с ней: --text-faint на --hover поверх
   утопленной полосы давал 3,9 */
.tab:not(.is-active):hover:where([data-hover="mouse"] *) .tab__n, .typechip:hover:where([data-hover="mouse"] *) .typechip__n { color: var(--text-dim); }
.prj-chip:not([aria-pressed="true"]):hover:where([data-hover="mouse"] *) { background: var(--hover-solid); }
.prof__chip:not([aria-pressed="true"]):hover:where([data-hover="mouse"] *) { background: color-mix(in oklab, var(--well), var(--ink) 6%); }
/* Строка таблицы задач: подсвечивают её клетки (правило выше), а своя
   заливка строки --well под ними на тёмной стороне давала провал */
.htbl__row:hover:where([data-hover="mouse"] *) { background: none; }
/* Возврат из настроек проекта — той же ссылкой, что «← Проекты» на
   странице проекта */
.setback {
  display: inline-flex; align-items: center; gap: var(--s-1); margin-bottom: var(--s-2);
  padding: 0; border: none; background: none; cursor: pointer;
  font: inherit; font-size: var(--t-sm); font-weight: 500; color: var(--ink-3);
}
.setback:hover:where([data-hover="mouse"] *) { color: var(--ink); }

/* ── Главная и колонки, 28 сентября 2026 (замечания владельца) ─────────────── */

/* Сводка «Сегодня»: шире и со скруглением плашки шапки — прежнее было
   меньше соседних стеклянных панелей и читалось чужим */
.svodka { border-radius: var(--radius-xl); }
.svodka--left { width: 360px; }
/* Окно уже 1100 — «Сегодня» уже на 40 точек, поле шире (владелец,
   1.10.2026, по аудиту); уже 960 колонка сама становится плашкой (app.js) */
@media (max-width: 1099px) and (min-width: 761px) { .svodka--left { width: 320px; } }
/* Кружок свежего у проекта — как у проектов в колонке «Задач» */
.svodka__new {
  flex: none; min-width: 20px; height: 20px; padding: 0 var(--s-1);
  border-radius: var(--radius-full); background: var(--late); color: var(--solid);
  font-size: var(--t-xs); font-weight: 600; line-height: 20px; text-align: center;
  font-variant-numeric: tabular-nums;
  /* Цифра сидела выше середины кружка: строка шрифта несёт место под
     выносные элементы, а у цифр их нет. Центрируем по самим знакам —
     от линии прописных до базовой (владелец, 30.09.2026) */
  display: inline-flex; align-items: center; justify-content: center;
  text-box: trim-both cap alphabetic;
}

/* Поле даты нашим календарём (датыНашимКалендарём): плашка-кнопка и крестик */
.dateinput__wrap { display: inline-flex; align-items: center; gap: var(--s-1); }
.dateinput { height: 36px; padding: 0 var(--s-3); border-radius: var(--radius-full); background: var(--well); }
.dateinput.tpill--act:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.dateinput__clear {
  display: inline-grid; place-items: center; width: 28px; height: 28px; padding: 0;
  border: none; border-radius: var(--radius-full); background: none; color: var(--ink-3); cursor: pointer;
}
.dateinput__clear:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--ink); }

/* Портреты: тонкая окантовка, чтобы портрет цвета фона не сливался с ним
   ни на светлой, ни на тёмной стороне, и чуть крупнее */
/* Размеры портрета — четыре, как в макете (сверка с ТЗ, 28 сентября 2026):
   22 в строках и стопках, 28 обычный, 36 команда, 64 карточка профиля.
   Было восемь: 20, 22, 26, 30, 32, 34, 36 и 72. Строка и карточка задачи
   держат --step-size (решение владельца, ниже). */
.avatar { width: 28px; height: 28px; box-shadow: 0 0 0 1px var(--line); }
/* Малый стоял выше по файлу, и общее правило здесь его перебивало: до
   сверки «малый» портрет был 32, крупнее обычного */
.avatar--sm { width: 22px; height: 22px; }
.avatar--team { width: 36px; height: 36px; }
.avatar--big { width: 64px; height: 64px; font-size: var(--t-xl); }

/* Страница рядом с колонкой раздела — у колонки, а не посередине окна:
   на широком экране между колонкой и списком стояла пустая полоса в
   треть экрана (владелец, 28 сентября 2026) */
.shell:has(.side:not(.side--bare)) .page { margin-left: 0; }

/* Колонки разделов читаемее: строка — основным кеглем и основным цветом,
   номер проекта — тише и мельче, узкой колонкой ровно под «192-1» */
.siderow { font-size: var(--t-base); color: var(--ink-2); }
.siderow.is-active { color: var(--ink); }
.siderow__code { min-width: 4.6ch; font-size: var(--t-xs); color: var(--ink-3); }

/* Лист «Мои задачи» и области «Бюро»: названия задач длинные — в две
   строки, а не многоточием через полслова (владелец, 28 сентября 2026) */
.sheet__body > .sheet__group:first-child { margin-top: 0; }
.sheet__body > .sheet__group:first-child .sheet__grouphead { border-top: 0; padding-top: 0; }
.svodka__trow .svodka__main, .byuro__name {
  white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere; line-height: 1.3;
}
.byuro__task { align-items: flex-start; }
.byuro__task .byuro__dot { margin-top: .35em; }
/* Строка области — блок: кружок статуса слева (кнопка), ссылка — всё
   остальное (30.09.2026; кнопка внутри ссылки — неверная разметка).
   Ссылка опущена на полразницы кружка и первой строки названия —
   они совмещаются серединами, как в .kcard__title */
.byuro__link {
  flex: 1; min-width: 0; display: flex; align-items: flex-start; gap: var(--s-2);
  color: inherit; text-decoration: none;
  margin-top: calc((var(--step-size) - 1em * 1.3) / 2);
}
.byuro__task .byuro__link:focus-visible { outline-offset: var(--s-1); }
/* ── Раздел «Бюро» (владелец, 28 сентября 2026) ─────────────────────────────
   «Бюро», «Команда», «Календарь», «Отпуска» — один раздел. Колонка —
   навигация (`бюроСбоку`), «Обзор» — что горит по областям слева и люди
   сегодня справа. Всё сплошными карточками без рамок, наведение — --hover. */
.side__note { padding: var(--s-1) var(--s-3); }
/* Счёт области — серым числом всех открытых задач; что горит — красной
   точкой перед ним. Красное число целиком читалось «горят 15», а горели
   две (владелец, 1 октября 2026, по аудиту; как «1 горит» на главной) */
.siderow__count.is-late { display: inline-flex; align-items: center; gap: var(--s-1); }
.siderow__count.is-late::before {
  content: ""; width: 6px; height: 6px; border-radius: var(--radius-full); background: var(--late);
}
.siderow--tiho { color: var(--ink-3); }
.siderow--tiho:hover:where([data-hover="mouse"] *) { color: var(--ink); }
.byuro__tabs { margin-bottom: var(--s-4); }
.byuro__chips { margin-bottom: var(--s-4); max-width: 100%; overflow-x: auto; scrollbar-width: none; }
.byuro__chips button { flex: none; }
/* «+ Область» на обзоре — только там, где колонки нет */
.byuro__top .byuro__narrow { display: none; }
@media (max-width: 1100px) { .byuro__top .byuro__narrow:not([hidden]) { display: inline-flex; } }

.byuro-obzor {
  display: grid; gap: var(--s-5); align-items: start;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 340px);
}
@media (max-width: 1100px) { .byuro-obzor { grid-template-columns: minmax(0, 1fr); } }
.byuro-obzor__main, .byuro-obzor__rail { display: flex; flex-direction: column; gap: var(--s-4); min-width: 0; }
.byuro__label {
  margin: 0; font-size: var(--t-xs); font-weight: 500; letter-spacing: .08em; text-transform: uppercase; font-family: var(--mono);
  color: var(--ink-3);
}
.byuro--obzor { grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); }
.byuro__head h3 { margin: 0; font-size: var(--t-md); font-weight: 600; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Имя области — ссылкой на все её задачи: подложкой под мышью, как строки */
.byuro__title {
  display: inline-flex; min-width: 0; margin: calc(var(--s-1) * -1) calc(var(--s-2) * -1);
  padding: var(--s-1) var(--s-2); border: none; border-radius: var(--radius); background: none;
  color: inherit; font: inherit; cursor: pointer; text-align: left; transition: background var(--fast);
}
.byuro__title:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.byuro__head .chip { flex: none; }
.byuro__more {
  align-self: flex-start; margin-top: var(--s-1); padding: var(--s-1) var(--s-2); border: none;
  border-radius: var(--radius); background: none; cursor: pointer;
  font: inherit; font-size: var(--t-sm); font-weight: 500; color: var(--ink-3);
  transition: background var(--fast), color var(--fast);
}
.byuro__more:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--ink); }

/* Люди сегодня: лицо, имя, чем занят или должность, плашка дня справа.
   Строка — кнопка: открывает карточку человека, как на «Людях»
   (владелец, 29 сентября 2026), — и подсвечивается под мышью */
.byuro__sum { padding: 0 var(--s-1) var(--s-2); font-size: var(--t-sm); color: var(--ink-3); }
.byuro__person { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-1); min-width: 0; }
button.byuro__person, button.svodka__person {
  width: 100%; border: none; background: none; font: inherit; color: inherit; text-align: left;
  border-radius: var(--radius); cursor: pointer;
}
button.byuro__person:hover:where([data-hover="mouse"] *), button.svodka__person:hover:where([data-hover="mouse"] *) { background: var(--hover); }
button.byuro__person:focus-visible, button.svodka__person:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.byuro__face {
  width: 30px; height: 30px; flex: none; border-radius: var(--radius-full); overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--well); color: var(--ink-2); font-size: var(--t-xs); font-weight: 600;
}
.byuro__face img { width: 100%; height: 100%; object-fit: cover; object-position: center center; display: block; }
.byuro__ptxt { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.byuro__pname, .byuro__pnote { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.byuro__pname { font-size: var(--t-sm); font-weight: 500; }
.byuro__pnote { font-size: var(--t-xs); color: var(--ink-3); }
.byuro__person > .chip, .byuro__person > .daystat { flex: none; }
.byuro__ptxt > .chip, .byuro__ptxt > .daystat { align-self: flex-start; margin-top: var(--s-05); }

/* Круглые кнопки — сплошной подложкой с лёгкой тенью: прежняя --surface-2
   совпадала с фоном страницы, и значки у заголовков (папка, закреп, «назад»)
   висели без видимой кнопки (владелец, 28 сентября 2026) */
.roundbtn { background: var(--solid); color: var(--ink-2); box-shadow: var(--sh-1); }
.roundbtn:hover:where([data-hover="mouse"] *) { background: color-mix(in srgb, var(--ink) 6%, var(--solid)); color: var(--ink); }
/* Строка заголовка папки: кнопки и название на одной средней линии, без
   скачка высоты, когда кнопки дорисовываются после ответа сервера */
.dhead__row { min-height: 40px; }
.dhead__row h1 { line-height: 1.15; }

/* Полоса прокрутки не налезает на скругление: дорожка отступает от углов
   у всех прокручиваемых блоков (колонки, сводка, листы, окна, меню) */
::-webkit-scrollbar-track { margin: var(--radius-lg); }

/* «Бюро»: люди — блоком в левой колонке под разделами; обзор на широком
   экране — во всю ширину под области. Без колонки (≤1100) — люди под
   областями, как прежде (владелец, 28 сентября 2026) */
.byuro-obzor { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 1101px) { .byuro-obzor__rail.byuro__narrow-only { display: none; } }
.side__people { display: flex; flex-direction: column; gap: var(--s-2); margin-top: var(--s-3); padding-top: var(--s-3); border-top: 1px solid var(--hair); }
.side__people:empty { display: none; }
.side__people .byuro__rail { background: none; box-shadow: none; border-radius: 0; padding: 0; }
.side__people .byuro__head { padding: 0 var(--s-3) var(--s-1); }
.side__people .byuro__head h3 {
  font-size: var(--t-2xs); font-weight: 500; letter-spacing: .08em; text-transform: uppercase; font-family: var(--mono); color: var(--text-faint);
}
.side__people .byuro__sum { padding: 0 var(--s-3) var(--s-1); font-size: var(--t-xs); color: var(--ink-3); }
.side__people .byuro__person { padding: var(--s-1) var(--s-3); gap: var(--s-2); }
.side__people .byuro__face { width: 28px; height: 28px; }
.side__people .byuro__pname { font-size: var(--t-sm); }
.side__people .byuro__pnote { font-size: var(--t-xs); }
.side__people .btn--ghost { font-size: var(--t-xs); height: 26px; }

/* Полоса прокрутки — тоньше и скруглённой капсулой, тише по цвету: прежняя
   читалась плоской серой чертой (владелец, 28 сентября 2026) */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb { background: var(--line-2); border: 2px solid transparent; background-clip: padding-box; border-radius: var(--radius-full); }
::-webkit-scrollbar-thumb:hover:where([data-hover="mouse"] *) { background: var(--ink-3); background-clip: padding-box; }
/* В строке задачи — номер и название проекта: плашка шире */
.trow__code { max-width: 34ch; }

/* Портреты в строках и карточках задач — размером с кружок-галочку, а не
   крупнее: общий портрет вырос до 32 и в строке задачи перетягивал взгляд
   (владелец, 28 сентября 2026) */
.trow .avatar, .htbl .avatar, .kcard__who .avatar, .is-rows .kcard__who .avatar {
  width: var(--step-size, 22px); height: var(--step-size, 22px); font-size: var(--t-2xs);
}

/* ── Канбан по макету (владелец, 28 сентября 2026: «в макете лучше») ────────
   Колонка — светлой подложкой со скруглением плашки, статус — цветной
   плашкой с точкой, карточки — чистые с лёгкой тенью. Просрочку говорит
   красный срок, а не рамка: красных рамок на доске было больше, чем
   карточек без них (решение от 3 сентября пересмотрено владельцем). */
.kcol {
  background: color-mix(in srgb, var(--solid) 55%, transparent);
  border-radius: var(--radius-xl); box-shadow: var(--sh-1);
}
.kcol__head { align-items: center; gap: var(--s-2); padding: var(--s-3) var(--s-3) var(--s-1); }
.kcol__name--pill {
  display: inline-flex; align-items: center; gap: var(--s-1); flex: 0 1 auto; min-width: 0;
  padding: 2px var(--s-2); border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--st-col, var(--ink-3)) 16%, transparent);
  color: var(--ink); font-size: var(--t-xs); font-weight: 500; letter-spacing: 0; text-transform: none;
}
.kcol__name--pill .kcol__dot { width: 6px; height: 6px; margin: 0; flex: none; }
.kcol__count { margin-left: 0; font-family: var(--font); font-variant-numeric: tabular-nums; }
.kcard { border-radius: var(--radius-lg); box-shadow: var(--sh-1); }
.kcard.is-hot, .kcard.is-hot:hover:where([data-hover="mouse"] *) { border-color: transparent; }

/* Логотип — на 5% меньше и с отступом внутри плашки, как .brand в макете */
.topbar__brand { padding-left: var(--s-2); }
.brand__name { height: .9em; }
/* ── Кто в сети (владелец, 28 сентября 2026) ────────────────────────────────
   Зелёная точка у лица — человек сейчас в портале (src/server/prisutstvie.js).
   Обводка точки — цветом подложки, чтобы точка читалась и на фото */
.onl { position: relative; display: inline-flex; flex: none; }
.onl__dot {
  position: absolute; right: -1px; bottom: -1px; width: 10px; height: 10px;
  border-radius: var(--radius-full); background: var(--ok); box-shadow: 0 0 0 2px var(--solid);
  display: none;
}
.onl.is-online .onl__dot { display: block; }

/* Сводка: «В бюро N из M» раскрывается списком людей */
.svodka__tail { display: inline-flex; align-items: center; gap: var(--s-2); flex: none; }
/* Значок «chevron» смотрит влево: свёрнуто — вниз, раскрыто — вверх */
.svodka__chev { display: inline-flex; color: var(--ink-3); transform: rotate(-90deg); transition: transform var(--fast); }
.svodka__chev.is-open { transform: rotate(90deg); }
.svodka__people { display: flex; flex-direction: column; margin: 0 0 var(--s-1); }
.svodka__personrow { min-width: 0; }
.svodka__personrow + .svodka__personrow { border-top: 1px solid var(--hair); }
.svodka__person { display: grid; grid-template-columns: 34px minmax(0, 1fr); align-items: center; gap: var(--s-3); padding: var(--s-2); min-width: 0; width: 100%; }
.svodka__person .svodka__face { width: 34px; height: 34px; box-shadow: none; }
.svodka__person .svodka__main { font-size: var(--t-base); white-space: normal; overflow-wrap: anywhere; }
.svodka__person .svodka__note { overflow-wrap: anywhere; }
.svodka__person.is-away .svodka__main { color: var(--ink-2); }
.svodka__personmeta { display: flex; align-items: center; gap: var(--s-1); }
.svodka__personmeta > .svodka__note { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.svodka__personmeta:empty, .svodka__status:empty { display: none; }
.svodka__status { min-width: 0; max-width: 100%; display: inline-flex; flex: 0 1 auto; }
.svodka__status .chip, .svodka__status .daystat { white-space: normal; height: auto; text-align: left; }
.svodka__more {
  align-self: flex-start; margin: var(--s-1) var(--s-2) 0; padding: var(--s-1) var(--s-2);
  border: none; border-radius: var(--radius); background: none; cursor: pointer;
  font: inherit; font-size: var(--t-sm); font-weight: 500; color: var(--ink-3);
  transition: background var(--fast), color var(--fast);
}
.svodka__more:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--ink); }

/* Правая колонка «Бюро» — люди и проекты в работе (владелец, 29 сентября
   2026). Того же стекла и вида, что «Сегодня», но уже: в ней лицо, имя,
   плашка дня и проекты с обложкой. Ширина — по самой длинной строке людей
   (лицо 28 + имя + плашка «в отпуске») на живых данных бюро. Сворачивается
   плашкой в правый угол отдельно от левой колонки */
.svodka--right { top: var(--s-3); right: var(--s-3); bottom: var(--s-3); width: var(--side-w); }
.svodka--right-folded { top: var(--s-3); right: var(--s-3); background: none; box-shadow: none; }
[data-glass='panels'] .svodka--right-folded { background: none; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
.svodka__btn--mirror svg { transform: scaleX(-1); }
.svodka__online { color: var(--ok, var(--ink-2)); }
/* Подзаголовки внутри «Моих задач» — тише группы, без капители */
.svodka__sub {
  padding: var(--s-2) var(--s-2) var(--s-1); font-size: var(--t-xs); font-weight: 500; color: var(--ink-3);
}
.svodka__sub.is-late { color: var(--danger); }
/* Проект — облаком с липкой шапкой (владелец, 30.09.2026, вариант А
   макета «Левая колонка»): один блок на мягкой подложке, шапка скруглена
   только сверху и при прокрутке колонки держится у её верха, оставаясь
   частью своего блока. В шапке номер на плашке моноширинным (у областей
   бюро — слово «Бюро» обычным шрифтом), название серым и мельче задач,
   «N горят» красным и «ещё N» пилюлей — своей строки она не занимает.
   Цвета проекта нет: говорят только статусы и красный срок.

   Подложка и шапка — своими переменными, потому что на тёмной стороне
   их пришлось поднять (владелец, 30.09.2026: «в тёмной теме шапочка
   проекта очень тёмная»). В макете шапка была из --well, а --well на
   тёмной стороне ТЕМНЕЕ стекла колонки (L .16 против .24): шапка
   проваливалась в дыру, а серое название на ней почти пропадало.
   На тёмной шапка теперь светлее и колонки, и строк задач — лестница
   «колонка → блок → шапка → плашка номера» идёт вверх, как на светлой
   идёт вниз; текст шапки — не ниже 4,5:1 (замеры — в ОБЛИК-И-ШКАЛЫ). */
.svodka {
  --grp-pod: var(--sunken);
  --grp-shapka: color-mix(in srgb, var(--well) 94%, transparent);
  --grp-plashka: var(--solid);
}
[data-scheme='dark'] .svodka {
  --grp-pod: color-mix(in srgb, var(--ink) 6%, transparent);
  --grp-shapka: color-mix(in srgb, var(--solid), var(--ink) 11%);
  --grp-plashka: color-mix(in srgb, var(--solid), var(--ink) 22%);
}
.svodka__grps { display: flex; flex-direction: column; gap: var(--s-3); padding: var(--s-1) 0 var(--s-2); }
.svodka__grp { background: var(--grp-pod); border-radius: var(--radius-lg); overflow: clip; }
.svodka__grphead {
  position: sticky; top: 0; z-index: 2;
  display: flex; align-items: center; gap: var(--s-2);
  padding: calc(var(--s-2) + var(--s-05)) var(--s-3);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0; border-bottom: 1px solid var(--hair);
  background: var(--grp-shapka); color: var(--ink);
  -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
}
.svodka__grpopen {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--s-2);
  padding: 0; border: none; background: none; cursor: pointer; text-align: left; font: inherit; color: inherit;
}
.svodka__grpcode {
  flex: none; padding: 0 var(--s-2); border-radius: var(--radius-sm);
  background: var(--grp-plashka); box-shadow: inset 0 0 0 1px var(--line);
  font-family: var(--mono); font-size: var(--t-mono); font-weight: 500; line-height: 1.6;
  color: var(--ink); font-variant-numeric: tabular-nums; letter-spacing: .02em; white-space: nowrap;
}
.svodka__grpcode.is-word { font-family: var(--font); font-size: var(--t-sm); letter-spacing: 0; }
.svodka__grpname {
  flex: 1; min-width: 0; font-size: var(--t-sm); font-weight: 500; line-height: 1.35; color: var(--ink);
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.svodka__grpopen:hover:where([data-hover="mouse"] *) .svodka__grpname { color: var(--ink); }
.svodka__grplate {
  flex: none; font-size: var(--t-xs); font-weight: 600; color: var(--late-fg);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.svodka__grpmore {
  flex: none; height: 22px; padding: 0 var(--s-2); border: none; border-radius: var(--radius-full); cursor: pointer;
  background: var(--grey-soft); color: var(--ink-2); font: inherit; font-size: var(--t-xs); font-weight: 500;
  font-variant-numeric: tabular-nums; white-space: nowrap; transition: background var(--fast), color var(--fast);
}
.svodka__grpmore:hover:where([data-hover="mouse"] *) { background: color-mix(in srgb, var(--ink) 13%, transparent); color: var(--ink); }
.svodka__grpmore[aria-expanded='true'] { background: var(--accent-soft); color: var(--accent-fg); }
.svodka__grp .svodka__tasks { border-top: 0; }
/* Задачи в колонке — той же строкой, что в разделе «Задачи» (.trow):
   кружок хода слева, название крупно, под ним проект и срок, строки
   разделены чертой (владелец, 30.09.2026: «мелкие, плохо отделены, слева
   ничего»). Колонка уже списка, поэтому поля меньше, а название — в две
   строки, а не многоточием на первой */
.svodka .trow { padding: var(--s-2) var(--s-2); gap: var(--s-2); border-radius: 0; }
.svodka__tasks > .trow:first-child { border-top: 0; }
.svodka .trow__name { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
/* В облаке проекта задачи — главное в колонке (вариант А, 30.09.2026):
   обычный вес и строка чуть выше, воздух 10–12 точек, черта — волосом */
.svodka__grp .trow { padding: calc(var(--s-2) + var(--s-05)) var(--s-3); gap: var(--s-3); border-top-color: var(--hair); }
.svodka__grp .trow__name { font-weight: 400; line-height: 1.4; }
.svodka .trow__due { min-width: 0; }
.svodka__dr { display: inline-flex; align-items: center; gap: var(--s-1); color: var(--accent-fg); }
.svodka__dr .ic { flex: none; }
.svodka__personrow .svodka__pozdr { margin: 0 var(--s-2) var(--s-1) calc(34px + var(--s-3) + var(--s-2)); }
/* Кнопки конференций сразу под датой — отступ от шапки, а не от группы */
.svodka__body > .svodka__links:first-child, .svodka__inner > .svodka__links:first-child { padding-top: 0; }

/* Объявления на поле главной (30 сентября 2026, владелец: «сделать очень
   простым — без дополнительных страниц, без лишних кнопок и режимов»).
   Тело виджета — наш узел поверх холста (`объявленияНаПоле`, app.js):
   рамку с шапкой «Объявления» рисует Ватман, узел ложится под шапку в
   точках холста, масштаб — transform от камеры. Цвет — подложка виджета
   (--solid: её же берёт Ватман, editor/oformlenie.js), низ скруглён под
   рамку. Сверху поле «Написать объявление…», под ним лента: лицо, имя,
   когда, текст. «⋯» видна всегда и тихо — под мышью ничего не прыгает и
   не подменяется (прежние дата↔«⋯» на наведении). */
.annw {
  position: absolute; z-index: 4; box-sizing: border-box; transform-origin: 0 0;
  overflow: auto; overscroll-behavior: contain;
  padding: var(--s-1) var(--s-4) var(--s-3);
  border-radius: 0 0 var(--radius) var(--radius);
  background: var(--solid); color: var(--ink); font-size: var(--t-base); cursor: auto;
}
.annw__in { display: flex; flex-direction: column; }
.annw__new:empty { display: none; }
.annw__new { padding-bottom: var(--s-2); }
.annw__compose { display: flex; flex-direction: column; gap: var(--s-2); }
/* Поле — одна строка, как поле комментария; в фокусе раскрывается и
   растёт по тексту (высоту ставит app.js по scrollHeight) */
.annw__field {
  display: block; width: 100%; box-sizing: border-box; min-height: 38px;
  padding: var(--s-2) var(--s-3); resize: none; overflow: hidden;
  border: 1px solid var(--line-2); border-radius: var(--radius);
  background: var(--well); color: var(--ink); font: inherit; line-height: 1.45; outline: none;
  transition: border-color var(--fast), box-shadow var(--fast), background var(--fast);
}
.annw__field::placeholder { color: var(--ink-3); }
.annw__field:focus { border-color: var(--accent); background: var(--solid); box-shadow: 0 0 0 3px var(--accent-ring); }
.annw__bar { display: none; align-items: center; justify-content: flex-end; gap: var(--s-2); }
.annw__compose.is-open .annw__bar { display: flex; }
.annw__hint { margin-right: auto; font-size: var(--t-xs); color: var(--ink-3); white-space: nowrap; }
.annw__list { display: flex; flex-direction: column; }
.annw__item {
  display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: var(--s-3);
  padding: var(--s-3) 0; border-top: 1px solid var(--line);
}
.annw__item:first-child { border-top: none; }
.annw__new:not(:empty) + .annw__list .annw__item:first-child { border-top: 1px solid var(--line); }
.annw__face { margin-top: var(--s-05); }
.annw__main { min-width: 0; display: flex; flex-direction: column; gap: var(--s-1); }
.annw__head { display: flex; align-items: center; gap: var(--s-2); min-height: 26px; }
.annw__who { min-width: 0; font-size: var(--t-sm); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.annw__when { flex: none; font-size: var(--t-xs); color: var(--ink-3); white-space: nowrap; }
.annw__pin { flex: none; display: inline-flex; color: var(--accent-fg); }
.annw__more {
  flex: none; margin-left: auto; display: inline-grid; place-items: center;
  width: 26px; height: 26px; padding: 0; border: none; border-radius: var(--radius-full);
  background: none; color: var(--ink-3); cursor: pointer;
}
.annw__more:hover:where([data-hover="mouse"] *), .annw__more.is-open { background: var(--hover); color: var(--ink); }
.annw__text { white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.5; }
.annw__lead { font-weight: 600; }
.annw__link { color: var(--accent-fg); text-decoration: underline; text-underline-offset: 2px; }
.annw__act { align-self: flex-start; margin-top: var(--s-1); text-decoration: none; }
.annw__empty { padding: var(--s-3) 0; color: var(--ink-3); font-size: var(--t-sm); }
.menurow.annw__del { color: var(--late-fg); }
/* Палец: тело пропускает касания на доску — её двигают и через виджет;
   нажимаются только поле, кнопки и ссылки. Прокрутки внутри нет: на
   телефоне виджет растёт под всё содержимое (app.js). Кегль поля — 16px,
   иначе Safari увеличит страницу при касании (--t-field) */
@media (pointer: coarse) {
  .annw { pointer-events: none; overflow: hidden; }
  .annw :is(a, button, textarea) { pointer-events: auto; }
  .annw__field { font-size: var(--t-field); }
  .annw__hint { display: none; }
}

/* Виджет «Диск» на доске Ватмана: кнопка вставки поверх холста и окно
   виджета — крошки, папки, плитки файлов (docs/ВАТМАН-В-ПОРТАЛЕ.md, «Окно
   диска», 29 сентября 2026) */
.diskw { display: flex; flex-direction: column; gap: var(--s-2); font-size: var(--t-sm); color: var(--ink); }
.diskw__head { display: flex; align-items: center; justify-content: flex-end; gap: var(--s-2); }
.diskw__btn {
  display: inline-flex; align-items: center; gap: var(--s-1); padding: var(--s-1) var(--s-2);
  border: 1px solid var(--line); border-radius: var(--radius); background: none; color: var(--ink-2); cursor: pointer;
}
.diskw__btn:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--ink); }
.diskw__path { color: var(--ink-3); font-size: var(--t-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.diskw__status { padding: var(--s-2); border-radius: var(--radius); background: var(--sunken); color: var(--ink-2); font-size: var(--t-xs); }
.diskw__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); gap: var(--s-2); }
.diskw__tile {
  display: flex; flex-direction: column; align-items: center; gap: var(--s-1); padding: var(--s-2);
  border: 1px solid transparent; border-radius: var(--radius); background: var(--sunken); cursor: grab; overflow: hidden;
}
.diskw__tile:hover:where([data-hover="mouse"] *) { border-color: var(--line); }
.diskw__tile span { font-size: var(--t-xs); color: var(--ink-2); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.diskw__tile img { width: 100%; height: 56px; object-fit: cover; border-radius: var(--radius-sm, 4px); }
.diskw__tile--folder { cursor: pointer; }

/* «Бюро → Обзор»: все задачи области, ссылка на область — внизу карточки */
.byuro__all {
  align-self: flex-start; display: inline-flex; align-items: center; gap: var(--s-1);
  margin-top: var(--s-1); padding: var(--s-1) var(--s-2); border: none; border-radius: var(--radius);
  background: none; cursor: pointer; font: inherit; font-size: var(--t-sm); font-weight: 500; color: var(--accent-fg);
  transition: background var(--fast);
}
.byuro__all:hover:where([data-hover="mouse"] *) { background: var(--hover); }
/* «+ Задача» в области и «Добавить задачу» над сводкой (4 октября 2026) */
.byuro__labelrow { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }
.byuro__addall > span { display: inline-flex; align-items: center; gap: var(--s-1); }
.byuro__add {
  align-self: flex-start; display: inline-flex; align-items: center; gap: var(--s-1);
  margin-top: var(--s-1); padding: var(--s-1) var(--s-2); border: 1px dashed var(--line-2); border-radius: var(--radius);
  background: none; cursor: pointer; font: inherit; font-size: var(--t-sm); color: var(--ink-2);
  transition: background var(--fast);
}
.byuro__add:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--ink); }

/* «Бюро → Офисы» */
.byuro__office { margin-top: var(--s-6); }
.byuro__office:first-child { margin-top: 0; }
.byuro__office-admin { margin-top: var(--s-6); display: inline-flex; align-items: center; gap: var(--s-2); }

/* Дедлайн «состоялось» — тихий, с галочкой; кнопка-меню той же формы */
.duechip__in { display: inline-flex; align-items: center; gap: var(--s-1); min-width: 0; }
.duechip.is-done { color: var(--ink-3); background: var(--well); }
.duechip.is-done .duechip__name { text-decoration: line-through; text-decoration-color: var(--line-2); }

/* «Загрузка»: доска высотой в окно — горизонтальная полоса всегда видна
   внизу экрана, а не под самой длинной колонкой (владелец, 28.09.2026);
   колонки листаются вниз все вместе внутри доски */
.kanban-host.planweek .kanban { max-height: calc(100dvh - 260px); overflow: auto; }
/* Колонки канбана — ближе к фону страницы, карточки на них — белые с тенью:
   белое на почти белом сливалось */
.kcol { background: color-mix(in srgb, var(--solid) 30%, transparent); }
.kcard { box-shadow: 0 0 0 1px var(--hair), var(--sh-1); }

/* ── Сверка с ТЗ (28 сентября 2026): телефон ─────────────────────────────────
   Шапка и полоса разделов на телефоне — плавающие слои: страница уезжает
   под них. По ТЗ (раздел 3) у плавающего — стекло «на панелях», а не
   сплошная заливка с чертой; «иерархия тоном, а не рамками» — черты над
   полосой нет, от страницы её отделяет тень. Выбранная вкладка — сплошной
   плашкой с тенью и акцентом текста, как .tabbar макета, а не мягкой
   акцентной заливкой: так же выбран раздел в полосе на компьютере.
   Размеры и --nav-h прежние — на них стоят меню Ватмана и нижние плашки. */
@media (max-width: 760px) {
  .nav { border-top: none; border-radius: var(--radius-xl) var(--radius-xl) 0 0; box-shadow: var(--sh-2); }
  .nav .navitem.is-active { background: var(--solid); color: var(--accent-fg); box-shadow: var(--sh-1); }
  [data-glass='panels'] .nav, [data-glass='panels'] .topbar {
    background: var(--glass-strong);
    -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  }
  [data-glass='panels'] .nav { box-shadow: var(--in), var(--sh-2); }
}

/* Пункт меню — орган управления: 500, как кнопка и вкладка (макет: .menu
   button); пояснение под ним — текстом, 400. Сверка с ТЗ, 28.09.2026 */
.menupop .menurow { font-weight: 500; }
.menupop .menurow .note { font-weight: 400; }

/* Телефон: значок и подпись — один пункт нижней навигации. Отдельная
   капсула под значком снята по просьбе владельца 1 октября 2026.
   Запас под домашний индикатор остаётся у полосы, не у выбранного пункта. */
@media (max-width: 760px) {
  .nav { border-radius: 0; }
  .nav .navitem.is-active { background: none; box-shadow: none; color: var(--accent-fg); }
  .nav .navitem__icon {
    display: inline-grid; place-items: center; width: 100%; height: var(--s-5);
    border-radius: 0;
  }
  .nav .navitem.is-active .navitem__icon { background: none; }
  .nav .navitem.is-active .navitem__label { font-weight: 600; }
  /* Владелец, 30 сентября 2026: «подсвечивается только значок, подпись
     нет». Подпись и была акцентом, но --accent-fg (L .46) рядом с --ink-2
     соседей (L .42) при 11 точках читается тем же тёмным: выделение нёс
     один только кружок под значком. Ярче акцент текстом брать нельзя —
     --accent не проходит 4,5 на фоне (см. токены), — поэтому разницу
     даёт тишина соседей: невыбранные значок и подпись — --ink-3, как
     у полосы вкладок телефона, выбранные — акцентом и 600. Так подпись
     выделена тем же цветом, что и значок, и это видно. */
  .nav .navitem:not(.is-active) { color: var(--ink-3); }
  .nav .navitem.is-active .navitem__label, .nav .navitem.is-active .navitem__icon { color: var(--accent-fg); }
}

/* ── Замок «Видит только администратор» (владелец, 28 сентября 2026) ─────────
   После подписи всего, что видит один администратор: пункты колонок, меню,
   вкладки, входы в админку. Тон — ink-3, как у подписи; значок не кнопка,
   подсказка — наведением (title). Ставит ядро: `замокАдмина()` в app.js */
.zamok-admina {
  display: inline-flex; flex: none; vertical-align: -1px;
  margin-left: var(--s-1); color: var(--ink-3);
}
.zamok-admina svg { display: block; }
/* На залитой кнопке ink-3 тонет в акценте — берёт цвет надписи, тише */
.btn--primary .zamok-admina { color: inherit; opacity: .7; }
.btn .zamok-admina { margin-left: 0; }


/* «Ссылки на главной» в админке: строка — подпись, пояснение, адрес, стрелки */
.ssylki { display: flex; flex-direction: column; gap: var(--s-2); margin-bottom: var(--s-3); }
.ssylki__row { display: grid; grid-template-columns: 9.5em 1fr 1.4fr 2fr auto; gap: var(--s-2); align-items: center; }
.ssylki__acts { display: flex; gap: var(--s-1); }
@media (max-width: 760px) { .ssylki__row { grid-template-columns: 1fr; } }

/* Гость области заказчика: шапки портала нет — плашка в первой строке, на
   одной линии с панелью людей, а не под пустым местом шапки */
.page--wb .wb__over--guest { top: var(--s-3); }

/* Ссылки главной (Zoom и такие же) — заметной кнопкой в сводке */
.svodka__links { display: flex; flex-direction: column; gap: var(--s-1); padding: var(--s-2); }
.svodka__link {
  display: flex; align-items: center; gap: var(--s-2); width: 100%;
  padding: var(--s-2) var(--s-3); border: none; border-radius: var(--radius-lg);
  background: var(--accent-soft); color: var(--accent-fg); font: inherit; text-align: left; cursor: pointer;
  transition: background var(--fast);
}
.svodka__link:hover:where([data-hover="mouse"] *) { background: color-mix(in srgb, var(--accent) 22%, var(--solid)); }
.svodka__linkic { display: inline-flex; flex: none; }
.svodka__linkname { flex: 1; min-width: 0; font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svodka__linknote {
  flex: none; padding: 1px var(--s-2); border-radius: var(--radius-full);
  background: var(--solid); color: var(--ink-2); font-size: var(--t-xs); font-variant-numeric: tabular-nums;
}
/* Кнопка ссылки выше — её ищут глазами каждое утро (владелец, 29.09.2026) */
.svodka__link { min-height: 52px; padding: var(--s-3) var(--s-4); }
.svodka__linkic { width: 32px; height: 32px; place-items: center; display: inline-grid; border-radius: var(--radius-full); background: var(--solid); }
.svodka__linkname { font-size: var(--t-md); }
.svodka__linktxt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.svodka__link .svodka__linknote { padding: 0; background: none; border-radius: 0; color: var(--ink-2); font-size: var(--t-xs); }

/* Сводка по варианту А (владелец, 29.09.2026): обложки проектов — размером
   со значки строк, одной колонкой с ними; значок кнопки ссылки — тоже 30 */
.svodka__thumb { width: 30px; height: 30px; border-radius: var(--radius); }
.svodka__link .svodka__linkic { width: 30px; height: 30px; }

/* Ссылки бюро — по две в ряд (владелец, 30.09.2026, колонка по варианту А):
   Zoom бюро с кодом и чат бюро в Телеграме. Других быстрых значков нет —
   всё остальное в верхнем меню. Одна ссылка — во всю ширину */
.svodka__links { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-1); }
.svodka__links > .svodka__link:only-child { grid-column: 1 / -1; }
.svodka__link {
  min-height: 40px; min-width: 0; padding: var(--s-1) var(--s-2); gap: var(--s-2); border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 12%, var(--solid));
}
.svodka__link .svodka__linkic { width: 28px; height: 28px; color: var(--accent-fg); }
.svodka__linktxt { gap: 0; line-height: 1.25; }
.svodka__linkname { font-size: var(--t-sm); }
.svodka__link .svodka__linknote { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Колонка во всю ширину телефона уже 340 точек — значки у ссылок уходят */
@media (max-width: 420px) {
  .svodka__link .svodka__linkic { display: none; }
  .svodka__link { padding: var(--s-1) var(--s-3); }
}

/* ── Панель Tertsia на доске (listy-tertsia-panel.js) ─────────────────────
   Контейнер справа даёт Ватман; здесь — наполнение. Сдержанно, как соседние
   панели доски: сплошная подложка контейнера — у Ватмана, у нас только
   разделы с подписями, сетка превью макетов и органы портала (.btn, .seg,
   .select). Фиолетовый знак «T» — тот же тон, что у рамки листа Tertsia
   (розовый Tertsia #E0457B, 29 сентября 2026). */
.tpanel { display: flex; flex-direction: column; gap: var(--s-4); padding: var(--s-3); font-size: var(--t-sm); color: var(--text); }
.tpanel__head { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
/* Значок программы Tertsia, а не буква (владелец, 29 сентября 2026);
   пока картинки нет — розовый квадрат цвета Tertsia */
.tpanel__mark { flex: none; width: 20px; height: 20px; border-radius: var(--radius-sm); object-fit: contain; }
.tpanel__mark--pusto { background: #E0457B; }
.tpanel__title { font-size: var(--t-base); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tpanel__sec { display: flex; flex-direction: column; gap: var(--s-2); }
.tpanel__label { font-size: var(--t-xs); font-weight: 500; color: var(--text-dim); }
.tpanel__note { font-size: var(--t-xs); color: var(--text-faint); }
.tpanel__note--bad { color: var(--late-fg); }
.tpanel__grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-2); }
.tpanel__layout {
  display: flex; flex-direction: column; align-items: center; gap: var(--s-1);
  padding: var(--s-1); border: none; border-radius: var(--radius-sm); background: none;
  cursor: pointer; color: var(--text-dim); min-width: 0;
}
.tpanel__layout:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--text); }
.tpanel__layout.is-active { box-shadow: inset 0 0 0 2px var(--accent); color: var(--text); }
.tpanel__layout:disabled { cursor: default; opacity: .5; }
.tpanel__thumb { width: 100%; height: auto; background: #fff; border-radius: var(--s-05); box-shadow: 0 0 0 1px var(--line); }
.tpanel__cap { font-size: var(--t-xs); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tpanel__list { display: flex; flex-direction: column; }
.tpanel__row { text-align: left; font-size: var(--t-sm); }
.tpanel__line { display: flex; align-items: center; gap: var(--s-2); }
.tpanel__size { width: 72px; height: 30px; }
.tpanel__font { height: 30px; font-size: var(--t-sm); }
.tpanel__seg { align-self: flex-start; }
.tpanel__b { font-weight: 700; }
.tpanel__i { font-style: italic; }
.tpanel__wide { width: 100%; justify-content: center; }
.tpanel__foot { margin-top: auto; padding-top: var(--s-2); }
/* Панель Tertsia — ниже шапки портала и островков доски: отступ меряет
   app.js (`отступПанелиTertsia`) и кладёт в --tpanel-top на холст */
.wb__canvas.wb__canvas--vatman .в-панель.в-панель-tertsia {
  top: var(--tpanel-top, 64px);
  max-height: calc(100% - var(--tpanel-top, 64px) - var(--s-7));
}

/* «Служебное → Сервер»: таблицы медленных запросов не вылезают за карточку.
   Длинный путь переносится внутри своей ячейки, числа — узким столбцом
   справа (владелец, 29 сентября 2026, скриншот: «Раз» и «В среднем» уезжали
   за край из-за адресов /api/obj/<ключ> по 150 знаков) */
.health__table { table-layout: fixed; width: 100%; }
.health__table .health__path { overflow-wrap: anywhere; word-break: break-word; }
.health__table .health__path code { white-space: normal; }
.health__table .num, .health__table th:not(:first-child) { white-space: nowrap; text-align: right; font-variant-numeric: tabular-nums; }
.health__table--puti th:nth-child(1) { width: auto; }
.health__table--puti th:nth-child(2) { width: 64px; }
.health__table--puti th:nth-child(3), .health__table--puti th:nth-child(4) { width: 96px; }
.health__table--poslednie th:nth-child(1) { width: 108px; text-align: left; }
.health__table--poslednie th:nth-child(3) { width: 88px; }
.health__table--poslednie th:nth-child(4) { width: 64px; }
.health__table--poslednie th:nth-child(5) { width: 160px; text-align: left; }
.health__table--poslednie td:nth-child(5) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── Вертикальный ритм страницы (29 сентября 2026) ──────────────────────
   Правило — docs/ОБЛИК-И-ШКАЛЫ.md, раздел того же имени: внутри группы
   --s-2, между блоками страницы --s-4. Замечание владельца по диску и
   странице проекта: «плохо с отступами». Блок в конце файла: он правит
   то, что объявлено выше. */

/* Диск. Шапка папки — группа (название → строка «2 папки · 1 файл»),
   дальше блоками через --s-4: крошки с видом, сетка. Кнопки справа
   («+ Папка», «Загрузить») — на средней линии названия, а не у низа
   шапки: прижатые к низу, они стояли между строкой названия и строкой
   подробностей и не принадлежали ни одной. */
.page--disk .page__head.dhead { align-items: flex-start; margin-bottom: var(--s-4); }
.dhead__t { gap: var(--s-2); }
.dhead .page__head-right { min-height: calc(var(--s-6) + var(--s-2)); }
/* «Назад», название и кнопки папки: от названия — на ступень шире, между
   кнопками — --s-2; раньше всё стояло через --s-2 и слипалось */
.dhead__row { gap: var(--s-3); }
.dhead__row > h1 ~ .roundbtn + .roundbtn { margin-left: calc(var(--s-2) - var(--s-3)); }
.dbar { margin-bottom: var(--s-4); }
/* Пустая строка хода загрузки добавляла к отбивке перед сеткой ещё 8 */
.diskupload:empty { margin: 0; }
/* Плитка: поле --s-2 вокруг лица, подпись и «кто · сколько · когда» —
   на --s-3 от края, как текст в карточке канбана. Было 6 и 10: подписи
   жались к краю плитки */
.dfile { padding: var(--s-2); gap: var(--s-2); }
.dfile__nm { padding: 0 var(--s-1); }
.dfile__mt { padding: 0 var(--s-1) var(--s-1); }
/* Колонка диска: заголовок → поиск → дерево → черта → группа — одним
   шагом. Подпись группы («Закреплённые») ближе к своим строкам, чем
   к строке над ней */
.side:has(.disktree) .side__search { padding-bottom: var(--s-1); }
.disktree > .side__group:not(:empty) { padding-top: var(--s-2); }

/* Проект: шапка → закреплённое → дедлайны → панель доски → колонки —
   через --s-4. У полосы дедлайнов своих полей нет (были 8 сверху и
   снизу — вместе с отбивкой закреплённого выходило 24), у холста —
   поля сверху (было 8 под панелью и 16 холста) */
.projboard .duebar, .duebar--flush { padding: 0; margin-bottom: var(--s-4); }
.projboard .board__bar { margin-bottom: var(--s-4); }
.projboard :is(.kanban-host, .list-host) { padding-top: 0; }
/* Карточка канбана: подвал (срок и лица) — на --s-2 под метками, как
   метки под названием. С --s-3 и кружком приоритета в 26 точек под
   последней строкой текста оставалась пустая полоса */
.kcol .kcard__meta { margin-top: var(--s-2); }

@media (max-width: 760px) {
  .dfile { padding: var(--s-2); gap: var(--s-2); }
}

/* ── Лист задачи, вариант «Г» (владелец, 30 сентября 2026) ──────────────────
   Макет «Боковая панель задачи», вариант «Г», с поправкой владельца: людям
   подписи как в «А». Лист — три яруса: закреплённая шапка (путь, ход по
   списку, «…»; кружок и слово статуса, название), прокрутка (слева
   описание, чек-лист, файлы, лента; справа свойства плашками) и поле
   ответа, прижатое к низу. Прокручивается только середина — шапку и поле
   ответа не нужно искать, где бы ни стояла лента. */
.sheet--task .sheet__body { display: flex; flex-direction: column; min-height: 0; padding: 0; overflow: hidden; }
.sheet--task .sheet__body > .page:not(.page--tz) { padding: var(--s-4) var(--s-5); overflow: auto; }
.page--sheet.page--tz { flex: 1; min-height: 0; width: 100%; margin: 0; display: flex; flex-direction: column; }
@media (max-width: 760px) {
  /* Снизу, как любой лист на телефоне, но высотой всегда полной: середина
     листа прокручивается сама, и высоте по содержимому не за что держаться */
  .sheet--task { height: min(86dvh, calc(100dvh - 40px)); }
}

.page--tz .tz__top {
  flex: none; position: relative; z-index: 1; background: var(--solid);
  padding: var(--s-3) var(--s-5); box-shadow: 0 1px 0 var(--hair);
}
.page--tz:not(.page--sheet) .tz__top { position: sticky; top: 0; z-index: 3; }
.page--tz .tview__bar {
  position: static; margin: 0 0 var(--s-2); padding: 0; background: none; min-height: 32px;
}
.page--sheet.page--tz .tview__bar { padding-right: var(--s-7); }

.tz__head {
  display: grid; grid-template-columns: var(--step-size) minmax(0, 1fr);
  column-gap: var(--s-3); align-items: start;
}
.tz__head--nokrug { grid-template-columns: minmax(0, 1fr); }
.tz__head > .krug { grid-row: 1 / 3; }
.tz__meta { display: flex; align-items: center; gap: var(--s-2); min-height: var(--step-size); min-width: 0; }
.tz__kind { font-size: var(--t-xs); font-weight: 500; color: var(--ink-3); }
/* Слово статуса — мелко, с точкой цвета колонки и уголком меню */
.tstword {
  display: inline-flex; align-items: center; gap: var(--s-1);
  min-height: var(--step-size); padding: 0 var(--s-2); margin-left: calc(-1 * var(--s-2));
  border: 0; background: none; border-radius: var(--radius-full); cursor: pointer;
  font: inherit; font-size: var(--t-xs); font-weight: 600; color: var(--ink-2); white-space: nowrap;
  transition: background var(--fast), color var(--fast);
}
.tstword::before { content: ''; width: 6px; height: 6px; border-radius: var(--radius-full); background: var(--st-color, var(--ink-3)); flex: none; }
button.tstword::after {
  content: ''; width: 5px; height: 5px; margin-left: var(--s-05);
  border: solid var(--ink-3); border-width: 0 1.5px 1.5px 0;
  transform: translateY(-2px) rotate(45deg);
}
button.tstword:hover:where([data-hover="mouse"] *), button.tstword.is-open { background: var(--hover); color: var(--ink); }
.tstword.is-ro { cursor: default; }
/* Название правится по месту: без рамки, пока его не трогают */
.tz__title .input {
  display: block; width: calc(100% + 2 * var(--s-2)); margin-left: calc(-1 * var(--s-2));
  height: auto; padding: var(--s-05) var(--s-2);
  font-family: inherit; font-size: var(--t-xl); font-weight: 600; line-height: 1.3; letter-spacing: -.01em;
  border-color: transparent; background: transparent; resize: none; overflow: hidden;
}
.tz__title .input:hover:where([data-hover="mouse"] *):not(:disabled) { border-color: transparent; background: var(--hover); }
.tz__title .input:focus { border-color: var(--accent); background: var(--solid); box-shadow: none; }
.tz__title .input:disabled { color: var(--ink); background: transparent; opacity: 1; }

.tz__scroll { min-width: 0; padding-top: var(--s-4); }
.page--sheet .tz__scroll {
  flex: 1; min-height: 0; overflow: auto; overscroll-behavior: contain;
  padding: var(--s-4) var(--s-5) var(--s-6); scrollbar-width: thin;
}
.tz { display: grid; grid-template-columns: minmax(0, 1fr) 236px; gap: var(--s-5) var(--s-6); align-items: start; }
.tz__main { min-width: 0; }
.tz__side { position: sticky; top: 0; min-width: 0; display: flex; flex-direction: column; gap: var(--s-3); }
.tz__side .tprops__note { margin: 0; background: var(--well); }

/* Чек-лист и файлы — без черт, крестик под курсором (как было в .tview) */
.tz .ckbar { height: 4px; margin-bottom: var(--s-2); }
.tz .ckrow { border-bottom: 0; padding: var(--s-1) 0; }
@media (hover: hover) {
  .tz .ckrow > .btn, .tz .tfile > .btn { opacity: 0; transition: opacity var(--fast); }
  .tz .ckrow:hover:where([data-hover="mouse"] *) > .btn, .tz .tfile:hover:where([data-hover="mouse"] *) > .btn,
  .tz .ckrow > .btn:focus-visible, .tz .tfile > .btn:focus-visible { opacity: 1; }
}
.tz .tfiles__drop {
  gap: var(--s-1); margin: var(--s-1) 0 0 calc(-1 * var(--s-2));
  padding: var(--s-05) 0; border: 1px dashed transparent;
}
.tz .tfiles__drop .tadd { margin-left: 0; }
.tz .tfiles__drop.is-dropping { border-color: var(--accent); background: var(--accent-soft); }
.tfold__lock { display: inline-flex; margin-left: var(--s-1); color: var(--ink-3); vertical-align: middle; }

/* ── Свойства: значок и плашка; люди — подписью над плашками ─────────── */
.tside { display: flex; flex-direction: column; gap: var(--s-4); min-width: 0; }
.tsgrp { display: flex; flex-direction: column; gap: var(--s-2); min-width: 0; }
.tsrow { display: grid; grid-template-columns: 18px minmax(0, 1fr); gap: var(--s-2); align-items: start; min-width: 0; }
.tsrow__ic { height: 28px; display: grid; place-items: center; color: var(--ink-3); }
.tsrow__ic svg { display: block; }
.tsrow__sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.tsrow__v { display: flex; flex-wrap: wrap; gap: var(--s-1); min-width: 0; }
.tsrow__stack { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-05); min-width: 0; max-width: 100%; }
.tspeople { display: flex; flex-direction: column; gap: var(--s-1); min-width: 0; }
.tspeople__l { font-size: var(--t-xs); color: var(--ink-3); }
.tspeople__v { display: flex; flex-wrap: wrap; gap: var(--s-1); min-width: 0; }
.tside__faint { font-size: var(--t-sm); color: var(--ink-3); }

/* Плашка — мягкая подложка с тонкой обводкой: нажимаемое видно без
   наведения. Составная (.tsp) — сроки, этаж с помещением — одна плашка,
   внутри которой каждое значение нажимается своё. */
.tside .tpill, .tside .tsp {
  display: inline-flex; align-items: center; flex-wrap: wrap; max-width: 100%;
  height: auto; min-height: 28px; padding: var(--s-1) var(--s-2);
  border: 0; border-radius: var(--radius-sm);
  background: var(--sunken); box-shadow: inset 0 0 0 1px var(--hair);
  font-size: var(--t-sm); font-weight: 400; line-height: 1.3; color: var(--ink);
  white-space: normal; text-align: left;
}
.tside .tsp { gap: var(--s-05); padding: var(--s-05) var(--s-1); }
.tside .tpill__in { min-width: 0; gap: var(--s-2); }
.tside .tpill__txt { white-space: normal; overflow-wrap: anywhere; }
.tside .tpill--act:hover:where([data-hover="mouse"] *), .tside .tpill--act.is-open { background: var(--hover); color: var(--ink); }
.tside .tpill .avatar { width: 18px; height: 18px; margin-left: calc(-1 * var(--s-05)); }
.tside .tpill--project { color: var(--accent-fg); font-weight: 500; }
.tside .tpill--type, .tside .tpill--prio { color: var(--tpill-color, var(--ink)); font-weight: 500; }
.tside .tpill--put { color: var(--ink-3); }
/* «+ Ещё», «Наблюдать», «Позвать» — обводкой, без заливки: действие, а не значение */
.tside .tpill--add { background: none; box-shadow: inset 0 0 0 1px var(--line); color: var(--ink-2); }
.tside .tpill--add:hover:where([data-hover="mouse"] *) { color: var(--ink); }
/* Внутри составной плашки значения — без своей подложки */
.tside .tsp .tpill {
  min-height: 24px; padding: 0 var(--s-1); background: none; box-shadow: none; border-radius: var(--radius-sm);
}
.tside .tsp .tpill--act:hover:where([data-hover="mouse"] *), .tside .tsp .tpill--act.is-open { background: var(--hover); }
.tside .tsp .tpill--late { color: var(--late-fg); font-weight: 600; }
.tsp__sep { color: var(--ink-3); }
.tsp__hint { color: var(--ink-3); white-space: nowrap; padding-right: var(--s-1); }
.tsp.is-late .tsp__hint { color: var(--late-fg); font-weight: 600; }
/* То, что нажать нельзя, — текстом, без подложки */
.tside .tpill:not(.tpill--act), .tside .tsp.is-ro { background: none; box-shadow: none; padding-left: 0; }
.tside .tsp.is-ro .tpill { padding-left: 0; }
.tside .tprop__link { padding: 0 var(--s-2); font-size: var(--t-xs); }

/* ── Лента: обсуждение и история вместе ─────────────────────────────── */
.tsec--feed .tsec__head { align-items: center; flex-wrap: wrap; row-gap: var(--s-2); }
.tsec__sp { flex: 1; }
.tseg {
  display: inline-flex; gap: var(--s-05); padding: var(--s-05);
  background: var(--sunken); border-radius: var(--radius-full); box-shadow: inset 0 0 0 1px var(--hair);
}
.tseg:empty { display: none; }
.tseg button {
  display: inline-flex; align-items: center; gap: var(--s-1); white-space: nowrap;
  border: 0; background: none; cursor: pointer; border-radius: var(--radius-full);
  padding: var(--s-1) var(--s-3); font: inherit; font-size: var(--t-sm); font-weight: 400; color: var(--ink-2);
  transition: background var(--fast);
}
.tseg button:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.tseg button[aria-pressed='true'] { background: var(--solid); color: var(--ink); font-weight: 500; box-shadow: var(--sh-1); }
.tseg__n { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.tfeed { display: flex; flex-direction: column; }
.tfeed .cmt { border-bottom: 0; padding: var(--s-2) 0; }
.tev--h { display: flex; gap: var(--s-2); padding: var(--s-1) 0; font-size: var(--t-sm); color: var(--ink-3); line-height: 1.45; }
.tev__rail { width: 22px; flex: none; display: flex; justify-content: center; }
.tev__rail::before {
  content: ''; width: 6px; height: 6px; margin-top: calc(var(--s-1) + var(--s-05));
  border-radius: var(--radius-full); background: var(--line-2);
}
.tev__b { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.tev__b b { font-weight: 500; color: var(--ink-2); }
.tev__v { color: var(--ink-2); }
.tev__t { white-space: nowrap; font-variant-numeric: tabular-nums; }
.tev__new {
  display: inline-block; margin-left: var(--s-1); padding: var(--s-05) var(--s-1); line-height: 1;
  font-size: var(--t-xs); font-weight: 600; border-radius: var(--radius-sm);
  background: var(--late-fg); color: var(--solid); vertical-align: .1em;
}
.tfeed__new {
  display: flex; align-items: center; gap: var(--s-2); margin: var(--s-2) 0 var(--s-1);
  font-size: var(--t-xs); font-weight: 600; color: var(--late-fg);
}
.tfeed__new::before, .tfeed__new::after {
  content: ''; flex: 1; height: 1px; background: color-mix(in oklab, var(--late-fg) 45%, transparent);
}

/* ── Поле ответа — внизу листа ───────────────────────────────────────── */
.tcomposer {
  flex: none; position: relative; z-index: 1; display: flex; gap: var(--s-3); align-items: flex-start;
  padding: var(--s-3) var(--s-5) var(--s-4); background: var(--solid); border-top: 1px solid var(--hair);
}
.page--tz:not(.page--sheet) .tcomposer { position: sticky; bottom: 0; margin-top: var(--s-5); }
.tcomposer__me { margin-top: var(--s-2); }
.tcomposer__box {
  flex: 1; min-width: 0; position: relative; display: flex; flex-direction: column; gap: var(--s-1);
  padding: var(--s-2) var(--s-3); border-radius: var(--radius); background: var(--well);
  transition: box-shadow var(--fast);
}
.tcomposer__box:focus-within { box-shadow: 0 0 0 1.5px var(--accent); }
.tcomposer .cmt__input {
  height: auto; min-height: 22px; padding: 0; border: 0; background: none; box-shadow: none;
  resize: none; overflow: auto; font-size: var(--t-base); line-height: 1.45;
}
.tcomposer .cmt__input:hover:where([data-hover="mouse"] *), .tcomposer .cmt__input:focus { border: 0; box-shadow: none; background: none; }
.tcomposer__foot { display: flex; align-items: center; gap: var(--s-3); min-width: 0; }
.tcomposer__foot > .note, .tcomposer__foot > a.note {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--t-xs);
}
.tcomposer__foot > .btn { margin-left: auto; flex: none; }

/* ── Узкий лист (телефон): одна колонка, свойства плашками с переносом
   под названием, люди с подписями отдельной строкой ─────────────────── */
@container (max-width: 580px) {
  .page--tz .tz__top { padding: var(--s-2) var(--s-4) var(--s-3); }
  .page--sheet .tz__scroll { padding: var(--s-3) var(--s-4) var(--s-5); }
  .tz { grid-template-columns: minmax(0, 1fr); gap: var(--s-4); }
  .tz__side { order: -1; position: static; }
  .tz__title .input { font-size: var(--t-lg); }
  .tside { flex-direction: row; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
  .tsgrp, .tsrow, .tsrow__v, .tsrow__stack { display: contents; }
  .tsrow__ic { display: none; }
  .tspeople { flex-basis: 100%; flex-direction: row; flex-wrap: wrap; align-items: center; gap: var(--s-1) var(--s-2); }
  .tspeople__l { min-width: 72px; }
  .tcomposer { padding: var(--s-2) var(--s-3) var(--s-3); }
  .tcomposer__me { display: none; }
  .tz .ckrow > .btn, .tz .tfile > .btn { opacity: 1; }
  .tfiles__hint { display: none; }
}

/* ── Карточка человека окном (владелец, 1 октября 2026, по аудиту) ─────────
   Про «сейчас» и с действиями сверху: шапка, три плитки связи, «Сейчас»
   (проекты, ближайшее отсутствие, день рождения), ниже подписанные поля.
   Подписи — столбцом слева той же ширины, что у всех строк: значения
   стоят на одной вертикали. Наведение — подложкой, без сдвигов. */
.pcard2 .modal__body { display: flex; flex-direction: column; gap: var(--s-4); }
.pcard2__top { display: flex; align-items: center; gap: var(--s-4); min-width: 0; }
.pcard2__who { min-width: 0; display: flex; flex-direction: column; gap: var(--s-1); }
.pcard2__name { font-size: var(--t-lg); font-weight: 600; line-height: 1.2; }
.pcard2__post { font-size: var(--t-sm); color: var(--ink-2); }
.pcard2__state { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-1); }
.pcard2__doing { font-size: var(--t-sm); color: var(--ink-2); }
.pcard2__x { margin-left: auto; align-self: flex-start; }
.pcard2__acts { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--s-2); }
.pcard2__act {
  display: flex; align-items: center; gap: var(--s-3); min-width: 0;
  padding: var(--s-3); border: none; border-radius: var(--radius);
  background: var(--hover); color: var(--ink); font: inherit; text-align: left;
  text-decoration: none; cursor: pointer; transition: background var(--fast);
}
.pcard2__act:hover:where([data-hover="mouse"] *) { background: color-mix(in oklch, var(--ink) 11%, transparent); }
.pcard2__act:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pcard2__acticon {
  flex: none; width: 32px; height: 32px; display: grid; place-items: center;
  border-radius: var(--radius-full); background: var(--solid); color: var(--accent-fg);
}
.pcard2__acttxt { display: flex; flex-direction: column; min-width: 0; }
.pcard2__actmain { font-size: var(--t-sm); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pcard2__actsub { font-size: var(--t-xs); color: var(--ink-3); }
.pcard2__rows { display: grid; grid-template-columns: 8.5rem minmax(0, 1fr); gap: var(--s-2) var(--s-3); font-size: var(--t-sm); }
.pcard2__rows[hidden] { display: none; }
.pcard2__rows + .pcard2__rows { padding-top: var(--s-4); border-top: 1px solid var(--line); }
.pcard2__rows:empty { display: none; }
.pcard2__row { display: contents; }
.pcard2__k { color: var(--ink-3); }
.pcard2__v { min-width: 0; overflow-wrap: anywhere; line-height: 1.45; }
.pcard2__v a { color: var(--accent-fg); }
.pcard2__soon { color: var(--accent-fg); }
.pcard2__soon.is-today { font-weight: 600; }
.pcard2__wait { color: var(--warn-fg); }
.pcard2__pills { display: flex; flex-wrap: wrap; gap: var(--s-1); }
.pcard2__prj {
  display: inline-flex; align-items: center; gap: var(--s-1); height: 24px; padding: 0 var(--s-2);
  border: none; border-radius: var(--radius-full); background: var(--hover);
  color: var(--ink); font: inherit; font-size: var(--t-xs); cursor: pointer; transition: background var(--fast);
}
.pcard2__prj:hover:where([data-hover="mouse"] *) { background: color-mix(in oklch, var(--ink) 11%, transparent); }
.pcard2__prj .code { color: var(--ink-3); }
.pcard2__foot { display: flex; justify-content: flex-end; margin-top: calc(-1 * var(--s-2)); }
@media (max-width: 760px) {
  .pcard2__rows { grid-template-columns: minmax(0, 1fr); gap: 0 var(--s-3); }
  .pcard2__k { font-size: var(--t-xs); margin-top: var(--s-2); }
  .pcard2__acts { grid-template-columns: minmax(0, 1fr); }
}

/* ── Главная телефона одной лентой (владелец, 1 октября 2026, по аудиту) ──
   Сводка «Сегодня» — обычным потоком страницы, без своей прокрутки и без
   стекла: страница прокручивается одна. Группы — сплошными карточками
   подряд: задачи, объявления, бюро, проекты; внизу — «Общая доска». */
.svodka--lenta {
  position: static; z-index: auto; background: none; box-shadow: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
[data-glass='panels'] .svodka--lenta { background: none; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
.svodka--lenta .svodka__head { padding: 0 0 var(--s-3); }
.svodka--lenta .svodka__head h2 { font-size: var(--t-xl); }
.svodka--lenta .svodka__body { overflow: visible; padding: 0; }
.svodka--lenta .svodka__inner { display: flex; flex-direction: column; gap: var(--s-3); }
.svodka--lenta .svodka__links { padding: 0; }
.svodka--lenta .svodka__group {
  padding: var(--s-2); background: var(--solid); border-radius: var(--radius-lg); box-shadow: var(--sh-1);
}
.svodka--lenta .svodka__group + .svodka__group { border-top: none; }
.glav-lenta__ann .annw__new, .glav-lenta__ann .annw__list { padding: 0 var(--s-2); }
.glav-lenta__ann .annw__item { padding: var(--s-2) 0; }
.glav-lenta__ann .annw__field { font-size: var(--t-field, var(--t-base)); }
.glav-lenta__doska {
  display: flex; align-items: center; gap: var(--s-3); width: 100%;
  padding: var(--s-3); border: none; border-radius: var(--radius-lg);
  background: var(--solid); box-shadow: var(--sh-1); color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.glav-lenta__chev { margin-left: auto; color: var(--ink-3); display: inline-flex; transform: rotate(180deg); }

/* ── «Команда» (владелец, 1 октября 2026: «кружки с тремя правками») ───────
   Витрина: крупный круглый портрет одного размера и кадра — 160 точек
   (96 на телефоне), под ним имя, роль, плашки дня, «чем полезен», софт
   уровнями. Пустых строк нет. Сетка от 220 точек: на 2560 — восемь в ряд,
   на 1920 — шесть. Наведение — тенью, без сдвигов. Рядом вид «Навыки». */
.lyudi__tools { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; margin-bottom: var(--s-4); }
.lyudi__tools .byuro__chips { margin: 0; }
.lyudi__search { margin-left: auto; width: min(320px, 100%); border-radius: var(--radius-full); }
.tgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); gap: var(--s-4); }
.tcard {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: var(--s-2);
  padding: var(--s-5) var(--s-4) var(--s-4); text-align: center;
  background: var(--solid); border-radius: var(--radius-xl); box-shadow: var(--sh-1);
  transition: box-shadow var(--fast);
}
.tcard:hover:where([data-hover="mouse"] *) { box-shadow: var(--sh-2); }
.tport {
  width: 160px; height: 160px; border-radius: var(--radius-full); object-fit: cover; flex: none;
  box-shadow: 0 0 0 4px var(--solid), 0 0 0 5px var(--line); margin-bottom: var(--s-2); background: var(--well);
}
.tport--ph, .tport-sm--ph {
  display: grid; place-items: center; color: var(--accent-fg); font-weight: 600; letter-spacing: .02em;
  background: color-mix(in oklch, var(--accent) 14%, var(--solid));
}
.tport--ph { font-size: var(--t-2xl); }
.tcard.is-away .tport { filter: grayscale(.7); opacity: .75; }
.tcard__name {
  all: unset; cursor: pointer; font-size: var(--t-lg); font-weight: 600; line-height: 1.25; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tcard__name::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.tcard__name:focus-visible::after { outline: 2px solid var(--accent); outline-offset: 2px; }
.tcard__role {
  display: inline-flex; align-items: center; height: 24px; padding: 0 var(--s-3); border-radius: var(--radius-full);
  background: var(--accent-soft); color: var(--accent-fg); font-size: var(--t-sm); font-weight: 500; white-space: nowrap;
}
.tcard__post { font-size: var(--t-sm); color: var(--ink-2); }
.tcard__chips { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-1); }
.tcard__helps {
  margin: 0; font-size: var(--t-sm); color: var(--ink-2); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.tsoft { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-2) var(--s-3); margin-top: var(--s-1); }
.tsoft__i { display: inline-flex; align-items: center; gap: var(--s-1); font-size: var(--t-xs); color: var(--ink-2); }
.tsoft__z {
  display: inline-grid; place-items: center; min-width: 26px; height: 22px; padding: 0 var(--s-1);
  border-radius: var(--radius-sm); background: var(--z); color: #fff;
  font-family: var(--mono); font-size: var(--t-xs); font-weight: 500;
  /* Тонкая обводка: тёмный знак (NOPS) не тонет в тёмной карточке */
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .18);
}
.tsoft__lv, .tskills__lv { display: inline-flex; gap: 2px; }
.tsoft__lv b, .tskills__lv b { width: 10px; height: 4px; border-radius: 2px; background: var(--line); }
.tsoft__lv b.is-on, .tskills__lv b.is-on { background: var(--accent); }

/* «Навыки» — люди × софт; таблица прокручивается в своей карточке */
.tskills { overflow-x: auto; background: var(--solid); border-radius: var(--radius-lg); box-shadow: var(--sh-1); padding: var(--s-2) var(--s-3); }
.tskills__t { border-collapse: collapse; width: 100%; font-size: var(--t-sm); }
.tskills__t th, .tskills__t td { padding: var(--s-2); text-align: center; white-space: nowrap; }
.tskills__t td { border-top: 1px solid var(--line); }
.tskills__t th { font-weight: 500; color: var(--ink-2); vertical-align: bottom; }
.tskills__who { text-align: left !important; position: sticky; left: 0; background: var(--solid); z-index: 1; }
.tskills__col {
  all: unset; cursor: pointer; display: inline-flex; flex-direction: column; align-items: center; gap: var(--s-1);
  padding: var(--s-1) var(--s-2); border-radius: var(--radius); font-size: var(--t-xs);
}
.tskills__col:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.tskills__col:focus-visible { outline: 2px solid var(--accent); }
.tskills__t .is-on { background: var(--accent-soft); }
.tskills__person { all: unset; cursor: pointer; display: inline-flex; align-items: center; gap: var(--s-2); padding: var(--s-1); border-radius: var(--radius); }
.tskills__person:hover:where([data-hover="mouse"] *) { background: var(--hover); }
.tskills__person:focus-visible { outline: 2px solid var(--accent); }
.tport-sm { width: 28px; height: 28px; border-radius: var(--radius-full); object-fit: cover; flex: none; }
.tport-sm--ph { font-size: var(--t-xs); }
.tskills__none { color: var(--ink-3); }
.tskills__sum td { font-family: var(--mono); color: var(--ink-3); }
.tskills__sum td.is-few { color: var(--late-fg); font-weight: 600; }
.tskills__empty { background: var(--solid); border-radius: var(--radius-lg); box-shadow: var(--sh-1); padding: var(--s-5); color: var(--ink-2); display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-2); }
.tskills__empty p { margin: 0; }

@media (max-width: 760px) {
  .lyudi__search { margin-left: 0; width: 100%; font-size: var(--t-field); }
  .tgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2); }
  .tcard { padding: var(--s-4) var(--s-2) var(--s-3); gap: var(--s-1); border-radius: var(--radius-lg); }
  .tport { width: 96px; height: 96px; box-shadow: 0 0 0 3px var(--solid), 0 0 0 4px var(--line); }
  .tport--ph { font-size: var(--t-xl); }
  .tcard__name { font-size: var(--t-base); white-space: normal; }
  .tcard__role { height: 20px; font-size: var(--t-xs); padding: 0 var(--s-2); }
  .tcard__helps, .tsoft { display: none; }
}

/* Софт уровнями в профиле: строка на программу бюро */
.softed { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 380px), 1fr)); gap: var(--s-1) var(--s-4); margin-top: var(--s-2); }
.softed__row { display: grid; grid-template-columns: auto minmax(0, 1fr) minmax(0, 1.5fr); align-items: center; gap: var(--s-2); padding: var(--s-1) 0; }
.softed__n { font-size: var(--t-sm); }
.softed__level { font-size: var(--t-sm); width: 100%; min-width: 0; }
@media (max-width: 760px) {
  .softed__row { grid-template-columns: auto minmax(0, 1fr); }
  .softed__level { grid-column: 1 / -1; }
}

/* Окно кадрирования аватарки: круг поверх снимка, овал «лицо сюда» */
.avacrop { max-width: 420px; }
.avacrop__body { display: flex; flex-direction: column; align-items: center; gap: var(--s-3); }
.avacrop__stage {
  position: relative; overflow: hidden; border-radius: var(--radius); background: var(--well);
  cursor: grab; touch-action: none; user-select: none;
}
.avacrop__stage:active { cursor: grabbing; }
.avacrop__stage:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.avacrop__cv { display: block; }
.avacrop__mask {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(circle closest-side, transparent calc(100% - 1px), rgb(10 12 16 / .55) 100%);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .12);
}
.avacrop__mask::after { content: ""; position: absolute; inset: 0; border-radius: var(--radius-full); box-shadow: 0 0 0 2px rgb(255 255 255 / .9); }
.avacrop__face {
  position: absolute; left: 50%; top: 44%; width: 42%; height: 52%; transform: translate(-50%, -50%);
  border: 1.5px dashed rgb(255 255 255 / .75); border-radius: 50%; pointer-events: none;
}
.avacrop__tip {
  position: absolute; left: var(--s-2); bottom: var(--s-2); pointer-events: none;
  background: rgb(0 0 0 / .5); color: #fff; font-size: var(--t-xs); padding: 2px var(--s-2); border-radius: var(--radius-full);
}
.avacrop__zoomrow { display: flex; align-items: center; gap: var(--s-2); width: 100%; max-width: 320px; color: var(--ink-3); }
.avacrop__zoom { flex: 1; accent-color: var(--accent); }
.avacrop__prev { display: flex; align-items: center; gap: var(--s-3); align-self: stretch; }
.avacrop__pv { border-radius: var(--radius-full); background: var(--well); flex: none; }
.avacrop__hint { align-self: stretch; font-size: var(--t-sm); padding: var(--s-2) var(--s-3); border-radius: var(--radius); }
.avacrop__hint.is-ok { background: var(--ok-soft); color: var(--ok-fg); }
.avacrop__hint.is-warn { background: var(--warn-soft); color: var(--warn-fg); }
.avacrop__body > .note { align-self: stretch; }
.pcard2__v .tsoft { justify-content: flex-start; margin-top: 0; }

/* Перенос — за ручку; на сенсорном экране она не запускает прокрутку. */
.task-drag-handle { flex: none; cursor: grab; touch-action: none; user-select: none; color: var(--ink-3); padding: var(--s-05); }
.zdcard.is-draggable { user-select: none; }
.tcard__contacts { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: var(--s-1); max-width: 100%; font-size: var(--t-sm); }
.tcard__contacts a { color: var(--accent-fg); overflow-wrap: anywhere; }
.tcard__contacts:empty { display: none; }
.tcard__about { margin: 0; font-size: var(--t-sm); color: var(--ink-2); line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }

.tsoft__z.is-image { padding: 0; min-width: 0; width: 20px; height: 20px; flex: 0 0 20px; background: transparent; box-shadow: none; }
.tsoft__z.is-image img { width: 100%; height: 100%; object-fit: contain; display: block; }
.tsoft__lv b { width: 4px; height: 3px; }
.kcard__title .kcard__name { flex: 1; min-width: 0; }

/* ── Боковая панель доски проекта (4 октября 2026) ───────────────────────────
   Сворачиваемая стеклянная колонка слева под плашкой: вверху доски проекта,
   ниже задачи. Холст под ней остаётся целым — панель плавает поверх, как
   островки. Только на широком экране: на телефоне места ей нет. */
.wbside { display: none; }
@media (min-width: 901px) {
  .wbside {
    position: absolute; z-index: 4; display: flex; flex-direction: column;
    left: var(--s-5); top: calc(var(--plashka, 0px) + var(--s-3) + 44px + var(--s-3));
    bottom: calc(var(--s-3) + 64px); width: 240px; min-height: 0; box-sizing: border-box;
    background: var(--solid); border-radius: var(--radius-lg); box-shadow: var(--sh-2);
  }
  [data-glass='panels'] .wbside {
    background: var(--glass-strong); -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
    box-shadow: var(--in), var(--sh-2);
  }
  .wbside--folded { bottom: auto; width: auto; }
  .wbside--folded .wbside__body, .wbside--folded .wbside__proj { display: none; }
  .wbside--folded .wbside__fold { transform: rotate(180deg); }
  .wbside__head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); padding: var(--s-2) var(--s-2) var(--s-1) var(--s-3); }
  .wbside__title { font-size: var(--t-sm); font-weight: 600; color: var(--ink-2); }
  /* Переключатель проекта панели: чьи доски и задачи показаны */
  .wbside__proj { flex: 1; min-width: 0; display: flex; }
  .wbside__projbtn {
    display: inline-flex; align-items: center; min-width: 0; max-width: 100%; height: 28px;
    padding: 0 var(--s-2); margin-left: calc(-1 * var(--s-2)); border: none; border-radius: var(--radius-full);
    background: none; color: var(--ink); font-size: var(--t-sm); font-weight: 600; cursor: pointer;
  }
  .wbside__projbtn:hover:where([data-hover="mouse"] *) { background: var(--hover); }
  .wbside__projbtn > span { display: inline-flex; align-items: center; gap: var(--s-1); min-width: 0; }
  .wbside__proj-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .wbside__body.is-loading { opacity: .5; }
  .wbside__fold { width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center; border: none; border-radius: var(--radius-full); background: none; color: var(--ink-2); cursor: pointer; }
  .wbside__fold:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--ink); }
  .wbside__body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 0 var(--s-1) var(--s-2); }
  /* Доски и задачи — двумя группами, с воздухом между ними (владелец, 4.10.2026) */
  .wbside__sec + .wbside__sec { margin-top: var(--s-4); }
  .wbside__h { margin: var(--s-2) var(--s-2) var(--s-1); font-size: var(--t-xs); font-weight: 600; color: var(--ink-3); text-transform: uppercase; letter-spacing: .04em; }
  .wbside__row { display: flex; align-items: center; gap: var(--s-2); padding: var(--s-1) var(--s-2); border-radius: var(--radius); font-size: var(--t-sm); color: var(--ink); text-decoration: none; }
  .wbside__row:hover:where([data-hover="mouse"] *) { background: var(--hover); }
  .wbside__row--on { background: var(--sunken); font-weight: 600; }
  .wbside__row--late .wbside__name { color: var(--late-fg); }
  .wbside__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .wbside__dot { flex: none; width: 8px; height: 8px; border-radius: var(--radius-full); }
  .wbside__me { flex: none; font-size: var(--t-xs); color: var(--ink-3); }
  .wbside__empty { padding: var(--s-1) var(--s-2); font-size: var(--t-sm); color: var(--ink-3); }
}

/* ── Закреплённые доски (7 октября 2026) ────────────────────────────────────
   Булавка на карточке и строке: закреплённая видна всегда и цветом акцента,
   незакреплённая — при наведении (под пальцем — тише, но видна). В «Всех»
   закреплённые — своей стопкой сверху; в колонке и в панели доски — блоком
   над отборами и досками проекта. */
.wbpin {
  flex: none; width: var(--s-6); height: var(--s-6); display: inline-flex; align-items: center; justify-content: center;
  border: none; border-radius: var(--radius-full); background: none; color: var(--ink-3); cursor: pointer;
  opacity: 0; transition: opacity var(--fast), background var(--fast), color var(--fast);
}
.wbpin:hover:where([data-hover="mouse"] *) { background: var(--hover); color: var(--ink); }
.wbpin.is-on { opacity: 1; color: var(--accent-fg); }
.wbcard:hover:where([data-hover="mouse"] *) .wbpin, .wblist__row:hover:where([data-hover="mouse"] *) .wbpin,
.wbpin:focus-visible { opacity: 1; }
@media (hover: none) { .wbpin { opacity: .45; } .wbpin.is-on { opacity: 1; } }
.wblist__act { display: flex; align-items: center; justify-content: flex-end; gap: var(--s-1); }
.group-title--pins h2 { display: inline-flex; align-items: center; gap: var(--s-2); }
.group-title--pins h2 .ic { color: var(--accent-fg); }
.wbgrid.is-pins .wbcard, .wblist.is-pins { box-shadow: 0 0 0 1.5px var(--accent-soft), var(--sh-1); }
/* Колонка раздела: блок закрепов над отборами */
.side__group--pins { display: flex; align-items: center; gap: var(--s-1); color: var(--accent-fg); }
.siderow--pin { gap: var(--s-2); }
.siderow--pin.is-drop { box-shadow: inset 0 2px 0 var(--accent); }
.siderow__pic {
  flex: none; width: var(--s-6); height: calc(var(--s-5) + var(--s-1)); border-radius: var(--radius-sm); object-fit: cover;
  background: var(--board-canvas) radial-gradient(var(--line) 1px, transparent 1.3px) 0 0 / var(--s-2) var(--s-2);
}
.siderow__pic--empty { display: grid; place-items: center; color: var(--ink-3); }
@media (min-width: 901px) {
  /* Панель на доске: закреплённые — первым блоком, на подложке акцента;
     открытая доска — подсвечена */
  .wbside__pins { margin: 0 0 var(--s-2); padding: var(--s-1); border-radius: var(--radius); background: var(--accent-soft); }
  .wbside__pinlabel { display: inline-flex; align-items: center; gap: var(--s-1); color: var(--accent-fg); }
  .wbside__head--proj[hidden], .wbside__pins[hidden] { display: none; }
  .wbside__pins .wbside__row--on { background: var(--solid); box-shadow: var(--shadow-xs); }
  .wbside__pins .siderow__pic { width: var(--s-5); height: var(--s-4); }
  .wbside__head--proj { padding: var(--s-1) var(--s-2) 0; }
  .wbside--folded .wbside__pinlabel { display: none; }
}
/* Булавка в плашке доски: закреплённая — цветом акцента */
.wb__pin.is-on { color: var(--accent-fg); }

/* Board performance panel (`?perf=1`): diagnostics on the device itself */
.perfpanel {
  /* top right, under the board bar: the bottom is the board's toolbar */
  position: fixed; right: var(--s-2); top: calc(var(--s-7) * 3); z-index: 10000; max-width: min(560px, calc(100vw - var(--s-4)));
  padding: var(--s-2); border-radius: var(--radius-sm); background: rgba(20, 20, 20, .88); color: #f1f3f5;
  font-size: var(--t-xs); pointer-events: auto;
}
.perfpanel__head { display: flex; gap: var(--s-1); align-items: center; flex-wrap: wrap; margin-bottom: var(--s-1); }
.perfpanel__head b { margin-right: auto; }
.perfpanel__text { margin: 0; font-size: var(--t-xs); white-space: pre-wrap; line-height: 1.35; }
.perfpanel__status { display: block; margin-top: var(--s-1); opacity: .8; }

/* ── Комплектация: панель позиции (этап 4 переработки, public/proc-panel.js) ──
   Механика листа задачи: справа поверх экрана, своя ссылка, на телефоне —
   снизу во всю ширину. Ширину и раскладку ставит скрипт по ширине окна:
   уже 1500 — 480 px и одна колонка; 1500–1700 — 760 px, две колонки
   (слева точки и оплаты, справа свойства 216 px, как у задачи); шире
   1700 — пристыкована: без затемнения, экран комплектации сужается. */
.procp, [data-glass='panels'] .procp {
  background: var(--solid); -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: var(--sh-3);
}
@media (min-width: 761px) {
  .procp { top: calc(env(safe-area-inset-top) + 56px + var(--s-3) * 2); }
}
@media (max-width: 760px) {
  .procp { height: min(86dvh, calc(100dvh - 40px)); }
}
.procp[data-vid='dock'] { animation: none; z-index: 30; box-shadow: var(--sh-2); }
body.proc-dock .proc-host { margin-right: calc(var(--proc-dock-w, 720px) + var(--s-3)); }
.procp__load { padding: var(--s-6) var(--s-5); color: var(--text-dim); font-size: var(--t-sm); }
.procp__head {
  flex: none; padding: var(--s-3) var(--s-5) var(--s-3); border-bottom: 1px solid var(--hair);
  display: flex; flex-direction: column; gap: var(--s-1);
}
.procp__crumbs { display: flex; align-items: center; gap: var(--s-1); font-size: var(--t-xs); color: var(--ink-3); min-width: 0; }
.procp__sp { flex: 1; }
.procp__ell { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.procp__close { flex: none; }
.procp__title {
  font: inherit; font-size: var(--t-xl); font-weight: 600; line-height: 1.25; color: var(--ink);
  border: 1px solid transparent; background: none; border-radius: var(--radius-sm);
  padding: var(--s-05) var(--s-1); margin-left: calc(-1 * var(--s-1)); width: 100%;
}
.procp__title:hover:where([data-hover="mouse"] *):not(:disabled) { border-color: var(--border); }
.procp__title:focus { outline: none; border-color: var(--accent); background: var(--surface); }
.procp__title:disabled { color: var(--ink); }
.procp__meta { display: flex; align-items: baseline; gap: var(--s-2); font-size: var(--t-sm); min-width: 0; }
.procp__supplier { color: var(--accent-fg); font-weight: 500; white-space: nowrap; text-decoration: none; }
.procp__supplier.is-plain { color: var(--ink-2); }
a.procp__supplier:hover { text-decoration: underline; }
.procp__sum { font-size: var(--t-xl); font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--ink); }
.procp__tags { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; margin-top: var(--s-1); font-size: var(--t-sm); }
.procp__who { display: inline-flex; align-items: center; gap: var(--s-1); color: var(--ink-2); }
.procp__av {
  width: 20px; height: 20px; border-radius: var(--radius-full); display: inline-grid; place-items: center;
  background: var(--accent-soft); color: var(--accent-fg); font-size: var(--t-2xs); font-weight: 600;
}
.procp__faint { color: var(--text-faint); }
.procp__hint { display: block; font-size: var(--t-xs); color: var(--ink-3); margin-top: var(--s-1); }
.procp__hint.is-bad { color: var(--late-fg); }

.procp__body { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: auto; }
.procp__main { padding: var(--s-3) var(--s-5) var(--s-4); }
.procp__side { padding: var(--s-3) var(--s-5) var(--s-5); border-top: 1px solid var(--hair); }
.procp--two .procp__body { display: grid; grid-template-columns: minmax(0, 1fr) 216px; overflow: hidden; }
.procp--two .procp__main, .procp--two .procp__side { overflow: auto; min-height: 0; }
.procp--two .procp__side { border-top: 0; border-left: 1px solid var(--hair); background: var(--well); padding: var(--s-3) var(--s-4) var(--s-5); }

.procp__sec { margin-top: var(--s-4); }
.procp__sec:first-child { margin-top: 0; }
.procp__sec h4 {
  display: flex; align-items: center; gap: var(--s-2); margin: 0 0 var(--s-2);
  font-size: var(--t-sm); font-weight: 600; color: var(--ink);
}
.procp__h4note { font-weight: 400; font-size: var(--t-xs); }
.procp__add {
  background: none; border: 0; padding: 0; font: inherit; font-size: var(--t-sm); font-weight: 500;
  color: var(--accent-fg); cursor: pointer;
}
.procp__add:hover { text-decoration: underline; }
.procp__empty { font-size: var(--t-sm); padding: var(--s-2) 0; }

/* Предупреждения */
.procp__warns { display: flex; flex-direction: column; gap: var(--s-2); margin-bottom: var(--s-3); }
.procp__warn {
  display: flex; align-items: center; gap: var(--s-2); padding: var(--s-2) var(--s-3);
  border-radius: var(--radius); background: var(--warn-soft); color: var(--warn-fg); font-size: var(--t-sm);
}
.procp__warn > span:not(.ic) { flex: 1; }
.procp__warn.is-bad { background: var(--late-soft); color: var(--late-fg); }

/* Лесенка точек */
.procp__steps { display: flex; flex-direction: column; }
.procp__main { container: procp-main / inline-size; }
/* Point row: name with its rule under it, then plan, lock, fact. In a narrow
   column (one-column panel, docked panel, phone) the fact goes under the plan */
.procp__step {
  display: grid; grid-template-columns: 18px minmax(0, 1fr) auto 24px auto;
  grid-template-areas: 'mk name plan lock fact' 'mk rule plan lock fact';
  align-items: center; column-gap: var(--s-2); padding: var(--s-1) 0; position: relative;
}
.procp__mk { grid-area: mk; }
.procp__ptname { grid-area: name; }
.procp__rule { grid-area: rule; }
.procp__plan { grid-area: plan; }
.procp__step > .procp__lock, .procp__lockph { grid-area: lock; }
.procp__fact { grid-area: fact; }
.procp__step--hd { grid-template-areas: 'mk name plan lock fact'; }
.procp__hd-name { grid-area: name; }
.procp__hd-plan { grid-area: plan; }
.procp__hd-fact { grid-area: fact; text-align: right; }
@container procp-main (max-width: 600px) {
  .procp__step { grid-template-columns: 18px minmax(0, 1fr) auto 24px; grid-template-areas: 'mk name plan lock' 'mk rule fact fact'; }
  .procp__step--hd { grid-template-areas: 'mk name plan lock'; }
  .procp__hd-fact { display: none; }
  .procp__fact { padding-top: var(--s-05); }
}
.procp__step--hd { font-size: var(--t-2xs); text-transform: uppercase; letter-spacing: .06em; color: var(--text-faint); font-family: var(--mono); padding: 0 0 var(--s-1); }
.procp__mk {
  width: 10px; height: 10px; transform: rotate(45deg); justify-self: center;
  border: 2px solid var(--ink-3); background: var(--solid); border-radius: 2px;
}
.procp__step.is-done .procp__mk { background: var(--ok-fg); border-color: var(--ok-fg); }
.procp__step.is-next .procp__mk { border-color: var(--accent); }
.procp__step.is-late .procp__mk { border-color: var(--late-fg); background: var(--late-soft); }
.procp__step:not(.procp__step--hd) + .procp__step::before {
  content: ''; position: absolute; left: 8px; top: -6px; height: 12px; border-left: 1px solid var(--hair);
}
.procp__ptname {
  font: inherit; font-size: var(--t-sm); font-weight: 500; color: var(--ink); background: none;
  border: 1px solid transparent; border-radius: var(--radius-sm); padding: 0 var(--s-1); margin-left: calc(-1 * var(--s-1));
  min-width: 0; width: 100%;
}
.procp__ptname:hover:where([data-hover="mouse"] *):not(:disabled) { border-color: var(--border); }
.procp__ptname:focus { outline: none; border-color: var(--accent); background: var(--surface); }
.procp__ptname:disabled { color: var(--ink); }
.procp__step.is-late .procp__ptname { color: var(--late-fg); }
.procp__rule { font-size: var(--t-xs); color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.procp__rule.is-lock { color: var(--warn-fg); }
.procp__plan { display: inline-flex; align-items: center; gap: var(--s-1); }
.procp__approx, .procp__lock {
  width: 24px; height: 24px; display: inline-grid; place-items: center; padding: 0;
  border: 1px solid transparent; border-radius: var(--radius-sm); background: none; color: var(--text-faint);
  font: inherit; font-size: var(--t-md); cursor: pointer;
}
.procp__approx:hover:not(:disabled), .procp__lock:hover:not(:disabled) { background: var(--hover); color: var(--ink); }
.procp__approx:not(.is-on) { opacity: 0; }
.procp__step:hover .procp__approx, .procp__approx:focus-visible { opacity: 1; }
@media (hover: none) { .procp__approx:not(.is-on) { opacity: .6; } }
.procp__approx.is-on { color: var(--accent-fg); border-color: var(--accent-soft); background: var(--accent-soft); font-weight: 600; }
.procp__approx.is-inh { background: none; border-style: dashed; }
.procp__approx:disabled, .procp__lock:disabled { cursor: default; }
.procp__lock.is-on { color: var(--warn-fg); }
.procp__fact { display: flex; align-items: center; gap: var(--s-1); justify-content: flex-end; }
.procp__factwrap { display: inline-flex; align-items: center; gap: var(--s-1); position: relative; }
.procp__factbtn {
  height: 26px; padding: 0 var(--s-2); border: 1px dashed var(--border-strong); border-radius: var(--radius-sm);
  background: none; font: inherit; font-size: var(--t-xs); color: var(--text-dim); cursor: pointer; white-space: nowrap;
}
.procp__factbtn:hover { border-color: var(--accent); color: var(--accent-fg); }
.procp__factok { display: inline-flex; align-items: center; color: var(--ok-fg); }
.procp__dev { font-style: normal; font-size: var(--t-xs); color: var(--ink-3); font-variant-numeric: tabular-nums; }
.procp__dev.is-late { color: var(--late-fg); }
.procp .dateinput { height: 28px; padding: 0 var(--s-2); font-variant-numeric: tabular-nums; }
.procp .dateinput__clear { width: 22px; height: 22px; }
.procp__plan.is-approx .dateinput { border: 1px dashed var(--border-strong); background: none; color: var(--ink-2); }
.procp__del {
  width: 20px; height: 20px; padding: 0; border: 0; background: none; color: var(--text-faint);
  display: inline-grid; place-items: center; border-radius: var(--radius-sm); cursor: pointer; opacity: 0;
}
.procp__step:hover .procp__del, .procp__del:focus-visible { opacity: 1; }
.procp__del:hover { color: var(--late-fg); background: var(--late-soft); }
@media (hover: none) { .procp__del { opacity: 1; } }
.procp__newpt { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); padding: var(--s-2) 0 0 26px; }
.procp__newpt .input:first-child { flex: 1 1 180px; }
.procp__num { width: 72px; }
.procp .select--sm { min-width: 0; }

/* Оплаты */
.procp__pays { border: 1px solid var(--hair); border-radius: var(--radius-lg); overflow: hidden; }
.procp__payrow + .procp__payrow { border-top: 1px solid var(--hair); }
.procp__pay {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: var(--s-3);
  width: 100%; padding: var(--s-2) var(--s-3); background: none; border: 0; font: inherit; text-align: left; cursor: pointer; color: inherit;
}
.procp__pay:hover { background: var(--hover); }
.procp__payl { display: flex; flex-direction: column; min-width: 0; }
.procp__payl b { font-weight: 500; font-size: var(--t-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.procp__payl > span { font-size: var(--t-xs); color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.procp__paysum { font-size: var(--t-sm); font-weight: 500; font-variant-numeric: tabular-nums; white-space: nowrap; text-align: right; }
.procp__payer { display: none; font-size: var(--t-xs); color: var(--ink-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.procp--two .procp__pay { grid-template-columns: minmax(0, 1fr) auto 120px auto; }
.procp--two .procp__payer { display: block; }
.procp--two .procp__compact { display: none; }
.procp__payedit {
  display: flex; flex-direction: column; gap: var(--s-2); padding: var(--s-2) var(--s-3) var(--s-3);
  background: var(--well); border-top: 1px dashed var(--hair);
}
.procp__f { display: grid; grid-template-columns: 92px minmax(0, 1fr); align-items: center; gap: var(--s-2); font-size: var(--t-sm); }
.procp__f > span:first-child { color: var(--ink-3); font-size: var(--t-xs); }
.procp__fv { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1); min-width: 0; }
.procp__fv > .input:not(.procp__num):not(.procp__date) { flex: 1 1 160px; }
.procp__unit { width: auto; }
.procp__money { font-variant-numeric: tabular-nums; }
.procp__payedit .procp__money.procp__num { width: 120px; }
.procp__payact { display: flex; justify-content: flex-end; }
.procp__payfoot {
  display: flex; align-items: center; gap: var(--s-4); padding: var(--s-2) var(--s-3);
  border-top: 1px solid var(--hair); background: var(--well); font-size: var(--t-sm); font-variant-numeric: tabular-nums;
}
.procp__payfoot { flex-wrap: wrap; row-gap: var(--s-1); }
.procp__payfoot > span { white-space: nowrap; }
.procp__payfoot b { font-weight: 600; }
.procp__payfoot b.is-ok { color: var(--ok-fg); }
.procp__notes { width: 100%; min-height: 64px; border-color: transparent; background: var(--well); border-radius: var(--radius-lg); }
.procp__notes:focus { border-color: var(--accent); background: var(--solid); }

/* Свойства */
.procp__props { display: flex; flex-direction: column; gap: var(--s-3); }
.procp:not(.procp--two) .procp__props { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
.procp__cap {
  display: block; font-size: var(--t-2xs); text-transform: uppercase; letter-spacing: .06em; font-family: var(--mono);
  color: var(--text-faint); margin-bottom: var(--s-1);
}
.procp__v { display: flex; flex-direction: column; gap: var(--s-1); font-size: var(--t-sm); min-width: 0; }
.procp__v .input, .procp__v .select { width: 100%; }
.procp__link { display: inline-flex; align-items: center; gap: var(--s-1); color: var(--accent-fg); text-decoration: none; min-width: 0; }
.procp__link:hover { text-decoration: underline; }
.procp__unlink { align-self: flex-start; font-size: var(--t-xs); }
.procp__acts { display: flex; flex-wrap: wrap; gap: var(--s-1); margin-top: var(--s-4); padding-top: var(--s-3); border-top: 1px solid var(--hair); }
.procp--two .procp__acts { flex-direction: column; align-items: flex-start; }
@media (max-width: 760px) {
  .procp__head, .procp__main, .procp__side { padding-left: var(--s-4); padding-right: var(--s-4); }
}

/* ── Комплектация: шаблоны этапов (настройки компании и проекта, public/proc-shablony.js) ── */
.tplset { display: flex; flex-direction: column; gap: var(--s-3); align-items: flex-start; }
.tplset__default { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; width: 100%; }
.tplset__default .note { flex-basis: 100%; }
.tplset__list { display: flex; flex-direction: column; width: 100%; border-top: 1px solid var(--border); }
.tplset__row {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) 0; border-bottom: 1px solid var(--border);
}
.tplset__row.is-archived .tplset__main { opacity: .6; }
.tplset__main { flex: 1; min-width: 0; }
.tplset__name { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.tplset__chain { color: var(--text-dim); font-size: var(--t-sm); margin-top: var(--s-05); }
.tplset__lots { color: var(--text-faint); font-size: var(--t-xs); }
.tplset__acts { display: flex; gap: var(--s-1); flex-wrap: wrap; justify-content: flex-end; flex: none; }
.tplset__sub { font-weight: 600; margin-top: var(--s-2); }
.tplset__empty { padding: var(--s-2) 0; }
.tplset__editor {
  display: flex; flex-direction: column; gap: var(--s-2); align-items: flex-start;
  padding: var(--s-3); margin: var(--s-2) 0; border: 1px solid var(--border-strong);
  border-radius: var(--radius); background: var(--surface);
}
.tplset__edhead { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; width: 100%; }
.tplset__title { width: 260px; height: 32px; font-weight: 600; }
.tplset__legend { font-size: var(--t-xs); }
.tplset__points { display: flex; flex-direction: column; gap: var(--s-1); width: 100%; }
.tplset__point {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  padding: var(--s-1); border-radius: var(--radius-sm);
}
.tplset__point.is-bad { background: var(--late-soft); }
.tplset__num { width: 16px; text-align: right; color: var(--text-faint); font-size: var(--t-sm); flex: none; }
/* One row per point: compact fields of the same 30px height */
.tplset__point .input, .tplset__point .select { height: 30px; font-size: var(--t-sm); flex: none; }
.tplset__point .select { min-width: 0; padding: 0 var(--s-5) 0 var(--s-2); background-position: right var(--s-2) center; }
.tplset__point .input { padding: 0 var(--s-2); }
.tplset__pname { width: 160px; }
.tplset__kind { width: 100px; }
.tplset__from { width: 188px; }
.tplset__days { width: 60px; }
.tplset__unit { width: 96px; }
.tplset__seg { width: 124px; }
.tplset__dur, .tplset__rule { display: inline-flex; align-items: center; gap: var(--s-1); font-size: var(--t-sm); }
.tplset__dur .input { width: 56px; }
.tplset__rule[hidden], .tplset__rule [hidden] { display: none; }
.tplset__move { display: inline-flex; gap: 0; margin-left: auto; }
.tplset__errors { margin: 0; padding-left: var(--s-4); color: var(--late-fg); font-size: var(--t-sm); }
.tplset__errors[hidden] { display: none; }
.tplset__preview { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.tplset__preview input { width: 150px; }
.tplset__preview-text { font-size: var(--t-sm); color: var(--text); }
.tplset__edfoot { display: flex; gap: var(--s-2); }
