:root {
  --line: #d8dce3;
  --muted: #6b7280;
  --accent: #1f6feb;
  --error: #b42318;
  --bg-soft: #f6f7f9;
}

* { box-sizing: border-box; }
/* .hint задаёт display: block, и он перебивал бы атрибут hidden — а им прячутся
   строки фильтра марок и подпись «ничего не найдено». */
[hidden] { display: none !important; }

body {
  margin: 0;
  padding: 24px;
  font: 15px/1.45 system-ui, "Segoe UI", Roboto, sans-serif;
  color: #16191d;
}

h1 { font-size: 22px; margin: 0 0 16px; }
h2 { font-size: 18px; margin: 0; }

/* Шапка страницы: заголовок слева, «кто вошёл» и выход — справа. */
.page-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}
.whoami { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.whoami__name { font-weight: 600; }
.whoami__role { color: var(--muted); }
.whoami form { margin: 0; }

/* Страница входа — единственная без шапки и вкладок. */
.login { max-width: 320px; margin: 10vh auto 0; }
.login__form { border: 1px solid var(--line); border-radius: 8px; padding: 20px; }
/* .field уже растягивает text и date; пароль в общем правиле не значился. */
.login__form input[type="password"] { width: 100%; }

.toolbar {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 16px;
}

.toolbar input[type="search"] {
  flex: 1 1 320px;
  max-width: 480px;
}

input, select, button { font: inherit; }

input[type="text"], input[type="search"], input[type="date"], select {
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: #fff;
}

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

.button {
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: #fff;
  cursor: pointer;
}
.button:hover { background: var(--bg-soft); }
.button:disabled { opacity: .5; cursor: not-allowed; }
.button--primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.button--primary:hover:not(:disabled) { background: #1a5fd0; }
.button--primary:disabled { background: var(--accent); }
.button--ghost { border-style: dashed; color: var(--muted); }
/* Выгрузка в Excel — ссылка, а не кнопка (браузер скачивает файл сам),
   поэтому ей отдельно снимаем подчёркивание и синий цвет ссылки. */
a.button { display: inline-block; text-decoration: none; color: inherit; }
.button--icon { padding: 4px 9px; line-height: 1; color: var(--muted); }

/* --- панель фильтров склада --- */

/* Отдельная полоса НАД таблицей, ниже строки поиска: поиск и фильтры — разные
   инструменты, и складывать их в одну строку значило бы прятать фильтры за
   переносом на узком окне.

   .field внутри панели сбрасывает нижний отступ формы (там поля идут в
   столбик, тут в строку) и получает фиксированную ширину: иначе выпадающий
   список поставок с длинным названием растягивал бы соседние поля. */
.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin-bottom: 16px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg-soft);
}
.filters .field { margin-bottom: 0; width: 190px; }
.filters .field > input[type="text"], .filters select { width: 100%; }
/* Подсказки лежат поверх таблицы под панелью, поэтому z-index у них выше
   собственного фона панели. */
.filters .suggestions { z-index: 6; }

/* --- список --- */

/* Ширины колонок заданы один раз в colgroup: и групповые строки, и строки бухт
   живут в одной таблице, поэтому колонки между ними не могут разъехаться.
   Три левые колонки прилипают при горизонтальном скролле — смещения ниже
   должны совпадать с суммой ширин слева.
   Сумма ширин держится под ~1370px, чтобы на окне 1440 таблица помещалась
   целиком вместе с кнопками в раскрытых строках; скролл остаётся запасным
   выходом для узких окон. Кнопок в раскрытой строке стало четыре
   (Копировать / Изменить / Пополнить / Списать) — они укладываются в два
   ряда, а не растягивают колонку вчетверо. */
.col-brand    { width: 135px; }
.col-section  { width: 90px; }
.col-color    { width: 125px; }
.col-place    { width: 105px; }
.col-price    { width: 90px; }
.col-cost     { width: 100px; }
.col-date     { width: 90px; }
.col-delivery { width: 110px; }
.col-length   { width: 115px; }
.col-weight   { width: 70px; }
.col-pieces   { width: 50px; }
.col-actions  { width: 200px; }

.table-wrap { overflow-x: auto; }

/* width: 100% + min-width, а не max-content: с max-content браузер раздвигал
   колонки под самое длинное значение и заданные в colgroup ширины переставали
   что-либо значить — таблица уезжала за экран из-за одной длинной ячейки.
   Теперь длинное режется многоточием, а скролл включается только когда окно
   уже самой таблицы. */
table.items {
  border-collapse: separate;
  border-spacing: 0;
  table-layout: fixed;
  width: 100%;
  min-width: 1370px;
}
/* У роли 'user' в таблице нет ни трёх денежных колонок (90 + 90 + 100 px), ни
   «Поставки» (110 px), и min-width от админской версии растягивал бы её пустым
   местом справа. 1370 - 390 = 980. */
table.items--lean { min-width: 980px; }
table.items th, table.items td {
  border-bottom: 1px solid var(--line);
  padding: 7px 8px;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  background: #fff;
}
/* Заголовкам разрешено переноситься: длинное «Цена продажи за м.» иначе
   держало бы колонку шире, чем нужно её значениям. */
table.items th {
  background: var(--bg-soft);
  font-weight: 600;
  white-space: normal;
  vertical-align: bottom;
}
table.items td.num { text-align: right; font-variant-numeric: tabular-nums; }
/* Длина прижата влево: «12 752,4 м» не нуждается в широкой колонке, а справа
   значение оказывалось за десятки пикселей от заголовка. */
table.items td.len { text-align: left; font-variant-numeric: tabular-nums; }

.sticky { position: sticky; z-index: 1; }
.sticky-1 { left: 0; }
.sticky-2 { left: 135px; }
.sticky-3 { left: 225px; box-shadow: 1px 0 0 var(--line); }
thead .sticky { z-index: 2; }

tr.group { cursor: pointer; }
tr.group:hover td { background: #f2f6fd; }
tr.group.is-open td { background: #eef3fb; }

.twisty {
  display: inline-block;
  width: 14px;
  color: var(--muted);
  transition: transform .12s;
}
.twisty::before { content: "\25B8"; }
tr.group.is-open .twisty { transform: rotate(90deg); }

tr.detail td { background: var(--bg-soft); color: #2b2f36; }
tr.detail:hover td { background: #eef0f4; }

/* Бухта с нулевым остатком — приезжает только с галочкой «Показать пустые».
   Приглушена И помечена словом: одного серого цвета мало (в таблице и так есть
   серые ячейки «—»), а одной пометки без цвета не хватает, чтобы строка
   считывалась как особая с одного взгляда. Кнопки в ней НЕ приглушаются —
   «Пополнить» на такой строке главное действие, за ним галочку и включают. */
tr.detail--empty td { background: #f2f1ee; color: var(--muted); }
tr.detail--empty:hover td { background: #eceae5; }
tr.detail--empty .actions .button { color: inherit; }
tr.detail--empty .bale-id { color: var(--muted); }
.mark-empty {
  margin-left: 6px;
  padding: 0 5px;
  border: 1px solid var(--line);
  border-radius: 3px;
  font-size: 11px;
  color: var(--muted);
  background: #fff;
}
/* В таблице внутри экрана поставки строки нет класса .detail, поэтому фон
   задаётся отдельно — правило выше цепляется за tr.detail. */
table.items--inline tr.detail--empty td { background: #f2f1ee; color: var(--muted); }

/* Галочка «Показать пустые»: в строке поиска и в шапке блока товаров поставки.
   inline-flex, чтобы подпись не отрывалась от квадратика при переносе. */
.toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  color: var(--muted);
  cursor: pointer;
}
.toggle input { margin: 0; }
/* В шапке блока (space-between) галочка прижимается к кнопке справа, а не
   болтается по центру между заголовком и ней. */
.block__head .toggle { margin-left: auto; }
.bale-id { color: var(--muted); font-size: 13px; padding-left: 14px; }

/* «Паспорт» в раскрытой строке бухты: мелкая ссылка рядом с подписью бухты,
   не колонка. Бухты без паспорта её не показывают вовсе — прочерка тут нет. */
.doc-link { font-size: 12px; color: var(--accent); margin-left: 8px; white-space: nowrap; }

/* Заголовок «Привязанные бухты» внутри региона экрана паспорта: между двумя
   таблицами, поэтому отступ сверху больше, чем снизу. */
.subhead { font-size: 14px; margin: 18px 0 6px; }

/* Поиск бухт живёт внутри экрана паспорта, а не в .toolbar вкладки — своя
   ширина ему нужна тут же. */
.bales-search { width: 100%; margin-bottom: 10px; }
/* Четыре кнопки в 200px в строку не встают, поэтому ячейке разрешён перенос:
   они укладываются в два ряда. Селектор обязан включать table.items — иначе
   общий `table.items td { white-space: nowrap }` весомее и кнопки уезжают
   за край ячейки, где их срезает overflow: hidden. display: flex тут не годится:
   ячейка перестала бы быть table-cell и строка таблицы разъехалась бы. */
table.items td.actions { text-align: right; white-space: normal; }
.button--small { padding: 3px 7px; font-size: 12px; margin: 2px 0 2px 4px; }

/* Квадратик цвета: только у известных базовых цветов (app/colors.py).
   Обводка нужна светлым — белый и бежевый иначе сливаются с фоном строки. */
.swatch {
  display: inline-block;
  width: 13px;
  height: 13px;
  margin-right: 6px;
  vertical-align: -2px;
  border-radius: 3px;
  border: 1px solid rgba(0, 0, 0, .25);
}

.empty { color: var(--muted); padding: 24px 0; }

/* --- модалка --- */

.modal {
  position: fixed;
  inset: 0;
  background: rgba(16, 20, 26, .45);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 32px 16px;
  overflow-y: auto;
  z-index: 10;
}

.modal__window {
  background: #fff;
  border-radius: 10px;
  padding: 20px;
  width: min(560px, 100%);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .25);
}

.modal__header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}
.modal__close {
  border: 0;
  background: none;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  color: var(--muted);
}
.modal__footer { display: flex; gap: 10px; margin-top: 18px; }
/* Вопрос в модалке подтверждения: это не подпись поля, а сам текст. */
.confirm { margin: 0 0 6px; font-size: 15px; }
.modal .toggle { margin-top: 12px; }

/* --- форма --- */

.field { margin-bottom: 14px; position: relative; }
.field > label { display: block; margin-bottom: 4px; font-weight: 600; font-size: 13px; }
.field > input[type="text"], .field > input[type="date"] { width: 100%; }

.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.row input[type="text"] { flex: 1 1 120px; min-width: 0; }

.piece { display: flex; gap: 8px; margin-bottom: 6px; }
.piece input { flex: 1 1 auto; min-width: 0; }

.total { margin: 6px 0 0; color: var(--muted); font-variant-numeric: tabular-nums; }

.formula { margin-top: 8px; padding: 8px; background: var(--bg-soft); border-radius: 6px; }
.formula label { font-size: 14px; }
.formula input { width: 90px; }
.hint { display: block; color: var(--muted); font-size: 12px; margin-top: 4px; }

/* Ширина колонок расположения тянется, а не фиксируется в px. */
.location {
  display: grid;
  grid-template-columns: repeat(3, minmax(80px, 1fr));
  gap: 8px;
}
.location .sub { display: flex; flex-direction: column; gap: 3px; }
.location .sub span { font-size: 12px; color: var(--muted); }
.location input { width: 100%; }

.note { margin: 0 0 12px; padding: 7px 10px; background: #eef7ee; border-radius: 6px; font-size: 13px; }
.error { color: var(--error); font-size: 13px; margin: 4px 0 0; }
.error--top { margin: 0 0 12px; }

/* --- автоподсказки --- */

.autocomplete { position: relative; }

.suggestions {
  list-style: none;
  margin: 2px 0 0;
  padding: 0;
  position: absolute;
  left: 0;
  right: 0;
  z-index: 5;
  background: #fff;
  border-radius: 6px;
  max-height: 220px;
  overflow-y: auto;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .16);
}
.suggestions:empty { display: none; }

.suggestion { padding: 6px 10px; cursor: pointer; }
.suggestion:hover, .suggestion.is-active { background: #e8f0fe; }
/* Остаток в подсказке бухты — приглушённым, как подпись «сейчас: …» под полем:
   выбирают всё-таки бухту, остаток тут справочный. */
.suggestion__stock { color: var(--muted); font-variant-numeric: tabular-nums; }

/* --- экран поставки --- */

/* Тот же оверлей, что и у модалки, но слоем ниже: форма товара открывается
   поверх экрана поставки, а не вместо него. */
.screen {
  position: fixed;
  inset: 0;
  background: rgba(16, 20, 26, .45);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 32px 16px;
  overflow-y: auto;
  z-index: 9;
}

.screen__window {
  background: #fff;
  border-radius: 10px;
  padding: 20px;
  width: min(900px, 100%);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .25);
}
.screen__window--narrow { width: min(460px, 100%); }

.screen h3 { font-size: 15px; margin: 0; }
.muted { color: var(--muted); font-weight: 400; font-size: 14px; }

/* Умолчания поставки: два поля в строку, подсказка под ними на всю ширину.
   Ширина полей не фиксируется — экран поставки уже, чем таблица склада, и
   растягиваться им есть куда. */
.delivery-defaults {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin-top: 4px;
}
.delivery-defaults .field { margin-bottom: 0; flex: 1 1 200px; }
.delivery-defaults .field input[type="text"] { width: 100%; }
.delivery-defaults .hint { flex-basis: 100%; margin-top: 0; }

.block { margin-top: 18px; }
.block__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}
.block > h3 { margin-bottom: 8px; }

.dropzone {
  border: 1px dashed var(--line);
  border-radius: 8px;
  padding: 14px;
  text-align: center;
  color: var(--muted);
  background: var(--bg-soft);
}
.dropzone p { margin: 0; }
.dropzone.is-over { border-color: var(--accent); background: #eef3fb; }

.files { list-style: none; margin: 10px 0 0; padding: 0; }
.file {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 5px 0;
  border-bottom: 1px solid var(--line);
}
.file a { color: var(--accent); }

/* Таблица товаров внутри экрана поставки: без sticky и colgroup — она узкая. */
/* min-width: 0 обязателен: без него таблица наследует min-width: 1370px от
   table.items и внутри 900-пиксельного окна поставки вылезает за его край,
   растягивая документ и роняя выравнивание модалки формы поверх экрана
   (формально .modal позиционируется от viewport, но горизонтальный скролл
   документа рвёт всю картинку). Ширины колонок тут не из colgroup, поэтому
   унаследованный min-width не значил ничего, кроме поломанной вёрстки. */
table.items--inline { width: 100%; min-width: 0; table-layout: auto; }
table.items--inline th, table.items--inline td { white-space: normal; }

/* --- вкладки --- */

.tabs { display: flex; gap: 4px; margin-bottom: 14px; border-bottom: 1px solid var(--line); }
.tab {
  padding: 8px 16px;
  border: 1px solid transparent;
  border-bottom: 0;
  border-radius: 8px 8px 0 0;
  background: none;
  cursor: pointer;
  color: var(--muted);
  margin-bottom: -1px;
}
.tab:hover { background: var(--bg-soft); }
.tab.is-active {
  background: #fff;
  border-color: var(--line);
  color: inherit;
  font-weight: 600;
}

/* --- карточки сертификатов --- */

.cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 12px;
}
.card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fff;
  cursor: pointer;
}
.card:hover, .card:focus { border-color: var(--accent); outline: none; }
.card__title { font-weight: 600; }
.card__meta { color: var(--muted); font-size: 13px; }

/* --- привязанные марки --- */

.chips { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 6px 3px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--bg-soft);
  font-size: 14px;
}
.chip__remove {
  border: 0;
  background: none;
  cursor: pointer;
  color: var(--muted);
  font-size: 16px;
  line-height: 1;
  padding: 0 2px;
}
.chip__remove:hover { color: var(--error); }

/* --- выбор марок --- */

.picker {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 320px;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: 8px;
}
/* Фильтр прячет строки атрибутом hidden — display у строки не задаём, чтобы
   его не пришлось перебивать !important. */
.picker__row { border-bottom: 1px solid var(--line); }
.picker__row:last-child { border-bottom: 0; }
.picker__row label { display: block; padding: 6px 10px; cursor: pointer; }
.picker__row label:hover { background: var(--bg-soft); }
.picker__row input { margin-right: 8px; }

/* --- пополнение и списание --- */

/* Остаток над полями модалки: потолок для списания виден без переключения
   контекста, поэтому он часть формы, а не подсказка мелким шрифтом. */
.stock {
  margin: 0 0 14px;
  padding: 8px 10px;
  background: var(--bg-soft);
  border-radius: 6px;
}
.stock__title { display: block; font-weight: 600; }
.stock__now { color: var(--muted); font-variant-numeric: tabular-nums; }

/* Плоские таблицы вкладки «Движения»: без colgroup и sticky — колонок мало
   и подгонять их друг под друга не с чем. */
table.items--flat { table-layout: auto; min-width: 0; width: 100%; }
/* Причина движения — свободный текст, ему перенос нужнее многоточия. */
table.items--flat td { white-space: normal; overflow: visible; }

.log__head { font-size: 15px; margin: 22px 0 8px; }
.kind--in { color: #1f7a3d; }
.kind--out { color: #a4491f; }

/* --- журнал движений: подсветка и раскрытие истории --- */

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

   Фон приглушённый, а акцент вынесен в полосу слева: это таблица данных, а не
   алерт, и красный во всю строку кричал бы на каждое обычное списание. Текст
   при этом остаётся тем же — контраст обычного тёмного текста на #fdf1f2 и
   #eff7f0 не хуже, чем на белом.

   Полоса — inset box-shadow, а не border-left: border сдвинул бы содержимое
   первой ячейки на свою толщину, и подсвеченные строки перестали бы совпадать
   по вертикали с непокрашенными.

   Специфичность тут та же, что у общего `table.items td` с белым фоном
   (по классу и по два элемента), поэтому правила обязаны идти НИЖЕ него —
   как и идут, в конце файла. */
tr.move--out td { background: #fdf1f2; }
tr.move--in td { background: #eff7f0; }
tr.move--out > td:first-child { box-shadow: inset 3px 0 0 #d38b93; }
tr.move--in > td:first-child { box-shadow: inset 3px 0 0 #79ad84; }

/* Строка журнала кликабельна целиком, включая «Кто» и «Причина»: попасть в
   раскрытие надо мышкой, а не в конкретную колонку. Треугольник рисуем через
   ::before первой ячейки, а не разметкой — ячейки общие с раскрытой историей,
   а она не кликабельна и указателя иметь не должна. */
tr.log-row { cursor: pointer; }
tr.log-row > td:first-child::before {
  content: "\25B8";
  display: inline-block;
  width: 14px;
  color: var(--muted);
  transition: transform .12s;
}
tr.log-row.is-open > td:first-child::before { transform: rotate(90deg); }
tr.log-row:hover td { filter: brightness(.97); }

/* История одной бухты под своей строкой журнала: та же подсветка прихода и
   расхода (это те же движения), но со сдвигом первой ячейки и без полосы —
   иначе вложенность не читалась бы вовсе, а две одинаковые полосы подряд
   выглядели бы как две независимые строки журнала. */
tr.log-detail > td:first-child {
  padding-left: 26px;
  box-shadow: inset 1px 0 0 var(--line);
}
tr.log-detail td { font-size: 13px; }

/* --- вкладка «Задания» --- */

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

   Рамка вокруг строки нужна: строк в задании несколько, и без неё три поля
   следующей читались бы как продолжение предыдущей. */
.task-line {
  display: grid;
  grid-template-columns: minmax(240px, 2fr) 1fr 1fr;
  gap: 12px;
  padding: 12px;
  margin-bottom: 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg-soft);
}
.task-line .field { margin-bottom: 0; }
.task-line .field > input[type="text"] { width: 100%; }
/* Подсказки бухт живут внутри строки — они обязаны лечь ПОВЕРХ соседней. */
.task-line .suggestions { z-index: 7; }
/* Ошибка и остаток относятся ко всей строке, а не к одной колонке. */
.task-line > .error { grid-column: 1 / -1; margin: 0; }

.task-note { margin-top: 14px; }
.task-note textarea {
  width: 100%;
  font: inherit;
  padding: 6px 9px;
  border: 1px solid var(--line);
  border-radius: 6px;
  resize: vertical;
}

/* Примечание в карточке — текст человека, ему нужен перенос и своя строка. */
.card__note { font-size: 13px; white-space: pre-wrap; }
.card__note--done { color: var(--muted); }
.card--done { background: var(--bg-soft); }

/* Подтверждение выполнения: список того, что сейчас спишется. Таблицей это не
   делаем — колонок две, а на телефоне таблица всё равно стала бы карточками. */
.write-offs { list-style: none; margin: 0; padding: 0; }
.write-off {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px;
  margin-bottom: 8px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
}
.write-off__title { font-weight: 600; }
.write-off__amount { font-variant-numeric: tabular-nums; }
/* Пропущенная строка приглушена, но видна: пропуск — тоже решение, и увидеть
   его перед списанием надо. */
.write-off--skipped { background: var(--bg-soft); color: var(--muted); }
.write-off--skipped .write-off__title { font-weight: 400; }

/* --- срочность и дедлайн задания --- */

/* Срочность и дата стоят рядом: оба про «когда», и на десктопе занимают одну
   строку под примечанием. На узком экране перенос делает сам flex-wrap. */
/* Галочка выравнивается по центру поля даты, а не по низу: у поля есть подпись
   сверху и «Необязательно» снизу, и по любому краю галочка вставала бы против
   них, а не против самого поля. */
.task-flags { display: flex; flex-wrap: wrap; align-items: center; gap: 20px; margin-top: 12px; }
.task-flags .field { margin: 0; }
.task-flags .toggle { margin: 0; }
/* Строка «Срочно · Дедлайн: …» на экране выполнения — тот же зелёный блок
   `.note`, что и примечание задания: это такая же вводная от создавшего. */
.task-flags-note { display: flex; align-items: center; gap: 10px; }

/* Бейдж «Срочно». Акцентный, но не красный: красный в этом приложении уже
   занят просрочкой и расходом в журнале, и два красных значения на одной
   карточке перестали бы различаться. */
.badge {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.6;
  vertical-align: middle;
}
.badge--urgent { background: #fdeee0; color: #a4491f; border: 1px solid #e6b892; }

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

   Полоса — inset box-shadow, а не border-left: border сдвинул бы содержимое
   карточки на свою толщину, и подсвеченные карточки разъехались бы с
   обычными по сетке. Правило идёт НИЖЕ `.card` — там белый фон по тому же
   весу селектора. */
.card--overdue { background: #fdf1f2; box-shadow: inset 3px 0 0 #d38b93; }
.card__meta--overdue { color: #a4491f; }

/* ====================================================================== */
/* --- мобильный вид ---------------------------------------------------- */
/* ====================================================================== */

/* Один breakpoint на всё приложение: max-width: 768px. Всё, что ниже этого
   комментария, кроме одного правила про новые элементы, живёт ВНУТРИ @media —
   десктопный вид этим блоком не затронут ни одним свойством.

   Разметка тронута так же осторожно: гамбургер, блок пользователя внутри
   ящика, подложка и кнопка «Фильтры» выше breakpoint не показываются вовсе, а
   data-label — атрибут, который без ::before ничего не рисует. */

.nav-toggle,
.nav-user,
.nav-backdrop,
.filters-toggle { display: none; }

@media (max-width: 768px) {

  /* --- общее --- */

  body { padding: 12px; }
  h1 { font-size: 19px; margin: 0; }

  /* 16px у полей ввода — не про читаемость, а про зум: меньший размер шрифта
     мобильный Safari считает поводом увеличить страницу на фокусе, и после
     ввода она остаётся увеличенной. 44px — минимальная площадь под палец. */
  input[type="text"], input[type="search"], input[type="date"],
  input[type="password"], select {
    font-size: 16px;
    min-height: 44px;
    padding: 8px 10px;
  }
  .button { min-height: 44px; padding: 10px 14px; }
  .button--small { min-height: 44px; padding: 10px 12px; font-size: 14px; margin: 0; }
  .button--icon { min-width: 44px; min-height: 44px; }
  .suggestion { min-height: 44px; padding: 12px 12px; }
  .toggle { min-height: 44px; }
  .toggle input { width: 20px; height: 20px; }
  .doc-link { display: inline-block; padding: 8px 0; }

  /* --- шапка и гамбургер --- */

  .page-header { align-items: center; gap: 10px; margin-bottom: 12px; }
  /* Имя, роль и «Выйти» переезжают в ящик: в шапке телефона на них не
     остаётся ширины рядом с гамбургером и заголовком. */
  .page-header .whoami { display: none; }

  .nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 44px;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: #fff;
    cursor: pointer;
  }
  /* Три полоски: сама полоса и две её тени сверху и снизу. */
  .nav-toggle__bars,
  .nav-toggle__bars::before,
  .nav-toggle__bars::after {
    display: block;
    width: 20px;
    height: 2px;
    border-radius: 2px;
    background: #16191d;
  }
  .nav-toggle__bars { position: relative; }
  .nav-toggle__bars::before { content: ""; position: absolute; top: -6px; }
  .nav-toggle__bars::after { content: ""; position: absolute; top: 6px; }

  /* --- выдвижной ящик: та же .tabs, что и на десктопе --- */

  /* Вкладки не дублируются второй разметкой, а переезжают: две копии кнопок
     разъехались бы по активному классу (его ставит app.js по [data-tab]). */
  .tabs {
    position: fixed;
    z-index: 30;
    top: 0;
    left: 0;
    bottom: 0;
    width: 82vw;
    max-width: 320px;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    margin: 0;
    padding: 12px;
    border-bottom: 0;
    background: #fff;
    box-shadow: 2px 0 24px rgba(0, 0, 0, .25);
    overflow-y: auto;
    transform: translateX(-100%);
    transition: transform .18s ease-out;
  }
  body.nav-open .tabs { transform: translateX(0); }

  .tab {
    min-height: 48px;
    margin: 0 0 4px;
    text-align: left;
    border: 1px solid transparent;
    border-radius: 8px;
  }
  .tab.is-active { background: var(--bg-soft); border-color: var(--line); }

  .nav-user {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: auto;
    padding-top: 12px;
    border-top: 1px solid var(--line);
    font-size: 14px;
  }
  .nav-user form { margin: 0 0 0 auto; }

  body.nav-open .nav-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 29;
    background: rgba(16, 20, 26, .45);
  }
  /* Под открытым ящиком страница не прокручивается. */
  body.nav-open { overflow: hidden; }

  /* --- таблицы: карточки вместо строк --- */

  /* Горизонтального скролла ниже breakpoint нет вообще: sticky-колонки,
     colgroup и min-width: 1370px — целиком десктопная история, тут таблица
     раскладывается в столбец карточек средствами CSS, без перестройки DOM.

     Селекторы длиннее необходимого намеренно: десктопные правила фона и
     nowrap висят на "tr.что-то td" (специфичность 0,1,2 и выше), и коротким
     "table.items td" их не перебить. */
  .table-wrap { overflow-x: visible; }
  .table-wrap colgroup { display: none; }
  .table-wrap table.items {
    display: block;
    width: 100%;
    min-width: 0;
  }
  .table-wrap table.items thead { display: none; }
  .table-wrap table.items tbody { display: block; }

  .table-wrap table.items tr {
    display: block;
    margin-bottom: 10px;
    padding: 10px 12px;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: #fff;
  }
  .table-wrap table.items tr td {
    display: block;
    position: static;
    padding: 3px 0;
    border: 0;
    background: transparent;
    box-shadow: none;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    text-align: left;
  }
  /* Подпись поля перед значением. Само значение — из разметки, подпись — из
     data-label той же ячейки, поэтому шапка и карточки не могут разъехаться. */
  .table-wrap table.items tr td[data-label]::before {
    content: attr(data-label) ": ";
    color: var(--muted);
    font-size: 12px;
  }
  /* Пустая ячейка (место хранения и вес группы, пустые sticky-2/3 раскрытой
     бухты) строки с одной подписью не занимает. */
  .table-wrap table.items tr td:empty { display: none; }

  /* Марка/Сечение/Цвет группы — заголовок карточки одной строкой и без
     подписей: что тут марка, а что цвет, видно и так. */
  .table-wrap table.items tr.group > td.sticky-1,
  .table-wrap table.items tr.group > td.sticky-2,
  .table-wrap table.items tr.group > td.sticky-3 {
    display: inline;
    padding: 0;
    font-size: 16px;
    font-weight: 600;
  }
  .table-wrap table.items tr.group > td.sticky-2::before,
  .table-wrap table.items tr.group > td.sticky-3::before {
    content: " · ";
    color: var(--muted);
    font-weight: 400;
  }

  /* Раскрытая бухта — та же карточка со сдвигом и полосой слева: карточки идут
     подряд, и без сдвига вложенность в группу не читалась бы. */
  .table-wrap table.items tr.detail {
    margin-left: 14px;
    border-left: 3px solid var(--accent);
    background: var(--bg-soft);
  }
  .table-wrap table.items tr.detail--empty { background: #f2f1ee; }
  .table-wrap table.items tr.detail > td.sticky-1 {
    padding-bottom: 4px;
    font-size: 15px;
    font-weight: 600;
  }
  .table-wrap table.items tr.detail > td.sticky-1 .bale-id,
  .table-wrap table.items--flat tr > td:first-child .bale-id {
    padding-left: 0;
    font-size: 15px;
    color: inherit;
  }

  /* Первая ячейка плоских таблиц — заголовок карточки: дата в журнале, подпись
     бухты в поиске «Движений» и на экране паспорта, марка в товарах поставки.
     Подписи у неё нет намеренно: в журнале это же ::before рисует треугольник
     раскрытия истории. */
  .table-wrap table.items--flat tr > td:first-child,
  .table-wrap table.items--inline tr > td:first-child {
    padding-bottom: 4px;
    font-size: 15px;
    font-weight: 600;
  }

  /* Журнал: подсветка прихода и расхода переезжает с ячеек на карточку —
     полоса слева больше не может быть тенью первой ячейки. */
  .table-wrap table.items tr.move--in { background: #eff7f0; border-left: 3px solid #79ad84; }
  .table-wrap table.items tr.move--out { background: #fdf1f2; border-left: 3px solid #d38b93; }
  .table-wrap table.items tr.log-detail { margin-left: 14px; }
  .table-wrap table.items tr.log-detail > td:first-child { padding-left: 0; }

  /* Кнопки раскрытой бухты (их до пяти) — сеткой, а не полосой мелких кнопок
     в ряд. auto-fit: одна кнопка занимает всю ширину, две и больше встают
     по две в ряд. */
  .table-wrap table.items tr td.actions {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 8px;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--line);
  }
  .table-wrap table.items tr td.actions .button { width: 100%; margin: 0; }

  /* --- тулбары, фильтры, карточки --- */

  .toolbar { flex-direction: column; align-items: stretch; gap: 8px; }
  .toolbar input[type="search"] { max-width: none; flex: 1 1 auto; }
  .toolbar .button, .toolbar a.button { width: 100%; text-align: center; }

  /* Кнопка «Фильтры» и свёрнутая по умолчанию панель «Движений». Панель
     прячется через display, а не hidden и не удалением из DOM: её скрытые
     *_id обязаны уезжать в hx-include и свёрнутыми. */
  .filters-toggle {
    display: block;
    width: 100%;
    min-height: 44px;
    margin-bottom: 12px;
    padding: 10px 14px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: #fff;
    font: inherit;
    text-align: left;
    cursor: pointer;
  }
  .filters-toggle::after { content: " \25B8"; color: var(--muted); }
  .filters-toggle[aria-expanded="true"]::after { content: " \25BE"; }
  .filters { display: none; }
  .filters.is-open { display: flex; }
  .filters .field { width: 100%; }
  .filters .button { width: 100%; }

  .cards { grid-template-columns: 1fr; }
  .card { padding: 14px; }

  /* --- модалки и экраны: во весь экран --- */

  /* Центрированное окошко поверх фона на телефоне съедает половину высоты
     рамкой и отступами. Ниже breakpoint форма — отдельный экран. */
  .modal, .screen { padding: 0; align-items: stretch; }
  .modal__window,
  .modal__window--narrow,
  .screen__window,
  .screen__window--narrow {
    width: 100%;
    min-height: 100%;
    padding: 14px 14px 24px;
    border-radius: 0;
    box-shadow: none;
  }
  .modal__close { flex: 0 0 44px; width: 44px; height: 44px; font-size: 30px; }
  .modal__footer { flex-direction: column; gap: 8px; }
  .modal__footer .button { width: 100%; }

  /* Поля формы — в одну колонку: «Расположение» на десктопе три поля в ряд. */
  .location { grid-template-columns: 1fr; }
  .field > input[type="text"], .field > input[type="date"] { width: 100%; }
  .row select { min-width: 96px; }
  .row .button { flex: 1 1 100%; }
  .piece input { min-width: 0; }
  .formula input { width: 100%; max-width: 150px; }
  .delivery-defaults .field { flex: 1 1 100%; }

  .block__head { flex-wrap: wrap; }
  .block__head .toggle { margin-left: 0; }
  .block__head .button { width: 100%; }

  .file { flex-wrap: wrap; }
  .file a { flex: 1 1 100%; padding: 8px 0; word-break: break-all; }
  .file .button { margin-left: auto; }
  .chip { padding: 6px 6px 6px 12px; font-size: 15px; }
  .chip__remove { min-width: 36px; min-height: 36px; }
  .picker { max-height: 50vh; }
  .picker__row label { min-height: 44px; padding: 12px 10px; }

  /* --- задания --- */

  /* Три колонки строки задания на телефоне не помещаются вовсе: поле поиска
     бухты становится нечитаемым уже на второй колонке. Кладём в одну. */
  .task-line { grid-template-columns: 1fr; gap: 10px; }

  /* --- вход --- */

  .login { max-width: none; margin: 6vh auto 0; }
  .login__form { padding: 16px; }
  .login__form .button { width: 100%; }
}
