/* ==================================================================
   Аккорд · главный экран (плитки)
   ================================================================== */

/*
 * Ширина под три плитки, а не под четыре.
 *
 * Прежние 1120 px были рассчитаны на восемь плиток в два ряда. Три плитки на
 * той же ширине растягивались до 340 px каждая — вдвое крупнее, чем в
 * референсе, и вместо аккуратной сетки получались три щита. Контейнер сужен
 * ровно под ряд из трёх плиток нормального размера, поэтому заголовок, сетка и
 * подвал остаются на одной вертикали.
 */
.app {
  width: min(840px, 100%);
  margin: 0 auto;
  padding: calc(16px + env(safe-area-inset-top)) 16px calc(40px + env(safe-area-inset-bottom));
}

/* ---------- верхняя панель ---------- */
.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 62px;
}
/* Сегмент посередине — он остался на экране подготовки во встрече
   («С камерой / Только голос»), эта же шапка служит и там. */
.topbar .seg {
  margin: 0 auto;
}
/*
 * На главной середина шапки пуста — переключатель «Все / Избранные» ушёл вместе
 * с избранным, — и аватар прижимается вправо сам. Только на главной: во встрече
 * посередине стоит сегмент, и второй авто-отступ сдвинул бы его влево.
 */
html:not(.room-page) .topbar .av {
  margin-left: auto;
}
.topbar .av {
  width: 46px;
  height: 46px;
  cursor: pointer;
  transition: transform 0.24s var(--ease);
}
.topbar .av:active {
  transform: scale(0.92);
}

/* ---------- заголовок ---------- */
.page-title {
  font-size: clamp(40px, 12.5vw, 62px);
  font-weight: 700;
  letter-spacing: -0.045em;
  line-height: 1;
  margin: 34px 4px 26px;
}
.page-sub {
  margin: -18px 6px 26px;
  font-size: 14.5px;
  color: var(--txt-3);
  letter-spacing: -0.01em;
}

/* ---------- сетка плиток ---------- */
.grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}
/*
 * Плиток четыре: подключиться, новая встреча, записи, сделки.
 *
 * Ряд снова полный, и колонок именно четыре, а не три с переносом: одинокая
 * плитка во второй строке читается как «забыли доделать», а не как продолжение
 * ряда. На узком экране те же четыре ложатся в два на два — тоже без остатка.
 *
 * Порог переноса — 760 px, а не 640: при четырёх колонках на 640 плитка ужалась
 * бы до 140 px в ширину при минимальной высоте 190 и вытянулась бы в столбик.
 */
@media (min-width: 760px) {
  .grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
  }
}

/* ---------- плитка ---------- */
.tile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  aspect-ratio: 1 / 1.05;
  min-height: 190px;
  padding: 16px 14px 20px;
  border-radius: var(--r-card);
  overflow: hidden;
  isolation: isolate;
  text-align: center;
  transition: transform 0.34s var(--ease), filter 0.34s var(--ease);
  animation: tile-in 0.6s var(--ease) both;
  animation-delay: calc(var(--i, 0) * 45ms);
}
.tile:hover {
  transform: translateY(-4px);
  filter: brightness(1.08);
}
.tile:active {
  transform: scale(0.975);
}
@keyframes tile-in {
  from {
    opacity: 0;
    transform: translateY(22px) scale(0.96);
  }
}

.tile .cap {
  position: relative;
  z-index: 3;
  width: 100%;
}
.tile .cap b {
  display: block;
  font-size: 15.5px;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tile .cap span {
  display: block;
  margin-top: 3px;
  font-size: 13px;
  letter-spacing: -0.01em;
  color: rgba(255, 255, 255, 0.46);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* центральная «сцена» плитки */
.tile .art {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  top: 0;
  bottom: 62px;
  display: grid;
  place-items: center;
  pointer-events: none;
}
.tile .art-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

/* угловые элементы */
.tile .corner-tl {
  position: absolute;
  z-index: 3;
  top: 14px;
  left: 14px;
}
.tile .corner-tc {
  position: absolute;
  z-index: 3;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
}

/* плюс-кнопка внутри плитки */
.tile .plus {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.tile .plus svg {
  width: 20px;
  height: 20px;
  stroke: rgba(255, 255, 255, 0.85);
}

/* ==================================================================
   Градиентные заливки плиток (по фото-референсу)
   ================================================================== */

.tile::before,
.tile::after {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 0;
  pointer-events: none;
}

/* 1 — графит */
.g-graphite::before {
  background: linear-gradient(158deg, #4a4a50 0%, #2a2a2e 38%, #131315 74%, #0a0a0c 100%);
}
.g-graphite::after {
  background: radial-gradient(120% 82% at 22% 6%, rgba(255, 255, 255, 0.2), transparent 62%);
}

/* 2 — аврора (бирюза → синий → фиолетовое ядро) */
.g-aurora::before {
  background: linear-gradient(180deg, #1a5f6b 0%, #1a4a76 38%, #241b5c 72%, #140f33 100%);
}
.g-aurora::after {
  background: radial-gradient(58% 40% at 50% 40%, rgba(150, 120, 255, 0.85), transparent 68%),
    radial-gradient(90% 60% at 50% 108%, rgba(10, 8, 30, 0.9), transparent 70%);
}

/* 3 — электрик (голубой → синий → фиолетовый) */
.g-electric::before {
  background: linear-gradient(196deg, #63dcf2 0%, #4f7bf0 44%, #7a45ef 78%, #6c2fd6 100%);
}
.g-electric::after {
  background: radial-gradient(80% 60% at 30% 18%, rgba(255, 255, 255, 0.26), transparent 60%);
}

/* 4 — нефрит */
.g-jade::before {
  background: linear-gradient(168deg, #3f8f7c 0%, #2a6a6e 42%, #1a4552 74%, #10262f 100%);
}
.g-jade::after {
  background: radial-gradient(72% 52% at 50% 44%, rgba(140, 255, 214, 0.24), transparent 68%);
}

/* 5 — сланец */
.g-slate::before {
  background: linear-gradient(162deg, #34343a 0%, #1d1d21 44%, #0e0e10 100%);
}
.g-slate::after {
  background: radial-gradient(110% 74% at 78% 8%, rgba(255, 255, 255, 0.13), transparent 60%);
}

/* 6 — индиго */
.g-indigo::before {
  background: linear-gradient(178deg, #3a2478 0%, #4a2597 42%, #2c1668 74%, #150c33 100%);
}
.g-indigo::after {
  background: radial-gradient(64% 44% at 50% 46%, rgba(168, 128, 255, 0.42), transparent 70%);
}

/* 7 — закат */
.g-ember::before {
  background: linear-gradient(172deg, #7a3a52 0%, #5a2a4a 44%, #2c1730 76%, #150c1a 100%);
}
.g-ember::after {
  background: radial-gradient(70% 48% at 50% 40%, rgba(255, 150, 170, 0.34), transparent 70%);
}

/* 8 — сталь */
.g-steel::before {
  background: linear-gradient(160deg, #2b3a46 0%, #1b2830 44%, #0d1418 100%);
}
.g-steel::after {
  background: radial-gradient(100% 70% at 20% 10%, rgba(160, 220, 255, 0.17), transparent 62%);
}

/* ==================================================================
   Декоративные элементы внутри плиток
   ================================================================== */

/* светящаяся сфера (плитка «Подключиться») */
.orb {
  position: relative;
  width: 84px;
  height: 84px;
  border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, #c9b8ff, #7a63ff 44%, #3f2fb0 78%, #241a6e);
  box-shadow: 0 0 60px 8px rgba(122, 99, 255, 0.55);
  animation: orb-float 6.5s ease-in-out infinite;
}
.orb::after {
  content: '';
  position: absolute;
  left: -32%;
  right: -32%;
  top: 58%;
  height: 130%;
  border-radius: 50% 50% 0 0;
  background: linear-gradient(180deg, rgba(20, 30, 60, 0.7), rgba(10, 12, 30, 0.98));
  filter: blur(6px);
}
@keyframes orb-float {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-7px);
  }
}

/* эквалайзер */
.eq {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 26px;
}
.eq i {
  width: 4px;
  border-radius: 99px;
  background: rgba(255, 255, 255, 0.82);
  height: 30%;
  animation: eq 1.15s ease-in-out infinite;
  animation-delay: calc(var(--d) * 110ms);
}
@keyframes eq {
  0%,
  100% {
    height: 22%;
  }
  50% {
    height: 100%;
  }
}

/* ==================================================================
   Мои записи: список, карточка, расшифровка
   Живёт в home.css нарочно — эти же шторки открываются и с экрана
   прощания после встречи, а room.html подключает этот файл тоже.
   ================================================================== */

/* эквалайзер на плитке записей — плотнее и шире обычного */
.eq.wide {
  gap: 5px;
  height: 30px;
}
.eq.wide i {
  width: 3.5px;
}

/*
 * Строка списка: вся плашка кликабельна, но внутри неё живёт кнопка удаления.
 * Вложить кнопку в кнопку нельзя, поэтому нажимаемая область — отдельный слой
 * под содержимым, а само содержимое клики не перехватывает.
 */
.rec-row {
  position: relative;
}
.rec-hit {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: 20px;
  cursor: pointer;
}
.rec-row > *:not(.rec-hit) {
  position: relative;
  z-index: 2;
  pointer-events: none;
}
.rec-row .rec-del {
  pointer-events: auto;
}

.rec-state {
  display: flex !important;
  align-items: center;
  gap: 7px;
  margin-top: 4px;
  font-size: 12.5px;
  color: var(--txt-3);
}
.rec-dot {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.26);
}
.rec-dot.ok {
  background: #4fe3a1;
  box-shadow: 0 0 10px rgba(79, 227, 161, 0.85);
}
.rec-dot.warn {
  background: #ffb347;
}
.rec-dot.bad {
  background: #ff6b6b;
}

/*
 * Идущая запись помечается пульсацией, а не просто цветом.
 *
 * Строка «идёт запись» относится к встрече, которая происходит прямо сейчас в
 * другой вкладке, и от завершённой записи её надо отличать с одного взгляда:
 * содержимое у неё через минуту будет другим. Цвет для этого слабоват — в
 * списке из десяти строк зелёная точка не читается как «живое».
 */
.rec-dot.live {
  background: #4fe3a1;
  animation: recPulse 1.8s var(--ease) infinite;
}
@keyframes recPulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 rgba(79, 227, 161, 0.6);
  }
  50% {
    box-shadow: 0 0 0 5px rgba(79, 227, 161, 0);
  }
}
/* Предпочтение «меньше движения» уважаем: пульсация тут — украшение, а не смысл. */
@media (prefers-reduced-motion: reduce) {
  .rec-dot.live {
    animation: none;
    box-shadow: 0 0 10px rgba(79, 227, 161, 0.85);
  }
}

/*
 * Предупреждение над карточкой записи.
 *
 * Стоит выше вкладок нарочно: неполную стенограмму человек может отправить
 * коллегам, и узнать о её неполноте он должен раньше, чем нажмёт «Скопировать»,
 * а не после.
 */
.rec-warn {
  margin: -4px 0 16px;
  padding: 12px 16px;
  border-radius: 16px;
  font-size: 13.5px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  background: rgba(255, 179, 71, 0.13);
  color: #ffce8f;
}
.rec-warn-live {
  background: rgba(79, 227, 161, 0.12);
  color: #9ff0cd;
}

/* ---------- карточка записи ---------- */

.rec-block {
  margin-bottom: 20px;
}
.rec-p {
  font-size: 15px;
  line-height: 1.55;
  letter-spacing: -0.01em;
  margin-bottom: 8px;
}
.rec-ul {
  margin: 0;
  padding-left: 20px;
  list-style: disc;
}
.rec-ul li {
  font-size: 14.5px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  margin-bottom: 8px;
  color: rgba(255, 255, 255, 0.82);
}
.rec-ul li::marker {
  color: var(--txt-4);
}

/*
 * Поиск по расшифровке.
 *
 * Счётчик справа внутри поля, а не под ним: он меняется на каждое нажатие, и
 * отдельной строкой под полем дёргал бы вниз весь список реплик.
 */
.rec-find {
  position: relative;
  display: block;
  margin-bottom: 14px;
}
.rec-find input {
  width: 100%;
  height: 48px;
  padding: 0 116px 0 18px;
  border-radius: 18px;
  background: var(--glass);
  color: var(--txt);
  font-size: 15px;
  letter-spacing: -0.01em;
  transition: background 0.2s var(--ease);
}
.rec-find input::placeholder {
  color: var(--txt-4);
}
.rec-find input:focus {
  background: var(--glass-2);
}
.rec-find input::-webkit-search-cancel-button {
  filter: invert(1) opacity(0.5);
}
.rec-find-n {
  position: absolute;
  top: 50%;
  right: 16px;
  transform: translateY(-50%);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--txt-4);
  pointer-events: none;
}
.rec-txt mark {
  padding: 0 2px;
  border-radius: 4px;
  background: hsl(var(--hue, 262) 80% 62% / 0.32);
  color: #fff;
}

/* ---------- кто сколько говорил ---------- */

.rec-share {
  margin-bottom: 14px;
}
.rec-share-t {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 12px;
  margin-bottom: 7px;
}
.rec-share-t b {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: hsl(var(--hue, 262) 85% 74%);
}
.rec-share-t span {
  font-size: 12.5px;
  color: var(--txt-4);
  font-variant-numeric: tabular-nums;
}
.rec-share-bar {
  height: 6px;
  border-radius: 99px;
  background: var(--glass);
  overflow: hidden;
}
.rec-share-bar i {
  display: block;
  height: 100%;
  border-radius: 99px;
  background: hsl(var(--hue, 262) 72% 58%);
  transition: width 0.35s var(--ease);
}

/*
 * Расшифровка длинная, и шторка не должна расти вместе с ней: у неё уже есть
 * своя прокрутка, и вложенная в неё вторая была бы ловушкой. Ограничиваем
 * высоту и прокручиваем сам список реплик.
 */
.rec-lines {
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* Нижняя граница нужна телефону боком: там 46 % экрана — это две строки,
     и список превращался в щель, по которой ничего не найти. */
  max-height: clamp(180px, 46dvh, 560px);
  overflow-y: auto;
  overscroll-behavior: contain;
  /*
   * Отступ справа был под ползунок. Ползунка в шторке больше нет (см. base.css),
   * и без правки здесь осталась бы полоса пустоты, из-за которой список не
   * сходился по правому краю с остальной карточкой.
   */
  padding-right: 0;
  /*
   * Нижний край растворяется — так видно, что список продолжается.
   *
   * Это замена ползунку, и она лучше по существу: ползунок показывает, сколько
   * осталось от окна, а затухание — что оборвана сама фраза, то есть ровно то,
   * ради чего человек и потянется листать. Восемнадцать пикселей: меньше не
   * читается, больше начинает съедать последнюю строку.
   */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent);
}
/*
 * Список, докрученный до конца, затухать не должен: там ничего не оборвано.
 *
 * Прогресс прокрутки отдаёт сам браузер (`animation-timeline: scroll()`), и
 * никакого обработчика на событие прокрутки для этого не нужно — а он бы здесь
 * стоил дорого: список длинный, а событие частое. Где такой временной шкалы нет
 * (Safari, Firefox), затухание просто остаётся всегда — восемнадцать пикселей
 * мягкого края никому не мешают.
 */
@supports (animation-timeline: scroll()) {
  .rec-lines {
    animation: rec-lines-fade linear both;
    animation-timeline: scroll(self block);
    animation-range: contain;
  }
  @keyframes rec-lines-fade {
    to {
      -webkit-mask-image: linear-gradient(to bottom, #000 100%, transparent);
      mask-image: linear-gradient(to bottom, #000 100%, transparent);
    }
  }
}

/*
 * В карточке сделки список реплик не прокручивается отдельно.
 *
 * В записи встречи над ним стоит поиск, и без собственной высоты список уносил
 * бы поле поиска за верхний край. В сделке поиска нет и реплик десяток — это
 * кусок разговора на минуту, а не часовая стенограмма. Своя прокрутка здесь
 * означала бы вложенную прокрутку без единой причины, а вложенная прокрутка —
 * это ловушка: колесо под курсором листает не то, что человек ожидает.
 */
.deal-lines {
  max-height: none;
  overflow: visible;
  -webkit-mask-image: none;
  mask-image: none;
  animation: none;
}
.rec-line {
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr);
  gap: 3px 10px;
}
.rec-at {
  grid-row: span 2;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--txt-4);
  padding-top: 3px;
}
.rec-who {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: hsl(var(--hue, 262) 85% 74%);
}
.rec-txt {
  font-size: 14.5px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  color: rgba(255, 255, 255, 0.84);
  word-break: break-word;
}

/* подвал */
.foot {
  margin: 34px 6px 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 18px;
  font-size: 12.5px;
  color: var(--txt-4);
  letter-spacing: -0.01em;
}
.foot b {
  color: var(--txt-3);
  font-weight: 600;
}

/* ==================================================================
   Мои сделки: плитка, список, карточка, сканирование лица

   Живёт в home.css по той же причине, что и «Мои записи»: эти шторки
   открываются и с главной, и прямо со встречи, а room.html подключает
   этот файл тоже. Разъехаться этим двум видам нельзя.
   ================================================================== */

/*
 * Печать на плитке сделок.
 *
 * Три кольца, расходящиеся из одной точки, — тот же жест, что у эквалайзера на
 * плитке записей: рисунок должен читаться как «здесь что-то происходит», не
 * изображая при этом ни денег, ни документов. Буквальная монета или папка
 * состарились бы вместе с модой на скевоморфизм, а кольца — нет.
 */
.seal {
  position: relative;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
}
.seal i {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle, transparent 56%, rgba(255, 255, 255, 0.78) 58%, transparent 68%);
  animation: seal-ring 3.2s var(--ease) infinite;
}
.seal i:nth-child(2) {
  animation-delay: 1.06s;
}
.seal i:nth-child(3) {
  animation-delay: 2.13s;
}
@keyframes seal-ring {
  from {
    transform: scale(0.4);
    opacity: 0;
  }
  35% {
    opacity: 1;
  }
  to {
    transform: scale(1.15);
    opacity: 0;
  }
}

/* ---------- строка списка ---------- */

/*
 * Сумма — заголовком строки, а не подписью.
 *
 * Сделку ищут по сумме: её человек помнит через полгода, а название придумывает
 * не всегда. Поэтому в первой строке крупные цифры, а во второй — стороны.
 */
.deal-row .t b {
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

/* ---------- карточка ---------- */

.deal-sum-big {
  font-size: clamp(30px, 8vw, 40px);
  font-weight: 700;
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  margin-bottom: 6px;
}
.deal-sum-note {
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--txt-2);
  letter-spacing: -0.01em;
}

.deal-sides {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.deal-side {
  flex: 1 1 220px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  background: var(--glass);
  min-width: 0;
}
.deal-side-t {
  min-width: 0;
}
.deal-side-t b {
  display: block;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/*
 * Место стороны сделки: точка и строка.
 *
 * Своя разметка, а не общая с плиткой участника: та живёт в room.css, а эта
 * карточка открывается ещё и с главной, где room.css не подключён. Цвета точки
 * при этом те же — человек уже видел их во встрече и не должен переучиваться.
 */
.deal-geo {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 3px;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--txt-3);
  letter-spacing: -0.01em;
}
.deal-geo i {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.28);
}
.deal-geo[data-kind="ok"] i {
  background: #4fe3a1;
  box-shadow: 0 0 8px rgba(79, 227, 161, 0.7);
}
.deal-geo[data-kind="soft"] i {
  background: rgba(255, 255, 255, 0.45);
}
.deal-geo[data-kind="warn"] i {
  background: #ffb347;
  box-shadow: 0 0 8px rgba(255, 179, 71, 0.7);
}

/*
 * Видеозапись условий.
 *
 * Со штатными органами управления браузера, а не со своими: это единственный
 * плеер во всём приложении, и своя перемотка здесь была бы сотней строк ради
 * того, что система уже умеет — включая полноэкранный режим и скорость
 * воспроизведения, которые на записи разговора нужны чаще всего.
 */
.deal-video {
  width: 100%;
  border-radius: var(--r-sm);
  background: #0a0a0c;
  margin-bottom: 8px;
}

.deal-faces {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 10px;
}
.deal-face {
  flex: 1 1 140px;
  max-width: 190px;
  margin: 0;
}
.deal-face img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--r-sm);
  background: var(--glass);
}
.deal-face-none {
  display: grid;
  place-items: center;
  aspect-ratio: 1 / 1;
  border-radius: var(--r-sm);
  background: var(--glass);
  font-size: 12.5px;
  color: var(--txt-4);
}
.deal-face figcaption {
  margin-top: 7px;
}
.deal-face figcaption b {
  display: block;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.deal-face figcaption span {
  display: block;
  font-size: 12.5px;
  color: var(--txt-3);
  font-variant-numeric: tabular-nums;
}

/* ---------- ввод суммы ---------- */

.deal-amount {
  display: flex;
  gap: 8px;
}
.deal-amount input {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 19px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.deal-amount select {
  flex: 0 0 auto;
  width: 116px;
}

/*
 * Сравнение сумм.
 *
 * Три состояния и три цвета: ждём вторую сторону, разошлись, совпали. Сводить
 * их в один нейтральный блок нельзя — «ждём» и «не совпало» требуют от человека
 * разного, и перепутать их значит либо зря ждать, либо зря переспрашивать.
 */
.deal-cmp {
  margin: -4px 0 16px;
  border-radius: var(--r-sm);
  font-size: 13.5px;
  line-height: 1.5;
  letter-spacing: -0.01em;
}
.deal-cmp:empty {
  display: none;
}
.deal-cmp b {
  display: block;
  font-size: 15px;
  font-weight: 650;
  letter-spacing: -0.02em;
  margin-bottom: 2px;
}
.deal-cmp.wait,
.deal-cmp.ok,
.deal-cmp.bad {
  padding: 12px 16px;
}
.deal-cmp.wait {
  background: var(--glass);
  color: var(--txt-2);
}
.deal-cmp.ok {
  background: rgba(79, 227, 161, 0.13);
  color: #9ff0cd;
}
.deal-cmp.bad {
  background: rgba(255, 107, 120, 0.14);
  color: #ffb3bb;
}

/*
 * Разбор «что мешает подписать».
 *
 * Список, а не абзац, потому что читают его не подряд, а глазами по галочкам:
 * человеку нужен один пункт с крестиком, остальные он пролистывает. Отсюда и
 * метка слева фиксированной ширины — чтобы крестик было видно, не вчитываясь.
 */
.pk-checks {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 14px 0 2px;
}
.pk-check {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 9px 12px;
  border-radius: var(--r-sm);
  background: var(--glass);
  font-size: 13.5px;
  line-height: 1.45;
}
.pk-check.bad {
  background: rgba(255, 107, 120, 0.13);
}
.pk-mark {
  flex: 0 0 auto;
  width: 18px;
  text-align: center;
  font-weight: 700;
  color: var(--txt-3);
}
.pk-check.ok .pk-mark {
  color: #4fe3a1;
}
.pk-check.bad .pk-mark {
  color: #ff6b78;
}
.pk-txt {
  min-width: 0;
}
.pk-txt b {
  display: block;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--txt-2);
}
.pk-check.bad .pk-txt b {
  color: #ffb3bb;
}
.pk-txt i {
  display: block;
  font-style: normal;
  color: var(--txt-3);
  overflow-wrap: anywhere;
}

/* галочка «подтвердил» в списке сторон */
.deal-tick {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--glass-2);
  transition: background 0.24s var(--ease);
}
.deal-tick.on {
  background: #4fe3a1
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23062018' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7'/%3E%3C/svg%3E")
    center / 13px 13px no-repeat;
}

/* ---------- сделка заключена ---------- */

.deal-done {
  text-align: center;
  margin-bottom: 18px;
}
.deal-done-ic {
  display: block;
  width: 74px;
  height: 74px;
  margin: 0 auto 16px;
  border-radius: 50%;
  background: linear-gradient(140deg, #4fe3a1, #2aa87a)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23052018' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7'/%3E%3C/svg%3E")
    center / 34px 34px no-repeat;
  box-shadow: 0 18px 46px -18px rgba(79, 227, 161, 0.85);
  animation: deal-done-in 0.5s var(--ease) both;
}
@keyframes deal-done-in {
  from {
    opacity: 0;
    transform: scale(0.6);
  }
}

/* ==================================================================
   Сканирование лица
   ================================================================== */

/*
 * Кадр — квадратом, а круг вокруг него рисуется на холсте.
 *
 * Квадрат, а не 4:3: круг с секторами вписывается в квадрат, и на прямоугольном
 * кадре он превратился бы в овал — а обводить носом надо именно круг, иначе
 * человек не понимает, докуда вести. Сам круг и сетка лица живут на одном
 * холсте поверх видео (см. lib/face-id.js): они обязаны быть в одних
 * координатах и не могут разъехаться на полпикселя.
 */
.face-scan {
  position: relative;
  width: min(100%, 340px);
  margin: 0 auto 16px;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  overflow: hidden;
  background: #0a0a0c;
  /* Мягкое кольцо вокруг кадра: без него круг секторов висит в пустоте. */
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06), 0 30px 70px -34px rgba(0, 0, 0, 0.95);
  animation: face-in 0.62s var(--ease) both;
}
@keyframes face-in {
  from {
    opacity: 0;
    transform: scale(0.92);
  }
}
.face-scan video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Себя человек привык видеть зеркально — так же, как на своей плитке. */
  transform: scaleX(-1);
}
.face-scan canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/*
 * Галочка в конце.
 *
 * Круг схлопывается к центру и превращается в отметку — то же движение, каким
 * заканчивается проверка на телефоне. Один элемент вместо анимации по кадрам:
 * весь эффект — это масштаб и прозрачность, и он бесплатен для видеокарты.
 */
.face-done {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  opacity: 0;
  pointer-events: none;
  background: radial-gradient(circle at center, rgba(20, 180, 130, 0.5), rgba(6, 26, 20, 0.86) 72%);
  transition: opacity 0.3s var(--ease);
}
.face-done::after {
  content: '';
  width: 42%;
  height: 42%;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23eafff6' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 12.6 5 5L20 6.5'/%3E%3C/svg%3E")
    center / contain no-repeat;
  transform: scale(0.4);
  opacity: 0;
}
.face-done.on {
  opacity: 1;
}
.face-done.on::after {
  animation: face-check 0.62s var(--ease) 0.06s both;
}
@keyframes face-check {
  0% {
    transform: scale(0.4);
    opacity: 0;
  }
  60% {
    transform: scale(1.08);
    opacity: 1;
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}

.face-count {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 76px;
  font-weight: 700;
  letter-spacing: -0.04em;
  color: #fff;
  text-shadow: 0 8px 40px rgba(0, 0, 0, 0.8);
  pointer-events: none;
}
.face-count:empty {
  display: none;
}

/* Вспышка затвора: без неё непонятно, что снимок уже сделан. */
.face-flash {
  position: absolute;
  inset: 0;
  background: #fff;
  opacity: 0;
  pointer-events: none;
}
.face-flash.on {
  animation: face-flash 0.42s var(--ease);
}
@keyframes face-flash {
  0% {
    opacity: 0.9;
  }
  100% {
    opacity: 0;
  }
}

.face-state {
  font-size: 17px;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: -0.02em;
  text-align: center;
  color: var(--txt);
  min-height: 24px;
}
.face-state[data-kind="ok"] {
  color: #9ff0cd;
}
.face-state[data-kind="warn"] {
  color: #ffce8f;
}
/* Смена подписи — короткий толчок: иначе строки подменяются незаметно. */
.face-state.bump {
  animation: face-bump 0.34s var(--ease);
}
@keyframes face-bump {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}

/* Что именно сделать: направление обхода, «моргните». Второй строкой и тише. */
.face-hint {
  margin-top: 6px;
  text-align: center;
  font-size: 14px;
  line-height: 1.45;
  letter-spacing: -0.01em;
  color: var(--txt-3);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
  min-height: 20px;
}
.face-hint.on {
  opacity: 1;
  transform: none;
}

/* ==================================================================
   Ход проверки: две колонки, своя и собеседника
   ================================================================== */

/*
 * Две одинаковые колонки рядом, а не список из четырёх строк.
 *
 * Смысл третьего шага в том, что проверок две и сторон две. Список смешал бы их
 * в одну очередь, и «кто из нас застрял» пришлось бы вычитывать из подписей.
 * Рядом же видно сразу: своя колонка слева, чужая справа, строки друг напротив
 * друга.
 */
.vgrid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin-top: 18px;
}
@media (max-width: 460px) {
  .vgrid {
    grid-template-columns: 1fr;
  }
}

.vcol {
  padding: 14px;
  border-radius: var(--r-sm);
  background: var(--glass);
  min-width: 0;
}
.vcol.me {
  background: rgba(106, 99, 242, 0.12);
}
.vhead {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 12px;
  min-width: 0;
}
.vhead b {
  /* min-width: 0 обязателен: без него флекс-элемент не сжимается ниже ширины
     содержимого, и длинное имя выезжает за колонку вместо многоточия. */
  min-width: 0;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/*
 * Строка проверки: точка, текст, полоска хода.
 *
 * Была сеткой из двух колонок, где тексту доставалась вторая — фиксированные
 * 192 px при шторке в 560. Подпись «сетка и круговой жест» в эти 192 px влезала
 * ровно впритык: на шрифте, который просит проект (Segoe UI Variable), она
 * вылезала на несколько пикселей и обрезалась первой буквой. Внешне это выглядит
 * не как тесная колонка, а как поехавшая вёрстка, — и на скриншоте пользователя
 * выглядело именно так.
 *
 * Теперь колонка одна на всю ширину, текст переносится, а точка стоит над ним
 * в своей строке. Ширина текста от длины подписи больше не зависит вовсе, и
 * подобрать шрифт, на котором она снова обрежется, нельзя.
 */
.vrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 9px;
  padding: 9px 0;
}
.vrow + .vrow {
  /* Разделитель заливкой, а не рамкой: рамок в проекте нет. */
  background: linear-gradient(rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.07)) top / 100% 1px
    no-repeat;
}
.vt {
  flex: 1 1 auto;
  min-width: 0;
}
.vt b {
  display: block;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.vt span {
  display: block;
  margin-top: 1px;
  font-size: 12px;
  line-height: 1.35;
  color: var(--txt-3);
  letter-spacing: -0.01em;
  /* Длинное слово не должно раздвигать колонку и уезжать за её край. */
  overflow-wrap: anywhere;
}

/*
 * Точка состояния.
 *
 * Четыре состояния и четыре разных поведения: серая — не начиналось, пульсирует
 * — идёт, зелёная — прошло, красная — нет. Пульсация обязательна: проверка
 * лицом идёт полминуты, и без движения «идёт» неотличимо от «зависло».
 */
.vdot {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
}
.vdot i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.2);
  transition: background 0.3s var(--ease), box-shadow 0.3s var(--ease), width 0.3s var(--ease),
    height 0.3s var(--ease);
}
.vrow[data-st="go"] .vdot i {
  background: var(--accent-a);
  box-shadow: 0 0 0 0 rgba(86, 217, 247, 0.55);
  animation: vpulse 1.5s var(--ease) infinite;
}
@keyframes vpulse {
  to {
    box-shadow: 0 0 0 9px rgba(86, 217, 247, 0);
  }
}
.vrow[data-st="ok"] .vdot i {
  width: 20px;
  height: 20px;
  background: #4fe3a1
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23052018' stroke-width='3.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7'/%3E%3C/svg%3E")
    center / 11px 11px no-repeat;
  box-shadow: 0 0 18px -2px rgba(79, 227, 161, 0.7);
  animation: vpop 0.44s var(--ease);
}
@keyframes vpop {
  0% {
    transform: scale(0.4);
  }
  60% {
    transform: scale(1.14);
  }
  100% {
    transform: scale(1);
  }
}
.vrow[data-st="fail"] .vdot i {
  background: var(--danger-a);
  box-shadow: 0 0 16px -2px rgba(255, 95, 109, 0.7);
}
.vrow[data-st="skip"] .vdot i {
  background: rgba(255, 179, 71, 0.75);
}

.vrow[data-st="ok"] .vt b {
  color: #9ff0cd;
}
.vrow[data-st="fail"] .vt b {
  color: #ffb3bb;
}

/*
 * Полоска хода — своей строкой под текстом, во всю ширину.
 *
 * `flex-basis: 100%` заставляет её перенестись на новую строку флекса: так она
 * не отнимает у подписи ни пикселя и не зависит от того, сколько строк заняла
 * подпись. Появляется только пока идёт и когда прошло — в остальное время её нет.
 */
.vbar {
  flex: 0 0 100%;
  height: 3px;
  border-radius: 99px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
  margin-top: 2px;
  opacity: 0;
  transition: opacity 0.3s var(--ease);
}
.vrow[data-st="go"] .vbar,
.vrow[data-st="ok"] .vbar {
  opacity: 1;
}
.vbar i {
  display: block;
  height: 100%;
  border-radius: 99px;
  background: linear-gradient(90deg, var(--accent-a), var(--accent-b));
  transition: width 0.5s var(--ease);
}
.vrow[data-st="ok"] .vbar i {
  background: #4fe3a1;
}

@media (prefers-reduced-motion: reduce) {
  .seal i,
  .deal-done-ic,
  .face-scan,
  .face-state.bump,
  .vrow[data-st="go"] .vdot i,
  .vrow[data-st="ok"] .vdot i {
    animation: none;
  }
}
