@import url('/fonts/fonts.css');

/* ── Токены. Всё, что задаёт вид системы, живёт здесь.
      Дизайн будет правиться — перекраска должна быть правкой этих значений,
      а не обходом разметки. Значения сняты с resedaodor.com. ── */
:root {
  --ink:      #2B2829;   /* фирменный тёплый почти-чёрный: текст и кнопки */
  --ground:   #FFFFFF;
  --panel:    #F5F5F5;   /* вторичная поверхность — тот же тон, что канва */
  --panel-2:  #FAFAFA;
  --ink-2:    #4A4A4A;
  /* #9D9C9C давал на белом контраст 2.7:1 — ниже порога WCAG AA (4.5:1),
     а этим цветом набраны все подписи, даты и пояснения. #767676 — минимальный
     серый, который порог проходит. Раздел 3.6 спеки обещает доступность,
     и обещание должно быть правдой. */
  /* ВХ-4: с переходом на канву как фон страницы порог пришлось пересчитать.
     #767676 на белом давал 4.54, но на #F5F5F5 — уже 4.17, ниже AA. #707070 —
     самый светлый серый, проходящий на ОБЕИХ поверхностях: 4.54 на канве,
     4.95 на белом. Присланный документ предлагал #737373 — 4.35 на канве. */
  --muted:    #707070;
  --line:     #E4E3E3;
  --line-2:   #D4D2D2;
  /* ТОЛЬКО тревога: ошибка, просрочено, опасное действие.
     Был #F42C2C — красный с распродажных плашек сайта. На белом он даёт 4.01:1,
     ниже порога AA, а им набраны «просрочено» и счётчик колокольчика — то есть
     ровно то, что обязано прочитаться с первого взгляда. #C42121 проходит порог
     и в обе стороны: и как текст на белом, и как заливка под белым текстом. */
  --accent:   #C42121;
  --accent-bg:#FDECEC;

  --display: 'Jost', 'Futura', 'Century Gothic', sans-serif;
  --body:    'Mulish', 'Segoe UI', system-ui, sans-serif;

  /* Шкала кеглей. До 10.09.2026 размеров было десять штук вразнобой —
     от 10 до 22 px, — и каждый новый экран добавлял свой. Теперь их шесть,
     и «сделать помельче» означает выбрать соседнюю ступень, а не вписать
     число, которого больше нигде нет.

     11 px — нижняя граница. Ниже капслок с трекингом перестаёт читаться,
     а именно им подписаны все разделы системы. Плотность берём отступами. */
  --t-micro: 11px;       /* капслок-подписи, плашки стадий, счётчики */
  --t-sm:    12px;       /* второстепенное: даты, пояснения, кнопки */
  --t-base:  13px;       /* основной текст интерфейса */
  --t-row:   14px;       /* названия строк списка */
  --t-lg:    16px;       /* логотип в панели */
  --t-h2:    20px;       /* заголовок карточки */
  --t-h1:    22px;       /* заголовок экрана */

  /* ВХ-4: радиус определяет иерархию — ровно два значения на всё интерактивное
     и на все контейнеры, третье осталось мелким элементам, которым капсула
     не идёт (флажки, полосы прокрутки). Промежуточных значений не заводить:
     именно из-за них до 10.09.2026 шкала расползлась на десяток чисел. */
  --radius-sm: 6px;      /* флажки и мелкие детали */
  /* Боковой отступ поля. Тем же отступом сдвигается подпись НАД полем,
     иначе она висит левее текста, который подписывает. Раньше величина
     стояла в двух местах числом, и когда поле переехало 13 → 16px
     (скругление резало первую букву), подпись осталась на 13 — форма входа
     разъехалась на 3px и держала так, пока не замерили 14.09.2026. */
  --fld-pad-x: 16px;
  --radius:    18px;     /* кнопки, поля, плашки статусов — капсула */
  --radius-lg: 24px;     /* карточки, панели, колонки доски */

  /* ВХ-4: поверхности тремя слоями — канва под всем, сайдбар на ступень светлее,
     белая карточка сверху. Слои различаются тоном, а не рамками, поэтому
     разделительные линии почти не нужны. */
  --canvas:   #F5F5F5;   /* фон страницы, заливка полей, вторичные кнопки */

  /* Тень карточки: хайрлайн плюс два еле заметных слоя. Задача — отделить
     карточку от канвы, а не изобразить высоту. Драмы тут быть не должно. */
  --shadow-card: 0 0 0 1px rgba(23,23,23,.05),
                 0 1px 3px rgba(0,0,0,.1),
                 0 1px 2px -1px rgba(0,0,0,.1);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  /* ВХ-4: страница стоит на канве, белый остаётся карточкам. До этого было
     наоборот, и карточке нечем было отделиться от фона, кроме рамки. */
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--body);
  font-size: var(--t-row);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--ink); }

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* ── Экраны периметра: вход, восстановление, новый пароль ── */

.auth {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 24px 16px 40px;
  gap: 22px;
}

.mark {
  text-align: center;
  font-family: var(--display);
  font-weight: 400;
  line-height: 1.15;
}
.mark b { display: block; font-size: var(--t-h1); letter-spacing: .24em; font-weight: 400; }
.mark span { display: block; font-size: var(--t-h1); letter-spacing: .24em; color: var(--muted); }

.card {
  width: 100%;
  max-width: 380px;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 26px 24px 24px;
  background: var(--ground);
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.card h1 {
  font-family: var(--display);
  font-weight: 400;
  font-size: var(--t-h2);
  margin: 0;
  text-wrap: balance;
}

.lede { margin: -8px 0 0; font-size: var(--t-base); color: var(--muted); line-height: 1.55; }

.field { display: flex; flex-direction: column; gap: 6px; }

label {
  font-size: var(--t-micro);
  font-weight: 600;
  /* .1em на кегле 11px растаскивает слово так, что оно читается по буквам.
     .07em оставляет капслок капслоком, но слово остаётся словом. */
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--muted);
}

input[type=email],
input[type=password],
input[type=text] {
  font-family: var(--body);
  /* ⚠️ Здесь стояло 15px с комментарием «16 и меньше зум не вызывает».
     Правило ровно обратное: Safari на iPhone увеличивает страницу, когда кегль
     поля МЕНЬШЕ 16px, — и 15px его как раз вызывал. Заведение карточки
     с телефона на выставке названо главным мобильным сценарием, а там каждое
     касание поля дёргало страницу. Зум лечится правилом для узких экранов
     (16px, см. ниже), а здесь размер возвращается на шкалу: 15px не был
     ни ступенью, ни защитой — он просто ни с чем не совпадал. */
  font-size: var(--t-row);
  color: var(--ink);
  background: var(--ground);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  padding: 10px 12px;
  width: 100%;
}
input:focus { outline: none; border-color: var(--ink); }

.check {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--t-base);
  color: var(--ink-2);
}
.check input { width: 15px; height: 15px; accent-color: var(--ink); margin: 0; }
.check label {
  font-size: var(--t-base); font-weight: 400; letter-spacing: 0;
  text-transform: none; color: var(--ink-2);
}

.btn {
  font-family: var(--body);
  font-size: var(--t-sm);
  font-weight: 600;
  letter-spacing: .048em;       /* трекинг кнопок с сайта */
  text-transform: uppercase;
  padding: 11px 18px;
  border: 1px solid var(--ink);
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--ground);
  cursor: pointer;
  width: 100%;
}
.btn:hover { opacity: .88; }

/* ⚠️ Заголовок и нижняя ссылка выравниваются по ТЕКСТУ полей, а не по краю
   карточки. Поле — капсула: его текст отступает внутрь на --fld-pad-x,
   и подпись над полем сдвинута туда же (см. правило подписей). Пока «Вход»
   и «Забыли пароль?» стояли у самого края, в карточке жили ДВЕ текстовые
   колонки в 16px друг от друга — замер 14.09.2026 на 491px: 80.4 против 96.4.
   Именно это читается как «всё съехало в разные стороны» (замечание Виталия).
   Коробки при этом остаются на своём краю: поля, кнопка и флажок — 80.4.
   То есть колонок ровно две и каждая выключена по своему признаку —
   рамки по рамкам, текст по тексту. */
.auth .card > h1,
.auth .card > .links { padding-left: var(--fld-pad-x); }

.links {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: var(--t-base);
  padding-top: 2px;
}
.links a { color: var(--ink-2); text-decoration: none; border-bottom: 1px solid var(--line-2); }
.links a:hover { color: var(--ink); border-bottom-color: var(--ink); }

/* Сообщения. Красный только для ошибки — это тревога, а не украшение. */
.msg {
  font-size: var(--t-base);
  line-height: 1.55;
  padding: 10px 12px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--ink-2);
}
.msg.err { border-color: var(--accent); background: var(--accent-bg); color: var(--accent); }

.foot { font-size: var(--t-sm); color: var(--muted); text-align: center; }

@media (max-width: 420px) {
  .auth { justify-content: flex-start; padding-top: 40px; }
  .card { border: 0; padding: 0; }
}

@media (prefers-reduced-motion: reduce) {
  /* ⚠️ С псевдоэлементами: стрелки summary::after и подобные анимировались
     в обход `*`. Колесо времени тоже становится плоским списком — это
     и есть нужное поведение, исключений не требуется. */
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

/* ════════════════════════════════════════════════════════════════════
   Оболочка приложения
   ════════════════════════════════════════════════════════════════════ */

.app { display: grid; grid-template-columns: 214px 1fr; min-height: 100vh; }

/* ⚠️ Свёрнутая панель убирается из СЕТКИ целиком, а не сдвигом (ВХ-16):
   `transform` увёл бы её за край, но место в раскладке осталось бы занятым,
   и доска не стала бы шире — то есть ради чего всё и затевалось.

   ⚠️ Дорожка при этом ОДНА, а не «0 и остальное». С двумя дорожками скрытая
   панель перестаёт быть элементом сетки, и основная область съезжает в первую
   дорожку — то есть в нулевую ширину. Замер показал `main: 0px` при дорожках
   «0px 1267px»: экран выглядел пустым. */
.app.rail-off { grid-template-columns: 1fr; }
.app.rail-off .rail { display: none; }

/* Кнопка стоит поверх содержимого, у самого края: внутри панели она исчезала бы
   вместе с ней. Полупрозрачный фон нужен, чтобы она читалась и на белом,
   и на канве — под ней бывает и то, и другое.
   ⚠️ `absolute`, а не `fixed`: приклеенная кнопка при прокрутке длинной
   страницы ложилась поверх текста (замечание Виталия 01.10.2026). Теперь она
   уезжает вверх вместе с шапкой. */
.rail-toggle {
  position: absolute; top: 12px; left: 12px; z-index: 50;
  width: 30px; height: 30px; padding: 0;
  display: grid; place-items: center;
  background: var(--ground); border: 1px solid var(--line);
  border-radius: var(--radius-sm); cursor: pointer;
  color: var(--ink-2);
}
.rail-toggle:hover { border-color: var(--line-2); color: var(--ink); }
.rail-toggle:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
/* Три полосы — тот же знак, что у ручки перестановки: одна форма на «меню». */
.rail-toggle span {
  width: 14px; height: 10px;
  background: linear-gradient(currentColor 0 1.5px, transparent 1.5px 100%) 0 0 / 100% 4.2px repeat;
}
/* Панель развёрнута — кнопка стоит в её поле, у логотипа; свёрнута — у края
   экрана. Логотип при этом не перекрывается: он ниже. */
.app:not(.rail-off) .rail-toggle { left: 172px; }
/* ⚠️ Свёрнутая панель освобождает место, и кнопка встаёт на него — прямо
   поверх заголовка страницы: на снимке «Клиенты» читалось как «≡иенты».
   Отступ ровно под кнопку: 12 слева + 30 её ширины + 12 зазора. */
.app.rail-off .topbar { padding-left: 54px; }

.rail {
  border-right: 1px solid var(--line);
  background: var(--panel-2);
  display: flex; flex-direction: column;
}
.mark-sm { padding: 20px 20px 18px; border-bottom: 1px solid var(--line); }
.mark-sm b, .mark-sm span {
  display: block; font-family: var(--display); font-weight: 400;
  font-size: var(--t-lg); letter-spacing: .22em; line-height: 1.15;
}
.mark-sm span { color: var(--muted); }

.rail nav { padding: 12px 0; flex: 1; }
.nav-a {
  display: block; padding: 9px 20px; font-size: var(--t-base); color: var(--ink-2);
  text-decoration: none; border-left: 2px solid transparent;
}
.nav-a:hover { background: var(--panel); color: var(--ink); }
/* ⚠️ Именно `="page"`, а не голый `[aria-current]`. Неактивные пункты несут
   `aria-current="false"` — это валидный ARIA и единственный способ вывести
   значение атрибута через `<%=` (сам атрибут строкой EJS экранирует, и он
   превращается в ничто). Голый селектор подсветил бы ВСЕ пункты разом. */
.nav-a[aria-current="page"] {
  border-left-color: var(--ink); color: var(--ink);
  font-weight: 600; background: var(--panel);
}

.whoami {
  padding: 14px 20px; border-top: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 3px;
}
.whoami b { font-size: var(--t-base); }
.whoami span { font-size: var(--t-micro); color: var(--muted); }
.linkish {
  background: none; border: 0; padding: 0; margin-top: 4px;
  font-family: var(--body); font-size: var(--t-sm); color: var(--muted);
  cursor: pointer; text-decoration: underline;
}
.linkish:hover { color: var(--ink); }

.main { min-width: 0; display: flex; flex-direction: column; }

.topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; padding: 12px 22px; border-bottom: 1px solid var(--line); flex-wrap: wrap;
}
.topbar h1 { font-family: var(--display); font-weight: 400; font-size: var(--t-h1); margin: 0; }
.topbar .sub { font-size: var(--t-sm); color: var(--muted); margin-top: 1px; }
.topbar .btn { width: auto; }

/* ⚠️ `flex: 1` и `min-height: 0` — чтобы доска забирала всю высоту, какая
   осталась под шапкой и фильтрами. Без `min-height: 0` гибкий элемент не даёт
   сжать себя ниже содержимого, и вместо прокрутки внутри колонок поехала бы
   вся страница. Нижний отступ убран в ноль: 32 пикселя пустоты под доской —
   это место, которое просили отдать карточкам. */
.body { padding: 14px 22px 0; display: flex; flex-direction: column; gap: 10px;
        flex: 1; min-height: 0; }

/* ── Фильтры ──
   Четыре списка убраны под <details>. Это нативный элемент: он открывается
   и закрывается сам, без строчки JavaScript, и потому не требует ни Alpine,
   ни послаблений в CSP. Раньше пять полей стояли в ряд и вместе с баннером
   и панелью действий отодвигали первую карточку на треть экрана.

   Поиск остаётся снаружи — им пользуются чаще всего. */
.filters { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
/* ⚠️ Второй селектор `input.fld` — не лишний. Выше по файлу стоит
   `input[type=email], input[type=password], input[type=text] { … }`, а это
   (0,1,1) против (0,1,0) у голого класса: точность решает раньше порядка,
   и `.fld` на поле ввода НЕ применялся вовсе. Из-за этого экраны входа
   держали старое оформление даже после того, как класс на них проставили
   (замер 14.09.2026: отступ 12px вместо 16, подпись разъезжалась с полем
   на 4px). `input.fld` уравнивает точность, а дальше побеждает порядок —
   это правило ниже. */
.fld, input.fld {
  font-family: var(--body); font-size: var(--t-base); color: var(--ink);
  /* ВХ-4: поле — слой канвы поверх белой карточки, а не белое в рамке.
     Рамка появляется на фокусе: пока поле не трогают, форму держит тон. */
  background: var(--canvas); border: 1px solid transparent;
  /* ⚠️ Боковой отступ не меньше радиуса. Поле высотой 32px со скруглением 18px
     браузер превращает в капсулу радиусом 16 — при отступе 13px первая буква
     вплотную подходила к дуге и читалась как обрезанная («дорого» в диалоге
     причины отказа, замечание Виталия 14.09.2026). */
  border-radius: var(--radius); padding: 7px var(--fld-pad-x);
}
/* ⚠️ Рамка на фокусе — именно --ink, а не бледная линия. Заливка поля ушла
   в тон канвы (ВХ-4), и если фокус обозначать слабым серым, он теряется
   на этом же сером. SPEC 3.6 обещает, что фокус виден всегда. */
.fld:focus { outline: none; border-color: var(--ink); background: var(--ground); }
.search { flex: 1 1 260px; min-width: 180px; }
/* ⚠️ Нативный <select> остаётся там, где список длинный или живёт вне
   карточки: часовые пояса, роли, фильтры, справочники. Свой выпадающий список
   на полусотне часовых поясов был бы хуже системного — тот умеет прокрутку,
   поиск с клавиатуры и родной вид на телефоне.

   Но закрытый вид выравнивается с остальным интерфейсом: та же заливка,
   тот же радиус, тот же треугольник, что у своих списков и у группы изменений
   в ленте. appearance: none убирает системную стрелку, иначе их было бы две.

   Треугольник нарисован как фон: цвет здесь жёсткий, потому что в data-URI
   переменные CSS не подставляются. Это #707070 — тот же --muted; если менять
   его, придётся поменять и здесь. */
select.fld {
  cursor: pointer; appearance: none; -webkit-appearance: none;
  padding-right: 32px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='7' viewBox='0 0 10 7'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23707070' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
}
select.fld::-ms-expand { display: none; }

.more { position: relative; flex: 0 0 auto; }
.more > summary {
  list-style: none; cursor: pointer; user-select: none;
  font-size: var(--t-sm); font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ink-2); border: 1px solid var(--line-2); border-radius: var(--radius);
  padding: 8px 13px; white-space: nowrap;
}
.more > summary::-webkit-details-marker { display: none; }
.more > summary:hover { background: var(--panel); color: var(--ink); }
.more[open] > summary { border-color: var(--ink); color: var(--ink); }
.more > summary .n {
  display: inline-block; min-width: 16px; margin-left: 6px; padding: 0 4px;
  background: var(--ink); color: var(--ground); border-radius: var(--radius-lg);
  font-size: var(--t-micro); text-align: center;
}

/* Выпадающая панель, а не вставка в поток: раскрытие фильтров не должно
   сдвигать список вниз ровно в тот момент, когда в него смотрят. */
.more-body {
  position: absolute; z-index: 20; top: calc(100% + 6px); right: 0;
  display: grid; grid-template-columns: repeat(2, minmax(170px, 1fr)); gap: 8px;
  padding: 12px; background: var(--ground);
  border: 1px solid var(--line-2); border-radius: var(--radius-lg);
  box-shadow: 0 8px 24px rgba(43, 40, 41, .10);
}
.more-body .fld { width: 100%; }

@media (max-width: 620px) {
  /* На телефоне выпадающая панель во всю ширину экрана и в одну колонку. */
  .more { flex: 1 1 100%; }
  .more > summary { text-align: center; }
  .more-body { left: 0; right: 0; grid-template-columns: 1fr; }
}

/* ── Список ──
   Таблица прокручивается ВНУТРИ своей рамки, а не тащит вбок всю страницу:
   при 1000–1200 px последняя колонка иначе просто обрезалась краем экрана. */
.list { border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden;
         background: var(--ground); box-shadow: var(--shadow-card); }

/* Обёртка нужна только списку клиентов — у него шесть колонок. Экраны
   сотрудников, справочников и журнала обходятся своей шириной, и рамка
   остаётся на самом .list. */
.listwrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius-lg); }
/* 744px — не «примерно», а сумма минимумов сетки:
   32 + 180 + 120 + 132 + 116 + 76 + пять зазоров по 12 + отступы 28.
   Занижение здесь не спасает от прокрутки, а ломает её: список сжимается
   ниже собственного минимума, и последняя колонка вылезает за свою строку. */
.listwrap > .list { min-width: 744px; border: 0; border-radius: 0; }

/* Сетка строки задаётся ОДИН раз, здесь. Раньше она переопределялась ещё
   дважды ниже по файлу — правка вида превращалась в поиск, какое из трёх
   правил победит. */
.row {
  display: grid;
  /* Колонка статуса — 132px, а не «на глаз». Самая широкая плашка,
     «Клиент активен», занимает 129px, и при 124px она вылезала на 5px
     в колонку ответственного. Ошибка тихая: на глаз плашка просто стоит
     чуть ближе к соседу, а ловится измерением. */
  grid-template-columns: 32px minmax(180px, 2.2fr) minmax(120px, 1.2fr) 132px 116px 76px;
  gap: 12px; align-items: center; padding: 8px 14px;
  border-top: 1px solid var(--line); cursor: pointer;
}
.row:first-child { border-top: 0; }
.row:hover { background: var(--panel-2); }
.row.head { background: var(--panel); cursor: default; padding: 7px 14px; }
.row.head:hover { background: var(--panel); }
.row.head > * {
  font-size: var(--t-micro); font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-2);
}
.co-name { font-size: var(--t-row); font-weight: 600; line-height: 1.3; }
.co-meta { font-size: var(--t-sm); color: var(--muted); margin-top: 1px; }
.person { font-size: var(--t-base); line-height: 1.3; }
.person small { display: block; font-size: var(--t-micro); color: var(--muted); }
.owner { font-size: var(--t-sm); color: var(--ink-2); }
.owner.none { color: var(--muted); font-style: italic; }
.touch { font-size: var(--t-sm); color: var(--muted); }
.touch.stale { color: var(--accent); }
.num { font-variant-numeric: tabular-nums; }

/* ── Статусы: пастельные оттенки по движению воронки ──
   Решение Виталия 10.09.2026, отменяет прежнюю шкалу насыщенности. Та была
   монохромной, и «в работе», «КП отправлено», «тест образцов» и «переговоры»
   давали четыре почти одинаковых серых: их приходилось читать, а не различать.

   Цвет здесь не украшение, а направление: холодные оттенки в начале воронки,
   тёплые в переговорах, зелёный в цели. Насыщенность низкая — на белом это
   остаётся сдержанным интерфейсом, а не светофором.

   ⚠️ Тревожный красный (--accent) в шкале НЕ участвует. Он остаётся ровно
   двум вещам: просроченному напоминанию и опасному действию. «Отказ» —
   пыльно-розовый: намёк, что плохо, но это не тревога. Покрасишь частый
   статус в цвет тревоги — и тревога перестанет читаться как тревога.

   Текст плашки — тёмный оттенок её же цвета, не чёрный и не серый: так она
   остаётся единым пятном. Контраст каждой пары считает test_design.js. */
.stage {
  display: inline-block; font-size: var(--t-micro); font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; padding: 3px 8px; border-radius: var(--radius-sm); white-space: nowrap;
  border: 1px solid;
}
/* ⚠️ Цвет статуса объявляется ТРЕМЯ переменными, а не готовыми свойствами.
   Причина — ВХ-8: подсветку колонки-приёмника при переносе решено делать
   её собственным цветом, а он был заперт внутри правил плашки. Второй список
   тех же восьми цветов рядом разошёлся бы с первым при первой же правке.
   Переменные наследуются вниз, поэтому класс статуса можно повесить и на всю
   колонку: сама она ничего не красит, но её потомки видят нужный цвет. */
.stage-new           { --st-bg: var(--ground); --st-line: #C9C6C6; --st-ink: #6E6B6B; }
.stage-in_work       { --st-bg: #E7EEF5; --st-line: #C3D4E4; --st-ink: #2C3E4D; }
.stage-proposal_sent { --st-bg: #ECE9F4; --st-line: #CFC8E2; --st-ink: #3A3250; }
.stage-sampling      { --st-bg: #E4F0EA; --st-line: #C0DCCD; --st-ink: #24402F; }
.stage-negotiation   { --st-bg: #F8EBDF; --st-line: #E5CBAE; --st-ink: #4C3722; }
.stage-active        { --st-bg: #CFE6D8; --st-line: #93BFA5; --st-ink: #1B3A28; }
.stage-refused       { --st-bg: #F4E7E7; --st-line: #DCC3C3; --st-ink: #4A3232; }
.stage-archived      { --st-bg: #F0EFEF; --st-line: #D9D7D7; --st-ink: #6E6B6B; }
/* Значения по умолчанию — для «вход» и «работает» в журналах: у них класса
   статуса нет вовсе, и без запасного варианта плашка осталась бы без цвета. */
.stage, .col-head {
  background: var(--st-bg, var(--ground));
  border-color: var(--st-line, var(--line-2));
  color: var(--st-ink, var(--ink-2));
}
/* ⚠️ Пунктир — особенность «нового», и селектор обязан называть носителей
   рамки поимённо. Голый `.stage-new` цеплял любой элемент с этим классом:
   стоило повесить класс статуса на колонку ради переменных палитры, как она
   получила `border-style: dashed` без заданной ширины — браузер подставил
   `medium`, и вокруг всей колонки появилась пунктирная рамка в три пикселя
   (замечание Виталия 11.09.2026). */
.stage.stage-new, .col-head.stage-new { border-style: dashed; }

/* ⚠️ Журнал входов — не воронка, и «отказ» там означает неудачную попытку
   входа. Раньше он брал .stage-refused, а та осталась спокойной пастелью —
   и неудачный вход не отличался бы от удачного беглым взглядом.
   Вот здесь красный как раз по делу: это ровно то, ради чего журнал ведут. */
.stage-fail { border-color: var(--accent); color: var(--accent); background: var(--accent-bg); }

.empty {
  border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 36px 20px;
  text-align: center; color: var(--muted); display: flex;
  flex-direction: column; align-items: center; gap: 14px;
}
.empty p { margin: 0; font-size: var(--t-row); }
.empty .btn { width: auto; }

.pager {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; font-size: var(--t-sm); color: var(--muted); flex-wrap: wrap;
}
.pages { display: flex; gap: 4px; align-items: center; }
.pg {
  border: 1px solid var(--line-2); background: transparent; color: var(--ink-2);
  border-radius: var(--radius); min-width: 30px; height: 30px; padding: 0 8px; cursor: pointer;
  font-family: var(--body); font-size: var(--t-sm); font-variant-numeric: tabular-nums;
}
.pg[aria-current] { background: var(--ink); border-color: var(--ink); color: var(--ground); font-weight: 700; }
.pg:hover:not([aria-current]) { background: var(--panel); }
.gap { color: var(--muted); padding: 0 2px; }

/* ── Панель карточки ── */
/* Карточка занимает ~70% ширины и не касается краёв экрана (правка Виталия
   10.09.2026). Отступ по кругу и скругление делают её отдельным предметом
   поверх страницы, а не вторым экраном: видно, что под ней остался список,
   и что закрыть её — не то же самое, что уйти со страницы. */
.scrim {
  position: fixed; inset: 0; background: rgba(43, 40, 41, .42);
  display: flex; justify-content: flex-end; align-items: center;
  padding: 22px; z-index: 50;
}
/* ⚠️ Прокручивается ТЕЛО карточки, а не сама карточка (правка Виталия
   15.09.2026). Пока прокрутка стояла здесь, полоса рисовалась по прямоугольнику
   и вылезала за скруглённый угол — у верхнего правого края торчал её кончик.
   Скругление режет содержимое только при `overflow: hidden` на самой карточке;
   тогда полоса уходит внутрь, к телу, и упирается в его прямые края.
   Та же причина и то же лечение, что у колонок доски 11.09.2026. */
/* ── Высота на iOS: dvh, а не vh ──
   ⚠️ `100vh` в Safari на телефоне — это высота БЕЗ панелей браузера, то есть
   БОЛЬШЕ видимой области примерно на высоту адресной строки с панелью кнопок.
   Карточка, ограниченная `calc(100vh - 20px)`, оказывалась выше экрана,
   а `.scrim` центрирует её по вертикали — и лишнее делилось поровну сверху
   и снизу: шапка с крестиком уезжала за верхний край, и закрыть карточку
   было нечем. Замечание Виталия 14.09.2026: «прокручиваешь — крестик
   скрывается».

   Лечится вторым объявлением с `dvh` («динамическая» высота, она и есть
   видимая). Порядок обязателен: браузер, который про `dvh` не знает,
   отбрасывает вторую строку и остаётся на первой. `@supports` не нужен.

   ⚠️ `min-height: 100vh` у страницы и у `.app` НЕ трогаем: там больше —
   безопаснее, содержимое просто прокручивается. Вред даёт только верхняя
   граница: она прячет то, что не поместилось. */
.sheet {
  width: min(70vw, 980px); background: var(--ground);
  height: auto; max-height: calc(100vh - 44px); max-height: calc(100dvh - 44px);
  overflow: hidden; border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  display: flex; flex-direction: column;
}
/* Шапка больше не липкая: она и так стоит вне прокрутки — крестик виден всегда,
   куда бы ни прокрутили ленту. */
.sheet-top {
  padding: 15px 20px 13px; border-bottom: 1px solid var(--line);
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  background: var(--ground); flex-shrink: 0;
}
.sheet-top h2 { font-family: var(--display); font-weight: 400; font-size: var(--t-h2); margin: 0 0 6px; }
.tags { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.eyebrow {
  font-size: var(--t-micro); font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted);
}
.x {
  border: 0; background: transparent; color: var(--muted);
  font-size: var(--t-h1); line-height: 1; cursor: pointer; padding: 2px 6px;
}
.x:hover { color: var(--ink); }
.x.sm { font-size: var(--t-lg); margin-left: auto; }

/* Зазор между блоками уменьшен вместе с отступами строк: между «Реквизитами»
   и «Напоминанием» стояло 30px пустоты (16 зазора плюс 14 отступа блока). */
/* `min-height: 0` обязателен: без него flex-элемент не даёт сжать себя ниже
   содержимого, и прокрутка не появляется вовсе — карточка просто вырастает
   за экран. Те же грабли, что у тела колонки на доске. */
.sheet-body {
  padding: 0 20px 22px; display: flex; flex-direction: column; gap: 11px;
  overflow-y: auto; flex: 1; min-height: 0;
}
.block {
  display: flex; flex-direction: column; gap: 6px;
  padding-top: 10px; border-top: 1px solid var(--line);
}
.block:first-child { border-top: 0; }

.kv { display: grid; grid-template-columns: 118px 1fr; gap: 5px 14px; font-size: var(--t-base); margin: 0; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; }

.acts { display: flex; gap: 8px; flex-wrap: wrap; }
.acts.end { justify-content: flex-end; padding-top: 8px; }
.btn-sm { padding: 7px 13px; font-size: var(--t-micro); width: auto; }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line-2); }
.btn-ghost:hover { background: var(--panel); opacity: 1; }
.btn-danger { background: transparent; color: var(--accent); border-color: var(--accent); }
.btn-danger:hover { background: var(--accent-bg); opacity: 1; }

.people { display: flex; flex-direction: column; }
.people div {
  display: flex; align-items: baseline; gap: 12px;
  padding: 8px 0; border-top: 1px solid var(--line); font-size: var(--t-base);
}
.people div:first-child { border-top: 0; }
.people small { display: block; font-size: var(--t-micro); color: var(--muted); margin-top: 1px; }

/* ── Кнопка «+», раскрывающая форму ──
   Тот же приём, что у фильтров: <details> вместо всегда открытой формы.
   Здесь причина в другом — карточку открывают десятки раз в день,
   а нового человека заводят изредка, и три пустых поля под каждым списком
   контактов просто шумят. */
.adder > summary {
  list-style: none; cursor: pointer; user-select: none; width: fit-content;
  font-size: var(--t-micro); font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; color: var(--ink-2);
  border: 1px solid var(--line-2); border-radius: var(--radius);
  padding: 6px 12px;
}
.adder > summary::-webkit-details-marker { display: none; }
.adder > summary:hover { background: var(--panel); color: var(--ink); }
.adder[open] > summary { border-color: var(--ink); color: var(--ink); margin-bottom: 9px; }
.adder > summary span { font-size: var(--t-base); line-height: 1; }

.inline-form { display: flex; gap: 6px; flex-wrap: wrap; }
/* Воздух вокруг строки «добавить»: вплотную к таблице над ней и к низу
   страницы она читалась продолжением списка (правка Виталия 01.10.2026). */
.inline-form { margin: 12px 0 24px; }
.inline-form .fld { flex: 1 1 100px; min-width: 0; }
.inline-form .btn { width: auto; }

.field { display: flex; flex-direction: column; gap: 6px; }
.field .fld { width: 100%; }
.two { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.dim { font-size: var(--t-sm); color: var(--muted); margin: 0; }

.composer { display: flex; flex-direction: column; gap: 8px; }
.composer textarea {
  font-family: var(--body); font-size: var(--t-base); line-height: 1.6; color: var(--ink);
  background: var(--panel-2); border: 1px solid var(--line-2);
  border-radius: var(--radius); padding: 10px 12px; resize: vertical; width: 100%;
}
.composer textarea:focus { outline: none; border-color: var(--ink); background: var(--ground); }
.row-end { display: flex; justify-content: flex-end; }
.row-end .btn { width: auto; }

.feed { display: flex; flex-direction: column; }
/* Лента — самая длинная часть карточки: замер дал 485px против 304 у реквизитов.
   Отступ записи 12→8 и зазор 4→3 снимают по 8px с каждой, а записей у живой
   карточки десятки. */
.entry { padding: 8px 0; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: 3px; }
.entry:first-child { border-top: 0; }
.entry-top { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.entry-top b { font-size: var(--t-sm); font-weight: 700; }
.entry-top time { font-size: var(--t-micro); color: var(--muted); }
.entry .edited { font-size: var(--t-micro); color: var(--muted); font-style: italic; }
.entry p { margin: 0; font-size: var(--t-base); line-height: 1.45; color: var(--ink-2); white-space: pre-wrap; }
.entry.sys {
  padding-left: 12px; border-left: 2px solid var(--line-2);
  border-top: 0; margin-top: 12px; padding-top: 8px; padding-bottom: 8px;
}
.entry.sys .entry-top b {
  font-weight: 600; color: var(--muted); letter-spacing: .06em;
  text-transform: uppercase; font-size: var(--t-micro);
}
.entry.sys p { font-size: var(--t-sm); }
/* Правило .entry.sys .lock убрано вместе с подписью «не редактируется»
   (ВХ-3): запрет и так виден — у системной записи нет ни кнопки правки,
   ни крестика, ни подчёркивания под курсором. */

/* ── Свёрнутая группа системных записей (ВХ-3) ──
   Подряд идущие служебные отметки схлопываются в одну строку, чтобы карточка
   не превращалась в список, сквозь который каждый раз ищут договорённость. */
.sysgroup { margin-top: 12px; }
.sysgroup > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: flex; align-items: center; gap: 8px;
  padding: 7px 12px; border-left: 2px solid var(--line-2);
  font-size: var(--t-micro); font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted);
}
.sysgroup > summary::-webkit-details-marker { display: none; }
.sysgroup > summary:hover { color: var(--ink-2); }
/* Треугольник рисуется сам и поворачивается при раскрытии: это единственная
   часть, которая обязана сказать, что строка нажимается. */
.sysgroup > summary::after {
  content: ''; width: 6px; height: 6px; margin-top: -3px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg); transition: transform .2s ease;
}
.sysgroup[open] > summary::after { transform: rotate(-135deg); margin-top: 2px; }
.sysgroup[open] > summary { color: var(--ink-2); }
.sysgroup-body .entry.sys { margin-top: 0; }

/* Плавное раскрытие — сдвигом содержимого, и только сдвигом.
   ⚠️ ЭТО ОГРАНИЧЕНИЕ НАМЕРЕННОЕ, а не бедность фантазии.

   Канонический современный рецепт — переход height через ::details-content
   и interpolate-size — здесь отвергнут по факту, а не по вкусу: пока страница
   не отрисовывается (фоновая вкладка, свёрнутое окно), браузер не продвигает
   анимации, и такой переход оставляет content-visibility застрявшим в hidden.
   Замерено: высота группы 80px и в закрытом, и в открытом виде — то есть
   содержимое не показывается ВООБЩЕ, хотя атрибут open стоит. То же самое
   случилось с вариантом, анимировавшим opacity: застряв на первом кадре,
   он оставлял записи прозрачными.

   Отсюда правило: анимировать здесь можно только то, чей застывший первый
   кадр не мешает читать. transform на 6 пикселей этому условию отвечает,
   height и opacity — нет. Само раскрытие остаётся нативным и мгновенным,
   оно не зависит ни от одной анимации.

   Побочно объясняет, почему присланный образец на motion/react не подошёл бы
   даже со сборкой: он анимирует записью в атрибут style, а инлайновые стили
   подчиняются style-src-attr, наследующему наш style-src 'self'
   без unsafe-inline (SPEC 2.1.5). */
@keyframes sysgroup-slide {
  from { transform: translateY(-6px); }
  to   { transform: translateY(0); }
}
.sysgroup[open] > .sysgroup-body { animation: sysgroup-slide .22s ease-out; }


.msg.warn { border-color: var(--line-2); background: var(--panel); color: var(--ink-2); }
.msg ul { margin: 6px 0 4px; padding-left: 18px; }

/* ── Телефон ── */
@media (max-width: 900px) {
  .app { grid-template-columns: 1fr; }

  /* ⚠️ Меню ПЕРЕНОСИТСЯ, а не прокручивается вбок. Раньше здесь был
     overflow-x: auto, и у руководителя последние пункты просто уезжали
     за край экрана — снаружи это выглядело как отсутствие раздела.
     Перенос занимает вторую строку, зато не прячет ничего. */
  .rail {
    flex-direction: row; align-items: center; flex-wrap: wrap;
    border-right: 0; border-bottom: 1px solid var(--line);
  }
  /* ⚠️ Логотип и пункты меню приводятся к ОДНОЙ высоте коробки и оба центрируют
     в ней свой текст. Пункты добирают 44px правилом целей нажатия, логотип
     оставался 41px с отступами сверху и снизу — текст в строке расходился
     на 3.5px, и меню читалось как приподнятое (замечание Виталия 15.09.2026).
     Выравнивание по базовой линии тут не помогает: у логотипа свои отступы,
     и базой он считает не то, что видит глаз — замер показал 2px в другую
     сторону. */
  .mark-sm {
    border-bottom: 0; border-right: 1px solid var(--line);
    display: flex; align-items: center; min-height: 44px;
    /* ⚠️ Тот же отступ, что у пунктов меню — величина одна на всю строку.
       Сначала было 14 против 13 у пунктов, и текст логотипа стоял на другой
       вертикали, чем «Клиенты» под ним. Потом 13 у всех перестало помещаться:
       логотип 125 плюс три пункта 257.8 — это 382.8 при экране 375, и меню
       переносилось на вторую строку («почему кнопки съехали? они должны быть
       на уровне с RESEDA CRM», замечание Виталия 14.09.2026). 10px у всех
       дают 358.8 — строка одна, ритм между пунктами по-прежнему единый. */
    padding: 0 10px; flex-shrink: 0;
  }
  .mark-sm b, .mark-sm span { display: inline; font-size: var(--t-base); }
  /* ⚠️ `space-between`: остаток ширины раздаётся между пунктами, а не копится
     хвостом справа от последнего. Хвост не постоянный — он равен тому, что
     осталось, и растёт с экраном: замер 14.09.2026 дал 9.7px на 375,
     24.7 на 390 и 64.7 на 430. Пустое место у правого края читается как
     недоделка («что это за отступ справа от „Ещё“?» — замечание Виталия),
     а равные промежутки — как раскладка. Промежутки при этом остаются
     равными ДРУГ ДРУГУ на любой ширине: 24.9 на 375, 52.4 на 430. */
  .rail nav {
    padding: 0; flex: 1 1 auto;
    display: flex; flex-wrap: wrap; justify-content: space-between;
  }
  .nav-a {
    border-left: 0; border-bottom: 2px solid transparent;
    /* Боковой отступ 10px, а не 13: на 375px логотип и три пункта при 13px
       не помещались в строку. Вертикальный не трогаем — высоту цели нажатия
       держит min-height. */
    white-space: nowrap; padding: 10px;
  }
  .nav-a[aria-current="page"] { border-left: 0; border-bottom-color: var(--ink); }

  /* ── ВХ-21: состав строки меню на телефоне ──
     В строке остаются «Клиенты», «Справочники» и «Ещё» — одинаково у обеих
     ролей. Всё остальное — внутри панели.

     ⚠️ История этого места за один день: сначала `.whoami` гасился здесь
     без объяснений, и на телефоне не было ни выхода, ни профиля вообще.
     Их вернули в строку — меню выросло у руководителя до ЧЕТЫРЁХ строк
     (176.8px, 22% экрана до содержимого). Теперь они снова скрыты, но
     разница принципиальная: не «недостижимы», а «на уровень глубже»,
     в панели «Ещё». Проверка достижимости выхода с телефона стоит
     в наборе оформления — без неё это место сломается тихо. */
  /* ⚠️ `.nav-a.nav-wide`, а не `.nav-wide`. Ниже по файлу есть ВТОРОЙ блок
     `max-width: 900px` с правилом `.nav-a { display: inline-flex }` (центровка
     текста в коробке, ВХ-19) — при равной точности побеждает он, и пункты
     оставались видимыми. Ловится только замером: `getComputedStyle` отдавал
     `flex` при написанном `none`. Пятый случай этого капкана за 14.09.2026. */
  .nav-a.nav-wide, .whoami { display: none; }

  .navmore { display: block; position: relative; }
  /* Кнопка набирается ровно как пункт меню рядом: тот же кегль, отступ
     и высота. Иначе она читается вставкой из чужого интерфейса. */
  /* ⚠️ Форму от выпадающего списка снимаем начисто. `.navmore` — это `.sel`,
     а `.sel > summary` даёт заливку канвы и скругление 18px, то есть капсулу.
     Рядом с «Клиенты» и «Справочники», набранными простым текстом, капсула
     читается органом другого рода: «не нужно кнопку „ещё“ выделять другой
     формой» (замечание Виталия 14.09.2026). Остаётся текст того же кегля
     и цвета, что у соседей, и та же нижняя черта для отметки активного.
     Порядок объявлений важен: `border: 0` обнуляет все стороны, поэтому
     нижняя черта задаётся ПОСЛЕ него.

     ⚠️ Селектор `.sel.navmore`, а не `.navmore`. `.sel > summary` объявлен
     НИЖЕ по файлу и при равной точности побеждал: замер отдавал заливку
     канвы и скругление 18px при написанных `none` и `0`. Шестой случай этого
     капкана за 14.09.2026 — и снова его показал только замер. */
  .sel.navmore > summary {
    list-style: none; cursor: pointer; white-space: nowrap;
    padding: 10px; min-height: 44px; display: flex; align-items: center;
    font-size: var(--t-base); color: var(--ink-2);
    background: none; border: 0; border-radius: 0;
    border-bottom: 2px solid transparent;
  }
  /* Треугольник остаётся: без него «Ещё» ничем не отличается от ссылки,
     которая уводит на страницу. Но он прижат к слову, а не к краю коробки —
     `margin-left: auto` из общего правила растащил бы их по ширине. */
  .sel.navmore > summary::after { margin: -3px 0 0 6px; }
  .sel.navmore > summary::-webkit-details-marker { display: none; }
  /* ⚠️ Отметка на САМОЙ кнопке, когда активный раздел лежит внутри панели.
     Без неё человек на «Настройках» не видит в строке ни одной подсветки,
     и экран выглядит ничьим (ВХ-21, edge case 2). */
  .sel.navmore.here > summary {
    color: var(--ink); font-weight: 600; border-bottom-color: var(--ink);
  }
  /* ⚠️ Панель раскрывается ВЛЕВО от кнопки. «Ещё» стоит последним пунктом
     строки, то есть у правого края: при раскрытии вправо панель уходила
     за экран на 18px и давала горизонтальную прокрутку всей странице
     (замер 14.09.2026: правый край 393.3 при экране 375). Тот же приём,
     что у списка ответственного и у формы «+ контакт».
     `max-width` страхует случай, когда и влево не хватает. */
  .navmore .sel-body {
    left: auto; right: 0;
    min-width: 200px; max-width: calc(100vw - 20px);
  }
  /* Пункты панели — цели пальца, как и всё в телефонной раскладке. */
  .navmore .sel-opt { min-height: 44px; padding: 5px 12px; }
  /* ⚠️ «Выйти» — кнопка формы, и `aria-current` у неё нет: она никуда
     не ведёт, помечать её нечем. Но отступ под галочку у соседей рисует
     именно правило `[aria-current="false"]::before`, и без него текст кнопки
     начинался на 20px левее остальных пунктов — замер 14.09.2026: 179 против
     199. Пустая заглушка той же ширины ставит её в общий столбец. */
  .sel.navmore .sel-opt:not([aria-current])::before {
    content: ''; width: 12px; flex-shrink: 0;
  }


  .body { padding: 12px 14px 32px; }
  .topbar { padding: 11px 14px; }

  /* ⚠️ 16px — не вкус, а порог: Safari на iPhone увеличивает страницу,
     когда кегль поля меньше шестнадцати. Касание любого поля в форме
     заведения карточки уводило масштаб, и дальше приходилось отъезжать
     руками. Касается всех полей ввода, включая списки и текстовую область. */
  input[type=email], input[type=password], input[type=text],
  input[type=search], input[type=tel], input[type=datetime-local],
  select, textarea, .fld, .composer textarea { font-size: 16px; }

  .two { grid-template-columns: 1fr; }
  .sheet { border-left: 0; }

  /* ── Цели нажатия ──
     SPEC 3.5 обещает не меньше 44px, и до 10.09.2026 обещание не выполнялось:
     кнопки были 28–30, переключатель 32, колокольчик 36, крестик 25×26.
     Промах пальцем — это не эстетика: человек жмёт второй раз, а на карточке
     вторым нажатием можно попасть в соседнюю строку и открыть чужого клиента.

     Крестики остаются мелкими на вид — растёт только зона нажатия. */
  .btn, .btn-sm, .view-a, .pg, .nav-a, .col-more,
  .fld, select.fld, .more > summary, .adder > summary { min-height: 44px; }
  /* ⚠️ Коробке добрали высоту, а содержимое осталось у верхней грани: summary —
     блочный элемент, min-height растит коробку и не двигает текст. «+ контакт»
     читался приклеенным к верху собственной рамки (замечание Виталия
     14.09.2026). Горизонтально ничего не меняется: у .adder ширина по
     содержимому. */
  .more > summary, .adder > summary { display: flex; align-items: center; }
  /* Флажок остаётся мелким квадратиком, но нажимается вся метка целиком.
     Замер поймал 321×18: сама галочка 15px, и промах пальцем по списку
     «Колонки» означал попадание в соседнюю строку. */
  .check { min-height: 44px; align-items: center; }
  /* Там, где подпись — отдельный <label> рядом с флажком (вход, «Не выходить
     30 дней»), высота ряда сама по себе ничего не нажимает: пустое место ряда
     мимо и галочки, и подписи. Подпись растянута на весь ряд — замер
     30.09.2026 нашёл её 134×20. */
  .check > label { min-height: 44px; display: flex; align-items: center; flex: 1; }
  /* ⚠️ На телефоне форма правки разворачивается на ОБЕ колонки сетки.
     Замер показал причину, которую по внешнему виду не угадать: сама форма
     зажата в 168px — это колонка значений, а не поля узкие. Три поля и две
     кнопки туда не помещаются никак, и каждый орган уезжает на свою строку.
     Обозначение слева остаётся на месте, форма встаёт под ним. */
  .kv dd:has(> .fieldform) { grid-column: 1 / -1; }
  /* ⚠️ `:not([hidden])` обязателен. Правило с классом перебивает атрибут
     `hidden` по специфичности: скрытая кнопка снова становится видимой,
     а `el.hidden` при этом честно отвечает «true» — ошибка не ловится ничем,
     кроме замера геометрии. Наступили дважды: 11.09.2026 на колесе времени
     и 15.09.2026 на кнопке «Сохранить» в напоминании (замер: атрибут стоит,
     display: flex, размер 107×44). */
  .btn:not([hidden]), .btn-sm:not([hidden]), .view-a, .pg, .col-more {
    display: inline-flex; align-items: center; justify-content: center;
  }
  .bell { width: 44px; height: 44px; }
  /* ⚠️ Размер задаётся напрямую, а не набирается отступами. Отступы подбирались
     на глаз и промахивались: замер на 375px давал 43×44 у крестика панели
     и 41×42 у мелкого — обещание 3.5 не выполнялось на 1–3 пикселя, увидеть
     которые нельзя. Ширина кнопки зависит ещё и от кегля символа «×»,
     поэтому арифметика «padding + содержимое» тут ненадёжна по построению. */
  /* Заголовок свёрнутой группы — такая же цель нажатия, как кнопка: замер
     на 375px дал 31px по высоте, то есть обещание 3.5 не выполнялось. */
  .sysgroup > summary { min-height: 44px; }
  .x { min-width: 44px; min-height: 44px; display: inline-flex;
       align-items: center; justify-content: center; padding: 0; }
  .x.sm { min-width: 44px; min-height: 44px; padding: 0; }

  /* Галочка выбора: сам квадратик остаётся мелким, но нажимается вся ячейка. */
  .pick { min-height: 44px; }
  /* ⚠️ Атрибутный селектор добавляет точности: базовое `.pick input`
     (15px) ниже по файлу иначе перебивало телефонные 19px. */
  .pick input[type="checkbox"] { width: 19px; height: 19px; }
}

/* ── Индикатор загрузки HTMX ──
   Свои правила взамен тега <style>, который HTMX вставляет сам:
   строгая CSP такую вставку запрещает (см. meta htmx-config в app-head.ejs). */
.htmx-indicator { opacity: 0; transition: opacity .2s; }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { opacity: 1; }

/* Пока список обновляется, он слегка гаснет — видно, что запрос идёт. */
#rows.htmx-request { opacity: .55; transition: opacity .15s; }

/* Узкая панель для коротких диалогов вроде выбора причины отказа:
   на всю ширину карточки такой вопрос выглядит несоразмерно. */
.sheet.narrow { width: min(420px, 100%); }
.sheet.narrow .sheet-body { padding-bottom: 20px; }

/* ── Карточка рядом со списком, а не поверх него ──
   На широком экране накрывать список затемнением незачем: места хватает обоим,
   и работать со списком, держа карточку открытой, — обычный сценарий
   (сверить два клиента, пройти подряд несколько напоминаний).

   Место освобождает сам список: .main из колонки становится сеткой
   «список | карточка». Шапка растягивается на обе колонки.

   ⚠️ Докуется только карточка (.scrim.dock). Колокольчик и короткие вопросы
   вроде причины отказа остаются накладками при любой ширине: у них ответ
   занимает секунду, и отдавать им треть экрана не за что. */
/* ⚠️ Стыковка — только на СПИСКЕ. `:not(:has(.board))` здесь не украшение:
   без него правила ловили карточку и на доске, `position: static` выкидывал
   её из накладки в обычный поток, и она оказывалась ПОД доской — за пределами
   экрана. Снаружи это выглядит как «карточка не открывается». */
@media (min-width: 1200px) {
  .main:not(:has(.board)):has(#panel .scrim.dock) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) clamp(380px, 30vw, 460px);
    align-items: start;
  }
  .main:not(:has(.board)):has(#panel .scrim.dock) > .topbar { grid-column: 1 / -1; }

  .main:not(:has(.board)) #panel .scrim.dock {
    position: static; background: none; display: block;
    padding: 0; border-left: 1px solid var(--line);
  }
  .main:not(:has(.board)) #panel .scrim.dock .sheet {
    width: 100%; border: 0; border-radius: 0;
    position: sticky; top: 0;
    height: auto; max-height: 100vh; max-height: 100dvh;
  }
}

/* Между 1200 и 1440 карточка забирает столько, что списку остаётся меньше
   его минимальной ширины, и снизу навсегда поселяется горизонтальный ползунок.
   Убираем колонку вместо ползунка: контактное лицо всё равно видно
   в открытой карточке, а прокручивать таблицу вбок при каждом взгляде — нет. */
@media (min-width: 1200px) and (max-width: 1439px) {
  .main:not(:has(.board)):has(#panel .scrim.dock) .row {
    grid-template-columns: 32px minmax(150px, 2fr) 132px 108px 72px;
  }
  .main:not(:has(.board)):has(#panel .scrim.dock) .person,
  .main:not(:has(.board)):has(#panel .scrim.dock) .row.head > :nth-child(3) { display: none; }
  .main:not(:has(.board)):has(#panel .scrim.dock) .listwrap > .list { min-width: 0; }

  /* ⚠️ Явные номера колонок из широкой раскладки здесь ОБЯЗАНЫ смениться.
     Колонок стало пять, а ответственный и касание по-прежнему просились
     в пятую и шестую: шестой не существует, браузер дорисовывал её сам,
     и вся строка съезжала относительно шапки — а плашка статуса попадала
     в колонку на 108px вместо 132px и вылезала на 21px в соседнюю.
     Одна забытая строка правил, и таблица разъезжается на целой ширине экрана. */
  .main:not(:has(.board)):has(#panel .scrim.dock) .rowlink > .st    { grid-column: 3; }
  .main:not(:has(.board)):has(#panel .scrim.dock) .row > .owner     { grid-column: 4; }
  .main:not(:has(.board)):has(#panel .scrim.dock) .rowlink > .touch { grid-column: 5; }
}

/* ── Массовые действия и передача ── */
/* Тонкая строка без рамки и заливки: это подсказка к списку, а не отдельный
   блок, и своей плитой она отодвигала данные вниз. */
.bulkbar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 0 2px; margin-bottom: 8px;
}
.bulkbar .dim { flex: 1; min-width: 160px; }
.bulkbar .btn-sm { padding: 5px 11px; font-size: var(--t-micro); }

@media (max-width: 620px) {
  /* Подсказка съедала две строки над самым списком. Кнопки говорят сами
     за себя, а место на телефоне дороже пояснения. */
  .bulkbar .dim { display: none; }
  .bulkbar { gap: 6px; }
  /* Обе кнопки в одну строку: по строке на кнопку — это две строки над самым
     списком ради действия, которым с телефона пользуются редко. */
  .bulkbar .btn-sm { flex: 1 1 140px; padding: 6px 8px; }

  /* Поля встык по три в ряд обрезают подсказку до «Имя и фами…».
     На телефоне каждое поле занимает строку целиком — заведение сотрудника
     и добавление значения в справочник происходит редко, а гадать,
     что просят ввести, не должно приходиться никогда. */
  .inline-form .fld { flex: 1 1 100%; }
  .inline-form .btn { width: 100%; }
}

.pick { display: flex; align-items: center; justify-content: center; cursor: default; }
.pick input { width: 15px; height: 15px; accent-color: var(--ink); margin: 0; cursor: pointer; }

.owner .req { display: block; font-size: var(--t-micro); color: var(--accent); margin-top: 2px; }

/* .badge удалён 10.09.2026: правило пережило разметку, которая его
   использовала. Счётчик в меню заменил колокольчик (SPEC 2.8), пункт
   «Запросы» убран, а стиль остался висеть — 8 строк, которые при следующей
   правке кто-то стал бы аккуратно поддерживать. */

/* Блок запроса на передачу — первым в карточке и с рамкой,
   чтобы его нельзя было пролистать мимо. */
.block.claim {
  border: 1px solid var(--ink); border-radius: var(--radius-lg);
  padding: 13px 15px; background: var(--panel); margin-top: 4px;
}
.block.claim p { margin: 0; font-size: var(--t-base); }
.block.claim .acts form { display: contents; }

/* Обёртка кликабельной части строки. display:contents оставляет её детей
   в сетке строки, но сама она не охватывает галочку — поэтому клик по галочке
   не открывает карточку, и обходиться без JavaScript в атрибутах получается. */
.rowlink { display: contents; cursor: pointer; }

/* ⚠️ Место каждой ячейки в сетке задано ЯВНО.
   Ответственный лежит вне .rowlink (иначе выбор в списке заодно открывал бы
   карточку), то есть порядок в разметке больше не совпадает с порядком колонок.
   Автоматическая раскладка расставила бы ячейки по порядку следования
   и увела ответственного в конец строки. */
.row > .pick        { grid-column: 1; }
.rowlink > :first-child { grid-column: 2; }
.rowlink > .person  { grid-column: 3; }
.rowlink > .st      { grid-column: 4; }
.row > .owner       { grid-column: 5; }
.rowlink > .touch   { grid-column: 6; }

/* Список ответственного в строке: у руководителя это рабочий орган, поэтому
   он не должен выглядеть тяжелее данных вокруг. Рамка появляется по наведению. */
.owner-sel {
  width: 100%; max-width: 100%; padding: 4px 6px; font-size: var(--t-sm);
  border-color: transparent; background: transparent; color: var(--ink-2);
}
.owner-sel:hover { border-color: var(--line-2); background: var(--ground); }
.owner-sel:focus { border-color: var(--ink); background: var(--ground); }

/* ── Телефон: правила строки после появления обёртки .rowlink ──
   Прежние селекторы вида «.row > .person» перестали совпадать: элементы
   теперь дети .rowlink, а не строки. Обёртка с display:contents участвует
   в сетке своими детьми, поэтому размещаем именно их. */
@media (max-width: 900px) {
  /* Прокрутка таблицы вбок нужна только там, где колонки не помещаются.
     На телефоне строка перестраивается в два яруса, и минимальная ширина
     обернулась бы вечным горизонтальным ползунком. */
  .listwrap { overflow-x: visible; }
  .listwrap > .list { min-width: 0; }

  .row {
    grid-template-columns: 28px 1fr auto;
    align-items: start;
    gap: 4px 10px;
  }
  .row.head { display: none; }

  /* Явные колонки широкой раскладки здесь только мешают: сетка другая,
     и ячейка с grid-column: 5 уехала бы в несуществующую колонку. */
  .row > *, .rowlink > * { grid-column: auto; }

  /* ⚠️ Только внутри строки списка. Здесь `.pick` — это КОЛОНКА С ФЛАЖКОМ
     массовых действий, а не выпадающий список. С ВХ-13 класс `pick` носит
     ещё и свой `<details>` (`partials/pick.ejs`), и без ограничения строкой
     правило ставило в ячейку 1/1 ВСЕ списки подряд: на телефоне четыре фильтра
     ложились друг на друга, и в панели было видно один — последний
     нарисованный. Замер 14.09.2026: у всех четырёх `grid-area: 1 / 1 / span 2`,
     одинаковые координаты. Замечание Виталия: «открываешь фильтры, а там одно
     значение».
     ⚠️ Само имя класса занято дважды — это ловушка, а не опечатка. Следующий
     `.pick` без области видимости выстрелит так же. */
  .row .pick, .rowlink .pick { grid-column: 1; grid-row: 1 / span 2; padding-top: 2px; }

  /* Компания — первая строка, стадия — вторая, касание — справа сверху. */
  .rowlink > div:nth-child(1) { grid-column: 2; grid-row: 1; min-width: 0; }
  .rowlink > div:nth-child(3) { grid-column: 2; grid-row: 2; }
  .row .touch { grid-column: 3; grid-row: 1; text-align: right; }

  /* Контактное лицо и ответственный на узком экране не помещаются —
     они видны в карточке. */
  .row .person, .row .owner { display: none; }
}

/* ── Напоминания, колокольчик, профиль ── */
.topbar-actions { display: flex; align-items: center; gap: 10px; }

.bell {
  position: relative; border: 1px solid var(--line-2); background: transparent;
  border-radius: var(--radius); width: 36px; height: 36px; cursor: pointer;
  color: var(--ink); display: grid; place-items: center; flex-shrink: 0;
}
.bell:hover { background: var(--panel); }
.bell .dot {
  position: absolute; top: -6px; right: -6px; min-width: 18px; height: 18px;
  padding: 0 5px; background: var(--accent); color: #fff; border-radius: 999px;
  font-size: var(--t-micro); font-weight: 700; display: grid; place-items: center;
}


.ticks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.ticks li {
  display: grid; grid-template-columns: 130px 1fr; gap: 12px; align-items: baseline;
  padding: 9px 0; border-top: 1px solid var(--line); cursor: pointer;
}
.ticks li:first-child { border-top: 0; }
.ticks li:hover b { text-decoration: underline; }
.ticks time { font-size: var(--t-sm); color: var(--muted); }
.ticks time.late { color: var(--accent); font-weight: 700; }
.ticks b { font-size: var(--t-base); }
.ticks small { display: block; font-size: var(--t-micro); color: var(--muted); margin-top: 1px; }

.narrow-body { max-width: 560px; }
.stack { display: flex; flex-direction: column; gap: 12px; }
.whoami a { text-decoration: none; }
.whoami a:hover b { text-decoration: underline; }

@media (max-width: 900px) {
  .ticks li { grid-template-columns: 1fr; gap: 2px; }
}

/* Компактное время помещается в узкую колонку одной строкой. */
.ticks li { grid-template-columns: 92px 1fr; }
.ticks time { white-space: nowrap; }
@media (max-width: 900px) {
  .ticks li { grid-template-columns: 1fr; }
}

/* ── Экраны администрирования ── */
/* ⚠️ Последняя колонка — ФИКСИРОВАННОЙ ширины, не auto.
   С `auto` ширина считается по содержимому строки, а содержимое разное:
   у заголовка там пусто (0 px), у строки сотрудника две кнопки (236 px).
   Колонки заголовка и данных расходились, и подписи стояли над чужими
   значениями — «Роль» над поясом, «Пояс» над числом карточек. В справочниках
   та же беда сдвигала строку в зависимости от того, есть ли у значения
   кнопка «Удалить». Снаружи это выглядит просто как кривая таблица. */
.urow { grid-template-columns: minmax(180px,2fr) 120px 150px 80px 110px 250px; }
.drow { grid-template-columns: 34px minmax(160px,2fr) 110px 90px 120px; align-items: center; }
/* ⚠️ Флажок без видимой подписи должен остаться кликабельным не только
   по самому квадратику в 15px: подпись держала цель нажатия. Возвращаем её
   отступами у самой метки. */
.dlist .check { padding: 4px 6px; margin: -4px -6px; }

/* У менеджера колонки «Скрыть» нет: править состав он не вправе (ВХ-12). */
.dlist-ro .drow { grid-template-columns: 34px minmax(160px,2fr) 90px 120px; }
.dname { font-size: var(--t-base); color: var(--ink); }

/* ⚠️ Ручка перестановки (ВХ-11). Три полосы, нарисованные фоном, а не значком
   из шрифта: значок пришлось бы тащить файлом ради тридцати пикселей.
   `touch-action: none` — именно здесь и только здесь: на ручке движение пальца
   не может означать ничего, кроме переноса, а прокрутка страницы остаётся
   везде вокруг неё. */
.grip {
  width: 26px; height: 26px; padding: 0; border: 0; border-radius: var(--radius-sm);
  background: transparent; cursor: grab; touch-action: none;
  display: grid; place-items: center;
}
.grip span {
  width: 12px; height: 9px;
  background: linear-gradient(var(--muted) 0 1.5px, transparent 1.5px 100%) 0 0 / 100% 3.7px repeat;
}
.grip:hover { background: var(--canvas); }
.grip:hover span { background-image: linear-gradient(var(--ink-2) 0 1.5px, transparent 1.5px 100%); }
.grip:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }
/* ⚠️ Переносимая строка выходит из потока. Пока она оставалась в нём, каждая
   перестановка сдвигала её собственную точку отсчёта, и строка прыгала
   на высоту соседа (замечание Виталия 14.09.2026). Вне потока точка отсчёта
   неподвижна, и строка едет за указателем, пока его не отпустят.
   `position: fixed` не режется рамкой списка: у него `overflow: hidden`,
   а фиксированный элемент этой обрезке не подчиняется. */
[data-rid].lifting {
  position: fixed; z-index: 40; margin: 0;
  background: var(--ground); border-top: 0;
  box-shadow: 0 10px 24px rgba(20, 18, 18, .16);
  cursor: grabbing; pointer-events: none;
}
[data-rid].lifting .grip { cursor: grabbing; }

/* Место, откуда строку взяли. Ничего не рисует — только держит высоту,
   иначе список схлопывается и соседи прыгают вверх. */
.ph-row { box-sizing: border-box; }

/* Справочники — короткие слова: «аптека», «врач». Во всю ширину монитора
   поле ввода растягивается на 660 px под одно слово. */
/* Заголовок раздела справочника. На мониторе это просто подпись: столбцы
   там объясняет шапка таблицы, и вторая подпись была бы повтором. */
.dhead { display: flex; align-items: center; justify-content: space-between; }
.dhead-hide { display: none; }

.dlist { max-width: 820px; }
.lrow { grid-template-columns: 150px minmax(160px,1.4fr) 90px 120px 1fr; }
.row.off { opacity: .55; }
.row .acts form { display: contents; }
.urow .acts, .drow .acts { display: flex; gap: 6px; flex-wrap: wrap; }

.link-box {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: var(--t-sm); word-break: break-all; background: var(--ground);
  border: 1px solid var(--line-2); border-radius: var(--radius);
  padding: 8px 10px; margin: 6px 0;
}
.ua { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.check span { font-size: var(--t-sm); color: var(--ink-2); }

@media (max-width: 900px) {
  .urow, .drow, .lrow { grid-template-columns: 1fr; gap: 6px; }
  /* ⚠️ Слово «скрыто» у каждой строки НЕ показываем (правка Виталия
     14.09.2026): повторённое пятнадцать раз подряд, оно занимает больше места,
     чем сами значения, и читается шумом. Подпись теперь одна — в шапке списка,
     над столбцом флажков (см. ниже). В разметке слово остаётся: это имя
     флажка для читалки экрана, и без него галочка безымянная. */
  /* На телефоне строки идут в столбик, и ручка стоит первой — цель нажатия
     добирается до 44px, как и всё остальное (SPEC 3.6). */
  .grip { width: 44px; height: 44px; }
  .row.head.urow, .row.head.drow, .row.head.lrow { display: none; }

  /* ⚠️ Подпись столбца флажков стоит В СТРОКЕ ЗАГОЛОВКА раздела (`.dhead`),
     а не отдельной плашкой над списком: плашку сделали и отвергли
     14.09.2026 — целая полоса ради одного слова. Сетка у заголовка та же,
     что у строк, поэтому подпись встаёт над своим столбцом по построению.

     ⚠️ Боковой отступ — 15px: 14px отступа строки плюс 1px рамки списка.
     Заголовок лежит СНАРУЖИ списка, и без поправки на рамку его дорожки
     считаются от ширины на 2px больше, чем у строк. Замер 14.09.2026:
     расхождение подписи с флажком было 10px, пока отступы не сошлись. */
  /* ⚠️ Дорожки — те же, что у строки руководителя ниже (44 / 1fr / 44):
     подпись «скрыть» есть только у него. Когда строка теряла четвёртую
     дорожку (счётчик ушёл под название, 30.09.2026), эта сетка осталась
     прежней, и подпись съехала с флажков на 84px. Меняются только вместе. */
  .dhead {
    display: grid;
    grid-template-columns: 44px minmax(0, 1fr) 44px;
    gap: 4px 8px; align-items: center; padding: 0 15px;
  }
  .dhead > .eyebrow:first-child { grid-area: 1 / 1 / 2 / 3; }
  .dhead-hide { display: block; grid-area: 1 / 3 / 2 / 4; text-align: center; }

  /* ── Строка справочника: две строки вместо пяти ──
     Замер 14.09.2026: общее правило `grid-template-columns: 1fr` ставило
     в столбик ВСЕ пять элементов — ручку, поле, флажок, счётчик и пустую
     обёртку кнопок, — и строка занимала 164.8px. На 28 значениях это 2473px
     списка и 5429px страницы. Замечание Виталия: «очень всё криво, сделай
     лаконичнее».

     Раскладка: ручка держит обе строки слева, название занимает первую
     целиком, флажок и счётчик делят вторую — счётчик прижат вправо.
     Всё, что читается вместе, стоит рядом; в столбик уходит только то,
     чему не хватает ширины.

     ⚠️ Селектор `.row.drow`, а не `.drow`: общее правило выше в этом же
     блоке имеет ту же точность, и спор решался бы порядком — тем самым
     капканом, на который сегодня наступили пять раз. */
  .row.drow {
    /* Четыре дорожки в ОДНУ строку: ручка, название, флажок, счётчик.
       ⚠️ Последняя задана числом, а не `auto`. Набор проверок запрещает `auto`
       в конце этих сеток: дорожка по содержимому считается для КАЖДОЙ строки
       отдельно, шапка и строки расходятся, и подписи встают над чужими
       значениями. «1234 карт.» занимает 66px, дорожка 76. */
    grid-template-columns: 44px minmax(0, 1fr) 44px 76px;
    align-items: center;
    gap: 4px 8px;
  }
  .drow > .grip  { grid-area: 1 / 1 / 2 / 2; }
  .drow > .fld,
  .drow > .dname { grid-area: 1 / 2 / 2 / 3; }
  /* Флажок — столбец шириной в цель нажатия. Сама галочка остаётся мелкой,
     растёт только зона: 44px по обеим сторонам (SPEC 3.6). */
  /* ⚠️ `margin: 0` обязателен. На мониторе у флажка отрицательный боковой
     отступ (`.dlist .check`, -6px) — им там добирается зона нажатия. Здесь
     зону даёт сам столбец в 44px, а отступ уводил галочку на 6px влево
     из-под своей подписи в шапке (замер 14.09.2026). */
  .drow > .check {
    grid-area: 1 / 3 / 2 / 4;
    justify-content: center; width: 44px; margin: 0;
  }
  .drow > .num   { grid-area: 1 / 4 / 2 / 5; text-align: right; white-space: nowrap; }
  /* Кнопка «Удалить» есть только у неиспользуемого значения — у остальных
     обёртка пустая. Пустая ячейка сетки всё равно забирает зазор, поэтому
     её убираем совсем, а не оставляем нулевой высоты. */
  /* ⚠️ `:has(button)`, а не `:empty`. Обёртка кнопок всегда содержит перенос
     строки из шаблона, поэтому пустой в смысле CSS она не бывает никогда,
     и `:empty` не срабатывал — замер показывал ячейку нулевой высоты,
     которая всё равно забирала зазор сетки. */
  .drow > .acts { display: none; }
  .drow > .acts:has(button) { display: flex; grid-area: 2 / 2 / 3 / -1; }
  /* У менеджера флажка нет вовсе: столбец под него не резервируем. */
  .dlist-ro .row.drow { grid-template-columns: 44px minmax(0, 1fr) 76px; }
  .dlist-ro .drow > .num { grid-area: 1 / 3 / 2 / 4; }

  /* ⚠️ Поле названия у руководителя — счётчик уходит ВТОРОЙ строкой под него.
     В одну строку с ручкой, флажком и счётчиком полю оставалось 129px из 345,
     а длинным значениям нужно до 216 («розничный клиент», «парикмахерская»):
     замер 30.09.2026 нашёл восемь обрезанных названий. Счётчик — подсказка,
     а не то, что правят, поэтому он и уступает место: мелко под названием,
     как должность под именем контакта. Строка выше на ~18px — это дешевле,
     чем название, которое не прочитать. У менеджера (.dlist-ro) названия —
     текст, он переносится, и там раскладка прежняя. */
  .dlist:not(.dlist-ro) .row.drow { grid-template-columns: 44px minmax(0, 1fr) 44px; }
  .dlist:not(.dlist-ro) .drow > .grip { grid-area: 1 / 1 / 3 / 2; }
  .dlist:not(.dlist-ro) .drow > .num {
    grid-area: 2 / 2 / 3 / 3; text-align: left;
    font-size: var(--t-micro); line-height: 1.2; padding-left: var(--fld-pad-x);
  }
  .dlist:not(.dlist-ro) .drow > .acts:has(button) { grid-area: 3 / 2 / 4 / -1; }
}

/* Подписи полей появляются только там, где скрыт заголовок таблицы. */
.lbl { display: none; }
@media (max-width: 900px) {
  .lbl { display: inline; color: var(--muted); font-size: var(--t-sm); }
  .urow > div { padding: 1px 0; }
}

/* ════════════════════════════════════════════════════════════════════
   Доска: те же карточки колонками по статусам
   ════════════════════════════════════════════════════════════════════
   Вторая раскладка списка, не отдельный раздел (SPEC 3.8). Выбор живёт
   в адресе — ссылку на доску с фильтрами можно переслать коллеге.

   Перетаскивания нет: без него доска остаётся читалкой воронки, и это
   осознанный предел. Перетаскивание требует либо библиотеки, либо своей
   обработки указателя с доступностью через клавиатуру — отдельное решение,
   которое незачем принимать до того, как выбрана сама раскладка.
   ════════════════════════════════════════════════════════════════════ */

.views { display: flex; border: 1px solid var(--line-2); border-radius: var(--radius); overflow: hidden; }
.view-a {
  padding: 7px 14px; font-size: var(--t-sm); font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; color: var(--ink-2); text-decoration: none; white-space: nowrap;
}
.view-a:hover { background: var(--panel); color: var(--ink); }
.view-a[aria-current] { background: var(--ink); color: var(--ground); }

/* Прокрутка вбок — ВНУТРИ рамки доски. Если пустить её по странице, вместе
   с колонками уедут шапка и фильтры, и вернуться к поиску можно будет
   только прокрутив всё обратно. */
/* ⚠️ Колонки делят ширину поровну, прокрутки вбок НЕТ.
   Правка Виталия 10.09.2026. Прежде доска ехала вбок, и колонки за краем
   переставали существовать: их не ищут, про них забывают. Теперь на экране
   ровно столько колонок, сколько влезает читаемо, а к остальным — стрелками.
   ⚠️ Число колонок приходит КЛАССОМ (`cols-1`…`cols-4`), а не переменной
   в атрибуте `style`. Так было до 15.09.2026 — и не работало ни дня: строгая
   CSP (`style-src 'self'`, без `style-src-attr`) запрещает атрибут `style`
   в разметке, браузер его отбрасывал, и сетка всегда падала на запасные
   четыре дорожки. При двух выбранных колонках замер показал 4 дорожки
   и 596px пустоты справа. Снаружи это выглядело как «доска почему-то
   не растягивается», а в консоли лежало 59 нарушений CSP.

   Классов ровно четыре: на странице перелистывания не бывает больше
   `BOARD_PER_PAGE = 4` колонок. */
.board {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px; align-items: start;
  /* Доска забирает остаток высоты, и от неё считают свой предел колонки.
     ⚠️ Ряд задан явно. Без него ряд сетки тянется по содержимому, и `100%`
     у колонки считается от этого же содержимого — то есть не ограничивает
     ничего: замер показал колонку 1558px в доске высотой 696. */
  flex: 1; min-height: 0; padding-bottom: 14px;
  grid-template-rows: minmax(0, 100%);
}
/* ⚠️ Правило `.board` выше держат ДВЕ проверки в наборе, и обе читают первый
   блок `.board { … }` целиком. Разрезать его нельзя: класс-модификаторы идут
   отдельными правилами ПОСЛЕ, а не внутри. */
.board.cols-1 { grid-template-columns: minmax(0, 1fr); }
.board.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.board.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.board.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Перелистывание и выбор колонок. */
.colbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.colpage { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.colpage-n { font-size: var(--t-sm); color: var(--muted); white-space: nowrap; }
.pg.off { opacity: .35; cursor: default; }
a.pg { text-decoration: none; display: inline-flex; align-items: center; justify-content: center; }
.cols-body { grid-template-columns: 1fr; min-width: 230px; }
/* ⚠️ Панель колонок раскрывается ВПРАВО от кнопки, а не влево, как фильтры.
   Общее .more-body { right: 0 } рассчитано на кнопку у правого края; «Колонки»
   стоит у левого края доски, и панель уезжала на 114px под боковое меню
   (замер 30.09.2026 на 1280). На телефоне панель остаётся во всю ширину. */
@media (min-width: 621px) {
  .cols-body { left: 0; right: auto; }
}
.cols-body form { display: flex; flex-direction: column; gap: 7px; }
/* Выбор колонок доски: та же ручка, что в справочнике (ВХ-14). */
.cols-list { display: flex; flex-direction: column; }
.colrow { display: flex; align-items: center; gap: 4px; padding: 1px 0; background: var(--ground); }
.colrow .check { flex: 1; }
.cols-body .check { gap: 9px; }

/* ⚠️ Прокручивается ТЕЛО колонки, а шапка стоит вне области прокрутки.
   До 11.09.2026 было наоборот: прокручивалась сама колонка, шапка держалась
   на `position: sticky`, а восемь пикселей её padding оставались щелью над
   плашкой — карточки в неё проезжали. Щель закрывалась заглушкой-псевдоэлементом,
   и с ней воевали три захода подряд: заглушка то съедала рамку плашки, то
   оставляла полосу, а полоса прокрутки всё равно шла от самого верха колонки,
   выше плашки.

   Все три дефекта — следствия одного решения: шапка лежала ВНУТРИ того, что
   прокручивается. Снаружи неё ни щель, ни заглушка, ни sticky не нужны:
   карточки обрезаются ровно по верху своей области, полоса прокрутки
   начинается под плашкой, а плашка рисует свою рамку сама. */
.col {
  display: flex; flex-direction: column; min-width: 0;
  /* ⚠️ Высота — вся оставшаяся, а не доля экрана. 62vh оставляли пустую полосу
     под доской на высоких экранах и резали колонку на низких: доля окна ничего
     не знает о том, сколько места заняли шапка и фильтры над ней.
     `100%` считается от доски, а та растянута на остаток (правка Виталия
     15.09.2026). Колонка при этом не тянется до низа насильно: `align-items:
     start` оставляет короткой колонке её собственную высоту. */
  max-height: 100%;
  /* ВХ-4: колонка — слой канвы, карточки на ней белые. Разделять их рамкой
     не нужно: хватает разницы тона. */
  background: var(--canvas); border-radius: var(--radius-lg); padding: 8px;
}
/* Колонки вне текущей страницы перелистывания: на мониторе их не видно.
   Разметка приходит целиком, чтобы на телефоне была вся воронка сразу. */
@media (min-width: 901px) { .col.off-page { display: none; } }

/* ⚠️ Рамка 1px нужна всем шапкам, у большинства — прозрачная. Плашки статусов
   задают только `border-color`, а ширину брали у `.stage`, которой на доске нет:
   у «нового» с `border-style: dashed` ширина выпадала в `medium` — три пикселя.
   Пунктир получался толще списочного, а шапка «НОВЫЙ» — на шесть пикселей выше
   соседних колонок (замер 11.09.2026: 33.3px против 28.5px). */
/* ⚠️ Заголовок — кнопка (ВХ-19): на телефоне по нему колонка раскрывается.
   На мониторе нажатий не принимает — там колонка не складывается, и заголовок
   остаётся подписью. Сброс шрифта и ширины обязателен: кнопка иначе приносит
   системный шрифт и сжимается по содержимому. */
.col-head {
  width: 100%; font: inherit; text-align: left;
  cursor: default; pointer-events: none;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  /* ⚠️ Цвет — прямо в сокращённой записи. Общее правило палитры стоит выше
     по файлу, и `border: 1px solid` без цвета перебивало его, сбрасывая
     рамку в currentColor: пунктир «нового» становился темнее плашки в карточке. */
  padding: 6px 10px; border: 1px solid var(--st-line, transparent);
  border-radius: var(--radius);
  /* Отступ до карточек принадлежит шапке, а не телу: у тела он лежал бы внутри
     области прокрутки, и карточка въезжала бы в него краем. Шапка больше
     не липкая — уехать вместе с ней отступ не может. */
  margin-bottom: 8px;
}

/* Заливку и цвет текста шапка берёт у плашки статуса — одна палитра
   на список и доску. Красить сами карточки в те же цвета нельзя:
   семь цветных колонок дают рябь, и читать становится нечего. */
.col-name {
  font-size: var(--t-micro); font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* ⚠️ `margin-left: auto`, а не надежда на `space-between`. На телефоне
   в заголовке три элемента — название, число и треугольник, — и промежуток
   делился между ними: правый край числа гулял на 35px от колонки к колонке
   (замер 15.09.2026, замечание Виталия «цифры расположены хаотично»).
   Отступ слева прижимает число к концу строки, и все они встают в одну
   вертикаль независимо от длины названия. */
.col-n { font-size: var(--t-micro); font-weight: 600; flex-shrink: 0; margin-left: auto; }

/* Тело колонки прокручивается само. Иначе одна длинная колонка растянула бы
   доску на весь экран, а рядом стояли бы шесть коротких с пустотой под ними.
   `min-height: 0` обязателен: без него flex-элемент не даёт себя сжать ниже
   содержимого, и прокрутка не появляется вовсе. */
.col-body {
  display: flex; flex-direction: column; gap: 7px;
  flex: 1; min-height: 0; overflow-y: auto;
}
.col-empty { margin: 0; padding: 8px 2px; font-size: var(--t-sm); color: var(--muted); }

.bcard {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--ground); padding: 9px 11px; cursor: pointer;
  display: flex; flex-direction: column; gap: 2px;
  /* ⚠️ Без тени, как в макете. Тень карточки — тоже обводка (хайрлайн
     0 0 0 1px) плюс размытие снизу; поверх рамки она давала двойную линию,
     и на скруглении углы выглядели жирными (замечание Виталия 01.10.2026). */
}
.bcard:hover { border-color: var(--line-2); background: var(--panel-2); }
/* ВХ-8 · Перенос карточки указателем.

   ⚠️ Анимируются только `transform` и `opacity`. Размеры и смещения здесь
   выставляются один раз при захвате — это установка, а не анимация: браузер
   пересчитает раскладку однажды, а не в каждом кадре. */
.bcard { touch-action: manipulation; }
/* ⚠️ Меню ссылки по долгому нажатию гасим (ВХ-20). После того как перенос
   на телефоне выключили, долгое нажатие отдаётся браузеру, и Safari на iPhone
   показывает своё меню ссылки с подсветкой содержимого. Это не дефект
   переноса, а поведение по умолчанию, и убирается оно отдельно. */
.bcard { -webkit-touch-callout: none; }
.bcard:active { cursor: grabbing; }

/* Переносимая карточка. Цельная и непрозрачная — она и есть карточка,
   а не снимок с неё: браузер рисует свой полупрозрачный призрак только
   в родном механизме, от которого мы ушли (ВХ-8).
   `position: fixed` уводит её из-под обрезки колонки: без этого карточка
   пропадала бы за краем прокручиваемого тела, едва его покинув. */
.bcard.carry {
  position: fixed; left: 0; top: 0; z-index: 60;
  margin: 0; pointer-events: none; cursor: grabbing;
  box-shadow: 0 12px 28px rgba(20, 18, 18, .18), 0 2px 6px rgba(20, 18, 18, .10);
  will-change: transform;
}
/* Пока карточку несут, курсор «схвачено» держится по всей странице —
   иначе он менялся бы на каждом элементе, над которым проносят. */
body.carrying { cursor: grabbing; user-select: none; }

/* Место, откуда карточку взяли, и куда она встанет. Ничего не рисует — только
   держит место: пунктирную рамку Виталий отклонил 11.09.2026. Высоту ставит
   скрипт по размеру карточки: заполнитель нулевой высоты означал бы, что соседи
   схлопываются и тут же расступаются обратно. */
.ph { flex: 0 0 auto; }

/* ⚠️ Подсветки колонки-приёмника НЕТ — отменена Виталием 11.09.2026 вместе
   с пунктиром заполнителя. Класс `.over` скрипт по-прежнему ставит: им он
   отмечает цель, в том числе при переносе с клавиатуры. Вешать на него вид —
   значит вернуть рамку, от которой отказались. Куда встанет карточка, видно
   по тому, как расступаются соседи. */

/* Карточка, чей статус сейчас сохраняется. Ничего не двигает — только гасит:
   подмена размеров в этот момент дёрнула бы колонку. */
.bcard.saving { opacity: .6; }

/* Сообщение об ошибке сети. Появляется снизу, сдвигом и прозрачностью. */
#toast {
  position: fixed; left: 50%; bottom: 22px; z-index: 80;
  max-width: min(520px, calc(100vw - 32px));
  padding: 11px 16px; border-radius: var(--radius);
  background: var(--ink); color: var(--ground);
  font-size: var(--t-sm); line-height: 1.4;
  box-shadow: 0 10px 24px rgba(20, 18, 18, .22);
  opacity: 0; transform: translate(-50%, 12px); pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
}
#toast.on { opacity: 1; transform: translate(-50%, 0); }

/* Текст для читалок экрана: есть в дереве доступности, не виден глазами.
   `display: none` не годится — читалка такой текст не произносит. */
.vh {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; border: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* ⚠️ Уважение к настройке «меньше движения» (SPEC 3.6). Сам перенос работает
   как обычно — он не украшение, а способ сделать дело. Отключается только
   расступание соседей и всплытие тоста: именно они вызывают недомогание
   у людей с вестибулярной чувствительностью. */

.bcard .co-name { font-size: var(--t-base); }
.bcard-foot {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; margin-top: 4px;
}
/* Имя переносится, а не обрезается многоточием: фамилия уходит на вторую
   строку целиком (правка Виталия 01.10.2026). `anywhere` — на случай слова
   длиннее карточки, иначе оно вылезло бы за край. */
.bcard .owner { min-width: 0; overflow-wrap: anywhere; }
.bcard .req { margin-top: 3px; font-size: var(--t-micro); color: var(--accent); }

/* ВХ-17 · Колокольчик: заголовок группы с кнопкой и крестик у записи. */
.bell-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
/* ⚠️ Строка списка — сетка из `display: contents` у ссылки (.cells), поэтому
   крестик становится её последней колонкой. Место под него держится всегда:
   появляйся оно вместе с крестиком, строки дёргались бы под курсором. */
.ticks li:has(.rm) { grid-template-columns: 92px 1fr 28px; }
.rm {
  opacity: 0; transition: opacity .12s ease;
  align-self: center; color: var(--muted);
}
.ticks li:hover .rm { opacity: 1; }
/* Клавиатура: при фокусе крестик виден всегда — иначе для того, кто не работает
   мышью, кнопки просто нет. */
.rm:focus-visible { opacity: 1; }
.rm:hover { color: var(--accent); }

/* ⚠️ Метка горящего напоминания в углу карточки (ВХ-18). Тот же кружок, что
   на колокольчике: одна форма на «требует внимания» во всём интерфейсе.
   Рамка цветом колонки, а не белая: карточка лежит на канве, и белый ободок
   на ней читался бы как щербина. */
.bcard { position: relative; }
/* ⚠️ Метка лежит ВНУТРИ карточки, а не свешивается за угол. Снаружи её резала
   колонка: у тела колонки `overflow-y: auto`, а это делает `auto` и по
   горизонтали — метка обрезалась, и внизу доски появлялась горизонтальная
   полоса прокрутки (замечание Виталия 15.09.2026). */
.bcard-fire {
  position: absolute; top: 7px; right: 9px;
  min-width: 18px; height: 18px; padding: 0 5px;
  background: var(--accent); color: #fff; border-radius: 999px;
  font-size: var(--t-micro); font-weight: 700; display: grid; place-items: center;
}
/* Название не заезжает под метку: без этого длинное имя компании подныривало
   под кружок и читалось «Сеть аптек «Гиппокра…1». */
.bcard.fires .co-name { padding-right: 24px; }

/* ВХ-17 · Напоминание на карточке доски. Сработавшее — цветом тревоги,
   будущее — спокойным серым: иначе красный перестаёт значить «горит». */
.bcard-rem {
  display: flex; align-items: baseline; gap: 6px; margin-top: 3px;
  font-size: var(--t-micro); color: var(--muted);
}
.bcard-rem .why { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bcard-rem.late { color: var(--accent); font-weight: 600; }

.col-more {
  font-size: var(--t-sm); color: var(--ink-2); text-decoration: none;
  border: 1px dashed var(--line-2); border-radius: var(--radius);
  padding: 7px 10px; text-align: center;
}
.col-more:hover { background: var(--panel); color: var(--ink); }

/* Карточка на доске остаётся накладкой при любой ширине: доска и так занимает
   всю ширину, и отдавать ей ещё треть под панель означало бы показывать
   три колонки вместо семи. */
.main:has(.board) { display: flex !important; }

/* ⚠️ На доске прокручиваются КОЛОНКИ, а не страница (правка Виталия 15.09.2026).
   Чтобы колонка знала свой предел, у раскладки должна быть заданная высота:
   `flex: 1` делит ОСТАТОК, а остатка нет там, где контейнер тянется
   по содержимому. Первый заход это и показал — колонка ушла на 1743px при
   окне 880, страница поехала целиком, а внутри колонок прокрутки не осталось.
   Только на широких экранах: на телефоне колонки идут друг под другом
   и прокручивается как раз страница. */
@media (min-width: 901px) {
  .app:has(.board) { height: 100vh; height: 100dvh; min-height: 0; }
  .main:has(.board) { min-height: 0; }
}

@media (max-width: 900px) {
  /* На телефоне доска бессмысленна: в 375 пикселей помещается одна колонка,
     и получается тот же список, только с прокруткой вбок. Колонки сужаются
     до ширины экрана — листать их движением пальца привычно. */
  /* На телефоне четыре колонки в ряд — это четыре полоски по 80 пикселей.
     Ставим их друг под друга: прокрутка вниз привычнее, чем вбок,
     и ни одна колонка не прячется за краем. */
  /* Явный ряд доски снимаем: на телефоне колонки идут друг под другом, каждая
     своей высоты, и прокручивается страница, а не они. */
  /* ⚠️ `align-content: start` обязателен. Доска растянута на остаток высоты,
     а сетка по умолчанию раздаёт лишнее место рядам: свёрнутые колонки
     в 38px стояли в рядах по 94px, и между заголовками зияли пустоты
     (замер 15.09.2026). */
  /* ⚠️ `.board[class]`, а не `.board`: точность 0,2,0 — как у `.board.cols-N`.
     Классы колонок (15.09.2026) перебивали голое `.board` точностью, хотя
     стоят выше по файлу, и на телефоне доска рисовалась четырьмя колонками
     по 63px в ряд, названия ломались по буквам. Найдено замером 30.09.2026. */
  .board[class] { grid-template-columns: 1fr; grid-template-rows: auto; align-content: start; }

  /* ⚠️ На телефоне заголовок колонки — работающая кнопка (ВХ-19): по нему
     колонка раскрывается. Треугольник показывает, что тут есть что открыть;
     свёрнутая воронка целиком помещается на один экран. */
  /* ⚠️ И цель нажатия: раз заголовок стал единственным способом раскрыть
     колонку, он обязан быть не меньше 44px (SPEC 3.5). Замер 14.09.2026
     нашёл 30.1px — правило целей нажатия перечисляет органы поимённо,
     а заголовок колонки стал органом позже и в список не попал. Это ровно
     тот случай, который набор проверок пропускает: он смотрит CSS, а высота
     здесь набиралась отступами. */
  .col-head { pointer-events: auto; cursor: pointer; min-height: 44px; }
  .col-head::after {
    content: ''; width: 7px; height: 7px; margin-left: 2px; flex-shrink: 0;
    border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform .18s ease;
  }
  .col:not(.folded) .col-head::after { transform: rotate(-135deg) translate(-2px, -2px); }
  /* Свёрнутой колонке ни тела, ни нижнего отступа: иначе под заголовком
     оставалась бы полоса канвы, будто список открыт и пуст. */
  .col.folded .col-body { display: none; }
  .col.folded { padding-bottom: 0; }
  .col.folded .col-head { margin-bottom: 0; }

  /* ⚠️ Кнопки сворачивания боковой панели на телефоне нет (правка Виталия
     15.09.2026): меню там и так сверху, скрывать нечего — а кнопка вдобавок
     налезала на пункт «Клиенты». */
  /* ⚠️ Текст ссылки центрируется внутри своей коробки. Высоту им добирает
     правило целей нажатия (44px), и без центрирования лишние пиксели уходили
     вниз: текст пунктов стоял на 3.5px выше логотипа, и строка читалась
     как съехавшая (замечание Виталия 15.09.2026). */
  .nav-a { display: inline-flex; align-items: center; }

  .rail-toggle { display: none; }
  /* ⚠️ И вместе с кнопкой — отмена самого сворачивания. Кука `rail=off`
     ставится на мониторе и ездит с человеком на телефон, а вернуть панель
     там больше нечем: кнопки нет. Меню исчезало целиком, без выхода
     (найдено 15.09.2026 при замере). */
  .app.rail-off .rail { display: flex; }

  /* Перелистывания колонок на телефоне нет: они все на экране, свёрнутые. */
  .colpage { display: none; }
  .col { max-height: none; }
  .col-body { overflow-y: visible; }
  .colpage { margin-left: 0; }
  .views { width: 100%; }
  .view-a { flex: 1; text-align: center; }
}

/* ── Цели нажатия: добор ──
   Эти два правила стоят в КОНЦЕ файла намеренно. Колокольчик и мелкий крестик
   описаны ниже по файлу, чем телефонный блок, и при равной специфичности
   побеждал более поздний — телефонные размеры молча не применялись.
   Переносить объявления местами рискованнее, чем дописать добор здесь. */
@media (max-width: 900px) {
  .bell { width: 44px; height: 44px; }
  .x.sm { min-width: 44px; min-height: 44px; padding: 0; margin-left: auto;
          display: inline-flex; align-items: center; justify-content: center; }
}

/* ── Кликабельные строки — настоящие ссылки ──
   Раньше это были div с role="button" и tabindex="0": фокус ставился,
   а Enter не делал ничего. HTMX слушает click, и браузер превращает Enter
   в click только на ссылках и кнопках. Фильтр hx-trigger="keyup[key=='Enter']"
   не вариант: HTMX вычисляет такие условия через new Function, то есть требует
   unsafe-eval, а его в политике нет.

   .cells — обёртка внутри строки-сетки: display:contents оставляет её детей
   ячейками этой сетки, но сама она их объединяет в одну ссылку. */
.rowlink, .cells { display: contents; }
.rowlink, .cells, .bcard { text-decoration: none; color: inherit; cursor: pointer; }

/* У обёртки с display:contents нет собственной рамки, и фокус на ней не виден.
   Показываем его на строке-родителе — иначе человек, идущий табом, не понимает,
   где он стоит. :has() здесь по делу: подсветить надо именно родителя. */
.row:has(> .rowlink:focus-visible),
.ticks li:has(.cells:focus-visible) { outline: 2px solid var(--ink); outline-offset: -2px; }
.rowlink:focus-visible, .cells:focus-visible { outline: none; }

/* ── «К содержимому» ──
   Клавиатурой до первого поля страницы приходилось прожимать девять раз:
   логотип, шесть пунктов меню, профиль, выход — и так на КАЖДОМ экране.
   Пока строки списка не были ссылками, это мало кого касалось; теперь касается.
   Ссылка не видна, пока на неё не встали фокусом. */
.skip {
  position: absolute; left: 8px; top: -60px; z-index: 100;
  background: var(--ink); color: var(--ground); text-decoration: none;
  font-size: var(--t-sm); font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; padding: 11px 16px; border-radius: var(--radius);
  transition: top .12s;
}
.skip:focus { top: 8px; }
.main:focus { outline: none; }

/* ── Длинные слитные значения ──
   Вставленная в заметку ссылка, слитое название, адрес почты без пробелов —
   всё это один «токен», и по умолчанию браузер его не рвёт. В сетке это
   выглядит так: текст молча вылезает из своей ячейки и рисуется ПОВЕРХ
   соседней колонки, не расширяя таблицу. Замерено: название в 63 символа
   вылезало на 317px, накрывая контактное лицо.

   overflow-wrap: anywhere разрешает перенос внутри слова и заодно опускает
   минимальную ширину ячейки до одного символа — колонка перестаёт
   распираться содержимым. */
.co-name, .co-meta, .person, .owner, .col-name,
.kv dd, .kv dt, .entry p, .people span,
.ticks b, .ticks small, .bcard .owner, .msg, .col-empty {
  overflow-wrap: anywhere;
}

/* ── Полосы прокрутки ──
   Правка Виталия 10.09.2026: тоньше. Системная полоса в 15–17px — это
   заметная серая лента вдоль каждой колонки доски, а колонок семь.

   ⚠️ Два набора правил ВЗАИМОИСКЛЮЧАЮЩИЕ, и держать их рядом нельзя.
   Chrome поддерживает стандартные scrollbar-width/scrollbar-color с версии 121,
   и как только они заданы, он ПЕРЕСТАЁТ применять ::-webkit-scrollbar.
   Так и вышло: полоса у карточки оставалась 12px вместо заданных семи,
   с системными стрелками по краям, торчащими из скруглённого угла.
   Замер: с thin — 12px, с auto — 17px, то есть размером управляло
   стандартное свойство, а вебкитовые правила просто не работали.

   Поэтому стандартные свойства отданы браузерам, где вебкитовых нет
   (Firefox), а Chrome и Safari идут по ::-webkit-scrollbar, где можно
   задать и толщину, и цвет, и убрать кнопки-стрелки. */
@supports not selector(::-webkit-scrollbar) {
  * { scrollbar-width: thin; scrollbar-color: var(--line-2) transparent; }
}
/* ⚠️ Ползунок отодвинут от содержимого прозрачной рамкой, а не отступом
   контейнера. Он прилипал к правому краю карточки вплотную (замечание
   Виталия 11.09.2026). Отступ у прокручиваемого тела дал бы то же самое,
   но сдвинул бы карточки и в колонках без прокрутки — там полосы нет,
   а щель справа осталась бы. Рамка живёт внутри самой полосы: где полосы
   нет, нет и следа. Видимая толщина ползунка — 5px, дорожка 13px. */
::-webkit-scrollbar { width: 13px; height: 13px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--line-2); border-radius: 4px;
  border: 4px solid transparent; background-clip: content-box;
}
/* ⚠️ Только `background-color`. Сокращённое `background` сбрасывает
   `background-clip` в `border-box`, и при наведении заливка растекалась
   на прозрачную рамку: ползунок раздувался с пяти пикселей до тринадцати
   и снова прилипал к карточке (замечание Виталия 11.09.2026). */
::-webkit-scrollbar-thumb:hover { background-color: var(--muted); }
::-webkit-scrollbar-corner { background: transparent; }
/* ⚠️ Кнопки-стрелки по краям полосы убираются отдельно: тонкую полосу
   они не наследуют и рисуются системными — два квадратика с треугольниками
   сверху и снизу, торчащие из скруглённого края карточки. Ширина в ноль
   нужна вместе с display: одного свойства мало, часть сборок Chromium
   оставляет для кнопки место. */
::-webkit-scrollbar-button { display: none; width: 0; height: 0; }

/* Родные органы управления красим в свой цвет: галочки, ползунки и подсветку
   выбранного значения в выпадающем календаре. Иначе браузер рисует их
   системным синим — единственным цветом в системе, который ниоткуда не следует. */
:root { accent-color: var(--ink); }
input[type=datetime-local], input[type=date], input[type=time] { accent-color: var(--ink); }

@media (max-width: 900px) {
  /* ⚠️ «70% ширины» имеет смысл только на мониторе. На телефоне те же 70%
     от 375 пикселей — это полоска в 263px с полями по бокам, в которую
     не помещается ни одна строка карточки. Здесь карточка почти во всю
     ширину, скругление и отступ остаются — она по-прежнему предмет
     поверх страницы, а не второй экран. */
  .scrim { padding: 10px; }
  .sheet { width: 100%; max-height: calc(100vh - 20px); max-height: calc(100dvh - 20px); }
  .skip { min-height: 44px; display: inline-flex; align-items: center; }
}

/* ════════════════════════════════════════════════════════════════════
   Правки 10.09.2026: всплывающие окна, правка по клику, выбор времени
   ════════════════════════════════════════════════════════════════════ */

/* ── Где встаёт всплывающее окно ──
   Раньше всё наследовало один .scrim, и после того как карточку сделали
   на 70% по центру, туда же уехал колокольчик — уведомления повисли
   посреди экрана вместо кнопки, которая их вызвала.

   Теперь три вида: .dock — карточка справа, .pop — под кнопкой сверху,
   .ask — короткий вопрос по центру. */
.scrim.pop {
  align-items: flex-start; justify-content: flex-end;
  padding: 66px 22px 22px; background: rgba(43, 40, 41, .18);
}
.scrim.pop .sheet { width: min(420px, 100%); max-height: min(70vh, 620px); }

.scrim.ask { align-items: center; justify-content: center; }
.scrim.ask .sheet { width: min(460px, 100%); max-height: calc(100vh - 44px); max-height: calc(100dvh - 44px); }

/* Курсор говорит, что по пустому месту можно нажать и окно закроется. */
.scrim { cursor: pointer; }
.scrim .sheet { cursor: auto; }

/* ── Стрелки перелистывания колонок ──
   Правка Виталия: были мелкими. Ровно тот случай, где размер — не вкус:
   это единственный способ добраться до остальных колонок. */
.colpage .pg {
  min-width: 38px; height: 38px; font-size: var(--t-h2); line-height: 1;
  color: var(--ink); border-color: var(--line-2);
}
.colpage .pg:hover:not(.off) { background: var(--panel); border-color: var(--ink); }
.colpage-n { font-size: var(--t-base); }

/* ── Правка реквизита нажатием на значение ──
   Кнопка не должна выглядеть кнопкой, пока на неё не навели: карточку
   читают чаще, чем правят, и шесть обведённых прямоугольников подряд
   превратили бы справку в форму. */
.valbtn {
  font: inherit; color: inherit; text-align: left;
  background: transparent; border: 1px solid transparent;
  /* Отрицательного отступа здесь нет намеренно: он выводил подсветку
     на 6px за пределы ячейки, в промежуток между подписью и значением.
     Все шесть значений смещены одинаково, и ряд остаётся ровным. */
  border-radius: var(--radius); padding: 1px 6px;
  cursor: pointer; width: 100%;
}
.valbtn:hover { background: var(--panel); border-color: var(--line-2); }
.kv.edit dd { min-width: 0; }

.fieldform { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
/* Поле правки не растягивается на всю ширину карточки (правка Виталия
   10.09.2026): телефон в поле на 600px читается как ошибка вёрстки, а ряд
   значений при открытой правке перестаёт держать общую линию. */
.fieldform .fld { flex: 0 1 200px; min-width: 0; max-width: 100%; }
/* ⚠️ Когда полей в строке несколько (правка контактного лица — имя, телефон,
   должность), базиса в 200px на каждое не хватает: три поля плюс две кнопки
   не укладываются, и «Отмена» уезжает на свою строку. Перенос случается ДО
   сжатия — flex-wrap раскладывает по basis, а ужимает уже внутри строки,
   поэтому одного shrink здесь мало. Замечено Виталием 11.09.2026: кнопки
   одного действия обязаны стоять рядом. */
.fieldform:has(.fld + .fld) .fld { flex: 1 1 110px; }
.fieldform .msg { flex: 1 1 100%; }

/* ⚠️ На телефоне поле правки, наоборот, РАСТЁТ. Ограничение в 200px выше
   написано против карточки в 980px, где поле во всю ширину читается как
   ошибка вёрстки. На карточке в 355px те же 200px оставляют ~100px пустоты
   справа от поля — замечание Виталия 14.09.2026 «справа много пустого места,
   можно расширить вводимые поля». Замер до правки: `flex: 0 1 200px`,
   поле 200px в форме 301.6px.

   ⚠️ Правило стоит НИЖЕ базового намеренно. В общем телефонном блоке
   (`max-width: 900px`, выше по файлу) оно лежало при равной точности
   селекторов и молча не применялось — ЧЕТВЁРТЫЙ случай того же капкана
   в этом файле. Форму с несколькими полями не трогаем: у неё селектор
   с `:has()` точнее, и она растёт и так. */
@media (max-width: 900px) {
  /* ⚠️ Ровно 100%, а не просто рост. С базисом 140px поле вырастало до 194.8,
     и в остаток на той же строке влезала «Сохранить» — а «Отмена» уезжала
     на следующую. Кнопки одного действия при этом расходятся по разным
     строкам, против чего стоит правило выше (замечание Виталия 11.09.2026).
     Целая строка под поле разводит их надёжно: поле сверху, обе кнопки под ним. */
  .fieldform .fld { flex: 1 1 100%; }
}

/* ⚠️ Подпись стоит над ТЕКСТОМ поля, а не над его рамкой.
   Замечание Виталия 11.09.2026: подписи выглядели сдвинутыми влево.
   Причина числовая: поле отступает внутрь на 13px, а подпись начиналась
   от края контейнера — то есть на те же 13px левее значения, которое
   подписывает. Правый столбец зеркально: там значение прижато к правому краю.
   Отступ берётся от той же величины, что padding поля; меняете там —
   меняйте здесь. */
/* Подписью бывает и .eyebrow (карточка), и обычный label (формы) — сдвиг
   нужен обоим, иначе выравнивание чинится на одном экране и остаётся
   сбитым на соседнем. */
.field > .eyebrow, .field > label { padding-left: var(--fld-pad-x); }
.field.right > .eyebrow, .field.right > label { padding-left: 0; padding-right: var(--fld-pad-x); }

/* ── Свой выпадающий выбор вместо системного <select> ──
   Правка Виталия 11.09.2026: системный список рисует операционная система,
   и рядом с округлыми полями он выглядит деталью из чужого интерфейса.
   Устройство то же, что у группы изменений в ленте: нативный <details>,
   ноль скриптов, ноль послаблений в CSP. */
.sel { position: relative; }
.sel > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: flex; align-items: center; gap: 8px;
  min-height: 30px; padding: 4px 12px;
  background: var(--canvas); border: 1px solid transparent;
  border-radius: var(--radius); font-size: var(--t-base); color: var(--ink);
}
.sel > summary::-webkit-details-marker { display: none; }
.sel > summary:hover { border-color: var(--line-2); }
/* Тот же треугольник, что у свёрнутой группы в ленте: одна форма на весь
   интерфейс, чтобы «здесь раскроется» читалось одинаково везде. */
.sel > summary::after {
  content: ''; width: 6px; height: 6px; margin: -3px 0 0 auto;
  border-right: 1.5px solid var(--muted); border-bottom: 1.5px solid var(--muted);
  transform: rotate(45deg); transition: transform .2s ease; flex-shrink: 0;
}
.sel[open] > summary::after { transform: rotate(-135deg); margin-top: 2px; }
.sel[open] > summary { border-color: var(--ink); background: var(--ground); }

/* ⚠️ Список сделан по образцу системных записей ленты, а не плашек статуса
   (правка Виталия 11.09.2026): вертикальная черта слева, ровный приглушённый
   текст, узкие строки. Цветные плашки в списке превращали выбор в витрину
   образцов — семь заливок подряд читать дольше, чем семь строк текста,
   а цвет текущего статуса и так стоит в шапке карточки. */
.sel-body {
  position: absolute; z-index: 30; top: calc(100% + 5px); left: 0;
  min-width: 100%; width: max-content; max-width: min(280px, 74vw);
  display: flex; flex-direction: column; padding: 4px 4px 4px 0;
  background: var(--ground);
  border: 1px solid var(--line); border-left: 2px solid var(--line-2);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-card);
}
/* Список ответственного прижат к правому краю: он и сам стоит справа,
   и раскрываться влево ему некуда. */
.sel.right .sel-body { left: auto; right: 0; }

/* ⚠️ Список в форме ведёт себя как поле ввода: во всю ширину (ВХ-13).
   В карточке список стоит в строке с другими элементами и занимает ровно
   свою надпись — там это правильно. В форме он оказался бы капсулой
   в 54px рядом с полями в 842px, и форма читалась бы как сломанная. */
.pick { width: 100%; }
.pick > summary { width: 100%; min-height: 34px; }
.pick .sel-body { max-width: min(100%, 74vw); }

/* Длинный список прокручивается ВНУТРИ себя, а не уводит страницу (01.10.2026).
   «Тип» в форме заведения — 15 значений: на мониторе 450px, на телефоне ~700,
   и нижние пункты уходили за край окна. Потолок — около восьми пунктов или
   половина экрана; короткие списки (статусы, ответственные) его не достигают
   и не меняются. Выбор времени исключён: у колеса своя прокрутка.
   overscroll-behavior — чтобы, докрутив список, палец не прокручивал карточку. */
.sel:not(.when-time) > .sel-body {
  max-height: min(340px, 50vh); max-height: min(340px, 50dvh);
  overflow-y: auto; overscroll-behavior: contain;
}
/* На телефоне пункт — цель нажатия в 44px, и 340px — это всего семь пунктов:
   восемь статусов карточки начинали прокручиваться, «Архив» прятался наполовину
   (замер 01.10.2026). Потолок — 45% экрана: на телефоне высотой 812px это 365px,
   восемь статусов (362px) целиком; 60% пробовали — «Тип» из фильтров доски снова
   уходил за нижний край. На совсем низких экранах (SE) статусы прокручиваются. */
@media (max-width: 900px) {
  .sel:not(.when-time) > .sel-body { max-height: 45vh; max-height: 45dvh; }
}

.sel-opt {
  display: flex; align-items: center; gap: 8px;
  background: transparent; border: 0; cursor: pointer;
  font-family: var(--body); font-size: var(--t-base); color: var(--ink-2);
  text-align: left; padding: 5px 10px; border-radius: var(--radius-sm);
  white-space: nowrap; min-height: 0;
}
.sel-opt:hover { background: var(--canvas); color: var(--ink); }
/* Текущее значение помечено галочкой, а не заливкой: заливка в одноцветном
   списке была бы единственным пятном и тянула бы взгляд сильнее самого
   выбора. */
.sel-opt[aria-current="true"], .sel-opt[aria-current="page"] { color: var(--ink); }
.sel-opt[aria-current="true"]::before,
.sel-opt[aria-current="page"]::before {
  content: '✓'; font-size: var(--t-sm); width: 12px; flex-shrink: 0;
}
.sel-opt[aria-current="false"]::before { content: ''; width: 12px; flex-shrink: 0; }
/* Ссылка в панели набирается как остальные пункты: у `<a>` свои умолчания. */
a.sel-opt { text-decoration: none; }
/* Кнопка «Выйти» лежит в форме — форма не должна ломать столбик пунктов. */
.sel-body > form { display: contents; }

/* ── ВХ-21: пункт «Ещё» ──
   На мониторе его нет вовсе: боковая панель показывает все разделы сразу,
   и прятать там нечего. Два разных меню на одном проекте — это два набора
   проверок и два места, где можно забыть раздел.

   ⚠️ Правило заключено в `min-width: 901px`, а не написано голым. Голым оно
   стоит НИЖЕ телефонного блока и гасило кнопку «Ещё» на телефоне тоже —
   замер отдавал `display: none` при написанном `block`. Взаимоисключающие
   медиазапросы снимают вопрос порядка целиком: правила просто не встречаются. */
@media (min-width: 901px) {
  .navmore { display: none; }
}

/* ── Статус и ответственный в шапке карточки ── */
.heads { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: start; }
.heads .field { gap: 5px; }

/* ── Выбор времени «как в будильнике» ──
   Родной <select size="6"> сам прокручивается к выбранному значению и сам
   его подсвечивает; цвет подсветки задаёт accent-color — наш почти-чёрный
   вместо системного синего. Самодельное колесо стоило бы полутораста строк
   скрипта, из которых доступность пришлось бы собирать заново. */
.when { display: flex; flex-direction: column; gap: 10px; }
.when-row { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; }
.when-row .grow { flex: 1 1 200px; }
.when .field { flex: 0 0 auto; }

@media (max-width: 620px) {
  .heads { grid-template-columns: 1fr; }
  
  .scrim.pop { padding: 60px 10px 10px; }
}

@media (max-width: 900px) {
  /* Новые органы управления тоже обязаны быть нажимаемыми пальцем:
     значение реквизита теперь кнопка правки, а «править» у записи ленты —
     единственный вход в неё. 26 и 15 пикселей высоты для пальца не годятся. */
  .valbtn { min-height: 44px; display: flex; align-items: center; }
  /* ⚠️ «Забыли пароль?» — тоже цель пальца. Замер 14.09.2026 нашёл 104×20.3px:
     правило целей нажатия перечисляет органы поимённо, и ссылка под формой
     входа в список не попала. Она при этом единственный путь восстановления
     доступа — промах по ней означает «не могу войти и не могу починить».
     `width: fit-content` обязателен: без него подчёркивание растянулось бы
     на всю строку. */
  .links a {
    display: inline-flex; align-items: center; min-height: 44px;
    width: fit-content;
  }
  .entry-top .linkish { min-height: 44px; padding: 0 10px; }
  /* «снять все» в колокольчике была 54×15 — не попадала в перечень выше
     (замер 30.09.2026). */
  .bell-head .linkish { min-height: 44px; padding: 0 10px; margin-top: 0; }
}

/* ── Напоминание ──
   Поле даты-времени, поле заметки и кнопка в один ряд. Двух списков-колонок
   здесь больше нет: они давали две коробки с собственными полосами прокрутки
   и выглядели хуже родного выпадающего окошка, которое было изначально. */
.when { display: flex; flex-direction: column; gap: 10px; }
.when-row { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; }
.when .field { gap: 5px; }
.when-when { flex: 0 0 auto; }
.when-when .fld { width: 210px; min-width: 0; }
/* Кнопки напоминания стоят рядом и переносятся вместе: порознь они уезжали
   каждая на свою строку в узкой правой колонке карточки. */
.when-acts { display: flex; gap: 8px; flex: 0 0 auto; }
/* Поле заметки не тянется до правого края: оно занимает столько, сколько
   нужно строке, а не всё, что осталось. */
.when .grow { flex: 0 1 340px; min-width: 0; }
.when .grow .fld { width: 100%; }

/* ⚠️ Ширину «когда связаться» на телефоне НЕ трогать растяжением на всю строку.
   Пробовали 14.09.2026 (`.when .when-when { flex: 1 1 100% }`) — на iPhone
   стало хуже: поле и его текст выросли, внизу появилась горизонтальная
   прокрутка. Причина в том, что у элемента флекса `min-width` по умолчанию
   `auto`, а у родного `datetime-local` при кегле 16px своя минимальная ширина
   содержимого — коробка отказывается ужиматься и распирает строку. Откачено
   в прежний вид. Замер в Chromium этого не показывает: там поле встаёт
   ровно в 301.6px, поэтому проверять такое можно ТОЛЬКО на живом iPhone. */

/* ── Колокольчик ──
   Кнопка прежнего размера (правка Виталия: увеличить просили не её, а значок
   внутри). Сам колокольчик подрос с 17 до 22 — в 36-пиксельной кнопке он
   выглядел потерянным.

   Счётчик остаётся исправленным: раньше он выезжал за правый край и подрезался
   соседом. Белая обводка делает налегание на угол намеренным, а не обрезком. */
.bell { width: 36px; height: 36px; margin-right: 4px; }
.bell svg { width: 22px; height: 22px; }
.bell .dot {
  top: -4px; right: -4px; min-width: 18px; height: 18px;
  padding: 0 4px; font-size: var(--t-micro); border: 2px solid var(--ground);
  border-radius: 999px;
}
.topbar-actions { gap: 12px; }

@media (max-width: 620px) {
}

@media (max-width: 900px) {
  /* Цель нажатия на телефоне — 44px. Правило стоит в самом конце: базовый
     размер кнопки объявлен выше, и при равной специфичности победило бы оно. */
  .bell { width: 44px; height: 44px; }
}

/* ── Шапка карточки и строка напоминания: ровные по высоте ──
   Правка Виталия 10.09.2026. Поле, соседнее поле и кнопка были 34, 32 и 30
   пикселей высотой и выровнены по низу — получалась лесенка. Причина не в
   выравнивании, а в том, что у трёх органов управления разная высота:
   выравнивать по низу разновысокое всё равно бессмысленно. */
.when-row .fld,
.when-row .btn { height: 36px; }
.when-row .btn { padding: 0 16px; }

/* ⚠️ Списки НЕ растягиваются на половину карточки (правка Виталия 10.09.2026).
   Ширина по содержимому: «КП отправлено» — это 200 пикселей текста, а поле
   было 458. Пустое поле шириной в пол-экрана читается как незаполненное.

   Блок «Ответственный» стоит справа, и подпись над ним выровнена по правому
   краю — иначе она висит в пустоте у левого края своей половины. А вот текст
   ВНУТРИ списка выровнен влево, как во всех остальных полях системы:
   выключка вправо у одного органа управления из десяти читается как ошибка. */
/* ⚠️ flex-direction: row обязателен. .heads — это .block, а у .block стоит
   flex-direction: column: без явного переопределения статус и ответственный
   вставали друг под друга, хотя обоим хватало места в строку. */
.heads {
  display: flex; flex-direction: row; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; align-items: flex-start;
}
.heads .field { flex: 0 1 auto; width: min(260px, 100%); }
.heads .field.right { align-items: flex-end; text-align: right; }
.heads .fld { text-align: left; }

/* ⚠️ Выключка вправо действует, только пока «Статус» и «Ответственный» стоят
   в строку. Когда карточка узкая, они встают друг под друга — и та же выключка
   бросает подпись и список на правый край пустой строки: на телефоне
   «Ответственный» читался центрированным, хотя «Статус» над ним выровнен
   по левому краю (замечание Виталия 14.09.2026).

   Порог — ширина КАРТОЧКИ, а не окна, по той же причине, что в ВХ-5:
   карточка бывает узкой и на мониторе. Считается он не на глаз —
   260px + 16px промежутка + 260px это 536, плюс по 20px полей .sheet-body
   с каждой стороны: до 576px поля стоят рядом, ниже переносятся. */
@container (max-width: 575px) {
  /* Замер 14.09.2026: оба поля стояли 260px при 301.6px содержимого карточки —
     списки обрывались на 41px раньше строк реквизитов под ними, и правый край
     карточки читался рваным. Ширина 260px нужна ровно для того, чтобы два поля
     встали в строку; когда они встали друг под друга, она держать перестала. */
  .heads .field { width: 100%; }
  .heads .field.right { align-items: stretch; text-align: left; }
  .heads .field.right > .eyebrow { padding-left: var(--fld-pad-x); padding-right: 0; }
  /* Список тоже раскрывается от левого края — вправо ему больше не от чего
     отсчитываться, и он уезжал за границу карточки. */
  .sel.right .sel-body { left: 0; right: auto; }
}

/* Своя запись в ленте правится нажатием на текст — как и реквизиты.
   Выглядит обычным абзацем, пока на него не навели. */
.valbtn.note {
  display: block; width: 100%; white-space: pre-wrap;
  font-size: var(--t-base); line-height: 1.6; color: var(--ink-2);
  overflow-wrap: anywhere;
}

/* ── Контактное лицо: имя, телефон и должность одной строкой ──
   Порядок в карточке задан Виталием 10.09.2026: компания → люди → остальное.
   Имя и телефон стоят рядом, потому что это номер человека, а не компании;
   разносить их по разным строкам значило бы разрывать одно на два. */

/* Третья пустая дорожка забирает остаток: без неё телефон уезжал к правому
   краю карточки и переставал читаться как номер стоящего рядом человека. */

/* То же на карточке доски — двумя строками, чтобы не распирать колонку. */
.bcard-person { margin-top: 4px; display: flex; flex-direction: column; gap: 1px; }
.bp-name { font-size: var(--t-sm); color: var(--ink); }
.bp-phone { font-size: var(--t-sm); color: var(--ink-2); }
.bp-note { font-size: var(--t-micro); color: var(--muted); }

/* «Телефон компании» — самая длинная подпись реквизитов; узкая колонка
   ломала её на две строки и сбивала ряд. */
.kv.edit { grid-template-columns: 132px 1fr; }

/* ── Разграничение строк реквизитов ──
   Замечание Виталия 11.09.2026: без линий девять строк подряд сливаются
   в сплошной текст, и глаз не за что зацепить.

   ⚠️ Линия отделяет СМЫСЛОВУЮ единицу, а не каждую строку сетки. У человека
   их две — «ФИО» и «Телефон», — и линия между ними разорвала бы одну карточку
   человека надвое: имя оказалось бы отдельно от своего же номера. Поэтому
   черта ставится перед первой строкой каждого блока, а вторая строка человека
   идёт без неё.

   ⚠️ Вертикальный зазор убран, отступы перенесены в ячейки: при gap линия
   рвалась бы на две — отдельно под обозначением, отдельно под значением.
   Горизонтальный отступ даёт padding-right у dt по той же причине. */
.kv.edit { row-gap: 0; column-gap: 0; }
.kv.edit dt { padding-right: 14px; }
/* ⚠️ Плотность берётся ОТСТУПАМИ, не кеглем (3.2.1) — правило остаётся в силе,
   и кегль здесь не тронут. Замер: строка реквизита занимала 40px при 13px
   текста, вся карточка — 1329px против 856px экрана, то есть полтора экрана
   прокрутки на карточку, которую открывают десятки раз в день.
   Отступ 7→4 и межстрочный 1.5→1.35 дают 28px на строку. */
.kv.edit dt, .kv.edit dd { padding-top: 4px; padding-bottom: 4px; line-height: 1.35; }

.kv.edit > dt:not(:first-child),
.kv.edit > dd:not(:nth-child(2)),
.kv.edit .kvgroup > dt:first-of-type,
.kv.edit .kvgroup > dd:first-of-type { border-top: 1px solid var(--line); }

/* ⚠️ Обозначение центрируется ВНУТРИ своей ячейки, а не ячейкой в ряду.
   Разница существенная. `align-items: center` у самой сетки даёт каждой
   ячейке высоту её содержимого — и два border-top, из которых сложена черта
   строки, расходятся ступенькой (так уже ломалось 14.09.2026). Растянутая
   ячейка с центрированным содержимым даёт и ровную черту, и подпись
   напротив значения. Замечание Виталия 14.09.2026: «статусы слева
   не отцентрованы с инфой напротив». */
.kv.edit > dt, .kv.edit .kvgroup > dt { display: flex; align-items: center; }

/* ── Реквизиты на телефоне ──
   ⚠️ Блок стоит ПОСЛЕ базовых правил намеренно, и это третий случай тех же
   граблей в этом файле. Телефонное правило лежало в общем блоке
   `max-width: 900px` ВЫШЕ по файлу, а `.kv.edit { grid-template-columns:
   132px 1fr }` — ниже. Точность селекторов одинаковая, значит побеждает
   последний: колонка обозначений на телефоне всё это время была 132px,
   а не 96px, и правило выглядело применённым, ничего не делая. Отсюда
   и «справа от подписи много пустого места» — под значение и под поле правки
   оставалось на 36px меньше, чем задумано. Правила, переопределяющие
   базовые, писать только НИЖЕ них. */
@media (max-width: 900px) {
  .kv.edit { grid-template-columns: 96px 1fr; }
  /* Высота строки — это и есть цель нажатия: `.valbtn` уже добирает свои 44px,
     а внешние отступы добавляли к ним ещё 8 и растягивали карточку впустую.
     Замечание Виталия: «интервал между компания и телефон большой». */
  .kv.edit dt, .kv.edit dd { padding-top: 0; padding-bottom: 0; }
}

/* ── Контактные лица внутри общей сетки реквизитов ──
   Обёртка с display: contents оставляет обе строки человека строками сетки,
   но даёт одну цель для подмены: правка меняет имя, телефон и должность
   вместе — это одна карточка человека, а не три поля порознь. */
.kv.edit .kvgroup { display: contents; }
/* Должность стоит СПРАВА от имени, а не под ним (правка Виталия 10.09.2026):
   отдельной строкой она удваивала высоту каждого человека, а список людей —
   самая длинная часть карточки. Точка-разделитель рисуется стилем: в разметке
   её нет, и читалка экрана не произносит «точка» между именем и должностью. */
.kv.edit .person-note { font-size: var(--t-sm); color: var(--muted); }
.kv.edit .person-note::before { content: '·'; margin: 0 6px; color: var(--line-2); }
.dd-act { display: flex; align-items: flex-start; gap: 6px; }
.dd-act .valbtn { flex: 1; }

/* Шапка блока: подпись слева, «+ контакт» прижат вправо (правка Виталия
   11.09.2026). Прежняя квадратная «+» стояла отдельной строкой сетки
   реквизитов и съедала высоту ровно там, где её жальче всего, — люди
   занимают в карточке больше всех места. В шапке кнопка не добавляет
   ни пикселя: строка заголовка была и так.
   position: relative — точка отсчёта для выпадающей формы ниже. */
.block-top {
  position: relative; display: flex; align-items: center;
  justify-content: space-between; gap: 12px; min-height: 24px;
}

.adder.mini > summary { padding: 3px 10px; letter-spacing: .04em; }
/* Общее правило .adder[open] отодвигает summary на 9px вниз — оно рассчитано
   на форму, раскрывающуюся В ПОТОКЕ. Здесь форма absolute, и этот отступ
   только сдвигал бы реквизиты при каждом раскрытии. */
.adder.mini[open] > summary { margin-bottom: 0; }

/* Форма выпадает панелью поверх, а не вставкой в поток, — тем же приёмом,
   что .more-body у фильтров списка, и по той же причине: раскрытие не должно
   сдвигать реквизиты вниз в тот момент, когда человек в них смотрит. */
.adder-body {
  position: absolute; z-index: 20; top: calc(100% + 6px); right: 0;
  width: min(300px, 100%);
  display: flex; flex-direction: column; gap: 6px;
  padding: 12px; background: var(--ground);
  border: 1px solid var(--line-2); border-radius: var(--radius-lg);
  box-shadow: 0 8px 24px rgba(43, 40, 41, .10);
}
/* ⚠️ flex-basis у полей задаётся заново. Класс .fieldform отсюда убран именно
   поэтому: там flex: 0 1 200px рассчитан на строку, а в колонке 200px
   становятся ВЫСОТОЙ — панель вырастала до 674px вместо 190. Наследовать
   горизонтальный стиль в вертикальной раскладке нельзя. */
.adder-body .fld { width: 100%; flex: 0 0 auto; }
.adder-body .btn { width: 100%; }

@media (max-width: 620px) {
  /* ⚠️ Ширина задаётся числом, а не растяжкой left:0/right:0/width:auto.
     Замер показал, что при такой растяжке панель брала 88px — ширину самой
     кнопки «+ контакт», а не контейнера, и подпись кнопки «Добавить»
     обрезалась на 2px. Спорить с этим дороже, чем назвать ширину. */
  .adder-body { left: auto; right: 0; width: min(300px, calc(100vw - 56px)); }
}

/* ── Поставки под реализацию (ВХ-23) ──
   Стоит ПОСЛЕ .block-top, .kv.edit и .adder.mini, которые здесь уточняются:
   при равной точности селекторов побеждает то, что ниже по файлу.

   «+ поставка» лежит вне сворачиваемого details: внутри details её не было бы
   видно в свёрнутом блоке, а внутри summary она переключала бы блок вместо
   того, чтобы открывать форму. Поэтому она прижата к строке заголовка
   абсолютно; 10px сверху — это padding-top у .block. */
.consign { position: relative; }
.consign-add { position: absolute; top: 10px; right: 0; z-index: 2; }
.consign-top { padding-right: 132px; }

/* Заголовок блока и есть кнопка сворачивания. Подпись, счёт и стрелка
   прижаты влево одной группой: space-between от .block-top растащил бы
   счёт к кнопке «+ поставка». */
.consign-fold > summary {
  list-style: none; cursor: pointer; user-select: none;
  justify-content: flex-start;
}
.consign-fold > summary::-webkit-details-marker { display: none; }
.consign-fold > summary:hover .eyebrow { color: var(--ink-2); }
.consign-sum { font-size: var(--t-sm); color: var(--muted); }

/* Стрелка и плавность — те же, что у группы изменений в ленте (ВХ-3),
   и по той же причине только сдвиг: анимация высоты или прозрачности
   застревает на первом кадре в невидимой вкладке, и список не показывается
   вовсе (подробно — у .sysgroup выше). */
.consign-fold > summary::after {
  content: ''; width: 6px; height: 6px; margin: -3px 0 0 2px;
  border-right: 1.5px solid var(--muted); border-bottom: 1.5px solid var(--muted);
  transform: rotate(45deg); transition: transform .2s ease;
}
.consign-fold[open] > summary::after { transform: rotate(-135deg); margin-top: 2px; }
.consign-fold[open] > .consign-list,
.consign-fold[open] > .consign-new { margin-top: 6px; animation: sysgroup-slide .22s ease-out; }
.consign .cform { animation: sysgroup-slide .22s ease-out; }

/* Поставка — одна кнопка правки на все её позиции, столбиком. Приём тот же,
   что у значений реквизитов (.valbtn); столбец задаётся здесь, ниже
   телефонного .valbtn { display: flex; align-items: center }, иначе позиции
   встали бы в строку. */
.consign-lines { display: flex; flex-direction: column; align-items: stretch; gap: 2px; }
.consign-line { display: flex; align-items: baseline; gap: 12px; }
.consign-prod { flex: 1; min-width: 0; overflow-wrap: anywhere; }
/* Количество — главное число строки, поэтому цветом текста, а не серым,
   как должность у контакта (решение Виталия 30.09.2026). */
.consign-qty { white-space: nowrap; color: var(--ink); }

/* Форма поставки встаёт в поток: новая — под заголовком, правка — на место
   поставки во всю ширину сетки. */
.consign-editrow { grid-column: 1 / -1; }
.cform { display: flex; flex-direction: column; gap: 8px; padding: 6px 0 10px; }
.cform-date { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.cform-date .fld { width: 180px; flex: 0 0 auto; }
.cform-items { display: flex; flex-direction: column; gap: 6px; }
.cform-pos {
  display: grid; grid-template-columns: minmax(0, 1fr) 120px auto;
  gap: 8px; align-items: center;
}
.cform-pos .fld { width: 100%; min-width: 0; }
.cform-more {
  align-self: flex-start; background: none; border: 0; padding: 4px 0;
  font: inherit; font-size: var(--t-sm); color: var(--ink-2);
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}
.cform-more:hover { color: var(--ink); }
.cform-acts { display: flex; justify-content: flex-end; gap: 8px; }

/* На телефоне строка заголовка — цель нажатия, как и «+ поставка» рядом. */
@media (max-width: 900px) {
  .consign-top { min-height: 44px; }
}

/* Узкий экран. Замер 30.09.2026 на 375px: в три колонки продукту оставалось
   92–111px из 302, и названия ломались на три строки, а счёт, зажатый между
   подписью и кнопкой «+ поставка», получал 66px и рвался надвое. */
@media (max-width: 620px) {
  /* Строка поставки складывается: дата сверху мелким, под ней продукт,
     количество и крестик на всю ширину. Черта остаётся над датой, то есть
     между поставками, а не между датой и её же продуктом. */
  .kv.edit.consign-list { grid-template-columns: 1fr; }
  .kv.edit.consign-list > dt { font-size: var(--t-sm); padding-top: 8px; }
  .kv.edit.consign-list > dd { border-top: 0; }
  /* Счёт уходит второй строкой под подпись, стрелка остаётся рядом с ней. */
  .consign-fold > summary { flex-wrap: wrap; row-gap: 2px; }
  .consign-fold > summary::after { order: 1; }
  .consign-sum { order: 2; flex-basis: 100%; }
  /* Строка позиции в форме: продукт на всю ширину, под ним штуки и «×». */
  .cform-pos { grid-template-columns: minmax(0, 1fr) 44px; }
  .cform-pos .fld[name="product"] { grid-column: 1 / -1; }
  .cform-more { min-height: 44px; }
  .cform-date .fld { flex: 1 1 auto; width: auto; }
}

/* ⚠️ САМЫЙ КОНЕЦ ФАЙЛА, и это принципиально.
   Телефонный размер для своего выбора статуса и ответственного: правила .sel
   объявлены далеко внизу, и любой медиаблок выше при равной специфичности
   им проигрывал — min-height оставался 36px, а замер показывал кнопки 39 и 36
   вместо обещанных 3.5 сорока четырёх. Дважды уже наступали на это же
   с колокольчиком и мелким крестиком; добор в конце дешевле перестановки. */
@media (max-width: 900px) {
  .sel > summary, .sel-opt { min-height: 44px; }
  /* ⚠️ `.sel.when-time`, а не `.when-time`: базовое `.when-time > summary`
     (min-height 36px) объявлено НИЖЕ по файлу и при равной точности
     перебивало 44px. Лишний класс решает раньше порядка. */
  .sel.when-time > summary { min-height: 44px; }
}

/* ── Выпадающие списки закрываются нажатием мимо ──
   Правка Виталия 11.09.2026. Нативный <details> закрывается только повторным
   нажатием на свой заголовок, а от списка ждут поведения выпадающего меню:
   ткнул мимо — закрылось.

   Сделано без единой строки скрипта. Открытый список растягивает невидимый
   слой на весь экран ПОД своей панелью: слой принадлежит самому summary,
   поэтому нажатие по нему считается нажатием на заголовок и закрывает список
   штатным способом. Панель лежит выше слоя, и нажатие по варианту до слоя
   не доходит.

   ⚠️ z-index здесь не украшение: слой 25 обязан быть НИЖЕ панели (.sel-body —
   30, .more-body и .adder-body — 20, им слой дан свой, 15) и выше остальной
   страницы. Поменяете числа местами — список перестанет открываться вовсе,
   потому что первое же нажатие будет попадать в слой. */
.sel[open] > summary::before,
.more[open] > summary::before,
.adder.mini[open] > summary::before {
  content: ''; position: fixed; inset: 0; cursor: default;
}
.sel[open] > summary::before { z-index: 25; }
.more[open] > summary::before,
.adder.mini[open] > summary::before { z-index: 15; }

/* ── Колесо часов и минут (ВХ-4) ──
   Включается скриптом только на широких экранах; на телефоне остаётся родное
   поле, которое iOS рисует барабаном сама.

   ⚠️ Искривление и затухание строк сделаны ПРОКРУТОЧНОЙ анимацией CSS,
   а не пересчётом стилей на каждый кадр из скрипта. Присланный образец
   считал transform для каждой строки в обработчике scroll — на шестидесяти
   строках это десятки вычислений на кадр. Здесь тем же занимается браузер,
   а где animation-timeline не поддерживается, список просто остаётся плоским
   и полностью рабочим. */
.when-native-off { display: none; }

/* ⚠️ :not([hidden]) обязателен. Правило с классом перебивает атрибут [hidden]
   по специфичности, и колесо показывалось ПОВЕРХ скрытия — на телефоне
   и родное поле, и колесо разом. Атрибут при этом стоял на месте, поэтому
   проверка «hidden ли элемент» отвечала «да», а на экране было «нет».
   Поймано замером фактической геометрии, а не чтением свойства. */
.when-wheel:not([hidden]) { display: flex; gap: 12px; align-items: flex-start; }
.when-wheel .wheel-date { width: 150px; }

/* Кнопка «выбрать время» и панель с колесом — тем же устройством, что списки
   статуса и ответственного: одинаковое закрытие нажатием мимо.

   ⚠️ Но панель здесь БЕЗ собственного вида: ни фона, ни рамки, ни тени,
   ни черты слева (правка Виталия 11.09.2026). У колеса уже есть своя серая
   плашка, и белая панель вокруг неё давала вторую рамку вокруг первой —
   две вложенные коробки вместо одного предмета. Панель осталась только
   позиционированием. */
/* ⚠️ Высота ровно как у соседних полей. Замер показал 30 против 36 у даты,
   заметки и кнопки — кнопка времени стояла на два пикселя выше строки,
   и ряд выглядел сбитым. Отступ тоже 13px, как у полей: текст времени
   обязан начинаться на той же вертикали, что текст даты. */
.when-time > summary {
  min-width: 96px; min-height: 36px; padding: 6px 13px;
  font-variant-numeric: tabular-nums;
}
.when-time .wheel-wrap {
  padding: 0; width: max-content; min-width: 0;
  background: transparent; border: 0; box-shadow: none;
}
.when-time .wheel-wrap .wheel { height: 132px; box-shadow: var(--shadow-card); }

/* ⚠️ gap нулевой, отступ симметричный: колонки обязаны быть одной ширины
   и стоять зеркально относительно середины. При зазоре и боковом отступе
   часы и минуты смещались к разным краям, и пара «00 30» читалась кривой. */
.wheel {
  position: relative; display: flex; gap: 0;
  background: var(--canvas); border-radius: var(--radius-lg);
  padding: 0 4px; height: 132px; overflow: hidden;
}
/* Полоса выделения посередине: показывает, какое значение считается выбранным.
   Без обводки — на сером фоне хватает одной белой заливки, а рамка добавляла
   третью линию к тем двум, что и просили убрать. */
.wheel-mark {
  position: absolute; left: 4px; right: 4px; top: 50%; height: 32px;
  transform: translateY(-50%); border-radius: var(--radius-sm);
  background: var(--ground);
  pointer-events: none;
}
.wheel-col {
  position: relative; z-index: 1; width: 46px; height: 100%;
  overflow-y: auto; scroll-snap-type: y mandatory;
  scrollbar-width: none; text-align: center;
}
.wheel-col::-webkit-scrollbar { display: none; }
.wheel-col:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; border-radius: var(--radius-sm); }
/* Отступы сверху и снизу ровно в половину высоты минус строка — чтобы первое
   и последнее значение могли встать в середину. */
.wheel-pad { height: 50px; }
.wheel-item {
  height: 32px; line-height: 32px; scroll-snap-align: center;
  font-size: var(--t-row); font-variant-numeric: tabular-nums; color: var(--ink);
}

@supports (animation-timeline: view()) {
  .wheel-item {
    animation: wheel-bend linear both;
    animation-timeline: view(block);
    animation-range: entry 0% exit 100%;
  }
  @keyframes wheel-bend {
    0%   { opacity: .25; transform: perspective(200px) rotateX(52deg) scale(.82); }
    50%  { opacity: 1;   transform: perspective(200px) rotateX(0deg) scale(1); }
    100% { opacity: .25; transform: perspective(200px) rotateX(-52deg) scale(.82); }
  }
}

/* Кому движение мешает — колесо плоское: глобальное правило в начале файла
   снимает animation, а без анимации пункты сами имеют opacity 1 и без transform. */

/* ── Реквизиты и напоминание в две колонки (ВХ-5, 11.09.2026) ──
   В реквизитах длинных строк не бывает, и колонка значений во всю ширину
   карточки стоила пустого места, а напоминание уезжало вниз. Замер примерки:
   карточка 480 → 341 px, то есть на треть короче.

   ⚠️ Переключение — по ширине КАРТОЧКИ, а не окна. Медиазапрос здесь врёт:
   карточка занимает ~70 % экрана, и при окне 1250 px она уже 875. Замер
   показал, чем это кончается: при карточке 700 px колонок оставалось две,
   колонка значений падала до 187 px, длинные адреса ломались на три строки —
   и экономия высоты съедалась обратно. */
.sheet { container-type: inline-size; }

.card-cols {
  /* ⚠️ 1.8 к 1, число подобрано замером. Ограничение — не левая колонка,
     а ПРАВАЯ: дата (210 px) и кнопка времени (96 px) обязаны стоять в одну
     строку, с зазором это 316 px. При 1.9 справа остаётся 317 — впритык,
     при 2.1 уже 296, и строка ломается. 1.8 даёт правой 328 px с запасом,
     а левой — 458 px под значения, где длинный адрес встаёт в строку. */
  display: grid; grid-template-columns: minmax(0, 1.8fr) minmax(0, 1fr);
  row-gap: 11px; column-gap: 0;
  /* stretch обязателен: при start правая колонка была бы высотой
     по содержимому, и разделитель обрывался бы на середине карточки. */
  align-items: stretch;
}
.card-cols > .block:first-child { border-top: 0; padding-top: 0; }
.card-col-r > .block { border-top: 0; padding-top: 0; }

/* Разделитель — та же хайрлайн-линия, что делит строки реквизитов. Висит
   на правой колонке, а не отдельным элементом: лишний div ради линии пришлось
   бы держать в разметке и прятать на узких экранах.
   ⚠️ Отступы с ОБЕИХ сторон одинаковые: без левого горизонтальные черты строк
   упирались в вертикальную, а кнопка «+ контакт» липла к ней вплотную.
   Линия должна читаться промежутком между колонками, а не рамкой правой. */
.card-col-r { border-left: 1px solid var(--line); padding-left: 20px; }
.card-cols > .block:first-child { padding-right: 20px; }

@container (max-width: 860px) {
  /* Узкая карточка — снова одна колонка. Линия и отступы снимаются: иначе
     левая колонка осталась бы уже правой без всякой причины. */
  .card-cols { grid-template-columns: 1fr; }
  .card-col-r { border-left: 0; padding-left: 0; }
  .card-cols > .block:first-child { padding-right: 0; }
  .card-col-r > .block { border-top: 1px solid var(--line); padding-top: 10px; }
}

/* В узкой колонке поля напоминания встают сеткой: дата и время в одну строку,
   «о чём» и кнопка под ними во всю ширину.
   ⚠️ Именно сетка, а не flex-колонка: у .grow задан рост, и в колоночном flex
   он растягивал поле «О чём» по ВЫСОТЕ — замер давал 340 px вместо 58.
   В гриде это свойство ни на что не влияет, и капкан закрыт по построению. */
@container (min-width: 861px) {
  /* ⚠️ Сетку получает .when-wheel, а не .when-row. В разметке дата и время
     лежат ВНУТРИ обёртки колеса, а в строке напоминания рядом с ней стоят
     ещё «о чём» и кнопка. Примерка была плоской, и перенесённое из неё
     правило раскладывало не те элементы: дата оказывалась одна в строке,
     а время уезжало ниже. Поймано замером на живой карточке. */
  .card-col-r .when-row { flex-direction: column; align-items: stretch; gap: 8px; }
  .card-col-r .when-row > .field { width: 100%; }
  /* .grow задаёт рост: в колоночном flex он растягивал бы «о чём» по ВЫСОТЕ. */
  .card-col-r .when-row > .field.grow { flex: 0 0 auto; }
  .card-col-r .when-row .btn { align-self: flex-start; }

  .card-col-r .when-wheel {
    display: grid; grid-template-columns: 1fr auto;
    gap: 8px 10px; align-items: end;
  }
  .card-col-r .when-wheel .field { width: auto; }
  .card-col-r .when-wheel .wheel-date { width: 100%; }
  /* Барабан прижат к правому краю кнопки: раскрываясь влево, в узкой колонке
     он вылезал бы за карточку. */
  .card-col-r .when-time .sel-body { left: auto; right: 0; }
}

/* ── Цель нажатия у стрелок перелистывания ──
   ⚠️ Правило стоит В САМОМ КОНЦЕ файла намеренно, и это третий заход.
   Внутри стрелки один символ, padding ширину не набирает: замер на 375px
   давал 38×44 при норме 44. Ширину задаёт `.colpage .pg` (строка ~1569),
   точность та же, и побеждает последний по файлу — поэтому ни основной
   телефонный блок, ни блок добора выше не сработали: оба стоят ВЫШЕ него.
   Проверять такие правки только замером: в файле правило выглядит применённым
   в любом из трёх мест. */
@media (max-width: 900px) {
  .colpage .pg { min-width: 44px; height: 44px; }
}

/* ── Цель нажатия у полей входа ──
   ⚠️ Экран входа — единственный, где поля не `.fld`, а голые `input[type=...]`,
   и телефонный добор `min-height: 44px` их не накрывал: замер на 375px давал
   42px. Два пикселя незаметны глазом и заметны пальцем — это первый экран,
   который человек видит с телефона. Правило в конце файла по той же причине,
   что и у стрелок: базовое объявление полей стоит выше, и одинаковая точность
   решается порядком. */
@media (max-width: 900px) {
  input[type=email], input[type=password], input[type=text] { min-height: 44px; }
}
