/* ЯЗЫК ИНТЕРФЕЙСА КАБИНЕТА. Один файл, из него собираются все экраны.
   Внешних адресов нет ни для шрифтов, ни для скриптов, ни для стилей:
   страница показывает ФИО пациента, диагнозы и значения показателей, и
   тянуть на неё чужой код нельзя — это правило 5 `CLAUDE.md`, а не
   удобство разработки.

   ЦВЕТА СЮДА НЕ ВПИСЫВАЮТСЯ. Палитра приходит переменными `--colors-*`
   из `app/render/tokens.yaml` через `app/web/tokens_css.py` — тем же
   файлом, по которому красится сам документ. Литерал здесь означал бы
   второй источник правды: оператор держит экран рядом с готовым PDF и
   сверяет кружки глазами, и другой оранжевый — это повод не поверить ни
   экрану, ни документу.

   ЧТО ВСЁ-ТАКИ ОБЪЯВЛЕНО ЗДЕСЬ ЧИСЛОМ — нейтрали (фон, панель, линия) и
   две длительности. У документа их нет вовсе: он печатается на белом и
   не имеет обвязки, поэтому второго источника здесь не возникает. Всё
   остальное выводится из токенов формулой, и формула видна.

   ПОЧЕМУ ТЁМНАЯ. Оператор смотрит светлый медицинский лист в
   предпросмотре. Тёмная обвязка вокруг светлого листа — то, как устроены
   просмотрщики PDF: документ выступает вперёд, а интерфейс отходит.

   ТРИ ДЕФЕКТА, КОТОРЫЕ ЗДЕСЬ ЛЕЧАТСЯ ЗАРАНЕЕ. Разобраны на соседнем
   проекте (`Perecras/moy-proekt/app/static/style.css`), где интерфейс
   сначала собрали функционально, а потом переписывали CSS всемеро — со
   245 строк до 1695 — по словам владельца «скудно выглядит», «миллион
   кнопочек», «резкие выпадания»:

     1. НЕЧЕМ ПОКАЗАТЬ НЕГЛАВНОЕ. Один вес кнопки — и «Выдать пациенту»
        весит столько же, сколько «Скачать отчёт». Отсюда `.btn-primary`
        ровно один на экран, остальное `.btn-ghost` и меню за `⋯`.
     2. НЕЧЕМ ПОКАЗАТЬ ПЕРЕХОД. Смена страницы подменяет кадр целиком —
        это и есть «резкие выпадания». Отсюда `@view-transition`, который
        делает сам браузер: шапка и подвал получают имена перехода и
        СТОЯТ на месте, пока меняется только `main`.
     3. НЕЧЕМ ПОКАЗАТЬ ВЕЩЬ. Отсюда плитки заказов и чипы статусов, а не
        список ссылок.

   ДЛИТЕЛЬНОСТЕЙ РОВНО ДВЕ, и третьей нет намеренно: как только их
   становится пять, интерфейс перестаёт звучать одним темпом, и на глаз
   это читается именно как «скудно и дёргано». 150–250 мс и ease-out:
   выше оператор начинает ЖДАТЬ интерфейс, ниже движения не видно и
   остаётся рывок.

   ДОСТУПНОСТЬ. `prefers-reduced-motion` гасит ВСЁ движение, включая
   переходы вида. Это не вежливость: настройка ОС может быть включена у
   самого оператора, и тогда плавность превращается в тошноту. */

/* ------------------------------------------------------------- величины */

:root {
  /* Нейтрали кабинета. С лёгким бирюзовым подмесом, чтобы обвязка
     читалась одной семьёй с документом, а не серым поверх бирюзового. */
  --bg: #0d1416;
  --panel: #131e20;
  --sunk: #0a1113;
  --line: #1d2a2c;
  --edge: #2a3a3c;
  --ink: #e9efef;

  /* Второстепенный текст — это `colors.muted` документа, не выдуманный
     серый: тот же грей-тил, которым в Атласе набраны колонтитулы. */
  --dim: var(--colors-muted);

  /* Акцент выводится из ФИРМЕННОЙ бирюзы документа, а не подбирается.
     `slide_heading` (#10797E) на тёмном почти не виден, поэтому он
     осветляется — и осветление записано формулой, чтобы при смене
     фирменного цвета акцент поехал за ним сам. */
  --accent: color-mix(in oklab, var(--colors-slide-heading) 55%, #cfeff0);
  --accent-deep: var(--colors-slide-heading);
  --accent-soft: color-mix(in oklab, var(--colors-slide-heading) 22%, var(--bg));

  /* Две длительности. Третьей нет. */
  --fast: 150ms;
  --calm: 220ms;
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  /* Шаг волны — это ЗАДЕРЖКА, а не длительность: плитки появляются с
     одним темпом, просто не одновременно. Лежит здесь, а не в шаблоне:
     в разметке это было числом, которого приёмка не видела. */
  --step: 40ms;

  --radius: 12px;
  --radius-sm: 8px;
  --shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
  --shadow-soft: 0 2px 10px rgba(0, 0, 0, 0.28);

  --gap: 16px;
  --pad: 20px;
  --max: 1180px;

  /* ---- Переменные basecoat: его компоненты, наша палитра --------------
     Библиотека рисует `.btn`, `.card`, диалоги и выпадающие по этим
     именам. Подменяя их здесь, мы получаем готовые компоненты в цветах
     Атласа и не держим вторую кнопку своей вёрстки. */
  --background: var(--bg);
  --foreground: var(--ink);
  --card: var(--panel);
  --card-foreground: var(--ink);
  --popover: var(--panel);
  --popover-foreground: var(--ink);
  --primary: var(--accent);
  --primary-foreground: #04282a;
  --secondary: var(--sunk);
  --secondary-foreground: var(--ink);
  --muted: var(--sunk);
  --muted-foreground: var(--dim);
  --accent-foreground: #04282a;
  --destructive: var(--colors-status-out);
  --border: var(--line);
  --input: var(--edge);
  --ring: var(--accent);
  --font-sans: Onest, system-ui, sans-serif;
  --font-mono: Montserrat, ui-monospace, monospace;
}

/* -------------------------------------------------------------- движение */

@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: var(--calm);
  animation-timing-function: var(--ease);
}

/* Шапка и подвал НЕ участвуют в переходе страницы: они стоят, меняется
   только содержимое. Ощущение «тот же кабинет, другой раздел». */
.site-head { view-transition-name: head; }
.site-foot { view-transition-name: foot; }

@keyframes rise {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}

/* -------------------------------------------------------------- каркас */

* { box-sizing: border-box; }

html { color-scheme: dark; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* Фирменная бирюза еле слышно подсвечивает верх страницы. Глубина
     вместо плоской заливки — то, чем «дорого» отличается от «скудно»;
     цвет при этом тот же, что у заголовков документа, и приходит из
     токенов, а не подобран. */
  background:
    radial-gradient(1200px 420px at 50% -220px,
      color-mix(in oklab, var(--colors-slide-heading) 26%, transparent),
      transparent 70%),
    var(--bg);
  background-attachment: fixed;
  color: var(--ink);
  font-family: Onest, system-ui, sans-serif;
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

main {
  flex: 1;
  width: 100%;
  max-width: var(--max);
  margin: 0 auto;
  padding: 32px var(--pad) 64px;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* --------------------------------------------------------------- шапка */

.site-head {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in oklab, var(--bg) 86%, transparent);
  backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--line);
}

.site-head__in {
  max-width: var(--max);
  margin: 0 auto;
  padding: 14px var(--pad);
  display: flex;
  align-items: center;
  gap: 28px;
}

.brand {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-weight: 500;
  font-size: 17px;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.brand:hover { text-decoration: none; }
.brand__mark {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-soft);
  align-self: center;
}
.brand__sub { color: var(--dim); font-size: 13px; font-weight: 400; }

.nav { display: flex; gap: 4px; margin-left: auto; }
.nav a {
  color: var(--dim);
  padding: 7px 12px;
  border-radius: var(--radius-sm);
  font-size: 14px;
  transition: color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.nav a:hover { color: var(--ink); background: var(--sunk); text-decoration: none; }
.nav a[aria-current="page"] { color: var(--ink); background: var(--sunk); }

.site-foot {
  border-top: 1px solid var(--line);
  color: var(--dim);
  font-family: Montserrat, system-ui, sans-serif;
  font-size: 12px;
}
.site-foot__in {
  max-width: var(--max);
  margin: 0 auto;
  padding: 18px var(--pad);
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
}

/* --------------------------------------------------------- типографика */

h1 {
  margin: 0 0 6px;
  font-size: 30px;
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.2;
}
h2 {
  margin: 0 0 12px;
  font-size: 19px;
  font-weight: 500;
  letter-spacing: -0.01em;
}
.lead { margin: 0 0 28px; color: var(--dim); font-size: 15px; max-width: 70ch; }

/* `position` и `z-index` здесь несущие: плитки ниже по документу
   поднимаются своей анимацией `rise` (ключевой кадр с `transform`
   создаёт контекст наложения), и выпадающее меню уезжало ПОД них —
   оператор видел обрезанный список. */
.page-head {
  position: relative;
  z-index: 10;
  display: flex;
  align-items: flex-end;
  gap: 20px;
  margin-bottom: 26px;
  animation: rise var(--calm) var(--ease) both;
}
.page-head .lead { margin: 0; }
.page-head__actions { margin-left: auto; display: flex; gap: 8px; }

/* Числа — табличными цифрами и Montserrat'ом: в документе техническое
   набрано им же, и колонки в списке не должны прыгать. */
.num {
  font-family: Montserrat, system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
}

/* -------------------------------------------------------------- кнопки */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 16px;
  border: 1px solid var(--edge);
  border-radius: var(--radius-sm);
  background: var(--panel);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--fast) var(--ease),
              border-color var(--fast) var(--ease),
              transform var(--fast) var(--ease);
}
.btn:hover { background: var(--sunk); border-color: var(--accent-deep); text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* РОВНО ОДНА на экран. Если их две — значит экран не решил, что главное. */
.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #04282a;
  font-weight: 500;
}
.btn-primary:hover {
  background: color-mix(in oklab, var(--accent) 86%, white);
  border-color: color-mix(in oklab, var(--accent) 86%, white);
}

.btn-ghost { background: transparent; border-color: transparent; color: var(--dim); }
.btn-ghost:hover { background: var(--sunk); color: var(--ink); border-color: transparent; }

.btn[disabled], .btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

.btn__icon { width: 16px; height: 16px; flex: none; }

/* ------------------------------------------- компактное меню действий */

.menu { position: relative; display: inline-flex; }
/* Квадратная, с рамкой: кнопка «ещё» обязана находиться глазом. */
.menu__dots {
  padding: 9px 12px;
  line-height: 1;
  font-size: 18px;
  color: var(--dim);
}
.menu__dots:hover { color: var(--ink); }
.menu[data-open="true"] .menu__dots { color: var(--ink); border-color: var(--accent-deep); }
.menu__list {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  min-width: 210px;
  padding: 6px;
  background: var(--panel);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  display: none;
  z-index: 30;
}
.menu[data-open="true"] .menu__list { display: block; animation: rise var(--fast) var(--ease) both; }
.menu__list a, .menu__list button {
  display: flex;
  width: 100%;
  gap: 10px;
  align-items: center;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}
.menu__list a:hover, .menu__list button:hover { background: var(--sunk); text-decoration: none; }

/* ------------------------------------------------------- панель, карточка */

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-soft);
}
.panel__head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px var(--pad);
  border-bottom: 1px solid var(--line);
}
.panel__head h2 { margin: 0; }
.panel__count {
  margin-left: auto;
  color: var(--dim);
  font-family: Montserrat, system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
  font-size: 13px;
}
.panel__body { padding: var(--pad); }

/* ---------------------------------------------------- плитки заказов */

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: var(--gap);
}

.tile {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 18px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: inherit;
  box-shadow: var(--shadow-soft);
  transition: border-color var(--fast) var(--ease),
              transform var(--calm) var(--ease),
              box-shadow var(--calm) var(--ease);
  animation: rise var(--calm) var(--ease) both;
  /* Номер плитки приходит из шаблона как `--tile-index`; задержку считает
     CSS. Без значения по умолчанию плитка не появилась бы вовсе. */
  animation-delay: calc(var(--tile-index, 0) * var(--step));
}
.tile:hover {
  border-color: var(--accent-deep);
  transform: translateY(-2px);
  box-shadow: var(--shadow);
  text-decoration: none;
}
.tile__top { display: flex; align-items: flex-start; gap: 12px; }
.tile__name { font-size: 16px; font-weight: 500; letter-spacing: -0.01em; }
.tile__meta {
  color: var(--dim);
  font-family: Montserrat, system-ui, sans-serif;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.tile__facts {
  display: flex;
  gap: 18px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-family: Montserrat, system-ui, sans-serif;
  font-size: 12px;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}
.tile__facts b { color: var(--ink); font-weight: 500; }

/* ---------------------------------------------------------------- чипы */

.chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--edge);
  background: var(--sunk);
  color: var(--dim);
  font-family: Montserrat, system-ui, sans-serif;
  font-size: 11.5px;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.chip--block { border-color: color-mix(in oklab, var(--colors-status-out) 55%, var(--edge));
               color: var(--colors-status-out); }
.chip--ready { border-color: color-mix(in oklab, var(--colors-status-norm) 55%, var(--edge));
               color: var(--colors-status-norm); }
.chip--work  { border-color: color-mix(in oklab, var(--colors-status-attention) 55%, var(--edge));
               color: var(--colors-status-attention); }

/* КРУЖОК СТАТУСА. Цвета берутся из токенов документа БЕЗ примеси: это
   единственное место, где экран и PDF сверяются глазами, и подмешивать
   сюда фон значило бы показать оператору не тот оттенок. */
.dot {
  width: 10px; height: 10px; border-radius: 50%;
  flex: none; display: inline-block;
}
.dot--norm      { background: var(--colors-status-norm); }
.dot--attention { background: var(--colors-status-attention); }
.dot--out       { background: var(--colors-status-out); }
.dot--deviation { background: var(--colors-status-deviation); }
.dot--unknown   { background: var(--colors-status-unknown); }

.legend { display: flex; gap: 16px; flex-wrap: wrap; color: var(--dim);
          font-family: Montserrat, system-ui, sans-serif; font-size: 12px; }
.legend span { display: inline-flex; align-items: center; gap: 7px; }

/* --------------------------------------------------------------- врезка */

/* Блок, а не flex: первая фраза во врезке — ведущая, она обязана течь
   в том же абзаце. Во flex она вставала отдельной колонкой. */
.note {
  display: block;
  padding: 14px 16px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--edge);
  border-left: 3px solid var(--accent-deep);
  background: var(--sunk);
  color: var(--dim);
  font-size: 14px;
}
.note--block { border-left-color: var(--colors-status-out); }
.note b { color: var(--ink); font-weight: 500; }

/* ------------------------------------------------------ пустое состояние */

.empty {
  padding: 56px 24px;
  text-align: center;
  color: var(--dim);
  border: 1px dashed var(--edge);
  border-radius: var(--radius);
  background: var(--sunk);
}
.empty h2 { color: var(--ink); }
.empty p { margin: 0 auto 20px; max-width: 46ch; }

/* ------------------------------------------------------- только экрану */

/* Текст для скринридера: кнопка `⋯` обязана называться словом, иначе
   она не имеет имени вовсе. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Скелетоны вернулись с фоновой сборкой (Ф5), как и было обещано.
   Скелетон, а не крутилка: крутилка говорит «ждите», скелетон говорит
   «здесь будет отчёт» — для шестидесяти секунд это разные вещи.

   ПЕРИОД МЕРЦАНИЯ — не темп, а длительность, и третьей её здесь нет:
   мерцание сделано задержкой на общей длительности `--calm`,
   с шагом `--step`, как волна плиток. Прежняя заготовка несла
   собственные `1.2s`, которых приёмка не видела. */
.working .skeleton {
  height: 14px;
  border-radius: var(--radius-sm);
  background: linear-gradient(
    90deg,
    var(--sunk) 0%,
    color-mix(in oklab, var(--accent-deep) 14%, var(--sunk)) 50%,
    var(--sunk) 100%
  );
  margin-top: 12px;
  opacity: 0.85;
  animation: rise var(--calm) var(--ease) both;
}
.working .skeleton--wide { width: 100%; }
.working .skeleton { width: 72%; animation-delay: var(--step); }
.working .skeleton--short { width: 44%; animation-delay: calc(2 * var(--step)); }
.working h2 { color: var(--accent); }

/* -------------------------------------------------------- кто вошёл/выход */

.who {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-left: 14px;
  padding-left: 14px;
  border-left: 1px solid var(--line);
}
.who__name {
  color: var(--dim);
  font-size: 13px;
  max-width: 190px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.who__out {
  border: 1px solid var(--edge);
  background: transparent;
  color: var(--dim);
  border-radius: var(--radius-sm);
  padding: 6px 11px;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.who__out:hover { color: var(--ink); border-color: var(--accent-deep); }

/* ----------------------------------------------------------------- вход */

/* Экран входа — единственный, который центрируется по высоте: на нём
   одна карточка и больше ничего, и прижатая к верху форма выглядела бы
   обрывком страницы. */
.gate {
  min-height: calc(100vh - 210px);
  display: grid;
  place-items: center;
  padding: 20px 0;
}
.gate__card {
  width: 100%;
  max-width: 390px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 30px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  /* Та же волна, что у плиток заказов, одним шагом: карточка приходит
     не рывком. Длительность и шаг — общие переменные, своих здесь нет. */
  animation: rise var(--calm) var(--ease) both;
  animation-delay: var(--step);
}
.gate__title { font-size: 22px; margin: 0; }
.gate__sub { color: var(--dim); font-size: 13px; margin: -6px 0 0; line-height: 1.5; }
.gate__field { display: flex; flex-direction: column; gap: 6px; }
.gate__field span { color: var(--dim); font-size: 13px; }
.gate__field input {
  background: var(--sunk);
  border: 1px solid var(--edge);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font: inherit;
  padding: 10px 12px;
  transition: border-color var(--fast) var(--ease);
}
.gate__field input:focus {
  outline: none;
  border-color: var(--accent-deep);
}
.gate__go {
  background: var(--accent-deep);
  border: 1px solid var(--accent-deep);
  border-radius: var(--radius-sm);
  color: #fff;
  cursor: pointer;
  font: inherit;
  font-weight: 500;
  padding: 11px 14px;
  transition: background var(--fast) var(--ease);
}
.gate__go:hover { background: var(--accent); border-color: var(--accent); }

/* Отказ красится цветом статуса «вне нормы» — тем же, которым в
   документе помечено отклонение. Второй красный кабинет не заводит. */
.gate__error {
  margin: 0;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid color-mix(in oklab, var(--colors-status-out) 55%, var(--edge));
  background: color-mix(in oklab, var(--colors-status-out) 12%, var(--sunk));
  color: var(--ink);
  font-size: 13px;
}
.gate__hint {
  margin: 0;
  color: var(--dim);
  font-size: 12px;
  line-height: 1.6;
  border-top: 1px solid var(--line);
  padding-top: 14px;
}
.gate__hint code {
  display: block;
  margin-top: 6px;
  color: var(--ink);
  font-size: 11px;
  word-break: break-all;
}

/* ------------------------------------------------------------ форма заказа */

.form {
  max-width: 660px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px;
  box-shadow: var(--shadow-soft);
  animation: rise var(--calm) var(--ease) both;
}
.form__row { display: flex; flex-direction: column; gap: 6px; }
.form__row--pair { flex-direction: row; gap: var(--gap); }
.form__row--pair > * { flex: 1; }

/* Подпись под полем объясняет, ЧТО с ним будет: поле, про которое
   человек не знает, что оно сверяется с документами, он заполнит
   наугад. Это не подсказка по вёрстке, а часть требования фазы. */
.gate__field small {
  color: var(--dim);
  font-size: 12px;
  line-height: 1.5;
}
.gate__field select {
  background: var(--sunk);
  border: 1px solid var(--edge);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font: inherit;
  padding: 10px 12px;
}
.gate__field input[type="file"] { padding: 9px 12px; color: var(--dim); }

.form__actions {
  display: flex;
  align-items: center;
  gap: 12px;
  justify-content: flex-end;
  border-top: 1px solid var(--line);
  padding-top: 18px;
}
.btn-quiet {
  color: var(--dim);
  padding: 11px 14px;
  border-radius: var(--radius-sm);
}
.btn-quiet:hover { color: var(--ink); background: var(--sunk); text-decoration: none; }

.lede { color: var(--dim); margin: 6px 0 0; max-width: 60ch; line-height: 1.6; }

/* ------------------------------------------------------- экран заказа */

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px 24px;
  margin-bottom: var(--gap);
  animation: rise var(--calm) var(--ease) both;
}
.panel h2 { font-size: 17px; margin: 0 0 14px; }
.order-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

/* Блокирующее — первым экраном и цветом «вне нормы» из tokens.yaml.
   Второго красного кабинет не заводит. */
.blocking,
.unsure,
.unchecked {
  border-radius: var(--radius);
  padding: 20px 24px;
  margin-bottom: var(--gap);
  border: 1px solid;
  animation: rise var(--calm) var(--ease) both;
}
.blocking {
  border-color: color-mix(in oklab, var(--colors-status-out) 60%, var(--edge));
  background: color-mix(in oklab, var(--colors-status-out) 12%, var(--panel));
}
/* «Не проверено» — НЕ красное и НЕ зелёное: это не находка и не её
   отсутствие. Цвет «требует внимания» из той же палитры. */
.unchecked {
  border-color: color-mix(in oklab, var(--colors-status-attention) 55%, var(--edge));
  background: color-mix(in oklab, var(--colors-status-attention) 10%, var(--panel));
}
/* «Здесь я не уверен» — цвет внимания, как у «не проверено», но полоса
   заметнее: этот раздел ЗАМЕНИЛ красный баннер запрета (решение владельца
   5 ноября), и если он потеряется среди панелей, снятие стопа станет
   снятием проверки — риск Р-б плана
   `plans/2026-11-05-pravka-rezultata-vmesto-blokirovki.md`.

   Отдельный класс, а НЕ `.unchecked`: с общим классом проверка «раздел
   „не проверено“ нарисован» прошла бы вхолостую — на экране всегда был
   бы класс от этого раздела. Поймано ревью 5 ноября. */
.unsure {
  border-color: color-mix(in oklab, var(--colors-status-attention) 70%, var(--edge));
  background: color-mix(in oklab, var(--colors-status-attention) 14%, var(--panel));
  border-left-width: 4px;
}
.blocking h2, .unsure h2, .unchecked h2 { margin: 0 0 10px; font-size: 17px; }
.blocking h3, .unsure h3 { margin: 14px 0 6px; font-size: 14px; color: var(--dim); }
.blocking ul, .unsure ul, .unchecked ul { margin: 0; padding-left: 20px; line-height: 1.7; }

.block { border-top: 1px solid var(--line); padding: 10px 0; }
.block summary {
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  list-style: none;
}
.block summary::-webkit-details-marker { display: none; }
.block summary::before { content: "▸ "; color: var(--dim); }
.block[open] summary::before { content: "▾ "; }
.block ul { margin: 10px 0 4px; padding-left: 26px; line-height: 1.7; }
.block--stop summary { color: var(--colors-status-out); font-weight: 500; }
/* Блок, который ПРОСИТ взгляда, помечен и в общем списке — парно к
   `block--stop`: оператор листает тринадцать блоков и должен видеть,
   какой из них его ждёт, а не только вспоминать баннер наверху. */
.block--check summary { color: var(--colors-status-attention); font-weight: 500; }
.block p.lede { margin: 8px 0 4px 20px; font-size: 13px; }

.facts { display: flex; gap: 20px; flex-wrap: wrap; color: var(--dim); font-size: 13px; }
.facts b { color: var(--ink); font-size: 15px; }
.dots { display: flex; align-items: center; gap: 8px; margin-top: 14px; }
.dots .num { margin-right: 10px; }

.files, .history { margin: 0; padding-left: 20px; line-height: 1.8; }
.history { color: var(--dim); font-size: 13px; }
.history b { color: var(--ink); }
.notes {
  white-space: pre-wrap;
  background: var(--sunk);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  margin: 14px 0 0;
  font-size: 12px;
  color: var(--dim);
}
.upload { display: flex; gap: 10px; align-items: center; margin-top: 16px; }
.preview {
  width: 100%;
  height: 620px;
  margin-top: 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--sunk);
}

/* ------------------------------------------------------------ узкий экран */

@media (max-width: 720px) {
  main { padding: 22px 14px 48px; }
  .site-head__in { gap: 14px; flex-wrap: wrap; }
  .nav { margin-left: 0; width: 100%; overflow-x: auto; }
  .who { margin-left: 0; padding-left: 0; border-left: none; }
  .page-head { flex-direction: column; align-items: flex-start; gap: 12px; }
  .page-head__actions { margin-left: 0; }
  .tiles { grid-template-columns: 1fr; }
  .gate { min-height: auto; }
  .gate__card { padding: 24px; }
  h1 { font-size: 25px; }
}

/* ── Экран правки ──────────────────────────────────────────────────────
   Таблица строк Атласа. Порядок строк задаёт сборка, оформление здесь
   только отделяет строку от строки: оператор сверяет экран с документом,
   и чем ближе вид к листу, тем меньше ошибок переноса. */
.rows { width: 100%; border-collapse: collapse; }
.rows td { border-top: 1px solid var(--line); padding: 10px 8px; vertical-align: top; }
.rows__dot { width: 24px; padding-top: 14px; }
.rows__act { width: 46%; }
.rows__form { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.rows__form input[type="text"] { flex: 1 1 180px; min-width: 140px; }
.rows__form select { min-width: 110px; }
/* Снятая строка видна, но приглушена: её в документе нет, а вернуть её
   можно только отсюда. */
.row--hidden { opacity: 0.6; }
.row--hidden b { text-decoration: line-through; }
/* Цвет, поставленный человеком, назван прямо на строке: иначе он
   неотличим от посчитанного правилом. */
.lede--human { color: var(--colors-status-attention); }

/* Выданный Атлас: факт, который важнее любого баннера — документ уже
   у пациента. Цвет «нормы», потому что это не тревога, а завершение. */
.panel--issued {
  border-color: color-mix(in oklab, var(--colors-status-norm) 55%, var(--edge));
}

/* Поле заключения: врачебная проза бывает на полстраницы, и набирать её
   в одну строку нельзя. Моноширинного шрифта здесь нет намеренно — это
   текст для пациента, а не код. */
.zakl {
  width: 100%;
  font: inherit;
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  padding: 10px 12px;
  resize: vertical;
}
