/* =============================================================================================
   ft-assistant.css — Assistente 3D: palco, conversa redesenhada e peça 2D com os rostos do kit.

   Fonte: porte de tests/assistant-3d/assistant-ui.css (mockup aprovado — D12 modal, D13 tela cheia,
   docs/assistant-3d-mapping.md §5b/§5c). ADITIVO: as regras `.assistant*` de 4 estados que já existem em
   `ft-assistant-avatar.css` (antes no ft-theme.css) NÃO são tocadas (regra de ouro #5/#2 — nada de config fluente por
   cima, nada reescrito). Este arquivo só ACRESCENTA.

   Registrado em `bundles.json` › array `~/wwwroot/css/fixtres-components`, logo depois de
   `ft-theme.css` (mesma posição relativa que `ft-simulation-override.css` já ocupava) — passo A2.

   CONVENÇÃO DE NOME (decidida nesta gravação, ao ler o que A1/A2 já tinham construído em
   paralelo — ft-assistant.js/ft-assistant-map.js já existiam quando este arquivo foi escrito):
     - Host-level, quem pluga no `:has()` dos hospedeiros reais e casa com os atributos
       `data-ft-assistant-*` que `ft-assistant.js` já lê: prefixo `ft-assistant-` — `.ft-assistant-stage`,
       `.ft-assistant-stage--left`, `.ft-assistant-stage--right`.
     - TUDO o que mora dentro do palco (parede/luminária/quadro/rodapé/piso, cartão de contexto,
       cartão de trace) e TODA a conversa redesenhada (log/mensagens/estado vazio/compositor/
       trilho/chip/fechar): nome NU `.assistant-*`, idêntico ao mockup. Dois motivos: (1) zero colisão
       — o namespace `.ft-ai-*` já está OCUPADO por `ft-chat-surface.css` (ex-`_FtAiChatStyle.cshtml`, movido em 2026-09-29) com significados
       diferentes para praticamente todo nome óbvio (`.ft-ai-log`, `.ft-ai-composer`, `.ft-ai-
       conv`, `.ft-ai-chip`, `.ft-ai-rail*`, `.ft-ai-empty`, `.ft-ai-close` não existe mas os
       acima já bastam) — renomear para esse prefixo teria colidido em silêncio com o chat que já
       está no ar; (2) `ft-assistant.js` (já escrito, ver Scripts/Components/ft-assistant.js:237-257) JÁ
       manipula `.assistant-trace__step` / `.assistant-trace__empty` / `.assistant-trace__cost` NUS — mudar o
       nome aqui quebraria aquele código sem eu tocar nele. Ver o mapa completo abaixo.
     - `--assistant-width` / `--assistant-aspect` no `<assistant-avatar>`: API do KIT (três.js), não escolha
       Fixtres — nomes fixos, não prefixar.
     - `--ft-assistant-stage-w` / `--ft-assistant-stage-overhang` (:root): token de dimensão nosso, mesmo
       padrão `--ft-*` do resto do tema.
     - Peça 2D com rostos do kit (Passo B3) e `.assistant-bubble2d`: nome NU, mesma família de
       `.assistant-shell`/`.assistant-cup`/`.assistant-face` já existentes em `ft-assistant-avatar.css` — são "partes do
       personagem", não hooks de hospedagem.

   MAPA mockup → produção (para B2/C1/C2 usarem):
     .assistant-stage            → .ft-assistant-stage            (+ --left/--right)
     .assistant-wall/.assistant-cord/.assistant-lamp/.assistant-lightcone/.assistant-frame/.assistant-baseboard/.assistant-floorplane
                             → mesmo nome (nu), descendente de .ft-assistant-stage
     .assistant-stage__label/__floor/__ctx  → mesmo nome (nu)
     .assistant-trace(+__empty/__step/__cost)  → mesmo nome (nu) — OBRIGATÓRIO casar com ft-assistant.js
     .assistant-conv/__head/__status/.head2d/.assistant-chip/.assistant-close/.assistant-log/.assistant-msg(--user/
     --assistant)/.assistant-empty/.assistant-sugg/.assistant-composer(__bar)/.assistant-send/.assistant-hint/.assistant-rail
     (__head/__acts/__search/__list/__group/__item/__foot/__count)/.assistant-ib/.assistant-new
                             → mesmo nome (nu). Em uso desde C1/C2 (2026-09-23) pela conversa
                               redesenhada de _FtAiChatPanel.cshtml: .assistant-conv(__head/__status/
                               __body), .assistant-chip, .assistant-empty/.assistant-sugg, .assistant-composer(__bar)/
                               .ib/.assistant-send, .assistant-hint; .assistant-close em Ai/Panel.cshtml. O log e
                               as mensagens seguem .ft-ai-log/.ft-ai-msg (o script cria por esse
                               nome); .assistant-log, .assistant-msg, .assistant-rail__* e .assistant-new ficam como
                               porte do mockup, sem hospedeiro. (⚠️ nunca escreva "asterisco+barra"
                               dentro deste comentário: fecha o comentário e derruba o :root abaixo —
                               aconteceu em 2026-09-23, modal abriu com 150 px; ver ft-assistant-css.test.mjs)
     .assistant-page/.assistant-panel → NÃO portados: são o grid da BANCADA standalone; em produção o
                               grid já existe (.ft-ai-app/.ft-ai-app--modal) e ganha a coluna do
                               palco via :has() abaixo, em vez de duplicar um sistema paralelo
     .ft-modal__dialog--assistant → seção "MODAL" (C1), junto do card que o iframe desenha

   TOKENS: trocados por `var(--ft-token)` sem fallback literal (mesma convenção de
   ft-chat-surface.css, ex-_FtAiChatStyle.cshtml) onde o token real já cobre — `--ft-border-color`, `--ft-bg-surface`,
   `--ft-bg-muted`, `--ft-bg-page`, `--ft-text-primary`, `--ft-text-muted`, `--ft-color-primary`,
   `--ft-color-primary-hover`, `--ft-color-assistant-primary/secondary`. A paleta ESCURA do palco
   (torre/parede/piso — `#1b2a20`/`#0f1712`/`#0a100c`/`#cfe3d5`/etc.) fica LITERAL de propósito:
   é um cenário de teatro, constante nos dois temas, mesmo raciocínio de `--ft-color-assistant-*`
   (marca, não estado — ver comentário em ft-light.css:19-22). `glow` `#4DFFA6` é fixo (D11).

   `:has()` — suporte já dado como certo pelo plano (Chrome/Edge/Safari/Firefox modernos).
   =============================================================================================*/

:root {
    --ft-assistant-stage-w: 300px;
    --ft-assistant-stage-overhang: 44px;
}

/* ============================================================ PALCO (torre 3D + cartões) === */
.ft-assistant-stage {
    position: relative; display: flex; flex-direction: column; align-items: center;
    margin-top: calc(-1 * var(--ft-assistant-stage-overhang)); height: calc(100% + var(--ft-assistant-stage-overhang));
    color: #cfe3d5; overflow: hidden;
    background: radial-gradient(120% 70% at 50% 22%, #1b2a20 0%, #0f1712 62%, #0a100c 100%);
    box-shadow: 0 24px 60px rgba(0, 0, 0, .35), inset 0 1px 0 rgba(255, 255, 255, .06);
}
/* --left = palco à esquerda da conversa (modal, D15 rotate-y -26) · --right = à direita (tela
   cheia, D15 rotate-y 26). O lado físico vem da ORDEM no DOM (grid, ver :has() abaixo); esta
   classe só arredonda o canto certo — ela NÃO decide o lado sozinha. */
.ft-assistant-stage--left  { border-radius: 28px 28px 0 28px; }
.ft-assistant-stage--right { border-radius: 28px 28px 28px 0; }

/* parede: cenário 2D atrás do canvas — IRMÃ do canvas, NUNCA ancestral (restrição do kit —
   nada de filter/backdrop-filter/opacity animada em ancestral de <assistant-avatar>). */
.assistant-wall { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; border-radius: inherit; }
.assistant-cord { position: absolute; top: 0; bottom: 630px; left: 209px; width: 2px; background: #3b4a41; }
.assistant-lamp { position: absolute; bottom: 586px; left: 150px; }
.assistant-lightcone {
    position: absolute; bottom: 122px; left: 75px; width: 270px; height: 464px;
    clip-path: polygon(43% 0, 57% 0, 100% 100%, 0 100%);
    background: linear-gradient(180deg, rgba(255, 205, 130, .17), rgba(255, 205, 130, .05) 55%, transparent 100%);
}
/* "quadro" da parede — nome NU de propósito: é DIFERENTE de `.ft-assistant-frame`, o <iframe> que já
   existe hoje (ft-rfq-create.css:935, usado por _FtModalAssistant.cshtml e citado em ft-assistant.js:264
   para o postMessage de fechar). São strings diferentes, sem colisão — só registrando por quê
   o nome ficou assim e não `.ft-assistant-frame`. */
.assistant-frame { position: absolute; bottom: 542px; left: 26px; }
.assistant-baseboard { position: absolute; left: 0; right: 0; bottom: 122px; height: 2px; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .09) 18%, rgba(255, 255, 255, .09) 82%, transparent); }
.assistant-floorplane { position: absolute; left: 0; right: 0; bottom: 0; height: 122px; background: linear-gradient(180deg, rgba(255, 255, 255, .04), rgba(255, 255, 255, 0) 70%); }

.assistant-stage__label, .assistant-stage__floor, .assistant-stage__ctx, .assistant-trace { position: relative; z-index: 1; }
.assistant-stage__label { position: absolute; top: calc(var(--ft-assistant-stage-overhang) + 16px); left: 24px; text-align: left; line-height: 1.25; }
.assistant-stage__label b { display: block; font-size: 13px; letter-spacing: .18em; text-transform: uppercase; color: #9fd3b1; font-weight: 800; }
.assistant-stage__label small { display: block; font-size: 10.5px; letter-spacing: .06em; color: #6f9a80; }

/* o assistente em pé na base, sobre o chão oval (o kit enquadra os pés a ~12% da base do canvas) */
.assistant-stage__floor { margin-top: auto; margin-bottom: 4px; }
.assistant-stage__floor::before {
    content: ""; position: absolute; left: 50%; bottom: 34px; width: 230px; height: 64px; transform: translateX(-50%);
    background: radial-gradient(50% 50% at 50% 50%, rgba(77, 255, 166, .26), rgba(77, 255, 166, .08) 45%, transparent 72%); pointer-events: none;
}
/* --assistant-aspect 0.72 (em vez do 4/5 do kit): canvas mais alto → o enquadramento cresce ~8% na
   vertical e o balão (topo em y≈5,0 no mundo) deixa de encostar na borda superior — medido
   2026-09-23 (docs/assistant-3d-mapping.md §4). --assistant-width/--assistant-aspect são API do KIT: nomes
   fixos, não prefixar. */
.ft-assistant-stage assistant-avatar { --assistant-width: 260px; --assistant-aspect: .72; display: block; position: relative; border-radius: 0; }

/* cartão de contexto (modal, B2 — _FtAssistantContextCard.cshtml) */
.assistant-stage__ctx { margin: 0 18px 18px; width: calc(100% - 36px); background: rgba(255, 255, 255, .06); border: 1px solid rgba(255, 255, 255, .08); border-radius: 16px; padding: 12px 14px; font-size: 13px; }
.assistant-stage__ctx b { display: block; color: #fff; font-size: 13px; }
.assistant-stage__ctx small { color: #8fb39c; }
.assistant-stage__ctx .dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--ft-color-assistant-primary); margin-right: 6px; vertical-align: 1px; }

/* cartão "o que o assistente está fazendo" (tela cheia, B2 — _FtAssistantTraceCard.cshtml). Classes NUAS
   obrigatórias: ft-assistant.js (já escrito) cria/lê estes nomes literalmente — traceStep() grava
   `class="assistant-trace__step is-run"`, traceOk() alterna para `is-ok`, traceCost() escreve no
   primeiro filho de `.assistant-trace__cost`. Não renomear sem atualizar aquele arquivo junto. */
.assistant-trace { margin: 0 18px 18px; width: calc(100% - 36px); background: rgba(255, 255, 255, .06); border: 1px solid rgba(255, 255, 255, .08); border-radius: 16px; padding: 12px 14px; font-size: 12.5px; display: grid; gap: 7px; }
.assistant-trace > b { color: #fff; font-size: 11px; letter-spacing: .1em; text-transform: uppercase; }
.assistant-trace__empty { color: #7fa38d; }
.assistant-trace__step { display: flex; gap: 9px; align-items: flex-start; color: #b7cfc0; line-height: 1.35; }
.assistant-trace__step .st { width: 13px; height: 13px; border-radius: 50%; flex: none; margin-top: 2px; border: 2px solid #4DFFA6; box-sizing: border-box; }
.assistant-trace__step.is-run .st { border-color: var(--ft-color-assistant-primary); border-top-color: transparent; animation: assistant-spin .9s linear infinite; }
.assistant-trace__step.is-ok .st { background: #4DFFA6; border-color: #4DFFA6; }
.assistant-trace__step.is-ok { color: #dbeee2; }
.assistant-trace__cost { margin-top: 2px; padding-top: 8px; border-top: 1px solid rgba(255, 255, 255, .08); font-size: 11px; color: #6f9a80; display: flex; justify-content: space-between; }
@keyframes assistant-spin { to { transform: rotate(360deg) } }
@media (prefers-reduced-motion: reduce) { .assistant-trace__step.is-run .st { animation: none; } }

/* ============================================================ INTEGRAÇÃO COM OS HOSPEDEIROS REAIS
   C1 — modal: Ai/Panel.cshtml põe o palco ANTES de _FtAiChatPanel (coluna da esquerda).
   C2 — tela cheia: Ai/Index.cshtml põe o palco DEPOIS de _FtAiChatPanel (coluna da direita).
   A ORDEM no DOM, não estas regras, decide o lado — o grid preenche em ordem de documento.

   Tudo pendurado em `:has(> .ft-assistant-stage)`: sem o nó (flag Assistant:Enable3D desligada, ou o ft-assistant.js
   o REMOVEU — sem WebGL, prefers-reduced-motion, erro do kit) nada daqui casa, e a tela fica sem palco:
   cabeça 2D no cabeçalho, progresso/plano/custo onde sempre estiveram.

   ⚠️ Limiares (§5b/§5c): tela cheia 1180 px da janela; modal 860 px da janela DO IFRAME (a modal nunca
   passa de ~1056 px, então o 1180 é só da tela cheia — senão escondia o palco da modal para sempre).
   Abaixo do limiar o palco some por `display: none`, mas o nó CONTINUA no DOM e `:has()` continua
   casando. Por isso tudo o que é "palco visível" mora dentro de `@media not all and (max-width: X)`, o
   complemento EXATO do `(max-width: X)` que esconde o palco: abaixo do limiar essas regras não existem
   e cada elemento volta ao PRÓPRIO display — sem reversão escrita à mão (que teria de adivinhar o
   display original de cada um) e sem a fresta que um `min-width: X+1px` deixaria em largura fracionária
   (zoom de 110% dá janela de 1180,5 px). =============================================================*/
@media (max-width: 1180px) {
    .ft-ai-app:not(.ft-ai-app--modal) > .ft-assistant-stage { display: none; }
}
@media (max-width: 860px) {
    .ft-ai-app--modal > .ft-assistant-stage { display: none; }
}

/* Com o palco visível, a cabeça 2D do cabeçalho e as linhas de progresso/plano/custo saem de vista — o
   assistente 3D, a linha de status e o cartão do palco assumem (P2, docs/assistant-3d-mapping.md §7). A cabeça
   continua no DOM: é da classe is-* dela que o ft-assistant.js copia o estado.
   ⚠️ O progresso NÃO leva display:none: ele é `aria-live`, e display:none o tiraria da árvore de
   acessibilidade — o leitor de tela pararia de ouvir o relato da tool. Sai só de VISTA (visually-hidden).
   ⚠️ E a cabeça é achada pelo wrapper `.assistant-2d` do cabeçalho: a âncora `[data-ft-assistant-head-anchor]` é
   IRMÃ do svg, não ancestral — `[âncora] svg.assistant` (versão anterior desta regra) não casava nada. */
/* ⚠️ `[data-ft-ai-plan]` NÃO sai: é o SELETOR de quem paga a conversa nova — entrada, não informação; o
   cartão do palco espelha o custo, não a escolha do plano (regressão apontada pelo loop em 2026-09-23). */
@media not all and (max-width: 1180px) {
    .ft-ai-app:not(.ft-ai-app--modal):has(> .ft-assistant-stage) .assistant-conv__head > .assistant-2d { display: none; }
    /* custo: some de vista (o cartão do palco o espelha), mas fica na árvore de acessibilidade — o palco
       inteiro é aria-hidden, então o cartão não serve ao leitor de tela */
    .ft-ai-app:not(.ft-ai-app--modal):has(> .ft-assistant-stage) [data-ft-ai-cost],
    .ft-ai-app:not(.ft-ai-app--modal):has(> .ft-assistant-stage) [data-ft-ai-progress] {
        position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0;
        overflow: hidden; clip-path: inset(50%); white-space: nowrap;
    }

    /* grid: trilho | divisor | conversa | palco (--ft-ai-rail vem do JS e vira 60px com o trilho recolhido) */
    .ft-ai-app:not(.ft-ai-app--modal):has(> .ft-assistant-stage) {
        --ft-assistant-stage-overhang: 24px;
        grid-template-columns: var(--ft-ai-rail, 272px) 10px minmax(0, 1fr) var(--ft-assistant-stage-w, 300px);
    }
    /* Conversa + palco lidos como UM bloco de raio 28 (§5c): a conversa desce 24 px e perde o lado direito;
       a torre ocupa a coluna inteira, então sobe 24 px acima dela, alinhada ao topo do trilho. Aqui a
       folga é a própria coluna do grid, e não a margem negativa da modal: acima do .ft-ai-app está o
       menu do site, não um fundo livre. */
    .ft-ai-app:not(.ft-ai-app--modal):has(> .ft-assistant-stage) > .ft-ai-main {
        margin-top: var(--ft-assistant-stage-overhang);
        border-right: 0; border-radius: 28px 0 0 28px;
    }
    .ft-ai-app:not(.ft-ai-app--modal) > .ft-assistant-stage { margin-top: 0; height: auto; }
}
@media not all and (max-width: 860px) {
    /* o custo FICA na modal: aqui não há cartão de passos para espelhá-lo (o palco leva o cartão de contexto) */
    .ft-ai-app--modal:has(> .ft-assistant-stage) .assistant-conv__head > .assistant-2d,
    /* o chip da entidade some também: o cartão de contexto do palco já diz de que entidade é (§5b) */
    .ft-ai-app--modal:has(> .ft-assistant-stage) .assistant-chip { display: none; }
    .ft-ai-app--modal:has(> .ft-assistant-stage) [data-ft-ai-progress] {
        position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0;
        overflow: hidden; clip-path: inset(50%); white-space: nowrap;
    }

    /* grid: palco | conversa (trilho e divisor já saem por .ft-ai-app--modal) */
    .ft-ai-app--modal:has(> .ft-assistant-stage) {
        grid-template-columns: var(--ft-assistant-stage-w, 300px) minmax(0, 1fr);
    }
}

/* ============================================================ MODAL (C1) — casca e card
   A casca (`Ai/_FtModalAssistant.cshtml` sobre `Shared/__FtModal.cshtml`) virou só moldura transparente:
   sem cabeçalho, sem rodapé, e o iframe a ocupa inteira. Quem desenha o card de 700 px, a torre de
   44 px que sobe acima dele e o × é o CONTEÚDO do iframe (`Ai/Panel.cshtml`, `html.ft-ai-embed`).
   Medidas de partida do mockup aprovado (D12, tests/assistant-3d/modal.html) — o encaixe fino é 🎬. ======*/

/* Largura: o card (1040) + 16 px de folga à direita para o × que flutua fora do canto — o × mora DENTRO
   do iframe, e o que passa da borda do iframe é cortado. `100%` e não o 96vw do mockup: o .ft-modal tem
   padding, e 96vw passava da área útil em janela estreita. Altura: o card (700, limitado a 100vh − 72
   como no mockup) MAIS a torre que sobe acima dele. Dois seletores: ganha de .ft-modal__dialog. */
.ft-modal__dialog.ft-modal__dialog--assistant {
    width: min(calc(1040px + 16px), 100%);
    height: min(calc(700px + var(--ft-assistant-stage-overhang)), calc(100vh - 72px + var(--ft-assistant-stage-overhang)));
}
.ft-modal__dialog--assistant > .ft-modal__content {
    height: 100%; border: 0; border-radius: 0; background: transparent; box-shadow: none;
}
.ft-modal__dialog--assistant .ft-modal__body { padding: 0; overflow: hidden; }
/* Dois seletores de classe de propósito: o `.ft-assistant-frame` de ft-rfq-create.css (72vh, min 26rem)
   carrega DEPOIS deste arquivo na tela da cotação e ganharia de um seletor só. */
.ft-assistant-frame.ft-assistant-frame--full {
    display: block; width: 100%; height: 100%; min-height: 0; border: 0; background: transparent;
}
/* Fundo do mockup: verde-escuro + desfoque. `backdrop-filter` SÓ aqui — o backdrop é IRMÃO do diálogo,
   nunca ancestral do <assistant-avatar> (restrição do kit). No tema escuro fica o tom do próprio tema. */
.ft-modal:has(> .ft-modal__dialog--assistant) > .ft-modal__backdrop {
    background: rgba(12, 22, 17, .58); backdrop-filter: blur(3px);
}
[data-theme="dark"] .ft-modal:has(> .ft-modal__dialog--assistant) > .ft-modal__backdrop { background: var(--ft-bg-backdrop); }

/* A MESMA modal sem FtModal (tela legada do app, que não carrega o fixtres-components — decisão do dono de
   2026-09-29: o avatar da topnav abre o chat SEMPRE em modal). ft-topnav.js › openAiDialog cria um <dialog
   class="ft-assistant-dialog"> nativo, aberto por showModal(), com o mesmo iframe .ft-assistant-frame--full (acima) para
   /Ai/Panel. Geometria da .ft-modal__dialog--assistant: o 100% de lá é a área dentro do padding de 1rem da .ft-modal,
   que aqui vira 100vw − 32px (a mesma conta do dialog.ft-desk--shell do Balcão). O UA dá ao dialog:modal
   max-width/max-height (100% − 6px − 2em, que no celular cortaria a largura), padding, borda, fundo e overflow
   próprios: todos reescritos. O fundo é o da FtModal do assistente, logo acima; o token do tema escuro leva o literal
   de fallback porque a tela legada tem data-theme e não tem os tokens (só vêm com o fixtres-components). */
dialog.ft-assistant-dialog {
    position: fixed; inset: 0; margin: auto; padding: 0; border: 0; background: transparent; overflow: visible;
    width: min(calc(1040px + 16px), calc(100vw - 32px)); max-width: none;
    height: min(calc(700px + var(--ft-assistant-stage-overhang)), calc(100vh - 72px + var(--ft-assistant-stage-overhang)));
    max-height: none;
}
dialog.ft-assistant-dialog::backdrop { background: rgba(12, 22, 17, .58); backdrop-filter: blur(3px); }
[data-theme="dark"] dialog.ft-assistant-dialog::backdrop { background: var(--ft-bg-backdrop, rgba(12, 22, 17, .58)); }

/* ---- dentro do iframe (Ai/Panel.cshtml) ---- */
/* Transparente: a torre "sai da moldura" sobre o fundo escuro da casca, e fora do card não há nada.
   `flow-root` no body: sem ele a margem de cima do card (a folga da torre) VAZA pelo body (colapso de
   margem) e empurra o body inteiro 44 px para baixo — o iframe ganharia rolagem. */
.ft-ai-embed, .ft-ai-embed body { background: transparent; }
.ft-ai-embed body { display: flow-root; }
/* O card — sempre, com ou sem palco: a casca não pinta mais nada. */
.ft-ai-embed .ft-ai-app--modal { position: relative; background: var(--ft-bg-surface); border-radius: 28px; }

/* × sem palco (flag desligada, sem WebGL, reduced-motion, iframe < 860 px): no cabeçalho, dentro do card —
   o cabeçalho reserva o lugar dele à direita. */
.ft-ai-app--modal > .assistant-close {
    top: 16px; right: 18px; width: 36px; height: 36px; font-size: 20px;
    background: var(--ft-bg-muted); box-shadow: none; z-index: 2;
}
.ft-ai-app--modal .assistant-conv__head { padding-right: 44px; }

@media not all and (max-width: 860px) {
    /* Com palco: o card desce 44 px (a torre sobe nesse espaço — margem negativa dela, lá em cima) e deixa
       16 px à direita para o × flutuar fora do canto, como no mockup. */
    .ft-ai-embed .ft-ai-app--modal:has(> .ft-assistant-stage) {
        margin: var(--ft-assistant-stage-overhang) 16px 0 0;
        height: calc(100% - var(--ft-assistant-stage-overhang));
    }
    .ft-ai-app--modal:has(> .ft-assistant-stage) > .assistant-close {
        top: -14px; right: -14px; width: 40px; height: 40px; font-size: 22px;
        background: var(--ft-bg-surface); box-shadow: 0 6px 20px rgba(0, 0, 0, .25);
    }
    .ft-ai-app--modal:has(> .ft-assistant-stage) .assistant-conv__head { padding-right: 0; }
}

/* ============================================================ CONVERSA / COMPOSITOR / TRILHO
   Portado do mockup (nome NU, ver nota de convenção no topo). Em uso pela conversa redesenhada de
   `_FtAiChatPanel.cshtml` (C1/C2) — o que é só dela (cabeçalho em três partes, estado vazio irmão do
   log, dica que encolhe) vem logo depois do porte. =================================================*/
.assistant-conv { display: flex; flex-direction: column; min-height: 0; padding: 22px 26px 20px 28px; }
.assistant-conv__head { display: flex; align-items: flex-start; gap: 12px; padding-bottom: 14px; border-bottom: 1px solid var(--ft-border-color); }
.assistant-conv__head h2 { margin: 0; font-size: 22px; line-height: 1.1; letter-spacing: -.3px; }
.assistant-conv__status { margin-top: 3px; font-size: 13px; color: var(--ft-text-muted); display: flex; align-items: center; gap: 7px; }
.assistant-conv__status::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--ft-color-assistant-secondary); box-shadow: 0 0 0 3px rgba(0, 182, 56, .18); transition: background .3s; }
.assistant-conv__status.is-busy::before { background: var(--ft-color-assistant-primary); box-shadow: 0 0 0 3px rgba(254, 148, 2, .2); animation: assistant-status 1.1s ease-in-out infinite; }
@keyframes assistant-status { 50% { opacity: .35 } }
.assistant-conv__head .head2d { display: none; }
.assistant-chip { display: inline-flex; align-items: center; gap: 7px; margin-left: auto; padding: 7px 12px; border-radius: 999px; font-size: 12.5px; font-weight: 600; color: var(--ft-text-primary);
    background: color-mix(in srgb, var(--ft-color-assistant-primary) 12%, var(--ft-bg-surface)); border: 1px solid color-mix(in srgb, var(--ft-color-assistant-primary) 30%, transparent); white-space: nowrap; }
.assistant-chip .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ft-color-assistant-primary); }
.assistant-chip a { color: inherit; text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--ft-color-assistant-primary) 55%, transparent); }

.assistant-close {
    position: absolute; top: -14px; right: -14px; width: 40px; height: 40px; border-radius: 50%; border: 0; cursor: pointer;
    background: var(--ft-bg-surface); color: var(--ft-text-primary); box-shadow: 0 6px 20px rgba(0, 0, 0, .25);
    display: grid; place-items: center; font-size: 22px; line-height: 1;
}
.assistant-close:hover { transform: scale(1.06); }

.assistant-log { flex: 1 1 auto; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; padding: 18px 4px 12px 0; }
.assistant-msg { max-width: 78%; padding: 10px 14px; border-radius: 16px; font-size: 14px; line-height: 1.45; }
.assistant-msg--user { align-self: flex-end; background: color-mix(in srgb, var(--ft-color-primary) 13%, var(--ft-bg-surface)); border-bottom-right-radius: 6px; }
.assistant-msg--assistant { align-self: flex-start; background: var(--ft-bg-muted); border-bottom-left-radius: 6px; }
.assistant-msg table { border-collapse: collapse; margin-top: 8px; font-size: 13px; }
.assistant-msg td, .assistant-msg th { padding: 4px 10px; border-bottom: 1px solid rgba(0, 0, 0, .08); text-align: left; }
.assistant-msg th { color: var(--ft-text-muted); font-weight: 600; }

/* estado vazio */
.assistant-empty { margin: auto 0; display: grid; gap: 14px; }
.assistant-empty h3 { margin: 0; font-size: 26px; letter-spacing: -.4px; line-height: 1.15; }
.assistant-empty p { margin: 0; color: var(--ft-text-muted); font-size: 14px; }
.assistant-sugg { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 6px; }
.assistant-sugg button {
    text-align: left; border: 1px solid var(--ft-border-color); background: var(--ft-bg-surface); border-radius: 16px; padding: 12px 14px; cursor: pointer; font: inherit; color: inherit;
    display: grid; gap: 6px; transition: border-color .15s, transform .15s, box-shadow .15s;
}
.assistant-sugg button:hover { border-color: var(--ft-color-assistant-primary); transform: translateY(-1px); box-shadow: 0 8px 20px rgba(0, 0, 0, .08); }
.assistant-sugg .ico { width: 28px; height: 28px; border-radius: 9px; display: grid; place-items: center; background: color-mix(in srgb, var(--ft-color-assistant-primary) 16%, var(--ft-bg-surface)); color: #d97706; }
.assistant-sugg .ico svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.assistant-sugg b { font-size: 13.5px; } .assistant-sugg small { color: var(--ft-text-muted); font-size: 12px; }

/* compositor: 3 linhas (cresce até 8) + barra de ações */
.assistant-composer { display: flex; flex-direction: column; gap: 4px; padding: 12px 12px 10px 16px; border: 1px solid var(--ft-border-color); border-radius: 20px; background: var(--ft-bg-surface); box-shadow: 0 1px 2px rgba(0, 0, 0, .04); transition: box-shadow .15s, border-color .15s; }
.assistant-composer:focus-within { border-color: var(--ft-color-assistant-primary); box-shadow: 0 0 0 4px rgba(254, 148, 2, .14); }
.assistant-composer textarea { width: 100%; box-sizing: border-box; border: 0; outline: 0; resize: none; background: transparent; font: inherit; font-size: 14px; line-height: 1.45; padding: 4px 0; min-height: calc(1.45em * 3 + 8px); max-height: calc(1.45em * 8 + 8px); color: inherit; }
.assistant-composer__bar { display: flex; align-items: center; gap: 2px; border-top: 1px solid color-mix(in srgb, var(--ft-border-color) 60%, transparent); padding-top: 8px; }
.assistant-composer__bar .spacer { flex: 1; }
.assistant-composer__bar .hint { font-size: 11.5px; color: var(--ft-text-muted); margin-right: 12px; }
.assistant-composer .ib { width: 34px; height: 34px; border-radius: 10px; border: 0; background: transparent; color: var(--ft-text-muted); cursor: pointer; display: grid; place-items: center; }
.assistant-composer .ib:hover { background: var(--ft-bg-muted); color: inherit; }
.assistant-composer .ib svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.assistant-send { height: 36px; padding: 0 16px 0 14px; border-radius: 999px; border: 0; background: var(--ft-color-primary); color: var(--ft-text-inverse, #fff); cursor: pointer; display: inline-flex; align-items: center; gap: 8px; font: inherit; font-size: 14px; font-weight: 600; box-shadow: 0 6px 16px rgba(13, 110, 253, .3); }
.assistant-send:hover { background: var(--ft-color-primary-hover); }
.assistant-send svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.assistant-hint { margin: 8px 4px 0; font-size: 11.5px; color: var(--ft-text-muted); text-align: center; }

/* ---- o que é só da conversa de produção (_FtAiChatPanel.cshtml), além do porte ---- */
/* Cabeçalho em três partes: cabeça 2D (.assistant-2d) · título + status (é a âncora do setAssistant) · chip da
   entidade + plano/custo, empurrados para a ponta. O bloco do meio encolhe antes de empurrar os outros. */
.assistant-conv__id { min-width: 0; }
.assistant-conv__aside { margin-left: auto; display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 10px; min-width: 0; }
.assistant-conv__aside > .assistant-chip { margin-left: 0; }
/* O ponto do status pulsa enquanto o assistente trabalha — parado com reduced-motion; a COR (laranja) continua
   dizendo "ocupado". */
@media (prefers-reduced-motion: reduce) { .assistant-conv__status.is-busy::before { animation: none; } }
/* A dica encolhe (reticências) antes de empurrar o Enviar para fora da barra. */
.assistant-composer__bar .hint { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ESTADO VAZIO — irmão do log, ANTES dele (o script esvazia o log por innerHTML ao trocar de conversa;
   dentro dele o convite morreria). Some com a primeira mensagem e volta sozinho numa conversa nova.
   ⚠️ `:empty` exige o log vazio DE VERDADE: nem um espaço em branco dentro do markup. */
[data-ft-ai-empty]:has(+ [data-ft-ai-log]:not(:empty)) { display: none; }
/* Enquanto o convite aparece, o log vazio não disputa a altura: o flex-grow dele comeria o espaço livre e
   o convite — que se centraliza pelas margens auto de .assistant-empty — iria parar colado no compositor. */
[data-ft-ai-empty]:not([hidden]) + [data-ft-ai-log]:empty { flex: 0 0 auto; padding: 0; }
/* Entra com atraso: ao trocar de conversa o log fica vazio até o histórico chegar, e sem o atraso o
   convite piscaria por cima dele. `visibility` junto do `opacity`: invisível, também não recebe clique.
   Opacity animada aqui é permitida — o convite não é ancestral do <assistant-avatar>. */
.assistant-empty { animation: assistant-empty-in .2s ease-out .45s both; }
@keyframes assistant-empty-in { from { opacity: 0; visibility: hidden; } }
@media (prefers-reduced-motion: reduce) { .assistant-empty { animation-duration: 0s; } }
/* Estreito (§5b/§5c: < 860 px, na modal é a janela do iframe): sugestões em uma coluna. */
@media (max-width: 860px) { .assistant-sugg { grid-template-columns: 1fr; } }
/* O convite pode ficar mais alto que o corpo (sugestões em coluna + a fileira "Atendimento" do Balcão, passo B7 de
   docs/Features/support.md): sem isto ele não encolhe, .assistant-conv__body tem overflow hidden e o compositor é
   empurrado para fora e cortado (medido em 2026-09-29: 108 px em 880×1000, 180 px em 390×844 na modal, cuja
   altura é travada em 700 px). Com min-height 0 o convite passa a rolar em tela estreita e o compositor fica. */
[data-ft-ai-empty] { min-height: 0; overflow-y: auto; }

/* ---------------------------------------------------------------- trilho de conversas (tela cheia) */
.assistant-rail { display: flex; flex-direction: column; min-height: 0; background: var(--ft-bg-surface); border: 1px solid var(--ft-border-color); border-radius: 24px; overflow: hidden; box-shadow: 0 10px 40px rgba(0, 0, 0, .06); }
.assistant-rail__head { display: flex; align-items: center; justify-content: space-between; padding: 18px 18px 10px; }
.assistant-rail__head h3 { margin: 0; font-size: 15px; }
.assistant-rail__acts { display: flex; gap: 2px; }
.assistant-rail__acts button, .assistant-ib { width: 32px; height: 32px; border-radius: 10px; border: 0; background: transparent; color: var(--ft-text-muted); cursor: pointer; display: grid; place-items: center; }
.assistant-rail__acts button:hover, .assistant-ib:hover { background: var(--ft-bg-muted); color: inherit; }
.assistant-rail__acts svg, .assistant-ib svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.assistant-rail__search { margin: 0 14px 8px; display: flex; align-items: center; gap: 8px; padding: 9px 12px; border: 1px solid var(--ft-border-color); border-radius: 12px; color: var(--ft-text-muted); font-size: 13px; background: var(--ft-bg-page); }
.assistant-rail__search svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; }
.assistant-rail__list { flex: 1; overflow-y: auto; padding: 4px 10px 10px; display: grid; gap: 2px; align-content: start; }
.assistant-rail__group { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--ft-text-muted); padding: 12px 8px 4px; }
.assistant-rail__item { display: grid; gap: 3px; padding: 10px 12px 10px 14px; border-radius: 14px; cursor: pointer; position: relative; }
.assistant-rail__item:hover { background: var(--ft-bg-muted); }
.assistant-rail__item.is-active { background: color-mix(in srgb, var(--ft-color-assistant-secondary) 9%, var(--ft-bg-surface)); }
.assistant-rail__item.is-active::before { content: ""; position: absolute; left: 0; top: 10px; bottom: 10px; width: 3px; border-radius: 3px; background: var(--ft-color-assistant-primary); }
.assistant-rail__item b { font-size: 13.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.assistant-rail__item small { font-size: 12px; color: var(--ft-text-muted); display: flex; gap: 6px; align-items: center; }
.assistant-rail__item .tag { font-size: 10.5px; padding: 1px 7px; border-radius: 999px; background: color-mix(in srgb, var(--ft-color-assistant-primary) 14%, var(--ft-bg-surface)); color: #b45309; font-weight: 600; }
.assistant-rail__foot { padding: 12px 14px 14px; border-top: 1px solid var(--ft-border-color); display: grid; gap: 8px; }
.assistant-rail__count { font-size: 12px; color: var(--ft-text-muted); text-align: center; }
.assistant-new { height: 40px; border-radius: 999px; border: 0; background: var(--ft-color-primary); color: #fff; font: inherit; font-size: 14px; font-weight: 600; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 8px; box-shadow: 0 6px 16px rgba(13, 110, 253, .3); }
.assistant-new svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2.4; stroke-linecap: round; }

/* ============================================================ PEÇA 2D — rostos do kit (D10, Passo B3)
   Irmã de .assistant-face (ft-assistant-avatar.css), mesmo estilo compacto daquele bloco de propósito —
   é a MESMA família de regra, só que vive aqui por nascer nesta gravação. Ver _FtAssistantAvatar.cshtml
   para o markup dos 10 grupos. Sem `Face` setado (default), nada aqui se aplica — os 4 estados de
   sempre continuam via `.assistant-face`, sem nenhuma regra nova entrando na jogada. ====================*/
.assistant .assistant-face-kit{display:none}
.assistant.face-curious .assistant-face-kit,.assistant.face-determined .assistant-face-kit,.assistant.face-happy .assistant-face-kit,.assistant.face-laugh .assistant-face-kit,.assistant.face-love .assistant-face-kit,.assistant.face-neutral .assistant-face-kit,.assistant.face-playful .assistant-face-kit,.assistant.face-sad .assistant-face-kit,.assistant.face-surprised .assistant-face-kit,.assistant.face-wink .assistant-face-kit{display:inline}
.assistant .assistant-face-kit>g{display:none}
.assistant.face-curious .assistant-face-kit__curious{display:inline}
.assistant.face-determined .assistant-face-kit__determined{display:inline}
.assistant.face-happy .assistant-face-kit__happy{display:inline}
.assistant.face-laugh .assistant-face-kit__laugh{display:inline}
.assistant.face-love .assistant-face-kit__love{display:inline}
.assistant.face-neutral .assistant-face-kit__neutral{display:inline}
.assistant.face-playful .assistant-face-kit__playful{display:inline}
.assistant.face-sad .assistant-face-kit__sad{display:inline}
.assistant.face-surprised .assistant-face-kit__surprised{display:inline}
.assistant.face-wink .assistant-face-kit__wink{display:inline}
.assistant.face-curious .assistant-face,.assistant.face-determined .assistant-face,.assistant.face-happy .assistant-face,.assistant.face-laugh .assistant-face,.assistant.face-love .assistant-face,.assistant.face-neutral .assistant-face,.assistant.face-playful .assistant-face,.assistant.face-sad .assistant-face,.assistant.face-surprised .assistant-face,.assistant.face-wink .assistant-face{display:none}
.assistant .assistant-face-kit{color:var(--ft-color-assistant-secondary);stroke-width:18}

/* balão 2D opcional acima da cabeça (ícone ou texto) — preparado para FtAssistant.express({bubble})
   quando o call site é a peça 2D (A2/D1, fora desta gravação); começa `hidden` (mesma convenção
   de .ft-ai-progress etc. — ver [hidden] global em ft-theme.css:66). O wrapper .assistant-2d é só
   ancoragem de posição: svg.assistant continua sendo o alvo de toda classe/seletor já existente. */
.assistant-2d { display: inline-block; position: relative; vertical-align: middle; flex: none; }
.assistant-bubble2d {
    position: absolute; left: 50%; bottom: 100%; transform: translateX(-50%); margin-bottom: 4px;
    white-space: nowrap; font-size: 11px; line-height: 1.3; padding: 3px 8px; border-radius: 999px;
    background: #0f1512; color: var(--ft-color-assistant-secondary); border: 1.5px solid var(--ft-color-assistant-secondary);
    pointer-events: none;
}
