/*
  style.css — визуальный язык «Зачёт» (этап 3 «Веб-скелет», волна 2б).
  Источники канона:
    - docs/zachet/юикс-требования.md, §3 «Адаптивность», §4 «Визуальный язык»
      (палитра §4.1/4.2, подсветка расхождений §4.3, типографика §4.4).
    - Палитра/акцент унаследованы у scripts/wb_cs_flow/index.html (синий
      #3B5BDB, светлый фон #EEF1F5) — чтобы два внутренних инструмента
      одного бизнеса не выглядели продуктами разных компаний.

  ПРАВИЛО (юикс-требования.md §4, критерий приёмки №12): хардкод цвета,
  размера шрифта или отступа МИМО токена --zc-* в шаблонах/компонентах
  запрещён — весь дизайн идёт через custom properties этого файла.

  Брейкпоинты — mobile-first (базовые правила без media query — для S,
  затем min-width для M/L). Причина порядка объяснена в юикс-требования.md
  §3.1: при обратном порядке любое незакрытое переопределение ломает именно
  телефон, то есть главного пользователя (Эльвира).
    S — 320-767px  (базовые правила, без media query)
    M — 768-1199px (min-width: 768px)
    L — >=1200px   (min-width: 1200px)
  Доп. точка 480px — «сверхкомпактный» режим внутри S (подписи нижней
  навигации скрываются).
*/

/* ============================================================ ТОКЕНЫ === */
:root{
  /* поверхности */
  --zc-bg:          #EEF1F5;
  --zc-surface:     #FFFFFF;
  --zc-surface-2:   #F6F8FB;
  --zc-surface-3:   #E8ECF2;

  /* текст */
  --zc-ink:         #1B2432;
  --zc-ink-muted:   #5B6472;
  --zc-ink-faint:   #8A93A2;
  --zc-ink-invert:  #FFFFFF;

  /* линии */
  --zc-line:        #CED5DF;
  --zc-line-soft:   #E2E7EE;
  --zc-line-strong: #A9B2BF;

  /* акцент */
  --zc-accent:        #3B5BDB;
  --zc-accent-hover:  #314CC0;
  --zc-accent-active: #2A42A6;
  --zc-accent-soft:   #E5EAFB;
  --zc-focus:         #1B4DFF;

  /* семантика действий / расхождений */
  --zc-success:      #0B7A54;  --zc-success-bg:  #E6F4EE;  --zc-success-line: #0B7A54;
  --zc-warning:      #8A5300;  --zc-warning-bg:  #FCF2DC;  --zc-warning-line: #C98A0E;
  --zc-danger:       #A3231B;  --zc-danger-bg:   #FBE9E7;  --zc-danger-line:  #C7362B;
  --zc-neutral:      #5B6472;  --zc-neutral-bg:  #F2F4F7;  --zc-neutral-line: #A9B2BF;
  --zc-info:         #1C4E9C;  --zc-info-bg:     #E7EFFA;  --zc-info-line:    #3B5BDB;

  /* типографика — системный стек, без веб-шрифтов (юикс-требования §4.4) */
  --zc-font-ui:   system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --zc-font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  --zc-t-display-size: 34px; --zc-t-display-lh: 40px; --zc-t-display-w: 600;
  --zc-t-h1-size:      22px; --zc-t-h1-lh:      28px; --zc-t-h1-w:      600;
  --zc-t-h2-size:      18px; --zc-t-h2-lh:      24px; --zc-t-h2-w:      600;
  --zc-t-body-size:    16px; --zc-t-body-lh:    24px; --zc-t-body-w:    400;
  --zc-t-small-size:   14px; --zc-t-small-lh:   20px; --zc-t-small-w:   400;
  --zc-t-caption-size: 13px; --zc-t-caption-lh: 18px; --zc-t-caption-w: 400;
  --zc-t-micro-size:   12px; --zc-t-micro-lh:   16px; --zc-t-micro-w:   500;

  /* раскладка — поля страницы/промежуток по точкам (юикс-требования §3.1) */
  --zc-page-pad:  16px;
  --zc-gap:       12px;
  --zc-radius:    10px;
  --zc-radius-lg: 16px;

  --zc-topnav-h:    64px;
  --zc-bottomnav-h: 56px;
  --zc-safe-bottom: env(safe-area-inset-bottom, 0px);
}

@media (min-width: 768px){
  :root{ --zc-page-pad: 24px; --zc-gap: 16px; }
}
@media (min-width: 1200px){
  :root{ --zc-page-pad: 32px; --zc-gap: 24px; }
}

/* тёмная тема НЕ реализуется в MVP (юикс-требования §4.1/§9) — токены уже
   объявлены так, что её добавление — одна секция ниже без правки компонентов. */
@media (prefers-color-scheme: dark){
  :root{ /* зарезервировано — намеренно пусто на этом этапе */ }
}

/* ============================================================= RESET === */
*, *::before, *::after{ box-sizing: border-box; }
html, body{
  margin: 0; padding: 0;
  max-width: 100%;
  overflow-x: hidden;               /* критерий приёмки: НЕТ горизонтальной прокрутки страницы */
}
body{
  background: var(--zc-bg);
  color: var(--zc-ink);
  font-family: var(--zc-font-ui);
  font-size: var(--zc-t-body-size);
  line-height: var(--zc-t-body-lh);
  font-weight: var(--zc-t-body-w);
  -webkit-text-size-adjust: 100%;
  padding-bottom: calc(var(--zc-bottomnav-h) + var(--zc-safe-bottom));
}
@media (min-width: 1200px){
  body{ padding-bottom: 0; }
}
img, svg{ max-width: 100%; height: auto; }
a{ color: var(--zc-accent); text-decoration: none; }
a:hover{ text-decoration: underline; }
h1, h2, h3, p, ul, ol{ margin: 0 0 var(--zc-gap) 0; }
ul, ol{ padding-left: 1.25em; }
button{ font-family: inherit; }

/* «Перейти к содержимому» — первая цель Tab на КАЖДОЙ странице, то есть
   единственный элемент интерфейса, который человек на клавиатуре встречает
   раньше всего остального. Раньше высота была 40px (24px строки + 8+8
   padding) — ниже минимума 44px (юикс-требования §3.5/§10.1 №2). Минимум
   задан явно через min-height + inline-flex, а не подгонкой padding: padding
   зависит от line-height темы, min-height — нет. */
.zc-skip-link{
  position: absolute; left: -9999px; top: 0;
  display: inline-flex; align-items: center;
  min-height: 44px;
  background: var(--zc-accent); color: var(--zc-ink-invert);
  padding: 8px 12px; border-radius: var(--zc-radius);
  z-index: 100;
}
.zc-skip-link:focus{ left: 8px; top: 8px; }

:focus-visible{ outline: 2px solid var(--zc-focus); outline-offset: 2px; }

/* Подпись только для скринридера. Нужна там, где у образца подписи нет
   ВООБЩЕ: колонка-чекбокс в шапке таблицы, поле поиска с одной лупой,
   стрелка возврата. Убирать элемент через display:none нельзя — тогда его
   не прочитает и скринридер; поэтому классический clip-приём. */
.zc-visually-hidden{
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}

/* Базовый тач-таргет для ЛЮБОГО <details>/<summary> в системе — без стилей
   браузер рисует inline-block ~20-24px, ниже минимума (юикс-требования
   §3.5/§10.1 №2). Более специфичные правила (.zc-confirm, .zc-bottomnav__item,
   .gd-filters) переопределяют это по мере надобности — селектор здесь
   намеренно низкой специфичности. */
details > summary{
  min-height: 44px;
  display: flex; align-items: center;
  padding: 8px 4px;
  cursor: pointer;
  list-style: none;
}
details > summary::-webkit-details-marker{ display: none; }

/* =========================================================== LAYOUT ==== */
.zc-container{
  max-width: 1200px;
  margin: 0 auto;
  padding: var(--zc-gap) var(--zc-page-pad);
  width: 100%;
}

/* ======================================================= TOPNAV (L) ==== */
.zc-topnav{
  display: none;                    /* показывается только на L (см. media ниже) */
  background: var(--zc-surface);
  border-bottom: 1px solid var(--zc-line-soft);
}
.zc-topnav__inner{
  max-width: 1200px; margin: 0 auto;
  height: var(--zc-topnav-h);
  padding: 0 var(--zc-page-pad);
  display: flex; align-items: center; gap: 24px;
}
.zc-topnav__brand{
  font-size: var(--zc-t-h2-size); font-weight: var(--zc-t-h2-w);
  color: var(--zc-ink);
}
.zc-topnav__brand:hover{ text-decoration: none; }
.zc-topnav__links{ display: flex; align-items: center; gap: 8px; flex: 1; }
.zc-topnav__link{
  color: var(--zc-ink-muted);
  font-weight: 600;
  font-size: var(--zc-t-small-size);
  padding: 0 4px;
  height: var(--zc-topnav-h);
  display: inline-flex; align-items: center;
  border-top: 2px solid transparent;   /* активный пункт — не только цветом */
}
.zc-topnav__link:hover{ color: var(--zc-ink); text-decoration: none; }
.zc-topnav__link.is-active{
  color: var(--zc-accent);
  border-top-color: var(--zc-accent);
}
.zc-topnav__profile{ display: flex; align-items: center; gap: 12px; }
.zc-topnav__user{ font-size: var(--zc-t-small-size); color: var(--zc-ink-muted); }
.zc-topnav__logout-form{ display: inline; }

@media (min-width: 1200px){
  .zc-topnav{ display: block; }
}

/* =================================================== BOTTOMNAV (S/M) === */
.zc-bottomnav{
  position: fixed; left: 0; right: 0; bottom: 0;
  height: calc(var(--zc-bottomnav-h) + var(--zc-safe-bottom));
  padding-bottom: var(--zc-safe-bottom);
  background: var(--zc-surface);
  border-top: 1px solid var(--zc-line-soft);
  /* 4 слота (Главная/Товары/Склады/Ещё) — акцентная «+» запрещена в этом
     этапе (создание документа появится в Этапе 4), см. base.html. Пятый
     слот и .zc-bottomnav__plus вернутся вместе с формой документа. */
  display: grid; grid-template-columns: repeat(4, 1fr);
  align-items: stretch;
  z-index: 30;
}
.zc-bottomnav__item{
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px;
  color: var(--zc-ink-muted);
  height: var(--zc-bottomnav-h);
  border-top: 2px solid transparent;
  min-height: 44px;
  list-style: none;
  cursor: pointer;
}
.zc-bottomnav__item:hover{ text-decoration: none; }
.zc-bottomnav__item.is-active{ color: var(--zc-accent); border-top-color: var(--zc-accent); }
.zc-bottomnav__icon{ font-size: 20px; line-height: 1; }
.zc-bottomnav__label{ font-size: var(--zc-t-micro-size); font-weight: var(--zc-t-micro-w); }
/* .zc-bottomnav__item--accent / .zc-bottomnav__plus (акцентная «+», 5-й слот)
   удалены вместе с кнопкой в base.html — план прямо запрещает «создать
   документ» на этом этапе (ложное ожидание у Эльвиры, что документ можно
   завести уже сейчас). Вернутся вместе с формой документа в Этапе 4. */

/* «Ещё» — нативный <details>/<summary>, работает БЕЗ единой строки JS */
.zc-bottomnav__more{ display: contents; }
.zc-bottomnav__more > summary{
  list-style: none;
}
.zc-bottomnav__more > summary::-webkit-details-marker{ display: none; }
.zc-bottomnav__sheet{
  position: fixed; left: 0; right: 0; bottom: 0;
  display: none;
  background: var(--zc-surface);
  border-top-left-radius: var(--zc-radius-lg);
  border-top-right-radius: var(--zc-radius-lg);
  box-shadow: 0 -4px 24px rgba(20, 30, 45, .18);
  padding: 12px 16px calc(16px + var(--zc-bottomnav-h) + var(--zc-safe-bottom));
  z-index: 40;
}
.zc-bottomnav__more[open] .zc-bottomnav__sheet{ display: flex; flex-direction: column; }
.zc-bottomnav__more[open]::before{
  content: ""; position: fixed; inset: 0;
  background: rgba(20, 30, 45, .35);
  z-index: 35;
}
.zc-bottomnav__sheet-link{
  display: block; padding: 14px 8px;
  font-size: var(--zc-t-body-size);
  color: var(--zc-ink);
  border-bottom: 1px solid var(--zc-line-soft);
  min-height: 44px;
  text-align: left; background: none; border-left: 0; border-right: 0; border-top: 0;
  width: 100%;
}
.zc-bottomnav__sheet-link:hover{ text-decoration: none; background: var(--zc-surface-2); }
.zc-bottomnav__sheet-link:last-child{ border-bottom: 0; }
.zc-bottomnav__sheet-form{ margin: 0; }
.zc-bottomnav__sheet-link--btn{ font: inherit; cursor: pointer; }

@media (max-width: 479px){
  .zc-bottomnav__label{ display: none; }   /* сверхкомпактный режим: только глифы */
}
@media (min-width: 1200px){
  .zc-bottomnav{ display: none; }
}

/* ============================================================ FOOTER === */
.zc-footer{
  border-top: 1px solid var(--zc-line-soft);
  color: var(--zc-ink-faint);
  font-size: var(--zc-t-caption-size);
}
.zc-footer__inner{ padding-top: var(--zc-gap); padding-bottom: var(--zc-gap); }

/* ========================================================= TYPOGRAPHY == */
.zc-h1{ font-size: var(--zc-t-h1-size); line-height: var(--zc-t-h1-lh); font-weight: var(--zc-t-h1-w); margin: 0 0 var(--zc-gap); }
.zc-h2{ font-size: var(--zc-t-h2-size); line-height: var(--zc-t-h2-lh); font-weight: var(--zc-t-h2-w); margin: 0 0 8px; }
.zc-display{ font-size: var(--zc-t-display-size); line-height: var(--zc-t-display-lh); font-weight: var(--zc-t-display-w); }
.zc-small{ font-size: var(--zc-t-small-size); line-height: var(--zc-t-small-lh); }
.zc-caption{ font-size: var(--zc-t-caption-size); line-height: var(--zc-t-caption-lh); color: var(--zc-ink-muted); }
.zc-micro{ font-size: var(--zc-t-micro-size); line-height: var(--zc-t-micro-lh); font-weight: var(--zc-t-micro-w); letter-spacing: .04em; text-transform: uppercase; }
.zc-ink-muted{ color: var(--zc-ink-muted); }
.zc-ink-faint{ color: var(--zc-ink-faint); }
.zc-mono{
  font-family: var(--zc-font-mono);
  font-variant-numeric: tabular-nums;
  /* длинные непрерывные строки без пробелов (пути файлов, sku_id с
     подчёркиваниями, id локаций WB:CENTRAL/KOLEDINO) иначе не находят точку
     разрыва и на 375px вылезают за край, обрезанные body{overflow-x:hidden}
     — это НЕ горизонтальная прокрутка страницы (тело её не даёт), но
     реальная визуальная порча текста; overflow-wrap:anywhere разрешает
     разрыв в любом месте токена, когда естественных пробелов не хватает. */
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* ============================================================= CARD ==== */
.zc-card{
  background: var(--zc-surface);
  border: 1px solid var(--zc-line-soft);
  border-radius: var(--zc-radius);
  padding: var(--zc-gap);
  margin-bottom: var(--zc-gap);
}

/* ============================================================ BUTTONS == */
.zc-btn{
  display: inline-flex; align-items: center; justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 16px;
  /* ПИЛЮЛЯ (05.08.2026, переделка под образец «Складолог», §4.2 каркаса):
     скругление на всю высоту у ВСЕХ кнопок системы. Раньше было
     var(--zc-radius)=10px. Изменение чисто косметическое — ни один сьют
     не проверяет радиус, а «кнопка = пилюля» опознаётся владельцем как
     главный признак образца. */
  border-radius: 999px;
  border: 1px solid transparent;
  font-size: var(--zc-t-body-size);
  font-weight: 600;
  cursor: pointer;
  /* ШИРИНА — ПО СОДЕРЖИМОМУ. Кнопка внутри flex-контейнера иначе тянется
     до высоты/ширины соседей (align-items:stretch), и «залитая пилюля»
     превращается в полосу. */
  flex: 0 0 auto;
  background: var(--zc-accent);
  color: var(--zc-ink-invert);
}
.zc-btn:hover{ background: var(--zc-accent-hover); text-decoration: none; color: var(--zc-ink-invert); }
.zc-btn:active{ background: var(--zc-accent-active); }
.zc-btn--ghost{
  background: transparent; color: var(--zc-accent);
  border-color: var(--zc-line);
}
.zc-btn--ghost:hover{ background: var(--zc-accent-soft); color: var(--zc-accent-hover); }
/* «Кнопка (вторичная, в ряду)» — юикс-требования §4.5, таблица высот: 44px на S/M
   (тач), 36px только на L (курсор). Раньше было плоских 36px везде — это и давало
   промахи на пагинации, «Применить» на карточке склада и т.д. на телефоне. */
.zc-btn--small{ min-height: 44px; padding: 0 12px; font-size: var(--zc-t-small-size); }
@media (min-width: 1200px){
  .zc-btn--small{ min-height: 36px; }
}
/* «Кнопка во всю ширину» — ТОЛЬКО телефон (05.08.2026, переделка под образец).
   У образца кнопок во всю ширину контента нет НИГДЕ: главное действие —
   пилюля по содержимому в левом краю строки действий (каркас §4.2). У нас же
   `zc-btn--block` стоял в разметке разделов и на широком экране рисовал
   синие полосы по 1300px — по две подряд («Добавить контрагента» и
   «Фильтры (0)»), из-за чего приоритет действий не читался вовсе.

   Правило снимает ширину НА УРОВНЕ ОБЩЕГО СЛОЯ, не трогая ни один шаблон
   раздела: на S кнопка остаётся во всю ширину (палец, одна колонка — это
   правильно и проверено сьютом test_zachet_web_mobile.py), с 768px
   становится по содержимому. Следующая волна убирает сам класс из разметки
   разделов; до тех пор это правило чинит все экраны разом. */
.zc-btn--block{ width: 100%; }
@media (min-width: 768px){
  .zc-btn--block{ width: auto; }
}
/* Модификаторы кнопки живут РЯДОМ с базовым .zc-btn и только здесь. До
   03.08.2026 три из них (--secondary/--danger/--danger-confirm) были объявлены
   инлайном в templates/users_extra_head.html: разметка `class="zc-btn
   zc-btn--secondary"` на любом другом экране давала обычную синюю кнопку —
   класс есть, стилей нет. Ровно этот дефект приёмка нашла на плитках отчётов;
   семейство кнопок закрыто здесь, чтобы он не повторился на формах этапа 4. */
.zc-btn--secondary{
  background: var(--zc-surface); color: var(--zc-ink); border: 1px solid var(--zc-line);
}
.zc-btn--secondary:hover{ background: var(--zc-surface-2); color: var(--zc-ink); }
.zc-btn--danger{
  background: var(--zc-surface); color: var(--zc-danger); border: 1px solid var(--zc-danger-line);
}
.zc-btn--danger:hover{ background: var(--zc-danger-bg); color: var(--zc-danger); }
.zc-btn--danger-confirm{
  background: var(--zc-danger-line); color: var(--zc-ink-invert); border-color: var(--zc-danger-line);
}
.zc-btn--danger-confirm:hover{ background: var(--zc-danger); color: var(--zc-ink-invert); }

/* Ссылка «← Назад» (zc-caption, под шапкой раздела) — сама по себе это 13/18
   текст без отступов, кликабельная область 15-19px. Класс расширяет тач-таргет
   до 44px по высоте, не трогая типографику (юикс-требования §3.5). */
.zc-back-link{
  display: inline-flex; align-items: center;
  min-height: 44px;
  padding: 4px 0;
}

/* Инлайн-текстовая ссылка с безопасным тач-таргетом — тот же приём, что и
   .zc-back-link (текстовая ссылка, не блочная кнопка), но без семантики
   «назад»: используется там, где ссылка не «шапка раздела», а часть текста
   или ячейки таблицы (баннер дублей контрагента, столбец «Наименование» в
   таблице контрагентов, «Отменить и вернуться к списку» в форме).
   Найдено 03.08.2026 мобильным сьютом: класс стоял в разметке четырёх мест,
   но НИ ОДНОГО правила для него в стилях не было — ссылка «Отменить и
   вернуться к списку» рисовалась 15px вместо честных 44px (юикс-требования
   §10.1, критерий №2). */
.zc-link{
  display: inline-flex; align-items: center;
  min-height: 44px;
  padding: 4px 0;
}

/* ================================================== ИНЛАЙН-ПОДТВЕРЖДЕНИЕ === */
/* Необратимое действие раскрывается на месте, без модалки (юикс-требования
   §5.7: «модалка — не место для формы») — нативный <details>/<summary>, без
   единой строчки JS.
   Переехал сюда из templates/users_extra_head.html 03.08.2026. Раньше здесь
   стоял только КОММЕНТАРИЙ «класс определён в шаблоне раздела» — то есть
   общий файл стилей ссылался на правила, которых в нём нет: ровно та связь,
   из-за которой на этапе 4 удаление документа получило бы <summary> без
   тач-таргета. */
.zc-confirm{
  margin-top: 8px;
  padding: var(--zc-gap);
  border-radius: var(--zc-radius);
  background: var(--zc-surface-2);
  border: 1px solid var(--zc-line-soft);
}
/* <summary> без явных размеров — нативный inline ~24px высотой, вдвое ниже
   минимального тач-таргета (юикс-требования §10.1, критерий №2) — и это на
   необратимых действиях (сброс пароля, деактивация), где промах на телефоне
   дорого стоит. display:flex + min-height дают честные 44px, не трогая
   типографику/окраску блока. */
.zc-confirm > summary{
  display: flex; align-items: center; gap: 6px;
  min-height: 44px;
  padding: 10px 4px;
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}
.zc-confirm > summary::-webkit-details-marker{ display: none; }
.zc-confirm > summary::before{ content: "▸"; font-size: 12px; color: var(--zc-ink-muted); }
.zc-confirm[open] > summary::before{ content: "▾"; }
.zc-confirm__text{ color: var(--zc-ink-muted); margin: 8px 0; }

/* ============================================== ФЛАЖОК В СТРОКЕ (44px) === */
/* «Показать деактивированных / архивные / служебные» — один и тот же по смыслу
   переключатель на четырёх экранах, и до 03.08.2026 он был сделан ЧЕТЫРЬМЯ
   разными способами: .gd-check с честными 44px на /goods/list, голый <label>
   на складах (флажок растягивался на всю ширину правилом input{width:100%}) и
   <label> с инлайновым style="width:auto;min-height:auto" на контрагентах —
   там тач-таргет схлопывался до 24px.

   Общий компонент: <label class="zc-check"><input type="checkbox" …> Текст
   </label>. Высота строки 44px берёт на себя ЛЕЙБЛ (кликабельна вся строка, а
   не 16px квадратика), а сам <input> освобождается от общего правила формы
   input{width:100%; min-height:44px}, которое флажку не подходит. */
.zc-check{
  display: flex; align-items: center; gap: 8px;
  min-height: 44px;
  cursor: pointer;
}
.zc-check input{
  width: auto; min-height: auto;
  flex: 0 0 auto;
  margin: 0;
}

/* ================================================== ИНЛАЙН-ФОРМА В РЯД === */
/* Ряд полей + кнопка, переносится на узком экране. Поля тянутся, кнопка
   прижата к их нижнему краю. Переехал сюда из users_extra_head.html, потому
   что класс с общим префиксом `zc-` использован на двух экранах раздела и
   заведомо понадобится формам этапа 4.
   Близкие по смыслу .gc-inline-form (goods_categories), .zcw-filters-row и
   .zcw-goods-filters (склады) ОСТАВЛЕНЫ инлайн сознательно: каждый из них
   живёт ровно на одном экране и отличается базисом поля. Новую форму писать
   на .zc-inline-form, а не копировать их. */
.zc-inline-form{ display: flex; gap: 8px; flex-wrap: wrap; align-items: flex-end; }
.zc-inline-form .zc-field{ flex: 1 1 200px; margin-bottom: 0; }

/* Мелкая поясняющая строка под полем/блоком. */
.zc-muted-note{ color: var(--zc-ink-muted); font-size: var(--zc-t-caption-size); margin: 4px 0 0; }

/* ============================================================= FORMS === */
/* Минимальный размер шрифта в полях ввода — 16px на ЛЮБОМ размере экрана.
   Требование безусловное (юикс-требования §4.4): меньший шрифт заставляет
   Safari iOS зумить страницу при фокусе и ломает липкую вёрстку. */
input, select, textarea{
  font-family: var(--zc-font-ui);
  font-size: var(--zc-t-body-size);
  line-height: var(--zc-t-body-lh);
  color: var(--zc-ink);
  background: var(--zc-surface);
  border: 1px solid var(--zc-line);
  border-radius: var(--zc-radius);
  padding: 10px 12px;
  min-height: 44px;
  width: 100%;
}
input:focus, select:focus, textarea:focus{
  border-color: var(--zc-line-strong);
  outline: 2px solid var(--zc-focus);
  outline-offset: 1px;
}
label{ display: block; font-size: var(--zc-t-caption-size); color: var(--zc-ink-muted); margin-bottom: 4px; }
.zc-field{ margin-bottom: var(--zc-gap); }

/* ============================================================= BADGES == */
/* Подсветка расхождений — юикс-требования §4.3. ЧЕТЫРЕ независимых носителя
   признака на каждое состояние: оттенок, глиф, знак числа, стиль левой
   границы — цвет НИКОГДА единственный носитель смысла (критично для
   дейтеранопии/протанопии и ч/б печати). */
.zc-badge{
  display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--zc-font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--zc-t-small-size);
  padding: 2px 8px;
  border-radius: 999px;
  border-left: 4px solid;
}
.zc-badge--ok{       color: var(--zc-success); background: var(--zc-success-bg); border-left-style: solid;   border-left-color: var(--zc-success-line); }
.zc-badge--surplus{  color: var(--zc-warning); background: var(--zc-warning-bg); border-left-style: dashed;  border-left-color: var(--zc-warning-line); }
.zc-badge--shortage{ color: var(--zc-danger);  background: var(--zc-danger-bg);  border-left-style: double;  border-left-width: 5px; border-left-color: var(--zc-danger-line); }
.zc-badge--unknown{  color: var(--zc-neutral); background: var(--zc-neutral-bg); border-left-style: dotted; border-left-color: var(--zc-neutral-line); }
/* Активность записи (пользователь/контрагент/склад — везде одна пара
   состояний). Переехали из templates/users_extra_head.html 03.08.2026:
   модификатор семейства обязан лежать там же, где базовый .zc-badge. */
.zc-badge--active{
  color: var(--zc-success); background: var(--zc-success-bg);
  border-left-style: solid; border-left-color: var(--zc-success-line);
}
.zc-badge--inactive{
  color: var(--zc-neutral); background: var(--zc-neutral-bg);
  border-left-style: dotted; border-left-color: var(--zc-neutral-line);
}

/* ============================================================= ALERTS === */
/* Баннер результата/ошибки над содержимым страницы. Четыре тона —
   info/success/warning/error, каждый несёт признак не только цветом, но и
   глифом в разметке (юикс-требования §4.3).
   Переехал сюда 03.08.2026 из templates/users_extra_head.html; заодно
   поглотил .zc-login__error из login.html — это была ПОБУКВЕННАЯ копия
   .zc-alert + .zc-alert--error под другим именем. Две копии одного баннера в
   двух шаблонах — то же самое, что плитки отчётов без стилей, только
   наоборот: стили есть, но каждый экран носит свои. */
.zc-alert{
  display: flex; gap: 10px; align-items: flex-start;
  border-left: 4px solid;
  border-radius: var(--zc-radius);
  padding: 12px var(--zc-gap);
  margin-bottom: var(--zc-gap);
  font-size: var(--zc-t-small-size);
}
.zc-alert__glyph{ font-size: 18px; line-height: var(--zc-t-body-lh); }
.zc-alert__body{ min-width: 0; }
.zc-alert__title{
  font-size: var(--zc-t-h2-size); font-weight: 600; margin: 0 0 4px;
}
.zc-alert--info{
  color: var(--zc-info); background: var(--zc-info-bg); border-color: var(--zc-info-line);
}
.zc-alert--success{
  color: var(--zc-success); background: var(--zc-success-bg); border-color: var(--zc-success-line);
}
.zc-alert--warning{
  color: var(--zc-warning); background: var(--zc-warning-bg); border-color: var(--zc-warning-line);
}
.zc-alert--error{
  color: var(--zc-danger); background: var(--zc-danger-bg); border-color: var(--zc-danger-line);
}

/* ============================================================== TILES === */
/* Сетка крупных ссылок-плиток: разделы на дашборде, отчёты на /reports.
   Ровно тот компонент, на котором сломалась приёмка 03.08.2026: разметку с
   классами .zc-dash__tile скопировали в reports_placeholder.html, а правила
   остались инлайном в <style> дашборда — и пять плиток отчётов вышли высотой
   19px вплотную друг к другу вместо 88px с промежутком. Класс переименован из
   .zc-dash__tile в .zc-tile: `__dash` в имени говорил «принадлежит дашборду»
   и провоцировал ровно ту копипасту, которая случилась.
   2 колонки на S, 3 на M, 5 на L. */
.zc-tiles{
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--zc-gap);
}
.zc-tile{
  display: flex; align-items: center; justify-content: center;
  min-height: 88px; text-align: center; padding: 8px;
  background: var(--zc-surface); border: 1px solid var(--zc-line-soft);
  border-radius: var(--zc-radius);
  font-weight: 600; color: var(--zc-ink);
}
.zc-tile:hover{ text-decoration: none; background: var(--zc-surface-2); }
@media (min-width: 768px){
  .zc-tiles{ grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 1200px){
  .zc-tiles{ grid-template-columns: repeat(5, 1fr); }
  .zc-tile{ min-height: 104px; }
}

/* ============================================== CARD-LIST (механизм A) == */
/* «Строка становится карточкой» — справочники/списки на S/M (юикс-требования
   §3.3). Роли: заголовок / ключ / значение. Используется будущими разделами
   (Номенклатура, Склады, Контрагенты, Пользователи) — готово заранее. */
.zc-rowcard{
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  padding: 14px 4px;
  border-bottom: 1px solid var(--zc-line-soft);
  min-height: 64px;
}
.zc-rowcard:last-child{ border-bottom: 0; }
.zc-rowcard__main{ min-width: 0; }
.zc-rowcard__title{
  font-size: var(--zc-t-h2-size); font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.zc-rowcard__key{
  font-size: var(--zc-t-caption-size); color: var(--zc-ink-muted);
  font-family: var(--zc-font-mono);
}
.zc-rowcard__value{
  font-size: var(--zc-t-h2-size);
  font-family: var(--zc-font-mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ============================================== ФОТО ТОВАРА (миниатюра) = */
/* Номенклатура WB здесь — семь артикулов подряд, отличающихся одной цифрой
   (`WB_краскопульт_макита_2/3/6`) — фото снижает риск перепутать позицию при
   приёмке. Размер контейнера ФИКСИРОВАН заранее (aspect-ratio, не зависит от
   реального размера файла) — страница не должна прыгать, пока картинки
   догружаются на плохой связи (юикс-требования §3, §9.1 «скелетоны загрузки»
   не делаем, но геометрия резервируется всегда).

   Соотношение сторон 3:4 подобрано под ОБА пресета WB, которые реально
   используются (tm 75x100, c246x328 246x328) — один aspect-ratio годится и
   миниатюре списка, и картинке карточки.

   «Нет фото» и «фото не загрузилось» ВИЗУАЛЬНО ОДИНАКОВЫ и НАМЕРЕННО: глиф
   лежит в разметке всегда, <img> (если ссылка вообще есть) кладётся поверх
   него абсолютным позиционированием. Успешная загрузка перекрывает глиф
   картинкой. Ссылка на WB может протухнуть (смена CDN, потеря карточки) —
   это тоже разновидность «фото нет», а не повод показывать сломанную иконку
   браузера или пустое место: единственный по-настоящему надёжный способ
   узнать, что <img> не загрузился, — браузерное событие `error`, поэтому
   у него один инлайновый обработчик `onerror="this.remove()"` (без
   framework/внешнего файла) — при ошибке загрузки просто убирает <img> из
   DOM, глиф проступает обратно. Иллюстраций тут нет (юикс-требования §9.1) —
   только этот глиф + подпись (у крупного варианта). */
.zc-thumb{
  position: relative;
  flex: 0 0 auto;
  width: 40px; aspect-ratio: 3 / 4;
  border-radius: var(--zc-radius);
  background: var(--zc-surface-2);
  border: 1px solid var(--zc-line-soft);
  overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px;
  color: var(--zc-ink-faint);
}
.zc-thumb svg{ width: 16px; height: 16px; flex: 0 0 auto; }
.zc-thumb img{
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  background: var(--zc-surface-2);
}
.zc-thumb__label{
  display: none;
  font-size: var(--zc-t-micro-size); color: var(--zc-ink-faint); text-align: center;
  padding: 0 4px;
}
.zc-thumb--lg{ width: 128px; }
.zc-thumb--lg svg{ width: 30px; height: 30px; }
.zc-thumb--lg .zc-thumb__label{ display: block; }

/* ==================================================== TABLE (карточки по умолчанию) = */
/* ПЕРЕВЁРНУТО 03.08.2026 (разбор трёх однотипных дефектов за один день:
   карточка товара, четыре заглушки документов, карточка контрагента — во
   всех трёх таблица на телефоне листалась вбок, потому что автор шаблона не
   вспомнил добавить явный класс карточного режима). Тот же принцип, что у
   guard'а маршрутов (routes/__init__.py, zachet_web_guard): новое ЗАКРЫТО по
   умолчанию, разрешение — явное. Здесь роль «маршрута» у любой таблицы:
   безопасное поведение (карточки на S/M) — умолчание для ЛЮБОГО <table>,
   даже вообще без класса .zc-table; горизонтальный скролл — исключение,
   которое теперь нужно включать явно (см. .zc-table--scroll ниже), а не
   помнить включить безопасность.

   Правила ниже разбиты на две части:
   1) .zc-table — чисто косметика (границы, отступы, фон шапки), которая
      не влияет на «скроллится вбок / стала карточкой» и одинакова что для
      обычной таблицы, что для карточной раскладки.
   2) @media (max-width: 1199px) — структурная подмена: ЛЮБАЯ таблица (тег
      <table>, класс не нужен) превращается в список карточек, шапка (thead)
      прячется, её роль берёт на себя атрибут data-th на каждой <td>. */
.zc-table-wrap{ overflow-x: auto; max-width: 100%; }
.zc-table{ border-collapse: collapse; width: 100%; }
.zc-table th, .zc-table td{
  padding: 8px 12px;
  text-align: left;
  border-bottom: 1px solid var(--zc-line-soft);
  font-size: var(--zc-t-small-size);
}
.zc-table th{
  background: var(--zc-surface-2);
  font-weight: 600; color: var(--zc-ink-muted);
}
.zc-table td.zc-mono, .zc-table th.zc-mono{ font-variant-numeric: tabular-nums; }

/* ПЛОТНОСТЬ СТРОКИ — образец, каркас §4.4: «~55-57px, не 40 (не excel), не 72
   (не карточки)». `height` на <tr> в таблице работает как МИНИМУМ: строка с
   переносом текста вырастет, но не сожмётся ниже. Только на L — на S/M строка
   и так карточка, и фиксировать ей высоту нельзя.
   Шапка при этом НАМЕРЕННО остаётся низкой (~40px): она входит в бюджет
   «от заголовка до первой строки данных», который мы ужимаем до 140-160px. */
@media (min-width: 1200px){
  .zc-table tbody tr{ height: 57px; }
  .zc-table th{ padding-top: 10px; padding-bottom: 10px; }
}

@media (max-width: 1199px){
  thead{ display: none; }
  table, tbody, tr, td{ display: block; width: 100%; }
  tr{
    border: 1px solid var(--zc-line-soft);
    border-radius: var(--zc-radius);
    padding: 10px 12px;
    margin-bottom: var(--zc-gap);
  }
  tr:last-child{ margin-bottom: 0; }
  td{
    border-bottom: 0;
    padding: 8px 0;
    white-space: normal;
    position: static;
    background: none;
  }
  /* Подпись колонки в карточном режиме — не декоративная мелочь, а
     единственный заголовок, который у ячейки остался (thead выше скрыт).
     Если data-th на <td> ЕСТЬ — подпись выводится как обычно. Если ЗАБЫТА —
     дефект не должен молча слиться с соседними ячейками (как забытая подпись
     схлопывалась бы в пустоту при обычном attr()); вместо неё — заметная
     плашка тревожного цвета: дефект виден на первом же просмотре страницы на
     телефоне, а не только при чтении HTML построчно. */
  td[data-th]::before{
    content: attr(data-th);
    display: block;
    font-size: var(--zc-t-caption-size);
    color: var(--zc-ink-muted);
    margin-bottom: 4px;
  }
  td:not([data-th])::before{
    content: "⚠ нет подписи столбца (забыт data-th)";
    display: block;
    font-size: var(--zc-t-caption-size);
    font-weight: 600;
    color: var(--zc-danger);
    background: var(--zc-danger-bg);
    padding: 2px 6px;
    border-radius: 4px;
    margin-bottom: 4px;
  }
  /* Ссылка внутри свёрнутой в карточку строки (например «Товар» в журнале
     движений) — тот же тач-таргет 44px, что у остального интерфейса на S/M.
     Найдено 03.08.2026: без этого правила ссылка на sku_id рисовалась
     42×16px, вдвое ниже требуемого. */
  td a{
    display: inline-flex; align-items: center;
    min-height: 44px; min-width: 44px;
  }
}

/* ============================================ TABLE SCROLL (явно, только L) = */
/* Горизонтальная прокрутка — законное исключение ТОЛЬКО для таблиц с большим
   числом колонок, которые на широком экране читать построчно (карточками)
   хуже, чем скроллом (отчёты этапа 7, ABC-анализ, длинный журнал). Требование
   безусловно: «горизонтальная прокрутка таблицы допустима только на
   компьютере» (юикс-требования §3.3) — поэтому весь блок целиком внутри
   min-width:1200px и НИЧЕГО не меняет на S/M: там, как у любой другой
   таблицы, работает карточный блок выше. Включается явно:
   <table class="zc-table zc-table--scroll"> внутри <div class="zc-table-wrap">. */
@media (min-width: 1200px){
  .zc-table--scroll{ min-width: 480px; }
  .zc-table--scroll th, .zc-table--scroll td{ white-space: nowrap; }
  .zc-table--scroll th{ position: sticky; top: 0; }
  .zc-table--scroll td:first-child, .zc-table--scroll th:first-child{
    position: sticky; left: 0;
    background: inherit;
  }
}

/* ==================================================== PLACEHOLDER PAGE = */
.zc-placeholder{ padding: 8px 0; }
.zc-placeholder__title{ font-size: var(--zc-t-h1-size); font-weight: var(--zc-t-h1-w); margin: 0 0 8px; }
.zc-placeholder__text{ color: var(--zc-ink-muted); margin: 0 0 var(--zc-gap); }
.zc-placeholder__error{ color: var(--zc-danger); }
.zc-placeholder__routes{ margin: 0; padding-left: 1.1em; }
.zc-placeholder__routes li{ margin-bottom: 4px; font-size: var(--zc-t-small-size); }


/* =============================================================================
   ============  СЛОЙ «ЭКРАН-СПИСОК» — общий каркас разделов  =================
   =============================================================================
   Заведён 05.08.2026, переделка интерфейса под образец «Складолог».
   Канон: docs/zachet/юикс-эталон-каркас.md, часть 4 («Общие правила образца —
   применить ко ВСЕМ экранам сразу»).

   ЗАЧЕМ ЭТОТ СЛОЙ. До него каждый раздел собирал шапку экрана сам: где-то
   «← Дашборд» отдельной строкой над H1, где-то возврата не было вовсе; главное
   действие рисовалось кнопкой во всю ширину контента, под ней второй такой же
   полосой — «Фильтры (0)»; фильтры жили отдельной карточкой с собственной
   кнопкой «Применить». От заголовка до первой строки данных уходило 450-620px:
   на ноутбуке владелец не видел ни одной строки таблицы без прокрутки.

   Здесь лежат ГОТОВЫЕ КЛАССЫ, из которых раздел собирает экран. Разметку по
   ним пишет не человек, а макросы `templates/_ui.html` — они и есть публичный
   интерфейс этого слоя. Прямое использование классов допустимо, но макрос
   гарантирует порядок элементов и атрибуты доступности.

   БЮДЖЕТ ВЫСОТЫ (цель задания: 140-160px от верха H1 до первой строки данных):
       строка заголовка ниже H1 ... 36px  (H1 центрирован в ряду 44px)
       промежуток ................. 12px
       строка действий ............ 44px
       промежуток ................. 12px
       шапка таблицы .............. 40px
                                   -----
                                    144px
   Любое новое правило в этом слое, добавляющее вертикаль, обязано сверяться
   с этой таблицей — она проверяется замером в браузере, а не на глаз.

   БЕЗ JS — ЭТО ЖЁСТКОЕ ОГРАНИЧЕНИЕ СИСТЕМЫ (в «Зачёте» нет ни одной строки
   script, сьют test_zachet_web_mobile.py проверяет работу с выключенным JS).
   Поэтому интерактив здесь сделан платформенными средствами:
     * раскрытие/закрытие окон — атрибуты `popover` / `popovertarget`
       (нативный top layer: Escape, клик мимо окна и фокус-ловушка бесплатно);
     * подсветка выделенной строки и показ панели массовых действий —
       селектор `:has()` по состоянию чекбоксов;
     * сортировка, фильтры и пагинация — обычные ссылки GET.
   ============================================================================= */

/* --------------------------------------------------- 1. СТРОКА ЗАГОЛОВКА --- */
/* `← H1  [чип] [? подсказка] ..................................... [Поиск]`
   Одна строка. Возврат — стрелка СЛЕВА ОТ ЗАГОЛОВКА, в одной строке с ним
   (каркас §1.2 «Возврат назад»): отдельная строка «← Дашборд» над H1 съедала
   вертикаль и создавала второе правило возврата там, где нужно одно. */
.zc-pagehead{
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 8px var(--zc-gap);
  min-height: 44px;
  /* ФИКСИРОВАННЫЕ 12px, а НЕ var(--zc-gap). Токен на L равен 24px, и две
     таких отбивки (под заголовком и под строкой действий) съедали 48px из
     бюджета в 144 — замер показывал 176px вместо 152px. Отбивка между
     строками одного заголовочного блока — не тот отступ, который должен
     расти вместе с полями страницы. */
  margin: 0 0 12px;
}
.zc-pagehead__back{
  display: inline-flex; align-items: center; justify-content: center;
  /* Тач-таргет 44px обязателен (юикс-требования §3.5), но занимать 44px
     ШИРИНЫ слева от заголовка стрелке незачем — отрицательный внешний отступ
     возвращает оптическое выравнивание H1 по левому краю контента. */
  min-width: 44px; min-height: 44px;
  margin-left: -10px; margin-right: -6px;
  font-size: 22px; line-height: 1;
  color: var(--zc-ink); text-decoration: none;
}
.zc-pagehead__back:hover{ color: var(--zc-accent); text-decoration: none; }
.zc-pagehead__title{
  font-size: var(--zc-t-h1-size); line-height: var(--zc-t-h1-lh);
  font-weight: var(--zc-t-h1-w);
  margin: 0;                       /* .zc-h1 несёт margin-bottom — здесь его нет */
  min-width: 0;
}
.zc-pagehead__count{
  color: var(--zc-ink-faint); font-weight: 400;
  font-size: var(--zc-t-body-size);
}
/* Всё, что правее заголовка, прижимается к правому краю строки. */
.zc-pagehead__right{
  margin-left: auto;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}

/* Чип-срез рядом с H1 — «1 Незаполненные» (каркас §4.5). Белая пилюля с
   акцентной рамкой; включённый срез — залит. Это ССЫЛКА, а не форма. */
.zc-chip{
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 32px; padding: 0 12px;
  border: 1px solid var(--zc-accent); border-radius: 999px;
  background: var(--zc-surface); color: var(--zc-accent);
  font-size: var(--zc-t-small-size); font-weight: 600;
  white-space: nowrap;
}
.zc-chip:hover{ background: var(--zc-accent-soft); text-decoration: none; }
.zc-chip.is-active{ background: var(--zc-accent); color: var(--zc-ink-invert); }
.zc-chip__num{ font-variant-numeric: tabular-nums; }
/* Тревожный срез (расхождения, недостачи) — тот же чип в красном. */
.zc-chip--danger{ border-color: var(--zc-danger-line); color: var(--zc-danger); }
.zc-chip--danger:hover{ background: var(--zc-danger-bg); }
.zc-chip--danger.is-active{ background: var(--zc-danger); color: var(--zc-ink-invert); }

/* Подсказка «? Как …» (каркас §4.9) — серый текст со значком-кружком. */
.zc-hint{
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px;
  color: var(--zc-ink-muted); font-size: var(--zc-t-small-size);
}
.zc-hint:hover{ color: var(--zc-ink); text-decoration: underline; }
.zc-hint::before{
  content: "?";
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; flex: 0 0 18px;
  border: 1px solid currentColor; border-radius: 50%;
  font-size: 12px; font-weight: 600; line-height: 1;
}

/* Поиск — НЕ фильтр (каркас §4.5): живёт в правом краю строки заголовка,
   компактным полем с лупой. Обычная GET-форма, submit по Enter. */
.zc-search{ display: flex; align-items: center; position: relative; }
.zc-search input[type="search"], .zc-search input[type="text"]{
  width: 220px; padding-right: 38px;
  border-radius: 999px;
  min-height: 40px;
}
.zc-search__glyph{
  position: absolute; right: 12px;
  color: var(--zc-ink-faint); font-size: 15px; line-height: 1;
  pointer-events: none;
}
@media (max-width: 767px){
  /* На телефоне поиск уходит на свою строку во всю ширину (как у образца:
     `order: -1; width: 100%`), иначе он выдавливает заголовок. */
  .zc-pagehead__right{ margin-left: 0; width: 100%; }
  .zc-search{ width: 100%; }
  .zc-search input[type="search"], .zc-search input[type="text"]{ width: 100%; }
}

/* --------------------------------------------------- 2. СТРОКА ДЕЙСТВИЙ ---- */
/* `[＋ Главное]  ВТОРИЧНОЕ ......... ⧩ ФИЛЬТР  ⧩ ФИЛЬТР  ЭКСПОРТ`
   Одна строка, ~56px вместе с нижним промежутком. Главное действие — слева.
   Всё, что после `.zc-actions__gap`, уезжает вправо. */
.zc-actions{
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 8px;
  min-height: 44px;
  margin: 0 0 12px;   /* см. пояснение к .zc-pagehead: не var(--zc-gap) */
}
.zc-actions__gap{ margin-left: auto; }
/* Форма внутри строки действий (экспорт POST-ом, submit фильтра) не должна
   ломать ряд собственным блочным поведением. */
.zc-actions form{ margin: 0; display: contents; }

/* Иерархия кнопок (каркас §4.3). Базовый `.zc-btn` = ГЛАВНОЕ действие:
   залитая акцентная пилюля, одна на экран. Ниже — остальные четыре уровня. */

/* Значимое вторичное: белая пилюля с акцентной рамкой. */
.zc-btn--outline{
  background: var(--zc-surface); color: var(--zc-accent);
  border-color: var(--zc-accent);
}
.zc-btn--outline:hover{ background: var(--zc-accent-soft); color: var(--zc-accent-hover); }

/* Обычное вторичное: ТЕКСТ КАПСОМ без рамки и фона. */
.zc-btn--text{
  background: transparent; color: var(--zc-accent); border-color: transparent;
  padding: 0 12px;
  font-size: var(--zc-t-small-size); font-weight: 600;
  letter-spacing: .04em; text-transform: uppercase;
}
.zc-btn--text:hover{ background: var(--zc-accent-soft); color: var(--zc-accent-hover); }

/* Недоступное: тот же текст капсом, но серый и некликабельный. Отдельный
   класс нужен ссылкам — у <a> нет атрибута disabled, а «выглядит серым, но
   ведёт куда-то» хуже, чем ничего. */
.zc-btn--muted,
.zc-btn--text[disabled], .zc-btn[disabled]{
  background: transparent; color: var(--zc-ink-faint); border-color: transparent;
  cursor: default; pointer-events: none;
}

/* Опасное в списке — текст капсом красным. Залитая красная кнопка (подтверждение
   необратимого) — это уже существующая `.zc-btn--danger-confirm`. */
.zc-btn--danger-text{
  background: transparent; color: var(--zc-danger); border-color: transparent;
  padding: 0 12px;
  font-size: var(--zc-t-small-size); font-weight: 600;
  letter-spacing: .04em; text-transform: uppercase;
}
.zc-btn--danger-text:hover{ background: var(--zc-danger-bg); color: var(--zc-danger); }

/* Значок внутри кнопки (＋, воронка) — всегда ВМЕСТЕ с текстом (каркас §4.7). */
.zc-btn__glyph{ font-size: 16px; line-height: 1; }

/* Счётчик выбранного НА САМОЙ кнопке фильтра (каркас §4.5: «счётчик выбранного
   — на кнопке»), а не отдельной строкой «Фильтры (0)» под ней. Ноль не
   печатается вовсе — макрос его не выводит. */
.zc-btn__count{
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: 999px;
  background: var(--zc-accent); color: var(--zc-ink-invert);
  font-size: var(--zc-t-micro-size); font-weight: 600;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}
.zc-btn--text .zc-btn__count{ background: var(--zc-accent); }
.zc-btn:not(.zc-btn--text):not(.zc-btn--outline) .zc-btn__count{
  background: var(--zc-ink-invert); color: var(--zc-accent);
}

/* ------------------------------------------- 3. ОКНА: ФИЛЬТР И МОДАЛКА ----- */
/* ОДИН механизм на оба: нативный `popover`. Кнопка-открыватель — это
   `<button popovertarget="ID">`, само окно — `<div id="ID" popover>`.
   Что даёт платформа без единой строки JS:
     * top layer — окно поверх всего, независимо от z-index и overflow предков
       (у прежнего `<details>` вложенность в карточку с overflow резала окно);
     * Escape закрывает;
     * клик мимо окна закрывает (popover=auto);
     * фокус уходит внутрь окна и возвращается на кнопку при закрытии;
     * `::backdrop` — затемнение фона.
   Где вводимые данные терять нельзя (форма создания/редактирования) — окно
   объявляется `popover="manual"`: Escape и клик мимо ОТКЛЮЧАЮТСЯ платформой,
   закрыть можно только крестиком или «Отмена», а те ведут в окно
   подтверждения. Это наш ответ на требование «подтверждение при потере
   введённого» в системе без JS: отличить «форма грязная» от «форма чистая»
   без скрипта нельзя, поэтому решение принимается ЗАРАНЕЕ, на уровне типа
   окна, а не в момент закрытия. */
.zc-modal{
  /* popover по умолчанию позиционируется браузером в центр с рамкой и
     отступами — снимаем всё и центрируем сами. */
  position: fixed; inset: 0;
  width: 100%; max-width: 100%; height: 100%; max-height: 100%;
  margin: 0; padding: var(--zc-page-pad);
  border: 0; background: transparent; overflow: auto;
  /* поверх содержимого окна не должно быть ничего своего */
  display: none;
}
.zc-modal:popover-open{
  display: flex; align-items: flex-start; justify-content: center;
}
.zc-modal::backdrop{ background: rgba(27, 36, 50, .5); }
.zc-modal__card{
  background: var(--zc-surface);
  border-radius: var(--zc-radius-lg);
  box-shadow: 0 12px 40px rgba(27, 36, 50, .28);
  width: 100%; max-width: 640px;
  margin: 6vh 0 var(--zc-page-pad);
  /* Появление «увеличением из центра», как у образца. Уважает системную
     настройку «уменьшить движение» (см. блок ниже). */
  animation: zc-modal-in .18s ease-out;
}
.zc-modal--narrow .zc-modal__card{ max-width: 480px; }
.zc-modal--wide   .zc-modal__card{ max-width: 880px; }
@keyframes zc-modal-in{
  from{ opacity: 0; transform: scale(.96); }
  to  { opacity: 1; transform: scale(1); }
}
@media (prefers-reduced-motion: reduce){
  .zc-modal__card{ animation: none; }
}
.zc-modal__head{
  display: flex; align-items: center; gap: var(--zc-gap);
  padding: var(--zc-gap) var(--zc-gap) 8px;
}
.zc-modal__title{
  font-size: var(--zc-t-h2-size); line-height: var(--zc-t-h2-lh);
  font-weight: var(--zc-t-h2-w); margin: 0; flex: 1 1 auto; min-width: 0;
}
.zc-modal__close{
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px; margin: -8px -8px -8px 0;
  border: 0; border-radius: 999px; background: transparent;
  color: var(--zc-ink); font-size: 20px; line-height: 1; cursor: pointer;
}
.zc-modal__close:hover{ background: var(--zc-surface-3); }
.zc-modal__body{ padding: 0 var(--zc-gap) var(--zc-gap); }
.zc-modal__note{ color: var(--zc-ink-muted); font-size: var(--zc-t-small-size); margin: 0 0 var(--zc-gap); }
/* Подвал: кнопки ПРИЖАТЫ ВПРАВО, отмена — левее главной (каркас §4.8). */
.zc-modal__foot{
  display: flex; align-items: center; justify-content: flex-end;
  flex-wrap: wrap; gap: 8px;
  padding: var(--zc-gap);
  border-top: 1px solid var(--zc-line-soft);
}
/* Вложенный блок на сером фоне внутри модалки. */
.zc-modal__group{
  background: var(--zc-surface-2);
  border-radius: var(--zc-radius);
  padding: var(--zc-gap);
  margin-bottom: var(--zc-gap);
}
/* Поля модалки в две колонки — с M и шире; на телефоне всегда одна. */
.zc-modal__grid{ display: grid; grid-template-columns: 1fr; gap: 0 var(--zc-gap); }
@media (min-width: 768px){
  .zc-modal__grid{ grid-template-columns: 1fr 1fr; }
  .zc-modal__grid .zc-field--wide{ grid-column: 1 / -1; }
}
/* Обязательное поле и ошибка валидации (каркас §4.8). */
.zc-req{ color: var(--zc-danger); }
.zc-field--error input, .zc-field--error select, .zc-field--error textarea{
  border-color: var(--zc-danger-line);
}
.zc-field__error{
  display: flex; align-items: center; gap: 6px;
  color: var(--zc-danger); font-size: var(--zc-t-caption-size); margin: 4px 0 0;
}
.zc-field__error::before{
  content: "!";
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; flex: 0 0 16px;
  border-radius: 50%; background: var(--zc-danger); color: var(--zc-ink-invert);
  font-size: 11px; font-weight: 700; line-height: 1;
}

/* Окно фильтра — та же механика, окно поменьше и прижато к верху. */
.zc-filterwin .zc-modal__card{ max-width: 420px; margin-top: 10vh; }
.zc-filterwin__list{ display: flex; flex-direction: column; }
/* Вариант фильтра — ССЫЛКА, применяется СРАЗУ (каркас §4.5: кнопки
   «Применить» нет). Отмеченный вариант помечен галочкой. */
.zc-filterwin__opt{
  display: flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 0 8px;
  border-radius: var(--zc-radius);
  color: var(--zc-ink); font-size: var(--zc-t-body-size);
}
.zc-filterwin__opt:hover{ background: var(--zc-surface-2); text-decoration: none; }
.zc-filterwin__opt.is-on{ color: var(--zc-accent); font-weight: 600; }
.zc-filterwin__opt::before{
  content: "";
  width: 18px; height: 18px; flex: 0 0 18px;
  border: 1px solid var(--zc-line); border-radius: 4px;
}
.zc-filterwin__opt.is-on::before{
  content: "\2713";
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--zc-accent); border-color: var(--zc-accent);
  color: var(--zc-ink-invert); font-size: 13px; line-height: 1;
}

/* ------------------------------------- 4. ПАНЕЛЬ МАССОВЫХ ДЕЙСТВИЙ --------- */
/* Появляется МЕЖДУ строкой действий и шапкой таблицы, как только отмечена
   хоть одна строка (каркас §1.2). Без JS это делает `:has()` по состоянию
   чекбоксов внутри общей обёртки `.zc-listing`.

   ВАЖНО про место: панель не «выталкивает» таблицу рывком — она занимает ту
   же высоту, что и была бы, потому что появляется в потоке ВМЕСТО пустоты
   ровно в момент выделения, и до выделения её нет вовсе (display:none), то
   есть в бюджет 140-160px «от заголовка до первой строки» она не входит. */
.zc-listing{ display: block; }
.zc-bulkbar{
  display: none;
  align-items: center; flex-wrap: wrap; gap: 8px;
  min-height: 44px; margin-bottom: 8px;
  padding: 0 8px;
  background: var(--zc-accent-soft); border-radius: var(--zc-radius);
}
.zc-listing:has(tbody input[type="checkbox"]:checked) .zc-bulkbar{ display: flex; }
.zc-bulkbar__count{
  font-size: var(--zc-t-small-size); font-weight: 600; color: var(--zc-accent);
  font-variant-numeric: tabular-nums;
}
/* Счётчик «N строк выбрано.» под таблицей слева — тоже только при выделении. */
.zc-listing__selected{ display: none; font-size: var(--zc-t-small-size); color: var(--zc-ink-muted); }
.zc-listing:has(tbody input[type="checkbox"]:checked) .zc-listing__selected{ display: block; }

/* ----------------------------------------------- 5. ТАБЛИЦА: ДОБАВКИ ------- */
/* Косметика и плотность самой таблицы — выше, в блоке TABLE. Здесь только то,
   что появилось вместе с образцом: колонка-чекбокс, сортировка кликом по
   заголовку, подсветка выделенной строки. */

/* Первая колонка — чекбокс, всегда (каркас §4.4). */
.zc-table__check{ width: 44px; }
.zc-table__check input[type="checkbox"]{
  width: 18px; height: 18px; min-height: 0; margin: 0; padding: 0;
}
/* Тач-таргет чекбокса на телефоне обеспечивает подпись-обёртка. */
.zc-table__check label{
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px; margin: 0;
}

/* Сортировка кликом по названию колонки; стрелка — ТОЛЬКО у активной. */
.zc-th-sort{
  display: inline-flex; align-items: center; gap: 4px;
  color: inherit; font: inherit;
}
.zc-th-sort:hover{ color: var(--zc-ink); text-decoration: none; }
.zc-th-sort__arrow{ font-size: 11px; color: var(--zc-ink); }

/* Выделенная строка — светло-голубая заливка на всю ширину (каркас §4.4).
   Держится на `:has()`: чекбокс отмечен → строка подсвечена, без JS. */
.zc-table tbody tr:has(input[type="checkbox"]:checked){
  background: var(--zc-accent-soft);
}
@media (min-width: 1200px){
  .zc-table tbody tr:hover{ background: var(--zc-surface-2); }
  .zc-table tbody tr:has(input[type="checkbox"]:checked):hover{ background: var(--zc-accent-soft); }
}
/* Таблица лежит в белой карточке со скруглением; фон страницы светло-серый. */
.zc-table-card{
  background: var(--zc-surface);
  border: 1px solid var(--zc-line-soft);
  border-radius: var(--zc-radius);
  overflow: hidden;
}
.zc-table-card > .zc-table-wrap{ margin: 0; }
@media (max-width: 1199px){
  /* На S/M строки — карточки сами по себе; вторая рамка вокруг них лишняя. */
  .zc-table-card{ background: transparent; border: 0; border-radius: 0; overflow: visible; }
}

/* Прочерк «значение пусто» и красное «Н/Д» для незаполненного обязательного
   (каркас §4.4). Носителей два — цвет И текст, как требует §4.3. */
.zc-dash{ color: var(--zc-ink-faint); }
.zc-na{ color: var(--zc-danger); font-weight: 600; }

/* --------------------------------------------------- 6. ПАГИНАЦИЯ ---------- */
/* Под таблицей, прижата вправо (каркас §1.2). Слева от неё — счётчик
   выделенного, поэтому обёртка — flex с space-between. */
.zc-listing__foot{
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 8px;
  margin-top: var(--zc-gap);
}
.zc-pager{
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  margin-left: auto;
}
.zc-pager__label{ font-size: var(--zc-t-small-size); color: var(--zc-ink-muted); margin-right: 8px; }
.zc-pager__size{ width: auto; min-height: 36px; padding: 4px 8px; border-radius: 999px; }
.zc-pager__btn{
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 36px; min-height: 36px; padding: 0 8px;
  border: 1px solid var(--zc-line); border-radius: 999px;
  background: var(--zc-surface); color: var(--zc-accent);
  font-size: var(--zc-t-small-size);
}
.zc-pager__btn:hover{ background: var(--zc-accent-soft); text-decoration: none; }
.zc-pager__btn.is-off{ color: var(--zc-ink-faint); border-color: var(--zc-line-soft); pointer-events: none; }
.zc-pager__cur{
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 36px; min-height: 36px; padding: 0 8px;
  border-radius: var(--zc-radius);
  background: var(--zc-accent); color: var(--zc-ink-invert);
  font-size: var(--zc-t-small-size); font-weight: 600;
  font-variant-numeric: tabular-nums;
}
@media (max-width: 767px){
  /* Тач-таргеты пагинации на телефоне — 44px, как всё остальное. */
  .zc-pager__btn, .zc-pager__cur, .zc-pager__size{ min-width: 44px; min-height: 44px; }
}

/* --------------------------------------------------- 7. ПУСТОЕ СОСТОЯНИЕ --- */
/* Формула образца (каркас §4.6): жирный заголовок «Нет <объектов>» + ОДНА
   строка-инструкция «чтобы появились — нужно …». Прижато влево, без картинок
   и без центровки. Таблица и пагинация при этом исчезают целиком, а строка
   заголовка и строка действий ОСТАЮТСЯ — главное действие всегда под рукой.

   Текст — не «ничего не найдено», а путь к данным. Наши честные формулировки
   («сумма неизвестна, а не ноль рублей»; «учёт по кабинету ещё не начат»)
   ЛУЧШЕ образца и переезжают сюда как есть — под них третья, необязательная
   строка `.zc-empty__note`. */
.zc-empty{ padding: var(--zc-gap) 0 var(--zc-page-pad); max-width: 68ch; }
.zc-empty__title{
  font-size: var(--zc-t-h2-size); line-height: var(--zc-t-h2-lh);
  font-weight: 600; color: var(--zc-ink); margin: 0 0 4px;
}
.zc-empty__lead{ color: var(--zc-ink-muted); margin: 0; }
.zc-empty__note{ color: var(--zc-ink-faint); font-size: var(--zc-t-caption-size); margin: 8px 0 0; }
.zc-empty__actions{ display: flex; gap: 8px; flex-wrap: wrap; margin-top: var(--zc-gap); }

/* --------------------------------------------- 8. КАРТОЧКА-ПЕРЕХОД (хаб) --- */
/* Раздел, объединяющий несколько сущностей, ведёт не в таблицу, а в хаб
   карточек (каркас §4.10): крупный заголовок, стрелка `→` в правом верхнем
   углу, короткое описание серым внизу, кликабельна ЦЕЛИКОМ.
   Кликабельность карточек — то, что у нас уже было лучше образца
   (на дашборде карточки-ссылки), и она сохранена. */
.zc-hubcards{
  display: grid; grid-template-columns: 1fr; gap: var(--zc-gap);
  margin-bottom: var(--zc-gap);
}
@media (min-width: 768px){ .zc-hubcards{ grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1200px){ .zc-hubcards{ grid-template-columns: repeat(3, 1fr); } }
.zc-hubcard{
  display: block; position: relative;
  background: var(--zc-surface-2);
  border: 1px solid var(--zc-line-soft); border-radius: var(--zc-radius);
  padding: var(--zc-gap);
  padding-right: 44px;
  color: var(--zc-ink); min-height: 88px;
}
.zc-hubcard:hover{ background: var(--zc-surface-3); text-decoration: none; border-color: var(--zc-line); }
.zc-hubcard__title{ font-size: var(--zc-t-h2-size); font-weight: var(--zc-t-h2-w); }
.zc-hubcard__lead{ color: var(--zc-ink-muted); font-size: var(--zc-t-caption-size); margin-top: 4px; }
.zc-hubcard__arrow{
  position: absolute; top: var(--zc-gap); right: var(--zc-gap);
  color: var(--zc-ink-muted); font-size: 18px; line-height: 1;
}
.zc-hubcard:hover .zc-hubcard__arrow{ color: var(--zc-accent); }
/* Число-показатель в карточке хаба (сколько документов, сколько товаров). */
.zc-hubcard__value{
  font-size: var(--zc-t-display-size); line-height: var(--zc-t-display-lh);
  font-weight: var(--zc-t-display-w); font-variant-numeric: tabular-nums;
}

/* ------------------------------- 9. МАРКЕР РАСКРЫТИЯ У СТАРЫХ ФИЛЬТРОВ ----- */
/* ВРЕМЕННОЕ правило — снять, когда все разделы переедут на `zc_filter_btn`.

   Разбор дефекта «в „Списаниях“ и „Перемещениях“ блок „Фильтры“ не
   раскрывается» (05.08.2026). Механика `<details>` исправна: настоящий клик
   настоящим Chromium раскрывает блок во ВСЕХ пяти отчётах, на копии боевых
   данных и на синтетике, на 1280px и на 375px — воспроизвести отказ не
   удалось. Что удалось найти — причину, по которой отказ ВЫГЛЯДИТ так:

   у `<summary>` в этой системе НЕТ НИ ОДНОГО признака раскрываемости.
   Правило `details > summary { list-style: none }` (строка ~146) гасит
   встроенный треугольник, а взамен не даёт ничего: свёрнутые «Фильтры» —
   просто белая полоса с жирным словом, неотличимая от заголовка секции.
   Раскрытие тоже не всегда заметно: в «Пополнениях» и «Остатке» под полосой
   разворачивается высокий блок с наборами «Источник»/«Режим», а в
   «Списаниях» и «Перемещениях» на пустом кабинете — четыре поля, дублирующие
   пресеты периода, которые уже видны выше строкой чипов. Клик «ничего не
   меняет» ровно там, где владелец это и сообщил.

   Поэтому чиним ПРИЗНАК, а не обработчик: треугольник ▸/▾, курсор, наведение
   и рамка-состояние. Селекторы адресуют классы, живущие в CSS разделов
   (reports.css/zc-docs.css и инлайн-стили) — намеренно: это общий механизм,
   один и тот же на пяти экранах, и чинить его пятью копиями нельзя. */
.rp-filters > summary,
.gd-filters > summary,
.zcd-filters > summary,
.rc-filters > summary{
  gap: 8px;
}
.rp-filters > summary::before,
.gd-filters > summary::before,
.zcd-filters > summary::before,
.rc-filters > summary::before{
  content: "\25B8";
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; flex: 0 0 16px;
  font-size: 12px; color: var(--zc-ink-muted);
  transition: transform .12s ease-out;
}
.rp-filters[open] > summary::before,
.gd-filters[open] > summary::before,
.zcd-filters[open] > summary::before,
.rc-filters[open] > summary::before{ content: "\25BE"; }
.rp-filters > summary:hover,
.gd-filters > summary:hover,
.zcd-filters > summary:hover,
.rc-filters > summary:hover{ background: var(--zc-surface-2); color: var(--zc-accent); }
@media (prefers-reduced-motion: reduce){
  .rp-filters > summary::before,
  .gd-filters > summary::before,
  .zcd-filters > summary::before,
  .rc-filters > summary::before{ transition: none; }
}
