/* ============================================================
   Averon Insurance — чат-форма подбора плана (/insurance-chat/).

   Источник: Figma, сборка «Desktop» (node 788:151). Экран собран из трёх
   частей: своя шапка (789:1936), навигация по разделам слева (788:647) и
   лента диалога (788:543) шириной 720px по центру.

   Лента — сетка из трёх колонок 2fr / 0.25fr / 2fr с шагом 16px: облака
   собеседника лежат в первой, ответы клиента — в третьей, карточки выбора
   растягиваются на все три. Отсюда и разная ширина у разных видов ввода:
   ничего не «центрируется вручную», всё встаёт по колонкам.

   Брейкпоинты — те же, что у главной и статей:
     Mobile   ≤ 767px   (макет 360)
     Tablet   768–1023
     Desktop  ≥ 1024px  (лента 720px)

   Палитра совпадает с токенами главной (main.css) и статей (article.css):
   один и тот же бежевый набор, поэтому чат не выглядит чужой страницей.

   Файл подключается поверх base.css / landing.css, все правила скоупятся
   классами .chat / .chat-header (и .chat-page на <body>). Первый блок гасит
   то, что base.css навязывает элементам внутри страницы.
   ============================================================ */

/* --- Токены -------------------------------------------------- */
.chat-page {
  --c-primary: #e25c42;
  --c-tint: #fbeae3;
  --c-page: #fdf8f4;
  --c-surface: #f5efe9;
  --c-border: #e4dcd5;
  --c-muted: #8a817b;
  --c-body: #4a433d;
  /* Рамка поля, не прошедшего проверку (телефон — не номер США). Кирпичный
     красный: отделён от --c-primary, но остаётся в тёплой гамме набора. */
  --c-danger: #c0392b;

  /* Геометрия. 1200 — контент внутри полей 120px макета (1440), 720 —
     лента, 180 — колонка навигации. Всё снято с фреймов 789:1936 и 788:334.

     Просветы: 16px между соседними репликами (это и шаг сетки ленты), и
     столько же между этапами — отдельного разрыва между ответом клиента и
     следующим вопросом нет. Поднять --chat-gap-turn выше --chat-gap —
     вернуть этапам подчёркнутый просвет. Разрыв в 64px остаётся только там,
     где меняется собеседник (.chat__msg--intro). */
  --chat-page-w: 1200px;
  --chat-w: 720px;
  --chat-aside-w: 178.765px;
  --chat-pad-x: 120px;
  --chat-pad-top: 96px;
  --chat-gap: 16px;
  --chat-gap-turn: 16px;
  --chat-bubble-pad-y: 16px;
  --chat-bubble-pad-x: 24px;
  --chat-radius: 8px;
  --chat-field-h: 56px;

  /* Высота липкой шапки (.chat-header) — под неё отступают меню разделов
     и цели прокрутки, чтобы шапка их не накрывала. Значение сходится с
     рендером: 24 сверху + логотип 40 + 24 снизу + 1 подводка. Держать
     руками: на мобиле логотип меньше — см. переопределение в медиазапросе. */
  --chat-header-h: 89px;

  --chat-fs: 16px;
  --chat-lh: 24px;

  /* Одна кривая на все переходы ленты: выход облака, разворот «печатает…» в
     текст, вход поля. Резкий старт, долгое мягкое торможение — движение
     «доезжает» и замирает, а не тормозит рывком. */
  --chat-ease: cubic-bezier(0.22, 1, 0.36, 1);

  background-color: var(--c-page);
}

@media (max-width: 1279px) {
  /* Навигация уезжает вместе с полями: держать её сбоку, отъедая у ленты,
     значит сузить сами облака — а они и есть содержание страницы. */
  .chat-page {
    --chat-pad-x: 40px;
    --chat-pad-top: 48px;
  }
}

@media (max-width: 767px) {
  /* Мобильный макет (node 960:1863) собран на своих размерах, а не на
     уменьшенных десктопных. Основной текст — реплики и ответы — 14/20:
     это body узкого экрана. В самом макете облака размечены «Mobile/Body
     Small» 12/16, но это подпись, а не основной текст, и на неё в чате
     живут только описания карточек.

     Поля облака при этом остаются десктопными (24 по горизонтали, 16 по
     вертикали — node 960:1922): раньше они здесь урезались до 16px заодно
     с шириной облака, а в макете облако широкое, и воздуха в нём столько
     же, сколько на десктопе. */
  .chat-page {
    --chat-pad-x: 20px;
    --chat-pad-top: 32px;
    --chat-fs: 14px;
    --chat-lh: 20px;
    /* Логотип на узком экране 30px: 32 сверху + 30 + 24 снизу + 1 подводка. */
    --chat-header-h: 87px;
  }
}

/* --- Нейтрализация глобальных стилей ------------------------- */
.chat,
.chat *,
.chat-header,
.chat-header * {
  box-sizing: border-box;
}

.chat :where(p, span, ul, li) {
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  font-weight: inherit;
  color: inherit;
}

.chat :where(button) {
  margin: 0;
  border: 0;
  background: none;
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.chat :where(form) {
  margin: 0;
}

/* --- Шапка чата ----------------------------------------------
   Источник: Figma, node 789:1936. Хедера сайта на странице нет: из середины
   разговора уходить некуда. Логотип стоит по центру, «Назад» — слева, обе
   стороны сетки одинаковой ширины (0.5fr / 1fr / 0.5fr), поэтому логотип
   центрируется по странице, а не по остатку места.

   Шапка липкая (position: sticky) — едет за клиентом вниз и вверх, как и
   меню разделов. Что предусмотрено против «дёрганья» и наложений:
     • will-change: transform — шапка уходит на свой слой композитора, на
       скролле её двигает GPU без перерисовки каждый кадр (иначе на iOS
       sticky заметно дрожит);
     • z-index: 30 поверх ленты и меню — въезжающая реплика (у неё на
       время chat-msg-in свой transform, а значит свой контекст наложения)
       не мелькает над шапкой;
     • margin: 0 — глушим header { margin: 4rem 0 2rem } из общего
       static/css/header.css: этот селектор ловит и наш <header>, а
       остаток margin у sticky-элемента = щель над шапкой при прокрутке;
     • НЕЛЬЗЯ вешать transform / filter / perspective / will-change /
       contain: paint|layout|strict на .chat, .chat__layout, <main> и
       прочих предков — любой из них отнимет у sticky точку отсчёта, и
       шапка с меню перестанут липнуть (см. также .chat__sections).
   ----------------------------------------------------------- */
.chat-header {
  position: sticky;
  top: 0;
  z-index: 30;
  will-change: transform;
  margin: 0;
  /* Шапка прижата к верху окна — это край страницы, а не отступ ленты;
     воздух под разговором задаёт уже --chat-pad-top на каркасе. */
  padding: 24px var(--chat-pad-x) 0;
  background-color: var(--c-page);
  font-family: "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
}

.chat-header__inner {
  display: grid;
  grid-template-columns: minmax(0, 0.5fr) minmax(0, 1fr) minmax(0, 0.5fr);
  gap: 32px;
  align-items: end;
  width: var(--chat-page-w);
  max-width: 100%;
  margin: 0 auto;
  /* 24px до подводки и сама подводка — низ фрейма шапки. */
  padding-bottom: 24px;
  border-bottom: 1px solid var(--c-border);
}

.chat-header__back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  justify-self: start;
  color: var(--c-muted);
  font-size: 15px;
  line-height: 22px;
  text-decoration: none;
  transition: color 0.2s ease;
}

.chat-header__back:hover,
.chat-header__back:focus-visible {
  outline: none;
  color: var(--c-primary);
}

.chat-header__back-icon {
  flex: 0 0 auto;
  display: block;
  width: 16px;
  height: 16px;
}

.chat-header__logo {
  display: block;
  justify-self: center;
  /* #8A817B — та же тёплая серо-коричневая, что и --c-muted. */
  color: var(--c-muted);
  transition: color 0.2s ease;
}

.chat-header__logo:hover,
.chat-header__logo:focus-visible {
  outline: none;
  color: var(--c-primary);
}

.chat-header__logo svg {
  display: block;
  width: 125px;
  height: 40px;
}

/* Правая колонка шапки: слот «Начать заново». Пустой (до регистрации
   обращения) он ничего не занимает, кнопка внутри — с той же подачей, что
   «Назад» слева, только прижата к правому краю и зеркально: текст, потом
   значок. */
.chat-header__restart {
  display: flex;
  justify-self: end;
  align-items: end;
}

.chat-header__restart-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--c-muted);
  font-family: inherit;
  font-size: 15px;
  line-height: 22px;
  cursor: pointer;
  transition: color 0.2s ease;
}

.chat-header__restart-button:hover,
.chat-header__restart-button:focus-visible {
  outline: none;
  color: var(--c-primary);
}

.chat-header__restart-icon {
  flex: 0 0 auto;
  display: block;
  width: 16px;
  height: 16px;
}

@media (max-width: 767px) {
  /* В макете (node 960:1866) в шапке двое: «Назад» слева и логотип справа —
     кнопки сброса там нет вовсе. Здесь она остаётся, а логотип при этом
     стоит ровно по центру страницы, как на десктопе: бока сетки одинаковой
     доли, логотип посередине.

     Ради этого центра «Начать заново» на узком экране остаётся одним
     значком — подпись прячется (.chat-header__restart-label ниже). Иначе
     центр не держится: на 320px после логотипа (94px) на бок остаётся по
     105px, а «Начать заново» занимает ~111px, испанское «Empezar de nuevo»
     — ~132px. Центр страницы требует боковых колонок по ширине самой
     длинной подписи С ОБЕИХ сторон, то есть вдвое больше свободного места,
     — и с подписью справа логотип неминуемо съезжает влево.

     Логотип мельче макетного (94×30 вместо 125×40), «Назад» — 13/18 вместо
     15/22. Ритм по вертикали макетный: 32 сверху, 24 до подводки. */
  .chat-header {
    padding-top: 32px;
  }

  .chat-header__inner {
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    gap: 8px;
    padding-bottom: 24px;
  }

  .chat-header__back,
  .chat-header__restart-button {
    font-size: 13px;
    line-height: 18px;
  }

  /* Подпись снята с глаз, но осталась названием кнопки для скринридера, —
     тот же приём, что у спрятанного radio «Пола» (.chat__choice-input).
     display: none отнял бы у кнопки имя, и она осталась бы безымянной. */
  .chat-header__restart-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }

  .chat-header__logo svg {
    width: 94px;
    height: 30px;
  }
}

/* --- Каркас страницы -----------------------------------------
   Три колонки: слева навигация, по центру лента, справа пусто. Боковые
   колонки одинаковой ширины, поэтому лента стоит ровно по центру страницы —
   как в макете, где она смещена от левого края на те же 240px.

   ВНИМАНИЕ: .chat и .chat__layout — предки липких .chat__sections (и одного
   уровня с липкой .chat-header). Не добавлять сюда transform, filter,
   perspective, will-change, contain: paint|layout|strict и backdrop-filter:
   любое из них создаёт новую точку отсчёта для position: sticky, и шапка с
   меню перестанут ехать за скроллом. Анимации появления реплик (chat-msg-in
   и прочие transform) этого не задевают — они на потомках ленты, не на
   предках липких блоков.
   ----------------------------------------------------------- */
.chat {
  padding: 0 var(--chat-pad-x);
  /* Подвала сайта на странице нет — чат занимает окно целиком до самого низа.

     Снизу оставлена пустой треть экрана. Это и спейсер, и упор прокрутки:
     свежая реплика после ответа встаёт на линию 2/3 высоты окна, а не
     липнет к нижнему краю (followTail в insurance-chat.js), и от неё вниз
     остаётся воздух — место, куда раскрываться спискам (выбор штата идёт
     вниз) и просто глазу отдохнуть. Пока клиент листает ленту, сообщения
     занимают весь экран; треть пустоты появляется только у самого нижнего
     сообщения, где прокрутка упирается в этот спейсер. */
  min-height: 60vh;
  padding-bottom: 33vh;
  padding-bottom: 33dvh;
  background-color: var(--c-page);
  color: var(--c-body);
  font-family: "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: var(--chat-fs);
  line-height: var(--chat-lh);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}

.chat__layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--chat-w) minmax(0, 1fr);
  align-items: start;
  width: var(--chat-page-w);
  max-width: 100%;
  margin: 0 auto;
  /* 64px от подводки шапки до первой реплики. */
  padding-top: 64px;
}

@media (max-width: 767px) {
  /* В мобильном макете первое облако стоит в 40px от подводки, а не в 64px
     (node 960:1863: подводка на 97, лента с 137). */
  .chat__layout {
    padding-top: 40px;
  }
}

/* --- Навигация по разделам -----------------------------------
   Источник: Figma, node 788:647. В макете она стоит у верхнего края
   контента; здесь ещё и липнет к окну — едет за клиентом, как и шапка.

   top отсчитывается от низа липкой шапки (--chat-header-h + 24px), иначе
   меню уезжало бы под неё. z-index ниже шапки (30), но меню и лента по
   горизонтали не пересекаются, так что это только на всякий случай.
   Как и для шапки: transform/filter/will-change/contain на предках
   (.chat__layout, .chat, <main>) сломают липкость — не ставить.
   ----------------------------------------------------------- */
.chat__sections {
  grid-column: 1;
  position: sticky;
  top: calc(var(--chat-header-h) + 24px);
  z-index: 20;
  justify-self: start;
  width: var(--chat-aside-w);
}

.chat__sections-list {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.chat__section {
  width: 100%;
  color: var(--c-muted);
  transition: color 0.2s ease;
}

.chat__section:hover,
.chat__section:focus-visible {
  outline: none;
  color: var(--c-body);
}

/* Текущий раздел — фирменным тоном, как в макете. Он же остаётся
   подсвеченным при наведении на соседние: подсветка курсора не должна
   спорить с «вы находитесь здесь». */
.chat__section--current,
.chat__section--current:hover,
.chat__section--current:focus-visible {
  color: var(--c-primary);
}

@media (max-width: 1279px) {
  /* Ниже 1280px боковой колонки не остаётся: лента 720px и поля съедают
     всю ширину. Навигация убирается совсем, а не сжимается в нечитаемую
     полосу — по ленте на таком экране проще прокрутить. */
  .chat__layout {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
  }

  .chat__sections {
    display: none;
  }
}

/* --- Лента ---------------------------------------------------
   Одна реплика — одна строка: облако собеседника и ответ клиента никогда не
   встают рядом, даже когда идут подряд (в макете 788:334 они всегда друг
   под другом). Поэтому лента — колонка, а сторону задаёт сама реплика:
   собеседник жмётся влево, клиент вправо.

   --chat-side — ширина облака из макета: 2 доли из 2 / 0.25 / 2, то есть
   8/17 от строки за вычетом просвета между сторонами. Карточки направлений
   и продуктов её перекрывают и занимают всю ширину ленты.
   ----------------------------------------------------------- */
.chat__thread {
  --chat-side: calc((100% - 2 * var(--chat-gap)) * 8 / 17);
  grid-column: 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--chat-gap);
  align-content: start;
  width: 100%;
  max-width: var(--chat-w);
  /* followTail (insurance-chat.js) сам доводит ленту к линии 2/3, пока
     подрастают облака нового шага, и по рассинхрону с прокруткой окна
     понимает, что дальше листает клиент. Anchor-скролл браузера сдвигал бы
     окно под растущей высотой ленты сам — и эта доводка читалась бы как
     прокрутка клиента, обрывая эффект на первом же такте. */
  overflow-anchor: none;
}

@media (max-width: 1279px) {
  .chat__thread {
    grid-column: 1;
  }
}

@media (max-width: 767px) {
  /* Мобильная лента (node 960:1913) — не сжатая десктопная, а своя сетка:
     две колонки 1fr / 0.25fr с тем же шагом 16px. Сторона выходит 4/5 от
     строки — ровно 243.2px из 320 макетных. Средней колонки, которая на
     десктопе разводит стороны, здесь нет: облако собеседника прижато к
     левому краю, ответ клиента — к правому, ширина у обоих одна.

     Раньше здесь стояла доля 5/12 — вдвое уже макетной; от неё облака на
     телефоне и выглядели узкими столбиками. */
  .chat__thread {
    --chat-side: calc((100% - var(--chat-gap)) * 4 / 5);
  }
}

/* --- Реплики -------------------------------------------------
   Реплика — ячейка сетки: собеседник в первой колонке, клиент в третьей.
   Внутри ячейки она сама столбик: карточка собеседника (если он сменился),
   облако, «Вернуться».
   ----------------------------------------------------------- */
.chat__msg {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-self: start;
  min-width: 0;
}

/* Прокрутка к реплике (клик по разделу в меню, followTail и focusPrompt в
   insurance-chat.js зовут scrollIntoView) оставляет зазор под липкую
   шапку — иначе верх цели уезжает ей за край. Один отступ на реплику и на
   поле ввода закрывает все вызовы scrollIntoView в ленте. */
.chat__msg,
.chat__prompt {
  scroll-margin-top: calc(var(--chat-header-h) + 24px);
}

.chat__msg--bot {
  width: var(--chat-side);
  align-items: flex-start;
}

.chat__msg--user {
  width: var(--chat-side);
  margin-left: auto;
  align-items: flex-end;
}

/* Начало следующего хода разговора (его размечает chat_flow.Turn). Сейчас
   стоит на базовом шаге сетки — 16px, как и любые две реплики подряд:
   --chat-gap-turn равен --chat-gap, и добавка нулевая. Разведёт этапы
   шире только подъём --chat-gap-turn над --chat-gap. */
.chat__msg--turn {
  margin-top: calc(var(--chat-gap-turn) - var(--chat-gap));
}

/* Смена собеседника — не просто следующая реплика, а новый разговор:
   в макете (node 810:3909) перед карточкой стоят 64px. Первой карточке
   ленты добирать нечего — над ней и так подводка шапки. */
.chat__msg--intro:not(:first-child) {
  margin-top: 48px;
}

.chat__bubble {
  width: 100%;
  padding: var(--chat-bubble-pad-y) var(--chat-bubble-pad-x);
  border-radius: var(--chat-radius);
  overflow-wrap: anywhere;
}

/* Хвостик облака — незакруглённый угол снизу: у собеседника слева, у
   клиента справа. Это единственное, чем облака различаются по форме. */
.chat__msg--bot .chat__bubble {
  border-bottom-left-radius: 0;
  background-color: var(--c-surface);
}

.chat__msg--user .chat__bubble {
  border-bottom-right-radius: 0;
  background-color: var(--c-tint);
}

/* Подстановки из ответов клиента: имя, штат, продукт, номер обращения. */
.chat__accent {
  color: var(--c-primary);
}

/* --- Карточка собеседника ------------------------------------
   Источник: Figma, nodes 809:3568 (компания) и 807:3400 (агент). Встаёт
   там, где собеседник сменился, и отделяется подводкой во всю ширину
   колонки.
   ----------------------------------------------------------- */
/* Подводка не во всю ширину колонки, а с отступом 8px по краям — ровно как
   аватар и подпись над ней (node 809:3509: x=8, ширина 307.765 из 323.765).
   Поэтому она нарисована фоном на псевдоэлементе, а не border-bottom самой
   карточки: тот тянулся бы по всей ширине padding-box. */
.chat__speaker {
  position: relative;
  display: flex;
  align-items: center;
  gap: 16px;
  width: 100%;
  padding: 0 8px 16px;
  /* 16px до первого облака под подводкой — тот же шаг, что и в макете
     (8px здесь плюс 8px просвета между детьми реплики). */
  margin-bottom: 8px;
}

.chat__speaker::after {
  content: "";
  position: absolute;
  right: 8px;
  bottom: 0;
  left: 8px;
  height: 1px;
  border-radius: 1px;
  background-color: var(--c-border);
}

/* Фото агента вписано в кружок по большей стороне — в макете оно так же
   выходит за кадр сверху и снизу. */
.chat__speaker-photo {
  flex: 0 0 auto;
  display: block;
  width: 62px;
  height: 62px;
  border-radius: 50%;
  border: 1px solid var(--c-border);
  background-color: var(--c-border);
  object-fit: cover;
}

/* Метка компании (icons/chat/company-mark.svg, node 809:3568) — уже готовый
   кружок с обводкой и логотипом. Рамку и фото-подложку, нужные фотографии
   агента, с неё снимаем, иначе обводка задваивается. */
.chat__speaker-photo--mark {
  border: 0;
  background-color: transparent;
  object-fit: fill;
}

.chat__speaker-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.chat__speaker-role,
.chat__speaker-note {
  color: var(--c-muted);
  font-size: 12px;
  line-height: 16px;
  letter-spacing: 0.01em;
}

.chat__speaker-name {
  color: var(--c-body);
  font-size: 15px;
  line-height: 22px;
}

/* --- «Вернуться» ---------------------------------------------
   Источник: Figma, node 795:2133. Стоит под ответом клиента и сбрасывает
   диалог вплоть до этой реплики.

   В покое кнопки не видно: в ленте, где ответов много, десяток серых
   стрелок вдоль правого края читался бы как список действий, а не как
   подпись к одному сообщению. Проступает по наведению на саму реплику —
   и по фокусу с клавиатуры, иначе до неё было бы не добраться.
   ----------------------------------------------------------- */
.chat__back {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--c-border);
  font-size: 13px;
  line-height: 18px;
  letter-spacing: 0.01em;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.18s ease, color 0.18s ease;
}

.chat__back-icon {
  flex: 0 0 auto;
  display: block;
  width: 16px;
  height: 16px;
}

.chat__msg:hover .chat__back,
.chat__msg:focus-within .chat__back {
  opacity: 1;
}

.chat__back:hover,
.chat__back:focus-visible {
  outline: none;
  color: var(--c-primary);
}

@media (hover: none) {
  /* Без курсора наводить нечем: на тач-экранах кнопка видна всегда. */
  .chat__back {
    opacity: 1;
  }
}

/* --- Появление ------------------------------------------------
   Реплики выходят по одной с нарастающей задержкой (--reveal её ставит
   landing/chat_flow.py, mark_new). Здесь — только появление самого облака;
   что происходит внутри него у реплик собеседника (индикатор «печатает…»,
   потом текст) — в следующем блоке.

   fill-mode — backwards: до своей задержки реплика уже спрятана, но
   после анимации возвращается к обычным стилям и не тащит за собой
   застывший transform.
   ----------------------------------------------------------- */
@keyframes chat-msg-in {
  from {
    opacity: 0;
    transform: translate3d(0, 8px, 0);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

.chat__msg--new,
.chat__prompt.chat__msg--new {
  animation: chat-msg-in 440ms var(--reveal, 0ms) var(--chat-ease) backwards;
}

/* Спокойный режим: реплики просто появляются на своих местах. Задержки
   остаются — они часть подачи диалога, а не украшение. */
@media (prefers-reduced-motion: reduce) {
  .chat__msg--new,
  .chat__prompt.chat__msg--new {
    animation-name: chat-fade-in;
  }
}

@keyframes chat-fade-in {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

/* --- Индикатор «печатает…» -------------------------------------
   Только у реплик собеседника (.chat__msg--typing — это is_new && typing
   вместе, см. landing/chat_flow.py, mark_new). Три точки пульсируют ровно
   --typing мс начиная с --reveal — момента, когда встаёт само облако, —
   а затем внутри того же облака разворачивается текст. Ответ клиента
   приходит без этой разметки вовсе: он не «печатается» на глазах у себя.

   Разворот сделан как «шторка», а не как набор текста. На засечке
   --reveal + --typing одновременно:
     • точки в хвосте окна тают (opacity + лёгкий scale вниз) и лишь потом,
       уже невидимыми, выпадают из потока — не пропадают рывком;
     • облако (.chat__bubble) едет из размера трёх точек в полную сторону
       по --chat-ease, с overflow: hidden — текст под скруглённым краем,
       ничего не торчит наружу, пока коробка догоняет;
     • текст лежит сразу на финальной ширине (не переверстывается по
       мере роста коробки) и проступает: opacity 0→1 и подъём на 6px,
       с отставанием в 40мс, чтобы читалось как «облако надувается под
       готовый текст», а не «коробка и буквы стартуют вместе».

   Точки и текст никогда не в потоке одновременно: пока точки видны,
   .chat__bubble-text вынут из разметки (display: none). display в
   keyframes «дискретный» — переключается ровно на границе кадра, не
   интерполируется; opacity, transform, width, max-height едут плавно.

   both — animation-fill-mode: до своей задержки всё уже в кадре 0%
   (backwards), после окна — остаётся в кадре 100% (forwards).

   Важно: «отдыхающее» (вне анимации) значение display у .chat__typing и
   .chat__bubble-text НЕ none — оно инлайновое, как у обычного текста.
   Прятать элемент статичным display: none нельзя: браузер тогда решает,
   что анимировать нечего, и не создаёт анимацию вовсе (display: none
   выключает элемент из рендера ДО того, как до него доходит очередь
   анимаций) — именно так индикатор молчал в первой версии этого блока.
   Скрытие на время задержки делает сам backwards-кадр 0%, а не статика.
   ----------------------------------------------------------- */
.chat__typing {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: var(--chat-lh);
  transform-origin: left center;
}

.chat__msg--typing .chat__typing {
  animation: chat-typing-window linear both;
  animation-delay: var(--reveal, 0ms);
  animation-duration: var(--typing, 0ms);
}

@keyframes chat-typing-window {
  0% {
    display: none;
  }

  /* Кадр вплотную к нулю, а не ровно на нём: keyframe на 0% с иным
     значением, чем «before» (0%, само собой), схлопнулся бы с ним в один
     и тот же момент времени, и точки либо не появились бы вовсе, либо
     появились без паузы — эффект «печатает» пропал бы. */
  0.1% {
    display: inline-flex;
    opacity: 1;
    transform: none;
  }

  /* Хвост окна — точки гаснут ещё в потоке, а из разметки выпадают уже
     прозрачными: без этого был виден «щелчок» их исчезновения. */
  88% {
    opacity: 1;
    transform: none;
    animation-timing-function: ease-in;
  }

  99.9% {
    display: inline-flex;
    opacity: 0;
    transform: scale(0.8) translateY(1px);
  }

  100% {
    display: none;
  }
}

.chat__typing-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background-color: var(--c-muted);
  animation: chat-typing-pulse 1.4s ease-in-out infinite;
}

.chat__typing-dot:nth-child(2) {
  animation-delay: 0.18s;
}

.chat__typing-dot:nth-child(3) {
  animation-delay: 0.36s;
}

/* Мягкая «дышащая» пульсация вместо подскока: масштаб и прозрачность
   ходят синусоидой, без вертикального рывка. */
@keyframes chat-typing-pulse {
  0%,
  100% {
    transform: scale(0.68);
    opacity: 0.32;
  }

  50% {
    transform: scale(1);
    opacity: 1;
  }
}

/* Текст реплики: у обычных сообщений в потоке сразу; у «печатающихся» —
   вынут из потока (display: none), пока пульсируют точки, и разворачивается
   на засечке --reveal + --typing.

   display меняется дискретно; блочный дисплей нужен, чтобы к строке
   применился transform (к инлайну он не применяется). */
.chat__bubble-text {
  display: inline;
}

.chat__msg--typing .chat__bubble-text {
  animation: chat-typing-text-in 340ms var(--chat-ease) both;
  animation-delay: calc(var(--reveal, 0ms) + var(--typing, 0ms) + 40ms);
}

/* Пиннинг ширины текста — только от 1024px, и только он: коробка растёт, а
   текст с первого кадра лежит на финальной ширине и под ней не
   переверстывается — облако с overflow: hidden открывает уже готовые
   строки, как шторка.

   Ширина считается от --chat-w статикой, а не процентом: процент считался
   бы от самой коробки, а она в этот момент едет. Значит, число верно ровно
   там, где лента гарантированно 720px, — с 1024px и выше. Ниже лента уже
   уже: на 800px это 705px, на мобиле — вся ширина экрана за полями. Там
   пиннинга нет, текст просто перетекает вслед за коробкой; разворот на
   узком экране и так короткий.

   Раньше это правило стояло без медиазапроса, а снимал его override в
   блоке ≤767px — но тот лежит в файле ВЫШЕ, и при равной специфичности
   проигрывал по порядку. Пиннинг в 275.76px действовал и на мобиле: текст
   на 57px вылезал из облака 243px и оставался торчать после разворота,
   пока следующий ответ сервера не перерисовывал реплику уже без --typing.
   Отсюда и «выступающий текст», который сам приходил в норму. */
@media (min-width: 1024px) {
  .chat__msg--typing .chat__bubble-text {
    width: calc((var(--chat-w) - 2 * var(--chat-gap)) * 8 / 17 - 2 * var(--chat-bubble-pad-x));
  }
}

@keyframes chat-typing-text-in {
  0% {
    display: none;
    opacity: 0;
  }

  0.1% {
    display: block;
    opacity: 0;
    transform: translateY(6px);
  }

  100% {
    display: block;
    opacity: 1;
    transform: none;
  }
}

/* Облако разворачивается из размера трёх точек в полную сторону на засечке
   --reveal + --typing. overflow: hidden держит текст под скруглённым краем,
   пока ширина и высота догоняют, — наружу ничего не торчит. max-height
   ведёт высоту: у коротких реплик коробка «открывается» за первые кадры
   кривой, у длинных — тянется дольше; на 100% overflow снова visible, так
   что реплику длиннее потолка ничто не срежет. Размеры from — из геометрии
   точек: 3 точки по 6px + 2 просвета по 5px + поля облака; по высоте —
   строка + поля. */
.chat__msg--typing .chat__bubble {
  overflow: hidden;
  animation: chat-bubble-grow 380ms var(--chat-ease) both;
  animation-delay: calc(var(--reveal, 0ms) + var(--typing, 0ms));
}

@keyframes chat-bubble-grow {
  from {
    width: calc(3 * 6px + 2 * 5px + 2 * var(--chat-bubble-pad-x));
    max-height: calc(var(--chat-lh) + 2 * var(--chat-bubble-pad-y));
    overflow: hidden;
  }

  99.9% {
    max-height: 12em;
    overflow: hidden;
  }

  to {
    width: 100%;
    /* none, а не число: после разворота высоту ничто не ограничивает даже
       у реплики длиннее потолка (её открывшийся хвост — один кадр на самом
       конце кривой, где движение уже почти замерло). */
    max-height: none;
    overflow: visible;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Пауза на «печать» и разворот облака остаются — это часть подачи диалога
     и повод дочитать предыдущую реплику. Снимаем только то, что дёргается:
     пульс точек и подъём текста; облако просто проявляется. */
  .chat__typing-dot {
    animation: none;
    opacity: 0.85;
  }

  .chat__msg--typing .chat__bubble-text {
    animation-name: chat-typing-text-fade;
  }
}

@keyframes chat-typing-text-fade {
  0% {
    display: none;
    opacity: 0;
  }

  0.1% {
    display: block;
    opacity: 0;
  }

  100% {
    display: block;
    opacity: 1;
  }
}

/* --- Ввод ----------------------------------------------------
   Поле встаёт на место реплики собеседника — в первую колонку ленты, той
   же ширины, что и облако вопроса над ним. Карточки выбора и поиск штата
   занимают все три колонки: под них в макете отведена вся ширина ленты.
   ----------------------------------------------------------- */
.chat__prompt {
  width: var(--chat-side);
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}

.chat__prompt--wide {
  width: 100%;
}

@media (max-width: 767px) {
  /* Широкого режима на узком экране нет: лента двухколоночная, и карточки
     направлений и продуктов стоят в той же колонке, что облака вопросов
     над ними (node 960:2040). */
  .chat__prompt--wide {
    width: var(--chat-side);
  }
}

.chat__form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.chat__search {
  position: relative;
}

/* --- Поле ввода ----------------------------------------------
   Источник: Figma, node 807:1981 — высота 56px, значок 16px слева,
   подсказка приглушённая. Фон тот же, что у облака собеседника: поле стоит
   на его месте и продолжает разговор, а не открывает форму.
   ----------------------------------------------------------- */
.chat__field-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.chat__field {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  /* 10px — замер по node 807:3336: значок 24…40, текст с 50. У поиска штата
     свой зазор, 12px (node 809:3677). */
  gap: 10px;
  min-width: 0;
  height: var(--chat-field-h);
  padding: 0 var(--chat-bubble-pad-x);
  border: 1px solid transparent;
  border-radius: var(--chat-radius);
  background-color: var(--c-surface);
  cursor: text;
  transition: border-color 0.2s ease, background-color 0.2s ease;
}

/* Фон и рамка поля не меняются ни на фокусе, ни на наведении: во всех
   четырёх вариантах макета (node 795:2425) поле остаётся #f5efe9, а
   состояние показывает кнопка отправки рядом. */
.chat__field--search {
  gap: 12px;
}

.chat__field-icon,
.chat__field-chevron {
  flex: 0 0 auto;
  display: block;
  width: 16px;
  height: 16px;
}

/* Шеврон поиска штата прижат к правому краю поля — знак «здесь есть что
   развернуть». Не переворачивается: в макете у него одно состояние. */
.chat__field-chevron {
  margin-left: auto;
}

.chat__input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--c-body);
  font-family: inherit;
  font-size: var(--chat-fs);
  line-height: var(--chat-lh);
  font-weight: 400;
}

.chat__input:focus {
  outline: none;
}

.chat__input::placeholder {
  color: var(--c-muted);
  opacity: 1;
}

/* Телефон не прошёл проверку на номер США — рамка поля краснеет. Признак
   ставит insurance-chat.js (aria-invalid), сам разбор — landing/chat_flow.py.
   Пустое поле не краснеет: пусто — ещё не ошибка. */
.chat__field:has(.chat__input[aria-invalid="true"]) {
  border-color: var(--c-danger);
}

/* --- Раскрывающийся список ---------------------------------
   Источник: Figma, node 807:3357 — «Удобное время» со значком часов слева и
   шевроном справа; той же разметкой отдаётся выбор возраста. Собран по
   образцу поиска штата (.chat__options), а не системным <select>: тот на
   бежевом фоне читается как чужой виджет.
   ----------------------------------------------------------- */
.chat__combo {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
}

/* Родной список — хранилище значения и запасной вариант. Виден, пока
   insurance-chat.js не подменил его своей шапкой (.is-enhanced). */
.chat__combo-native {
  flex: 1 1 auto;
  min-width: 0;
  height: var(--chat-field-h);
  padding: 0 var(--chat-bubble-pad-x);
  border: 1px solid transparent;
  border-radius: var(--chat-radius);
  background-color: var(--c-surface);
  color: var(--c-body);
  font-family: inherit;
  font-size: var(--chat-fs);
  cursor: pointer;
}

/* Пока не выбрано — подсказка приглушена, как ::placeholder у текстовых полей. */
.chat__combo-native:invalid {
  color: var(--c-muted);
}

.chat__combo.is-enhanced .chat__combo-native {
  display: none;
}

/* Шапка списка — та же полоса 56px, что и поле ввода, только кликабельная. */
.chat__field--combo {
  width: 100%;
  cursor: pointer;
  text-align: left;
}

.chat__combo-value {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--c-muted);
}

/* Выбор сделан — значение в шапке тёмное, как набранный текст. */
.chat__combo.is-filled .chat__combo-value {
  color: var(--c-body);
}

/* Единственный шеврон в форме, который переворачивается: у поиска штата
   состояние одно, здесь их два — закрыт и раскрыт. */
.chat__field--combo .chat__field-chevron {
  transition: transform 0.16s ease;
}

.chat__field--combo[aria-expanded="true"] .chat__field-chevron {
  transform: rotate(180deg);
}

.chat__combo.is-open .chat__options--combo {
  opacity: 1;
  visibility: visible;
  transform: none;
}

/* Строка списка — кнопка, как у подсказок штата; выбранную подсвечиваем
   фирменным, как отмеченный вариант «Пола». */
.chat__option--combo[aria-selected="true"] {
  background-color: var(--c-tint);
}

.chat__option--combo[aria-selected="true"] .chat__option-name {
  color: var(--c-primary);
}

/* --- Точки этапов --------------------------------------------
   Источник: Figma, node 807:1985. Появляются, когда полей у шага больше
   одного и insurance-chat.js показывает их по очереди: точки говорят,
   сколько вопросов осталось. Без скрипта этапов нет — нет и точек, их
   рисует тот же скрипт.
   ----------------------------------------------------------- */
.chat__steps {
  display: flex;
  align-items: center;
  gap: 8px;
  justify-content: center;
}

/* Точка текущего этапа крупнее остальных: 10px против 8px (замер по
   node 807:3341 — окружности r=5 и r=4). Пройденные и предстоящие этапы в
   макете не различаются, поэтому и здесь у них один цвет. */
.chat__step-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: var(--c-muted);
  transition: width 0.2s ease, height 0.2s ease, background-color 0.2s ease;
}

.chat__step-dot--current {
  width: 10px;
  height: 10px;
  background-color: var(--c-primary);
}

/* Пока идут этапы, в потоке стоит только текущее поле — остальные ждут
   своей очереди. Класс вешает скрипт: без него все поля видны сразу. */
.chat__form--wizard .chat__field-row {
  display: none;
}

.chat__form--wizard .chat__field-row--current {
  display: flex;
}

/* --- Выбор варианта ----------------------------------------
   Источник: Figma, node 807:1794 — этап «Пол»: вместо поля ввода две кнопки
   в ряд, «Мужской» / «Женский», без значка слева. Под кнопками — настоящие
   radio: выбор и отправка формы работают и без скрипта.
   ----------------------------------------------------------- */
.chat__choice {
  display: flex;
  flex: 1 1 auto;
  gap: 8px;
  min-width: 0;
}

.chat__choice-option {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  height: var(--chat-field-h);
  padding: 0 var(--chat-bubble-pad-x);
  border: 1px solid transparent;
  border-radius: var(--chat-radius);
  background-color: var(--c-surface);
  color: var(--c-muted);
  font-size: var(--chat-fs);
  line-height: var(--chat-lh);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

/* Настоящий radio спрятан — метку рисует сама кнопка; фокус с клавиатуры
   показываем рамкой на ней. */
.chat__choice-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.chat__choice-option:hover {
  background-color: var(--c-tint);
  color: var(--c-primary);
}

.chat__choice-option:has(.chat__choice-input:focus-visible) {
  border-color: var(--c-primary);
}

/* Отмеченный вариант — фирменным, как облако ответа клиента: выбор и есть
   реплика в диалоге. */
.chat__choice-option:has(.chat__choice-input:checked) {
  background-color: var(--c-tint);
  color: var(--c-primary);
}

/* --- Кулдаун -------------------------------------------------
   Источник: Figma, node 810:4156. Стоит рядом с полем кода: пока он тикает,
   новый код не запросить. Отсчёт ведёт insurance-chat.js — сервер о нём не
   знает, как не знает и о самом коде.
   ----------------------------------------------------------- */
.chat__cooldown {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: var(--chat-field-h);
  padding: 0 var(--chat-bubble-pad-x);
  border-radius: var(--chat-radius);
  background-color: var(--c-surface);
  color: var(--c-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

@media (max-width: 767px) {
  /* В колонке 243px рядом с полем кода и кнопкой отправки макетные поля
     счётчика съедали бы само поле кода почти целиком. */
  .chat__cooldown {
    padding: 0 12px;
  }
}

/* --- Подпись под полем ---------------------------------------
   Источник: Figma, nodes 807:3350 и 809:3597. Она английская, и это не
   недосмотр: формулировки про звонки и обработку данных живут на языке
   регулятора и не переводятся.
   ----------------------------------------------------------- */
.chat__note {
  color: var(--c-muted);
  font-size: 13px;
  line-height: 18px;
  letter-spacing: 0.01em;
  text-align: center;
}

/* Ссылка не подчёркнута: в макете (node 807:3350) это вторая строка той же
   подписи, тем же цветом и без выделения. Что это ссылка, показывает
   наведение. */
.chat__note-link {
  color: var(--c-muted);
  /* landing.css задаёт a { font-size: var(--p1-font-size) } — без явного
     inherit ссылка вылезает крупнее самой подписи. */
  font-size: inherit;
  line-height: inherit;
  text-decoration: none;
  transition: color 0.2s ease;
}

.chat__note-link:hover,
.chat__note-link:focus-visible {
  outline: none;
  color: var(--c-primary);
}

/* --- Отправка ответа -----------------------------------------
   Источник: Figma, node 795:2425 — варианты Default / Active / Hover / Push.
   Квадрат 56×56 рядом с полем, шаг 8px.

   В покое (Default) кнопки нет вовсе: поле пустое, отправлять нечего.
   Появляется она ровно тогда, когда в поле что-то набрано, — это и есть
   Active. Условие на :placeholder-shown, а не на классе от скрипта: кнопка
   должна работать и до того, как выполнится JS, иначе ответ отправить будет
   нечем.
   ----------------------------------------------------------- */
.chat__send {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--chat-field-h);
  height: var(--chat-field-h);
  border-radius: var(--chat-radius);
  background-color: var(--c-surface);
  color: var(--c-muted);
  transition: background-color 0.2s ease, color 0.2s ease;
}

/* Пустое поле — кнопки нет. display: none, а не прозрачность: при gap: 8px
   спрятанный прозрачностью квадрат оставил бы после поля пустое место
   шириной 64px, которого в варианте Default нет. */
.chat__field-row:has(.chat__input:placeholder-shown) .chat__send {
  display: none;
}

.chat__send:hover,
.chat__send:focus-visible {
  outline: none;
  background-color: var(--c-tint);
  color: var(--c-primary);
}

/* Push: нажатая кнопка заливается фирменным, а шеврон уходит в тинт —
   единственное место в форме, где цвета меняются местами. */
.chat__send:active {
  background-color: var(--c-primary);
  color: var(--c-tint);
}

.chat__send-icon {
  display: block;
  width: 16px;
  height: 16px;
}

/* --- Подсказки к поиску штата ---------------------------------
   Список раскрывается на :focus-within, без скрипта: кнопка подсказки
   лежит внутри той же обёртки, поэтому клик по ней фокус не теряет.

   Панель абсолютная — иначе лента прыгала бы по высоте на каждой букве,
   а поле уезжало бы из-под курсора.
   ----------------------------------------------------------- */
.chat__options {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  z-index: 5;
  /* Штатов полсотни, и все они в списке сразу: высота ограничена так,
     чтобы было видно ровно «список продолжается», а не полстраницы. */
  max-height: 296px;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 8px;
  border: 1px solid var(--c-border);
  border-radius: var(--chat-radius);
  /* Фон страницы, а не белый: белая плашка на бежевом читается как чужой
     системный виджет — тот же разнобой, что у стандартного <select>. */
  background-color: var(--c-page);
  box-shadow: 0 16px 32px -12px rgb(74 67 61 / 0.22);
  opacity: 0;
  visibility: hidden;
  transform: translate3d(0, -4px, 0);
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0.16s;

  /* Полоса прокрутки в тех же тонах, что и рамки: системная синяя выбивалась
     из палитры сильнее всего остального в списке. */
  scrollbar-width: thin;
  scrollbar-color: var(--c-border) transparent;
}

.chat__options::-webkit-scrollbar {
  width: 10px;
}

.chat__options::-webkit-scrollbar-track {
  background: transparent;
}

.chat__options::-webkit-scrollbar-thumb {
  border: 3px solid transparent;
  border-radius: 999px;
  background-color: var(--c-border);
  background-clip: content-box;
}

.chat__options::-webkit-scrollbar-thumb:hover {
  background-color: var(--c-muted);
}

.chat__search:focus-within .chat__options,
.chat__search.is-open .chat__options {
  opacity: 1;
  visibility: visible;
  transform: none;
}

.chat__option {
  display: flex;
  align-items: baseline;
  gap: 12px;
  width: 100%;
  padding: 10px 16px;
  border-radius: 6px;
  transition: background-color 0.15s ease, color 0.15s ease;
}

/* Наведение подсвечивает строку тем же розовым, что и облако ответа: список
   показывает будущую реплику клиента, а не пункт меню. */
.chat__option:hover,
.chat__option:focus-visible {
  outline: none;
  background-color: var(--c-tint);
}

.chat__option-name {
  color: var(--c-body);
}

.chat__option:hover .chat__option-name,
.chat__option:focus-visible .chat__option-name {
  color: var(--c-primary);
}

/* Английское название — подсказка для тех, кто набирает «Texas». Прижато
   вправо и мельче: это опора для поиска, а не второй заголовок строки. */
.chat__option-en {
  margin-left: auto;
  color: var(--c-muted);
  font-size: 13px;
  line-height: 18px;
  white-space: nowrap;
}

.chat__option-empty {
  padding: 10px 16px;
  color: var(--c-muted);
}

@media (max-width: 767px) {
  /* Английское название — опора для поиска, а не часть строки: в панели
     шириной в колонку (243px) оно отжимало бы русское название на две
     строки. Поиск по нему (chat_flow.search_states) работает и без показа. */
  .chat__option-en {
    display: none;
  }
}

/* --- Карточки выбора -----------------------------------------
   Направления: node 749:2905, четыре в ряд, карточка 250px, шаг 16px.
   Продукты:   node 764:643, две в ряд, карточка 250px, поля 32px.

   У обеих текст прижат к нижнему краю: в макете он висит на фиксированной
   высоте, но подсказка в одну или три строки не должна ломать карточку.
   ----------------------------------------------------------- */
.chat__cards {
  display: grid;
  gap: 16px;
}

.chat__cards--directions {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

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

@media (max-width: 767px) {
  /* Колонка ленты на мобиле — 243px (см. .chat__thread): карточки встают в
     неё по одной. Обе сетки одинаково, как в макете (node 960:2040), а не
     разными столбцами: два столбца направлений в этой колонке дали бы по
     113px на карточку — туда не влезает ни «Имущество», ни подсказка. */
  .chat__cards--directions,
  .chat__cards--products {
    grid-template-columns: minmax(0, 1fr);
  }
}

.chat__card {
  display: flex;
  flex-direction: column;
  /* Прозрачная рамка держит геометрию: у активной карточки меняется только
     её цвет, поэтому сетка не дёргается на наведении. */
  border: 1px solid transparent;
  border-radius: 16px;
  background-color: var(--c-surface);
}

.chat__card-body {
  display: flex;
  flex-direction: column;
  width: 100%;
  /* Прижимает текст к нижнему краю карточки. */
  margin-top: auto;
}

/* Кегль и интерлиньяж заданы явно, а не наследуются от страницы: на мобильном
   --chat-lh падает до 20px, и текстовый блок карточки становился ниже —
   название уезжало с макетной высоты. */
.chat__card-title {
  color: var(--c-body);
  font-size: 16px;
  line-height: 24px;
  font-weight: 500;
}

.chat__card-hint {
  color: var(--c-muted);
  font-size: 13px;
  line-height: 18px;
}

/* --- Карточка направления ------------------------------------
   Иллюстрации — те же карандашные рисунки, что на плитках главной.
   Кадрирование из макета запечено в сам файл скриптом, а не выражено в CSS:
   в макете у каждого рисунка свой вылет за кадр, и четыре набора процентов
   в стилях пришлось бы держать в голове при каждой правке.
   ----------------------------------------------------------- */
.chat__card--direction {
  position: relative;
  align-items: center;
  height: 250px;
  padding: 32px 13px;
  text-align: center;
}

.chat__card-art {
  display: block;
  width: 89px;
  height: 89px;
}

.chat__card--direction .chat__card-body {
  gap: 8px;
}

.chat__card--direction .chat__card-title {
  /* В макете название направления полужирное — в отличие от продукта. */
  font-weight: 700;
}

.chat__card--direction .chat__card-hint {
  letter-spacing: 0.01em;
}

@media (max-width: 767px) {
  /* Поля 13px были расчётом на карточку 173px в ряду из четырёх; в одном
     столбце текст должен отступать от края так же, как в карточке продукта
     (node 960:2041). */
  .chat__card--direction {
    padding: 32px;
  }

  .chat__card--direction .chat__card-hint {
    font-size: 12px;
    line-height: 16px;
  }
}

/* Направление, продуктов в котором сейчас нет: карточка обесцвечена.
   В макете «Имущество» нарисовано наравне с остальными, но за ним пустой
   список продуктов — по такой карточке диалог упирался бы в тупик. */
.chat__card--off {
  cursor: default;
}

/* Рисунок обесцвечивается, а не гасится прозрачностью: приглушённый
   оранжевый на бежевом читается как выцветший, а серый — как выключенный. */
.chat__card--off .chat__card-art {
  filter: grayscale(1);
  opacity: 0.65;
}

.chat__card--off .chat__card-title {
  color: var(--c-muted);
}

/* Пометка «Скоро» лежит поверх карточки, а не в её потоке: в потоке она
   сдвигала бы рисунок и текст вверх, и карточка выбилась бы из ряда.
   Отступы — 10px от угла, поверх скругления 16px пометка не заезжает. */
.chat__card-note {
  position: absolute;
  top: 10px;
  right: 10px;
  padding: 2px 10px;
  border-radius: 999px;
  background-color: var(--c-border);
  color: var(--c-muted);
  font-size: 11px;
  line-height: 16px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* --- Карточка продукта ---------------------------------------
   Названия остаются английскими: это марки программ (ACA Marketplace,
   Medicare), под которыми их знают в США. Понятность даёт описание.
   ----------------------------------------------------------- */
.chat__card--product {
  height: 250px;
  padding: 32px;
  text-align: left;
}

.chat__card--product .chat__card-body {
  gap: 16px;
}

.chat__card--product .chat__card-title {
  font-size: 22px;
  line-height: 30px;
}

.chat__card--product .chat__card-hint {
  font-size: 14px;
  line-height: 20px;
}

@media (max-width: 767px) {
  /* Мобильная карточка (node 960:2041): вся ширина колонки, высота 175,
     поля 32, название «Mobile/H4» 16/22, описание «Mobile/Body Small» 12/16.

     min-height вместо height: в макете описание влезает в четыре строки, но
     в каталоге есть продукты с описанием длиннее, и жёсткая высота срезала
     бы им хвост. */
  .chat__card--product {
    height: auto;
    min-height: 175px;
    padding: 32px;
  }

  .chat__card--product .chat__card-title {
    font-size: 16px;
    line-height: 22px;
  }

  .chat__card--product .chat__card-hint {
    font-size: 12px;
    line-height: 16px;
  }
}

/* --- Наведение: «прожектор» ----------------------------------
   Состояние Active из макета: карточка заливается тинтом, контур и название
   уходят в фирменный тон, подсказка перестаёт быть приглушённой — на тинте
   --c-muted почти не читается.

   Соседние карточки гаснут до 0.45 — тот же приём, что у плиток главной
   (main.css, .home__tiles-grid). :has() висит на сетке, а не на карточке:
   иначе эффект срабатывал бы и когда курсор в промежутке между карточками,
   то есть активной нет ни одной.

   Всё под (hover: hover): на тач-экранах «прожектор» бессмыслен, а
   зависшее состояние после касания только мешает.
   ----------------------------------------------------------- */
@media (hover: hover) {
  .chat__card {
    transition: background-color 0.3s ease, border-color 0.3s ease,
      opacity 0.3s ease;
  }

  .chat__card-title,
  .chat__card-hint {
    transition: color 0.3s ease;
  }

  /* Неактивное направление «прожектор» не включает: выбрать его нельзя,
     и гасить из-за него остальные не за что. */
  .chat__cards:has(.chat__card:hover:not(.chat__card--off)) .chat__card {
    opacity: 0.45;
  }

  .chat__cards:has(.chat__card:hover:not(.chat__card--off)) .chat__card:hover {
    opacity: 1;
  }

  .chat__card:hover:not(.chat__card--off),
  .chat__card:focus-visible:not(.chat__card--off) {
    outline: none;
    border-color: var(--c-primary);
    background-color: var(--c-tint);
  }

  .chat__card:hover:not(.chat__card--off) .chat__card-title,
  .chat__card:focus-visible:not(.chat__card--off) .chat__card-title {
    color: var(--c-primary);
  }

  .chat__card:hover:not(.chat__card--off) .chat__card-hint,
  .chat__card:focus-visible:not(.chat__card--off) .chat__card-hint {
    color: var(--c-body);
  }
}

/* Без hover-указателя подсветка нужна хотя бы на фокусе — иначе с
   клавиатуры не видно, где ты находишься. */
@media not all and (hover: hover) {
  .chat__card:focus-visible:not(.chat__card--off) {
    outline: none;
    border-color: var(--c-primary);
    background-color: var(--c-tint);
  }
}

/* --- Действие в конце диалога --------------------------------
   Источник: Figma, node 810:4295 — «Перейти в личный кабинет». Кнопка
   выключена: кабинета, в который она ведёт, пока нет.
   ----------------------------------------------------------- */
/* Ссылка, а не кнопка: кабинет уже есть, и ведёт она наружу из диалога.
   Отсюда inline-flex с центровкой — у ссылки нет собственного выравнивания
   текста по высоте, которое кнопка давала даром. */
.chat__aside {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: var(--chat-field-h);
  padding: 0 var(--chat-bubble-pad-x);
  border-radius: var(--chat-radius);
  background-color: var(--c-surface);
  color: var(--c-muted);
  font-size: 13px;
  line-height: 18px;
  letter-spacing: 0.01em;
  text-align: center;
  text-decoration: none;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.chat__aside:hover,
.chat__aside:focus-visible {
  outline: none;
  background-color: var(--c-tint);
  color: var(--c-primary);
}
