/* Светлая палитра ZooWork. Тёмная тема убрана целиком: и медиазапрос
   prefers-color-scheme, и фиксированный тёмный набор, что стоял тут
   раньше. Значения — из бандла design_handoff_zoomix_redesign/README.md,
   менять их на глазок нельзя: те же цифры продублированы в <style>
   внутри warehouse.html. */
:root {
  --bg: #eef0f2;
  --surface: #ffffff;
  --surface-2: #f6f7f8;
  --surface-3: #f1f3f5;
  --surface-4: #eff1f3;

  --ink: #14181c;
  --ink-2: #2b333a;
  --ink-3: #4a5560;
  --label: #5c666f;

  --line: #c9ced3;
  --line-input: #a9b0b7;
  --line-mid: #d3d7db;
  --line-soft: #e3e7ea;

  --accent: #0d5f52;
  --accent-ink: #0a4a40;
  --accent-soft: #eef6f4;
  --accent-line: #9cc4bc;

  /* Статусы: у каждого свой цвет текста, подложка и граница. Цвет никогда
     не единственный признак — рядом всегда иконка и подпись. */
  --ok-ink: #0f5029;   --ok-bg: #e7f2ec;   --ok-line: #7fb595;   --ok-dot: #178048;
  --ok-ink-2: #12572f; --ok-bg-2: #f1f8f3; --ok-line-2: #b3d5c2;
  --busy-ink: #6f4008;   --busy-bg: #fbf1e3;   --busy-line: #cfa768;
  --busy-ink-2: #7a4708; --busy-bg-2: #fbf3e8; --busy-line-2: #ddc39a;
  --book-ink: #1a3b78;   --book-bg: #eaf0fb;   --book-line: #8ba4d6;
  --book-ink-2: #1c3f80; --book-bg-2: #eef2fb; --book-line-2: #b6c4e5;
  --prep-ink: #43297a;   --prep-bg: #f2ecfa;   --prep-line: #a693cf;
  --prep-ink-2: #4b3383; --prep-bg-2: #f4f0fa; --prep-line-2: #c8bce0;

  /* Подсказка и предупреждение — тёплая плашка с левой полосой. */
  --note-bg: #fbf9f5; --note-line: #e2d6c2; --note-bar: #cfa768;

  /* Разрушающее действие. Красного как «опасности» в палитре нет:
     кнопка нейтральная, опасность объясняется словами в подтверждении. */
  --danger-ink: #6d3232; --danger-bg: #faf5f5;
  --danger-line: #d9c3c3; --danger-line-2: #b98686;

  --mono: "Roboto Mono", Consolas, ui-monospace, SFMono-Regular, monospace;
  --sans: "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif;

  /* Высота, которую шапка обязана уступить статус-бару. В браузере её
     задаёт сам браузер (обычно 0), с домашнего экрана — вырез айфона. */
  --safe-top: env(safe-area-inset-top, 0px);
}

/* Запущено с домашнего экрана: страница идёт во весь экран, под часы и
   Dynamic Island. Полагаться на одно env() нельзя — в этом режиме iOS
   отдавал 0, и шапка садилась ровно на вырез (фото от 29.08.2026).
   Поэтому снизу подпираем фиксированной величиной: что больше, то и берём.
   Оба признака standalone дублируют друг друга — медиазапрос и класс,
   который ставит navigator.standalone в <head> страницы. */
@media (display-mode: standalone), (display-mode: fullscreen) {
  :root { --safe-top: max(env(safe-area-inset-top, 0px), 54px); }
}
html.standalone { --safe-top: max(env(safe-area-inset-top, 0px), 54px); }

* { box-sizing: border-box; }
body {
  margin: 0;
  font: 16px/1.5 var(--sans);
  background: var(--bg);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}

/* Кольцо фокуса одно на весь проект: работа с клавиатуры должна быть
   видна на любой кнопке, поле, чипе и карточке. */
:focus-visible { outline: 3px solid var(--accent); outline-offset: 1px; }

/* ================================================================ шапка */

header {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  min-height: 64px; background: var(--surface);
  border-bottom: 1px solid var(--line-mid);
  position: sticky; top: 0; z-index: 40;
  padding: 10px 24px;
  padding-top: calc(var(--safe-top) + 10px);
}
.brand { width: 36px; height: 36px; border-radius: 8px; flex: none; }
a.brand-link { display: flex; align-items: center; gap: 12px; text-decoration: none; color: inherit; }
h1 { margin: 0; font-size: 19px; font-weight: 600; letter-spacing: -0.01em; }
h1 span { color: var(--ink-3); font-weight: 400; }
.crumb {
  font-size: 15px; color: var(--ink-3);
  padding-left: 16px; border-left: 1px solid var(--line-mid);
}
.spacer { flex: 1; }
.who { color: var(--ink-3); font-size: 15px; }
.who b { color: var(--ink); font-weight: 600; }

/* Ссылка, которая должна выглядеть и нажиматься как кнопка: цель у мыши
   крупная, потому что за этим экраном сидят не только с клавиатурой. */
.ghost-link {
  display: inline-flex; align-items: center; height: 40px; padding: 0 16px;
  font-size: 15px; color: var(--ink-2); text-decoration: none;
  background: var(--surface); border: 1px solid var(--line); border-radius: 6px;
  transition: background .13s, border-color .13s;
}
.ghost-link:hover { background: var(--surface-3); border-color: var(--line-input); }

/* ============================================================== каркас */

.shell { display: flex; align-items: stretch; min-height: 0; }

.sidenav {
  width: 264px; flex: none; background: var(--surface);
  border-right: 1px solid var(--line-mid);
  padding: 16px 12px 32px;
  position: sticky; top: calc(var(--safe-top) + 64px);
  align-self: flex-start;
  height: calc(100vh - var(--safe-top) - 64px);
  overflow-y: auto;
}
.nav-group {
  padding: 18px 12px 6px; font-size: 12.5px; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--label);
}
.nav-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 42px; padding: 0 12px; margin: 2px 0;
  font: 16px/1.3 var(--sans); text-align: left; text-decoration: none;
  color: var(--ink); background: var(--surface);
  border: 1px solid transparent; border-radius: 6px; cursor: pointer;
  transition: background .13s, border-color .13s;
}
.nav-item span { flex: 1; }
.nav-item:hover { background: var(--surface-3); border-color: var(--line-mid); }
.nav-item.active {
  font-weight: 600; color: var(--accent-ink); background: #e2efec;
  border: 1px solid #b9d8d2; border-left: 4px solid var(--accent);
  padding-left: 9px;
}
.nav-item.active:hover { background: #e2efec; border-color: #b9d8d2; }
/* Закрытый раздел виден, но нажать его нельзя: причина написана на
   плитке раздела, отдельного экрана «закрыто» в проекте нет. */
.nav-item.locked { color: var(--label); cursor: default; }
.nav-item.locked:hover { background: var(--surface); border-color: transparent; }

main { flex: 1; min-width: 0; padding: 24px 32px 48px; }

/* Нижняя панель — только на телефоне. Четыре пункта, текущий выделен
   цветом и жирным: цвет здесь не единственный признак. */
.tabbar { display: none; }

/* ================================================================ вход */

.login-page {
  display: flex; align-items: center; justify-content: center;
  min-height: 100vh; padding: 24px;
}
.login-box {
  width: 100%; max-width: 380px; text-align: center;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; padding: 32px 28px;
}
/* Подложка под логотипом больше не нужна: фон и так белый. */
.login-logo { width: 100%; max-width: 250px; height: auto; }
.login-box h1 { margin: 16px 0 24px; font-size: 20px; }
.login-box label {
  display: block; text-align: left; margin: 0 0 6px;
  font-size: 14.5px; font-weight: 700; color: var(--label);
}
.login-box input {
  width: 100%; height: 46px; padding: 0 12px; margin-bottom: 16px;
  border: 1px solid var(--line-input); border-radius: 6px;
  background: var(--surface); color: var(--ink);
  font-size: 16.5px;   /* меньше 16px — Safari зумит страницу при фокусе */
  transition: border-color .13s;
}
.login-box input:focus { border-color: var(--accent); }
.login-box button { width: 100%; height: 46px; font-size: 16.5px; }
.login-error {
  color: var(--danger-ink); font-size: 15.5px; margin: 16px 0 0; min-height: 1em;
}

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

.tabs {
  display: flex; gap: 4px; flex-wrap: wrap;
  border-bottom: 1px solid var(--line-mid); margin-bottom: 16px;
}
.tab {
  height: 44px; padding: 0 18px; font-size: 16.5px; color: var(--ink-2);
  background: transparent; border: 1px solid transparent;
  border-radius: 6px 6px 0 0; cursor: pointer;
  transition: background .13s;
}
/* Наведение на вкладку не должно выглядеть как выбранная вкладка: общее
   правило button:hover перебивало .tab:hover по весу и рисовало ту же
   подложку с рамкой. Из-за этого «не работает кнопка» выглядело так, будто
   вкладка переключилась, хотя она просто была под курсором. */
.tab:hover:not(.active) { background: var(--surface-3); border-color: transparent; }
.tab.active {
  font-weight: 600; color: var(--accent-ink); background: var(--surface);
  border-color: var(--line-mid); border-bottom: 3px solid var(--accent);
  margin-bottom: -1px;
}
.badge {
  display: inline-block; min-width: 22px; padding: 1px 7px; margin-left: 6px;
  background: var(--busy-bg); color: var(--busy-ink);
  border: 1px solid var(--busy-line); border-radius: 5px;
  font-size: 14px; font-weight: 600; text-align: center;
}
.badge:empty, .badge.zero { display: none; }

/* ============================================================== панели */

.panel { display: none; }
.panel.active { display: block; }

.card, .pane {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 10px; padding: 20px;
}
.pane h2 { margin: 0 0 8px; font-size: 20px; font-weight: 600; }
.pane-head { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.pane-head h2 { margin: 0; }

h2 { font-size: 20px; font-weight: 600; }
h3 { margin: 22px 0 10px; font-size: 17.5px; font-weight: 600; }

.page-head { margin-bottom: 14px; }
.page-head h1 { font-size: 24px; font-weight: 600; }
.page-head p { margin: 6px 0 0; font-size: 16.5px; color: var(--ink-3); }
/* Счётчики групп — справочные, крупными их держать незачем: место наверху
   дороже, под ним рабочие кнопки. */
.page-head .chips { margin-top: 10px; }
.page-head .chip { height: 32px; padding: 0 11px; font-size: 15px; }

/* Две колонки: слева ввод, справа то, что из него получилось. Колонки
   выравниваются по верху — иначе короткая тянется под высоту длинной. */
.split {
  display: grid; gap: 20px; align-items: start;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.split > .col, .split > .pane { min-width: 0; }
.hidden { display: none; }

/* Подсказка — тёплая плашка с левой полосой, а не серый мелкий текст:
   её читают, а не пролистывают. */
.hint {
  margin: 0 0 14px; padding: 12px 14px; font-size: 16px; line-height: 1.5;
  background: var(--note-bg); border: 1px solid var(--note-line);
  border-left: 4px solid var(--note-bar); border-radius: 8px;
}
.note { font-size: 15.5px; color: var(--ink-3); }
.warn-note { color: var(--busy-ink); }

textarea, input[type=text], input[type=number], input[type=date] {
  width: 100%; padding: 12px 14px;
  border: 1px solid var(--line-input); border-radius: 8px;
  background: var(--surface); color: var(--ink);
  font: 16.5px/1.5 var(--sans);
  transition: border-color .13s;
}
textarea { font: 16px/1.7 var(--mono); resize: vertical; }
textarea:focus, input:focus { border-color: var(--accent); }

/* ============================================================== кнопки */

.row { display: flex; gap: 10px; align-items: center; margin: 16px 0; flex-wrap: wrap; }

button {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 44px; padding: 0 16px; border-radius: 6px;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink);
  font: 16.5px/1 var(--sans); cursor: pointer;
  transition: background .13s, border-color .13s, color .13s;
}
button:hover:not(:disabled) { background: var(--surface-3); border-color: var(--line-input); }
button:disabled { color: #7b848c; background: var(--surface-4); border-color: var(--line-mid); cursor: default; }
button.primary {
  height: 46px; padding: 0 22px; font-weight: 600;
  color: #fff; background: var(--accent); border-color: var(--accent);
}
button.primary:hover:not(:disabled) { background: var(--accent-ink); border-color: var(--accent-ink); }
/* «Применить», «Сегодня», «Откатить» — вторичные кнопки с акцентной
   рамкой: сплошная заливка одна на экран, у кнопки, которую жмут первой. */
button.go {
  font-weight: 600; color: var(--accent-ink);
  background: var(--surface); border-color: var(--accent);
}
button.go:hover:not(:disabled) { background: var(--accent-soft); }
button.ghost { color: var(--ink-3); }
button.small { height: 36px; padding: 0 12px; font-size: 15px; }
/* Разрушающее действие: нейтральная кнопка, никакой красной заливки. */
button.danger { font-size: 16px; color: var(--danger-ink); background: var(--danger-bg); border-color: var(--danger-line); }
button.danger:hover:not(:disabled) { background: #f5eaea; border-color: #c2a1a1; }
/* Ссылка-действие внутри карточки («очистить», «Удалить совсем»). */
button.linky {
  height: auto; min-height: 40px; padding: 0 6px; font-size: 15.5px;
  color: var(--ink-3); background: transparent; border: none;
  text-decoration: underline;
}
button.linky:hover:not(:disabled) { color: var(--ink); background: transparent; }
button.linky.danger { color: var(--danger-ink); background: transparent; border: none; }

/* Скачивание — обычная ссылка, а не кнопка: браузер сам качает файл,
   а на айфоне открывает его в «Файлах». Выглядеть должна как кнопка. */
.filebtn, a.primary {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 46px; padding: 0 18px; border-radius: 6px;
  border: 1px solid var(--line); background: var(--surface);
  font-size: 16.5px; cursor: pointer; text-decoration: none;
  transition: background .13s, border-color .13s;
}
a.primary {
  font-weight: 600; color: #fff;
  background: var(--accent); border-color: var(--accent);
}
a.primary:hover { background: var(--accent-ink); border-color: var(--accent-ink); }
/* «Сохранить файл» — тоже ссылка: без этого браузер красит её как обычную. */
a.filebtn { color: var(--ink); }
.filebtn:hover { background: var(--surface-3); border-color: var(--line-input); }
.filebtn.busy { opacity: .6; cursor: progress; }
.filebtn input { display: none; }

/* Разобранных заявок в одной вставке бывает несколько — карточки не
   должны слипаться. Блок стоит над полями ввода, поэтому отступ снизу. */
#order-result .card { margin-bottom: 20px; }
#order-result > h3 { margin: 0 0 12px; }
#order-result .err-box { margin-top: 0; }

/* Подтверждение необратимого действия — блок на месте, а не окно браузера:
   человек видит, что именно исчезнет, и может передумать. */
.confirm {
  margin-top: 14px; padding: 16px; max-width: 620px;
  background: var(--danger-bg); border: 1px solid var(--danger-line); border-radius: 8px;
}
.confirm-title { font-size: 16.5px; font-weight: 600; margin-bottom: 6px; }
.confirm-text { font-size: 16px; color: var(--ink-2); margin-bottom: 14px; }
.confirm .row { margin: 0; }
.confirm button.yes {
  font-weight: 600; color: var(--danger-ink);
  background: var(--surface); border-color: var(--danger-line-2);
}
.confirm button.yes:hover { background: #f5eaea; }

/* ================================================== зона перетаскивания */

.dropzone {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; padding: 44px 24px; cursor: pointer;
  border: 2px dashed var(--accent-line); border-radius: 12px;
  background: #f8fbfa; text-align: center;
  transition: border-color .13s, background .13s;
}
.dropzone:hover, .dropzone.over { border-color: var(--accent); background: var(--accent-soft); }
.drop-title { font-size: 19px; font-weight: 600; }
.drop-note { font-size: 16px; color: var(--ink-3); }
/* Внутри <label> настоящая кнопка ловила бы клик на себя и открывала
   выбор файла дважды. Поэтому это span, который просто выглядит кнопкой. */
.fake-btn {
  display: inline-flex; align-items: center; justify-content: center;
  height: 46px; padding: 0 22px; margin-top: 4px;
  font-size: 16.5px; font-weight: 600; color: #fff;
  background: var(--accent); border: 1px solid var(--accent); border-radius: 6px;
}
.dropzone:hover .fake-btn { background: var(--accent-ink); border-color: var(--accent-ink); }

/* Свёрнутая подсказка: нужна раз в жизни, а место занимает каждый день. */
button.toggle {
  width: 100%; justify-content: flex-start; margin-bottom: 14px;
  font-size: 16px; font-weight: 600; color: var(--accent-ink);
}
button.toggle .label { flex: 1; text-align: left; }
button.toggle .chev { transition: transform .13s; }
button.toggle[aria-expanded="true"] .chev { transform: rotate(180deg); }

/* Вкладки «Файл заказа» / «Заявка текстом» — только на телефоне: на широком
   экране обе колонки стоят рядом, переключать нечего. */
.pane-tabs { display: none; }

/* ================================================== строки разбора */

.item {
  display: flex; gap: 12px; align-items: baseline;
  padding: 10px 12px; margin-bottom: 6px; font-size: 16px;
  background: var(--surface-2); border: 1px solid var(--line-mid);
  border-left: 4px solid var(--line); border-radius: 6px;
}
.item .mark { flex: none; width: 22px; text-align: center; font-family: var(--mono); font-weight: 700; }
.item .body { flex: 1; min-width: 0; }
.item .note { font-size: 15px; }
.item.ok      { background: var(--ok-bg-2);   border-color: var(--ok-line-2);   border-left-color: var(--ok-ink); }
.item.already { background: var(--busy-bg-2); border-color: var(--busy-line-2); border-left-color: var(--busy-line); }
.item.partial { background: var(--busy-bg-2); border-color: var(--busy-line-2); border-left-color: var(--busy-line); }
.item.need    { background: var(--note-bg);   border-color: var(--note-line);   border-left-color: var(--note-bar); }
.item.err     { background: var(--danger-bg); border-color: var(--danger-line); border-left-color: var(--danger-line-2); }

.cands { margin: 8px 0 12px 34px; }
.cand {
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
  padding: 8px 12px; margin-bottom: 6px; font-size: 15.5px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 6px;
}
.cand .score { color: var(--ink-3); font-family: var(--mono); }
.cand .name { flex: 1; min-width: 140px; }
.picker { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 12px; }
.picker button { text-align: left; justify-content: flex-start; }

/* ================================================== сводки и счётчики */

.summary {
  margin: 16px 0; padding: 14px 16px; font-size: 16.5px;
  background: var(--surface-2); border: 1px solid var(--line-mid); border-radius: 8px;
}
.summary.ok { background: var(--ok-bg-2); border-color: var(--ok-line-2); color: var(--ok-ink-2); }

/* Плитки сводки: цифра моноширинная, в цвете статуса. */
.tiles { display: flex; gap: 10px; flex-wrap: wrap; margin: 14px 0; }
.tile {
  min-width: 120px; padding: 10px 14px;
  background: var(--surface-2); border: 1px solid var(--line-mid); border-radius: 8px;
}
.tile .n { font: 700 22px/1.15 var(--mono); }
.tile .l { font-size: 14px; color: var(--ink-3); }
.tile.ok   { background: var(--ok-bg-2);   border-color: var(--ok-line-2); }
.tile.ok .n, .tile.ok .l { color: var(--ok-ink-2); }
.tile.busy { background: var(--busy-bg-2); border-color: var(--busy-line-2); }
.tile.busy .n, .tile.busy .l { color: var(--busy-ink-2); }
.tile.book { background: var(--book-bg-2); border-color: var(--book-line-2); }
.tile.book .n, .tile.book .l { color: var(--book-ink-2); }
.tile.prep { background: var(--prep-bg-2); border-color: var(--prep-line-2); }
.tile.prep .n, .tile.prep .l { color: var(--prep-ink-2); }
.tile.note { background: var(--note-bg); border-color: var(--note-line); }

.bar { height: 8px; background: var(--line-soft); border-radius: 4px; overflow: hidden; margin: 10px 0; }
.bar > div { height: 100%; background: var(--accent); transition: width .3s; }

/* Чипы-счётчики групп прайса. Кликабельными их не делаем: фильтровать
   на этом экране нечего — здесь поле ввода, а не список позиций. */
.chips { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.chip {
  display: inline-flex; align-items: center; height: 40px; padding: 0 14px;
  font-size: 15.5px; color: var(--ink); background: var(--surface);
  border: 1px solid var(--line); border-radius: 6px;
}
.chip.active { font-weight: 600; color: #fff; background: var(--accent); border-color: var(--accent); }
.chip.mono { font-family: var(--mono); }

/* ---- ход работы: полоса и строка под ней ----
   Три плитки «Загрузил → Проверка → Применение» убраны: они занимали верх
   экрана, а кнопки за это уезжали под сгиб. Полоса показывает то же самое
   и стоит одну строку. setStage() в app.js по-прежнему ищет #steps .step —
   не находит и просто ничего не подсвечивает. */
.bar.wizard { margin: 0 0 8px; }
.step-note { color: var(--ink-3); font-size: 15.5px; margin-bottom: 14px; }

/* Панель действий над полем ввода: отступ сверху не нужен, она идёт
   сразу за свёрнутой подсказкой. */
.row.actions { margin-top: 0; }

/* ============================================================== таблица */

table { width: 100%; border-collapse: collapse; font-size: 16.5px; }
th {
  padding: 12px 14px; text-align: left; font-size: 14.5px; font-weight: 700;
  color: var(--ink-2); background: var(--surface-3);
  border-bottom: 1px solid var(--line-mid);
}
td { padding: 13px 14px; text-align: left; border-bottom: 1px solid var(--line-soft); }
td.num { font-family: var(--mono); }

/* Бейдж «откачена» и прочие нейтральные пометки в строке. */
.tag {
  display: inline-flex; align-items: center; gap: 6px; height: 26px; padding: 0 9px;
  font-size: 14px; color: var(--ink-2);
  background: var(--surface-3); border: 1px solid #c2c8ce; border-radius: 5px;
}

/* Кнопки в правой ячейке строки истории: «Позиции» и «Откатить». */
.row-actions { display: flex; gap: 8px; justify-content: flex-end; white-space: nowrap; }

/* Раскрытая пачка: что в ней включали и выключали. Лежит отдельной строкой
   таблицы во всю ширину, поэтому у ячейки своя подложка и нет разделителя. */
tr.details > td { padding: 0 14px 14px; background: var(--surface-2); border-bottom: 1px solid var(--line-soft); }
.batch-items .summary { margin: 12px 0; }
.batch-items h4 { margin: 14px 0 8px; font-size: 15px; font-weight: 700; color: var(--ink-2); }
.batch-items .item:last-child { margin-bottom: 0; }

.err-box {
  padding: 14px 16px; margin: 16px 0; font-size: 16px; color: var(--danger-ink);
  background: var(--danger-bg); border: 1px solid var(--danger-line); border-radius: 8px;
}

/* ================================================== разделы (плитки) */

.hub {
  display: grid; gap: 16px; max-width: 1500px;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
.hub-tile {
  position: relative; display: flex; flex-direction: column; gap: 14px;
  min-height: 170px; padding: 24px; text-align: left;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  color: var(--ink); text-decoration: none; cursor: pointer;
  transition: border-color .15s, background .15s, box-shadow .15s;
}
a.hub-tile:hover {
  border-color: var(--accent); background: #f7fbfa;
  box-shadow: 0 0 0 1px var(--accent);
}
.hub-title { font-size: 21px; font-weight: 600; }
.hub-sub { font-size: 15px; color: var(--ink-3); }
/* Закрытый раздел не прячем: видно и что он есть, и почему недоступен.
   Курсор обычный — по нему намеренно нельзя кликнуть. */
.hub-tile.locked {
  background: #f7f8f9; border-color: #dde1e4; cursor: default;
}
.hub-tile.locked .hub-title { color: #3d454c; }
.hub-tile.locked .hub-icon { color: #7b848c; }
.hub-icon { color: var(--accent); }
.hub-top { display: flex; justify-content: space-between; align-items: flex-start; color: var(--label); }
.hub-text { display: flex; flex-direction: column; gap: 5px; }

/* Файл из «Поделиться» (/share/<id>): экран, подходящий по имени файла,
   стоит первым и обведён. Строка над экраном, куда файл пришёл, — пока
   файл скачивается или ждёт курса. */
.hub-tile.suggested { border-color: var(--accent); background: var(--accent-soft); box-shadow: 0 0 0 1px var(--accent); }
.share-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin: 0 0 14px; padding: 12px 14px; font-size: 16px;
  background: var(--accent-soft); border: 1px solid var(--accent); border-radius: 10px;
}
.share-bar .share-text { flex: 1 1 220px; }

/* Кто вошёл: кружок с первой буквой логина, сам логин и уровень доступа. */
.avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; margin-right: 8px; border-radius: 50%;
  background: var(--surface-4); color: var(--ink-2);
  font-size: 13px; font-weight: 600;
}
.who { display: inline-flex; align-items: center; }
.who b { margin-right: 4px; }

/* Списки расхождений бывают под сотню строк — не даём им растянуть страницу */
.sheet-list { max-height: 340px; overflow-y: auto; }
.cols { display: grid; gap: 6px; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); }
.cols .item { margin-bottom: 0; }

/* ============================================ редкая загрузка файла
   Справочник (категории позиций в дашборде, карточки для «Себестоимости
   Тайланд») грузят раз в полгода — не кнопка, а мелкая строка со ссылкой. */
.cat-line { margin: 10px 0 0; font-size: 13px; line-height: 1.45; color: var(--ink-3); }
.cat-line b { color: var(--ink); font-weight: 600; }
.cat-link { cursor: pointer; color: var(--ink-3); text-decoration: underline; text-underline-offset: 2px; white-space: nowrap; margin-left: 4px; }
.cat-link:hover { color: var(--accent-ink); }

/* ================================================== себестоимость Тайланд */

/* Курс — единственное, что вводится руками: короткое поле в строке над
   зоной загрузки, а не во всю ширину, как textarea. */
.th-rate-row { margin: 14px 0; }
.th-rate-label { font-size: 16.5px; font-weight: 600; }
input.th-rate { width: 140px; font-family: var(--mono); text-align: right; }
/* Разбор партии: подпись слева, число справа моноширинным; итог жирным. */
.th-calc { font-size: 15.5px; }
.th-calc td { padding: 8px 10px; }
.th-calc td.num { text-align: right; white-space: nowrap; font-family: var(--mono); }
.th-calc tr.total td { font-weight: 700; border-bottom: 2px solid var(--line); }

/* ================================================== карточка заказа */

.order-title { font-size: 21px; font-weight: 600; }
.order-who { color: var(--ink-3); font-size: 16.5px; }
.order-note {
  margin-top: 12px; padding: 12px 14px; font-size: 16px;
  background: var(--note-bg); border: 1px solid var(--note-line);
  border-left: 4px solid var(--note-bar); border-radius: 8px;
}
.order-note b { color: var(--ink); }
/* Кадр, из которого печатается реестр: на экране его быть не должно,
   но display:none Safari не печатает — поэтому нулевой размер. */
.print-frame { position: fixed; right: 0; bottom: 0; width: 0; height: 0; border: 0; }

/* ================================================== индикатор занятости
   Долгие действия (проверка, каталог, прайс, таблица) идут секундами,
   а то и минутами. Без видимого признака работы человек решает, что сайт
   завис, и жмёт снова: так на сервере накопилось 65 браузеров и кончилась
   память. Крутилку показываем везде, где ждём сервер. */
.spin {
  display: inline-block; width: 15px; height: 15px; vertical-align: -2px;
  margin-right: 9px; border: 2px solid var(--line);
  border-top-color: var(--accent); border-radius: 50%;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spin { animation-duration: 2.4s; } }

.working {
  display: flex; align-items: center; margin: 16px 0; padding: 14px 16px;
  font-size: 16px; color: var(--ink-2);
  background: var(--surface-2); border: 1px solid var(--line-mid); border-radius: 8px;
}
button.busy { cursor: progress; }

/* ================================================== телефон и планшет */

/* Узкий экран: колонки складываются одна под другую — поле ввода и
   превью рядом не помещаются. */
@media (max-width: 1100px) {
  .split { grid-template-columns: minmax(0, 1fr); }
  .step { flex-basis: 100%; }
}

@media (max-width: 900px) {
  /* padding целиком тут писать нельзя: сокращённая запись затирала
     padding-top с отступом под вырез — из-за этого шапка и наезжала
     на часы ровно там, где это важно, на телефоне. */
  header { padding: 8px 14px; padding-top: calc(var(--safe-top) + 8px); gap: 11px; }
  header h1 { font-size: 18px; }
  /* Крошка на телефоне не нужна: тем же словом называется заголовок
     экрана прямо под шапкой, а место она съедает целой строкой. */
  header .crumb { display: none; }
  /* Кто вошёл — только на экране разделов: на рабочих экранах шапка
     нужна узкой, а логин там ничего не решает. */
  header .who { display: none; }
  body[data-tiles] header .who { display: inline-flex; font-size: 14.5px; }
  h1 { font-size: 18px; }

  /* Боковой навигации нет — разделы уходят в нижнюю панель. */
  .sidenav { display: none; }
  main { padding: 14px 16px 24px; }

  .tabbar {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
    background: var(--surface); border-top: 1px solid var(--line-mid);
    padding: 6px 6px env(safe-area-inset-bottom);
  }
  .tab-item {
    flex: 1; min-height: 52px; display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: 3px;
    font: 13px/1.2 var(--sans); color: var(--ink-3); text-decoration: none;
    background: none; border: none; cursor: pointer;
  }
  .tab-item.active { font-weight: 700; color: var(--accent-ink); }
  .tab-item.locked { color: #9aa2a9; cursor: default; }
  /* Панель прижата к низу и перекрывает конец страницы — освобождаем место. */
  body { padding-bottom: calc(58px + env(safe-area-inset-bottom)); }

  /* Кнопки на телефоне — во всю ширину и не ниже 44px: палец в перчатке
     на складе в мелкую цель не попадает. */
  .row { gap: 8px; }
  .row > button, .row > .filebtn, .row > a.primary { flex: 1 1 100%; min-height: 50px; }
  .th-rate-row .note { flex-basis: 100%; }
  /* Расчёт партии в 390px: число переносится по « = » и « / » (внутри
     чисел пробелы неразрывные) — иначе «9 941,83 $ = 894 764 ₽» в одну
     строку раздувал таблицу шире экрана и вся страница ездила вбок. */
  .th-calc { font-size: 15px; }
  .th-calc td { padding: 7px 4px; vertical-align: top; }
  .th-calc td:first-child { padding-left: 0; }
  .th-calc td.num { white-space: normal; padding-right: 0; }
  .th-tiles .tile { flex: 1 1 26%; }
  .th-tiles .tile.wide { flex-basis: 40%; }
  .tabs { gap: 0; overflow-x: auto; flex-wrap: nowrap; }
  .tab { flex: none; height: 46px; padding: 0 14px; font-size: 16px; border-radius: 0; border: none; border-bottom: 3px solid transparent; }
  .tab.active { background: none; border: none; border-bottom: 3px solid var(--accent); margin-bottom: 0; }
  .card, .pane { padding: 14px; border-radius: 10px; }
  .page-head h1 { font-size: 21px; }
  .cands { margin-left: 8px; }
  .hub { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  /* Плитка раздела на телефоне — строка во всю ширину. */
  .hub-tile { flex-direction: row; align-items: center; gap: 14px; min-height: 88px; padding: 14px; }
  .hub-tile .hub-text { flex: 1; min-width: 0; }
  .hub-title { font-size: 19px; }
  /* Строка плитки: иконка — подпись — замок справа. display:contents
     выпускает детей .hub-top прямо в строку, порядок задаём order. */
  .hub-top { display: contents; }
  .hub-tile .hub-text { order: 2; }
  .hub-tile .hub-lock { order: 3; flex: none; }
  .tile { min-width: 0; flex: 1 1 0; padding: 8px 6px; text-align: center; }
  .tile .n { font-size: 20px; }
  .tile .l { font-size: 11.5px; }
  .cols { grid-template-columns: minmax(0, 1fr); }

  /* Таблица истории в 390px не живёт — те же строки становятся карточками,
     подпись колонки берётся из data-label. Разметка одна на оба экрана. */
  .table-cards thead, .table-cards tr:first-child th { display: none; }
  .table-cards, .table-cards tbody { display: block; }
  .table-cards tr {
    display: block; margin-bottom: 8px; padding: 12px;
    background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  }
  .table-cards td {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; padding: 4px 0; border: none;
  }
  .table-cards td::before { content: attr(data-label); color: var(--ink-3); font-size: 15px; }
  .table-cards td:empty { display: none; }
  /* Раскрытая пачка на телефоне — продолжение карточки, а не вторая карточка. */
  .table-cards tr.details { margin-top: -8px; padding-top: 0; border-top-left-radius: 0; border-top-right-radius: 0; }
  .table-cards tr.details > td { display: block; padding: 0; background: none; border: none; }
  .table-cards tr.details > td::before { content: none; }

  /* Прайс: на телефоне кнопки возвращаются под поле ввода. Наверху они
     нужны только на компьютере, где поле высокое и уводит их за нижний
     край; на телефоне страница и так прокручивается, а пять кнопок в
     столбик перед полем — это лишний экран прокрутки до самого поля. */
  #tab-price .card { display: flex; flex-direction: column; }
  #tab-price #input { order: 2; }
  #tab-price .row.actions { order: 3; margin-top: 12px; }
  #tab-price #cache-confirm { order: 4; }

  /* Заказы: два способа становятся двумя вкладками. Заголовок внутри
     колонки после этого повторяет вкладку — убираем. */
  .pane-tabs { display: flex; }
  .pane-tabs .tab { flex: 1; }
  #order-panes .pane-head { display: none; }
  .split[data-active="file"] > .pane[data-pane="text"] { display: none; }
  .split[data-active="text"] > .pane[data-pane="file"] { display: none; }
}

/* ---- Прайс Тайланд: два поля в одной строке, таблица разбора партии ---- */
.tp-params { gap: 10px 18px; }
.tp-field { display: inline-flex; align-items: center; gap: 10px; }
input.tp-boxes { width: 96px; }
.tp-sheet-note { margin: 12px 0 0; font-size: 14.5px; color: var(--ink-3); }
.tp-fold > summary { margin: 22px 0 10px; font-size: 17.5px; font-weight: 600; cursor: pointer; }
.tp-fold > summary::marker { color: var(--ink-3); }
