/* ═══════════════════════════════════════════════════════════════════════════
   GOLDJAXE Scribe · assistant.css — окно помощника по продукту (GS-50).

   Отдельным файлом, а не в components.css: помощник — надстройка, которой в
   установке заказчика может не быть вовсе (флаг ASSISTANT_WEBHOOK_URL). Файл
   подключается из base.html только при включённом помощнике, и выключенный
   виджет не стоит клиенту ни байта.

   Вызывающая кнопка и разворот окна — по образцу чат-виджета goldjaxe.org
   (components/ChatWidget.tsx): маленькая ненавязчивая кнопка, а не текстовая
   плашка; окно раскрывается в двух фиксированных размерах (компакт/просторно),
   на телефоне — во весь экран. Цвета и радиусы — свои, токенами продукта:
   лендинг ведёт крайм-эстетику отдельного бренда, здесь — Corporate Brutalism
   самого Scribe (нулевые радиусы, золотой акцент), копировать её один в один
   означало бы завести в кабинете чужой визуальный язык.

   Цвета, радиусы и тени — только токенами: собственные значения разъедутся с
   темами (их три: светлая, тёмная, ночная).
   ═══════════════════════════════════════════════════════════════════════════ */

/* 🔴 box-sizing ЗДЕСЬ, а не надеждой на каркас страницы — тот же случай, что
   у модалки (modal.css, .projform). Размеры файла считаны под border-box
   (min-height поля 38px = строка + padding + рамка), и без своего правила
   виджет зависит от глобального сброса style.css: не применился сброс — поле
   ввода становится на строку выше кнопки отправки (38px контента + 20px
   обвязки; поймано принципалом 18.08.2026). Виджет обязан выглядеть одинаково
   на любой странице, при любом каркасе. */
.sc-asst,
.sc-asst *,
.sc-asst *::before,
.sc-asst *::after { box-sizing: border-box; }

.sc-asst {
  position: fixed;
  right: 20px;
  bottom: 20px;
  /* Над содержимым страницы, но НИЖЕ модалок (1001) и их подложки: диалог
     подтверждения обязан перекрывать помощника, а не наоборот. */
  z-index: 900;
}

/* ── Кнопка вызова ─────────────────────────────────────────────────────────────
   Квадрат 44px с одной иконкой — не текстовая плашка. «Спросить о сервисе»
   отдельной строкой рядом с кнопкой каждой страницы конкурировала бы за
   внимание с самим интерфейсом; подпись остаётся в aria-label и title, кнопка
   на экране — тихая. */

.sc-asst__open {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--c-gold-line);
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  color: var(--c-gold);
  box-shadow: var(--elev-2);
  cursor: pointer;
  transition: background .15s, border-color .15s, transform .15s, box-shadow .15s;
}
.sc-asst__open:hover {
  background: var(--c-gold-bg);
  border-color: var(--c-gold);
  transform: scale(1.06);
  box-shadow: var(--elev-3);
}
.sc-asst__open:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
.sc-asst__open svg { width: 20px; height: 20px; flex: none; }

/* Кнопка прячется, когда окно открыто: одно место вызова/закрытия, не два
   рядом стоящих элемента с одинаковым смыслом «закрыть помощника». */
.sc-asst.is-open .sc-asst__open { display: none; }

/* …и когда открыта справка по странице (замечание владельца 19.08.2026: «кнопка
   бота уже начинает мешать чтению»). На телефоне панель справки занимает низ
   экрана, а кнопка помощника стоит поверх её текста — золотой кружок посреди
   читаемого абзаца. Помощник при этом никуда не девается: справку закрывают
   крестиком, Escape или касанием мимо, и кнопка возвращается тем же движением.

   Класс ставит help.js на <body>: справка не лезет внутрь чужого компонента, а
   помощник сам решает, как ему уйти с дороги. Условие видимости остаётся одно и
   живёт здесь же, рядом с правилом выше. */
body.sc-help-is-open .sc-asst__open {
  opacity: 0;
  visibility: hidden;
  transition: opacity .15s, visibility .15s;
}

/* ── Панель разговора ──────────────────────────────────────────────────────────
   Два фиксированных размера, а не свободный ресайз мышью: тянущийся угол —
   лишний узел разметки и лишняя история состояния (сохранять размер между
   визитами или нет?). Переключатель «просторнее/компактнее» даёт ту же
   пользу — увидеть длинный ответ целиком — без этой цены. */

.sc-asst__panel {
  position: absolute;
  right: 0;
  bottom: calc(44px + 12px);
  width: 380px;
  height: 560px;
  max-width: calc(100vw - 40px);
  max-height: calc(100vh - 120px);
  display: flex;
  flex-direction: column;
  background: var(--c-surface);
  border: 1px solid var(--c-line-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-3);
  overflow: hidden;
  transition: width .2s ease, height .2s ease;
}
/* hidden сам по себе перебивается display:flex — снимаем явно. */
.sc-asst__panel[hidden] { display: none; }

.sc-asst.is-expanded .sc-asst__panel {
  width: 620px;
  height: 760px;
}

/* Шапка «Терминал»: знак + бренд, без подзаголовка. Золотая линия снизу
   вместо серой — она же отделяет ленту и держит характер варианта. */
.sc-asst__head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--c-gold-line);
  background: var(--c-surface);
}
.sc-asst__mark {
  flex: none;
  width: 30px; height: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--c-gold-line);
  border-radius: var(--radius-sm);
  background: var(--c-gold-bg);
  color: var(--c-gold-strong);
}
.sc-asst__mark svg { width: 15px; height: 15px; }
.sc-asst__brand {
  font-family: var(--font-brand);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .14em;
  color: var(--c-gold-strong);
}

.sc-asst__head-actions { margin-left: auto; display: flex; align-items: center; gap: 4px; flex: none; }

.sc-asst__clear,
.sc-asst__expand,
.sc-asst__close {
  flex: none;
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--c-ink-3);
  cursor: pointer;
}
.sc-asst__clear:hover,
.sc-asst__expand:hover,
.sc-asst__close:hover { background: var(--c-surface-3); color: var(--c-ink); }
.sc-asst__clear:focus-visible,
.sc-asst__expand:focus-visible,
.sc-asst__close:focus-visible { outline: var(--focus-ring); outline-offset: 1px; }
.sc-asst__clear svg,
.sc-asst__expand svg,
.sc-asst__close svg { width: 16px; height: 16px; }

/* Кнопка очистки стоит рядом с крестиком закрытия — стирать нечего, пока нет
   разговора, а рядом с закрытием ей ещё и легко нажаться по ошибке. Тот же
   класс has-dialog, что прячет приветствие (ниже) — одно состояние ленты,
   одно правило видимости. */
.sc-asst__clear { display: none; }
.sc-asst.has-dialog .sc-asst__clear { display: inline-flex; }

/* Подтверждение очистки: первое нажатие меняет значок на слово «Стереть?»,
   второе стирает. Разговор пропадал молча и необратимо от промаха по соседнему
   крестику — тут нужен спрос, а не модалка: окно бывает шириной в 320px.

   Красным намеренно: до нажатия кнопка нейтральна, как соседи по шапке, и
   только став опасной — окрашивается. Цвет здесь несёт смысл, а не украшает.
   Ширина отпускается под текст, поэтому соседние кнопки не прыгают: у них
   flex: none, а шапка тянется вправо от margin-left: auto. */
.sc-asst__clear-label { display: none; font-size: 12px; font-weight: 600; white-space: nowrap; }
.sc-asst__clear.is-confirming {
  width: auto;
  gap: 4px;
  padding: 0 8px;
  border-color: var(--c-danger-line);
  background: var(--c-danger-bg);
  color: var(--c-danger);
}
.sc-asst__clear.is-confirming:hover { background: var(--c-danger-bg); color: var(--c-danger); }
.sc-asst__clear.is-confirming svg { display: none; }
.sc-asst__clear.is-confirming .sc-asst__clear-label { display: inline; }

/* Иконка «свернуть» показывается только в развёрнутом виде, и наоборот —
   переключаем видимость классом на корне, а не два обработчика с разным DOM. */
.sc-asst__expand .sc-asst__ic-shrink { display: none; }
.sc-asst.is-expanded .sc-asst__expand .sc-asst__ic-grow   { display: none; }
.sc-asst.is-expanded .sc-asst__expand .sc-asst__ic-shrink { display: inline-flex; }

/* ── Лента реплик ──────────────────────────────────────────────────────────── */

.sc-asst__feed {
  flex: 1 1 auto;
  /* min-height:0 обязателен, иначе flex-элемент не сжимается ниже собственного
     содержимого: когда поле ввода растёт под длинный вопрос, лента не отдаёт
     ему место, а выдавливает форму за нижний край панели — набранного текста
     не видно вовсе. Со сжатием растущее поле забирает высоту у ленты, лента
     скроллится, форма остаётся на месте. */
  min-height: 0;
  overflow-y: auto;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* Ответ модели — сплошной текст; без предела строка тянется на всю ширину
     и читается тяжело. */
  font-size: 14px;
  line-height: 1.55;
}

/* Приветствие живёт до первого вопроса и уходит СОВСЕМ (display:none, не
   прозрачность): дальше его место нужнее разговору. Класс ставит assistant.js
   на корень при отправке первого вопроса. */
.sc-asst__hello {
  color: var(--c-ink-3);
  font-size: 13px;
  margin: 0;
}
.sc-asst.has-dialog .sc-asst__hello { display: none; }

/* ── Реплики: аватарка + плашка, зеркалом для человека ────────────────────────
   Жалоба «сейчас всё смешивается» — оба голоса были одинаковой серой строкой
   без опоры для глаза. Решение: аватарка (кто), плашка с фоном (что) и сторона
   (реплика человека прижата вправо, бота — влево) — три независимых сигнала.
   Текстовых подписей ролей рядом НЕТ: в варианте «Терминал» они признаны шумом,
   аватарки хватает (решение принципала 18.08.2026). */

.sc-asst__msg {
  display: flex;
  gap: 10px;
  max-width: 100%;
}
.sc-asst__msg--me { flex-direction: row-reverse; }

.sc-asst__avatar {
  flex: none;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Квадрат со скруглением, а не круг: перекликается со знаком в шапке и с
     общей брутальной геометрией продукта (радиусы у нас почти нулевые). */
  border-radius: var(--radius-sm);
  margin-top: 2px;
}
.sc-asst__avatar svg { width: 15px; height: 15px; }

/* Дублей на --pending/--error здесь больше нет: класс роли (--bot) ставится
   всегда, состояние идёт вторым классом — см. bubble() в assistant.js. */
.sc-asst__msg--bot .sc-asst__avatar {
  background: var(--c-gold-bg);
  color: var(--c-gold);
  border: 1px solid var(--c-gold-line);
}
.sc-asst__msg--me .sc-asst__avatar {
  background: var(--c-surface-3);
  color: var(--c-ink-3);
  border: 1px solid var(--c-line);
}

.sc-asst__col {
  display: flex;
  flex-direction: column;
  min-width: 0;
  max-width: calc(100% - 38px);
}
.sc-asst__msg--me .sc-asst__col { align-items: flex-end; }

/* Подпись роли остаётся в разметке для скринридера, но с экрана убрана:
   зрячий читает роль по аватарке, а незрячему подпись нужна — без неё реплики
   в озвучке сливаются в один поток без указания, кто говорит. */
.sc-asst__who {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.sc-asst__text {
  color: var(--c-ink);
  /* Ответ приходит с переносами строк — сохраняем их, иначе список шагов
     склеивается в абзац. Разбирает их сам renderMarkdown() узлами <br>, здесь
     остаётся только перенос длинного слова/ссылки, которое некуда перенести. */
  overflow-wrap: anywhere;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
}
.sc-asst__text strong { color: var(--c-ink); font-weight: 700; }
.sc-asst__text em     { font-style: italic; }
.sc-asst__text code   {
  font-family: var(--font-mono);
  font-size: .9em;
  background: var(--c-surface-3);
  padding: 1px 5px;
  border-radius: var(--radius-xs);
}
.sc-asst__text ul { margin: 4px 0; padding-left: 18px; }
.sc-asst__text li { margin: 2px 0; }

.sc-asst__msg--bot .sc-asst__text {
  background: var(--c-surface-2);
  border-left: 2px solid var(--c-gold);
}
/* Отступы у вопроса меньше, чем у ответа: короткий вопрос в одну строку иначе
   давал плашку 42px против аватарки 28px, и иконка выглядела мелкой рядом с
   ней (замер 18.08.2026). Теперь плашка 32px — почти вровень. */
.sc-asst__msg--me .sc-asst__text {
  padding: 4px 12px;
  background: var(--c-gold-bg);
  border: 1px solid var(--c-gold-line);
}
.sc-asst__msg--pending .sc-asst__text { color: var(--c-ink-4); background: var(--c-surface-2); }
.sc-asst__msg--error   .sc-asst__text { color: var(--c-danger); background: var(--c-surface-2); }

/* ── Ожидание: три бегущие точки ──────────────────────────────────────────────
   Заменили фразу «Ищу ответ…» в ленте: текст читался как реплика бота, хотя был
   состоянием, и через секунду подменялся ответом — глаз успевал начать читать.
   Точки же ничего не обещают словами и понятны без языка (решение 18.08.2026).

   Высота плашки удержана вровень со строкой текста: точки наследуют ту же
   строчную высоту (1.55 при 14px), а не берут своё число. Жёсткие 22px здесь
   уже стояли и давали плашку 40px против 37.7px у ответа — при подмене точек
   текстом лента дёргалась на 2.3px (замер 18.08.2026). */

/* display:flex, а не inline-flex, и высота ровно в одну строку (1.55 при 14px).
   Инлайновая раскладка здесь мешала: элемент на базовой линии тянул за собой
   место под «хвосты» букв, и плашка ожидания выходила выше строки ответа — при
   подмене точек текстом лента дёргалась. Замеры 18.08.2026: inline-flex дал
   39.8px против 37.7px у ответа, vertical-align:middle убрал лишь часть (39.0),
   блочная раскладка сравняла в 37.7. */
.sc-asst__dots {
  display: flex;
  align-items: center;
  gap: 4px;
  height: 1.55em;
}
.sc-asst__dots i {
  width: 6px;
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--c-gold);
  opacity: .3;
  animation: sc-asst-dot 1.2s ease-in-out infinite;
}
/* Сдвиг фазы соседних точек и даёт бегущую волну. */
.sc-asst__dots i:nth-child(2) { animation-delay: .18s; }
.sc-asst__dots i:nth-child(3) { animation-delay: .36s; }

@keyframes sc-asst-dot {
  0%, 70%, 100% { opacity: .3; transform: translateY(0); }
  35%           { opacity: 1;  transform: translateY(-3px); }
}

/* ── Подсказки следующих вопросов ─────────────────────────────────────────────
   Чипы под последним ответом: вопросы присылает конвейер полем follow_up.
   Прижаты влево под ответ бота и с отступом слева на ширину аватарки (28px +
   10px зазора) — так они читаются как продолжение ответа, а не как отдельная
   реплика неизвестно кого. */

.sc-asst__suggest {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-left: 38px;
  /* Отрицательный отступ съедает половину gap ленты (12px): чипы относятся к
     ответу над ними и не должны висеть от него так же далеко, как реплики
     друг от друга. */
  margin-top: -6px;
}
.sc-asst__chip {
  max-width: 100%;
  padding: 5px 10px;
  border: 1px solid var(--c-gold-line);
  border-radius: var(--radius-sm);
  background: var(--c-surface);
  color: var(--c-gold-strong);
  font: inherit;
  font-size: 12.5px;
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
  transition: background .15s, border-color .15s;
}
.sc-asst__chip:hover { background: var(--c-gold-bg); border-color: var(--c-gold); }
.sc-asst__chip:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }

/* ── Строка ввода ──────────────────────────────────────────────────────────── */

/* Разделителя сверху у формы НЕТ намеренно: он давал третью линию подряд —
   граница формы, рамка поля и обводка фокуса шли друг за другом в 3-4 пикселя,
   и низ окна выглядел грязно (замечание принципала 18.08.2026). Поле само
   отделено от ленты своей рамкой и фоном полосы. */
.sc-asst__form {
  display: flex;
  gap: 8px;
  align-items: flex-end;
  padding: 10px 12px;
  background: var(--c-surface-2);
}
/* Поле растёт под текст, высоту считает JS (autoGrow в assistant.js) — здесь
   только пределы. Предел задан в em, а не в пикселях и не в долях экрана:
   em привязан к line-height, поэтому «шесть строк» остаются шестью строками
   и при 14px десктопа, и при 13px телефона. Доля экрана (50vh) здесь была бы
   ошибкой: на телефоне окно полноэкранное, всплывшая клавиатура съедает больше
   половины высоты, и поле «в пол-экрана» вытолкнуло бы за край ту самую ленту
   с ответом, ради которой человек и печатает.
   8.4em = 6 строк × 1.4 line-height. Дальше поле скроллится само (overflow-y),
   но при этом СТОИТ на месте: max-height достигнут, форма больше не растёт. */
.sc-asst__input {
  flex: 1 1 auto;
  box-sizing: border-box;
  /* height задан наравне с min-height: без него пустое поле берёт высоту от
     rows="1" (строка + padding + рамки = 40px), а поле с текстом получает от
     JS ровно scrollHeight = 38px — и строка ввода дёргалась на 2px на первом
     же набранном знаке. Теперь обе высоты равны, скачка нет. */
  height: 38px;
  min-height: 38px;
  max-height: calc(8.4em + 20px);   /* 6 строк + вертикальные padding'и поля */
  padding: 9px 10px;
  border: 1px solid var(--c-control-line);
  border-radius: var(--radius-sm);
  background: var(--c-surface);
  color: var(--c-ink);
  font: inherit;
  font-size: 14px;
  line-height: 1.4;
  resize: none;
  overflow-y: auto;
}
/* Фокус — подмена цвета собственной рамки, а не вторая обводка поверх неё:
   outline рисуется СНАРУЖИ рамки и наезжал на неё, получалось два кольца.
   Снимаем и на :focus тоже, не только на :focus-visible: у текстового поля
   фокус всегда «видимый», и системный outline браузера иначе остаётся. */
.sc-asst__input:focus,
.sc-asst__input:focus-visible {
  outline: none;
  border-color: var(--c-gold);
  box-shadow: 0 0 0 1px var(--c-gold);
}
/* Квадратная кнопка под высоту поля: подпись «Спросить» съедала ширину ввода
   в узком окне, действие теперь читается иконкой (aria-label на месте). */
.sc-asst__send {
  flex: none;
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--c-gold);
  border-radius: var(--radius-sm);
  background: var(--c-gold);
  color: var(--c-gold-contrast);
  cursor: pointer;
  transition: background .15s;
}
.sc-asst__send svg { width: 17px; height: 17px; }
.sc-asst__send:hover:not(:disabled) { background: var(--c-gold-mid); }
.sc-asst__send:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }

/* Пока вопрос в полёте кнопка гаснет И крутит кольцо. Одно гашение читается
   как «нажатие не прошло»; вращение отвечает «работа идёт». Прозрачность
   выше, чем у обычного disabled (.55): под ней должно быть видно кольцо. */
.sc-asst__send:disabled { cursor: default; opacity: .55; }
.sc-asst__form.is-busy .sc-asst__send:disabled { opacity: .8; }

.sc-asst__ic-send,
.sc-asst__ic-busy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.sc-asst__ic-busy { display: none; }
.sc-asst__form.is-busy .sc-asst__ic-send { display: none; }
.sc-asst__form.is-busy .sc-asst__ic-busy {
  display: inline-flex;
  animation: sc-asst-spin .7s linear infinite;
}

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

/* Правил .sc-asst__privacy здесь больше нет: плашка «помощник не имеет доступа
   к вашим встречам» убрана из разметки 18.08.2026 (решение принципала — окно
   должно быть чище). Обещание не потеряно: помощник произносит его сам в ответ
   на прямой вопрос, это правило 4 системного промта, см. product/assistant.md. */

/* ── Телефон: окно на весь экран ──────────────────────────────────────────────
   Плавающая панель на маленьком экране либо обрезается, либо накрывает всё
   вокруг себя — обе беды разом снимает полноэкранный режим, тот же приём,
   что у референса на goldjaxe.org. Переключатель размера прячем: «просторнее»
   не имеет смысла, когда окно уже во весь экран. */

@media (max-width: 640px) {
  .sc-asst__panel,
  .sc-asst.is-expanded .sc-asst__panel {
    position: fixed;
    inset: 0;
    width: auto;
    height: auto;
    max-width: none;
    max-height: none;
    border-radius: 0;
    border: none;
  }
  .sc-asst__expand { display: none; }
  /* Поле ввода на узком экране ниже кнопки «Спросить»: плейсхолдер в две
     строки обрезался на середине слова («Как загрузить запись встре…»).
     Две строки по 13px помещаются целиком, а тач-цель остаётся 44px. */
  /* Пять строк вместо шести: на телефоне поверх полноэкранного окна всплывает
     клавиатура, и видимой области остаётся меньше половины экрана. Шестая
     строка выигрывала бы строку набора ценой строки ответа — размен не в нашу
     пользу, читать человек хочет ответ. 7em = 5 строк × 1.4. */
  .sc-asst__input {
    font-size: 13px;
    /* height рядом с min-height по той же причине, что и на десктопе: пустое
       поле обязано стоять ровно на тач-цели 44px, а не на 38px из общего блока. */
    height: 44px;
    min-height: 44px;
    max-height: calc(7em + 20px);
  }
  /* Кнопка отставала от поля на 4px (40px против входных 44px) — при общем
     align-items:flex-end формы верх кнопки уезжал ниже верха поля, и рядом с
     44px-строкой сама кнопка читалась мельче и «подвисшей» (замечание
     принципала 18.08.2026). На телефоне тач-цель у обеих одна. */
  .sc-asst__send {
    width: 44px;
    height: 44px;
  }
  /* Кнопки шапки на телефоне были 28px при норме тач-цели 44px — и стояли
     вплотную друг к другу. Соседство «стереть разговор» с «закрыть окно» на
     мелких целях и приводило к промахам (замечание принципала 19.08.2026);
     подтверждение делает промах безобидным, а размер — редким.
     Ширина у корзины не задаётся: в состоянии «Стереть?» она тянется под
     текст (см. .is-confirming выше). */
  .sc-asst__clear,
  .sc-asst__close {
    min-width: 44px;
    height: 44px;
  }
  /* Разрыв между «стереть» и «закрыть» больше, чем между обычными соседями:
     цена промаха у них разная, и расстояние это отражает. */
  .sc-asst__head-actions { gap: 10px; }
}

@media (prefers-reduced-motion: reduce) {
  .sc-asst__open,
  .sc-asst__panel { transition: none; }
  /* Точки и кольцо замирают, но НЕ исчезают: они здесь единственный признак
     того, что вопрос ушёл и ответа ещё нет. Убрать их совсем значило бы
     оставить человека перед пустым окном. */
  .sc-asst__dots i,
  .sc-asst__form.is-busy .sc-asst__ic-busy { animation: none; }
  .sc-asst__dots i { opacity: .55; }
}

/* ── Оценка ответа (GS-61) ──────────────────────────────────────────────────
   Кнопки под ответом бота; появляются, только когда сервер прислал rate_token
   (включён журнал помощника). Выбранная подсвечивается золотом; состоянием
   служит aria-pressed — отдельного класса нет: одно состояние, один источник. */
.sc-asst__rate { display: flex; gap: 4px; margin-top: 6px; }
.sc-asst__rate-btn {
  display: flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0;
  border: 1px solid var(--c-line-strong);
  border-radius: var(--radius-sm);
  background: var(--c-surface);
  color: var(--c-ink-3);
  cursor: pointer;
}
.sc-asst__rate-btn svg { width: 14px; height: 14px; }
.sc-asst__rate-btn:hover { color: var(--c-ink); background: var(--c-surface-3); }
.sc-asst__rate-btn:focus-visible { outline: var(--focus-ring); outline-offset: 1px; }
.sc-asst__rate-btn[aria-pressed="true"] {
  color: var(--c-gold-strong);
  border-color: var(--c-gold);
  background: var(--c-gold-bg);
}

/* ═══ Помощник над панелью вкладок (GS-138) ════════════════════════════════
   Помощник остаётся плавающей кнопкой — им пользуются часто и из любого места,
   это как раз тот случай, ради которого канон П10 допускает постоянную кнопку
   поверх содержимого. Но стоять он обязан НАД панелью, а не на ней: замер
   27.08.2026 (390×844) показал, что на bottom:20px он перекрывал вкладку «Ещё».

   Высота панели 56px + её собственная безопасная область + зазор. Считаем
   через env(), а не фиксированным числом: на iPhone с жестовой навигацией
   панель выше на величину индикатора home. */
@media (max-width: 1023px){
  body:has(.app-shell.has-tabs) .sc-asst{
    bottom: calc(56px + env(safe-area-inset-bottom) + 16px);
  }
}

/* Открыта шторка — помощник уходит (GS-138).
   z-index помощника 900 против 101 у шторки: без этого правила он висит
   поверх её содержимого и закрывает первую строку меню (замер 27.08.2026,
   390×844 — перекрывал строку «Загрузка»).

   Скрываем, а не понижаем этаж: шторка модальна (aria-modal), и кнопка под
   затемнением всё равно не нажимается — видимая, но мёртвая кнопка хуже
   отсутствующей. Признак ставит контроллер шторок на <body>. */
body.has-sheet-open .sc-asst{ opacity: 0; pointer-events: none; }
.sc-asst{ transition: opacity .18s ease; }
@media (prefers-reduced-motion: reduce){ .sc-asst{ transition: none; } }
