/*
  Тёмная тема по ТЗ §7.4: почти чёрный фон, мятно-зелёный акцент, крупная
  типографика, карточки со скруглениями. Одна палитра, без переключателя.

  Основа заложена для формы входа (Е7), экраны периода и графики добавлены
  в Т10 и Т11; окончательную доводку оформления и тёмной темы делает Т13.1,
  мобильную адаптацию — Т13.0 (снимки согласованы с владельцем 14.09, В9).

  Шрифты СИСТЕМНЫЕ: ни одного внешнего адреса в статике (Р13, К-137, П-33).
*/

:root {
  --bg: #0d0f0e;
  --card: #161a18;
  --line: #252b28;
  --text: #e8efe9;
  --muted: #8c9a91;
  --accent: #6ee7a8;
  --danger: #ff7b72;
  --radius: 14px;

  /* ==================================================================
     Ритм и иерархия (Э4, Р46, П-114, П-115)

     🔴 Отступы и размеры заголовков живут ОДНИМ местом, а не числами
     по месту — именно «числа по месту» и дали два замечания владельца
     18.09. Замер до правки, карточка заказчика при 1920:
     промежутки между блоками чередовались 34 / 30 px восемь раз подряд,
     а `H2` и `H3` были оба 15px/600 uppercase, то есть заголовок раздела
     неотличим ни от подзаголовка, ни от подписи колонки (14 px).

     Шкала кратна 2 и растёт примерно в полтора раза: соседние ступени
     различимы глазом, а не «почти одинаковы».
     ================================================================== */
  --space-1: 6px;
  --space-2: 10px;
  --space-3: 14px;
  --space-4: 20px;
  --space-5: 28px;
  --space-6: 40px;

  /* Две величины, которыми меряются ВСЕ вертикальные промежутки между
     блоками (П-115): раздел от раздела и блок от блока внутри раздела.
     Внутренний строго меньше межразделного — ровно вдвое. */
  --space-section: var(--space-5);
  --space-block: var(--space-3);

  /* Три уровня заголовка (П-114). Шаг между соседними — 4 и 3 px, и это
     не украшение: на неразличимости уровней стояло замечание 6 бэклога.
     Уровни различаются ещё и цветом с регистром, а не только размером:
     раздел — светлый и обычным регистром, подраздел — приглушённый,
     подпись поля или колонки — приглушённая и мельче всех. */
  --text-section: 20px;
  --text-subsection: 16px;
  --text-label: 13px;

  /* Высота закреплённой шапки (Э4, требование владельца 19.09). Величина
     нужна не для красоты: под шапкой липнет подтверждение правки, и на неё
     же отступают цели якорей — иначе строка, к которой вернула форма,
     окажется ПОД шапкой. Значения сняты замером: 66 px на рабочем экране,
     58 на среднем, 74 на узком (там шапка переносится на две строки). */
  --topbar-height: 66px;

  /* 🔴 Тёмная схема для ВСТРОЕННЫХ виджетов браузера: календарь у полей даты,
     раскрытый список у `select`, полосы прокрутки. Без неё браузер считает
     страницу светлой и рисует их белыми — на тёмном экране это выглядит
     чужой вставкой (найдено владельцем 17.09 на формах ставок и лимитов).
     Объявлено на `:root`, а не у отдельного селектора: правило относится
     ко всем нативным элементам сразу, и точечные копии разошлись бы —
     ровно это и случилось, когда `color-scheme` стояла только у формы
     периода, а новые поля дат Т19 остались светлыми. */
  color-scheme: dark;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

/* 🔴 Ширина страницы — по экрану, а не 1100 px «как принято».
   Причина замером, а не вкусом: на мониторе 1920 контейнер в 1100 оставлял
   по 410 px пустых полей С КАЖДОЙ стороны, а таблице периода нужно 1182 px —
   и она уезжала в горизонтальную прокрутку РЯДОМ с этой пустотой. Владелец
   18.09: «категорически неприемлема горизонтальная прокрутка».
   1440 — не предел экрана, а предел читаемости: дальше строка текста
   становится длиннее, чем глаз держит без потери строки. Таблица в него
   помещается с запасом 178 px. */
.shell {
  max-width: 1440px;
  margin: 0 auto;
  padding: 48px 20px;
}

/* 🔴 Экранам с широкими таблицами — своя мера (Э4, Р49). 1440 введено
   как предел читаемости ТЕКСТА, и для таблицы он не действует: у неё
   читают строку, а не абзац. Замер до правки при окне 1920: контейнер
   1440, таблицы 1400, по 240 px пустого с каждой стороны — владелец
   18.09: «да и таблицу можно расширить — полно места».
   Проза внутри ограничена 108ch правилом ниже и от расширения не растёт. */
.shell--wide { max-width: 1760px; }

/* 🔴 Ритм задаёт ОДНО правило, а не отступ у каждого блока (П-115).
   Промежуток ставится СВЕРХУ и только соседям: первый блок экрана
   лишнего отступа не получает, а порядок блоков в шаблоне можно менять,
   не пересчитывая отступы.

   Селектор опирается на `data-screen` — машинное имя корня экрана,
   которое есть у всех шести экранов и которое запрещено переименовывать
   (П-142). Карточки-экраны (вход, подтверждение, «показывать нечего»)
   исключены: у них внутри не разделы, а одна короткая форма, и
   межразделный интервал разорвал бы её на части. */
[data-screen]:not(.card) > * + * { margin-top: var(--space-section); }

/* Проза в широком контейнере не растягивается на всю ширину: у пояснений
   под таблицами своя мера, и она про чтение, а не про сетку. Таблиц,
   графиков и плиток это не касается — им ширина на пользу. */
.shell p.muted,
.shell .note {
  max-width: 108ch;
}

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 28px;
}

.card--narrow {
  max-width: 380px;
  margin: 10vh auto 0;
}

h1 {
  margin: 0 0 4px;
  font-size: 28px;
  letter-spacing: -0.01em;
}

.muted { color: var(--muted); margin: 0 0 20px; }

.error {
  color: var(--danger);
  background: rgba(255, 123, 114, 0.08);
  border: 1px solid rgba(255, 123, 114, 0.3);
  border-radius: 10px;
  padding: 10px 12px;
  margin: 0 0 16px;
}

.form { display: flex; flex-direction: column; gap: 14px; }

/* Пояснение под формой отделяется от кнопки заметным полем: без него текст
   читается как подпись к кнопке, а не как отдельное примечание (правка
   по замечанию владельца 17.09). У `.muted` собственный нижний отступ
   уже есть — добавляется только верхний. */
.form + .muted { margin-top: 22px; }

/* Правила лимита рядом с полями (П-109): не сноска мелким шрифтом, а
   отдельный блок — их читают в тот момент, когда смотрят на числа. */
.rules {
  border-top: 1px solid var(--line);
  margin-top: 26px;
  padding-top: 18px;
}

.rules__list { color: var(--muted); font-size: 14px; margin: 0; padding-left: 22px; }
.rules__list li { margin: 0 0 12px; }
.rules__list li:last-child { margin-bottom: 0; }
.rules__list b { color: var(--text); font-weight: 600; }

.field { display: flex; flex-direction: column; gap: 6px; }
/* Подпись поля (П-114, уровень 3): та же мера, что у подписи колонки
   таблицы — это один уровень, и разводить их незачем. */
.field span { color: var(--muted); font-size: var(--text-label); }

input[type="text"],
input[type="password"],
input[type="date"] {
  background: #0b0e0d;
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--text);
  font: inherit;
  padding: 11px 12px;
}

input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.button {
  background: var(--accent);
  /* Рамка ПРОЗРАЧНАЯ, а не отсутствующая: у `.button--ghost` она есть, и без
     неё две кнопки одного ряда отличались по высоте на 2 px (35 против 37 —
     замер снимком при сборке Т24). Соседние кнопки разной высоты читаются
     как разные по значимости, хотя они равны. */
  border: 1px solid transparent;
  border-radius: 10px;
  color: #06120c;
  cursor: pointer;
  font: inherit;
  font-weight: 600;
  padding: 11px 16px;
}

.button--ghost {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--text);
}

/* ==========================================================================
   Экран месяца (Т10.3). Тёмная тема продолжает палитру формы входа; свои
   классы, без библиотек — ни одного внешнего адреса (Р13, П-33).
   ========================================================================== */

/* 🔴 Шапка закреплена (требование владельца 19.09): на длинных экранах —
   папки 4 500 px, карточка заказчика 4 700 — переход к другому разделу
   означал прокрутку в самый верх и обратно.
   `z-index` выше, чем у подтверждения: шапка перекрывает его, а не наоборот,
   иначе плашка наезжала бы на меню. Фон непрозрачный по той же причине,
   по какой он непрозрачен у плашки: под ней проезжает содержимое. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  background: var(--card);
}

.topbar__brand {
  color: var(--text);
  font-weight: 700;
  letter-spacing: -0.01em;
  text-decoration: none;
}

.topbar__logout { display: flex; align-items: center; gap: 12px; margin: 0; }

.muted-inline { color: var(--muted); font-size: 14px; }

.button--small { font-size: 14px; padding: 7px 12px; }

/* Кнопка-ссылка не подчёркивается: подчёркнутая надпись внутри рамки
   читается как две разные вещи сразу. */
a.button { display: inline-block; text-decoration: none; }

/* Заголовок РАЗДЕЛА (П-114, уровень 1 из трёх). До Э4 он был
   15px/600 uppercase приглушённым — то есть выглядел ровно как подпись
   колонки таблицы (12px uppercase приглушённая), и страница читалась
   сплошным полотном: «глазу не за что зацепиться» (замечание 6).
   Теперь он светлый, обычным регистром и заметно крупнее всего, что
   вокруг, — кроме заголовка страницы (32 px). */
.section-title {
  font-size: var(--text-section);
  font-weight: 600;
  letter-spacing: -0.01em;
  text-transform: none;
  color: var(--text);
  margin: 0 0 var(--space-block);
}

/* Подзаголовок ВНУТРИ раздела (уровень 2): «Период с 24.02.2026»,
   «Как считается лимит», подписи графиков. От раздела отличается
   размером (−4 px) и цветом, от подписи поля — размером (+3 px).
   Регистр обычный: капс на этом уровне спутался бы с подписью колонки. */
.subsection-title {
  font-size: var(--text-subsection);
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
  margin: 0 0 var(--space-2);
}

.small { font-size: 13px; }

/* --- шапка месяца и переключатель --- */

.month__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}

.month__title h1 { margin: 0; font-size: 32px; }
.month__title .muted { margin: 6px 0 0; }

.month__switch { display: flex; gap: 8px; }

.months {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* Ряд занимает ВСЮ ширину: его левый и правый края совпадают с рядами выше
   (заголовок и поля периода) и ниже (карточки метрик) — замечание владельца
   17.09. Растягиваются сами кнопки, а не промежутки между ними: при переносе
   на вторую строку `space-between` оставил бы в последней строке дыры.
   `min-width: max-content` держит каждую кнопку не у́же её текста, поэтому
   названия месяцев не переносятся внутри кнопки. */
.months__item { flex: 1 1 auto; min-width: max-content; text-align: center; }

.months__item {
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted);
  font-size: 13px;
  padding: 5px 12px;
  text-decoration: none;
}

.months__item:hover { color: var(--text); border-color: var(--muted); }

.months__item--current {
  background: var(--accent);
  border-color: var(--accent);
  color: #06120c;
  font-weight: 600;
}

/* Полоса экрана периода (П5.1, 28.09.2026): пин «30 дней» и последние месяцы
   с данными — ОДНОЙ строкой во всю ширину. Сетка равных колонок, а не
   растягивание флекса: у флекса кнопка, перенесённая на вторую строку одна,
   растягивалась на всю ширину («Сентябрь 2026» отдельной строкой — замечание
   владельца 25.09, воспроизведено на 1024 px). Модификатор, а не правка
   `.months`: та же полоса соседних дней стоит в шапке экрана дня.

   Сервер отдаёт не больше шести месяцев (П-60); уже 1000 px видно три
   последних, на телефоне два — в историю смотрят редко (решение владельца
   28.09), а более ранние открываются выбором дат. Порог 1000, а не 900:
   на 901…1000 px в седьмую часть строки не помещается «Сентябрь 2026».
   Прячутся СТАРЫЕ месяцы: месяцы идут по возрастанию и стоят в конце
   полосы, поэтому `nth-last-child` отсчитывает от самого нового. */
.months--strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
}

.months--strip .months__item { min-width: 0; white-space: nowrap; }

@media (max-width: 1000px) {
  .months--strip .months__item--month:nth-last-child(n+4) { display: none; }
}

@media (max-width: 600px) {
  /* Три кнопки на телефоне — снова флекс с шириной по тексту: в равной
     трети строки на 320 px «Сентябрь 2026» не помещается (замер 28.09:
     91 px ячейки против 94 px текста). По тексту все три входят в строку
     и на 320 px. */
  .months--strip { display: flex; }
  .months--strip .months__item { min-width: max-content; padding: 5px 6px; }
  .months--strip .months__item--month:nth-last-child(n+3) { display: none; }
}

/* --- карточки шапки --- */

.metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 14px;
}

.metric {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px 20px;
}

.metric__label { color: var(--muted); font-size: 13px; }
.metric__value { font-size: 30px; font-weight: 700; letter-spacing: -0.02em; }
.metric__value--muted { color: var(--muted); font-size: 22px; font-weight: 600; }
.metric__note { color: var(--muted); font-size: 12px; line-height: 1.4; }

/* --- три группы (Р14) --- */

.groups__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px;
}

.groups__item {
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px 18px;
}

.groups__item[data-group="personal"] { border-left-color: #7aa2f7; }
.groups__item[data-group="unassigned"] { border-left-color: var(--muted); }

.groups__title { color: var(--muted); font-size: 13px; }
.groups__value { font-size: 22px; font-weight: 600; }
.groups__share { color: var(--muted); font-size: 13px; }

/* --- три крупнейших --- */

.tops__list {
  counter-reset: top;
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.tops__list li {
  align-items: baseline;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 10px;
  display: flex;
  gap: 12px;
  padding: 10px 16px;
}

.tops__list li::before {
  counter-increment: top;
  content: counter(top);
  color: var(--accent);
  font-weight: 700;
  min-width: 16px;
}

.tops__name { flex: 1; }
.tops__value { font-weight: 600; }
.tops__share { color: var(--muted); font-size: 13px; min-width: 64px; text-align: right; }

/* --- таблица проектов --- */

/* Блок-таблица отбивается от предыдущего блока сверху, а не только снизу:
   её заголовок («Проекты заказчика», «Проекты периода») стоял вплотную
   к тексту над ним и читался как продолжение чужого блока — замечание
   владельца 17.09. Первый блок на экране лишнего отступа не получает.
   🔴 С Э4 величину отступа задаёт общее правило ритма (`--space-section`),
   а не это место: собственные числа здесь и давали чередование 34 / 30. */

/* Узкий экран: таблица прокручивается сама, страница по горизонтали — нет. */
.table-scroll { overflow-x: auto; }

.table {
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
  min-width: 720px;
  width: 100%;
}

.table th,
.table td {
  border-bottom: 1px solid var(--line);
  padding: 10px 12px;
  text-align: left;
}

.table thead th {
  color: var(--muted);
  font-size: var(--text-label);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
}

.table tbody th { font-weight: 500; }
.table .num { text-align: right; white-space: nowrap; }
.table tbody tr:hover { background: rgba(110, 231, 168, 0.05); }

.table .row--unassigned th,
.table .row--unassigned td { color: var(--muted); }

.table tfoot td,
.table tfoot th {
  border-bottom: none;
  border-top: 2px solid var(--line);
  font-weight: 700;
  padding-top: 12px;
}

/* Средний экран (ноутбук, окно в половину монитора): таблице периода
   не хватает ширины, и она уходила бы в собственную прокрутку. Отпускаем
   перенос в шапке и сжимаем отступы — это возвращает около 190 px и держит
   таблицу целой примерно до 1000 px. Ниже её всё равно ждёт карточная
   раскладка (900 px), поэтому дальше сжимать незачем.
   Заголовки при этом становятся в две строки — это читается, а горизонтальная
   прокрутка нет (замер 18.09: таблице нужно 1182 px при 1045 доступных). */
/* 🔴 Верхняя граница 1359, а не 1279 (правка Э4, замер при приёмке партии 1):
   на 1280 таблице периода нужно 1303 px при 1225 доступных, и она уходила
   в собственную прокрутку — 65 px ещё до Э4, 78 после того, как подпись
   колонки выросла с 12 до 13 px вместе с уровнями заголовков (П-114).
   Со сжатием влезает целиком на всём диапазоне: замер 1360 / 1300 / 1280 / 1200
   даёт превышение 0. Порог выбран по факту: на 1360 таблица помещается и так. */
@media (max-width: 1359px) and (min-width: 901px) {
  /* `.num` (две ячейки правила) перебивает `thead th` по специфичности,
     поэтому перенос снимается ИМЕННО с `th.num` — иначе правило молча
     не действует, а замер показывает прежнюю ширину. */
  .table--period thead th,
  .table--period thead th.num { white-space: normal; }
  .table--period th,
  .table--period td { padding-left: 6px; padding-right: 6px; }
}

/* --- «показывать нечего» --- */

.empty { margin-top: 8px; }
.empty h1, .empty h2 { margin: 0 0 8px; font-size: 22px; }

/* --- выбор периода: две даты и кнопка (Р21) --- */

.period-form {
  align-items: end;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.period-form__field { display: flex; align-items: center; gap: 6px; }
.period-form__field span { color: var(--muted); font-size: 13px; }

.period-form input[type="date"] {
  /* Общий вид поля даты — выше, у `input[type="date"]`; здесь только
     размер: в строке периода поле мельче, чем в формах справочников. */
  font-size: 14px;
  padding: 7px 10px;
}

.period-form input[type="date"]:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

/* --- графики периода (Т11) --- */

.charts {
  display: grid;
  gap: 24px;
}

.chart {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  margin: 0;
  padding: 20px 20px 16px;
  /* 🔴 Без `min-width: 0` элемент сетки не может стать уже своего
     содержимого (по умолчанию `min-width: auto`), а содержимое здесь —
     холст, которому Chart.js проставляет ширину в пикселях. Из-за этого
     при СУЖЕНИИ окна холст держал прежние 1018 px, родитель не сжимался,
     и страница уезжала вбок: 1623 px против 1425 (замер 15.09 сужением
     контейнера). На первой загрузке узкого экрана дефекта не видно —
     холст сразу создаётся по месту, поэтому ловится он только сменой
     размера, то есть поворотом телефона. */
  min-width: 0;
}

.chart .subsection-title { margin-top: 0; }

/* Холсту нужна ЯВНАЯ высота: Chart.js работает с `maintainAspectRatio:
   false`, а без размера у родителя рисует в нулевой прямоугольник.
   У графика проектов высоту доуточняет скрипт — строк бывает и двадцать,
   и одна, потому что проекты не сворачиваются в «Прочее». */
.chart__canvas { position: relative; width: 100%; }
.chart__canvas--projects { height: 320px; }
.chart__canvas--days { height: 340px; }

.chart .muted.small { margin: 12px 0 0; }

/* Строка «Часы на графиках» (Т45, Р74): одна пара кнопок над ОБОИМИ
   графиками и разбором дня. Стоит в сетке `.charts` отдельной строкой,
   поэтому у переключателя снят свой внешний отступ — промежуток даёт сетка.
   Подпись под кнопками занимает строку целиком: на телефоне кнопки
   и название переносятся вместе, а не разъезжаются по краям. */
.charts__hours { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }
.charts__hours .switch { margin: 0; }
.charts__hours-label { color: var(--text); font-weight: 600; }
.charts__hours .muted.small { flex-basis: 100%; margin: 0; }

/* Перечень дней — источник сверки П-37 и запасной вид страницы, когда
   скрипт не отработал. Свёрнут в `details`, а не спрятан насовсем:
   `display: none` не читается ни глазами, ни экранным диктором, а
   развёрнутые 203 строки занимают пол-экрана на длинном интервале. */
.chart__numbers {
  border-top: 1px solid var(--line);
  margin-top: 14px;
  padding-top: 10px;
}

.chart__numbers > summary {
  color: var(--muted);
  cursor: pointer;
  font-size: 13px;
  list-style-position: inside;
}

.chart__numbers > summary:hover { color: var(--text); }

.chart__data {
  color: var(--muted);
  display: flex;
  flex-wrap: wrap;
  font-size: 12px;
  gap: 4px 14px;
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
}

.chart__data li { display: flex; gap: 5px; white-space: nowrap; }
.chart__data-date { color: var(--text); }

/* --- шапка: пункты меню (Т12) ------------------------------------------- */

.topbar__nav { display: flex; gap: 16px; margin-left: 4px; flex: 1; }

.topbar__nav a {
  color: var(--muted);
  text-decoration: none;
  font-size: 14px;
  border-bottom: 1px solid transparent;
}

.topbar__nav a:hover { color: var(--text); border-bottom-color: var(--muted); }

/* --- экран дня и «Не распределено» (Т12.1, Т12.2) ------------------------ */

/* Ссылки внутри таблиц не подчёркиваются постоянно: в столбце цифр
   подчёркивание спорит с выравниванием по правому краю. */
.table a { color: inherit; text-decoration: none; border-bottom: 1px dotted var(--muted); }
.table a:hover { color: var(--accent); border-bottom-color: var(--accent); }

.badge {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-size: 11px;
  line-height: 1.6;
  white-space: nowrap;
  vertical-align: middle;
}

.badge--warn { color: #e3b341; border-color: rgba(227, 179, 65, 0.4); }
.badge--danger { color: var(--danger); border-color: rgba(255, 123, 114, 0.45); }

/* --- состояние сбора (Т12.3) --------------------------------------------- */

.collection__rows {
  display: grid;
  /* `minmax(0, 1fr)`, а не `1fr`: элемент сетки по умолчанию не может стать
     уже своего содержимого, и длинная строка («последний приём …») распирала
     бы страницу вбок на узком экране — та же грабля, что с холстом графика
     в Т11. */
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: 12px;
}

.collection__row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  padding: 14px 16px;
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line);
  border-radius: var(--radius);
}

.collection__row--stale { border-left-color: var(--danger); }

.collection__title { color: var(--muted); font-size: 13px; }
.collection__value { font-size: 20px; font-weight: 600; }
.collection__value--muted { color: var(--muted); font-size: 18px; }
.collection__note { color: var(--muted); font-size: 12px; line-height: 1.4; }
.collection__row .badge { align-self: flex-start; margin-top: 4px; }

.collection__days {
  margin-top: 14px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 16px;
}

.collection__days > summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 13px;
}

.collection__days > summary:hover { color: var(--text); }

.collection__days-list {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr));
  gap: 6px;
  font-size: 13px;
}

.collection__days-list li { display: flex; gap: 8px; align-items: baseline; min-width: 0; }
.collection__days-list a { color: var(--text); text-decoration: none; border-bottom: 1px dotted var(--muted); }
.collection__days-list a:hover { color: var(--accent); }
.collection__flag { color: var(--muted); }
.collection__flag--missing { color: var(--danger); }
.collection__flag--partial { color: #e3b341; }

/* ==========================================================================
   Телефон (Т13.0, П-63, К-182). Одна сетка сразу для всех четырёх экранов:
   вход, период, день, «Не распределено» — адаптировать их по отдельности
   значило бы трижды писать одно и то же и трижды разойтись.

   Порог 900 px, а не 390, и он выбран ЗАМЕРОМ, а не на глаз: между телефоном
   и рабочим окном лежит планшет в портрете (768) и половина экрана ноутбука,
   и там таблицы возятся пальцем ровно так же — проба 16.09 на 768 px дала
   у таблицы отрезков 191 px прокрутки внутри коробки. Под порогом таблица
   превращается в карточки, над ним остаётся таблицей. Замер 16.09 на 390 px
   ДО правки: страница вбок не прокручивалась (375 = 375), но таблица периода
   занимала 890 px в коробке 335, таблица отрезков — 904, то есть числа
   приходилось возить пальцем; до таблицы месяца было 3278 px прокрутки.

   🔴 Проверять эти правила надо СМЕНОЙ РАЗМЕРА окна, а не только первой
   загрузкой узкого: холст Chart.js получает ширину в пикселях, и дефект
   «элемент сетки не сжимается ниже содержимого» на первой загрузке
   не виден вовсе (грабля Т11, `min-width: 0` у `.chart`).
   ========================================================================== */

/* На узком экране шапка переносится на две строки (замер: 74 px при 320),
   и подтверждение под ней обязано это учитывать. Порог 360, а не 375:
   на 375 шапка ещё в одну строку. */
@media (max-width: 360px) {
  :root { --topbar-height: 74px; }
}

@media (max-width: 900px) {

  /* 🔴 Ритм на телефоне теснее, и задаётся он теми же ДВУМЯ переменными
     (Э4, П-115): на 375 px межразделные 28 px съедали бы экран, а править
     полтора десятка правил по месту значило бы завести второй ритм,
     который однажды разойдётся с первым. */
  :root {
    --space-section: 20px;
    --space-block: 12px;
    /* Шапка здесь компактнее: свой `padding` у `.topbar` ниже по файлу. */
    --topbar-height: 58px;
  }

  /* --- общий воздух: на телефоне 48 px сверху — это четверть экрана --- */

  .shell { padding: 20px 14px 32px; }

  .card { padding: 20px 16px; }
  .card--narrow { margin-top: 6vh; }

  h1 { font-size: 24px; }
  .month__title h1 { font-size: 24px; }

  /* --- шапка: логин уводим, он не помогает выбирать действие --- */

  /* 🔴 Шапка переносится на вторую строку: с Э3 в ней три ссылки вместо
     одной, и на 375 px кнопка «Выйти» уезжала за край экрана — поймано
     снимком на телефонной ширине, а не чтением стилей. */
  .topbar { padding: 10px 14px; gap: 8px 10px; flex-wrap: wrap; }
  .topbar__nav { gap: 12px; margin-left: 0; flex-wrap: wrap; }
  .topbar__nav a { font-size: 13px; }
  .topbar__logout .muted-inline { display: none; }

  /* --- шапка периода: форма дат переносится под заголовок --- */

  .month__head { gap: 12px; }
  .period-form { gap: 8px; width: 100%; }
  .period-form__field { flex: 1 1 130px; }
  .period-form input[type="date"] { width: 100%; }
  .months { gap: 6px; }

  /* --- карточки шапки: значение крупное, пояснение остаётся (И-7) --- */

  .metrics { gap: 10px; grid-template-columns: 1fr; }
  .metric { padding: 14px 16px; gap: 4px; }
  .metric__value { font-size: 24px; }
  .metric__value--muted { font-size: 18px; }
  .metric__note { font-size: 11px; line-height: 1.35; }

  /* Группа на телефоне — строка, а не карточка в столбик: три карточки
     по 110 px занимали треть экрана, ничего к числам не добавляя. */
  .groups__row { grid-template-columns: 1fr; gap: 8px; }

  .groups__item {
    align-items: baseline;
    display: grid;
    grid-template-columns: 1fr auto;
    column-gap: 10px;
    padding: 10px 14px;
  }

  .groups__title { grid-row: 1; }
  .groups__value { font-size: 18px; grid-column: 2; grid-row: 1; }
  .groups__share { grid-column: 2; grid-row: 2; text-align: right; }

  .tops__list li { padding: 8px 12px; gap: 8px; }
  .tops__share { min-width: 52px; }

  /* --- графики: высота под экран, в ландшафте столбцы не должны быть выше него --- */

  .charts { gap: 16px; }
  .chart { padding: 14px 12px 12px; }
  .chart__canvas--projects { height: 260px; }
  .chart__canvas--days { height: 260px; }

  .collection__row { padding: 12px 14px; }
  .collection__value { font-size: 18px; }

  /* --- таблицы карточками ------------------------------------------------
     Числа перестают ездить вбок: строка таблицы становится карточкой,
     а подпись колонки берётся из `data-label` шаблона. Заголовок таблицы
     при этом не нужен — он повторялся бы в каждой карточке.

     `display: block` на элементах таблицы меняет только раскладку: DOM,
     а с ним и весь контракт разметки (`data-*` на `tr` и на корне), остаётся
     прежним — сверка П-26 и П-28 идёт по атрибутам, а не по виду.
     ---------------------------------------------------------------------- */

  .table-scroll { overflow-x: visible; }

  .table { display: block; min-width: 0; width: 100%; }
  .table thead { display: none; }
  .table tbody, .table tfoot { display: block; }

  /* Колонок в карточке столько, сколько влезает: на 390 px это две,
     на планшете — четыре-пять. Фиксированные две оставляли бы на широком
     краю порога половину карточки пустой. */
  .table tbody tr,
  .table tfoot tr {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 4px 12px;
    padding: 12px 2px;
    border-bottom: 1px solid var(--line);
  }

  .table tfoot tr { border-bottom: none; border-top: 2px solid var(--line); }

  .table tbody th[scope="row"],
  .table tfoot th[scope="row"] {
    border: none;
    font-size: 15px;
    font-weight: 600;
    grid-column: 1 / -1;
    padding: 0;
  }

  .table tbody td,
  .table tfoot td {
    border: none;
    display: block;
    font-size: 14px;
    padding: 0;
  }

  /* 🔴 Ни одна ячейка карточки не имеет права быть шире самой карточки.
     Правило общее для `th` и `td`, а не для названного места: элемент сетки
     по умолчанию не сжимается ниже содержимого (`min-width: auto`), а длинное
     значение без пробелов не переносится вовсе — и то и другое возвращает
     боковую прокрутку страницы, то есть ломает П-63.
     Замер 16.09 на `/unassigned` при 390 px ДО этого правила: имя папки
     `kortex_procurement_order_very_long_folder_name_2026` давало 25 px
     прокрутки, сплошная строка без разделителей — 63 px. Дефисы при этом
     переносились сами, поэтому на обычных папках дефект не виден
     (найдено ревью Codex, воспроизведено пробой). */
  .table tbody th[scope="row"],
  .table tfoot th[scope="row"],
  .table tbody td,
  .table tfoot td {
    min-width: 0;
    overflow-wrap: anywhere;
  }

  /* Подпись величины обязательна: без неё в карточке остаются голые
     числа, и «8 ч 43 м» неотличимо от «к оплате» (И-7). */
  .table td[data-label]::before {
    color: var(--muted);
    content: attr(data-label);
    display: block;
    font-size: 11px;
    letter-spacing: 0.03em;
    text-transform: uppercase;
  }

  /* Числа в карточке выравниваются по левому краю: правый край здесь
     не общий для строк, и выравнивание по нему ничего не даёт. */
  .table .num { text-align: left; white-space: normal; }

  /* Заказчик — на всю ширину и без подписи колонки: названия вроде
     «Не распределено по заказчикам (Э3)» в половине карточки рвутся
     на четыре строки, а подпись «ЗАКАЗЧИК» повторялась бы у каждой
     из двадцати карточек, ничего не объясняя — под названием проекта
     заказчик читается и так. */
  .table td[data-label="Заказчик"] {
    color: var(--muted);
    font-size: 13px;
    grid-column: 1 / -1;
    margin-top: -2px;
  }

  .table td[data-label="Заказчик"]::before { content: none; }

  /* Пустая ячейка подвала не должна занимать место в карточке. */
  .table td:empty { display: none; }

  .table tbody tr:hover { background: none; }

  /* --- карточка отрезка (экран дня) --------------------------------------
     Здесь подписи колонок не нужны: «09:15 → 10:03» и «48 м» читаются сами,
     а семь подписей на отрезок дали бы 66 карточек по семь строк. Поэтому
     ячейки раскладываются ПО МЕСТУ, и раскладка привязана к порядку колонок
     в `day.html`: начало, конец, проект, папка, инструмент, сессия, время.
     Порядок меняется — меняется и этот блок (соседство файлов намеренное).
     ---------------------------------------------------------------------- */

  .table[data-table="segments"] tbody tr {
    grid-template-columns: auto auto 1fr;
    column-gap: 8px;
    row-gap: 2px;
  }

  .table[data-table="segments"] tbody th[scope="row"] { grid-area: 1 / 1 / 2 / 4; }
  .table[data-table="segments"] tbody td:nth-child(1) { grid-area: 2 / 1 / 3 / 2; }
  .table[data-table="segments"] tbody td:nth-child(2) { grid-area: 2 / 2 / 3 / 3; }
  .table[data-table="segments"] tbody td:nth-child(4) { grid-area: 3 / 1 / 4 / 4; }
  .table[data-table="segments"] tbody td:nth-child(5) { grid-area: 4 / 1 / 5 / 2; }
  .table[data-table="segments"] tbody td:nth-child(6) { grid-area: 4 / 2 / 5 / 4; text-align: right; }
  .table[data-table="segments"] tbody td:nth-child(7) { grid-area: 2 / 3 / 3 / 4; text-align: right; }

  .table[data-table="segments"] tbody td:nth-child(1)::after {
    color: var(--muted);
    content: " →";
  }

  .table[data-table="segments"] tbody td:nth-child(4),
  .table[data-table="segments"] tbody td:nth-child(5),
  .table[data-table="segments"] tbody td:nth-child(6) {
    color: var(--muted);
    font-size: 13px;
    overflow-wrap: anywhere;
  }

  /* Заказчику колонка «Папка» не рендерится (Т40.7, П-179), и ячейки после
     неё сдвинуты на одну позицию: инструмент — 4-я, сессия — 5-я, время —
     6-я. Без этой поправки длительность уезжала вниз серой мелкой строкой,
     сессия сжималась в треть ширины, а строка под папку стояла пустой
     (замер 25.09 на 375 px). Разметку не трогаем — поправка только по роли. */
  [data-viewer-role="client"] .table[data-table="segments"] tbody td:nth-child(4) { grid-area: 4 / 1 / 5 / 2; }
  [data-viewer-role="client"] .table[data-table="segments"] tbody td:nth-child(5) { grid-area: 4 / 2 / 5 / 4; text-align: right; }
  [data-viewer-role="client"] .table[data-table="segments"] tbody td:nth-child(6) {
    color: inherit;
    /* Размер обычной ячейки карточки — из общего правила `.table tbody td`
       выше (14 px); `inherit` дал бы размер строки, 16 px (замер 25.09). */
    font-size: 14px;
    grid-area: 2 / 3 / 3 / 4;
    text-align: right;
  }
}

/* ------------------------------------------------------------------ */
/* Справочники (Э3, Т18): формы правки прямо в таблице                 */
/* ------------------------------------------------------------------ */

/* 🔴 Подтверждение ЛИПКОЕ (Э4, Р48, П-128). Якорь возврата сделан 18.09,
   и он же обнажил остаток: человек правит слагаемое в середине длинной
   карточки, возвращается на своё место — а полоса «Слагаемое лимита
   изменено» осталась в начале страницы, за экраном. Связи между своим
   нажатием и подтверждением он не видит вовсе.
   Фон непрозрачный: под плашкой проезжает содержимое страницы. */
.notice-done {
  margin: 0 0 20px;
  padding: 10px 14px;
  border: 1px solid rgba(110, 231, 168, 0.4);
  border-left-width: 3px;
  border-radius: 8px;
  color: var(--text);
  background: #16241d;
}

/* 🔴 Липкое — ТОЛЬКО подтверждение верхнего уровня, прямой ребёнок экрана.
   Тот же класс носит вложенная плашка внутри сводки («Предыдущий период
   лимита закрыт формой»), и сделав липкими обе, я получил бы два элемента
   с одинаковым `top` и `z-index`: при прокрутке сводки вложенная плашка
   закрывала бы основную вместе с обязательной ссылкой на сводку (П-128).
   Найдено ревью Codex по коду партии 1. */
[data-screen] > .notice-done {
  position: sticky;
  top: var(--topbar-height);
  z-index: 5;
}

/* Ссылка от подтверждения к сводке «до/после» (П-128). Сводка остаётся
   наверху блоком — она большая, и место ей там, — а плашка ведёт к ней. */
.notice-done__link { color: var(--accent); margin-left: 8px; white-space: nowrap; }

/* Кнопка, которой нечего сохранять (Т26, П-124). Гасит её ТОЛЬКО скрипт:
   в разметке кнопка приходит активной (И-32). `disabled` браузер рисует
   по-своему и по-разному, поэтому вид задан явно — иначе «приглушена»
   означало бы разное в разных браузерах. */
.button--idle,
.button:disabled {
  background: #1d2a24;
  border-color: var(--line);
  color: var(--muted);
  cursor: default;
}

.button--ghost:disabled { background: transparent; color: var(--muted); }

.tag {
  margin-left: 8px;
  padding: 2px 7px;
  border: 1px solid var(--muted);
  border-radius: 999px;
  color: var(--muted);
  font-size: 12px;
  white-space: nowrap;
}

/* 🔴 Поля выравниваются по ВЕРХУ, а не по низу (правка 19.09 по замечанию
   владельца: «поля лесенкой»). `align-items: end` прижимал содержимое ячейки
   к нижнему краю, и поля расходились по вертикали ровно на высоту того, что
   под ними: у «Папки на компьютере» подсказка в три строки, у «Названия
   проекта» — в одну, у остальных её нет вовсе. Замер до правки: разброс
   верхних краёв полей одной формы — 56 px.

   ⚠️ Моя проверка этого не видела: К-260 меряет, совпадает ли ЛЕВЫЙ край
   подписи с левым краем поля, то есть горизонталь. Вертикаль не мерил никто,
   и дефект нашёл владелец на снимке. */
.form--grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px;
  align-items: start;
}

/* Подписи и поля стоят строка в строку даже тогда, когда подпись переносится
   на две строки, а подсказки под полями разной высоты: три ряда сетки —
   подпись, поле, подсказка — общие для всех ячеек строки.
   Через `@supports`, потому что это УЛУЧШЕНИЕ: без него работает
   выравнивание по верху выше, и лесенки всё равно нет. */
@supports (grid-template-rows: subgrid) {
  .form--grid > .field {
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span 3;
    row-gap: var(--space-1);
  }

  /* Ряд кнопок подписи и подсказки не имеет — он занимает свою строку
     целиком и в общую сетку рядов не встраивается. */
  .form--grid > .field--actions {
    display: flex;
    grid-row: auto;
  }

  /* 🔴 Кнопка-одиночка встаёт СЛЕДУЮЩЕЙ КОЛОНКОЙ после последнего поля
     (замечание владельца 20.09: «почему Сохранить внизу, хотя справа явно
     есть место?»). Замер до правки на 1440: поля заняли шесть ячеек
     из десяти, кнопка ушла отдельной строкой, справа пустовало 959 px,
     форма была 284 px высотой.

     Берёт те же три ряда подсетки, что и поле рядом, а сама кнопка встаёт
     во ВТОРОЙ ряд — тот, где стоят поля. Без этого она оказывалась
     на уровне ПОДПИСИ соседа и висела над его полем (проверено снимком,
     числа этого не показали: по низу ячейки всё сходилось). */
  .form--grid > .field--actions--inline {
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span 3;
  }

  .form--grid > .field--actions--inline > * {
    align-self: center;
    grid-row: 2;
  }
}

/* 🔴 Поле не вылезает за свою ячейку. Элемент сетки по умолчанию не может
   стать уже своего содержимого (`min-width: auto`), а содержимое `select` —
   самый длинный вариант списка: «Не распределено по заказчикам · …».
   Замер до правки: ячейка 205 px, список 287 — он налезал на соседнее поле
   на 82 px. Это ТРЕТЬЕ появление той же грабли в этом файле (первое — холст
   графика в Т11, второе — строка состояния сбора в Т12), поэтому правило
   стоит на всех полях сетки сразу, а не у названного места. */
.form--grid .field > input,
.form--grid .field > select {
  min-width: 0;
  max-width: 100%;
}

.form--grid .field--wide { grid-column: 1 / -1; }

/* Поле шире соседей, но не во всю строку: описание слагаемого и название
   проекта длиннее даты и ставки, а растянутые на 1620 px под слово «Работы»
   они читаются как ошибка вёрстки (замер снимком при сборке Т24).

   🔴 `span 2` действует ТОЛЬКО там, где колонок и правда две: на 375 px
   сетка даёт одну, и требование двух распирало страницу вбок на 98 px —
   то есть возвращало горизонтальную прокрутку, запрещённую П-119.
   Поймано замером на четырёх ширинах, а не на одной: на 1920, 1440 и 1280
   дефекта не видно вовсе. */
@media (min-width: 640px) {
  .form--grid .field--x2 { grid-column: span 2; }
}
/* Названия работ в таблице дня (Т32). Список, а не строка через запятую:
   у каждой работы своё время, и склеенные в строку они перестают читаться
   как отдельные дела. */
/* Отступ между работами больше прежних 2 px (Э8, Р112): хвост длинного описания
   иначе сливается со следующим заголовком. */
.works { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }

.works__item {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
}

.works__title { color: var(--text); }

/* Подпись по ТИПУ прогона — не то же, что название, которое придумал
   инструмент: человек должен видеть разницу, не вчитываясь. */
.works__title--kind { color: var(--muted); font-style: italic; }
.works__kind { color: var(--muted); font-size: var(--text-label); }
.works__time { color: var(--muted); font-size: var(--text-label); white-space: nowrap; }
/* «Подробнее» ручной записи (Э7, Р99) — строкой под названием: во флекс-
   строке элемента он занимает всю ширину и уходит на свою строку. */
.works__desc {
  color: var(--muted);
  display: block;
  flex-basis: 100%;
  font-size: var(--text-label);
  overflow-wrap: anywhere;
  white-space: pre-line;
}
/* Описание работы (Э8, Р112, вид Б): название описания — заголовком, текст —
   строкой `works__desc` / `pwork__desc`, а прежнее название сессии — мелкой
   приглушённой строкой под ними, только владельцу: по нему он находит сессию
   у себя в инструменте. У прогона прежнее название — подпись вида, курсивом. */
.works__session, .pwork__session {
  color: var(--muted);
  display: block;
  font-size: 12px;
  margin-top: 2px;
  overflow-wrap: anywhere;
}
.works__session { flex-basis: 100%; }
.works__session--kind, .pwork__session--kind { font-style: italic; }
/* «Изменить» и «Удалить» у ручной записи в «Отрезках» (Э7, П-299): две
   ссылки одного веса; удаление — форма (запись идёт методом POST), но
   выглядит ссылкой, а не кнопкой: шаг подтверждения всё равно впереди. */
.manual__row-actions { display: inline-flex; flex-wrap: wrap; gap: 10px; margin-left: 8px; font-size: var(--text-label); }
.manual__row-delete { display: inline; margin: 0; }
.link-button {
  background: none;
  border: 0;
  color: var(--accent);
  cursor: pointer;
  font: inherit;
  padding: 0;
  text-decoration: underline;
}
.link-button:hover { color: var(--text); }

/* Группа флажков в форме-сетке: проекты заказчика у задачи (Т28).

   🔴 `flex-direction: row` у самого флажка обязателен: базовый `.field`
   ставит КОЛОНКУ (подпись над полем), и без сброса квадратик встал бы
   над своей подписью. Та же грабля уже ловилась в Э4 трижды —
   у `.form--row`, у `.field--actions` и здесь. */
.checks {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-2);
}

.check {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  padding: 4px 10px 4px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
}

.check input { margin: 0; }
.check span { color: var(--text); font-size: var(--text-label); }

.form--grid .button { justify-self: start; }

/* Кнопки формы — своя ячейка сетки, а не поле: у них нет подписи, и по низу
   они обязаны стоять на одной линии с полями (`align-items: end` у сетки). */
.field--actions {
  display: flex;
  /* 🔴 `flex-direction: row` обязателен: базовый `.field` ставит КОЛОНКУ
     (подпись над полем), и без сброса кнопки встают друг под другом.
     Ровно та же грабля уже описана выше у `.form--row`, и поймана она
     снова снимком, а не чтением стилей. */
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  /* 🔴 Своей строкой сетки, а не колонкой: в колонку шириной 225 px две
     кнопки не влезают и встают друг под другом — поймано снимком, а не
     чтением стилей. Формы создания в этом же файле раскладываются так же. */
  grid-column: 1 / -1;
}

/* 🔴 Форма с ОДНОЙ кнопкой ставит её соседней колонкой, а не своей строкой
   (замечание владельца 20.09: «почему Сохранить внизу, хотя справа явно есть
   место?»). Довод про две кнопки выше остаётся в силе — он про две; одна
   кнопка шириной 96 px в колонку 225 px влезает с запасом, а лишняя строка
   удлиняла форму на 64 px и оставляла справа 959 px пустоты (замер на 1440).
   Модификатор ставится в шаблоне явно, потому что число кнопок известно
   только там. */
.field--actions--inline { grid-column: auto; }

/* Пояснение под полем: чем оно отличается от соседнего и чего стоит ошибка.
   Заведено для пары «папка / название проекта» — пункт 8 бэклога: два
   одинаковых текстовых поля подряд, и различить их было нечем. */
.field__hint {
  color: var(--muted);
  font-size: 12px;
  line-height: 1.35;
}

/* ------------------------------------------------------------------ */
/* Список записей со своей формой правки (Э4, Т24, Р45 п.2)            */
/*                                                                     */
/* 🔴 Здесь были ТАБЛИЦЫ, и они были фикцией: шапка объявляла столбцы,  */
/* а строка была одной ячейкой `colspan` с flex внутри, поэтому         */
/* заголовки и поля выкладывались разными механизмами и совпасть        */
/* не могли в принципе (пункт 3 бэклога, П-118). Запись — это форма,    */
/* и выглядит она как форма: подпись над каждым полем, равные колонки.  */
/* ------------------------------------------------------------------ */

.records {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.record {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-4);
}

/* Форма ЗАВЕДЕНИЯ новой записи стоит в том же списке и тем же блоком:
   она делает то же самое, и разный вид у неё означал бы разный смысл. */
.record--new { display: grid; }

/* Посчитанная величина (вклад слагаемого в часах) — не поле формы, поэтому
   она отдельной строкой под полями и подписана словом, а не столбцом,
   которого больше нет. */
.record__note {
  grid-column: 1 / -1;
  margin: 0;
  color: var(--muted);
  font-size: 13px;
}

/* Строчная форма правки: поля в одну линию, переносятся на узком экране.
   🔴 `flex-direction: row` обязателен: базовый `.form` ставит колонку,
   и без сброса поля выстраиваются вертикально, а `flex-basis` начинает
   задавать ВЫСОТУ — поймано снимком экрана, а не чтением стилей. */
.form--row {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

.form--row input,
.form--row select { flex: 1 1 140px; min-width: 120px; }

/* Строка данных и её форма — ОДИН блок, и линии обязаны это показывать.
   Между ними линии нет вовсе, а блок от блока отделяет линия потолще.
   Поля при этом не прилипают к границе: отступ сверху даёт воздух, ради
   которого правило и заведено (замечание владельца 18.09 по экрану
   проектов — там этих правил не было, они висели на `.table--bind`). */
.table--forms .row--form td { padding-top: 6px; border-top: none; }

.table--forms tbody tr:not(.row--form) > th,
.table--forms tbody tr:not(.row--form) > td { border-bottom: none; }

.table--forms .row--form > td { border-bottom: 2px solid #313a35; }

/* Подсветка при наведении — на весь блок, а не на половину: иначе строка
   и её форма подсвечиваются порознь и снова читаются как разные. */
.table--forms tbody tr:not(.row--form):hover,
.table--forms tbody tr:not(.row--form):hover + .row--form,
.table--forms .row--form:hover { background: rgba(110, 231, 168, 0.05); }

/* Задачи заказчика в строке проекта (Т43, Р67; макет `.claude/mockups/p56`,
   вариант Б, принят владельцем 25.09). Колонка держит «идентификатор +
   название» и потому самая широкая: на компьютере длинные названия задач
   иначе рвутся на три строки при пустых числовых колонках рядом. */
.table--forms th.col-tasks { width: 42%; }
.task-list { display: flex; flex-direction: column; gap: 6px; list-style: none; margin: 0; padding: 0; }
.task-list__item { align-items: baseline; display: flex; flex-wrap: wrap; gap: 2px 8px; }
.task-list__id { color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
.task-list__none { color: var(--muted); }

/* Формы задач — отдельные узлы под формой проекта, в свёрнутом блоке.
   Свёрнут по умолчанию: раскрытые формы удлиняли страницу на 35 % на 1280 px
   и на 38 % на телефоне, свёрнутые — на 14 % и 10 % (замер макета, Т43.1).
   Раскрывает его сам браузер — скрипт не нужен (И-32). */
.form--task { border-top: 1px dashed var(--line); margin-top: var(--space-3); padding-top: var(--space-3); }
.form--task > .form__caption { color: var(--muted); font-size: var(--text-label); font-weight: 600;
  grid-column: 1 / -1; margin: 0; }
.task-add { border-top: 1px dashed var(--line); margin-top: var(--space-3); padding-top: var(--space-2); }
.task-add > summary { color: var(--accent); cursor: pointer; font-size: 14px; list-style-position: inside; }
.task-add > summary:hover { color: var(--text); }
.task-add[open] > summary { margin-bottom: var(--space-2); }
.task-add > .form--task:first-of-type { border-top: none; margin-top: 0; padding-top: 0; }
.task-add__note { margin: var(--space-2) 0 0; }
.task-add__lead { margin: 0 0 var(--space-2); }

/* Новый проект из строки папки (П3.5): форма живёт в ячейке «Проект», а она
   у́же двух полей на любой ширине — на 1280 в ней 392 px, на телефоне
   половина карточки, 181 px. Колонка поэтому одна всегда, и `minmax(0, …)`
   вместо общих 200 px: с ними на 375 px поля распирали страницу вбок
   на 19 px (замер на стенде 30.09). */
.folder-new__form { grid-template-columns: minmax(0, 1fr); }

/* На телефоне ячейка задач — на всю ширину карточки: в половине карточки
   название задачи рвалось бы на пять строк. Ячейка «Что делал» экрана дня —
   по той же причине (Э8, Р112): в половине карточки описания работ вытягивали
   карточку OpenClaw за 28.09 на 375 px до 1648 px, на всю ширину — до 891. */
@media (max-width: 900px) {
  .table td[data-label="Задачи заказчика"] { grid-column: 1 / -1; }
  .table td[data-label="Что делал"] { grid-column: 1 / -1; }
}

/* Форма привязки папки (Т20, с Э4 — прямо в ячейке колонки «Проект», Р45 п.1).

   🔴 `flex-direction: row` обязателен и здесь: базовый `.form` ставит КОЛОНКУ,
   и без сброса список с кнопкой встают друг под другом. Цена ошибки не
   косметическая — замер: страница `/unassigned` выросла с 8 692 до 40 504 px,
   то есть впятеро, при том что строк стало ВДВОЕ МЕНЬШЕ. Это третий случай
   той же грабли за один этап (`.form--row`, `.field--actions`, здесь).

   Список не растягивается на всю ячейку: у самого длинного варианта 65 знаков,
   и колонка «Проект» иначе съедает половину таблицы. */
.form--bind {
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-1);
}

.form--bind select {
  /* 🔴 Список занимает ОСТАТОК ячейки, а не свои 320 px: при фиксированной
     раскладке колонка «Проект» на 1280 равна 392 px, и «320 + кнопка» в неё
     не влезали — кнопка переносилась на вторую строку, и КАЖДАЯ строка
     таблицы становилась вдвое выше (замер: 7 243 px против 4 563 на 1440,
     где место есть). `min-width: 0` обязателен: без него элемент flex
     не сжимается ниже своего содержимого, а содержимое здесь — вариант
     в 65 знаков. */
  flex: 1 1 0;
  min-width: 0;
  /* Поле в ячейке таблицы — мельче и теснее, чем в форме справочника:
     строк много, и 11 px отступа на каждой дают лишние 600 px прокрутки. */
  font-size: 14px;
  padding: 6px 8px;
}

.form--bind .button { padding: 6px 10px; flex: 0 0 auto; }

/* Столбец по содержимому (П-123). `width: 1%` — обычный приём для таблицы
   с `width: 100%`: браузер отдаёт такому столбцу минимум, а остаток делит
   между колонками без ограничения («Папка» и «Проект» — им место и нужно).
   `nowrap` не даёт значению переноситься внутри узкой колонки. */
/* 🔴 Одна раскладка колонок на ОБЕ таблицы экрана папок (требование
   владельца 19.09). `table-layout: fixed` заставляет браузер считать ширины
   по `<colgroup>`, а не по содержимому — только так столбцы двух разных
   таблиц встают ровно друг под другом. Узкие колонки получают ровно столько,
   сколько нужно их ЗАГОЛОВКУ (он здесь шире данных: «ПОСЛЕДНИЙ ДЕНЬ» против
   «12.09»), а «Папка» и «Проект» делят остаток поровну. */
.table--bind { table-layout: fixed; }

/* 🔴 Ширины ИЗМЕРЕНЫ, а не подобраны на глаз: каждая равна самому длинному
   НЕРАЗРЫВНОМУ слову своего заголовка плюс отступы ячейки. Перенос спасает
   только там, где в заголовке есть пробел, — а «ИНСТРУМЕНТ» и «ПОСЛЕДНИЙ»
   рвать негде, и в узкой колонке они вылезали за неё, уводя таблицу
   во внутреннюю прокрутку (замер на 1280: «ПОСЛЕДНИЙ» требует 127 px при
   колонке 92 — не хватало 35). Данные во всех четырёх колонках у́же
   заголовка, поэтому решает именно он. */
.table--bind .col--tool { width: 130px; }   /* «ИНСТРУМЕНТ» — 130 */
.table--bind .col--time { width: 104px; }   /* «ПОЛНОЕ» / «ВРЕМЯ» — 93 */
.table--bind .col--days { width: 70px; }    /* «ДНЕЙ» — 69 */
.table--bind .col--date { width: 130px; }   /* «ПОСЛЕДНИЙ» — 127 */

/* 🔴 Заголовку узкой колонки разрешён перенос в две строки, и это не мелочь:
   «ПОСЛЕДНИЙ ДЕНЬ» в одну строку требует 150 px при данных шириной 40, и на
   1280 эти лишние 180 px отбирались у колонки «Папка» — имена папок ломались
   на три строки, и страница вырастала с 4 724 до 7 174 px. Шапка выше
   на одну строку стоит дешевле. Сами ДАННЫЕ не переносятся: у них `.num`
   с `nowrap`, и «12.09» на две строки не рвётся. */
.table--bind thead th.col-tight { white-space: normal; }

/* При фиксированной раскладке длинное имя папки без пробелов не сжимает
   колонку, а вылезает за неё — поэтому перенос разрешён в любом месте.
   Та же грабля уже закрыта в карточной раскладке на телефоне. */
.table--bind th[scope="row"] { overflow-wrap: anywhere; }

.table--bind td.col-tight { white-space: nowrap; }

/* Выпадающие списки: в Э2 их не было ни одного, и без своего стиля
   браузер рисует их белыми на тёмной странице. */
select {
  background: #0b0e0d;
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--text);
  font: inherit;
  padding: 11px 12px;
}

select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.money { display: block; white-space: nowrap; }

/* Пояснение под числом в ячейке: отдельной строкой, мелким и С ПЕРЕНОСОМ.
   🔴 `nowrap` здесь был ошибкой: подпись «часть часов без ставки… сумма
   посчитана не за всё» в одну строку растягивает столбец, и вся таблица
   уезжает за край экрана вместе с числами (поймано снимком). Ширина
   ограничена, чтобы пояснение не растягивало колонку и на длинном тексте. */
.cell-note {
  display: block;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.3;
  white-space: normal;
}

/* 🔴 Прижимается вправо и сужается до 22 знаков ТОЛЬКО в ячейке с числом
   по правому краю — там подпись обязана стоять под своим числом, а не
   растягивать колонку (это и был исходный повод, Т21).
   Везде ещё — в плитке метрики, под итогом потолка, в абзаце — те же два
   свойства ломали текст в лесенку и вешали его в пустоте справа. Правило
   закрыто по МЕСТУ ПРИМЕНЕНИЯ, а не тремя исключениями по одному на
   пострадавший блок (И-13): исключения кончились бы на четвёртом. */
.table .num .cell-note {
  max-width: 22ch;
  margin-left: auto;
}

/* Подпись «без лимита N» под суммой строки и итога у заказчика (Т44, Р71).
   Правила — ТОЛЬКО для неё, а не для общего `.cell-note` выше: общее правило
   держит подписи экрана владельца, и его правка изменила бы экран, который
   обязан остаться прежним (П-217).
   * Число не рвётся: на узкой колонке «100 317 ₽» переносилось посередине
     (поймано макетом на 1000 px) — переносится только промежуток между
     «без лимита» и суммой.
   * В карточке телефона число прижато влево, и подпись обязана стоять под
     ним с того же края: общее `margin-left: auto` уводило её вправо, и она
     висела отдельно от числа (снимок макета). Существующие подписи этим
     задеты так же — это вне Т44 (spec.md §9.2). */
.table .num .cell-note[data-full-amount] [data-full-amount-rubles],
.table .num .cell-note[data-calendar-time] > span { white-space: nowrap; }

/* «меньше минуты» в строке таблицы периода (макрос `row_hours`): ячейка
   с числом неразрывна, а фразе перенос разрешён — иначе она держала две
   колонки шириной 130 px, и таблица на 901–1049 px уходила в свою прокрутку
   (замер 30.09: 121 px на 901, 22 на 1000). Числа по-прежнему не рвутся. */
.table .num .num__phrase { white-space: normal; }
@media (max-width: 900px) {
  .table .num .cell-note[data-full-amount],
  .table .num .cell-note[data-calendar-time] { margin-left: 0; }
}

/* Т46 (Р77, Р78), только экран владельца: вторая строка «Полного времени»
   («календарное N») держится теми же двумя правилами, что подпись «без
   лимита», — селектор добавлен к ним, а не заведён копией рядом. Сноска
   неполноты у итога — мелкая, цвета подписи; слова к ней — отдельной
   строкой первой фразой примечаний под таблицей.
   🔴 Сноска ВИСЯЧАЯ: отрицательный правый отступ гасит её ширину, и она
   рисуется в поле ячейки. Иначе она расширяла неразрывное число итога,
   а с ним колонку «Сумма» — на 1000 px таблица уезжала в свою прокрутку
   на 33 px против прежних 25 (замер Т46.5, П-240). Попутно число итога
   стоит по правому краю вровень с числами строк. */
.cell-mark { color: var(--muted); font-size: 12px; margin-left: 1px; margin-right: -0.6em; }
[data-unpriced-legend] { display: block; margin-bottom: 4px; }

/* 🔴 Средний экран, только таблица владельца (Т46, П-240). С Т46 колонка
   суммы подписана «Сумма (с лимитом)», и слово «лимитом)» на 4 px шире чисел
   под ним: на 1000 px таблица уходила в свою прокрутку на 29 px против
   прежних 25. Возвращено в соседней колонке: у владельца её ширину (135 px)
   держали неразрывные «ставка не задана» и «не оплачивается» строк без
   ставки — им разрешён перенос (замер: прокрутка 29 → 7 px). Только
   владельцу: у заказчика таких строк нет, и его экран не меняется (П-238).
   Верхняя граница 1099, а не 1359, как у сжатия выше: на 1280 таблица
   помещается и так, а перенос там только удлинял страницу на 50 px. */
@media (max-width: 1099px) and (min-width: 901px) {
  [data-viewer-role="owner"] .table--period td[data-label="Ставка"] .muted { white-space: normal; }
}

.button--danger { border-color: #f7768e; color: #f7768e; background: transparent; }
.button--danger:hover { background: rgba(247, 118, 142, 0.12); }

.confirm__what { font-size: 20px; font-weight: 600; margin: 0 0 6px; }
.confirm__actions { display: flex; gap: 10px; align-items: center; }

/* ------------------------------------------------------------------ */
/* Деньги на экране периода (Э3, Т21)                                  */
/* ------------------------------------------------------------------ */

.money-summary__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 14px;
}

/* Сумма — главное число экрана, поэтому она в плитке метрики, но с своим
   размером: «1 234 567 ₽» в 30 px не влезает в колонку 230 px, а перенос
   посередине числа читается как два числа. */
.metric--money .metric__value { font-size: 26px; }
.metric--money .money { font-size: 26px; font-weight: 700; }

/* Р173: обе составляющие общей оплаты внутри одной из четырёх карточек. */
.metric__breakdown { display: grid; gap: 7px; }
.metric__breakdown > div { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 8px; }
.metric__breakdown [data-work-rubles],
.metric__breakdown [data-subscription-rubles] { color: var(--text); font-variant-numeric: tabular-nums; }

/* Четыре карточки денег заказчика (Т42, Р66) — ровными рядами: 4 в ряд,
   2 × 2 или столбиком. Автоподбор `auto-fit` выше давал на средней ширине
   «3 + 1» (замер 25.09 на 768 px): четвёртая карточка уезжала одна, и ряд
   читался как два разных блока. Ниже 900 px — столбиком, как плитки шапки. */
.money-summary__row--four { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1100px) {
  .money-summary__row--four { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .money-summary__row--four { grid-template-columns: 1fr; }
}
/* Пояснение под карточками заказчика: у владельца между ними стоит
   переключатель, у заказчика его нет, и строка без отступа прилипала
   к карточкам (снимок 25.09). Отступ — как у блока выгрузки ниже. */
.money-summary__note { margin-top: 14px; }


/* Цель якоря не прижимается к верхней кромке окна: после сохранения строка
   оказывалась вплотную к краю, и не было видно ни её заголовка, ни того, что
   выше. Отступ — свойство самой цели, а не прокрутки, поэтому работает и при
   переходе по ссылке, и после переадресации формы. */
[id^="project-"],
[id^="rate-"],
[id^="limit-"],
#rates, #limits, #contacts, #projects, #bound, #client-form, #change-summary {
  /* С Э4 подтверждение липкое и стоит поверх страницы, поэтому цель якоря
     отступает на ЕГО высоту — иначе плашка накрывает то, к чему привела
     ссылка (найдено при сборке Т26, а не вычитыванием).

     🔴 Величина не постоянная: плашка растёт, когда текст переносится.
     Замер худшего случая — самое длинное сообщение («Период лимита удалён
     вместе с составом.») плюс ссылка на сводку при окне 320 px: 94 px против
     прежних фиксированных 72, то есть цель уходила под плашку. Найдено ревью
     Codex по коду партии 1.

     Поэтому величина — переменная: умолчание 100 px покрывает этот худший
     случай БЕЗ скрипта (И-32), а `forms.js` уточняет её по фактической высоте
     плашки, и на широком экране отступ снова становится ровно нужным. */
  scroll-margin-top: calc(var(--topbar-height) + var(--notice-height, 100px));
}

/* Выгрузка (Т22): кнопка и подпись в одну строку, а на узком экране —
   в две. Подпись рядом обязательна: без неё «Скачать CSV» не говорит,
   что именно окажется в файле и за какой период. */
.money-summary__export {
  align-items: baseline;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 14px 0 0;
}

/* Переключатель (кнопки «Машинные / Календарные» у графиков; до Т46 — ещё
   и денежные «Фактически / К оплате», Р76): ссылки, а не форма — положение
   обязано быть видно в адресе (Р31, Р74). Выбранное подсвечено рамкой акцента,
   а не только цветом: на тёмной странице разница в оттенке серого не читается. */
.switch {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 16px 0 10px;
}

.switch__item {
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted);
  font-size: 14px;
  padding: 8px 16px;
  text-decoration: none;
}

.switch__item:hover { border-color: var(--accent); color: var(--text); }

.switch__item--current {
  border-color: var(--accent);
  color: var(--text);
  background: rgba(110, 231, 168, 0.1);
  font-weight: 600;
}

/* Колонка «Заказчик» в таблице проектов периода: одна строка с усечением.
   🔴 Причина — замер, а не вкус: с двумя новыми столбцами (ставка и сумма)
   колонка сузилась до 128 px, и название «Не распределено по заказчикам»
   переносилось в ТРИ строки — высота строки таблицы выросла с 40 до 117 px,
   то есть таблица из 21 проекта стала втрое длиннее. Полное название
   остаётся доступным: оно в `title` ячейки.
   На узком экране таблица рисуется карточками, и там усечение снимается —
   иначе имя заказчика пропало бы ровно там, где места и так мало. */
.table--period tbody td[data-label="Заказчик"] {
  /* 26ch, а не 18: усечение заводилось в Т21 от тесноты (колонка была
     128 px), а с широким контейнером место есть, и резать название
     заказчика там, где оно помещается, незачем. На среднем экране
     возвращается 18ch — правилом НИЖЕ по файлу (порядок важен: выше
     оно не действовало вовсе).
     34ch — мера с ЖИВЫХ данных, а не на глаз: самое длинное название
     («Не распределено по заказчикам (Э3)») требует 273 px, то есть
     ровно 34 знака этим шрифтом. Запас в таблице есть — ей нужно
     1182 px при 1400 доступных. */
  max-width: 34ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 🔴 Средний экран возвращает узкую меру, и правило стоит ЗДЕСЬ, а не наверху
   вместе с остальным сжатием таблицы периода. Причина — порядок в файле:
   при равной специфичности побеждает последнее правило, поэтому `18ch`,
   объявленный выше `34ch`, не действовал НИКОГДА. Комментарий рядом с `34ch`
   при этом утверждал обратное («на среднем экране возвращается 18ch») —
   то есть описывал намерение, которого код не исполнял. Найдено замером
   при приёмке партии 1 Э4, дефект не новый. */
@media (max-width: 1359px) and (min-width: 901px) {
  .table--period tbody td[data-label="Заказчик"] { max-width: 18ch; }
}

@media (max-width: 900px) {
  .table--period tbody td[data-label="Заказчик"] {
    max-width: none;
    white-space: normal;
  }
}


/* ======================================================================
   Экран одного проекта (Э4, Е28, задача Т33)

   Устройство по Р54: шапка с выбором проекта и периода, липкая крышка
   с числами и графиком по дням, под ней лента дней с работами.

   🔴 График нарисован СТОЛБЦАМИ РАЗМЕТКИ, а не холстом Chart.js: без
   скрипта на холсте остаётся пустой прямоугольник, а П-156 требует,
   чтобы график приходил в разметке. Высоту столбца задаёт единственный
   в проекте инлайновый стиль — величина вычисляется из данных.
   ====================================================================== */

/* Подпись для тех, кто читает экран голосом, и для тех, кто листает
   формой без мыши: поле даты обязано иметь имя, но рисовать его незачем —
   рядом стоит тире, и что это период, видно глазом. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.project-pick { align-items: flex-end; display: flex; gap: var(--space-2); }
.project-pick select { max-width: 280px; }
/* 🔴 Кнопка «Открыть» — обычного размера, а не `--small` (замечание владельца
   20.09). Замер до правки: список 47 px, кнопка 37 px; выровнены по низу,
   но разной высоты, и пара читалась как «поле и приписка к нему». Обычная
   кнопка берёт `font: inherit` и те же 11 px отступа, что и select рядом,
   поэтому высоты совпадают САМИ — без числа, которое разъехалось бы
   от первой же правки поля. Попытка подогнать отступами оставляла 2 px:
   у `--small` шрифт 14 px против 16 px у поля.

   Оставшийся 1 px (48 против 47) снимается общей мерой на оба элемента:
   у кнопки `font-weight: 600`, и строка в ней чуть выше при том же шрифте.
   Мера названа один раз и действует на обе стороны пары — поле, ставшее
   выше, потянет за собой и кнопку. */
.project-pick select,
.project-pick button { min-height: 48px; }

/* Пины периода и произвольный диапазон — ОДНОЙ строкой (П-154).
   Замер макета на 1280: строка занимает 829 px из 1225 доступных. */
.periods {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
}

.pin {
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted);
  font-size: 14px;
  padding: 7px 14px;
  text-decoration: none;
  white-space: nowrap;
}

.pin:hover { border-color: var(--muted); color: var(--text); }

.pin--on {
  background: var(--accent);
  border-color: var(--accent);
  color: #06120c;
  font-weight: 600;
}

.periods__sep {
  align-self: stretch;
  background: var(--line);
  margin: 0 var(--space-1);
  width: 1px;
}

.periods__range { align-items: center; display: flex; gap: var(--space-1); }
.periods__field { display: block; }
.periods__range input[type="date"] { font-size: 13px; padding: 6px 8px; }
.periods__dash { color: var(--muted); }

/* Липкая крышка (П-153). `top` — ровно под закреплённой шапкой, иначе
   числа заезжают под неё. Фон непрозрачный: лента проезжает ПОД крышкой,
   и сквозь неё просвечивали бы строки. */
.project-top {
  background: var(--bg);
  box-shadow: 0 10px 18px -12px #000;
  padding-bottom: var(--space-2);
  padding-top: var(--space-1);
  position: sticky;
  top: var(--topbar-height);
  z-index: 4;
}

/* Плитки этого экрана мельче общих: их пять, и в полный рост они заняли бы
   треть окна — а крышка обязана оставлять место ленте, ради которой
   экран и открывают. */
.metrics--compact { gap: var(--space-2); grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
.metrics--compact .metric { gap: 2px; padding: var(--space-2) var(--space-3); }
.metrics--compact .metric__label { font-size: 12px; }
.metrics--compact .metric__value { font-size: 22px; }

.daybars {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  margin: var(--space-2) 0 0;
  padding: var(--space-3) var(--space-3) var(--space-1);
}

.daybars__row {
  align-items: flex-end;
  display: flex;
  gap: 3px;
  height: 140px;
  padding-bottom: 20px;
  position: relative;
}

/* Столбец — колонка постоянной ширины, растущая снизу. `min-width: 0`
   обязателен: без него длинный период растягивает ряд за края карточки. */
.daybar {
  align-items: center;
  display: flex;
  flex: 1;
  flex-direction: column;
  height: 100%;
  justify-content: flex-end;
  min-width: 0;
  position: relative;
  text-decoration: none;
}

.daybar__bar {
  background: var(--accent);
  border-radius: 3px 3px 0 0;
  display: block;
  min-height: 2px;
  opacity: 0.7;
  transition: opacity 0.1s;
  width: 100%;
}

.daybar:hover .daybar__bar,
.daybar--on .daybar__bar { opacity: 1; }

/* День без работы — не пустое место, а тонкая полоса цвета линии: место
   он занимать ОБЯЗАН (П-157), иначе форма периода врёт и выходные
   исчезают, но и высотой не притворяется. */
.daybar--empty .daybar__bar { background: var(--line); height: 2px; opacity: 1; }

.daybar__tick {
  bottom: -18px;
  color: var(--muted);
  font-size: 10px;
  position: absolute;
  white-space: nowrap;
}

/* Подсказку строит скрипт из того, что УЖЕ есть в разметке (И-38):
   всё, что она показывает, напечатано в ленте ниже. */
.project-tip {
  background: #0b0e0d;
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 12px 30px -12px #000;
  font-size: 13px;
  max-width: 340px;
  padding: var(--space-2) var(--space-3);
  pointer-events: none;
  position: fixed;
  z-index: 20;
}

.project-tip b { display: block; margin-bottom: 4px; }
.project-tip ul { color: var(--muted); margin: 6px 0 0; padding-left: 16px; }

/* Лента дней */
.feed {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 var(--space-4);
}

.feed__day {
  border-bottom: 1px solid var(--line);
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 124px 1fr;
  margin: 0 calc(var(--space-2) * -1);
  padding: var(--space-3) var(--space-2);
  border-radius: 8px;
  /* Цель якоря отступает на шапку И на крышку: без этого строка, к которой
     ведёт столбец, оказывается ПОД ними — то есть «переводит к строке»
     не выполняется ровно тогда, когда им пользуются.

     330 px — замер крышки на рабочем экране (шапка 66 + плитки + график);
     он действует, когда скрипта нет. Со скриптом величину подставляет
     сам экран, потому что на узком окне плитки переносятся на два ряда
     и крышка выше. */
  scroll-margin-top: var(--project-top-height, 330px);
}

.feed__day:last-child { border-bottom: none; }
.feed__day--on { background: rgba(110, 231, 168, 0.07); }

.feed__head { display: flex; flex-direction: column; gap: 2px; }
.feed__date { color: var(--text); font-weight: 600; text-decoration: none; }
.feed__date:hover { color: var(--accent); }
.feed__meta { color: var(--muted); font-size: 12px; }

.feed__works { display: flex; flex-direction: column; }

.pwork {
  align-items: baseline;
  display: grid;
  gap: var(--space-3);
  grid-template-columns: 1fr auto;
  padding: 6px 0;
}

.pwork + .pwork { border-top: 1px dashed rgba(37, 43, 40, 0.7); }
.pwork__text { overflow-wrap: anywhere; }
.pwork__title { color: var(--text); }
.pwork__title--kind { color: var(--muted); font-style: italic; }
/* Работа, которую инструмент не назвал (история до 19.09.2026). Подписана
   иначе, чем название, — выдавать её за имя работы нельзя (К-313). */
.pwork__title--none { color: var(--muted); }
/* «Подробнее» ручной записи (Э7, Р99) и описание работы (Э8) — строкой под
   названием, на всю ширину колонки. Прежний предел 90 знаков снят (замечание
   владельца 30.09): на широком экране текст занимал половину строки, и список
   с описаниями вырастал в высоту вдвое. */
.pwork__desc {
  color: var(--muted);
  display: block;
  font-size: 13px;
  margin-top: 2px;
  white-space: pre-line;
}

.pwork__tool {
  color: var(--muted);
  font-size: 11px;
  letter-spacing: 0.04em;
  margin-right: 8px;
  text-transform: uppercase;
}

.pwork__time {
  color: var(--muted);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

@media (max-width: 900px) {
  /* На телефоне крышка НЕ липкая: вместе с шапкой она съела бы половину
     экрана, и читать ленту стало бы нечем. */
  .project-top { position: static; }
  /* Пять плиток в один столбец — это 570 px до первой строки ленты, то есть
     на телефоне лента начинается за экраном. Два столбца сокращают крышку
     вдвое, а числа остаются читаемыми: замер на 375 — 22 px величина. */
  .metrics--compact { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .feed__day { grid-template-columns: 1fr; gap: var(--space-1); scroll-margin-top: calc(var(--topbar-height) + 12px); }
  .feed__head { align-items: baseline; flex-direction: row; gap: var(--space-2); }
  .project-pick { width: 100%; }
  .project-pick select { max-width: none; }
  /* Без `min-width: 0` поле не сжимается меньше своего списка: самое длинное
     имя проекта растягивает его до 344 px, и на 320 px страница уезжает вбок
     на 53 px. Где места хватает, ширина списка прежняя. */
  .project-pick .field { min-width: 0; }
  .daybars__row { height: 110px; }
}

/* П5.2. На узком экране у периода длиннее двух недель подписи дат идут
   вплотную и читаются одной строкой «1011121314…» (замер: 380 px, 31 день —
   зазор −0,8 px). Остаются первый и последний день периода и каждое пятое
   ЧИСЛО МЕСЯЦА. Число берётся из `data-day`, а не из позиции столбца, поэтому
   период не с 1-го тоже подписан круглыми числами (3, 5, 10 … 25, 29). Число,
   стоящее вплотную к первому или последнему дню, прячется, иначе у августа
   слиплись бы «30 31». Прячется прозрачностью: у столбца нет другого текста,
   и дата остаётся доступной читалке экрана. Разметка прежняя: шире 600 px
   и на двух неделях видны все подписи, а без `:has()` правило отпадает
   целиком и остаётся прежний вид. */
@media (max-width: 600px) {
  .daybars__row:has(> :nth-child(15))
    > :not(:first-child, :last-child, [data-day$="-05"], [data-day$="-10"],
           [data-day$="-15"], [data-day$="-20"], [data-day$="-25"], [data-day$="-30"])
    > .daybar__tick,
  .daybars__row:has(> :nth-child(15))
    > :is(:nth-child(2), :nth-last-child(2)) > .daybar__tick { opacity: 0; }
}

/* --- Разбор дня под графиком периода (Т34, Е29) --------------------------
   Секцию присылает сервер готовой (`_day_breakdown.html`), скрипт только
   вставляет её сюда. Пустой слот ничего не занимает: без скрипта
   в странице остаётся ровно то, что было до Т34. */
.breakdown-slot:empty { display: none; }
.breakdown-slot__error { margin: 0; }

.breakdown {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
  /* Секция раскрывается ПОД графиком, и прокрутка к ней не должна прятать
     её под липкой шапкой. */
  scroll-margin-top: calc(var(--topbar-height) + 12px);
}

.breakdown__head {
  align-items: baseline;
  border-bottom: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  justify-content: space-between;
  margin-bottom: var(--space-2);
  padding-bottom: var(--space-3);
}

.breakdown__title { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); }
.breakdown__day { font-size: 19px; font-weight: 700; }
.breakdown__total { color: var(--muted); font-size: 14px; font-variant-numeric: tabular-nums; }
.breakdown__actions { align-items: center; display: flex; gap: var(--space-3); }
.breakdown__link { color: var(--muted); font-size: 13px; }
.breakdown__link:hover { color: var(--accent); }

.breakdown__close {
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted);
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  padding: 5px 12px;
}

.breakdown__close:hover { border-color: var(--muted); color: var(--text); }
.breakdown__empty { margin: var(--space-3) 0 0; }
.breakdown__note { margin: var(--space-3) 0 0; }

.bproj { border-bottom: 1px solid rgba(37, 43, 40, 0.75); padding: var(--space-3) 0; }
.bproj:last-of-type { border-bottom: none; }

/* Шапка проекта — она же переключатель сворачивания (`<summary>`): стрелка,
   точка цвета, название, часы. Стрелка смотрит вниз у открытого проекта
   и вправо у свёрнутого. */
.bproj__head {
  align-items: baseline;
  cursor: pointer;
  display: grid;
  gap: var(--space-2);
  grid-template-columns: 8px 10px 1fr auto;
  list-style: none;
}
.bproj__head::-webkit-details-marker { display: none; }
.bproj__head::before {
  align-self: start;
  border: solid var(--muted);
  border-width: 0 1.5px 1.5px 0;
  content: "";
  height: 6px;
  margin-top: 7px;
  transform: rotate(45deg);
  width: 6px;
}
.bproj__fold:not([open]) > .bproj__head::before { margin-top: 9px; transform: rotate(-45deg); }
.bproj__head:hover::before { border-color: var(--text); }
.bproj__head:hover .bproj__name { color: var(--accent); }
.bproj__fold[open] > .bproj__head { margin-bottom: 4px; }

/* Цвет точки — тот же, что у слоя столбца над разбором: его считает
   `server/web/charts.py` и ставит шаблон, здесь только форма.
   🔴 Точка встаёт по ПЕРВОЙ строке шапки, а не по центру: в календарном
   положении у часов вторая строка («машинных …»), шапка становится двухстрочной,
   и `align-self: center` опускал точку ниже названия (замечание владельца 30.09).
   Отступ — половина разницы высоты строки и точки: (24 − 10) / 2. */
.bproj__dot { align-self: start; border-radius: 2px; height: 10px; margin-top: 7px; margin-top: calc((1lh - 10px) / 2); width: 10px; }
.bproj__name { font-weight: 600; overflow-wrap: anywhere; }
.bproj__time { font-variant-numeric: tabular-nums; font-weight: 600; }
/* Работы — под названием проекта: отступ на стрелку и точку с их зазорами. */
.bproj__works { margin-left: calc(8px + 10px + var(--space-2) * 2); }
.bproj__works > p { margin: 2px 0 0; }

@media (max-width: 900px) {
  .breakdown { padding: var(--space-3) var(--space-3); }
  .breakdown__day { font-size: 17px; }
  .bproj__works { margin-left: 0; }
}

/* Вторая величина у проекта в календарном положении: работы считаются
   машинным временем, и без неё строка читается как поломка. */
.bproj__machine {
  color: var(--muted);
  display: block;
  font-size: 12px;
  font-weight: 400;
  text-align: right;
}

/* Числа разбора посчитаны свежими, а столбец над ним нарисован при отрисовке
   страницы: если между этим пришли новые данные, разбор говорит об этом сам. */
.breakdown__stale {
  border-top: 1px dashed var(--line);
  margin: var(--space-3) 0 0;
  padding-top: var(--space-2);
}

/* Кнопка, которую страница со скриптом отправляет сама, не должна мелькать
   (замечание владельца 20.09). Метку ставит <head> той страницы, где скрипт
   подключён, поэтому правило действует ещё до первой отрисовки — а на экране
   выбора проекта, где скрипта нет, кнопка остаётся видимой (П-156). */
.js-auto-submit [data-auto-submit-button] { display: none; }

/* ==========================================================================
   Фильтры, поиск и порядок на «Проектах» и «Папках» (Т47, Р80…Р84).
   Панель работает на странице скриптом `filters.js`; правил в нём нет —
   признаки строк и порядок посчитал сервер (`server/web/listing.py`).
   ========================================================================== */

/* 🔴 Без скрипта панели нет вовсе (П-245): метку `js-filters` ставит <head>
   этих страниц до первой отрисовки, поэтому со скриптом панель не мигает,
   а без него строки просто идут по алфавиту, как их отдал сервер. */
html:not(.js-filters) [data-filters-bar] { display: none; }

/* 🔴 Скрытое фильтром — скрыто и в карточной раскладке телефона. До 900 px
   `.table tbody tr` получает `display: grid`, а правило автора сильнее
   атрибута `hidden`: без этих строк скрытые строки на телефоне остались бы
   видны (spec §12.2). Та же беда у плитки (`display: grid`). */
.table tbody tr[hidden] { display: none; }
.table-scroll[hidden],
.metrics[hidden] { display: none; }

.filters {
  align-items: flex-end;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0 0 var(--space-block);
}
.filters > .field,
.filters__item { margin: 0; min-width: 190px; }
/* Список с флажками — НЕ внутри `.field`: общее правило `.field span`
   красило бы названия в строках списка подписью поля. Подпись и отступ —
   те же, что у `.field`. */
.filters__item { display: flex; flex-direction: column; gap: 6px; }
.filters__caption { color: var(--muted); font-size: var(--text-label); }

/* Выпадающий список с поиском и флажками (Р82). */
.multi { position: relative; }
.multi > summary {
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--text);
  cursor: pointer;
  list-style: none;
  padding: 11px 14px;
  white-space: nowrap;
}
.multi > summary::-webkit-details-marker { display: none; }
.multi > summary::after { color: var(--muted); content: " ▾"; }
.multi[open] > summary { border-color: var(--accent); }
.multi--on > summary {
  background: rgba(110, 231, 168, 0.1);
  border-color: var(--accent);
  font-weight: 600;
}
/* Общая мера на пару «выпадающий список / список с флажками»: поле,
   ставшее выше, потянет за собой и соседа. */
.filters select,
.multi > summary { box-sizing: border-box; min-height: 48px; }

.multi__panel {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 14px 30px -12px #000;
  left: 0;
  padding: var(--space-2);
  position: absolute;
  top: calc(100% + 6px);
  width: min(460px, calc(100vw - 32px));
  z-index: 6;
}
.multi__search {
  background: #0b0e0d;
  border: 1px solid var(--line);
  border-radius: 10px;
  box-sizing: border-box;
  color: var(--text);
  font: inherit;
  padding: 11px 12px;
  width: 100%;
}
.multi__list { list-style: none; margin: 8px 0; max-height: 320px; overflow: auto; padding: 0; }
.multi__list label {
  align-items: center;
  border-radius: 8px;
  cursor: pointer;
  display: flex;
  gap: 8px;
  padding: 6px;
}
.multi__list label:hover { background: rgba(255, 255, 255, 0.04); }
.multi__list li[hidden] { display: none; }
.multi__name { overflow-wrap: anywhere; }
/* Своя подпись, а не общий `.muted`: у того нижний отступ 20 px, и строка
   списка вырастала с 36 до 52 px (замер макета). */
.multi__note {
  color: var(--muted);
  font-size: 13px;
  margin-left: auto;
  overflow-wrap: anywhere;
  text-align: right;
}
.multi__none { color: var(--muted); font-size: 13px; margin: 0; padding: 6px; }
.multi__actions { align-items: center; display: flex; gap: var(--space-2); justify-content: flex-end; }

/* Раздел, под который не попала ни одна строка, — одна строка вместо
   таблицы (П-248). */
.filters__empty { color: var(--muted); margin: var(--space-2) 0; }

/* На телефоне поля по два в ряд (П-250): столбиком панель занимала 241 px
   на «Проектах» и 324 на «Папках» — треть экрана до первой строки. */
@media (max-width: 600px) {
  .filters > .field,
  .filters__item { flex: 1 1 calc(50% - var(--space-2)); min-width: 0; }
  .filters select,
  .multi > summary { width: 100%; }
  .multi > summary { overflow: hidden; text-overflow: ellipsis; }
}

/* Подсказка пары «Заказчик / Оплачиваемый» в формах проекта (П-256):
   красное — личный проект отмечен оплачиваемым; жёлтое — проект уходит
   к заказчику и не оплачивается (законно, но стоит взгляда, Р86);
   зелёное — «не оплачивается» поставлено само. */
.field--invalid select { border-color: var(--danger); box-shadow: 0 0 0 1px var(--danger); }
.field--warn select { border-color: #e3b341; box-shadow: 0 0 0 1px #e3b341; }
.field--auto select { border-color: var(--accent); }
.field__alert { font-size: 12px; line-height: 1.35; }
.field__alert[hidden] { display: none; }
.field--invalid .field__alert { color: var(--danger); }
.field--warn .field__alert { color: #e3b341; }
.field--auto .field__alert { color: var(--accent); }

/* ==========================================================================
   Переключатель «чья работа» в шапке (Т48, Р88, spec Э6 §13.4)

   Кнопка с подписью выбора перед «Выйти»; по нажатию — панель со строками
   «Все проекты», «Заказчики» и заказчики под ней, «Личное», «Не
   распределено». При выборе кнопка подсвечена: цифры одного заказчика
   иначе легко принять за общие. Панель — `details`, открывается без
   скрипта; на узком экране — под шапкой во всю ширину.
   ========================================================================== */

.selection { position: relative; }

.selection__button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 260px;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted);
  font-size: 14px;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.selection__button::-webkit-details-marker { display: none; }
.selection__button::after { content: "▾"; font-size: 11px; }
.selection__value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.selection__button:hover { color: var(--text); }
.selection--active .selection__button {
  border-color: var(--accent);
  color: var(--accent);
}

.selection__panel {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  z-index: 20;
  width: 300px;
  max-height: 70vh;
  overflow-y: auto;
  padding: 10px 12px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
}

.selection__form { margin: 0; }

.selection__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px;
  border-radius: 8px;
}
.selection__row a { color: var(--text); text-decoration: none; flex: 1; }
.selection__row a:hover { text-decoration: underline; }
.selection__row--child { padding-left: 32px; }
.selection__row--child a { color: var(--muted); }
.selection__row--current { background: rgba(110, 231, 168, 0.10); }
.selection__row--current a { color: var(--accent); }
.selection__row input[type="checkbox"] { margin: 0; flex: none; }
.selection__spacer { width: 13px; flex: none; }

.selection__hint { margin: 8px 8px 0; color: var(--muted); font-size: 12px; }
.selection__actions { margin: 10px 8px 0; }
.selection__actions [hidden] { display: none; }

.remaining-partial { color: var(--muted); font-size: 12px; }

@media (max-width: 900px) {
  /* Первая строка шапки — «Worklog · переключатель · Выйти», меню — второй
     строкой (П-262): переключатель — главное действие шапки, и уезжать
     за меню ему нельзя. */
  .topbar--selection .topbar__brand { order: 1; }
  .topbar--selection .selection { order: 2; margin-left: auto; }
  /* «＋ Вручную» (Э7) — в той же первой строке перед переключателем:
     без `order` она вставала первой, левее «Worklog». */
  .topbar--selection .manual { order: 2; margin-left: auto; }
  .topbar--selection .manual + .selection { margin-left: 0; }
  .topbar--selection .topbar__logout { order: 3; }
  .topbar--selection .topbar__nav { order: 4; flex-basis: 100%; }
  .selection__button { max-width: 180px; }
  .selection { position: static; }
  .selection__panel {
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    width: auto;
    border-radius: 0 0 var(--radius) var(--radius);
  }
  /* Шапка с переключателем — всегда две строки: закреплённые крышки экранов
     (`top: var(--topbar-height)`) иначе уезжали бы под неё. Замер 27.09
     на стенде: 86 px от 318 до 900 px ширины. `forms.js` меряет высоту
     сам, но грузится не на каждом экране. */
  :root:has(.topbar--selection) { --topbar-height: 86px; }
}

@media (max-width: 317px) {
  /* Уже 317 px меню переносится ещё раз — третья строка (замер: 118 px при 316). */
  :root:has(.topbar--selection) { --topbar-height: 118px; }
}

/* ==================================================================
   Общий календарь дат (Э7, Т51, Р105, П-316…П-319) — `datepicker.js`.

   Поле `type="date"` остаётся в форме тем же полем (И-75), но не видно:
   поверх него — кнопка того же вида, что поле, и свой календарь под ней.
   Без скрипта этих классов на странице нет, и работает окно браузера.
   Поле прозрачное, а не `display: none`: скрытое так поле браузер не может
   показать при отказе `required` и молча не отправляет форму вовсе.
   ================================================================== */

:root { --manual: #c4a7ff; }

/* `span.datepick`, а не `.datepick`: обёртка стоит внутри подписи поля, и правила
   `.field span` / `.period-form__field span` иначе перекрасили бы её и сменили размер
   шрифта кнопке. По той же причине у вложенных `span` — префикс `.datepick`. */
span.datepick { color: var(--text); display: inline-block; font-size: inherit; position: relative; vertical-align: middle; }
.datepick__native {
  height: 100%;
  left: 0;
  margin: 0;
  opacity: 0;
  pointer-events: none;
  position: absolute;
  top: 0;
  width: 100%;
}
.datepick__button {
  background: #0b0e0d;
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--text);
  cursor: pointer;
  font: inherit;
  font-variant-numeric: tabular-nums;
  min-width: 8.5em;
  padding: 11px 12px;
  text-align: left;
  width: 100%;
}
.datepick__button--empty { color: var(--muted); }
.datepick__button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
span.datepick__error { color: var(--danger); display: block; font-size: var(--text-label); margin-top: 4px; }

/* Размеры — те же, что были у самого поля в строке периода и на экране проекта. */
.period-form .datepick__button { font-size: 14px; padding: 7px 10px; }
.periods__range .datepick__button { font-size: 13px; padding: 6px 8px; }
.form--row .datepick { flex: 1 1 140px; min-width: 120px; }

.datepick__cal {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 14px 30px -12px #000;
  left: 0;
  max-width: calc(100vw - 16px);
  padding: 10px 12px;
  position: absolute;
  top: calc(100% + 4px);
  width: 296px;
  z-index: 30;
}
.datepick__cal[hidden] { display: none; }
.datepick__cal--up { bottom: calc(100% + 4px); top: auto; }
.datepick__head {
  align-items: center;
  display: flex;
  font-weight: 600;
  justify-content: space-between;
  margin-bottom: 4px;
}
.datepick .datepick__head span { color: var(--text); font-size: 15px; }
.datepick__nav {
  background: transparent;
  border: none;
  color: var(--text);
  cursor: pointer;
  font: inherit;
  font-size: 22px;
  line-height: 1;
  padding: 0 10px 2px;
}
.datepick__nav:disabled { cursor: default; opacity: 0.25; }
.datepick__grid { display: grid; gap: 2px; grid-template-columns: repeat(7, 1fr); }
.datepick .datepick__wd { color: var(--muted); font-size: 11px; padding: 4px 0; text-align: center; }
.datepick__day {
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
  color: var(--text);
  cursor: pointer;
  font: inherit;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  height: 36px;
  padding: 0 0 4px;
  position: relative;
}
.datepick__day:hover:not(:disabled) { border-color: var(--muted); }
.datepick__day:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
.datepick__day:disabled { color: rgba(140, 154, 145, 0.35); cursor: default; }
.datepick__day--today { border-color: var(--line); }
.datepick__day--on {
  background: rgba(110, 231, 168, 0.14);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 700;
}
.datepick .datepick__dots { bottom: 4px; display: flex; gap: 3px; justify-content: center; left: 0; position: absolute; right: 0; }
.datepick__dot { background: var(--accent); border-radius: 50%; display: inline-block; height: 4px; width: 4px; }
.datepick__dot--manual { background: var(--manual); }
.datepick .datepick__legend { color: var(--muted); display: flex; flex-wrap: wrap; font-size: 11px; gap: 4px 12px; margin: 8px 0 0; }
.datepick .datepick__legend span { color: inherit; font-size: inherit; }
.datepick__legend .datepick__dot { margin-right: 5px; vertical-align: middle; }
.datepick__foot { display: flex; justify-content: flex-end; margin-top: 6px; }

@media (max-width: 900px) {
  .period-form .datepick { width: 100%; }
}

/* ==================================================================
   Ручная запись в шапке (Э7, Т52, Р101, П-303…П-315).

   `<details class="manual">` с настоящей формой: без скрипта раскрывается
   под шапкой и работает. `manual.js` ставит `manual--js` и собирает из
   формы панель макета (`.claude/mockups/manual/`), перекладывая в неё те же
   поля — что уходит на сервер, не меняется. На узком экране кнопка круглая
   внизу справа, панель выезжает снизу — это CSS, без скрипта тоже.
   ================================================================== */

.manual { position: relative; }
.manual__toggle { cursor: pointer; list-style: none; white-space: nowrap; }
.manual__toggle::-webkit-details-marker { display: none; }
.manual__panel {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 22px 48px -14px #000;
  box-sizing: border-box;
  max-height: calc(100vh - var(--topbar-height, 64px) - 24px);
  overflow: auto;
  padding: 18px 20px 16px;
  position: fixed;
  right: 20px;
  top: calc(var(--topbar-height, 64px) + 8px);
  width: min(640px, calc(100vw - 40px));
  z-index: 30;
}
.manual__panel *, .manual__panel *::before, .manual__panel *::after { box-sizing: border-box; }
.manual__heading { font-size: 17px; font-weight: 700; margin: 0 0 12px; }
.manual__form textarea {
  background: #0b0e0d; border: 1px solid var(--line); border-radius: 10px; color: var(--text);
  font: inherit; padding: 9px 12px; resize: vertical; width: 100%;
}
.manual .form--grid { grid-template-columns: 1fr 1fr; }
.manual__wide { grid-column: 1 / -1; }
.manual__flash { margin: 0 0 16px; }

/* --- со скриптом: панель макета --- */
.manual--js .manual__heading { display: none; }
.manual__head { align-items: center; display: flex; gap: 10px; }
.manual__title { flex: 1; font-size: 17px; font-weight: 700; }
.manual__x {
  background: none; border: 0; color: var(--muted); cursor: pointer; font: inherit; font-size: 18px;
  line-height: 1; padding: 4px;
}
.manual__x:hover { color: var(--text); }
.manual__x--small { font-size: 13px; padding: 2px 4px; }
.manual--js .manual__form { display: block; }
.manual__form[hidden] { display: none; }
.manual__row { margin-top: 14px; }
.manual .manual__label {
  color: var(--muted); display: block; font-size: 12px; letter-spacing: 0.06em; margin-bottom: 7px;
  text-transform: uppercase;
}
.manual .manual__opt { color: var(--muted); font-size: 12px; letter-spacing: 0; text-transform: none; }
.manual__chips { align-items: center; display: flex; flex-wrap: wrap; gap: 6px; }
.manual__chips--tight { margin-top: 8px; }
.manual__chip {
  background: transparent; border: 1px solid var(--line); border-radius: 999px; color: var(--text); cursor: pointer;
  font: inherit; font-size: 14px; padding: 6px 12px;
}
.manual__chip:hover { border-color: var(--muted); }
.manual__chip--on { background: rgba(110, 231, 168, 0.14); border-color: var(--accent); color: var(--accent); font-weight: 600; }
.manual__chip--small { font-size: 13px; padding: 4px 10px; }
.manual__chip--prev { border-color: rgba(196, 167, 255, 0.55); }
.manual__chip--gap { border-style: dashed; }
.manual__chip--gap:hover { border-color: var(--accent); }
.manual--js .manual__form input[type="text"],
.manual--js .manual__form textarea {
  background: var(--bg); border: 1px solid var(--line); border-radius: 10px; color: var(--text);
  font: inherit; font-size: 14px; padding: 7px 10px;
}
.manual--js .manual__form input[type="text"]:focus,
.manual--js .manual__form textarea:focus { border-color: var(--accent); outline: none; }
.manual__wideinput { display: block; width: 100%; }
.manual--js .manual__form textarea { display: block; margin-top: 8px; min-height: 54px; width: 100%; }
/* Кнопка общего календаря — третья кнопка даты («другой день ▾», П-307). */
.manual--js .datepick__button { border-radius: 999px; font-size: 14px; min-width: 0; padding: 6px 12px; }
.manual__date-other--on .datepick__button {
  background: rgba(110, 231, 168, 0.14); border-color: var(--accent); color: var(--accent); font-weight: 600;
}
.manual__combo { margin-top: 8px; position: relative; }
.manual--js .manual__form .manual__combo-input { width: 100%; }
.manual__combo--on .manual__combo-input { background: rgba(110, 231, 168, 0.08) !important; border-color: var(--accent) !important; color: var(--accent) !important; font-weight: 600; }
.manual__combo--on .manual__combo-input:focus { background: var(--bg) !important; color: var(--text) !important; font-weight: 400; }
.manual__combo-list, .manual__tlist {
  background: var(--card); border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 14px 30px -12px #000;
  list-style: none; margin: 4px 0 0; overflow: auto; padding: 4px 0; position: absolute; top: 100%; z-index: 3;
}
.manual__combo-list { left: 0; max-height: 260px; right: 0; }
.manual__combo-list[hidden], .manual__tlist[hidden] { display: none; }
.manual__combo-group { color: var(--muted); font-size: 11px; letter-spacing: 0.06em; padding: 8px 12px 2px; text-transform: uppercase; }
.manual__combo-item { cursor: pointer; font-size: 14px; padding: 6px 12px 6px 22px; position: relative; }
.manual__combo-item--active, .manual__tlist-item--active { background: rgba(110, 231, 168, 0.12); }
.manual__combo-item--on, .manual__tlist-item--on { color: var(--accent); font-weight: 600; }
.manual__combo-item--on::before, .manual__tlist-item--on::before { content: "✓"; left: 8px; position: absolute; }
.manual__combo-item mark { background: rgba(196, 167, 255, 0.35); border-radius: 2px; color: inherit; }
.manual__combo-empty, .manual__tlist-empty { color: var(--muted); font-size: 13px; padding: 8px 12px; }
.manual__range { align-items: center; color: var(--muted); display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.manual__tfield { display: inline-block; position: relative; }
.manual--js .manual__tfield input { cursor: pointer; font-variant-numeric: tabular-nums; width: 84px; }
.manual__tlist { left: 0; max-height: 232px; width: 132px; }
.manual__tlist--end { width: 196px; }
.manual__tlist--up { bottom: 100%; margin: 0 0 4px; top: auto; }
.manual__tlist-item {
  color: var(--text); cursor: pointer; font-size: 14px; font-variant-numeric: tabular-nums;
  padding: 6px 12px 6px 26px; position: relative; white-space: nowrap;
}
.manual__tlist-dur { color: var(--muted); font-weight: 400; margin-left: 10px; }
.manual__len { color: var(--text); font-weight: 600; }
.manual__bad { color: var(--danger); font-weight: 500; }
.manual__strip {
  background: rgba(255, 255, 255, 0.02); border: 1px solid var(--line); border-radius: 10px; cursor: crosshair;
  height: 60px; margin-top: 12px; overflow: hidden; position: relative; touch-action: none; user-select: none;
}
.manual__bar { border-radius: 3px; height: 14px; pointer-events: none; position: absolute; }
.manual__bar--own { background: var(--accent); top: 6px; }
.manual__bar--other { background: rgba(140, 154, 145, 0.5); top: 23px; }
.manual__bar--man { background: var(--manual); top: 40px; }
.manual__sel {
  background: rgba(196, 167, 255, 0.2); border: 1px solid var(--manual); border-radius: 4px; bottom: 0;
  pointer-events: none; position: absolute; top: 0;
}
.manual__now { background: var(--danger); bottom: 0; pointer-events: none; position: absolute; top: 0; width: 2px; }
.manual__ticks { color: var(--muted); font-size: 11px; height: 18px; margin-top: 4px; position: relative; }
.manual__ticks span { position: absolute; transform: translateX(-50%); }
.manual__ticks span[data-edge="start"] { transform: none; }
.manual__ticks span[data-edge="end"] { transform: translateX(-100%); }
.manual__legend { align-items: center; color: var(--muted); display: flex; flex-wrap: wrap; font-size: 12px; gap: 4px 14px; margin: 2px 0 0; }
.manual__key { border-radius: 2px; display: inline-block; height: 8px; margin-right: 5px; vertical-align: middle; width: 14px; }
.manual__key--own { background: var(--accent); }
.manual__key--other { background: rgba(140, 154, 145, 0.5); }
.manual__key--man { background: var(--manual); }
.manual__key--sel { background: rgba(196, 167, 255, 0.2); border: 1px solid var(--manual); }
.manual__info { margin-top: 8px; }
.manual__note { font-size: 13px; line-height: 1.45; margin: 6px 0 0; }
.manual__note--own { border-left: 3px solid var(--accent); padding-left: 9px; }
.manual__note--warn { border-left: 3px solid #e3b341; padding-left: 9px; }
.manual__actions { align-items: center; display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.manual--js [data-manual-submit] { flex: 1; font-size: 15px; font-weight: 700; padding: 9px 12px; }
.manual--js [data-manual-submit]:disabled {
  background: transparent; border-color: var(--line); color: var(--muted); cursor: not-allowed; font-weight: 500;
}
.manual__daylist { border-top: 1px solid var(--line); margin-top: 16px; padding-top: 12px; }
.manual__daylist:empty { display: none; }
.manual__daylist ul { list-style: none; margin: 0; padding: 0; }
.manual__daylist li { align-items: baseline; display: flex; font-size: 14px; gap: 10px; padding: 3px 0; }
.manual__daylist-time, .manual__daylist-dur { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.manual__daylist-what { flex: 1; min-width: 0; }
.manual__daylist-edit .manual__daylist-what { color: var(--accent); }
.manual__daylist form { display: inline; margin: 0; }
.manual__foot { border-top: 1px solid var(--line); color: var(--muted); font-size: 12px; margin: 14px 0 0; padding-top: 10px; }
.manual__foot kbd { border: 1px solid var(--line); border-radius: 4px; font: inherit; padding: 0 5px; }

@media (max-width: 700px) {
  .manual__toggle {
    align-items: center; border-radius: 50%; bottom: 20px; box-shadow: 0 12px 26px -8px #000;
    display: flex; font-size: 30px; font-weight: 600; height: 58px; justify-content: center;
    padding: 0; position: fixed; right: 16px; width: 58px; z-index: 25;
  }
  .manual__word { display: none; }
  /* Прятать кнопку и затемнять страницу — только со скриптом: без него закрыть
     панель можно лишь той же кнопкой (ревью Codex, Р101). */
  .manual--js[open] .manual__toggle { visibility: hidden; }
  .manual:not(.manual--js)[open] .manual__toggle { z-index: 31; }
  .manual--js[open]::before { background: rgba(0, 0, 0, 0.55); content: ""; inset: 0; position: fixed; z-index: 29; }
  .manual__panel {
    border-radius: 18px 18px 0 0; bottom: 0; left: 0; max-height: 90vh; padding: 16px 16px 22px;
    right: 0; top: auto; width: auto;
  }
  .manual .form--grid { grid-template-columns: 1fr; }
  /* 16 px в полях — иначе телефон увеличивает страницу при вводе. */
  .manual__panel input, .manual__panel textarea, .manual__panel select,
  .manual--js .manual__form input[type="text"], .manual--js .manual__form textarea { font-size: 16px; }
  .manual__tlist--end { left: auto; right: 0; }
  .manual__chip { font-size: 15px; padding: 8px 13px; }
  .manual__chip--small { font-size: 14px; padding: 6px 11px; }
  .manual__foot { display: none; }
}

/* ==========================================================================
   Страница «Задачи» (Э9, Т61; Р126). Канбан: четыре колонки от 1100 px,
   две на 641–1099, одна до 640 (П-395). Группы и карточки — `<details>`:
   работают без скрипта и с клавиатуры, «Сделано» свёрнуто по умолчанию.
   ========================================================================== */
.board__summary { margin: 0 0 var(--space-block); }
.board__note { color: var(--muted); display: block; font-size: var(--text-label); margin-top: 4px; }
/* Справка о колонках под заголовком (03.10): мера строки — как у текста, а не во всю ширину доски. */
.board__help { color: var(--muted); margin: 6px 0 0; max-width: 980px; }
.board__help > summary { cursor: pointer; font-size: 14px; list-style-position: inside; }
.board__help > summary:hover { color: var(--text); }
.board__help[open] > summary { margin-bottom: 6px; }
.board__help p { margin: 0 0 6px; }
.board__help ul { margin: 0; padding-left: 20px; }
.board__help li + li { margin-top: 2px; }
.board__help b { color: var(--text); font-weight: 600; }

.board__cols {
  align-items: start;
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 1099px) {
  .board__cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .board__cols { grid-template-columns: minmax(0, 1fr); }
}

.board__col {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  min-width: 0;
  padding: var(--space-2) var(--space-3);
}
.board__col-head {
  display: flex;
  font-size: var(--text-subsection);
  justify-content: space-between;
  margin: 0 0 var(--space-2);
}
.board__count { color: var(--muted); font-weight: 400; }

/* Скрытая фильтром группа — скрыта: правило автора сильнее атрибута
   `hidden`, как у строк таблиц «Проектов». */
.board__group[hidden] { display: none; }
.board__group { margin: 0 0 var(--space-2); }
.board__group-head { cursor: pointer; padding: 4px 0; }
.board__dot { border-radius: 2px; display: inline-block; height: 10px; margin-right: 4px; width: 10px; }
.board__project { font-weight: 600; overflow-wrap: anywhere; }
.board__meta { color: var(--muted); font-size: var(--text-label); white-space: nowrap; }

.board-card {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 10px;
  margin: 6px 0;
  padding: 8px 10px;
}
/* «Работы без задачи» — пунктиром (Р126): это не задача, а сигнал
   «модель не отнесла работу», и спутать их глаз не должен. */
.board-card--orphan { border-style: dashed; }
.board-card__head { cursor: pointer; }
.board-card__title { overflow-wrap: anywhere; }
.board-card__line { color: var(--muted); display: block; font-size: var(--text-label); }
.board-card__summary { font-size: 14px; margin: 8px 0; overflow-wrap: anywhere; }
.board-card__works { font-size: 13px; list-style: none; margin: 0; padding: 0; }
.board-card--with-reminder {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: start;
}
.board-card--with-reminder > .board-card { border: 0; margin: 0; padding: 0; }
.board-card__remind { max-inline-size: 8rem; white-space: normal; text-align: center; }
.board-reminder-status {
  position: sticky; bottom: 0; z-index: 2; padding: 10px 14px; margin-top: 12px;
  background: var(--bg); border: 1px solid var(--line); border-radius: 10px;
}
.board-reminder-status p { margin: 0 0 6px; }
.board-reminder {
  box-sizing: border-box; inline-size: min(38rem, calc(100% - 24px)); max-block-size: calc(100% - 24px);
  padding: clamp(12px, 4vw, 24px); border: 1px solid var(--line); border-radius: 12px;
  background: var(--bg); color: var(--text);
}
.board-reminder::backdrop { background: rgb(0 0 0 / 65%); }
.board-reminder h2 { margin: 0; }
.board-reminder label { display: grid; gap: 4px; margin-bottom: 12px; }
.board-reminder select, .board-reminder input, .board-reminder textarea {
  box-sizing: border-box; min-inline-size: 0; max-inline-size: 100%; padding: 8px;
  color: var(--text); background: var(--bg); border: 1px solid var(--line); border-radius: 6px;
}
.board-reminder label[for="board-reminder-text"] { margin-bottom: 4px; }
.board-reminder__prefix { overflow-wrap: anywhere; }
.board-reminder textarea { inline-size: 100%; font: inherit; resize: vertical; }
.board-reminder__actions { display: flex; flex-wrap: wrap; gap: 8px; }
.bwork { border-top: 1px solid var(--line); padding: 4px 0; }
.bwork__meta { color: var(--muted); }
.bwork__title { display: block; overflow-wrap: anywhere; }

/* ==================================================================
   Сводка для заказчика (Э10, Т67…Т68; Р130…Р134). Только новые классы:
   существующие не трогаются (`docs/e10/plan.md` §3).
   ================================================================== */
.brief__client { margin: 0 0 var(--space-section); }
.brief__client h2 { margin-top: 0; overflow-wrap: anywhere; }
.brief__form { display: flex; flex-direction: column; gap: var(--space-2); }
/* Поле сводки — на всю ширину карточки и в рост текста: сводка 06.10 —
   27 строк, и править её в окошке на пять строк неудобно. */
.brief__text {
  background: #0b0e0d; border: 1px solid var(--line); border-radius: 10px; color: var(--text);
  box-sizing: border-box; font: inherit; line-height: 1.5; min-height: 16em; padding: 10px 12px;
  resize: vertical; width: 100%;
}
.brief__text--read { margin: 0 0 var(--space-block); min-height: 0; overflow-wrap: anywhere; white-space: pre-wrap; }
.brief__actions { align-items: center; display: flex; flex-wrap: wrap; gap: var(--space-2); }
.brief__refused { margin: 0 0 var(--space-section); }
/* Рабочее место сводки (замечание владельца 26.10): поле текста и «Что было»
   стоят рядом и ровно в высоту окна под шапкой, у каждого своя прокрутка.
   Раньше они шли друг под другом, и прокрутка страницы к строкам проекта
   уводила с экрана его абзац в поле. На экранах у́же 1100 px колонки встают
   одна под другой и делят ту же высоту пополам. `overscroll-behavior` — чтобы
   докрученная до конца колонка не сдвигала страницу под рукой. */
.brief__workspace {
  display: grid; gap: var(--space-3); grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  height: calc(100vh - var(--topbar-height) - 2 * var(--space-3)); margin-top: var(--space-3);
  min-height: 480px;
}
.brief__editor { display: flex; flex-direction: column; min-height: 0; }
.brief__editor .brief__form { flex: 1; min-height: 0; }
.brief__editor .brief__text { flex: 1; min-height: 0; overscroll-behavior: contain; resize: none; }
.brief__facts {
  border: 1px solid var(--line); border-radius: 10px; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain; padding: 0 12px 10px;
}
.brief__facts h3 { color: var(--muted); font-size: var(--text-subsection); margin: 10px 0 var(--space-2); }
/* Название проекта липнет к верху колонки: в длинной группе видно, чьи строки. */
.brief__facts .brief__project { background: var(--card); padding: 4px 0 2px; position: sticky; top: 0; }
@media (max-width: 1099px) {
  .brief__workspace { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) minmax(0, 1fr); }
}
.brief__history { margin-top: var(--space-4); }
.brief__history summary { color: var(--muted); cursor: pointer; }
.brief__versions { margin: var(--space-2) 0 0; padding-left: 1.4em; }
.brief__versions li { margin: 2px 0; overflow-wrap: anywhere; }
.brief__group { margin: 0 0 var(--space-2); }
.brief__project { font-weight: 600; margin: 0 0 2px; overflow-wrap: anywhere; }
.brief__lines { font-size: 14px; list-style: none; margin: 0; padding: 0 0 0 12px; }
.brief__lines li { margin: 2px 0; overflow-wrap: anywhere; }
.brief__column { color: var(--muted); }
.brief__works { color: var(--muted); font-size: 13px; list-style: disc; margin: 2px 0 4px; padding-left: 1.4em; }
.brief__works li { margin: 1px 0; }
.brief__warn { color: #e3b341; margin: 0 0 var(--space-2); }
