
  /* ── углы экрана до входа ───────────────────────────────────────────────
     Шапки-полосы в кабинете нет: в углах просто стоят два знака. Оба живут
     в разметке всегда, но показываются только гостю — у клиента и логотип,
     и профиль стоят в панели слева. */
  /* Знак Pin.Point стоит всегда — это логотип кабинета и путь на первый экран.
     А вот знак человека только у гостя: у клиента в том же углу его профиль
     (.profile-foot, sidebar.css). */
  .hd-logo { display:flex }
  .hd-acc { display:none }
  .app.guest .hd-acc { display:flex }
  .hd-logo { position:absolute; z-index:12; left:24px; top:12px; height:42px;
             align-items:center; color:var(--ink); text-decoration:none }
  /* Знак поворачивается на 180° и подрастает — ровно как в шапке лендинга.
     Заодно фигура переходит во вторую, ту же, что в шапке лендинга. Обе
     записаны одной последовательностью команд и одинаковым числом координат,
     поэтому переход — это линейная смесь чисел, и считает её сам браузер:
     `d` здесь свойство CSS, а не атрибут разметки. Одна кривая (--spring) на
     поворот и на форму — иначе они разъезжаются во времени. Где свойство `d`
     не поддержано, знак просто поворачивается, без морфинга.
     Центр вращения тот же, что во Framer: 10 / 16. */
  .hd-mark { width:32px; height:42px; overflow:visible; flex:0 0 auto }
  .hd-mark path { transform-origin:10px 16px;
                  transition:transform var(--dur-logo) var(--spring),
                             d var(--dur-logo) var(--spring) }
  .hd-logo:hover .hd-mark path, .hd-logo:focus-visible .hd-mark path {
                  transform:rotate(180deg) scale(1.1);
                  d:path("M 7.944 29.256 L 20.364 16.378 C 20.52 16.216 20.792 16.432 20.675 16.625 L 11.486 31.716 C 11.327 31.978 10.974 32.045 10.703 31.866 L 8.075 30.13 C 7.768 29.927 7.704 29.505 7.944 29.256 Z M 0.889 19.218 L 17.782 15.444 C 18.334 15.321 18.683 16.056 18.265 16.459 L 7.688 26.618 C 6.408 27.847 4.393 27.489 3.555 25.884 L 0.522 20.077 C 0.341 19.732 0.526 19.299 0.889 19.218 Z M 5.162 3.26 L 19.811 13.532 C 19.995 13.661 20.221 13.397 20.069 13.23 L 8.17 0.169 C 7.964 -0.058 7.605 -0.056 7.373 0.172 L 5.124 2.377 C 4.861 2.635 4.879 3.061 5.162 3.26 Z M 0.561 14.488 L 17.87 14.667 C 18.436 14.673 18.624 13.881 18.131 13.574 L 5.672 5.836 C 4.165 4.901 2.268 5.67 1.782 7.414 L 0.023 13.724 C -0.082 14.1 0.189 14.485 0.56 14.489 Z") }
  /* Надпись не обрезается, а вырастает из-за знака и отодвигает всё справа:
     ширина — это тоже часть анимации. */
  .hd-word { display:block; flex:0 0 auto; width:0; overflow:hidden;
             transition:width var(--dur-logo) var(--spring) }
  .hd-word svg { display:block; margin-left:2px; width:68px; height:28px; max-width:none;
                 opacity:0; transform:scale(.5); transform-origin:left center;
                 transition:opacity var(--dur-logo) var(--spring),
                            transform var(--dur-logo) var(--spring) }
  .hd-logo:hover .hd-word, .hd-logo:focus-visible .hd-word { width:70px }
  .hd-logo:hover .hd-word svg, .hd-logo:focus-visible .hd-word svg { opacity:1; transform:none }
  /* Человек в правом углу: под курсором просто разрастается. */
  .hd-acc { position:absolute; z-index:12; right:24px; top:16px; width:25px; height:25px;
            padding:0; border:0; background:none; cursor:pointer; color:var(--ink);
            align-items:center; justify-content:center }
  .hd-acc svg { width:100%; height:100%; display:block;
                transition:transform var(--dur-logo) var(--spring) }
  .hd-acc:hover svg, .hd-acc:focus-visible svg { transform:scale(1.2) }

  /* ── основная область ── */
  .main { flex:1; display:flex; flex-direction:column; min-width:0; position:relative }
  /* overflow-x:clip, а не visible: при смене экрана содержимое приезжает
     справа со сдвигом (см. --in-x), и на узком окне этот сдвиг успевал
     показать горизонтальную полосу прокрутки. Рядом с overflow-y:auto clip по
     спецификации считается как hidden — полосы всё равно нет, а лишние 20-30px
     ширины живут только те доли секунды, пока идёт анимация, и браузер сам
     возвращает scrollLeft в ноль, когда переполнение исчезает. */
  .log { flex:1; overflow-y:auto; overflow-x:clip; padding:28px 0; position:relative }
  .wrap { max-width:720px; margin:0 auto; padding:0 20px; display:flex; flex-direction:column; gap:18px;
          transition:max-width .28s cubic-bezier(.22,.61,.36,1) }
  /* Шаг объявления работает в ДВЕ колонки (форма + превью), и колонки для чтения ему
     тесновато. Прибавка небольшая, около пятой части: широкая лента разъезжается и
     перестаёт читаться как чат, а полторы строки текста в поле экономит и такая. */
  .wrap.wide { max-width:860px }
  /* Реплики за лентой не тянутся: строка в 1120px не читается, а раскрыть переписку
     на этом шаге можно в любой момент. */
  .wrap.wide .bubble { max-width:46em }
  .row { display:flex }
  .row.user { justify-content:flex-end }
  .bubble { line-height:1.55; font-size:15px; white-space:pre-wrap; word-wrap:break-word }
  /* Выделение в реплике агента. Без этого правила <strong> в ленте не работал
     ВООБЩЕ: корпус набран переменным шрифтом через font-variation-settings, а он
     перебивает font-weight — жирное выглядело обычным текстом. Из-за этого в
     сборе данных рекламодателя не было видно, что именно спрашивают: вопрос
     «ИНН компании?» терялся среди пояснений к нему.
     Вес задаём осью, как велит система, а не font-weight. */
  .bubble strong, .bubble b { font-weight:400; font-variation-settings:var(--axis-active);
                              color:var(--ink) }
  /* ── реплика человека ──
     Ни плашки, ни глубины. В этой системе вдавленность означает ровно одно:
     «сюда можно нажать» — так набраны поле ввода, чипы и кнопки. Сказанное
     нажать нельзя, и объёмный блок под ним врал: реплика выглядела так же,
     как «Отправить снова» и «Другой номер» строкой выше.

     Отличаем тем же, чем система отличает всё остальное, — стороной и осью:
     слова человека прижаты вправо и набраны плотнее (wght 480), речь агента
     идёт слева обычным весом. Цвет у обоих один: делать реплику темнее значит
     кричать там, где достаточно сказать. */
  .user .bubble { max-width:82%; padding:0; border:0; border-radius:0;
                  background:none; box-shadow:none; text-align:right;
                  font-variation-settings:var(--axis-active) }
  .assistant .bubble { max-width:100% }
  .assistant .bubble.typing { color:var(--muted) }
  .empty { color:var(--ink-muted); text-align:center; margin-top:22vh;
           font-family:var(--font-script); font-weight:300; font-size:var(--fs-lead-sm) }
  /* Заставка нового чата: вопрос вместо инструкции — сразу задаёт, о чём говорить. */
  /* Отрицательного отступа больше нет: экран центрируется целиком (см. выше),
     а поднимать блок руками поверх этого значит спорить с самим собой. */
  .empty-hero { margin-top:0; display:flex; flex-direction:column; align-items:center }
  /* Знак и вопрос стоят вплотную: в макете их рамки даже слегка находят
     друг на друга — воздух между ними даёт сам рисунок, а не отступ. */
  .empty-hero svg { color:var(--ink-strong); margin-bottom:0 }
  /* Узкая гротеска: font-stretch подхватывают вариативные системные шрифты,
     PT Sans Narrow / Arial Narrow — запасной вариант для остальных. */
  /* Вопрос агента — та же роль, что заголовок первого экрана: 65px, тот же
     интерлиньяж и тот же цвет. Чистого чёрного здесь нет: в макете весь
     заголовочный шрифт набран на 80%. */
  .empty-hero h2 { margin:0; font-family:var(--font-display);
                   font-size:var(--fs-title); line-height:var(--lh-title); font-weight:700;
                   letter-spacing:0; color:var(--ink-strong); text-wrap:balance }
  .empty-hero p { margin:12px auto 0; max-width:620px; font-family:var(--font-script); font-weight:300;
                  font-size:var(--fs-lead-sm); line-height:var(--lh-lead-sm); color:var(--ink-strong);
                  text-wrap:balance }
  /* ── стартовый экран стоит по центру страницы ──
     По вертикали — посередине ленты (композер на этом экране скрыт, лента
     занимает всю высоту). По горизонтали — от складки бумаги до правого края:
     слева от складки поля страницы, и центрировать по окну значило бы увести
     текст влево. Когда панель развёрнута, отступ не нужен — колонка и так
     начинается сразу за складкой.

     :has(.intent) — чтобы это касалось только первого экрана: на форме входа
     и в переписке лента прокручивается и центрировать её нельзя. */
  .log:has(.intent), .log:has(.empty-hero) { display:flex; align-items:center }
  .log:has(.intent) .intent, .log:has(.empty-hero) .empty { margin-top:0 }
  /* Замер макета на 2000px: центр содержимого стоит на 1020 при середине окна
     1000 — то есть колонка центрирована по ОКНУ, а не по остатку справа от
     складки, и сдвинута вправо ровно на своё левое поле (40px). Раньше здесь
     стоял отступ по складке (130px) — он уводил блок вправо вдвое сильнее. */
  .app.blank .log:has(.intent) { padding-left:40px }
  /* По вертикали содержимое стоит чуть выше середины — в макете центр блока на
     551 при середине 580. Нижнее поле в 5vh поднимает его на те же 2.5vh. */
  /* padding-top снимаем: у ленты он 28px, и без этого блок садится на
     половину от них ниже, чем в макете. */
  .log:has(.intent), .log:has(.empty-hero) { padding-top:0; padding-bottom:5vh }

  /* ── смена экрана ──
     Экраны рисуются синхронно: старое дерево стирается и на его место сразу
     встаёт новое. Без анимации это читается рывком — то самое «мелькание».
     Новый экран приезжает справа и вырастает, старый уезжает влево и гаснет
     (его копию делает ghostLog). Движение одно на все экраны — .pp-in из
     ds.css; второй анимации появления заводить нельзя.

     ГРАНИЦА, которую легко перейти и один раз уже переходили: .pp-in — это
     появление ЭКРАНА, того, что заменяет собой всё содержимое области. То,
     что приходит ВНУТРИ уже идущего разговора — реплика, раскрывшийся шаг
     конструктора, новый факт в карточке, — так не приезжает. Диалог должен
     оставаться диалогом: реплики появляются по одной, а не влетают справа
     цельной плитой вместе с ответом. Сюда попадают только корни экранов. */
  .empty-hero, .intent-main, .intent-rule, .intent-more, .camp-page {
    transform-origin:50% 0;
    animation:pp-in var(--dur-in) var(--spring-in) backwards }

  /* ── стартовый экран: сначала выбор задачи, потом уже ввод ──
     Поля ввода здесь нет намеренно: под пустым композером непонятно, что писать —
     кампанию заказывают или интересы смотрят. Сначала выбор, ввод на следующем шаге. */
  /* margin-top перебивает .empty: класс тот же элемент, а не вложенный, как .empty-hero */
  .intent { margin-top:11vh; display:flex; flex-direction:column; align-items:center }
  .intent-main { border:0; background:transparent; font:inherit; color:inherit; cursor:pointer;
                 display:flex; flex-direction:column; align-items:center;
                 padding:14px 18px 16px; border-radius:20px; transition:background .12s ease }
  .intent-main:hover { background:transparent }
  /* Наведение не подсвечивает, а приближает: знак и надпись подрастают, знак
     заодно проворачивается на пол-оборота влево. Плашки и заливки под ними
     нет — на бумаге они читаются наклейкой. */
  .intent-main svg { color:var(--ink-strong); margin-bottom:0;
                     transition:transform var(--dur-logo) var(--spring) }
  .intent-main h2, .intent-main p { transition:transform var(--dur-logo) var(--spring) }
  .intent-main:hover svg, .intent-main:focus-visible svg { transform:rotate(-180deg) scale(1.14) }
  .intent-main:hover h2, .intent-main:focus-visible h2 { transform:scale(1.05) }
  .intent-main:hover p, .intent-main:focus-visible p { transform:scale(1.03) }
  /* Кегль и ширина колонки — с макета: 65px (--fs-title), интерлиньяж 86% и
     колонка около 500px, чтобы заголовок ложился в две строки. Одной длинной
     строкой он и крупнее кажется мельче, и уводит блок вбок: центр тяжести
     уезжает вместе с концом строки. Ширина в пикселях, а не в em, — она
     привязана к колонке страницы, а не к кеглю. */
  /* Цвет — --ink-strong, а не чистый чёрный: в макете ВЕСЬ заголовочный шрифт
     набран на 80%, чистого чёрного в нём нет нигде. */
  .intent-main h2 { margin:0; max-width:500px; font-family:var(--font-display);
                    font-size:var(--fs-title); line-height:var(--lh-title); font-weight:700;
                    letter-spacing:0; color:var(--ink-strong); text-wrap:balance }
  /* Подпись уже заголовка — как в макете: 440px против 500px. Она читается
     как приписка к нему, а не как второй абзац во всю ширину. */
  .intent-main p { margin:18px 0 0; max-width:440px; font-family:var(--font-script); font-weight:300;
                   font-size:var(--fs-lead-sm); line-height:var(--lh-lead-sm); color:var(--ink-strong);
                   text-wrap:balance }
  /* Разделитель от руки, а не <hr>: ровная линейка режет экран на две карточки,
     а здесь второй пункт — приписка к первому, а не равный ему раздел. */
  /* Штрих, а не нарисованная от руки кривая: линия в системе одна на всех —
     тот же PNG, что отбивает разделы в счёте и в отчёте. Ширина и отбивки
     сняты с макета: 622px, 48 сверху и 16 снизу. */
  /* Ширина фиксированная, а не 100%: колонка .intent сжимается по самому
     широкому ребёнку, и на 100% штрих получался короче макетных 622px.
     Отбивка сверху 32, а не 48: 16 уже дал нижний паддинг кнопки над ней. */
  .intent-rule { width:622px; max-width:100%; margin:32px 0 16px; height:var(--rule-h);
                 background:var(--rule-src) center / 100% 100% no-repeat }
  .intent-rule svg { display:none }
  /* Действие строкой: знак и надпись заголовочным шрифтом, без плашки вовсе —
     ровно как переход «узнать интересы» на стартовом экране макета. */
  /* Поля щедрые намеренно: зона нажатия должна совпадать с тем, что читается
     как кнопка. По одной строке текста в 24px промахнуться мимо неё слишком
     легко — курсор не меняется, и действие кажется неживым. */
  .intent-alt { display:inline-flex; align-items:center; gap:11px; border:0; background:transparent;
                cursor:pointer; padding:16px 28px; border-radius:var(--radius-mark); color:var(--ink-strong);
                font-family:var(--font-display); font-size:var(--fs-lead); letter-spacing:.24px;
                font-weight:700; opacity:.96; transition:opacity var(--dur-hover) var(--ease-out) }
  .intent-alt:hover, .intent-alt:focus-visible { background:transparent; opacity:1; color:var(--ink) }
  .intent-alt svg, .intent-alt span { display:inline-block; cursor:pointer;
                                      transition:transform var(--dur-logo) var(--spring) }
  /* Вокруг кнопки кликать нечего — курсор об этом и говорит. */
  .intent-more { cursor:default }
  .intent-alt:hover svg, .intent-alt:focus-visible svg { transform:scale(1.16) }
  .intent-alt:hover span, .intent-alt:focus-visible span { transform:scale(1.05) }
  .intent-more { display:flex; flex-direction:column; align-items:center; gap:2px }
  .intent-alt svg { flex:0 0 auto; color:var(--ink-strong) }
  /* На телефоне колонка сама по себе узкая — ограничивать её незачем, а кегль
     сбавляем: 65px в 320px ширины ложатся по два слова в строку. */
  @media (max-width:640px) {
    .intent-main h2 { font-size:44px; max-width:none }
    .intent-main p { font-size:17px; max-width:none }
  }
  /* приветствие над экраном выбора: показываем ровно один раз, сразу после входа */
  .intent-hello { margin:-2vh 0 20px; font-family:var(--font-script); font-weight:300;
                  font-size:var(--fs-script-note); color:var(--ink-muted) }

  /* DEV-код в реплике: локальный стенд без токена Gateway. Намеренно неприметный —
     это отладочная подсказка, а не часть разговора. */
  .dev-code { display:inline-block; margin-top:6px; font-family:var(--mono); font-size:12.5px;
              color:var(--muted) }

  /* Гость видит ТОТ ЖЕ экран, что и клиент: сайдбар на месте, просто пустой —
     подменять интерфейс на урезанный ради «вы не вошли» значит показывать другой
     продукт. Меняем только подвал: вместо профиля — кнопка входа. */
  /* У гостя в панели не остаётся ничего, что ведёт в закрытое: ни профиля, ни
     «Всех кампаний» с «Моими интересами» — они всё равно упёрлись бы во вход.
     Кнопки входа тут тоже нет: она уже стоит блоком в центре, а два одинаковых
     входа на одном экране заставляют выбирать там, где выбора нет. */
  .app.guest .profile-foot, .app.guest .pinned { display:none }
  /* Пустой список чатов у гостя объясняем словами: голая панель читается как сбой. */
  .convos-hint { margin:auto 0; padding:14px 12px; color:var(--ink-muted);
                 font-family:var(--font-script); font-weight:300; font-size:var(--fs-script-note);
                 line-height:1.4; text-align:center }
