﻿/* =============================================================
   ДВОР РАБОТА — дизайн-система DVOR APP (ПРИЛ DVOR).
   Paper & Graphite: бумага #fcfcfc / графит #181818–#222,
   оранжевый #FF6B00 строго дозированно («5% Contextual Orange»),
   Montserrat + Unbounded (дисплей), радиусы 36/28/20,
   тёмные внутренние плашки, фирменная оранжевая линия-инсет.
   Мелкий капс с разрядкой не используется нигде, кроме баннеров.
   ============================================================= */

:root {
  color-scheme: light;
  color-scheme: light;

  --brand: #ff6b00;
  /* нижняя точка градиента фирменного знака */
  --logo-ink: #5a2a06;
  /* высота шапки вместе с её отступами */
  --chrome-h: 90px;
  /* ЕДИНЫЙ ШАГ. Столько же, сколько между соседними плашками, — ровно
     столько и отделяет первую плашку от шапки. Разный отступ сверху и
     между блоками читается как сбитый ритм. */
  --stack: 16px;
  --brand-light: #ff8533;
  --brand-dark: #e65c00;
  --brand-soft: rgba(255, 107, 0, 0.1);
  --brand-line: rgba(255, 107, 0, 0.35);

  --bg: #fcfcfc;
  --bg-grad: linear-gradient(180deg, rgba(255, 107, 0, 0.05) 0%, rgba(252, 252, 252, 0) 40%), #fcfcfc;
  --card: #ffffff;
  --card-2: #f5f5f5;
  --ink: #2d2d2d;
  --ink-2: #222222;
  --ink-fg: #ffffff;

  --text: #222222;
  --muted: #71717a;
  --muted-2: #a1a1aa;
  --border: rgba(0, 0, 0, 0.08);
  --border-2: rgba(0, 0, 0, 0.13);

  --success: #16a34a;
  --success-soft: rgba(22, 163, 74, 0.1);
  --info: #3b82f6;
  --info-soft: rgba(59, 130, 246, 0.1);
  --warning: #b45309;
  --warning-soft: rgba(180, 83, 9, 0.1);
  --danger: #ef4444;
  --danger-soft: rgba(239, 68, 68, 0.1);

  /* Шрифты дворделивери: Montserrat — текст, Unbounded — дисплей */
  --f: 'Montserrat', system-ui, sans-serif;
  --f2: 'Montserrat', system-ui, sans-serif;
  --fd: 'Unbounded', 'Montserrat', system-ui, sans-serif;
  --fnum: 'Unbounded', 'Montserrat', sans-serif;

  /* Кривые дворделивери: резкий выход + фирменная пружина */
  --ez: cubic-bezier(0.22, 1, 0.36, 1);
  --ez-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --dur-tap: 0.09s;
  --dur-fast: 0.2s;

  --shadow: 0 4px 20px 0 rgba(0, 0, 0, 0.08);
  --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.14), 0 4px 8px rgba(0, 0, 0, 0.07);
  --shadow-brand: 0 6px 20px -4px rgba(255, 107, 0, 0.4);
  /* Кольцо фокуса тенью, а не контуром: outline рисует жёсткую линию с
     отбивкой и на скруглённых карточках читается как вторая рамка */
  --focus-ring: 0 0 0 3px var(--brand-soft), 0 0 0 4.5px var(--brand-line);
  /* Фирменный инсет: тонкая оранжевая линия по нижней кромке стекла */
  --brand-inset: 0 4px 20px 0 rgba(0, 0, 0, 0.08), inset 0 -1.5px 0 rgba(255, 107, 0, 0.35);

  --r-widget: 36px;
  --r-card: 28px;
  --r-inner: 30px;
  --r-btn: 16px;
  --r-input: 16px;
  /* «таблеток» в интерфейсе нет: у чипов и значков свой умеренный радиус */
  --r-pill: 11px;

  --header-bg: rgba(252, 252, 252, 0.78);
}


/* ===================== База ===================== */

*, *::before, *::after { box-sizing: border-box; }
* { -webkit-tap-highlight-color: transparent; }


body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg-grad);
  background-attachment: fixed;
  color: var(--text);
  font-family: var(--f);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  transition: color 0.25s var(--ez);
}

h1, h2, h3, h4 { margin: 0; line-height: 1.18; text-wrap: balance; }
p { margin: 0; text-wrap: pretty; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
img, svg { display: block; max-width: 100%; }

/* Фокус с клавиатуры обязан быть виден, но рисуем его мягким кольцом:
   контур с отбивкой обводил фигуру по внешнему габариту и на карточках
   и плитках выглядел кривой оранжевой рамкой. Базовую тень сохраняем,
   иначе элемент под кольцом теряет объём. */
:where(button, a, input, textarea, select):focus-visible {
  outline: none;
  box-shadow: var(--shadow), var(--focus-ring);
}

/* Слой-ссылка занимает всю карточку: обводить его — значит обводить
   карточку целиком. Вместо этого мягко подсвечиваем саму карточку, и
   только при ходьбе с клавиатуры. */
.vc-hit:focus-visible, .row-hit:focus-visible { outline: none; box-shadow: none; }

.vac-card:has(.vc-hit:focus-visible),
.item-row:has(.row-hit:focus-visible) {
  box-shadow: var(--shadow-lg), var(--focus-ring);
}

/* Мышью и пальцем обводки нет вовсе — она была бы шумом */
:where(a, button):focus:not(:focus-visible) { outline: none; }

:where(button, a, label, [role='button'], input, textarea, select) {
  touch-action: manipulation;
}

/* Заголовки — Unbounded, как в дворделивери */
.hero-title, .section-title, .page-title {
  font-family: var(--fd);
  font-weight: 700;
  letter-spacing: -0.01em;
}

.muted { color: var(--muted); }

.container { width: 100%; max-width: 1180px; margin: 0 auto; padding: 0 20px; }
.grow { flex: 1; }

/* ===================== Движение ===================== */

/* Появление лесенкой — тайминги дворделивери: короткий путь, резкий
   старт, хвост списка не ждёт головы */
@keyframes dd-rise {
  from { opacity: 0; transform: translateY(12px) scale(0.99); }
  to { opacity: 1; transform: none; }
}

.dd-rise { animation: dd-rise 0.3s var(--ez) both; animation-delay: calc(min(var(--i, 0), 6) * 40ms); }

.dd-stagger > * { animation: dd-rise 0.3s var(--ez) both; }
.dd-stagger > *:nth-child(2) { animation-delay: 40ms; }
.dd-stagger > *:nth-child(3) { animation-delay: 80ms; }
.dd-stagger > *:nth-child(4) { animation-delay: 120ms; }
.dd-stagger > *:nth-child(5) { animation-delay: 160ms; }
.dd-stagger > *:nth-child(6) { animation-delay: 200ms; }
.dd-stagger > *:nth-child(7) { animation-delay: 240ms; }
.dd-stagger > *:nth-child(n + 8) { animation-delay: 280ms; }

@keyframes dd-pop {
  from { opacity: 0; transform: scale(0.82); }
  to { opacity: 1; transform: none; }
}

.dd-pop { animation: dd-pop 0.34s var(--ez-spring) both; }

@keyframes dd-fade { from { opacity: 0; } to { opacity: 1; } }
.dd-fade { animation: dd-fade 0.25s var(--ez) both; }

/* Переход между экранами — dd-page из дворделивери: смена экрана
   читается движением, но не задерживает содержимое */
@keyframes dd-page-in {
  from { opacity: 0; transform: translate3d(0, 10px, 0); }
  to { opacity: 1; transform: none; }
}

/* ЗАЛИВКА ТОЛЬКО ВПЕРЁД, А НЕ В ОБЕ СТОРОНЫ — И ЭТО НЕ ПРИДИРКА.

   both оставляет последний кадр висеть навсегда, а в последнем кадре есть
   transform. Элемент с transform становится системой отсчёта для всех
   потомков с position: fixed — и любое окно внутри страницы начинает
   мериться не от экрана, а от неё.

   Замерено, когда сюда положили окно фильтров: 8302 точки высоты вместо
   812 и подвал с кнопкой за краем экрана. Ловушка тихая: в разметке всё
   правильно, в стилях всё правильно, а fixed мерит не то.

   backwards заливает только до начала анимации. После неё свойства
   возвращаются к своим обычным значениям — то есть transform исчезает
   совсем, и системой отсчёта снова становится экран. Вид при этом тот же:
   последний кадр и базовое состояние совпадают. */
.dd-page-anim { animation: dd-page-in 0.22s var(--ez) backwards; }

/* Подмена содержимого на месте (фильтры, вкладки) */
@keyframes dd-swap {
  from { opacity: 0; transform: translate3d(0, 7px, 0); }
  to { opacity: 1; transform: none; }
}

.dd-swap { animation: dd-swap 0.18s var(--ez) both; }

/* Дыхание акцентной кнопки — ровно три пульсации, как в ДД:
   свечение показывает, куда нажимать, и не греет телефон вечно */
@keyframes dd-halo {
  0%, 100% { opacity: 0; }
  50% { opacity: 1; }
}

.dd-halo { position: relative; }

.dd-halo::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  box-shadow: 0 8px 28px -4px rgba(255, 107, 0, 0.55);
  animation: dd-halo 2.6s ease-in-out 3;
}

/* Нажатие — упругое сжатие дворделивери: вниз мгновенно и без пружины,
   обратно кнопка возвращается длинной пружиной */
.dd-press {
  transition:
    transform 0.34s var(--ez-spring),
    scale 0.34s var(--ez-spring),
    background-color var(--dur-fast) var(--ez),
    color var(--dur-fast) var(--ez),
    border-color var(--dur-fast) var(--ez),
    opacity var(--dur-fast) var(--ez),
    box-shadow 0.25s var(--ez);
}

.dd-press:active {
  transform: scale(0.955);
  transition-duration: var(--dur-tap);
  transition-timing-function: var(--ez);
}

/* Крупные карточки: слегка проседают, а не сжимаются целиком */
.dd-lift {
  transition: transform 0.4s var(--ez-spring), box-shadow 0.3s var(--ez), border-color 0.25s var(--ez);
}

@media (hover: hover) {
  .dd-lift:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
}

.dd-lift:active {
  transform: translateY(1px) scale(0.99);
  box-shadow: var(--shadow);
  transition-duration: 0.12s;
  transition-timing-function: var(--ez);
}

/* Тикер городов с ✦ */
@keyframes dd-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

.marquee {
  /* Тикер — такая же плашка, только во всю ширину. Без собственной отбивки
     он прилипал к секциям сверху и снизу: там, где у всех два шага, у него
     был один. */
  margin: var(--stack) 0;
  overflow: hidden;
  white-space: nowrap;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}

.marquee-track {
  display: inline-flex;
  align-items: center;
  min-width: 200%;
  animation: dd-marquee var(--marquee-duration, 38s) linear infinite;
  will-change: transform;
}

.marquee-track span {
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  padding: 15px 24px;
}

.marquee-track b { color: var(--brand); font-size: 10px; }

@media (prefers-reduced-motion: reduce) {
  .dd-rise, .dd-stagger > *, .dd-pop, .dd-fade, .dd-page-anim, .dd-swap { animation: none; opacity: 1; transform: none; }
  .dd-halo::after { animation: none; }
  .marquee-track { animation: none; will-change: auto; }
  /* Модалки, тосты, панели и док — тоже без движения */
  .modal-root .backdrop, .modal, .modal-root.leaving .backdrop, .modal-root.leaving .modal,
  .toast, .toast.leaving, .mobile-nav .panel, .fav-btn.fav-anim svg, .dock .pill,
  .wx-sun svg, .wx-cloud svg, .wx-rain svg > path:nth-of-type(2), .info-circ.green svg { animation: none; }
  .dd-press, .dd-lift, .dock a, .dock .tb-wrap { transition: none; }
}

/* Док внизу занимает свою полосу — уведомление встаёт над ним, а не на него.
   Эти два правила по недосмотру оказались заперты внутри блока про
   уменьшенное движение и не работали ни у кого, кроме тех, кто его включил. */
@media (max-width: 760px) {
  .toasts { bottom: calc(var(--плита) + 28px + env(safe-area-inset-bottom, 0px)); }
}

html.in-chat .toasts { bottom: calc(22px + env(safe-area-inset-bottom, 0px)); }

/* ===================== Шапка ===================== */

/* Шапка — отдельная плашка, а не полоса во всю ширину: она плавает над
   содержимым так же, как док внизу, и страница проезжает под ней. */
.header {
  position: sticky;
  top: 0;
  z-index: 50;
  /* Высота шапки известна заранее и объявлена величиной: экран диалога
     считает от неё свою высоту сразу, без замеров после отрисовки. Замер
     давал скачок — сначала рисовалось по запасному числу, потом по факту. */
  height: var(--chrome-h);
  box-sizing: border-box;
  padding: 10px 0 6px;
  /* Подложка за плашкой: без неё в зазоре сверху мелькали бы края карточек,
     проезжающих под шапкой, и верх страницы читался бы рваным */
  background: linear-gradient(to bottom, var(--bg) 62%, transparent);
}

/* ШАПКА И НАВИГАЦИЯ — ОДНА И ТА ЖЕ ПЛИТА.

   Раньше высота и скругление у них расходились: шапка 68 точек и радиус
   30, на телефоне 60 и 26, а док внизу всегда 68 и 30. Две плашки,
   плавающие над одной страницей, читались как детали из разных наборов —
   и это видно на любом экране, где они попадают в кадр вместе.

   Теперь размер один и задаётся здесь. Разойтись они больше не могут: у
   них общая цифра, а не два одинаковых числа в разных концах файла. */
:root {
  --плита: 58px;
  --плита-радиус: 24px;
}

.header-plate {
  display: flex;
  align-items: center;
  gap: 18px;
  min-height: var(--плита);
  padding: 10px 10px 10px 18px;
  border-radius: var(--плита-радиус);
  background: var(--header-bg);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border);
  box-shadow: var(--brand-inset);
}

/* ПРИЛОЖЕНИЕ С ДОМАШНЕГО ЭКРАНА ЗАНИМАЕТ ЭКРАН ЦЕЛИКОМ.

   Значит шапка оказывается под вырезом и часами. Отступ берём у самой
   системы: в обычной вкладке браузера env() равен нулю, и правило там
   ничего не меняет. Снизу такой же расчёт уже сделан — под жест «домой». */
.header-wrap { padding-top: env(safe-area-inset-top, 0px); }

.logo { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }

.logo-img { height: 19px; width: auto; }


.logo-word {
  font-family: var(--fd);
  font-weight: 700;
  font-size: 14px;
  color: var(--brand);
  padding-top: 2px;
}

.nav { display: flex; align-items: center; gap: 3px; }

.nav a {
  padding: 9px 15px;
  border-radius: var(--r-btn);
  font-weight: 600;
  font-size: 14px;
  color: var(--muted);
  transition: color var(--dur-fast), background-color var(--dur-fast);
}

.nav a:hover { color: var(--text); background: var(--card-2); }

/* Активный пункт — тёмная пилюля, как в доке приложения */
.nav a.active {
  color: #fff;
  background: var(--ink-2);
}

.header-actions { display: flex; align-items: center; gap: 9px; margin-left: auto; }

.icon-btn {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  color: var(--muted);
  position: relative;
}

.icon-btn:hover { color: var(--brand); }

.icon-btn .dot {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--r-pill);
  background: #ef4444;
  color: #fff;
  font-family: var(--f2);
  font-size: 10px;
  font-weight: 700;
  display: grid;
  place-items: center;
  border: 2px solid var(--bg);
}

/* КНОПКА КАБИНЕТА — ЕДИНСТВЕННАЯ СПРАВА В ШАПКЕ.

   Круглая, размером с прежние значки: инициалы у вошедшего, человечек у
   гостя. Счётчик на ней общий — новые отклики и непрочитанные сообщения
   вместе; разбираться, что именно пришло, человек будет уже внутри. */
.cab-btn,
.hdr-bell {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  color: var(--muted);
  position: relative;
  flex-shrink: 0;
}

.cab-btn:hover, .hdr-bell:hover { color: var(--brand); }

/* НА ТЕЛЕФОНЕ КНОПКИ КАБИНЕТА В ШАПКЕ НЕТ.

   Внизу стоит навигация, и в ней уже есть кнопка профиля — та же дверь,
   только ближе к пальцу. Две двери в одно место на экране шириной в
   ладонь — это не запас, это лишний предмет.

   На широком экране навигации внизу нет вовсе, и кнопка остаётся
   единственным входом в кабинет.

   Колокольчик при этом остаётся наверху и на телефоне: это разные вещи и
   разные места. Кабинет — куда пойти, колокольчик — что случилось. */
@media (max-width: 760px) {
  .cab-btn { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .hdr-bell.alive svg { animation: none; }
}
.cab-btn .avatar { width: 30px; height: 30px; border-radius: 11px; font-size: 12px; }

/* Колокольчик с непрочитанным горит фирменным и изредка качается.
   Движение здесь не украшение: это единственный способ заметить новое,
   не вглядываясь в цифру. Раз в три секунды и коротко — иначе шапка
   начинает мельтешить на каждом экране. */
.hdr-bell.alive { color: var(--brand); border-color: var(--brand); }
.hdr-bell.alive svg { animation: качнуть 3.2s var(--ez) infinite; transform-origin: 50% 15%; }

@keyframes качнуть {
  0%, 70%, 100% { transform: rotate(0); }
  74% { transform: rotate(11deg); }
  80% { transform: rotate(-9deg); }
  86% { transform: rotate(5deg); }
  92% { transform: rotate(-3deg); }
}

.cab-btn .dot,
.hdr-bell .dot {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--r-pill);
  background: #ef4444;
  color: #fff;
  font-family: var(--f2);
  font-size: 10px;
  font-weight: 700;
  display: grid;
  place-items: center;
  border: 2px solid var(--bg);
}

.user-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 11px 4px 4px;
  border-radius: var(--r-pill);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  font-weight: 700;
  font-size: 12.5px;
  max-width: 210px;
}

.user-chip .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.avatar {
  width: 30px;
  height: 30px;
  border-radius: 11px;
  background: linear-gradient(135deg, #ff8533, #ff6b00);
  color: #fff;
  display: grid;
  place-items: center;
  font-weight: 700;
  font-size: 12px;
  flex-shrink: 0;
}

/* Фото вместо инициалов, где оно загружено */
.avatar-img {
  object-fit: cover;
  display: block;
  flex-shrink: 0;
  box-shadow: var(--shadow);
  background: var(--card-2);
}

.menu {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  min-width: 240px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 22px;
  box-shadow: var(--shadow-lg);
  padding: 8px;
  z-index: 60;
}

.menu a, .menu button {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 12px;
  border-radius: 14px;
  font-weight: 700;
  font-size: 13px;
  text-align: left;
}

.menu a:hover, .menu button:hover { background: var(--card-2); }
.menu .sep { height: 1px; background: var(--border); margin: 6px 4px; }
.menu .danger { color: var(--danger); }

.burger { display: none; }

.mobile-nav { display: none; position: fixed; inset: 0; z-index: 90; }
.mobile-nav .backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.4); backdrop-filter: blur(4px); }

.mobile-nav .panel {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(320px, 86vw);
  background: var(--bg);
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  box-shadow: var(--shadow-lg);
  animation: mobile-in 0.3s var(--ez) both;
  overflow-y: auto;
}

@keyframes mobile-in {
  from { transform: translateX(40px); opacity: 0; }
  to { transform: none; opacity: 1; }
}

.mobile-nav a, .mobile-nav .panel button {
  padding: 12px 14px;
  border-radius: 16px;
  font-weight: 700;
  font-size: 14px;
  text-align: left;
  display: flex;
  align-items: center;
  gap: 10px;
}

.mobile-nav a:hover { background: var(--card-2); }
.mobile-nav.open { display: block; }

/* ===================== Кнопки ===================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 22px;
  border-radius: var(--r-btn);
  font-weight: 700;
  font-size: 13.5px;
  letter-spacing: 0;
  line-height: 1.2;
  border: 1px solid transparent;
  user-select: none;
  white-space: nowrap;
  transition: all 0.2s var(--ez);
}

/* btn-brand из приложения — премиальный оранжевый с фасками */
.btn-primary {
  background: linear-gradient(135deg, #ff8533 0%, #ff6b00 100%);
  color: #fff;
  box-shadow:
    0 6px 20px -4px rgba(255, 107, 0, 0.4),
    inset 0 1px 1px rgba(255, 255, 255, 0.4),
    inset 0 -2px 4px rgba(204, 85, 0, 0.4);
  border: 1px solid rgba(255, 255, 255, 0.15);
}

.btn-primary:hover {
  background: linear-gradient(135deg, #ff944d 0%, #ff7b1a 100%);
  box-shadow: 0 8px 24px -4px rgba(255, 107, 0, 0.5), inset 0 1px 1px rgba(255, 255, 255, 0.5);
}

.btn-primary:active {
  transform: scale(0.96);
  box-shadow: 0 2px 8px -2px rgba(255, 107, 0, 0.3), inset 0 2px 6px rgba(204, 85, 0, 0.6);
}

/* btn-dark — графитовый премиум */
.btn-dark {
  background: linear-gradient(135deg, #3f3f46 0%, #18181b 100%);
  color: #fff;
  box-shadow: 0 6px 20px -4px rgba(0, 0, 0, 0.3), inset 0 1px 1px rgba(255, 255, 255, 0.15);
  border: 1px solid rgba(255, 255, 255, 0.05);
}


.btn-dark:active {
  transform: scale(0.96);
  box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.4), inset 0 2px 6px rgba(0, 0, 0, 0.6);
}

.btn-ghost {
  background: var(--card);
  border-color: var(--border-2);
  color: var(--text);
  box-shadow: var(--shadow);
}

/* Наведение — тёплая подложка и подъём: оранжевая кромка кнопки била в
   глаза сильнее самой надписи */
.btn-ghost:hover { background: var(--brand-soft); color: var(--brand); box-shadow: var(--shadow-lg); }

.btn-soft { background: var(--brand-soft); color: var(--brand); }
.btn-soft:hover { background: rgba(255, 107, 0, 0.18); }

.btn-flat { background: var(--card-2); color: var(--text); }
.btn-flat:hover { background: var(--border-2); }

.btn-danger-soft { background: var(--danger-soft); color: var(--danger); }

/* Радиус кнопки не зависит от её размера: 24px при высоте ~47px и 15px при
   ~33px — это ровно половина высоты, то есть таблетка. Крупная берёт общий
   --r-btn, мелкой он сам оказался бы вровень с полукругом, поэтому у неё
   чиповый --r-pill. */
.btn-lg { padding: 15px 30px; font-size: 12.5px; border-radius: var(--r-btn); }
.btn-sm { padding: 9px 15px; font-size: 10.5px; border-radius: var(--r-pill); }
.btn-block { width: 100%; }
.btn[disabled] { opacity: 0.5; pointer-events: none; }

/* ===================== Карточки ===================== */

.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  box-shadow: var(--shadow);
}

.card-pad { padding: 24px; }

/* ===================== Чипсы и бейджи ===================== */

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 13px;
  border-radius: var(--r-pill);
  background: var(--card-2);
  font-size: 11.5px;
  font-weight: 700;
  color: var(--muted);
}

.chip-brand { background: var(--brand-soft); color: var(--brand); }
.chip-xs { padding: 5px 11px; font-size: 10.5px; }

a.chip:hover, button.chip:hover { background: var(--brand-soft); color: var(--brand); }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4.5px 11px;
  border-radius: var(--r-pill);
  font-family: var(--f2);
  font-size: 11.5px;
  font-weight: 700;
}

.badge-success { background: var(--success-soft); color: var(--success); }
.badge-warning { background: var(--warning-soft); color: var(--warning); }
.badge-danger { background: var(--danger-soft); color: var(--danger); }
.badge-info { background: var(--info-soft); color: var(--info); }
.badge-muted { background: var(--card-2); color: var(--muted); }
.badge-brand { background: var(--brand-soft); color: var(--brand); }

/* ===================== Формы ===================== */

.field { display: flex; flex-direction: column; gap: 7px; }

.field > label {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--muted);
}

.field .hint { font-size: 11.5px; font-weight: 500; color: var(--muted-2); }

.input, .select, .textarea {
  width: 100%;
  padding: 13px 16px;
  border-radius: var(--r-input);
  border: 1px solid var(--border-2);
  background: var(--card);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  transition: border-color var(--dur-fast), box-shadow var(--dur-fast);
}

.input::placeholder, .textarea::placeholder { color: var(--muted-2); }

.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(255, 107, 0, 0.15);
}

.textarea { resize: vertical; min-height: 110px; }

.select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%2371717a' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 15px center;
  padding-right: 38px;
}

.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.form-grid .span2 { grid-column: span 2; }

.check {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  user-select: none;
}

.check input { width: 18px; height: 18px; accent-color: var(--brand); cursor: pointer; }

.segment {
  display: flex;
  background: var(--card-2);
  border-radius: var(--r-btn);
  padding: 4px;
  gap: 4px;
}

.segment button {
  flex: 1;
  padding: 11px 16px;
  border-radius: 16px;
  font-weight: 600;
  font-size: 13.5px;
  color: var(--muted);
  transition: all var(--dur-fast) var(--ez);
}

.segment button.active {
  background: linear-gradient(135deg, #ff8533, #ff6b00);
  color: #fff;
  box-shadow: var(--shadow-brand);
}

/* ===================== Герой ===================== */

/* Герой поднят над последующими секциями: выпадашка поиска обязана
   лететь ПОВЕРХ баннеров и всего остального */
/* Сверху шаг с половиной: шапка уже несёт под своей плашкой половину шага
   собственного поля, вместе выходит те же два шага, что и между остальными
   плашками. Снизу — ровно шаг, чтобы стык с рекламной лентой ничем не
   отличался от прочих стыков. */
.hero { padding-top: calc(var(--stack) * 1.5); padding-bottom: var(--stack); position: relative; z-index: 30; }

.hero-plate { position: relative; }

.hero-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--f2);
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 20px;
}

.hero-badge .verified { color: var(--brand); }

.hero-title {
  font-size: clamp(30px, 5vw, 56px);
  line-height: 1.06;
  max-width: 800px;
}

.hero-title .accent { color: var(--brand); }

.hero-sub {
  margin-top: 18px;
  font-family: var(--f2);
  font-size: 15.5px;
  font-weight: 500;
  color: var(--muted);
  max-width: 520px;
  line-height: 1.65;
}

/* ============ Рекламные баннеры — один в один из дворделивери ============ */

/* Лента, которую листают пальцем: снап по баннеру, один жест — один слайд */
.dd-scroll-x {
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  scroll-snap-type: x proximity;
  overscroll-behavior-x: contain;
}

.dd-scroll-x::-webkit-scrollbar { display: none; }

.dd-swipe-x {
  scroll-snap-type: x mandatory;
  overscroll-behavior: none;
  touch-action: pan-x pan-y;
}

/* Один жест — один баннер: без этого быстрый свайп пролетает два-три */
.dd-swipe-x > * { scroll-snap-stop: always; }

/* ============ РЯД «ГЕРОЙ + БАННЕРЫ» ============

   На телефоне это обычный столбец: плашка, под ней лента. На широком
   экране — две колонки, лента справа от заголовка.

   Порог 1080: ниже него колонка под баннеры получалась уже 340 точек, и
   заголовок «Работа во Вьетнаме — без хаоса чатов» начинал ломаться на
   четыре строки. */
.hero-row { display: flex; flex-direction: column; gap: var(--stack); }

.hero-ads { min-width: 0; }

@media (min-width: 1080px) {
  .hero-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 380px; /* перекрывается долями ниже по файлу */
    gap: 24px;
    align-items: stretch;
  }

  /* Лента тянется во всю высоту плашки: две колонки разной высоты рядом
     читаются как «одна из них не доехала». */
  .hero-ads { display: flex; }
  .hero-ads .pb-wrap { flex: 1; display: flex; flex-direction: column; }
  .hero-ads .pb-track { flex: 1; }

  /* ТЕЛЕФОННАЯ КАРУСЕЛЬ НА ШИРОКОМ ЭКРАНЕ.

     Десктопные правила (ниже по файлу, @media min-width: 761px) раскладывают
     ленту по 2,2 баннера в кадр и прячут точки — в колонке 400 точек это
     нечитаемо. Возвращаем телефонный вид: один кадр, скругление и тень на
     обёртке, точки видны. Тот же приём и теми же правилами применён к
     мини-аппу телеграма в css/tma.css. */
  .hero-ads .pb-wrap {
    overflow: hidden;
    border-radius: var(--r-card);
    box-shadow: var(--shadow-lg);
  }

  .hero-ads .pb-track { gap: 0; padding: 0; }

  .hero-ads .pb-slide {
    width: 100%;
    aspect-ratio: auto;
    min-height: 0;
    border-radius: 0;
    box-shadow: none;
    scroll-snap-align: center;
  }

  .hero-ads .pb-dots { display: flex; }
}

/* БАННЕР — ШИРОКИЙ, А НЕ УЗКАЯ КОЛОНКА.

   При фиксированных 380 точках на экране 1640 плашка забирала 966, а
   баннеру оставалось 396 — почти квадрат высотой 411. Баннер квадратом не
   бывает: он читается как плакат, а не как объявление, и текст в нём
   сползает в самый низ.

   ШИРИНУ ОГРАНИЧИВАЕТ ЗАГОЛОВОК, И ЭТО ИЗМЕРЕНО. При кегле 56 «Работа во
   Вьетнаме — без хаоса чатов» держится в три строки, пока левой колонке
   остаётся 576 точек и больше; на 519 он ломается на четыре. Отсюда две
   ступени, а не одна.

   Первая — от 1080 до 1600, где контейнер упёрт в 1180: баннер получает
   чуть меньше половины ряда, около 528 точек, и заголовок цел.

   Вторая — от 1600, где контейнер вырастает до 1440: там места хватает,
   чтобы баннер стал шире плашки. Он получает около 757 точек при 659 у
   плашки — то есть становится широким, как ему и положено, а заголовок
   по-прежнему в три строки. */
@media (min-width: 1080px) {
  .hero-row { grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr); }
}

@media (min-width: 1600px) {
  .hero-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); }
}

.pb-wrap {
  position: relative;
  overflow: hidden;
  border-radius: 32px;
  box-shadow: var(--shadow-lg);
}

.pb-track { display: flex; }

.pb-slide {
  position: relative;
  aspect-ratio: 16 / 6;
  width: 100%;
  flex-shrink: 0;
  scroll-snap-align: center;
  overflow: hidden;
  display: block;
  text-align: left;
  color: #fff;
  cursor: pointer;
}

.pb-bg { position: absolute; inset: 0; }

/* Мягкие пятна и кольцо — радиальными градиентами, не blur:
   лента листается нативной прокруткой, размытие перерисовывалось бы каждым кадром */
.pb-spot-light {
  position: absolute;
  right: -40px;
  top: -48px;
  width: 176px;
  height: 176px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.3) 0%, rgba(255, 255, 255, 0.16) 42%, rgba(255, 255, 255, 0.04) 65%, transparent 78%);
}

.pb-spot-dark {
  position: absolute;
  left: -32px;
  bottom: -56px;
  width: 192px;
  height: 192px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(0, 0, 0, 0.34) 0%, rgba(0, 0, 0, 0.18) 44%, rgba(0, 0, 0, 0.05) 66%, transparent 78%);
}

.pb-ring {
  position: absolute;
  right: -24px;
  top: 16px;
  width: 128px;
  height: 128px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.25);
}

/* Затемнение снизу — текст читается на любом фоне */
.pb-shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0.25) 50%, rgba(0, 0, 0, 0.05));
}

/* Содержимое баннера: заголовок и строка пояснения, прижатые к низу.
   Шильдик и белая кнопка убраны — весь баннер и так ссылка, а два
   дополнительных элемента поверх картинки делали его крикливым. */
.pb-content {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 18px 56px 18px 18px;
}

.pb-title {
  font-family: var(--fd);
  font-weight: 500;
  font-size: 20px;
  line-height: 1.15;
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
  filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.45));
}

.pb-sub {
  margin-top: 4px;
  font-family: var(--f2);
  font-size: 12.5px;
  line-height: 1.35;
  color: rgba(255, 255, 255, 0.86);
  max-width: 92%;
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Вместо кнопки — тихая стрелка в углу: подсказывает, что можно нажать,
   и не спорит с заголовком. */
.pb-go {
  position: absolute;
  right: 16px;
  bottom: 16px;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.16);
  backdrop-filter: blur(6px);
  color: #fff;
  transition: background-color 0.25s var(--ez), transform 0.25s var(--ez);
}

.pb-slide:hover .pb-go { background: rgba(255, 255, 255, 0.28); transform: translateX(2px); }

.pb-dots {
  pointer-events: none;
  position: absolute;
  bottom: 14px;
  right: 20px;
  display: flex;
  align-items: center;
  gap: 6px;
}

.pb-dot {
  height: 6px;
  width: 6px;
  border-radius: var(--r-pill);
  background: #fff;
  opacity: 0.55;
  transition: width 0.3s ease-out, opacity 0.3s ease-out;
}

.pb-dot.on { width: 28px; opacity: 1; }

/* Широкий экран: лента остаётся лентой, в одну строку.
   Сеткой repeat(2, …) четыре баннера складывались квадратом 2×2 и съедали
   пол-экрана по высоте, а overflow: visible на дорожке глушил прокрутку из
   .dd-scroll-x — вбок было не листать. */
@media (min-width: 761px) {
  .pb-wrap { overflow: visible; border-radius: 0; box-shadow: none; }

  /* Поля сверху и снизу — не воздух, а место для тени карточек: у ленты
     overflow-x: auto, а в этом случае браузер считает overflow-y тоже auto
     и срезал бы тень ровно по краю слайда. */
  .pb-track { gap: 16px; padding: 12px 0; }

  .pb-slide {
    /* 2,2 баннера в кадре: край третьего сам подсказывает, что листается */
    width: calc((100% - 32px) / 2.2);
    /* Пропорция шире телефонной — иначе строка из широких карточек снова
       вырастает в громадину: на 1280 выходит около 180 точек вместо 437 */
    aspect-ratio: 16 / 5;
    /* На узком десктопе и планшете карточка становится слишком приплюснутой:
       заголовку с пояснением и стрелке нужно около 82 точек, ниже не опускаем */
    min-height: 118px;
    border-radius: var(--r-card);
    /* Тень как у соседних карточек каталога, а не тяжёлая --shadow-lg:
       крупная всё равно не поместилась бы в поля ленты и обрезалась */
    box-shadow: var(--shadow);
    /* Крайние баннеры по центру не встают, и при mandatory-снапе лента
       дёргалась бы на первом и последнем — выравниваем по началу */
    scroll-snap-align: start;
  }

  .pb-dots { display: none; }
  .pb-title { font-size: 22px; }
  .pb-sub { font-size: 12.5px; }
}
/* Аккуратный промо-блок в сайдбарах */
.side-promo {
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: var(--brand-soft);
  border: 1px solid rgba(255, 107, 0, 0.25);
  border-radius: 22px;
  padding: 16px;
}

.side-promo .sp-ico {
  width: 32px;
  height: 32px;
  border-radius: 11px;
  background: linear-gradient(135deg, #ff8533, #ff6b00);
  color: #fff;
  display: grid;
  place-items: center;
  margin-bottom: 4px;
}

.side-promo b { font-size: 13.5px; }
.side-promo span { font-family: var(--f2); font-size: 12px; color: var(--muted); line-height: 1.5; }
.side-promo .btn { margin-top: 8px; align-self: flex-start; }

/* ===================== Секции ===================== */

/* Единственный вертикальный ритм страницы. Секция отбивается шагом сверху и
   снизу, поэтому между двумя соседними плашками всегда ровно два шага — и на
   телефоне, и на мониторе, где --stack сам становится больше. Собственных
   чисел у секции нет намеренно: из-за них соседи расходились то на 26, то на
   52 точки, и главная читалась как набор слипшихся кусков. */
.section { padding-top: var(--stack); padding-bottom: var(--stack); }

.section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 22px;
}

.section-title { font-size: clamp(18px, 2.4vw, 24px); }

.section-link {
  font-weight: 700;
  font-size: 13.5px;
  color: var(--brand);
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding-bottom: 3px;
}

.section-link:hover { color: var(--brand-dark); }

/* Направления сеткой — плитки в духе виджетов приложения */
.cat-tiles {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 12px;
}

/* Плитка направления — строкой: значок слева, название и счётчик справа.
   Столбиком она занимала вдвое больше высоты ради того же самого. */
.cat-tile {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 14px 10px 10px;
  border-radius: 22px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  /* Плавим тень и подъём, а не рамку: правило стоит ниже .dd-lift с той же
     специфичностью и раньше гасило его переход — тень вспыхивала рывком */
  transition: box-shadow 0.3s var(--ez), transform 0.4s var(--ez-spring);
}

/* Наведение показываем тенью и подъёмом, а не рамкой вокруг плитки */
.cat-tile:hover { box-shadow: var(--shadow-lg); }

.cat-tile .ico {
  width: 34px;
  height: 34px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  background: var(--brand-soft);
  color: var(--brand);
  flex-shrink: 0;
}

.cat-tile .ct-txt { min-width: 0; }
.cat-tile b { display: block; font-size: 12.5px; font-weight: 700; line-height: 1.25; }

.cat-tile small {
  display: block;
  font-size: 11.5px;
  font-family: var(--f2);
  color: var(--muted-2);
  margin-top: 2px;
}

/* Карточки-бенефиты */
.cat-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--stack); }

/* Сетка на три карточки. Раньше три колонки прибивались инлайн-стилем прямо
   в разметке — он сильнее любого правила ниже, и на телефоне карточки
   сжимались в столбики шириной в одно слово. */
.cat-grid.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

@media (max-width: 900px) {
  .cat-grid.cols-3 { grid-template-columns: 1fr; }
}

.cat-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 22px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.cat-card .ico {
  width: 44px;
  height: 44px;
  border-radius: 15px;
  display: grid;
  place-items: center;
  background: var(--brand-soft);
  color: var(--brand);
}

.cat-card .ttl { font-weight: 700; font-size: 15px; }
.cat-card .cnt { font-family: var(--f2); font-size: 13px; color: var(--muted); line-height: 1.55; }

/* ===================== Карточка вакансии ===================== */

.vac-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--stack); }

/* Миниатюра вакансии: четыре строки сверху вниз — компания, должность,
   деньги, место. Ровный ритм важнее плотности: карточка читается за
   полсекунды, а подробности ждут на самой странице вакансии. */
.vac-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  position: relative;
}

/* СТРОКА КОМПАНИИ — ТРЕТЬЕЙ, ПОСЛЕ ДОЛЖНОСТИ И ДЕНЕГ.

   Логотип в ней прижат вправо и появляется только у компаний, которым мы
   доверяем. В ленте без логотипов каждый оставшийся читается как знак, а
   не как украшение — ради этого их и убрали у остальных. */
.vc-co-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}

.vc-co-row .vc-logo {
  margin-left: auto;
  flex-shrink: 0;
  position: relative;
  z-index: 2;
}

.vc-co-row .co-logo { width: 34px; height: 34px; border-radius: 12px; }

.vc-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}

/* ПЛАТНОЕ РАЗМЕЩЕНИЕ ДОЛЖНО БЫТЬ ВИДНО.

   Прошлая попытка выделяла «топ» подложкой в 2,8% черноты, а «срочно» не
   выделяла ничем: правила для promo-hot в файле просто не было. На ленте
   это неразличимо — человек платил за поднятие и получал только место в
   сортировке. Значок в углу дела не решает: его замечают, когда карточку
   уже читают, а решение смотреть или пролистнуть принимается раньше.

   Выделяем полосой по левому краю. Полоса работает на просмотре по
   диагонали: глаз ловит вертикаль раньше, чем текст. Оранжевого при этом
   ровно три точки ширины — это линия, а не заливка, и ленту она не
   красит. Два уровня различаются силой: «срочно» — полоса, «топ» — полоса
   потолще, приподнятая карточка и чуть тёплая подложка. */
/* СРОЧНО — ПОЛОСА ПО ЛЕВОМУ КРАЮ. */
.vac-card.promo-hot {
  border-left-width: 3px;
  border-left-color: var(--brand);
}

/* ═════ ВЫСШИЙ УРОВЕНЬ ═════

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

   Карточка приподнята тенью и чуть теплее ленты — но подложка здесь
   слабая, почти незаметная: всю работу делает блок с названием. */
.vac-card.promo-top {
  overflow: hidden;
  background:
    linear-gradient(180deg, rgba(255, 107, 0, 0.04), rgba(255, 107, 0, 0)),
    var(--card);
  box-shadow: var(--shadow-lg);
}

/* КРУПНЫЙ ЗНАК ПРОЛЕТАЕТ ПО ПРАВОЙ ТРЕТИ.

   Обесцвеченный и почти прозрачный: это фон, а не сообщение. Если его
   можно прочитать — он мешает читать вакансию, ради которой карточка и
   существует. Событий мыши не ловит вовсе, чтобы не отнимать нажатие у
   карточки-ссылки. */
.vc-fly {
  position: absolute;
  top: 50%;
  right: 0;
  width: 34%;
  max-width: 190px;
  aspect-ratio: 1 / 1;
  opacity: 0;
  filter: grayscale(1);
  color: #71717a;
  pointer-events: none;
  z-index: 0;
  animation: пролёт 11s linear infinite;
}

.vc-fly svg { width: 100%; height: 100%; display: block; }

@keyframes пролёт {
  0%   { transform: translate(30%, -50%) rotate(-8deg); opacity: 0; }
  12%  { opacity: 0.14; }
  74%  { opacity: 0.14; }
  100% { transform: translate(-90%, -50%) rotate(6deg); opacity: 0; }
}

/* НАЗВАНИЕ И ОПЛАТА В ОДНОМ БЛОКЕ.

   У обычной карточки блок ничего не меняет — он прозрачный и без полей.
   У высшего уровня становится оранжевым, а текст в нём белым. */
.vc-plate { position: relative; z-index: 1; }

/* ═════ ОПЛАТА ЭТАПАМИ ═════

   Путь и его оформление взяты из ДВОР ДЕЛИВЕРИ и переложены на нашу
   палитру: там тёмная тема и лаймовые акценты, здесь одна светлая и
   оранжевый. Всё остальное — полоски шагов, крупная сумма в шапке,
   строки реквизитов с копированием, кольцо ожидания, оранжевый финал —
   повторено как есть, потому что в этом и был смысл: человек, который
   платил в ДД, должен узнать тот же путь. */

.pay-dots { display: flex; gap: 6px; margin-bottom: 16px; }
.pay-dots span {
  flex: 1;
  height: 5px;
  border-radius: var(--r-pill);
  background: var(--border);
  transition: background 0.3s var(--ez);
}
.pay-dots span.done { background: #10b981; }
.pay-dots span.now { background: var(--brand); }

.pay-hero {
  border-radius: 24px;
  padding: 18px;
  background: linear-gradient(135deg, rgba(255,107,0,0.14), rgba(255,107,0,0.04));
  border: 1px solid rgba(255,107,0,0.22);
}
.pay-hero .ph-top { display: flex; align-items: center; gap: 11px; }
.pay-hero .ph-ico {
  width: 40px; height: 40px; border-radius: 14px;
  display: grid; place-items: center;
  background: var(--brand); color: #fff; flex-shrink: 0;
}
.pay-hero .ph-top b { display: block; font-size: 14.5px; }
.pay-hero .ph-top small { display: block; font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.pay-hero .ph-sum { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-top: 14px; }
.pay-hero .ph-sum span { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.14em; color: var(--muted); }
.pay-hero .ph-sum b { font-family: var(--f2); font-size: 26px; font-weight: 700; }

.pay-rows {
  margin-top: 12px;
  border-radius: 20px;
  background: var(--card);
  border: 1px solid var(--border);
  overflow: hidden;
}
.pay-row { display: flex; align-items: center; gap: 10px; padding: 11px 14px; border-top: 1px solid var(--border); }
.pay-row:first-child { border-top: 0; }
.pay-row > span {
  width: 78px; flex-shrink: 0;
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.12em; color: var(--muted);
}
.pay-row > b { flex: 1; min-width: 0; font-size: 13px; overflow-wrap: anywhere; }
.pay-row > b.hot { color: var(--brand); font-size: 14.5px; }
.pay-copy {
  width: 32px; height: 32px; border-radius: 11px; flex-shrink: 0;
  display: grid; place-items: center;
  background: var(--card-2); color: var(--muted); border: 0;
}
.pay-copy:hover { color: var(--brand); }

.pay-note {
  display: flex; gap: 9px; align-items: flex-start;
  margin-top: 12px; padding: 12px 14px;
  border-radius: 16px; background: var(--card-2);
  font-size: 12.5px; line-height: 1.5; color: var(--text);
}
.pay-note svg { color: #10b981; flex-shrink: 0; margin-top: 1px; }

/* Выбор способа оплаты. Плитками, а не списком: способов четыре, и
   выбирают их одним касанием, не вчитываясь. */
/* Строка реквизита в админке: тумблер сверху, три поля под ним.
   Выключатель рядом с полями нарочно — включают сразу после того, как
   вписали, и ходить за ним в другой конец экрана незачем. */
.adm-pay-row {
  padding: 16px;
  border-radius: 18px;
  background: var(--card);
  border: 1px solid var(--border);
  margin-bottom: 12px;
}
.adm-pay-row .apr-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.adm-pay-row .apr-head b { font-size: 15px; }
.adm-pay-row .apr-head .muted { font-size: 12px; }
.adm-pay-row .apr-head .adm-switch { margin-left: auto; }
.adm-pay-row .field { margin-bottom: 10px; }

.pay-methods { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-top: 14px; }

.pay-method {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: 14px 16px; border-radius: 18px;
  background: var(--card); border: 1px solid var(--border); box-shadow: var(--shadow);
  text-align: left;
}
.pay-method:hover { border-color: var(--brand); }
.pay-method b { font-size: 15px; }

/* Сумма в валюте способа — крупнее названия: человек выбирает не «USDT»,
   а «семь семьдесят семь». */
.pay-method .pm-sum {
  font-family: var(--f2);
  font-weight: 700;
  font-size: 16px;
  color: var(--brand);
}

/* Донги под пересчитанной суммой: основная цифра — та, которую
   переводят, а донги остаются опорой, по которой сверяют. */
.pay-hero .ph-base {
  margin-top: 4px;
  font-size: 11.5px;
  color: var(--muted);
  text-align: right;
}
.pay-method small { font-size: 11.5px; color: var(--muted); }

/* Сколько осталось на перевод. Цифра крупная и одна: это единственное,
   что тут может закончиться. */
.pay-left {
  margin-top: 12px; padding: 10px 14px; border-radius: 14px;
  background: var(--card-2); font-size: 13px; text-align: center;
}
.pay-left b { font-family: var(--f2); font-size: 16px; }

/* Код. Белое поле вокруг обязательно — без полей камера его не берёт. */
.pay-qr {
  margin-top: 12px; padding: 14px; border-radius: 20px;
  background: #fff; border: 1px solid var(--border);
  display: flex; flex-direction: column; align-items: center; gap: 8px;
}
.pay-qr svg { width: 200px; max-width: 100%; }
.pay-qr small { font-size: 11.5px; color: var(--muted); text-align: center; }

.pay-back { width: 100%; margin-top: 8px; }

/* Выходы с экрана ожидания. В строку и мелкими: это не то, ради чего
   человек здесь, но без них экран становится ловушкой. */
.pay-exits { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.pay-exits .btn { flex: 1; min-width: 140px; }

/* Поле для чека. Крупное и нажимается целиком: на телефоне маленькая
   скрепка сбоку — это промах пальцем и раздражение на ровном месте. */
.pay-file {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 12px;
  padding: 14px;
  border-radius: 20px;
  border: 1.5px dashed var(--border);
  background: var(--card);
  cursor: pointer;
  transition: border-color 0.25s var(--ez), background 0.25s var(--ez);
}
.pay-file:hover { border-color: var(--brand); }

/* Чек выбран — пунктир становится сплошным и зелёным: это не «можно
   нажать», а «сделано». */
.pay-file.ready {
  border-style: solid;
  border-color: rgba(16,185,129,0.5);
  background: rgba(16,185,129,0.06);
}
.pay-file.ready .pf-ico { background: #10b981; color: #fff; }

.pay-file .pf-ico {
  width: 40px; height: 40px; border-radius: 14px; flex-shrink: 0;
  display: grid; place-items: center;
  background: var(--card-2); color: var(--muted);
}
.pay-file .pf-txt { min-width: 0; }
.pay-file .pf-txt b { display: block; font-size: 13.5px; overflow-wrap: anywhere; }
.pay-file .pf-txt small { display: block; font-size: 11.5px; color: var(--muted); margin-top: 2px; line-height: 1.4; }

.pay-go:disabled { opacity: 0.5; }

.pay-go { width: 100%; margin-top: 14px; }
.pay-small { font-size: 11.5px; line-height: 1.5; margin: 10px 0 0; }

/* Ожидание. Кольцо крутится ровно и без рывков — это единственное, что
   человек видит, пока за экраном работает живой оператор. */
.pay-wait {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 8px; padding: 26px 18px;
  border-radius: 24px; background: var(--card-2); border: 1px solid var(--border);
}
.pay-wait b { font-size: 17px; }
.pay-wait small { font-size: 12.5px; color: var(--muted); line-height: 1.5; max-width: 280px; }
.pay-wait .pw-ring {
  width: 64px; height: 64px; border-radius: 50%;
  border: 4px solid rgba(255,107,0,0.18); border-top-color: var(--brand);
  animation: pay-spin 1.1s linear infinite;
  margin-bottom: 4px;
}
.pay-wait .pw-time { font-family: var(--f2); font-size: 24px; font-weight: 700; margin-top: 4px; }
.pay-wait.green { background: rgba(16,185,129,0.07); border-color: rgba(16,185,129,0.24); }
.pay-wait.green .pw-ring { border-color: rgba(16,185,129,0.2); border-top-color: #10b981; }
.pay-wait.red { background: rgba(239,68,68,0.06); border-color: rgba(239,68,68,0.22); }
.pay-wait .pw-x { color: #ef4444; }

@keyframes pay-spin { to { transform: rotate(360deg); } }

.pay-bar { height: 6px; border-radius: var(--r-pill); background: var(--border); overflow: hidden; margin-top: 12px; }
.pay-bar i { display: block; height: 100%; width: 0; background: linear-gradient(90deg, #ff8533, #ff6b00); transition: width 0.9s var(--ez); }

/* Финал — единственное место, где оранжевый заливает блок целиком. */
.pay-done {
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: 6px;
  padding: 30px 20px; border-radius: 26px; color: #fff;
  background: linear-gradient(135deg, #ff8533, #ff6b00 55%, #e65c00);
}
.pay-done .pd-ico {
  width: 68px; height: 68px; border-radius: 50%;
  display: grid; place-items: center; margin-bottom: 6px;
  background: rgba(255,255,255,0.2); border: 1px solid rgba(255,255,255,0.32);
}
.pay-done b { font-size: 24px; }
.pay-done span { font-size: 13.5px; font-weight: 600; }
.pay-done small { font-size: 12.5px; opacity: 0.9; }

@media (prefers-reduced-motion: reduce) {
  .pay-wait .pw-ring { animation: none; }
}

/* ═════ ВИТРИНА ПЛАТНЫХ УСЛУГ ═════

   Карточка услуги устроена как карточка вакансии: значок, название,
   объяснение, цифра. Это нарочно — человек уже умеет их читать, и
   отдельный язык для прайса пришлось бы разбирать заново.

   Цена стоит последней и крупно. В прайсе, где цену прячут, её ищут
   первой и всё равно находят — только с раздражением. */
/* ═════ ВСТАВКИ В ЛЕНТЕ ВАКАНСИЙ ═════

   Отличаются от карточек нарочно: без белой подложки и без тени, на
   ленте они читаются как «другое», а не как ещё одна вакансия. Именно
   поэтому их нельзя перепутать с выдачей — и именно поэтому мимо них не
   проскакивает взгляд. */
.feed-block {
  grid-column: 1 / -1;
  margin: 4px 0 2px;
}

.feed-head {
  font-weight: 700;
  font-size: 14px;
  margin-bottom: 10px;
}

.feed-cos {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  padding-bottom: 4px;
  scrollbar-width: none;
}
.feed-cos::-webkit-scrollbar { display: none; }

.feed-co {
  flex: 0 0 auto;
  width: 132px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  text-align: center;
  padding: 14px 10px;
  border-radius: 20px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.feed-co b { font-size: 13px; line-height: 1.3; }
.feed-co span { font-size: 11.5px; color: var(--muted); }

/* Полоса про платное — единственная оранжевая вещь в ленте, и она
   намеренно не похожа на вакансию: без карточки, одной строкой. */
.feed-promo {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-radius: 20px;
  background: var(--brand-soft);
  border: 1px solid rgba(255, 107, 0, 0.22);
}

.feed-promo-mark { width: 34px; height: 34px; flex-shrink: 0; color: var(--brand); }
.feed-promo-mark svg { width: 100%; height: 100%; }
.feed-promo-txt { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.feed-promo-txt b { font-size: 14px; }
.feed-promo-txt span { font-size: 12.5px; color: var(--muted); line-height: 1.45; }
.feed-promo-go { margin-left: auto; color: var(--brand); flex-shrink: 0; }

.price-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 12px;
}

.price-card {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 18px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.price-card .ico {
  width: 42px;
  height: 42px;
  border-radius: 14px;
  display: grid;
  place-items: center;
  background: var(--brand-soft);
  color: var(--brand);
  margin-bottom: 3px;
}

.price-card .ico svg { width: 22px; height: 22px; }
.price-card .ico [data-lottie] { width: 24px; height: 24px; display: block; }
.price-card .ico [data-lottie] svg { width: 100%; height: 100%; }

.price-card .ttl { font-weight: 700; font-size: 15.5px; }
.price-card .cnt { font-size: 13px; color: var(--muted); line-height: 1.5; flex: 1; }

.price-card .sum {
  font-family: var(--f2);
  font-weight: 700;
  font-size: 19px;
  color: var(--brand);
  margin-top: 4px;
}

/* Примечание идёт под всей сеткой, а не внутри колонки. */
.price-note {
  grid-column: 1 / -1;
  font-size: 13px;
  margin: 6px 0 0;
  line-height: 1.55;
}

.vac-card.promo-top .vc-plate {
  background: var(--brand);
  border-radius: 18px;
  padding: 11px 14px 13px;
  margin: 4px 0 2px;
  box-shadow: 0 8px 20px rgba(255, 107, 0, 0.26);
}

/* Белым — всё, что внутри: в строке оплаты бывают свои цвета, и одного
   правила на ссылку заголовка не хватает. */
.vac-card.promo-top .vc-plate,
.vac-card.promo-top .vc-plate * { color: #fff; }
.vac-card.promo-top:hover .vc-plate .vc-title a { color: #fff; }

@media (prefers-reduced-motion: reduce) {
  .vc-fly { animation: none; opacity: 0.1; transform: translate(-20%, -50%); }
}


/* НОВАЯ — ЧУТЬ ЗАМЕТНЕЕ, И ТОЛЬКО СУТКИ.

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

   Слабее, чем было у платных: там заливка была фоном, здесь — намёком. */
.vac-card.just-now {
  background:
    linear-gradient(180deg, rgba(255, 107, 0, 0.055), rgba(255, 107, 0, 0) 120px),
    var(--card);
}


.vc-fresh {
  padding: 3px 8px;
  /* Это правило перекрыто вторым .vc-fresh ниже по файлу; радиус правим и
     здесь, чтобы форма не зависела от того, какой дубль переживёт чистку */
  border-radius: 8px;
  background: var(--brand-soft);
  color: var(--brand);
  font-family: var(--f2);
  font-size: 11px;
  font-weight: 700;
}

/* Низ карточки: слева — когда опубликовано, справа — избранное. Ровно два
   якоря по краям, между ними воздух. */
.vc-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}

/* Дата и избранное держатся вместе справа, действие — слева */
.vc-tail { display: flex; align-items: center; gap: 8px; }
.vc-apply { white-space: nowrap; }
.vac-card.archived .vc-foot { opacity: 0.8; }

.vc-state {
  font-family: var(--f2);
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-2);
}

.vc-state.done { color: var(--success); display: inline-flex; align-items: center; gap: 5px; }

@media (hover: hover) {
  .vac-card:hover { box-shadow: var(--shadow-lg); }
}

.vc-top { display: flex; align-items: flex-start; gap: 12px; }
.vc-main { flex: 1; min-width: 0; }

.vc-title {
  font-family: var(--f);
  font-weight: 700;
  font-size: 16px;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.vc-title a:hover { color: var(--brand); }

/* КЛИКАБЕЛЬНА ВСЯ КАРТОЧКА, А НЕ ОДНО НАЗВАНИЕ.
   Слой-ссылка лежит поверх карточки, а всё, что кликается само — логотип,
   название компании, кнопки, избранное и сам заголовок, — поднято над ним.
   Растянуть вместо этого псевдоэлемент заголовка нельзя: заголовок обрезан
   по двум строкам (line-clamp), и слой обрезался бы вместе с ним. */
.vc-hit {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  z-index: 1;
}

.vac-card .vc-title a, .vac-card .vc-logo, .vac-card .vc-co,
.vac-card .btn, .vac-card .fav-btn { position: relative; z-index: 2; }

/* Наведение на карточку подсвечивает название — видно, что кликается вся */
.vac-card:hover .vc-title a { color: var(--brand); }

.vc-salary {
  font-weight: 700;
  font-size: 17px;
  margin-top: 2px;
}

.vc-nosalary { font-family: var(--f2); font-weight: 600; font-size: 13px; color: var(--muted); letter-spacing: 0; }

.co-logo {
  width: 46px;
  height: 46px;
  border-radius: 15px;
  display: grid;
  place-items: center;
  flex-shrink: 0;
  background: var(--co-bg, var(--card-2));
  color: var(--co-fg, var(--muted));
}

.co-logo.lg { width: 62px; height: 62px; border-radius: 20px; }
.co-logo.xl { width: 84px; height: 84px; border-radius: 26px; }

/* МОНОГРАММА. Заглавным шрифтом, плотно, с чуть увеличенным межбуквенным —
   так две буквы читаются как знак, а не как обрубок слова. */
.co-mono {
  font-family: var(--fd);
  font-weight: 800;
  font-size: 17px;
  letter-spacing: 0.02em;
  line-height: 1;
  user-select: none;
}

.co-mono.lg { font-size: 23px; }
.co-mono.xl { font-size: 31px; }


/* Знак ДВОРа — единственный настоящий логотип в коде. Ему подложка не
   нужна: он и так узнаётся. */
.co-mark { background: var(--brand-soft); color: var(--brand); }

.vc-logo { transition: transform 0.3s var(--ez-spring); }
.vc-logo:hover { transform: scale(1.06); }

.vc-co {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.vc-co:hover { color: var(--text); }

.vc-fresh {
  padding: 3px 9px;
  /* Высота та же ~23px, что и у .vc-promo, — на ней --r-pill даёт полукруг */
  border-radius: 8px;
  background: var(--brand-soft);
  color: var(--brand);
  font-family: var(--f2);
  font-size: 11px;
  font-weight: 700;
}

/* Бейджи продвижения */
/* Шильдик продвижения — высотой всего ~23px, и --r-pill совпадает с
   половиной высоты: выходила оранжевая таблетка, самая заметная на
   карточке. 8px возвращают ему прямоугольник. */
.vc-promo {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 3px 9px;
  border-radius: 8px;
  font-family: var(--f2);
  font-size: 11px;
  font-weight: 700;
}

.vc-promo.hot {
  background: linear-gradient(135deg, #ff8533, #ff6b00);
  color: #fff;
  box-shadow: var(--shadow-brand);
}

.vc-promo.top {
  background: var(--ink-2);
  color: #fff;
}

.vc-per { font-size: 11px; font-weight: 700; color: var(--muted); }

/* Сегмент-кнопки анкеты — как плитки выбора у hh */
.seg-row { display: flex; flex-wrap: wrap; gap: 8px; }

.seg-btn {
  padding: 10px 18px;
  border-radius: 15px;
  border: 1.5px solid var(--border-2);
  background: var(--card);
  font-weight: 700;
  font-size: 13px;
  color: var(--text);
  transition: border-color var(--dur-fast), color var(--dur-fast), background-color var(--dur-fast);
}

/* Выбор и наведение показываем заливкой: ряд из шести-семи сегментов с
   оранжевой кромкой превращал экран в решётку из рамок */
.seg-btn:hover { background: var(--card-2); }

.seg-btn.active {
  border-color: transparent;
  color: var(--brand);
  background: var(--brand-soft);
}

/* Форма вакансии: секции слева + липкий степпер справа */
.vform-layout {
  display: grid;
  grid-template-columns: 1fr 230px;
  gap: 26px;
  align-items: start;
}

.vform-nav {
  position: sticky;
  top: 84px;
  display: flex;
  flex-direction: column;
  padding: 14px 8px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 24px;
  box-shadow: var(--shadow);
}

.vform-nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 8px 10px;
  font-weight: 700;
  font-size: 12.5px;
  color: var(--muted);
  border-radius: 12px;
}

.vform-nav a:hover { color: var(--text); }

.vform-nav a .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--border-2);
  flex-shrink: 0;
  transition: background-color 0.2s, box-shadow 0.2s;
}

/* линия между точками, как у hh */
.vform-nav a + a::before {
  content: '';
  position: absolute;
  left: 13.5px;
  top: -7px;
  width: 1.5px;
  height: 12px;
  background: var(--border);
}

.vform-nav a.active { color: var(--text); }
.vform-nav a.active .dot {
  background: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
}

.vform-sec { scroll-margin-top: 84px; }

.vform-sec h2 {
  font-family: var(--fd);
  font-weight: 700;
  font-size: 16px;
  margin-bottom: 14px;
}

/* Степпер анкеты прячем только когда для него правда нет места: на
   планшете (860+) он помещается рядом с формой и помогает не потеряться
   в десяти разделах. */
@media (max-width: 860px) {
  .vform-layout { grid-template-columns: 1fr; }
  .vform-nav { display: none; }
}

@media (min-width: 861px) and (max-width: 1000px) {
  .vform-layout { grid-template-columns: 1fr 210px; }
}

.vc-tags { display: flex; flex-wrap: wrap; gap: 6px; }

.vc-foot { display: flex; align-items: center; gap: 8px; margin-top: auto; padding-top: 8px; }
.vc-date { font-family: var(--f2); font-size: 11.5px; font-weight: 600; color: var(--muted-2); }

.jobs-list .vac-card { gap: 6px; }

.vac-card.archived { opacity: 0.72; }

.fav-btn {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  /* Тот же квадрат 34px, что у .mf-ico и значка плитки направления —
     общий --r-pill держит их одной формой, 14px выбивались в кругляш. */
  border-radius: var(--r-pill);
  background: var(--card-2);
  color: var(--muted);
  flex-shrink: 0;
}

.fav-btn:hover { color: var(--brand); }
.fav-btn.active { background: var(--brand-soft); color: var(--brand); }
.fav-btn.fav-anim svg { animation: dd-pop 0.34s var(--ez-spring); }

.verified { color: var(--brand); display: inline-flex; align-items: center; }

/* ЗНАЧОК СТАЛ ССЫЛКОЙ, А ВЫГЛЯДИТ ПО-ПРЕЖНЕМУ.

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

   Что даём — след нажатия и заметную обводку при ходьбе с клавиатуры:
   кликабельное обязано выглядеть кликабельным хотя бы под курсором. */
a.verified { text-decoration: none; cursor: pointer; border-radius: 50%; }
a.verified:hover { opacity: 0.72; }
a.verified:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* ===================== Страница поиска ===================== */

/* ============ ВЫДАЧА И КОЛОНКА ФИЛЬТРОВ ============

   Одна разметка, два поведения. Ниже 1080 точек фильтры — окно, которое
   поднимается снизу по кнопке. От 1080 и шире — закреплённая колонка
   справа: место под неё есть, и прятать под кнопку то, что и так
   помещается, значит просить нажатие даром.

   Порог 1080, а не 1000: при 1000 на выдачу оставалось бы 700 с небольшим
   точек, и строка вакансии начинала бы ломаться переносами. */
.list-body { display: block; }

/* ——— Узкий экран: панель поднимается окном ——— */

.list-side {
  position: fixed;
  inset: 0;
  z-index: 180;
  display: none;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(2px);
}

.list-side.open { display: flex; animation: dd-fade 0.18s var(--ez) both; }

html.sheet-open { overflow: hidden; }

.sheet {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 620px;
  max-height: 86vh;
  background: var(--card);
  border-radius: var(--r-card) var(--r-card) 0 0;
  box-shadow: var(--shadow-lg);
  animation: sheet-rise 0.26s var(--ez) both;
}

@keyframes sheet-rise {
  from { transform: translateY(24px); opacity: 0; }
  to { transform: none; opacity: 1; }
}

.sheet-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 18px 12px;
  border-bottom: 1px solid var(--border);
  font-size: 16px;
}

/* Тело — единственное, что прокручивается. Подвал стоит на месте: искать
   кнопку прокруткой после каждой галочки невыносимо. */
.sheet-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 18px;
}

.sheet-foot {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 18px calc(12px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--border);
  background: var(--card);
}

.sheet-foot .btn-primary { flex: 1; justify-content: center; }

@media (min-width: 700px) and (max-width: 1079.98px) {
  .list-side.open { align-items: center; padding: 24px; }
  .sheet { border-radius: var(--r-card); max-height: 80vh; }
}

/* ——— Широкий экран: колонка справа, закреплённая ——— */

@media (min-width: 1080px) {
  .list-body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 288px;
    gap: 24px;
    align-items: start;
  }

  /* Подложки, затемнения и замка прокрутки здесь нет вовсе: панель не
     перекрывает страницу, она её часть. */
  .list-side {
    position: static;
    display: block;
    background: none;
    backdrop-filter: none;
    z-index: auto;
    /* ЯЧЕЙКА ТЯНЕТСЯ ВО ВСЮ ВЫСОТУ РЯДА, ИНАЧЕ ЗАКРЕПЛЕНИЕ НЕ РАБОТАЕТ.

       Ряд выровнен по верху (align-items: start), и без этой строки высота
       ячейки равна высоте самой панели — то есть внутри неё нет места, по
       которому липкий элемент мог бы ехать. Панель просто уезжала бы вверх
       вместе со страницей, и «закреплённые фильтры» оказались бы обычными. */
    align-self: stretch;
  }

  /* ЗАКРЕПЛЕНА, НО НЕ ПРИБИТА. Прокручиваешь выдачу — условия остаются
     перед глазами; станет условий больше, чем экрана, — прокрутятся
     внутри себя, а не утащат страницу. */
  .list-side .sheet {
    position: sticky;
    top: 84px;
    max-height: calc(100vh - 104px);
    max-width: none;
    border-radius: var(--r-card);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
    animation: none;
  }

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

     По классу, а не по идентификатору: панель одна и та же на поиске
     вакансий и в каталоге компаний, и правило с чужим id молча не
     срабатывало бы на второй странице. */
  .sheet-close,
  .sheet-show { display: none; }

  .sheet-foot .btn-flat { flex: 1; justify-content: center; }

  /* Кнопка «Фильтры» в полосе условий тоже не нужна — открывать нечего.

     Селектор с родителем не для красоты: правило .qf { display: inline-flex }
     стоит ниже по файлу, и при равном весе побеждало бы оно — кнопка так и
     осталась бы на месте. Замерено: display оставался flex. */
  .quick-filters .qf-more { display: none; }
}

.filters h3 {
  font-size: 15px;
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: 8px;
}

.fgroup { display: flex; flex-direction: column; gap: 9px; }

.fgroup .fttl {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--muted-2);
}

.fgroup .check { font-size: 13px; }

/* ОДИН РИТМ НА ВСЮ СТРАНИЦУ.

   Здесь стояло 12, у сеток компаний и резюме — 14, а всё остальное на
   странице живёт шагом --stack, то есть 16. Разница в две-четыре точки
   глазом не читается как замысел — она читается как небрежность: список
   лепится плотнее, чем всё вокруг, и непонятно почему.

   Один шаг на все списки и сетки. Он же меняется вместе с --stack на
   больших экранах — то есть остаётся согласованным сам собой. */
.jobs-list { display: flex; flex-direction: column; gap: var(--stack); }

/* МЕЖДУ КАРТОЧКАМИ НЕ БЫЛО ОТСТУПА ВООБЩЕ. ЗАМЕРЕНО: НОЛЬ.

   Промежуток задан списку, а карточки лежат не в нём: при смене фильтров
   содержимое подменяется целиком, и ради плавности его заворачивают в
   обёртку с анимацией. Обёртка обычная, блочная — она и съедала весь
   промежуток: gap действует только на прямых детей, а прямой ребёнок у
   списка оказался один.

   display: contents убирает обёртку из раскладки, не убирая её из дерева:
   карточки снова становятся детьми списка и получают свой промежуток, а
   анимация появления остаётся — она висит на детях, а не на обёртке.

   Только для этого списка: в поиске резюме та же обёртка САМА является
   сеткой (dd-swap res-grid), и убрать её из раскладки значило бы разложить
   резюме в одну колонку. */
.jobs-list > .dd-swap { display: contents; }

/* Две колонки, когда ширины хватает на две полноценные карточки рядом:
   одна растянутая на весь экран читается как полоса. Правило стоит после
   базового — иначе flex выше по файлу перебивал бы сетку. */
/* Колонок столько, сколько поместится карточек шириной от 340 точек —
   порог по ширине окна тут не работает: рядом со списком стоят фильтры,
   и на одном и том же экране места бывает то на две карточки, то на одну.
   Ниже 340 карточка обрезает название компании и ставит факты столбиком. */
/* ============ ВЫДАЧА — СТРОКАМИ, А НЕ СЕТКОЙ ============

   Была сетка в три колонки из карточек 371 на 247. Три колонки на списке,
   отсортированном по важности, — это чтение зигзагом: глаз идёт слева
   направо, потом возвращается, и порядок «сверху лучше» распадается. Плюс
   каждая карточка тянулась в высоту, и на экран влезало три с половиной
   штуки при девятистах точках высоты.

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

   Сетку оставляем там, где она уместна: подборки на главной, похожие
   вакансии, избранное — это .vac-grid, короткие наборы без порядка. */
@media (min-width: 900px) {
  .jobs-list > .dd-swap { display: contents; }

  /* СЕТКИ У КАРТОЧКИ БОЛЬШЕ НЕТ, И ЭТО НАРОЧНО.

     На широком экране карточка раскладывалась в две колонки: слева
     компания, название и метки, справа деньги и кнопка. Порядок чтения
     получался свой, не такой, как на телефоне, и деньги отрывались от
     должности, к которой относятся.

     Теперь порядок один на всех ширинах и ровно тот, в котором человек
     принимает решение: должность → деньги → кто нанимает → условия →
     действие. Так же устроены карточки на больших досках вакансий, и
     причина у всех одна.

     Широкому экрану остаётся то, ради чего он широкий: больше воздуха по
     краям и кнопка, прижатая вправо, чтобы не болталась посреди пустой
     строки. */
  .jobs-list .vac-card { padding: 18px 22px; }

  .jobs-list .vc-foot { justify-content: space-between; }
}

.jobs-toolbar { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; flex-wrap: wrap; }
.jobs-toolbar .found { font-weight: 700; font-size: 15px; }
.jobs-toolbar .sort { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.jobs-toolbar .sort .select { width: auto; padding: 8px 34px 8px 13px; font-size: 12.5px; border-radius: 12px; }

/* ===================== Страница вакансии ===================== */

.vpage {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 24px;
  align-items: start;
  padding: 28px 0 52px;
}

/* Колонка отклика прибита к первой строке сетки: без явного места
   авторазмещение уводило её под блок «похожие вакансии», и главная
   кнопка страницы оказывалась ниже экрана. */
.vpage-side {
  grid-column: 2;
  grid-row: 1;
  position: sticky;
  top: calc(var(--chrome-h) + var(--stack));
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Подборка похожих живёт в первой колонке — под описанием вакансии */
.vpage-similar { grid-column: 1; padding-top: 30px; }

.vpage h1 {
  font-family: var(--fd);
  font-weight: 700;
  letter-spacing: -0.01em;
  font-size: clamp(19px, 2.6vw, 26px);
  line-height: 1.25;
}

.vpage .salary-line { font-weight: 700; font-size: 20px; margin-top: 12px; }
.salary-line .accent, .salary .accent { color: var(--brand); }

.meta-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }

.rich h3 {
  font-size: 15.5px;
  font-weight: 700;
  margin: 24px 0 12px;
}

.rich p { margin: 0 0 10px; font-family: var(--f2); font-size: 14.5px; color: var(--text); opacity: 0.85; }

.rich ul {
  margin: 0 0 10px;
  padding-left: 4px;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.rich li { padding-left: 22px; position: relative; font-family: var(--f2); font-size: 14.5px; opacity: 0.85; }

.rich li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 8px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: linear-gradient(135deg, #ff8533, #ff6b00);
}

/* ===================== Компании ===================== */

/* Колонок столько, сколько поместится карточек шириной от 300 точек. Раньше
   стояло жёсткое repeat(3): на экране 2200 точек три карточки растягивались
   до шестисот каждая — под одну строку слогана. */
.co-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--stack);
}

.co-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 22px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

/* ОТРАСЛЬ НАДСТРОЧНИКОМ.

   Она показывалась только при пустом слогане, а слоган заполнен у всех —
   то есть не показывалась никогда. Над названием ей место и по смыслу:
   листая каталог, сначала ищут «кто это вообще», а потом читают имя. */
.co-card .co-field {
  font-family: var(--f2);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-2);
  margin-bottom: -6px;
}

/* Перенос обязателен: знак доверия ушёл в угол, но название компании может
   быть длинным само по себе. */
.co-card .ttl {
  font-weight: 700;
  font-size: 15.5px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 7px;
  padding-right: 8px;
}

.co-card .desc { font-family: var(--f2); font-size: 13px; color: var(--muted); flex: 1; line-height: 1.6; }

.co-facts { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

/* ЗНАК ДОВЕРИЯ — В УГЛУ КАРТОЧКИ.

   position: relative у .co-card обязателен, и не только ради этого знака:
   у карточки есть .dd-lift, который на наведении применяет transform. А
   transform сам создаёт систему отсчёта для absolute — без явного relative
   знак стоял бы в покое от одного предка, а под курсором прыгал бы к
   карточке. Дефект плавающий и на глаз необъяснимый. */
.trust-corner {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 2;
}

/* Логотипу надо оставить место: в углу теперь плашка. */
.co-card .trust-corner + .co-logo { margin-top: 2px; }

/* ===================== Табы ===================== */

.tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 22px;
  overflow-x: auto;
  scrollbar-width: none;
}

.tabs::-webkit-scrollbar { display: none; }

.tabs a, .tabs button {
  padding: 12px 16px;
  font-weight: 600;
  font-size: 14px;
  color: var(--muted);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.tabs a:hover, .tabs button:hover { color: var(--text); }
.tabs a.active, .tabs button.active { color: var(--brand); border-bottom-color: var(--brand); }

/* Счётчик у вкладки — самый низкий шильдик в макете, около 19px, и на нём
   даже --r-pill срезается браузером до полукруга. Держим 7px, как у
   .ri-new: это уже принятая в проекте форма мелкого счётчика. */
.tabs .cnt {
  background: var(--card-2);
  border-radius: 7px;
  font-family: var(--f2);
  font-size: 10px;
  padding: 2px 8px;
  color: var(--muted);
}

.tabs .active .cnt { background: var(--brand-soft); color: var(--brand); }

/* ===================== Кабинеты ===================== */

/* Верх внутренних экранов считается так же, как верх главной: половину шага
   даёт шапка, полтора — сама страница */
/* СВЕРХУ И СНИЗУ ПОРОВНУ.

   Было 30 сверху и 4 снизу — заголовок висел прижатым к тому, что под ним,
   и оторванным от того, что над. Причём тридцатка получалась молча: в
   calc(--stack * 1.5) сам шаг на широком экране подменяется с 16 на 20, и
   отступ вырастал с 24 до 30 без единого правила про заголовок.

   Теперь ровно шаг с обеих сторон: 16 на телефоне, 20 на большом экране.
   Сверху стало меньше, снизу — столько же, сколько сверху. */
.page-head { padding-top: var(--stack); padding-bottom: var(--stack); }
.page-title { font-size: clamp(20px, 2.8vw, 28px); }
.page-sub { color: var(--muted); margin-top: 10px; font-family: var(--f2); font-size: 14px; }

.item-row {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 18px 20px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  flex-wrap: wrap;
}

.item-row { position: relative; }

/* Строка в кабинете открывается нажатием куда угодно — как и карточка
   вакансии. Кнопки действий и ссылки подняты над слоем-ссылкой. */
.row-hit { position: absolute; inset: 0; border-radius: inherit; z-index: 1; }
.item-row .ttl a, .item-row .actions, .item-row .badge,
.item-row .notice, .item-row .chip { position: relative; z-index: 2; }

.item-row .body { flex: 1; min-width: 220px; }

/* НА ТЕЛЕФОНЕ СТРОКА СТАНОВИТСЯ КАРТОЧКОЙ.

   Аватар и текст остаются рядом — так читается «кто и что», — а кнопки
   переезжают вниз на всю ширину. Раньше все трое делили одну строку:
   кнопки наезжали на заголовок, а подпись «город · зарплата · дата»
   ужималась до колонки в одно слово. */
@media (max-width: 700px) {
  .item-row {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    align-items: start;
    gap: 12px;
  }

  .item-row > .body { grid-column: 2; min-width: 0; }
  .item-row:not(:has(> .co-logo)):not(:has(> .avatar)) > .body { grid-column: 1 / -1; }

  .item-row > .actions {
    grid-column: 1 / -1;
    width: 100%;
    justify-content: flex-start;
    flex-wrap: wrap;
    gap: 8px;
  }

  .item-row > .actions > * { flex: 0 1 auto; }
  .item-row .sub { overflow-wrap: anywhere; }
}
.item-row .ttl { font-weight: 700; font-size: 15px; }
.item-row .ttl a:hover { color: var(--brand); }
.item-row .sub { font-family: var(--f2); font-size: 12.5px; color: var(--muted); margin-top: 5px; }
.item-row .actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

a.item-row:hover { box-shadow: var(--shadow-lg); }

.stat-cards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; margin: 18px 0 26px; }

.stat-card {
  padding: 20px 22px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--brand-inset);
}

.stat-card .num { font-family: var(--fnum); font-weight: 700; font-size: 20px; }

.stat-card .lbl {
  font-family: var(--f2);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted-2);
  margin-top: 7px;
}

.stat-card.brand {
  background: var(--ink);
  border: 0;
  color: #fff;
  box-shadow: var(--shadow);
}


.stat-card.brand .num { color: var(--brand-light); }
.stat-card.brand .lbl { color: rgba(255, 255, 255, 0.45); }

/* ===================== Пустые состояния ===================== */

.empty {
  text-align: center;
  padding: 54px 24px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1.5px dashed var(--border-2);
}

.empty-ico {
  width: 52px;
  height: 52px;
  border-radius: 18px;
  background: var(--brand-soft);
  color: var(--brand);
  display: grid;
  place-items: center;
  margin: 0 auto 14px;
}

/* Живая лотти в пустом состоянии — без плитки, крупнее */
.empty-ico.empty-lottie {
  width: 84px;
  height: 84px;
  background: transparent;
  border-radius: 0;
}

.empty-ico.empty-lottie svg { width: 100%; height: 100%; }

/* Значок в цвет надписи рядом — CSS, а не перекраска данных: json разбирается
   один раз и лежит в общем кэше, а тема переключается на лету, и застывший
   цвет остался бы от того мгновения, когда значок собрали. */
.lot-inherit path[fill]:not([fill='none']) { fill: currentColor; }
.lot-inherit path[stroke]:not([stroke='none']) { stroke: currentColor; }
.lot-ico svg { display: block; width: 100%; height: 100%; }
/* Пока плеер не поднялся, в контейнере лежит обычная иконка-фолбэк —
   ей полный размер не нужен, она центрируется как была */
.lot-ico:not(.lot-live) svg { width: auto; height: auto; }
.empty .ttl { font-family: var(--fd); font-weight: 700; font-size: 16px; }
.empty .sub { color: var(--muted); margin-top: 10px; font-family: var(--f2); font-size: 13.5px; }
.empty .btn { margin-top: 18px; }

/* Подключение Telegram в профиле */
.tg-head { display: flex; gap: 12px; align-items: flex-start; color: var(--brand); }
.tg-head b { color: var(--text); font-size: 14.5px; }
.tg-head svg { flex-shrink: 0; margin-top: 2px; }
.tg-state { margin-top: 14px; }

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

/* Один шаг между всеми плашками разговора: шапка, вакансия, лента, поле
   ввода стоят через одинаковый просвет — и такой же просвет остаётся
   сверху и снизу экрана. */
.container.chat-wrap {
  --chat-gap: var(--stack);
  display: flex;
  flex-direction: column;
  gap: var(--chat-gap);
  height: calc(100dvh - var(--chrome-h));
  /* Никакой жёсткой нижней границы: в альбомной ориентации телефона
     высоты 360 точек, и «не меньше 420» выталкивало поле ввода за экран. */
  min-height: 0;
  padding-top: var(--chat-gap);
  padding-bottom: var(--chat-gap);
}

/* В ДИАЛОГЕ ЛИШНЕЙ ОКАЗАЛАСЬ И ШАПКА.

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

   На телефоне это ещё и сотня точек высоты, отобранная у переписки, — то
   есть примерно две реплики, которые человек не видит. */
html.in-chat .tabbar { display: none; }
html.in-chat .footer { display: none; }
/* Прячем саму полосу, а не её содержимое: .header липкая и с заданной
   высотой, так что от спрятанной начинки осталась бы пустая полоса в
   девяносто точек — то самое место, ради которого всё и затевалось. */
html.in-chat .header { display: none; }

/* И сама страница не ездит: двигается только лента сообщений. Иначе экран
   разговора уползает под шапку, а поле ввода уходит за нижний край. */
html.in-chat, html.in-chat body { height: 100dvh; overflow: hidden; }

/* Анимация появления страницы сдвигает содержимое на несколько точек.
   На обычном экране это незаметно, а в диалоге высота считается впритык —
   и поле ввода уезжало за нижнюю кромку ровно на величину сдвига. */
html.in-chat .dd-page-anim { animation: none; transform: none; }
html.in-chat #app { padding: 0; margin: 0; }
/* Высоту диалога берём ОТ РОДИТЕЛЯ, а не расчётом. Цепочка body → #app уже
   занимает ровно то, что осталось от шапки, а расчёт «100dvh минус
   --chrome-h» расходился с фактом на безопасную область и нижнее поле —
   из-за расхождения первый кадр ленты вставал не на своё место. */
html.in-chat .container.chat-wrap { flex: 1; min-height: 0; height: auto; max-height: 100%; }

/* ШАПКА РАЗГОВОРА ВСТАЁТ РОВНО ТУДА, ГДЕ БЫЛА ШАПКА САЙТА.

   Убрав шапку сайта, я оставила разговору общий верхний просвет — и его
   шапка встала на восемь точек ниже. Мелочь, но она читается: переходишь из
   списка в диалог, и всё содержимое дёргается вниз.

   Восемь точек — не выдумка, а замер: плашка шапки сайта стоит на 8, плашка
   разговора стояла на 16. Если шапку сайта когда-нибудь подвинут, это число
   надо перемерить — других способов их связать нет, они на разных экранах. */
html.in-chat .container.chat-wrap { padding-top: 8px; }

/* Цепочка на всю высоту: страница → содержимое → экран диалога */
/* Нижнее поле страницы держит место под доком. В диалоге дока нет, а поле
   оставалось: под полем ввода зияла полоса в сотню точек, и вся цепочка
   высот расходилась с расчётом по --chrome-h. */
html.in-chat body { display: flex; flex-direction: column; padding-bottom: 0; }
html.in-chat #app { flex: 1; min-height: 0; display: flex; flex-direction: column; }
html.in-chat #app > .dd-page-anim { flex: 1; min-height: 0; display: flex; flex-direction: column; }

.chat-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px 10px 10px;
  border-radius: 22px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.chat-back {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 12px;
  background: var(--card-2);
  color: var(--muted);
  transform: rotate(180deg);
  flex-shrink: 0;
}

.chat-who { min-width: 0; flex: 1; }
.chat-who b { display: block; font-size: 14.5px; font-weight: 700; }

/* ОДНА СТРОКА НА ДВЕ НАДПИСИ, И МЕСТО ПОД НЕЁ ДЕРЖИТСЯ ВСЕГДА.

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

   Поэтому строка теперь одна, высота у неё постоянная, а подпись и
   «печатает…» просто сменяют друг друга внутри. Что бы в ней ни лежало и
   лежит ли вообще — шапка не меняется ни на точку. */
.chat-line {
  display: block;
  height: 18px;
  margin-top: 2px;
  overflow: hidden;
}

.chat-who small,
.chat-typing {
  display: block;
  font-family: var(--f2);
  font-size: 12px;
  line-height: 18px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.chat-who small { color: var(--muted); }
/* Цветом, а не серым: это единственная строка в шапке, которая говорит о
   происходящем прямо сейчас. */
.chat-typing { color: var(--brand); }

/* НЕ ТОЧКА, А СЛОВО.

   Здесь был зелёный кружок «связь есть». Стоял он рядом с именем и
   аватаркой собеседника, а в этом месте зелёный кружок во всех
   мессенджерах значит ровно одно — человек в сети. Получалось, что мы
   сообщаем неправду, и собеседник выглядел вечно онлайн.

   Теперь показывается только поломка и только словами: исправная связь —
   не новость, о ней сообщать незачем. */
.chat-live {
  flex-shrink: 0;
  padding: 3px 9px;
  border-radius: var(--r-pill);
  background: var(--warning-soft);
  color: var(--warning);
  font-family: var(--f2);
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}

.chat-vac {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 14px;
  border-radius: 16px;
  background: var(--brand-soft);
  color: var(--brand);
  font-size: 12.5px;
  font-weight: 700;
}

.chat-vac span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-vac-go { margin-left: auto; font-weight: 600; opacity: 0.75; flex-shrink: 0; }

.chat-feed {
  flex: 1;
  /* Флекс-элемент по умолчанию не ужимается ниже своего содержимого — та же
     причина, по которой в сетках пишется minmax(0, 1fr). Без этого лента
     распирает разговор и выталкивает поле ввода за нижнюю кромку. */
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Место под полосу прокрутки держим всегда: иначе первое же длинное
     сообщение сужает ленту на её ширину и весь разговор съезжает вбок. */
  scrollbar-gutter: stable;
  /* Браузерная «якорная» прокрутка спорит с нашей: место под снимок уже
     занято его пропорциями, а низ ленты мы держим сами. */
  overflow-anchor: none;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px;
  border-radius: 24px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.msg {
  max-width: 78%;
  align-self: flex-start;
  padding: 10px 14px;
  border-radius: 20px 20px 20px 6px;
  background: var(--card-2);
}

.msg.mine {
  align-self: flex-end;
  background: var(--ink-2);
  color: #fff;
  border-radius: 20px 20px 6px 20px;
}

/* ПЕРЕНОСЫ СТРОК ОСТАЮТСЯ ТАКИМИ, КАК ИХ НАБРАЛИ.

   Раньше перевод строки подменялся тегом переноса. Одиночный работал, а
   вот пустая строка между абзацами схлопывалась, и отступ, которым человек
   разделил «условия» и «график», пропадал. Список из четырёх пунктов
   приезжал сплошным куском.

   pre-wrap сохраняет и переносы, и пустые строки, и ведущие пробелы — то
   есть ровно то, что набрали, — но по-прежнему переносит длинные строки по
   ширине пузыря. */
.msg-body {
  font-family: var(--f2);
  font-size: 14px;
  line-height: 1.5;
  word-break: break-word;
  white-space: pre-wrap;
}

/* Спрятано от глаз, но не от экранного диктора. display:none и
   visibility:hidden убирают содержимое и из его дерева тоже — поэтому
   прячем размером и обрезкой. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.msg-meta { font-size: 10.5px; margin-top: 4px; color: var(--muted-2); }
.msg.mine .msg-meta { color: rgba(255, 255, 255, 0.6); }

.msg-day, .msg-system {
  align-self: center;
  font-family: var(--f2);
  font-size: 11.5px;
  color: var(--muted-2);
  padding: 6px 0;
}

.chat-empty { margin: auto; text-align: center; padding: 20px; }
.chat-empty .ttl { font-family: var(--fd); font-weight: 700; font-size: 15px; }
.chat-empty .sub { font-family: var(--f2); font-size: 13px; color: var(--muted); margin-top: 8px; max-width: 340px; }
.chat-loading { padding: 40px 0; text-align: center; color: var(--muted); }

.chat-form {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 8px;
  border-radius: 24px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--brand-inset);
}

.chat-form textarea {
  flex: 1;
  min-width: 0;
  resize: none;
  border: 0;
  outline: none;
  background: transparent;
  font: inherit;
  font-family: var(--f2);
  font-size: 14.5px;
  line-height: 1.45;
  color: var(--text);
  padding: 11px 12px;
  max-height: 140px;
}

.chat-form textarea::placeholder { color: var(--muted-2); }

.chat-send {
  width: 46px;
  height: 46px;
  padding: 0;
  border-radius: 18px;
  flex-shrink: 0;
}

/* ============ Вложения в переписке ============ */

.msg.bare { padding: 6px; }
.msg-photos { display: grid; gap: 4px; margin-bottom: 6px; }
.msg-photos.grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.msg-photo {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: 14px;
  overflow: hidden;
  background: var(--card-2);
  cursor: zoom-in;
  /* Место под картинку резервируем по её пропорциям: без этого лента
     дёргается каждый раз, когда снимок догружается */
  aspect-ratio: 1 / var(--ratio, 0.7);
  max-height: 320px;
}

.msg-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.msg-photo.failed { display: grid; place-items: center; min-height: 90px; }
.msg-photo.failed::after { content: 'Файл недоступен'; font-size: 12px; color: var(--muted); }

.msg-file {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: 14px;
  background: rgba(0, 0, 0, 0.05);
  margin-bottom: 6px;
}

.msg.mine .msg-file { background: rgba(255, 255, 255, 0.14); }


/* ЗВУК И ВИДЕО ВНУТРИ ПУЗЫРЯ.

   Проигрыватель рисует браузер, и выглядит он у каждого свой. Спорить с
   ним не пытаемся — задаём только ширину, углы и подпись под ним: чужая
   вёрстка, натянутая на системный элемент, ломается на первом же
   обновлении браузера, а голосовое должно играть всегда. */
.msg-audio, .msg-video { margin-bottom: 6px; }
.msg-audio audio { width: 100%; min-width: 210px; max-width: 280px; height: 38px; display: block; }
.msg-video video {
  width: 100%;
  max-width: 320px;

  /* МЕСТО ПОД РОЛИК ЗАДАНО ЗАРАНЕЕ И НЕ МЕНЯЕТСЯ НИКОГДА.

     Замерено на боевой странице: пустой <video> браузер рисует своим
     умолчанием — триста на полтораста точек. Как только приезжает заголовок
     файла, элемент берёт настоящие пропорции и вырастает до трёхсот
     восьмидесяти. Двести тридцать точек посреди уже собранной ленты — это и
     есть тот самый скачок.

     Заголовок десятимегабайтного ролика на мобильной сети приезжает через
     несколько секунд, то есть намного позже, чем лента встала на место. К
     этому моменту сторожа сняты, и человек просто видит, как разговор
     поехал.

     ОТСЮДА ДВА ПРАВИЛА.

     Первое: соотношение сторон — величина ПОСТОЯННАЯ, а не «auto». С «auto»
     коробка всё равно перестраивается, когда пропорции становятся известны:
     вертикальный ролик с телефона — это девять к шестнадцати, и он бы
     подскочил ровно так же, только позже и сильнее.

     Второе: если ширина и высота ролика известны из записи вложения, они
     приходят сюда переменной --vratio ещё до отрисовки — тогда коробка сразу
     верная. Не известны (все ролики, отправленные до этой правки) — держим
     четыре к трём и вписываем кадр целиком.

     object-fit: contain, а не cover: обрезать чужое видео по краям мы права
     не имеем, а чёрные поля вокруг кадра — то, к чему человек привык в любом
     проигрывателе. */
  aspect-ratio: 1 / var(--vratio, 0.75);
  object-fit: contain;
  border-radius: 14px;
  background: #000;
  display: block;
}
/* НИ У ЗВУКА, НИ У ВИДЕО ПОДПИСИ НЕТ.

   Под проигрывателем стояла строка с именем файла и его весом. У
   голосового имя мы придумали сами в момент записи, у ролика с телефона
   оно выглядит как «copy_B5196742-7F05-4500-BF5F-5151E2BEBB02.mov», а вес
   не говорит человеку ничего ни в том, ни в другом случае. Длительность и
   так стоит в самом проигрывателе.

   Оставалась строка, которую незачем читать, — и она же занимала место в
   пузыре и лишний раз переносилась на узком экране. Имя файла по-прежнему
   хранится в записи вложения: оно нужно при скачивании, а не на экране.

   У обычных документов подпись, наоборот, единственное, что есть: там
   имя — это и содержимое (см. .msg-file ниже). */

/* Ссылка протухла или файл не отдался — говорим об этом словами, а не
   пустым чёрным прямоугольником. */
.msg-audio.failed audio, .msg-video.failed video { display: none; }
.msg-audio.failed::after, .msg-video.failed::after {
  content: 'Файл недоступен';
  font-size: 12px;
  color: var(--muted);
}

.mf-ico { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 11px; background: var(--brand-soft); color: var(--brand); flex-shrink: 0; }
.msg.mine .mf-ico { background: rgba(255, 255, 255, 0.16); color: #fff; }
.mf-body { min-width: 0; }
.mf-body b { display: block; font-size: 13px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mf-body small { display: block; font-size: 11.5px; opacity: 0.7; margin-top: 2px; }

/* Выбранные, но ещё не отправленные */
.chat-draft { display: flex; gap: 8px; flex-wrap: wrap; padding: 0 4px; }
/* Атрибут hidden сам по себе слабее правила display — без этого пустая
   плашка вложений не видна, но продолжает занимать свой шаг в сетке, и
   просвет над полем ввода становится вдвое больше остальных. */
.chat-draft[hidden] { display: none; }

.draft-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border-radius: 14px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  font-size: 12px;
  max-width: 220px;
}

.draft-item img,
.draft-item video { width: 28px; height: 28px; border-radius: 8px; object-fit: cover; background: #000; }
.di-ico { color: var(--brand); display: grid; place-items: center; }
.di-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.di-size { color: var(--muted-2); flex-shrink: 0; }
.di-x { border: 0; background: transparent; color: var(--muted); padding: 2px; cursor: pointer; display: grid; place-items: center; }
.di-x:hover { color: var(--danger); }

.chat-clip {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 16px;
  color: var(--muted);
  cursor: pointer;
  flex-shrink: 0;
  transition: color var(--dur-fast), background-color var(--dur-fast);
}

.chat-clip:hover { color: var(--brand); background: var(--brand-soft); }

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

   ДОЛГОЕ НАЖАТИЕ БРАУЗЕР ПОНИМАЕТ ПО-СВОЕМУ.

   Палец, задержанный на кнопке, на телефоне означает «выделить и показать
   меню»: всплывает «скопировать», значок подсвечивается синим, а запись при
   этом идёт. Гасим всё три способами сразу — они закрывают разные движки. И
   отбираем у браузера сам жест: без touch-action он на первом же движении
   пальца решит, что это прокрутка, отберёт указатель и оборвёт запись — а
   увести палец в сторону нам нужно, это отмена. */
.chat-mic {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  flex-shrink: 0;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  transition: color var(--dur-fast), background-color var(--dur-fast);
}

.chat-mic:hover { color: var(--brand); background: var(--brand-soft); }

/* Кнопка эмодзи — того же вида, что скрепка и микрофон: три кнопки вокруг
   поля ввода должны выглядеть одним рядом, а не тремя разными идеями. */
.chat-emo {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  flex-shrink: 0;
  transition: color var(--dur-fast), background-color var(--dur-fast);
}

.chat-emo:hover, .chat-emo[aria-expanded='true'] { color: var(--brand); background: var(--brand-soft); }

/* Панель стоит НАД полем ввода, а не поверх ленты: перекрывать разговор,
   в который человек как раз отвечает, — плохая идея. Высота ограничена,
   дальше прокрутка: на невысоком экране панель во весь рост не оставила бы
   от переписки ничего. */
.chat-emoji {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  gap: 2px;
  max-height: 180px;
  overflow-y: auto;
  padding: 8px;
  margin: 0 4px 6px;
  border-radius: 16px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
}

.chat-emoji[hidden] { display: none; }

.emo {
  border: 0;
  background: transparent;
  font-size: 20px;
  line-height: 1;
  padding: 5px 0;
  border-radius: 9px;
  cursor: pointer;
}

.emo:hover { background: var(--brand-soft); }
.emo:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

@media (max-width: 420px) {
  /* На узком экране символы становятся мельче, но их остаётся девять в
     ряд: перескакивать с девяти на шесть значит менять всю раскладку
     панели под пальцем. */
  .emo { font-size: 18px; }
}
.chat-mic[hidden] { display: none; }
.chat-mic.recording { color: #fff; background: var(--danger); }

/* Полоса записи. Красная точка мигает, потому что это единственное место
   на экране, где нужно сказать «прямо сейчас идёт запись микрофона» —
   такое сообщение обязано быть заметным. */
.chat-rec {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 8px 12px;
  margin: 0 4px 6px;
  border-radius: 14px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  font-size: 13px;
}

.cr-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--danger);
  flex-shrink: 0;
  animation: cr-pulse 1.1s ease-in-out infinite;
}

.cr-text { font-weight: 600; }
.cr-time { font-family: var(--f2); color: var(--muted); font-variant-numeric: tabular-nums; margin-left: auto; }
.cr-x {
  border: 0;
  background: transparent;
  color: var(--danger);
  font: inherit;
  font-weight: 700;
  font-size: 12.5px;
  cursor: pointer;
  padding: 2px 4px;
}

/* ЖЕСТ, О КОТОРОМ НЕ НАПИСАНО, ДЛЯ ЧЕЛОВЕКА НЕ СУЩЕСТВУЕТ.

   Запись идёт, пока кнопку держат, и до кнопки «Отменить» пальцем в этот
   момент не дотянуться. Отменяют так же, как в мессенджерах, — уводом
   пальца в сторону, но догадаться об этом неоткуда. Поэтому подсказка стоит
   прямо в полосе записи, своей строкой, и меняется на «отпустите», как
   только палец действительно уехал. */
.cr-hint {
  flex-basis: 100%;
  font-family: var(--f2);
  font-size: 11.5px;
  color: var(--muted);
}

.chat-rec.cancel { border-color: var(--danger); }
.chat-rec.cancel .cr-text { color: var(--danger); }
.chat-rec.cancel .cr-hint { color: var(--danger); font-weight: 700; }

@keyframes cr-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}

@media (prefers-reduced-motion: reduce) {
  .cr-dot { animation: none; }
}

/* Перетаскивание файла на диалог */
/* Цель перетаскивания подсвечиваем заливкой и подъёмом — рамка вокруг
   всей ленты сообщений была самым громким пятном на экране */
.chat-wrap.dropping .chat-feed {
  background: linear-gradient(0deg, var(--brand-soft), var(--brand-soft)), var(--card);
  box-shadow: var(--shadow-lg);
}

.msg-sending {
  align-self: stretch;
  padding: 10px 14px;
  border-radius: 14px;
  background: var(--card-2);
  font-size: 12.5px;
  color: var(--muted);
}

.ms-bar { display: block; height: 4px; border-radius: 2px; background: var(--border); margin-top: 8px; overflow: hidden; }
.ms-bar i { display: block; height: 100%; width: 3%; background: var(--brand); transition: width 0.2s linear; }

/* Просмотр фотографии */
.photo-view {
  position: fixed;
  inset: 0;
  z-index: 130;
  background: rgba(0, 0, 0, 0.9);
  display: grid;
  place-items: center;
  padding: 40px 16px;
  animation: dd-fade 0.2s var(--ez);
}

.photo-view img { max-width: 100%; max-height: 100%; border-radius: 12px; }

.pv-close, .pv-save {
  position: absolute;
  top: 16px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 14px;
  border-radius: 14px;
  border: 0;
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  backdrop-filter: blur(10px);
}

.pv-close { right: 16px; width: 42px; height: 42px; padding: 0; justify-content: center; }
.pv-save { left: 16px; }
.pv-close:hover, .pv-save:hover { background: rgba(255, 255, 255, 0.24); }

/* ============ Уведомление внутри приложения ============ */

/* УВЕДОМЛЕНИЯ ЖИВУТ ВНИЗУ.

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

   Внизу свободно: дока в диалоге нет вовсе, а на остальных экранах место
   над ним мы держим отступом. И палец там ближе — уведомление нажимают
   сразу, а не тянутся через весь экран. */
.inapp-root {
  position: fixed;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 14px);
  right: 14px;
  z-index: 140;
  display: flex;
  flex-direction: column-reverse;
  gap: 8px;
  pointer-events: none;
}

/* Док внизу занимает своё место — поднимаем карточки над ним. В диалоге
   дока нет, и подниматься не над чем. */
body:has(.tabbar) .inapp-root { bottom: calc(env(safe-area-inset-bottom, 0px) + var(--плита) + 28px); }
html.in-chat .inapp-root { bottom: calc(env(safe-area-inset-bottom, 0px) + 14px); }

.inapp {
  display: flex;
  align-items: center;
  gap: 12px;
  width: min(360px, calc(100vw - 28px));
  padding: 12px 14px;
  border-radius: 22px;
  background: var(--header-bg);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg), var(--brand-inset);
  pointer-events: auto;
  touch-action: pan-y;
}

.inapp.leaving { animation: inapp-out 0.24s var(--ez) forwards; }

@keyframes inapp-out {
  to { opacity: 0; transform: translateX(16px) scale(0.97); }
}

/* Карточка приезжает снизу — оттуда, где теперь живёт. */
.inapp.dd-pop { animation: inapp-in 0.26s var(--ez) both; }

@keyframes inapp-in {
  from { opacity: 0; transform: translateY(14px) scale(0.97); }
  to { opacity: 1; transform: none; }
}

.ia-ava { flex-shrink: 0; }
.ia-body { flex: 1; min-width: 0; }
.ia-body b { display: block; font-size: 13.5px; font-weight: 700; }

.ia-text {
  display: block;
  font-family: var(--f2);
  font-size: 12.5px;
  color: var(--muted);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ia-go { flex-shrink: 0; font-size: 12.5px; font-weight: 700; color: var(--brand); }

@media (max-width: 760px) {
  .inapp-root { right: 10px; left: 10px; }
  .inapp { width: auto; }
  .msg-photo { max-height: 240px; }
}

/* Список диалогов */
.chat-list { display: flex; flex-direction: column; gap: 10px; }

.chat-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-radius: 22px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.chat-row:hover { box-shadow: var(--shadow-lg); }
.chat-row-body { flex: 1; min-width: 0; }
.chat-row-top { display: flex; align-items: baseline; gap: 8px; }
.chat-row-top b { font-size: 14.5px; font-weight: 700; }
.chat-row-time { margin-left: auto; font-size: 11.5px; color: var(--muted-2); flex-shrink: 0; }
.chat-row-vac { font-family: var(--f2); font-size: 12px; color: var(--brand); margin-top: 2px; }
.chat-row-last {
  font-family: var(--f2);
  font-size: 13px;
  color: var(--muted);
  margin-top: 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-row-unread {
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  /* 11px тут — ровно половина высоты: на однозначном числе выходил круг,
     на двузначном — пилюля. 8px оставляют счётчик прямоугольным. */
  border-radius: 8px;
  background: var(--brand);
  color: #fff;
  font-size: 11.5px;
  font-weight: 700;
  display: grid;
  place-items: center;
  flex-shrink: 0;
}

@media (max-width: 760px) {
  /* Без дока внизу диалогу достаётся вся высота, минус шапка сайта */

  .msg { max-width: 86%; }
}

/* ===================== Модалки ===================== */

/* Прокручивается оверлей, а не само окно: при длинной форме кнопка внизу
   оказывалась за краем экрана, а шторка позади заканчивалась на середине. */
.modal-root {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: safe center;
  padding: 20px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.modal-root .backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(5px);
  animation: dd-fade 0.22s var(--ez) both;
}

.modal {
  position: relative;
  /* Растягиваем явно: в центрирующей сетке элемент иначе ужимается по
     содержимому, и на телефоне окно выходило заметно уже экрана. Но
     stretch отменяет центрирование, и на широком экране окно прилипало
     к левому краю — поля возвращаем сами. */
  justify-self: stretch;
  width: 100%;
  max-width: 520px;
  margin-inline: auto;
  max-height: calc(100dvh - 48px);
  overflow-y: auto;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-lg);
  padding: 28px;
  animation: dd-pop 0.34s var(--ez-spring) both;
}

.modal h3 {
  font-family: var(--fd);
  font-weight: 700;
  font-size: 17px;
  margin-bottom: 8px;
  padding-right: 40px;
  line-height: 1.35;
}

/* Выход модалки — зеркало входа */
.modal-root.leaving .backdrop { animation: dd-fade 0.2s var(--ez) reverse both; }
.modal-root.leaving .modal { animation: modal-out 0.2s var(--ez) both; }

@keyframes modal-out {
  to { opacity: 0; transform: scale(0.94) translateY(8px); }
}

.modal .close {
  position: absolute;
  top: 18px;
  right: 18px;
  width: 36px;
  height: 36px;
  border-radius: 13px;
  display: grid;
  place-items: center;
  background: var(--card-2);
  color: var(--muted);
}

.modal .close:hover { color: var(--danger); background: var(--danger-soft); }

/* ===================== Тосты ===================== */

.toasts {
  position: fixed;
  bottom: 22px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 120;
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: center;
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: center;
  gap: 10px;
  background: linear-gradient(135deg, #3f3f46 0%, #18181b 100%);
  color: #fff;
  padding: 13px 22px;
  border-radius: var(--r-btn);
  font-weight: 700;
  font-size: 13px;
  box-shadow: var(--shadow-lg), inset 0 1px 1px rgba(255, 255, 255, 0.15);
  animation: dd-pop 0.34s var(--ez-spring) both;
  max-width: min(92vw, 480px);
}

.toast.leaving { animation: toast-out 0.25s var(--ez) both; }
@keyframes toast-out { to { opacity: 0; transform: translateY(12px) scale(0.95); } }
.toast .t-ico { color: var(--brand-light); display: grid; place-items: center; }

/* ===================== Auth ===================== */

.auth-wrap { max-width: 470px; margin: 44px auto 64px; padding: 0 20px; }

.auth-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-widget);
  box-shadow: var(--brand-inset);
  padding: 32px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.auth-card h1 { font-family: var(--fd); font-weight: 700; font-size: 20px; }

.demo-plate {
  background: var(--ink);
  color: #fff;
  border-radius: var(--r-inner);
  padding: 16px 18px;
  font-size: 13px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}


.demo-plate b { font-size: 13px; color: rgba(255, 255, 255, 0.65); }
.demo-plate .row { display: flex; gap: 8px; flex-wrap: wrap; }
.demo-plate .btn-ghost { background: rgba(255, 255, 255, 0.08); border-color: rgba(255, 255, 255, 0.15); color: #fff; box-shadow: none; }
.demo-plate .btn-ghost:hover { background: rgba(255, 255, 255, 0.16); color: var(--brand-light); }

/* ===================== Футер ===================== */

.footer {
  margin-top: 44px;
  border-top: 1px solid var(--border);
  padding: 44px 0 48px;
  background: var(--card);
}


.footer-in { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: 28px; }

.footer .about { font-family: var(--f2); font-size: 12.5px; color: var(--muted); margin-top: 14px; max-width: 260px; line-height: 1.7; }

.footer h4 {
  font-size: 13px;
  font-weight: 700;
  color: var(--muted-2);
  margin-bottom: 14px;
}

.footer ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.footer a { font-family: var(--f2); font-size: 13px; font-weight: 600; color: var(--muted); }
.footer a:hover { color: var(--brand); }

.footer-bottom {
  margin-top: 34px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  font-family: var(--f2);
  font-size: 11.5px;
  color: var(--muted-2);
}

/* ===================== Резюме ===================== */

.res-exp { display: flex; flex-direction: column; gap: 14px; }

.res-exp .job {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: 14px;
  padding: 14px 0;
  border-top: 1px solid var(--border);
}

.res-exp .job:first-child { border-top: 0; }
.res-exp .period { font-family: var(--f2); font-size: 12px; color: var(--muted-2); font-weight: 700; }
.res-exp .role { font-weight: 700; }
.res-exp .at { font-family: var(--f2); font-size: 13px; color: var(--muted); margin-top: 2px; }
.res-exp .desc { font-family: var(--f2); font-size: 13px; margin-top: 6px; color: var(--muted); }

/* Строки-указатели */
.index-row {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 15px 16px;
  border-radius: 18px;
  font-weight: 700;
}

.index-row::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 18px;
  transform: scaleX(0);
  transform-origin: left center;
  background: linear-gradient(90deg, var(--brand-soft), transparent 85%);
  transition: transform 0.45s var(--ez);
}

.index-row:hover::before { transform: scaleX(1); }
.index-row .arr { margin-left: auto; color: var(--muted-2); }
.index-row:hover .arr { color: var(--brand); }

/* ===================== Разное ===================== */

.divider-h { height: 1px; background: var(--border); border: 0; margin: 18px 0; }

.notice {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 14px 16px;
  border-radius: 18px;
  background: var(--info-soft);
  font-family: var(--f2);
  font-size: 13px;
  line-height: 1.55;
}

.notice.warn { background: var(--warning-soft); }
.notice.brand { background: var(--brand-soft); }

/* B2B-плашка — тёмный графит с оранжевым CTA */
.cta-employer {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-widget);
  background: var(--ink);
  color: #fff;
  padding: 44px 46px;
  display: flex;
  align-items: center;
  gap: 30px;
  flex-wrap: wrap;
  box-shadow: var(--shadow-lg);
}


.cta-employer::before {
  content: '';
  position: absolute;
  width: 380px;
  height: 380px;
  right: -110px;
  top: -190px;
  border-radius: 50%;
  filter: blur(80px);
  background: rgba(255, 107, 0, 0.22);
  pointer-events: none;
}

.cta-employer h2 {
  font-family: var(--fd);
  font-weight: 700;
  letter-spacing: -0.01em;
  font-size: clamp(19px, 2.6vw, 25px);
  max-width: 520px;
  position: relative;
}

.cta-employer p { margin-top: 12px; font-family: var(--f2); color: rgba(255, 255, 255, 0.6); max-width: 460px; position: relative; }
.cta-employer .btn { position: relative; }

/* ===================== Профиль ===================== */

.profile-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 18px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--brand-inset);
  margin-bottom: 14px;
  max-width: 560px;
}

.profile-menu {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  max-width: 560px;
}

.profile-menu .index-row { padding: 13px 12px; font-size: 13.5px; }

.profile-menu .index-row .ico {
  width: 36px;
  height: 36px;
  border-radius: 13px;
  display: grid;
  place-items: center;
  background: var(--card-2);
  color: var(--muted);
  flex-shrink: 0;
}

.profile-menu .index-row:hover .ico { background: var(--brand-soft); color: var(--brand); }
.profile-menu .index-row.danger { color: var(--danger); }
.profile-menu .index-row.danger .ico { background: var(--danger-soft); color: var(--danger); }

/* ===================== Адаптив ===================== */

@media (max-width: 1000px) {
  .cat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cat-tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .co-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .vac-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .stat-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .vpage { grid-template-columns: 1fr; }
  .vpage-side { grid-column: 1; grid-row: auto; position: static; order: 2; }
  /* На узком экране подборка уходит в самый низ: сначала вакансия и отклик */
  .vpage-similar { order: 3; padding-top: 8px; }
  .footer-in { grid-template-columns: repeat(2, minmax(0, 1fr)); }

}

@media (max-width: 760px) {
  body { font-size: 14.5px; }

  .container { padding: 0 16px; }
  .nav { display: none; }
  .burger { display: grid; }
  .header-actions .btn-header-auth { display: none; }
  .header-actions { gap: 8px; }
  .header { padding: 8px 0 4px; }
  :root { --chrome-h: 76px; }
  .header-plate { gap: 12px; padding: 8px 8px 8px 14px; }
  .user-chip .name { display: none; }
  .user-chip { padding: 4px; }
  .user-chip svg:last-child { display: none; }

  /* Вертикальный ритм на телефоне не переопределяем: --stack здесь и так 16,
     а собственные 8 и 24 точки и давали ту самую слипшуюся ленту — 14 точек
     до поиска против 48 между секциями. Размеры шрифта остаются своими. */
  .hero-badge { margin-bottom: 14px; font-size: 12.5px; }
  .hero-title { font-size: clamp(24px, 7.6vw, 32px); }
  .hero-sub { font-size: 13.5px; margin-top: 12px; }

  .hero-chips { margin-top: 14px; }

  .section-head { margin-bottom: 14px; }
  /* Ужимать низ отдельно больше не надо: он равен верху, а верх на телефоне
     и так меньше — шаг там 16, а не 20. */

  .vac-grid { grid-template-columns: 1fr; }
  /* На узком экране заголовок секции и ссылка не делят одну строку */
  .section-head { flex-wrap: wrap; gap: 6px 14px; }
  .section-link { font-size: 13px; }

  .cat-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .cat-tile { padding: 9px 12px 9px 9px; border-radius: 20px; gap: 9px; }
  .cat-tile .ico { width: 30px; height: 30px; border-radius: 11px; }
  .cat-tile b { font-size: 12px; }
  .cat-tile small { font-size: 11px; }
  .form-grid { grid-template-columns: 1fr; }
  .form-grid .span2 { grid-column: span 1; }

  .cta-employer { padding: 28px 22px; }
  .res-exp .job { grid-template-columns: 1fr; gap: 4px; }
  .modal-root { padding: 16px; }
  .modal { padding: 22px; border-radius: 26px; }
  .card-pad { padding: 18px; }

  .cat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .co-grid { grid-template-columns: 1fr; }

  .item-row { padding: 16px; gap: 12px; }
  .item-row .actions { width: 100%; }
  .jobs-toolbar .sort { margin-left: 0; width: 100%; justify-content: flex-start; }

  .auth-wrap { margin: 22px auto 40px; padding: 0 16px; }
  .auth-card { padding: 22px; }

  .footer { padding: 32px 0 36px; }
  .marquee-track span { padding: 12px 16px; font-size: 10px; }
}

/* Совсем узкие экраны: две плитки в ряд режут названия направлений */
@media (max-width: 390px) {
  .cat-tiles { grid-template-columns: 1fr; }
}

@media (max-width: 460px) {
  .cat-grid { grid-template-columns: 1fr; }
  .stat-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .stat-card { padding: 14px 16px; }
  .stat-card .num { font-size: 20px; }
  .footer-in { grid-template-columns: 1fr; }
}

/* Прокрутка */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb {
  background: rgba(128, 128, 128, 0.35);
  border-radius: 99px;
  border: 3px solid var(--bg);
}
::-webkit-scrollbar-track { background: transparent; }


/* ===================== Док-навигация (прямо из приложения DVOR) =====================
   Два стеклянных блока: основной (три вкладки) и отдельный квадрат профиля.
   Активная вкладка — тёмная стеклянная пилюля, иконка в бренде. */

.tabbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  z-index: 80;
  display: none;
  justify-content: center;
  padding: 0 16px;
  pointer-events: none;
}

html[data-tg='1'] .tabbar { display: flex; }
@media (max-width: 760px) { .tabbar { display: flex; } }

.dock { display: flex; gap: 12px; width: 100%; max-width: 420px; pointer-events: auto; }

.dock-main, .dock-profile {
  position: relative;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.35);
  backdrop-filter: blur(40px);
  -webkit-backdrop-filter: blur(40px);
  border: 1px solid rgba(255, 255, 255, 0.6);
  box-shadow:
    0 8px 32px rgba(0, 0, 0, 0.14),
    0 4px 8px rgba(0, 0, 0, 0.07),
    inset 0 1px 0 rgba(255, 255, 255, 0.6),
    inset 0 -1px 0 rgba(0, 0, 0, 0.04);
}

.dock-main::before, .dock-profile::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0.5), transparent);
  pointer-events: none;
}


.dock-main {
  flex: 1;
  height: var(--плита);
  border-radius: var(--плита-радиус);
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* Профиль — той же формы, что и вкладка поиска рядом. Круг выбивался из
   ряда: в доке четыре кнопки, и одна из них не должна выглядеть деталью из
   другого набора. */
.dock-profile { width: var(--плита); height: var(--плита); border-radius: var(--плита-радиус); flex-shrink: 0; }

.dock a {
  flex: 1;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  color: #71717a;
  transition: color 0.25s var(--ez);
}


.dock-profile a { width: 100%; }

/* ВЫБРАННЫЙ ПРОФИЛЬ ТЕМНЕЕТ ТОЙ ЖЕ ФОРМОЙ.

   У вкладок выбранную показывает тёмная подложка; профиль стоял отдельной
   кнопкой и не показывал ничего — по доку нельзя было понять, что открыт
   именно он.

   Заливка повторяет форму белой плиты и отступает от неё на две точки с
   каждой стороны: светлый кант остаётся видимым, и кнопка не выглядит
   просто перекрашенной. */
.dock-profile a.active::before {
  content: '';
  position: absolute;
  inset: 2px;
  border-radius: calc(var(--плита-радиус) - 2px);
  background: rgba(24, 24, 27, 0.75);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  border: 1px solid rgba(255, 255, 255, 0.15);
  animation: dd-pop 0.34s var(--ez-spring) both;
}
.dock a.active { color: var(--brand); }

/* ТЁМНАЯ ПОДЛОЖКА ПЕРЕЕЗЖАЕТ МЕЖДУ ВКЛАДКАМИ.

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

   Пружинное замедление даёт лёгкий недолёт-перелёт: подложка приходит
   чуть дальше и возвращается. Это и есть разница между «переехала» и
   «переставили».

   Ширина едет вместе со сдвигом: вкладки бывают разной ширины, и без
   этого подложка меняла бы размер рывком в конце пути. */
.dock .pill {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 0;
  width: 0;
  /* Подложка лежит внутри плиты с отступом в 4 точки — и скругление у неё
     ровно на эти 4 точки меньше, иначе угол внутри угла смотрится кривым. */
  border-radius: calc(var(--плита-радиус) - 4px);
  background: rgba(24, 24, 27, 0.75);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  border: 1px solid rgba(255, 255, 255, 0.15);
  opacity: 0;
  transform: translateX(0);
  transition:
    transform 0.52s var(--ez-spring),
    width 0.52s var(--ez-spring),
    opacity 0.24s var(--ez);
  will-change: transform, width;
}

.dock .pill.видна { opacity: 1; }


.dock .tb-wrap { position: relative; z-index: 1; transition: transform 0.52s var(--ez-spring); }
.dock a:active .tb-wrap { transform: scale(0.82); }
/* ЗНАЧОК НЕ ПРЫГАЕТ.

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

   Осталось одно: значок поднимается на точку, тем же временем и той же
   плавностью, что и подложка. Всё заметное делает она. */
.dock a.active .tb-wrap { transform: translateY(-1px); }
.dock .tb-wrap svg { width: 27px; height: 27px; }

.dock .tb-dot {
  position: absolute;
  top: -6px;
  right: -9px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--r-pill);
  background: #ef4444;
  color: #fff;
  font-size: 10px;
  font-style: normal;
  font-weight: 700;
  display: grid;
  place-items: center;
  border: 2px solid #fff;
  z-index: 2;
}


@media (max-width: 760px) {
  body { padding-bottom: calc(var(--плита) + 36px + env(safe-area-inset-bottom, 0px)); }
}

/* ===================== Плашки главной (из приложения DVOR) ===================== */

/* Погода и курс: оранжевая подложка + две белые карточки */
.info-plate {
  padding: 8px;
  border-radius: 36px;
  background: linear-gradient(135deg, rgba(255, 107, 0, 0.18), rgba(255, 107, 0, 0.08) 45%, var(--card));
  border: 1px solid rgba(255, 107, 0, 0.25);
  box-shadow: var(--brand-inset);
  display: flex;
  gap: 8px;
  margin-top: 26px;
  max-width: 640px;
}

/* Виджет самым верхом главной — до заголовка, как в приложении */
.info-plate-top { margin-top: 0; margin-bottom: var(--stack); }

.info-card {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  border-radius: 28px;
  padding: 12px;
  min-width: 0;
}

.info-card.right { justify-content: space-between; }

.info-circ {
  width: 36px;
  height: 36px;
  border-radius: var(--r-pill);
  display: grid;
  place-items: center;
  background: var(--brand-soft);
  color: var(--brand);
  flex-shrink: 0;
}

.info-circ.green { background: rgba(16, 185, 129, 0.1); color: #10b981; }

/* ═════ ВИДЖЕТ ЖИВЁТ ПОСТОЯННО ═════

   Погода и курс — единственное на странице, что меняется само по себе,
   без участия человека. Неподвижный значок этого не показывает: виджет
   выглядел снимком, сделанным неизвестно когда.

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

   Погода: у каждого состояния своё движение и другого быть не может —
   солнце крутится, облако плывёт, дождь капает. Значок и движение
   говорят одно и то же, и второе читается быстрее первого.

   Курс: одна и та же анимация всегда, какой бы ни была цифра. Разное
   движение на росте и падении означало бы оценку, а мы курс не
   комментируем — мы его показываем. */

.info-circ svg { display: block; transform-box: fill-box; transform-origin: 50% 50%; }

.wx-sun svg { animation: wx-солнце 24s linear infinite; }
@keyframes wx-солнце { to { transform: rotate(360deg); } }

.wx-cloud svg { animation: wx-облако 7s var(--ez) infinite; }
@keyframes wx-облако {
  0%, 100% { transform: translateX(-1.2px); }
  50% { transform: translateX(1.2px); }
}

/* Тучу оставляем на месте, падают только три чёрточки — второй путь в
   значке. Двигать вместе с тучей было бы неправдой: дождь идёт из неё, а
   не вместе с ней. */
.wx-rain svg > path:nth-of-type(2) {
  transform-box: fill-box;
  transform-origin: 50% 0;
  animation: wx-капли 1.4s linear infinite;
}
@keyframes wx-капли {
  0% { transform: translateY(-2.4px); opacity: 0; }
  30% { opacity: 1; }
  100% { transform: translateY(2.8px); opacity: 0; }
}

.info-circ.green svg { animation: wx-курс 5.2s var(--ez) infinite; }
@keyframes wx-курс {
  0%, 66%, 100% { transform: translateY(0) scale(1); }
  76% { transform: translateY(-1.7px) scale(1.06); }
  88% { transform: translateY(0.7px) scale(0.98); }
}


.info-lbl {
  display: flex;
  align-items: center;
  gap: 4px;
  font-family: var(--f2);
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-2);
  margin-bottom: 4px;
  white-space: nowrap;
}

.info-val { font-weight: 700; font-size: 14px; line-height: 1; white-space: nowrap; letter-spacing: 0.01em; }
.info-sub { font-size: 11px; font-weight: 700; color: var(--muted); margin-top: 4px; line-height: 1; }

/* Плашка поиска: две подложки — инпут и квадратная кнопка btn-brand */
.search-plate {
  display: flex;
  gap: 8px;
  align-items: stretch;
  position: relative;
  margin-top: 12px;
  max-width: 640px;
  z-index: 40;
}

.sp-pod {
  padding: 8px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--brand-inset);
  border-radius: 32px;
  flex-shrink: 0;
}

.sp-pod.grow { flex: 1; min-width: 0; }

.sp-input-in {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 16px;
  height: 52px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  border-radius: 24px;
  transition: box-shadow 0.3s var(--ez);
}

.sp-input-in:focus-within { box-shadow: var(--shadow), 0 0 0 2px rgba(255, 107, 0, 0.18); }

.sp-input-in input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: 0;
  outline: none;
  font: inherit;
  font-size: 15px;
  font-weight: 500;
  color: var(--text);
}

.sp-input-in input::placeholder { color: var(--muted-2); }

.sp-btn {
  width: 52px;
  height: 52px;
  border-radius: 24px;
  display: grid;
  place-items: center;
  color: #fff;
}

.sp-drop {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 24px;
  box-shadow: var(--shadow-lg);
  padding: 8px;
  z-index: 60;
}

.sp-drop .sp-ttl {
  padding: 8px 12px 6px;
  font-size: 13px;
  font-weight: 700;
  color: var(--muted-2);
}

.sp-list { display: flex; flex-direction: column; gap: 2px; }

.sp-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 16px;
  font-size: 13px;
  font-weight: 700;
  text-align: left;
  width: 100%;
}

.sp-item:hover { background: var(--card-2); }

.sp-item .circ {
  width: 32px;
  height: 32px;
  border-radius: var(--r-pill);
  display: grid;
  place-items: center;
  background: var(--card-2);
  color: var(--muted);
  flex-shrink: 0;
  transition: background-color 0.2s, color 0.2s;
}

.sp-item:hover .circ { background: var(--ink-2); color: #fff !important; }

.sp-item b { display: block; font-size: 13px; }
.sp-item small { display: block; font-family: var(--f2); font-size: 11px; font-weight: 600; color: var(--muted); margin-top: 1px; }
.sp-item.sp-go { color: var(--brand); }

/* =============================================================
   АДАПТАЦИЯ ПОД ОСТАЛЬНЫЕ УСТРОЙСТВА

   Ниже — диапазоны, которые основная сетка не покрывала: планшет в обеих
   ориентациях, телефон боком, очень узкие экраны и большие мониторы.
   Каждое правило отвечает на конкретный измеренный перекос, а не добавлено
   «на всякий случай».
   ============================================================= */

/* ---------- Планшет: 761–1000 ----------
   Сюда попадают iPad в портрете и телефоны боком. Дока уже нет, меню в
   шапке есть, но сетки оставались телефонными — по одной карточке во всю
   ширину. */
@media (min-width: 761px) and (max-width: 1000px) {
  .container { padding: 0 24px; }
  .cat-tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .vac-grid, .co-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .res-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---------- Телефон боком и низкие окна ----------
   Высота меньше ширины: вертикаль в дефиците, поэтому крупные отступы и
   ростовые блоки ужимаются, чтобы на экран помещалось содержимое, а не
   воздух. */
@media (max-height: 560px) and (orientation: landscape) {
  /* Ритм страницы остаётся общим — он и так завязан на --stack. Вертикаль
     здесь экономим там, где она правда в обрез: на разговоре, доке и шапке
     диалога, а не на отступах между плашками. */
  .container.chat-wrap { min-height: 0; --chat-gap: 8px; }
  /* Вертикали в обрез: шапка разговора ужимается, а плашка вакансии
     уходит совсем — она есть на самой странице вакансии, а здесь съедала
     треть ленты. */
  .chat-head { padding: 6px 12px 6px 6px; }
  .chat-head .co-logo, .chat-head .avatar { transform: scale(0.85); }
  /* Строку под именем здесь ужимаем, но не убираем: в ней по очереди лежат
     подпись и «печатает…», и стоит её спрятать — шапка снова начнёт расти в
     тот момент, когда собеседник берётся за клавиатуру. */
  .chat-line { height: 15px; }
  .chat-who small, .chat-typing { font-size: 11px; line-height: 15px; }
  .chat-vac { display: none; }
  .chat-feed { padding: 10px; }
  .chat-form { padding: 5px; }
  .chat-form textarea { padding: 8px 10px; max-height: 76px; }
  .chat-send { width: 40px; height: 40px; border-radius: 14px; }
  .msg-photo { max-height: 160px; }
  .modal { max-height: 88dvh; overflow-y: auto; }
  .dock { transform: scale(0.92); transform-origin: bottom center; }
}

/* ---------- Очень узкие экраны: 360 и меньше ----------
   Малые телефоны и Telegram на них: контент важнее полей, а нажимать
   пальцем всё ещё должно быть удобно. */
@media (max-width: 380px) {
  .container { padding: 0 12px; }

  /* Шапка на узком телефоне: четыре круглые кнопки подряд не помещаются и
     вылезают за край. Колокольчик уходит — уведомления и так приходят
     всплывающей карточкой, а счётчик виден на значке в навигации. */
  .header-plate { padding: 8px 8px 8px 14px; gap: 8px; }
  .header-actions { gap: 6px; }
  .header-actions .icon-btn[aria-label="Уведомления"] { display: none; }
  .icon-btn { width: 38px; height: 38px; }
  .logo svg { width: 26px; height: 26px; }
  .logo-word { font-size: 13px; }
  .hero-title { font-size: clamp(22px, 7.4vw, 28px); }
  .vac-card { padding: 15px; }
  .vc-title { font-size: 15px; }
  .vc-salary { font-size: 16px; }
  .btn { padding: 11px 16px; font-size: 13px; }
  .tabs a, .tabs button { padding: 11px 12px; font-size: 13px; }
  .chat-head { padding: 8px 12px 8px 8px; }
  .chat-who b { font-size: 13.5px; }
}

/* Палец, а не курсор: на сенсорных экранах цели крупнее — 34 точки для
   сердечка мало, промахи по нему раздражают больше, чем лишние 6 точек. */
@media (hover: none) and (pointer: coarse) {
  .fav-btn { width: 42px; height: 42px; }
  .icon-btn { width: 42px; height: 42px; }
  .chat-clip, .chat-mic { width: 44px; height: 44px; }

  /* ЭМОДЗИ НА ТЕЛЕФОНЕ УБИРАЕМ, И ЭТО НЕ ПОТЕРЯ.

     Панель эмодзи я заводила для тех, кто печатает на компьютере: там их
     взять неоткуда. На телефоне они и так лежат на системной клавиатуре,
     одним нажатием, — и наша кнопка только повторяет её.

     Зато места она стоит дорого. Замерено на экране в 375 точек: форма
     ввода 351, четыре кнопки съедали 186, и полю с текстом оставалось 116 —
     подсказка «Написать сообщение» переносилась на три строки. Ради
     кнопки-дубликата. */
  .chat-emo { display: none; }
  .di-x { padding: 6px; }
}

/* ---------- Большие мониторы: 1600 и шире ----------
   Полоса контента 1180 точек посреди широкого экрана выглядит как окно
   мобильного приложения на телевизоре. Даём ей вырасти, но не бесконечно:
   строка длиннее ~90 знаков читается тяжело. */
@media (min-width: 1600px) {
  .container { max-width: 1440px; }
  .vac-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .cat-tiles { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .rich p, .rich li { max-width: 78ch; }
}

/* ---------- Очень широкие мониторы ----------
   Полоса в 1320 точек посреди экрана в 1920 и шире оставляла по 300 точек
   пустоты с каждой стороны — рабочее место превращалось в узкий столбец.
   Ширина растёт вместе с окном, но не бесконечно: строки текста ограничены
   отдельно, чтобы их не приходилось читать «через всю стену». */
@media (min-width: 1800px) {
  .container { max-width: 1660px; }
  .jobs-layout { grid-template-columns: 300px minmax(0, 1fr); gap: 26px; }
  .vpage { grid-template-columns: minmax(0, 1fr) 360px; }
}

@media (min-width: 2200px) {
  .container { max-width: 1880px; }
}

/* Экраны с высокой плотностью точек: волосяные границы не должны исчезать */
@media (min-resolution: 2dppx) {
  .card, .vac-card, .chat-head, .chat-form, .header-plate { border-width: 0.5px; }
}

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

/* Карточки в ряду одной высоты: align-items: start оставлял рваный низ,
   и сетка выглядела как набор случайно упавших плашек. */
.res-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--stack);
  align-items: stretch;
}

.res-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.res-card:hover { box-shadow: var(--shadow-lg); }
.res-card:hover .rc-title { color: var(--brand); }

.rc-head { display: flex; align-items: center; gap: 9px; margin-bottom: 2px; }

.rc-name {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rc-title {
  font-weight: 700;
  font-size: 16px;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  transition: color var(--dur-fast);
}

.rc-salary { font-weight: 700; font-size: 17px; margin-top: 2px; }
.rc-nosalary { font-family: var(--f2); font-weight: 600; font-size: 13px; color: var(--muted); }
.rc-facts { font-family: var(--f2); font-size: 12.5px; color: var(--muted); }
.rc-skills { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.rc-foot {
  margin-top: auto;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding-top: 10px;
  font-family: var(--f2);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--muted-2);
}

/* Живое резюме помечено точкой, а не плашкой: в сетке из двадцати карточек
   двадцать зелёных плашек перестают что-либо значить. */
.rc-live { display: inline-flex; align-items: center; gap: 5px; color: var(--success); }
.rc-live::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

@media (max-width: 1000px) {
  .res-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 620px) {
  .res-grid { grid-template-columns: 1fr; }
}

/* =============================================================
   ДОВОДКА ПОД СЕНСОРНЫЕ ЭКРАНЫ

   Три вещи, которые видны только на настоящем телефоне: браузер сам
   масштабирует страницу, если поле мельче шестнадцати точек; палец
   промахивается по целям ниже сорока; и горизонтальные ленты выглядят
   обрезанными, если не показать, что они продолжаются.
   ============================================================= */

@media (max-width: 760px) {
  /* Ровно 16 точек — порог, ниже которого Safari на iOS увеличивает
     страницу при касании поля, и после этого вся вёрстка уезжает вбок.
     Это не про читаемость, это про то, чтобы экран не «прыгал». */
  .input, .select, .textarea,
  .jobs-toolbar .sort .select,
  .chat-form textarea,
  .sp-input-in input { font-size: 16px; }
}

@media (hover: none) and (pointer: coarse) {
  .check { min-height: 44px; }
  .check input { width: 22px; height: 22px; }
  .btn-sm { padding: 11px 15px; }
  .jobs-toolbar .sort .select { padding: 11px 34px 11px 13px; }
  .footer a, .section-link { display: inline-block; padding: 5px 0; }
  .sp-item { padding: 12px; }
}

/* Вкладки шире экрана прокручиваются, но полосы прокрутки не видно.
   Затухающий край показывает, что список продолжается. */
.tabs {
  mask-image: linear-gradient(90deg, #000 88%, transparent);
  -webkit-mask-image: linear-gradient(90deg, #000 88%, transparent);
}

/* Переключатель роли при регистрации: на узком экране подписи ломались
   на две строки и сегмент раздувался вдвое. */
@media (max-width: 420px) {
  .segment button { padding: 10px 8px; font-size: 12.5px; }
}

/* Шапка: запас на узких экранах был в три точки — стоило шрифту
   отрисоваться чуть шире, и кнопки вылезали за плашку. Порог поднят,
   а на самых узких подпись у знака убирается совсем. */
@media (max-width: 430px) {
  .header-actions .icon-btn[aria-label="Уведомления"] { display: none; }
}

@media (max-width: 360px) {
  .logo-word { display: none; }
}

/* =============================================================
   ДЕЛОВОЙ ВИД НА БОЛЬШОМ ЭКРАНЕ

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

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

@media (min-width: 1001px) {
  :root {
    --r-card: 18px;
    --r-btn: 12px;
    --r-pill: 8px;
    --shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.05);
    --shadow-lg: 0 10px 28px rgba(0, 0, 0, 0.1), 0 2px 6px rgba(0, 0, 0, 0.05);
    --stack: 20px;
  }

  

  /* Кнопка остаётся фирменной, но перестаёт светиться: подсветка вокруг
     каждой кнопки — приём витрины, а не рабочего инструмента. */
  .btn-primary {
    box-shadow:
      0 1px 2px rgba(204, 85, 0, 0.28),
      inset 0 1px 0 rgba(255, 255, 255, 0.22);
  }

  .btn { padding: 10px 18px; font-size: 13.5px; }
  .btn-lg { padding: 13px 22px; font-size: 14.5px; }

  /* Плотнее: на большом экране между блоками не должно быть пустых полей
     в половину карточки. Отдельного числа для секции здесь больше нет — за
     плотность отвечает сам шаг, он на этой ширине уже 20 точек. */
  .vac-card, .res-card { padding: 16px; }
  .card-pad { padding: 20px; }
  /* КАТЕГОРИИ НА ВЕБЕ КРУПНЕЕ.

     Было пять колонок по 218 точек и плитка высотой 55: строка иконки с
     подписью на девять пунктов. На экране 1440 это выглядело как список
     настроек, а не как главный способ выбрать направление.

     Четыре колонки дают 276 точек на плитку, иконка и подписи растут
     соразмерно. На экране от 1600 колонок снова пять — там контейнер шире,
     и плитка остаётся тех же 270 точек. */
  .cat-tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
  .cat-tile { padding: 13px 16px 13px 13px; border-radius: 22px; gap: 13px; }
  .cat-tile .ico { width: 42px; height: 42px; border-radius: 14px; }
  .cat-tile b { font-size: 13.5px; }
  .cat-tile small { font-size: 12px; }
  .item-row { padding: 15px 18px; }

  /* Типографика делового текста: чуть мельче, плотнее, с ровной строкой */
  .vc-title, .rc-title { font-size: 15px; }
  .vc-salary, .rc-salary { font-size: 16px; }
  .page-title { letter-spacing: -0.015em; }
  .rich p, .rich li { font-size: 14px; line-height: 1.65; }

  /* Шапка ниже и спокойнее — она не главный герой страницы */
  .header-plate { padding-left: 22px; }
  :root { --chrome-h: 82px; }

  /* Плитка логотипа компании в деловом виде — прямоугольная, как в реестрах */
  .co-logo { border-radius: 10px; }
}

/* ===================== Компания: шапка и настройки ===================== */

/* Полоса оттенка — первое, что видно на странице компании. Логотип лежит
   на границе полосы и карточки, как в профилях: так он читается крупно,
   не занимая отдельного блока. */
.co-hero {
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  overflow: hidden;
}

/* НАЗВАНИЕ И ЗНАК — С ПЕРЕНОСОМ.

   Строка была flex без переноса, а у карточки стоит overflow: hidden. На
   узком экране знак «Проверено» не помещался рядом с названием и просто
   срезался по краю карточки: галочка видна, слова нет. Перенос кладёт знак
   на вторую строку — это некрасивее, чем в одну, и честнее, чем наполовину. */
.co-title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.co-hero-band { height: 104px; background: var(--co-tint, linear-gradient(135deg, #ff8533, #ff6b00)); }

.co-hero[data-tint='graphite'] { --co-tint: linear-gradient(135deg, #3a3a3d, #1c1c1e); }
.co-hero[data-tint='ocean'] { --co-tint: linear-gradient(135deg, #2a7fb8, #12566f); }
.co-hero[data-tint='forest'] { --co-tint: linear-gradient(135deg, #2f7d5a, #17513a); }
.co-hero[data-tint='plum'] { --co-tint: linear-gradient(135deg, #6d4a86, #3f2a52); }
.co-hero[data-tint='sand'] { --co-tint: linear-gradient(135deg, #c9a06a, #8a6a3f); }

/* НАД ПОЛОСУ ПОДНИМАЕТСЯ ТОЛЬКО ЛОГОТИП.

   Отрицательный отступ стоял на всей строке, и вместе с логотипом на
   цветную полосу заезжало название со знаком. Тёмному тексту это сходило с
   рук, а знак «Проверено» — оранжевый контур без заливки — на оранжевой
   полосе исчезал совсем: замерено, полоса 93–171, знак 149–172.

   Красить знак под каждый оттенок шапки — двенадцать оттенков и
   бесконечная погоня. Правильнее не класть его на цветное: над полосу
   поднимается логотип, ему там и место, а текст начинается под ней. */
.co-hero-body {
  display: flex;
  gap: 20px;
  align-items: flex-start;
  flex-wrap: wrap;
  padding: 0 24px 22px;
}

.co-hero-logo { margin-top: -34px; }

.co-hero-logo .co-logo {
  width: 84px;
  height: 84px;
  border-radius: 22px;
  border: 4px solid var(--card);
  box-shadow: var(--shadow);
}

.co-hero-logo .co-logo svg { width: 40px; height: 40px; }
.co-hero-body .page-title { margin-top: 12px; }

/* Логотип-картинка вместо фирменного знака */
.co-photo { overflow: hidden; background: var(--card-2); }
.co-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Настройки: логотип и оттенок */
.co-logo-row { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; }
.co-logo-preview .co-logo { width: 72px; height: 72px; border-radius: 20px; }
.co-logo-preview .co-logo svg { width: 34px; height: 34px; }
.co-logo-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }

.tint-row { display: flex; gap: 10px; flex-wrap: wrap; }

.tint {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 12px 7px 7px;
  border-radius: 12px;
  border: 1.5px solid var(--border);
  background: var(--card);
  cursor: pointer;
}

.tint-swatch { width: 26px; height: 26px; border-radius: 8px; }
.tint-name { font-size: 12.5px; font-weight: 700; color: var(--muted); }
/* Выбранный оттенок помечаем подложкой: рядом стоит сам образец цвета,
   и обводка вокруг него только спорит с ним */
.tint.active { border-color: transparent; background: var(--brand-soft); }
.tint.active .tint-name { color: var(--text); }

@media (max-width: 560px) {
  .co-hero-body { padding: 0 16px 18px; gap: 14px; }
  .co-hero-band { height: 78px; }
  .co-hero-logo .co-logo { width: 68px; height: 68px; border-radius: 18px; }
}

/* Значок показателя в виджете кабинета: живёт своей анимацией, но не
   спорит с цифрой — сидит в углу и держит фирменный цвет. */
.stat-card { position: relative; }

.stat-ico {
  display: block;
  width: 34px;
  height: 34px;
  margin-bottom: 8px;
  color: var(--brand);
}

.stat-ico svg { width: 100%; height: 100%; }
.stat-card.brand .stat-ico { color: var(--brand-light); }

/* ===================== Фотография в анкете резюме ===================== */

.photo-field {
  display: flex;
  /* .field выше по файлу выкладывает содержимое столбиком — здесь нужен ряд */
  flex-direction: row;
  align-items: center;
  gap: 18px;
  padding: 16px;
  border-radius: var(--r-card);
  background: var(--card-2);
}

.photo-preview { position: relative; flex-shrink: 0; }
.photo-preview .avatar, .photo-preview .avatar-img { width: 96px; height: 96px; border-radius: 30px; font-size: 32px; }

/* Значок на углу снимка: подсказывает, что фото можно поставить, и
   подтверждает, когда оно уже выбрано. */
.photo-badge {
  position: absolute;
  right: -4px;
  bottom: -4px;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 11px;
  background: var(--brand);
  color: #fff;
  border: 3px solid var(--card-2);
}

.photo-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.photo-body b { font-size: 14.5px; }
.photo-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }

/* Атрибут hidden слабее правила display у кнопки: без этого «Убрать»
   показывалась и тогда, когда убирать нечего. */
.btn[hidden], [hidden] { display: none !important; }

@media (max-width: 560px) {
  .photo-field { flex-direction: column; align-items: flex-start; gap: 14px; }
}

/* ===================== Живая навигация =====================
   Анимируется только выбранный пункт: он «дышит» и коротко отзывается на
   переключение. Остальные стоят неподвижно — иначе нижняя панель
   превращается в мельтешение, и понять, где ты находишься, труднее. */

.dock a .tb-wrap svg { transition: transform 0.3s var(--ez-spring); }

/* Постоянное покачивание активного значка убрано: вместе с подъёмом и
   едущей подложкой это третье движение в одной точке, и складывались они
   в дрожь, а не в жизнь. */
.dock a.active .tb-wrap svg { transform-origin: 50% 60%; }

@keyframes dock-alive {
  0%, 72%, 100% { transform: none; }
  78% { transform: translateY(-2.5px) scale(1.07); }
  85% { transform: translateY(0) scale(0.97); }
  91% { transform: none; }
}

/* Короткий отклик на само переключение — поверх «дыхания» */
.dock a.active .pill { animation: dock-pill 0.42s var(--ez-spring) both; }

@keyframes dock-pill {
  from { transform: scale(0.82); opacity: 0.4; }
  to { transform: none; opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .dock a.active .tb-wrap svg,
  .dock a.active .pill { animation: none; }
}

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

.app-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 18px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.ac-head { display: flex; align-items: flex-start; gap: 12px; }
.ac-who { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ac-who b { font-size: 15px; font-weight: 700; }
.ac-role { font-family: var(--f2); font-size: 13px; color: var(--muted); }
.ac-sub { font-family: var(--f2); font-size: 12.5px; color: var(--muted-2); }

/* Статус — якорь правого верхнего угла: взгляд находит его первым и
   сразу понимает, в каком состоянии отклик. */
.ac-status { flex-shrink: 0; margin-left: auto; }

.ac-letter {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 12px 14px;
  border-radius: 14px;
  background: var(--card-2);
  font-family: var(--f2);
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--text);
}

.ac-letter svg { flex-shrink: 0; color: var(--muted); margin-top: 2px; }

/* Ряд действий: одно главное слева, второстепенные следом, отказ —
   отдельно справа, чтобы не нажать его по инерции. */
.ac-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}

.ac-actions .btn { min-height: 38px; }
.ac-decline { margin-left: auto; color: var(--danger); }
.ac-decline:hover { background: var(--danger-soft); }

@media (max-width: 560px) {
  .ac-actions .btn { flex: 1 1 calc(50% - 4px); justify-content: center; }
  .ac-decline { margin-left: 0; }
}

/* Отклики — список во всю ширину колонки, а не плитки: в карточке живут
   письмо и четыре действия, и в узкой плитке они ломаются на этажи. */
.app-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 860px;
}

/* ===================== Поиск: строка и быстрые условия =====================
   Условия стоят сверху, а не колонкой сбоку: колонка занимала треть экрана
   постоянно, хотя фильтрами пользуются урывками. */

.search-bar {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-bottom: 12px;
}

.sb-input {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  height: 52px;
  padding: 0 16px;
  border-radius: var(--r-btn);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  color: var(--muted);
}

.sb-input input {
  flex: 1;
  min-width: 0;
  border: 0;
  outline: none;
  background: transparent;
  font: inherit;
  font-size: 15px;
  color: var(--text);
}

.sb-more.active { background: var(--brand-soft); color: var(--brand); }

/* Кнопка «Найти» на телефоне сжимается до значка: слово рядом с полем
   отнимает у поля треть ширины, а поиск по нажатию Enter никуда не делся. */
.sb-go { flex: 0 0 auto; gap: 8px; }
.sb-go svg { display: none; }

/* ПОЛОСА УСЛОВИЙ ЕЗДИТ ВБОК, А НЕ ПЕРЕНОСИТСЯ ВНИЗ.

   Перенос строит из трёх плашек три этажа — сто семьдесят точек экрана до
   первой вакансии. Полоса, которая едет вбок, занимает один этаж всегда,
   сколько бы условий в ней ни лежало. Так это устроено в каждом мобильном
   приложении, и жест знаком без объяснений. */
.quick-filters {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* Полоса едет от края до края, а не внутри отступов контейнера: обрезать
     плашку по границе колонки — значит показать, что там что-то есть. */
  padding-bottom: 2px;
}

.quick-filters::-webkit-scrollbar { display: none; }

.qf {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex: 0 0 auto;
  height: 38px;
  padding: 0 13px;
  border-radius: var(--r-pill);
  background: var(--card);
  border: 1px solid var(--border);
  cursor: pointer;
  white-space: nowrap;
}

.qf:hover { border-color: var(--brand); }

.qf select {
  border: 0;
  outline: none;
  background: transparent;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  cursor: pointer;
  max-width: 46vw;
}

/* Кнопка окна — та же плашка, но со значком и счётчиком выбранного. */
.qf-more { color: var(--text); font-size: 13px; font-weight: 700; }
.qf-more.active { border-color: var(--brand); color: var(--brand); background: var(--brand-soft); }

.qf-n {
  display: inline-grid;
  place-items: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--brand);
  color: #fff;
  font-family: var(--f2);
  font-size: 11px;
  font-weight: 800;
}

/* Строка «Найдено …» и одна строка правды рядом с ней. */
.list-meta {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

.list-meta .found {
  font-family: var(--f2);
  font-weight: 700;
  font-size: 14px;
  color: var(--text);
  flex: 0 0 auto;
}

@media (min-width: 760px) {
  .sb-go svg { display: block; }
  .qf select { max-width: 210px; }
}

/* Планшет и окно в половину экрана (760–900): четыре пункта меню, две
   круглые кнопки и чип пользователя не помещались в плашку шапки, и она
   распирала страницу вбок. */
@media (min-width: 760.02px) and (max-width: 900px) {
  .header-plate { gap: 10px; padding: 8px 8px 8px 14px; }
  .nav { min-width: 0; flex-shrink: 1; gap: 1px; }
  .nav a { padding: 9px 10px; font-size: 13px; }
  .header-actions { flex-shrink: 0; gap: 7px; }
  .icon-btn { width: 36px; height: 36px; }
  .user-chip { padding: 4px; }
  .user-chip .name { display: none; }
  .user-chip svg:last-child { display: none; }
}

/* ===================== Ленты статусов, метрики, паспорт фактов =====================
   Общие блоки для экранов-списков: статус работает фильтром, цифра — ссылкой,
   факты выстроены парами «подпись — значение». */

.statusbar {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 2px;
  margin-bottom: 16px;
}

.statusbar::-webkit-scrollbar { display: none; }

.sb-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 36px;
  padding: 0 14px;
  /* Высота жёсткая, 36px, и --r-btn почти дотягивал до её половины —
     чип читался таблеткой. Чипу положен --r-pill, а не кнопочный радиус. */
  border-radius: var(--r-pill);
  border: 1px solid var(--border);
  background: var(--card);
  font-size: 13.5px;
  font-weight: 700;
  color: var(--muted);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}

.sb-chip:hover { color: var(--text); }

/* Выбранное состояние — графит, а не оранжевый: оранжевый бережём для
   действия, иначе на экране два одинаково громких пятна. */
.sb-chip.active { background: var(--ink-2); border-color: var(--ink-2); color: #fff; }

.sb-chip .cnt { font-family: var(--fnum); font-size: 11.5px; opacity: 0.75; }
.sb-chip .cnt.fresh { color: var(--brand); opacity: 1; }
.sb-chip.active .cnt.fresh { color: var(--brand-light); }

/* Ряд показателей */
.metrics { display: flex; align-items: center; flex-wrap: wrap; gap: 0; margin-top: 8px; }

.mt {
  display: flex;
  align-items: baseline;
  gap: 6px;
  padding: 0 14px;
  border-left: 1px solid var(--border);
}

.mt:first-child { padding-left: 0; border-left: 0; }
.mt-num { font-family: var(--fnum); font-size: 16px; font-weight: 700; }
.mt-num.accent { color: var(--brand); }
.mt-lbl { font-family: var(--f2); font-size: 12px; color: var(--muted); }
a.mt:hover .mt-num { color: var(--brand); }

/* Паспорт фактов */
.kv { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 24px; margin: 0; }
.kv-row { display: flex; gap: 10px; align-items: baseline; min-width: 0; }
.kv dt { flex-shrink: 0; font-family: var(--f2); font-size: 12.5px; color: var(--muted); }
.kv dd { margin: 0; font-size: 13.5px; font-weight: 700; overflow-wrap: anywhere; }

@media (max-width: 700px) {
  .kv { grid-template-columns: 1fr; gap: 8px; }
  .metrics { gap: 6px 0; }
  .mt { padding: 0 10px; }
}

/* Новый отклик: оранжевая точка перед именем и еле заметная тёплая
   подложка сверху. Рамка по кромке спорила с точкой и превращала ленту
   откликов в набор обводок. */
.app-card.is-new {
  background: linear-gradient(180deg, var(--brand-soft), rgba(255, 107, 0, 0) 72px), var(--card);
}

.ac-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--brand);
  margin-right: 8px;
  vertical-align: middle;
}

/* Факты кандидата — строкой под должностью: по ним решение принимается
   прямо в ленте, без открытия резюме. */
.ac-facts { font-family: var(--f2); font-size: 12.5px; color: var(--text); }
.ac-skills { display: flex; flex-wrap: wrap; gap: 6px; }

/* ===================== Кабинет: список и колонка =====================
   На широком экране рядом со списком оставалось пустое поле в треть
   ширины. Туда встаёт колонка с вакансиями и счётчиками — то, ради чего
   работодатель и лез в выпадающий фильтр. Ниже 1100px колонки нет:
   там место дороже, и её работу делает обычный выбор над списком. */

.cab-layout { display: grid; grid-template-columns: minmax(0, 1fr); }
.cab-main { min-width: 0; }
.cab-rail { display: none; }

@media (min-width: 1100px) {
  .cab-layout {
    grid-template-columns: minmax(0, 1fr) 288px;
    gap: var(--stack);
    align-items: start;
  }

  .cab-layout .app-list { max-width: none; }
  .cab-pick { display: none; }

  .cab-rail {
    display: flex;
    flex-direction: column;
    gap: 10px;
    position: sticky;
    top: calc(var(--chrome-h) + var(--stack));
  }
}

.rail-card {
  display: flex;
  flex-direction: column;
  padding: 8px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.rail-title {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--muted);
  padding: 8px 10px 10px;
}

.rail-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  font: inherit;
  font-size: 13.5px;
  color: var(--text);
  text-align: left;
  cursor: pointer;
  transition: background 0.16s var(--ez);
}

.rail-item:hover { background: var(--card-2); }
.rail-item.on { background: var(--card-2); font-weight: 700; }

.ri-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ri-total { font-family: var(--f2); font-size: 12.5px; color: var(--muted-2); }

/* Счётчик новых — единственное цветное пятно в колонке: он и должен
   притягивать взгляд, всё остальное здесь просто навигация. */
.ri-new {
  flex-shrink: 0;
  min-width: 20px;
  padding: 1px 6px;
  border-radius: 7px;
  background: var(--brand);
  color: #fff;
  font-size: 11.5px;
  font-weight: 700;
  text-align: center;
}

.rail-add { justify-content: center; }

/* ===================== Карточка своей вакансии / своего отклика =====
   Заголовок, строка условий, ряд показателей, ряд действий. Раньше это
   была общая «строка списка», где цифры прятались в подпись серым по
   серому — понять, где ждут ответа, можно было только вчитавшись. */

.mvac {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 18px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

/* Вакансия, где кто-то ждёт ответа, помечена тёплой подложкой сверху и
   подъёмом: кромка по периметру в списке из двадцати штук читалась
   решёткой из оранжевых прямоугольников. */
.mvac.is-hot {
  background: linear-gradient(180deg, var(--brand-soft), rgba(255, 107, 0, 0) 72px), var(--card);
  box-shadow: var(--shadow-lg);
}

.mv-head { display: flex; align-items: center; gap: 12px; }
.mv-ttl { flex: 1; min-width: 0; }

.mv-ttl a {
  font-size: 16px;
  font-weight: 700;
  color: var(--text);
  text-decoration: none;
}

.mv-ttl a:hover { color: var(--brand); }

.mv-sub {
  font-family: var(--f2);
  font-size: 13px;
  color: var(--muted);
}

.mvac .notice { margin: 0; }
.mvac .ac-actions { margin-top: 2px; }

/* Панель над списком: состояния слева, кнопка размещения справа —
   на узком экране кнопка уходит под панель во всю ширину. */
.vac-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: var(--stack);
}

.vac-toolbar .statusbar { flex: 1; margin-bottom: 0; }

@media (max-width: 700px) {
  .vac-toolbar .btn { width: 100%; justify-content: center; }
}

/* На широком экране показатели уходят вправо отдельным столбцом — так
   устроены списки на больших биржах труда, и не случайно: слева читают
   «что за вакансия», справа сверяют цифры, глаз не мечется по строке.
   Заодно закрывается пустое поле, которое оставалось справа от списка. */
@media (min-width: 1000px) {
  .app-list.wide { max-width: none; }

  .app-list.wide .mvac {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 26px;
    align-items: start;
  }

  .app-list.wide .mvac > * { grid-column: 1; }

  .app-list.wide .mvac .metrics {
    grid-column: 2;
    grid-row: 1 / span 4;
    align-self: center;
    flex-direction: column;
    align-items: flex-end;
    gap: 12px;
    margin-top: 0;
    min-width: 168px;
    padding-left: 26px;
    border-left: 1px solid var(--border);
  }

  .app-list.wide .mvac .mt {
    padding: 0;
    border-left: 0;
    gap: 7px;
  }
}

/* Строка подборки в колонке: название и одна строка условий */
.rail-vac {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 10px;
  border-radius: 12px;
  text-decoration: none;
  color: var(--text);
  transition: background 0.16s var(--ez);
}

.rail-vac:hover { background: var(--card-2); }
.rv-ttl { font-size: 13.5px; font-weight: 600; }
.rv-sub { font-family: var(--f2); font-size: 12px; color: var(--muted); }

/* Паспорт вакансии стоит сразу под шапкой — отделяем его от неё и от
   описания той же линией, что делит карточку на смысловые части. */
.vpage .kv {
  margin: 14px 0 0;
  padding: 14px 0 0;
  border-top: 1px solid var(--border);
}

/* На узком экране значок состояния уходит на свою строку: рядом с
   логотипом и названием он отбирал ширину, и заголовок ломался на три
   строки по одному слову. */
@media (max-width: 560px) {
  .mvac .mv-head { flex-wrap: wrap; }
  .mvac .ac-status { order: 3; flex-basis: 100%; margin-left: 0; }
  .mv-ttl a { font-size: 15px; }
}

/* Заготовки ответов и обязательное поле в окне решения */
.tpl-row { display: flex; flex-wrap: wrap; gap: 8px; }
.tpl-row .chip { cursor: pointer; }
.tpl-row .chip.on { background: var(--brand-soft); color: var(--brand); }

.field label .req {
  font-family: var(--f2);
  font-size: 11px;
  font-weight: 600;
  color: var(--danger);
  text-transform: none;
}

.textarea.invalid,
.input.invalid {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px var(--danger-soft);
}

/* ===================== Знак продвижения =====================
   Оплаченное размещение помечено живым значком в правом верхнем углу
   карточки, а не словами «Топ» и «Горячая»: слова из прайс-листа
   соискателю ничего не говорят, а угол карточки всё равно пустует. */

.vc-mark {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 2;
  width: 22px;
  height: 22px;
  pointer-events: none;
}

.vc-mark svg { width: 100%; height: 100%; }

/* УГОЛ ВАКАНСИИ ДЕРЖИТ ДВА ЗНАКА СРАЗУ.

   Плашка «DVOR ДОВЕРЯЕТ» и значок платного размещения оба метили в
   правый верхний угол — по отдельности они встали бы друг на друга. Общая
   полоса ставит их в ряд: плашка слева, значок у самого края.

   Оба знака внутри переходят на обычный поток — иначе каждый снова начал
   бы отсчитывать свои 14 точек, теперь уже от самой полосы. */
.vc-corner {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 8px;
  pointer-events: none;
}

.vc-corner:empty { display: none; }
.vc-corner .trust-corner,
.vc-corner .vc-mark { position: static; top: auto; right: auto; }

/* Строке с именем компании оставляем место под плашку: без этого длинное
   имя уезжает под неё и читается обрывком. */
/* Место под угловую плашку освобождает название: шапки с логотипом,
   которая занимала эту строку раньше, больше нет, а плашка осталась. */
.vac-card:has(.trust-corner) .vc-plate { padding-right: 116px; }
.vac-card:has(.trust-corner):has(.vc-mark) .vc-plate { padding-right: 146px; }

/* У высшего уровня название лежит в оранжевом блоке со своими полями —
   там отступ считается от блока, а не поверх него. */
.vac-card.promo-top:has(.trust-corner) .vc-plate { padding-right: 14px; margin-top: 30px; }

/* ЗНАКИ ПЛАТНОГО РАЗМЕЩЕНИЯ — НЕ ОРАНЖЕВЫЕ.

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

   Оба знака теперь спокойного серого веса: они помечают, а не кричат. */
/* ЗНАКИ ПРОДВИЖЕНИЯ — ОРАНЖЕВЫЕ.

   Здесь были серые с прозрачностью 0.75 и комментарием «они помечают, а не
   кричат». Владелец решил иначе, и решение его: это платное место, и оно
   обязано быть видно. Ракета и молния — фирменным, в полную силу. */
/* Логотип вместо анимации: та же коробка 22×22, чтобы карточка не
   дёргалась при смене оформления. */
.vc-mark-logo .co-logo { width: 22px; height: 22px; border-radius: 7px; }
.vc-mark-logo .co-logo svg { width: 13px; height: 13px; }
.vc-mark-logo.co-mono, .vc-mark-logo .co-mono { font-size: 9px; }

.vc-mark-top { color: var(--brand); opacity: 1; }
.vc-mark-hot { color: var(--brand); opacity: 1; }

/* На странице вакансии знак стоит в потоке рядом с направлением */
.meta-row .vc-mark {
  position: static;
  width: 20px;
  height: 20px;
}

/* ===================== Чат: состояние, ответ, поиск =====================
   Всё, что появилось при закрытии чата по чек-листу: галочки состояния,
   полоса ответа и правки, поиск по переписке, черта непрочитанного,
   кнопка возврата к последним сообщениям. */

/* Кнопки в шапке диалога — рядом со значком связи, тем же размером */
.chat-tool {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition: background 0.16s var(--ez), color 0.16s var(--ez);
}

.chat-tool:hover { background: var(--card-2); color: var(--text); }

/* Состояние своей реплики. Три знака вместо пяти из чек-листа — потому что
   «доставлено» и «отправлено» здесь одно событие: строка появилась в базе,
   и с этого мгновения её видят все устройства собеседника. Второй значок
   на ту же мысль был бы враньём. */
.msg-state {
  display: inline-flex;
  align-items: center;
  margin-left: 5px;
  vertical-align: -2px;
}

.msg-state svg { width: 12px; height: 12px; }
.msg-state.read svg:last-child { margin-left: -6px; }
.msg-state.wait { opacity: 0.6; }
.msg-state.err { color: var(--danger); }

.msg.failed { border: 1px solid rgba(220, 38, 38, 0.35); }
.msg.gone .msg-body { font-style: italic; color: var(--muted); }
.msg-edited { opacity: 0.75; }

/* Повтор — прямо в пузыре: тост исчезает, а неотправленное остаётся,
   и решение по нему принимают там же, где его видят. */
.msg-retry { display: flex; gap: 8px; margin-top: 8px; }

.msg-retry button {
  border: 0;
  border-radius: 10px;
  padding: 5px 10px;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}

.mr-go { background: var(--brand); color: #fff; }
.mr-drop { background: var(--card-2); color: var(--muted); }

/* Кнопка действий появляется при наведении, а на телефоне — всегда:
   наведения там нет, и иначе до неё не добраться. */
.msg-more {
  position: absolute;
  top: 4px;
  right: 4px;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  opacity: 0;
  cursor: pointer;
  transition: opacity 0.16s var(--ez);
}

.msg { position: relative; }
.msg:hover .msg-more { opacity: 1; }
.msg.mine .msg-more { color: rgba(255, 255, 255, 0.75); }

@media (hover: none) {
  .msg-more { opacity: 0.5; }
}

/* Цитата над ответом: короткая полоса, по нажатию уводит к оригиналу */
.msg-quote {
  display: block;
  width: 100%;
  margin-bottom: 6px;
  padding: 6px 10px;
  border-left: 2px solid currentColor;
  border-radius: 0 8px 8px 0;
  background: rgba(127, 127, 127, 0.12);
  font-family: var(--f2);
  font-size: 12.5px;
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
  opacity: 0.85;
}

.msg-quote.missing { cursor: default; font-style: italic; }

/* Найденная реплика подсвечивается на секунду — иначе после прокрутки
   непонятно, к какой именно из десяти похожих тебя привели. */
.msg.lit { animation: msg-lit 1.4s var(--ez) both; }

@keyframes msg-lit {
  0%, 60% { box-shadow: 0 0 0 3px rgba(255, 107, 0, 0.35); }
  100% { box-shadow: 0 0 0 0 rgba(255, 107, 0, 0); }
}

/* Черта непрочитанного */
.msg-newline {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0;
  font-family: var(--f2);
  font-size: 11.5px;
  font-weight: 700;
  color: var(--brand);
}

.msg-newline::before,
.msg-newline::after {
  content: "";
  flex: 1;
  height: 1px;
  background: rgba(255, 107, 0, 0.3);
}

/* Полоса «отвечаю» / «изменяю» над полем ввода */
.chat-strip {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-radius: 12px;
  background: var(--card-2);
  font-family: var(--f2);
  font-size: 12.5px;
}

.cs-kind {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex-shrink: 0;
  font-weight: 700;
  color: var(--brand);
}

.cs-text {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
}

.cs-x {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}

/* Поиск по переписке */
.chat-search {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: 12px;
  background: var(--card-2);
}

.chat-search input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: 14px;
  color: var(--text);
  outline: none;
}

.cs-ico { display: flex; color: var(--muted); }

.chat-found {
  max-height: 240px;
  overflow-y: auto;
  border-radius: 12px;
  background: var(--card);
  border: 1px solid var(--border);
}

.cf-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  padding: 9px 12px;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: transparent;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.cf-row:last-child { border-bottom: 0; }
.cf-row:hover { background: var(--card-2); }
.cf-when { font-family: var(--f2); font-size: 11px; color: var(--muted-2); }
.cf-text { font-size: 13px; }
.cf-empty { padding: 14px; text-align: center; font-size: 13px; color: var(--muted); }

/* Кнопка возврата к последним сообщениям. Появляется, только когда человек
   ушёл читать выше: тогда новая реплика ждёт здесь, а не дёргает ленту. */
.chat-down {
  position: absolute;
  right: 18px;
  bottom: 92px;
  z-index: 5;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--card);
  color: var(--text);
  box-shadow: var(--shadow-lg);
  cursor: pointer;
}

.chat-down svg { transform: rotate(90deg); }

/* НАВЕРХ, К ЧЕРТЕ «НОВЫЕ СООБЩЕНИЯ».

   Лента больше не уезжает туда сама: движение без спроса читается как сбой,
   даже когда оно задумано как забота. Вместо него — кнопка, и она сама
   объясняет, куда ведёт. Стоит вверху, а не внизу: направление подсказывает
   и место, и стрелка.

   Показываем её, только когда черта действительно выше видимой части. */
.chat-up {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: 8px;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 6px 12px 6px 9px;
  border: 1px solid var(--brand-line);
  border-radius: 13px;
  background: var(--card);
  color: var(--brand);
  font: inherit;
  font-family: var(--f2);
  font-size: 12.5px;
  font-weight: 600;
  box-shadow: var(--shadow-lg);
  cursor: pointer;
}

.chat-up[hidden] { display: none; }
.chat-up svg { transform: rotate(-90deg); }
.chat-up:hover { background: var(--brand-soft); }

.cd-count {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 18px;
  padding: 1px 5px;
  border-radius: 7px;
  background: var(--brand);
  color: #fff;
  font-family: var(--f2);
  font-size: 11px;
  font-weight: 700;
  line-height: 1.4;
}

.chat-wrap { position: relative; }

/* Список действий в шторке — общий для меню диалога и меню реплики */
.menu-list { display: flex; flex-direction: column; gap: 4px; }

.menu-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  border: 0;
  border-radius: 14px;
  background: transparent;
  font: inherit;
  color: var(--text);
  text-align: left;
  cursor: pointer;
  transition: background 0.16s var(--ez);
}

.menu-row:hover { background: var(--card-2); }
.menu-row svg { flex-shrink: 0; margin-top: 1px; color: var(--muted); }
.menu-row b { display: block; font-size: 14px; }
.menu-row small { display: block; margin-top: 2px; font-family: var(--f2); font-size: 12px; color: var(--muted); }
.menu-row.danger b { color: var(--danger); }
.menu-row.danger svg { color: var(--danger); }

/* Ссылки на документы в подвале */
.footer-legal { display: flex; gap: 14px; flex-wrap: wrap; }

/* Ссылка «забыли пароль» под формой входа — кнопкой, а не ссылкой:
   поведение у неё кнопочное (открывает шторку), и читалка должна
   объявлять её именно так. */
.auth-forgot {
  align-self: center;
  margin-top: -4px;
  border: 0;
  background: transparent;
  font: inherit;
  font-family: var(--f2);
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
}

.auth-forgot:hover { color: var(--brand); }

/* ===================== Обводка полей ввода =====================

   Кольцо фокуса рисуется тенью по форме самого элемента. У поля внутри
   скруглённой оболочки своего скругления нет — и кольцо ложилось острым
   прямоугольником прямо внутри «таблетки». Смотрелось как чужая рамка.

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

.chat-form textarea:focus,
.chat-form textarea:focus-visible,
.chat-search input:focus,
.chat-search input:focus-visible,
.sb-input input:focus,
.sb-input input:focus-visible,
.sp-input-in input:focus,
.sp-input-in input:focus-visible {
  outline: none;
  box-shadow: none;
}

.chat-form:focus-within {
  box-shadow: var(--brand-inset), var(--focus-ring);
}

.chat-search:focus-within,
.sb-input:focus-within,
.sp-input-in:focus-within {
  box-shadow: var(--focus-ring);
}

/* Скругление самому полю тоже задаём: браузеры рисуют поверх него и
   собственную подсветку — выделение текста, автозаполнение, подсказку
   проверки. Без радиуса каждая из них снова была бы острым углом. */
.chat-form textarea,
.chat-search input { border-radius: 14px; }


/* Подсказка под полем пароля. Три состояния и три цвета: нейтральное —
   пока считаем, зелёное — пароль чистый, красное — нашли в утечках или
   он слишком прост. Место под строку держим всегда, иначе форма прыгает
   ровно в тот момент, когда человек печатает. */
.pass-hint {
  display: block;
  min-height: 16px;
  margin-top: 6px;
  font-family: var(--f2);
  font-size: 12px;
  line-height: 1.35;
  color: var(--muted-2);
}

.pass-hint.ok { color: var(--success); }
.pass-hint.bad { color: var(--danger); }

/* ===================== Знаки состояния реплики =====================

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

.mark {
  display: inline-flex;
  align-items: center;
  width: 15px;
  height: 15px;
  flex-shrink: 0;
}

.mark svg { width: 100%; height: 100%; overflow: visible; }

.mark svg path,
.mark svg circle,
.mark svg ellipse,
.mark svg rect { fill: currentColor; }

.msg-state .mark { margin-left: 5px; vertical-align: -3px; }

/* Доставлено — спокойный вес: это ожидаемое состояние, а не событие. */
.msg-state.sent { opacity: 0.7; }

/* Просмотрено — событие, ради которого на значок и смотрят. */
.msg-state.read { color: var(--brand); }
.msg.mine .msg-state.read { color: #fff; }

.mark-read { animation: mark-pop 0.4s var(--ez-spring) both; }

@keyframes mark-pop {
  0% { transform: scale(0.7); opacity: 0.4; }
  60% { transform: scale(1.1); opacity: 1; }
  100% { transform: none; }
}

/* ===================== Колокольчик в шапке =====================

   Единственный живой плеер на экране, и движение здесь несёт смысл: пока
   есть непрочитанное — качается, иначе стоит на собранном кадре. */

.bell-btn { position: relative; }

.bell-ico {
  display: block;
  width: 19px;
  height: 19px;
  color: inherit;
}

.bell-ico svg { width: 100%; height: 100%; }

/* Пока читать нечего — значок тише остального в шапке, чтобы не тянуть
   взгляд без повода. */
.bell-btn:not(.alive) .bell-ico { opacity: 0.75; }
.bell-btn.alive { color: var(--brand); }

@media (prefers-reduced-motion: reduce) {
  .mark-read { animation: none; }
}

/* ===================== Реакции, закреплённое, запрет =====================

   Всё, чем разговор о работе живёт дольше пары реплик: короткий ответ без
   слов, договорённость на виду и возможность разговор прекратить. */

.msg-reacts { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }

.react {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 7px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
  font: inherit;
  font-size: 12.5px;
  line-height: 1.5;
  cursor: pointer;
  transition: background 0.16s var(--ez), border-color 0.16s var(--ez);
}

.react:hover { background: var(--card-2); }

/* Своя реакция подсвечена: по ней же её и снимают, и это должно быть видно
   без наведения — на телефоне наведения нет вовсе. */
.react.mine { border-color: var(--brand); background: var(--brand-soft); }

.re-n { font-family: var(--fnum); font-size: 11.5px; font-weight: 700; color: var(--muted); }
.react.mine .re-n { color: var(--brand); }

/* Ряд выбора в шторке — крупнее: сюда целятся пальцем. */
.react-row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 16px; }

.react.big {
  width: 46px;
  height: 46px;
  justify-content: center;
  font-size: 22px;
  border-radius: 14px;
}

/* Пометка о пересылке — над текстом, тише текста */
.msg-fwd {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-bottom: 5px;
  font-family: var(--f2);
  font-size: 11.5px;
  font-weight: 600;
  opacity: 0.75;
}

/* Закреплённое — полосой под шапкой: время собеседования и адрес должны
   быть на виду, а не в двадцати сообщениях выше. */
.chat-pinned {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 14px;
  border-radius: 14px;
  background: var(--brand-soft);
  color: var(--text);
}

.cp-ico { display: flex; color: var(--brand); flex-shrink: 0; }

.cp-text {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  font: inherit;
  font-family: var(--f2);
  font-size: 13px;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
  color: inherit;
}

/* Разговор прекращён: спокойная плашка вместо поля ввода. Не красная —
   это не ошибка, а решение, которое человек принял сам. */
.chat-blocked {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-radius: var(--r-card);
  background: var(--card-2);
  border: 1px solid var(--border);
  font-family: var(--f2);
  font-size: 13px;
  line-height: 1.45;
}

.cb-ico { display: flex; flex-shrink: 0; color: var(--muted); }
.cb-text { flex: 1; min-width: 0; }
.chat-blocked .btn { flex-shrink: 0; }

@media (max-width: 560px) {
  .chat-blocked { flex-wrap: wrap; }
  .chat-blocked .btn { width: 100%; justify-content: center; }
}

/* ===================== Код из письма =====================

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

.code-input {
  font-family: var(--fnum), ui-monospace, monospace;
  font-size: 26px;
  font-weight: 700;
  letter-spacing: 0.32em;
  text-align: center;
  /* Разрядка добавляет пустоту справа от последней цифры — возвращаем
     симметрию, иначе строка выглядит смещённой влево. */
  text-indent: 0.32em;
  padding: 14px 12px;
}

.code-input::placeholder { letter-spacing: 0.32em; opacity: 0.35; }

.code-again {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
}

.code-again .auth-forgot { text-decoration: none; }
.code-again .auth-forgot[disabled] { opacity: 0.6; cursor: default; }

/* Догрузка старого — кнопка в самом верху ленты. Ведёт в прошлое разговора,
   потому и стоит первой; исчезает, когда доехали до начала. */
.chat-older {
  display: block;
  width: 100%;
  margin-bottom: 8px;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--card);
  font: inherit;
  font-family: var(--f2);
  font-size: 12.5px;
  font-weight: 700;
  color: var(--muted);
  cursor: pointer;
  transition: background 0.16s var(--ez), color 0.16s var(--ez);
}

.chat-older:hover:not(:disabled) { background: var(--card-2); color: var(--text); }
.chat-older:disabled { opacity: 0.6; cursor: default; }

/* ===================== Продвижение: покупка =====================

   Список услуг в окне: строка на услугу, цена справа. Не карточки и не
   плитки — здесь выбирают из четырёх строк, а не разглядывают витрину. */

.promo-list { display: flex; flex-direction: column; gap: 8px; }

.promo-opt {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  text-align: left;
  padding: 13px 15px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  cursor: pointer;
  transition: border-color 0.15s var(--ez), box-shadow 0.25s var(--ez);
}

.promo-opt:hover { border-color: var(--brand); box-shadow: var(--shadow); }

.po-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.po-main b { font-size: 14px; }
.po-main small { font-family: var(--f2); font-size: 12px; color: var(--muted); line-height: 1.5; }

.po-price {
  flex: 0 0 auto;
  font-family: var(--f2);
  font-size: 14.5px;
  font-weight: 800;
  color: var(--brand);
  white-space: nowrap;
}

/* Счёт: три строки, последняя — сумма. Похоже на бумажный счёт, и это
   нарочно: человек будет по нему платить. */
.promo-bill {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  overflow: hidden;
}

.pb-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  padding: 11px 15px;
  border-bottom: 1px solid var(--border);
  font-family: var(--f2);
  font-size: 13px;
}

.pb-row:last-child { border-bottom: 0; }
.pb-row span { color: var(--muted); }
.pb-row b { font-family: var(--f1); font-size: 13.5px; }

.pb-sum { background: var(--card-2); }
.pb-sum b { font-size: 17px; color: var(--brand); }

/* Остаток продвижения в списке вакансий */
.mv-promo {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px 3px;
  border-radius: 7px;
  border: 1px solid var(--brand);
  color: var(--brand);
  font-family: var(--f2);
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}

/* ===================== Админка =====================

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

.adm-note {
  font-family: var(--f2);
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--muted);
  margin: 0 0 16px;
}

/* ——— Переключатель уровня доверия ———

   Три положения в ряд, текущее погашено и не нажимается. Выпадающий список
   здесь был бы хуже: в нём текущее значение надо сначала открыть, чтобы
   увидеть, а тут вся шкала перед глазами — и видно, куда компанию можно
   двинуть в обе стороны. */
.adm-tiers {
  display: flex;
  gap: 4px;
  padding: 3px;
  border-radius: 999px;
  background: var(--card-2);
  border: 1px solid var(--border);
}

.adm-tier {
  appearance: none;
  border: 0;
  background: transparent;
  font-family: var(--f2);
  font-size: 11.5px;
  font-weight: 700;
  line-height: 1;
  padding: 7px 11px;
  border-radius: 999px;
  color: var(--muted);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s var(--ez), color 0.15s var(--ez);
}

.adm-tier:hover { background: var(--card); color: var(--ink); }

.adm-tier.active {
  background: var(--card);
  color: var(--ink);
  box-shadow: var(--shadow);
  cursor: default;
}

/* Сумма в строке счёта — справа от названия услуги, тем же весом, что и она:
   это не украшение, это то, ради чего строку и открывают. */
.adm-sum {
  font-family: var(--f2);
  font-size: 13px;
  font-weight: 800;
  color: var(--brand);
  white-space: nowrap;
}

.adm-count {
  font-family: var(--f2);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted-2);
  margin: 0 0 12px;
}

/* ——— Сводка ——— */

.adm-group { margin-bottom: 26px; }

.adm-group h2 {
  font-family: var(--fd);
  font-size: 15px;
  font-weight: 700;
  margin: 0 0 12px;
}

.adm-stats {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
  gap: 12px;
}

/* Тень нейтральная, без оранжевой черты внизу. В остальном приложении
   плитки с числами носят --brand-inset, но здесь их сразу тринадцать в
   сетке, и тонкая рыжая полоса под каждой складывается в ту самую дешёвую
   подсветку, от которой мы только что избавились на карточках вакансий.
   Одна плитка с ней смотрится, тринадцать — рябят. */
.adm-stat {
  display: block;
  padding: 18px 20px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  color: var(--text);
}

.adm-stat .num { font-family: var(--fnum); font-weight: 700; font-size: 22px; }

.adm-stat .num .unit {
  font-family: var(--f2);
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-2);
  margin-left: 4px;
}

.adm-stat .lbl {
  font-family: var(--f2);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted-2);
  margin-top: 7px;
}

a.adm-stat:hover { box-shadow: var(--shadow-lg); }

/* Тревожное выделяем цветом, а не размером: «жалоб не разобрано» обязано
   вылавливаться взглядом из ряда одинаковых плиток, но ломать сетку ради
   этого нельзя — тогда перестанет читаться всё остальное. */
.adm-stat.alarm {
  background: var(--danger-soft);
  border-color: transparent;
  box-shadow: none;
}

.adm-stat.alarm .num { color: var(--danger); }
.adm-stat.alarm .lbl { color: var(--danger); opacity: 0.75; }

/* ——— Списки ——— */

.adm-list { display: flex; flex-direction: column; gap: 14px; }

/* ——— Карточка жалобы ——— */

.adm-report {
  padding: 20px 22px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.adm-report-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 12px;
  font-family: var(--f2);
  font-size: 12px;
}

/* Предмет жалобы — чужие слова, и выглядеть он должен цитатой, а не нашей
   записью о них. Отсюда линия слева: она же и граница того, что модератору
   вообще показано. */
.adm-quote {
  border-left: 3px solid var(--brand-line);
  padding: 2px 0 2px 14px;
  margin-bottom: 14px;
}

.adm-quote .k {
  font-family: var(--f2);
  font-size: 11.5px;
  font-weight: 700;
  color: var(--muted-2);
}

.adm-quote .v {
  font-size: 14px;
  line-height: 1.55;
  margin-top: 4px;
  overflow-wrap: anywhere;
}

.adm-quote .adm-open {
  display: inline-block;
  margin-top: 6px;
  font-family: var(--f2);
  font-size: 12px;
  font-weight: 700;
  color: var(--brand);
}

.adm-kv {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  padding: 3px 0;
  font-family: var(--f2);
  font-size: 13px;
}

.adm-kv .k { min-width: 108px; color: var(--muted-2); font-weight: 600; }
.adm-kv .v { flex: 1; min-width: 180px; overflow-wrap: anywhere; }

.adm-said {
  margin-top: 12px;
  padding: 12px 14px;
  border-radius: 18px;
  background: var(--card-2);
  font-family: var(--f2);
  font-size: 13px;
  line-height: 1.55;
  overflow-wrap: anywhere;
}

.adm-decision {
  margin-top: 12px;
  padding: 12px 14px;
  border-radius: 18px;
  background: var(--brand-soft);
  font-family: var(--f2);
  font-size: 12.5px;
}

.adm-decision .answer {
  margin-top: 6px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--text);
  overflow-wrap: anywhere;
}

.adm-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; }

/* ——— Поиск по людям ——— */

.adm-search { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
.adm-search .input { flex: 1; min-width: 200px; }

/* ——— Компании ——— */

.adm-mark {
  font-family: var(--f2);
  font-size: 12px;
  color: var(--muted);
  margin-top: 8px;
}

.adm-mark .why {
  display: block;
  color: var(--muted-2);
  margin-top: 3px;
  overflow-wrap: anywhere;
}

.adm-vacs {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.adm-vac { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.adm-vac .body { flex: 1; min-width: 200px; }
.adm-vac .body > a { font-weight: 700; font-size: 13.5px; }
.adm-vac .body > a:hover { color: var(--brand); }

.adm-vac .sub {
  font-family: var(--f2);
  font-size: 12px;
  color: var(--muted);
  margin-top: 3px;
}

/* ——— Тумблеры площадки ——— */

.adm-toggle {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 18px 20px;
  border-radius: var(--r-card);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  margin-bottom: 12px;
}

.adm-toggle .body { flex: 1; min-width: 200px; }
.adm-toggle .body b { font-size: 15px; }

.adm-toggle .body p {
  font-family: var(--f2);
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--muted);
  margin: 5px 0 0;
}

/* Положение видно и цветом, и местом ручки: одного цвета мало тому, кто
   его не различает, а тумблер здесь выключает вещи на живой площадке. */
.adm-switch {
  position: relative;
  flex: 0 0 auto;
  width: 52px;
  height: 30px;
  border-radius: 15px;
  background: var(--card-2);
  border: 1.5px solid var(--border-2);
  transition: background-color var(--dur-fast), border-color var(--dur-fast);
}

.adm-switch .knob {
  position: absolute;
  top: 50%;
  left: 3px;
  width: 21px;
  height: 21px;
  margin-top: -10.5px;
  border-radius: 50%;
  background: var(--muted-2);
  transition: transform var(--dur-fast) var(--ez), background-color var(--dur-fast);
}

.adm-switch.on { background: var(--brand-soft); border-color: var(--brand-line); }
.adm-switch.on .knob { transform: translateX(22px); background: var(--brand); }
.adm-switch:disabled { opacity: 0.5; }

/* ——— Журнал ——— */

.adm-log { display: flex; flex-direction: column; gap: 10px; }

.adm-log-row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  padding: 14px 18px;
  border-radius: 20px;
  background: var(--card);
  border: 1px solid var(--border);
}

.adm-log-when {
  flex: 0 0 auto;
  min-width: 150px;
  font-family: var(--f2);
  font-size: 12px;
  color: var(--muted-2);
}

.adm-log-body { flex: 1; min-width: 220px; }
.adm-log-body .ttl { font-family: var(--f2); font-size: 13.5px; }
.adm-log-body .subj { color: var(--muted); }

.adm-change {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 6px;
  font-family: var(--f2);
  font-size: 12.5px;
}

.adm-change .from { color: var(--muted-2); text-decoration: line-through; }
.adm-change .arr { color: var(--muted-2); }
.adm-change .to { color: var(--brand); font-weight: 700; }

.adm-why {
  margin-top: 6px;
  font-family: var(--f2);
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--muted);
  overflow-wrap: anywhere;
}

/* ——— Окно «почему» ——— */

.adm-modal-foot { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 18px; }

.adm-modal-err {
  margin-top: 12px;
  padding: 11px 14px;
  border-radius: 16px;
  background: var(--danger-soft);
  color: var(--danger);
  font-family: var(--f2);
  font-size: 12.5px;
  line-height: 1.5;
}

@media (max-width: 700px) {
  .adm-stats { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }
  .adm-stat { padding: 16px; }
  .adm-report { padding: 18px 16px; }
  .adm-toggle { align-items: flex-start; gap: 12px; padding: 16px; }
  .adm-log-when { min-width: 0; flex: 1 0 100%; }
  .adm-kv .k { min-width: 0; flex: 1 0 100%; }
}

/* ОБЕЩАНИЕ РАБОТОДАТЕЛЯ — ОТДЕЛЬНЫМ ВИДОМ.

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

   Оранжевым их красить нельзя: оранжевый на площадке значит «нажми». */
.chip.chip-promise {
  background: rgba(28, 122, 82, 0.1);
  color: #1c7a52;
  font-weight: 700;
}


/* Переключатели обещаний в форме вакансии: подпись под названием объясняет,
   за что человек расписывается, — без неё их ставят не глядя. */
.vac-promise {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px;
  border-radius: var(--r-card);
  background: rgba(28, 122, 82, 0.06);
  border: 1px solid rgba(28, 122, 82, 0.18);
}


.vac-promise .check { align-items: flex-start; }
.vac-promise .check span { display: block; }
.vac-promise .check b { display: block; font-size: 14px; }
.vac-promise .check small {
  display: block;
  margin-top: 3px;
  font-family: var(--f2);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
}

.vac-promise-note {
  margin: 0;
  font-family: var(--f2);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted-2);
}
/* На совсем узких экранах и оставшиеся кнопки поджимаются: поле с текстом
   важнее их всех вместе взятых. */
@media (max-width: 400px) {
  .chat-clip, .chat-mic { width: 40px; height: 40px; }
  .chat-form .chat-send { width: 42px; height: 42px; }
  .chat-form { gap: 2px; }
}
/* ШИЛЬДИК «ПРОВЕРЕНО ДВОР».

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

   Цвет зелёный, как у отметок «Виза» и «Официально»: на этой площадке
   зелёный означает «условие выполнено», и все три знака про одно. */
/* ЗНАК «ПРОВЕРЕНО ДВОР» — ГАЛОЧКА ПЛЮС СЛОВО В РАМКЕ.

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

   Рамка без заливки. Залитая плашка на карточке спорит с настоящими
   кнопками и с плашкой «новая»: их на одной карточке бывает три, и все
   залитые — карточка превращается в набор наклеек. Контур говорит то же
   самое и не претендует на нажатие. */
.trust-dvor {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
  vertical-align: 1px;
  color: var(--brand);
}

.trust-dvor svg { flex-shrink: 0; }

.trust-word {
  padding: 1px 6px 2px;
  border: 1px solid var(--brand);
  border-radius: 6px;
  color: var(--brand);
  font-family: var(--f2);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1.35;
}

.trust-link { text-decoration: none; }
.trust-link:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 8px; }

/* На странице компании знак крупнее — там он стоит рядом с названием в
   заголовке, и мелкий выглядел бы припиской. */
.page-title .trust-word { font-size: 12px; padding: 2px 8px 3px; }
/* Оговорка про непроверенные объявления. Одна строка рядом со счётчиком:
   её читают один раз, и отдавать ей четыре строки экрана навсегда — плата
   не по товару. Полный текст — по ссылке. */
.jobs-disclaimer {
  font-family: var(--f2);
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--muted-2);
  min-width: 0;
}

.jobs-disclaimer a { color: var(--muted); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }
.jobs-disclaimer a:hover { color: var(--brand); }

/* Отметка, до которой компания ещё не доросла. Не прячем: человек должен
   видеть, что она существует и чего стоит, — иначе он не узнает, что её
   можно получить. Гасим и объясняем прямо в подписи. */
.check-locked { opacity: 0.62; cursor: default; }
.check-locked input { cursor: not-allowed; }
.check-locked small a { color: var(--brand); font-weight: 700; }

/* ===================== Документ на телефоне =====================

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

html.pdf-open { overflow: hidden; }

.pdf-veil {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

.pdf-bar {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: calc(env(safe-area-inset-top, 0px) + 12px) 14px 12px;
  background: var(--card);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.pdf-say {
  font-family: var(--f2);
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--muted);
}

.pdf-say b { color: var(--text); }

.pdf-acts { display: flex; gap: 8px; flex-wrap: wrap; }
.pdf-acts .btn { flex: 1 1 auto; justify-content: center; }

/* Площадка под лист прокручивается, а сам лист остаётся размером с A4 и
   уменьшается целиком — см. подогнать() в js/pdf.js. Белый фон задан
   жёстко: документ печатается на белом, и показывать его на тёмном — врать
   про то, как он будет выглядеть на бумаге. */
.pdf-stage {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  background: var(--card-2);
  padding: 12px 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
}

.pdf-fit { flex: 0 0 auto; overflow: hidden; }

.pdf-sheet {
  flex: 0 0 auto;
  width: 794px;
  height: 1123px;
  border: 0;
  background: #ffffff;
  transform-origin: top left;
  box-shadow: var(--shadow);
}
/* Отозванный отклик: приглушён, но не спрятан. Человек должен видеть, что
   он сделал, и иметь возможность вернуть контакты обратно. */
.mvac.is-withdrawn { opacity: 0.78; }
.mvac.is-withdrawn .mv-ttl a { color: var(--muted); }
