/*
 * Стили Parallels OS. Один файл, разделы идут в таком порядке:
 *
 *   1. Токены: цвета тем, тона статусов, радиусы, размеры, шкала слоёв.
 *   2. Основа: сброс, шрифты, [hidden].
 *   3. Каркас: боковая панель, меню профиля, шапка, область содержимого.
 *   4. Компоненты: карточки, кнопки, поля форм, сообщения.
 *   5. Списки: панель над таблицей, фильтры, чипы, вкладки модуля.
 *   6. Таблицы: прокрутка, закреплённые столбцы, панель действий, статусы.
 *   7. Узкие экраны: каркас и компоненты на 1200, 1023 и 768px.
 *   8. Страницы: формы, справочники, аналитика, реклама, роли.
 *   9. Карточная вёрстка таблиц на телефоне.
 *
 * Разделы отмечены заголовками «── N.». Правила печати стоят рядом с тем,
 * что они уточняют; у печатных форм свои стили в их шаблонах.
 *
 * Точки перелома — только 768/769px (телефон и планшет / компьютер), 1023px и
 * 1200px. Новое правило для узкого экрана кладётся в @media с одной из них
 * рядом с правилом, которое оно уточняет.
 *
 * Слои (z-index) — только через --z-* из токенов: числа, разбросанные по
 * файлу, перестают быть сравнимыми, и новое всплывающее окно оказывается
 * под панелью, которую должно перекрывать.
 *
 * Прежнее имя файла — telegram.css: первая версия интерфейса была оформлена
 * в стиле Telegram.
 */

/* ── 1. Токены ─────────────────────────────────────────────────────────── */

:root {
    --primary: #2563eb;
    --on-primary: #ffffff;
    --primary-container: #dbeafe;
    --on-primary-container: #0b1d4d;

    --secondary: #5b6b8a;
    --on-secondary: #ffffff;
    --secondary-container: #e4ebff;
    --on-secondary-container: #1a2540;

    --surface: #f6f8fc;
    --surface-container-low: #f1f4f9;
    --surface-container: #ebeff6;
    --surface-container-high: #e4e9f2;
    --surface-container-highest: #dde3ee;
    --on-surface: #1f2937;
    --on-surface-variant: #5f6b7f;

    --outline: #c2cbda;
    --outline-variant: #d4dbe7;

    --error: #c62828;
    --on-error: #ffffff;
    --error-container: #fde8e8;
    --on-error-container: #5f1010;

    --success: #1f9d60;
    --warning: #f59e0b;

    --chart-1: #2a78d6;
    --chart-2: #eb6834;
    --chart-3: #1baf7a;
    --chart-4: #eda100;
    --chart-5: #e87ba4;
    --chart-6: #008300;

    --shadow-1: 0 1px 2px rgba(15, 23, 42, 0.08);
    --shadow-2: 0 4px 14px rgba(15, 23, 42, 0.08);

    --radius-xs: 8px;
    --radius-sm: 10px;
    --radius-md: 12px;
    --radius-lg: 16px;

    --sidebar-width: 272px;
    --rail-width: 84px;
    --topbar-height: 64px;

    /* Нативные элементы (календарь, выпадающие списки, полосы прокрутки)
       берут схему отсюда: без неё в тёмной теме они оставались светлыми, и
       значок календаря на тёмном поле почти не был виден. */
    color-scheme: light;

    /* Тона статусов. Модели отдают тон (success, info…), а не цвет: цвет
       зашитым hex не менялся вместе с темой. */
    --tone-success: #22c55e;
    --tone-info: #3b82f6;
    --tone-warning: #f59e0b;
    --tone-danger: #ef4444;
    --tone-neutral: #6b7280;
    --tone-accent: #8b5cf6;

    /* Смены и отметки штатного календаря. День — тёплый янтарный, ночь —
       тёмный индиго со светлым знаком, 5/2 — голубой. Различие держится не
       только на цвете: у дневной и ночной смены разные знаки (солнце и
       луна), у отметок — буквенные коды. */
    --shift-day-bg: #fdecc4;
    --shift-day-fg: #8a5208;
    --shift-night-bg: #2b3375;
    --shift-night-fg: #e6e9ff;
    --shift-night-border: transparent;
    --shift-office-bg: #dbe7fd;
    --shift-office-fg: #1d4ed8;
    --absence-vacation-bg: #d6f1e1;
    --absence-vacation-fg: #146c43;
    --absence-sick-bg: #fde1e1;
    --absence-sick-fg: #b42318;
    --absence-day-off-bg: #e6e9f0;
    --absence-day-off-fg: #4b5568;
    --absence-unpaid-bg: #fde8d4;
    --absence-unpaid-fg: #9a420a;
    --absence-absent-bg: #d92d20;
    --absence-absent-fg: #ffffff;
    --absence-trip-bg: #ebe3fd;
    --absence-trip-fg: #5b2bb5;

    /* Шкала слоёв снизу вверх. */
    --z-sticky-cell: 2;      /* закреплённые ячейки таблицы */
    --z-sticky-head: 4;      /* их заголовки */
    --z-raised: 5;           /* ручки ширины столбцов, полоса прокрутки таблицы */
    --z-tooltip: 10;         /* подсказки диаграмм */
    --z-bulk-bar: 15;        /* панель действий над отмеченными строками */
    --z-toolbar: 20;         /* закреплённая панель фильтров */
    --z-bulk-bar-phone: 45;  /* она же у низа окна телефона */
    --z-topbar: 50;          /* верхняя панель */
    --z-popover: 60;         /* панель «Столбцы» */
    --z-fab: 80;             /* кнопка «+» */
    --z-overlay: 90;         /* затемнение под меню телефона */
    --z-sidebar: 100;
    --z-sidebar-resizer: 110;
    --z-dropdown: 120;       /* меню профиля */
}

:root[data-theme='dark'] {
    --primary: #9abaff;
    --on-primary: #0a2d73;
    --primary-container: #1d3f87;
    --on-primary-container: #dbe7ff;

    --secondary: #b8c5e6;
    --on-secondary: #24314d;
    --secondary-container: #36425f;
    --on-secondary-container: #dde6ff;

    --surface: #0f1726;
    --surface-container-low: #142033;
    --surface-container: #1b293d;
    --surface-container-high: #223248;
    --surface-container-highest: #2b3a52;
    --on-surface: #e7edf7;
    --on-surface-variant: #a7b4ca;

    --outline: #4b5d79;
    --outline-variant: #36475f;

    --error: #ffb4ab;
    --on-error: #690005;
    --error-container: #93000a;
    --on-error-container: #ffdad6;

    --success: #72d5a3;
    --warning: #ffcb77;

    --chart-1: #3987e5;
    --chart-2: #d95926;
    --chart-3: #199e70;
    --chart-4: #c98500;
    --chart-5: #d55181;
    --chart-6: #008300;

    --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.35);
    --shadow-2: 0 6px 20px rgba(0, 0, 0, 0.4);

    color-scheme: dark;

    /* Светлее, чем в светлой теме: на тёмном поле насыщенные точки теряли
       контраст. */
    --tone-success: #4ade80;
    --tone-info: #60a5fa;
    --tone-warning: #fbbf24;
    --tone-danger: #f87171;
    --tone-neutral: #9ca3af;
    --tone-accent: #a78bfa;

    --shift-day-bg: #4a3812;
    --shift-day-fg: #fcd380;
    --shift-night-bg: #252c6b;
    --shift-night-fg: #d3d8ff;
    /* Тёмно-синяя плашка на тёмно-синем поле сливалась бы с фоном. */
    --shift-night-border: #5f6bd0;
    --shift-office-bg: #1d3461;
    --shift-office-fg: #b3cdff;
    --absence-vacation-bg: #173d2a;
    --absence-vacation-fg: #8fe3b3;
    --absence-sick-bg: #4d1f1f;
    --absence-sick-fg: #ffb4ab;
    --absence-day-off-bg: #2b3548;
    --absence-day-off-fg: #c8d0de;
    --absence-unpaid-bg: #4a2c12;
    --absence-unpaid-fg: #ffc48a;
    --absence-absent-bg: #e5484d;
    --absence-absent-fg: #ffffff;
    --absence-trip-bg: #33265a;
    --absence-trip-fg: #d0bcff;
}

/* ── 2. Основа ─────────────────────────────────────────────────────────── */

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

/* Атрибут hidden скрывает всегда. Правило браузера для него — самое слабое,
   и любой display в классе (.btn, панели) его перебивал: раньше для этого у
   шести компонентов были свои правила [hidden], а у новых их забывали. */
[hidden] {
    display: none !important;
}

html,
body {
    min-height: 100%;
}

body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: var(--surface);
    color: var(--on-surface);
    line-height: 1.45;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

body.is-resizing {
    cursor: col-resize;
    user-select: none;
}

/* Строку тащат (static/js/row-reorder.js): курсор «держу» на всём экране и
   без выделения текста, пока строка едет по списку. */
body.is-row-dragging {
    cursor: grabbing;
    user-select: none;
}

/* Поля и кнопки шрифт не наследуют: без этого поля ввода и списки набирались
   системным шрифтом браузера, а textarea и поля даты — моноширинным, «как на
   печатной машинке», посреди интерфейса на Inter. */
button,
input,
select,
textarea {
    font-family: inherit;
}

/* Ссылки без своего класса («Забыли пароль?», артикул и кампания в таблицах
   рекламы) иначе выходили браузерным синим, а посещённые — фиолетовым. */
a {
    color: var(--primary);
    text-underline-offset: 2px;
}

.material-symbols-rounded {
    font-size: 20px;
}

.app-layout {
    display: flex;
    min-height: 100vh;
    /* dvh учитывает адресную строку мобильного браузера: с одним vh внизу
       оставалась полоса лишней прокрутки на всю её высоту. */
    min-height: 100dvh;
}

/* ── 3. Каркас ───────────────────────────────────────────────────────────── */

.sidebar {
    width: var(--sidebar-width);
    background: var(--surface-container-low);
    border-right: 1px solid var(--outline-variant);
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: var(--z-sidebar);
    transition: width 220ms ease, transform 220ms ease;
}

.sidebar-header {
    height: var(--topbar-height);
    padding: 0 16px;
    border-bottom: 1px solid var(--outline-variant);
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.logo {
    font-size: 21px;
    font-weight: 700;
    color: var(--primary);
    letter-spacing: -0.2px;
}

/* Два варианта названия. В свёрнутом меню ширина равна --rail-width, и полное
   название туда не помещается: раньше ему просто уменьшали шрифт, отчего оно
   выглядело сломанным, а не свёрнутым. */
.logo-full {
    display: inline;
}

.logo-short {
    display: none;
}

.sidebar-close {
    display: none;
    width: 36px;
    height: 36px;
    border-radius: 999px;
    border: 1px solid var(--outline);
    background: transparent;
    color: var(--on-surface-variant);
    cursor: pointer;
}

.sidebar-resizer {
    position: absolute;
    top: 0;
    right: -4px;
    width: 8px;
    height: 100%;
    cursor: col-resize;
    z-index: var(--z-sidebar-resizer);
    /* Палец тянет ручку, а не прокручивает страницу. */
    touch-action: none;
}

.sidebar-resizer::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 3px;
    width: 2px;
    background: transparent;
    transition: background-color 150ms ease;
}

.sidebar-resizer:focus-visible::after,
.sidebar-resizer:hover::after {
    background: var(--outline);
}

.sidebar-nav {
    flex: 1;
    overflow-y: auto;
    padding: 8px;
}

.nav-section {
    padding: 14px 12px 8px;
    font-size: 12px;
    font-weight: 600;
    color: var(--on-surface-variant);
    letter-spacing: 0.2px;
}

.nav-item {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 2px 4px;
    padding: 10px 12px;
    color: var(--on-surface);
    text-decoration: none;
    border-radius: 999px;
    transition: background-color 150ms ease, color 150ms ease;
}

.nav-item:hover {
    background: var(--surface-container);
}

.nav-item:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.nav-item.active {
    background: var(--secondary-container);
    color: var(--on-secondary-container);
    font-weight: 600;
}

.nav-item .nav-icon {
    width: 20px;
    min-width: 20px;
    color: currentColor;
}

.nav-item.active .nav-icon {
    font-variation-settings: 'FILL' 1, 'wght' 500, 'GRAD' 0, 'opsz' 20;
}

.nav-text {
    font-size: 14px;
    white-space: nowrap;
}

/* Разделитель между тремя модулями, справочниками и администрированием.
   Заменил заголовки секций: заголовок над одним пунктом — это шум. */
.nav-divider {
    height: 1px;
    margin: 10px 12px;
    background: var(--outline-variant);
}

/* Счётчик инцидентов. Цвета — токенами, а не литералами: в ads/* уже есть
   бейджи с захардкоженным фоном без указания цвета текста, которые
   проваливают контраст в обеих темах. Новый делаем сразу правильно. */
.nav-badge {
    margin-left: auto;
    min-width: 20px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--error-container);
    color: var(--on-error-container);
    font-size: 12px;
    font-weight: 700;
    line-height: 20px;
    text-align: center;
}

.nav-group-toggle {
    width: calc(100% - 8px);
    border: 0;
    background: transparent;
    font-family: inherit;
    font-size: inherit;
    text-align: left;
    cursor: pointer;
}

.nav-arrow {
    margin-left: auto;
    color: var(--on-surface-variant);
    transition: transform 200ms ease;
}

.nav-group-toggle[aria-expanded="true"] .nav-arrow {
    transform: rotate(180deg);
}

/* Раскрытие без замера высоты в JS: grid-template-rows от 0fr к 1fr
   анимируется, в отличие от height: auto. */
.nav-group {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 200ms ease;
}

.nav-group.is-open {
    grid-template-rows: 1fr;
}

.nav-group-inner {
    overflow: hidden;
    min-height: 0;
}

.nav-subitem {
    display: flex;
    align-items: center;
    margin: 2px 4px;
    padding: 8px 12px 8px 44px;
    color: var(--on-surface-variant);
    text-decoration: none;
    border-radius: 999px;
    font-size: 13px;
    white-space: nowrap;
    transition: background-color 150ms ease, color 150ms ease;
}

.nav-subitem:hover {
    background: var(--surface-container);
}

.nav-subitem:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.nav-subitem.active {
    background: var(--secondary-container);
    color: var(--on-secondary-container);
    font-weight: 600;
}

.sidebar-footer {
    padding: 12px;
    border-top: 1px solid var(--outline-variant);
}

.profile-menu {
    position: relative;
}

.profile-trigger {
    width: 100%;
    border: 1px solid transparent;
    border-radius: 14px;
    padding: 8px;
    background: transparent;
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--on-surface);
    cursor: pointer;
    text-align: left;
}

.profile-trigger:hover {
    background: var(--surface-container);
}

.profile-trigger:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.profile-avatar {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--primary-container);
    color: var(--on-primary-container);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: 13px;
}

.profile-meta {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.user-name {
    font-size: 14px;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.user-role {
    font-size: 12px;
    color: var(--on-surface-variant);
}

.profile-arrow {
    color: var(--on-surface-variant);
    transition: transform 150ms ease;
}

.profile-trigger[aria-expanded='true'] .profile-arrow {
    transform: rotate(180deg);
}

.profile-dropdown {
    position: absolute;
    left: 0;
    right: 0;
    bottom: calc(100% + 8px);
    background: var(--surface-container-high);
    border: 1px solid var(--outline-variant);
    border-radius: 14px;
    box-shadow: var(--shadow-2);
    padding: 6px;
    display: grid;
    gap: 4px;
    z-index: var(--z-dropdown);
}

/* Пункты меню профиля — и <button>, и <a>. Ссылке обязательно снимать
   подчёркивание и выравнивать шрифт: браузер не наследует их от кнопки, и
   «Уведомления» выбивался из списка подчёркнутой строкой другого кегля. */
.profile-action {
    width: 100%;
    border: none;
    border-radius: 10px;
    background: transparent;
    color: var(--on-surface);
    padding: 8px 10px;
    font-family: inherit;
    font-size: 14px;
    line-height: 20px;
    text-align: left;
    text-decoration: none;
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
}

.profile-action:hover,
.profile-action:focus-visible {
    text-decoration: none;
}

.profile-action:hover {
    background: var(--surface-container-highest);
}

.profile-action-danger {
    color: var(--error);
}

/* Колонка «Канал» в настройках уведомлений. Заголовок короткий, поэтому
   таблица сжимала ячейку по нему, а селект с width: 100% обрезал подписи:
   «Выключено» превращалось в «Выключ». Ширину задаём самому полю, а ячейке
   запрещаем переносить строку. */
.notification-channel-cell {
    width: 1%;
    white-space: nowrap;
}

.notification-channel-cell .form-control {
    width: auto;
    min-width: 180px;
}

/* «Уходит на адрес» вместо списка — обычный текст: без переноса строка с
   адресом уезжала за край ячейки, а в плитке на телефоне — за левый край
   экрана. */
.notification-channel-cell .helper-text {
    min-width: 200px;
    max-width: 320px;
    white-space: normal;
    overflow-wrap: anywhere;
}

.sidebar-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(8, 15, 30, 0.45);
    z-index: var(--z-overlay);
}

.main-content {
    flex: 1;
    min-width: 0;
    margin-left: var(--sidebar-width);
    min-height: 100vh;
    /* dvh учитывает адресную строку мобильного браузера: с одним vh внизу
       оставалась полоса лишней прокрутки на всю её высоту. */
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    transition: margin-left 220ms ease;
}

body.sidebar-collapsed .sidebar {
    width: var(--rail-width);
}

body.sidebar-collapsed .main-content {
    margin-left: var(--rail-width);
}

body.sidebar-collapsed .sidebar-resizer {
    display: none;
}

body.sidebar-collapsed .logo-full {
    display: none;
}

body.sidebar-collapsed .logo-short {
    display: inline;
}

body.sidebar-collapsed .nav-section {
    margin: 10px 8px;
    padding: 0;
    height: 1px;
    background: var(--outline-variant);
    color: transparent;
    overflow: hidden;
}

body.sidebar-collapsed .nav-item {
    justify-content: center;
    padding: 10px;
}

body.sidebar-collapsed .nav-item .nav-text,
body.sidebar-collapsed .profile-meta,
body.sidebar-collapsed .profile-arrow {
    display: none;
}

body.sidebar-collapsed .nav-group,
body.sidebar-collapsed .nav-arrow {
    display: none;
}

body.sidebar-collapsed .nav-divider {
    margin: 10px 8px;
}

/* В свёрнутом меню число не помещается, но сам факт «есть инциденты» терять
   нельзя — счётчик превращается в точку на иконке. */
body.sidebar-collapsed .nav-item {
    position: relative;
}

body.sidebar-collapsed .nav-badge {
    position: absolute;
    top: 4px;
    right: 8px;
    min-width: 8px;
    height: 8px;
    padding: 0;
    font-size: 0;
    line-height: 0;
    background: var(--error);
}

body.sidebar-collapsed .profile-trigger {
    justify-content: center;
}

body.sidebar-collapsed .profile-dropdown {
    left: 0;
    right: auto;
    width: 220px;
}

.top-bar {
    background: var(--surface-container-low);
    border-bottom: 1px solid var(--outline-variant);
    /* Высота по содержимому, но не ниже обычной. Жёсткая высота выталкивала
       кнопки за правый край экрана: на «Товарах» их пять, и при развёрнутой
       боковой панели на 1024px они требовали 840px при доступных 752 —
       страница получала горизонтальную прокрутку. Теперь ряд кнопок
       переносится, а на широком экране всё остаётся в одну строку. */
    min-height: var(--topbar-height);
    padding: 8px 20px;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    position: sticky;
    top: 0;
    z-index: var(--z-topbar);
}

.menu-toggle {
    width: 40px;
    height: 40px;
    border: 1px solid var(--outline);
    border-radius: 999px;
    background: transparent;
    color: var(--on-surface-variant);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.menu-toggle:hover {
    background: var(--surface-container);
}

.page-title {
    font-size: 24px;
    line-height: 32px;
    font-weight: 600;
    letter-spacing: -0.1px;
    flex: 1;
}

.top-bar-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    justify-content: flex-end;
    /* Прижать вправо и когда ряд кнопок перенесён на свою строку: заголовок
       с flex: 1 занимает первую строку целиком, и на второй без этого кнопки
       ушли бы к левому краю. */
    margin-left: auto;
    gap: 8px;
}

.icon-button {
    width: 40px;
    height: 40px;
    border-radius: 999px;
    border: 1px solid var(--outline);
    background: transparent;
    color: var(--on-surface-variant);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.icon-button:hover {
    background: var(--surface-container);
}

/* «⋮» — только на телефоне (блок max-width: 768px). */
.top-bar-more {
    display: none;
}

.content-wrapper {
    padding: 20px;
    flex: 1;
    min-width: 0;
}

.messages {
    margin-bottom: 16px;
}

.message {
    padding: 10px 12px;
    border-radius: 10px;
    margin-bottom: 8px;
    border: 1px solid transparent;
    font-size: 14px;
}

.message-success {
    background: color-mix(in oklab, var(--success) 14%, var(--surface));
    border-color: color-mix(in oklab, var(--success) 40%, var(--surface));
}

.message-error {
    background: var(--error-container);
    color: var(--on-error-container);
    border-color: color-mix(in oklab, var(--error) 45%, var(--surface));
}

.message-warning {
    background: color-mix(in oklab, var(--warning) 18%, var(--surface));
    border-color: color-mix(in oklab, var(--warning) 40%, var(--surface));
}

/* ── 4. Компоненты ───────────────────────────────────────────────────────── */

.card {
    background: var(--surface-container-low);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-1);
    padding: 16px;
    margin-bottom: 16px;
}

.card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}

.card-title {
    font-size: 16px;
    font-weight: 600;
}

button:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 40px;
    padding: 0 16px;
    border-radius: 999px;
    border: 1px solid transparent;
    font-size: 14px;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 150ms ease, border-color 150ms ease, color 150ms ease;
    white-space: nowrap;
}

/* Кнопка, за которой идёт обращение к внешней службе: пока запрос в пути,
   она погашена и крутит колечко. Без этого страница выглядела неподвижной, и
   ту же операцию запускали повторно. */
.btn:disabled,
.btn.is-busy {
    opacity: 0.6;
    cursor: default;
    pointer-events: none;
}

.btn.is-busy::after {
    content: '';
    width: 14px;
    height: 14px;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: btn-spin 700ms linear infinite;
}

@keyframes btn-spin {
    to { transform: rotate(360deg); }
}

.btn-primary {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--on-primary);
}

.btn-primary:hover {
    filter: brightness(0.95);
}

.btn-outline {
    background: transparent;
    color: var(--primary);
    border-color: var(--outline);
}

.btn-outline:hover {
    background: var(--surface-container);
}

.btn-outline.is-active {
    background: var(--primary-container);
    border-color: var(--primary);
    color: var(--primary);
}

.btn-tonal {
    background: var(--secondary-container);
    color: var(--on-secondary-container);
    border-color: transparent;
}

.btn-tonal:hover {
    filter: brightness(0.97);
}

.btn-text {
    background: transparent;
    color: var(--primary);
    border-color: transparent;
}

.btn-text:hover {
    background: var(--surface-container);
}

.btn-danger {
    background: var(--error);
    color: var(--on-error);
    border-color: var(--error);
}

.btn-danger:hover {
    filter: brightness(0.95);
}

.btn-danger-outline {
    background: transparent;
    color: var(--error);
    border-color: color-mix(in oklab, var(--error) 45%, var(--outline));
}

.btn-danger-outline:hover {
    background: var(--error-container);
}

.btn-sm {
    min-height: 34px;
    padding: 0 12px;
    font-size: 13px;
}

.btn-icon-square {
    width: 36px;
    min-width: 36px;
    height: 36px;
    padding: 0;
    border-radius: 10px;
}

.form-group {
    margin-bottom: 16px;
}

.form-label {
    display: block;
    margin-bottom: 6px;
    font-size: 12px;
    font-weight: 600;
    color: var(--on-surface-variant);
}

.form-control,
.filter-group input,
.filter-group select {
    width: 100%;
    height: 40px;
    padding: 0 12px;
    border: 1px solid var(--outline);
    border-radius: 10px;
    background: var(--surface-container-low);
    color: var(--on-surface);
    font-size: 14px;
}

textarea.form-control {
    height: auto;
    min-height: 84px;
    padding: 10px 12px;
}

.form-control:focus,
.filter-group input:focus,
.filter-group select:focus {
    outline: 2px solid color-mix(in oklab, var(--primary) 65%, transparent);
    outline-offset: 1px;
    border-color: var(--primary);
}

.form-control-color {
    padding: 2px;
    height: 40px;
}

.form-control[readonly],
.form-control:disabled {
    background: var(--surface-container);
    color: var(--on-surface-variant);
    cursor: default;
}

.form-error {
    margin-top: 4px;
    color: var(--error);
    font-size: 12px;
}

.required-mark {
    color: var(--error);
    margin-left: 2px;
}

/* ── 5. Списки ───────────────────────────────────────────────────────────── */

.shipments-toolbar {
    display: grid;
    gap: 12px;
}

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

   Только на компьютере. На телефоне закреплённая панель съедала бы четверть
   экрана (см. .top-bar в блоке max-width: 768px), да и не заработала бы:
   .main-content там контейнер прокрутки.

   top равен высоте верхней панели — стыкуются без щели. z-index 20 выше
   закреплённых колонок таблицы (2-4) и ниже .top-bar (50). Панель «Столбцы»
   (z-index 60) попадает внутрь нового контекста наложения и ограничивается
   уровнем 20 — ей хватает: она раскрывается вниз, поверх таблицы. */
@media (min-width: 769px) {
    .shipments-toolbar {
        position: sticky;
        /* Не var(--topbar-height): шапка переносит кнопки и бывает выше одной
           строки. Фактическую высоту публикует base.html; значение по
           умолчанию — на случай, если скрипт не отработал. */
        top: var(--topbar-current, var(--topbar-height));
        z-index: var(--z-toolbar);
    }
}

.toolbar-main {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.search-field {
    flex: 1;
    min-width: 260px;
    position: relative;
}

.search-field .material-symbols-rounded {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--on-surface-variant);
    pointer-events: none;
}

.search-field input {
    width: 100%;
    height: 40px;
    border: 1px solid var(--outline);
    border-radius: 999px;
    padding: 0 14px 0 40px;
    background: var(--surface-container-low);
    color: var(--on-surface);
    /* На телефоне «Поиск по наименованию оплаты» не помещается и обрезался
       посреди слова; многоточие честно показывает, что текст длиннее. */
    text-overflow: ellipsis;
}

.search-field input:focus {
    outline: 2px solid color-mix(in oklab, var(--primary) 65%, transparent);
    outline-offset: 1px;
    border-color: var(--primary);
}

.filters-toggle {
    position: relative;
}

.filter-active-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--primary);
}

.filters-panel {
    display: none;
    border-top: 1px solid var(--outline-variant);
    padding-top: 12px;
}

.filters-panel.is-open {
    display: block;
}

.filters-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(150px, 1fr));
    gap: 10px;
}

/* Фильтры страниц рекламы (отчёт по точкам, журнал, кампании). Своей
   раскладки у формы не было, и шесть полей стояли столбиком и на широком
   экране — фильтр занимал больше экрана, чем сам отчёт. Колонок столько,
   сколько помещается; на телефоне остаётся одна. Карточка — во всю ширину,
   как таблица под ней: в прежние 760px поля всё равно переносились по одному.
   Длина строки вводного текста ограничена — на всю ширину его не прочесть. */
.filters-card p.helper-text {
    max-width: 90ch;
}

.filters-form {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    /* Промежутки — сеткой, а не отступами полей: отступ последнего ряда
       добавлялся к отступу карточки, и под кнопками пустоты было вдвое
       больше, чем над полями. */
    gap: 16px;
    align-items: end;
}

.filters-form > .form-group {
    margin-bottom: 0;
}

.filters-form > .form-actions {
    grid-column: 1 / -1;
    justify-content: flex-end;
    margin: 0;
}

.filters-form > .form-actions .btn:first-child {
    margin-right: 0;
}

/* На широком экране кнопки занимают две последние колонки: если полей меньше,
   чем колонок, они встают в тот же ряд, а не отдельной строкой под пустотой. */
@media (min-width: 769px) {
    .filters-form > .form-actions {
        grid-column: -3 / -1;
    }
}

.filter-group {
    display: grid;
    gap: 4px;
}

.filter-group label {
    font-size: 12px;
    font-weight: 600;
    color: var(--on-surface-variant);
}

.active-filters {
    display: flex;
    align-items: center;
    margin-top: 10px;
    flex-wrap: wrap;
    gap: 6px;
}

.filter-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 28px;
    padding: 0 10px;
    border-radius: 999px;
    background: var(--surface-container);
    color: var(--on-surface-variant);
    font-size: 12px;
    border: 1px solid var(--outline-variant);
}

/* Чип снимает свой фильтр: это ссылка на тот же список без него. */
a.filter-chip-removable {
    text-decoration: none;
    padding-right: 6px;
}

a.filter-chip-removable .material-symbols-rounded {
    font-size: 16px;
}

a.filter-chip-removable:hover,
a.filter-chip-removable:focus-visible {
    border-color: var(--primary);
    color: var(--on-surface);
}

.active-filters .filters-reset {
    min-height: 28px;
}

/* Вкладки внутри модуля (реклама): горизонтальный ряд, на телефоне
   прокручивается вбок, а не переносится в несколько строк. */
.module-tabs {
    display: flex;
    gap: 2px;
    margin-bottom: 16px;
    border-bottom: 1px solid var(--outline-variant);
    overflow-x: auto;
    scrollbar-width: none;
}

.module-tabs::-webkit-scrollbar {
    display: none;
}

.module-tab {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 10px 14px;
    margin-bottom: -1px;
    border-bottom: 2px solid transparent;
    color: var(--on-surface-variant);
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
    text-decoration: none;
}

.module-tab:hover {
    color: var(--on-surface);
}

.module-tab.is-active {
    color: var(--primary);
    border-bottom-color: var(--primary);
}

/* Свой класс, а не .nav-badge: у того в свёрнутом меню абсолютное
   положение, и во вкладке счётчик улетал бы в угол. */
.tab-badge {
    min-width: 20px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--error-container);
    color: var(--on-error-container);
    font-size: 12px;
    font-weight: 700;
    line-height: 20px;
    text-align: center;
}

.shipment-table-card {
    padding: 0;
    /* clip, а не hidden: скругление обрезается так же, но карточка не
       становится контейнером прокрутки. С hidden липкая полоса прокрутки
       таблицы (.table-hscroll) прилипала бы к карточке, а не к окну. */
    overflow: clip;
}

.shipment-table-card .table-container {
    border: 0;
    border-radius: inherit;
}

.table-container {
    overflow: auto;
    overscroll-behavior-inline: contain;
    border-radius: 14px;
    border: 1px solid var(--outline-variant);
    /* Ограничения высоты здесь сознательно нет. Раньше стояло
       max-height: calc(100dvh - 260px) — оно требовалось липкой шапке
       таблицы: без прокручиваемого контейнера прилипать не к чему. Шапки
       больше не закрепляются (требование заказчика), и ограничение осталось
       бы чистым вредом: страница получала вторую полосу прокрутки, и список
       листался внутри короткого окошка, а 260px были подобраны на глаз и не
       следили за реальной высотой панелей. */
}

/* ── 6. Таблицы ──────────────────────────────────────────────────────────── */

/* ── Прокрутка широкой таблицы (static/js/table-scroll.js) ──────────────────
 *
 * Родная полоса прокрутки контейнера стоит под последней строкой — на длинном
 * списке за экраном. Скрипт ставит свою, прилипающую к низу окна, и родную
 * тогда прячем (только тогда: без скрипта остаётся она).
 */
.table-container.has-hscroll {
    scrollbar-width: none;
}

.table-container.has-hscroll::-webkit-scrollbar {
    display: none;
}

.table-hscroll {
    position: sticky;
    bottom: 0;
    z-index: var(--z-raised);
    overflow-x: auto;
    overflow-y: hidden;
    background: var(--surface-container-low);
    border-top: 1px solid var(--outline-variant);
    /* Полоса нарисована явно: системная «всплывающая» полоса (macOS, Android)
       видна только во время прокрутки, и у липкой полосы не было бы вида. */
    scrollbar-width: thin;
    scrollbar-color: var(--outline) transparent;
}

.table-hscroll > div {
    height: 1px;
}

.table-hscroll::-webkit-scrollbar {
    height: 10px;
}

.table-hscroll::-webkit-scrollbar-thumb {
    border-radius: 999px;
    background: var(--outline);
}

/* Под закреплёнными столбцами есть скрытые — тень у их края. Без неё текст
   просто обрывался под столбцом «Действия», как будто таблица кончилась. */
.table-container.has-overflow-right .shipments-table [data-col="actions"] {
    box-shadow: -10px 0 10px -8px rgb(15 23 42 / 0.18);
}

.table-container.has-overflow-left .shipments-table [data-col="number"],
.table-container.has-overflow-left .expenses-table [data-col="name"] {
    box-shadow: 10px 0 10px -8px rgb(15 23 42 / 0.18);
}

/* Кнопки «Действия» в конце строки (справочники, пользователи, реклама) на
   компьютере закреплены справа, как в Поставках: таблица, которой не хватило
   ширины — хоть на слитное название вроде «Складные стеллажи_АВТО_ПиР…», —
   иначе уводила их за край. Тень — тот же знак скрытых столбцов. На телефоне
   таблица — плитки, закреплять там нечего. */
@media (min-width: 769px) {
    .data-table:has(td.actions-cell:last-child) tr > :last-child {
        position: sticky;
        right: 0;
        z-index: var(--z-sticky-cell);
    }

    .table-container.has-overflow-right .data-table:has(td.actions-cell:last-child) tr > :last-child {
        box-shadow: -10px 0 10px -8px rgb(15 23 42 / 0.18);
    }
}

/* Таблица без закреплённых столбцов и без кнопок в конце (отчёт по точкам,
   журналы) гаснет к краю, за которым есть ещё столбцы. Там, где у края кнопки,
   гасить нельзя — они выглядели бы неактивными. */
.table-container:not(:has(.shipments-table, td.actions-cell:last-child)) {
    --fade-left: 0px;
    --fade-right: 0px;
}

.table-container.has-overflow-left:not(:has(.shipments-table, td.actions-cell:last-child)) {
    --fade-left: 40px;
}

.table-container.has-overflow-right:not(:has(.shipments-table, td.actions-cell:last-child)) {
    --fade-right: 40px;
}

.table-container.has-overflow-left:not(:has(.shipments-table, td.actions-cell:last-child)),
.table-container.has-overflow-right:not(:has(.shipments-table, td.actions-cell:last-child)) {
    mask-image: linear-gradient(
        to right,
        transparent,
        #000 var(--fade-left),
        #000 calc(100% - var(--fade-right)),
        transparent
    );
}

/* «Решение» в отчёте по точкам — решение и пояснение к нему. Таблица шире
   экрана, и автоматическая раскладка ужимала этот столбец до ~110px: текст
   шёл в шесть строк и растягивал каждую строку отчёта. Именно min-width:
   width у ячейки таблица, которой не хватает места, игнорирует. */
.data-table th.decision-col {
    min-width: 240px;
}

/* Комментарий в таблице — не больше трёх строк. Длинный растягивал строку до
   полутора сотен пикселей, причём часто из столбца, уехавшего за край, — и
   на экране оставались высокие пустые строки. Полностью он виден в подсказке
   при наведении и в карточке записи. На телефоне плитки его не показывают. */
@media (min-width: 769px) {
    .data-table td[data-col="comment"] .line-item {
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 3;
        line-clamp: 3;
        overflow: hidden;
    }
}

/* Печать и печатные формы: ограничение высоты там вредно — страница должна
   разворачиваться целиком, а не прокручиваться внутри себя. */
@media print {
    .table-container {
        max-height: none;
        overflow: visible;
        mask-image: none;
    }

    .table-hscroll {
        display: none;
    }
}

.data-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 14px;
}

.shipments-table {
    table-layout: fixed;
}

/* Таблица фиксированной раскладки не растёт под содержимое: ширины столбцов
   задают <col> и перетаскивание (или равная доля — у «Ролей и доступа»).
   Слово длиннее столбца — склад «МСК_ЧЕРМЯНСКАЯ_ОБС», контрагент
   «Металлоконструкции», заголовок «Администратор» на 1024px — при
   overflow: visible ложилось поверх соседней ячейки. Такое слово переносится
   внутри — и только когда целиком не помещается в столбец; остальной текст
   переносится по словам, как прежде. Новую таблицу с table-layout: fixed
   добавляйте сюда. */
.shipments-table th,
.shipments-table td,
.permissions-table th,
.permissions-table td,
.staff-log-table td {
    overflow-wrap: anywhere;
}

.data-table th,
.data-table td {
    border-bottom: 1px solid var(--outline-variant);
    padding: 10px 12px;
    text-align: left;
    vertical-align: top;
    background: var(--surface-container-low);
}

.data-table th {
    /* relative, а не sticky: шапки таблиц не закрепляются. Позиционирование
       всё же нужно — .col-resizer внутри ячейки абсолютный, и ему требуется
       позиционированный предок. */
    position: relative;
    background: var(--surface-container);
    color: var(--on-surface-variant);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.2px;
    text-transform: none;
    vertical-align: middle;
}

.shipments-table th {
    text-align: center;
}

.shipments-table tbody tr:nth-child(even) td {
    background: color-mix(in oklab, var(--surface-container-low) 84%, var(--surface-container) 16%);
}

.shipments-table tbody tr:hover td {
    background: var(--surface-container-high);
}

.shipments-table tbody tr[data-shipment-id] {
    cursor: pointer;
}

/* Только кнопки: ручке перетаскивания нужен её собственный курсор «взять»
   (.drag-grip). Раньше она стояла в этом же правиле, оно перебивало «взять»
   специфичностью, и над ручкой была стрелка — ручку не узнавали. */
.shipments-table .table-actions {
    cursor: default;
}

.shipments-table tbody tr:focus-visible td {
    background: var(--primary-container);
    outline: 2px solid var(--primary);
    outline-offset: -2px;
}

.shipments-table tbody tr:last-child td {
    border-bottom: none;
}

.shipments-table th[data-col="number"],
.shipments-table td[data-col="number"] {
    position: sticky;
    left: 0;
    z-index: var(--z-sticky-cell);
}

.shipments-table th[data-col="actions"],
.shipments-table td[data-col="actions"] {
    position: sticky;
    right: 0;
    z-index: var(--z-sticky-cell);
}

.shipments-table th[data-col="number"],
.shipments-table th[data-col="actions"] {
    z-index: var(--z-sticky-head);
}

/* Строка, которая открывает запись щелчком (static/js/app.js). */
.data-table tbody tr[data-row-url] {
    cursor: pointer;
}

/* Таблица плана расходов переиспользует всё оформление .shipments-table
   (зебра, hover, sticky-колонки и т.д.), но её первая закреплённая колонка
   называется "name", а не "number" — только эти 2 правила специфичны. */
.expenses-table th[data-col="name"],
.expenses-table td[data-col="name"] {
    position: sticky;
    left: 44px;
    z-index: var(--z-sticky-cell);
}

.expenses-table th[data-col="name"] {
    z-index: var(--z-sticky-head);
}

.expenses-table th.select-col,
.expenses-table td.select-col {
    position: sticky;
    left: 0;
    z-index: var(--z-sticky-cell);
    width: 44px;
    text-align: center;
}

.expenses-table th.select-col {
    z-index: var(--z-sticky-head);
}

/* Сотрудники штатного календаря и карточки товарного контента: то же
   оформление .shipments-table, первым закреплён столбец «name» (ФИО,
   название товара). */
.employees-table th[data-col="name"],
.employees-table td[data-col="name"],
.content-cards-table th[data-col="name"],
.content-cards-table td[data-col="name"] {
    position: sticky;
    left: 0;
    z-index: var(--z-sticky-cell);
}

.employees-table th[data-col="name"],
.content-cards-table th[data-col="name"] {
    z-index: var(--z-sticky-head);
}

.table-container.has-overflow-left .employees-table [data-col="name"],
.table-container.has-overflow-left .content-cards-table [data-col="name"] {
    box-shadow: 10px 0 10px -8px rgb(15 23 42 / 0.18);
}

/* Заголовок, по которому сортируется список: клик — по возрастанию,
   повторный — по убыванию; стрелка показывает текущий порядок. */
.sort-link {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: inherit;
    text-decoration: none;
}

.sort-link:hover {
    color: var(--on-surface);
    text-decoration: underline;
}

.sort-arrow {
    color: var(--primary);
    font-weight: 700;
}

/* Панель действий над отмеченными строками стоит под таблицей и
   прилипает к низу окна, пока таблица на экране: отмеченные строки бывают
   далеко внизу, и панель над таблицей оказывалась за краем экрана. На
   телефоне липкость внутри .main-content не работает (см. блок max-width:
   768px), поэтому там панель закреплена у низа окна, а кнопка «+» на это
   время прячется. */
.bulk-actions-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    padding: 10px 16px;
    background: var(--primary-container);
    border-top: 1px solid var(--outline-variant);
    position: sticky;
    bottom: 0;
    z-index: var(--z-bulk-bar);
}

@media (max-width: 768px) {
    .bulk-actions-bar {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: var(--z-bulk-bar-phone);
        box-shadow: 0 -4px 12px rgb(0 0 0 / 0.12);
    }

    body.has-bulk-selection .fab-new-shipment {
        display: none;
    }

    body.has-bulk-selection .main-content {
        padding-bottom: 160px;
    }
}

.bulk-actions-info {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    font-size: 13px;
    font-weight: 600;
    color: var(--on-primary-container);
}

.bulk-actions-controls {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}

.bulk-action-select,
.bulk-action-input {
    height: 36px;
    padding: 0 10px;
    border: 1px solid var(--outline);
    border-radius: 10px;
    background: var(--surface-container-low);
    color: var(--on-surface);
    font-size: 13px;
}

.bulk-action-input {
    width: 240px;
    max-width: 100%;
}

.col-resizer {
    position: absolute;
    top: 0;
    right: -3px;
    bottom: 0;
    width: 6px;
    cursor: col-resize;
    z-index: var(--z-raised);
    touch-action: none;
}

.col-resizer::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 2px;
    width: 2px;
    background: transparent;
    transition: background-color 150ms ease;
}

.col-resizer:hover::after,
.col-resizer:focus-visible::after {
    background: var(--primary);
}

.col-resizer:focus-visible,
.sidebar-resizer:focus-visible {
    outline: none;
}

.col-hidden {
    display: none;
}

.columns-menu {
    position: relative;
}

.columns-panel {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    min-width: 220px;
    max-height: 320px;
    overflow-y: auto;
    background: var(--surface-container-high);
    border: 1px solid var(--outline-variant);
    border-radius: 14px;
    box-shadow: var(--shadow-2);
    padding: 6px;
    display: grid;
    gap: 2px;
    z-index: var(--z-popover);
}

.column-toggle-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    border-radius: 10px;
    font-size: 14px;
    color: var(--on-surface);
    cursor: pointer;
}

.column-toggle-item:hover {
    background: var(--surface-container-highest);
}

.column-toggle-item input {
    accent-color: var(--primary);
    width: 16px;
    height: 16px;
}

.column-toggle-item label {
    flex: 1;
    cursor: pointer;
}

.column-drag-grip,
.column-drag-spacer {
    flex: 0 0 18px;
    width: 18px;
    min-height: 20px;
    font-size: 18px;
}

.column-drag-grip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--on-surface-variant);
    cursor: grab;
    user-select: none;
    touch-action: none;
}

.column-drag-grip:active {
    cursor: grabbing;
}

.column-toggle-item.is-dragging {
    opacity: 0.6;
    background: var(--primary-container);
}

.line-item {
    padding: 1px 0;
    line-height: 1.35;
}

.line-empty {
    color: var(--on-surface-variant);
}

.cell-number .line-item {
    text-align: right;
    font-feature-settings: 'tnum';
    font-variant-numeric: tabular-nums;
}

/* Универсальные утилиты выравнивания значений по типу данных — числовые
   вправо, текстовые влево (по умолчанию у .data-table td) — применяются
   во всех таблицах, включая справочники и печатную форму. */
.data-table th.text-center,
.data-table td.text-center {
    text-align: center;
}

.data-table td.cell-number {
    text-align: right;
    font-feature-settings: 'tnum';
    font-variant-numeric: tabular-nums;
}

/* Телефон +7(999)999-99-99 не переносится: по дефису он разрывался на
   «+7(800)100-» и «80-00» на разных строках и читался как два номера. */
.data-table td.cell-phone {
    white-space: nowrap;
}

/* Центрирование заголовков столбцов там, где это явно требуется —
   таблица поставок (.shipments-table) уже центрирует их отдельным
   правилом ниже, здесь — переиспользуемый модификатор для других таблиц. */
.table-head-center th {
    text-align: center;
}

.date-main {
    display: block;
    font-weight: 500;
}

.date-sub {
    display: block;
    font-size: 12px;
    color: var(--on-surface-variant);
}

.status-cell,
.actions-cell {
    text-align: center;
}

.status-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border-radius: 999px;
    padding: 4px 10px;
    background: var(--surface-container);
    font-size: 12px;
    font-weight: 600;
    /* В карточной вёрстке ячейка становится flex-контейнером, и бейдж в ней —
       flex-элемент рядом с подписью поля. Без запрета на сжатие его обрезало
       правым краем карточки. max-width оставляет ему возможность перенестись
       на свою строку, а не вылезти за карточку. */
    flex-shrink: 0;
    max-width: 100%;
}

.status-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    /* Кружок фиксированного размера: при сжатии он расплющивался в эллипс. */
    flex-shrink: 0;
    background: var(--tone-neutral);
}

.status-dot--success { background: var(--tone-success); }
.status-dot--info { background: var(--tone-info); }
.status-dot--warning { background: var(--tone-warning); }
.status-dot--danger { background: var(--tone-danger); }
.status-dot--neutral { background: var(--tone-neutral); }
.status-dot--accent { background: var(--tone-accent); }

.product-photo-thumb {
    display: block;
    width: 40px;
    height: 40px;
    border-radius: 8px;
    object-fit: cover;
    background: var(--surface-container);
}

.product-photo-preview {
    display: block;
    max-width: 160px;
    max-height: 160px;
    border-radius: 12px;
    object-fit: contain;
    background: var(--surface-container);
}

.readonly-field-value {
    padding: 10px 12px;
    border-radius: 12px;
    background: var(--surface-container);
    color: var(--on-surface-variant);
}

.shipment-number-cell {
    min-width: 150px;
}

.shipment-number {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    min-width: 0;
}

.shipment-number > span:last-child {
    min-width: 0;
}

.drag-grip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 18px;
    width: 18px;
    min-height: 20px;
    color: var(--on-surface-variant);
    cursor: grab;
    user-select: none;
    touch-action: none;
    font-size: 18px;
}

.drag-grip:active {
    cursor: grabbing;
}

.draggable-row.is-dragging td {
    opacity: 0.7;
    background: var(--primary-container);
}

.table-actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    opacity: 0.9;
}

.fab-new-shipment {
    display: none;
    position: fixed;
    right: 20px;
    bottom: 20px;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--primary);
    color: var(--on-primary);
    align-items: center;
    justify-content: center;
    box-shadow: var(--shadow-2);
    z-index: var(--z-fab);
    text-decoration: none;
}

.fab-new-shipment:hover {
    filter: brightness(0.95);
}

.fab-new-shipment .material-symbols-rounded {
    font-size: 26px;
}

.inline-delete-form {
    display: inline-flex;
    margin: 0;
}

/* Форма в шапке — обёртка для отправки, а не блок раскладки. Две кнопки в
   одной форме («Собрать статистику» и «Проверить сейчас») иначе переносились
   только вместе, и на телефоне неделимая пара уезжала за левый край экрана. */
.top-bar-actions form {
    display: contents;
}

.action-button .material-symbols-rounded {
    font-size: 18px;
}

.empty-state {
    text-align: center;
    color: var(--on-surface-variant);
    padding: 44px 20px;
}

.empty-state-icon {
    font-size: 28px;
    margin-bottom: 8px;
}

.empty-state-title {
    color: var(--on-surface);
    font-size: 18px;
    font-weight: 600;
    margin-bottom: 6px;
}

.pagination {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-top: 14px;
}

.pagination a,
.pagination span {
    min-height: 34px;
    padding: 0 12px;
    border-radius: 999px;
    border: 1px solid var(--outline);
    background: var(--surface-container-low);
    color: var(--on-surface);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
}

.pagination .current {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--on-primary);
}

.auth-layout {
    min-height: 100vh;
    /* dvh учитывает адресную строку мобильного браузера: с одним vh внизу
       оставалась полоса лишней прокрутки на всю её высоту. */
    min-height: 100dvh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}

.auth-subtitle {
    text-align: center;
    margin-bottom: 24px;
}

/* «Забыли пароль?» и «Вернуться ко входу» под кнопкой: без отступа ссылка
   прилипала к ней вплотную. */
.auth-card form + .auth-subtitle {
    margin: 16px 0 0;
}

.auth-error {
    margin-bottom: 16px;
}

.auth-submit {
    width: 100%;
}

.auth-card {
    width: 100%;
    max-width: 400px;
    padding: 28px;
    border-radius: 24px;
    border: 1px solid var(--outline-variant);
    background: var(--surface-container-low);
    box-shadow: var(--shadow-2);
}

.auth-logo {
    text-align: center;
    font-size: 38px;
    margin-bottom: 8px;
}

.auth-title {
    text-align: center;
    font-size: 22px;
    font-weight: 600;
    margin-bottom: 18px;
}

.formset-header {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr 1fr 1fr 96px;
    gap: 10px;
    padding: 0 12px 6px;
    color: var(--on-surface-variant);
    font-size: 12px;
    font-weight: 600;
}

.formset-row {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr 1fr 1fr 96px;
    gap: 10px;
    align-items: end;
    padding: 12px;
    border-radius: 12px;
    border: 1px solid var(--outline-variant);
    background: var(--surface-container-low);
    margin-bottom: 10px;
}

/* Убранная несохранённая строка: отмечена DELETE и спрятана. */
.formset-row label {
    display: none;
}

.delete-row {
    display: flex;
    align-items: center;
    padding-bottom: 6px;
}

.formset-row .delete-row label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--on-surface-variant);
    cursor: pointer;
}

.formset-row .delete-row input {
    accent-color: var(--error);
}

/* ── 7. Узкие экраны ─────────────────────────────────────────────────────── */

@media (max-width: 1200px) {
    .filters-grid {
        grid-template-columns: repeat(2, minmax(150px, 1fr));
    }

    .page-title {
        font-size: 22px;
    }
}

@media (max-width: 1023px) {
    .sidebar {
        /* На пиксель дальше края: ширина 88vw дробная (316,8px на 360px), и
           сглаживание выводило на экран полоску правой рамки спрятанной
           панели — тонкую серую линию вдоль левого края. */
        transform: translateX(calc(-100% - 1px));
        width: min(88vw, 320px);
    }

    .sidebar.open {
        transform: translateX(0);
    }

    .sidebar-close {
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

    .sidebar-overlay.open {
        display: block;
    }

    .sidebar-resizer {
        display: none;
    }

    .main-content,
    body.sidebar-collapsed .main-content {
        margin-left: 0;
    }

    .top-bar {
        /* Вертикальный отступ нужен, когда кнопки переносятся на свои строки:
           без него нижняя ложилась прямо на границу шапки, а верхняя — на
           край экрана. В одну строку высота прежняя: 8 + 40 + 8 = 56px. */
        padding: 8px 14px;
    }

    .page-title {
        font-size: 18px;
        line-height: 24px;
    }

    .content-wrapper {
        padding: 16px;
    }

    .toolbar-main {
        align-items: stretch;
    }

    .search-field {
        min-width: 100%;
    }

    .filters-grid {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 768px) {
    /* Страховка от горизонтального переполнения страницы (из-за которого
       position: fixed кнопка "+" могла уезжать за пределы экрана): даже
       если что-то на странице всё же окажется шире экрана, скролл/зум
       затронет только его, а не всю страницу целиком.

       ВАЖНО, И ПРЕЖНИЙ КОММЕНТАРИЙ ЗДЕСЬ ВРАЛ. overflow-x: hidden не бывает
       односторонним: по спецификации overflow-y при этом вычисляется в auto,
       и обе обёртки становятся контейнерами прокрутки. Прокручиваться внутри
       себя им нечем (высота растёт по содержимому), поэтому любой
       position: sticky внутри них под 768px не работает вовсе — молча, без
       единого признака в инспекторе. Именно так и было с .top-bar: она
       числилась липкой и уезжала вместе со страницей.

       Это допустимо ровно потому, что на телефоне мы сознательно ничего не
       закрепляем (см. .top-bar ниже). Если когда-нибудь понадобится липкий
       элемент внутри .main-content на узком экране — сначала убрать отсюда
       overflow-x, иначе время уйдёт на поиск несуществующей ошибки. */
    .app-layout,
    .main-content {
        overflow-x: hidden;
    }

    /* Safari на iPhone и iPad автоматически увеличивает страницу, когда фокус
       попадает в поле со шрифтом мельче 16px, и обратно сам не отматывает.
       То есть каждое касание любого поля формы или фильтра «зумило» страницу,
       и её приходилось отщипывать пальцами назад — на каждом экране ввода.

       Поле поиска от этого было избавлено случайно: у него размер шрифта не
       задан, и оно наследовало 16px от body. Теперь так у всех полей.

       Визуально разница почти незаметна, раздражитель уходит целиком. */
    .form-control,
    .filter-group input,
    .filter-group select,
    .filter-group textarea,
    input[type='text'],
    input[type='number'],
    input[type='date'],
    input[type='datetime-local'],
    input[type='password'],
    input[type='email'],
    input[type='search'],
    select,
    textarea {
        font-size: 16px;
    }

    .top-bar {
        min-height: 56px;
        /* На телефоне шапка не закрепляется. Закреплённая, она заняла бы
           около 95px: .top-bar-actions ниже получает width: 100% и всегда
           уходит на вторую строку, даже с одной кнопкой темы. Это четверть
           экрана там, где нужен список. Основное действие никуда не девается —
           оно на плавающей кнопке "+" (.fab-new-shipment, position: fixed). */
        position: static;
    }

    /* Кнопки страницы — в меню «⋮». В шапке шириной 360px они переносились
       в два-три ряда и отнимали треть экрана, а основное действие и так на
       кнопке «+». Меню раскрывается под шапкой во всю её ширину. */
    .top-bar {
        position: relative;
        flex-wrap: nowrap;
    }

    .top-bar-more:not([hidden]) {
        display: inline-flex;
        flex-shrink: 0;
    }

    .top-bar-actions {
        display: none;
        position: absolute;
        top: calc(100% + 4px);
        left: 14px;
        right: 14px;
        z-index: var(--z-dropdown);
        flex-direction: column;
        align-items: stretch;
        gap: 6px;
        padding: 8px;
        background: var(--surface-container-high);
        border: 1px solid var(--outline-variant);
        border-radius: var(--radius-md);
        box-shadow: var(--shadow-2);
    }

    .top-bar-actions.is-open {
        display: flex;
    }

    .top-bar-actions .btn {
        justify-content: flex-start;
    }

    /* «Столбцы» управляют таблицей, а на телефоне таблица — плитки: кнопка
       ничего видимого не меняла. */
    .columns-menu {
        display: none;
    }

    .data-table th,
    .data-table td {
        padding: 9px 10px;
        font-size: 13px;
    }

    .formset-header {
        display: none;
    }

    .formset-row {
        grid-template-columns: 1fr;
    }

    .formset-row label {
        display: block;
        font-size: 12px;
        color: var(--on-surface-variant);
    }

    .delete-row {
        padding-bottom: 0;
    }

    .top-bar-actions .btn {
        min-height: 36px;
        padding: 0 12px;
    }

    /* Правила, которые обслуживали таблицу в виде таблицы, убраны: с
       карточной вёрсткой (блок ниже) они потеряли смысл.

       Что именно ушло и почему:
         * table-layout: auto — в карточках ширины колонок не участвуют;
         * скрытие кнопки удаления — она пряталась потому, что три кнопки не
           помещались в узкую колонку; в карточке действия идут отдельной
           строкой, и места хватает всем;
         * отмена закрепления первой колонки — закреплять в карточке нечего.

       Вместе с последним правилом из файла исчез единственный !important. */

    .col-resizer {
        display: none;
    }

    .columns-panel {
        left: auto;
        right: 0;
        max-width: min(280px, calc(100vw - 32px));
    }

    .btn-new-shipment-desktop {
        display: none;
    }

    .fab-new-shipment {
        display: inline-flex;
    }

    /* Итог в карточке («Итого к производству…», «В очереди…») на узком экране
       переносится на две-три строки. Выровненные вправо, они читались
       лесенкой и стояли на 16px правее текста под ними. */
    .card > .table-total-summary {
        padding: 0 0 12px;
        text-align: left;
    }

    .card > .table-total-summary:last-child {
        padding-bottom: 0;
    }

    /* Кнопка "+" висит над списком (56px и 20px от края), а под последней
       плиткой оставалось 32px — её кнопки действий уходили под "+", и
       дотянуться до них было нельзя даже в самом низу страницы. */
    .content-wrapper:has(.fab-new-shipment) {
        padding-bottom: 96px;
    }
}

.table-total-summary {
    padding: 12px 16px;
    border-bottom: 1px solid var(--outline-variant);
    text-align: right;
    font-size: 14px;
    color: var(--on-surface-variant);
}

.table-total-summary strong {
    color: var(--on-surface);
    font-size: 15px;
}

/* Разделитель нужен, когда под итогом что-то есть. В «Аналитике» расходов
   итог стоит в карточке один, и линия под ним висела над пустотой. */
.table-total-summary:last-child {
    border-bottom: 0;
}

/* ── 8. Страницы ─────────────────────────────────────────────────────────── */

/* Унифицированные страницы форм, справочников и служебных состояний. */
.page-form-card {
    max-width: 760px;
}

.page-form-card.page-form-wide {
    max-width: none;
}

.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0 16px;
}

.form-section-title {
    margin: 24px 0 12px;
    font-size: 16px;
    line-height: 24px;
    font-weight: 600;
}

.form-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 24px;
}

.form-actions .btn:first-child {
    margin-right: auto;
}

/* Отступ сверху отделяет кнопки от полей. Когда кнопки — всё содержимое
   карточки («Отметить как просмотренные» под инцидентами), он давал пустоту
   над кнопкой вдвое больше, чем под ней. */
.form-actions:first-child {
    margin-top: 0;
}

.form-actions form {
    display: contents;
}

.detail-value {
    min-height: 40px;
    padding: 9px 2px;
    font-size: 14px;
    line-height: 1.4;
    color: var(--on-surface);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}

/* Габариты товара в форме: длина × ширина × высота одной строкой. На
   320px поле — около 70px, этого хватает на четырёхзначное число. */
.dimension-inputs {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    gap: 6px;
}

.dimension-inputs .form-control {
    min-width: 0;
}

.dimension-sep {
    color: var(--on-surface-variant);
}

/* Фразы «одна в строке» (ключевые слова, характеристики) в карточке
   просмотра и длинные тексты описаний: по строкам, слово длиннее строки
   переносится, а не раздвигает карточку. Без маркеров списка: строка
   показана так, как уйдёт на площадку, — характеристики часто сами
   начинаются с «-», и маркер давал «• -». */
.content-lines {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 2px;
}

.content-lines,
.detail-value.content-text {
    overflow-wrap: anywhere;
}

.detail-value.content-text {
    display: block;
}

/* Ручной запуск на странице артикулов рекламы: задача и её ход. Не таблица:
   на телефоне узкая колонка названий ломала слова по слогам. */
.manual-run {
    display: grid;
    gap: 6px;
    padding: 12px 0;
    border-top: 1px solid var(--outline-variant);
}

.analytics-block-title + .manual-run {
    border-top: 0;
    padding-top: 4px;
}

.checkbox-field {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 40px;
    color: var(--on-surface);
    cursor: pointer;
}

.checkbox-field input {
    accent-color: var(--primary);
    width: 18px;
    height: 18px;
}

.helper-text {
    color: var(--on-surface-variant);
    font-size: 14px;
    line-height: 20px;
}

/* Вводный абзац перед формой или таблицей («Каждая строка — решение…»)
   упирался прямо в подпись первого поля. Под полем такой абзац стоит
   последним в группе, и его отступ поглощается отступом группы. Вес нулевой
   (:where): свой отступ у абзаца с классом (.auth-subtitle) важнее общего. */
:where(p.helper-text:not(:last-child)) {
    margin-bottom: 12px;
}

/* Флажок, вложенный в подпись: без этого он оставался браузерным квадратиком
   13px рядом с 18px-флажками остальных форм. */
.checkbox-label {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
}

.checkbox-label input[type='checkbox'] {
    width: 18px;
    height: 18px;
    margin: 0;
    accent-color: var(--primary);
}

.import-description {
    margin-bottom: 16px;
}

/* Правила импорта списком (товарный контент). */
.import-rules {
    padding-left: 18px;
    display: grid;
    gap: 4px;
}

/* Ошибки импорта: «Что не так» — несколько пояснений, слово длиннее
   столбца (артикул без пробелов) переносится внутри ячейки. */
.import-errors-card {
    margin-bottom: 16px;
}

.import-errors-table td {
    overflow-wrap: anywhere;
    vertical-align: top;
}

.page-state-card,
.confirmation-card {
    max-width: 520px;
    margin-right: auto;
    margin-left: auto;
    text-align: center;
    padding: 32px;
}

.page-state-card .empty-state-icon,
.confirmation-card .empty-state-icon {
    width: 56px;
    height: 56px;
    margin: 0 auto 12px;
    border-radius: 16px;
    background: var(--primary-container);
    color: var(--on-primary-container);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.confirmation-card .empty-state-icon {
    background: var(--error-container);
    color: var(--on-error-container);
}

.page-state-card .empty-state-icon .material-symbols-rounded,
.confirmation-card .empty-state-icon .material-symbols-rounded {
    font-size: 28px;
}

.page-state-card .helper-text,
.confirmation-card .helper-text {
    margin-top: 8px;
}

.confirmation-actions {
    justify-content: center;
}

.confirmation-actions .btn:first-child {
    margin-right: 0;
}

.dense-actions {
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
    width: 100%;
}

.table-cell-muted {
    color: var(--on-surface-variant);
}

/* Подпись поля в ячейке — название строки («Уведомления»: событие, под ним
   описание). В стиле подписи над полем ввода (12px, серая) название
   читалось мельче собственного описания. */
.data-table td > .form-label {
    margin-bottom: 2px;
    font-size: 14px;
    color: var(--on-surface);
}

/* Таблицы редактора правил трека: поля прямо в ячейках. С width: 100% у
   .form-control таблица на десять колонок сжимала выпадающие списки уже их
   текста — «Остановить, замену не создавать» читалось как «Оста», а текст
   упирался в стрелку. Теперь список шириной по самому длинному пункту, с
   местом под стрелку, а числовое поле не уже своего значения. Таблица,
   ставшая шире карточки, прокручивается в своём .table-container.
   В карточном режиме (до 768px) поля по-прежнему во всю ширину плитки. */
@media (min-width: 769px) {
    .rules-table select.form-control {
        width: auto;
        min-width: 100%;
        padding-right: 32px;
    }

    .rules-table input.form-control {
        min-width: 6rem;
    }
}

.file-input {
    width: 100%;
    min-height: 40px;
    padding: 8px 12px;
    border: 1px solid var(--outline);
    border-radius: 10px;
    background: var(--surface-container-low);
    color: var(--on-surface);
}

.file-input:focus {
    outline: 2px solid color-mix(in oklab, var(--primary) 65%, transparent);
    outline-offset: 1px;
    border-color: var(--primary);
}

.file-input::file-selector-button {
    margin-right: 10px;
    padding: 6px 10px;
    border: 0;
    border-radius: 8px;
    background: var(--secondary-container);
    color: var(--on-secondary-container);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

@media (max-width: 768px) {
    .form-actions {
        flex-wrap: wrap;
    }

    .form-actions .btn:first-child {
        margin-right: 0;
    }

    .form-actions .btn {
        flex: 1 1 auto;
    }

    .page-state-card,
    .confirmation-card {
        padding: 24px 20px;
    }
}

/* Аналитика плана расходов — круговые диаграммы + таблицы-легенды. */
.analytics-filter-card form {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px;
}

.analytics-filter-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.analytics-filter-grid .filter-group {
    min-width: 170px;
}

.analytics-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
    gap: 16px;
    align-items: start;
}

/* Без этого колонка сетки не уже своего содержимого: таблица с числами
   распирала её шире экрана телефона, вместо того чтобы прокручиваться в
   своей рамке. */
.analytics-grid > * {
    min-width: 0;
}

.analytics-block-title {
    font-size: 16px;
    font-weight: 600;
    margin-bottom: 14px;
}

.analytics-chart-wrap {
    position: relative;
    display: flex;
    justify-content: center;
    margin-bottom: 18px;
}

.analytics-chart-wrap svg {
    width: 220px;
    height: 220px;
    overflow: visible;
}

.analytics-chart-wrap path {
    cursor: pointer;
    transition: filter 0.1s ease;
}

.analytics-chart-wrap path:hover,
.analytics-chart-wrap path:focus-visible {
    filter: brightness(1.1);
    outline: none;
}

.analytics-tooltip {
    position: absolute;
    left: 0;
    top: 0;
    pointer-events: none;
    background: var(--surface-container-high);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-sm);
    padding: 6px 10px;
    font-size: 12px;
    line-height: 1.4;
    box-shadow: var(--shadow-2);
    transform: translate(-50%, calc(-100% - 10px));
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.1s ease;
    z-index: var(--z-tooltip);
}

.analytics-tooltip.is-visible {
    opacity: 1;
    visibility: visible;
}

.analytics-tooltip strong {
    display: block;
    color: var(--on-surface);
    font-size: 13px;
}

.analytics-legend-dot-cell {
    width: 28px;
}

.analytics-legend-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
}

.analytics-dot-0 { background: var(--chart-1); }
.analytics-dot-1 { background: var(--chart-2); }
.analytics-dot-2 { background: var(--chart-3); }
.analytics-dot-3 { background: var(--chart-4); }
.analytics-dot-4 { background: var(--chart-5); }
.analytics-dot-5 { background: var(--chart-6); }
.analytics-dot-other { background: var(--on-surface-variant); }

/* График платежей на ближайшие дни (static/js/bar-chart.js). Цвета — здесь,
   через токены темы: SVG перекрашивается вместе с темой без перерисовки.
   Шире карточки (телефон) график прокручивается в своей рамке, а не
   растягивает страницу. Подсказка — снаружи прокрутки, чтобы её не
   обрезало. */
.upcoming-payments {
    margin-bottom: 16px;
}

.upcoming-summary {
    margin: -8px 0 12px;
}

.bar-chart {
    position: relative;
    margin-bottom: 12px;
}

/* Ось Y — отдельным SVG слева и не прокручивается: на телефоне столбцы
   уезжают вбок, а шкала остаётся на виду. */
.bar-chart-body {
    display: flex;
}

.bar-chart-axis-svg {
    flex: none;
    display: block;
}

.bar-chart-scroll {
    flex: 1;
    min-width: 0;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-inline: contain;
    --fade-left: 0px;
    --fade-right: 0px;
}

.bar-chart-scroll.has-overflow-left {
    --fade-left: 32px;
}

.bar-chart-scroll.has-overflow-right {
    --fade-right: 32px;
}

/* За краем есть ещё дни — край гаснет, как у широких таблиц. */
.bar-chart-scroll.has-overflow-left,
.bar-chart-scroll.has-overflow-right {
    mask-image: linear-gradient(
        to right,
        transparent,
        #000 var(--fade-left),
        #000 calc(100% - var(--fade-right)),
        transparent
    );
}

.bar-chart-svg {
    display: block;
}

.bar-chart-bar {
    fill: var(--chart-1);
}

.bar-chart-hit {
    fill: transparent;
    cursor: default;
}

.bar-chart-col.is-active .bar-chart-hit {
    fill: color-mix(in oklab, var(--primary) 8%, transparent);
}

.bar-chart-col:focus {
    outline: none;
}

.bar-chart-col:focus-visible .bar-chart-hit {
    stroke: var(--primary);
    stroke-width: 2px;
}

.bar-chart-weekend {
    fill: var(--surface-container);
}

.bar-chart-grid {
    stroke: var(--outline-variant);
    stroke-width: 1px;
}

.bar-chart-baseline {
    stroke: var(--outline);
    stroke-width: 1px;
}

.bar-chart-axis,
.bar-chart-label {
    fill: var(--on-surface-variant);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
}

.bar-chart-label.is-today {
    fill: var(--on-surface);
    font-weight: 700;
}

.upcoming-days summary {
    width: fit-content;
    cursor: pointer;
    color: var(--primary);
    font-weight: 600;
    font-size: 14px;
}

.upcoming-days[open] summary {
    margin-bottom: 12px;
}

@media (max-width: 768px) {
    .analytics-grid {
        grid-template-columns: 1fr;
    }
}

/* Список отступлений от регламента на странице профиля правил. Отступ
   слева — место для маркеров: общий сброс обнуляет его у всех списков. */
.deviations-list {
    display: grid;
    gap: 6px;
    padding-left: 20px;
}

/* ── Страница модуля «Реклама Ozon» ─────────────────────────────────────── */

/* Полоса состояния модуля. Цвет задаётся токенами, а не литералами: в
   ads/* уже есть бейджи с захардкоженным фоном без указания цвета текста,
   которые проваливают контраст в тёмной теме. Здесь так не делаем. */
.module-state {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px 16px;
    margin-bottom: 16px;
    border-radius: var(--radius-lg);
    border: 1px solid var(--outline-variant);
    background: var(--surface-container-low);
    color: var(--on-surface);
    font-size: 14px;
    line-height: 1.5;
}

.module-state a {
    color: inherit;
    text-decoration: underline;
    white-space: nowrap;
}

.module-state-warning {
    background: var(--error-container);
    color: var(--on-error-container);
    border-color: transparent;
}

.module-state-watch {
    background: var(--secondary-container);
    color: var(--on-secondary-container);
    border-color: transparent;
}

.module-state-active {
    background: var(--primary-container);
    color: var(--on-primary-container);
    border-color: transparent;
}

.module-state-muted {
    color: var(--on-surface-variant);
}

.module-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 16px;
    align-items: stretch;
}

.module-tile {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-bottom: 0;
    text-decoration: none;
    color: var(--on-surface);
    transition: border-color 150ms ease, box-shadow 150ms ease, transform 150ms ease;
}

.module-tile:hover {
    border-color: var(--primary);
    box-shadow: var(--shadow-2);
}

.module-tile:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.module-tile-icon {
    color: var(--primary);
    margin-bottom: 6px;
}

.module-tile-value {
    font-size: 26px;
    font-weight: 700;
    line-height: 1.2;
    color: var(--on-surface);
}

/* Плитки, у которых вместо счётчика стоит слово («Подключено», «Действуют»):
   26px рассчитаны на две-три цифры, а слово в них переносится и ломает сетку.
   Кегль меньше, смысл тот же. */
.module-tile-value-text {
    font-size: 18px;
    line-height: 1.35;
}

.module-tile-name {
    font-size: 15px;
    font-weight: 600;
}

.module-tile-hint {
    font-size: 13px;
    color: var(--on-surface-variant);
}

/* Плитка с непросмотренными инцидентами или ошибками за сутки: приглушённый
   красный на фоне, а не только цифра — иначе ноль и десяток выглядят одинаково. */
.module-tile-alert .module-tile-icon,
.module-tile-alert .module-tile-value {
    color: var(--error);
}

.module-tile-action .module-tile-icon {
    color: var(--on-surface-variant);
}

@media (prefers-reduced-motion: reduce) {
    .module-tile,
    .nav-group,
    .nav-arrow {
        transition: none;
    }

    /* Колечко ожидания не крутим, но и не убираем: оно единственный признак
       того, что запрос ещё идёт. Статичная дуга эту роль исполняет. */
    .btn.is-busy::after {
        animation: none;
    }
}

/* ── Штатный календарь ────────────────────────────────────────────────────── */

/* Подпись графика: «5/2 · 8–17», «2/2 день», «2/2 ночь». Цвета — те же, что у
   ячеек шахматки, чтобы график в карточке и смены в сетке читались одинаково. */
.schedule-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-height: 24px;
    padding: 0 9px;
    border-radius: 999px;
    border: 1px solid transparent;
    background: var(--surface-container);
    color: var(--on-surface-variant);
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    vertical-align: middle;
}

.schedule-pill .material-symbols-rounded {
    font-size: 15px;
}

td > .schedule-pill:first-child:not(:only-child) {
    margin-right: 6px;
}

.schedule-pill--office {
    background: var(--shift-office-bg);
    color: var(--shift-office-fg);
}

.schedule-pill--day {
    background: var(--shift-day-bg);
    color: var(--shift-day-fg);
}

.schedule-pill--night {
    background: var(--shift-night-bg);
    color: var(--shift-night-fg);
    border-color: var(--shift-night-border);
}

/* Произвольный график дни не расставляет — плашка без заливки смены, с
   пунктиром: рабочие дни у такого сотрудника появляются только отметками. */
.schedule-pill--manual {
    background: transparent;
    border: 1px dashed var(--outline);
    color: var(--on-surface-variant);
}

/* Кнопки внутри полосы состояния: общее правило полосы подчёркивает ссылки и
   красит их в цвет текста — кнопке это не идёт. */
.module-state-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
}

.module-state-actions .btn {
    text-decoration: none;
    color: var(--on-surface);
}

/* Переключатель периода: «‹ 2026 ›», «‹ Октябрь 2026 ›». */
.period-nav {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.period-nav-title {
    min-width: 150px;
    font-size: 18px;
    font-weight: 700;
    text-align: center;
}

.period-nav-summary {
    color: var(--on-surface-variant);
    font-size: 14px;
}

.calendar-year-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.staff-name-list {
    columns: 2 220px;
    margin-bottom: 16px;
    list-style: none;
    font-size: 14px;
}

.staff-name-list li {
    padding: 2px 0;
    break-inside: avoid;
}

.staff-hint-list {
    display: grid;
    gap: 4px;
    padding-left: 18px;
    margin-bottom: 8px;
}

.schedule-kind-hint p {
    margin-bottom: 6px;
}

.schedule-week-hint {
    margin-bottom: 16px;
}

/* Галочка правки задним числом — сразу под полем даты, к которому относится. */
.past-confirm {
    display: grid;
    gap: 4px;
    margin: 10px 0 16px;
}

/* Карточка сотрудника: что сделать с ручными отметками при смене графика. */
.plan-marks {
    display: grid;
    gap: 4px;
    margin: 4px 0 16px;
}

.plan-marks-choices {
    display: flex;
    flex-wrap: wrap;
    gap: 0 24px;
}

.data-table td.cell-nowrap {
    white-space: nowrap;
}

/* Код отметки дня: ОТ, Б, ОГ, ДО, ПР, К. Тот же цвет, что в шахматке. */
.absence-code {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 26px;
    height: 22px;
    padding: 0 6px;
    border-radius: 6px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.2px;
    vertical-align: middle;
}

.absence-code--vacation { background: var(--absence-vacation-bg); color: var(--absence-vacation-fg); }
.absence-code--sick { background: var(--absence-sick-bg); color: var(--absence-sick-fg); }
.absence-code--day_off { background: var(--absence-day-off-bg); color: var(--absence-day-off-fg); }
.absence-code--unpaid { background: var(--absence-unpaid-bg); color: var(--absence-unpaid-fg); }
.absence-code--absent { background: var(--absence-absent-bg); color: var(--absence-absent-fg); }
.absence-code--trip { background: var(--absence-trip-bg); color: var(--absence-trip-fg); }

.staff-block-gap {
    margin-top: 20px;
}

/* Журнал изменений: «что изменено» — столбик строк «Поле: было → стало».
   Таблица фиксированной раскладки: иначе длинный список изменений
   растягивал столбец и выдавливал дату и автора в узкие полоски. Под
   «Что изменено» остаётся не меньше 300px: уже — и строка журнала
   вытягивалась в десяток строк по слову; на узком экране таблица
   прокручивается в своей рамке, как другие широкие списки. */
.staff-log-table {
    table-layout: fixed;
    min-width: 930px;
}

/* Раздел — подписью под действием: отдельный столбец отнимал место у
   списка изменений. */
.staff-log-action .date-sub {
    margin-top: 4px;
}

.staff-log-table td {
    vertical-align: top;
}

.staff-log-changes {
    display: grid;
    gap: 3px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.staff-log-label,
.staff-log-old,
.staff-log-details {
    color: var(--on-surface-variant);
}

.staff-log-details {
    font-size: 13px;
}

@media (max-width: 768px) {
    .staff-log-table {
        min-width: 0;
        table-layout: auto;
    }

    /* В плитке список изменений — своим абзацем на всю ширину под подписью,
       по левому краю: прижатый вправо столбик строк читался лесенкой. */
    .data-table td.staff-log-changes-cell {
        justify-content: flex-start;
        text-align: left;
    }

    .staff-log-changes-cell .staff-log-changes {
        flex-basis: 100%;
    }
}

/* Первый раздел формы — у верхнего края карточки, без отступа заголовка. */
.employee-form-card .form-section-title:first-of-type {
    margin-top: 0;
}

/* Карточка сотрудника: предпросмотр двух недель по выбранному графику. */
.schedule-preview,
.schedule-history {
    margin-bottom: 16px;
}

.schedule-preview-title {
    margin-bottom: 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--on-surface);
}

.schedule-preview-days {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.preview-day {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 44px;
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-xs);
    color: var(--on-surface-variant);
    font-size: 13px;
    line-height: 1.1;
}

.preview-day small {
    font-size: 10px;
}

.preview-day--office {
    background: var(--shift-office-bg);
    color: var(--shift-office-fg);
    border-color: transparent;
}

.preview-day--day {
    background: var(--shift-day-bg);
    color: var(--shift-day-fg);
    border-color: transparent;
}

.preview-day--night {
    background: var(--shift-night-bg);
    color: var(--shift-night-fg);
    border-color: var(--shift-night-border);
}

/* Строки плановых отпусков в карточке сотрудника. */
.vacation-days {
    padding-bottom: 10px;
    color: var(--on-surface-variant);
    font-size: 14px;
}

@media (min-width: 769px) {
    .vacation-header,
    .vacation-row {
        grid-template-columns: 170px 170px 70px 1fr 96px;
    }
}

@media (max-width: 768px) {
    .vacation-days {
        padding-bottom: 0;
    }
}

/* Небольшая таблица чисел, которая и на телефоне остаётся таблицей. Плитки
   (.data-table до 768px) хороши для записей с десятком полей, а двенадцать
   месяцев по три числа превращали в двенадцать карточек на пять экранов. */
.mini-table-wrap {
    overflow-x: auto;
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-md);
}

.mini-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
}

.mini-table th,
.mini-table td {
    padding: 8px 12px;
    border-bottom: 1px solid var(--outline-variant);
    text-align: left;
}

.mini-table th {
    background: var(--surface-container);
    color: var(--on-surface-variant);
    font-size: 12px;
    font-weight: 600;
}

.mini-table tbody tr:last-child td {
    border-bottom: 0;
}

.mini-table .num {
    text-align: right;
}

.mini-table td.num {
    white-space: nowrap;
}

@media (max-width: 768px) {
    .mini-table th,
    .mini-table td {
        padding: 8px;
    }
}

/* ── Шахматка ─────────────────────────────────────────────────────────────
 *
 * Сетка прокручивается внутри своей карточки в обе стороны, как в прототипе:
 * закреплены строка дней, столбцы ФИО и графика слева и итоги справа. Только
 * так строка дней видна у нижних участков, а имя — у последних чисел месяца.
 * Высота — экран за вычетом шапки: прокрутив страницу до сетки, человек
 * видит её целиком.
 */

/* Переключатель из нескольких положений: «Факт | План», «Месяц | Неделя». */
.segmented {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    /* min-width: 0 — иначе во flex-строке переключатель не уже своего
       содержимого и распирает панель шире экрана. */
    min-width: 0;
    max-width: 100%;
    padding: 3px;
    border-radius: 999px;
    background: var(--surface-container);
    /* На телефоне четыре положения не помещаются — листаются вбок. */
    overflow-x: auto;
    scrollbar-width: none;
}

.segmented::-webkit-scrollbar {
    display: none;
}

.segmented-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 32px;
    padding: 0 14px;
    border-radius: 999px;
    color: var(--on-surface-variant);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}

.segmented-item .material-symbols-rounded {
    font-size: 17px;
}

.segmented-item:hover {
    color: var(--on-surface);
}

.segmented-item.is-active {
    background: var(--primary-container);
    color: var(--on-primary-container);
}

.segmented-strong .segmented-item.is-active {
    background: var(--primary);
    color: var(--on-primary);
}

.staff-today {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 22px;
    padding: 12px 16px;
    background: var(--primary-container);
    border-color: transparent;
    color: var(--on-primary-container);
    font-size: 14px;
}

.staff-today-date {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-weight: 700;
}

.staff-today-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    cursor: default;
}

.staff-grid-card {
    padding: 0;
    overflow: clip;
}

/* Форма — элемент сетки панели; без min-width: 0 она не уже своего
   содержимого, и переключатель графиков распирал панель шире экрана. */
.staff-grid-toolbar > form {
    min-width: 0;
}

/* Панель фильтров над шахматкой не закрепляется: у сетки своя прокрутка,
   и закреплённая панель отнимала бы у неё высоту экрана. */
@media (min-width: 769px) {
    .shipments-toolbar.staff-grid-toolbar {
        position: static;
    }
}

.staff-grid-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 16px;
    padding: 12px 16px;
}

.staff-grid-bar .period-nav-title {
    min-width: 170px;
}

.staff-grid-mode {
    margin-left: auto;
}

.staff-legend {
    padding: 0 16px 10px;
    font-size: 12px;
    color: var(--on-surface-variant);
}

.staff-legend summary {
    width: max-content;
    cursor: pointer;
    font-weight: 600;
}

.staff-legend-items {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    margin-top: 6px;
}

.staff-legend-items > span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.sg-cover-sample {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    width: 24px;
    font-size: 10px;
    font-weight: 600;
    line-height: 1.15;
    color: var(--on-surface);
}

.sg-cover-sample .is-short {
    color: var(--error);
}

.staff-grid-wrap {
    overflow: auto;
    max-height: calc(100dvh - var(--topbar-current, var(--topbar-height)) - 32px);
    overscroll-behavior: contain;
    border-top: 1px solid var(--outline-variant);
}

.staff-grid-empty {
    padding: 40px 16px;
}

.staff-grid {
    border-collapse: separate;
    border-spacing: 0;
    min-width: 100%;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
}

.staff-grid th,
.staff-grid td {
    padding: 0;
    border-bottom: 1px solid var(--outline-variant);
    background: var(--surface-container-low);
    font-weight: 400;
    text-align: center;
    vertical-align: middle;
}

.staff-grid thead th {
    position: sticky;
    top: 0;
    z-index: var(--z-sticky-head);
    height: 48px;
    background: var(--surface-container);
    color: var(--on-surface-variant);
    font-size: 12px;
    font-weight: 600;
}

/* Закреплённые слева столбцы: ФИО и график. */
.staff-grid .sg-name {
    position: sticky;
    left: 0;
    z-index: var(--z-sticky-cell);
    width: 200px;
    min-width: 200px;
    max-width: 200px;
    padding: 4px 8px 4px 16px;
    text-align: left;
}

.staff-grid .sg-schedule {
    position: sticky;
    left: 200px;
    z-index: var(--z-sticky-cell);
    width: 112px;
    min-width: 112px;
    padding: 4px 8px;
    border-right: 1px solid var(--outline-variant);
    text-align: left;
}

/* График строки начинается внутри периода: «с 10.10» под плашкой. */
.sg-schedule-from {
    display: block;
    margin-top: 2px;
    color: var(--on-surface-variant);
    font-size: 11px;
    line-height: 13px;
}

.staff-grid .sg-total {
    position: sticky;
    right: 0;
    z-index: var(--z-sticky-cell);
    width: 104px;
    min-width: 104px;
    padding: 4px 10px;
    border-left: 1px solid var(--outline-variant);
    text-align: right;
}

/* Углы: закреплены и сверху, и сбоку — выше остальных ячеек шапки. */
.staff-grid thead .sg-name,
.staff-grid thead .sg-schedule,
.staff-grid thead .sg-total {
    z-index: var(--z-raised);
}

.staff-grid .sg-day,
.staff-grid .sg-cell,
.staff-grid .sg-cover {
    width: 40px;
    min-width: 40px;
}

.staff-grid .sg-cell {
    height: 46px;
    padding: 3px 2px;
}

.sg-day-number,
.sg-day-weekday {
    display: block;
    line-height: 1.25;
}

.sg-day-number {
    font-size: 13px;
    color: var(--on-surface);
}

.sg-day-weekday {
    font-size: 10px;
    font-weight: 500;
}

.staff-grid th.is-off .sg-day-number,
.staff-grid th.is-off .sg-day-weekday {
    color: var(--error);
}

.staff-grid th.is-today .sg-day-number {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--primary);
    color: var(--on-primary);
}

/* Праздник: число подчёркнуто точками, название — в подсказке. */
.staff-grid th.is-holiday .sg-day-number {
    text-decoration: underline dotted;
    text-underline-offset: 3px;
}

/* Выходные столбцы темнее, сегодняшний — подсвечен. */
.staff-grid td.is-off {
    background: color-mix(in oklab, var(--surface-container) 70%, var(--surface-container-low));
}

.staff-grid td.is-today {
    background: color-mix(in oklab, var(--primary-container) 45%, var(--surface-container-low));
}

/* До приёма и после увольнения дня нет — штриховка. */
.staff-grid td.is-outside {
    background-image: repeating-linear-gradient(
        135deg, transparent 0 5px, var(--outline-variant) 5px 6px
    );
}

/* Строка участка: название, число людей и сколько на смене. */
.sg-group-row th,
.sg-group-row td {
    background: var(--surface-container);
}

.sg-group-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    min-height: 36px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--on-surface);
    font: inherit;
    font-size: 14px;
    font-weight: 700;
    text-align: left;
    cursor: pointer;
}

.sg-group-toggle .material-symbols-rounded {
    flex: none;
    font-size: 20px;
    transition: transform 150ms ease;
}

.sg-group-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sg-group-count {
    flex: none;
    min-width: 22px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--surface-container-highest);
    color: var(--on-surface-variant);
    font-size: 12px;
    line-height: 20px;
    text-align: center;
}

.sg-group.is-collapsed .sg-group-toggle .material-symbols-rounded {
    transform: rotate(-90deg);
}

.sg-group.is-collapsed .sg-row {
    display: none;
}

.sg-cover-labels span,
.sg-cover span {
    display: block;
    font-size: 11px;
    line-height: 1.3;
    color: var(--on-surface-variant);
}

.sg-cover span {
    font-weight: 600;
    color: var(--on-surface);
}

.sg-cover .sg-cover-night {
    color: var(--on-surface-variant);
}

.sg-cover .is-short {
    color: var(--error);
    font-weight: 700;
}

/* Сотрудник: короткое имя и должность. Ссылка — в карточку. */
.sg-person {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 6px;
    align-items: center;
    color: var(--on-surface);
    text-decoration: none;
}

.sg-person:hover .sg-person-name {
    color: var(--primary);
    text-decoration: underline;
}

.sg-person-mark {
    display: none;
    grid-row: 1 / span 2;
    width: 8px;
    height: 8px;
    border-radius: 50%;
}

.sg-person-mark--office { background: var(--shift-office-fg); }
.sg-person-mark--day { background: var(--shift-day-fg); }
.sg-person-mark--night { background: var(--shift-night-bg); box-shadow: 0 0 0 1px var(--shift-night-border); }
.sg-person-mark--manual { box-shadow: inset 0 0 0 1.5px var(--on-surface-variant); }

.sg-person-name {
    grid-column: 2;
    overflow: hidden;
    font-size: 13px;
    font-weight: 600;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sg-person-position {
    grid-column: 2;
    overflow: hidden;
    color: var(--on-surface-variant);
    font-size: 11px;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sg-total-main,
.sg-total-sub {
    display: block;
    white-space: nowrap;
}

.sg-total-main {
    color: var(--on-surface-variant);
}

.sg-total-main strong {
    color: var(--on-surface);
}

.sg-total-sub {
    font-size: 11px;
}

.sg-total-sub.is-even {
    color: var(--success);
}

.sg-total-sub.is-off-norm {
    color: var(--absence-unpaid-fg);
    font-weight: 600;
}

/* Плашка дня. Знак, а не только цвет: солнце, луна, число часов, код. */
.sg-chip {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    width: 34px;
    height: 36px;
    border: 1px solid transparent;
    border-radius: var(--radius-xs);
    font-size: 12px;
    font-weight: 700;
    line-height: 1;
    vertical-align: middle;
}

.sg-chip .material-symbols-rounded {
    font-size: 18px;
}

.sg-chip--mini {
    width: 24px;
    height: 22px;
    border-radius: 6px;
    font-size: 10px;
}

.sg-chip--mini .material-symbols-rounded {
    font-size: 14px;
}

.sg-chip--office { background: var(--shift-office-bg); color: var(--shift-office-fg); }
.sg-chip--day { background: var(--shift-day-bg); color: var(--shift-day-fg); }
.sg-chip--night {
    background: var(--shift-night-bg);
    color: var(--shift-night-fg);
    border-color: var(--shift-night-border);
}
.sg-chip--absence-vacation { background: var(--absence-vacation-bg); color: var(--absence-vacation-fg); }
.sg-chip--absence-sick { background: var(--absence-sick-bg); color: var(--absence-sick-fg); }
.sg-chip--absence-day_off { background: var(--absence-day-off-bg); color: var(--absence-day-off-fg); }
.sg-chip--absence-unpaid { background: var(--absence-unpaid-bg); color: var(--absence-unpaid-fg); }
.sg-chip--absence-absent { background: var(--absence-absent-bg); color: var(--absence-absent-fg); }
.sg-chip--absence-trip { background: var(--absence-trip-bg); color: var(--absence-trip-fg); }
/* Отсутствие любого вида — в полосе «Сегодня»: код больничного «Б» там
   говорил бы, что все отсутствующие на больничном. */
.sg-chip--neutral { background: var(--surface-container-highest); color: var(--on-surface-variant); }

/* Пустая плашка: в факте выхода нет, хотя по плану был, — без неё такой
   день ничем не отличался бы от обычного выходного. */
.sg-chip--empty {
    border: 1px dashed var(--outline);
    background: transparent;
}

/* Будущий день в факте — это ещё план: чуть приглушён, но читается. */
.sg-chip.is-expected {
    opacity: 0.72;
}

/* Не так, как в плане: уголок справа сверху. */
.sg-chip.is-changed::after {
    content: '';
    position: absolute;
    top: -1px;
    right: -1px;
    border-top: 10px solid var(--primary);
    border-left: 10px solid transparent;
    border-top-right-radius: var(--radius-xs);
}

/* Не по графику: ручная смена или выходной в плане перекрывает график —
   уголок слева снизу. ::before свободен: замена (точка) такой пометки не
   получает, а уголок «не так, как в плане» занимает ::after. */
.sg-chip.is-manual::before {
    content: '';
    position: absolute;
    bottom: -1px;
    left: -1px;
    border-bottom: 10px solid var(--tone-accent);
    border-right: 10px solid transparent;
    border-bottom-left-radius: var(--radius-xs);
}

/* Замена или подработка: точка слева сверху. */
.sg-chip.is-substitution::before {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--primary);
    box-shadow: 0 0 0 1.5px var(--surface-container-low);
}

/* Неделя: столбцы шире, в плашке видно время. */
.staff-grid--week .sg-day,
.staff-grid--week .sg-cell,
.staff-grid--week .sg-cover {
    width: auto;
    min-width: 96px;
}

.staff-grid--week .sg-chip {
    width: calc(100% - 4px);
    max-width: 150px;
    padding: 0 6px;
}

.sg-chip-time {
    font-size: 11px;
    font-weight: 600;
}

/* Ноутбук: рядом с боковым меню на дни оставалась неделя. Столбец графика
   уходит, вид смены — точкой у имени, график целиком — в подсказке. */
@media (max-width: 1200px) {
    .staff-grid .sg-schedule {
        display: none;
    }

    .sg-person-mark {
        display: block;
    }

    .staff-grid .sg-name {
        width: 170px;
        min-width: 170px;
        max-width: 170px;
    }
}

@media (max-width: 768px) {
    .staff-grid-wrap {
        max-height: calc(100dvh - var(--topbar-current, var(--topbar-height)) - 16px);
    }

    /* На телефоне закреплено одно имя: две колонки слева заняли бы пол-экрана.
       Вид смены — точкой у имени, график целиком — в подсказке. */
    .staff-grid .sg-name {
        width: 124px;
        min-width: 124px;
        max-width: 124px;
        padding-left: 10px;
    }

    .staff-grid .sg-schedule {
        display: none;
    }

    .staff-grid .sg-total {
        position: static;
    }

    .sg-person-mark {
        display: block;
    }

    .staff-grid-mode {
        margin-left: 0;
    }

    .staff-grid-bar .period-nav {
        width: 100%;
    }

    /* Неделя на стыке месяцев на узком телефоне — в две строки, а не
       обрезанной: даты здесь и есть смысл заголовка. */
    .staff-grid-bar .period-nav-title {
        min-width: 0;
        flex: 1;
        font-size: 15px;
        line-height: 1.25;
        overflow-wrap: anywhere;
    }

    .staff-grid-toolbar .search-field {
        min-width: 0;
        flex-basis: 100%;
    }
}

/* Текст только для экранного диктора: «Сохранено» после отметки дня. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* ── Отметки в шахматке ────────────────────────────────────────────────── */

/* Ячейка, которую можно отметить: ссылка на всю ячейку. */
.sg-cell-link {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 38px;
    border-radius: var(--radius-xs);
    color: inherit;
    text-decoration: none;
    cursor: pointer;
    user-select: none;
}

.sg-cell-link:hover {
    background: color-mix(in oklab, var(--primary) 10%, transparent);
}

.sg-cell-link:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: -2px;
}

.staff-grid td.is-selected {
    background: color-mix(in oklab, var(--primary) 22%, var(--surface-container-low));
}

.staff-grid td.is-selected .sg-cell-link {
    box-shadow: inset 0 0 0 2px var(--primary);
}

.staff-grid-hint {
    margin: -6px 0 16px;
    font-size: 13px;
}

/* Всплывающее меню: рядом с выделенными днями, на телефоне — снизу. */
.sg-popover {
    position: fixed;
    z-index: var(--z-popover);
    width: 380px;
    max-height: min(86vh, 720px);
    overflow: auto;
    padding: 16px;
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-lg);
    background: var(--surface-container-low);
    box-shadow: var(--shadow-2);
}

.sg-popover.is-sheet {
    right: 0;
    bottom: 0;
    left: 0;
    width: auto;
    max-height: 86dvh;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}

.day-form {
    display: grid;
    gap: 12px;
}

.day-form .form-group {
    margin-bottom: 0;
}

.day-form-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.day-form-name {
    font-size: 16px;
    font-weight: 700;
}

.day-form-sub,
.day-form-now {
    font-size: 13px;
    color: var(--on-surface-variant);
}

.day-form-now > div:first-child {
    color: var(--on-surface);
}

.day-form-hint {
    font-size: 13px;
    line-height: 18px;
}

.day-form-layer {
    flex: none;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 700;
}

.day-form-layer--fact {
    background: var(--primary);
    color: var(--on-primary);
}

.day-form-layer--plan {
    background: var(--primary-container);
    color: var(--on-primary-container);
}

.day-form-label {
    margin-bottom: 6px;
    font-size: 12px;
    font-weight: 600;
    color: var(--on-surface-variant);
}

/* Варианты отметки — плашки с тем же кодом, что в шахматке. */
.day-actions {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 6px;
    border: 0;
}

.day-action {
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 38px;
    padding: 4px 8px;
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-sm);
    font-size: 13px;
    cursor: pointer;
}

.day-action input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.day-action:hover {
    border-color: var(--outline);
}

.day-action:has(input:checked) {
    border-color: var(--primary);
    background: var(--primary-container);
    color: var(--on-primary-container);
}

.day-action:has(input:focus-visible) {
    outline: 2px solid var(--primary);
    outline-offset: 1px;
}

.day-action-mark {
    display: inline-flex;
}

.day-work {
    display: grid;
    gap: 10px;
    padding: 12px;
    border-radius: var(--radius-sm);
    background: var(--surface-container);
}

.day-presets {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.day-preset {
    gap: 4px;
    min-height: 32px;
    padding: 0 10px;
    font-size: 12px;
}

.day-preset .material-symbols-rounded {
    font-size: 16px;
}

.day-form-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}

.day-form-grid--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* На телефоне три поля времени в строку не помещались: время обрезалось
   до «08:0». Часы — отдельной строкой под началом и концом. */
@media (max-width: 768px) {
    .day-form-grid--3 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .day-form-grid--3 > :last-child {
        grid-column: 1 / -1;
    }
}

.day-form .checkbox-field {
    min-height: 32px;
}

.day-form-actions {
    margin-top: 4px;
}

/* В меню над сеткой кнопки прилипают к низу: с блоком времени и «За кого»
   форма выше экрана ноутбука, а на телефоне шторка всегда прокручивается, и
   «Применить» оказывалось под краем. Отрицательные поля — до краёв меню,
   поверх его внутреннего отступа. */
.sg-popover .day-form-actions {
    position: sticky;
    bottom: -16px;
    z-index: 1;
    margin: 4px -16px -16px;
    padding: 12px 16px;
    border-top: 1px solid var(--outline-variant);
    background: var(--surface-container-low);
}

.day-form-page {
    max-width: 520px;
}

/* ── Аналитика штатного календаря ──────────────────────────────────────── */

.staff-analytics-note {
    margin: -4px 0 12px;
    font-size: 13px;
}

.staff-tiles {
    margin-bottom: 16px;
}

/* Девять плиток по одной в ряд на телефоне — пять экранов прокрутки. По
   две в ряд, числа чуть мельче. */
@media (max-width: 768px) {
    .staff-tiles {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 10px;
    }

    .staff-tiles .module-tile {
        padding: 12px;
    }

    .staff-tiles .module-tile-value {
        font-size: 20px;
    }

    .staff-tiles .module-tile-value-text {
        font-size: 15px;
    }

    .staff-tiles .module-tile-name {
        font-size: 13px;
    }

    .staff-tiles .module-tile-hint {
        font-size: 12px;
    }
}

/* Плитка-сводка, а не ссылка: без подсветки при наведении. */
.module-tile.is-static:hover {
    border-color: var(--outline-variant);
    box-shadow: var(--shadow-1);
}

.staff-short {
    color: var(--error);
}

.mini-table td.cell-nowrap,
.data-table td.cell-number.cell-nowrap {
    white-space: nowrap;
}

.staff-over-limit {
    margin-top: 6px;
}

.staff-over-limit summary {
    cursor: pointer;
    font-weight: 600;
}

/* Нехватка людей: в строке дня — участки и смены, где людей меньше минимума. */
.staff-shortages > .helper-text {
    margin-bottom: 8px;
}

/* Сменщики по людям: разделы «Дневная смена» и «Ночная смена» — как строка
   участка в шахматке, итог раздела — жирным. */
.staff-shift-workers > .helper-text {
    margin-bottom: 8px;
}

.data-table .staff-shift-section th {
    color: var(--on-surface);
    font-size: 14px;
    font-weight: 700;
}

.data-table .staff-shift-total td {
    font-weight: 700;
}

/* В плитках подпись раздела — заголовок над плитками его людей, а не
   плитка из одной строки. */
@media (max-width: 768px) {
    .data-table tr.staff-shift-section {
        margin: 18px 0 8px;
        padding: 0;
        border: 0;
        border-radius: 0;
        background: transparent;
        box-shadow: none;
    }

    .data-table tr.staff-shift-section:first-child {
        margin-top: 4px;
    }

    .data-table tbody tr.staff-shift-section > th:first-child {
        margin: 0;
        padding: 0;
        border: 0;
        font-size: 15px;
    }

    /* Пустая ячейка участка в итоге: в плитке — подпись без значения. */
    .data-table tr.staff-shift-total > td:empty {
        display: none;
    }
}

.shortage-items {
    display: flex;
    flex-wrap: wrap;
    gap: 2px 18px;
    list-style: none;
}

.staff-more {
    margin-top: 10px;
}

.staff-more summary {
    width: max-content;
    margin-bottom: 8px;
    color: var(--primary);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
}

.staff-subtitle {
    margin: 14px 0 6px;
    font-size: 13px;
    font-weight: 700;
}

.analytics-block-title + .staff-subtitle {
    margin-top: 0;
}

.staff-event-list {
    display: grid;
    gap: 6px;
    list-style: none;
    font-size: 14px;
}

.staff-event-list li {
    display: flex;
    align-items: center;
    gap: 8px;
}

.staff-event-list li.is-past {
    color: var(--on-surface-variant);
}

.staff-event-list .material-symbols-rounded {
    font-size: 18px;
    color: var(--primary);
}

.staff-name-inline {
    font-size: 14px;
    line-height: 1.6;
}

/* Печать шахматки: кнопка в шапке раскрывает выбор периода. Форма внутри
   <details> — блок раскладки, а не «display: contents», как прочие формы
   шапки (правило .top-bar-actions form выше). */
.print-menu {
    position: relative;
}

.print-menu > summary {
    list-style: none;
}

.print-menu > summary::-webkit-details-marker {
    display: none;
}

.print-menu[open] > summary {
    border-color: var(--primary);
}

.top-bar-actions .print-menu .print-menu-panel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: var(--z-dropdown);
    display: grid;
    gap: 10px;
    width: 320px;
    padding: 14px;
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-md);
    background: var(--surface-container-high);
    box-shadow: var(--shadow-2);
}

.print-menu-panel .form-group {
    margin-bottom: 0;
}

.print-menu-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

@media (max-width: 768px) {
    .top-bar-actions .print-menu .print-menu-panel {
        position: static;
        width: auto;
        margin-top: 6px;
        box-shadow: none;
    }

    .print-menu > summary {
        width: 100%;
        justify-content: flex-start;
    }
}

/* ── Роли и доступ ─────────────────────────────────────────────────────────
   Матрица «раздел × роль»: в ячейке две галочки, и читать её должно быть
   так же легко, как бумажную таблицу. Поэтому подписи у галочек полные
   («Смотреть», «Изменять»), а не заголовок колонки на всю таблицу: колонок
   четыре, и глазу иначе не за что зацепиться. */
.section-title {
    margin: 24px 0 12px;
    font-size: 15px;
    font-weight: 600;
    color: var(--on-surface);
}

.section-title:first-of-type {
    margin-top: 0;
}

.data-table th.text-left {
    text-align: left;
}

/* Общая сетка для обеих таблиц страницы: без неё каждая считала ширины сама,
   и вертикальные оси столбцов ролей не совпадали. Ширина задана только первому
   столбцу — остальные при table-layout: fixed делят остаток поровну, сколько
   бы ролей ни было. */
.permissions-table {
    table-layout: fixed;
}

.permissions-section-col {
    width: 240px;
}

/* Ноутбук: рядом с боковым меню на четыре роли оставалось по ~110px, и
   «Администратор» с «маркетплейсов» в шапке рвались посреди слова. Названия
   разделов переносятся по словам — им хватает и 180px. */
@media (max-width: 1200px) {
    .permissions-section-col {
        width: 180px;
    }
}

.permission-cell {
    white-space: nowrap;
}

.permission-option {
    display: flex;
    align-items: center;
    gap: 8px;
    /* 32px — минимальная цель касания, которую удаётся дать в плотной
       таблице; 24px по норме приходятся на сам квадрат. */
    min-height: 32px;
    font-size: 13px;
    color: var(--on-surface-variant);
    cursor: pointer;
}

.permission-option input {
    width: 18px;
    height: 18px;
    cursor: pointer;
}

.permission-option input:disabled {
    cursor: default;
}

.permission-option input:disabled + span {
    opacity: 0.6;
}

/* ── 9. Карточная вёрстка ────────────────────────────────────────────────── */

/* ── Карточная вёрстка таблиц на узком экране ──────────────────────────────
 *
 * Суммарная ширина колонок — 1706px в Поставках и 2120px в Плане расходов.
 * При экране 360px это в пять-шесть раз шире, и до сих пор ширину уменьшала
 * не вёрстка, а скрипт: при первом заходе с телефона пряталось восемь
 * колонок. Оставалось около 830px — всё равно вдвое шире экрана, то есть
 * горизонтальная прокрутка никуда не девалась, а настройка столбцов
 * разъезжалась между телефоном и компьютером.
 *
 * Здесь строка таблицы превращается в карточку: первое поле крупно сверху,
 * остальные — парами «подпись: значение», действия внизу. Горизонтальная
 * прокрутка исчезает совсем, и панель «Столбцы» на телефоне становится не
 * нужна (она остаётся доступной, но набор по умолчанию больше не урезается).
 *
 * Подписи берутся из data-label, который проставляет static/js/table-columns.js
 * по заголовкам столбцов. Без скрипта карточки останутся без подписей, но
 * значения будут видны — это приемлемая деградация.
 */
@media (max-width: 768px) {
    .table-container {
        /* В карточном виде прокручивать внутри контейнера нечего: карточки
           идут по ширине экрана. Рамка и фон тоже лишние — их рисует каждая
           карточка. */
        overflow: visible;
        border: 0;
        background: transparent;
    }

    /* То же — с карточкой, в которую обёрнута таблица. Плитки сами себе
       карточки, а общая рамка вокруг них давала непрерывные линии по бокам
       списка, серое поле между плитками (её фон темнее фона страницы) и
       двойную рамку под последней плиткой. overflow: hidden обрезал бы тени
       крайних плиток. Обёртка остаётся блоком, но без собственного вида.

       Таблица может лежать и глубже — в форме («Роли и доступ», инциденты).
       Таблица «поле — значение» (.kv-table) плитками не становится, и её
       карточка остаётся карточкой. */
    .card:has(.table-container > .data-table:not(.kv-table)) {
        padding: 0;
        border: 0;
        border-radius: 0;
        background: transparent;
        box-shadow: none;
        overflow: visible;
    }

    .data-table,
    .data-table tbody,
    .data-table tr,
    .data-table tbody th,
    .data-table td {
        display: block;
        width: auto;
    }

    /* Закрепление колонок — приём горизонтальной прокрутки, а в карточке
       прокручивать нечего. Сброс обязан быть не слабее исходных правил
       (:1102-1147, вес 0,2,1) и стоять ниже по файлу — тогда при равном весе
       побеждает он. Без сброса ячейка «Наименование оплаты» и колонка
       чекбоксов оставались липкими и торчали поверх карточки обрезками. */
    .shipments-table th[data-col],
    .shipments-table td[data-col],
    .expenses-table th[data-col],
    .expenses-table td[data-col],
    .expenses-table th.select-col,
    .expenses-table td.select-col {
        position: static;
        left: auto;
        right: auto;
        z-index: auto;
        width: auto;
    }

    /* Колонка выбора: массовые действия — приём для мыши и широкой таблицы.
       В карточке у записи есть свои кнопки, а 44px-чекбокс превращался в
       «осколок» над первой карточкой. */
    .expenses-table th.select-col,
    .expenses-table td.select-col {
        display: none;
    }

    /* Шапка и разметка ширин в карточном виде не участвуют. */
    .data-table thead,
    .data-table colgroup,
    .data-table .col-resizer {
        display: none;
    }

    .data-table tr {
        /* relative — для ячейки-метки в углу плитки (.row-marker ниже). */
        position: relative;
        margin-bottom: 12px;
        padding: 12px 14px;
        border: 1px solid var(--outline-variant);
        border-radius: var(--radius-md);
        background: var(--surface-container-low);
        box-shadow: var(--shadow-1);
    }

    /* Полосатость и подсветка строк — приёмы таблицы. В плитке они красили
       ячейки, а не плитку, и внутри каждой второй карточки проступал
       прямоугольник другого оттенка; подсветка к тому же залипала после
       касания. Вес тот же, что у исходных правил (0,2,3), а стоит ниже по
       файлу — поэтому побеждает. Фокус с клавиатуры рисуется рамкой плитки,
       а не рамками каждой ячейки. */
    .shipments-table tbody tr:nth-child(even) td,
    .shipments-table tbody tr:hover td,
    .shipments-table tbody tr:focus-visible td {
        background: transparent;
        outline: 0;
    }

    .shipments-table tbody tr:focus-visible {
        outline: 2px solid var(--primary);
        outline-offset: 2px;
    }

    .data-table td,
    .data-table tbody th {
        border: 0;
        padding: 6px 0;
        display: flex;
        /* Значение прижимается вправо и тогда, когда перенеслось на свою
           строку: при space-between оно оставалось одно в строке и уходило к
           левому краю, выбиваясь из столбика значений. Подпись отодвигает его
           своим margin-right: auto. */
        justify-content: flex-end;
        align-items: baseline;
        gap: 12px;
        text-align: right;
        /* Фон рисует плитка. У ячеек-заголовков th свой, более тёмный, и он
           проступал прямоугольником за заголовком плитки. */
        background: transparent;
        /* Значение и бейдж переносятся на свою строку, а не обрезаются правым
           краем карточки; «монолитные» имена вида
           Складные_стеллажи_АВТО_ПиР_15.09.26-5731345508 рвутся по месту,
           потому что пробелов для переноса в них нет. */
        flex-wrap: wrap;
        min-width: 0;
        overflow-wrap: anywhere;
    }

    .data-table td::before,
    .data-table tbody th::before {
        content: attr(data-label);
        /* Подпись не сжимается: иначе она расходуется первой и превращается
           в лесенку из одной буквы. */
        flex-shrink: 0;
        max-width: 45%;
        margin-right: auto;
        font-size: 12px;
        font-weight: 600;
        color: var(--on-surface-variant);
        text-align: left;
    }

    /* Заголовок карточки: подпись ему не нужна, значение крупное и на всю
       ширину. Перечислено явно, а не одним :first-child — в расходах первая
       ячейка строки скрыта (колонка выбора), а display: none не снимает
       :first-child; на «Ролях и доступе» первая ячейка вообще th. После
       ячейки-метки (.row-marker, см. ниже) заголовком становится следующая. */
    .data-table tbody tr > td:first-child,
    .data-table tbody tr > th:first-child,
    .data-table tbody tr > td.row-marker + td,
    .expenses-table tbody tr > td[data-col="name"] {
        padding-top: 0;
        padding-bottom: 10px;
        margin-bottom: 6px;
        border-bottom: 1px solid var(--outline-variant);
        justify-content: flex-start;
        /* Цвет явно: заголовок-th («Роли и доступ») иначе оставался серым,
           как подпись шапки таблицы. */
        color: var(--on-surface);
        font-size: 16px;
        font-weight: 600;
        text-align: left;
    }

    .data-table tbody tr > td:first-child::before,
    .data-table tbody tr > th:first-child::before,
    .data-table tbody tr > td.row-marker + td::before,
    .expenses-table tbody tr > td[data-col="name"]::before {
        display: none;
    }

    /* Заголовок плитки из подписи поля и описания («Уведомления»): подпись
       читается заголовком, описание — обычным текстом своей строкой, а не
       жирным, унаследованным от заголовка. */
    .data-table tbody tr > td:first-child .form-label {
        margin: 0;
        font-size: inherit;
        color: inherit;
    }

    .data-table tbody tr > td:first-child .helper-text {
        flex-basis: 100%;
        font-size: 13px;
        font-weight: 400;
    }

    /* Ячейка-метка: флажок выбора строки (кампании, инциденты) или цветная
       точка легенды (аналитика). Заголовком плитки она быть не может — выходил
       одинокий квадратик или точка над чертой, а название уезжало ниже с
       подписью. Метка встаёт в правый верхний угол плитки, заголовком
       становится следующая ячейка. */
    .data-table tbody tr > td.row-marker {
        position: absolute;
        top: 12px;
        right: 14px;
        margin: 0;
        padding: 0;
        border: 0;
        min-height: 24px;
        align-items: center;
    }

    .data-table tbody tr > td.row-marker + td {
        padding-right: 32px;
    }

    /* Действия — строкой внизу карточки, без подписи и с крупными целями
       касания: в карточке места на это хватает, в отличие от узкой колонки. */
    .data-table td.actions-cell {
        padding-top: 10px;
        margin-top: 6px;
        border-top: 1px solid var(--outline-variant);
        justify-content: flex-end;
    }

    .data-table td.actions-cell::before {
        display: none;
    }

    .data-table td.actions-cell .dense-actions {
        gap: 8px;
    }

    .data-table td.actions-cell .action-button {
        min-width: 40px;
        min-height: 40px;
    }

    /* Пустое состояние остаётся обычным блоком, а не карточкой. */
    .data-table td.empty-state {
        display: block;
        text-align: center;
    }

    .data-table td.empty-state::before {
        display: none;
    }

    /* Многострочные ячейки (состав поставки) выравниваются по левому краю:
       столбик значений справа читается хуже, чем список. */
    .data-table td.cell-lines {
        flex-direction: column;
        align-items: flex-start;
        text-align: left;
    }

    .data-table td.cell-lines::before {
        max-width: none;
    }

    /* Ручка перетаскивания строк в карточке не нужна: перетаскивать карточки
       пальцем по вертикальному списку неудобно. */
    .data-table .drag-grip {
        display: none;
    }

    /* ── Состав плитки ─────────────────────────────────────────────────────
     *
     * Карточка, дословно повторяющая все колонки таблицы, вырастает на два
     * экрана, и полезное уходит вниз за служебным. В плитке остаётся то, по
     * чему запись узнают и выбирают в списке; остальное — в карточке записи,
     * куда ведёт тап по плитке.
     *
     * Скрываем в карточном виде, а не в шаблоне: на компьютере колонки нужны,
     * и раздваивать разметку ради телефона дороже, чем одно правило. Побочное
     * следствие: включить эти поля на телефоне через панель «Столбцы» нельзя —
     * она там и так не нужна.
     *
     * План расходов переиспользует класс .shipments-table (см. разметку
     * expense_list.html), поэтому правила по data-col действуют на обе
     * таблицы. Пересекается только "comment" — его убираем в обеих, так и
     * задумано.
     */

    /* Поставки: остаются № поставки, дата отгрузки, маркетплейс, склад,
       перевозчик, статус, действия. Состав поставки (товары, единицы,
       грузоместа, тип) — в карточке поставки: четыре параллельных списка, где
       строка N одного отвечает строке N другого, на узком экране нечитаемы. */
    .shipments-table td[data-col="products"],
    .shipments-table td[data-col="units"],
    .shipments-table td[data-col="places"],
    .shipments-table td[data-col="place_type"],
    .shipments-table td[data-col="comment"] {
        display: none;
    }

    /* План расходов: остаются наименование оплаты, сумма, контрагент, дата
       оплаты, статус оплаты, ответственный сотрудник, действия. */
    .expenses-table td[data-col="category"],
    .expenses-table td[data-col="account"],
    .expenses-table td[data-col="budget_status"],
    .expenses-table td[data-col="receipt_status"],
    .expenses-table td[data-col="received_at"] {
        display: none;
    }

    /* Товарный контент: остаются название, производственный артикул,
       артикулы ВБ и Озон, базовая цена, действия — по ним товар узнают;
       остальное — в карточке. */
    .content-cards-table td[data-col="wb_barcode"],
    .content-cards-table td[data-col="ozon_barcode"],
    .content-cards-table td[data-col="brand"],
    .content-cards-table td[data-col="manufacturer"],
    .content-cards-table td[data-col="color"],
    .content-cards-table td[data-col="weight"],
    .content-cards-table td[data-col="package_size"],
    .content-cards-table td[data-col="updated_at"] {
        display: none;
    }

    /* Справочник «Товары»: название Ozon дублирует наименование — в карточке
       остаётся одно название. На компьютере и в форме правки столбец есть.
       Правило — только для таблицы справочника: у товарного контента
       «Название Озон» — своё поле, и в его плитке оно нужно. */
    .directory-table--product td[data-col="ozon_name"] {
        display: none;
    }

    /* «Роли и доступ»: карточка — это раздел, а её строки — роли. Заголовком
       становится ячейка раздела (th scope="row"), подписи ролей приходят из
       шапки. Запрет переноса нужен широкой таблице на компьютере, а здесь
       из-за него не помещалось «Менеджер маркетплейсов».

       Подпись роли — своей строкой, пара галочек — под ней. Раньше пара
       стояла справа от подписи, и помещалась ли она, решала длина названия
       роли: у «Редактора» пара стояла в строку, у «Администратора» и
       «Менеджера маркетплейсов» «Изменять» перескакивало вниз к левому краю.
       Одинаковая раскладка для всех ролей читается как таблица. */
    .data-table td.permission-cell {
        justify-content: flex-start;
        white-space: normal;
        gap: 2px 24px;
    }

    .data-table td.permission-cell::before {
        flex-basis: 100%;
        max-width: none;
        margin-right: 0;
    }

    /* Таблица «поле — значение» (карточка артикула, параметры профиля правил)
       в две колонки помещается и на телефоне. Плитками её строки становиться
       не должны: каждое поле выходило отдельной карточкой. Здесь это ровный
       список «подпись — значение» внутри одной карточки. */
    .data-table.kv-table tr {
        display: flex;
        align-items: baseline;
        gap: 12px;
        margin: 0;
        padding: 8px 0;
        border: 0;
        border-bottom: 1px solid var(--outline-variant);
        border-radius: 0;
        background: transparent;
        box-shadow: none;
    }

    .data-table.kv-table tr:last-child {
        border-bottom: 0;
    }

    .data-table.kv-table td {
        flex: 1 1 auto;
        padding: 0;
        font-size: 14px;
    }

    /* Подпись не сжимается: переносы «где угодно» (overflow-wrap: anywhere у
       ячеек) иначе ломали её по буквам — «Това / р» рядом с длинным
       названием товара. Сжимается и переносится значение. */
    .data-table.kv-table tbody tr > td:first-child {
        flex: 0 0 auto;
        max-width: 50%;
        margin: 0;
        padding: 0;
        border: 0;
        font-size: 13px;
        font-weight: 600;
        color: var(--on-surface-variant);
    }
}
