/* Раздел «Чат»: список тредов, лента сообщений, композер.

   Каркас — тот же приём, что у `.graph-page` (DESIGN_SYSTEM.md §8.7): фиксированная высота под
   хром страницы, внутри — собственная прокрутка панелей, а не прокрутка `.fb-main` целиком. Была бы
   она у `.fb-main`, композер уезжал бы за нижний край окна на длинном треде — а он обязан быть
   виден постоянно, не только внизу страницы.

   Колонка тредов даёт вместе с постоянным рельсом навигации (`.fb-nav`, shell.css) ровно ТРИ
   колонки на экране: рельс приложения → список тредов → тело чата. Свою колонку заводить под
   каждую панель отдельно незачем — композер и лента делят общий столбец `.chat-main`. */

.chat-shell {
    display: grid;
    grid-template-columns: 280px 1fr;
    /* Своя высота, а не общая --fb-page-chrome: у раздела нет шапки страницы (её заменила узкая
       .chat-topbar внутри), поэтому вычитать её высоту не из чего. Это запасной вариант — точную
       высоту даёт правило с :has ниже. */
    height: calc(100vh - var(--fb-chat-chrome, 96px));
    min-height: 480px;
    border: 1px solid var(--fb-line);
    border-radius: var(--fb-r-page);
    overflow: hidden;
    background: var(--fb-surface);
    /* Точка отсчёта для выезжающего списка разговоров в узком окне: он ложится поверх ленты внутри
       раздела, а не поверх страницы, — иначе он накрыл бы и шапку чата, из которой его вызвали. */
    position: relative;
}

/* В широком окне список — постоянная колонка: звать его нечем и незачем, гасить под ним тоже
   нечего. Оба элемента живут в разметке всегда и снимаются здесь. */
.chat-threads-toggle.mud-button-root { display: none; }
.chat-threads-scrim { display: none; }

/* Точная высота: раздел занимает ровно то, что осталось от рабочей области, что бы над ним ни
   стояло. Считать вычитанием из 100vh нельзя — над разделом может появиться полоса «исполнитель
   молчит», и вычитаемое перестаёт быть постоянным: композер уезжал под нижний край экрана ровно
   тогда, когда что-то шло не так, то есть когда смотреть на него нужнее всего. */
.fb-main:has(> .chat-shell) {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.fb-main:has(> .chat-shell) > .chat-shell {
    height: auto;
    flex: 1 1 auto;
    min-height: 0;
}

/* ---------- список тредов ---------- */

.chat-threads {
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: var(--fb-bg);
    border-right: 1px solid var(--fb-line);
}

.chat-threads-head {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: none;
    padding: 10px 10px 8px;
    border-bottom: 1px solid var(--fb-line);
}

.chat-threads-head > .mud-input-control { flex: 1 1 auto; }

.chat-threads-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 6px;
}

.chat-thread-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 8px;
    margin-bottom: 2px;
    border-radius: var(--fb-r-in);
    cursor: pointer;
    color: var(--fb-ink-dim);
    transition: background .12s ease, color .12s ease;
}

.chat-thread-item:hover { background: var(--fb-hover); color: var(--fb-ink); }

.chat-thread-item.is-active {
    background: var(--fb-sunken);
    color: var(--fb-ink);
}

.chat-thread-item-main {
    flex: 1 1 auto;
    min-width: 0;
}

.chat-thread-title {
    font: var(--type-ui);
    color: inherit;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.chat-thread-date {
    font: var(--type-caption);
    color: var(--fb-ink-faint);
}

/* Действия строки — приглушены до наведения: их нажимают изредка, а название читают постоянно
   (тот же приём, что у счётчика ноды, §8.6.4). */
.chat-thread-actions {
    display: flex;
    gap: 2px;
    opacity: 0;
    transition: opacity .12s ease;
}

.chat-thread-item:hover .chat-thread-actions,
.chat-thread-item.is-active .chat-thread-actions { opacity: 1; }

.chat-threads-more {
    padding: 6px;
}

/* ---------- тело чата ---------- */

.chat-main {
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
}

/* Сама прокрутка живёт на `.chat-messages` (MessageList.razor), а не здесь: автопрокрутке (chat.js,
   isNearBottom/scrollToBottom) нужен ОДИН элемент, чью геометрию она читает и до, и после того, как
   в ленту дописан новый кусок, — а пустое состояние (`.chat-empty`) вставало бы в тот же контейнер
   без своей прокрутки и путало бы вычисление. */
.chat-body {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.chat-messages {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 18px 20px;
}

/* ---------- витрина примеров (пустой тред, задача 13) ---------- */

/* Пустое состояние теперь не приглашение текстом, а витрина: своя прокрутка внутри `.chat-body`
   (тот же контейнер, что и у ленты сообщений — см. класс-комментарий `.chat-messages` выше). */
.chat-gallery {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 20px;
}

.chat-gallery-head {
    max-width: 60ch;
    margin: 0 auto 16px;
    text-align: center;
}

.chat-gallery-title {
    font: var(--type-h3);
    color: var(--fb-ink);
}

.chat-gallery-note {
    margin-top: 4px;
    font: var(--type-body-sm);
    color: var(--fb-ink-dim);
}

.chat-gallery-tabs {
    display: flex;
    justify-content: center;
    gap: 6px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}

.chat-gallery-empty {
    /* align-content, а не place-items: две строки в гриде высотой 150px растягивались по всей
       высоте, и между заголовком пустого состояния и объяснением зияла дыра в полсотни точек —
       выглядело как сломанная вёрстка, а не как ответ «пока пусто». */
    display: grid;
    grid-auto-rows: min-content;
    align-content: center;
    justify-items: center;
    gap: 4px;
    min-height: 120px;
    text-align: center;
    color: var(--fb-ink-faint);
    font: var(--type-body-sm);
}

/* Сетка плиток — тот же приём, что у `.fb-gallery` (pages.css): карточки сравнивают глазами, а не
   читают строка за строкой. */
.chat-gallery-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 12px;
}

.chat-gallery-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    height: 200px;
    border: 1px solid var(--fb-line);
    border-radius: var(--fb-r-card);
    background: var(--fb-canvas);
    overflow: hidden;
    cursor: pointer;
    transition: border-color .12s ease, box-shadow .15s ease;
}

.chat-gallery-tile:hover { border-color: var(--fb-primary); box-shadow: var(--fb-ring); }

.chat-gallery-tile > img,
.chat-gallery-tile > video {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Звуковой пример картинки не имеет — крупная иконка по центру вместо чёрного прямоугольника (тот же
   довод, что у `.fb-example.is-audio`, только там место есть под плеер, а тут плитка маленькая и
   плеер до открытия просмотрщика не нужен). */
.chat-gallery-tile.is-audio {
    display: grid;
    place-items: center;
    color: var(--fb-ink-faint);
}

/* Подложка под видео — ПОД самим роликом: позиционированный блок рисуется поверх потокового, и без
   z-index она закрывала бы и постерный кадр, и ролик (та же беда была у обложек галереи шаблонов). */
.chat-gallery-fallback { position: absolute; inset: 0; z-index: 0; background: var(--fb-canvas); }

.chat-gallery-tile > img,
.chat-gallery-tile > video {
    position: relative;
    z-index: 1;
}

/* Третья ступень лестницы слоёв плитки: подложка 0 -> кадр 1 -> всё, что лежит ПОВЕРХ кадра, 2.
   Без неё накладки пропадали, едва картинка догружалась: позиционированный кадр с z-index 1 рисуется
   поверх позиционированного блока с z-index auto, каким бы поздним тот ни был в разметке (CSS 2.1,
   приложение E: шаги 8 и 9). Видно накладку было ровно те миллисекунды, пока у <img> нет пикселей и
   он прозрачен, — оттого баг и читался как мигание, а не как перекрытие.
   Отбирался при этом и клик: поле подписи в админке лежало под кадром и не нажималось.
   НОВАЯ НАКЛАДКА НА ПЛИТКЕ ДОБАВЛЯЕТСЯ СЮДА — иначе она повторит ту же судьбу. */
.chat-gallery-mark,
.chat-gallery-tile-title,
.chat-gallery-remove,
.chat-admin-order,
.chat-admin-remove,
.chat-admin-foot {
    z-index: 2;
}

.chat-gallery-mark {
    position: absolute;
    right: 8px;
    bottom: 30px;
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--fb-overlay);
    border: 1px solid var(--fb-line);
    color: var(--fb-ink-dim);
    transition: opacity .15s ease;
}

.chat-gallery-tile:hover .chat-gallery-mark { opacity: 0; }

.chat-gallery-tile-title {
    position: absolute;
    inset: auto 0 0 0;
    padding: 6px 8px;
    background: linear-gradient(to top, color-mix(in srgb, var(--fb-canvas) 88%, transparent), transparent);
    font: var(--type-caption);
    color: var(--fb-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Снять с витрины — приглушено до наведения, тем же приёмом, что у действий строки треда
   (`.chat-thread-actions`): нажимают изредка, а плитку разглядывают постоянно. */
.chat-gallery-remove {
    position: absolute;
    top: 4px;
    right: 4px;
    opacity: 0;
    transition: opacity .12s ease;
}

.chat-gallery-tile:hover .chat-gallery-remove { opacity: 1; }

/* ---------- витрина чата в админке (Задача 17) ---------- */

/* Плитка админки не открывает просмотрщик по клику (в ExampleGallery он открывается) — здесь плитка
   несёт органы правки прямо на себе, курсор кликабельности только путал бы. */
.chat-admin-tile { cursor: default; }

.chat-admin-order {
    position: absolute;
    top: 4px;
    left: 4px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    background: var(--fb-overlay);
    border: 1px solid var(--fb-line);
    border-radius: var(--fb-r-chip);
}

.chat-admin-remove {
    position: absolute;
    top: 4px;
    right: 4px;
}

/* Подпись правится прямо на плитке, а не в отдельном диалоге: правка одной строки не стоит перехода
   на другой экран, тот же довод, что у роли/тарифа в AdminUsers.razor. */
.chat-admin-foot {
    position: absolute;
    inset: auto 0 0 0;
    padding: 2px 4px;
    background: linear-gradient(to top, color-mix(in srgb, var(--fb-canvas) 92%, transparent), transparent);
}

/* ::deep — только внутри изолированных .razor.css; chat.css подключён обычной ссылкой, туда его брать
   нельзя. Тот же приём таргетинга, что и у mud.css — класс, который MudBlazor кладёт прямо на <input>. */
.chat-admin-title-field .mud-input-slot {
    font: var(--type-caption);
    color: var(--fb-ink);
}

/* ---------- просмотрщик генерации (GenerationViewer, задачи 13/14) ---------- */

.gen-viewer {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 260px;
    gap: 16px;
}

@media (max-width: 640px) {
    .gen-viewer { grid-template-columns: minmax(0, 1fr); }
}

.gen-viewer-media {
    height: fit-content;
    border-radius: var(--fb-r-in);
    overflow: hidden;
    background: var(--fb-canvas);
}

.gen-viewer-media > img,
.gen-viewer-media > video { display: block; width: 100%; max-height: 60vh; object-fit: contain; }

.gen-viewer-audio {
    display: grid;
    place-items: center;
    gap: 10px;
    padding: 24px 12px;
    color: var(--fb-ink-faint);
}

.gen-viewer-audio audio { width: 100%; }

/* Ответ текстового вызова (задача 14) — тем же контейнером, что у media, но моноширинным блоком
   вместо картинки: у текста нет файла-результата. */
.gen-viewer-text {
    margin: 0;
    padding: 14px;
    max-height: 60vh;
    overflow-y: auto;
    font: var(--type-body-sm);
    font-family: var(--fb-ui);
    color: var(--fb-ink);
    white-space: pre-wrap;
    word-break: break-word;
}

.gen-viewer-info {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
}

.gen-viewer-facts {
    display: grid;
    gap: 4px;
    padding-bottom: 10px;
    border-bottom: var(--fb-div);
}

.gen-viewer-row {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    font: var(--type-body-sm);
}

.gen-viewer-key { color: var(--fb-ink-faint); }
.gen-viewer-val { color: var(--fb-ink); text-align: right; }
.gen-viewer-val.is-price { font-family: var(--fb-mono); color: var(--fb-primary); }

.gen-viewer-label {
    display: block;
    margin-bottom: 4px;
    font: var(--type-overline);
    letter-spacing: var(--fb-tr-eyebrow);
    text-transform: uppercase;
    color: var(--fb-ink-faint);
}

.gen-viewer-prompt {
    font: var(--type-body-sm);
    color: var(--fb-ink-dim);
    white-space: pre-wrap;
    word-break: break-word;
}

.gen-viewer-params {
    margin: 0;
    padding: 8px 10px;
    border-radius: var(--fb-r-in);
    background: var(--fb-sunken);
    font-family: var(--fb-mono);
    font-size: var(--fb-fs-11);
    color: var(--fb-ink-dim);
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 200px;
    overflow-y: auto;
}

.gen-viewer-inputs {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.gen-viewer-input-thumb {
    width: 72px;
    text-align: center;
}

.gen-viewer-input-thumb img,
.gen-viewer-input-thumb video {
    display: block;
    width: 72px;
    height: 72px;
    object-fit: cover;
    border-radius: var(--fb-r-in);
    border: 1px solid var(--fb-line);
}

.gen-viewer-input-label {
    display: block;
    margin-top: 2px;
    font: var(--type-caption);
    color: var(--fb-ink-faint);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Отметка усечённого контекста: тред вырос длиннее, чем модель видит за один запрос. Приглушённая
   плашка сверху ленты — сообщает факт, а не мешает читать. */
.chat-trimmed {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 14px;
    padding: 6px 10px;
    border-radius: var(--fb-r-in);
    background: var(--fb-sunken);
    color: var(--fb-ink-faint);
    font: var(--type-caption);
}

.chat-trimmed .mud-icon-root { font-size: 14px; }

/* ---------- сообщения ---------- */

.chat-msg {
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-width: 74%;
    margin-bottom: 16px;
}

.chat-msg.is-user { margin-left: auto; align-items: flex-end; }
.chat-msg.is-assistant { margin-right: auto; align-items: flex-start; }

.chat-msg-role {
    font: var(--type-overline);
    letter-spacing: var(--fb-tr-eyebrow);
    text-transform: uppercase;
    color: var(--fb-ink-faint);
    padding: 0 2px;
}

.chat-bubble {
    padding: 10px 12px;
    border-radius: var(--fb-r-card);
    border: 1px solid var(--fb-line);
    font: var(--type-body);
    white-space: pre-wrap;
    word-break: break-word;
}

.chat-msg.is-user .chat-bubble { background: var(--fb-sunken); }
.chat-msg.is-assistant .chat-bubble { background: var(--fb-surface); }

/* Курсор печати потокового ответа — не анимация: система избегает третьего непрерывного движения,
   а мигающий текстовый курсор браузер рисует сам через `content` без keyframes. */
.chat-bubble.is-streaming::after {
    content: "▍";
    color: var(--fb-primary);
}

.chat-msg-error {
    padding: 10px 12px;
    border-radius: var(--fb-r-card);
    border: 1px solid color-mix(in srgb, var(--fb-danger) 40%, var(--fb-line));
    background: var(--fb-danger-soft);
    color: var(--fb-danger);
    font: var(--type-body-sm);
}

.chat-msg-cancelled {
    padding: 8px 12px;
    border-radius: var(--fb-r-card);
    border: 1px dashed var(--fb-line);
    color: var(--fb-ink-faint);
    font: var(--type-body-sm);
}

/* Вложения и результаты — сеткой тумбов, а не в столбик: варианты и приложенные файлы сравнивают
   глазами (тот же довод, что у `.fb-gallery`, §8.6.3). */
.chat-msg-files {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.chat-file-thumb {
    position: relative;
    width: 160px;
    max-width: 100%;
    border-radius: var(--fb-r-in);
    overflow: hidden;
    border: 1px solid var(--fb-line);
    background: var(--fb-sunken);
}

.chat-file-thumb img,
.chat-file-thumb video { display: block; width: 100%; max-height: 220px; object-fit: cover; }
.chat-file-thumb audio { display: block; width: 100%; }

.chat-file-thumb.is-doc {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 10px;
    font: var(--type-body-sm);
    color: var(--fb-ink);
}

/* Ячейка ленты: превью и действия РЯДОМ, а не поверх. Значок «в витрину» лежал на самом файле и
   закрывал то, ради чего на него смотрят, — угол кадра, а у звука регулятор громкости. */
.chat-file-cell {
    display: flex;
    align-items: flex-start;
    gap: 4px;
}

/* Публикация в витрину (задача 13) — приглушена до наведения, тем же приёмом, что у «Снять с витрины»
   на самой плитке ниже: нажимают изредка, а результат разглядывают постоянно. */
.chat-file-publish {
    flex: none;
    align-self: center;
    opacity: 0;
    transition: opacity .12s ease;
}

.chat-file-cell:hover .chat-file-publish { opacity: 1; }

/* Заглушка результата, который ещё не пришёл. Пульс — тот же keyframe, что и на графе для «идёт
   работа» (tokens.css: fabrika-pulse), третьей анимации система не заводит. */
.chat-skeleton {
    width: 220px;
    max-width: 100%;
    height: 96px;
    border-radius: var(--fb-r-in);
    background: var(--fb-sunken);
    animation: fabrika-pulse var(--duration-pulse) linear infinite;
}

.chat-skeleton-text { height: 14px; width: 70%; }

.chat-skeleton-label {
    margin-top: 6px;
    font: var(--type-caption);
    color: var(--fb-ink-faint);
}

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

/* ---------- композер ---------- */

/* ---------- композер (задача 18: пересборка) ----------

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

.chat-composer {
    flex: none;
    border-top: 1px solid var(--fb-line);
    background: var(--fb-bg);
    padding: 8px 12px 10px;
}

.chat-composer-card {
    border: 1px solid var(--fb-line);
    border-radius: var(--fb-r-card);
    background: var(--fb-surface);
    padding: 6px 6px 4px;
}

.chat-composer-card:focus-within {
    border-color: var(--fb-primary);
    box-shadow: var(--fb-ring);
}

/* Рамки лишается ТОЛЬКО поле ввода сообщения: рамка одна на всю карточку, иначе выходит рамка в
   рамке, а между ними полоса чужого фона. Селектор нарочно узкий (.chat-composer-input, а не вся
   карточка): под общий он подводил и поля во всплывающих настройках, и те оставались без обводки —
   выглядели как подписи, а не как поля. */
.chat-composer-input > div > .mud-input-control .mud-input.mud-input-outlined,
.chat-composer-input > div > .mud-input-control .mud-input.mud-input-outlined:hover {
    background: transparent;
    border-color: transparent;
    box-shadow: none;
}

.chat-composer-input {
    display: flex;
    align-items: flex-end;
    gap: 6px;
}

.chat-composer-input .mud-input-control { flex: 1 1 auto; }

/* Кнопка отправки/остановки — квадратная, не растягивается вместе с полем: она одна и та же и в
   покое, и во время потока (задача 12, требование «Остановить обрывает поток»). */
.chat-send-btn.mud-button-root {
    flex: none;
    min-width: 34px;
    width: 34px;
    height: 34px;
    padding: 0;
    border-radius: 50%;
    margin-bottom: 2px;
}

/* ---------- рельса управления под полем ---------- */

.chat-composer-rail {
    display: flex;
    align-items: center;
    gap: 2px;
    padding: 2px 2px 0;
    min-height: 30px;
}

/* Скрепка стоит в одном ряду с остальными кнопками рельсы. MudFileUpload — это «поле ввода» в
   понимании Mud'а: его обёртка несёт заготовки под подпись и список файлов и выходит на 37 точек в
   высоту, из-за чего сама кнопка съезжала на четыре точки вниз относительно соседних чипов. Обёртке
   задан рост кнопки, заготовки убраны — список выбранных файлов мы всё равно рисуем свой. */
.chat-rail-upload.mud-input-control,
.chat-rail-upload .mud-input-control-input-container {
    display: inline-flex;
    align-items: center;
    height: 28px;
    min-height: 0;
    margin: 0;
    padding: 0;
}

.chat-rail-upload .mud-file-upload-files { display: none; }

.chat-rail-btn.mud-button-root {
    color: var(--fb-ink-faint);
    border-radius: var(--fb-r-chip);
}

.chat-rail-btn.mud-button-root:hover { color: var(--fb-ink); background: var(--fb-hover); }

/* Занятый слот виден по самой скрепке — не нужно открывать панель, чтобы узнать, приложено ли
   что-нибудь (требование задачи 18: вложения всегда на виду). */
.chat-rail-btn.is-on.mud-button-root { color: var(--fb-primary); }

/* Кнопка-чип рельсы: своя, не Mud'овская — у Mud'овской кнопки собственные отступы и высота под
   material-ритм, из-за которых ряд вырастал вдвое против нужного. */
.chat-rail-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 26px;
    max-width: 220px;
    padding: 0 6px;
    border: 0;
    border-radius: var(--fb-r-chip);
    background: transparent;
    color: var(--fb-ink-dim);
    font: var(--type-caption);
    cursor: pointer;
}

.chat-rail-chip:hover:not(:disabled) { background: var(--fb-hover); color: var(--fb-ink); }
.chat-rail-chip:disabled { opacity: .5; cursor: default; }
.chat-rail-chip:focus-visible { outline: none; box-shadow: var(--fb-ring); }
.chat-rail-chip.is-icon { padding: 0 5px; }

.chat-rail-chip > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.chat-rail-chip .mud-icon-root { font-size: 14px; flex: none; }

/* Счётчик вариантов на кнопке настроек: значение, спрятанное за кнопку, обязано оставлять след
   снаружи — иначе человек забудет, что просил четыре варианта, и удивится цене. */
.chat-rail-badge {
    min-width: 15px;
    height: 15px;
    padding: 0 3px;
    border-radius: var(--fb-r-chip);
    background: var(--fb-primary);
    color: var(--fb-on-primary);
    font: var(--type-overline);
    line-height: 15px;
    text-align: center;
}

.chat-price {
    margin-left: auto;
    padding-right: 4px;
    font-family: var(--fb-mono);
    font-size: var(--fb-fs-11);
    color: var(--fb-ink-faint);
    white-space: nowrap;
}

.chat-price.is-priced { color: var(--fb-ink-dim); }

/* ---------- вложения ---------- */

.chat-attachments {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 2px 2px 6px;
}

/* Карточка вложения: у картинки она ЕСТЬ картинка во всю плитку — единственный вопрос человека
   «ту ли я приложил», и подпись «Картинка» на него не отвечает. Прежний узкий чип с превьюшкой в
   22 пикселя не отвечал тоже. Размер плитки — как у превью в привычных чатах: заметно, но не
   отбирает у поля ввода высоту. */
.chat-attach-card {
    position: relative;
    display: flex;
    width: 108px;
    height: 88px;
    border-radius: var(--fb-r-in);
    border: 1px solid var(--fb-line);
    background: var(--fb-sunken);
    overflow: hidden;
    cursor: zoom-in;
}

.chat-attach-card:hover { border-color: var(--fb-line-hi); }
.chat-attach-card:focus-visible { outline: none; box-shadow: var(--fb-ring); }

.chat-attach-cover {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Файл без превью: значок, назначение слота и расширение — три вещи, по которым видно, что лежит. */
.chat-attach-body {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px;
    width: 100%;
    font: var(--type-caption);
    color: var(--fb-ink-dim);
}

.chat-attach-body .mud-icon-root { font-size: 18px; color: var(--fb-ink-faint); }

.chat-attach-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--fb-ink);
}

/* Объём документа под именем: «26 строк» отвечает на вопрос «это тот файл или не тот» быстрее, чем
   что угодно другое, и заодно намекает на цену — за длинный файл модель возьмёт больше. */
.chat-attach-meta {
    font: var(--type-caption);
    color: var(--fb-ink-faint);
}

.chat-attach-badge {
    align-self: flex-start;
    margin-top: auto;
    padding: 0 5px;
    border-radius: var(--fb-r-chip);
    border: 1px solid var(--fb-line);
    font: var(--type-overline);
    color: var(--fb-ink-faint);
}

/* Крестик — по наведению: постоянный значок поверх маленькой превьюшки рябит и закрывает как раз
   тот угол, по которому человек узнаёт свою картинку. С клавиатуры он доступен всегда (:focus). */
.chat-attach-x {
    position: absolute;
    top: 4px;
    right: 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: color-mix(in srgb, var(--fb-bg) 72%, transparent);
    color: var(--fb-ink);
    cursor: pointer;
    opacity: 0;
    transition: opacity .12s ease;
}

.chat-attach-card:hover .chat-attach-x,
.chat-attach-x:focus-visible { opacity: 1; }

.chat-attach-x:hover { background: var(--fb-bg); }
.chat-attach-x .mud-icon-root { font-size: 13px; }

/* ---------- выпадающие меню рельсы ---------- */

/* Меню рельсы открываются ВВЕРХ: рельса стоит у самого низа экрана, и выпадающее вниз меню
   уезжало за край окна целиком — кнопка нажималась, а списка человек не видел вовсе. */
.chat-rail-popover .mud-list-item { min-height: 30px; }

.chat-rail-popover { max-height: 60vh; overflow-y: auto; }

.chat-menu-group {
    padding: 6px 12px 2px;
    font: var(--type-overline);
    color: var(--fb-ink-faint);
}

.chat-model-item {
    display: flex;
    align-items: baseline;
    gap: 10px;
    width: 100%;
}

.chat-model-name { flex: 1 1 auto; }

.chat-model-price {
    font-family: var(--fb-mono);
    font-size: var(--fb-fs-11);
    color: var(--fb-ink-faint);
    white-space: nowrap;
}

.chat-settings-popover { max-width: 340px; }

.chat-settings-sheet {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 10px 12px;
    min-width: 240px;
}

/* ---------- ряд действий под сообщением (MessageActions.razor, задача 14) ---------- */

/* Ряд на месте всегда — но приглушён, пока курсор не над сообщением: постоянный ряд в полную силу
   спорил с самим текстом ответа за внимание, а он тут не главный. Не opacity:0, как у действий
   строки треда: там кнопки нужны изредка, здесь же человек должен видеть, что действия ЕСТЬ, ещё
   до того, как поведёт мышью. */
.chat-msg-actions {
    display: flex;
    align-items: center;
    gap: 0;
    margin-top: 2px;
    opacity: .35;
    transition: opacity .12s ease;
}

.chat-msg:hover .chat-msg-actions,
.chat-msg-actions:focus-within { opacity: 1; }

/* Скачивание идёт через обычную ссылку (нужен нативный download), а не MudIconButton: кнопка внутри
   ссылки — невалидный контент, а иконка внутри ссылки со своей рамкой ведёт себя как кнопка визуально. */
.chat-msg-action-link {
    display: grid;
    place-items: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    color: var(--fb-ink-faint);
    transition: background .12s ease, color .12s ease;
}

.chat-msg-action-link:hover { background: var(--fb-hover); color: var(--fb-ink); }
.chat-msg-action-link .mud-icon-root { font-size: 15px; }

/* ---------- правка последнего сообщения (MessageList.razor, задача 14) ---------- */

.chat-edit-box {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
}

.chat-edit-field { width: 100%; }

.chat-edit-warning {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    border-radius: var(--fb-r-in);
    background: var(--fb-danger-soft);
    color: var(--fb-danger);
    font: var(--type-caption);
}

.chat-edit-warning .mud-icon-root { font-size: 14px; flex: none; }

.chat-edit-actions {
    display: flex;
    justify-content: flex-end;
    gap: 6px;
}

/* ---------- панель файлов треда (ThreadFilesPanel.razor, задача 14) ---------- */

.thread-files-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 12px;
}

.thread-file-card {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--fb-line);
    border-radius: var(--fb-r-card);
    background: var(--fb-canvas);
    overflow: hidden;
}

.thread-file-thumb {
    display: grid;
    place-items: center;
    height: 120px;
    background: var(--fb-sunken);
    color: var(--fb-ink-faint);
}

.thread-file-thumb img,
.thread-file-thumb video { display: block; width: 100%; height: 100%; object-fit: cover; }

.thread-file-meta {
    display: flex;
    justify-content: space-between;
    gap: 6px;
    padding: 6px 8px 0;
    font: var(--type-caption);
    color: var(--fb-ink-faint);
}

.thread-file-actions {
    display: flex;
    align-items: center;
    gap: 2px;
    padding: 4px 6px 6px;
}

/* ---------- «Мои генерации» (ChatLibrary.razor, задача 14) ---------- */

.chat-library-filters { margin-bottom: 16px; }

.chat-library-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 14px;
}

.chat-library-tile {
    display: flex;
    flex-direction: column;
    height: 220px;
    border: 1px solid var(--fb-line);
    border-radius: var(--fb-r-card);
    background: var(--fb-surface);
    overflow: hidden;
    cursor: pointer;
    transition: border-color .12s ease, box-shadow .15s ease;
}

.chat-library-tile:hover { border-color: var(--fb-primary); box-shadow: var(--fb-ring); }

.chat-library-tile-media {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    display: grid;
    place-items: center;
    background: var(--fb-canvas);
    color: var(--fb-ink-faint);
    overflow: hidden;
}

.chat-library-tile-media img,
.chat-library-tile-media video {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.chat-library-tile-text {
    padding: 10px;
    font: var(--type-caption);
    color: var(--fb-ink-dim);
    white-space: pre-wrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.chat-library-tile-foot {
    flex: none;
    padding: 8px 10px;
    border-top: 1px solid var(--fb-line);
}

.chat-library-tile-title {
    font: var(--type-label);
    color: var(--fb-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.chat-library-tile-sub {
    display: flex;
    justify-content: space-between;
    gap: 6px;
    margin-top: 2px;
    font: var(--type-caption);
    color: var(--fb-ink-faint);
}

.chat-library-tile-sub .is-price { color: var(--fb-primary); font-family: var(--fb-mono); }

.chat-library-pager {
    display: flex;
    justify-content: center;
    margin-top: 20px;
}

/* ---------- узкие окна ----------

   Раздел перестаёт быть двумя колонками и становится РАЗГОВОРОМ во весь экран, а список разговоров
   выезжает поверх него по кнопке в шапке чата.

   Прежде список ложился полосой в 220 точек НАД лентой, и арифметика была такая: из 730 точек
   экрана топбар брал 52, навигация 55, список 220, шапка чата 38, композер 86 — ленте оставалось
   130. То есть на экране, целиком отданном переписке, переписки было видно на полтора сообщения, а
   две трети занимало то, ЧЕМ её выбирают.

   Панель, а не вторая страница по адресу: композер обязан быть под рукой всегда, а разделив список
   и ленту по разным адресам, мы бы отправляли за ним через промежуточный экран. Жест тот же, что у
   рельса приложения (shell.css) — вытянуть слева, — и это единственное движение, которое человек
   учит на телефоне во всём кабинете. */

@media (max-width: 900px) {
    /* Одна колонка: список из потока вынут (position: absolute ниже), в сетке остаётся лента. */
    .chat-shell { grid-template-columns: 1fr; }

    .chat-threads-toggle.mud-button-root { display: inline-flex; }

    .chat-threads {
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        z-index: 12;
        width: min(86%, 320px);
        border-right: 1px solid var(--fb-line);
        box-shadow: var(--shadow-dialog);
        transform: translateX(-100%);
        /* visibility гасится с задержкой в длину переезда — иначе обратного движения не видно, а
           Tab уводит фокус в список за краем экрана. Тот же приём, что у рельса. */
        visibility: hidden;
        transition:
            transform var(--duration-base) var(--ease-standard),
            visibility 0s linear var(--duration-base);
    }

    .chat-shell.threads-open .chat-threads {
        transform: none;
        visibility: visible;
        transition: transform var(--duration-base) var(--ease-standard);
    }

    .chat-threads-scrim {
        display: block;
        position: absolute;
        inset: 0;
        z-index: 11;
        background: var(--fb-overlay);
        opacity: 0;
        pointer-events: none;
        transition: opacity var(--duration-base) var(--ease-standard);
    }

    .chat-shell.threads-open .chat-threads-scrim { opacity: 1; pointer-events: auto; }

    /* Строка разговора под палец: промах здесь означает «открыл чужой разговор», а действия строки
       (переименовать, удалить) на касании не всплывают по наведению и потому видны сразу. */
    .chat-thread-item { padding: 10px 8px; }
    .chat-thread-actions { opacity: 1; }

    /* Пузырь почти во всю ширину: поля по 8% с каждой стороны на 414 точках — это 66 точек, отданных
       пустоте, то есть примерно семь знаков строки. */
    .chat-msg { max-width: 94%; }
    .chat-messages { padding: 14px 12px; }
}

@media (prefers-reduced-motion: reduce) {
    .chat-threads,
    .chat-shell.threads-open .chat-threads,
    .chat-threads-scrim { transition: none; }
}

@media (max-width: 560px) {
    /* Разговор — во всю ширину экрана: рамка, скругление и поля рабочей области отнимали у него
       около 30 точек по горизонтали и рисовали карточку там, где карточки нет — раздел и есть
       экран. Правило смотрит на `.fb-main`, содержащий чат, а не на все страницы подряд. */
    .fb-main:has(> .chat-shell) { padding: 0; }

    .chat-shell {
        border: 0;
        border-radius: 0;
        /* min-height в 480 точек на телефоне в альбомной ориентации выдавливал композер за нижний
           край — ровно то, ради чего у раздела своя высота. */
        min-height: 0;
    }

    .chat-composer { padding: 6px 8px 8px; }

    /* Рельса под полем переносится. В одну строку не влезали ни «Заметки о модели», ни цена справа
       — а цена здесь единственное, что человек обязан увидеть ДО отправки. */
    .chat-composer-rail { flex-wrap: wrap; row-gap: 4px; }
}

/* ---------- узкая шапка рабочей области (задача 18) ----------

   Заменила общий PageHeader раздела: тот занимал под слово «Чат» с надзаголовком «Работа» около
   семидесяти точек и не сообщал ничего, чего не сообщает подсвеченный пункт навигации. Здесь та же
   строка несёт имя открытого разговора и два действия иконками. */

.chat-topbar {
    flex: none;
    display: flex;
    align-items: center;
    gap: 8px;
    height: 38px;
    padding: 0 8px 0 14px;
    border-bottom: 1px solid var(--fb-line);
}

.chat-topbar-title {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font: var(--type-body-sm);
    color: var(--fb-ink);
}

.chat-topbar-actions {
    flex: none;
    display: flex;
    align-items: center;
    gap: 2px;
}

.chat-topbar-actions .mud-button-root { color: var(--fb-ink-faint); }
.chat-topbar-actions .mud-button-root:hover { color: var(--fb-ink); }

/* ---------- пустой экран: с чего начать (задача 18) ----------

   Показывается вместо витрины, когда примеров нет вовсе. Пустое поле ввода отвечает на вопрос
   «куда нажать», но не на вопрос «что написать», а именно он и стоит перед человеком, впервые
   открывшим раздел. */

.chat-start {
    max-width: 60ch;
    margin: 0 auto;
    padding: 8vh 0 0;
    text-align: center;
}

.chat-start-title {
    font: var(--type-h3);
    color: var(--fb-ink);
}

.chat-start-note {
    margin-top: 4px;
    font: var(--type-body-sm);
    color: var(--fb-ink-dim);
}

.chat-start-chips {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
    margin-top: 16px;
}

.chat-start-chip {
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    padding: 6px 12px;
    border: 1px solid var(--fb-line);
    border-radius: var(--fb-r-chip);
    background: var(--fb-sunken);
    color: var(--fb-ink-dim);
    font: var(--type-body-sm);
    cursor: pointer;
    text-align: left;
}

.chat-start-chip:hover {
    border-color: var(--fb-primary);
    color: var(--fb-ink);
}

.chat-start-chip:focus-visible { outline: none; box-shadow: var(--fb-ring); }

/* Вид генерации на заготовке: она переключает не только текст запроса, но и то, ЧТО получится, —
   и человек вправе знать это до нажатия, а не удивляться картинке в ответ на «придумай названия». */
.chat-start-chip-kind {
    flex: none;
    font: var(--type-overline);
    color: var(--fb-ink-faint);
}

.chat-start-chip:hover .chat-start-chip-kind { color: var(--fb-primary); }

/* ---------- свои выпадающие меню рельсы (задача 18) ----------

   Написаны разметкой, а не MudMenu: у того активатор не отзывался на клик по вложенной кнопке, а
   всплывашка открывалась ВНИЗ — за нижний край окна, потому что рельса стоит у самого низа экрана.
   Здесь меню раскрывается вверх от своей кнопки и закрывается подложкой. */

.chat-rail-menu { position: relative; display: inline-flex; }

.chat-rail-chip.is-open { background: var(--fb-hover); color: var(--fb-ink); }

.chat-rail-sheet {
    position: absolute;
    bottom: calc(100% + 6px);
    left: 0;
    z-index: 30;
    min-width: 200px;
    max-height: 60vh;
    overflow-y: auto;
    padding: 4px;
    border: 1px solid var(--fb-line);
    border-radius: var(--fb-r-card);
    background: var(--fb-surface);
    box-shadow: var(--fb-shadow-pop, 0 8px 24px rgb(0 0 0 / .28));
}

.chat-rail-sheet.is-wide { min-width: 300px; }
/* Настройки шире прочих меню и прокручиваются только вниз: у моделей вроде расшифровки речи полей
   много и подписи длинные — в узком листе они не помещались, и всплывашка обзаводилась сразу двумя
   полосами прокрутки, горизонтальной и вертикальной. */
.chat-rail-sheet.is-settings {
    min-width: 320px;
    max-width: min(420px, 90vw);
    max-height: min(60vh, 460px);
    overflow-x: hidden;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px;
}

/* Сетка параметров внутри узкого листа — в одну колонку: две по 50% дают поля шириной в полторы
   подписи. */
.chat-rail-sheet.is-settings .mud-grid-item {
    max-width: 100%;
    flex-basis: 100%;
}

.chat-menu-item {
    display: flex;
    align-items: baseline;
    justify-content: flex-start;
    gap: 12px;
    width: 100%;
    padding: 6px 8px;
    border: 0;
    border-radius: var(--fb-r-chip);
    background: transparent;
    color: var(--fb-ink);
    font: var(--type-body-sm);
    text-align: left;
    cursor: pointer;
}

.chat-menu-item:hover { background: var(--fb-hover); }
.chat-menu-item.is-active { color: var(--fb-primary); }
.chat-menu-item:focus-visible { outline: none; box-shadow: var(--fb-ring); }

.chat-menu-note { padding: 8px; color: var(--fb-ink-faint); font: var(--type-caption); }

/* Подложка ловит клик мимо меню. Прозрачная: затемнять экран ради выбора модели — слишком громкий
   жест для такого мелкого решения. */
.chat-rail-backdrop {
    position: fixed;
    inset: 0;
    z-index: 25;
}

/* ---------- разметка ответа модели (задача 18) ---------- */

.chat-md > :first-child { margin-top: 0; }
.chat-md > :last-child { margin-bottom: 0; }

.chat-md-p { margin: 0 0 8px; }

.chat-md-h {
    margin: 12px 0 6px;
    color: var(--fb-ink);
    font-weight: var(--weight-semibold);
}

.chat-md-h1 { font: var(--type-h3); }
.chat-md-h2 { font-size: var(--text-md); }
.chat-md-h3 { font-size: var(--text-sm); }

.chat-md-li {
    display: flex;
    gap: 8px;
    margin: 2px 0;
}

.chat-md-marker {
    flex: none;
    min-width: 14px;
    color: var(--fb-ink-faint);
}

.chat-md-quote {
    margin: 6px 0;
    padding-left: 10px;
    border-left: 2px solid var(--fb-line);
    color: var(--fb-ink-dim);
}

.chat-md-code {
    margin: 8px 0;
    padding: 10px 12px;
    border-radius: var(--fb-r-in);
    background: var(--fb-sunken);
    font-family: var(--fb-mono);
    font-size: var(--fb-fs-11);
    overflow-x: auto;
    white-space: pre;
}

.chat-md-inline-code {
    padding: 1px 4px;
    border-radius: var(--fb-r-chip);
    background: var(--fb-sunken);
    font-family: var(--fb-mono);
    font-size: 0.92em;
}

.chat-md a { color: var(--fb-primary); }

/* ---------- общий размер кнопок-иконок раздела (задача 18, замечания) ----------

   Одна беда на все места: MudIconButton рисует иконку в 20–24px в кнопке 40×40 — на плотном экране
   чата это выглядит крупно и грубо. Здесь иконка мельче, поле вокруг больше, скругление заметнее;
   правило одно на ряд действий, список тредов, рельсу композера и панель файлов, чтобы они не
   разъехались по размеру между собой. */

.chat-msg-actions .mud-button-root,
.chat-thread-actions .mud-button-root,
.chat-composer-rail .mud-button-root,
.chat-topbar-actions .mud-button-root,
.chat-files-actions .mud-button-root {
    width: 28px;
    height: 28px;
    min-width: 28px;
    padding: 0;
    border-radius: var(--fb-r-in);
    color: var(--fb-ink-faint);
}

/* Переименование и удаление разговора — ещё тише остальных: в списке они стоят у каждой строки, а
   нажимают их изредка. Крупные значки спорили с названием, ради которого список и существует. */
.chat-thread-actions .mud-button-root {
    width: 22px;
    height: 22px;
    min-width: 22px;
}

.chat-thread-actions .mud-icon-root { font-size: 13px; }

.chat-msg-actions .mud-button-root:hover,
.chat-thread-actions .mud-button-root:hover,
.chat-composer-rail .mud-button-root:hover,
.chat-topbar-actions .mud-button-root:hover,
.chat-files-actions .mud-button-root:hover {
    color: var(--fb-ink);
    background: var(--fb-hover);
}

.chat-msg-actions .mud-icon-root,
.chat-thread-actions .mud-icon-root,
.chat-composer-rail .mud-icon-root,
.chat-topbar-actions .mud-icon-root,
.chat-files-actions .mud-icon-root {
    font-size: 15px;
}

/* ...НО не внутри выпадающих панелей рельсы: они рисуются ВНУТРИ неё же, и правило выше накрывало
   собой всё, что в них лежит. Материаловскому переключателю оно снимало отступы, и кружок уезжал
   выше полоски; числовым полям — стрелки. Внутри панели размеры возвращаются материаловские. */
.chat-rail-sheet .mud-button-root {
    width: auto;
    height: auto;
    min-width: auto;
}

.chat-rail-sheet .mud-switch-base.mud-button-root {
    padding: 9px;
    border-radius: 50%;
}

.chat-rail-sheet .mud-input-numeric-spin .mud-icon-button { padding: 1px; }
.chat-rail-sheet .mud-input-adornment .mud-icon-button { padding: 3px; }
.chat-rail-sheet .mud-icon-root { font-size: inherit; }

/* Ссылка-скачивание живёт в том же ряду и обязана выглядеть так же, как соседние кнопки. */
.chat-msg-action-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--fb-r-in);
    color: var(--fb-ink-faint);
}

.chat-msg-action-link:hover { color: var(--fb-ink); background: var(--fb-hover); }
.chat-msg-action-link .mud-icon-root { font-size: 15px; }

/* Картинка в ленте кликабельна — курсор обязан об этом сказать. */
.chat-file-thumb img { cursor: zoom-in; }

.chat-file-expand {
    position: absolute;
    top: 4px;
    left: 4px;
    opacity: 0;
    transition: opacity .12s ease;
}

.chat-file-thumb:hover .chat-file-expand { opacity: 1; }

/* Карточка файла в панели разговора: подпись и кнопки стоят ПОД превью на своей поверхности, а не
   поверх картинки. Поверх — они читались только на тёмных кадрах, а на светлых пропадали вовсе. */
.thread-file-meta,
.thread-file-actions {
    background: var(--fb-surface);
    position: relative;
    z-index: 1;
}

.thread-file-thumb.is-media { cursor: zoom-in; }

/* ---------- варианты ответа, цена и время под сообщением ---------- */

.chat-msg-variants {
    display: inline-flex;
    align-items: center;
    gap: 1px;
    margin-left: 2px;
}

.chat-msg-variant-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border: 0;
    border-radius: var(--fb-r-chip);
    background: transparent;
    color: var(--fb-ink-faint);
    cursor: pointer;
}

.chat-msg-variant-btn:hover:not(:disabled) { color: var(--fb-ink); background: var(--fb-hover); }
.chat-msg-variant-btn:disabled { opacity: .35; cursor: default; }
.chat-msg-variant-btn .mud-icon-root { font-size: 14px; }

.chat-msg-variant-count {
    font-family: var(--fb-mono);
    font-size: var(--fb-fs-11);
    color: var(--fb-ink-faint);
    padding: 0 2px;
}

/* Цена и время — тем же приглушённым тоном, что и иконки рядом: это справка, а не содержание. */
.chat-msg-meta {
    margin-left: 6px;
    font-size: var(--fb-fs-11);
    color: var(--fb-ink-faint);
    white-space: nowrap;
}

/* Ответ модели — без рамки: она обводила текст, который и так стоит отдельным блоком, и делала
   ленту решётчатой. Сообщение человека рамку сохраняет — по ней видно, где чья реплика. */
.chat-msg.is-assistant .chat-bubble {
    border-color: transparent;
    background: transparent;
    padding-left: 0;
    padding-right: 0;
}

/* Кнопка заметки о модели — тише соседей по рельсе: это справка, а не выбор. */
.chat-rail-chip.is-note { color: var(--fb-ink-faint); }

/* ---------- всплывающие подсказки ----------

   Своя ширина и перенос строк: подсказка из двух смысловых строк в одну не читается.

   Фон НЕПРОЗРАЧНЫЙ. Полупрозрачная подсказка выглядела легче, но сквозь неё просвечивало то, что
   лежит под ней, и собственный текст подсказки становился нечитаемым — а подсказка существует
   ровно для того, чтобы её прочитали. Отделяет её от страницы тень, а не прозрачность. */
.mud-popover.mud-tooltip.chat-tip {
    width: max-content;
    max-width: 320px;
    white-space: pre-line;
    line-height: 1.45;
    padding: 8px 10px;
    border-radius: var(--fb-r-in);
    background: var(--fb-surface);
    color: var(--fb-ink);
    border: 1px solid var(--fb-line);
    box-shadow: var(--fb-shadow);
}

/* Полосы прокрутки от всплывашек: слой Mud'а лежит в конце body обычным блоком, и подсказка,
   раскрывшаяся у правого или нижнего края, растягивала документ — на миг появлялась полоса
   прокрутки и страница дёргалась. Фиксированный слой нулевого размера этого не делает: его дети
   считаются от окна, а не от документа. */
.mud-popover-provider {
    position: fixed;
    inset: 0;
    overflow: hidden;
    /* ОБЯЗАТЕЛЬНО вместе с position: fixed. Фиксированный элемент сам по себе заводит слой
       наложения, и всплывашки внутри перестают сравниваться со страницей своими z-index'ами —
       сравнивается ОДИН слой, а он при z-index: auto стоит на нуле и проигрывает по порядку в
       разметке любому позиционированному блоку страницы. Подсказка кнопки «в витрину» из-за этого
       уходила ПОД картинку, над которой стоит сама кнопка.

       Значение выше диалога Mud'а (1400): внутри диалога тоже бывают подсказки и выпадающие списки,
       и весь слой обязан стоять над ним целиком — свои z-index'ы отдельных всплывашек теперь ничего
       не решают. Ниже просмотрщика файлов (3000) — тот открыт поверх всего намеренно. */
    z-index: 2000;
    /* Слой ловит клики только там, где реально что-то нарисовано: растянутый на весь экран прозрачный
       блок иначе перехватывал бы всё подряд. */
    pointer-events: none;
}

.mud-popover-provider > * { pointer-events: auto; }

/* ---------- документ в ленте и его предпросмотр ---------- */

/* Карточка документа среди вложений сообщения — тот же вид, что в композере, чтобы приложенный файл
   и файл в истории читались как одно и то же. */
.chat-doc-card {
    width: 150px;
    min-height: 84px;
    border: 1px solid var(--fb-line);
    border-radius: var(--fb-r-in);
    background: var(--fb-sunken);
    cursor: pointer;
}

.chat-doc-card:hover { border-color: var(--fb-line-hi); }

/* Ячейка документа не обрезает содержимое рамкой превью: у неё своя карточка внутри. */
.chat-file-thumb.is-doc,
.chat-file-thumb.is-audio {
    width: auto;
    border: 0;
    background: transparent;
    overflow: visible;
}

/* Проигрывателю в ленте нужна ШИРИНА: полосой в полтораста точек невозможно попасть в секунду. */
.chat-file-thumb.is-audio .fb-player { width: 360px; max-width: 100%; }



/* Окно предпросмотра: шапка с именем и объёмом, тело — сам текст моноширинным, со своей прокруткой. */
.fb-doc-head {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.fb-doc-title {
    font: var(--type-ui);
    color: var(--fb-ink);
    word-break: break-all;
}

.fb-doc-meta {
    font: var(--type-caption);
    color: var(--fb-ink-faint);
}

.fb-doc-text {
    margin: 0;
    max-height: 60vh;
    overflow: auto;
    padding: 12px;
    border: 1px solid var(--fb-line);
    border-radius: var(--fb-r-in);
    background: var(--fb-canvas);
    color: var(--fb-ink-dim);
    font-family: var(--fb-mono);
    font-size: var(--fb-fs-12);
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-word;
}

.fb-doc-empty {
    padding: 24px 0;
    text-align: center;
    color: var(--fb-ink-faint);
    font: var(--type-body-sm);
}

/* ---------- цепочка обработки звука в чате ----------

   Эффекты — теми же блоками, что и вложения, и стоят там же, рядом с полем ввода: цепочка это набор
   блоков, идущих ДРУГ ЗА ДРУГОМ, и порядок в ней — суть обработки. Держать её за кнопкой настроек
   значило бы открывать эту кнопку перед каждым решением. Клик по блоку раскрывает настройку эффекта
   панелью ПОД рядом — сам ряд при этом остаётся на виду. */

.chat-fx {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 2px 2px 6px;
}

.chat-fx-row {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 6px;
}

.chat-fx-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    width: 108px;
    height: 88px;
    padding: 8px;
    border: 1px solid var(--fb-line);
    border-radius: var(--fb-r-in);
    background: var(--fb-sunken);
    color: var(--fb-ink);
    cursor: pointer;
    transition: border-color .12s ease, opacity .12s ease;
}

.chat-fx-tile:hover { border-color: var(--fb-line-hi); }
.chat-fx-tile.is-open { border-color: var(--fb-primary); }
.chat-fx-tile.is-off { opacity: .5; }
.chat-fx-tile:focus-visible { outline: none; box-shadow: var(--fb-ring); }

/* Номер — порядок в цепочке, а не украшение: по нему видно, что за чем идёт. */
.chat-fx-tile-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--fb-canvas);
    font: var(--type-overline);
    color: var(--fb-ink-faint);
}

.chat-fx-tile-name {
    font: var(--type-caption);
    color: var(--fb-ink);
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

/* Крестик — по наведению, тем же приёмом и по тому же доводу, что у карточки вложения. */
.chat-fx-tile-x {
    position: absolute;
    top: 4px;
    right: 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: color-mix(in srgb, var(--fb-bg) 72%, transparent);
    color: var(--fb-ink);
    cursor: pointer;
    opacity: 0;
    transition: opacity .12s ease;
}

.chat-fx-tile:hover .chat-fx-tile-x,
.chat-fx-tile-x:focus-visible { opacity: 1; }
.chat-fx-tile-x .mud-icon-root { font-size: 13px; }

.chat-fx-tile.is-add {
    align-items: center;
    justify-content: center;
    gap: 4px;
    border-style: dashed;
    background: transparent;
    color: var(--fb-ink-faint);
    font: var(--type-caption);
    text-align: center;
}

.chat-fx-tile.is-add:hover { color: var(--fb-primary); border-color: var(--fb-primary); }

.chat-fx-catalog {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.chat-fx-catalog-item {
    padding: 4px 8px;
    border: 1px solid var(--fb-line);
    border-radius: var(--fb-r-chip);
    background: var(--fb-sunken);
    color: var(--fb-ink-dim);
    font: var(--type-caption);
    cursor: pointer;
}

.chat-fx-catalog-item:hover { color: var(--fb-primary); border-color: var(--fb-primary); }

/* Панель настройки выбранного эффекта. Под рядом, а не поверх него: ряд — это карта цепочки, и
   прятать её ради двух чисел значит заставлять человека помнить порядок наизусть. */
.chat-fx-panel {
    border: 1px solid var(--fb-line);
    border-radius: var(--fb-r-in);
    background: var(--fb-canvas);
    padding: 8px 10px;
}

.chat-fx-panel-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
}

.chat-fx-panel-title {
    font: var(--type-ui);
    font-size: var(--fb-fs-12);
    color: var(--fb-ink);
    flex: none;
}

.chat-fx-help {
    flex: 1 1 auto;
    min-width: 0;
    font: var(--type-caption);
    color: var(--fb-ink-faint);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.chat-fx-panel-actions {
    display: flex;
    gap: 1px;
    flex: none;
}

.chat-fx-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    border-radius: var(--fb-r-chip);
    background: transparent;
    color: var(--fb-ink-faint);
    cursor: pointer;
}

.chat-fx-btn:hover:not(:disabled) { color: var(--fb-ink); background: var(--fb-hover); }
.chat-fx-btn:disabled { opacity: .35; cursor: default; }
.chat-fx-btn .mud-icon-root { font-size: 13px; }

/* Параметры в ряд, а не столбиком: у эффекта их два-четыре, и столбик вытянул бы композер на
   пол-экрана вверх. */
.chat-fx-params {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.chat-fx-field { width: 132px; }

.chat-fx-chain {
    font-family: var(--fb-mono);
    font-size: var(--fb-fs-10);
    color: var(--fb-ink-faint);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
