/* ==================================================================
   «Рядом» · экраны договорённости (UI.md §3, ТЗ §39)

   Третий и последний css-файл приложения. Подключается ПОСЛЕ
   theme.css и screens.css — порядок обязателен: здесь есть правила,
   которые намеренно перебивают тему (высота поля суммы, форма
   кнопки-двери на главном), и они держатся на порядке загрузки,
   а не на !important и не на раздутых селекторах.

   Четыре правила, которым подчинён файл:

   1. Ни одного нового цвета. Только переменные theme.css. Допустимы
      прозрачные чёрный и белый в тенях — ровно та же вольность,
      которую берут theme.css и screens.css, и только там.
   2. Размеры берутся из шкалы FIXES6 Д1: главная кнопка 3.5rem
      (56px), обычная 3rem (48px), поле ввода 3rem, знак состояния
      2.25rem. Прежние границы «кнопка не ниже 72px, шрифт не мельче
      17px» ОТМЕНЕНЫ вместе с постановкой «для очень пожилых»: это
      деловое приложение для двоих. Кому нужно крупнее — включает
      «Крупный текст», и всё вырастает разом.
   3. Все размеры в rem. Два исключения те же, что в теме, и оба
      не размеры: 1px в волосяном контуре (линия обязана остаться
      линией и при «крупном тексте») и var(--r-pill) = 999px
      («скругли до упора»).
   4. Ни одна кнопка ни в одном media-query не опускается ниже общей
      шкалы. В альбомной ориентации и на узких телефонах отбирается
      только воздух: отступы, промежутки, размер украшений.

   --------------------------------------------------------------
   КОНТРАКТ РАЗМЕТКИ (что этот файл ждёт от index.html и от js)

   Шапка сделки — на s-review, s-ack, s-amount, s-sign, s-signed:
     <header class="deal-head">
       <p class="deal-head-line">Договор · версия <span id="dealVersion">3</span></p>
       <p class="deal-fp">отпечаток <span class="fp" id="dealHash">9c9dfca8</span></p>
       <p class="deal-peer" id="dealPeer">Пётр ознакомился</p>
     </header>

   Статусы сторон (§15, §21). В .card НЕ оборачивать — плашка своя:
     <ul class="party-status">
       <li class="party done">
         <span class="party-mark" aria-hidden="true"></span>
         <span class="party-text">
           <span class="party-name">Иван Иванов</span>
           <span class="party-state">ознакомился</span>
         </span>
       </li>
       <li class="party wait">… <span class="party-state">ожидается</span></li>
     </ul>
   Знак рисуется css (галочка и кружок), эмодзи и тире в разметке
   не нужны: состояние и так подписано словом.

   Неопределённое условие (§12):
     <div class="undef-card">
       <span class="ic" data-ic="help" aria-hidden="true"></span>
       <div class="undef-text">
         <h3>Условие не определено</h3>
         <p class="undef-what">Срок оплаты. Рекомендуется уточнить его.</p>
       </div>
     </div>
   Список пуст → та же карточка с классом ok и data-ic="check".

   Текст договора для чтения:
     <div class="doc-text">…</div>              ← textContent, переносы \n
     <div class="doc-text rich">…разметка…</div> ← если текст размечен тегами
   По умолчанию white-space: pre-wrap, поэтому внутрь кладётся ТОЛЬКО
   текст: отступы разметки в html станут видимыми пробелами.

   Сумма (§16):
     <div class="amount-field">
       <input class="amount-input" id="amountValue" inputmode="decimal">
       <select id="amountCur">…</select>
     </div>
     <p class="cap amount-cap">Валюта</p>

   Итог сравнения (§17, §18):
     <div class="verdict verdict-ok">   /  <div class="verdict verdict-bad">
       <span class="verdict-mark" aria-hidden="true"></span>
       <h1 class="hero">Сумма<br><em>подтверждена</em></h1>
       <p class="verdict-note">…</p>
     </div>

   Подтверждение личности (§20):
     <div class="identity-cam"><video id="identityVideo" autoplay muted playsinline></video></div>
     <p class="identity-say">Посмотрите прямо</p>
     <div class="step-bar" style="--done:.33"><span></span></div>
     <ol class="steps">
       <li class="step done"><span class="step-mark"></span><span>Посмотрите прямо</span></li>
       <li class="step now">…</li><li class="step wait">…</li>
     </ol>

   Итоговый документ (§24):
     <article class="doc-view">
       <section class="doc-sec">
         <h2>Участники</h2>
         <dl class="doc-rows"><dt>Meeting ID</dt><dd class="mono">MTG-…</dd></dl>
       </section>
       <section class="doc-sec"><h2>Местоположение</h2>
         <div class="doc-map"><svg …></svg></div></section>
       <section class="doc-sec"><h2>Журнал событий</h2>
         <ol class="doc-log"><li><span class="doc-log-at">14:32</span>
           <span class="doc-log-what">Создана встреча</span></li></ol></section>
     </article>

   Списки «Мои встречи» и «Мои договоры» (§29):
     <div class="list">
       <button class="list-card" type="button" data-id="DOC-…">
         <span class="list-title">Договор с Иваном Ивановым</span>
         <span class="list-sub">12 500 ₽ · 3 сентября</span>
         <span class="chip done">Завершён</span>
       </button>
     </div>
   Пусто → <div class="card empty">…</div>

   Фотография профиля:
     <span class="avatar big" data-letter="И"><img src="…" alt=""></span>
   Тег <img> добавляется, только когда фотография есть: буква лежит
   под ним и служит заглушкой.
   ================================================================== */

/* ------------------------------------------------------------------
   1. Две служебные переменные

   Обе — не цвет и не размер, поэтому их отсутствие в theme.css не
   нарушает правило «только переменные темы»: цвета по-прежнему все
   оттуда.
   ------------------------------------------------------------------ */

:root {
  /* Моноширинная цепочка. Отпечаток договора (§14) сличают глазами
     по знакам: в пропорциональном шрифте «l» и «1», «0» и «O» стоят
     разной ширины и путаются, в моноширинном — нет. Своего шрифта
     не грузим: лишний файл ради восьми знаков не окупается. */
  --font-mono: ui-monospace, 'SF Mono', 'Cascadia Mono', 'Segoe UI Mono',
    'Roboto Mono', 'Liberation Mono', Consolas, monospace;

  /* Галочка одной формой на всё приложение: статус стороны, итог
     сравнения сумм, чип «Завершён», флажок согласия. Нарисована
     обрезкой заливки, а не картинкой и не шрифтом, потому что
     currentColor делает её правильной на лайме, на белом и на
     тёмном без единого нового цвета. */
  --check-shape: polygon(14% 44%, 0 60%, 39% 100%, 100% 16%, 86% 2%, 39% 72%);
}

/* ------------------------------------------------------------------
   2. Ввод, которого нет в theme.css

   Тема покрывает .field, select, input[type=text|search]. Новые
   экраны приносят телефон, число, пароль и многострочный текст —
   без этих строк они получили бы системный вид и системную высоту,
   то есть примерно 30px вместо 48px.
   ------------------------------------------------------------------ */

input[type='tel'],
input[type='number'],
input[type='password'],
input[type='email'],
input[type='url'] {
  width: 100%;
  min-height: 3rem;               /* 48px — та же величина, что у кнопки */
  padding: 0 0.875rem;
  border-radius: var(--r-card-s);
  background: var(--card-2);
  color: var(--text);
  font-size: var(--fs-lead);
  font-weight: 400;
}

/* Телефон и код набираются цифрами и читаются по цифрам: моноширинные
   цифры не пляшут при вводе, и человек не теряет место в номере. */
input[type='tel'],
input[type='number'] {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

/* Многострочное поле: расшифровка (§10) и правка договора (§13).
   Строка набрана --fs-lead, высота — девять рем: меньше выглядит как
   поле «на одну фразу» и провоцирует писать коротко там, где нужен
   полный текст. Величина ужата вместе со всей шкалой Д1, но осталась
   примерно теми же девятью строками текста — их стало на 6px ниже.

   resize: vertical, а не none: человеку с большим текстом надо дать
   растянуть поле, а по горизонтали растягивать нечего — колонка
   и так во всю ширину экрана. */
textarea {
  display: block;
  width: 100%;
  min-height: 9rem;
  padding: 0.875rem;
  border-radius: var(--r-card-s);
  background: var(--card-2);
  color: var(--text);
  font-size: var(--fs-lead);
  line-height: 1.5;
  resize: vertical;
}

textarea::placeholder {
  color: var(--text-3);
}

/* Флажок и переключатель выбора. Нажимаемая область у них своя,
   строкой .agree / .choice (48px), а сам знак — 28px: знак во всю
   высоту строки превращается в плашку и перестаёт читаться
   как флажок.

   Отмеченный флажок красится пастельным --lime-soft, а не главным
   --lime. Причина не косметическая: насыщенный лайм в приложении
   означает «единственное действие этого экрана», и второе такое
   пятно рядом с кнопкой «Получить код» заставляет выбирать между
   ними. */
input[type='checkbox'],
input[type='radio'] {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 0.5rem;
  background: var(--glass);
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--hair);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background 0.16s;
}

input[type='radio'] {
  border-radius: 50%;
}

input[type='checkbox']:checked,
input[type='radio']:checked {
  background: var(--lime-soft);
  box-shadow: none;
}

input[type='checkbox']:checked::after {
  content: '';
  width: 1rem;
  height: 1rem;
  background: currentColor;
  clip-path: var(--check-shape);
}

input[type='radio']:checked::after {
  content: '';
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 50%;
  background: currentColor;
}

/* Строка согласия (§8, §35) и строка выбора в настройках. Это не
   кнопки, но нажимают их так же, поэтому высота у них кнопочная. */
.agree,
.choice {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  min-height: 3rem;
  padding: 0.625rem 0.875rem;
  border-radius: var(--r-card-s);
  background: var(--card-2);
  color: var(--text);
  font-size: var(--fs-body);
  line-height: 1.35;
  cursor: pointer;
  text-align: left;
}

.agree .grow,
.choice .choice-text {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}

.choice-title {
  font-size: var(--fs-body);
  font-weight: 500;
}

.choice-sub {
  font-size: var(--fs-cap);
  color: var(--text-2);
}

/* Ссылку внутри строки согласия оставляем стилизованной на случай,
   если она там окажется, но правильный путь другой: отдельная
   кнопка «Прочитать соглашение» ведёт на s-terms. Ссылка в строке —
   это цель размером в слово внутри цели размером в экран, и человек
   с дрожащей рукой попадает в неё случайно. */
.agree a,
.consent a {
  color: var(--lime-soft);
  text-decoration: underline;
  text-underline-offset: 0.1875rem;
}

/* ------------------------------------------------------------------
   3. Мелкие общие блоки новых экранов
   ------------------------------------------------------------------ */

/* Пояснение, которое нельзя пропустить, но которое не должно пугать:
   «сумма собеседника не показывается», «версия составлена без ИИ»,
   «проверка личности упрощённая». Плашка, а не крик. */
.note {
  padding: 0.75rem 0.875rem;
  border-radius: var(--r-card-s);
  background: var(--card-2);
  color: var(--text-2);
  font-size: var(--fs-body);
  line-height: 1.4;
  text-wrap: pretty;
}

/* Тот же блок, когда сказанное меняет ход дела: «новая версия
   сбрасывает ознакомление и суммы». Громкость даётся не цветом
   тревоги (красного в палитре нет), а весом текста и лаймовым
   заголовком: человек должен прочитать, а не испугаться. */
.note.strong {
  color: var(--text);
}

.note-title {
  display: block;
  margin-bottom: 0.25rem;
  color: var(--lime-soft);
  font-size: var(--fs-lead);
  font-weight: 500;
}

/* Спокойное ожидание вместо спиннера (§39.14, §39.21). Крутящийся
   кружок не сообщает ничего; строка словами сообщает, чего именно
   ждём и что делать не надо. */
.await {
  padding: 0.375rem 0;
  color: var(--text-2);
  font-size: var(--fs-h2);
  font-weight: 400;
  line-height: 1.25;
  text-align: center;
  text-wrap: balance;
}

/* «Составляем договор…» — время, когда экран занят. Крупно и по
   центру, потому что это единственное, что сейчас происходит. */
.busy {
  padding: 0.875rem 0;
  color: var(--lime-soft);
  font-size: var(--fs-h2);
  font-weight: 500;
  text-align: center;
  text-wrap: balance;
}

/* Пустой список: «Договоров пока нет». Не ошибка, поэтому тон
   обычный, а рядом — обычная кнопка «Новая встреча». */
.empty {
  align-items: center;
  padding: 1.375rem 0.875rem;
  text-align: center;
  text-wrap: pretty;
}

/* Моноширинные технические значения: Document ID, Hash, Verification ID.
   break-all — потому что это не слова, переносить их можно где угодно,
   а вылезти за край экрана они не имеют права. */
.mono {
  font-family: var(--font-mono);
  font-variant-ligatures: none;
  font-size: var(--fs-body);
  line-height: 1.4;
  /* anywhere, а не break-word: это не слова, переносить их можно
     в любом месте, а вылезти за край экрана они права не имеют.
     Обычный текст (имена, названия) переносится по-другому —
     см. .party-name. */
  overflow-wrap: anywhere;
}

/* ------------------------------------------------------------------
   4. .deal-head — шапка договора (UI.md §2)

   «Договор · версия 3 · отпечаток 9c9dfca8» — единственная проверка
   §14, которая работает, когда сломалось всё остальное: двое сличают
   восемь знаков глазами через камеру. Поэтому отпечаток здесь
   крупнее заголовка карточки, стоит отдельной строкой и по центру,
   а не дописан хвостом к версии мелким шрифтом.
   ------------------------------------------------------------------ */

.deal-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  padding: 0.875rem 0.75rem;
  border-radius: var(--r-card);
  background: var(--card);
  text-align: center;
}

.deal-head-line {
  font-size: var(--fs-body);
  color: var(--text-2);
}

.deal-head-line span,
.deal-head-line b {
  color: var(--text);
  font-weight: 500;
}

.deal-fp {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.125rem;
  font-size: var(--fs-cap);
  color: var(--text-2);
}

/* Отпечаток. Разрядка крупная — знаки сличают по одному, слитная
   строка для этого не годится. nowrap: восемь знаков обязаны
   остаться одной строкой, иначе сличать нечего. */
.fp {
  font-family: var(--font-mono);
  font-variant-ligatures: none;
  font-size: clamp(1.25rem, 5.5vw, 1.625rem); /* 20…26px */
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: 0.12em;
  color: var(--lime-soft);
  white-space: nowrap;
}

/* Статус второй стороны словами — «Пётр ознакомился», «Ждём Петра».
   Стоит в шапке, а не внизу экрана: это часть ответа на вопрос
   «где мы сейчас», а не примечание. */
.deal-peer {
  margin-top: 0.1875rem;
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--text);
  text-wrap: balance;
}

/* ------------------------------------------------------------------
   5. .party-status — кто что сделал (§15, §21)

   Знак и слово всегда вместе: галочка отвечает за «увидел издалека»,
   слово — за «понял точно». Одного знака мало, одного слова мало.
   ------------------------------------------------------------------ */

.party-status {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  padding: 0.75rem 0.875rem;
  border-radius: var(--r-card);
  background: var(--card);
  list-style: none;
}

/* Строка переносится: в разметке имя и состояние лежат прямо в .party,
   без обёртки, и на узком экране «Константин Константинопольский (вы)»
   вместе со словом «ожидается» требует 339px. Раньше состояние просто
   уезжало за край экрана вместе с горизонтальной прокруткой всей
   страницы; теперь оно встаёт под именем. Высота строки от этого
   растёт, а не падает — 3rem остаются нижней границей. */
.party {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.625rem;
  min-height: 3rem;
  padding: 0.1875rem 0;
}

.party-text {
  display: flex;
  flex-direction: column;
  gap: 0.0625rem;
  min-width: 0;
}

/* Имя переносится только тогда, когда целиком не влезает, и не
   влияет на минимальную ширину колонки: с anywhere «Иван Иванов»
   в тесной строке разваливается на «Ивано / в» ещё до того, как
   место действительно кончилось. */
.party-name {
  font-size: var(--fs-lead);
  font-weight: 500;
  color: var(--text);
  /* min-width снимает запрет гибкой строки сжимать имя ниже самого
     длинного слова — без него break-word ниже никогда не срабатывает:
     строка раздувается раньше, чем слово успевает перенестись. */
  min-width: 0;
  overflow-wrap: break-word;
}

.party-state {
  font-size: var(--fs-body);
  color: var(--text-2);
}

/* Знак состояния. Общий с полосой шагов проверки личности — там
   ровно та же смысловая пара «сделано / ожидается», и рисовать её
   дважды значит однажды развести их видом. */
.party-mark,
.step-mark {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 2.25rem;                 /* 36px — видно боковым зрением */
  height: 2.25rem;
  border-radius: 50%;
  background: var(--glass);
  color: var(--text-3);
  box-shadow: inset 0 0 0 1px var(--hair);
}

/* Ожидается — полый кружок: он читается как «место, которое ещё
   не заполнено», в отличие от закрашенного. */
.party.wait .party-mark::after,
.step.wait .step-mark::after,
.step.now .step-mark::after {
  content: '';
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 50%;
  box-shadow: inset 0 0 0 0.125rem currentColor;
}

/* Текущий шаг проверки личности — тот же кружок, но лаймовый и
   плотный: он не «ожидается», он «сейчас». */
.step.now .step-mark {
  color: var(--lime);
}

.step.now .step-mark::after {
  box-shadow: inset 0 0 0 0.375rem currentColor;
}

.party.done .party-mark,
.step.done .step-mark {
  background: var(--lime);
  color: var(--ink);
  box-shadow: none;
}

.party.done .party-mark::after,
.step.done .step-mark::after {
  content: '';
  width: 1.125rem;
  height: 1.125rem;
  background: currentColor;
  clip-path: var(--check-shape);
}

/* Сделанное подсвечивается и словом: цвет здесь дублирует смысл,
   а не заменяет его. */
.party.done .party-state {
  color: var(--lime-soft);
}

/* ------------------------------------------------------------------
   6. .undef-card — условие не определено (§12)

   Заметная, но не тревожная. ИИ не имеет права додумывать условие,
   значит карточка сообщает о пробеле в договорённости — это повод
   поговорить, а не сигнал бедствия. Отсюда пастельный знак вопроса
   и обычная тёмная плашка вместо «предупреждающей» окраски.
   ------------------------------------------------------------------ */

.undef-card {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.875rem;
  border-radius: var(--r-card);
  background: var(--card-2);
  color: var(--text);
}

/* Значок в круге — icons.js кладёт внутрь .ic готовый svg.
   Подпись словами даёт сама карточка, отдельной строки под значком
   не нужно. */
.undef-card > .ic {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background: var(--lime-soft);
  color: var(--ink);
}

.undef-card.ok > .ic {
  background: var(--lime);
}

.undef-text {
  display: flex;
  flex-direction: column;
  gap: 0.1875rem;
  min-width: 0;
}

/* Карточка неопределённого условия стоит рядом со значком 36px,
   и на узком экране тексту остаётся немного. Слова «определено»
   и «Рекомендуется» шире этой полосы, поэтому им разрешён перенос
   внутри слова: пробел в договорённости — это то, ради чего карточка
   существует, и прочитать её надо целиком. */
.undef-text h3 {
  font-size: var(--fs-lead);
  font-weight: 500;
  color: var(--text);
  overflow-wrap: break-word;
}

.undef-what {
  font-size: var(--fs-body);
  line-height: 1.4;
  color: var(--text-2);
  text-wrap: pretty;
  overflow-wrap: break-word;
}

/* Список условий: карточки одна под другой, без разделителей. */
.undef-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  list-style: none;
}

/* ------------------------------------------------------------------
   7. .doc-text — текст договора для чтения

   Три вещи, от которых зависит, прочтут договор или пролистают:
   длина строки, межстрочное расстояние и воздух между разделами.
   34em — это примерно 60–70 знаков в строке, дальше глаз теряет
   начало следующей строки; 1.55 — межстрочное для чтения с листа,
   а не для подписи под кнопкой.
   ------------------------------------------------------------------ */

.doc-text {
  max-width: 34em;
  padding: 1rem 0.875rem;
  border-radius: var(--r-card);
  background: var(--card);
  color: var(--text);
  font-size: var(--fs-body);
  line-height: 1.55;
  /* Сервер отдаёт готовый текст с переносами строк, и js кладёт его
     через textContent. Без pre-wrap абзацы договора слиплись бы
     в одну простыню. Размеченный текст — .doc-text.rich ниже. */
  white-space: pre-wrap;
  overflow-wrap: break-word;
  text-wrap: pretty;
}

.doc-text.rich {
  white-space: normal;
}

/* Разделы договора разделяются пустотой, а не линиями: линий в
   приложении нет вообще, а полтора интервала между абзацами
   человек читает как «здесь новая мысль». */
.doc-text.rich > * + * {
  margin-top: 0.875rem;
}

.doc-text.rich h2,
.doc-text.rich h3 {
  margin-top: 1.375rem;
  font-size: var(--fs-lead);
  font-weight: 500;
  color: var(--lime-soft);
}

.doc-text.rich > :first-child {
  margin-top: 0;
}

.doc-text.rich ul,
.doc-text.rich ol {
  padding-left: 1.125rem;
}

.doc-text.rich li + li {
  margin-top: 0.5rem;
}

/* ------------------------------------------------------------------
   8. .amount-field — сумма (§16)

   Сумму вводят вдвоём и вслепую, поэтому цифры остаются крупнейшим
   вводом приложения — до 30px, вдвое крупнее обычного текста. Валюта
   стоит рядом, а не в отдельной карточке: это одно решение
   («сколько и в чём»), и разносить его по экрану незачем.
   ------------------------------------------------------------------ */

.amount-field {
  display: flex;
  align-items: stretch;
  gap: 0.5rem;
}

/* Поле выше обычного (56px против 48px): это главный ввод экрана,
   и промахнуться мимо него нельзя. Крупные цифры сами требуют высоты. */
/* Второй селектор записан с тегом намеренно: theme.css красит поля
   через input[type='text'], и голый класс .amount-input проиграл бы
   ему по весу — поле осталось бы обычной высоты с обычными цифрами. */
.amount-field input,
input.amount-input {
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
  min-height: 3.5rem;
  padding: 0 0.875rem;
  border-radius: var(--r-card-s);
  background: var(--card-2);
  color: var(--text);
  font-size: clamp(1.375rem, 6vw, 1.875rem);   /* 22…30px */
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  text-align: left;
}

/* Валюта: список ровно той же высоты, что поле, и не шире, чем нужно
   трём буквам. Стрелку и заливку списка задаёт theme.css. */
.amount-field select,
.amount-cur {
  flex: 0 0 auto;
  width: auto;
  min-width: 6rem;
  min-height: 3.5rem;
  font-size: var(--fs-lead);
  font-weight: 500;
}

.amount-cap {
  color: var(--text-2);
}

/* Подтверждённая сумма на экранах §17 и §24 — крупно, но переносимо:
   «12 500 ₽» на узком телефоне должно уметь встать в две строки,
   иначе вылезет за край.
   Шкала пересчитана по самой длинной реальной сумме — «1 234 567,89 ₽».
   Разряды в ней разделены неразрывным пробелом (deal.js, fmtMoney), то
   есть двенадцать знаков переносу не подлежат вовсе, и слишком крупный
   кегль превращал её в строку шириной в полтора экрана. Нижняя граница
   18px подобрана так, чтобы такая сумма целиком помещалась в карточку
   на 280px, и всё равно остаётся заметно крупнее обычного текста. */
.amount-big {
  font-size: clamp(1.125rem, 5.5vw, 2rem);
  overflow-wrap: break-word;
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  text-wrap: balance;
}

/* ------------------------------------------------------------------
   9. .verdict-ok / .verdict-bad — суммы совпали и не совпали (§17, §18)

   Оба экрана — один знак и один текст. Красного в палитре нет и не
   будет, поэтому «не совпало» решено не цветом тревоги, а формой:
   лаймовый круг с галочкой против белого круга со знаком внимания.
   Белое пятно на тёмно-зелёном — самый контрастный элемент
   приложения, и этого достаточно, чтобы человек остановился.
   ------------------------------------------------------------------ */

.verdict {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  text-align: center;
}

.verdict .hero,
.verdict-note {
  text-wrap: balance;
}

.verdict-note {
  font-size: var(--fs-lead);
  line-height: 1.4;
  color: var(--text-2);
  max-width: 28em;
}

.verdict-mark {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  flex: 0 0 auto;
  width: 4.5rem;                  /* 72px */
  height: 4.5rem;
  border-radius: 50%;
}

.verdict-ok .verdict-mark {
  background: var(--lime);
  color: var(--ink);
}

/* Галочка той же формы, что в статусах сторон. */
.verdict-ok .verdict-mark::after {
  content: '';
  width: 2.125rem;
  height: 2.125rem;
  background: currentColor;
  clip-path: var(--check-shape);
}

.verdict-bad .verdict-mark {
  background: var(--white);
  color: var(--ink);
}

/* Знак внимания собран из палочки и точки, а не взят эмодзи:
   эмодзи в интерфейсе запрещены, а системный «⚠» на разных
   телефонах рисуется по-разному — от плоского треугольника до
   жёлтой картинки с чужой палитрой. */
.verdict-bad .verdict-mark::before {
  content: '';
  width: 0.375rem;
  height: 1.5rem;
  border-radius: var(--r-pill);
  background: currentColor;
}

.verdict-bad .verdict-mark::after {
  content: '';
  width: 0.375rem;
  height: 0.375rem;
  border-radius: 50%;
  background: currentColor;
}

/* ------------------------------------------------------------------
   10. .identity-cam — подтверждение личности (§20, §39.19)

   Круглая рамка вокруг лица делает две вещи сразу: показывает, куда
   поместить голову, и отличает проверку от обычного видеозвонка,
   где кадр прямоугольный. Кольцо мягкое, стеклянное; лаймовым оно
   становится, только когда идёт шаг, — цвет здесь означает «сейчас».
   ------------------------------------------------------------------ */

.identity-cam {
  position: relative;
  align-self: center;
  width: min(62vw, 14rem);
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
  background: var(--card-2);
  box-shadow: 0 0 0 0.375rem var(--glass), inset 0 0 0 1px var(--hair);
  transition: box-shadow 0.2s var(--ease);
}

.identity-cam.on {
  box-shadow: 0 0 0 0.375rem var(--lime), inset 0 0 0 1px var(--hair);
}

.identity-cam video,
.identity-cam img,
.identity-cam canvas,
.identity-cam iframe {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Себя человек узнаёт зеркальным — как в зеркале над раковиной.
     Незеркальное собственное лицо читается как чужое, и человек
     поворачивает голову не в ту сторону. */
  transform: scaleX(-1);
}

/* Внешний провайдер рисует свой WebSDK на этом же экране: его iframe
   зеркалить нельзя, он показывает собственную подсказку с текстом. */
.identity-cam.sdk video,
.identity-cam.sdk iframe {
  transform: none;
}

/* Текущее действие — самая крупная строка экрана после заголовка:
   её читают, держа телефон на вытянутой руке. */
.identity-say {
  font-size: var(--fs-h2);
  font-weight: 500;
  line-height: 1.2;
  color: var(--lime-soft);
  text-align: center;
  text-wrap: balance;
}

/* Полоса шагов. Сама полоса — это «сколько осталось», список под
   ней — «что именно». Одной полосы мало: она не называет действий. */
.step-bar {
  --done: 0;
  height: 0.5rem;
  border-radius: var(--r-pill);
  background: var(--glass);
  overflow: hidden;
  box-shadow: inset 0 0 0 1px var(--hair);
}

.step-bar > span {
  display: block;
  width: calc(100% * clamp(0, var(--done), 1));
  height: 100%;
  border-radius: var(--r-pill);
  background: var(--lime);
  transition: width 0.3s var(--ease);
}

.steps {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  list-style: none;
}

.step {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  min-height: 3rem;
  font-size: var(--fs-body);
  color: var(--text-2);
}

.step.now {
  color: var(--text);
  font-weight: 500;
}

.step.done {
  color: var(--lime-soft);
}

/* ------------------------------------------------------------------
   11. .doc-view — итоговый документ (§24, §27)

   Восемь разделов по порядку. Каждый — отдельная плашка: документ
   читают не подряд, а выборочно («а где там сумма?»), и плашка
   работает закладкой.
   ------------------------------------------------------------------ */

.doc-view {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.doc-sec {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  padding: 1rem 0.875rem;
  border-radius: var(--r-card);
  background: var(--card);
}

.doc-sec > h2 {
  font-size: var(--fs-h2);
  font-weight: 500;
  color: var(--lime-soft);
  text-wrap: balance;
}

/* Внутри документа текст договора уже лежит на плашке раздела —
   второй фон и второе скругление здесь были бы коробкой в коробке. */
.doc-view .doc-text {
  max-width: none;
  padding: 0;
  border-radius: 0;
  background: none;
}

/* Пара «подпись — значение». Значение под подписью, а не рядом:
   в две колонки на телефоне и то и другое сжимается до нечитаемого,
   а вертикальная пара остаётся крупной при любой ширине.

   Отступы расставлены соседними селекторами, а не общим gap:
   при равномерном gap подпись и значение отстояли бы друг от друга
   ровно так же, как две разные пары, и документ рассыпался бы на
   строки без пар. Здесь внутри пары воздуха мало, между парами —
   много, и глаз сам собирает их обратно. */
.doc-rows dt,
.doc-row-key {
  font-size: var(--fs-cap);
  color: var(--text-2);
}

.doc-rows dd,
.doc-row-val {
  margin: 0.0625rem 0 0;
  font-size: var(--fs-body);
  line-height: 1.4;
  color: var(--text);
  overflow-wrap: break-word;
}

.doc-rows dd + dt,
.doc-row + .doc-row {
  margin-top: 0.625rem;
}

/* Отметки участников (§25): те же строки статуса, что на s-ack,
   но без собственной плашки — она уже есть у раздела. */
.doc-sec .party-status {
  padding: 0;
  border-radius: 0;
  background: none;
}

/* Место под SVG-схему местоположений (§23). Схему рисует сервер
   (src/map.js) и отдаёт разметкой — здесь только рама и поведение:
   схема тянется по ширине, высоту держит соотношение сторон.
   Плашка под ней светлее фона, чтобы точки и линейка читались,
   даже если схема ещё не пришла. */
.doc-map {
  width: 100%;
  aspect-ratio: 4 / 3;
  border-radius: var(--r-card-s);
  overflow: hidden;
  background: var(--card-2);
  box-shadow: inset 0 0 0 1px var(--hair);
}

.doc-map > svg,
.doc-map > img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
}

/* Снимок с проверки личности (`docs/FIXES12.md` Р3). Ширина ограничена:
   во всю колонку лицо выглядело бы паспортной страницей, а это отметка в
   разделе подтверждений. Высоту держат размеры самого кадра (атрибуты
   width/height у img) — пока картинка раскодируется, текст под ней не
   прыгает. */
.doc-shot {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0;
}

.doc-shot > img {
  display: block;
  width: 100%;
  max-width: 20rem;
  height: auto;
  border-radius: var(--r-card-s);
  background: var(--card-2);
  box-shadow: inset 0 0 0 1px var(--hair);
}

/* Журнал событий (§30). Время — колонкой слева, ровным моноширинным
   столбиком: так видно последовательность, а не набор строк. */
.doc-log {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  list-style: none;
}

.doc-log > li {
  display: flex;
  align-items: baseline;
  gap: 0.625rem;
  font-size: var(--fs-body);
  line-height: 1.35;
}

.doc-log-at {
  flex: 0 0 auto;
  min-width: 3.75rem;
  font-family: var(--font-mono);
  font-size: var(--fs-cap);
  font-variant-numeric: tabular-nums;
  color: var(--text-2);
}

.doc-log-what {
  min-width: 0;
  color: var(--text);
  overflow-wrap: break-word;
}

/* --- Сводка документа (docs/FIXES8.md Д2) --------------------------

   По референсу: крупное значение и мелкая подпись под ним, одна
   лаймовая плитка на экран — для главного, остальные тёмные. Всё
   остальное содержимое документа лежит ниже сложенными плашками
   (.doc-fold) — ни одна строка §24 не пропала, но читать их подряд
   больше не приходится.
   ------------------------------------------------------------------ */

/* Лаймовая плитка: состояние договора и сумма. Незавершённый договор
   — та же плитка, но серая: лайм здесь означает «сделано». */
.doc-hero {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.125rem;
  border-radius: var(--r-card);
  background: var(--lime);
  color: var(--ink);
}

.doc-hero.wait {
  background: var(--gray);
  color: var(--text);
}

.doc-hero-head {
  display: flex;
  align-items: center;
  gap: 0.875rem;
}

/* Знак в квадрате со скруглением — как на референсе рядом с
   заголовком карточки. */
.doc-hero-mark {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 3rem;
  height: 3rem;
  border-radius: 0.875rem;
  background: rgba(16, 22, 12, 0.14);
  color: var(--ink);
}

.doc-hero.wait .doc-hero-mark {
  background: var(--lime);
}

.doc-hero-mark > svg {
  width: 1.5rem;
  height: 1.5rem;
}

.doc-hero-words {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}

.doc-hero-words h2 {
  font-size: var(--fs-h2);
  font-weight: 600;
  line-height: 1.15;
  text-wrap: balance;
}

.doc-hero-words p {
  font-size: var(--fs-body);
  opacity: 0.74;
}

.doc-hero-sum {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

/* Сумма — самое крупное на экране: ради неё документ и открывают.
   Шкала та же, что у .amount-big, чуть выше сверху. */
.doc-hero-amount {
  font-size: clamp(1.75rem, 8vw, 2.5rem);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: break-word;
  text-wrap: balance;
}

.doc-hero-cap {
  font-size: var(--fs-cap);
  line-height: 1.35;
  opacity: 0.74;
  text-wrap: pretty;
}

/* Плитки по две в ряд; на совсем узком экране — в столбик. */
.doc-tiles {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.5rem;
}

.doc-tile {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  min-width: 0;
  padding: 1rem 0.875rem;
  border-radius: var(--r-card);
  background: var(--card);
  color: var(--text);
}

.doc-tile-cap {
  font-size: var(--fs-cap);
  line-height: 1.3;
  color: var(--text-2);
}

.doc-tile-name {
  font-size: var(--fs-lead);
  font-weight: 500;
  line-height: 1.2;
  overflow-wrap: break-word;
}

/* Состояние подписи: точка и слово. Точка полая, пока не подписал. */
.doc-tile-state {
  display: flex;
  align-items: center;
  gap: 0.4375rem;
  font-size: var(--fs-cap);
  line-height: 1.3;
  color: var(--text-2);
}

.doc-tile-dot {
  flex: 0 0 auto;
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 50%;
  box-shadow: inset 0 0 0 0.125rem var(--text-3);
}

.doc-tile.signed .doc-tile-state {
  color: var(--lime-soft);
}

.doc-tile.signed .doc-tile-dot {
  background: var(--lime);
  box-shadow: none;
}

/* Плитка факта: значок сверху, крупное значение, подпись. Нечётная
   последняя занимает весь ряд — полплитки пустоты рядом с ней читалось
   бы как недогруженное место. */
.doc-tile.fact {
  gap: 0.5rem;
}

.doc-tiles.facts > .doc-tile:last-child:nth-child(odd) {
  grid-column: 1 / -1;
}

.doc-tile-ic {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 0.75rem;
  background: rgba(205, 245, 111, 0.14);
  color: var(--lime);
}

.doc-tile-ic > svg {
  width: 1.25rem;
  height: 1.25rem;
}

.doc-tile-value {
  font-size: 1.125rem;
  font-weight: 500;
  line-height: 1.2;
  overflow-wrap: break-word;
  text-wrap: balance;
}

/* Оговорки — складка под сводкой; заголовок лаймовый, чтобы её не
   приняли за ещё один раздел подробностей. */
.doc-fold.warn > .doc-fold-head .doc-fold-words > b {
  color: var(--lime-soft);
}

.doc-fold.warn > .doc-fold-head .doc-fold-ic {
  background: var(--lime);
  color: var(--ink);
}

.doc-notice-list {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  list-style: none;
}

.doc-notice {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  font-size: var(--fs-body);
  line-height: 1.4;
  color: var(--text-2);
  text-wrap: pretty;
}

.doc-notice > b {
  font-size: var(--fs-cap);
  font-weight: 500;
  color: var(--text-3);
}

.doc-notice.warn > b {
  color: var(--lime-soft);
}

.doc-notice.warn > p {
  color: var(--text);
}

/* Текст договора: карточка с заголовком, разделы — подзаголовками. */
.doc-agree {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1.125rem;
  border-radius: var(--r-card);
  background: var(--card);
}

.doc-agree > h2 {
  font-size: var(--fs-h2);
  font-weight: 500;
  color: var(--lime-soft);
}

.doc-view .doc-agree-text {
  font-size: var(--fs-lead);
  line-height: 1.5;
}

.doc-view .doc-agree-text > h3 {
  margin-top: 1rem;
  font-size: var(--fs-cap);
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-3);
}

.doc-view .doc-agree-text > h3 + p {
  margin-top: 0.25rem;
}

.doc-view .doc-agree-text > p.cap {
  font-size: var(--fs-cap);
  color: var(--text-3);
}

/* Складки: заголовок раздела в строку с подписью и уголком; внутри —
   те же строки «подпись — значение», что и раньше. Родной <details>:
   раскрытие без js, с клавиатуры, с экранного диктора. */
.doc-folds {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

.doc-folds-title {
  padding: 0 0.25rem;
  font-size: var(--fs-cap);
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-3);
}

.doc-fold {
  border-radius: var(--r-card);
  background: var(--card);
  overflow: hidden;
}

.doc-fold-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 4rem;
  padding: 0.75rem 0.875rem;
  cursor: pointer;
  list-style: none;
  -webkit-tap-highlight-color: transparent;
}

.doc-fold-head::-webkit-details-marker {
  display: none;
}

.doc-fold-head:focus-visible {
  outline: 0.125rem solid var(--lime);
  outline-offset: -0.125rem;
}

.doc-fold-ic {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 0.8125rem;
  background: rgba(205, 245, 111, 0.14);
  color: var(--lime);
}

.doc-fold-ic svg {
  width: 1.25rem;
  height: 1.25rem;
}

.doc-fold-words {
  display: flex;
  flex-direction: column;
  gap: 0.0625rem;
  flex: 1 1 auto;
  min-width: 0;
}

.doc-fold-words > b {
  font-size: var(--fs-lead);
  font-weight: 500;
  color: var(--text);
  overflow-wrap: break-word;
}

.doc-fold-words > small {
  font-size: var(--fs-cap);
  line-height: 1.3;
  color: var(--text-2);
  overflow-wrap: break-word;
}

.doc-fold-chev {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--glass);
  color: var(--text-2);
  transition: transform 0.24s var(--ease), background 0.16s;
}

.doc-fold-chev svg {
  width: 1.125rem;
  height: 1.125rem;
}

.doc-fold[open] > .doc-fold-head .doc-fold-chev {
  transform: rotate(180deg);
  background: var(--lime);
  color: var(--ink);
}

.doc-fold-body {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  padding: 0 0.875rem 1rem;
}

/* Внутри складки строки-статусы и текст лежат на её фоне, без второй
   плашки — как раньше в .doc-sec. Знак и слова — в одну строку: полная
   отметка времени длинная, и без явной доли колонка текста уезжала
   под знак, а список из восьми отметок растягивался вдвое. */
.doc-fold-body .party-status {
  padding: 0;
  border-radius: 0;
  background: none;
}

.doc-fold-body .party {
  flex-wrap: nowrap;
}

.doc-fold-body .party-text {
  flex: 1 1 0;
}

.doc-fold-body .doc-text {
  max-width: none;
  padding: 0;
  border-radius: 0;
  background: none;
}

.doc-fold-body > h3 {
  margin-top: 0.375rem;
  font-size: var(--fs-lead);
  font-weight: 500;
  color: var(--lime-soft);
}

/* История версий на s-doc: та же складка снаружи документа. */
.doc-versions {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  list-style: none;
}

.doc-versions > li {
  display: flex;
  flex-direction: column;
  gap: 0.0625rem;
}

#s-doc > .doc-fold {
  margin-top: -0.25rem;
}

@media (max-width: 20rem) {
  .doc-tiles {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (prefers-reduced-motion: reduce) {
  .doc-fold-chev {
    transition: none;
  }
}

/* ------------------------------------------------------------------
   12. .list / .list-card — «Мои встречи» и «Мои договоры» (§29)
   ------------------------------------------------------------------ */

.list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  list-style: none;
}

/* Карточка списка — это кнопка во всю ширину: цель размером с
   карточку, а не строчка-ссылка внутри неё. Содержимое колонкой
   и по левому краю — заголовок, пояснение, статус: так строка
   читается сверху вниз одним движением глаза и не ломается,
   когда имя собеседника длинное. */
.list-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.375rem;
  width: 100%;
  min-height: 3.75rem;
  padding: 0.875rem 1rem;
  border-radius: var(--r-card);
  background: var(--gray);      /* тот же серый, что у строк на главном */
  color: var(--text);
  text-align: left;
  transition: transform 0.12s var(--ease), background 0.16s;
}

.list-card:active {
  transform: scale(0.985);
  background: #4f4f4e;
}

/* Заголовок и подпись карточки — строки в вертикальной колонке, и
   ширину им назначает самое длинное слово в них: «Константинопольский»
   при «крупном тексте» шире карточки, и строка просто вылезала за её
   край. anywhere уменьшает эту минимальную ширину, и слово переносится
   внутри себя — но только когда иначе не помещается. */
.list-title {
  font-size: var(--fs-lead);
  font-weight: 500;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.list-sub {
  font-size: var(--fs-body);
  color: var(--text-2);
  /* В подписи карточки стоит имя собеседника и первая строка договора —
     то есть чужой текст произвольной длины. Перенос ей нужен по той же
     причине и на тех же основаниях, что заголовку выше. */
  overflow-wrap: anywhere;
}

/* Статус-чип. «Завершён» красится пастельным лаймом, а не главным:
   в списке из десяти договоров десять насыщенных лаймовых пятен
   спорили бы с единственной лаймовой кнопкой экрана. */
.chip.done {
  background: var(--lime-soft);
  color: var(--ink);
  box-shadow: none;
}

/* Знак перед словом в чипе — тот же язык, что в статусах сторон:
   галочка «сделано», полый кружок «ждём». Слово рядом обязательно. */
.chip.done::before {
  content: '';
  flex: 0 0 auto;
  width: 0.8125rem;
  height: 0.8125rem;
  background: currentColor;
  clip-path: var(--check-shape);
}

.chip.wait::before {
  content: '';
  flex: 0 0 auto;
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 50%;
  box-shadow: inset 0 0 0 0.125rem currentColor;
}

/* ------------------------------------------------------------------
   13. .avatar — фотография профиля (§4)

   Заглушка — первая буква имени, а не силуэт человека: силуэт
   выглядит как «данные не загрузились», буква — как осознанный
   знак. Буква лежит фоном, фотография кладётся поверх, поэтому
   разметке достаточно не вставлять <img>, когда фотографии нет.
   ------------------------------------------------------------------ */

.avatar {
  position: relative;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 3rem;                    /* 48px — размер для списков */
  height: 3rem;
  border-radius: 50%;
  overflow: hidden;
  background: var(--card-2);
  color: var(--lime-soft);
  box-shadow: inset 0 0 0 1px var(--hair);
  font-size: var(--fs-h2);
  font-weight: 500;
  line-height: 1;
  text-transform: uppercase;
  user-select: none;
}

.avatar::before {
  content: attr(data-letter);
}

.avatar > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Крупный вариант — на экране профиля, где фотография и есть
   содержание экрана. */
.avatar.big {
  width: 5.5rem;                  /* 88px */
  height: 5.5rem;
  font-size: clamp(1.75rem, 8vw, 2.375rem);
}

/* ------------------------------------------------------------------
   14. s-boot · Загрузка (§39.1)

   Пока /api/me не ответил, виден только этот экран — ни одного
   мелькающего промежуточного. Отсюда центрирование: на экране
   нет ничего, кроме знака приложения.
   ------------------------------------------------------------------ */

#s-boot.on {
  align-items: center;
  justify-content: center;
  text-align: center;
}

.boot-mark {
  display: grid;
  place-items: center;
  color: var(--lime);
  /* Медленное дыхание вместо крутящегося кружка: вращение читается
     как «зависло», спокойная пульсация — как «идёт». */
  animation: boot-breathe 2.4s ease-in-out infinite alternate;
}

@keyframes boot-breathe {
  from { opacity: 0.55; }
  to { opacity: 1; }
}

#s-boot .hero,
#s-boot .lead {
  text-align: center;
}

/* Сбой сети: крупный текст и одна кнопка «Повторить». */
#s-boot .actions {
  width: 100%;
  margin-top: 1rem;
}

/* ------------------------------------------------------------------
   15. s-reg · Регистрация (§39.2) и s-otp · Код (§39.3)
   ------------------------------------------------------------------ */

.form {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

/* Подпись над полем, а не placeholder внутри: placeholder исчезает
   при первом знаке, и человек перестаёт понимать, что он заполняет. */
.form label {
  display: block;
  margin-bottom: 0.25rem;
  font-size: var(--fs-cap);
  color: var(--text-2);
}

/* Код разработки (SMS_PROVIDER=dev). Показывается крупно и с честной
   пометкой: без него в режиме разработки войти нельзя вовсе, а
   спрятать его мелким шрифтом — значит заставить искать. */
.dev-code {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  padding: 0.75rem 0.875rem;
  border-radius: var(--r-card-s);
  background: var(--card-2);
  text-align: center;
}

.dev-code .code {
  font-family: var(--font-mono);
  color: var(--lime-soft);
}

.dev-code .cap {
  color: var(--text-3);
}

#s-otp .code-slots {
  margin: 0.125rem 0 0.375rem;
}

/* Клавиатура на экране кода — та же, что на s-join: одна привычка
   на два экрана вместо двух разных. Крупнее цифр в ячейках, потому
   что по клавишам работает рука, а не глаз. */
#s-otp .keypad .key {
  font-size: 1.625rem;            /* 26px */
}

/* Обратный отсчёт до повторной отправки. Строка, а не таймер на
   кнопке: надпись на кнопке, меняющаяся каждую секунду, мешает
   прочитать саму кнопку. */
.countdown {
  font-size: var(--fs-body);
  color: var(--text-2);
  text-align: center;
}

#s-otp .hint,
#s-reg .hint {
  text-align: center;
  color: var(--text-2);
}

/* ------------------------------------------------------------------
   16. s-model · Данные распознавания (`docs/FIXES7.md` Д6)

   Обязательный шаг регистрации: между кодом из сообщения и главным
   экраном. Здесь человек ждёт дольше, чем где-либо ещё в приложении
   — двести с лишним мегабайт, — и от того, что он видит эти минуты,
   зависит, дождётся ли он вообще.

   Отсюда три решения:

   1. Вес назван до нажатия и крупно. Это не подпись к кнопке, а то,
      на что человек соглашается: с мобильного интернета 233 МБ —
      решение, а не мелочь.
   2. Полоса показывает долю, мегабайты и остаток времени, а не
      «идёт загрузка». Неизмеримое ожидание кончается тем, что
      вкладку закрывают.
   3. Полоса светится сиренево-голубым свечением капсулы
      (`.capsule-glow` из motion.css). Приём сильный и от повтора
      тускнеет, поэтому во всём приложении он применён считаное
      число раз — и это один из них: минута ожидания, ради которой
      он и придуман.
   ------------------------------------------------------------------ */

/* Название модели и её вес: «GigaAM v3 · 233 МБ». Крупнее обычного
   текста и лаймовое — это главное показание карточки, ради которого
   она стоит на экране. Не --fs-h2: заголовок карточки уже набран им,
   и два одинаковых кегля подряд читаются как одна строка. */
.model-size {
  margin: 0;
  font-size: var(--fs-lead);
  font-weight: 500;
  line-height: 1.3;
  color: var(--lime-soft);
  font-variant-numeric: tabular-nums;
  text-wrap: pretty;
}

/* Полоса загрузки: сама полоса и строка чисел под ней. Одной полосы
   мало — она не называет ни мегабайтов, ни остатка времени; одних
   чисел мало — по ним не видно, сколько пути пройдено. */
.progress {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

/* Дорожка. Капсульная форма — та же, что у полосы шагов проверки
   личности (.step-bar): это одно и то же показание «сколько
   осталось», и разводить их видом незачем.

   position: relative обязателен: свечение .capsule-glow ложится
   отдельным слоем вокруг дорожки, и без точки отсчёта оно уехало бы
   к краю экрана. А вот overflow: hidden здесь нельзя — он обрезал бы
   этот слой ровно по дорожке, то есть убрал бы свечение целиком.
   Заливку внутри скругления держит её собственное скругление, оно
   у неё то же самое. */
.progress-track {
  position: relative;
  /* Свой контекст наложения: слой свечения стоит на z-index: -1 и без
     этого уходил бы под всю страницу — под фон и под виньетку, — а
     браузер на телефоне перерисовывал бы из-за него весь экран. */
  isolation: isolate;
  height: 0.75rem;
  border-radius: var(--r-pill);
  background: var(--glass);
  box-shadow: inset 0 0 0 1px var(--hair);
}

/* Заливка. Ширину пишет app.js в процентах; переход сглаживает
   рывки между кусками — файлы качаются в несколько потоков, и без
   него полоса дёргалась бы вперёд ступеньками. */
.progress-fill {
  display: block;
  width: 0;
  height: 100%;
  border-radius: var(--r-pill);
  background: var(--lime);
  transition: width 0.3s var(--e-out);
}

/* «74 % · 172 из 233 МБ · осталось около минуты». Моноширинные цифры
   обязательны: доля меняется восемь раз в секунду, и на пропорциональных
   цифрах строка дёргалась бы по ширине на каждом обновлении. */
.progress-nums {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.35;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  text-wrap: pretty;
}

/*
 * Свечение горит всё время загрузки.
 *
 * В motion.css свечение капсулы — событие: вспышка на .capsule.open,
 * которая гаснет сама. Здесь оно нужно состоянием — человек ждёт
 * минуты, и одна вспышка в начале ничего ему не скажет. Поэтому
 * слой дышит теми же кадрами breathe, что и знак приложения на
 * экране загрузки: медленный пульс читается как «идёт», в отличие
 * от вращения, которое читается как «зависло».
 *
 * Селектор с id перебивает правило motion.css по силе, а не по
 * порядку: файл движения подключён после этого и при равном весе
 * победил бы он. Гасить свечение при prefers-reduced-motion и в
 * экономном профиле незачем — motion.css гасит его сам, и оба его
 * правила сильнее этого.
 */
#modelBar.capsule-glow::before {
  /*
   * Здесь свечение не такое, как у капсулы в motion.css. Там слой
   * размыт фильтром, обрезан маской и в кадрах breathe растёт на 9% —
   * для полосы во всю ширину экрана это значило, что размытый слой
   * каждый кадр выезжал за края экрана, а телефон перерисовывал и
   * мерцал. Свет теперь мягкий сам по себе — радиальный градиент с
   * прозрачными краями, — не выходит за поля экрана и дышит только
   * прозрачностью: это рисует композитор, без перерисовки.
   */
  inset: -0.75rem -0.5rem;
  filter: none;
  -webkit-mask-image: none;
  mask-image: none;
  background: radial-gradient(
    60% 100% at 50% 50%,
    rgba(214, 196, 255, 0.55) 0%,
    rgba(255, 255, 255, 0.22) 45%,
    rgba(176, 210, 255, 0) 100%
  );
  opacity: 0.6;
  animation: glow-breathe 2.6s var(--e-in-out) infinite;
}

@keyframes glow-breathe {
  0%, 100% { opacity: 0.45; }
  50% { opacity: 0.95; }
}

/* ------------------------------------------------------------------
   17. s-home · Главный (§39.4)

   Четыре двери одна под другой. Нижней панели на этом экране нет
   намеренно: четыре крупные двери плюс дублирующая панель — это
   уже выбор из семи, а не линейный путь.
   ------------------------------------------------------------------ */

/* Дверь — это .btn с другой формой: высокая пилюля выглядит как
   надутая кнопка, карточное скругление — как раздел приложения.
   Класс ставится вместе с .btn, чтобы заливки, нажатие и состояние
   [disabled] пришли из темы и не переписывались здесь заново.
   72px — это две строки (название и подпись) плюс поля: ниже
   подпись начинает упираться в край. */
.door {
  min-height: 4.5rem;             /* 72px */
  padding: 0.875rem 1rem;
  border-radius: var(--r-card);
  gap: 0.75rem;
  justify-content: flex-start;
  text-align: left;
}

.door-text {
  display: flex;
  flex-direction: column;
  gap: 0.1875rem;
  min-width: 0;
  flex: 1 1 auto;
}

.door-title {
  font-size: var(--fs-btn);
  font-weight: 500;
  line-height: 1.15;
}

/* Подпись под названием двери («2 договора», «последняя встреча
   вчера»). Цвет наследуется и приглушается прозрачностью, а не
   берётся из --text-2: одна и та же дверь бывает лаймовой и
   стеклянной, а белый с прозрачностью на лайме исчезает. */
.door-sub {
  font-size: var(--fs-cap);
  font-weight: 400;
  line-height: 1.25;
  color: inherit;
  opacity: 0.72;
}

/* Стрелка справа — не отдельная кнопка, а часть двери. */
.door > .ic:last-child {
  margin-left: auto;
  opacity: 0.7;
}

/* ------------------------------------------------------------------
   18. s-meeting-new · Создание встречи (§39.5)
   ------------------------------------------------------------------ */

/* Белая карточка с номером — самый громкий элемент экрана, и на ней
   ровно одна вещь: шесть цифр, которые диктуют по телефону.
   Раскладка та же, что у s-invite в screens.css: один и тот же
   номер не должен выглядеть на двух экранах по-разному. */
#s-meeting-new .card.light {
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 0.5rem;
  padding: 1.5rem 0.875rem;
}

/* Meeting ID нужен поддержке, а не человеку: он стоит под номером,
   тише всего, но не мельче --fs-cap — нечитаемых надписей в
   приложении нет вообще. Прозрачность вместо цвета — карточка
   бывает и белой, и тёмной. */
.meet-id {
  font-family: var(--font-mono);
  font-size: var(--fs-cap);
  color: inherit;
  opacity: 0.6;
  overflow-wrap: anywhere;
}

#s-meeting-new .actions {
  margin-top: auto;
  padding-top: 0.75rem;
}

.wave-meter.pulse path {
  transform: none;
  animation: wave-pulse 2.6s ease-in-out infinite alternate;
}

.wave-meter.pulse path:nth-of-type(2) {
  animation-delay: -0.9s;
}

.wave-meter.pulse path:nth-of-type(3) {
  animation-delay: -1.8s;
}

@keyframes wave-pulse {
  from { transform: scaleY(0.34); }
  to { transform: scaleY(1); }
}

/* ------------------------------------------------------------------
   19. s-call · кнопка «Зафиксировать договорённость» (§39.7)

   Кнопка живёт в существующей панели .controls и получает от неё
   всю раскладку (theme.css растягивает прямого потомка .btn на всю
   ширину сетки). Здесь — только длинный текст: «Зафиксировать
   договорённость» не влезает в строку на узком телефоне, и ему
   нужно разрешение переноситься, не теряя высоты.
   ------------------------------------------------------------------ */

#btnDeal {
  padding: 0.5rem 0.875rem;
  line-height: 1.15;
  text-wrap: balance;
}

/* ------------------------------------------------------------------
   20. s-deal-start · Согласия (§39.8) и s-gps · Местоположение (§39.20)

   Согласие — это экран, а не галочка мелким шрифтом: человек должен
   прочитать, куда уйдёт звук (§8) и что попадёт в документ (§35),
   до того, как включится микрофон или запросятся координаты.
   ------------------------------------------------------------------ */

.consent {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  padding: 1rem 0.875rem;
  border-radius: var(--r-card);
  background: var(--card);
  font-size: var(--fs-body);
  line-height: 1.45;
  text-wrap: pretty;
}

.consent h2 {
  font-size: var(--fs-lead);
  font-weight: 500;
  color: var(--lime-soft);
}

/* Куда именно уходит звук при выбранном способе распознавания.
   Это главное предложение экрана согласия — оно выделено весом,
   чтобы его не пролистали вместе с остальным текстом. */
.consent .where {
  font-weight: 500;
  color: var(--text);
}

.consent ul {
  padding-left: 1.125rem;
}

.consent li + li {
  margin-top: 0.375rem;
}

/* Созвон не прерывается — об этом сказано прямо на экране, и строка
   стоит рядом с кнопками, а не в конце длинного текста. */
.consent-keep {
  font-size: var(--fs-body);
  color: var(--text-2);
  text-align: center;
}

/* ------------------------------------------------------------------
   21. s-dictate · Голосовой ввод (§39.9) и s-raw · Расшифровка (§39.10)
   ------------------------------------------------------------------ */

#s-dictate .wave-meter {
  height: 5rem;                   /* выше обычного: это главный
                                     показатель «вас слышно» */
  margin: 0.125rem 0;
}

/* Живой текст распознавания. Растёт вниз, но не бесконечно: когда
   текста больше экрана, прокручивается сам, а кнопки «Готово» и
   «Начать заново» остаются на месте — иначе человек говорит и
   смотрит, как уезжает кнопка. */
.dictate-live {
  min-height: 7rem;
  max-height: 46vh;
  overflow-y: auto;
  padding: 0.875rem;
  border-radius: var(--r-card-s);
  background: var(--card-2);
  font-size: var(--fs-lead);
  line-height: 1.5;
  text-wrap: pretty;
}

/* Ещё не подтверждённый кусок распознавания — приглушённо: он
   меняется на глазах, и его не нужно читать как окончательный. */
.dictate-live .partial {
  color: var(--text-2);
}

/* Подсказка с примером (§10 ТЗ): образец фразы, с которой стоит
   начать. Курсива нет — в геометрическом гротеске он чужероден. */
.example {
  padding: 0.75rem 0.875rem;
  border-radius: var(--r-card-s);
  background: var(--card);
  font-size: var(--fs-body);
  line-height: 1.45;
  color: var(--text-2);
}

.example b {
  display: block;
  margin-bottom: 0.1875rem;
  color: var(--lime-soft);
  font-weight: 500;
}

/* --- Рация: кнопка «Надиктовать», которую держат -------------------

   Запись идёт только пока кнопку держат (deal.js, `hold`), и вид
   кнопки обязан говорить об этом сам, без чтения инструкции:

     - в покое — лаймовая плашка с двумя строками: что это и как
       («Зажмите и держите, пока говорите»);
     - пока держат — плашка становится белой (самый громкий цвет
       палитры), микрофон в круге — лаймовым, вокруг расходятся два
       кольца, а подпись меняется на «Слушаем…». Всё это вместе, а не
       что-то одно: цвет видят издалека, кольца — боковым зрением,
       слова — тот, кто не понял первых двух.

   Выделение текста, вызов контекстного меню долгим нажатием и жесты
   прокрутки на самой кнопке погашены: Android на второй секунде
   удержания иначе показывает меню поверх записи, а iOS — лупу.

   Форма и место (`docs/FIXES12.md` Р1, просьба владельца): круг внизу
   экрана по центру, поверх всего остального. Прежде это была плашка во
   всю ширину в середине экрана, и пока лента расшифровки росла, кнопка
   уезжала вверх вместе с ней: чтобы сказать ещё фразу, её приходилось
   искать прокруткой. Теперь она там, где большой палец лежит сам, —
   как кнопка записи у диктофона и рации, — и не двигается никогда.

   Центрируется полями (`left: 0; right: 0; margin-inline: auto`), а не
   `transform: translateX(-50%)`: свой `transform` у кнопки уже занят —
   ею она вдавливается и растёт в руке (`:active`, `.held`), и сдвиг на
   половину ширины пропадал бы на каждом нажатии.

   Подпись «как» (`.ptt-sub`) — плашкой над кругом: в круг под палец
   влезает одно слово, а «Зажмите и держите, пока говорите» человек,
   который видит экран впервые, должен прочитать до первого касания.
   ------------------------------------------------------------------ */

.ptt-steps {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.875rem;
  border-radius: var(--r-card);
  background: var(--card);
  list-style: none;
}

.ptt-steps li {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  font-size: var(--fs-body);
  line-height: 1.3;
  color: var(--text);
}

/* Номер шага — лаймовый кружок с цифрой. Цифра читается сразу и задаёт
   порядок; значок пришлось бы разгадывать. */
.ptt-n {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 1.625rem;
  height: 1.625rem;
  border-radius: 50%;
  background: var(--lime);
  color: var(--ink);
  font-size: var(--fs-cap);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

:root {
  /* 120px — круг под большой палец, который прижимают, не целясь; меньше
     прежней плашки по площади, но больше любой другой кнопки приложения. */
  --ptt-size: 7.5rem;
  --ptt-bottom: calc(var(--safe-b) + 1.25rem);
  /* Сколько места внизу экрана занимает рация вместе с подписью над ней:
     столько содержимое экрана отступает снизу, чтобы последняя кнопка
     («Начать заново») прокручивалась выше круга, а не пряталась под ним. */
  --ptt-zone: calc(var(--ptt-bottom) + var(--ptt-size) + 4.5rem);
}

.ptt {
  position: fixed;
  /* Над содержимым и панелью разговора (40), под входящим приглашением
     (95): звонок важнее записи, и его карточка обязана быть видна. */
  z-index: 50;
  left: 0;
  right: 0;
  bottom: var(--ptt-bottom);
  display: block;
  width: var(--ptt-size);
  height: var(--ptt-size);
  margin-inline: auto;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--lime);
  color: var(--ink);
  font: inherit;
  text-align: center;
  cursor: pointer;
  isolation: isolate;
  /* Тёмный ободок отделяет круг от текста, который прокручивается под
     ним: лаймовое на лаймовом подсвеченном слове иначе сливалось бы. */
  box-shadow:
    0 0 0 0.375rem rgba(10, 14, 8, 0.72),
    0 1rem 2.25rem rgba(0, 0, 0, 0.6);
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.14s var(--ease), background 0.16s, box-shadow 0.2s;
}

.ptt-face {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  height: 100%;
  padding: 0.5rem;
}

.ptt-mic {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: rgba(16, 22, 12, 0.12);
  color: var(--ink);
  transition: background 0.16s, transform 0.16s var(--ease);
}

.ptt-mic .ic > svg {
  width: 1.625rem;
  height: 1.625rem;
}

/* Обёртка слов не задаёт раскладку: заголовок стоит в круге, подпись —
   над ним (`position: absolute` от `.ptt-face`). */
.ptt-words {
  display: contents;
}

.ptt-title {
  max-width: 100%;
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.1;
  overflow-wrap: anywhere;
}

.ptt-sub {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 0.875rem);
  transform: translateX(-50%);
  width: max-content;
  max-width: min(18rem, calc(100vw - 2rem));
  padding: 0.5rem 0.875rem;
  border-radius: var(--r-pill);
  background: var(--card-2);
  color: var(--text);
  font-size: var(--fs-body);
  font-weight: 500;
  line-height: 1.3;
  text-wrap: balance;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.12),
    0 0.75rem 1.75rem rgba(0, 0, 0, 0.55);
  pointer-events: none;
}

/* Содержимое экрана отступает снизу на высоту рации: прокрутив до конца,
   человек видит «Готово» и «Начать заново» над кругом, а не под ним. */
#s-dictate.on {
  padding-bottom: var(--ptt-zone);
}

/* Подсказка hint() стоит внизу по центру — ровно там, где теперь круг.
   На экране диктовки она поднимается над рацией. `:has()` нет в старых
   браузерах; там подсказка ляжет поверх круга на четыре секунды — она
   прозрачна для нажатий (`pointer-events: none`), запись это не ломает. */
body:has(#s-dictate.on) .hint-pop {
  bottom: var(--ptt-zone);
}

/* Низкий экран (телефон боком): круг меньше, иначе он закрыл бы половину
   ленты расшифровки. Палец от поворота не тоньше — 92px всё ещё больше
   любой обычной кнопки. */
@media (max-height: 30rem) {
  :root {
    --ptt-size: 5.75rem;
    --ptt-bottom: calc(var(--safe-b) + 0.75rem);
  }

  .ptt-mic {
    width: 2.25rem;
    height: 2.25rem;
  }

  .ptt-title {
    font-size: var(--fs-cap);
  }
}

/* Кольца лежат всегда, но видны только пока держат. */
.ptt-ring {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  opacity: 0;
  pointer-events: none;
  box-shadow: 0 0 0 0 rgba(205, 245, 111, 0.55);
}

.ptt:active {
  transform: scale(0.985);
}

/* Микрофон ещё включается: кнопка бледнее, подпись говорит об этом
   словами (deal.js), нажатие уже принимается и не пропадёт. */
.ptt.opening {
  background: var(--lime-soft);
}

/* Держат. Порядок правил важен: `.held` стоит после `:active`, чтобы
   рост на 2% перебивал вдавливание — нажатая рация растёт, а не
   проваливается: она «включилась». */
.ptt.held {
  background: var(--white);
  transform: scale(1.05);         /* круг растёт заметнее плашки: он меньше */
  box-shadow:
    0 0 0 0.375rem rgba(205, 245, 111, 0.55),
    0 0.75rem 2rem rgba(205, 245, 111, 0.28);
}

.ptt.held .ptt-mic {
  background: var(--lime);
  transform: scale(1.08);
}

.ptt.held .ptt-ring {
  opacity: 1;
  animation: ptt-ring 1.4s ease-out infinite;
}

.ptt.held .ptt-ring.two {
  animation-delay: 0.7s;
}

@keyframes ptt-ring {
  from { box-shadow: 0 0 0 0 rgba(205, 245, 111, 0.55); }
  to { box-shadow: 0 0 0 1.25rem rgba(205, 245, 111, 0); }
}

/* Распознавать нечем — рация гаснет вместе с волной: обещать запись,
   из которой не выйдет ни слова, нельзя. */
.ptt[disabled] {
  opacity: 0.38;
  pointer-events: none;
}

.ptt:focus-visible {
  outline: 0.1875rem solid var(--white);
  outline-offset: 0.1875rem;
}

@media (prefers-reduced-motion: reduce) {
  .ptt,
  .ptt-mic {
    transition: none;
  }

  .ptt.held {
    transform: none;
  }

  .ptt.held .ptt-ring {
    animation: none;
    box-shadow: 0 0 0 0.5rem rgba(205, 245, 111, 0.35);
  }
}

/* ------------------------------------------------------------------
   22. s-ai · Договор от ИИ (§39.11) и s-edit · Правка (§39.12)
   ------------------------------------------------------------------ */

#s-ai .undef-list,
#s-ai .note {
  margin-top: 0.125rem;
}

/* Между текстом договора и кнопками — воздух: кнопка, приклеенная
   к последней строке текста, нажимается раньше, чем текст дочитан. */
#s-ai .actions,
#s-review .actions,
#s-edit .actions {
  margin-top: 0.75rem;
}

/* ------------------------------------------------------------------
   23. s-review · Проверьте договор (§39.13) и s-ack · Ознакомление (§39.14)
   ------------------------------------------------------------------ */

#s-ack.on {
  justify-content: center;
}

#s-ack .party-status,
#s-signed .party-status,
#s-sign .party-status {
  margin-top: 0.125rem;
}

/* ------------------------------------------------------------------
   24. s-amount (§39.15), s-amount-ok (§39.16), s-amount-bad (§39.17)
   ------------------------------------------------------------------ */

#s-amount .amount-field {
  margin: 0.375rem 0 0.1875rem;
}

/* Подтверждённая сумма на s-amount-ok лежит в элементе с классом .code,
   а .code в теме — это номер встречи: он набран по ширине экрана и
   не переносится. Для шести цифр это верно, для «1 234 567,89 ₽» —
   нет: такая строка при том же кегле шире экрана на любой ширине, от
   280px до планшета, и на s-amount-ok была единственная в приложении
   горизонтальная прокрутка в сотню с лишним пикселей.

   Правило стоит здесь, а не в теме: класс общий, а лечим мы один
   экран, где в нём лежит не номер. Знак валюты отделён обычным
   пробелом и может уйти на вторую строку — само число остаётся
   неразрывным и целым. */
#amountOkValue {
  font-size: clamp(1.25rem, 6vw, 2rem);
  white-space: normal;
  overflow-wrap: break-word;
}

#s-amount-ok.on,
#s-amount-bad.on,
#s-signed.on {
  justify-content: center;
}

#s-amount-ok .actions,
#s-amount-bad .actions,
#s-signed .actions {
  width: 100%;
  margin-top: 1rem;
}

/* ------------------------------------------------------------------
   25. s-sign (§39.18), s-identity (§39.19), s-signed (§39.21)
   ------------------------------------------------------------------ */

/* «Подписывая, вы соглашаетесь именно с этой версией» — строка,
   которая объясняет юридический смысл нажатия (§37). Она стоит
   между шапкой с отпечатком и кнопкой, то есть ровно там, где
   человек её прочитает. */
.sign-statement {
  padding: 0.75rem 0.875rem;
  border-radius: var(--r-card-s);
  background: var(--card-2);
  font-size: var(--fs-body);
  line-height: 1.45;
  color: var(--text);
  text-wrap: pretty;
}

#s-identity.on {
  align-items: stretch;
}

#s-identity .identity-cam {
  margin: 0.375rem 0;
}

/* ------------------------------------------------------------------
   26. s-result · Итог (§39.22) и s-pdf (§39.23)
   ------------------------------------------------------------------ */

#s-result .actions,
#s-doc .actions {
  margin-top: 0.75rem;
}

/* Отказ сервера отдать PDF (нет шрифта — 503) объясняется словами
   и не оставляет человека без выхода: «Открыть договор» и печать
   из браузера работают всегда. Это обычная плашка .note, здесь —
   только отбив от кнопок. */
#s-pdf .note {
  margin-top: 0.375rem;
}

/* ------------------------------------------------------------------
   27. s-contracts, s-meetings (§39.24), s-profile (§39.25), s-terms
   ------------------------------------------------------------------ */

#s-contracts .list,
#s-meetings .list {
  margin-top: 0.125rem;
}

/* Профиль: фотография и имя одной строкой сверху, дальше поля. */
.profile-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  border-radius: var(--r-card);
  background: var(--card);
}

.profile-head .grow {
  display: flex;
  flex-direction: column;
  gap: 0.1875rem;
  min-width: 0;
}

.profile-name {
  font-size: var(--fs-lead);
  font-weight: 500;
  overflow-wrap: break-word;
}

.profile-phone {
  font-family: var(--font-mono);
  font-size: var(--fs-body);
  color: var(--text-2);
}

/* Выбор файла: системную кнопку «Обзор…» не показываем никогда —
   она мелкая, называется по-разному в каждом браузере и не имеет
   подписи словами. Вместо неё нажимается обычная крупная кнопка
   (<label class="btn glass wide" for="...">), а само поле спрятано.

   display: none здесь нельзя — в части браузеров скрытое поле
   перестаёт открывать выбор файла и выпадает из порядка обхода
   с клавиатуры. Поэтому оно остаётся в потоке, но невидимым.
   1px — не размер интерфейса, а «не ноль»: у нулевого поля тот же
   отказ, что у display: none, и расти вместе с крупным текстом
   этой точке незачем. */
.file-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* Соглашение (§37) — длинный текст, и читают его глазами, а не
   пролистывают: те же 34em и 1.55, что у договора. */
#s-terms .doc-text {
  white-space: normal;
}

/* ------------------------------------------------------------------
   28. Узкие телефоны

   Отбирается только воздух. Ни одна кнопка, ни одно поле и ни один
   знак состояния здесь не уменьшаются: 320px по ширине — это не
   повод делать цель мельче пальца.
   ------------------------------------------------------------------ */

@media (max-width: 22.5rem) {
  .deal-head,
  .party-status,
  .doc-sec,
  .doc-text,
  .doc-hero,
  .doc-agree,
  .doc-notices,
  .doc-fold-head,
  .consent,
  .list-card,
  .profile-head {
    padding-left: 0.75rem;
    padding-right: 0.75rem;
  }

  .doc-fold-body {
    padding-left: 0.75rem;
    padding-right: 0.75rem;
  }

  /* Валюта уходит под поле суммы: рядом они оставляют цифрам
     меньше половины экрана, и сумма перестаёт читаться. */
  .amount-field {
    flex-direction: column;
  }

  .amount-field select,
  .amount-cur {
    width: 100%;
  }

  /* Время события встаёт над строкой: узкая колонка съедала бы
     половину ширины у самого текста события. */
  .doc-log > li {
    flex-direction: column;
    gap: 0.125rem;
  }

  .identity-cam {
    width: min(70vw, 11rem);
  }

  /* Фотография в профиле уступает место имени и телефону: на 320px
     крупный круг оставляет им полосу в полтора слова. Фотография —
     украшение, имя — содержание. */
  .avatar.big {
    width: 4.5rem;
    height: 4.5rem;
  }
}

/* ------------------------------------------------------------------
   29. Телефон в альбомной ориентации

   Высоты почти нет, и соблазн уменьшить кнопки здесь самый сильный.
   Не уменьшаем: палец в альбомном режиме не становится тоньше.
   Место берётся у круглой камеры, у полей плашек и у промежутков —
   то есть у пустоты и у украшений. Если и этого мало, экран просто
   прокручивается: прокрутка лучше кнопки не по размеру.
   ------------------------------------------------------------------ */

@media (orientation: landscape) and (max-height: 30rem) {
  /* Круглая рамка меряется высотой экрана, иначе в альбомном кадре
     она вылезает за верх и низ. Это украшение с функцией, а не
     кнопка, — уменьшать её можно. */
  .identity-cam {
    width: min(42vh, 14rem);
  }

  .deal-head,
  .party-status,
  .doc-sec,
  .doc-text,
  .consent,
  .profile-head {
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
  }

  .party {
    min-height: 3rem;             /* повторено намеренно: правило рядом
                                     с ужатыми отступами напоминает,
                                     что вот эту величину не трогаем */
  }

  .dictate-live {
    max-height: 34vh;
  }

  #s-dictate .wave-meter {
    height: 3.75rem;
  }

  .verdict-mark {
    width: 3.75rem;
    height: 3.75rem;
  }

  .verdict-ok .verdict-mark::after {
    width: 1.75rem;
    height: 1.75rem;
  }

  .avatar.big {
    width: 4.5rem;
    height: 4.5rem;
  }
}

/* ------------------------------------------------------------------
   30. Планшет и десктоп

   Колонка остаётся шириной --shell по центру — как и на всех
   остальных экранах. Растут только поля и украшения.
   ------------------------------------------------------------------ */

@media (min-width: 56.25rem) {
  .identity-cam {
    width: min(17rem, 60vh);
  }

  .doc-map {
    aspect-ratio: 3 / 2;          /* на широкой колонке схема двух
                                     точек читается лучше вытянутой */
  }

  .doc-log-at {
    min-width: 4.5rem;
  }
}

/* ------------------------------------------------------------------
   31. Отключение движения

   theme.css уже гасит анимации по prefers-reduced-motion, но два
   места надо назвать прямо. Дыхание логотипа на s-boot выключаем
   совсем: ускоренное до долей миллисекунды мигание хуже, чем его
   отсутствие. Пульсирующая волна ожидания замирает в спокойном
   среднем положении — экран ожидания не должен выглядеть сломанным.
   ------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .boot-mark {
    animation: none !important;
    opacity: 1;
  }

  .wave-meter.pulse path {
    animation: none !important;
    transform: scaleY(0.55) !important;
  }

  .step-bar > span {
    transition: none !important;
  }
}

/* ================================================================== */
/*  Дописанное по итогам живой проверки                                */
/*                                                                     */
/*  Эти классы стояли в разметке, но правил под них не было ни в одной */
/*  таблице: заголовок и подпись в карточках главного экрана слипались */
/*  в одну строку, а шапка сделки — та самая, по которой двое сличают  */
/*  версию и отпечаток глазами (§14), — выглядела обычным абзацем.     */
/* ================================================================== */

/* --- карточки главного экрана --------------------------------------- */

/*
 * Кнопка на главном — это две строки, а не одна: название действия и
 * подсказка, что за ним стоит. Без раскладки они склеивались в
 * «Мои встречи Пока ни одной», и человеку приходилось разбирать, где
 * кончается одно и начинается другое.
 */
.home-card {
  justify-content: flex-start;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  min-height: 4.25rem;
  text-align: left;
}

.home-card > .ic {
  flex: 0 0 auto;
}

.home-card-text {
  display: flex;
  flex-direction: column;
  gap: 0.1875rem;
  min-width: 0;
}

.home-card-title {
  font-size: var(--fs-btn);
  font-weight: 500;
  line-height: 1.2;
}

/* --fs-body, а не --fs-cap: подписи под иконками — короткие слова
   вроде «Звук», которые узнают по форме, и им хватает --fs-cap.
   Здесь же лежит целая фраза («Создать номер и позвать собеседника»),
   и читают её именно как текст — значит она набрана размером обычного
   текста. */
.home-card-note {
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.3;
  color: var(--text-2);
}

/* На лаймовой кнопке подпись тоже тёмная: --text-2 на лайме нечитаем. */
.btn.primary .home-card-note {
  color: color-mix(in srgb, var(--ink) 72%, transparent);
}

/* --- шапка сделки: версия и отпечаток -------------------------------- */

/*
 * Самая простая проверка §14 — сличить эти два значения с экраном
 * собеседника. Значит они обязаны читаться с метра и не сливаться с
 * остальным текстом: отпечаток моноширинный, чтобы глаз шёл по знакам,
 * номер версии — лаймовый, потому что меняется именно он.
 */
.deal-head {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  padding: 0.75rem 0.875rem;
  border-radius: var(--r-card-s);
  background: var(--glass);
}

.deal-line {
  margin: 0;
  font-size: var(--fs-cap);
  line-height: 1.4;
  color: var(--text-2);
}

.deal-version {
  font-weight: 500;
  color: var(--lime);
}

.deal-hash {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", "Segoe UI Mono", monospace;
  letter-spacing: 0.08em;
  color: var(--text);
}

/* --- сумма ----------------------------------------------------------- */

.amount-row {
  display: flex;
  gap: 0.5rem;
  align-items: stretch;
}

.amount-row .amount-field {
  flex: 1 1 auto;
  min-width: 0;
}

.amount-row select.field {
  flex: 0 0 auto;
  width: 6rem;
}

/* Валюта уходит под поле суммы на узких телефонах.

   Рядом они делят карточку так: несжимаемый список валют плюс
   промежуток, а сумме остаётся то, что осталось. Пока список занимал
   136px, сумме на экране 280px доставалось 48px — в такое поле не
   видно даже трёх знаков из двенадцати, а вводят его вслепую и
   сверяют потом с чужим. На шкале Д1 список ужался до 96px, и порог
   опустился с 432px до 320px: с этой ширины сумме остаётся больше
   половины строки, и рядом они стоят честно. */
@media (max-width: 20rem) {
  .amount-row {
    flex-direction: column;
  }

  .amount-row select.field {
    width: 100%;
  }
}

/* --- согласия и соглашение ------------------------------------------- */

/*
 * Согласие §8 и §35 человек должен прочитать, а не проскочить. Поэтому
 * оно набрано обычным размером текста, а не мелким «юридическим»: мелкий
 * шрифт в согласии — способ не быть прочитанным.
 */
.consent-text {
  margin: 0 0 0.75rem;
  font-size: var(--fs-body);
  line-height: 1.5;
  color: var(--text-2);
}

.legal {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.legal p {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.55;
  color: var(--text-2);
}

.legal h2 {
  margin: 0;
  font-size: var(--fs-h2);
  font-weight: 500;
  color: var(--text);
}

/* --- текстовые блоки -------------------------------------------------- */

/*
 * Договор читают целиком, и от длины строки зависит, дочитают ли.
 * 34em — граница, за которой глаз начинает терять начало следующей строки.
 */
.text-body {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.55;
  max-width: 34em;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.text-in {
  width: 100%;
}

.hero-step {
  margin: 0;
  font-size: var(--fs-h2);
  font-weight: 500;
  line-height: 1.2;
  text-align: center;
}

/* --- итоговый документ ------------------------------------------------ */

.doc {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.section-title {
  margin: 0 0 0.5rem;
  font-size: var(--fs-h2);
  font-weight: 500;
  line-height: 1.2;
}

.parties {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.parties > li {
  font-size: var(--fs-body);
  line-height: 1.4;
}

/* --- проверка личности ------------------------------------------------ */

/*
 * Круглая рамка под фронтальную камеру: она подсказывает, куда смотреть,
 * без единого слова инструкции.
 */
.face {
  width: min(12rem, 64vw);
  aspect-ratio: 1 / 1;
  margin: 0 auto;
  border-radius: 50%;
  overflow: hidden;
  background: var(--video-bg);
  box-shadow: 0 0 0 0.25rem var(--glass);
}

.face video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scaleX(-1); /* зеркало: человек ждёт увидеть себя как в зеркале */
}

/* --- выбор файла ------------------------------------------------------ */

/*
 * Это <label for>, а не <button>: скрытый <input type=file> открывается
 * по нему сам, без единой строки кода. Но выглядеть и нажиматься он
 * обязан как кнопка — размер тот же, что у остальных.
 */
.file-pick {
  cursor: pointer;
}

.file-pick input[type='file'] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* ==================================================================
   ПЯТЬ ЭТАПОВ СДЕЛКИ — вид новых элементов (движение в motion.css §10)

   Что здесь: лента этапов, экран «Собеседник записывает», отметки
   сторон, кнопка «принято», квитанция, печать, сцена проверки лица,
   результат замера местоположения. Всё — тем же языком, что и остальной
   файл: ни одной видимой рамки, объём заливками, скругления в rem.

   Контракт разметки:
     .stage-line[data-stage-line]  — лента, наполняет deal.js: .stage-dots > i×5 (.done/.now), .stage-text
     .record-orb.live / .stale     — знак записи на экране ожидания
     .parties .party.done / .wait  — сторона сделала шаг / ещё нет; .just — только что
     .accept-btn.accepted          — кнопка после приёма (серая), .btn-label — слова
     .receipt.receipt-in           — квитанция появляется
     .seal.ok / .bad / .big        — печать: галочка или крест, .seal-ring — кольцо
     .face-stage[--p]              — сцена проверки: .loading .live .face-ok .face-lost .sealed .failed
     .geo-result.ok / .bad         — итог замера
   ================================================================== */

/* --- лента этапов ------------------------------------------------------ */

.stage-line {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin: 0;
  min-height: 1.5rem;
  font-size: var(--fs-cap);
  line-height: 1.3;
  color: var(--text-2);
}

.stage-line:empty {
  display: none;
}

.stage-dots {
  display: inline-flex;
  align-items: center;
  gap: 0.3125rem;
  flex: 0 0 auto;
}

.stage-dots > i {
  position: relative;
  display: block;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--glass-2);
  transition: background 0.3s var(--e-out), transform 0.3s var(--e-spring);
}

.stage-dots > i.done {
  background: var(--lime);
}

/* Текущий этап — крупнее и дышит: одна точка из пяти живая. */
.stage-dots > i.now {
  background: var(--lime);
  transform: scale(1.35);
}

.stage-dots > i.now::after {
  content: '';
  position: absolute;
  inset: -0.25rem;
  border-radius: 50%;
  box-shadow: 0 0 0 0.125rem var(--lime);
  opacity: 0.45;
}

.stage-text {
  font-weight: 500;
  color: var(--text);
  text-wrap: balance;
}

/* --- этап 1: кто записывает ------------------------------------------- */

.lock-note {
  padding: 0.75rem 0.875rem;
  border-radius: var(--r-card-s);
  background: var(--glass);
  color: var(--lime-soft);
}

.wait-card {
  align-items: center;
  text-align: center;
  padding-top: 1.5rem;
}

/* Три волны записи. В покое — три низкие плашки; .live — дышат
   поочерёдно; .stale — гаснут до серого: пульса от записывающего нет. */
.record-orb {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  width: 5rem;
  height: 5rem;
  border-radius: 50%;
  background: var(--card-2);
  box-shadow: inset 0 0 0 1px var(--hair);
}

.record-orb > span {
  display: block;
  width: 0.5rem;
  height: 1rem;
  border-radius: var(--r-pill);
  background: var(--text-3);
  transform-origin: center;
  transition: background 0.4s var(--e-out);
}

.record-orb.live > span {
  background: var(--lime);
}

.record-orb.stale > span {
  background: var(--text-3);
}

/* --- отметки сторон (§15, §21) ------------------------------------------ */

/* У строк списка сторон в разметке нет отдельного знака — он рисуется
   псевдоэлементом тем же видом, что .party-mark: полый кружок «ждём»,
   лаймовый круг с галочкой «сделано». */
.parties .party {
  position: relative;
}

.parties .party::before {
  content: '';
  display: block;
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background:
    radial-gradient(circle, transparent 0.25rem, var(--text-3) 0.25rem, var(--text-3) 0.375rem, transparent 0.375rem),
    var(--glass);
  box-shadow: inset 0 0 0 1px var(--hair);
  transition: background 0.35s var(--e-out), box-shadow 0.35s var(--e-out);
}

.parties .party.done::before {
  background: var(--lime);
  box-shadow: none;
}

.parties .party.done::after {
  content: '';
  position: absolute;
  left: 0.5625rem;
  top: calc(50% - 0.5625rem);
  width: 1.125rem;
  height: 1.125rem;
  background: var(--ink);
  clip-path: var(--check-shape);
}

/* --- кнопка «принято» ---------------------------------------------------- */

/* Слова на кнопке — отдельный элемент, чтобы менять их с движением.
   Иконка остаётся на месте: у неё своя подпись, и она меняется вместе
   со словами по смыслу, а не по виду. */
.accept-btn {
  position: relative;
  overflow: hidden;
  transition:
    transform 0.12s var(--ease),
    background 0.45s var(--e-out),
    color 0.45s var(--e-out),
    box-shadow 0.45s var(--e-out);
}

.accept-btn .btn-label {
  display: inline-block;
}

/* Принято: лаймовая становится серой, как выключатель, который щёлкнул.
   Не гаснет через opacity — это не «недоступно», а «сделано», и читаться
   должно ровно так: плотная серая плашка с белым словом. */
.btn.primary.accept-btn.accepted {
  background: var(--gray);
  color: var(--text);
  pointer-events: none;
  box-shadow: inset 0 0 0 1px var(--hair);
}

.btn.primary.accept-btn.accepted[disabled] {
  opacity: 1;
}

/* --- квитанция ----------------------------------------------------------- */

.receipt {
  align-items: center;
  text-align: center;
  gap: 0.375rem;
  padding: 1.25rem 1.125rem;
}

.receipt > .ic {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  background: var(--lime);
  color: var(--ink);
  margin-bottom: 0.25rem;
}

.receipt-title {
  margin: 0;
  font-size: var(--fs-h2);
  font-weight: 500;
  line-height: 1.2;
  color: inherit;
}

.receipt-value {
  font-size: clamp(1.5rem, 7vw, 2.25rem);
  white-space: normal;
  overflow-wrap: break-word;
  letter-spacing: 0.02em;
}

.receipt .lead {
  margin: 0;
}

.amount-round {
  margin: 0;
  color: var(--lime-soft);
}

/* --- печать -------------------------------------------------------------- */

/* Знак «зафиксировано»: круг с галочкой и кольцо, расходящееся от него.
   Один и тот же на трёх местах — совпавшая сумма, распознанное лицо,
   поставленная подпись: человек узнаёт его на третьем шаге по первому. */
.seal {
  position: relative;
  display: grid;
  place-items: center;
  width: 4rem;
  height: 4rem;
  border-radius: 50%;
  background: var(--lime);
  color: var(--ink);
  margin: 0 auto;
}

.seal.big {
  width: 5rem;
  height: 5rem;
}

.seal .ic > svg {
  width: 1.75rem;
  height: 1.75rem;
}

.seal.big .ic > svg {
  width: 2.25rem;
  height: 2.25rem;
}

.seal-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: 0 0 0 0.1875rem var(--lime);
  opacity: 0;
  pointer-events: none;
}

/* Крест — не красный: красного в палитре нет. Серый круг с чернильным
   крестом читается как «стоп» без тревоги. */
.seal.bad {
  background: var(--gray);
  color: var(--text);
}

.seal.bad .seal-ring {
  box-shadow: 0 0 0 0.1875rem var(--gray);
}

.seal-cross {
  position: relative;
  width: 1.5rem;
  height: 1.5rem;
}

.seal-cross::before,
.seal-cross::after {
  content: '';
  position: absolute;
  left: calc(50% - 0.125rem);
  top: 0;
  width: 0.25rem;
  height: 100%;
  border-radius: var(--r-pill);
  background: currentColor;
  transform: rotate(45deg);
}

.seal-cross::after {
  transform: rotate(-45deg);
}

.match-card,
.mismatch-card,
.signed-card {
  align-items: center;
  text-align: center;
}

.mismatch-card .seal {
  margin-bottom: 0.25rem;
}

/* --- сцена проверки лица (§20) ------------------------------------------- */

.face-stage {
  --p: 0;
  position: relative;
  width: min(13.5rem, 70vw);
  aspect-ratio: 1 / 1;
  margin: 0.25rem auto;
}

.face-stage .face {
  position: absolute;
  inset: 0.625rem;
  width: auto;
  box-shadow: none;
  transition: filter 0.6s var(--e-out), transform 0.6s var(--e-out);
}

.face-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
  overflow: visible;
}

.face-ring circle {
  fill: none;
  stroke-width: 3;
  stroke-linecap: round;
}

.face-ring-track {
  stroke: var(--glass-2);
}

/* Заполнение кольца — по --p от 0 до 1. Длина окружности r=47 ≈ 295.3;
   переход по dashoffset даёт плавное дотягивание между кадрами. */
.face-ring-fill {
  stroke: var(--text-3);
  stroke-dasharray: 295.31;
  stroke-dashoffset: calc(295.31 * (1 - var(--p)));
  transition: stroke-dashoffset 0.18s var(--e-out), stroke 0.3s var(--e-out), opacity 0.3s;
}

.face-stage.face-ok .face-ring-fill {
  stroke: var(--lime);
}

.face-stage.face-lost .face-ring-fill,
.face-stage.face-lost .face-ring-track {
  opacity: 0.45;
}

.face-stage.face-lost .face {
  filter: saturate(0.6) brightness(0.8);
}

/* Распознано: видео уходит в тень, поверх — печать. */
.face-stage.sealed .face {
  filter: brightness(0.45) saturate(0.5);
  transform: scale(0.96);
}

.face-stage.sealed .face-ring-fill {
  stroke: var(--lime);
}

.face-seal {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
}

.face-seal .seal {
  width: 4.5rem;
  height: 4.5rem;
}

.face-stage.failed .face-ring-fill {
  stroke: var(--text-3);
  opacity: 0.5;
}

.face-hint {
  margin: 0;
  text-align: center;
  min-height: 1.2em;
}

#s-identity .hero-step {
  min-height: 2.4em;
}

/* --- результат замера местоположения (§22) -------------------------------- */

.geo-result.bad > .ic {
  background: var(--gray);
  color: var(--text);
}

.geo-result.bad > .ic > svg {
  display: none;
}

.geo-result.bad > .ic::before {
  content: '!';
  font-size: var(--fs-h2);
  font-weight: 600;
  line-height: 1;
}

/* Строка согласия — флажок и слова в один ряд. Флажок выше нарисован
   сеткой (display: grid) и потому блочный: без этого правила он вставал
   отдельной строкой над текстом, и галочку искали глазами под ним. */
.consent-text {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
}

.consent-text > label {
  flex: 1 1 auto;
  cursor: pointer;
  padding-top: 0.125rem;
}

/* ------------------------------------------------------------------ */
/*  s-template · выбор вида договора (docs/FIXES13.md Р2)              */
/* ------------------------------------------------------------------ */

/* Карточка-кнопка на всю ширину: попасть можно в любую точку, как и в
   двери главного экрана. Список, а не ряд: названия видов договора
   длинные, и в две колонки они переносились бы на три строки. */
.tpl-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}

.tpl {
  width: 100%;
  border: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
  background: var(--gray);
  gap: 0.375rem;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.18s var(--e-out), background-color 0.18s var(--e-out);
}

.tpl:active {
  transform: scale(0.985);
}

.tpl:disabled {
  opacity: 0.55;
  cursor: default;
}

.tpl b {
  font-size: var(--fs-h2);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.015em;
}

.tpl .cap {
  color: var(--text-2);
}

/* Почему макет подошёл. Обычным текстом, а не подписью: это довод, по
   которому человек решает, и мелкий шрифт здесь — способ не быть прочитанным. */
.tpl-why {
  font-size: var(--fs-body);
  line-height: 1.4;
}

.tpl .tag {
  align-self: flex-start;
}

/* Лучший вариант — лаймовый целиком: на этом экране он и есть главная
   кнопка, и другой лаймовой заливки здесь нет. */
.tpl.best {
  background: var(--lime);
  color: var(--ink);
}

.tpl.best .cap {
  color: rgba(16, 22, 12, 0.72);
}

.tpl.best .tag {
  background: var(--ink);
  color: var(--lime);
}

.tpl.best:active {
  background: var(--lime-deep);
}

/* Макет, которым составлен нынешний текст, — когда к выбору вернулись. */
.tpl.current:not(.best) {
  box-shadow: inset 0 0 0 1.5px rgba(205, 245, 111, 0.5);
}
