/*
 * This is a manifest file that'll be compiled into application.css.
 *
 * With Propshaft, assets are served efficiently without preprocessing steps. You can still include
 * application-wide styles in this file, but keep in mind that CSS precedence will follow the standard
 * cascading order, meaning styles declared later in the document or manifest will override earlier ones,
 * depending on specificity.
 *
 * Consider organizing styles into separate files for maintainability.
 */

/* ==================== TYPING INDICATOR ==================== */
.typing-indicator {
  animation: fadeInTyping 0.3s ease-in-out;
}
.typing-dots {
  display: flex;
  align-items: center;
  gap: 4px;
  height: 20px;
}
.typing-dots span {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: #90949c;
  animation: typingBounce 1.4s infinite ease-in-out both;
}
.typing-dots span:nth-child(1) {
  animation-delay: 0s;
}
.typing-dots span:nth-child(2) {
  animation-delay: 0.2s;
}
.typing-dots span:nth-child(3) {
  animation-delay: 0.4s;
}
@keyframes typingBounce {
  0%, 80%, 100% {
    transform: scale(0.6);
    opacity: 0.4;
  }
  40% {
    transform: scale(1);
    opacity: 1;
  }
}
@keyframes fadeInTyping {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ==================== CLEARFIX DO AdminLTE x .card-header.d-flex ====================
 * AdminLTE define ".card-header::after{display:block;clear:both;content:''}"
 * (clearfix pra layout com float). Um pseudo-elemento com content:"" e
 * display != none vira um item FLEX de verdade (não é ignorado) quando o
 * pai é display:flex — em qualquer .card-header.d-flex.justify-content-between
 * com 2 filhos "visíveis", esse ::after entra como um 3º item invisível na
 * ponta, e o space-between reparte o espaço em DOIS vãos (entre os filhos
 * reais, e entre o 2º filho e o ::after fantasma) em vez de UM vão só entre
 * os dois filhos — sobra um vão extra depois do último filho, colado na
 * borda, sem elemento nenhum ali (bug relatado: badges/botões do cabeçalho
 * da conversa não ficavam realmente encostados na borda direita do card).
 * content:none neutraliza o pseudo-elemento (deixa de gerar caixa) só onde
 * .card-header também é .d-flex — headers sem flex mantêm o clearfix. */
.card-header.d-flex::after {
  content: none;
}

/* ==================== BACKDROP DOS MODAIS ==================== */
/* Cinza TRANSLÚCIDO garantido (pedido do QA: ver a tela atrás do modal).
 * Em produção o fundo aparecia 100% preto opaco; localmente o padrão do
 * Bootstrap (preto + opacity .5) está correto — este override defensivo com
 * !important e rgba (cor+alpha na MESMA propriedade, independente de
 * `opacity`) torna o resultado imune a conflito de tema do navegador,
 * extensão, ordem de carga de CSS ou backdrop empilhado no ambiente. */
.modal-backdrop {
  background-color: rgba(33, 37, 41, 0.5) !important;
}
/* opacity 1 só com .show — preserva o fade de entrada/saída (.fade => 0). */
.modal-backdrop.show {
  opacity: 1 !important;
}
/* Backdrops EMPILHADOS (órfãos/duplicados) compõem alpha (0.5ⁿ → preto):
 * garante um único backdrop visível, qualquer que seja a origem do extra. */
.modal-backdrop.show ~ .modal-backdrop.show {
  display: none !important;
}

/* ==================== UTILITÁRIOS p/ remover style="" inline (CSP) ==================== */
/* Substituem atributos style= nas views renderizadas — necessário para que o
 * Content-Security-Policy possa rodar sem 'unsafe-inline' em style-src. */

/* Visibilidade controlada por markup */
.is-hidden { display: none !important; }

/* Avatares circulares e thumbnails */
.avatar-circle-sm { width: 40px; height: 40px; }
.avatar-circle-md { width: 45px; height: 45px; }
.avatar-img-cover { object-fit: cover; }

/* Painel de mensagens do agente */
.chat-messages-pane { max-height: 60vh; }
.chat-message-bubble { max-width: 75%; }
/* Quebras de linha digitadas (Shift+Enter) renderizam na bolha; palavras/URLs
   compridas sem espaço quebram em vez de estourar a largura. */
.chat-message-bubble .message-body {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* Vídeo anexado na bolha: mesmo espírito do cap de imagem — nunca domina o
   histórico; o player nativo cuida do resto. */
.chat-message-bubble .message-attachment.video-attachment video {
  max-width: 260px;
  max-height: 180px;
  border-radius: 6px;
  display: block;
}
/* Campo de mensagem: textarea auto-crescente (mensagem longa QUEBRA linha em
   vez de rolar horizontalmente — bug relatado). Altura controlada pelo JS
   (autosizeField); depois do teto, rola internamente. */
.chat-input-autogrow {
  resize: none;
  overflow-y: auto;
  max-height: 132px;
}

/* Tamanhos de ícone usados em listas/empty states */
.icon-1-5rem { font-size: 1.5rem; }
.icon-1-8rem { font-size: 1.8rem; }
.icon-2rem   { font-size: 2rem; }
.icon-4rem   { font-size: 4rem; }

/* Campo numérico estreito (ex.: limite simultâneo nos modais) */
.input-narrow { width: 110px; }

/* ==================== MODAIS ROLÁVEIS COM FORM ====================
 * Nos modais .modal-dialog-scrollable em que um <form> envolve
 * header/body/footer (ex.: Editar/Cadastrar widget), o form vira o ÚNICO
 * filho flex do .modal-content e cresce além do max-height — o conteúdo é
 * CLIPADO pelo overflow:hidden sem nunca ativar o scroll do .modal-body.
 * Este bloco propaga o layout flex do Bootstrap através do form, devolvendo
 * ao .modal-body a altura restrita (e o scroll) e mantendo o footer visível. */
.modal-dialog-scrollable .modal-content > form {
  display: flex;
  flex-direction: column;
  max-height: 100%;
  min-height: 0;
  overflow: hidden;
}

/* ==================== ANEXOS (painel do agente) ====================
 * Mesmas classes de widget.css (preview de upload + anexo na mensagem) —
 * o layout admin não carrega widget.css, então precisam existir aqui também. */
#chatForm .attachment-preview {
  display: none;
  padding: 8px 12px;
  background: #f8f9fa;
  border-radius: 6px;
}
#chatForm .attachment-preview.show {
  display: flex;
  align-items: center;
  gap: 10px;
}
#chatForm .attachment-preview .file-info {
  flex: 1;
  font-size: 0.85rem;
  color: #495057;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#chatForm .attachment-preview .file-info i {
  margin-right: 5px;
  color: #6c757d;
}
#chatForm .attachment-preview .remove-attachment {
  background: none;
  border: none;
  color: #dc3545;
  cursor: pointer;
  padding: 2px 6px;
}

.chat-message-bubble .message-attachment {
  margin-top: 8px;
}
.chat-message-bubble .message-attachment.image-attachment img {
  max-width: 200px;
  max-height: 150px;
  border-radius: 8px;
  cursor: pointer;
  transition: transform 0.2s;
}
.chat-message-bubble .message-attachment.image-attachment img:hover {
  transform: scale(1.02);
}
.chat-message-bubble .message-attachment.file-attachment .attachment-link {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: rgba(0, 0, 0, 0.1);
  border-radius: 8px;
  color: inherit;
  text-decoration: none;
  font-size: 0.85rem;
  transition: background 0.2s;
}
.chat-message-bubble .message-attachment.file-attachment .attachment-link:hover {
  background: rgba(0, 0, 0, 0.18);
}
.chat-message-bubble .message-attachment.file-attachment .attachment-link i:first-child {
  font-size: 1.5rem;
}
.chat-message-bubble .message-attachment.file-attachment .attachment-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Abas do painel de atendimentos (Humano / Anne / Em espera): coluna lateral
   é estreita (col-lg-3) e as 3 abas quebravam em duas linhas. flex-nowrap no
   markup segura a linha única; aqui o conteúdo encolhe pra caber nela e, se
   ainda faltar, rola horizontal em vez de quebrar. */
.chat-panel-tabs {
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
}
.chat-panel-tabs .nav-link {
  white-space: nowrap;
  padding: 0.4rem 0.55rem;
  font-size: 0.85rem;
}
.chat-panel-tabs .nav-link .badge {
  font-size: 0.68rem;
}
@media (min-width: 992px) and (max-width: 1399px) {
  /* Faixa em que a coluna é mais apertada: ícone das abas sai, o rótulo fica. */
  .chat-panel-tabs .nav-link .bi {
    display: none;
  }
}

/* Tela de atendimento (Admin::Chats#index): layout fixo tipo TomTicket.
   Sem isto, .row.g-3 (index.html.slim) cresce com o conteúdo (lista de
   conversas + histórico de mensagens) e é a página inteira (.app-main) que
   rola — o cabeçalho "Atendimentos Ativos" e as abas Humano/Anne/Em espera
   somem junto, escondendo mudança na fila enquanto o atendente lê mensagens
   antigas (bug reportado). A cadeia abaixo trava a altura de .row.g-3 no
   espaço visível de .app-main e move a rolagem pra DENTRO de cada coluna
   (lista de contatos / mensagens), que ficam com cabeçalho e abas fixos.
   Escopado pela classe de controller/action no <body> (ver layout) pra não
   afetar o scroll normal das demais páginas do admin.
   min-width:768px (breakpoint "md" do Bootstrap, mesmo usado pelas colunas
   .col-md-4/.col-md-8 do index.html.slim): abaixo disso as duas colunas
   EMPILHAM (viram col-12), e essa cadeia de altura travada assume colunas
   lado a lado — aplicada às colunas empilhadas, ela reparte a altura FIXA
   da .row entre as duas (confirmado via teste headless: 141px pra CADA
   card empilhado, cortando toda a conversa/mensagens). Sem o media query
   a versão mobile fica pior que o scroll de página normal que ela substitui
   no desktop. */
@media (min-width: 768px) {
body:is(.admin-chats-index, .admin-chats-show) .app-wrapper {
  /* .app-wrapper só tem min-height:100vh — SEM altura travada, a trilha
     "1fr" de .app-main (grid) cresce pra caber o conteúdo (lista de
     conversas + histórico de mensagens) em vez de ficar presa a 100vh, e é
     a PÁGINA inteira que passa a rolar (confirmado via teste headless com
     lista/mensagens estressadas: .app-wrapper cresceu de 757px pra 2500px+
     e o cabeçalho "Atendimentos Ativos" saiu da tela). height (não só
     min-height) trava o tamanho da grid de verdade. */
  height: 100vh;
}
body:is(.admin-chats-index, .admin-chats-show) .app-main {
  /* Item de grid: min-height:auto (default) usa o tamanho mínimo
     intrínseco do conteúdo como piso pra trilha "1fr" — com min-height:0
     ele aceita encolher abaixo do conteúdo, e overflow:auto vira a rede de
     segurança (só aparece scrollbar aqui se algum nível abaixo vazar). */
  min-height: 0;
  overflow: auto;
}
body:is(.admin-chats-index, .admin-chats-show) .app-content {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}
body:is(.admin-chats-index, .admin-chats-show) .app-content > .container-fluid {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
body:is(.admin-chats-index, .admin-chats-show) .app-content > .container-fluid > .row.g-3 {
  flex: 1 1 auto;
  min-height: 0;
}
body:is(.admin-chats-index, .admin-chats-show) #chatContactList,
body:is(.admin-chats-index, .admin-chats-show) turbo-frame#chatView {
  /* align-items:stretch da .row (Bootstrap) devia bastar pro #chatContactList,
     mas o .card.h-100 (height:100% percentual) não resolve de forma
     confiável dentro de <turbo-frame> (custom element, não é container flex
     pros filhos por padrão) — confirmado via teste headless: a página
     show isolada (sem .row.g-3, só container-fluid > turbo-frame > .card)
     tinha o .card crescendo pro dobro da altura disponível apesar do
     height:100%. display:flex aqui + "flex: 1 1 auto" no .card (abaixo)
     evita depender de resolução de % e funciona em qualquer contexto.
     "flex: 1 1 auto" AQUI também é necessário (não só nos descendentes):
     no fluxo normal (index.html.slim) este elemento é filho de .row.g-3
     (flex-direction:row) — a altura vem de align-items:stretch (eixo
     cruzado), grow/shrink não importam. Mas na página show isolada
     (conversa aberta direto por URL) o pai é container-fluid
     (flex-direction:COLUMN) — aí a altura é o eixo PRINCIPAL, e sem
     flex-grow:1 este elemento não cresce pra ocupar o espaço disponível,
     só encolhe se o conteúdo for maior (comportamento que "acertava por
     sorte" enquanto o .card tinha conteúdo grande o bastante pra disparar
     o shrink — confirmado via teste headless: ao encolher o conteúdo
     interno do .card, ESTE elemento colapsou pra 2px por falta de grow). */
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}
/* _show_conversation.html.slim embrulha o .card num <div
   data-chat-agent-conversation-id-value=...> (alvo do Stimulus) ANTES dele
   — só no turbo-frame#chatView.display:flex acima o .card fica órfão de
   contexto flex (o pai DIRETO dele é essa div, não o frame), e "flex: 1 1
   auto" no .card não tem efeito nenhum num pai que continua display:block
   (confirmado via teste headless: .card somava 990px = soma crua dos
   filhos, shrink nunca acionado). No estado vazio (index.html.slim sem
   conversa selecionada) o .card É filho direto do frame — o seletor
   "> *" cobre os dois casos. */
body:is(.admin-chats-index, .admin-chats-show) turbo-frame#chatView > * {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
body:is(.admin-chats-index, .admin-chats-show) #chatContactList .card,
body:is(.admin-chats-index, .admin-chats-show) turbo-frame#chatView .card {
  /* "flex: 1 1 auto" (basis:auto) usa o tamanho do CONTEÚDO como ponto de
     partida — com Resumo da Anne + avaliação + autoria (conversa vinda da
     IA) o conteúdo passa fácil de 900px, e min-height:0/max-height:100%
     não bastam: o .card fica com caixa própria travada (confirmado 427px
     via teste headless), mas os FILHOS continuam layoutados pelo tamanho
     "hypothetical" (baseado no conteúdo, não no espaço disponível) —
     max-height só corta visualmente, sem re-rodar o cálculo de shrink dos
     filhos. Resultado: card-footer (campo de digitar) ficava fora da
     caixa cortada, invisível, só reaparecendo com zoom out extremo
     (relatado pelo usuário). basis:0 faz o .card assumir o espaço
     DISPONÍVEL do pai (já travado corretamente na cadeia acima) como
     ponto de partida — daí sim os filhos (regra ".card > *" abaixo)
     encolhem contra um tamanho real, e overflow:hidden aqui (não mais só
     no ancestral) garante que é O CARD quem corta, coerente com o que
     ele mesmo calculou. */
  flex: 1 1 0;
  min-height: 0;
  overflow: hidden;
}
body:is(.admin-chats-index, .admin-chats-show) #chatContactList .card > .card-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}
/* Painel de mensagens do lado direito (_show_conversation.html.slim) já
   usa .overflow-auto.flex-grow-1 — só faltava min-height:0 pra não crescer
   além do espaço disponível (mesmo problema do painel de contatos).
   "flex" explícito (não só min-height) é necessário: a regra ".card > *"
   abaixo dá flex-shrink:0 pra tudo — sem reafirmar shrink:1 aqui (mesma
   especificidade + declaração explícita vence), o card-body pararia de
   encolher/rolar igual aos irmãos, voltando a estourar o .card. */
body:is(.admin-chats-index, .admin-chats-show) turbo-frame#chatView .card > .card-body {
  flex: 1 1 auto;
  min-height: 0;
}
/* Header, alerta de modo-visualização, Resumo da Anne, avaliação e autoria
   (_show_conversation.html.slim) e o rodapé com o campo de mensagem são
   TODOS irmãos do .card-body dentro de .card, sem proteção nenhuma contra
   encolher — com espaço apertado (tela real, sem zoom out) o
   flex-shrink:1 default reparte o déficit entre TODOS eles, e não só o
   .card-body some (relatado: só volta a aparecer tudo zoom out no
   extremo). Só o .card-body pode encolher/rolar; os demais ficam do
   tamanho natural, do contrário o rodapé com o campo de digitar some. */
body:is(.admin-chats-index, .admin-chats-show) #chatContactList .card > *,
body:is(.admin-chats-index, .admin-chats-show) turbo-frame#chatView .card > * {
  flex-shrink: 0;
}
body:is(.admin-chats-index, .admin-chats-show) #contactListPanel {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
/* Sem flex-shrink:0 a barra de abas (Humano/Anne/Em espera) concorre por
   espaço com .tab-content e é ela quem encolhe (confirmado via teste
   headless: caiu de 43px pra 16px, texto/badge cortados) — é uma barra de
   altura fixa, nunca deveria ceder espaço pra lista rolar. */
body:is(.admin-chats-index, .admin-chats-show) #contactListPanel > .chat-panel-tabs {
  flex-shrink: 0;
}
/* .tab-content precisa virar container flex (Bootstrap deixa ele block) —
   sem isso .tab-pane.active vira flex ITEM de um pai não-flex, ignora
   "flex: 1 1 auto" e volta a crescer pelo conteúdo. */
body:is(.admin-chats-index, .admin-chats-show) #contactListPanel .tab-content {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}
body:is(.admin-chats-index, .admin-chats-show) #contactListPanel .tab-pane.active {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
/* .contact-list é quem realmente rola: sem "flex: 1 1 auto" ele não
   assume a altura disponível do .tab-pane e overflow-y:auto nunca ativa
   (o item só cresce com o conteúdo, igual ao bug do .tab-content acima). */
body:is(.admin-chats-index, .admin-chats-show) #contactListPanel .contact-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
}
