/* Модуль «Поставщики»: справочник бюро.

   Перенесено из public/styles.css как было (24 сентября 2026). Подключается
   отдельным <link> только у включённого модуля — renderIndex() в server.js.
   Токены облика те же, из :root общего styles.css: кегль, отступы и
   радиусы — только ими, числами не писать (docs/ОБЛИК-И-ШКАЛЫ.md).

   В общем styles.css остались то, чем пользуются и другие экраны:
   полоса загрузки (.progress), выбор строкой (.pickbox), .pageicon. */

/* Вкладки справочника и переключатель вида — одной строкой.
   Переключатель не внутри полосы вкладок: та листается вбок, когда вкладок
   много, и переключатель уезжал бы вместе с ними. */
.supviews { display: flex; align-items: flex-end; gap: var(--s-3); margin-bottom: var(--s-4); }
.supviews .tabs { flex: 1; min-width: 0; margin-bottom: 0; }
.supviews .viewseg { flex: none; margin-bottom: var(--s-1); }

/* Поиск первым и во всю ширину: справочник открывают с вопросом «у кого мы
   брали свет», а не «покажи всех подряд». */
.supsearch { width: 100%; height: 42px; font-size: var(--t-md); }
/* Отбор по категориям — теми же фишками, что типы задач на доске: один язык
   на всё приложение, и объяснять его второй раз не нужно. */
.supcats { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-bottom: var(--s-4); }
.typechip__n {
  margin-left: var(--s-1); font-size: var(--t-2xs); color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.typechip--add { border-style: dashed; color: var(--text-faint); }

.suptbl { background: var(--surface); border-radius: var(--radius); overflow: hidden; }
.suptbl td { padding: var(--s-1) var(--s-2); vertical-align: top; }
.suptbl th { cursor: default; }
/* Заголовок — кнопка порядка. Нажатая помечена стрелкой, а не только цветом:
   по цвету не видно, вверх сортировка или вниз. */
.suptbl__th { cursor: pointer; user-select: none; white-space: nowrap; }
.suptbl__th:hover { color: var(--text); }
.suptbl__th.is-sorted { color: var(--text); }
.suptbl__ord { margin-left: 3px; font-size: var(--t-2xs); }

/* Ячейка — текст, пока в неё не встали. Рамка у каждой из сотни ячеек
   превратила бы таблицу в анкету: не видно, где данные, а где пустота. */
.supcell {
  display: flex; align-items: flex-start; gap: var(--s-1); min-height: 30px;
  flex-wrap: wrap;
  border-radius: var(--radius-sm); padding: 0 var(--s-1); cursor: text;
  transition: background var(--fast), box-shadow var(--fast);
}
.supcell:hover { background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--border); }
/* Текст переносится, а не тянет столбец. Раньше ячейка была в одну строку,
   и «Что продаёт» с описанием на полтораста знаков растягивало столбец на
   пол-экрана, а таблицу — на четыре ширины монитора. Перенос по любому месту
   нужен ради ссылок и почты: пробелов в них нет, и без него строка всё равно
   распирала бы столбец. */
.supcell__text {
  flex: 1; min-width: 0; font-size: var(--t-sm);
  white-space: normal; overflow-wrap: anywhere;
}
/* В таблице текст в покое обрезан до двух строк.
   Обрезка появилась не ради красоты. На мониторе видны первые семь столбцов
   с короткими значениями, а высоту строки задавали «Отзывы» и «Разбор
   аудита» далеко справа: из шестисот строк четыре сотни выходили выше
   восьмидесяти точек, и таблица читалась пустыми провалами между строками.
   Данные при этом не теряются — под срезом стоит «ещё», и в правке текст
   по-прежнему весь. На странице поставщика обрезки нет: там поле и открывают
   затем, чтобы прочитать целиком. */
.supcell__text.is-cut {
  display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
}
/* «ещё» — своей строкой под текстом и тише текста: это не орган управления
   строкой, а признак того, что под срезом что-то осталось. */
.supcell__more {
  flex: 0 0 100%; margin: 0; padding: 0; border: none; background: none;
  font: inherit; font-size: var(--t-2xs); color: var(--text-faint);
  text-align: left; cursor: pointer;
}
.supcell__more:hover { color: var(--accent); }
.supcell__empty { flex: 1; color: var(--text-faint); font-size: var(--t-sm); }
.supcell__input {
  width: 100%; height: 28px; padding: 0 var(--s-1); font-size: var(--t-sm);
}
/* Ссылка отдельным знаком: нажатие ради правки не должно уводить со страницы */
.supcell__go {
  flex: none; color: var(--text-faint); text-decoration: none; padding: 0 2px;
  font-size: var(--t-xs);
}
.supcell__go:hover { color: var(--accent); text-decoration: none; }
/* Источник — словом в цвете, а не фишкой: столбец читают колонкой сверху
   вниз, и «работали» должно выделяться среди непроверенного, не крича. */
.suporigin { font-size: var(--t-sm); text-align: left; }
.suporigin.is-worked { color: var(--ok); font-weight: 500; }
.suporigin.is-viki { color: var(--text); }
.suporigin.is-bought { color: var(--text-faint); }
/* Две кнопки в строке — чёрный список и удаление — в один ряд, без переноса */
.suptbl__act { white-space: nowrap; }
.supcell__pick {
  background: none; border: none; padding: 0; cursor: pointer; font: inherit;
  display: flex; align-items: center; min-width: 0;
}

/* Перебранная руками строка — светло-зелёная. Отметка не про поставщика,
   а про разбор базы: две трети строк пришли пачкой из купленной таблицы,
   и без цвета не видно, докуда дошли. Цвет бледный намеренно — это фон под
   двадцатью столбцами, а не сообщение. */
.suptbl tr.is-checked td { background: color-mix(in srgb, var(--ok) 9%, transparent); }
/* Категорий у поставщика бывает пять — метки переносятся, а не режутся */
.supcell--tags .supcell__pick { flex: 1; }
.supcell__tags { display: flex; flex-wrap: wrap; gap: 3px; }

/* Страница одного поставщика: то же, что в строке таблицы, но читаемо.
   В двадцати пяти столбцах человека не покажешь, а ссылкой делятся именно
   на человека — «вот у кого брали ту плитку». */
.suppage__state {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  margin-bottom: var(--s-4);
}
.suppage__cats { margin-bottom: var(--s-5); }
.suppage__grid {
  display: grid; gap: var(--s-3) var(--s-5);
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  margin-bottom: var(--s-6);
}
.suppage__label {
  font-size: var(--t-xs); color: var(--text-dim); text-transform: uppercase;
  letter-spacing: .04em; margin-bottom: 2px;
}
.suppage__field .supcell { border: 1px solid var(--border); }
.suppage__more { grid-column: 1 / -1; justify-self: start; }
.suppage__kon { margin-bottom: var(--s-6); }
.suppage__kon h3 { margin-bottom: var(--s-2); }
.suppage__foot {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  padding-top: var(--s-4); border-top: 1px solid var(--border);
}
/* Номер записи внизу страницы. Голым UUID он стоял среди слов и читался
   как данные о поставщике; на деле это техническая строка, которую не
   читают, а копируют. Отсюда подпись словами и курсор «копировать». */
.supidbtn {
  padding: 0; border: none; background: none; font: inherit;
  font-size: var(--t-xs); color: var(--text-faint); cursor: copy;
}
.supidbtn:hover { color: var(--text-dim); }

/* Окно заведения поставщика: два поля в ряд, полки фишками */
.newsup__row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
.newsup__cats {
  display: flex; flex-wrap: wrap; gap: var(--s-1);
  max-height: 190px; overflow-y: auto;
}

/* Поиск — в строке заголовка: отдельной строкой он съедал полсотни пикселей
   высоты, а их не хватает таблице.

   Полоса разложена сеткой, а не флексом. Флексом название, поле и кнопки
   вставали подряд от левого края, и на широком экране треть строки оставалась
   пустой справа. Здесь боковые колонки равны — значит поле стоит по центру
   страницы, а не по центру остатка, — а кнопки уходят к правому краю. */
.suphead {
  display: grid; align-items: center;
  grid-template-columns: 1fr minmax(200px, 560px) 1fr;
  gap: var(--s-3);
}
/* Своя нижняя граница ширины: общее правило шапок разделов ставит
   заголовку `min-width: 0`, и в сетке его колонка сжималась ниже самого
   слова — «Поставщики» вылезало из своей клетки и уезжало под поле поиска
   на экранах от 760 до 1100 точек. */
.suphead h1 { justify-self: start; min-width: max-content; }
.suphead .supsearch { min-width: 0; max-width: none; margin: 0; }
.suphead .page__head-right { justify-self: end; }
/* На телефоне поиск уходит на свою строку.

   В одну строку с названием раздела и двумя кнопками он не помещался
   и распирал страницу: сама страница уезжала вбок, и заголовок с фишками
   уходили за левый край. Поиск при этом главный орган раздела — прятать
   или ужимать его нельзя, значит место ему нужно своё. */
@media (max-width: 760px) {
  /* Сетка в три колонки на узком экране не нужна: колонок нет, всё
     переносится. Возвращаем флекс, которым и написана мобильная раскладка. */
  .suphead { display: flex; flex-wrap: wrap; }
  .suphead .supsearch { flex: 1 0 100%; order: 3; max-width: none; }
  /* Заголовку хватает своей ширины: общее правило широких разделов давало
     ему всю строку, и кнопка заведения сваливалась под него отдельным рядом
     на пустом месте. */
  .page--wide .suphead h1 { flex: 1 1 auto; }
  /* Длинное название полки не распирает ряд: «Индивидуальные
     изготовления/корпусная мебель» шире экрана целиком. */
  .typechip { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
}

/* Отметка «перебрано» — не системная галочка. Пока она рисовалась галочкой,
   её читали как «выбрать строку»: это разные вещи, и путать их нельзя. */
.supmark {
  border: 1px solid var(--border); background: none; cursor: pointer;
  border-radius: 999px; padding: 2px var(--s-2); font: inherit;
  font-size: var(--t-xs); color: var(--text-faint); white-space: nowrap;
  transition: color var(--fast), border-color var(--fast), background var(--fast);
}
.supmark:hover { color: var(--text-dim); border-color: var(--border-strong); }
.supmark.is-on {
  color: var(--ok); border-color: color-mix(in srgb, var(--ok) 45%, transparent);
  background: color-mix(in srgb, var(--ok) 10%, transparent);
}
.supcell--check { cursor: default; }
.supcell--check:hover { background: none; box-shadow: none; }

/* Выбор пачкой: своя колонка, своя галочка, свой цвет строки */
.suptbl__pick { text-align: center; vertical-align: middle; }
.suptbl__pick input { margin: 0; cursor: pointer; }
/* Переход на страницу поставщика — свой столбец сразу за выбором пачкой.
   Кнопка тихая: строк шестьсот, и шестьсот заметных кнопок легли бы решёткой
   поверх данных. Она проясняется на строке под курсором и загорается под
   самим курсором — то есть находится ровно тогда, когда её ищут. */
.suptbl__open { text-align: center; vertical-align: middle; }
.supopen {
  display: inline-grid; place-items: center;
  width: 28px; height: 28px; padding: 0;
  border: none; border-radius: var(--radius-sm);
  background: none; cursor: pointer; color: var(--text-faint);
  transition: color var(--fast), background var(--fast);
}
.suptbl tr:hover .supopen { color: var(--text-dim); }
.supopen:hover { color: var(--accent); background: var(--surface-2); }
.supopen:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.suptbl tr.is-picked td { background: color-mix(in srgb, var(--accent) 10%, transparent); }

/* Что можно сделать с выбранными. Появляется, когда есть кого. */
.suppick {
  display: none; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  margin-bottom: var(--s-3); padding: var(--s-2) var(--s-3);
  border: 1px solid var(--accent); border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}
.suppick.is-on { display: flex; }
.suppick__n { font-size: var(--t-sm); font-weight: 500; white-space: nowrap; }

/* Технический номер строки: моноширинный, тусклый, копируется нажатием */
.supcell--id { cursor: copy; }
.supid {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: var(--t-2xs); color: var(--text-faint); overflow-wrap: anywhere;
}

/* Контакты в ячейке: у поставщика их бывает пять, и каждый — своя строка */
.supkon { display: flex; flex-direction: column; gap: 3px; width: 100%; }
.supkon__row { display: flex; flex-wrap: wrap; gap: var(--s-1); align-items: baseline; }
.supkon__name { font-size: var(--t-sm); font-weight: 500; }
.supkon__val {
  font-size: var(--t-xs); color: var(--text-dim); text-decoration: none;
  overflow-wrap: anywhere;
}
a.supkon__val:hover { color: var(--accent); }

/* Правка контакта: четыре поля в ряд, заметка под ними, крестик справа */
.konedit {
  position: relative; border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--s-3); padding-right: 40px; margin-bottom: var(--s-2);
  display: flex; flex-direction: column; gap: var(--s-2);
}
.konedit__grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2);
}
.konedit__del { position: absolute; top: var(--s-2); right: var(--s-2); }

/* Справочник на телефоне — карточками.

   Двадцать пять столбцов на экране в 375 точек — лента шириной в пятнадцать
   экранов. С телефона в справочник заходят найти поставщика и позвонить ему;
   разбирают базу за столом. */
/* Сеткой, а не столбцом: на телефоне столбец выходит сам собой — там
   помещается один, — а за столом карточка во всю ширину монитора это строка
   таблицы, только высокая. 300 точек — ширина, на которой имя поставщика
   и строчка «что продаёт» читаются без переносов посреди слова. */
.supcards {
  display: grid; gap: var(--s-2);
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  align-items: start;
}
/* Строка «показаны первые двести» — во всю ширину сетки, а не карточкой. */
.supcards__more { grid-column: 1 / -1; }
.supcard {
  /* Обводка, а не одна заливка. На светлой теме карточку от полотна отделяла
     разница в светлоте, и её хватало; на тёмной обе плоскости тёмные, разница
     сходит на нет, и сетка карточек превращалась в одно поле с текстом.
     Граница держит карточку карточкой в любой теме. */
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--s-3); display: flex; flex-direction: column; gap: var(--s-1);
  transition: border-color var(--fast), box-shadow var(--fast);
}
.supcard:hover { border-color: var(--border-strong); box-shadow: var(--shadow-xs); }
.supcard.is-checked { box-shadow: inset 3px 0 0 var(--ok); }
.supcard__name {
  border: none; background: none; padding: 0; text-align: left; cursor: pointer;
  font: inherit; font-size: var(--t-md); font-weight: 600; color: var(--text);
}
.supcard__cats { display: flex; flex-wrap: wrap; gap: 3px; }
.supcard__what {
  font-size: var(--t-sm); color: var(--text-dim);
  /* Две строки: описание бывает в полтораста слов, и карточка вырастала
     на пол-экрана — до следующего поставщика приходилось листать. */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.supcard__kon { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-2); }
.supcard__who { font-size: var(--t-sm); font-weight: 500; }
.supcard__link { font-size: var(--t-sm); text-decoration: none; }
.supcard__foot {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s-2); margin-top: 2px;
}
.supcard__go { font-size: var(--t-sm); text-decoration: none; flex: none; }
.supcards__more { padding: var(--s-3) 0; text-align: center; }

.konedit__move { position: absolute; top: var(--s-2); right: 40px; }

/* Разбор повторов. Куча — это строки об одном поставщике; отмеченная
   останется, остальные подошьются к ней. */
.dupgroup {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--s-3); margin-bottom: var(--s-3);
}
.dupgroup__why { margin-bottom: var(--s-2); }
.dupgroup__foot { margin-top: var(--s-2); display: flex; justify-content: flex-end; }
.duprow {
  display: flex; align-items: baseline; gap: var(--s-2); cursor: pointer;
  padding: var(--s-1) 0;
}
.duprow input { margin: 0; flex: none; }
.duprow__name { font-weight: 500; flex: none; }
.duprow__meta { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Отборы, которых не бывает у категорий: сегмент и оценка. Списками,
   а не фишками — значений мало, и в ряду с полусотней категорий они
   читались бы ещё одной категорией. */
.supfilters {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  margin-bottom: var(--s-3);
}
.supfilters__n { margin-left: var(--s-2); white-space: nowrap; }
/* Оценка аудита — буквой в цвете. Читать её приходится колонкой сверху вниз,
   и цвет отвечает на «где тут плохо» быстрее, чем чтение букв. */
.suptbl__grade .supcell__text { font-weight: 600; }
.suptbl__grade.is-A .supcell__text { color: var(--ok); }
.suptbl__grade.is-B .supcell__text { color: var(--text); }
.suptbl__grade.is-C .supcell__text { color: var(--warn); }
.suptbl__grade.is-D .supcell__text { color: var(--critical); }
/* Таблица шире экрана и листается вбок: столбцов пятнадцать, и ужимать их
   до нечитаемости хуже, чем листать. Ширины заданы в точках, а не в долях:
   в долях «Сегмент» получал столько же, сколько «Что продаёт». */
/* Ширины столбцов — предел, а не запрос: fixed держит их ровно такими,
   какие заданы, и содержимое переносится внутри. min-width таблице ставит
   сама страница, суммой видимых столбцов: столбцы включаются и выключаются,
   и зашитое сюда число врало бы при каждом переключении. */
.suptbl { table-layout: fixed; }
/* Поле правки на несколько строк — для тех полей, где лежит абзац */
.supcell__input--long {
  height: auto; min-height: 120px; resize: vertical; line-height: 1.4;
  padding: var(--s-1);
}
/* Таблица шире экрана листается в своей рамке, а не вместе со страницей.
   Пока вбок ехала страница, уезжало всё разом — шапка раздела, поиск,
   фишки категорий, — и слева оставалось пустое поле шириной в монитор.
   Тень у правого края говорит, что справа ещё есть: слой local едет с
   содержимым и закрывает её на самом краю, слой scroll стоит на месте. */
.tblscroll {
  overflow: auto; max-width: 100%;
  border-radius: var(--radius);
  /* Высоту ставит разметка: над таблицей то одна строка отборов, то три,
     и зашитое сюда число врало бы через раз. */
  background:
    linear-gradient(to left, var(--surface), transparent) right center / 24px 100% no-repeat local,
    radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, .13), transparent)
      right center / 10px 100% no-repeat scroll;
}
/* Шапка таблицы стоит на месте, пока едет всё остальное. Без неё на шестой
   сотне строк уже не помнишь, какой столбец что значит, а столбцов двадцать. */
.suptbl thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--surface);
  box-shadow: inset 0 -1px 0 var(--border);
}
