/* ===========================================================================
   cabinet.css — слой кабинета «Сторно» поверх студийного ядра.
   Порядок подключения: fonts.css → core.css → skins/alfa.css → cabinet.css.

   Арт-направление (формула, п.1 studio-design-discipline):
       СТРОГИЙ · СЧИТАЕМЫЙ · ЧЕСТНЫЙ
   • строгий  — рабочий инструмент, а не витрина: без декора, без пятен и пульсаций;
   • считаемый— каждое число (чеки, суммы, ФД, время) живёт на СВЕТЛОЙ поверхности
                .surface-calc моноширинными табличными цифрами;
   • честный  — необратимое действие выглядит опасным, а не «красивым»: 926 фискальных
                документов отменить нельзя, и интерфейс обязан это показывать.

   🔴 Ни одного магического значения: всё, чего не было в ядре и скине, объявлено
   токеном ниже. Ни одного внешнего запроса: шрифты, htmx и стили лежат в /static.

   🔴 Контраст каждой пары посчитан (WCAG 2.x, скрипт замера — см. отчёт роли 6,
   прогон 10.09.2026) и подписан числом рядом с правилом.
   =========================================================================== */

:root {
  /* --- Раскладка кабинета: боковое меню + рабочая область --- */
  --sidebar-w: 260px;          /* ширина меню на ≥1024px; ниже — меню сверху */
  --shell-max: 1360px;         /* рабочая область кабинета шире промо-контейнера: тут таблицы */
  --shell-gap: var(--space-6);

  /* Кегль числа в плитке считается от ширины САМОЙ ПЛИТКИ, а не вьюпорта.
     Замер 10.09.2026 на 1280px: колонка плитки 220px, «507 070,00 ₽» — 13 глифов
     моноширинного шрифта (advance ≈0.6em) = 7.8em, влезает пока em ≤ W/7.8 ≈ 12.8cqi.
     Берём 12.5cqi и никогда не крупнее --fs-h2. Приём — из .price__value ядра. */
  --fs-stat-fit: min(var(--fs-h2), 12.5cqi);

  /* --- Полоса прогресса прогона --- */
  --progress-h: 12px;          /* высота дорожки; сам смысл дублируется текстом и aria */
  --progress-h-lg: 20px;       /* на экране прогона — оператор смотрит на телефон издалека */

  /* Точка складывания таблиц — 47.9375rem (767px), она же брейкпойнт ядра 768px.
     Токеном не выносится сознательно: custom property в @media не работает,
     переменная здесь была бы враньём. Значение встречается ровно в двух медиа-запросах ниже. */

  /* --- Максимальная высота блока с «сырым» JSON-заданием перерегистрации --- */
  --pre-max-h: 24rem;
}

/* ===========================================================================
   1. ОБОЛОЧКА: шапка · меню · рабочая область
   =========================================================================== */
.shell {
  width: 100%;
  max-width: var(--shell-max);
  margin-inline: auto;
  padding: var(--space-6) var(--gutter) var(--space-9);
  display: grid;
  gap: var(--shell-gap);
}
/* 🔴 Замер 10.09.2026 на 375px: страница кейса имела scrollWidth 444 при vw 375.
   Причина — не «лишний блок», а min-width:auto у grid-элемента: лента меню шириной 420px
   растягивала колонку, хотя сама скроллится. Чиним в раскладке, а не overflow:hidden
   (тот прячет переполнение и обесценивает проверку — урок ядра студии, DS-2). */
.shell > * { min-width: 0; }

@media (min-width: 1024px) {
  .shell { grid-template-columns: var(--sidebar-w) minmax(0, 1fr); align-items: start; }
}

/* Шапка ядра — flex без переноса; на 375px «ИНН … · Выйти» уезжал за правый край
   (замер 10.09.2026). Перенос разрешаем всегда: на десктопе он не срабатывает. */
.site-header__inner { flex-wrap: wrap; row-gap: var(--space-2); }
.site-header__nav   { flex-wrap: wrap; align-items: center; }

/* Меню: на мобильном — горизонтальная лента над контентом, на десктопе — колонка.
   Горизонтальный скролл здесь осознан: пунктов 7, и они не должны занимать пол-экрана. */
.side-nav {
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  padding-bottom: var(--space-2);
  -webkit-overflow-scrolling: touch;
}
.side-nav__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--control-h-sm);           /* тач-таргет 44px */
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md);
  border: var(--border-w) solid transparent;
  color: var(--color-text-muted);            /* 11.07:1 к --color-bg ✓ */
  font-size: var(--fs-small);
  white-space: nowrap;
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.side-nav__link:hover  { background: var(--color-action-quiet); color: var(--color-text); }
.side-nav__link:active { transform: translateY(var(--press-active)); }
.side-nav__link[aria-current="page"] {
  background: var(--color-action-quiet);
  color: var(--color-text);                  /* 15.84:1 ✓ */
  border-color: var(--color-action);         /* 6.94:1 к фону — рамка активного пункта ✓ (1.4.11) */
  font-weight: 600;
}
.side-nav__count {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-caption);
  color: var(--color-text-subtle);           /* 6.25:1 ✓ */
}
@media (min-width: 1024px) {
  .side-nav {
    position: sticky;
    top: calc(var(--control-h-lg) + var(--space-5));
    flex-direction: column;
    overflow: visible;
  }
  .side-nav__link { justify-content: space-between; }
}

.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}
.page-head__title { font-size: var(--fs-h2); }
.page-head__sub   { color: var(--color-text-muted); font-size: var(--fs-small); max-width: var(--measure); }
.page-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); }

.panel {
  background: var(--color-surface-1);
  border: var(--border-w) solid var(--color-line);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}
@media (min-width: 768px) { .panel { padding: var(--space-6); } }
.panel + .panel { margin-top: var(--space-5); }
.panel__title { font-size: var(--fs-h3); margin-bottom: var(--space-2); }
.panel__head  { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-4); }

/* Сетка карточек обзора */
.cards { display: grid; gap: var(--space-4); }
@media (min-width: 768px)  { .cards--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .cards--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* ===========================================================================
   2. ОТМЕТКА СВЕЖЕСТИ ДАННЫХ
   Правило входного экрана (TECH-DESIGN §0): кабинет читает БД, а не ОФД и не кассу.
   Значит у каждого статуса обязана стоять честная отметка «когда мерили».
   Пустой слот — видимый дефект, как .fact__source в скине.
   =========================================================================== */
.stamp {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-caption);
  color: var(--color-text-subtle);           /* 6.25:1 ✓ */
  font-variant-numeric: tabular-nums;
}
.stamp::before { content: "◷"; font-family: var(--font-mono); }
.stamp:empty { display: none; }
.stamp--stale { color: var(--color-warn); }  /* 11.1:1 ✓, смысл дублируется словом «давно» в тексте */

/* ===========================================================================
   3. ПОЛОСКИ-СООБЩЕНИЯ: баннер тарифа, уведомления, ошибки
   Статус НИКОГДА не только цветом — обязательный глиф + текст (п.12 скилла).
   =========================================================================== */
.notice {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-2) var(--space-3);
  align-items: start;
  padding: var(--space-4);
  /* 🔴 Ядро ограничивает <p> шириной строки (--measure, 66ch) — это верно для текста,
     но полоса-сообщение обязана идти во всю ширину панели. Найдено на замере 1280px:
     баннер демо и предупреждение «ошибка не прекращена» обрывались на 540px. */
  max-width: none;
  border: var(--border-w) solid var(--color-line-strong);
  border-radius: var(--radius-md);
  background: var(--color-surface-2);
  color: var(--color-text-muted);            /* 10.03:1 к --color-surface-2 ✓ */
  font-size: var(--fs-small);
}
.notice::before { font-family: var(--font-mono); font-weight: 700; line-height: var(--lh-body); }
.notice__title { font-weight: 600; color: var(--color-text); grid-column: 2; }
.notice__body  { grid-column: 2; }
.notice__body > * + * { margin-top: var(--space-2); }
.notice[data-kind="info"]::before    { content: "i"; color: var(--color-text-subtle); }
.notice[data-kind="success"] { border-color: var(--color-success); background: var(--color-success-bg); }
.notice[data-kind="success"]::before { content: "✓"; color: var(--color-success); }   /* 10.54:1 ✓ */
.notice[data-kind="warn"]    { border-color: var(--color-warn); background: var(--color-warn-bg); }
.notice[data-kind="warn"]::before    { content: "!"; color: var(--color-warn); }      /* 11.1:1 ✓ */
.notice[data-kind="error"]   { border-color: var(--color-error); background: var(--color-error-bg); }
.notice[data-kind="error"]::before   { content: "✕"; color: var(--color-error); }     /* 6.52:1 ✓ */

/* Баннер тарифа в шапке: демо, дни до конца, «только просмотр» */
.plan-banner {
  display: flex;
  max-width: none;         /* тот же случай, что и у .notice: это не абзац текста, а полоса */
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--gutter);
  background: var(--color-bg-alt);
  border-bottom: var(--border-w) solid var(--color-line);
  font-size: var(--fs-small);
  color: var(--color-text-muted);            /* 10.03:1 ✓ */
}
.plan-banner__glyph { font-family: var(--font-mono); font-weight: 700; }
.plan-banner[data-kind="warn"]  { color: var(--color-warn); }   /* 11.1:1 к bg-alt (11.1 к bg, 10.0 к alt) ✓ */
.plan-banner[data-kind="error"] { color: var(--color-error); }  /* 5.91:1 к --color-bg-alt ✓ */

/* ===========================================================================
   4. ЧИСЛА И ТАБЛИЦЫ — всё «считаемое» на светлой поверхности .surface-calc
   (правило R1 ядра студии; класс сам переопределяет токены внутри себя).
   =========================================================================== */
.stats { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.stat  { display: grid; gap: var(--space-1); align-content: start; container-type: inline-size; }
/* 🔴 Цвета плитки берутся из ЛОКАЛЬНЫХ токенов, а не из --surface-light-*: класс .stat
   используется и на тёмной панели (счётчик касс на обзоре, «было/станет» в перерегистрации).
   Живой замер 10.09.2026 поймал провал 1.21:1 и 1.92:1 ровно там, где были жёстко
   прописаны светлые значения. Внутри .surface-calc эти же токены сами становятся тёмными. */
.stat__label { font-size: var(--fs-caption); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--color-text-subtle); }
   /* 6.25:1 на тёмном фоне · 7.14:1 внутри .surface-calc ✓ */
.stat__value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-h2);
  line-height: var(--lh-num);
  font-weight: 600;
  white-space: nowrap;
  color: var(--color-text);                  /* 15.84:1 на тёмном · 16.57:1 внутри .surface-calc ✓ */
}
/* Фолбэк выше (--fs-h2, по вьюпорту): движок без container queries получает прежнее
   поведение, а не сломанную вёрстку. */
@supports (container-type: inline-size) {
  .stat__value { font-size: var(--fs-stat-fit); }
}
.stat__unit  { font-size: var(--fs-small); color: var(--color-text-muted); }   /* 11.07:1 тёмный · 7.14:1 светлый ✓ */
.stat__note  { font-size: var(--fs-caption); color: var(--color-text-muted); }

/* Таблица данных. Мобильный первым: до 768px строка складывается в карточку,
   заголовок колонки приезжает из data-label — горизонтального скролла нет. */
.table-wrap { overflow-x: auto; }
.data-table { width: 100%; border-collapse: collapse; font-size: var(--fs-small); }
.data-table caption { text-align: left; font-size: var(--fs-caption); color: var(--color-text-subtle); padding-bottom: var(--space-3); }
.data-table th, .data-table td { padding: var(--space-3) var(--space-4); text-align: left; vertical-align: top; }
.data-table thead th { font-size: var(--fs-caption); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--color-text-subtle); border-bottom: var(--border-w) solid var(--color-line-strong); }
.data-table tbody tr { border-bottom: var(--border-w) solid var(--color-line); }
.data-table td.is-num, .data-table th.is-num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; text-align: right; }
.data-table tbody tr:last-child { border-bottom: 0; }

@media (max-width: 47.9375rem) {
  .data-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .data-table tbody tr {
    display: grid;
    gap: var(--space-1);
    padding: var(--space-4) 0;
    border-bottom: var(--border-w) solid var(--color-line);
  }
  .data-table td { display: grid; grid-template-columns: minmax(0, 8rem) minmax(0, 1fr); gap: var(--space-3); padding: var(--space-1) 0; text-align: left; }
  .data-table td.is-num { text-align: left; }
  .data-table td::before {
    content: attr(data-label);
    font-size: var(--fs-caption);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--color-text-subtle);
    font-family: var(--font-text);
  }
  .data-table td:empty { display: none; }
}

/* Плотная таблица цифр ядра (.calc-table) на узком экране: шаг сетки мельче, иначе
   четыре колонки «чеки/количество/цена/сумма» не помещаются в 375px (замер 10.09.2026). */
@media (max-width: 47.9375rem) {
  .calc-table th, .calc-table td { padding: var(--space-2); font-size: var(--fs-caption); }
}

/* Список «ключ — значение»: реквизиты кассы, кейса, прогона */
.kv { display: grid; gap: var(--space-3); }
.kv > div { display: grid; grid-template-columns: minmax(0, 11rem) minmax(0, 1fr); gap: var(--space-2) var(--space-4); align-items: baseline; }
.kv dt { font-size: var(--fs-caption); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--color-text-subtle); }
.kv dd { color: var(--color-text); }
.kv dd.is-num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
@media (max-width: 47.9375rem) { .kv > div { grid-template-columns: minmax(0, 1fr); } }

/* Отпечаток ключа ОФД. 🔒9 Значение ключа в UI не появляется НИКОГДА — только key_fp. */
.fingerprint {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--color-surface-2);
  color: var(--color-text-muted);            /* 10.03:1 ✓ */
  word-break: break-all;
}

/* ===========================================================================
   5. ОПАСНЫЕ ДЕЙСТВИЯ
   Критерий приёмки 4 брифа: «Запустить прогон» и «Выполнить перерегистрацию»
   ОТЛИЧАЮТСЯ визуально и требуют подтверждения, рядом — честный текст о необратимости.

   🔴 Почему красный, а не второй акцент: это не декоративный цвет, а семантика
   ядра (--color-error) в её прямом значении «отменить нельзя». Оранжевый акцент
   действия остаётся один; красным покрашены ровно две кнопки на весь кабинет.
   =========================================================================== */
.btn--danger {
  background: var(--color-error);
  color: var(--color-bg);                    /* #1A1030 на #FF6B6B = 6.52:1 ✓ */
  border-color: transparent;
}
.btn--danger::before { content: "!"; font-family: var(--font-mono); font-weight: 700; }
.btn--danger:hover  { background: var(--color-error); filter: brightness(0.92); }
.btn--danger:active { filter: brightness(0.86); transform: translateY(var(--press-active)); }
.btn--danger:focus-visible { outline: var(--focus-w) solid var(--color-focus); outline-offset: var(--focus-offset); }
.btn--danger[disabled], .btn--danger[aria-disabled="true"] {
  background: var(--color-disabled-bg);
  color: var(--color-disabled-text);         /* 5.2:1 ✓ */
  filter: none;
  cursor: not-allowed;
}

/* Блок «что именно произойдёт» рядом с опасной кнопкой */
.danger-zone {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-5);
  border: var(--border-w) solid var(--color-error);
  border-radius: var(--radius-md);
  background: var(--color-error-bg);
}
.danger-zone__title { font-size: var(--fs-h3); color: var(--color-text); }
.danger-zone__text  { font-size: var(--fs-small); color: var(--color-text-muted); }   /* 10.03:1 на error-bg поверх bg ✓ */
/* 🔴 QA n-1 (10.09.2026): подсказка поля пароля и подпись у кнопки лежат на ДРУГОЙ подложке —
   --color-error-bg (12% #FF6B6B) поверх --color-surface-1 = #462757, а не на самой панели.
   --color-text-subtle там даёт 4,30:1 — провал AA (нужно 4,5). Тот же токен, что уже взят выше
   для .danger-zone__text: --color-text-muted = 7,61:1 на #462757 ✓ (замер — tests/test_templates.py,
   он же ловит повтор регресса при смене палитры). Правим ТОКЕН у мелкого текста, а не размер шрифта. */
.danger-zone .field__hint,
.danger-zone .caption { color: var(--color-text-muted); }

/* ===========================================================================
   6. ПРОГОН: прогресс, пауза, живые числа
   Мобильный первым — оператор стоит у кассы с телефоном (бриф B).
   =========================================================================== */
.progress {
  display: grid;
  gap: var(--space-2);
}
.progress__track {
  height: var(--progress-h);
  border-radius: var(--radius-full);
  background: var(--color-surface-2);
  border: var(--border-w) solid var(--color-line-strong);   /* 3.66:1 — граница видима ✓ (1.4.11) */
  overflow: hidden;
}
.progress--lg .progress__track { height: var(--progress-h-lg); }
.progress__fill {
  height: 100%;
  background: var(--color-action);           /* единственный акцент — здесь он уместен: это ход дела */
  transition: width var(--dur-base) var(--ease-out);
}
.progress[data-state="paused"]  .progress__fill { background: var(--color-warn); }    /* 11.1:1 ✓ + текст «пауза» */
.progress[data-state="error"]   .progress__fill { background: var(--color-error); }   /* 6.52:1 ✓ + текст ошибки */
.progress[data-state="done"]    .progress__fill { background: var(--color-success); } /* 10.54:1 ✓ + слово «готово» */
.progress__text {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-small);
  color: var(--color-text-muted);
}

/* Крупные числа прогона: сделано/всего, скорость, остаток, текущий ФД */
.run-stats { display: grid; gap: var(--space-4); grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 768px) { .run-stats { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* Кнопки управления прогоном: на телефоне — во всю ширину, палец попадает */
.run-controls { display: grid; gap: var(--space-3); }
@media (min-width: 768px) { .run-controls { display: flex; flex-wrap: wrap; } }
.run-controls .btn { min-height: var(--control-h-lg); }   /* 56px: жмут в перчатках у кассы */

/* ===========================================================================
   7. ЧЕК-ЛИСТ ПРЕД-УСЛОВИЙ И ШАГОВ
   =========================================================================== */
.checklist { display: grid; gap: var(--space-3); }
.checklist__item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-3);
  align-items: start;
  padding: var(--space-3) var(--space-4);
  border: var(--border-w) solid var(--color-line);
  border-radius: var(--radius-md);
  background: var(--color-surface-2);
}
.checklist__item::before { font-family: var(--font-mono); font-weight: 700; line-height: var(--lh-body); }
.checklist__item[data-status="open"]::before    { content: "□"; color: var(--color-text-subtle); }
.checklist__item[data-status="done"]::before    { content: "✓"; color: var(--color-success); }   /* 8.58:1 ✓ */
.checklist__item[data-status="skipped"]::before { content: "–"; color: var(--color-text-subtle); }
.checklist__item[data-blocking="true"] { border-color: var(--color-warn); }
.checklist__text { color: var(--color-text); }
.checklist__note { font-size: var(--fs-caption); color: var(--color-text-subtle); }

/* Шаги «до / после» перерегистрации */
.ba-grid { display: grid; gap: var(--space-4); }
@media (min-width: 768px) { .ba-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.sno-list { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* Задание кассе показывается ЦЕЛИКОМ (правило спеки §3): не сворачиваем, не сокращаем */
.task-json {
  max-height: var(--pre-max-h);
  overflow: auto;
  padding: var(--space-4);
  border: var(--border-w) solid var(--color-line-strong);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  color: var(--color-text-muted);            /* 11.07:1 к --color-bg ✓ */
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  line-height: var(--lh-snug);
  white-space: pre;
  tab-size: 2;
}
.task-json:focus-visible { outline: var(--focus-w) solid var(--color-focus); outline-offset: var(--focus-offset); }

/* ===========================================================================
   8. ФОРМЫ КАБИНЕТА
   =========================================================================== */
.form { display: grid; gap: var(--space-5); }
.form-grid { display: grid; gap: var(--space-4); }
@media (min-width: 768px) { .form-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.form-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }

/* Группа флажков/радио — тач-таргет у ярлыка, а не только у квадратика */
.choice { display: grid; gap: var(--space-2); }
.choice__row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--control-h-sm);
  padding: var(--space-2) var(--space-3);
  border: var(--border-w) solid var(--color-line);
  border-radius: var(--radius-md);
  cursor: pointer;
}
.choice__row:hover { border-color: var(--color-action); }
.choice__row:focus-within { outline: var(--focus-w) solid var(--color-focus); outline-offset: var(--focus-offset); }
.choice__row input { width: var(--space-5); height: var(--space-5); accent-color: var(--color-action); flex: none; }
.choice__label { font-size: var(--fs-small); }
.choice__hint  { font-size: var(--fs-caption); color: var(--color-text-subtle); }

/* Поле, куда вводят цифры (ИНН, РНМ, число чеков): моно и табличные цифры */
.input.is-num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* Ряд «за одну строку»: период с/по.
   🔴 До 480px две даты рядом не влезают: у input[type=date] своя минимальная ширина
   (замер 375px — страница разъезжалась до 380). Складываем в столбик. */
.row-2 { display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 30rem) { .row-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ===========================================================================
   9. СОСТОЯНИЯ СТРАНИЦЫ
   Пусто ≠ загрузка ≠ ошибка. Каркасы .empty-state/.loading-state — из ядра,
   здесь только то, чего там нет.
   =========================================================================== */
.empty-state__hint { font-size: var(--fs-small); color: var(--color-text-subtle); }
.loading-state[aria-busy="true"] { color: var(--color-text-muted); }

/* Строка «ошибка и что делать» внутри панели */
.inline-error {
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
  color: var(--color-error);                 /* 5.31:1 на --color-surface-1 ✓ */
  font-size: var(--fs-small);
}
.inline-error::before { content: "✕"; font-family: var(--font-mono); font-weight: 700; }

/* Дословный текст ошибки ККТ — не пересказываем, показываем как пришло */
.device-error {
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--color-error-bg);
  border: var(--border-w) solid var(--color-error);
  color: var(--color-text);                  /* 15.84:1 — сам текст белый, красным только рамка ✓ */
  white-space: pre-wrap;
  word-break: break-word;
}

/* ===========================================================================
   10. МЕЛОЧИ
   =========================================================================== */
/* Команда/имя файла внутри текста инструкции */
code {
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  padding: 0 var(--space-1);
  border-radius: var(--radius-sm);
  background: var(--color-surface-2);
  color: var(--color-text);                  /* 15.84:1 на --color-surface-2 (≈bg-alt) ✓ */
  word-break: break-word;
}

.muted   { color: var(--color-text-muted); }
.subtle  { color: var(--color-text-subtle); }
.nowrap  { white-space: nowrap; }
.list-plain { display: grid; gap: var(--space-2); }
.list-plain li {
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
  /* Внутри пунктов инструкции живут команды (`driver10://tcp:IP:ПОРТ`): без min-width:0
     flex-элемент отказывается сжиматься и разъезжает страницу — замер 375px, экран агентов. */
  min-width: 0;
  overflow-wrap: anywhere;
}
.list-plain li::before { content: "—"; color: var(--color-text-subtle); }
.hr { height: var(--border-w); background: var(--color-line); border: 0; margin-block: var(--space-5); }

/* Ссылка «назад к кейсу» и хлебные крошки */
.crumbs { display: flex; flex-wrap: wrap; gap: var(--space-2); font-size: var(--fs-caption); color: var(--color-text-subtle); margin-bottom: var(--space-3); }
.crumbs a { text-decoration: underline; text-underline-offset: 0.22em; }
.crumbs a:hover { color: var(--color-text); }

/* Подвал кабинета: дисклеймер про налоговые гарантии виден на каждой странице */
.cabinet-foot {
  border-top: var(--border-w) solid var(--color-line);
  padding: var(--space-5) var(--gutter) var(--space-7);
  font-size: var(--fs-caption);
  color: var(--color-text-subtle);           /* 6.25:1 ✓ */
}
.cabinet-foot p { max-width: var(--measure); }
