/* Соя ДВ — интерфейс под телефон в поле: крупно, контрастно, без лишнего. */

/* Палитра снята с логотипа: зелень хохломского письма, охра бобов,
   червлёный красный и бумажный кремовый фон. */
:root {
  --ground: #f2f4f5;
  --surface: #ffffff;
  --surface-2: #eef1f2;
  --ink: #101418;
  --ink-2: #3c464f;
  --muted: #6d7780;
  --line: #e3e7ea;
  --line-soft: #eef1f3;

  /* Зелёный поля — действие. Всё, что нажимают, зелёное; больше ничего.
     --on-* это цвет текста ПОВЕРХ заливки: в тёмной теме заливка светлеет,
     и белые надписи на ней перестали бы читаться. */
  --ru: #1f9d3d;
  --ru-soft: #e2f5e6;
  --ru-ink: #14702b;
  --on-ru: #ffffff;

  /* Красный Китая — цена и китайская сторона. На 1688 цена именно красная,
     и китайскому закупщику так привычнее всего. */
  --cn: #d7261e;
  --cn-soft: #fde8e6;
  --cn-ink: #a81a13;
  --on-cn: #ffffff;

  /* Золото зерна — третий и последний цвет: им отмечают подтверждённое. */
  --gold: #f5b500;
  --gold-soft: #fff2cc;

  /* Переписка: своё сообщение сплошной зеленью, чужое — белым. */
  --bub-out: #1f9d3d;
  --bub-out-ink: #ffffff;
  --bub-in: #ffffff;
  --thread-bg: #e8ecef;
  --warn: #b57400;
  --warn-soft: #fff2cc;
  --bad: #d7261e;
  --bad-soft: #fde8e6;

  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB",
    "Microsoft YaHei", "Noto Sans SC", "Noto Sans", Roboto, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  /* Типографика: пять ступеней и ни одной больше. Раньше в файле жили
     34 размера — от этого экран выглядит грязным, даже когда всё правильно.
     Мельче 13px не опускаемся: читают на солнце и в перчатках. */
  --t-xs: 0.8125rem;   /* 13px — метки, время, единицы */
  --t-sm: 0.9375rem;   /* 15px — вспомогательный текст */
  --t-md: 1.0625rem;   /* 17px — основной, совпадает с телом страницы */
  --t-lg: 1.25rem;     /* 20px — заголовок блока, крупное число */
  --t-xl: 1.5rem;      /* 24px — заголовок страницы */
  --lh: 1.5;
  --lh-tight: 1.25;   /* заголовки и подписи в две строки */

  /* Глифы кнопок — стрелка, крестик, микрофон. Это знак, а не текст:
     его размер задаётся кнопкой, а не читаемостью строки. */
  --g-sm: 1.25rem;
  --g-md: 1.5rem;

  /* Три насыщенности. 650 и 800 системные шрифты рисуют так же, как 600 и 700:
     разница была задумана, но на экране её нет. */
  --w-reg: 400;
  --w-mid: 600;
  --w-bold: 700;

  /* Три радиуса вместо десяти: 9px, 11px и 3px были ручной подгонкой. */
  --r-sm: 8px;
  --r: 14px;
  --r-lg: 16px;
  --r-pill: 999px;
  --r-tail: 4px;   /* хвостик пузыря переписки */

  --tap: 48px;
  --pad: 16px;
}

/* Тёмной темы у биржи нет намеренно.
   Соя, зерно, накладные — это дневная работа, и заказчик хочет один вид
   на всех экранах: светлый. Автоматическое переключение по системной
   настройке телефона дало бы половине людей вид, которого никто не
   утверждал, и разговор «почему у меня всё чёрное» вместо разговора о деле.
   Поэтому цвета заданы один раз, выше, и не переопределяются. */

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--t-md);
  line-height: var(--lh);
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

/* Фон приложения: три очень мягкие волны — зелёная от левого верха, чуть
   золотистая справа и ещё одна зелёная снизу, все растворяются в прежнем
   сером. Смысл в том, чтобы по бокам от рабочей области не было мёртвого
   поля, но и читать не мешало: карточки остаются белыми, поэтому цифры и
   белок видны ровно как раньше.

   Волны лежат отдельным закреплённым слоем, а не фоном самой страницы.
   Это не украшательство, а необходимость: background-attachment: fixed
   заставляет браузер перерисовывать градиенты на каждом кадре прокрутки,
   и лента партий начинала подтормаживать. Отдельный слой видеокарта держит
   готовым и при прокрутке просто оставляет на месте — рисовать нечего. */
body:not(.land)::before {
  content: '';
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(1200px 700px at 4% -12%, #d5ebd4 0%, rgb(213 235 212 / 0%) 64%),
    radial-gradient(900px 560px at 100% 0%, #f2ead0 0%, rgb(242 234 208 / 0%) 60%),
    radial-gradient(1000px 620px at 92% 108%, #dfeedd 0%, rgb(223 238 221 / 0%) 62%);
}

a { color: inherit; }

h1, h2, h3 { margin: 0; font-weight: var(--w-bold); letter-spacing: -0.02em; line-height: var(--lh-tight); text-wrap: balance; }
h1 { font-size: var(--t-xl); }
h2 { font-size: var(--t-lg); }
h3 { font-size: var(--t-md); letter-spacing: -0.012em; }
p { margin: 0; }

/* ——— шапка ——— */

/* Шапка уезжает при прокрутке, вкладки остаются. Прилипать к одной точке
   они не могут — вкладки просто спрячутся под шапкой, и на телефоне человек
   после первой же прокрутки останется без навигации. Язык меняют раз в жизни,
   а по вкладкам ходят постоянно, поэтому остаются вкладки. */
.top {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding-top: env(safe-area-inset-top);
}
.top__in {
  max-width: 62rem;
  margin: 0 auto;
  padding: 10px var(--pad);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.brand { display: flex; align-items: center; gap: 9px; text-decoration: none; }
.brand__mark { width: 28px; height: 28px; flex: none; display: block; }
.brand__text {
  font-weight: var(--w-bold); letter-spacing: -0.02em; font-size: var(--t-md);
  white-space: nowrap;   /* «Соя ДВ» не должна ломаться на две строки */
}

/* Тот же знак крупно — на экране входа. */
.emblem { width: 84px; height: 84px; display: block; margin: 0 auto 4px; }

.langs { display: flex; gap: 2px; }
.lang {
  /* Раньше на узком экране был крупнее, чем на широком, и высотой 34px —
     мимо собственного правила проекта в 48px. По 中文 промахивались. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--t-sm);
  padding: 0 10px;
  border-radius: var(--r-sm);
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
}
.lang--on { background: var(--surface-2); color: var(--ink); font-weight: var(--w-mid); }

/* ——— вкладки ——— */

.tabs {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  position: sticky;
  top: 0;
  z-index: 15;
  /* У оператора восемь вкладок и они не влезают. Тень справа показывает,
     что список продолжается, — иначе про остальные просто не узнают. */
  background-image: linear-gradient(to left, var(--ground), transparent 24px);
  background-repeat: no-repeat;
  background-position: right center;
  background-size: 24px 100%;
  background-attachment: local, scroll;
}
/* Прилипшие вкладки должны отделяться от контента, который под них уезжает. */
.tabs::after { content: ''; }
.tabs { box-shadow: 0 1px 0 var(--line); }
.tabs::-webkit-scrollbar { display: none; }
.tabs__in { max-width: 62rem; margin: 0 auto; display: flex; padding: 0 8px; }
.tab {
  padding: 13px 12px;
  font-size: var(--t-sm);
  font-weight: var(--w-mid);
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  display: flex; align-items: center; gap: 6px;
}
.tab--on { color: var(--ink); border-bottom-color: var(--ru); }
.tab__n {
  background: var(--ru); color: var(--on-ru); font-size: var(--t-xs); font-weight: var(--w-bold);
  min-width: 18px; height: 18px; border-radius: var(--r);
  display: inline-flex; align-items: center; justify-content: center; padding: 0 5px;
}

/* ——— каркас ——— */

.main {
  flex: 1;
  width: 100%;
  max-width: 42rem;
  margin: 0 auto;
  padding: 20px var(--pad) 48px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.main--wide { max-width: 62rem; }

.back {
  font-size: var(--t-sm); color: var(--muted); text-decoration: none;
  align-self: flex-start; padding: 4px 0;
}

.foot {
  border-top: 1px solid var(--line);
  padding: 16px var(--pad) calc(16px + env(safe-area-inset-bottom));
  font-size: var(--t-sm);
  color: var(--muted);
  display: flex; justify-content: space-between; gap: 12px;
  max-width: 62rem; margin: 0 auto; width: 100%;
}

.head { display: flex; flex-direction: column; gap: 4px; }
.head__sub { color: var(--ink-2); font-size: var(--t-sm); }

/* ——— формы ——— */

form { display: contents; }
.form { display: flex; flex-direction: column; gap: 14px; }

.field { display: flex; flex-direction: column; gap: 6px; }
.field__label { font-size: var(--t-sm); font-weight: var(--w-mid); color: var(--ink-2); }
.field__hint { font-size: var(--t-sm); color: var(--muted);  }
.field__error { font-size: var(--t-sm); color: var(--bad); font-weight: var(--w-mid); }
.field--error .input { border-color: var(--bad); }

.input {
  font: inherit;
  font-size: var(--t-md); /* < 16px заставляет iOS зумить при фокусе */
  color: var(--ink);
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: var(--r);
  padding: 0 14px;
  height: var(--tap);
  width: 100%;
  appearance: none;
}
textarea.input { height: auto; min-height: 96px; padding: 12px 14px;  resize: vertical; }
select.input {
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: right 18px center, right 12px center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 34px;
}
.input:focus-visible { outline: 3px solid var(--ru); outline-offset: 1px; border-color: var(--ru); }
.input[type="file"] { padding: 11px 12px; height: auto; }
.input::placeholder { color: var(--muted); }
.input:disabled { background: var(--surface-2); color: var(--muted); }

.row { display: grid; gap: 10px; grid-template-columns: 1fr 1fr; }
.row-3 { display: grid; gap: 10px; grid-template-columns: repeat(3, 1fr); }
@media (max-width: 380px) { .row-3 { grid-template-columns: 1fr 1fr; } }
/* длинные подписи фильтров не влезают в половину узкого экрана */
@media (max-width: 460px) { .filters .row { grid-template-columns: 1fr; } }
/* Пара полей с длинными подписями на узком экране лучше читается в столбик. */
.row--long { grid-template-columns: 1fr; }
@media (min-width: 30rem) { .row--long { grid-template-columns: 1fr 1fr; } }

.check {
  display: flex; align-items: center; gap: 11px;
  min-height: var(--tap); cursor: pointer; font-size: var(--t-sm);
}
.check input { width: 22px; height: 22px; accent-color: var(--ru); flex: none; }

/* ——— кнопки ——— */

.btn {
  font: inherit; font-weight: var(--w-bold); font-size: var(--t-md); letter-spacing: -0.01em;
  min-height: var(--tap);
  padding: 0 20px;
  border-radius: var(--r);
  border: 1.5px solid transparent;
  background: var(--ru);
  color: var(--on-ru);
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  text-decoration: none;
  text-align: center;
}
.btn:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }
.btn--block { width: 100%; }
.btn--cn { background: var(--cn); color: var(--on-cn); }
.btn--ghost { background: transparent; color: var(--ink); border-color: var(--line); }
.btn--quiet { background: var(--surface-2); color: var(--ink); font-weight: var(--w-mid); }
.btn--sm { min-height: 38px; font-size: var(--t-sm); padding: 0 14px; border-radius: var(--r); }
.btn--danger { background: transparent; color: var(--bad); border-color: var(--line); }

.btns { display: flex; gap: 10px; flex-wrap: wrap; }
.btns--end { justify-content: flex-end; }

/* ——— карточки ——— */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 15px;
  display: flex; flex-direction: column; gap: 11px;
  text-decoration: none;
  color: inherit;
}
.card--link { transition: border-color 0.12s ease, transform 0.08s ease; }
.card--link:active { border-color: var(--ru); transform: scale(0.995); }
@media (hover: hover) { .card--link:hover { border-color: var(--ru); } }
.cards { display: flex; flex-direction: column; gap: 11px; }

.card__top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.card__title { font-weight: var(--w-bold); font-size: var(--t-md); letter-spacing: -0.015em; }
.card__place { font-size: var(--t-sm); color: var(--ink-2); }

.specs {
  /* Характеристики — одной строкой через точку, а не россыпью цветных плашек.
     На бирже строка = позиция: глаз идёт по одной линии, а не прыгает
     по семи прямоугольникам разного цвета. */
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 6px;
  color: var(--ink-2);
  font-size: var(--t-sm);
}
.spec {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  font-size: var(--t-sm);
}
.spec + .spec::before { content: "·"; color: var(--line); margin-right: 6px; }
.spec b { font-weight: var(--w-bold); }
.spec--hi { color: var(--ink); }

.thumb {
  width: 100%; height: 128px; object-fit: cover;
  border-radius: var(--r); background: var(--surface-2); display: block;
}
.thumb--ph {
  display: flex; align-items: center; justify-content: center;
  height: 160px; overflow: hidden;
  background: linear-gradient(180deg, var(--gold-soft), var(--surface-2));
}
.thumb__pic { max-width: 78%; max-height: 128px; object-fit: contain; display: block; }

/* ——— деньги ——— */

.price { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
/* Цена — главное число на карточке, поэтому крупнее и плотнее остального. */
.price__main {
  font-size: var(--t-xl); font-weight: var(--w-bold); letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.price__unit { font-size: var(--t-sm); color: var(--muted); }
.price__alt { font-size: var(--t-sm); color: var(--muted); font-variant-numeric: tabular-nums; }
.price--ask { font-size: var(--t-md); font-weight: var(--w-bold); color: var(--ink-2); }

/* ——— закрытая цена ——— */

/* В разметке под размытием стоит заглушка «00 000», а не настоящее число:
   гостю цена не уходит вовсе, подсматривать в исходнике нечего. */
.blurred {
  filter: blur(6px);
  user-select: none; -webkit-user-select: none;
  pointer-events: none;
  opacity: 0.75;
}
.price--locked { align-items: center; gap: 12px; }
.price__lock {
  font-size: var(--t-sm); font-weight: var(--w-bold); color: var(--ru);
  background: var(--ru-soft); border-radius: var(--r-sm); padding: 4px 9px;
  white-space: nowrap;
}
/* ——— «требует внимания» ——— */

.attn {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); overflow: hidden;
  display: flex; flex-direction: column;
}
.attn__row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: var(--tap); padding: 0 14px;
  text-decoration: none; color: var(--ink);
  border-bottom: 1px solid var(--line-soft);
  border-left: 3px solid transparent;
}
.attn__row:last-child { border-bottom: 0; }
.attn__row--urgent { border-left-color: var(--ru); }
.attn__row--info { border-left-color: var(--line); }
.attn__row:active { background: var(--surface-2); }
@media (hover: hover) { .attn__row:hover { background: var(--surface-2); } }
.attn__text { font-size: var(--t-sm); font-weight: var(--w-mid); }
.attn__n {
  min-width: 24px; height: 24px; border-radius: var(--r); padding: 0 7px;
  background: var(--ru-soft); color: var(--ru-ink);
  font-size: var(--t-sm); font-weight: var(--w-bold);
  display: inline-flex; align-items: center; justify-content: center;
  font-variant-numeric: tabular-nums; flex: none;
}
.attn__row--info .attn__n { background: var(--surface-2); color: var(--ink-2); }

.cta {
  background: var(--ru); color: var(--on-ru);
  border-radius: var(--r); padding: 15px;
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
}
.cta__text { display: flex; flex-direction: column; gap: 2px; min-width: 12rem; flex: 1; }
.cta__text b { font-size: var(--t-md); letter-spacing: -0.015em; }
.cta__text span { font-size: var(--t-sm); opacity: 0.85; }
.cta .btn { background: var(--on-ru); color: #2e4620; border-color: var(--on-ru); }
.cta .btn:focus-visible { outline-color: var(--on-ru); }

/* карточка без действия — видна, но не тянет на себя внимание */
.card--dim { opacity: 0.62; }

.delivered {
  background: var(--ru-soft); color: var(--ru);
  border-radius: var(--r); padding: 9px 11px;
  font-size: var(--t-sm); font-weight: var(--w-mid);
  display: flex; flex-direction: column; gap: 2px;
  font-variant-numeric: tabular-nums;
}
.delivered__row {
  display: flex; justify-content: space-between; gap: 10px; align-items: baseline;
}
.delivered b { font-size: var(--t-md); white-space: nowrap; }
.delivered small { font-weight: var(--w-mid); opacity: 0.8; font-size: var(--t-xs); }
/* строка «набрано / не хватает» в заявке остаётся в одну линию */
.delivered:not(:has(.delivered__row)) { flex-direction: row; justify-content: space-between; align-items: baseline; }

.calc { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.calc__head {
  padding: 12px 15px; background: var(--surface-2);
  font-weight: var(--w-bold); font-size: var(--t-sm); letter-spacing: -0.01em;
  display: flex; justify-content: space-between; gap: 10px; align-items: center;
}
.calc__row {
  display: flex; justify-content: space-between; gap: 14px;
  padding: 11px 15px; font-size: var(--t-sm);
  border-top: 1px solid var(--line-soft);
}
.calc__row span:last-child { font-variant-numeric: tabular-nums; white-space: nowrap; }
.calc__row--sub { font-size: var(--t-sm); color: var(--muted); padding-top: 7px; padding-bottom: 7px; }
.calc__row--sub span:last-child { color: var(--muted); }
.calc__row--total {
  background: var(--ru-soft); color: var(--ru-ink); font-weight: var(--w-bold); border-top-color: transparent;
}
.calc__note { padding: 11px 15px; font-size: var(--t-sm); color: var(--muted); border-top: 1px solid var(--line-soft); }

/* ——— значки и плашки ——— */

.badge {
  font-size: var(--t-xs); font-weight: var(--w-bold); letter-spacing: 0.01em;
  padding: 4px 8px; border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--ink-2);
  white-space: nowrap;
}
.badge--ok { background: var(--ru-soft); color: var(--ru); }
.badge--warn { background: var(--warn-soft); color: var(--warn); }
.badge--bad { background: var(--bad-soft); color: var(--bad); }
.badge--cn { background: var(--cn-soft); color: var(--cn-ink); }
.badge--ru { background: var(--ru-soft); color: var(--ru-ink); }
/* в колоночном flex значок иначе растягивается на всю ширину карточки */
.card > .badge, .stack > .badge { align-self: flex-start; }

.alert {
  border-radius: var(--r); padding: 13px 15px; font-size: var(--t-md); 
  border: 1px solid var(--line); background: var(--surface);
}
.alert--ok { background: var(--ru-soft); border-color: transparent; color: var(--ru); font-weight: var(--w-mid); }
.alert--warn { background: var(--warn-soft); border-color: transparent; color: var(--warn); }
.alert--bad { background: var(--bad-soft); border-color: transparent; color: var(--bad); }
.alert b { font-weight: var(--w-bold); }

.empty {
  text-align: center; padding: 44px 20px;
  color: var(--muted);
  display: flex; flex-direction: column; gap: 16px; align-items: center;
}
/* Картинку рисуем настоящим изображением, а не фоном у ::before:
   объёмный рендер должен масштабироваться и грузиться отложенно. */
.empty__pic {
  /* Знак, а не картинка: пустому месту нечего иллюстрировать, а рисунок там
     всегда читается не так, как задумано. Размер сдержанный — это подпись
     к строке текста, а не сама новость. */
  width: 72px; height: 72px; object-fit: contain; opacity: 0.65;
}
/* ——— фильтры ——— */

/* Панель фильтров свёрнута по умолчанию — партии видны сразу, без прокрутки. */
.fbox {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
}
.fbox__sum {
  list-style: none; cursor: pointer;
  min-height: var(--tap); padding: 0 14px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.fbox__sum::-webkit-details-marker { display: none; }
.fbox__sum:focus-visible { outline: 3px solid var(--ru); outline-offset: -3px; border-radius: var(--r); }
.fbox__digest {
  font-size: var(--t-sm); font-weight: var(--w-mid); color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fbox__chev {
  width: 9px; height: 9px; flex: none;
  border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
  transform: rotate(45deg) translate(-2px, -2px);
}
.fbox[open] .fbox__chev { transform: rotate(225deg) translate(-2px, -2px); }
.fbox[open] .fbox__sum { border-bottom: 1px solid var(--line-soft); }

.filters {
  padding: 12px 14px 14px; display: flex; flex-direction: column; gap: 10px;
}

/* ——— ползунки ——— */




.count { font-size: var(--t-sm); color: var(--muted); }

/* ——— полоса этапов сделки ——— */

/* линия между кружками */

/* ——— переписка ———
   Пузыри, лента и композер собраны в одном месте: раньше .thread, .msg__time
   и .msg__img были заданы по два раза в разных концах файла, и правка
   попадала не туда. */

.msg__orig { display: block; font-size: var(--t-xs); color: var(--muted); margin-top: 5px; font-family: var(--mono); }
/* Исходник под переводом в своём пузыре — тоже светлым, а не серым. */
.msg--me .msg__orig { color: rgb(255 255 255 / 72%); }
.msg--me .msg__also { color: rgb(255 255 255 / 82%); }
/* Единица прямо в поле ввода: цена на бирже всегда за тонну, и человек
   должен видеть это, пока набирает, а не догадываться по плейсхолдеру. */
.unit { position: relative; display: block; }
.unit .input { padding-right: 4.2rem; }
.unit__tag {
  position: absolute; top: 50%; right: 12px; transform: translateY(-50%);
  color: var(--muted); font-size: var(--t-sm); pointer-events: none;
  font-variant-numeric: tabular-nums;
}

/* Маршрут без денег: пока ставка ориентировочная, в карточке остаётся
   только «куда и сколько километров». Тише цены, но на своей строке. */
.route {
  /* Маршрут — такая же вспомогательная строка, как характеристики.
     Раньше это была зелёная плашка: третий цветной прямоугольник в карточке. */
  color: var(--ink-2);
  font-size: var(--t-sm);
}

/* Попытки обхода: что человек пробовал передать, читаемо и с переносами. */
.tries { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.tries li {
  display: flex; flex-direction: column; gap: 2px;
  padding: 8px 10px; border-radius: var(--r); background: var(--warn-soft);
  font-size: var(--t-sm); overflow-wrap: anywhere;
}
.tries b { font-family: var(--mono); color: var(--warn); }
.tries .muted { font-size: var(--t-xs); }

/* Спрятанный контакт: обе стороны видят, что здесь что-то было, и почему. */
.msg__hid {
  display: inline-block; margin-top: 6px; padding: 2px 8px; border-radius: var(--r-pill);
  font-size: var(--t-xs); background: var(--warn-soft); color: var(--warn);
}
/* Та же пилюля, но живая: кнопка «Перевести» под сообщением без перевода.
   Зелёная, как всё нажимаемое на площадке, и с полем под палец. */
.msg__trbtn {
  border: 0; cursor: pointer; font: inherit;
  font-size: var(--t-xs); font-weight: var(--w-mid);
  padding: 4px 12px; background: var(--ru-soft); color: var(--ru-ink);
}
.msg__trbtn:disabled { cursor: default; opacity: 0.7; }
.msg__trbtn:focus-visible { outline: 2px solid var(--ru); outline-offset: 1px; }

/* ——— таблицы оператора ——— */

.tablewrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
table { border-collapse: collapse; width: 100%; font-size: var(--t-sm); }
th, td { padding: 11px 13px; text-align: left; border-bottom: 1px solid var(--line-soft); white-space: nowrap; }
th { font-size: var(--t-xs); text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); font-weight: var(--w-bold); }
tr:last-child td { border-bottom: 0; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--mono); }

/* ——— мелочи ——— */

.stack { display: flex; flex-direction: column; gap: 12px; }
.muted { color: var(--muted); font-size: var(--t-sm); }
.sep { height: 1px; background: var(--line); border: 0; margin: 4px 0; }
.hint { font-size: var(--t-sm); color: var(--muted);  }

.pick__opt:has(input:checked) .pick__h,

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* Готовые фразы — основной способ написать; свои слова спрятаны под «details»,
   потому что переводчика нет и такое сообщение уйдёт как есть. */
.composer--phrase { gap: 12px; }
.composer--phrase .field { margin: 0; }

/* ——— мессенджер ——— */

/* Список разговоров: имя, обрывок последнего сообщения, непрочитанное.
   Всё, по чему человек узнаёт диалог, не открывая его. */
.dialogs { display: flex; flex-direction: column; gap: 2px; }
.dlg {
  display: flex; flex-direction: column; gap: 3px;
  padding: 12px 14px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
  text-decoration: none; min-height: var(--tap);
}
.dlg--new { border-color: var(--ru); background: var(--ru-soft); }
.dlg__top { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.dlg__name {
  font-weight: var(--w-mid); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dlg__time { font-size: var(--t-xs); color: var(--muted); white-space: nowrap; }
.dlg__bottom { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.dlg__last {
  color: var(--ink-2); font-size: var(--t-sm); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dlg--new .dlg__last { color: var(--ink); }
.dlg__n {
  flex: none; background: var(--ru); color: var(--on-ru);
  font-size: var(--t-xs); font-weight: var(--w-bold); min-width: 20px; height: 20px;
  border-radius: var(--r); display: inline-flex; align-items: center; justify-content: center; padding: 0 6px;
}
.dlg__lot { font-size: var(--t-xs); color: var(--muted); }

/* Лента прокручивается вместе со страницей, а не внутри своей рамки:
   вложенная прокрутка на телефоне всегда промахивается мимо пальца.
   На месте остаётся поле ввода — оно прилипает к низу экрана.

   Своя подложка у ленты — чтобы пузыри читались как разговор, а не как
   карточки на общем фоне страницы. */
.thread {
  display: flex; flex-direction: column; gap: 10px;
  min-height: 34vh;
  margin: 0 -14px; padding: 12px 14px;
  background: var(--thread-bg);
}

/* Пузырь. Свой — зелёный, как привык китайский покупатель в WeChat;
   чужой — белый лист. Разница видна на солнце и на дешёвом экране. */
.msg {
  max-width: 78%; padding: 9px 12px; border-radius: var(--r);
  font-size: var(--t-md);
}
/* Объём у пузырей — тенью и лёгким градиентом, а не картинками: разговор
   должен читаться, а не разглядываться. Пузырь лежит НА подложке ленты,
   и тень говорит об этом лучше рамки. */
.msg--them {
  background: var(--bub-in); border: 1px solid var(--line-soft);
  align-self: flex-start; border-bottom-left-radius: var(--r-tail);
  box-shadow: 0 1px 2px rgb(16 20 24 / 7%);
}
.msg--me {
  background: linear-gradient(175deg, #27ac47, var(--bub-out) 62%);
  color: var(--bub-out-ink);
  align-self: flex-end; border-bottom-right-radius: var(--r-tail);
  box-shadow: 0 1px 2px rgb(20 110 45 / 22%), 0 4px 10px -4px rgb(20 110 45 / 30%);
}
/* Подряд идущие сообщения одного автора — одной группой, без хвостика. */
.msg--cont { margin-top: -7px; }
.msg--cont.msg--them { border-bottom-left-radius: var(--r); border-top-left-radius: var(--r-tail); }
.msg--cont.msg--me { border-bottom-right-radius: var(--r); border-top-right-radius: var(--r-tail); }

/* Системная запись — не пузырь, а отметка посередине: цена, проба, событие. */
.msg--sys {
  align-self: center; max-width: 92%;
  background: var(--surface-2); color: var(--ink-2);
  font-size: var(--t-sm); text-align: center; border-radius: var(--r);
  padding: 8px 12px;
}
/* Событие сделки — со значком слева: рукопожатие про цену, грузовик про
   перевозку. Видно, что произошло, ещё до чтения строки. */
.msg--sys--ico {
  display: grid; grid-template-columns: auto 1fr; align-items: center;
  gap: 10px; text-align: left; padding: 8px 14px 8px 10px;
  background: var(--surface);
  box-shadow: 0 1px 2px rgb(16 20 24 / 7%);
}
.msg__sysico { width: 26px; height: 26px; display: block; object-fit: contain; grid-row: span 2; }
.msg--sys--ico .msg__meta { justify-content: flex-start; margin-top: 1px; }
.msg--sys .msg__meta { justify-content: center; }

/* Разделитель: день или большой перерыв в разговоре. */
.thread__sep {
  align-self: center; margin: 6px 0 2px;
  font-size: var(--t-xs); color: var(--muted);
  background: var(--surface-2); border-radius: var(--r-pill); padding: 3px 12px;
}

.msg__text { display: block; white-space: pre-wrap; overflow-wrap: anywhere; }
.msg__img {
  display: block; max-width: 100%; border-radius: var(--r); margin-bottom: 6px;
}
.msg__time { font-size: var(--t-xs); color: var(--muted); }
.msg--me .msg__time { color: var(--bub-out-ink); opacity: 0.62; }
.msg__meta { display: flex; align-items: center; gap: 8px; margin-top: 4px; justify-content: flex-end; }
.msg--them .msg__meta { justify-content: flex-start; }

/* Композер — фразы, цитата и поле ввода одним липким блоком НАД нижней
   панелью. Раньше .say липла сама по себе с z-index ниже панели и на
   прокрутке уезжала под «Торговля / Переписка / Новости». */
.composer {
  position: sticky;
  bottom: calc(var(--bottom-h, 0px) + env(safe-area-inset-bottom));
  z-index: 17;
  display: flex; flex-direction: column; gap: 8px;
  padding: 8px 0 10px;
  background: var(--ground);
  box-shadow: 0 -10px 18px -12px rgba(0, 0, 0, 0.35);
}

/* Строка ввода: скрепка, поле, кнопка. Ничего лишнего между пальцем и «отправить». */
.say {
  display: flex; align-items: flex-end; gap: 8px;
  padding: 8px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
}
textarea.say__text {
  flex: 1; min-height: 44px; height: 44px; max-height: 33vh;
  border: 0; background: transparent; padding: 11px 4px; resize: none;
  border-radius: 0;
}
.say__text:focus-visible { outline: none; }
.say__clip {
  flex: none; width: 44px; height: 44px; border-radius: var(--r);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; font-size: var(--t-lg); background: var(--surface-2);
}
.say__clip input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.say__send {
  flex: none; width: 44px; height: 44px; border: 0; border-radius: var(--r);
  background: var(--ru); color: var(--on-ru); font-size: var(--g-sm); line-height: 1;
  cursor: pointer;
  box-shadow: var(--lift-btn);
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.say__send:active { transform: translateY(1px); box-shadow: 0 1px 2px rgb(20 110 45 / 30%); }
.say__send:focus-visible { outline: 3px solid var(--ru); outline-offset: 2px; }

/* Быстрые фразы: для тех, у кого другой язык. Свёрнуты, чтобы не мешать. */
.quick[open] > summary::before { content: '– '; }
.chip {
  font: inherit; font-size: var(--t-sm); cursor: pointer;
  padding: 8px 12px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--ink); border: 1px solid var(--line);
}
.chip:active { background: var(--ru-soft); }

/* Перевозка — то, ради чего площадка существует. Поэтому она над перепиской,
   а не спрятана в меню. */
.ship {
  background: var(--cn-soft); border: 1px solid var(--cn); border-radius: var(--r);
  padding: 12px 14px; display: flex; flex-direction: column; gap: 6px;
}
.ship__top { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.ship--ask > summary {
  cursor: pointer; font-weight: var(--w-bold); color: var(--cn-ink); list-style: none;
}
.ship--ask > summary::-webkit-details-marker { display: none; }
.ship--ask > summary::after { content: ' →'; }

.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

/* ——— выбор роли при регистрации ——— */
.rolecards { display: flex; flex-direction: column; gap: 14px; }
/* Крупные кнопки: выбор роли — первое решение человека на бирже,
   и промахнуться в нём нельзя. Поэтому картинка, а не значок. */
.rolecard {
  width: 100%; font: inherit; text-align: center; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 26px 18px; border-radius: var(--r-lg);
  background: var(--surface); border: 2px solid var(--line); color: var(--ink);
}
.rolecard:hover { border-color: var(--ru); }
.rolecard:active { background: var(--ru-soft); border-color: var(--ru); }
.rolecard:focus-visible { outline: 3px solid var(--ru); outline-offset: 2px; }
.rolecard__img { width: 88px; height: 88px; display: block; }
.rolecard__t { font-weight: var(--w-bold); font-size: var(--t-lg); letter-spacing: -0.015em; }
.rolecard__h { font-size: var(--t-sm); color: var(--muted); }
/* На широком экране три кнопки встают в ряд. */
@media (min-width: 46rem) {
  .rolecards { flex-direction: row; }
  .rolecards > form { flex: 1; display: flex; }
}

/* ——— мессенджер: голос, цитаты, ответ ——— */
.msg { position: relative; }
/* Цитата: на что отвечают.
   Дважды была нечитаемой. Сначала серой на зелёном, потом белой с
   прозрачностью 78% поверх осветлённого фона — то есть светлым по светлому.
   На насыщённом зелёном работает наоборот: подложку ЗАТЕМНЯЕМ, а текст
   оставляем чистым белым. Тогда цитата отделяется от пузыря и читается. */
.msg__quote {
  display: block; font-size: var(--t-sm); line-height: var(--lh-tight);
  color: var(--ink-2);
  background: rgb(16 20 24 / 5%);
  border-left: 3px solid var(--ru);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  padding: 5px 9px; margin-bottom: 6px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}
.msg--me .msg__quote {
  color: #fff;
  background: rgb(0 0 0 / 20%);
  border-left-color: rgb(255 255 255 / 90%);
}
.msg__voice { display: block; max-width: 220px; height: 40px; margin: 2px 0; }
.msg__vt { font-size: var(--t-xs); color: var(--muted); }
/* Ответить: цель под палец, а не 18 пикселей. Состояние :active — потому что
   :hover на телефоне не существует. */
.msg__reply {
  border: 0; background: transparent; cursor: pointer; color: var(--muted);
  font-size: var(--g-sm); line-height: 1; border-radius: var(--r);
  width: 34px; height: 34px; margin: -6px 0;
  display: flex; align-items: center; justify-content: center;
}
.msg__reply:hover, .msg__reply:active { background: var(--surface-2); color: var(--ink); }

/* [hidden] у элемента с display:flex не работает — правило автора сильнее
   браузерного. Без этой строки плашка «В ответ на» висит пустой. */
.replybar[hidden] { display: none; }
.replybar {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px; border-radius: var(--r) var(--r) 0 0;
  background: var(--surface-2); font-size: var(--t-sm);
  border: 1px solid var(--line); border-bottom: 0;
}
.replybar__t { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.replybar__x {
  border: 0; background: transparent; font-size: var(--g-sm); line-height: 1;
  cursor: pointer; color: var(--muted); padding: 0 4px;
}

.say__mic {
  flex: none; width: 44px; height: 44px; border: 0; border-radius: var(--r);
  background: var(--surface-2); font-size: var(--g-sm); cursor: pointer; line-height: 1;
}
.say__mic--on { background: var(--cn); color: var(--on-cn); animation: pulse 1s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: 0.55; } }
@media (prefers-reduced-motion: reduce) { .say__mic--on { animation: none; } }

/* Поле ИНН на время запроса в ЕГРЮЛ. */
.input--loading { background-image: linear-gradient(90deg, transparent, var(--ru-soft), transparent); background-size: 200% 100%; animation: shine 1s linear infinite; }
@keyframes shine { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .input--loading { animation: none; } }

/* ——— лента уведомлений ——— */
.feed { display: flex; flex-direction: column; gap: 2px; }
.ev {
  display: flex; gap: 12px; align-items: center;
  padding: 12px 14px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
  text-decoration: none; min-height: var(--tap);
}
.ev--new { border-color: var(--ru); background: var(--ru-soft); }
.ev__icon { flex: none; display: block; object-fit: contain; }
.ev__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ev__text { color: var(--ink); font-size: var(--t-sm); }
.ev__time { color: var(--muted); font-size: var(--t-xs); }

/* ——— отзывы на профиле ——— */
.rep { display: flex; gap: 16px; font-size: var(--t-md); font-weight: var(--w-bold); }
.rep__good { color: var(--ru); }
.rep__bad { color: var(--bad); }
.rev-pick { display: flex; gap: 10px; }
.rev-opt { flex: 1; }
.rev-opt input { position: absolute; opacity: 0; }
.rev-opt span {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 12px; border-radius: var(--r); border: 1.5px solid var(--line);
  background: var(--surface); cursor: pointer; font-weight: var(--w-mid);
}
.rev-opt input:checked + span { border-color: var(--ru); background: var(--ru-soft); color: var(--ru-ink); }

/* ——— новости ——— */
/* Лента новостей: карточками, как в обычной ленте, а не сплошным текстом. */
.news { display: flex; flex-direction: column; gap: 10px; }
.news__item {
  display: block;
  padding: 14px 16px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
  text-decoration: none;
}
.news__item:hover { border-color: var(--ru); }
.news__title {
  display: block; color: var(--ink); font-weight: var(--w-mid);
  font-size: var(--t-md);  margin-bottom: 8px;
  text-decoration: none;
}
.news__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  color: var(--muted); font-size: var(--t-sm);
}
/* Источник обязателен: заголовки чужие, авторство должно быть видно. */
.news__src {
  background: var(--surface-2); color: var(--ink-2);
  padding: 2px 8px; border-radius: var(--r-pill); font-weight: var(--w-mid);
}

/* ——— колокольчик уведомлений в шапке ——— */
.top__right { display: flex; align-items: center; gap: 10px; }
.bell {
  position: relative; display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: var(--r); text-decoration: none;
  flex: none;
}
.bell:active { background: var(--surface-2); }
.bell__ico { display: block; object-fit: contain; }
/* Значки — объёмные, цветные и одинаково яркие. Чтобы было видно, где ты
   сейчас, приглушаем невыбранные, а не подкрашиваем выбранный. */
.bell__ico { opacity: .75; filter: saturate(.7); transition: opacity .12s, filter .12s; }
.bell:hover .bell__ico { opacity: 1; filter: none; }
/* Есть непрочитанное — колокольчик оживает и получает счётчик. */
.bell--on .bell__ico { opacity: 1; filter: none; }
.bell__n {
  position: absolute; top: 1px; right: 0;
  background: var(--cn); color: var(--on-cn);
  font-size: var(--t-xs); font-weight: var(--w-bold); line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 5px; border-radius: var(--r-pill);
  display: inline-flex; align-items: center; justify-content: center;
  border: 2px solid var(--surface);
}

/* ——— документы на проверку ——— */
.docs { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.doc {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 12px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
}
.doc__name { color: var(--ink); text-decoration: none; font-size: var(--t-sm); }
.doc__x {
  border: 0; background: transparent; cursor: pointer; color: var(--muted);
  font-size: var(--g-md); line-height: 1; padding: 0 6px;
}
.doc__x:hover { color: var(--bad); }

/* Документы стоят выше формы профиля и отделены рамкой, чтобы не сливаться
   с реквизитами: это разные действия и разные формы. */
.docsbox {
  display: flex; flex-direction: column; gap: 10px;
  padding: 16px; border-radius: var(--r);
  background: var(--surface-2); border: 1px solid var(--line);
}

/* ——— просмотр фото из переписки ——— */
.msg__img { cursor: zoom-in; }
.lightbox {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(0, 0, 0, 0.9);
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
}
.lightbox[hidden] { display: none; }
.lightbox__img {
  max-width: 100%; max-height: 100%;
  border-radius: var(--r); object-fit: contain;
}
/* Крестик крупный и в безопасной зоне — на телефоне под чёлкой не спрячется. */
.lightbox__x {
  position: absolute; top: calc(12px + env(safe-area-inset-top)); right: 12px;
  width: 48px; height: 48px; border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, 0.16); color: #fff;
  font-size: var(--g-md); line-height: 1; cursor: pointer;
}
.lightbox__x:active { background: rgba(255, 255, 255, 0.3); }

/* Продавец на карточке партии: имя, значок проверки и вход в отзывы. */
.seller { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: var(--t-sm); }
.seller__name { color: var(--ink-2); font-weight: var(--w-mid); }
.seller__rev { color: var(--ru); font-size: var(--t-sm); text-decoration: none; }
.seller__rev:hover { text-decoration: underline; }
.head__link { text-decoration: none; }
.head__link:hover { text-decoration: underline; }

/* Документы: строка «название — файл — кнопка». Без списка «что за документ»:
   человек видит сразу, какие сканы нужны, и прикладывает их по очереди. */
.docrow {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px 12px;
  align-items: center;
  padding: 12px 0;
  border-top: 1px solid var(--line);
}
.docrow__label { font-weight: var(--w-mid); }
.docrow__file { grid-column: 1 / -1; font: inherit; color: var(--ink-2); }
.docrow__file::file-selector-button {
  font: inherit;
  padding: 8px 14px;
  margin-right: 10px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface-2);
  color: var(--ink);
  cursor: pointer;
}
@media (min-width: 640px) {
  .docrow { grid-template-columns: minmax(140px, 200px) minmax(0, 1fr) auto; align-items: center; }
  .docrow__file { grid-column: auto; }
}
/* Кнопка не должна выезжать за карточку: имя файла — длинное, поэтому
   средней колонке разрешаем сжиматься, а кнопке — держать одну строку. */
.docrow__label { min-width: 0; overflow-wrap: anywhere; }
.docrow__file { min-width: 0; max-width: 100%; }
.docrow .btn { white-space: nowrap; justify-self: end; }

/* Кружок «i» у цены: из чего сложилась цена под ключ. Раскрывается и по
   наведению, и по тапу — на телефоне наведения нет. */

/* Живой пересчёт на форме партии: своя цена, доставка, итог под ключ. */
.turnkey {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface-2);
  padding: 10px 12px;
  margin: -4px 0 4px;
}
.turnkey__row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 3px 0;
  font-size: var(--t-sm);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.turnkey__row b { color: var(--ink); }
.turnkey__row--total { border-top: 1px solid var(--line); margin-top: 4px; padding-top: 6px; }

/* ——— Две главные плашки: покупка и продажа сои ———
   Это первое, что видно на экране, и первое, что человек выбирает:
   смотреть, кто покупает, или смотреть, кто продаёт. Цветом разделены,
   как на биржах, — глаз находит нужную сторону без чтения. */

/* ——— Нижняя панель: своё, разговор, новости ———
   Прижата книзу и всегда под большим пальцем. Всё, что относится
   к рынку, живёт наверху; здесь — только личное. */
.bottom {
  position: sticky;
  bottom: 0;
  z-index: 16;
  background: var(--surface);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
}
.bottom__in {
  max-width: 62rem;
  margin: 0 auto;
  display: flex;
  justify-content: space-around;
}
.bnav {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 8px 4px 10px;
  color: var(--muted);
  text-decoration: none;
  font-size: var(--t-xs);
  font-weight: var(--w-mid);
  position: relative;
}
.bnav__ico {
  display: block; object-fit: contain;
  opacity: .55; filter: saturate(.5);
  transition: opacity .12s, filter .12s;
}
.bnav:hover .bnav__ico { opacity: .8; filter: saturate(.8); }
.bnav--on { color: var(--ink); }
.bnav--on .bnav__ico { opacity: 1; filter: none; }
.bnav__n {
  position: absolute;
  top: 4px;
  left: 50%;
  margin-left: 4px;
  min-width: 17px;
  padding: 0 5px;
  border-radius: var(--r-pill);
  background: var(--ru);
  color: #fff;
  font-size: var(--t-xs);
  line-height: 1;
  text-align: center;
}

/* На телефоне в шапке колокольчик, профиль и языки. Вместе с именем шапке
   нужно 410 пикселей, поэтому на обычном телефоне имя прячем — иначе языки
   уезжают за край и до 中文 не дотянуться. На широких телефонах (430 и больше)
   место есть, и знак снова стоит с именем. */
@media (max-width: 420px) {
  .brand__text { display: none; }
}
@media (max-width: 480px) {
  .top__right { gap: 6px; }
  .langs { gap: 2px; }
  .lang { padding: 0 8px; }
  .bell { padding: 4px 6px; }
}

/* ——— Компьютер: раскладка как на биржах ———
   Крупные плашки и нижняя панель — это телефон. На широком экране нижняя
   панель уезжает наверх строкой ссылок, а «покупка / продажа» становится
   компактным переключателем над списком. Порядок блоков меняем flex-order,
   разметка одна на оба случая. */
@media (min-width: 720px) {
  body { display: flex; flex-direction: column; min-height: 100vh; }
  .top    { order: 1; }
  .bottom { order: 2; }
  .tabs   { order: 3; }
  .main   { order: 5; }
  .foot   { order: 6; margin-top: auto; }

  /* «Моё» — строка ссылок под шапкой */
  .bottom {
    position: static;
    border-top: none;
    border-bottom: 1px solid var(--line);
    padding-bottom: 0;
  }
  .bottom__in { justify-content: flex-start; gap: 2px; padding: 0 12px; }
  .bnav {
    flex: 0 0 auto;
    flex-direction: row;
    gap: 8px;
    padding: 13px 14px;
    font-size: var(--t-sm);
    border-bottom: 2px solid transparent;
  }
  .bnav__ico { width: 24px; height: 24px; }
  .bnav--on { border-bottom-color: var(--ru); }
  .bnav__n { position: static; margin: 0; }

  /* Покупка / продажа — один компактный переключатель */
}

/* Строка быстрых фильтров над списком: сколько тонн и через какой город.
   Два поля, с которых начинается разговор о партии. */
.qrow {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 0 0 12px;
  flex-wrap: wrap;
}
.qrow .input { flex: 1 1 130px; min-width: 0; }
.qrow .btn { flex: 0 0 auto; }

/* Подпись на карточке: продажа или покупка. Цвета те же, что у переключателя
   наверху, — карточка сразу читается как «эту сою продают» / «эту ищут». */
.badge--sell { background: var(--cn-soft); color: var(--cn-ink); }
.badge--buy  { background: var(--ru-soft); color: var(--ru-ink); }

/* Что площадка добавляет к цене фермера. Отдельным блоком, но некрупно:
   это пояснение к полю цены, а не главный элемент экрана. */
.addon {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px 12px;
  align-items: center;
  margin: 2px 0 10px;
  padding: 9px 12px;
  border: 1px solid var(--ru);
  border-left-width: 3px;
  border-radius: var(--r);
  background: var(--ru-soft);
}
.addon__sum {
  grid-row: span 2;
  font-size: var(--t-md);
  font-weight: var(--w-bold);
  color: var(--ru-ink);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.addon__text { display: flex; flex-direction: column; }
.addon__text b { font-size: var(--t-sm); color: var(--ink); }
.addon__text span { font-size: var(--t-xs); color: var(--ink-2); }
.addon__list {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 5px;
}
.addon__item {
  padding: 2px 8px;
  border-radius: var(--r-pill);
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: var(--t-xs);
  color: var(--ink-2);
}
@media (max-width: 460px) {
  .addon { grid-template-columns: 1fr; }
  .addon__sum { grid-row: auto; }
}

/* Проба — такая же зелёная плашка, как белок: это признак партии,
   а не выкрик. Отличается только тем, что стоит не у всех. */
.spec--ok { color: var(--ru-ink); font-weight: var(--w-mid); }
.spec--off { color: var(--muted); }

/* Покупатель вписывает свой объём прямо в расчёте. */
.calc__buy { align-items: center; gap: 10px; }
.calc__take { display: flex; align-items: center; gap: 8px; color: var(--ink-2); flex-wrap: wrap; }
.calc__take .input { width: 7.5em; padding: 6px 10px; font-size: var(--t-sm); text-align: right; }
.calc__note--warn { color: var(--warn); }

/* Панель фильтров: галочки в одну строку и без лишнего воздуха —
   это уточнения к полям выше, а не самостоятельный блок. */
.filters .checks {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 22px;
  margin: -2px 0 2px;
}
.filters .check { min-height: 0; padding: 6px 0; font-size: var(--t-sm); }
.filters .check input { width: 18px; height: 18px; }
.filters { gap: 12px; }

/* Цена одобрена — зелёная плашка: это главный результат разговора. */

/* Предложение ждёт ответа — та же карточка, но нейтральная. */

/* Итог расчёта — крупнее и заметнее остальных строк. */
.turnkey__row--total {
  margin: 6px -12px -10px;
  padding: 11px 12px;
  border-top: none;
  border-radius: 0 0 var(--r) var(--r);
  background: var(--ru-soft);
  color: var(--ru-ink);
  font-size: var(--t-md);
  font-weight: var(--w-bold);
}
.turnkey__row--total b { color: var(--ru-ink); }

/* Действия по сделке — компактной строкой над ценой, справа. */

/* Две кнопки сделки одной строкой: цена занимает ширину, проба — сбоку.
   На узком экране встают друг под друга. */
@media (max-width: 560px) {
}

/* Высота нижней панели — композер прилипает точно над ней. */
:root { --bottom-h: 0px; }
@media (max-width: 719px) { :root { --bottom-h: 62px; } }

/* Партия, о которой идёт разговор: липкой строкой под шапкой. */

/* ——— переписка: список слева, разговор справа ———

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

   На телефоне колонок нет: остаётся ровно та половина, за которой пришли —
   на /deals список, в разговоре сам разговор. Переключает их не скрипт,
   а класс на обёртке: mail--list или mail--chat. */
.mail {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}
.mail__side { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.mail__sideh {
  font-size: var(--t-sm); font-weight: var(--w-bold); color: var(--muted);
  letter-spacing: 0.04em; text-transform: uppercase;
}
.mail__view { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.mail__pick { padding: 40px 0; }

/* Список прилипает: в длинном разговоре он иначе остаётся где-то вверху,
   и до соседней переписки надо прокручивать обратно. */
@media (min-width: 861px) {
  .mail__side {
    position: sticky; top: 16px;
    max-height: calc(100vh - 120px); overflow-y: auto;
    padding-right: 4px;
  }
  /* Переписке нужна вся ширина: 62rem на две колонки — это узкий разговор
     рядом с узким списком, ради чего огород и не городили. */
  .main--mail { max-width: 78rem; }
  /* Слева и так список — стрелка «← Переписка» здесь лишняя. */
  .main--mail > .back { display: none; }
  /* Внутри своей колонки лента не должна вылезать за её края. */
  .mail .thread { margin: 0; border-radius: var(--r); }
  .mail .composer { bottom: 0; }
  /* Страница-приложение: сама она не едет, едет только лента сообщений.
     Раньше прокручивалось всё разом — шапка с именем, карточка сделки и поле
     ввода уползали вверх вместе с разговором, а при переходе в соседнюю
     переписку страница прыгала вниз, к последнему сообщению. Теперь на месте
     стоят и шапка, и сделка, и поле ввода, а прыгать нечему. */
  body.app { height: 100vh; overflow: hidden; }
  body.app .main--mail {
    flex: 1; min-height: 0; overflow: hidden;
    padding-top: 14px; padding-bottom: 14px;
  }
  body.app .mail { height: 100%; min-height: 0; }
  body.app .mail__side { position: static; max-height: 100%; overflow-y: auto; }
  body.app .mail__view { height: 100%; min-height: 0; }
  body.app .mail__view .thread { flex: 1; min-height: 0; overflow-y: auto; }
  /* Липкость больше не нужна: поле ввода и так стоит в самом низу колонки. */
  body.app .composer { position: static; box-shadow: none; }
}

@media (max-width: 860px) {
  /* Именно minmax(0, 1fr), а не 1fr: у голого 1fr нижняя граница равна
     ширине содержимого, и одна длинная строка в списке переписок растягивала
     колонку шире экрана — страница ехала вбок. */
  .mail { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .mail--chat .mail__side { display: none; }
  .mail--list .mail__view { display: none; }
  .mail__sideh { display: none; }
}

.dlg--on {
  border-color: var(--ru);
  background: var(--ru-soft);
}
.dlg--on .dlg__name { color: var(--ru-ink); }

/* Шапка разговора: с кем говорим и о какой партии. */
.chathead { display: flex; flex-direction: column; gap: 4px; }
.chathead__name {
  font-size: var(--t-xl); font-weight: var(--w-bold); color: var(--ink);
  text-decoration: none; line-height: var(--lh-tight);
}
.chathead__name:hover { text-decoration: underline; }
.chathead__lot {
  font-size: var(--t-sm); color: var(--muted); text-decoration: none;
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
}
.chathead__lot b { color: var(--ink); font-weight: var(--w-mid); }
.chathead__lot:hover { color: var(--ink-2); }
.chathead__go { color: var(--muted); }
.chathead__lang { font-size: var(--t-xs); color: var(--muted); }

/* На каком языке читает собеседник — одна строка вместо извинения
   за отсутствующий перевод под полем ввода в каждой переписке. */
.head__lang { color: var(--muted); font-size: var(--t-sm); }

/* Пустая переписка: с чего начать разговор с иностранцем. */
.starters { padding: 6px 0 2px; display: flex; flex-direction: column; align-items: center; }
.starters__pic { width: 220px; max-width: 70%; height: auto; display: block; opacity: 0.9; }
.starters__grid { width: 100%; }
.starters__t { color: var(--muted); font-size: var(--t-sm); margin: 0 0 8px; text-align: center; }
.starters__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.starter {
  font: inherit; cursor: pointer; width: 100%; min-height: 62px;
  display: flex; flex-direction: column; gap: 3px; justify-content: center;
  padding: 10px 12px; border-radius: var(--r); text-align: left;
  background: var(--surface); border: 1px solid var(--line); color: var(--ink);
}
.starter:active { background: var(--ru-soft); }
.starter__a { font-weight: var(--w-mid); font-size: var(--t-sm); }
.starter__b { color: var(--muted); font-size: var(--t-sm); }

/* Готовая фраза на языке собеседника — прямо под своим пузырём. */
.msg__also {
  display: block; margin-top: 5px; padding-top: 5px;
  border-top: 1px dashed rgb(128 128 128 / 35%);
  font-size: var(--t-sm); opacity: 0.75;
}

/* ——— полоса быстрых фраз ———
   Она над полем ввода и всегда видна: для половины участников это
   единственный способ написать на языке собеседника. */
.quickbar { display: flex; flex-direction: column; gap: 6px; }
.quickbar__row {
  display: flex; gap: 6px; overflow-x: auto; padding-bottom: 2px;
  scrollbar-width: none; scroll-snap-type: x proximity;
}
.quickbar__row::-webkit-scrollbar { display: none; }
.quickbar__f { flex: none; }
.quickbar .chip { white-space: nowrap; min-height: 38px; scroll-snap-align: start; }
.chip--slot { border-style: dashed; }
.chip--more { background: var(--ru-soft); color: var(--ru-ink); border-color: var(--ru-soft); font-weight: var(--w-mid); }

/* [hidden] у элемента с display:flex не работает — правило автора сильнее
   браузерного. Без этих строк поле числа и панель «Ещё» висят раскрытыми. */
.slotrow[hidden], .plus[hidden] { display: none; }

/* Одно поле для числа или даты — вместо списка на чужом языке. */
.slotrow {
  display: flex; align-items: center; gap: 6px;
  padding: 8px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
}
.slotrow__t { font-size: var(--t-sm); color: var(--ink-2); flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.slotrow .unit { flex: none; width: 8.5rem; }
.slotrow .input { height: 40px; }

/* Все фразы по группам — поверх ленты, не сдвигая её. */
.plus {
  max-height: 46vh; overflow-y: auto;
  display: flex; flex-direction: column; gap: 10px;
  padding: 10px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
}
.plus__t {
  position: sticky; top: -10px; z-index: 1;
  background: var(--surface); padding: 2px 0 4px;
  font-size: var(--t-xs); color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em;
}
.plus__row { display: flex; flex-wrap: wrap; gap: 6px; }

/* Ответы на последнюю чужую фразу — под её пузырём, слева. */
.answers { display: flex; flex-wrap: wrap; gap: 6px; align-self: flex-start; margin: -4px 0 2px; }
.answers .chip { min-height: 36px; font-size: var(--t-sm); }

/* На узком экране подпись состояния уводит строку цены в два ряда —
   название важнее, состояние видно по раскрытому блоку. */
@media (max-width: 430px) {
}

/* Сообщение в пути и сообщение, которое не ушло. Второе — кликабельно:
   тап повторяет отправку, потому что «связь моргнула» это норма в поле. */
.msg--pending { opacity: 0.55; }
.msg--failed { opacity: 1; border: 1px solid var(--bad); cursor: pointer; }
.msg--failed::after {
  content: '!'; display: inline-block; margin-left: 8px;
  color: var(--bad); font-weight: var(--w-bold);
}
.say__send:disabled { opacity: 0.4; cursor: default; }

/* Выбранное фото до отправки: видно, что уходит, и можно передумать. */
.photobar {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
  font-size: var(--t-sm); color: var(--ink-2);
}
.photobar img { width: 40px; height: 40px; object-fit: cover; border-radius: var(--r); }
.photobar span { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.photobar__x {
  border: 0; background: var(--surface-2); color: var(--ink); cursor: pointer;
  width: 32px; height: 32px; border-radius: var(--r); font-size: var(--g-sm); line-height: 1;
}

/* Подпись «Доставлено / Прочитано» под последним своим сообщением.
   Живёт внутри .msg__meta рядом со временем: отдельным узлом в .thread
   она стала бы элементом флекс-колонки и уехала влево. */
.msg__st {
  font-size: var(--t-xs);
  color: var(--muted);
  white-space: nowrap;
}
.msg--me .msg__st { color: var(--bub-out-ink); opacity: 0.6; }

/* Черта «отсюда непрочитанное». По образцу разделителя дней, но с чертой
   во всю ширину — она должна читаться как граница, а не как ещё одна дата. */
.thread__sep--new {
  align-self: stretch;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0 2px;
  color: var(--ru);
  font-weight: var(--w-mid);
  font-size: var(--t-xs);
  background: none;
  padding: 0;
}
.thread__sep--new::before,
.thread__sep--new::after {
  content: "";
  flex: 1;
  height: 1px;
  background: currentColor;
  opacity: 0.35;
}

/* Плашка «включить уведомления». Живёт над перепиской и уходит навсегда,
   как только человек ответил — второй раз браузер спросить не даст. */
.pushbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  margin: 0 0 10px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface-2);
}
.pushbar[hidden] { display: none; }   /* у флекса атрибут сам по себе не работает */
.pushbar__t { flex: 1 1 200px; font-size: var(--t-sm); }
.pushbar__btns { display: flex; gap: 8px; }

/* ——— панель сделки ———
   Одна строка над разговором. Раньше цена, проба и перевозка стояли тремя
   блоками подряд и выдавливали ленту за нижний край: человек открывал
   переписку и видел формы вместо сообщений. */
.deal {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  margin: 0 0 10px;
  overflow: hidden;
}
.deal__sum {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 36px;
  padding: 5px 12px;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.deal__sum::-webkit-details-marker { display: none; }
.deal__ic { width: 26px; height: 26px; flex: none; display: block; object-fit: contain; }
.deal__t { font-weight: var(--w-bold); white-space: nowrap; }
.deal__state {
  flex: 1;
  min-width: 0;
  color: var(--muted);
  font-size: var(--t-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Ход за человеком — говорим об этом цветом, а не ещё одной плашкой. */
.deal__state--act { color: var(--ru); font-weight: var(--w-mid); }
.deal__chev {
  width: 10px; height: 10px; flex: none;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(45deg);
  transition: transform 0.15s ease;
}
.deal[open] .deal__chev { transform: rotate(-135deg); }
.deal__in {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 0 12px 10px;
}
/* Внутри панели блоки уже не спорят за внимание — снимаем их собственные
   рамки и фон, чтобы не было коробки в коробке. */

/* Содержимое панели сделки: строки «подпись → число» и одна кнопка.
   Раньше внутри панели стояли ещё две карточки со своими рамками и фоном —
   коробка в коробке, из-за чего экран выглядел заваленным. */
.dl { display: flex; flex-direction: column; gap: 2px; }
.dl__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding: 7px 0;
  font-size: var(--t-sm);
}
.dl__row span { color: var(--muted); }
.dl__row b { font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Итог отделён чертой и крупнее: это то число, о котором договариваются. */
/* Черты сверху больше нет: она отделяла итог от слагаемых, а слагаемое
   осталось одно — и черта повисла под заголовком панели сама по себе. */
.dl__row--sum {
  padding-top: 4px;
  font-size: var(--t-md);
}
.dl__row--sum b { font-size: var(--t-lg); font-weight: var(--w-bold); }
.dl__note { padding: 7px 0; color: var(--muted); font-size: var(--t-sm); }
.dl form { margin-top: 10px; }
.dl .hint { margin: 8px 0 0; }

/* Третье действие в панели — не кнопка, а строка: просьба о пробе не должна
   выглядеть так же весомо, как согласие на три миллиона. */
/* ——— строка цены: столько за тонну × столько тонн = столько всего ———
   Раньше это были два поля с подписями сверху и отдельный ряд с итогом —
   три этажа вместо одного, а сказано ровно то же самое. */
.fixrow { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fixrow__f { flex: 1 1 130px; min-width: 0; }
.fixrow__f--nar { flex: 0 1 96px; }
.fixrow__f .input { height: 40px; padding: 0 10px; }
.fixrow__x, .fixrow__eq { color: var(--muted); flex: none; }
.fixrow__sum {
  margin-left: auto;
  font-size: var(--t-lg); font-weight: var(--w-bold);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
@media (max-width: 420px) {
  /* На узком экране «= сумма» уезжает на свою строку, а не жмёт поля. */
  .fixrow__eq { display: none; }
  .fixrow__sum { flex: 1 0 100%; margin: 0; text-align: right; }
}
.form--fix { gap: 8px; }

/* ——— «Дальше — наша работа» ———
   Логистика, таможня и склад — то, чего покупатель не купит ни у фермера,
   ни сам, и то, ради чего биржа существует. Поэтому не серой строкой внизу,
   а тёплой плашкой прямо над кнопкой: это читают перед нажатием. */
.wedo {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: var(--r);
  background: var(--gold-soft);
}
.wedo__ic { width: 32px; height: 32px; flex: none; display: block; object-fit: contain; }
.wedo__txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
/* Слева перечень работ, справа — то, что человек получает. Правая часть
   темнее и жирнее: именно она отвечает на вопрос «а мне-то что». */
.wedo__eq {
  display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap;
  font-size: var(--t-sm); font-weight: var(--w-mid); color: var(--ink-2);
  line-height: var(--lh-tight);
}
.wedo__eq i { font-style: normal; color: var(--muted); }
.wedo__eq em { font-style: normal; font-weight: var(--w-bold); color: #8a5d00; }
.wedo__when { font-size: var(--t-xs); color: var(--muted); line-height: var(--lh-tight); }

.dl__minor { display: flex; justify-content: center; margin-top: 2px; }

/* Цена согласована — короткая зелёная строка над суммой. */
.dl__agreed {
  color: var(--ru-ink);
  font-size: var(--t-sm);
  font-weight: var(--w-bold);
}
/* Что делает площадка прямо сейчас. Стоит сразу под согласованной суммой:
   после согласия человек смотрит именно сюда. */
.dl__ship {
  display: flex; flex-direction: column; gap: 2px;
  margin-top: 8px; padding: 10px 12px;
  border-radius: var(--r);
  background: var(--ru-soft);
}
.dl__ship b { color: var(--ru-ink); }
.dl__ship span { color: var(--ink-2); font-size: var(--t-sm); line-height: var(--lh); }
.dl__where { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.dl__where .field { margin: 0; width: 100%; }

/* Обещание под кнопкой: что произойдёт после нажатия. Тихим текстом, но
   на самом видном месте — прямо под тем, что человек собирается нажать.
   Это единственное место, где покупателю говорят, ради чего вся биржа. */
.dl__promise {
  margin: 8px 0 0;
  color: var(--ink-2);
  font-size: var(--t-sm);
  line-height: var(--lh);
}
/* Цена согласована — короткая зелёная строка над суммой. */
.dl__agreed {
  color: var(--ru-ink);
  font-size: var(--t-sm);
  font-weight: var(--w-bold);
}
/* Что делает площадка прямо сейчас. Стоит сразу под согласованной суммой:
   после согласия человек смотрит именно сюда. */
.dl__ship {
  display: flex; flex-direction: column; gap: 2px;
  margin-top: 8px; padding: 10px 12px;
  border-radius: var(--r);
  background: var(--ru-soft);
}
.dl__ship b { color: var(--ru-ink); }
.dl__ship span { color: var(--ink-2); font-size: var(--t-sm); line-height: var(--lh); }
.dl__where { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.dl__where .field { margin: 0; width: 100%; }
.linkbtn {
  font: inherit;
  font-size: var(--t-sm);
  color: var(--muted);
  background: none;
  border: 0;
  padding: 10px 12px;
  min-height: var(--tap);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--line);
}
.linkbtn:hover { color: var(--ink); text-decoration-color: currentColor; }

/* Ссылка-кнопка «Отклонить и предложить свою цену» в панели сделки:
   ведёт в ту же плашку, где цифры сменяются полями. Отдельная выпадающая
   коробка под ценой читалась как второй экран внутри первого. */
.dl .btn--ghost { margin-top: 8px; }
.dl .turnkey { margin: 12px 0 0; }
.dl .form { margin: 0; }
.dl .form .row { margin-bottom: 0; }
.dl > .linkbtn { align-self: center; margin-top: 4px; }

/* Когда в расчёте одна строка — итог, — коробка вокруг неё лишняя:
   сверху оставалась пустая белая полоска в высоту исчезнувших строк. */
.turnkey:has(> .turnkey__row--total:only-child) {
  padding: 0;
  border: 0;
  background: none;
}
.turnkey:has(> .turnkey__row--total:only-child) > .turnkey__row--total {
  margin: 0;
  border-radius: var(--r);
}

/* Оценка в отзыве — словом и цветом, а не эмодзи: эмодзи рисует шрифт
   устройства, и на дешёвом Android половина выходит квадратом. */
.rev__mark {
  font-size: var(--t-xs);
  font-weight: var(--w-mid);
  padding: 3px 9px;
  border-radius: var(--r-pill);
  white-space: nowrap;
}
.rev__mark--good { background: var(--ru-soft); color: var(--ru-ink); }
.rev__mark--bad { background: var(--bad-soft); color: var(--bad); }

/* Таймер записи поверх значка микрофона — отдельной подписью: писать его
   в саму кнопку нельзя, там теперь рисунок, а не буква. */
.say__mic { position: relative; }
.say__mic-t {
  position: absolute;
  inset: auto 0 2px 0;
  font-size: var(--t-xs);
  font-weight: var(--w-bold);
  font-variant-numeric: tabular-nums;
}
.say__mic--on .ic { opacity: 0.35; }

/* Значок в строке текста: размер наследуется от кнопки, цвет — от текста,
   поэтому тёмная тема подхватывается сама. */
.ic { width: 1.25em; height: 1.25em; flex: none; }
.bnav__ico, .bell__ico { width: 26px; height: 26px; }
.ev__icon { width: 28px; height: 28px; flex: none; }

/* ——— отзывы: звёзды, факты о человеке, ответ ———
   Оценку показываем словом и звёздами, а не числом с запятой: при двух-пяти
   сделках за сезон «4,6» — не статистика, а видимость точности. */
.stars { display: inline-flex; gap: 2px; vertical-align: -2px; }
.stars__s { width: 16px; height: 16px; fill: var(--line); }
.stars__s--on { fill: var(--gold); }

.rep { display: flex; align-items: center; gap: 10px; margin: 0 0 4px; }
.rep__avg { font-size: var(--t-lg); font-weight: var(--w-bold); font-variant-numeric: tabular-nums; }
.rep__n { color: var(--muted); font-size: var(--t-sm); }

/* То, что мы знаем сами: проверен, сколько сделок довёл до конца, с какого месяца.
   Это честнее любых звёзд, потому что не зависит от чужого настроения. */
.facts { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.fact {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--t-sm); color: var(--ink-2);
  background: var(--surface-2); border-radius: var(--r-pill); padding: 5px 12px;
}
.fact--ok { background: var(--ru-soft); color: var(--ru-ink); font-weight: var(--w-mid); }

.rev__reply {
  border-left: 2px solid var(--line); padding-left: 10px; margin-top: 8px;
}
.rev__reply b { font-size: var(--t-xs); color: var(--muted); font-weight: var(--w-mid); }
.rev__reply p { margin: 2px 0 0; font-size: var(--t-sm); }

/* ——— «Чем закончилось» и оценка ——— */
.outcome {
  display: flex; flex-direction: column; gap: 10px;
  padding: 14px; margin-bottom: 10px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
}
.outcome__q { font-weight: var(--w-bold); }
.outcome__btns { display: flex; flex-wrap: wrap; gap: 8px; }

.rate {
  display: flex; flex-direction: column; gap: 10px;
  padding: 14px; margin-bottom: 10px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
}
.rate__t { font-weight: var(--w-bold); }
/* Звёзды идут в разметке от пятой к первой: так соседний селектор гасит
   те, что правее выбранной, без единой строчки скрипта. */
.rate__stars { display: flex; flex-direction: row-reverse; justify-content: flex-end; gap: 4px; }
.rate__in { position: absolute; opacity: 0; width: 1px; height: 1px; }
.rate__star { cursor: pointer; padding: 4px; line-height: 0; }
.rate__star svg { width: 32px; height: 32px; fill: var(--line); transition: fill 0.1s ease; }
.rate__in:checked ~ .rate__star svg,
.rate__star:hover svg,
.rate__star:hover ~ .rate__star svg { fill: var(--gold); }
.rate__in:focus-visible + .rate__star svg { outline: 2px solid var(--ru); outline-offset: 2px; }
.rate__ends { display: flex; justify-content: space-between; font-size: var(--t-xs); color: var(--muted); }

/* ═══════════ Витрина плитками ═══════════
   Выбранное оформление: партии идут плитками, а не длинным списком.
   Плитка узнаваема покупателю с Alibaba, и на экран влезает вдвое больше.
   Всё выше цены имеет заданную высоту — иначе цены разъезжаются по строке,
   потому что «Ханкайский р-н · Камень-Рыболов» вдвое длиннее «Ленинского». */
/* Плитка никогда не уже 230 пикселей: в узкой колонке «через Суйфэньхэ ·
   101 км» ломается на три строки, и ряд перестаёт читаться. Сколько плиток
   поместится — столько и будет. */
.cards--tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 12px;
}
@media (max-width: 520px) {
  /* На телефоне две в ряд: 230px там не помещаются, но и текста меньше. */
  .cards--tiles { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; }
}
/* Карточки в ряду выравниваются построчно: цена под ценой, отметки под
   отметками, белок под белком. Раньше это держалось на подпорках — каждой
   строке задавали min-height «на две строки текста», — и стоило одной
   карточке остаться без плашки «Пробу предоставляет», а другой уместить
   район в одну строку, как ряд разъезжался.

   Теперь ряд задаёт сетка: карточка занимает четыре строки общей сетки и
   берёт их высоты у неё (subgrid). Высоту каждой строки определяет самая
   высокая карточка ряда, а остальные к ней подстраиваются сами — сколько бы
   строк ни занял район и есть ли у партии отметки. */
.cards--tiles .card {
  padding: 13px;
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 4;
  row-gap: 6px;
  align-content: start;
  /* Без этого длинное слово внутри распирает колонку: у элемента сетки
     min-width по умолчанию не ноль, и на телефоне вторая плитка вылезала
     за край экрана. */
  min-width: 0;
}
.cards--tiles .card__top { display: block; }
.cards--tiles .card__title {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Длинное название района обрезаем на второй строке: без этого одна партия
   с длинным адресом растягивала весь ряд. */
.cards--tiles .card__place {
  line-height: var(--lh-tight);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.cards--tiles .price { display: block; }
/* В плитке места мало, и «Пробу предоставляет» вылезало за край карточки.
   Переносим по словам: subgrid поднимет всю строку ряда одинаково, так что
   от переноса ряд не разъедется. */
.cards--tiles .mark { white-space: normal; }
.cards--tiles .price__unit { display: block; line-height: var(--lh-tight); }
/* Цена с НДС — подробность для страницы партии. В плитке она есть не у всех
   и одна сдвигает вниз всё, что ниже, ломая ряд. */
.cards--tiles .price__alt { display: none; }
.cards--tiles .spec { align-self: flex-start; }
.cards--tiles .specs { flex-direction: column; gap: 0; align-content: start; }
.cards--tiles .specs .spec + .spec::before { content: ""; margin: 0; }

/* Цена — красная: так её читает китайский закупщик у себя дома. */
.price__main { color: var(--cn); }

/* Значки доверия: подтверждено — золотом, объём — нейтрально. */
.marks { display: flex; flex-wrap: wrap; gap: 5px; }
.mark {
  font-size: var(--t-xs); font-weight: var(--w-mid);
  padding: 2px 8px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--muted);
  white-space: nowrap;
}
.mark--ok { background: var(--gold-soft); color: #8a5d00; }

/* ═══════════ Рабочий стол биржи ═══════════
   На узком экране всё идёт в столбик, как и раньше: поиск, фильтры, партии.
   На широком страница раздаётся вширь, фильтры уезжают в левую колонку и
   остаются на виду при прокрутке, а партии получают всё освободившееся
   место — вместо двух карточек в ряд помещается четыре. Раньше на большом
   мониторе по бокам оставались пустые поля, а список жался в узкую полосу. */
.work { display: flex; flex-direction: column; gap: 14px; }
.work__side { display: flex; flex-direction: column; gap: 14px; }
.work__main { min-width: 0; }

@media (min-width: 1080px) {
  .main--work { max-width: 82rem; }
  .work {
    display: grid; grid-template-columns: 290px minmax(0, 1fr);
    gap: 22px; align-items: start;
  }
  .work__side { position: sticky; top: 16px; }
  /* В своей колонке фильтры — панель, а не сворачиваемая полоска:
     заголовок с подсказкой «Фильтры» там лишний. */
  .work__side .fbox__sum { display: none; }
  .work__side .filters { padding-top: 14px; }
  /* Строка поиска в узкой колонке встаёт столбиком: иначе список регионов
     сжимается до «Весь Дальн…» и его не прочитать. */
  .work__side .qrow { flex-direction: column; align-items: stretch; margin: 0; }
  .work__side .qrow .input,
  .work__side .qrow .select,
  .work__side .qrow .btn { width: 100%; flex: none; }
}

/* ═══════════ Объём ═══════════
   Плоские рамки заменены на подъём: карточка лежит на фоне, кнопка выступает,
   нажатая — проваливается. Это и есть «объём» без картинок и без библиотек:
   тень, лёгкий градиент и сдвиг при нажатии. */
:root {
  --lift-1: 0 1px 2px rgb(16 20 24 / 6%), 0 2px 8px -2px rgb(16 20 24 / 8%);
  --lift-2: 0 2px 4px rgb(16 20 24 / 7%), 0 12px 24px -8px rgb(16 20 24 / 14%);
  --lift-btn: 0 1px 0 rgb(255 255 255 / 22%) inset, 0 2px 6px rgb(20 110 45 / 28%);
}
.card {
  border-color: transparent;
  box-shadow: var(--lift-1);
  transition: box-shadow 0.15s ease, transform 0.12s ease;
}
.card--link:active { transform: translateY(1px); box-shadow: var(--lift-1); }
@media (hover: hover) {
  .card--link:hover { box-shadow: var(--lift-2); border-color: transparent; transform: translateY(-1px); }
}

/* Кнопка действия: светлый кант сверху, тень снизу — палец видит, что она
   выступает. При нажатии уходит вниз, как настоящая. */
.btn {
  background-image: linear-gradient(180deg, rgb(255 255 255 / 14%), rgb(0 0 0 / 6%));
  box-shadow: var(--lift-btn);
  transition: transform 0.08s ease, box-shadow 0.12s ease, filter 0.12s ease;
}
.btn:active { transform: translateY(1px); box-shadow: 0 1px 3px rgb(20 110 45 / 30%); }
.btn--ghost, .btn--quiet {
  background-image: none;
  box-shadow: var(--lift-1);
}
.btn--ghost:active, .btn--quiet:active { transform: translateY(1px); box-shadow: none; }

/* Поля ввода — вдавленные, в противоположность кнопкам. */
.input, textarea.input, select.input {
  box-shadow: 0 1px 2px rgb(16 20 24 / 5%) inset;
  border-color: var(--line);
}

/* Пузыри переписки поднимаются над лентой. */
.msg--them { box-shadow: var(--lift-1); border-color: transparent; }
.msg--me { box-shadow: 0 2px 6px rgb(20 110 45 / 24%); }

/* Плитка партии: воздуха больше, строки не липнут друг к другу. */
.cards--tiles { gap: 12px; }
.cards--tiles .card { padding: 15px; }
.cards--tiles .card__title { font-size: var(--t-md); }
.cards--tiles .card__place { font-size: var(--t-sm); }
.cards--tiles .specs { gap: 3px 0; }
.cards--tiles .spec { line-height: 1.45; }
.cards--tiles .price { margin-top: 8px; }
.cards--tiles .marks { margin-top: 8px; }
.cards--tiles .specs { margin-top: 8px; }
