/* components.css — все классы из таблицы docs/interfaces.md §7.3, до единого.
 *
 * Это контракт с тем, кто пишет разметку: имя класса отсюда он использует как
 * есть, нового имени не изобретает. Порядок разделов повторяет порядок строк
 * в таблице §7.3, чтобы искать по документу и по файлу можно было одинаково.
 *
 * Правила, действующие во всём файле:
 *   — цвет только ролью var(--md-sys-color-*) либо фирменной переменной;
 *     прямых значений цвета нет ни одного;
 *   — размеры только из шкал в base.css, промежуточных нет;
 *   — область нажатия у всего кликабельного не меньше 48×48px (design.md §10);
 *   — высота показывается тоном поверхности, тень только у того, что физически
 *     висит над содержимым: плавающая кнопка и диалог (design.md §6).
 *
 * Раскладка (design.md §7): до 600px одна колонка и нижняя панель,
 * 600–1240px две колонки, от 1240px боковая полоса навигации.
 */

/* ================================================================== */
/* Каркас: sl-app · sl-rail · sl-bar · sl-topbar · sl-main            */
/* ================================================================== */

.sl-app {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "topbar"
    "main";
  background: var(--md-sys-color-surface);
  color: var(--md-sys-color-on-surface);
}

/* Шапка. Уровень 2 по design.md §6 — тоном, без тени. */
.sl-topbar {
  grid-area: topbar;
  position: sticky;
  top: 0;
  z-index: var(--sl-z-topbar);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sl-space-8);
  min-height: var(--sl-topbar-h);
  padding-block: var(--sl-space-8);
  padding-inline: var(--sl-space-16);
  background: var(--md-sys-color-surface-container);
  color: var(--md-sys-color-on-surface);
  border-block-end: var(--sl-line) solid var(--md-sys-color-outline-variant);
}

/* Название системы, слева в шапке.
 *
 * Размер задан через :where() — у такого правила нулевая специфичность.
 * Поэтому класс типографики из разметки (sl-title-m, sl-title-l) его
 * перебьёт, и последнее слово о размере останется за разметкой. Если же
 * класса типографики нет, работает Title Large — размер заголовка шапки
 * по M3, а не унаследованный от body текст в 14px. */
:where(.sl-topbar__brand) {
  font-size: var(--sl-type-title-l-size);
  line-height: var(--sl-type-title-l-line);
  font-weight: var(--sl-type-title-l-weight);
  letter-spacing: var(--sl-type-title-l-track);
}

.sl-topbar__brand {
  min-width: 0;
  color: var(--md-sys-color-on-surface);
}

/* Группа справа: имя вошедшего, переключатель темы, выход.
 *
 * К правому краю её прижимает одно margin-inline-start: auto. Второго
 * auto (на бренде) быть не должно: два встречных auto делят свободное
 * место пополам, и группа до края не доходит.
 *
 * Своя перенос-строка: на 360px шапка переносится на две строки, группа
 * уходит на вторую целиком и остаётся прижатой вправо. */
.sl-topbar__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sl-space-16);
  min-width: 0;
  margin-inline-start: auto;
}

/* Рабочая область. Одна колонка на телефоне, две от 600px.
 * minmax(0, 1fr) вместо 1fr — колонка не раздувается от широкого содержимого
 * внутри, поэтому страница по горизонтали не едет.
 * Нижний отступ до 1240px держит место под нижней панелью: она position: fixed
 * и содержимое иначе уезжает под неё. */
.sl-main {
  grid-area: main;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sl-space-16);
  align-content: start;
  padding: var(--sl-space-16);
  padding-block-end: calc(var(--sl-bar-h) + var(--sl-space-16));
  overflow-x: clip;
}

/* Заголовки разделов и заведомо широкое содержимое занимают всю ширину:
 * таблице и полосе загрузки половина колонки не нужна.
 *
 * Родителем считается и сама .sl-main, и корневой <section> экрана. Правило
 * писалось для прямых детей .sl-main, но с приходом экранов между ней и
 * содержимым всегда стоит <section>, и по одному родителю оно переставало
 * работать. */
:where(.sl-main, .sl-main > section)
  > :where(h1, h2, .sl-table, .sl-table__pager, .sl-progress, .sl-empty) {
  grid-column: 1 / -1;
}

/* Корень экрана.
 *
 * Экран приезжает в .sl-main одним <section>. Без этого правила он занимал бы
 * половину ширины — в .sl-main две колонки от 600px (замерено исполнителями:
 * 414 из 900 и 624 из 1400), — а содержимое слипалось бы: классы типографики
 * обнуляют margin, своего просвета у <section> нет.
 *
 * minmax(0, 1fr), а не 1fr: колонка с автоминимумом раздувается до min-content
 * содержимого, и широкая таблица вылезает целиком вместо того, чтобы
 * прокручиваться внутри своей рамки.
 *
 * Экран по умолчанию идёт ОДНОЙ колонкой во всю ширину: под таблицы нужна вся
 * ширина. Две колонки каркаса (design.md §7) на экраны сами собой не
 * распространяются — экран берёт их классом sl-cols ниже. */
.sl-main > section {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
  gap: var(--sl-space-16);
  min-width: 0;
}

/* Экран, которому нужны две колонки от 600px — те же, что .sl-main даёт своим
 * прямым детям. Без этого класса экран остаётся одноколоночным. */
.sl-main > section.sl-cols {
  grid-template-columns: minmax(0, 1fr);
}

/* Боковая полоса навигации. До 1240px её нет — там нижняя панель. */
.sl-rail {
  grid-area: rail;
  display: none;
  position: sticky;
  top: 0;
  z-index: var(--sl-z-rail);
  flex-direction: column;
  align-items: center;
  gap: var(--sl-space-12);
  width: var(--sl-rail-w);
  height: 100dvh;
  padding-block: var(--sl-space-12);
  background: var(--md-sys-color-surface-container);
  color: var(--md-sys-color-on-surface-variant);
  border-inline-end: var(--sl-line) solid var(--md-sys-color-outline-variant);
  overflow-y: auto;
}

/* Нижняя панель навигации, телефон и планшет. До 5 пунктов (design.md §8).
 * position: fixed, потому что панель обязана оставаться на месте при прокрутке
 * длинного списка дел; место под неё зарезервировано отступом .sl-main. */
.sl-bar {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: var(--sl-z-bar);
  display: flex;
  align-items: center;
  justify-content: space-around;
  gap: var(--sl-space-4);
  min-height: var(--sl-bar-h);
  padding-inline: var(--sl-space-8);
  background: var(--md-sys-color-surface-container);
  color: var(--md-sys-color-on-surface-variant);
  border-block-start: var(--sl-line) solid var(--md-sys-color-outline-variant);
}

/* Планшет: две колонки, навигация по-прежнему снизу. */
@media (min-width: 600px) {
  .sl-main {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sl-space-24);
    padding: var(--sl-space-24);
    padding-block-end: calc(var(--sl-bar-h) + var(--sl-space-24));
  }

  /* Тот же просвет между блоками, что и у каркаса: экран внутри <section>
   * держит ритм страницы, а не свой. */
  .sl-main > section {
    gap: var(--sl-space-24);
  }

  .sl-main > section.sl-cols {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Рабочий стол: слева полоса навигации, нижняя панель убирается. */
@media (min-width: 1240px) {
  .sl-app {
    grid-template-columns: var(--sl-rail-w) minmax(0, 1fr);
    grid-template-areas:
      "rail topbar"
      "rail main";
  }

  .sl-rail {
    display: flex;
  }

  .sl-bar {
    display: none;
  }

  .sl-main {
    padding-block-end: var(--sl-space-24);
  }
}

/* ================================================================== */
/* Экран входа: sl-auth                                               */
/* ================================================================== */

/* Обёртка экрана входа: карточка по центру окна по обеим осям, ширина
 * ограничена — форму из двух полей на всю ширину монитора не растягиваем.
 *
 * Раздел стоит ПОСЛЕ раскладки каркаса намеренно. Если разметка повесит
 * sl-main и sl-auth на один элемент, побеждает написанное ниже: display
 * становится flex, и грид каркаса не спорит с центрированием. Отступ задан
 * краткой записью padding — она перекрывает в том числе padding-block-end
 * из медиа-запросов .sl-main, иначе центр по вертикали уехал бы вверх на
 * высоту нижней панели.
 *
 * Боковой отступ держит карточку от краёв на узком экране, а box-sizing:
 * border-box из base.css не даёт обёртке вылезти за окно — горизонтальной
 * прокрутки нет и на 360px. */
.sl-auth {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sl-space-16);
  width: 100%;
  min-height: 100vh;
  min-height: 100dvh;
  padding: var(--sl-space-24) var(--sl-space-16);
}

/* Карточка входа и всё, что стоит рядом с ней, — не шире 400px. */
.sl-auth > * {
  width: 100%;
  max-width: var(--sl-auth-max);
}

/* ================================================================== */
/* Страница клиента: sl-measure · sl-brandbar · __name · sl-brand-title */
/* ================================================================== */

/* Единственный экран, который видит человек снаружи фирмы. Отдельные правила
 * §9 design.md: одна колонка на любой ширине, содержимое ограничено по ширине
 * для читаемости, только светлая тема. */

/* Мера строки. Ширина в знаках, а не в пикселях (см. --sl-measure в base.css):
 * на 1440px текст иначе идёт во всю ширину и строку тяжело вести глазом.
 * margin-inline: auto — колонка встаёт по центру, иначе на широком экране она
 * жалась бы к левому краю и отрывалась от шапки. */
.sl-measure {
  max-width: var(--sl-measure);
  margin-inline: auto;
}

/* Фирменная шапка. Подложка --brand-deep (design.md §3 отдаёт её именно сюда),
 * текст светлый: контраст пары проверен и держит норму для любого кегля.
 *
 * Роли светлой темы взяты намеренно: страница клиента всегда светлая
 * (design.md §2), и разметка закрепляет это атрибутом data-theme="light" на
 * <html>. Внутри системы этот класс не применяется.
 *
 * Логотипа нет и рисовать его не надо — design.md §11 прямо запрещает;
 * названия фирмы достаточно. */
.sl-brandbar {
  padding-block: var(--sl-space-16);
  padding-inline: var(--sl-space-24);
  background: var(--brand-deep);
  color: var(--md-sys-color-surface);
}

/* Название фирмы. Мера та же, что у содержимого, и центрируется так же —
 * тогда название стоит над текстом, а не улетает к краю экрана. */
.sl-brandbar__name {
  display: block;
  max-width: var(--sl-measure);
  margin-inline: auto;
  font-family: var(--font-brand);
  font-size: var(--sl-type-title-l-size);
  line-height: var(--sl-type-title-l-line);
  font-weight: 600;
  letter-spacing: var(--sl-type-title-l-track);
}

/* Заголовок фирменным шрифтом. Ставится рядом с классом типографики:
 * <h1 class="sl-headline-l sl-brand-title">. Кегль и высота строки остаются за
 * типографикой, здесь только гарнитура — иначе шкала разъехалась бы.
 * Только страница клиента: внутри системы заголовки на Roboto (design.md §4). */
.sl-brand-title {
  font-family: var(--font-brand);
}

/* ================================================================== */
/* Пункт навигации: sl-nav-item · --active · __icon · __label         */
/* ================================================================== */

/* Один класс на оба места — и в боковой полосе, и в нижней панели.
 * Область нажатия 48×48 держится min-height/min-width, даже когда значок 24px. */
.sl-nav-item {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sl-space-4);
  min-height: var(--sl-touch);
  min-width: var(--sl-touch);
  padding: var(--sl-space-4);
  border: 0;
  border-radius: var(--sl-shape-l);
  background: transparent;
  color: var(--md-sys-color-on-surface-variant);
  text-decoration: none;
  cursor: pointer;
  transition: color var(--sl-dur-short) var(--sl-ease);
}

.sl-nav-item:hover {
  color: var(--md-sys-color-on-surface);
}

/* Указатель выбора — заливка под значком, как в M3.
 * Выбранный пункт помечается ещё и aria-current="page": цвет не единственный
 * носитель смысла (design.md §10). */
.sl-nav-item__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--sl-nav-ind-w);
  height: var(--sl-nav-ind-h);
  border-radius: var(--sl-shape-full);
  transition: background-color var(--sl-dur-short) var(--sl-ease);
}

.sl-nav-item__icon > svg,
.sl-nav-item__icon > img {
  width: var(--sl-icon);
  height: var(--sl-icon);
  fill: currentColor;
}

.sl-nav-item__label {
  font-size: var(--sl-type-label-m-size);
  line-height: var(--sl-type-label-m-line);
  font-weight: var(--sl-type-label-m-weight);
  letter-spacing: var(--sl-type-label-m-track);
  text-align: center;
}

.sl-nav-item--active {
  color: var(--md-sys-color-on-secondary-container);
}

.sl-nav-item--active .sl-nav-item__icon {
  background: var(--md-sys-color-secondary-container);
}

.sl-nav-item--active .sl-nav-item__label {
  font-weight: var(--sl-type-title-s-weight);
}

/* ================================================================== */
/* Кнопка: sl-btn + --filled · --tonal · --outlined · --text · --fab  */
/*         иконка внутри — sl-btn__icon                                */
/* ================================================================== */

/* Основа общая для пяти видов. Высота 48px — это размер M3 «medium» и
 * одновременно минимальная область нажатия из design.md §10. */
.sl-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sl-space-8);
  min-height: var(--sl-touch);
  min-width: var(--sl-touch);
  padding-inline: var(--sl-space-24);
  border: 0;
  border-radius: var(--sl-shape-full);
  background: transparent;
  color: var(--md-sys-color-primary);
  font-family: var(--font-sans);
  font-size: var(--sl-type-label-l-size);
  line-height: var(--sl-type-label-l-line);
  font-weight: var(--sl-type-label-l-weight);
  letter-spacing: var(--sl-type-label-l-track);
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color var(--sl-dur-short) var(--sl-ease),
    color var(--sl-dur-short) var(--sl-ease);
}

/* Значок внутри кнопки. flex: none — не сжимается, когда подпись длинная. */
.sl-btn__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--sl-icon);
  height: var(--sl-icon);
}

.sl-btn__icon > svg,
.sl-btn__icon > img {
  width: 100%;
  height: 100%;
  fill: currentColor;
}

/* Недоступная кнопка: подпись on-surface 38%, заливка on-surface 12% — доли M3.
 * Оба значения набираются из роли через color-mix, прямого цвета нет. */
.sl-btn:disabled,
.sl-btn[aria-disabled="true"] {
  color: color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent);
  cursor: default;
  pointer-events: none;
}

/* --- Главное действие на экране (design.md §8) --------------------- */
.sl-btn--filled {
  background: var(--md-sys-color-primary);
  color: var(--md-sys-color-on-primary);
}

.sl-btn--filled:hover {
  background: color-mix(in srgb, var(--md-sys-color-on-primary) 8%, var(--md-sys-color-primary));
}

.sl-btn--filled:active {
  background: color-mix(in srgb, var(--md-sys-color-on-primary) 12%, var(--md-sys-color-primary));
}

/* --- Второстепенное действие --------------------------------------- */
.sl-btn--tonal {
  background: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
}

.sl-btn--tonal:hover {
  background: color-mix(
    in srgb,
    var(--md-sys-color-on-secondary-container) 8%,
    var(--md-sys-color-secondary-container)
  );
}

.sl-btn--tonal:active {
  background: color-mix(
    in srgb,
    var(--md-sys-color-on-secondary-container) 12%,
    var(--md-sys-color-secondary-container)
  );
}

/* --- Второстепенное действие, нейтральное -------------------------- */
.sl-btn--outlined {
  border: var(--sl-line) solid var(--md-sys-color-outline);
  background: transparent;
  color: var(--md-sys-color-primary);
}

.sl-btn--outlined:hover {
  background: color-mix(in srgb, var(--md-sys-color-primary) 8%, transparent);
}

.sl-btn--outlined:active {
  background: color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent);
}

.sl-btn--outlined:disabled,
.sl-btn--outlined[aria-disabled="true"] {
  border-color: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent);
  background: transparent;
}

/* --- Третьестепенное, в ряду --------------------------------------- */
.sl-btn--text {
  padding-inline: var(--sl-space-12);
  background: transparent;
  color: var(--md-sys-color-primary);
}

.sl-btn--text:hover {
  background: color-mix(in srgb, var(--md-sys-color-primary) 8%, transparent);
}

.sl-btn--text:active {
  background: color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent);
}

/* --- Плавающая кнопка: добавить дело с любого экрана ---------------- *
 * Скругление large (16px) и тень — она единственная физически висит над
 * содержимым. Место на экране задаёт разметка: класс отвечает за вид,
 * не за положение.                                                     */
.sl-btn--fab {
  width: var(--sl-fab-size);
  height: var(--sl-fab-size);
  min-width: var(--sl-fab-size);
  min-height: var(--sl-fab-size);
  padding-inline: 0;
  border-radius: var(--sl-shape-l);
  background: var(--md-sys-color-primary-container);
  color: var(--md-sys-color-on-primary-container);
  box-shadow: var(--sl-shadow-3);
}

.sl-btn--fab:hover {
  background: color-mix(
    in srgb,
    var(--md-sys-color-on-primary-container) 8%,
    var(--md-sys-color-primary-container)
  );
}

.sl-btn--filled:disabled,
.sl-btn--tonal:disabled,
.sl-btn--fab:disabled,
.sl-btn--filled[aria-disabled="true"],
.sl-btn--tonal[aria-disabled="true"],
.sl-btn--fab[aria-disabled="true"] {
  background: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent);
  box-shadow: none;
}

/* ================================================================== */
/* Карточка: sl-card · __title · __body · __actions                   */
/* ================================================================== */

/* Уровень 1 по design.md §6 — карточка в списке. Тени нет намеренно:
 * высота показывается тоном. Рамка — outline-variant (design.md §3). */
.sl-card {
  display: flex;
  flex-direction: column;
  gap: var(--sl-space-8);
  min-width: 0;
  padding: var(--sl-space-16);
  border: var(--sl-line) solid var(--md-sys-color-outline-variant);
  border-radius: var(--sl-shape-m);
  background: var(--md-sys-color-surface-container-low);
  color: var(--md-sys-color-on-surface);
}

.sl-card__title {
  margin: 0;
  font-size: var(--sl-type-title-m-size);
  line-height: var(--sl-type-title-m-line);
  font-weight: var(--sl-type-title-m-weight);
  letter-spacing: var(--sl-type-title-m-track);
  color: var(--md-sys-color-on-surface);
}

.sl-card__body {
  margin: 0;
  font-size: var(--sl-type-body-m-size);
  line-height: var(--sl-type-body-m-line);
  font-weight: var(--sl-type-body-m-weight);
  letter-spacing: var(--sl-type-body-m-track);
  color: var(--md-sys-color-on-surface-variant);
}

.sl-card__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sl-space-8);
  padding-block-start: var(--sl-space-8);
}

/* ================================================================== */
/* Флажок: sl-check · __box · __label                                  */
/* ================================================================== */

/* Булево поле формы: «НДС включён», «Работает», «Агент вёл клиента».
 * До появления этого класса такие поля собирались списком выбора «да/нет» —
 * работало, но список из двух значений это обход, а не флажок.
 *
 * Обёртка — сам элемент label, а не div рядом с ним. Тогда подпись и рамка
 * образуют одну область нажатия без атрибута for и без совпадающих
 * идентификаторов: щелчок по слову переключает флажок силами браузера.
 *
 * Область нажатия тянется до 48px невидимой рамкой (design.md §10): рисованный
 * квадратик 18px пальцем не берётся, а увеличивать сам квадратик значит рисовать
 * не флажок, а кнопку.
 *
 * Галочку рисует БРАУЗЕР, ей задаётся только цвет ролью. Рукописная галочка —
 * это своя картинка, свой цвет мимо палитры и своя же работа над состояниями
 * «отмечен», «недоступен», «неопределён», которые браузер уже умеет. */
.sl-check {
  display: flex;
  align-items: center;
  gap: var(--sl-space-12);
  min-height: var(--sl-touch);
  cursor: pointer;
}

.sl-check__box {
  flex: none;
  inline-size: var(--sl-check-size);
  block-size: var(--sl-check-size);
  margin: 0;
  /* Цвет отметки — роль, а не значение. Браузер сам берёт контрастный
   * знак поверх заливки. */
  accent-color: var(--md-sys-color-primary);
  cursor: inherit;
}

.sl-check__label {
  font-size: var(--sl-type-body-l-size);
  line-height: var(--sl-type-body-l-line);
  font-weight: var(--sl-type-body-l-weight);
  letter-spacing: var(--sl-type-body-l-track);
  color: var(--md-sys-color-on-surface);
  min-width: 0;
}

/* Недоступный флажок гасится вместе с подписью: серый квадратик рядом с чёрным
 * словом читается как «можно нажать». Соседний селектор, а не :has() — подпись
 * и так стоит следом за флажком, и правило остаётся читаемым без обхода вверх. */
.sl-check__box:disabled {
  cursor: default;
}

.sl-check__box:disabled + .sl-check__label {
  color: var(--md-sys-color-on-surface-variant);
}

/* ================================================================== */
/* Ряд действий вне карточки: sl-actions                               */
/* ================================================================== */

/* Кнопки НАД списком: «Завести клиента», «Добавить этап». Это не sl-card__actions:
 * тот прижимает кнопки вправо и живёт нижней строкой карточки, а действие над
 * списком — первое, что читают, и стоит оно слева, у начала строки.
 *
 * Просвет тот же, что у действий карточки, — ряды кнопок в системе не должны
 * выглядеть по-разному в зависимости от того, внутри они или снаружи. */
.sl-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: var(--sl-space-8);
}

/* ================================================================== */
/* Пара «поле — значение»: sl-kv · __label · __value                   */
/* ================================================================== */

/* Ставится либо на <dl> целиком — тогда внутри чередуются <dt> и <dd>, — либо
 * на обёртку одной пары. Работает одинаково: раскладка пары не считает, она
 * раскладывает подпись и значение.
 *
 * Узко — подпись над значением, широко — рядом. Порог считается от ширины
 * КОНТЕЙНЕРА, а не окна: карточка в две колонки на широком мониторе бывает уже
 * телефонной. Механика — перенос flex: пока значению хватает своей основы, оно
 * стоит рядом с подписью; не хватает — уезжает на свою строку во всю ширину.
 * Порог выходит около 376px ширины контейнера.
 *
 * Отступы <dl> и <dd> от браузера сброшены: из-за них подпись и значение
 * слипались, а значение уезжало вправо на 40px. */
.sl-kv {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--sl-space-16);
  row-gap: var(--sl-space-4);
  margin: 0;
}

.sl-kv__label {
  flex: 0 1 var(--sl-kv-label);
  min-width: 0;
  margin: 0;
  color: var(--md-sys-color-on-surface-variant);
}

.sl-kv__value {
  flex: 1 1 var(--sl-kv-value);
  min-width: 0;
  margin: 0;
  color: var(--md-sys-color-on-surface);
}

/* Пары отделены друг от друга сильнее, чем подпись от своего значения: иначе
 * <dl> из пяти пар сливается в один столбик и читать его так же тяжело. */
.sl-kv > .sl-kv__label:not(:first-child) {
  margin-block-start: var(--sl-space-8);
}

/* Всё прочее внутри пары — пояснение под значением — занимает свою строку. */
.sl-kv > :not(.sl-kv__label):not(.sl-kv__value) {
  flex: 1 1 100%;
  margin: 0;
}

/* Размер задан с нулевой специфичностью: класс типографики из разметки его
 * перебьёт. Экраны уже пишут sl-label-m и sl-body-m — выбор остаётся за ними.
 * Без такого класса работает design.md §4: «названия полей» — Title Small,
 * содержимое — Body Medium. */
:where(.sl-kv__label) {
  font-size: var(--sl-type-title-s-size);
  line-height: var(--sl-type-title-s-line);
  font-weight: var(--sl-type-title-s-weight);
  letter-spacing: var(--sl-type-title-s-track);
}

:where(.sl-kv__value) {
  font-size: var(--sl-type-body-m-size);
  line-height: var(--sl-type-body-m-line);
  font-weight: var(--sl-type-body-m-weight);
  letter-spacing: var(--sl-type-body-m-track);
}

/* ================================================================== */
/* Поле ввода: sl-field · __label · __input · __hint · --invalid ·     */
/*             __error                                                 */
/* ================================================================== */

/* Outlined text field по design.md §8. Подпись стоит над полем отдельным
 * элементом (Title Small — «названия полей», design.md §4), а не всплывает
 * внутрь рамки: контракт §7.3 даёт отдельный класс __label, и связка
 * <label for> с <input id> проще и надёжнее для чтения с экрана. */
.sl-field {
  display: flex;
  flex-direction: column;
  gap: var(--sl-space-4);
  min-width: 0;
}

.sl-field__label {
  font-size: var(--sl-type-title-s-size);
  line-height: var(--sl-type-title-s-line);
  font-weight: var(--sl-type-title-s-weight);
  letter-spacing: var(--sl-type-title-s-track);
  color: var(--md-sys-color-on-surface-variant);
}

.sl-field__input {
  width: 100%;
  min-height: var(--sl-touch);
  padding: var(--sl-space-12) var(--sl-space-16);
  border: var(--sl-line) solid var(--md-sys-color-outline);
  border-radius: var(--sl-shape-s);
  background: var(--md-sys-color-surface);
  color: var(--md-sys-color-on-surface);
  font-size: var(--sl-type-body-l-size);
  line-height: var(--sl-type-body-l-line);
  font-weight: var(--sl-type-body-l-weight);
  letter-spacing: var(--sl-type-body-l-track);
  transition: border-color var(--sl-dur-short) var(--sl-ease);
}

.sl-field__input::placeholder {
  color: var(--md-sys-color-on-surface-variant);
}

/* Рамка на фокусе только меняет цвет, толщина остаётся 1px: иначе поле
 * дёргалось бы на 1px при каждом заходе. Видимость фокуса обеспечивает
 * общая рамка 2px с отступом 2px из base.css. */
.sl-field__input:focus-visible {
  border-color: var(--md-sys-color-primary);
}

.sl-field__input:disabled {
  border-color: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent);
  color: color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent);
}

/* Одно имя на три элемента: input, select и textarea. Так уже сделали три
 * модуля из четырёх, и это правильнее отдельных имён — поле остаётся полем,
 * чем бы его ни отрисовал браузер. */

/* Стрелку у <select> рисует браузер и рисует по color-scheme из palette.css,
 * поэтому appearance не сбрасываем: свою стрелку пришлось бы класть картинкой
 * с цветом внутри, а прямых цветов вне palette.css у нас нет. Отступ справа
 * увеличен, чтобы длинное значение не подлезало под стрелку. */
select.sl-field__input {
  padding-inline-end: var(--sl-space-32);
  cursor: pointer;
}

/* Тянуть можно только по высоте: у браузера по умолчанию resize: both, и таким
 * полем карточку растягивают вширь — вместе с ней разъезжается вся раскладка.
 * Высота от двух областей нажатия: одна строка в поле ввода коротка для текста,
 * который набирают абзацем. */
textarea.sl-field__input {
  min-height: calc(var(--sl-touch) * 2);
  resize: vertical;
}

.sl-field__hint {
  font-size: var(--sl-type-body-s-size);
  line-height: var(--sl-type-body-s-line);
  font-weight: var(--sl-type-body-s-weight);
  letter-spacing: var(--sl-type-body-s-track);
  color: var(--md-sys-color-on-surface-variant);
}

/* Ошибка поля. Разметка обязана дать <input aria-invalid="true"
 * aria-describedby="<id ошибки>">, а самому тексту — role="alert":
 * иначе о неверном значении узнает только зрячий. */
.sl-field--invalid .sl-field__input {
  border-color: var(--md-sys-color-error);
}

.sl-field--invalid .sl-field__input:focus-visible {
  border-color: var(--md-sys-color-error);
}

.sl-field--invalid .sl-field__label {
  color: var(--md-sys-color-error);
}

.sl-field__error {
  font-size: var(--sl-type-body-s-size);
  line-height: var(--sl-type-body-s-line);
  font-weight: var(--sl-type-body-s-weight);
  letter-spacing: var(--sl-type-body-s-track);
  color: var(--md-sys-color-error);
}

/* ================================================================== */
/* Чипы-фильтры: sl-chips · sl-chip · --selected                      */
/* ================================================================== */

/* Промежуток 16px, а не 8px: у чипа высота 32px, а область нажатия
 * растянута до 48px невидимым слоем — при меньшем промежутке слои
 * соседних рядов накладывались бы друг на друга. */
.sl-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sl-space-16);
}

.sl-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--sl-space-8);
  min-height: var(--sl-chip-h);
  min-width: var(--sl-touch);
  padding-inline: var(--sl-space-16);
  border: var(--sl-line) solid var(--md-sys-color-outline);
  border-radius: var(--sl-shape-s);
  background: transparent;
  color: var(--md-sys-color-on-surface-variant);
  font-size: var(--sl-type-label-l-size);
  line-height: var(--sl-type-label-l-line);
  font-weight: var(--sl-type-label-l-weight);
  letter-spacing: var(--sl-type-label-l-track);
  cursor: pointer;
  transition:
    background-color var(--sl-dur-short) var(--sl-ease),
    color var(--sl-dur-short) var(--sl-ease);
}

/* Область нажатия 48×48 при видимой высоте 32px: невидимый слой поверх
 * чипа, по 8px сверху и снизу. Вид M3 сохраняется, палец попадает. */
.sl-chip::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 50%;
  height: var(--sl-touch);
  transform: translateY(-50%);
}

.sl-chip:hover {
  background: color-mix(in srgb, var(--md-sys-color-on-surface-variant) 8%, transparent);
}

/* Выбранный чип: заливка secondary-container. Разметка обязана поставить
 * aria-pressed="true" — тогда выбор слышен, а не только виден. */
.sl-chip--selected {
  border-color: transparent;
  background: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
}

.sl-chip--selected:hover {
  background: color-mix(
    in srgb,
    var(--md-sys-color-on-secondary-container) 8%,
    var(--md-sys-color-secondary-container)
  );
}

.sl-chip:disabled {
  border-color: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent);
  color: color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent);
  cursor: default;
  pointer-events: none;
}

/* ================================================================== */
/* Диалог: sl-dialog · __title · __body · __actions                   */
/* ================================================================== */

/* Пишется на <dialog> и открывается showModal(): тогда ловушка фокуса,
 * закрытие по Escape и затемнение достаются от браузера, а не пишутся
 * руками. Уровень 3 (design.md §6) плюс тень — диалог висит над содержимым. */
.sl-dialog {
  max-width: var(--sl-dialog-max);
  width: calc(100% - var(--sl-space-48));
  padding: var(--sl-space-24);
  border: 0;
  border-radius: var(--sl-shape-xl);
  background: var(--md-sys-color-surface-container-high);
  color: var(--md-sys-color-on-surface);
  box-shadow: var(--sl-shadow-3);
}

/* display задаётся только открытому диалогу: правило автора перебивает
 * встроенное dialog:not([open]) { display: none }, и закрытый диалог
 * остался бы на экране. */
.sl-dialog[open] {
  display: flex;
  flex-direction: column;
  gap: var(--sl-space-16);
}

/* Открытый обычным open (без showModal) встаёт в поток — так его показывает
 * витрина demo.html. На showModal это не влияет: там :modal. */
.sl-dialog:not(:modal) {
  position: static;
}

.sl-dialog::backdrop {
  background: color-mix(in srgb, var(--md-sys-color-scrim) 32%, transparent);
}

.sl-dialog__title {
  margin: 0;
  font-size: var(--sl-type-headline-s-size);
  line-height: var(--sl-type-headline-s-line);
  font-weight: var(--sl-type-headline-s-weight);
  letter-spacing: var(--sl-type-headline-s-track);
  color: var(--md-sys-color-on-surface);
}

.sl-dialog__body {
  margin: 0;
  font-size: var(--sl-type-body-m-size);
  line-height: var(--sl-type-body-m-line);
  font-weight: var(--sl-type-body-m-weight);
  letter-spacing: var(--sl-type-body-m-track);
  color: var(--md-sys-color-on-surface-variant);
}

.sl-dialog__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sl-space-8);
}

/* ================================================================== */
/* Сообщение: sl-snackbar · --error                                   */
/* ================================================================== */

/* Роли inverse — design.md §3: всплывающие сообщения об успехе и об ошибке.
 * Разметка обязана дать role="status" (успех) либо role="alert" (ошибка),
 * иначе сообщение не будет объявлено при чтении с экрана. */
.sl-snackbar {
  display: flex;
  align-items: center;
  gap: var(--sl-space-8);
  min-height: var(--sl-touch);
  max-width: var(--sl-snackbar-max);
  padding: var(--sl-space-12) var(--sl-space-16);
  border-radius: var(--sl-shape-xs);
  background: var(--md-sys-color-inverse-surface);
  color: var(--md-sys-color-inverse-on-surface);
  font-size: var(--sl-type-body-m-size);
  line-height: var(--sl-type-body-m-line);
  font-weight: var(--sl-type-body-m-weight);
  letter-spacing: var(--sl-type-body-m-track);
  box-shadow: var(--sl-shadow-3);
}

/* Кнопка внутри сообщения берёт inverse-primary: обычный primary на
 * перевёрнутой поверхности читается плохо. */
.sl-snackbar .sl-btn--text {
  color: var(--md-sys-color-inverse-primary);
}

.sl-snackbar .sl-btn--text:hover {
  background: color-mix(in srgb, var(--md-sys-color-inverse-primary) 8%, transparent);
}

/* Сообщение об ошибке. Подложка остаётся inverse (design.md §3), различие
 * несёт полоса error-container слева — и слово в тексте: цвет не может быть
 * единственным носителем смысла (design.md §10). */
.sl-snackbar--error {
  border-inline-start: var(--sl-space-4) solid var(--md-sys-color-error-container);
}

/* Положение внизу экрана получает только сообщение, добавленное прямо в
 * <body> — так его вешает snackbar() из ядра. Вложенное в разметку (витрина)
 * остаётся в потоке. */
body > .sl-snackbar {
  position: fixed;
  z-index: var(--sl-z-snackbar);
  inset-inline-start: 50%;
  bottom: calc(var(--sl-bar-h) + var(--sl-space-16));
  width: calc(100% - var(--sl-space-32));
  transform: translateX(-50%);
}

@media (min-width: 1240px) {
  body > .sl-snackbar {
    bottom: var(--sl-space-24);
  }
}

/* ================================================================== */
/* Таблица: sl-table · __head · __row · __cell · __pager              */
/* ================================================================== */

/* Разметка: <div class="sl-table"><table>…</table></div>.
 * Прокрутка живёт на контейнере, поэтому широкий отчёт едет внутри своей
 * рамки, а страница по горизонтали не двигается. Настоящий <table> внутри
 * нужен для чтения с экрана: заголовки колонок связываются с ячейками.
 * Если класс повешен прямо на <table>, прокрутка тоже работает. */
.sl-table {
  display: block;
  max-width: 100%;
  overflow-x: auto;
  border: var(--sl-line) solid var(--md-sys-color-outline-variant);
  border-radius: var(--sl-shape-m);
  background: var(--md-sys-color-surface-container-low);
}

.sl-table > table {
  width: 100%;
  border-collapse: collapse;
}

.sl-table__head {
  background: var(--md-sys-color-surface-container);
}

.sl-table__head .sl-table__cell {
  font-size: var(--sl-type-title-m-size);
  line-height: var(--sl-type-title-m-line);
  font-weight: var(--sl-type-title-m-weight);
  letter-spacing: var(--sl-type-title-m-track);
  color: var(--md-sys-color-on-surface);
  text-align: start;
  white-space: nowrap;
}

.sl-table__row {
  border-block-end: var(--sl-line) solid var(--md-sys-color-outline-variant);
}

.sl-table__head .sl-table__row {
  border-block-end-color: var(--md-sys-color-outline);
}

/* Наведение — уровень 4 (design.md §6). */
.sl-table tbody .sl-table__row:hover {
  background: var(--md-sys-color-surface-container-highest);
}

.sl-table tbody .sl-table__row:last-child {
  border-block-end: 0;
}

.sl-table__cell {
  padding: var(--sl-space-12) var(--sl-space-16);
  font-size: var(--sl-type-body-m-size);
  line-height: var(--sl-type-body-m-line);
  font-weight: var(--sl-type-body-m-weight);
  letter-spacing: var(--sl-type-body-m-track);
  color: var(--md-sys-color-on-surface);
  text-align: start;
  vertical-align: middle;
}

/* Постраничный переключатель ставится следом за таблицей, снаружи полосы
 * прокрутки — иначе он уезжал бы вбок вместе с широкими колонками. */
.sl-table__pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sl-space-8);
  padding: var(--sl-space-8) var(--sl-space-16);
  font-size: var(--sl-type-body-m-size);
  line-height: var(--sl-type-body-m-line);
  font-weight: var(--sl-type-body-m-weight);
  letter-spacing: var(--sl-type-body-m-track);
  color: var(--md-sys-color-on-surface-variant);
}

.sl-table + .sl-table__pager {
  border: var(--sl-line) solid var(--md-sys-color-outline-variant);
  border-block-start: 0;
  border-end-start-radius: var(--sl-shape-m);
  border-end-end-radius: var(--sl-shape-m);
  background: var(--md-sys-color-surface-container-low);
}

.sl-table:has(+ .sl-table__pager) {
  border-end-start-radius: 0;
  border-end-end-radius: 0;
}

/* ================================================================== */
/* Пустой список: sl-empty · __text · __action                        */
/* ================================================================== */

/* design.md §8: короткий текст плюс одно действие, не голый экран. */
.sl-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sl-space-16);
  padding: var(--sl-space-48) var(--sl-space-24);
  border: var(--sl-line) dashed var(--md-sys-color-outline-variant);
  border-radius: var(--sl-shape-m);
  color: var(--md-sys-color-on-surface-variant);
  text-align: center;
}

.sl-empty__text {
  margin: 0;
  font-size: var(--sl-type-body-m-size);
  line-height: var(--sl-type-body-m-line);
  font-weight: var(--sl-type-body-m-weight);
  letter-spacing: var(--sl-type-body-m-track);
  color: var(--md-sys-color-on-surface-variant);
}

/* :not(.sl-btn) — чтобы вид кнопки задавался в одном месте: если разметка
 * добавила sl-btn sl-btn--filled, правила кнопки не перебиваются этим. */
.sl-empty__action:not(.sl-btn) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sl-space-8);
  min-height: var(--sl-touch);
  min-width: var(--sl-touch);
  padding-inline: var(--sl-space-24);
  border: 0;
  border-radius: var(--sl-shape-full);
  background: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
  font-size: var(--sl-type-label-l-size);
  line-height: var(--sl-type-label-l-line);
  font-weight: var(--sl-type-label-l-weight);
  letter-spacing: var(--sl-type-label-l-track);
  text-decoration: none;
  cursor: pointer;
}

/* ================================================================== */
/* Полоса загрузки: sl-progress · --indeterminate                     */
/* ================================================================== */

/* Разметка обязана дать role="progressbar" и подпись aria-label: без них
 * при чтении с экрана полоса — пустой прямоугольник.
 * Доля заполнения передаётся переменной --sl-progress-value (например
 * style="--sl-progress-value: 60%") вместе с aria-valuenow. */
.sl-progress {
  display: block;
  position: relative;
  overflow: hidden;
  width: 100%;
  height: var(--sl-progress-h);
  /* flex: none — внутри карточки (колоночный flex) полоса в 4px иначе
   * сжимается до нуля и пропадает с экрана. */
  flex: none;
  border-radius: var(--sl-shape-full);
  background: var(--md-sys-color-surface-container-highest);
}

.sl-progress::after {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: var(--sl-progress-value, 0%);
  border-radius: inherit;
  background: var(--md-sys-color-primary);
  transition: width var(--sl-dur-med) var(--sl-ease);
}

/* Неизвестная длительность: полоска 40% ширины ходит по дорожке.
 * Движение задано transform — его считает композитор, раскладка не
 * пересчитывается на каждом кадре. */
.sl-progress--indeterminate::after {
  width: 40%;
  transition: none;
  animation: sl-progress-slide var(--sl-dur-loop) var(--sl-ease) infinite;
}

@keyframes sl-progress-slide {
  from {
    transform: translateX(-100%);
  }

  to {
    transform: translateX(350%);
  }
}

/* При системной настройке «уменьшить движение» общий сброс из base.css
 * оборвал бы ход на последнем кадре — полоса пропала бы с экрана. Поэтому
 * здесь она становится неподвижной заливкой во всю дорожку: видно, что
 * идёт работа, и это не путается с готовыми 100% (там роль primary). */
@media (prefers-reduced-motion: reduce) {
  .sl-progress--indeterminate::after {
    width: 100%;
    transform: none;
    animation: none;
    background: var(--md-sys-color-primary-container);
  }
}

/* ================================================================== */
/* Типографика: sl-headline/title/body/label -l/-m/-s                 */
/* ================================================================== */

/* Сами размеры и высоты строк заданы один раз в base.css §3 — здесь их
 * нет, чтобы шкала не разъехалась по двум файлам. Это правило добавляет
 * то, что нужно только в раскладке: длинное слово (почта, номер дела,
 * идентификатор) не растягивает колонку грида и переносится по месту,
 * иначе страница поехала бы по горизонтали. */
.sl-headline-l,
.sl-headline-m,
.sl-headline-s,
.sl-title-l,
.sl-title-m,
.sl-title-s,
.sl-body-l,
.sl-body-m,
.sl-body-s,
.sl-label-l,
.sl-label-m,
.sl-label-s {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* ================================================================== */
/* Запрет переноса: sl-nowrap                                          */
/* ================================================================== */

/* Идентификатор, который нельзя рвать: номер дела CL-001-2026/05/01 в узкой
 * колонке таблицы рвался на четыре строки.
 *
 * Стоит ПОСЛЕ типографики намеренно. Та разрешает разрыв внутри слова
 * (overflow-wrap: anywhere), и здесь разрыв отменяется обоими свойствами сразу
 * — иначе итог зависел бы от порядка классов в разметке.
 *
 * Ширину это добавляет только там, где текст длиннее колонки, а таблица
 * прокручивается внутри своей рамки — страница по горизонтали не едет. */
.sl-nowrap {
  white-space: nowrap;
  overflow-wrap: normal;
}

/* ================================================================== */
/* Состояние дела и задачи: sl-state · --done · --active · --waiting · */
/*                          --overdue · --cancelled                    */
/* ================================================================== */

/* Пять состояний и их роли заданы в design.md §3. Это требование заказчика,
 * а не оформление: цвета обязаны совпадать внутри системы и на странице
 * клиента. Внутри значка всегда стоит слово состояния — цвет не может быть
 * единственным носителем смысла (design.md §10). */
.sl-state {
  display: inline-flex;
  align-items: center;
  gap: var(--sl-space-4);
  padding: var(--sl-space-4) var(--sl-space-12);
  border-radius: var(--sl-shape-full);
  font-size: var(--sl-type-label-m-size);
  line-height: var(--sl-type-label-m-line);
  font-weight: var(--sl-type-label-m-weight);
  letter-spacing: var(--sl-type-label-m-track);
  white-space: nowrap;
}

/* Завершено — спокойная заливка, без ликования. */
.sl-state--done {
  background: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
}

/* В работе — самое заметное на экране. */
.sl-state--active {
  background: var(--md-sys-color-primary);
  color: var(--md-sys-color-on-primary);
}

/* Ждёт или запланировано — приглушённое. */
.sl-state--waiting {
  background: var(--md-sys-color-surface-container-high);
  color: var(--md-sys-color-on-surface-variant);
}

/* Просрочено — тревожное. */
.sl-state--overdue {
  background: var(--md-sys-color-error-container);
  color: var(--md-sys-color-on-error-container);
}

/* Отменено — видно, что было, и что больше не в плане. */
.sl-state--cancelled {
  background: var(--md-sys-color-surface-container);
  color: var(--md-sys-color-on-surface-variant);
  text-decoration: line-through;
}
