/* Identidade visual ZZ Telecom
   verde #2fac66 · azul #36a9e1 · branco · cinza #e3e3e3 · cinza escuro #999999 · preto
   O vermelho não é cor de marca: é funcional (erros e exclusões), mantido por clareza.
   Cores de marca (verde/azul/vermelho) não mudam entre claro e escuro, só as
   superfícies (fundo, branco, tinta, linha) e os tons de apoio que dependem delas. */
:root {
  --largura-lateral: 220px;   /* .app.lateral-recolhida redefine pra 68px */
  --verde: #2fac66;
  --verde-escuro: #268a52;   /* hover dos botões verdes */
  --verde-fundo: #e8f6ee;    /* fundos suaves de selos/etiquetas verdes */
  --azul: #36a9e1;
  --azul-fundo: #eaf6fc;
  --azul-texto: #1d7fb4;     /* azul mais escuro, usado como texto (não em cima do --azul) */
  --vermelho: #b00020;
  --vermelho-fundo: #fde7e9; /* fundo do selo "Verificar"/erro */
  /* status "no sistema, mas fora da tela de Chat" (coluna Equipe ZZ), cor
     nova, funcional (não muda entre claro/escuro, igual ao vermelho) */
  --laranja: #d4831e;
  --laranja-fundo: #fbf0e0;
  /* fundo da faixa de aviso de sessão: mais forte que --laranja-fundo no tema
     claro, onde o bege clarinho passava despercebido (pedido do usuário,
     24/09/2026). No escuro fica igual ao --laranja-fundo, ver bloco dark */
  --laranja-faixa: #f6d5a5;
  /* texto secundário e ícone em cima dela: o cinza (--suave) e o --laranja
     sumiam nesse fundo mais forte */
  --laranja-faixa-texto: #8a5a1f;
  --laranja-faixa-icone: #a8600f;
  /* mesma ideia pra faixa quando fica urgente (2 min), o rosa do
     --vermelho-fundo era claro demais ali (pedido do usuário, 24/09/2026) */
  --vermelho-faixa: #f5c2c7;
  /* dupla "neon" só pro centro da bolinha de status sobre o avatar (ver
     .avatar-com-bolinha .pessoa-bolinha mais abaixo), tokens PRÓPRIOS, não
     --verde/--laranja de cima: aqueles são usados em botões/selos por todo
     o sistema, deixar a bolinha mais vívida não pode mudar a cor deles
     junto (pedido do usuário, 2026-08-28) */
  --status-verde-neon: #39ff6e;
  --status-laranja-neon: #ff9500;
  /* vermelho vívido só pra bolinha de aviso da lateral recolhida (ver
   .badge-solicitacoes ali embaixo), --vermelho de marca é fosco/sério de
   propósito (erro), aqui o pedido foi o oposto: chamar atenção */
  --vermelho-neon: #ff2d55;
  /* trinca só pras bolinhas de cor de fundo da conversa do Chat (ver
     .chat-config-swatch/.chat-caixa.fundo-* em estilo.css), tons pastel bem
     fracos de propósito (pedido do usuário, 2026-08-27, 2ª rodada: "todas
     mais fracas", já eram a versão enfraquecida uma vez antes) */
  --amarelo: #ddd08f;
  --amarelo-fundo: #fbf9f0;
  --ciano: #7fc4c4;
  --ciano-fundo: #eaf7f7;
  --magenta: #d3a8c4;
  --magenta-fundo: #fbf1f6;
  /* verde e azul do Chat são tokens PRÓPRIOS, não --verde/--verde-fundo nem
     --azul/--azul-fundo de cima: esses dois são usados em botões/selos por
     todo o sistema, se a bolinha do Chat reaproveitasse os mesmos tokens,
     enfraquecer essa cor (pedido do usuário) ia clarear botões/etiquetas de
     outras telas junto, efeito colateral que ninguém pediu */
  --chat-verde: #9ad0b3;
  --chat-verde-fundo: #f1f8f4;
  --chat-azul: #8ec5e6;
  --chat-azul-fundo: #eff7fb;
  /* lilás: só pra sinalizar "ramal descoberto pela automação AMI, ninguém da
     equipe revisou ainda" (ver ramais.criado_via_automacao), cor nova de
     propósito, nenhuma das outras (verde/azul/vermelho/dourado) já tem esse
     significado ocupado */
  --lilas-fundo: #f1e7fb;
  /* mesma cor do lilás acima, saturada o bastante pra virar TRAÇO e não fundo
     (o #f1e7fb sumiria como borda). Usada só na borda do cartão "descoberto"
     na visão em Blocos, onde o fundo do cartão já está ocupado pelo status,
     ver .cartao-ramal-descoberto. Mesmo raciocínio de --vermelho-cartao logo
     abaixo: precisa aparecer sobre fundos sólidos coloridos, não sobre branco */
  --lilas-cartao: #7433cc;
  /* dupla nova só pra completar a paleta do avatar (círculo com a inicial,
     ver .avatar-usuario/CORES_AVATAR abaixo e em app.js), pedido do usuário,
     2026-08-28: as outras 4 cores da paleta reaproveitam --azul/--verde/
     --laranja/--lilas-cartao de cima (mesmo tom vívido, não precisa de cor
     nova), só faltava um teal e um vinho pra fechar as 6 opções */
  --avatar-teal: #17a398;
  --avatar-vinho: #a13a5a;
  /* 8 cores a mais na paleta do avatar (pedido do usuário, 2026-08-31,
     incluindo uma preta), pra dar mais opção de distinguir cada pessoa da
     equipe visualmente. Todas escolhidas pra não repetir o matiz das 6
     originais (azul/verde/laranja/lilás/teal/vinho) e com escurecimento
     suficiente pro texto branco do avatar continuar legível em cima */
  --avatar-preto: #262626;
  --avatar-marrom: #8b5a2b;
  --avatar-rosa: #c94f7c;
  --avatar-mostarda: #b8860b;
  --avatar-cinza: #566573;
  --avatar-coral: #d9583f;
  --avatar-oliva: #5c7a1e;
  --avatar-indigo: #5a55b0;
  /* exceção à regra acima (vermelho não muda entre temas): usado só no selo
     "Verificar" dos cartões da tela de ramais, que ficam sobre fundos
     coloridos sólidos (verde/cinza escuro), não sobre branco, o vermelho
     de marca praticamente some ali no escuro, por isso essa variante mais
     clara só pro modo escuro (ver :root[data-theme="dark"] abaixo) */
  --vermelho-cartao: var(--vermelho);
  /* mesma saturação/luminosidade de --verde/--verde-escuro, só girando o matiz
     pro vermelho (HSL 146°→0°), usado só no mapa, pra distinguir Paraguai
     dos estados brasileiros sem "gritar" mais forte que o verde */
  --vermelho-mapa: #ac2f2f;
  --vermelho-mapa-escuro: #8a2626;
  --tinta: #000000;
  --suave: #999999;
  --linha: #e3e3e3;
  --fundo: #f4f4f4;
  --branco: #fff;
  --fundo-sutil: #f7f8fa;    /* cabeçalho de tabela, linha em hover, card tracejado */
  --linha-hover: #d6d6d6;    /* hover do botão .btn-claro */
  --navy: #000000;           /* legado: onde era azul-marinho, agora é o preto da marca */
  /* barra lateral: azul bem claro da marca no tema claro, com texto no
     azul-marinho; no escuro continua o azul-marinho de antes (ver bloco
     dark). Até 2026-10-29 era azul-marinho fixo nos 2 temas; o usuário pediu
     que o tema claro tivesse menu claro também. Tokens próprios em vez de
     --tinta/--suave porque no escuro o texto da lateral é branco sobre navy,
     não o cinza do resto da página */
  --lateral-fundo: var(--azul-fundo);
  --lateral-borda: rgba(22, 38, 74, .08);
  --lateral-texto: #16264a;
  --lateral-texto-suave: rgba(22, 38, 74, .72);
  --lateral-texto-apagado: rgba(22, 38, 74, .65); /* ~4.5:1 sobre o fundo claro */
  --lateral-hover: rgba(22, 38, 74, .08);
  --lateral-divisor: rgba(22, 38, 74, .14);
  --lateral-pilula: rgba(22, 38, 74, .1);
  /* mesmo azul-marinho, mas só pra TEXTO de destaque (títulos), precisa
     poder clarear no tema escuro (ver :root[data-theme="dark"] abaixo),
     diferente de --lateral-fundo, que é sempre a mesma cor escura nos 2
     temas por ser fundo da barra lateral, não texto sobre fundo escuro */
  --destaque-navy: #16264a;
  --topo-fundo: #000;
  --sombra: 0 1px 2px rgba(0, 0, 0, .05), 0 4px 14px rgba(0, 0, 0, .06);
  /* altura real do .topo logo abaixo (62px), usada pelas barras de busca/
     filtro pra saberem onde "grudar" ao ficar sticky; sobrescrita pra 48px
     quando .topo-interno está presente (ver abaixo) */
  --altura-topo: 62px;
  /* avisa o navegador do tema atual pros controles NATIVOS dele (calendário do
     input[type=date], scrollbar do SO etc.), sem isso, essas peças ficam sempre
     claras, mesmo com o resto da página em modo escuro */
  color-scheme: light;
}

/* aplicado via JS em <html data-theme="dark">, conforme a escolha em Configurações
   (ou a preferência do sistema, no modo "Automático") */
:root[data-theme="dark"] {
  --tinta: #eaeaea;
  --suave: #9a9a9a;
  --linha: #34383e;
  --fundo: #16181b;
  --branco: #23262b;
  --fundo-sutil: #2a2d33;
  --verde-fundo: #1f5136;
  /* faltava essa variante escura (achado do usuário, 2026-08-26): sem ela, o
     halo da bolinha laranja "no sistema, fora do chat" ficava com o tom claro
     do tema claro (#fbf0e0) mesmo no escuro, virando um anel quase branco
     em cima do fundo escuro, mesma ideia de escurecer usada em --verde-fundo
     logo acima */
  --laranja-fundo: #4d3319;
  --laranja-faixa: var(--laranja-fundo);
  --laranja-faixa-texto: var(--suave);
  --laranja-faixa-icone: var(--laranja);
  --vermelho-faixa: var(--vermelho-fundo);
  --amarelo-fundo: #3c3a2c;
  --ciano-fundo: #223c3c;
  --magenta-fundo: #392e35;
  --chat-verde-fundo: #29362f;
  --chat-azul-fundo: #1c3540;
  --azul-fundo: #123244;
  --azul-texto: #5ec2ee;
  --vermelho-fundo: #511f2d;
  --vermelho-cartao: #ff6b6b;
  --lilas-fundo: #3a2a52;
  /* no escuro o lilás saturado do tema claro (#7433cc) fica quase preto contra
     os fundos escuros do cartão, versão bem mais clara, mesma lógica de
     --vermelho-cartao acima */
  --lilas-cartao: #b98cf5;
  --linha-hover: #3f434a;
  --navy: #d8d8d8;
  /* no escuro, o azul-marinho de --lateral-fundo quase não aparece em cima
     de texto (fundo já é escuro), versão bem mais clara só pra isso */
  --destaque-navy: #7ea6ea;
  --lateral-fundo: #16264a;
  --lateral-borda: transparent;
  --lateral-texto: #fff;
  --lateral-texto-suave: rgba(255, 255, 255, .75);
  --lateral-texto-apagado: rgba(255, 255, 255, .5);
  --lateral-hover: rgba(255, 255, 255, .12);
  --lateral-divisor: rgba(255, 255, 255, .28);
  --lateral-pilula: rgba(255, 255, 255, .2);
  --topo-fundo: var(--azul);
  --sombra: 0 1px 2px rgba(0, 0, 0, .35), 0 4px 14px rgba(0, 0, 0, .4);
  color-scheme: dark;
}

/* ---------- tela de login ---------- */
/* tela de marca, fixa nas cores da ZZ, não muda com o tema claro/escuro,
   igual a uma capa/splash screen */
.tela-login {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, #2fac66, #36a9e1);
  padding: 20px;
}
.tela-login.oculto { display: none; }

.login-caixa {
  background: rgba(255, 255, 255, .94);
  border-radius: 18px;
  padding: 44px 40px;
  width: 100%;
  max-width: 380px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .28);
  text-align: center;
}
.login-logo { width: 100%; max-width: 230px; margin-bottom: 34px; }
/* logo_login do cliente pode vir em qualquer proporção (quadrada, vertical...),
   diferente da logo padrão (sempre uma faixa larga), sem um teto de altura,
   uma logo quadrada sobe até 230px e domina o cartão de login inteiro */
#login-logo-cliente { max-height: 70px; width: auto; max-width: 230px; object-fit: contain; }

/* especificidade com DUAS classes (.tela-login .login-caixa), de propósito:
   a tela de login é fixa nas cores da marca e nunca deve seguir o tema
   escuro, com uma classe só (.login-caixa input) ela empata em
   especificidade com a regra genérica de inputs (input[type="text"] etc.,
   linha ~560) que MUDA com o tema, e como essa vem depois no arquivo, vencia
   o empate e deixava o campo de usuário com fundo escuro (bug real, achado
   pelo QA visual) */
.tela-login .login-caixa input {
  width: 100%;
  margin-bottom: 14px;
  text-align: center;
  border-radius: 22px;
  border: 1px solid #dcdcdc;
  padding: 12px 18px;
  font-size: 14px;
  background: #fff;
  color: #000;
}
.tela-login .login-caixa input:focus { border-color: var(--verde); box-shadow: 0 0 0 3px rgba(47, 172, 102, .15); }

/* etapa 1 do login em duas etapas do painel do cliente (painel-cliente.js):
   antes de saber a empresa, mostra a marca padrão; depois de identificar o
   login, troca pela logo própria do cliente (ou o texto de boas-vindas) */
.login-marca-cliente { margin-bottom: 20px; }
.login-bemvindo { font-size: 19px; font-weight: 700; color: #17181a; margin-bottom: 34px; }
.login-voltar {
  background: none; border: 0; padding: 0; margin-bottom: 14px;
  color: var(--suave, #666); font-size: 13px; cursor: pointer; text-decoration: underline;
}

.btn-entrar {
  width: 100%;
  margin-top: 10px;
  background: #17181a;
  color: #fff;
  border: 0;
  border-radius: 22px;
  padding: 12px 18px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .8px;
  cursor: pointer;
}
.btn-entrar:hover { background: #000; }
.btn-entrar:disabled { opacity: .6; cursor: default; }

.login-erro { margin-top: 16px; color: #c0203a; font-size: 13px; font-weight: 600; }

/* transição de login: some o formulário, escurece a tela inteira e roda o
   lottie (telefone caindo) até completar, só então a tela do app aparece.
   Começa com background transparente (o JS troca pra .ativa 1 frame depois
   de tirar o .oculto, senão o navegador não anima a mudança de transparente
   pra escuro, já que as duas mudanças aconteceriam no mesmo frame) */
.login-transicao {
  position: fixed;
  inset: 0;
  z-index: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(10, 12, 16, 0);
  transition: background .4s ease;
}
.login-transicao.ativa { background: rgba(10, 12, 16, .94); }
.login-transicao.oculto { display: none; }
#login-lottie { width: 240px; height: 240px; }

/* ---------- usuário logado (barra do topo) ---------- */
.usuario-logado { color: #fff; font-weight: 400; font-size: 13px; opacity: .95; }
/* avatar circular com a inicial do nome (ver aplicarAvatarUsuario em app.js/
   painel-cliente.js), no lugar do ícone de silhueta genérico de antes.
   --azul é só o PADRÃO (quem nunca escolheu uma cor, ver cor_avatar em
   db.js); a cor de cada pessoa vem de usuarios.cor_avatar, editável por ela
   mesma (Configurações do Chat) ou por um admin (Editar usuário), ver
   .cor-* logo abaixo e CORES_AVATAR em app.js (pedido do usuário,
   2026-08-28). Peso normal, mesma fonte do resto do app */
.avatar-usuario {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--azul);
  color: #fff;
  font-weight: 400;
  font-size: 13px;
  line-height: 1;
}
.avatar-usuario.cor-azul { background: var(--azul); }
.avatar-usuario.cor-verde { background: var(--verde); }
.avatar-usuario.cor-laranja { background: var(--laranja); }
.avatar-usuario.cor-lilas { background: var(--lilas-cartao); }
.avatar-usuario.cor-teal { background: var(--avatar-teal); }
.avatar-usuario.cor-vinho { background: var(--avatar-vinho); }
.avatar-usuario.cor-preto { background: var(--avatar-preto); }
.avatar-usuario.cor-marrom { background: var(--avatar-marrom); }
.avatar-usuario.cor-rosa { background: var(--avatar-rosa); }
.avatar-usuario.cor-mostarda { background: var(--avatar-mostarda); }
.avatar-usuario.cor-cinza { background: var(--avatar-cinza); }
.avatar-usuario.cor-coral { background: var(--avatar-coral); }
.avatar-usuario.cor-oliva { background: var(--avatar-oliva); }
.avatar-usuario.cor-indigo { background: var(--avatar-indigo); }
/* avatar maior, só como pré-visualização dentro do modal "Editar usuário"/
   "Novo usuário" (ver tipo:'cor-avatar' em abrirModal, app.js) */
.avatar-usuario.avatar-preview-modal { width: 40px; height: 40px; font-size: 16px; }
/* bolinhas de seleção de cor (mesmo picker usado no modal de usuário e no
   painel de Configurações do Chat, self-service): quadrado de círculos
   sólidos, sem borda (a cor já é vívida o bastante pra não precisar, ao
   contrário de .chat-config-swatch, que é sempre um tom pastel) */
.avatar-swatch {
  width: 22px;
  height: 22px;
  padding: 0;
  border-radius: 50%;
  border: 0;
  cursor: pointer;
}
.avatar-swatch.cor-azul { background: var(--azul); }
.avatar-swatch.cor-verde { background: var(--verde); }
.avatar-swatch.cor-laranja { background: var(--laranja); }
.avatar-swatch.cor-lilas { background: var(--lilas-cartao); }
.avatar-swatch.cor-teal { background: var(--avatar-teal); }
.avatar-swatch.cor-vinho { background: var(--avatar-vinho); }
.avatar-swatch.cor-preto { background: var(--avatar-preto); }
.avatar-swatch.cor-marrom { background: var(--avatar-marrom); }
.avatar-swatch.cor-rosa { background: var(--avatar-rosa); }
.avatar-swatch.cor-mostarda { background: var(--avatar-mostarda); }
.avatar-swatch.cor-cinza { background: var(--avatar-cinza); }
.avatar-swatch.cor-coral { background: var(--avatar-coral); }
.avatar-swatch.cor-oliva { background: var(--avatar-oliva); }
.avatar-swatch.cor-indigo { background: var(--avatar-indigo); }
.avatar-swatch.selecionado { outline: 2px solid var(--verde-escuro); outline-offset: 2px; }
.campo-cor-avatar { display: flex; align-items: center; gap: 14px; }
.cor-avatar-opcoes { display: flex; flex-wrap: wrap; gap: 8px; }

/* atalho de tema claro/escuro no topo, mostra o ícone do que está ativo
   agora (sol = claro, lua = escuro); qual dos dois aparece é decidido só
   pelo data-theme do <html>, então segue junto mesmo no modo "Automático" */
.btn-tema-rapido {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: rgba(0, 0, 0, .2);
  border: 1px solid rgba(255, 255, 255, .2);
  color: #fff;
  cursor: pointer;
}
.btn-tema-rapido:hover { background: rgba(0, 0, 0, .34); }
/* ícones "lottie" (assets originais em assets/lotties/sun.json e moon.json,
   servidos em public/lotties/, ver carregamento em app.js/cliente.js/
   painel-cliente.js). Cor vem de dentro do próprio arquivo lottie (não dá
   pra usar currentColor num SVG gerado por animação), por isso não tem
   regra de `color` aqui como o ícone da lua desenhado à mão tinha antes */
.lottie-sol, .lottie-lua { width: 22px; height: 22px; pointer-events: none; }
.lottie-lua { display: none; }
:root[data-theme="dark"] .lottie-sol { display: none; }
:root[data-theme="dark"] .lottie-lua { display: block; }

/* botão de usuário (ícone + nome + seta) que abre o menu suspenso com "Sair" */
.menu-usuario { position: relative; }
.btn-usuario {
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(0, 0, 0, .2);
  border: 1px solid rgba(255, 255, 255, .2);
  border-radius: 20px;
  padding: 6px 12px 6px 10px;
  color: #fff;
  cursor: pointer;
  /* sem isso, todo <button> cai na fonte padrão do navegador (Arial), não na
     do site (achado do usuário, 2026-08-28, com o avatar/nome saindo em
     fonte diferente do resto do app); mesmo ajuste já feito em outros
     botões/inputs do projeto, só faltava aqui */
  font: inherit;
}
.btn-usuario:hover { background: rgba(0, 0, 0, .34); }
.btn-usuario.aberto .icone-seta { transform: rotate(180deg); }

.dropdown-usuario {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 160px;
  background: var(--branco);
  border-radius: 11px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .18);
  padding: 6px;
  z-index: 20;
}
.item-dropdown {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  background: none;
  border: 0;
  border-radius: 7px;
  padding: 9px 10px;
  font: inherit;
  font-weight: 500;
  color: var(--tinta);
  text-align: left;
  cursor: pointer;
}
.item-dropdown:hover { background: var(--fundo-sutil); }
/* "Regra padrão empresa/unidade" travada enquanto o Alerta (regra própria)
   está ligado nesse ramal, visual de campo desabilitado, sem hover/clique */
.item-dropdown-travado { color: var(--suave); cursor: not-allowed; }
.item-dropdown-travado:hover { background: none; }

/* bloco do "Alerta" no menu ⋮ (ver abrirMenuMaisRamal em app.js): checkbox +
   sininho numa linha, campos de dias/horas/minutos numa 2ª linha (só quando
   ligado), por isso não usa .item-dropdown puro (que é 1 linha só) */
.item-alerta-bloco { padding: 9px 10px; border-radius: 7px; }
.item-alerta-bloco:hover { background: var(--fundo-sutil); }
.item-alerta-cabecalho { display: flex; align-items: center; gap: 10px; font-weight: 500; cursor: pointer; }
.alerta-tempo { display: flex; align-items: center; gap: 3px; margin-top: 8px; padding-left: 24px; font-size: 12px; color: var(--suave); }
.alerta-tempo input[type="number"] {
  width: 40px;
  padding: 3px 4px;
  border: 1px solid var(--linha);
  border-radius: 5px;
  font: inherit;
  color: var(--tinta);
  background: var(--branco);
}
/* prazo zerado recusado (ver .campo-invalido), precisa repetir aqui porque a
   regra acima é mais específica e ganharia da borda vermelha */
.alerta-tempo input.campo-invalido { border-color: var(--vermelho); box-shadow: 0 0 0 3px rgba(176, 0, 32, .15); }
.alerta-tempo .btn-mini { margin-left: 8px; }
.alerta-som-linha { display: flex; align-items: center; gap: 6px; margin-top: 6px; padding-left: 24px; font-size: 12px; color: var(--suave); cursor: pointer; }

/* "negrito" num ícone de contorno (sininho do Alerta) é o traço mais grosso;
   dourado + chacoalhar dão o feedback de "ligado" ao marcar o checkbox */
.icone-alerta { display: inline-flex; transform-origin: 50% 0%; }
.icone-alerta-ativo { color: #d4a017; }
.icone-alerta-ativo svg { stroke-width: 3; }
@keyframes chacoalhar-sino {
  0%, 100% { transform: rotate(0deg); }
  20% { transform: rotate(-16deg); }
  40% { transform: rotate(13deg); }
  60% { transform: rotate(-9deg); }
  80% { transform: rotate(5deg); }
}
.icone-alerta-chacoalhar { animation: chacoalhar-sino .5s ease; }

/* sininho de "chamada tocando" (cartão em Blocos e coluna Ações da tabela),
   mesmo ícone/keyframe do Alerta acima, só que contínuo (infinite) enquanto
   a ligação estiver tocando, não um pulso único de feedback */
.icone-chamada-tocando {
  display: inline-flex;
  vertical-align: -2px;
  margin-right: 4px;
  color: #d4a017;
  animation: chacoalhar-sino .6s ease infinite;
}
.icone-chamada-tocando svg { stroke-width: 3; }

/* número da outra ponta da ligação, ao lado do cronômetro (cartão em
   Blocos, estado "andamento"), seta indica direção (ICONE_SETA_CIMA/BAIXO) */
/* tabular-nums: cada dígito ocupa a mesma largura, então o texto não
   "treme" a cada segundo que o cronômetro atualiza (mesma técnica já usada
   em .tempo-status, na tabela) */
.chamada-cronometro { font-variant-numeric: tabular-nums; }
.chamada-outro { opacity: .85; }
.chamada-outro svg { vertical-align: -1px; margin: 0 1px; }
.chamada-outro-numero { font-weight: 700; filter: brightness(.8); }
/* "entrando" reaproveita o SVG de "saindo" girado 180°, garante que as duas
   direções ficam realmente opostas (2 ícones desenhados à mão, um "espelhado"
   na unha, ficavam parecidos demais no tamanho pequeno do cartão) */
.icone-chamada-girada { display: inline-flex; transform: rotate(180deg); }

/* variante do .dropdown-usuario reaproveitada fora do menu de usuário (ex.:
   menu "⋮" de uma linha da tabela de ramais), precisa de position:fixed
   porque é 1 elemento só, reposicionado via JS perto de qualquer botão que
   o abrir, em vez de position:absolute preso a um pai fixo */
.dropdown-flutuante { position: fixed; top: 0; left: 0; right: auto; }

* { box-sizing: border-box; margin: 0; padding: 0; }

/* reserva sempre o espaço da barra de rolagem: sem isso, uma tela com menos
   conteúdo (sem rolagem) fica ~15px mais larga que uma com rolagem, e tudo
   parece "pular" de posição ao trocar de tela */
html {
  overflow-y: scroll;
  scrollbar-gutter: stable;
}

/* Comfortaa (Google Fonts) baixada e embutida em public/fontes/comfortaa/,
   mesma filosofia do resto do projeto (ex.: cidades do IBGE): nada é
   buscado de fora em runtime, só os 2 arquivos locais (latin + latin-ext,
   cobre acentuação do português). Fonte variável: cada arquivo já cobre
   sozinho todo o intervalo de peso 300–700 (`font-weight: 300 700`), então
   basta 1 @font-face por subset, negrito/seminegrito já existentes no CSS
   continuam funcionando normalmente, sem precisar declarar peso por peso. */
@font-face {
  font-family: "Comfortaa";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fontes/comfortaa/comfortaa-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Comfortaa";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fontes/comfortaa/comfortaa-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

body {
  /* Comfortaa é a fonte do sistema inteiro agora (pedido do usuário), os
     nomes seguintes só entram se, por algum motivo, os arquivos locais
     acima não carregarem */
  font-family: "Comfortaa", "Chambers Sans Pro", "Chambers Sans", "Neue Haas Grotesk Display Pro",
    "Neue Haas Grotesk Display", "Neue Haas Grotesk", "Helvetica Neue", "Segoe UI",
    system-ui, sans-serif;
  background: var(--fundo);
  color: var(--tinta);
  font-size: 14px;
  line-height: 1.5;
}

.oculto { display: none !important; }

/* ---------- layout geral: barra lateral + coluna de conteúdo ---------- */
.app { display: flex; min-height: 100vh; }

.principal { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* ---------- barra lateral ---------- */
.lateral {
  width: var(--largura-lateral);
  flex: 0 0 auto;
  background: var(--lateral-fundo);
  border-right: 1px solid var(--lateral-borda);
  color: var(--lateral-texto);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  transition: width .18s ease;
}

.marca { display: flex; align-items: center; gap: 10px; padding: 18px 16px; position: relative; }
.marca::after {
  content: '';
  position: absolute;
  right: 16px;
  bottom: 0;
  left: 16px;
  height: 1px;
  background: var(--lateral-divisor);
}
/* o ícone fica numa plaqueta branca: o fundo é preto e o símbolo tem partes escuras */
.marca .logo {
  width: 36px;
  height: 36px;
  border-radius: 8px;
  background: #fff;
  padding: 3px;
  object-fit: contain;
  flex-shrink: 0;
}
.marca strong { display: block; font-size: 15px; letter-spacing: .2px; }
/* --suave é pensado para texto apagado sobre fundo branco/neutro; aqui embaixo
   o fundo é o da lateral, que muda de tom entre os temas (ver --lateral-*) */
.marca small { color: var(--lateral-texto-suave); font-size: 11px; }

/* botão de recolher/expandir a barra lateral (pedido do usuário, 2026-09-25,
   mesmo jeito do ChatGPT/Gemini). Aberta: fica no topo, à direita do nome,
   com o ícone de painel, que vira "|<" no hover. Recolhida: some por cima da
   logo, e no hover da logo ela dá lugar ao "|>" (clicar expande). Os 3
   ícones estão sempre no HTML, o CSS só escolhe qual aparece */
/* nome numa linha só: com o botão ao lado, "Ramais PABX" quebrava em duas e
   empurrava a logo pra baixo (achado testando, 2026-09-25) */
.marca-texto { min-width: 0; white-space: nowrap; }
.btn-recolher-lateral {
  margin-left: auto;
  margin-right: -6px; /* encosta mais na borda, sobra espaço pro nome */
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: 7px;
  background: none;
  border: 0;
  color: var(--lateral-texto-suave);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  transition: background .12s, color .12s, opacity .12s;
}
.btn-recolher-lateral:hover,
.btn-recolher-lateral:focus-visible { background: var(--lateral-hover); color: var(--lateral-texto); }
.btn-recolher-lateral svg { display: none; }
.btn-recolher-lateral .ic-painel { display: block; }
.btn-recolher-lateral:hover .ic-painel,
.btn-recolher-lateral:focus-visible .ic-painel { display: none; }
.btn-recolher-lateral:hover .ic-recolher,
.btn-recolher-lateral:focus-visible .ic-recolher { display: block; }
.marca .logo { transition: opacity .12s; }

.abas { display: flex; flex-direction: column; flex: 1; gap: 4px; padding: 8px 10px; }

.aba {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  background: none;
  border: 0;
  color: var(--lateral-texto-suave);
  padding: 10px 14px;
  border-radius: 7px;
  font: inherit;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
}
.aba:hover { background: var(--lateral-hover); color: var(--lateral-texto); }
.aba.ativa { background: var(--verde); color: #fff; }

.aba-texto { display: flex; align-items: center; gap: 8px; }
.aba-icone { flex-shrink: 0; }

/* ---------- barra lateral recolhida (ver #btn-recolher-lateral em app.js) ----------
   a classe fica no #app (não em .lateral), porque .paginacao-fixa (rodapé fixo de
   página, mais abaixo) também precisa saber a largura atual pra não ficar coberta
   pela lateral, e ela não é descendente de .lateral */
.app.lateral-recolhida { --largura-lateral: 68px; }
.app.lateral-recolhida .marca-texto,
.app.lateral-recolhida .aba-rotulo,
.app.lateral-recolhida .grupo-lateral-titulo,
.app.lateral-recolhida .contador-presenca-nav,
.app.lateral-recolhida .submenu-mapa {
  display: none;
}
.app.lateral-recolhida .marca { justify-content: center; padding: 18px 8px; }
/* recolhida: o botão fica exatamente por cima da logo (36x36), invisível;
   passar o mouse em qualquer parte do topo esconde a logo e mostra o "|>" */
.app.lateral-recolhida .btn-recolher-lateral {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 36px;
  height: 36px;
  margin: 0;
  transform: translate(-50%, -50%);
  border-radius: 8px;
  opacity: 0;
}
.app.lateral-recolhida .btn-recolher-lateral .ic-painel,
.app.lateral-recolhida .btn-recolher-lateral .ic-recolher { display: none; }
.app.lateral-recolhida .btn-recolher-lateral .ic-expandir { display: block; }
.app.lateral-recolhida .marca:hover .btn-recolher-lateral,
.app.lateral-recolhida .btn-recolher-lateral:focus-visible { opacity: 1; background: var(--lateral-hover); color: var(--lateral-texto); }
.app.lateral-recolhida .marca:hover .logo,
.app.lateral-recolhida .marca:has(.btn-recolher-lateral:focus-visible) .logo { opacity: 0; }
.app.lateral-recolhida .abas { padding: 8px 6px; }
.app.lateral-recolhida .aba { justify-content: center; padding: 10px 6px; position: relative; }
.app.lateral-recolhida .lateral-rodape { padding: 10px 6px; }
/* sem o rótulo, o aviso (badge-solicitacoes, ex.: mensagem nova no Chat) vira
   uma bolinha no canto do ícone em vez de ficar solto ao lado dele */
.app.lateral-recolhida .badge-solicitacoes {
  position: absolute;
  top: 4px;
  right: 12px;
  min-width: 9px;
  width: 9px;
  height: 9px;
  padding: 0;
  font-size: 0;
  line-height: 0;
  background: var(--vermelho-neon);
  box-shadow: 0 0 5px 1px var(--vermelho-neon);
  animation: pulso-badge-lateral 2s ease-in-out infinite;
}
.app.lateral-recolhida .badge-solicitacoes.badge-chat {
  background: var(--status-verde-neon);
  box-shadow: 0 0 5px 1px var(--status-verde-neon);
}
/* mesmo espírito do pulso da bolinha de status do chat (sutil, em loop),
   mas sem o anel de box-shadow: aqui é só a própria bolinha "respirando" */
@keyframes pulso-badge-lateral {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.3); opacity: .6; }
}

/* badge da aba "Solicitações" (ver checarSolicitacoesNome em app.js), vermelho
   sólido (não --vermelho-fundo, pensado pra fundo claro): precisa ler bem em
   cima do azul-marinho da lateral, inclusive quando a aba está ativa (fundo
   verde), por isso fixo nos 2 temas, igual --vermelho de marca já é */
.badge-solicitacoes {
  flex-shrink: 0;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--vermelho);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
}

/* mensagem nova no chat é aviso de conversa, não de pendência: fica verde, e o
   vermelho continua reservado pro badge de Solicitações (pedido do usuário,
   2026-08-21). Verde escuro (não --verde) porque o badge aparece em cima da
   aba ativa, que já é verde clara, e um sobre o outro sumia */
.badge-solicitacoes.badge-chat { background: var(--verde-escuro); }

/* sub-abas "Pendentes"/"Concluídas" dentro da tela Solicitações (ver
   desenharAbaSolicitacoes em app.js), pílulas simples, mesmo espírito visual
   do .aba da lateral (fundo verde quando ativa), só que num contexto
   horizontal/claro em vez da lateral escura */
.abas-solicitacoes { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.aba-solic {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--linha);
  background: var(--branco);
  color: var(--suave);
  padding: 7px 14px;
  border-radius: 20px;
  font: inherit;
  font-weight: 600;
  font-size: 12px;
  cursor: pointer;
  transition: transform .15s ease;
}
.aba-solic:hover { border-color: var(--verde); color: var(--verde-escuro); }
/* "ativa" (aba selecionada agora) cresce por `transform`, não por padding/
   fonte, padding real chegou a ser tentado, mas aumenta a CAIXA do botão de
   verdade, e isso empurra a lista de solicitações pra baixo cada vez que a
   pessoa troca de aba (achado do usuário testando ao vivo). `transform` é só
   visual: não participa do layout, então o container não muda de tamanho e
   nada abaixo se mexe. `gap` subiu pra 12px de folga, pra a aba ampliada não
   encostar visualmente na vizinha */
.aba-solic.ativa { transform: scale(1.12); }
/* preenchimento por conteúdo, não por seleção (ver com-itens em app.js):
   Pendentes chama atenção (vermelho, precisa de ação da equipe); Concluídas
   fica na cor "tudo certo" (verde), a mesma que Pendentes usava antes,
   só que agora o significado é "tem coisa aqui", não "é essa aba" */
.aba-solic[data-aba-solic="pendentes"].com-itens { background: var(--vermelho); border-color: var(--vermelho); color: #fff; }
.aba-solic[data-aba-solic="concluidas"].com-itens { background: var(--verde); border-color: var(--verde); color: #fff; }
.aba-solic.com-itens:hover { color: #fff; }
/* contador dentro da própria aba "Pendentes", mais discreto que o badge da
   lateral (que já cumpre o papel de chamar atenção de longe); aqui é só
   reforço, por isso outline em vez de preenchido */
.contador-aba-solic {
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  border: 1px solid currentColor;
  font-size: 11px;
  line-height: 16px;
  text-align: center;
}

/* linha "atendida" na aba Concluídas, verde suave (mesma família de
   --verde-fundo já usada em selos de sucesso no resto do sistema), com um
   ✓ à esquerda do nome final */
.solic-linha-atendida td { color: var(--tinta); }
.solic-check { color: var(--verde-escuro); font-weight: 700; margin-right: 4px; }

/* espaço extra embaixo da lista/tela pra elas não ficarem escondidas atrás da
   barra fixa de paginação (.paginacao-fixa, abaixo) */
#lista-solicitacoes, #tela-historico-ramal, #tela-historico { padding-bottom: 64px; }

/* rodapé de paginação (20 por vez, ver TAMANHO_PAGINA_LISTA em app.js),
   compartilhado entre a aba Concluídas de Solicitações e a tela de Histórico
   de um ramal (#paginacao-historico-ramal). Fixo na parte de baixo da TELA
   (não no final da lista), pra continuar visível não importa até onde a
   pessoa rolou. `left` segue --largura-lateral (220px normal, 68px com a
   lateral recolhida, ver #btn-recolher-lateral em app.js), pra nunca cobrir
   a barra lateral em nenhum dos dois estados */
.paginacao-fixa {
  position: fixed;
  left: var(--largura-lateral);
  right: 0;
  bottom: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 14px;
  background: var(--fundo);
  box-shadow: 0 -2px 8px rgba(0, 0, 0, .12);
  color: var(--suave);
  font-size: 16px;
  font-weight: 600;
  transition: left .18s ease;
}

/* ---------- chat da equipe / comentários no ramal ---------- */
/* duas colunas na aba Chat: equipe à esquerda, conversa à direita. A altura
   vive no layout, e a .chat-caixa (que tem altura própria por ser usada
   sozinha no HTML) é neutralizada aqui dentro pra esticar junto */
/* 96px = os 72px que ficam acima da caixa (topo da página + respiro do <main>)
   mais 24px de folga embaixo. Medido no navegador, não estimado: antes eram
   210px, o que deixava 138px de espaço morto no rodapé (pedido do usuário,
   2026-08-21: usar a tela toda, deixando só uma folga) */
.chat-layout { display: flex; align-items: stretch; gap: 14px; height: calc(100vh - 96px); min-height: 320px; }
.chat-layout > .chat-caixa { flex: 1 1 auto; height: 100%; min-height: 0; }
.chat-pessoas {
  display: flex;
  flex-direction: column;
  flex: 0 0 260px;
  background: var(--branco);
  border-radius: 11px;
  box-shadow: var(--sombra);
  overflow: hidden;
}
.chat-pessoas-topo {
  position: relative;
  padding: 10px 14px 14px;
  border-top: 1px solid var(--linha);
  color: var(--suave);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .6px;
  text-transform: uppercase;
  text-align: center;
}
/* engrenagem fica com position:absolute de propósito: assim ela não entra na
   régua de centralização do texto ao lado (text-align:center no pai), pedido
   do usuário, 2026-08-27, "EQUIPE ZZ" tem que continuar centralizado mesmo
   com o ícone na mesma linha */
.chat-config-abrir { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); width: 22px; height: 22px; }

/* ---- painel de Configurações do chat (ver btn-chat-config-abrir acima):
   ocupa o MESMO espaço de #chat-pessoas-eu + #lista-equipe-chat quando
   aberto (os dois ganham .oculto), não é modal separado, pedido do usuário */
.chat-config-painel { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
/* seta fica position:absolute de propósito, mesma ideia da engrenagem em
   .chat-pessoas-topo/.chat-config-abrir: assim "Configurações" continua
   centralizado no meio da linha, sem a seta puxar a régua de centralização
   pra um lado (pedido do usuário, 2026-08-27, seta ao invés de engrenagem
   clicável, e o título deixou de ser botão, só texto) */
.chat-config-topo { position: relative; padding: 12px 14px; border-bottom: 1px solid var(--linha); text-align: center; }
.chat-config-titulo { font-weight: 700; font-size: 13px; color: var(--tinta); }
.chat-config-voltar { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); width: 26px; height: 26px; }
.chat-config-secoes { flex: 1 1 auto; overflow-y: auto; padding: 14px; display: flex; flex-direction: column; gap: 18px; }
.chat-config-secao { display: flex; flex-direction: column; gap: 8px; }
.chat-config-rotulo {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .6px;
  text-transform: uppercase;
  color: var(--suave);
}
/* subdivisões dentro de uma seção (ex.: "Tema" e "Cor" dentro de "Visual",
   pedido do usuário, 2026-08-27), rótulo mais discreto que o da seção-mãe
   pra deixar clara a hierarquia sem competir com ele */
.chat-config-subsecao { display: flex; flex-direction: column; gap: 6px; }
.chat-config-sublabel { font-size: 10px; font-weight: 600; color: var(--suave); opacity: .8; }
.chat-config-opcoes { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
/* botões de Tema (ver .chat-caixa.tema-* logo abaixo dela): quadrado (não
   bolinha, pra não confundir com as cores) mostrando uma amostra em miniatura
   do próprio tile repetido (pedido do usuário, 2026-08-27: separar o toggle
   único "com/sem imagem" em botões, um por variante: sem imagem, logo+abacaxi
   junto, só logo, só abacaxi, ver scripts/gerar-fundo-chat.js) */
.chat-config-tema {
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 6px;
  border: 1px solid var(--linha);
  background-color: var(--branco);
  background-repeat: repeat;
  background-size: 40px 40px;
  color: var(--suave);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.chat-config-tema.selecionado { outline: 2px solid var(--verde-escuro); outline-offset: 2px; }
.chat-config-tema.tema-preview-mix { background-image: url('fundo-chat.png'); }
.chat-config-tema.tema-preview-logo { background-image: url('fundo-chat-logo.png'); }
.chat-config-tema.tema-preview-abacaxi { background-image: url('fundo-chat-abacaxi.png'); }
/* bolinhas de cor de fundo da conversa (ver .chat-caixa.fundo-azul acima);
   a "cinza" é o --branco atual (não é cinza de verdade, mas é como o usuário
   chamou o fundo padrão, pra distinguir do azul novo), com borda porque fica
   quase invisível em cima do próprio fundo branco do painel */
.chat-config-swatch {
  width: 22px;
  height: 22px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--linha);
  background: var(--branco);
  cursor: pointer;
}
.chat-config-swatch.swatch-azul { background: var(--chat-azul-fundo); border-color: var(--chat-azul); }
.chat-config-swatch.swatch-verde { background: var(--chat-verde-fundo); border-color: var(--chat-verde); }
.chat-config-swatch.swatch-amarelo { background: var(--amarelo-fundo); border-color: var(--amarelo); }
.chat-config-swatch.swatch-ciano { background: var(--ciano-fundo); border-color: var(--ciano); }
.chat-config-swatch.swatch-magenta { background: var(--magenta-fundo); border-color: var(--magenta); }
.chat-config-swatch.selecionado { outline: 2px solid var(--verde-escuro); outline-offset: 2px; }
/* nome de quem está logado agora, topo da coluna (pedido do usuário,
   2026-08-26, no lugar de onde "Equipe ZZ" ficava antes de descer pro
   rodapé, ver .chat-pessoas-topo) */
.chat-pessoas-eu {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 14px 14px 10px;
  border-bottom: 1px solid var(--linha);
  font-size: 13px;
  font-weight: 700;
  color: var(--tinta);
}
/* sem overflow:hidden aqui: cortaria o halo (box-shadow) da bolinha junto
   com o nome comprido, o corte de texto já é feito só no span do nome
   logo abaixo */
.chat-pessoas-eu-identidade { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* avatar com o selinho de status no canto (ver .pessoa-bolinha mais abaixo:
   MESMA classe/cores/transição de sempre, só ganha position:absolute e uma
   borda de recorte quando está dentro deste wrapper, fora dele, ex. no
   seletor de status, continua um ponto normal ao lado do texto, sem quebrar
   nada ali). Repaginação pedida pelo usuário, 2026-08-28: antes disso a
   bolinha de status ficava sozinha ao lado do nome, sem avatar nenhum */
.avatar-com-bolinha { position: relative; display: inline-flex; flex: 0 0 auto; }
.avatar-com-bolinha .pessoa-bolinha {
  position: absolute;
  right: -1px;
  bottom: -1px;
  border: 2px solid var(--branco);
}
/* centro "neon" só quando a bolinha está sobre o avatar (pedido do usuário,
   2026-08-28): mais vívido que o --laranja/--verde de marca, com um brilho
   ao redor pra reforçar o efeito. Precisa de mais uma classe no seletor
   (.avatar-com-bolinha) que as regras de cor "normais" (.pessoa-equipe.online
   .pessoa-bolinha etc.) pra ganhar na especificidade e sobrescrever aqui */
.pessoa-equipe.online .avatar-com-bolinha .pessoa-bolinha,
.chat-pessoas-eu.online .avatar-com-bolinha .pessoa-bolinha {
  background: var(--status-laranja-neon);
  box-shadow: 0 0 4px 1px var(--status-laranja-neon);
}
.pessoa-equipe.online.no-chat .avatar-com-bolinha .pessoa-bolinha,
.chat-pessoas-eu.online.no-chat .avatar-com-bolinha .pessoa-bolinha {
  background: var(--status-verde-neon);
  box-shadow: 0 0 4px 1px var(--status-verde-neon);
}
/* feixe de luz saindo da borda da bolinha, só na SUA própria linha
   (#chat-pessoas-eu), não nos colegas da lista (pedido do usuário,
   2026-08-31; duração alongada pra 2,5s no mesmo dia, achou 1s rápido
   demais). Anel separado num ::after (não no box-shadow da bolinha em si)
   pra não brigar com o halo estático já usado acima */
.chat-pessoas-eu.online .avatar-com-bolinha .pessoa-bolinha::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  animation: pulso-bolinha-eu-laranja 2.5s ease-out infinite;
  pointer-events: none;
}
.chat-pessoas-eu.online.no-chat .avatar-com-bolinha .pessoa-bolinha::after {
  animation-name: pulso-bolinha-eu-verde;
}
/* BEM SUTIL de propósito (pedido do usuário): opacidade inicial baixa e anel
   curto (6px), num ponto de 9px isso já é bem perceptível se for maior */
@keyframes pulso-bolinha-eu-laranja {
  0%   { box-shadow: 0 0 0 0 rgba(255, 149, 0, .45); }
  100% { box-shadow: 0 0 0 6px rgba(255, 149, 0, 0); }
}
@keyframes pulso-bolinha-eu-verde {
  0%   { box-shadow: 0 0 0 0 rgba(57, 255, 110, .45); }
  100% { box-shadow: 0 0 0 6px rgba(57, 255, 110, 0); }
}
.chat-pessoas-eu-textos { display: flex; flex-direction: column; min-width: 0; }
.chat-pessoas-eu #chat-pessoas-eu-nome {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
/* status atual (Automático/Online/Ausente/Offline) embaixo do nome, fonte
   menor e sem negrito (pedido do usuário, 2026-08-26), preenchido em
   desenharPessoasChat junto com a bolinha */
.chat-pessoas-eu-status {
  font-size: 11px;
  font-weight: 400;
  color: var(--suave);
  text-transform: none;
  letter-spacing: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* mesma régua de cor da bolinha de cada pessoa na lista abaixo (ver
   .pessoa-equipe.online/.no-chat): laranja = no sistema fora do chat,
   verde = olhando o Chat agora. As classes são ligadas em
   desenharPessoasChat, a partir da própria entrada "eh_voce" */
.chat-pessoas-eu.online .pessoa-bolinha { background: var(--laranja); box-shadow: 0 0 0 3px var(--laranja-fundo); }
.chat-pessoas-eu.online.no-chat .pessoa-bolinha { background: var(--verde); box-shadow: 0 0 0 3px var(--verde-fundo); }

/* botão "Status" (ver menu-status-chat/abrirMenuStatusChat em app.js), pílula
   pequena pra caber ao lado do nome sem disputar espaço com ele */
.chat-status-botao {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 4px;
  border: 1px solid var(--linha);
  background: var(--branco);
  color: var(--suave);
  border-radius: 999px;
  padding: 6px 11px;
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
}
/* hover na cor do status ATUAL de verdade (pedido do usuário, 2026-08-26),
   não sempre verde: reaproveita as mesmas classes online/no-chat já ligadas
   em #chat-pessoas-eu pra colorir a bolinha (ver desenharPessoasChat em
   app.js), então cobre certo até o Automático, que muda de cor sozinho */
.chat-status-botao:hover { border-color: var(--suave); color: var(--tinta); }
.chat-pessoas-eu.online .chat-status-botao:hover { border-color: var(--laranja); color: var(--laranja); }
.chat-pessoas-eu.online.no-chat .chat-status-botao:hover { border-color: var(--verde); color: var(--verde-escuro); }
.chat-status-seta { font-size: 9px; }

/* opções do seletor de status: reaproveita .item-dropdown (mesmo menu "⋮" da
   tabela de ramais), só acrescenta a bolinha de prévia da cor e, quando
   selecionada, um destaque de fundo */
.item-status-chat { gap: 8px; }
.item-status-chat.item-dropdown-selecionado { background: var(--fundo-sutil); font-weight: 700; color: var(--tinta); }
/* sem o halo (box-shadow) que a bolinha "ao vivo" tem em outros lugares: aqui
   é só um chip de cor pequeno, o halo (2 tons próximos) deixava a cor mais
   apagada nesse tamanho; sólido fica mais vivo (pedido do usuário, 2026-08-26).
   Selector composto (.pessoa-bolinha.bolinha-status-X, não só .bolinha-status-X)
   de propósito: mesma especificidade de .pessoa-bolinha (a regra cinza padrão,
   definida DEPOIS no arquivo) faria o cinza vencer no empate, foi achado
   testando visualmente que as 4 bolinhas saíam cinza mesmo com a cor certa
   aqui */
.pessoa-bolinha.bolinha-status-online { background: var(--verde); }
.pessoa-bolinha.bolinha-status-ausente { background: var(--laranja); }
/* Automático/Offline não têm cor de marca própria (não são verde/laranja),
   mas ainda precisam ficar visíveis: --linha-hover (o cinza padrão da
   bolinha "apagada") é forte demais pra HOVER e fraco demais como cor de
   repouso no tema escuro (achado do usuário, 2026-08-26, ficava "apagada"
   demais pra ler). --suave é o mesmo cinza médio usado em texto secundário,
   com contraste OK nos 2 temas */
.pessoa-bolinha.bolinha-status-offline { background: var(--suave); }
/* Automático não é uma cor só, é as 3 cores possíveis (verde/laranja/cinza)
   ao mesmo tempo, num terço cada, tipo mini roda de cores (pedido do
   usuário, 2026-08-26), pra diferenciar de bater o olho das outras 3 opções
   (cada uma sólida numa cor fixa) */
.pessoa-bolinha.bolinha-status-automatico {
  background: conic-gradient(var(--verde) 0deg 120deg, var(--laranja) 120deg 240deg, var(--suave) 240deg 360deg);
}
/* "?" de explicação (Automático/Offline), mesmo espírito do title=""
   informativo usado no resto do sistema, só que com um alvo de clique/hover
   maior que o texto sozinho ofereceria */
.dica-status {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 15px;
  height: 15px;
  margin-left: auto;
  border-radius: 50%;
  background: var(--fundo-sutil);
  color: var(--suave);
  font-size: 10px;
  font-weight: 700;
  cursor: help;
}
.chat-pessoas-lista { flex: 1 1 auto; overflow-y: auto; padding: 8px; }
.pessoa-equipe { display: flex; align-items: center; gap: 8px; padding: 7px 8px; border-radius: 7px; }
.pessoa-equipe:hover { background: var(--fundo-sutil); }
.pessoa-nome { font-size: 13px; color: var(--suave); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; transition: color .4s ease; }
/* quem está no sistema agora: nome em cor cheia, além da bolinha verde */
.pessoa-equipe.online .pessoa-nome { color: var(--tinta); font-weight: 600; }
.pessoa-bolinha {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--linha-hover);
  /* troca de cor suave entre os estados (cinza/laranja/verde), em vez de
     abrupta (pedido do usuário, 2026-08-28); cobre tanto a lista de pessoas
     quanto #chat-pessoas-eu, que reaproveita a mesma classe */
  transition: background-color .4s ease, box-shadow .4s ease;
}
/* online, mas em outra tela do sistema (não no Chat): laranja. Só quem está
   olhando o Chat de verdade ganha o verde (ver .no-chat), pedido do usuário,
   2026-08-24, antes qualquer conexão aberta já virava bolinha verde */
.pessoa-equipe.online .pessoa-bolinha { background: var(--laranja); box-shadow: 0 0 0 3px var(--laranja-fundo); }
.pessoa-equipe.online.no-chat .pessoa-bolinha { background: var(--verde); box-shadow: 0 0 0 3px var(--verde-fundo); }

/* tela estreita: a coluna vira uma faixa acima da conversa, rolando de lado,
   em vez de espremer o balão das mensagens */
@media (max-width: 1000px) {
  .chat-layout { flex-direction: column; height: auto; }
  .chat-pessoas { flex: 0 0 auto; }
  .chat-pessoas-lista { display: flex; gap: 6px; overflow-x: auto; overflow-y: hidden; }
  .pessoa-equipe { flex: 0 0 auto; }
  /* mesma folga de 24px do caso normal, descontando também a faixa da equipe
     que passou pra cima da conversa nesta largura */
  .chat-layout > .chat-caixa { height: calc(100vh - 167px); }
}
/* altura travada na viewport (não cresce com o conteúdo) pra o campo de envio
   ficar sempre visível no rodapé, com a rolagem acontecendo só na lista de
   mensagens. 210px = topo + respiro das bordas do <main> */
.chat-caixa {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 210px);
  min-height: 320px;
  background: var(--branco);
  border-radius: 11px;
  box-shadow: var(--sombra);
  overflow: hidden;
}
/* papel de parede da conversa: a logo da ZZ e/ou o abacaxi repetidos (ver
   scripts/gerar-fundo-chat.js pros 3 tiles em public/fundo-chat*.png, e o
   Tema do painel de Configurações pra escolher entre eles). Fica na
   .chat-caixa, que NÃO rola, e não na lista de mensagens: assim o padrão
   continua parado enquanto a conversa passa por cima, como em qualquer app
   de conversa. Os filhos ganham z-index pra ficar acima do papel de parede
   (o ::before é posicionado, então sem isso ele seria pintado depois do
   texto) */
.chat-caixa { position: relative; }
.chat-caixa::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background: url('fundo-chat.png') repeat;
  background-size: 240px 240px;
  opacity: .06;
  pointer-events: none;
}
/* a logo é colorida: no fundo escuro ela precisa de um pouco mais de presença
   pra não desaparecer, no claro um pouco menos pra não competir com o texto */
:root[data-theme="dark"] .chat-caixa::before { opacity: .085; }
/* opções de Visual do painel de Configurações (ver #tema-fundo-* e
   #swatch-fundo-*, pedido do usuário, 2026-08-27): Tema e Cor são
   independentes, dá pra ter fundo azul com o tile "só logo", ou fundo cinza
   sem imagem nenhuma, por exemplo. .tema-mix é o padrão (já vem do ::before
   acima, url('fundo-chat.png'), repetido aqui só por simetria/clareza) */
.chat-caixa.tema-nenhum::before { display: none; }
.chat-caixa.tema-mix::before { background-image: url('fundo-chat.png'); }
.chat-caixa.tema-logo::before { background-image: url('fundo-chat-logo.png'); }
.chat-caixa.tema-abacaxi::before { background-image: url('fundo-chat-abacaxi.png'); }
.chat-caixa.fundo-azul { background: var(--chat-azul-fundo); }
.chat-caixa.fundo-verde { background: var(--chat-verde-fundo); }
.chat-caixa.fundo-amarelo { background: var(--amarelo-fundo); }
.chat-caixa.fundo-ciano { background: var(--ciano-fundo); }
.chat-caixa.fundo-magenta { background: var(--magenta-fundo); }
.chat-caixa > * { position: relative; z-index: 1; }

.chat-mensagens { flex: 1 1 auto; overflow-y: auto; padding: 18px; display: flex; flex-direction: column; gap: 12px; }
.chat-msg { max-width: 68%; align-self: flex-start; }
/* mensagem da própria pessoa vai pra direita e ganha o verde do sistema,
   mesma leitura instantânea de "quem falou" de qualquer app de conversa */
.chat-msg.propria { align-self: flex-end; }
/* mensagem seguida da mesma pessoa: sem nome (ver htmlMensagens) e mais perto
   da anterior, pra ler como um bloco só. A margem negativa desconta parte do
   gap de 12px da lista */
.chat-msg.em-sequencia { margin-top: -6px; }
.chat-msg-topo { display: flex; align-items: baseline; gap: 8px; margin-bottom: 3px; font-size: 11px; color: var(--suave); }
.chat-msg.propria .chat-msg-topo { justify-content: flex-end; }
.chat-msg-autor { font-weight: 700; color: var(--tinta); font-size: 12px; }
.chat-msg-balao {
  position: relative;
  background: var(--fundo-sutil);
  border: 1px solid var(--linha);
  border-radius: 12px;
  padding: 8px 12px 5px;
  line-height: 1.45;
}
/* pre-wrap vive no TEXTO, não no balão: o balão tem outros filhos (a hora) e o
   HTML deles é indentado, então as quebras de linha da própria marcação viravam
   linhas em branco de verdade dentro do balão (achado medindo, 2026-08-21: o
   balão de uma linha aparecia com 174px de altura).
   overflow-wrap: mensagem é texto livre, e palavra gigante/URL colada precisa
   quebrar em vez de esticar o balão e criar rolagem horizontal na tela toda */
.chat-msg-texto {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.chat-msg.propria .chat-msg-balao { background: var(--verde-fundo); border-color: var(--verde); }
/* só aparecem no hover do próprio balão, pra não poluir a conversa (editar e
   apagar; as duas ações existem apenas na mensagem da própria pessoa) */
.chat-msg-acao { opacity: 0; transition: opacity .15s; width: 22px; height: 22px; }
/* editar fica neutro em repouso, igual aos outros, e só puxa o azul quando o
   mouse está em cima; o hover vermelho do .btn-icone continua valendo pra
   lixeira, que é a ação destrutiva (pedido do usuário, 2026-08-21) */
.btn-icone.acao-editar:hover { border-color: var(--azul); color: var(--azul); }
.chat-msg:hover .chat-msg-acao { opacity: 1; }
/* reagir/editar/apagar numa faixa só, ao lado do balão (fora dele): antes
   editar e apagar ficavam na linha do nome, que deixou de existir na própria
   mensagem (pedido do usuário, 2026-08-21) */
.chat-msg-acoes { display: flex; align-items: center; gap: 4px; flex: 0 0 auto; }
/* hora dentro do balão, embaixo do texto e à direita, com a etiqueta "editada"
   antes dela quando for o caso */
.chat-msg-hora {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: 4px;
  margin-top: 2px;
  font-size: 10px;
  color: var(--suave);
}
.chat-msg-editada { font-style: italic; color: var(--suave); }
/* durante a edição a hora sai da frente: o campo ocupa o balão inteiro */
.chat-msg-texto.editando + .chat-msg-hora { display: none; }

/* edição no lugar: o balão vira campo + dois botões, mantendo a largura que a
   mensagem já tinha em vez de pular de tamanho ao entrar em edição */
.chat-msg-texto.editando { min-width: 240px; }
.chat-editar-campo {
  width: 100%;
  min-width: 220px;
  resize: none;
  max-height: 180px;
  font: inherit;
  line-height: 1.45;
}
.chat-editar-acoes { display: flex; justify-content: flex-end; gap: 6px; margin-top: 6px; }

/* confirmação de apagar mensagem, no lugar do balão (ver ligarApagarMensagem).
   .btn-mini vem depois de .btn-perigo no arquivo e ganhava o fundo cinza dele
   de volta (mesma especificidade, uma classe cada, vale a ordem no arquivo),
   por isso o vermelho é reforçado aqui, depois da definição de .btn-mini */
.chat-apagar-confirmacao p { margin: 0; font-size: 12.5px; line-height: 1.4; min-width: 200px; }
.chat-apagar-confirmacao .btn-perigo { background: var(--vermelho); border-color: var(--vermelho); color: #fff; }
.chat-apagar-confirmacao .btn-perigo:hover { background: #8e0019; border-color: #8e0019; }

/* ---- reações nas mensagens (ver htmlReacoes/montarBarraReacoes em app.js) ---- */
/* o botão de reagir fica FORA do balão, do lado de fora da conversa: à direita
   nas mensagens dos outros (que ficam à esquerda) e à esquerda nas próprias
   (que ficam à direita), por isso o row-reverse */
.chat-msg-corpo { display: flex; align-items: center; gap: 6px; }
.chat-msg.propria .chat-msg-corpo { flex-direction: row-reverse; }

/* modal de comentários do ramal: é bem mais estreito que a tela de Chat, e a
   bolha limitada a 68% deslocada pra um lado sobrava pouca largura pro texto,
   fazendo o comentário quebrar em muitas linhas e rolar mais do que precisava
   (pedido do usuário, 2026-08-24). Aqui a bolha ocupa a linha inteira; nome
   (chat-msg-topo) e hora continuam alinhados à esquerda/direita de quem
   mandou, só a largura da bolha em si muda */
#comentarios-ramal .chat-msg { max-width: 100%; align-self: stretch; }
#comentarios-ramal .chat-msg-balao { flex: 1 1 auto; min-width: 0; }
.reagir-caixa { position: relative; flex: 0 0 auto; }
.btn-reagir {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 1px solid var(--linha);
  background: var(--branco);
  color: var(--suave);
  border-radius: 50%;
  cursor: pointer;
  opacity: 0;
  transition: opacity .15s;
}
/* some junto com o de apagar, mas continua visível enquanto a barra dele
   estiver aberta (senão o botão desaparece embaixo do mouse) */
.chat-msg:hover .btn-reagir, .btn-reagir.ativo { opacity: 1; }
.btn-reagir:hover, .btn-reagir.ativo { border-color: var(--verde); color: var(--verde-escuro); }

/* barra que abre ao lado do botão, na mesma linha (não acima): a área de
   mensagens rola, e qualquer coisa que passasse do topo/fundo dela seria
   cortada. A grade expandida ainda é reposicionada por encaixarBarraNaArea */
.barra-reacoes {
  position: absolute;
  top: 50%;
  left: calc(100% + 6px);
  transform: translateY(-50%);
  z-index: 4;
  display: flex;
  gap: 2px;
  padding: 4px 6px;
  background: var(--branco);
  border: 1px solid var(--linha);
  border-radius: 999px;
  box-shadow: var(--sombra);
}
.chat-msg.propria .barra-reacoes { right: calc(100% + 6px); left: auto; }
/* a grade inteira (depois do "+") não é mais uma "barra": vira um painel de 8
   colunas, com a mesma medida do painel de emoji do campo de envio */
.barra-reacoes.expandida {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 2px;
  width: 268px;
  max-height: 196px;
  overflow-y: auto;
  padding: 6px;
  border-radius: 11px;
}
.reacao-opcao {
  border: 0;
  background: none;
  border-radius: 6px;
  padding: 0;
  width: 28px;
  height: 28px;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
}
.barra-reacoes.expandida .reacao-opcao { width: auto; }
.reacao-opcao:hover { background: var(--linha-hover); }
/* a reação que a pessoa já deixou nessa mensagem (é uma só por pessoa) */
.reacao-opcao.escolhida { background: var(--azul-fundo); box-shadow: inset 0 0 0 1.5px var(--azul); }
.reacao-mais { color: var(--suave); font-size: 18px; font-weight: 700; }

/* pílulas embaixo do balão, uma por emoji, com a contagem */
.reacoes-msg { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.chat-msg.propria .reacoes-msg { justify-content: flex-end; }
.reacao-pilula {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  border: 1px solid var(--linha);
  background: var(--fundo-sutil);
  border-radius: 999px;
  padding: 1px 7px 2px;
  font: inherit;
  font-size: 13px;
  line-height: 1.5;
  cursor: pointer;
}
.reacao-pilula:hover { border-color: var(--verde); }
/* a da própria pessoa fica marcada: é o que mostra que outro clique desfaz */
.reacao-pilula.minha { border-color: var(--azul); background: var(--azul-fundo); }
.reacao-conta { color: var(--suave); font-size: 11px; font-weight: 700; }

/* popup de quem reagiu (ver mostrarPopupReacao em app.js). Vive no <body> com
   position: fixed de propósito: dentro da conversa ele seria cortado pelo
   overflow da lista de mensagens. A setinha aponta pra pílula, e vira pro outro
   lado quando o popup precisa abrir embaixo */
.popup-reacao {
  position: fixed;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: 260px;
  padding: 8px 12px;
  background: var(--branco);
  border: 1px solid var(--linha);
  border-radius: 10px;
  box-shadow: var(--sombra);
  pointer-events: none;
}
.popup-reacao::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: -5px;
  width: 9px;
  height: 9px;
  margin-left: -5px;
  background: var(--branco);
  border-right: 1px solid var(--linha);
  border-bottom: 1px solid var(--linha);
  transform: rotate(45deg);
}
.popup-reacao.abaixo::after { top: -5px; bottom: auto; transform: rotate(225deg); }
.popup-reacao-emoji { font-size: 22px; line-height: 1; }
.popup-reacao-nomes { display: flex; flex-direction: column; gap: 1px; font-size: 12px; color: var(--tinta); }
.popup-reacao-nomes span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.reacao-pilula.minha .reacao-conta { color: var(--azul-texto); }
.chat-envio { display: flex; gap: 10px; padding: 12px; border-top: 1px solid var(--linha); align-items: flex-end; }
/* no chat da equipe o campo de envio não tem linha em cima (pedido do usuário,
   2026-08-21): o papel de parede já atravessa a caixa inteira e a divisória
   cortava o padrão no meio. A borda continua valendo no outro lugar que usa
   .chat-envio, o modal de comentários do ramal, onde não há papel de parede */
.chat-caixa .chat-envio { border-top: 0; }
.chat-envio textarea { flex: 1; resize: none; max-height: 140px; font: inherit; line-height: 1.45; }
/* campo de comentários do ramal (modal, fora de .chat-caixa) cresce sozinho
   igual ao campo do chat geral (ver ajustarAlturaChat/.rolando em app.js),
   sem barra de rolagem enquanto o texto couber no teto de 140px */
#comentario-texto { overflow-y: hidden; }
#comentario-texto.rolando { overflow-y: auto; }
/* campo de escrever do chat da equipe (pedido do usuário, 2026-08-21): quinas
   bem mais arredondadas e um tom mais escuro que o resto da caixa. --fundo
   serve pros dois temas: é sempre um passo mais escuro que --branco (o fundo
   do cartão), no claro e no escuro */
.chat-caixa .chat-envio textarea {
  border-radius: 18px;
  /* 39px de altura com uma linha, a mesma do botão Enviar e do botão de emoji
     ao lado (pedido do usuário, 2026-08-21): 19px de linha + 18px de padding +
     2px de borda. O min-height é o piso, porque a altura de fato é escrita pelo
     JS conforme o texto cresce (ver ajustarAlturaChat) */
  padding: 9px 16px;
  min-height: 39px;
  line-height: 1.35;
  background: var(--fundo);
  /* sem barra de rolagem enquanto o texto couber: o campo cresce sozinho até
     o teto (ver ajustarAlturaChat em app.js), e só quando passa disso a
     rolagem entra, pela classe .rolando */
  overflow-y: hidden;
}
.chat-caixa .chat-envio textarea.rolando { overflow-y: auto; }
.chat-vazio { margin: auto; text-align: center; color: var(--suave); }

/* ---- seletor de emoji do campo de envio (ver montarPainelEmoji em app.js) ---- */
/* o painel abre pra CIMA e fica dentro da .chat-caixa de propósito: a caixa
   tem overflow:hidden, então qualquer coisa que passasse da borda dela seria
   cortada. Por isso o teto de altura, calculado pra caber sobre a lista de
   mensagens (a caixa tem min-height 320px) */
.emoji-caixa { position: relative; flex: 0 0 auto; }
.btn-emoji {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 39px pra bater com o campo e com o Enviar */
  width: 39px;
  height: 39px;
  padding: 0;
  border: 1px solid var(--linha);
  background: var(--branco);
  color: var(--suave);
  border-radius: 9px;
  cursor: pointer;
}
.btn-emoji:hover { border-color: var(--verde); color: var(--verde-escuro); }
.btn-emoji.ativo { border-color: var(--verde); color: var(--verde-escuro); background: var(--verde-fundo); }
.painel-emoji {
  position: absolute;
  /* alinhado à esquerda porque o botão fica antes do campo (à esquerda dele) */
  left: 0;
  bottom: calc(100% + 8px);
  z-index: 5;
  width: 292px;
  max-height: 232px;
  overflow-y: auto;
  padding: 8px 10px 10px;
  background: var(--branco);
  border: 1px solid var(--linha);
  border-radius: 11px;
  box-shadow: var(--sombra);
}
.emoji-grupo {
  padding: 6px 2px 4px;
  color: var(--suave);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .6px;
  text-transform: uppercase;
}
.emoji-grade { display: grid; grid-template-columns: repeat(8, 1fr); gap: 2px; }
.emoji-item {
  border: 0;
  background: none;
  border-radius: 6px;
  padding: 0;
  height: 30px;
  /* o emoji é caractere de texto: o tamanho aqui é o "tamanho do desenho" */
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
}
.emoji-item:hover { background: var(--linha-hover); }
/* botão "carregar mais antigas" no topo da lista (paginação de 50, ver
   TAMANHO_PAGINA_MENSAGENS em server.js) */
.chat-mais { align-self: center; flex: 0 0 auto; }

/* balãozinho de comentários na linha da tabela de ramais, herda o quadrado
   cinza de .btn-icone; o número só aparece quando há algum comentário */
.btn-icone.com-comentarios { border-color: var(--azul); color: var(--azul); }
.contador-comentarios { font-size: 10px; font-weight: 700; margin-left: 2px; }

/* submenu Brasil/Paraguai, abaixo da aba "Visualizar Mapa", mesma paleta
   escura da lateral, recuado pra ficar claro que pertence à aba de cima */
.submenu-mapa { display: flex; flex-direction: column; gap: 2px; padding: 2px 10px 6px 30px; }
.subitem-mapa {
  display: flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: 0;
  color: var(--lateral-texto-suave);
  padding: 7px 12px;
  border-radius: 6px;
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}
.subitem-mapa:hover { background: var(--lateral-hover); color: var(--lateral-texto); }
/* bandeira desenhada em SVG (não emoji), no Windows, o emoji de bandeira
   às vezes cai pra um "BR"/"PY" dentro de uma caixinha em vez da bandeira de
   verdade, dependendo da fonte do sistema */
.bandeira-pais { width: 18px; height: 13px; flex-shrink: 0; border-radius: 2px; }

/* grupo "Comunicação" (Chat + Solicitações) dentro do <nav class="abas">,
   mesma linha de 1px que separa o rodapé (Histórico/Configurações), só que
   recuada 6px de cada lado em vez de 16px, porque o nav já tem 10px de
   padding lateral (6 + 10 = os mesmos 16px da borda do aside) */
.grupo-lateral { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; padding-top: 10px; position: relative; }
.grupo-lateral::before {
  content: '';
  position: absolute;
  top: 0;
  right: 6px;
  left: 6px;
  height: 1px;
  background: var(--lateral-divisor);
}
.grupo-lateral-titulo {
  color: var(--lateral-texto-apagado);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .8px;
  text-transform: uppercase;
  padding: 2px 14px 2px;
}

.lateral-rodape { display: flex; flex-direction: column; gap: 4px; padding: 10px; position: relative; }
.lateral-rodape::before {
  content: '';
  position: absolute;
  top: 0;
  right: 16px;
  left: 16px;
  height: 1px;
  background: var(--lateral-divisor);
}
.aba-config { width: 100%; }

/* ---------- topo ---------- */
/* .topo (barra escura) é a base compartilhada pelas 3 páginas (sistema
   interno, link público do cliente, painel do cliente), .topo-interno é o
   modificador "sem barra colorida" (2026-08-05, só index.html no início;
   2026-08-18 estendido pras outras duas telas também, deixando as 3
   idênticas nesse aspecto) */
.topo {
  display: flex;
  align-items: center;
  padding: 0 24px;
  height: 62px;
  background: var(--topo-fundo);
  color: #fff;
  position: sticky;
  top: 0;
  z-index: 10;
}
/* sem barra colorida: os controles (tema/usuário/presença) ficam soltos
   sobre o próprio fundo da página, junto com o resto do conteúdo, mais
   baixa que a barra escura original (48px em vez de 62px), pra sobrar menos
   vão vazio entre os ícones e o título da tela logo abaixo */
.topo-interno { height: 48px; background: var(--fundo); color: var(--tinta); }
/* --altura-topo só pode ser redefinida aqui olhando pro documento inteiro
   (:has), porque .topo-interno e .barra-filtros são primos na árvore (um
   dentro de <header>, outro dentro de <main>), uma variável definida só em
   .topo-interno não "vazaria" pra fora do próprio <header> */
body:has(.topo-interno) { --altura-topo: 48px; }
.topo-interno .usuario-logado { color: var(--tinta); opacity: 1; }
.topo-interno .btn-tema-rapido {
  background: none;
  border: 0;
  color: var(--tinta);
}
.topo-interno .btn-tema-rapido:hover { background: var(--fundo-sutil); }
/* botão de usuário continua em formato "pill" (borda + fundo) mesmo no
   cabeçalho claro, em vez de ficar todo transparente até o hover: repaginação
   pedida pelo usuário, 2026-08-28, pra bater com a referência que ele mandou
   (avatar + nome + seta dentro de um "chip" sempre visível, não só no hover) */
.topo-interno .btn-usuario {
  background: var(--fundo-sutil);
  border: 1px solid var(--linha);
  color: var(--tinta);
}
.topo-interno .btn-usuario:hover { background: var(--linha-hover); }
/* falta menos de 1h pra sessão vencer: contador em volta do botão (ver
   desenharAnelSessao em app.js). SVG por cima, 1px pra fora de cada lado,
   em vez de mexer na borda: não muda o tamanho do botão nem empurra o topo.
   --vermelho-cartao pelo mesmo motivo do .bloco-sessao.urgente (o --vermelho
   puro some no tema escuro) */
.btn-usuario { position: relative; }
/* -3px e +6px (não -2/+4): o absoluto se mede a partir da face de DENTRO da
   borda de 1px do botão, então isto dá exatamente 2px pra fora da borda de
   cada lado, que é o que desenharAnelSessao assume ao montar o contorno */
.anel-sessao {
  display: none;
  position: absolute;
  top: -3px;
  left: -3px;
  width: calc(100% + 6px);
  height: calc(100% + 6px);
  pointer-events: none;
  overflow: visible;
}
.btn-usuario.sessao-urgente .anel-sessao { display: block; }
.anel-sessao path { fill: none; stroke: var(--vermelho-cartao); stroke-width: 2; }
/* trilho apagado mostra o tamanho da volta inteira, pra dar pra ler quanto falta */
.anel-sessao-trilho { opacity: .2; }
.anel-sessao-progresso {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  stroke-linecap: round;
  transition: stroke-dashoffset 1s linear;
}
/* feixe de luz branca que corre pelo trecho vermelho, do começo (meio de cima)
   até a ponta, e repete a cada 5s: passa em ~1,2s e fica parado (invisível) no
   resto. Traço de 6 (de 100) com um vão enorme, e o dashoffset NEGATIVO empurra
   ele pra frente no contorno. --anel-fim vem do app.js (desenharAnelSessao) e
   já desconta o tamanho do feixe, então ele some antes de sair do vermelho */
.anel-sessao .anel-sessao-brilho {
  stroke: #fff;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-dasharray: 6 300;
  stroke-dashoffset: 0;
  opacity: 0;
  filter: drop-shadow(0 0 2px rgba(255, 255, 255, .9));
  animation: anel-sessao-feixe 5s ease-in-out infinite;
}
.anel-sessao.sem-brilho .anel-sessao-brilho { display: none; }
@keyframes anel-sessao-feixe {
  0% { stroke-dashoffset: 0; opacity: 0; }
  3% { opacity: .95; }
  21% { opacity: .95; }
  24% { stroke-dashoffset: var(--anel-fim, 0); opacity: 0; }
  100% { stroke-dashoffset: var(--anel-fim, 0); opacity: 0; }
}
/* quem pediu menos movimento no sistema operacional fica só com o contador */
@media (prefers-reduced-motion: reduce) {
  .anel-sessao .anel-sessao-brilho { display: none; }
}
/* contador de presença (cliente.html) tinha só a versão pensada pro fundo
   escuro do .topo original (texto branco sobre preto translúcido), sem
   isso ficaria quase invisível (texto branco sobre o fundo claro do
   .topo-interno). Precisa do prefixo ".acoes-topo" pra especificidade bater
   (e vencer) a regra ".acoes-topo .contador-presenca-nav" mais abaixo no
   arquivo, mesma especificidade + vindo depois faria ela ganhar por ordem
   de origem, e a correção não teria efeito nenhum (achado real testando) */
.topo-interno .acoes-topo .contador-presenca-nav {
  color: var(--tinta);
  background: var(--fundo-sutil);
  border-color: var(--linha);
}

.acoes-topo { margin-left: auto; display: flex; align-items: center; gap: 10px; }

/* escurece (não clareia) o que estiver atrás, funciona tanto no preto quanto no
   azul do modo claro; a borda clara garante o contorno do botão nos dois casos */
.usuario {
  background: rgba(0, 0, 0, .2);
  border: 1px solid rgba(255, 255, 255, .2);
  color: #fff;
  font: inherit;
  font-weight: 600;
  height: 34px;
  min-width: 34px;
  padding: 0 12px;
  border-radius: 17px;
  cursor: pointer;
}
.usuario:hover { background: rgba(0, 0, 0, .34); }

/* ---------- botões ---------- */
.btn {
  border: 0;
  border-radius: 7px;
  padding: 9px 15px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
  white-space: nowrap;
}
.btn:disabled { opacity: .5; cursor: default; }
.btn-principal { background: var(--verde); color: #fff; }
.btn-principal:hover { background: var(--verde-escuro); }
/* claro = cinza com texto escuro por padrão; translúcido só sobre a barra escura do topo */
.btn-claro { background: var(--linha); color: var(--tinta); }
.btn-claro:hover { background: var(--linha-hover); }
.topo .btn-claro { background: rgba(0, 0, 0, .2); border: 1px solid rgba(255, 255, 255, .2); color: #fff; }
.topo .btn-claro:hover { background: rgba(0, 0, 0, .34); }
.btn-perigo { background: var(--vermelho); color: #fff; }
.btn-perigo:hover { background: #8e0019; }

.btn-mini {
  border: 1px solid var(--linha);
  background: var(--branco);
  color: var(--suave);
  border-radius: 6px;
  padding: 4px 9px;
  font-size: 12px;
  cursor: pointer;
  font-weight: 600;
}
.btn-mini:hover { border-color: var(--verde); color: var(--verde-escuro); }
.btn-mini.perigo:hover { border-color: var(--vermelho); color: var(--vermelho); }
.btn-mini:disabled { opacity: .5; cursor: default; border-color: var(--linha); color: var(--suave); }
.btn-mini:disabled:hover { border-color: var(--linha); color: var(--suave); }
/* "Enviar solicitação" (painel do cliente) só fica azul quando há texto no
   campo "Nome desejado", ver blocoSolicitarNome/enviarSolicitacaoNome em
   painel-cliente.js. Precisa vencer o :disabled acima quando os dois
   coexistem por 1 instante (não deveria acontecer, mas por garantia) */
.btn-mini.azul { background: var(--azul); border-color: var(--azul); color: #fff; }
.btn-mini.azul:hover { background: var(--azul-texto); border-color: var(--azul-texto); color: #fff; }
.btn-mini.azul:disabled { background: var(--azul); border-color: var(--azul); color: #fff; opacity: .5; }
/* botão circular só com a seta (setas de paginação de Concluídas, ver
   .paginacao-solic), mesmo .btn-mini por baixo (cor, hover, :disabled já
   prontos), só vira redondo e centraliza o glifo em vez do padding de texto */
.btn-mini.redondo {
  width: 38px;
  height: 38px;
  padding: 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
}
.btn-mini.redondo svg { width: 18px; height: 18px; }
.link-modo-ramal { display: block; margin-bottom: 14px; }

.btn-icone {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 1px solid var(--linha);
  background: var(--branco);
  color: var(--suave);
  border-radius: 6px;
  cursor: pointer;
}
.btn-icone:hover { border-color: var(--vermelho); color: var(--vermelho); }
/* variante pra ações que NÃO são destrutivas (ex.: atalho "abrir" no
   Histórico), herda o quadrado cinza do .btn-icone, mas o hover vermelho
   de exclusão não faz sentido aqui */
.btn-icone.neutro:hover { border-color: var(--verde); color: var(--verde-escuro); }
/* ícone de "ver mensagem do cliente" (Solicitações), azul fixo, não só no
   hover, pra chamar atenção de que aquele pedido tem algo a mais pra ler */
.btn-icone.azul { border-color: var(--azul); color: var(--azul); }
.btn-icone.azul:hover { border-color: var(--azul-texto); color: var(--azul-texto); }
/* botão "⋮" quando o ramal tem alguma regra especial ligada (ver
   ramalTemRegraEspecial em app.js), borda mais grossa e colorida, pra dar
   pra notar mesmo com o menu fechado que ali tem algo configurado */
.btn-icone-regra { border: 1.5px solid var(--tinta); }

/* sininho fora do menu "⋮" (coluna Ações da tabela), sinaliza de longe,
   sem precisar abrir o menu, que a automação de Verificar-por-tempo-offline
   está de fato valendo pra esse ramal (ver classeSinoLinha em app.js):
   preto = seguindo a regra padrão da empresa/unidade, dourado = Alerta
   (regra própria) ligado. Fica oculto (mas ocupa o espaço) quando nenhuma
   das duas vale, pra não fazer as colunas "pularem" de largura */
.sino-linha { display: inline-flex; align-items: center; margin-right: 4px; visibility: hidden; }
.sino-linha-preto { visibility: visible; color: var(--tinta); }
.sino-linha-dourado { visibility: visible; color: #d4a017; }

/* aviso de "central inacessível" (clientes.ami_offline_desde), vermelho a
   pedido do usuário (2026-08-14); mesma família de cor do vermelho de
   "sumiu"/erro (--vermelho), mas o piscar distingue visualmente "sem
   conexão agora" (efêmero) de "sumiu da central" (estado fixo da linha) */
.aviso-central-offline { display: inline-flex; align-items: center; margin-right: 4px; color: var(--vermelho); animation: piscar-central-offline 1.8s ease-in-out infinite; }
@keyframes piscar-central-offline { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

/* "conectado com a central", estado de dia a dia (não é problema, por
   isso sem piscar, diferente do vermelho de .aviso-central-offline) que
   antes não tinha nenhum aviso equivalente: a linha/cartão simplesmente não
   mostrava nada quando estava tudo certo (pedido do usuário, 2026-08-19) */
.aviso-central-online { display: inline-flex; align-items: center; margin-right: 4px; color: var(--verde-escuro); }

/* aviso de "a automação em si não dá sinal de vida" (ver PUT
   /api/automacao-ami/heartbeat), dourado (mesma cor de "Alerta" em
   .sino-linha-dourado) e SEM piscar, de propósito diferente do vermelho
   piscante de .aviso-central-offline: é um problema mais estrutural (nada
   está sendo verificado, não só uma central específica) e os dois nunca
   aparecem juntos (ver avisoAutomacaoAmiHtml em app.js) */
.aviso-automacao-parada { display: inline-flex; align-items: center; margin-right: 4px; color: #d4a017; }

/* width:100% é o que garante a largura igual em qualquer tela: sem isso, o
   main (item flex de .principal) encolhe para caber no conteúdo em vez de
   sempre ocupar o espaço disponível até o limite de max-width */
main { width: 100%; padding: 24px; max-width: 1600px; margin: 0 auto; }

/* ---------- cabeçalho do Painel ---------- */
/* puxa pra mais perto do topo, ficando bem próximo da mesma altura dos
   ícones (tema/usuário), negativo só aqui, não em `main`, que é
   compartilhado por toda tela; limitado a no máximo os 24px de
   padding-top do `main` (ver estilo.css, regra `main`), senão o título
   passaria por baixo da barra de ícones (sticky, fica por cima) */
.painel-cabecalho { margin-top: -22px; margin-bottom: 22px; }
.painel-migalha {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--azul-texto);
  margin-bottom: 4px;
}
.painel-cabecalho h1 { font-size: 26px; font-weight: 800; margin-bottom: 4px; }
.painel-boas-vindas { color: var(--suave); font-size: 14px; }

/* ---------- cartões ---------- */
.cartoes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
  margin-bottom: 20px;
}

.titulo-secao-painel {
  font-size: 13px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .6px;
  color: var(--destaque-navy);
  margin-bottom: 10px;
}

.cartao {
  background: var(--branco);
  border-radius: 11px;
  padding: 16px 18px;
  box-shadow: var(--sombra);
}
/* só os cards de "Clientes" ficaram um pouco mais altos, os de "Ramais"
   (.cartao-info) continuam do tamanho original */
#cartoes-clientes .cartao { padding-top: 24px; padding-bottom: 24px; }
.cartao .rotulo {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .6px;
  color: var(--suave);
  font-weight: 700;
}
.cartao .valor { font-size: 30px; font-weight: 700; line-height: 1.25; }
.cartao .nota { font-size: 12px; color: var(--suave); }

/* ícone em círculo colorido à esquerda do rótulo/valor (cards de Clientes e
   Ramais do Painel), a cor do círculo acompanha a mesma cor da plataforma
   (ou --navy pro card "Total"), calculada via color-mix inline no app.js */
.cartao-com-icone { display: flex; align-items: center; gap: 14px; }
.cartao-icone {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
}
.cartao-icone svg { width: 18px; height: 18px; }

.cartao-clicavel { cursor: pointer; transition: transform .12s, box-shadow .12s; }
.cartao-clicavel:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(0, 0, 0, .12); }

/* ---------- status dos ramais em destaque ---------- */
.status-ramais {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
  margin-bottom: 20px;
}
@media (max-width: 700px) { .status-ramais { grid-template-columns: 1fr; } }

.cartao-status {
  position: relative;
  display: flex;
  align-items: center;
  gap: 20px;
  border-radius: 16px;
  padding: 28px 30px;
  color: #fff;
  overflow: hidden;
}

/* ícone enorme e bem apagado no canto, só pra dar textura/profundidade ao
   cartão, puramente decorativo, por isso aria-hidden não é nem necessário
   (o SVG já não carrega nenhuma informação que a legenda não diga) */
.cs-fundo {
  position: absolute;
  right: -14px;
  bottom: -18px;
  width: 110px;
  height: 110px;
  opacity: .16;
}
.cs-fundo svg { width: 100%; height: 100%; }

.cs-icone {
  position: relative;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .18);
}
.cs-icone svg { width: 30px; height: 30px; }

.cs-corpo { position: relative; }
.cartao-status .cs-valor { display: flex; font-size: 44px; font-weight: 800; line-height: 1; }

/* "hodômetro": cada dígito é uma janela de 1 caractere de altura (overflow
   escondido) com uma faixa vertical de 0 a 9 dentro, deslocar a faixa com
   transition anima o número "rolando" pra cima/baixo (ver atualizarOdometro
   em app.js). font-variant-numeric garante que todo dígito tem a mesma
   largura, senão a faixa treme de leve ao trocar de número */
.odom-digito { height: 1em; overflow: hidden; font-variant-numeric: tabular-nums; }
.odom-tira { display: flex; flex-direction: column; transition: transform .5s cubic-bezier(.4, 0, .2, 1); }
.odom-tira span { height: 1em; line-height: 1; }
.cartao-status .cs-rotulo {
  margin-top: 8px;
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .6px;
  opacity: .85;
}
.status-ativo {
  background: linear-gradient(135deg, #37c07a, var(--verde) 65%);
  box-shadow: 0 10px 24px -8px rgba(47, 172, 102, .55);
}
.status-inativo {
  background: linear-gradient(135deg, #565656, #383838 65%);
  box-shadow: 0 10px 24px -8px rgba(0, 0, 0, .35);
}
.status-offline {
  background: linear-gradient(135deg, #353535, #171717 65%);
  box-shadow: 0 10px 24px -8px rgba(0, 0, 0, .48);
}
.status-verificar {
  background: linear-gradient(135deg, #e33a54, var(--vermelho) 65%);
  box-shadow: 0 10px 24px -8px rgba(184, 20, 48, .5);
}
/* "A verificar" com zero não precisa chamar atenção em vermelho, mesmo
   cinza neutro do card "Ramais inativos" */
.status-neutro {
  background: linear-gradient(135deg, #565656, #383838 65%);
  box-shadow: 0 10px 24px -8px rgba(0, 0, 0, .35);
}

/* chama atenção quando "A verificar" sobe (Painel se auto-atualiza a cada
   5s, pensado pra ficar aberto fixo numa tela/monitor), pisca algumas
   vezes e para sozinho, sem precisar de JS pra limpar a classe depois */
@keyframes piscar-alerta {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: .45; transform: scale(1.03); }
}
.piscar { animation: piscar-alerta 0.7s ease-in-out 4; }

/* contador de presença (link público do cliente): o ícone do olho dá uma
   volta completa no eixo vertical quando o número muda, pra chamar atenção
   de quem já está com a tela aberta, só o ícone gira, o número ao lado fica
   parado */
@keyframes girar-olho-vertical {
  from { transform: rotateY(0deg); }
  to { transform: rotateY(360deg); }
}
.girar-presenca svg { animation: girar-olho-vertical 0.6s ease-in-out; }

/* ---------- caixas ---------- */
.painel-grade {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
@media (max-width: 900px) { .painel-grade { grid-template-columns: 1fr; } }

.caixa {
  background: var(--branco);
  border-radius: 11px;
  padding: 18px;
  box-shadow: var(--sombra);
}
.caixa.sem-padding { padding: 0; overflow: hidden; }

/* mesma cor do pontinho de cada item nas listas "por empresa" (ver
   INFO_ITEM_STATUS em app.js), reforça visualmente qual card é qual status
   já na borda, antes mesmo de ler o título */
.caixa-status-verificar { border-top: 3px solid var(--vermelho); }
.caixa-status-offline { border-top: 3px solid #5c5c5c; }
.caixa-status-inativo { border-top: 3px solid var(--suave); }

.caixa-topo {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 16px;
  gap: 12px;
}
.caixa-topo h2 { font-size: 15px; }
/* só as 6 caixas "por empresa" do Painel (Verificar/Offline/Inativos × simples
   e lista), não é o `.caixa-topo h2` genérico, reaproveitado em telas fora
   do Painel (ex.: Administração de Usuários), que continua como estava */
.painel-grade .caixa-topo h2 {
  font-size: 16px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .3px;
  color: var(--destaque-navy);
}
.dica { font-size: 11px; color: var(--suave); text-align: right; }

/* ---------- barras ---------- */
.barra-item { margin-bottom: 16px; }
.barra-item:last-child { margin-bottom: 0; }

.barra-legenda {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  margin-bottom: 6px;
}
.barra-legenda b { font-weight: 600; }
.barra-legenda span { color: var(--suave); font-size: 12px; }

.barra-trilho {
  height: 9px;
  background: var(--linha);
  border-radius: 5px;
  overflow: hidden;
}
.barra-preenchida { height: 100%; border-radius: 5px; transition: width .4s; }

.aviso-filtro-unidades {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: -8px 0 16px;
  font-size: 12px;
  color: var(--suave);
}

/* ---------- pendências ---------- */
/* margem negativa + padding iguais: o conteúdo fica exatamente onde estava,
   mas sobra 10px de cada lado DENTRO da área de rolagem, onde o fundo que
   pisca da .pendencia-alerta cabe sem ser cortado nem gerar barra horizontal */
.lista-pendencias { max-height: 300px; overflow-y: auto; margin: 0 -10px; padding: 0 10px; }

.pendencia {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 0;
  border-bottom: 1px solid var(--linha);
  cursor: pointer;
}
.pendencia:last-child { border-bottom: 0; }
.pendencia:hover .pend-nome { color: var(--verde-escuro); }
.pend-ponto { display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; vertical-align: middle; }
.pend-nome { font-weight: 600; }
.pend-plat { font-size: 11px; color: var(--suave); }
.pend-num { margin-left: auto; font-size: 12px; color: var(--suave); white-space: nowrap; }
.pend-num b { color: inherit; }
/* empresa com ramal de Alerta (regra própria) em Verificar, nas 2 caixas de
   Verificar do Painel (pedido do usuário, 2026-09-25): a linha pisca em
   vermelho sem parar enquanto o Alerta estiver em Verificar, e o servidor já
   manda ela primeiro. Margem negativa + padding lateral pro fundo não colar
   no texto, sem mudar o alinhamento das outras linhas. A duração tem que
   bater com CICLO_PISCAR_ALERTA_MS (app.js), que mantém a fase entre os
   redesenhos de 5s do Painel */
.pendencia-alerta {
  margin: 0 -10px;
  padding-left: 10px;
  padding-right: 10px;
  border-radius: 8px;
  animation: piscar-pendencia-alerta 1.6s ease-in-out infinite;
}
.pendencia-alerta .pend-ponto { animation: inherit; animation-name: pulsar-ponto-alerta; }
.pendencia-alerta .pend-num { color: var(--tinta); font-weight: 600; }
.pend-sino { display: inline-flex; vertical-align: -2px; margin-left: 4px; color: #d4a017; transform-origin: 50% 0%; }
.pend-sino svg { stroke-width: 3; }
@keyframes piscar-pendencia-alerta {
  0%, 100% { background: transparent; }
  50% { background: var(--vermelho-faixa); }
}
@keyframes pulsar-ponto-alerta {
  0%, 100% { box-shadow: 0 0 0 0 rgba(176, 0, 32, .55); }
  50% { box-shadow: 0 0 0 5px rgba(176, 0, 32, 0); }
}
/* quem pediu menos movimento no sistema operacional: fundo fixo, sem piscar */
@media (prefers-reduced-motion: reduce) {
  .pendencia-alerta, .pendencia-alerta .pend-ponto { animation: none; }
  .pendencia-alerta { background: var(--vermelho-faixa); }
}

/* ---------- filtros ---------- */
/* sticky logo abaixo do .topo (ver --altura-topo), fica visível enquanto a
   lista por baixo rola, em vez de sumir da tela assim que rola um pouco.
   Fundo sólido + padding/margin negativos "por fora" das bordas do <main>
   (24px, ver `main { padding: 24px }`) garante que nada da lista passa por
   baixo visualmente enquanto ela está grudada no topo. z-index 5: abaixo do
   .topo (10) e dos menus/dropdowns (20+), acima do conteúdo normal da lista */
.barra-filtros {
  display: flex;
  gap: 10px;
  margin-bottom: 16px;
  flex-wrap: wrap;
  position: sticky;
  top: var(--altura-topo);
  z-index: 5;
  background: var(--fundo);
  padding: 12px 24px;
  margin-left: -24px;
  margin-right: -24px;
  width: calc(100% + 48px);
}

input[type="search"], input[type="text"], input[type="number"], input[type="password"], select, textarea {
  border: 1px solid var(--linha);
  border-radius: 7px;
  padding: 9px 12px;
  font: inherit;
  background: var(--branco);
  color: var(--tinta);
  outline: none;
}
input:focus, select:focus, textarea:focus { border-color: var(--verde); box-shadow: 0 0 0 3px rgba(47, 172, 102, .15); }
/* campo recusado ao salvar (ex.: prazo zerado da verificação automática, ver
   marcarPrazoZerado em app.js), ganha do verde do :focus de propósito */
.campo-invalido, .campo-invalido:focus { border-color: var(--vermelho); box-shadow: 0 0 0 3px rgba(176, 0, 32, .15); }
/* campo travado (ex.: integração ainda não implementada, tipo FreeSWITCH/ESL),
   mesmo espírito visual de .btn:disabled, só mais sutil pra não parecer erro */
input:disabled { background: var(--fundo-sutil); color: var(--suave); cursor: not-allowed; opacity: .8; }

/* campo com "dono" na central telefônica via PABX (readonly, não disabled,
   ver ramalTravadoPelaCentral em app.js/painel-cliente.js), ex.: campo
   Usuário no modal de editar ramal do painel do cliente. Mesmo azul de
   .celula-travada (tabela do sistema interno), aqui via seletor por tipo
   (mesma lista de `input[type=...]` da regra base acima) porque o modal usa
   `<input>` comum, sem essa classe.
   Bug real corrigido (2026-08-12): um `input:read-only` genérico "casava"
   com TODO checkbox do sistema (Ignorar sinalização, Administrador,
   Automação etc.), checkbox nunca tem o atributo `readonly` (nem existe pra
   esse tipo de campo), mas a especificação CSS considera qualquer
   checkbox/radio como ":read-only" por padrão, então o cursor "bloqueado" (e
   a cor azul) vazava pra eles sem nenhuma trava de verdade por trás (o
   clique sempre funcionou normalmente), só o visual estava errado */
input[type="search"]:read-only, input[type="text"]:read-only,
input[type="number"]:read-only, input[type="password"]:read-only {
  background: var(--azul-fundo); color: var(--azul-texto); cursor: not-allowed;
}

.barra-filtros input[type="search"] { flex: 1; min-width: 220px; }
.barra-filtros-acoes-unidade { display: flex; align-items: center; gap: 10px; margin-left: auto; }

/* ---------- grade de clientes ---------- */
.grade-clientes {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}
@media (max-width: 1050px) { .grade-clientes { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 780px)  { .grade-clientes { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px)  { .grade-clientes { grid-template-columns: 1fr; } }

/* separador entre plataformas, na grade de clientes com "Todas as plataformas" */
.separador-grupo {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 10px 0 0;
  color: var(--suave);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .6px;
}
.separador-grupo:first-child { margin-top: 0; }
.separador-grupo::before,
.separador-grupo::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--linha);
}

/* cabeçalho de País, nível acima do separador de Estado, mais forte pra
   deixar clara a hierarquia (País contém Estados) */
.separador-pais {
  grid-column: 1 / -1;
  margin: 22px 0 4px;
  color: var(--tinta);
  font-size: 14px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .6px;
}
.separador-pais:first-child { margin-top: 0; }

/* separador de Estado quando aninhado dentro de um País: recuado, pra ficar
   claro que pertence ao país logo acima */
.separador-grupo-aninhado { margin-left: 18px; }

.cartao-cliente {
  position: relative;
  background: var(--branco);
  border-radius: 11px;
  padding: 15px 16px;
  box-shadow: var(--sombra);
  cursor: pointer;
  border-left: 4px solid var(--verde);
  transition: transform .12s, box-shadow .12s;
}
/* selo de status da automação AMI (ver seloAvisoAmiCartaoHtml em app.js) no
   canto inferior-direito do cartão, pedido do usuário 2026-08-19, mesmo
   selo já usado no cabeçalho do cliente, agora também na grade de Clientes */
.selo-aviso-ami-cartao {
  position: absolute;
  bottom: 10px;
  right: 12px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--branco);
  /* sem o anel de 1px em volta (pedido do usuário, 2026-09-25) */
  display: flex;
  align-items: center;
  justify-content: center;
}
.selo-aviso-ami-cartao > span { margin-right: 0; }
.cartao-cliente:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .12);
}
/* card dos ramais que ficaram fora de qualquer unidade: visual mais discreto */
.cartao-soltos { border-left-style: dashed; background: var(--fundo-sutil); }
/* cartão de unidade (ou "Ramais sem unidade") com ramal de Alerta (regra
   própria) em Verificar, na grade de unidades do sistema interno: pisca do
   fundo normal do cartão até o mesmo vermelho da .pendencia-alerta do
   Painel. --cartao-alerta-base guarda o fundo de cada tipo de cartão, pra a
   animação voltar pra cor certa (branco ou o cinza do tracejado). Mesma
   duração de CICLO_PISCAR_ALERTA_MS (app.js) */
.cartao-cliente.cartao-alerta {
  --cartao-alerta-base: var(--branco);
  animation: piscar-cartao-alerta 1.6s ease-in-out infinite;
}
.cartao-cliente.cartao-soltos.cartao-alerta { --cartao-alerta-base: var(--fundo-sutil); }
@keyframes piscar-cartao-alerta {
  0%, 100% { background: var(--cartao-alerta-base); }
  50% { background: var(--vermelho-faixa); }
}
@media (prefers-reduced-motion: reduce) {
  .cartao-cliente.cartao-alerta { animation: none; background: var(--vermelho-faixa); }
}

/* cartão de unidade na Lista de Ramais pública (cliente.js), ícone de
   folha/agenda gigante e bem apagado ao fundo, dando profundidade (mesma
   ideia dos cartões de status do Painel). min-height garante que o ícone não
   fique cortado nos cards sem telefone (mais baixos que os com telefone) */
.cartao-unidade-lista { position: relative; overflow: hidden; min-height: 78px; display: flex; align-items: center; }
.cartao-unidade-lista > * { position: relative; }
/* mesma marca d'água acima, só que no card da grade ADMINISTRATIVA de
   unidades (desenharUnidades em app.js), conteúdo mais alto e sem
   centralização flex (nome, observações, número de ramais, etiquetas), por
   isso não reaproveita .cartao-unidade-lista, só o necessário pro
   .icone-agenda-fundo (absoluto) ficar contido atrás do conteúdo real */
.cartao-unidade-marca { position: relative; overflow: hidden; }
.cartao-unidade-marca > * { position: relative; }
.icone-agenda-fundo {
  position: absolute;
  right: -14px;
  bottom: -18px;
  width: 84px;
  height: 84px;
  color: var(--verde);
  opacity: .12;
}
.icone-agenda-fundo svg { width: 100%; height: 100%; }
/* logo do cliente no lugar do ícone genérico, em tom de marca d'água,
   diferente do SVG (que tem folga interna e tolera o "vazamento" de
   right/bottom negativos do ícone padrão), a logo enviada pelo cliente
   preenche a caixa inteira (object-fit:contain), então aqui a caixa fica
   inteira DENTRO do card, senão o overflow:hidden do card corta um pedaço
   real da imagem, não só espaço vazio */
.icone-agenda-fundo-logo {
  right: 6px;
  bottom: 6px;
  width: 64px;
  height: 64px;
  opacity: .16;
}
.icone-agenda-fundo-logo img { width: 100%; height: 100%; object-fit: contain; filter: grayscale(1); }
/* só na grade ADMINISTRATIVA de unidades (desenharUnidades) a marca d'água
   fica colorida, nas outras telas que reaproveitam .icone-agenda-fundo-logo
   (Lista de Ramais, ficha pública/painel) continua em tons de cinza */
.cartao-unidade-marca .icone-agenda-fundo-logo img { filter: none; }

/* cliente com contrato encerrado: continua visível, mas não navega mais (a
   gestão dele passou pra Administração de clientes), nem cursor de "clicável"
   nem a animação de levantar no hover */
.cartao-inativo {
  opacity: .55;
  cursor: default;
  transition: none;
}
.cartao-inativo:hover { transform: none; box-shadow: var(--sombra); }

.cartao-cliente h3 { font-size: 15px; margin-bottom: 2px; }
.cc-plat { font-size: 11px; color: var(--suave); text-transform: uppercase; letter-spacing: .4px; font-weight: 600; }

.cc-cabecalho { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; margin-bottom: 10px; }

.ch-nome-logo { display: flex; align-items: center; gap: 12px; }
.ch-nome-logo h1 { margin: 0; }

/* selo de status da automação AMI no canto superior-esquerdo do CABEÇALHO
   do cliente (ver seloAvisoAmiCabecalhoHtml em app.js), `.cliente-cabecalho`
   já é position:relative. Pedido do usuário 2026-08-19: não em cima do logo,
   encostado no canto, acima do nome. Fundo igual ao do cabeçalho
   (var(--branco)) pra "recortar" o canto em vez de deixar um quadrado por cima */
.selo-aviso-ami-cabecalho {
  position: absolute;
  top: 12px;
  left: 16px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--branco);
  /* sem o anel de 1px em volta (pedido do usuário, 2026-09-25) */
  display: flex;
  align-items: center;
  justify-content: center;
}
.selo-aviso-ami-cabecalho > span { margin-right: 0; }

/* só a setinha do botão "Acessar servidor" (ver setaServidorHtml em app.js),
   mesmo sinal verde/vermelho do selo acima, aplicado num detalhe pequeno
   do botão em vez do botão inteiro */
.seta-servidor-online { color: var(--verde-escuro); }
.seta-servidor-offline { color: var(--vermelho); }
:root[data-theme="dark"] .seta-servidor-online { color: #00e676; }

.marca-unidades { color: var(--suave); vertical-align: middle; display: inline-flex; }

/* alinhado à direita: fica no "final" da linha, não colado na borda esquerda */
.link-acoes { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px; }
.admin-cliente-acoes { display: flex; flex-wrap: wrap; gap: 6px; }
/* sem fundo cinza diferente do resto da tabela, dá a impressão de que é
   uma continuação do cliente logo acima, não uma seção à parte */
.linha-link td { padding-top: 12px; padding-bottom: 12px; }

/* enquanto "Lista de ramais" está aberta, some a linha que separaria o
   cliente da sua própria sub-linha de link (o separador entre CLIENTES
   continua normal, porque fica só na sub-linha, não aqui) */
#corpo-admin-clientes tr.linha-expandida td { border-bottom: none; }

/* separa visualmente os grupos de plataforma na tabela de Administração de clientes */
.separador-tabela td {
  padding: 18px 16px 6px;
  border-bottom: none;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .6px;
  color: var(--suave);
}
.separador-tabela:first-child td { padding-top: 6px; }

.btn-expandir { display: inline-flex; align-items: center; gap: 6px; }
.icone-seta { transition: transform .15s; }
.btn-expandir.aberto .icone-seta { transform: rotate(180deg); }
.btn-expandir.aberto { background: var(--verde); border-color: var(--verde); color: #fff; }

/* seta que expande/recolhe os clientes de uma plataforma, começam todos
   recolhidos, pra não vir tudo de uma vez */
.btn-expandir-plataforma {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .6px;
  color: var(--suave);
}
.oculto-plataforma { display: none !important; }

/* a linha inteira (não só o texto/seta) é clicável pra expandir/recolher,
   como é um <div> de bloco dentro de um <td colspan>, já ocupa a largura
   toda sozinho, então só precisava do cursor pra avisar que é clicável */
.separador-linha { display: flex; align-items: center; justify-content: space-between; cursor: pointer; }
.separador-linha:hover .btn-expandir-plataforma { color: var(--tinta); }
.separador-linha.aberto .icone-seta { transform: rotate(180deg); }
.separador-contador { color: var(--suave); }

.telefone {
  font-size: 12px;
  color: var(--suave);
  margin-top: 4px;
  font-variant-numeric: tabular-nums;
}

.btn-copiar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border: 1px solid var(--linha);
  background: var(--branco);
  color: var(--suave);
  border-radius: 5px;
  padding: 0;
  cursor: pointer;
  margin-left: 4px;
  vertical-align: middle;
}
.btn-copiar svg { width: 12px; height: 12px; }
.btn-copiar:hover { border-color: var(--verde); color: var(--verde-escuro); }
.telefone strong { color: var(--tinta); font-weight: 600; }

/* linha "Cidade - UF" no cabeçalho do cliente/unidade (ver linhaLocal em
   app.js), mesmo peso visual do telefone logo abaixo dela */
.local-empresa {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  color: var(--suave);
  margin-top: 4px;
}
.local-empresa svg { flex: 0 0 auto; }

/* confirmação visual de "copiado" (2,5s, ver copiarTexto em app.js), vale
   tanto pro botão "Copiar" do telefone quanto pro "Copiar link" */
.btn-mini.copiado, .btn-copiar.copiado {
  background: var(--verde);
  color: #fff;
  border-color: var(--verde);
}
/* mesma confirmação, versão ícone (ver botão de copiar nome desejado na aba
   "Pendentes" de Solicitações), sem preencher o quadrado inteiro de verde
   (ficaria pesado num botão tão pequeno), só a borda/ícone reagem */
.btn-icone.copiado { border-color: var(--verde); color: var(--verde-escuro); }

.cc-numeros {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin-top: 12px;
}
.cc-numeros .grande { font-size: 24px; font-weight: 700; }
.cc-numeros .de { color: var(--suave); font-size: 13px; }

.cc-rodape {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 8px;
  margin-top: 8px;
  flex-wrap: wrap;
  /* reserva espaço pro selo de status AMI (.selo-aviso-ami-cartao, absoluto
     no canto inferior-direito do cartão), sem isso, um cliente com várias
     etiquetas (ex.: "51 a verificar" + "83 offline") numa coluna estreita
     empurraria a última etiqueta pra baixo do selo. Aplicado sempre (não só
     quando o selo existe de fato) pra não fazer as etiquetas "pularem" de
     lugar se a automação for ligada/desligada depois */
  padding-right: 26px;
}

/* botão maior, na tela do cliente */
.btn-servidor {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--azul-fundo);
  color: var(--azul-texto);
  border: 1px solid var(--azul);
  padding: 5px 12px;
  font-size: 12px;
  border-radius: 6px;
}
.btn-servidor:hover { background: var(--azul); color: #fff; border-color: var(--azul); }

.coluna-acoes { display: flex; flex-direction: column; gap: 6px; }
.coluna-acoes .btn,
.coluna-acoes .btn-mini {
  height: 28px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 12px;
}

.etiqueta {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 20px;
}
.et-ok { background: var(--verde-fundo); color: var(--verde-escuro); }
.et-falta { background: var(--vermelho-fundo); color: var(--vermelho); }
:root[data-theme="dark"] .et-falta { color: var(--vermelho-cartao); }
.et-vazio { background: var(--linha); color: var(--suave); }

/* ---------- detalhe do cliente ---------- */
.voltar {
  background: none;
  border: 0;
  color: var(--suave);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
  margin-bottom: 14px;
}
.voltar:hover { color: var(--verde-escuro); }

.cliente-cabecalho {
  position: relative;
  background: var(--branco);
  border-radius: 11px;
  padding: 18px 20px;
  box-shadow: var(--sombra);
  margin-bottom: 18px;
  display: flex;
  align-items: center;
  gap: 22px;
  border-left: 5px solid var(--verde);
  flex-wrap: wrap;
}
.ch-titulo h1 { font-size: 21px; }
.ch-titulo .cc-plat { display: block; }
.ch-metricas { margin-left: auto; display: flex; align-items: center; gap: 26px; text-align: center; flex-wrap: wrap; }
.ch-metricas-caixa {
  display: flex;
  gap: 26px;
  text-align: center;
  flex-wrap: wrap;
  background: var(--fundo-sutil);
  border: 1px solid var(--linha);
  border-radius: 10px;
  padding: 12px 18px;
}
.ch-metricas .rotulo {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--suave);
  font-weight: 700;
}
.ch-metricas .valor { font-size: 22px; font-weight: 700; }

/* ---------- timeline de histórico de um ramal (ícone de relógio na linha) ---------- */
/* botões 7/15/30 dias (ver .segmentado mais abaixo) à direita, ícones de
   status ao vivo (wifi da central + telefone do ramal) à esquerda, acima da
   barra (pedido do usuário, 2026-08-31) */
.timeline-topo { display: flex; align-items: center; justify-content: space-between; }
.historico-status-atual { display: flex; align-items: center; gap: 10px; }
/* .aviso-central-offline/-online (o wifi) já tem cor/piscar/dark-theme
   próprios, ver mais abaixo no arquivo; aqui só o telefone precisa de cor
   nova, mesmo raciocínio do wifi: --verde-escuro sozinho fica apagado no
   tema escuro. display/align-items iguais ao wifi, sem isso o SVG do
   telefone fica alinhado pela linha de base do texto (herdada por padrão),
   uns pixels mais alto que o do wifi (achado do usuário, 2026-08-31) */
.historico-status-telefone { display: inline-flex; align-items: center; }
.status-tel-online { color: var(--verde-escuro); }
/* #5c5c5c, não var(--vermelho): pedido do usuário (2026-08-31) pra usar o
   MESMO cinza que "Offline" já usa na barra logo abaixo/no card "Tempo
   Offline" (CORES_STATUS_TIMELINE.Offline em app.js), não o vermelho que
   nesta tela já significa "Verificar"/vermelho de erro */
.status-tel-offline { color: #5c5c5c; }
.status-tel-neutro { color: var(--suave); }
:root[data-theme="dark"] .status-tel-online { color: #00e676; }
.timeline-ramal {
  display: flex;
  height: 30px;
  border-radius: 7px;
  overflow: hidden;
  border: 1px solid var(--linha);
}
/* sem borda entre os trechos: cores coladas uma na outra, sem "risco"
   separando (pedido do usuário, 2026-08-31; antes tinha um traço de 2px
   entre cada segmento) */
.timeline-seg {
  height: 100%;
  min-width: 1px;
}
/* "sem dado" (nenhum evento registrado nesse trecho ainda pra saber o
   status), textura listrada em vez de cor sólida, pra não sugerir uma
   certeza que não existe */
.timeline-seg-sem-dado {
  background: repeating-linear-gradient(135deg, var(--fundo-sutil), var(--fundo-sutil) 5px, var(--linha) 5px, var(--linha) 10px);
}
/* trecho "futuro" da janela "Hoje" (ver server.js/desenharHistoricoRamal):
   transparente de propósito, não é "sem dado" (que significa "não sabemos o
   que aconteceu"), é "ainda não aconteceu", só existe pra completar a escala
   de 24h da barra até meia-noite */
.timeline-seg-futuro { background: transparent; }
.timeline-marcadores {
  display: flex;
  justify-content: space-between;
  margin-top: 4px;
  font-size: 10px;
  color: var(--suave);
}
.timeline-legenda {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 14px;
  font-size: 12px;
  color: var(--suave);
}
.timeline-legenda-item { display: flex; align-items: center; gap: 6px; }
.timeline-legenda-item i {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 3px;
}
/* destaca só o valor NOVO (depois do →) na coluna Detalhe do Histórico do
   ramal (ver destacarValorNovo em app.js), pedido do usuário, 2026-08-31 */
.hist-valor-online { color: var(--verde-escuro); }
.hist-valor-offline { color: var(--vermelho); }

/* ---------- tabela ---------- */
.tabela { width: 100%; border-collapse: collapse; }
.tabela th {
  text-align: left;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--suave);
  padding: 12px 16px;
  border-bottom: 1px solid var(--linha);
  background: var(--fundo-sutil);
}
.tabela td { padding: 11px 16px; border-bottom: 1px solid var(--linha); }
.tabela tr:last-child td { border-bottom: 0; }
.tabela tbody tr:hover { background: var(--fundo-sutil); }
.tabela .num { font-weight: 700; font-variant-numeric: tabular-nums; }
.tabela .acoes { text-align: right; white-space: nowrap; }
.tabela .acoes button { margin-left: 4px; }
/* Tipo/Estado/Status/Tempo/Validado em/Validado por, o texto/valor fica
   centralizado; text-align é herdado, então também centraliza o texto
   dentro do <input> da célula, não só o <td>. Um <select> é diferente:
   o valor mostrado na caixa fechada segue `text-align-last`, não
   `text-align`, sem isso, só as opções da lista abrem centralizadas, mas
   o valor selecionado continua colado à esquerda */
.tabela .centro { text-align: center; }
.tabela .centro .celula-select { text-align-last: center; }

/* ---------- linha de filtros ---------- */
.linha-filtros th {
  background: var(--fundo-sutil);
  padding: 7px 8px;
  border-bottom: 1px solid var(--linha);
}

.filtro {
  width: 100%;
  border: 1px solid var(--linha);
  border-radius: 6px;
  padding: 5px 7px;
  font: inherit;
  font-size: 12px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  color: var(--tinta);
  background: var(--branco);
  outline: none;
}
.filtro:focus { border-color: var(--verde); box-shadow: 0 0 0 3px rgba(47, 172, 102, .15); }

/* botão Filtros quando ligado */
.btn-claro.ativo { background: var(--verde); color: #fff; }
.btn-claro.ativo:hover { background: var(--verde-escuro); }

.contador {
  align-self: center;
  font-size: 12px;
  color: var(--suave);
  font-weight: 600;
  white-space: nowrap;
}

/* a célula editável já tem padding próprio; o da <td> soma e desalinha do cabeçalho */
#tela-cliente .tabela td { padding: 6px 8px; }
#tela-cliente .tabela td.acoes { padding-right: 16px; }

/* a grade tem 13 colunas: em tela estreita ela espremia tudo e cortava nomes
   ("Thiag" no Validado por, achado do usuário, 2026-10-29). Agora cada coluna
   tem um mínimo e, abaixo dele, a tabela rola na horizontal DENTRO da caixa,
   a página em si continua sem rolagem lateral (ver scripts/checar-visual.js) */
#caixa-tabela-ramais,
#tela-pendencia-empresa .caixa.sem-padding { overflow-x: auto; }
.celula-validado-por { min-width: 92px; }
#corpo-ramais .celula-select[data-campo="tipo"] { min-width: 76px; }
#corpo-ramais .celula[data-campo="setor"] { min-width: 110px; }
#corpo-ramais .celula[data-campo="usuario"] { min-width: 140px; }
/* Ações grudada na direita enquanto a tabela rola: num notebook (1366px) ela
   ficava fora da tela. Precisa de fundo opaco; nas linhas que têm cor própria
   (e no hover) herda a do <tr>, que é quem pinta a linha */
#caixa-tabela-ramais thead th:last-child,
#corpo-ramais td.acoes { position: sticky; right: 0; z-index: 1; }
#caixa-tabela-ramais thead th:last-child { background: var(--fundo-sutil); }
#corpo-ramais td.acoes { background: var(--branco); }
#corpo-ramais tr:hover td.acoes,
#corpo-ramais tr.linha-descoberta td.acoes,
#corpo-ramais tr.linha-sumida td.acoes,
#corpo-ramais tr.linha-tocando td.acoes,
#corpo-ramais tr.linha-andamento td.acoes,
#corpo-ramais tr.linha-destacada td.acoes { background: inherit; }
/* o piscar do alerta passa por "transparent" (ver piscar-pendencia-alerta),
   herdar deixaria o conteúdo rolado aparecer atrás dos botões */
#corpo-ramais tr.linha-alerta td.acoes,
#corpo-ramais tr.linha-alerta:hover td.acoes { background: var(--branco); }

/* linhas mais estreitas que o padrão, pensado pra caber mais ramal na tela
   sem rolar, já que aqui é só leitura (sem célula editável ocupando espaço).
   .tabela tbody tr:hover já dá o destaque ao passar o mouse (ver acima) */
#tela-pendencia-empresa .tabela td { padding: 6px 16px; cursor: pointer; }

/* ---------- células editáveis ---------- */
/* parecem texto comum; só viram campo ao passar o mouse ou focar */
.celula, .celula-select {
  width: 100%;
  border: 1px solid transparent;
  background: transparent;
  border-radius: 6px;
  padding: 5px 8px;
  font: inherit;
  color: var(--tinta);
  outline: none;
}
.celula:hover, .celula-select:hover { border-color: var(--linha); background: var(--branco); }
.celula:focus, .celula-select:focus {
  border-color: var(--verde);
  background: var(--branco);
  box-shadow: 0 0 0 3px rgba(47, 172, 102, .15);
}
.celula::placeholder { color: #c4c4c4; }
.celula-num { font-weight: 700; font-variant-numeric: tabular-nums; }

/* o Chrome mostra "dd/mm/aaaa" quando vazio e abre o calendário ao clicar */
.celula-data { cursor: pointer; font-variant-numeric: tabular-nums; }
.celula-data::-webkit-calendar-picker-indicator { cursor: pointer; opacity: .5; }
.celula-data:hover::-webkit-calendar-picker-indicator { opacity: 1; }

/* tabular-nums evita que os dígitos "dancem" de largura a cada segundo que o
   cronômetro atualiza (ver formatarDuracaoStatus/setInterval em app.js) */
.tempo-status { font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
/* mesmas cores das células/selos de Status (ver classeStatus/classeTempo em
   app.js), deixa visualmente óbvio, só pela cor, há quanto tempo cada
   ramal está em qual situação, sem precisar olhar a coluna Status ao lado */
.tempo-status.tempo-online { color: var(--verde-escuro); }
.tempo-status.tempo-offline { color: var(--tinta); }
.tempo-status.tempo-neutro { color: var(--suave); }
.tempo-status.tempo-tocando { color: #a17400; }
.tempo-status.tempo-andamento { color: var(--azul-texto); }

/* ramal descoberto pela automação AMI, ainda não revisado por ninguém da
   equipe (ver ramais.criado_via_automacao, TITULO_LINHA_DESCOBERTA em app.js),
   ANTES de .linha-tocando/.linha-andamento de propósito: se uma ligação
   estiver em curso bem no momento em que o ramal é descoberto, o aviso de
   chamada (mais urgente) prevalece sobre o lilás (só "novo, dá uma olhada") */
#corpo-ramais tr.linha-descoberta { background: var(--lilas-fundo); }

/* ramal que EXISTIA na central e sumiu de lá (ver ramais.sumiu_da_central,
   TITULO_LINHA_SUMIDA em app.js), vermelho (mesma variável já usada pro
   selo "Verificar"/erro), mais forte que o lilás acima: dado desatualizado/
   possivelmente errado é mais urgente que "só não foi revisado ainda" (as
   duas classes nunca coexistem na mesma linha, ver classeEstadoAutomacao em
   app.js, mas a ordem aqui garante a prioridade de qualquer forma). ANTES de
   .linha-tocando/.linha-andamento pelo mesmo motivo do lilás: chamada em
   curso de verdade continua sendo o mais urgente de todos */
#corpo-ramais tr.linha-sumida { background: var(--vermelho-fundo); }

/* chamada em curso (AMI, ver chamada_estado), mesmo fundo cheio de linha já
   usado por .linha-destacada (navegação), aplicado aqui de forma persistente
   enquanto a ligação durar, não só um flash temporário */
#corpo-ramais tr.linha-tocando { background: #ffe6a8; }
:root[data-theme="dark"] #corpo-ramais tr.linha-tocando { background: #4a380c; }
#corpo-ramais tr.linha-andamento { background: var(--azul-fundo); }

/* Alerta (regra própria) que disparou (ramal crítico em Verificar, ver
   alertaDisparado em app.js): a linha pisca até o mesmo vermelho da
   .pendencia-alerta do Painel. O JS nem põe a classe com chamada em curso
   (.linha-tocando/.linha-andamento), porque animação passaria por cima do
   fundo delas. Duração = CICLO_PISCAR_ALERTA_MS (app.js) */
#corpo-ramais tr.linha-alerta,
#lista-pendencia-empresa tr.linha-alerta { animation: piscar-pendencia-alerta 1.6s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  #corpo-ramais tr.linha-alerta,
  #lista-pendencia-empresa tr.linha-alerta { animation: none; background: var(--vermelho-faixa); }
}

/* ramal com Estado=Inativo: linha inteira baixa de prioridade visual, sem
   negrito, cor mais fraca, itálico, pra não competir com ramal com problema
   de verdade (Offline/Verificar), que continua em destaque normal. Precisa
   de mais especificidade que as cores por status (.tempo-verificar,
   .selo-*, .tp-*) pra vencer aqui, por isso o `#corpo-ramais` na frente. */
#corpo-ramais tr.linha-inativa { font-style: italic; }
#corpo-ramais tr.linha-inativa td,
#corpo-ramais tr.linha-inativa .celula,
#corpo-ramais tr.linha-inativa .celula-select,
#corpo-ramais tr.linha-inativa .tempo-status {
  color: var(--suave);
  font-weight: 400;
}

/* ramal com "Ignorar sinalização" ligado (ver menu ⋮): texto riscado em toda
   a linha, sinal visível de que ele não conta em nenhuma estatística/alerta.
   A maioria das células é <input>/<select>, que não renderiza
   text-decoration de verdade em nenhum navegador, por isso o "traço" é
   desenhado por cima de cada célula via ::after, não com text-decoration */
#corpo-ramais tr.linha-ignorada td { position: relative; }
#corpo-ramais tr.linha-ignorada td::after {
  content: '';
  position: absolute;
  left: 6px;
  right: 6px;
  top: 50%;
  height: 1px;
  background: var(--suave);
  pointer-events: none;
}

/* linha destacada ao chegar da visão em Bloco (ver irParaRamalNaLista em
   app.js), fundo temporário que se apaga sozinho (a classe é removida via
   setTimeout, a transition só cuida do fade visual) */
#corpo-ramais tr.linha-destacada { background: var(--verde-fundo); transition: background 1.5s ease; }

/* alternador Bloco/Lista da tela de ramais, mesmo grid responsivo de
   .grade-clientes, cor cheia por Status (ao contrário dos selos da tabela,
   que só colorem o texto) */
.grade-ramais {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
  margin-bottom: 16px;
}
@media (max-width: 1050px) { .grade-ramais { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 780px)  { .grade-ramais { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px)  { .grade-ramais { grid-template-columns: 1fr; } }

/* "Ver ramais" da grade de unidades: TODOS os ramais do cliente, mesmo
   cartão de .grade-ramais, mas separados por cidade (.separador-grupo) e
   com mais colunas / cartão mais compacto (ver regras logo abaixo), cabe
   mais porque não tem os botões de Bloco/Lista/Filtros disputando espaço
   com a busca nessa tela, e clientes com muitos ramais (ex.: 400+) se
   beneficiam de ver mais de uma vez sem rolar tanto */
/* auto-fill/minmax em vez de contagem fixa por breakpoint: o número de
   colunas se ajusta sozinho à largura real disponível (nunca força um
   cartão a ficar mais estreito que seu conteúdo mínimo), o que evitou um
   estouro horizontal real medido em telas entre ~480px e 780px com a
   versão anterior de colunas fixas. O min(190px, 100%) é o ajuste seguinte:
   sem ele, com o container mais estreito que 190px (janela ≲463px, sobra
   pouco depois da barra lateral), a única coluna ainda insistia em ter
   190px e vazava, min() trava o mínimo em 100% do container nesse caso,
   então a coluna nunca fica maior que o espaço disponível */
.grade-ramais-cliente {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(190px, 100%), 1fr));
  gap: 10px;
  margin-bottom: 16px;
}

/* cartão mais compacto só nessa grade (a de .grade-ramais, usada na tela de
   Bloco/Lista de uma unidade só, continua do tamanho original) */
/* padding também descontado dos 2px da borda base (era 8px 10px), ver
   comentário em .cartao-ramal */
.grade-ramais-cliente .cartao-ramal { padding: 6px 8px; border-radius: 8px; }
/* fonte menor + sem quebra de linha (nome comprido corta com "…" em vez de
   empurrar o cartão pra 2-3 linhas, o que deixava a linha toda desalinhada) */
.grade-ramais-cliente .cartao-ramal .cr-linha1 {
  font-size: 12px;
  margin-bottom: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.grade-ramais-cliente .cartao-ramal .cr-linha2 { font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.grade-ramais-cliente .cr-verificar { top: 6px; right: 8px; font-size: 10px; }
.grade-ramais-cliente .cartao-ramal-verificar .cr-linha1 { padding-right: 56px; }

.cartao-ramal {
  position: relative;
  display: block;
  border-radius: 11px;
  /* a borda fica na BASE (transparente) e só troca de cor em
     .cartao-ramal-descoberto/.cartao-ramal-sumido, assim um cartão marcado
     tem exatamente o mesmo tamanho de um normal, sem "pular" na grade quando
     a automação liga/desliga a marca sozinha no ciclo de 5s. O padding já
     entra descontado dos 2px (era 14px 16px antes da borda existir), pra
     posição do texto continuar idêntica à de antes */
  border: 2px solid transparent;
  padding: 12px 14px;
  cursor: pointer;
  box-shadow: var(--sombra);
  transition: transform .12s, box-shadow .12s;
  /* cartão em #grade-ramais é um link tel: (ver cartaoRamal em app.js),
     tira o sublinhado/cor azul padrão de link; o cartão em
     #grade-ramais-cliente continua sendo <div>, essas duas regras não
     fazem diferença nele */
  text-decoration: none;
}
.cartao-ramal:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(0, 0, 0, .12); }
/* Alerta (regra própria) que disparou, em Blocos (ver alertaDisparado em
   app.js): o fundo do cartão já é a cor do status, então o pisca é um
   contorno vermelho em volta, por FORA (outline não ocupa espaço, o cartão
   não muda de tamanho nem empurra a grade, e não briga com a borda de
   .cartao-ramal-descoberto/.cartao-ramal-sumido). Cabe no gap de 14px da
   .grade-ramais. Duração = CICLO_PISCAR_ALERTA_MS (app.js) */
.cartao-ramal-alerta {
  outline: 3px solid transparent;
  outline-offset: 2px;
  animation: piscar-contorno-alerta 1.6s ease-in-out infinite;
}
@keyframes piscar-contorno-alerta {
  0%, 100% { outline-color: transparent; }
  50% { outline-color: var(--vermelho-neon); }
}
@media (prefers-reduced-motion: reduce) {
  .cartao-ramal-alerta { animation: none; outline-color: var(--vermelho-neon); }
}
.cartao-ramal .cr-linha1 { font-weight: 700; margin-bottom: 4px; }
.cartao-ramal .cr-linha2 { font-size: 13px; }
/* ícone de telefone no cartão (Online e Offline), ICONE_TELEFONE (app.js) é
   desenhado como contorno (fill="none", só stroke); só aqui ele é preenchido
   sólido, via CSS, em vez de duplicar o SVG com outro nome (os outros usos
   continuam contorno) */
.cr-icone { display: inline-block; vertical-align: -2px; margin-right: 5px; transform: scaleX(-1); }
.cr-icone svg { fill: currentColor; stroke: none; }
.cr-icone-online { color: var(--verde-escuro); }
/* no tema escuro o fundo do cartão Online fica um verde forte (ver
   .cartao-ramal-online mais abaixo), um verde bem vivo aqui (em vez de
   --verde-escuro, parecido demais com esse fundo) mantém o ícone visível
   sem precisar virar branco */
:root[data-theme="dark"] .cr-icone-online { color: #00e676; }
/* mesmo verde vivo acima, pro ícone de "conectado com a central" (wifi
   verde, ver avisoAutomacaoAmiHtml em app.js): --verde-escuro sozinho fica
   apagado demais no tema escuro, mesmo motivo do comentário acima */
:root[data-theme="dark"] .aviso-central-online { color: #00e676; }
/* Offline já tem texto branco no cartão (ver .cartao-ramal-offline mais
   abaixo), o ícone acompanha a mesma cor */
.cr-icone-offline { position: relative; color: #fff; }
/* risco diagonal por cima do ícone (estilo "desligado"), pseudo-elemento em
   vez de outro SVG, já que é só uma barra reta cruzando o ícone */
.cr-icone-offline::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 18px;
  height: 2px;
  background: currentColor;
  transform: translate(-50%, -50%) rotate(-45deg);
}
/* ícone de telefone durante ligação em andamento, azul (mesma cor do
   cartão) e balançando devagar sem parar, indicando "em uso" (diferente do
   chacoalhar-sino do "tocando", mais forte/rápido, aqui é sutil, contínuo).
   O keyframe repete o scaleX(-1) fixo do .cr-icone (linha acima) porque a
   animação substitui o transform inteiro, não soma a ele */
.cr-icone-andamento { color: var(--azul-texto); animation: balancar-telefone 1.2s ease-in-out infinite; }
@keyframes balancar-telefone {
  0%, 100% { transform: scaleX(-1) rotate(0deg); }
  25% { transform: scaleX(-1) rotate(-10deg); }
  75% { transform: scaleX(-1) rotate(10deg); }
}
/* ícone de power (Inativo) fica em contorno, não preenchido, diferente do
   telefone (Online/Offline), o círculo+traço não faz sentido sólido, então
   cancela o "fill: currentColor" herdado de .cr-icone svg */
.cr-icone-inativo { color: var(--suave); }
.cr-icone-inativo svg { fill: none; stroke: currentColor; }
/* selo "Verificar" no canto superior do cartão, some espaço na 1ª linha
   (número/usuário) pra não ficar por baixo dele */
.cr-verificar {
  position: absolute;
  top: 10px;
  right: 12px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 700;
  color: var(--vermelho-cartao);
}
.cartao-ramal-verificar .cr-linha1 { padding-right: 76px; }
/* verde mais suave que o --verde de marca (#2fac66), esse é vibrante demais
   pro cartão inteiro, funciona melhor num detalhe pequeno (botão, selo).
   Texto preto fixo (não var(--tinta), que viraria cinza-claro no tema escuro
   e perderia contraste nesse fundo, que também é fixo). No tema escuro esse
   verde claro fica apagado demais contra o fundo escuro ao redor, por isso
   a versão dark é mais forte (e troca pra texto branco, já que fundo mais
   escuro perde contraste com preto). */
.cartao-ramal-online { background: #c3e6cf; color: #000; }
:root[data-theme="dark"] .cartao-ramal-online { background: #2f8f5c; color: #fff; }
/* cinza mais claro que o #5c5c5c usado em outros lugares do app como cor de
   "Offline" (INFO_ITEM_STATUS.Offline em app.js, .caixa-status-offline),
   só aqui no cartão, pra equilibrar com o verde mais forte ao lado; fixo
   (não muda por tema) igual à convenção original */
.cartao-ramal-offline { background: #7a7a7a; color: #fff; }
.cartao-ramal-neutro  { background: var(--fundo-sutil); color: var(--suave); }
.cartao-ramal-inativo { background: var(--linha); color: var(--suave); font-style: italic; }
/* chamada em curso (AMI), tocando em amarelo/laranja, atendida (andamento)
   no azul de marca (mesma paleta de --azul-fundo/--azul-texto usada em botão
   "Acessar servidor" etc.). Fixo por tema, mesmo padrão de Online/Offline
   acima (não usa variável CSS, cor própria pra cada tema) */
.cartao-ramal-tocando { background: #ffe6a8; color: #000; animation: radiar-borda-tocando 1.5s ease-out infinite; }
:root[data-theme="dark"] .cartao-ramal-tocando { background: #6b4f10; color: #fff; }
/* cor própria (não var(--azul-fundo)/--azul-texto) pra poder ajustar a
   intensidade sem afetar outros usos dessa variável no resto do sistema,
   mais forte que o padrão no claro, mais fraco (apagado) no escuro.
   Borda "radia" igual o tocando (ver @keyframes abaixo), só mais devagar,
   tocando é mais urgente (precisa atender), andamento já foi atendida, só
   sinaliza "ainda em curso" */
.cartao-ramal-andamento { background: #bfe0f5; color: #0f5f8c; animation: radiar-borda-andamento 3s ease-out infinite; }
:root[data-theme="dark"] .cartao-ramal-andamento { background: #16303d; color: #7fb8d6; }
/* só a borda "radia" (anel de box-shadow expandindo e sumindo), sem
   escalar/mover o cartão inteiro, que já foi tentado e descartado */
@keyframes radiar-borda-tocando {
  0%   { box-shadow: 0 0 0 0 rgba(212, 160, 23, .55); }
  100% { box-shadow: 0 0 0 12px rgba(212, 160, 23, 0); }
}
/* mesma ideia acima, cor azul (--azul, #36a9e1, mesmo azul de marca usado no
   resto do sistema pra "isso é coisa de chamada/PABX") em vez do dourado */
@keyframes radiar-borda-andamento {
  0%   { box-shadow: 0 0 0 0 rgba(54, 169, 225, .55); }
  100% { box-shadow: 0 0 0 12px rgba(54, 169, 225, 0); }
}
/* equivalentes, na visão em Blocos, dos fundos lilás/vermelho que a visão em
   Lista usa na linha inteira (#corpo-ramais tr.linha-descoberta/.linha-sumida).
   Aqui vira BORDA e não fundo porque o fundo do cartão já significa outra
   coisa, o status (ver .cartao-ramal-online/-offline/-tocando/-andamento/
   -inativo): pintar o cartão de vermelho apagaria a informação de status, que
   é o motivo de a visão existir. Mesma prioridade da Lista (sumido depois de
   descoberto: se as duas valessem, sumido vence, ver classeAutomacaoCartao
   em app.js, que já garante que nunca coexistem) */
.cartao-ramal-descoberto { border-color: var(--lilas-cartao); }
.cartao-ramal-sumido { border-color: var(--vermelho-cartao); }

/* ramal com "Ignorar sinalização" ligado, aqui o texto é <div> normal (não
   input), então text-decoration funciona direto, ao contrário da tabela */
.cartao-ramal-ignorado .cr-linha1,
.cartao-ramal-ignorado .cr-linha2 { text-decoration: line-through; }

.chk-lembrar-modo { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; color: var(--suave); cursor: pointer; }

.barra-transferencia { display: flex; align-items: center; gap: 10px; margin-left: auto; font-size: 13px; color: var(--suave); }
.celula-selecao { text-align: center; width: 34px; }
.celula-selecao input[type="checkbox"] { width: 16px; height: 16px; cursor: pointer; }

.celula-select { font-weight: 700; font-size: 12px; cursor: pointer; appearance: none; }
.celula-select.selo-ativo { color: var(--verde-escuro); }
.celula-select.selo-inativo { color: var(--suave); }
.celula-select.selo-offline { color: var(--tinta); background: var(--fundo-sutil); }
.celula-select.selo-verificar { color: var(--vermelho); background: var(--vermelho-fundo); }
.celula-select.selo-verificar:hover { border-color: var(--vermelho); }
/* Status vazio (ramal com Estado=Inativo, ver statusParaSalvar em server.js):
   sem cor de badge nenhuma, só o mesmo cinza apagado de um campo sem valor */
.celula-select.selo-neutro { color: var(--suave); }
/* Físico era var(--azul-texto), mesmo azul de .celula-travada (campo
   travado pela sincronização), o que confundia "esse ramal é Físico" com
   "esse campo está bloqueado" agora que Estado também ficou azul quando
   travado (2026-08-19). Sem cor própria (herda o padrão da célula) */
.celula-select.tp-fisico { color: var(--tinta); }
.celula-select.tp-softphone { color: var(--tinta); }

/* célula travada pela sincronização automática via PABX (ver
   ramalTravadoPelaCentral em app.js/painel-cliente.js): campo TEM dono (a
   central telefônica), diferente de "sem permissão" (que usa input:disabled,
   cinza apagado, ver embaixo), por isso o texto no mesmo azul já usado pra
   sinalizar "isso é coisa do PABX" noutro lugar da tela (chamada em
   andamento, --azul-texto), não o cinza neutro de "desligado". SEM fundo
   azul de propósito (2026-08-12, removido a pedido do usuário, achou que
   não ficou bom visualmente; ficou só cor do texto + cursor bloqueado +
   tooltip explicando o motivo).
   DE PROPÓSITO depois dos seletores "celula-select" com "selo" e "tp" acima
   (2026-08-12, bug real corrigido: o <select> de Status trava junto agora,
   ver statusTravadoAttrs em app.js, como ele também carrega uma classe
   selo-online/selo-offline/etc pra colorir o status, e essa regra tem a
   MESMA especificidade de duas classes que .celula-travada:disabled, quem
   vem depois no arquivo ganhava o empate; antes disso não importava porque
   só .celula/.celula-num, sem selo-*, usavam esta classe) */
/* :disabled entra também porque quem não tem permissão de editar ("Status"
   só) recebe as duas condições juntas (disabled + travada), sem isso,
   `input:disabled` (mais específico, ver abaixo) venceria e devolveria o
   cinza genérico, escondendo que o motivo real deste campo é outro */
.celula-travada,
.celula-travada:hover,
.celula-travada:focus,
.celula-travada:disabled {
  color: var(--azul-texto);
  border-color: transparent;
  box-shadow: none;
  cursor: not-allowed;
  opacity: 1;
}
/* exceção: o <select> de Status travado NÃO usa o azul genérico acima pro
   texto, mantém a cor de verdade do status (verde Online/cinza Offline/
   vermelho Verificar), achado real do usuário (2026-08-12): com o azul
   uniforme, Online e Offline ficavam quase indistinguíveis (só a diferença
   sutil do fundo do selo restava), perdendo a informação mais importante
   daquele campo específico. Cursor bloqueado + tooltip já avisam "isso é
   travado", não precisa também apagar a cor do status pra isso. Mesma
   especificidade de duas classes que .celula-travada:disabled acima, então
   precisa vir DEPOIS pra ganhar o empate nos elementos que têm as duas */
.celula-travada.selo-ativo { color: var(--verde-escuro); }
.celula-travada.selo-offline { color: var(--tinta); }
.celula-travada.selo-verificar { color: var(--vermelho); }
.celula-travada.selo-neutro { color: var(--suave); }

.selo {
  font-size: 11px;
  font-weight: 700;
  padding: 3px 9px;
  border-radius: 20px;
  white-space: nowrap;
}
.selo-ativo { background: var(--verde-fundo); color: var(--verde-escuro); }
.selo-inativo { background: var(--linha); color: var(--suave); }
.selo-offline { background: var(--fundo-sutil); color: var(--tinta); }
.selo-verificar { background: var(--vermelho-fundo); color: var(--vermelho); }
.selo-neutro { background: transparent; color: var(--suave); }
.selo-fisico { background: var(--azul-fundo); color: var(--azul-texto); }
.selo-softphone { background: var(--linha); color: var(--tinta); }

/* interruptor (switch), mesmo checkbox de sempre por baixo (mantém teclado,
   foco e o listener de "change" já existente), só a aparência muda */
.interruptor { position: relative; display: inline-block; width: 38px; height: 21px; vertical-align: middle; }
.interruptor input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.interruptor-trilho {
  position: absolute; inset: 0; border-radius: 21px;
  background: var(--linha); transition: background .15s;
}
.interruptor-trilho::before {
  content: ""; position: absolute; width: 15px; height: 15px; left: 3px; top: 3px;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0, 0, 0, .3);
  transition: transform .15s;
}
.interruptor input:checked + .interruptor-trilho { background: var(--verde); }
.interruptor input:checked + .interruptor-trilho::before { transform: translateX(17px); }
.interruptor input:focus-visible + .interruptor-trilho { box-shadow: 0 0 0 3px rgba(47, 172, 102, .3); }

.vazio { padding: 44px 20px; text-align: center; color: var(--suave); }
/* container do lottie de estado vazio, reaproveitado em mais de uma tela
   (lista de ramais de um cliente, aba Pendentes/Concluídas de Solicitações) */
.lottie-vazio { width: 160px; height: 160px; margin: 0 auto 8px; }
/* espaço entre a tabela de ramais (cabeçalho RAMAL/SETOR/USUÁRIO...) e esta
   mensagem quando a lista está vazia (sem isso as duas caixas ficam
   grudadas, sem separação visual) */
#vazio-ramais { margin-top: 16px; }

/* ---------- modal ---------- */
.fundo-modal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
  padding: 20px;
}

.modal {
  background: var(--branco);
  border-radius: 13px;
  padding: 24px;
  width: 100%;
  max-width: 440px;
  max-height: 90vh;
  box-shadow: 0 20px 50px rgba(0, 0, 0, .25);
  display: flex;
  flex-direction: column;
}
.modal h2 { font-size: 18px; margin-bottom: 18px; flex: 0 0 auto; }
#modal-form { overflow-y: auto; flex: 1 1 auto; padding-right: 6px; margin-right: -6px; }
.modal-rodape { flex: 0 0 auto; }

/* ---------- botão flutuante (Exportar CSV) ---------- */
.btn-flutuante {
  position: fixed;
  right: 24px;
  bottom: 24px;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  border: none;
  background: var(--verde);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .25);
  transition: transform .12s, box-shadow .12s;
  z-index: 40;
}
.btn-flutuante svg { width: 22px; height: 22px; }

/* ---------- atendimento flutuante (painel do cliente) ---------- */
/* mesmo canto/z-index do .btn-flutuante acima (nunca aparecem juntos na
   mesma tela, este é só do painel-cliente.html, aquele só do index.html).
   O círculo verde (ícone de conversa) abre um menu com duas opções
   empilhadas acima dele (zeze = assistente virtual, ícone do WhatsApp =
   WhatsApp da equipe). O wrapper fica
   em right/bottom 21px com a área do botão FIXA em 66px (o tamanho do
   hover): o círculo de 60px parado continua a 24px do canto, como antes, e
   crescer no hover não empurra o menu aberto pra cima */
.atendimento-flutuante {
  position: fixed;
  right: 21px;
  bottom: 21px;
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
}
.atendimento-botao {
  width: 66px;
  height: 66px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* .ativo (menu OU conversa abertos, ver painel-cliente.js) troca o balão de
   conversa pelo X e segura o círculo no tamanho do hover */
.atendimento-botao-miolo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: var(--verde);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .25);
  transition: width .15s ease, height .15s ease, background .15s ease;
}
.atendimento-botao:hover .atendimento-botao-miolo,
.atendimento-botao.ativo .atendimento-botao-miolo { width: 66px; height: 66px; background: var(--verde-escuro); }
.atendimento-icone-fechar,
.atendimento-botao.ativo .atendimento-icone-conversa { display: none; }
.atendimento-botao.ativo .atendimento-icone-fechar { display: block; }
.atendimento-botao:focus-visible { outline: none; }
.atendimento-botao:focus-visible .atendimento-botao-miolo { box-shadow: 0 0 0 3px var(--azul), 0 6px 20px rgba(0, 0, 0, .25); }
/* o zeze (opção do menu e topo da conversa) vem de zeze-wink.json, que usa 3
   imagens PNG embutidas (não é vetor puro como sol/lua): QUALQUER
   transform:scale (não importa em qual elemento da árvore) faz o navegador
   esticar a imagem já renderizada como textura, borrando (achado real do
   usuário). Por isso o menu abaixo entra com translateY, nunca scale */
.atendimento-lottie { display: block; width: 100%; height: 100%; }

/* menu fechado = visibility:hidden (além do opacity), assim as opções saem
   também da ordem do Tab e do leitor de tela, sem precisar mexer em tabindex
   pelo JS. margin-right centraliza os avatares de 48px em cima do círculo */
.atendimento-opcoes {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
  margin-right: 9px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity .15s ease, transform .15s ease, visibility 0s linear .15s;
}
.atendimento-opcoes.aberto {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity .15s ease, transform .15s ease, visibility 0s;
}
.atendimento-opcao {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}
.atendimento-opcao-rotulo {
  background: var(--branco);
  color: var(--tinta);
  border: 1px solid var(--linha);
  border-radius: 999px;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  box-shadow: var(--sombra);
  transition: border-color .15s ease;
}
.atendimento-opcao:hover .atendimento-opcao-rotulo,
.atendimento-opcao:focus-visible .atendimento-opcao-rotulo { border-color: var(--verde); }
.atendimento-opcao:focus-visible { outline: none; }
.atendimento-opcao-avatar {
  display: block;
  width: 48px;
  height: 48px;
  flex: 0 0 auto;
  border-radius: 50%;
  overflow: hidden;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .22);
}
/* verde oficial do WhatsApp (só aqui; o resto do sistema usa --verde da ZZ) */
.atendimento-avatar-whats { display: flex; align-items: center; justify-content: center; background: #25d366; }

/* caixa de conversa do assistente: abre logo acima do círculo (24px do canto
   + 66px do botão + folga), no mesmo alinhamento à direita */
.assistente-caixa {
  position: fixed;
  right: 24px;
  bottom: 100px;
  z-index: 41;
  width: 360px;
  max-width: calc(100vw - 32px);
  height: 480px;
  max-height: calc(100vh - 124px);
  display: flex;
  flex-direction: column;
  background: var(--branco);
  border: 1px solid var(--linha);
  border-radius: 16px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .22);
  overflow: hidden;
}
@media (max-width: 480px) {
  .assistente-caixa { right: 16px; left: 16px; width: auto; max-width: none; }
}
.assistente-topo {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 12px 12px 14px;
  background: var(--azul);
  color: #fff;
}
.assistente-topo-avatar {
  width: 38px;
  height: 38px;
  flex: 0 0 auto;
  border-radius: 50%;
  overflow: hidden;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .7);
}
.assistente-topo-textos { flex: 1 1 auto; display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.assistente-topo-textos strong { font-size: 15px; }
.assistente-topo-textos span { font-size: 12px; opacity: .85; }
.assistente-fechar {
  width: 32px;
  height: 32px;
  flex: 0 0 auto;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.assistente-fechar:hover, .assistente-fechar:focus-visible { background: rgba(255, 255, 255, .2); outline: none; }
.assistente-mensagens {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--fundo-sutil);
}
/* pre-wrap + overflow-wrap pelo mesmo motivo do .chat-msg-texto da equipe:
   texto livre, quebra de linha do usuário vale e palavra gigante/URL colada
   quebra em vez de criar rolagem horizontal */
.assistente-msg {
  max-width: 82%;
  align-self: flex-start;
  padding: 8px 12px;
  border-radius: 12px;
  border: 1px solid var(--linha);
  background: var(--branco);
  color: var(--tinta);
  font-size: 14px;
  line-height: 1.45;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.assistente-msg.propria { align-self: flex-end; background: var(--verde-fundo); border-color: var(--verde); }
.assistente-msg-link {
  display: inline-block;
  margin-top: 8px;
  padding: 6px 12px;
  font-size: 13px;
}
.assistente-digitando { display: flex; gap: 4px; padding: 12px 14px; }
.assistente-digitando span {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--suave);
  animation: assistente-pontinho 1s ease-in-out infinite;
}
.assistente-digitando span:nth-child(2) { animation-delay: .15s; }
.assistente-digitando span:nth-child(3) { animation-delay: .3s; }
@keyframes assistente-pontinho {
  0%, 60%, 100% { opacity: .3; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-3px); }
}
.assistente-envio {
  display: flex;
  gap: 8px;
  padding: 10px;
  border-top: 1px solid var(--linha);
  align-items: flex-end;
}
.assistente-envio textarea {
  flex: 1;
  resize: none;
  max-height: 100px;
  font: inherit;
  line-height: 1.45;
  overflow-y: hidden;
}
.assistente-envio textarea.rolando { overflow-y: auto; }
.assistente-enviar { display: flex; align-items: center; justify-content: center; padding: 9px 12px; }
.btn-flutuante:hover { transform: translateY(-2px); box-shadow: 0 10px 26px rgba(0, 0, 0, .3); }

/* ---------- modal de exportar CSV ---------- */
.exportar-colunas { display: flex; flex-direction: column; gap: 10px; margin-bottom: 4px; }
.exportar-unidades { margin-top: 14px; border-top: 1px solid var(--linha); padding-top: 14px; }
.exportar-unidades-estado { margin-bottom: 10px; }
.exportar-unidades-estado h4 { font-size: 12px; text-transform: uppercase; letter-spacing: .4px; color: var(--suave); margin-bottom: 6px; }
.exportar-unidades-lista { display: flex; flex-direction: column; gap: 6px; }
.exportar-campo-check { display: flex; align-items: center; gap: 8px; font-size: 14px; }

/* ---------- segmentado (controle de opções lado a lado, ver .timeline-topo
   acima: botões 7/15/30 dias do Histórico do ramal) ---------- */
.segmentado {
  display: inline-flex;
  background: var(--linha);
  border-radius: 9px;
  padding: 3px;
  gap: 2px;
  margin-bottom: 14px;
}
.segmentado button {
  border: 0;
  background: none;
  padding: 8px 16px;
  border-radius: 7px;
  font: inherit;
  font-weight: 600;
  color: var(--suave);
  cursor: pointer;
}
.segmentado button:hover { color: var(--tinta); }
.segmentado button.ativo {
  background: var(--branco);
  color: var(--tinta);
  box-shadow: var(--sombra);
}
.tema-explicacao { margin-top: 12px; font-size: 12px; color: var(--suave); }

/* ---------- mapa do Brasil (2ª forma de ver as unidades, mapa-brasil.js) ---------- */
.mapa-brasil-legenda { color: var(--suave); font-size: 13px; margin-bottom: 12px; }

.mapa-brasil-layout {
  display: flex;
  gap: 28px;
  align-items: flex-start;
  flex-wrap: wrap;
}

.mapa-brasil-container { flex: 1 1 320px; max-width: 460px; position: relative; }
.mapa-brasil-svg { display: block; width: 100%; height: auto; }
.mapa-brasil-envolucro { position: relative; }

/* tooltip ao passar o mouse num estado com unidade (ver criarMapaBrasil em
   mapa-brasil.js) */
.mapa-brasil-tooltip {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  background: var(--branco);
  color: var(--tinta);
  padding: 6px 10px;
  border-radius: 8px;
  box-shadow: var(--sombra);
  font-size: 12px;
  line-height: 1.5;
  white-space: nowrap;
  z-index: 5;
}

/* estado sem unidade: neutro e sem interação. Com unidade: colorido e
   clicável. Selecionado: mesmo tom mais escuro do hover, pra indicar qual
   está aberto no painel de cidades ao lado, sem contorno adicional.
   Traço preto e fixo (sem transição) separando as peças em TODOS os mapas
   (combinado, Brasil dedicado, Paraguai dedicado), só o fill anima. */
.mapa-brasil-estado { fill: var(--linha); stroke: #000; stroke-width: 0.5; transition: fill .12s; }
.mapa-brasil-estado.tem-unidade { fill: var(--verde); cursor: pointer; }
.mapa-brasil-estado.tem-unidade:hover { fill: var(--verde-escuro); }
/* o quadrado preto que aparece ao clicar é o foco padrão do navegador em SVG
   com tabindex, some no clique (:focus none) e só volta pra quem navega
   pelo teclado (:focus-visible), que é o caso que esse contorno deveria servir */
.mapa-brasil-estado.tem-unidade:focus { outline: none; }
.mapa-brasil-estado.tem-unidade:focus-visible { outline: 2px solid var(--azul-texto, #36a9e1); outline-offset: 1px; }
.mapa-brasil-estado.selecionado { fill: var(--verde-escuro); }

/* Paraguai, mesmo comportamento dos estados brasileiros, só que em vermelho
   no mesmo tom do verde (mesma saturação/luminosidade, só o matiz muda), pra
   deixar claro visualmente que é outro país, não mais um estado do Brasil */
.mapa-brasil-estado.mapa-brasil-paraguai.tem-unidade { fill: var(--vermelho-mapa); }
.mapa-brasil-estado.mapa-brasil-paraguai.tem-unidade:hover { fill: var(--vermelho-mapa-escuro); }
.mapa-brasil-estado.mapa-brasil-paraguai.selecionado { fill: var(--vermelho-mapa-escuro); }

/* mapa combinado (nível país, dentro de Visualizar Mapa): Brasil também vira
   vários <path> aqui (um por estado), mas o clique é do país inteiro. O traço
   preto já vem da regra base (.mapa-brasil-estado) acima, falta só destacar
   o país inteiro no hover, já que cada estado é um <path> separado e o
   `:hover` nativo do navegador não enxerga os "irmãos". `.pais-hover` é
   aplicada via JS a TODOS os pedaços do mesmo país ao passar o mouse em
   qualquer um deles (ver criarMapaPaises em mapa-brasil.js). */
.mapa-paises-combinado .mapa-brasil-estado.tem-unidade.pais-hover { fill: var(--verde-escuro); }
.mapa-paises-combinado .mapa-brasil-estado.mapa-brasil-paraguai.tem-unidade.pais-hover { fill: var(--vermelho-mapa-escuro); }

.mapa-brasil-painel-cidades { flex: 1 1 260px; min-width: 240px; }
/* só o título do estado (filho direto), os cartões de cidade logo abaixo
   têm seu próprio <h3> menor (ver .cartao-cidade-mapa h3) */
.mapa-brasil-painel-cidades > h3 { margin: 0 0 12px; font-size: 16px; }

/* mesmo visual dos cartões da Grade (.cartao-cliente/.cartao-unidade-lista),
   só que menor, precisa caber no painel ao lado do mapa sem alterar o
   tamanho do mapa em si */
.mapa-cidades-grade {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 10px;
  margin-bottom: 16px;
}
.cartao-cidade-mapa { padding: 10px 12px; min-height: 56px; border-radius: 9px; }
.cartao-cidade-mapa .icone-agenda-fundo { width: 52px; height: 52px; right: -8px; bottom: -10px; }
.cartao-cidade-mapa .icone-agenda-fundo-logo { width: 40px; height: 40px; right: 4px; bottom: 4px; }
.cartao-cidade-mapa h3 { font-size: 13px; margin: 0; }
.cartao-cidade-mapa .telefone { font-size: 11px; }
.cartao-cidade-mapa.ativa { box-shadow: 0 0 0 2px var(--verde); }

.mapa-brasil-cartoes-cidade {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
}
/* mesmo destaque da cidade, marca qual unidade (dentre as da cidade aberta)
   foi a última clicada, pra saber onde estava ao voltar da lista de ramais */
.mapa-brasil-cartoes-cidade .cartao-unidade-lista.ativa { box-shadow: 0 0 0 2px var(--verde); }

/* cabeçalho de seção dentro de um modal (ver tipo:'secao' em abrirModal),
   só separa visualmente grupos de campos relacionados (ex.: "Cliente",
   "Sincronização automática via PABX"), sem ser um campo de verdade */
.modal-secao {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 20px 0 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--linha);
  color: var(--tinta);
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.modal-secao:first-child { margin-top: 0; }
.modal-secao svg { flex-shrink: 0; }

.campo { margin-bottom: 14px; }
.campo label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  color: var(--suave);
  margin-bottom: 5px;
}
.campo input, .campo select, .campo textarea { width: 100%; }
.campo textarea { resize: vertical; min-height: 60px; }

/* botão "+" ao lado de um select (ex.: País/Estado da unidade), pra
   adicionar um valor novo que ainda não está na lista */
.linha-select-add { display: flex; gap: 8px; align-items: stretch; }
.linha-select-add select { flex: 1; width: auto; }
.btn-add-localidade {
  flex-shrink: 0;
  padding: 0 14px;
  border-radius: 7px;
  border: 1px solid var(--linha);
  background: var(--fundo-sutil);
  color: var(--tinta);
  font-size: 18px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}
.btn-add-localidade:hover { background: var(--linha-hover); }
.btn-add-localidade:disabled { opacity: .35; cursor: default; background: var(--fundo-sutil); }

.add-localidade-form { display: flex; gap: 8px; margin-top: 8px; }
.add-localidade-form input { flex: 1; width: auto; }

/* ---------- campo de senha: input + olho de mostrar/ocultar ---------- */
.campo-senha { position: relative; }
.campo-senha input { padding-right: 40px; }
.btn-olho {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  border: 0;
  background: none;
  color: var(--suave);
  padding: 6px;
  border-radius: 6px;
  cursor: pointer;
  display: flex;
}
.btn-olho:hover { color: var(--tinta); background: var(--linha); }

/* ---------- medidor de força de senha ---------- */
.medidor-senha { margin-top: 10px; display: flex; align-items: center; gap: 8px; }
.medidor-barra { flex: 1; height: 6px; background: var(--linha); border-radius: 3px; overflow: hidden; }
.medidor-preenchido { height: 100%; border-radius: 3px; transition: width .2s, background .2s; }
.medidor-texto { font-size: 11px; font-weight: 700; white-space: nowrap; }
.forca-fraca .medidor-preenchido { width: 33%; background: var(--vermelho); }
.forca-fraca .medidor-texto { color: var(--vermelho); }
.forca-media .medidor-preenchido { width: 66%; background: #b8860b; }
.forca-media .medidor-texto { color: #b8860b; }
.forca-forte .medidor-preenchido { width: 100%; background: var(--verde); }
.forca-forte .medidor-texto { color: var(--verde-escuro); }

/* ---------- checklist de critérios da senha ---------- */
.checklist-senha { list-style: none; margin-top: 10px; display: flex; flex-direction: column; gap: 5px; }
.checklist-senha li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--suave);
  transition: color .15s;
}
.checklist-senha li.regra-ok { color: var(--verde-escuro); font-weight: 600; }
.checklist-senha .check {
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
  border: 1.5px solid var(--linha);
  border-radius: 4px;
  position: relative;
  transition: background .15s, border-color .15s;
}
.checklist-senha li.regra-ok .check { background: var(--verde); border-color: var(--verde); }
.checklist-senha li.regra-ok .check::after {
  content: '';
  position: absolute;
  left: 4px;
  top: 1px;
  width: 3px;
  height: 7px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

/* ---------- logo do cliente (card, cabeçalho e modal de edição) ---------- */
.logo-cliente {
  flex: 0 0 auto;
  border-radius: 8px;
  background: #fff;
  object-fit: contain;
  padding: 3px;
}
.logo-cliente-vazia {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .5px;
  color: var(--linha-hover);
  background: var(--fundo-sutil);
  border: 1px solid var(--linha);
}

.campo-imagem { display: flex; align-items: center; gap: 12px; }
.imagem-preview img.logo-cliente,
.imagem-preview img { width: 48px; height: 48px; border-radius: 8px; background: #fff; object-fit: contain; padding: 3px; }

/* círculo de cor de fundo da logo (modal de editar cliente), encostado na
   ponta direita da linha. É o <input type="color"> nativo, só arredondado: o
   seletor do próprio navegador já traz conta-gotas pra pegar cor da tela.
   O seletor precisa das DUAS classes (.campo-imagem .swatch-cor-fundo): com
   uma só, ele perde para ".campo input { width: 100% }" (mais específico) lá
   em cima, e o círculo vira uma elipse esticada na largura toda da linha */
.campo-imagem .cor-fundo-controles {
  margin-left: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
.campo-imagem .btn-remover-cor {
  padding: 0;
  border: none;
  background: none;
  color: var(--suave);
  font-size: 10px;
  text-decoration: underline;
  cursor: pointer;
  white-space: nowrap;
}
.campo-imagem .btn-remover-cor:hover { color: #e53935; }
.campo-imagem .btn-remover-cor[hidden] { display: none; }
.campo-imagem .swatch-cor-fundo {
  flex: 0 0 30px;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 2px solid var(--linha);
  border-radius: 50%;
  background: none;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}
.campo-imagem .swatch-cor-fundo:hover { border-color: var(--azul); }
.campo-imagem .swatch-cor-fundo::-webkit-color-swatch-wrapper { padding: 0; }
.campo-imagem .swatch-cor-fundo::-webkit-color-swatch { border: none; border-radius: 50%; }
.campo-imagem .swatch-cor-fundo::-moz-color-swatch { border: none; border-radius: 50%; }
/* nenhuma cor salva ainda (hidden vazio): X vermelho por cima do branco. Vai
   no próprio swatch como background-image porque <input> não aceita
   ::before/::after; a imagem pinta por cima da cor que o navegador põe ali */
/* branco forçado: sem cor, o valor do campo é o cinza de partida do seletor
   (COR_INICIAL_SEM_FUNDO em app.js), mas o círculo continua com a cara de
   sempre (branco + X). Uma regra por navegador: juntas na mesma lista, o
   seletor desconhecido (-moz no Chrome, -webkit no Firefox) invalida a regra
   inteira */
.campo-imagem .swatch-cor-fundo.sem-cor::-webkit-color-swatch { background-color: #fff !important; }
.campo-imagem .swatch-cor-fundo.sem-cor::-moz-color-swatch { background-color: #fff !important; }
.campo-imagem .swatch-cor-fundo.sem-cor::-webkit-color-swatch {
  background-image:
    linear-gradient(45deg, transparent calc(50% - 0.5px), #e53935 calc(50% - 0.5px), #e53935 calc(50% + 0.5px), transparent calc(50% + 0.5px)),
    linear-gradient(-45deg, transparent calc(50% - 0.5px), #e53935 calc(50% - 0.5px), #e53935 calc(50% + 0.5px), transparent calc(50% + 0.5px));
}
.campo-imagem .swatch-cor-fundo.sem-cor::-moz-color-swatch {
  background-image:
    linear-gradient(45deg, transparent calc(50% - 0.5px), #e53935 calc(50% - 0.5px), #e53935 calc(50% + 0.5px), transparent calc(50% + 0.5px)),
    linear-gradient(-45deg, transparent calc(50% - 0.5px), #e53935 calc(50% - 0.5px), #e53935 calc(50% + 0.5px), transparent calc(50% + 0.5px));
}
.imagem-controles { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; min-width: 0; flex: 1; }
/* botão nosso + nome do arquivo salvo, no lugar do texto nativo do
   <input type=file> (ver campo 'imagem' em app.js). min-width: 0 em toda a
   cadeia é o que deixa o nome longo cortar com "..." em vez de empurrar o
   círculo de cor pra fora do modal */
.imagem-arquivo { display: flex; align-items: center; gap: 8px; min-width: 0; max-width: 100%; }
.imagem-arquivo .btn-mini { flex-shrink: 0; }
.imagem-arquivo-nome { font-size: 12px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.campo-imagem input[type="file"][hidden] { display: none; }
.dica-campo { font-size: 11px; color: var(--suave); margin-top: 6px; }

/* painel do cliente: pedido de troca de nome (ver blocoSolicitarNome em
   painel-cliente.js), só aparece quando o campo Usuário está travado pela
   central. Azul (mesma família de --azul-fundo/--azul-texto, "isso é sobre
   PABX/central") pra não competir visualmente com o vermelho de erro nem o
   verde de sucesso do resto da tela */
.solicitar-nome { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--linha); }
.solicitar-nome label { display: block; font-size: 12px; font-weight: 600; margin-bottom: 6px; }
.solicitar-nome-linha { display: flex; gap: 8px; }
.solicitar-nome-linha input { flex: 1; min-width: 0; }
/* contador "x/limite" dos campos de solicitação de troca de nome (nome
   desejado e mensagem opcional), mesmo texto discreto do resto do sistema */
.contador-caracteres { display: block; text-align: right; font-size: 11px; color: var(--tinta); opacity: 0.55; margin-top: 3px; }
.solicitacao-nome-pendente {
  margin-top: 10px;
  padding: 8px 10px;
  border-radius: 6px;
  background: var(--azul-fundo);
  color: var(--azul-texto);
  font-size: 12px;
}
/* mensagem opcional em cima do pedido de nome (destaque diferente do texto
   ao redor, "isso é o que o cliente escreveu", não parte do aviso fixo) */
.solicitacao-nome-mensagem { font-style: italic; }

/* "+ Adicionar mensagem" (ver blocoSolicitarNome), botão tipo link, sem
   caixa, pra não competir visualmente com "Enviar solicitação" (o botão de
   verdade da ação) */
.btn-adicionar-mensagem {
  display: block;
  margin-top: 8px;
  border: 0;
  background: none;
  padding: 0;
  color: var(--azul-texto);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.btn-adicionar-mensagem:hover { text-decoration: underline; }
#campo-mensagem-solicitacao { display: block; width: 100%; margin-top: 8px; min-height: 60px; resize: vertical; box-sizing: border-box; }

.campo-permissoes { display: flex; flex-direction: column; gap: 14px; }
.aviso-permissoes-automacao {
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--fundo-sutil);
  border: 1px solid var(--linha);
  border-left: 3px solid var(--vermelho);
  font-size: 12px;
  line-height: 1.5;
  color: var(--suave);
}
.permissao-secao h4 { margin: 0 0 8px; font-size: 13px; color: var(--suave); }
.permissao-acoes { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }
.campo-permissoes .permissao-item { display: flex; align-items: center; gap: 6px; font-weight: 400; cursor: pointer; margin-bottom: 0; }
.permissao-separador { width: 1px; height: 14px; background: var(--linha); }
.campo-permissoes .permissao-todos { font-weight: 600; }

.modal-rodape {
  display: flex;
  justify-content: flex-end;
  gap: 9px;
  margin-top: 20px;
}

/* ---------- aviso ---------- */
.aviso {
  position: fixed;
  bottom: 22px;
  left: 50%;
  transform: translateX(-50%);
  /* sempre escuro com texto claro, nos dois temas, por isso não usa var(--tinta),
     que se inverte no escuro (viraria claro, e o texto branco sumiria em cima) */
  background: #1a1a1a;
  color: #fff;
  padding: 11px 20px;
  border-radius: 8px;
  font-weight: 500;
  z-index: 100;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .22);
}
.aviso.erro { background: var(--vermelho); }

/* ---------- lista de ramais (folha estilo planilha, pra futura visão do cliente) ---------- */
.folha-ramais {
  position: relative;
  background: var(--branco);
  border-radius: 11px;
  box-shadow: var(--sombra);
  overflow: hidden;
  max-width: 720px;
  margin: 0 auto;
}

/* contador de presença (quem está vendo esta lista agora), no sistema
   interno (index.html) vive junto do próprio botão "Lista de Ramais" na
   barra lateral; no link público do cliente (cliente.html) vive no topo,
   ao lado do botão de tema (ver .acoes-topo .contador-presenca-nav abaixo) */
.contador-presenca-nav {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 700;
  background: var(--lateral-pilula);
  border-radius: 20px;
  padding: 2px 8px;
}
.acoes-topo .contador-presenca-nav {
  height: 34px;
  font-size: 12px;
  color: #fff;
  background: rgba(0, 0, 0, .2);
  border: 1px solid rgba(255, 255, 255, .2);
  padding: 0 10px;
}
.folha-cabecalho {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 28px 20px 22px;
  text-align: center;
}
.folha-cabecalho h1 { font-size: 22px; }
.folha-cabecalho .cc-plat { display: block; font-weight: 600; }

/* quando o cliente tem capa cadastrada, ela substitui nome+logo e ocupa
   todo o espaço do cabeçalho (banner de ponta a ponta, sem o padding do modo
   padrão), object-fit:contain mostra a imagem inteira, centralizada, sem
   cortar/dar zoom nela (a maioria das capas é mais uma logomarca larga do
   que uma foto panorâmica). As bordas arredondadas vêm do overflow:hidden
   do .folha-ramais, que já recorta o fundo. */
.folha-cabecalho-capa { padding: 0; background: var(--branco); }
.folha-capa { display: block; width: 100%; height: 170px; object-fit: contain; background: var(--branco); }
.folha-local {
  background: var(--azul);
  color: #fff;
  text-align: center;
  font-weight: 700;
  letter-spacing: .4px;
  padding: 11px;
  text-transform: uppercase;
}
.folha-telefone {
  background: var(--azul-fundo);
  color: var(--azul-texto);
  text-align: center;
  font-weight: 600;
  padding: 9px;
}
.folha-tabela { width: 100%; border-collapse: collapse; }
.folha-tabela th {
  background: var(--azul);
  color: #fff;
  text-transform: uppercase;
  font-size: 12px;
  letter-spacing: .4px;
  padding: 11px 16px;
  text-align: left;
}
.folha-tabela td { padding: 10px 16px; border-bottom: 1px solid var(--linha); }
.folha-tabela tr:last-child td { border-bottom: 0; }

/* ramal com pedido de troca de nome ainda em aberto (ver desenharFolha em
   painel-cliente.js): linha em azul e um relógio ao lado do nome, pra dar pra
   ver na lista o que já foi pedido e está na mão da equipe ZZ. Mesmo par de
   cores da caixa .solicitacao-nome-pendente do modal, que já tem os dois
   temas resolvidos */
.folha-tabela tr.folha-linha-pendente td { background: var(--azul-fundo); }
.marca-pendente { display: inline-flex; vertical-align: middle; margin-left: 6px; color: var(--azul-texto); }
/* variação discreta do .btn-mini.azul (aquele é azul sólido, forte demais em
   cima de uma linha que já está azul): só a borda e o texto marcam o estado */
.btn-mini.azul-claro { border-color: var(--azul); color: var(--azul-texto); }
.btn-mini.azul-claro:hover { border-color: var(--azul-texto); color: var(--azul-texto); }

/* coluna de ações de cada ramal no painel do cliente ("Solicitar" + lápis do
   setor, ver desenharFolha em painel-cliente.js). Sem display:flex na célula
   de propósito: um <td> que deixa de ser table-cell sai do alinhamento das
   colunas do <thead>, então o espaçamento vem de margin/nowrap mesmo */
.folha-acoes-ramal { white-space: nowrap; text-align: right; }
.folha-acoes-ramal .btn-mini,
.folha-acoes-ramal .btn-icone { vertical-align: middle; }
.folha-acoes-ramal .btn-icone { margin-left: 6px; }

/* botão "Organizar por setor", fica entre o telefone/local e a tabela */
.folha-acoes { display: flex; align-items: center; gap: 10px; padding: 10px 16px; background: var(--fundo-sutil); }
/* "Organizar por setor" (quando existe) fica onde nasceu (esquerda); esse
   margin-left:auto empurra só o Imprimir pra ponta direita da barra, sozinho
   ou não. #btn-imprimir-lista é o mesmo botão nas 3 telas (interna, painel
   do cliente, link público), então um ajuste aqui já cobre as três */
#btn-imprimir-lista { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; }

/* barra que aparece na grade de unidades (tela-unidades) quando pelo menos 1
   está marcada pra impressão combinada (ver #barra-selecao-unidades) */
/* linha divisória de cada grupo de setor, dentro da própria tabela */
.folha-separador-setor td {
  background: var(--linha-hover);
  color: var(--tinta);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .5px;
  padding: 8px 16px;
  text-align: center;
  border-bottom: 1px solid var(--linha);
}
.folha-legenda {
  background: var(--azul-fundo);
  color: var(--azul-texto);
  text-align: center;
  font-size: 12px;
  padding: 10px;
  line-height: 1.6;
}
.folha-voltar {
  display: block;
  background: var(--azul);
  color: #fff;
  text-align: center;
  font-weight: 700;
  text-transform: uppercase;
  padding: 13px;
  cursor: pointer;
  border: 0;
  width: 100%;
  font: inherit;
  letter-spacing: .4px;
}
.folha-voltar:hover { background: var(--azul-texto); }
.folha-vazia { padding: 34px 20px; text-align: center; color: var(--suave); }


/* ================= tempo de sessão (menu do usuário + aviso de fim) =================
   A equipe ZZ reloga a cada 7 dias (teto absoluto, ver SETE_DIAS_SEG no
   server.js). Estas regras ficam no FIM do arquivo de propósito por causa do
   --altura-topo lá embaixo: ele precisa vencer o `body:has(.topo-interno)` da
   seção do topo, e as duas regras têm a mesma especificidade, então quem vem
   por último ganha. */

/* --- bloco no dropdown do usuário --- */
/* mesmas medidas do .item-alerta-bloco (o outro bloco de 2 linhas que já existe
   dentro de dropdown), mas SEM :hover e SEM cursor: é texto, e a ausência de
   hover é o que avisa "não me clique" pra quem está mirando o Sair logo abaixo */
.bloco-sessao { padding: 9px 10px; border-radius: 7px; cursor: default; }
.sessao-restante {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--tinta);
}
.sessao-restante svg { flex-shrink: 0; color: var(--suave); }
/* recuo de 24px alinha a 2ª linha embaixo do TEXTO da 1ª, não embaixo do
   ícone, mesmo truque do .alerta-tempo */
.sessao-login { display: block; margin-top: 4px; padding-left: 24px; font-size: 11px; color: var(--suave); }
/* --vermelho-cartao, nunca --vermelho puro: o puro some no tema escuro */
.bloco-sessao.urgente .sessao-restante { color: var(--vermelho-cartao); font-weight: 700; }
.bloco-sessao.urgente .sessao-restante svg { color: var(--vermelho-cartao); }
.separador-dropdown { height: 1px; margin: 4px 6px; background: var(--linha); }
/* largura no ID, nunca na classe: .dropdown-usuario é compartilhada com o menu
   "⋮" da tabela de ramais e com o de status do chat, que ficariam largos à toa */
#dropdown-usuario { min-width: 252px; }

/* --- faixa de aviso abaixo do topo --- */
/* sticky (em fluxo), não fixed: assim ela EMPURRA o conteúdo pra baixo em vez
   de cobrir a primeira linha da tela. O top é 48px fixo (altura do .topo-interno)
   e não var(--altura-topo), senão a faixa empurraria a si mesma */
.faixa-sessao {
  position: sticky;
  top: 48px;
  z-index: 9;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  padding: 8px 24px;
  background: var(--laranja-faixa);
  border-bottom: 1px solid var(--linha);
  color: var(--tinta);
}
.faixa-sessao-icone { display: inline-flex; color: var(--laranja-faixa-icone); }
.faixa-sessao-texto { flex: 1 1 260px; font-size: 13px; }
.faixa-sessao-texto strong { font-weight: 600; }
.faixa-sessao-dica { color: var(--laranja-faixa-texto); font-size: 12px; }
.faixa-sessao .btn { padding: 6px 12px; font-size: 13px; }
/* o X de dispensar só fecha o aviso, não "confirma" nada: sem o verde do hover
   do .btn-icone.neutro, que ao lado do "Continuar conectado" (verde) confundia.
   Só clareia, pra mostrar que é clicável (pedido do usuário, 24/09/2026) */
.faixa-sessao .btn-icone.neutro:hover { border-color: var(--suave); color: var(--tinta); }
.faixa-sessao.urgente { background: var(--vermelho-faixa); }
.faixa-sessao.urgente .faixa-sessao-icone,
.faixa-sessao.urgente .faixa-sessao-texto strong { color: var(--vermelho-cartao); }
/* as barras de busca/filtro grudam em var(--altura-topo); com a faixa visível
   elas passariam POR BAIXO dela, então o ponto de gruda desce junto */
body:has(.faixa-sessao:not(.oculto)) { --altura-topo: 92px; }
/* X de dispensar: a faixa encolhe pra cima e some, em vez de sumir de uma vez
   (o .oculto entra no fim, ver btn-dispensar-sessao em app.js). Altura
   animada a partir da real (--altura-faixa), senão o conteúdo de baixo pularia;
   o texto sobe um pouco e apaga junto, dando a sensação de "recolher" */
.faixa-sessao.recolhendo {
  overflow: hidden;
  pointer-events: none;
  animation: faixa-sessao-recolher .3s ease-in forwards;
}
.faixa-sessao.recolhendo > * { animation: faixa-sessao-recolher-conteudo .3s ease-in forwards; }
@keyframes faixa-sessao-recolher {
  from { max-height: var(--altura-faixa, 60px); }
  to { max-height: 0; padding-top: 0; padding-bottom: 0; border-bottom-width: 0; }
}
@keyframes faixa-sessao-recolher-conteudo {
  to { opacity: 0; transform: translateY(-10px); }
}
/* o mesmo aviso, quando um modal está aberto: aí ele vai pra DENTRO do modal,
   porque o escurecimento do .fundo-modal cobriria a faixa justo na hora que
   mais importa (pessoa com cadastro preenchido na tela) */
.modal .faixa-sessao {
  position: static;
  margin: -20px -20px 16px;
  border-radius: 12px 12px 0 0;
  border-bottom: 1px solid var(--linha);
}
/* na impressão a faixa não tem o que fazer */
@media print { .faixa-sessao { display: none; } }

/* --- sobreposição "Continuar conectado" --- */
/* acima do .fundo-modal (z-index 50): ela precisa aparecer POR CIMA de um
   cadastro aberto, que é justamente o caso que ela existe pra salvar */
.fundo-reautenticar { z-index: 60; }
.modal-reautenticar { max-width: 380px; }
.reautenticar-texto { font-size: 13px; color: var(--suave); margin-bottom: 16px; line-height: 1.5; }
.reautenticar-conta { font-size: 13px; color: var(--suave); margin-bottom: 10px; }
.reautenticar-conta strong { color: var(--tinta); }
/* font: inherit é obrigatório em input novo: sem isso o campo herda a fonte do
   sistema operacional e destoa do resto da tela (já aconteceu no .btn-usuario) */
#reautenticar-senha {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--linha);
  border-radius: 8px;
  font: inherit;
  color: var(--tinta);
  background: var(--branco);
}
#reautenticar-senha:focus { outline: none; border-color: var(--verde); }
#reautenticar-erro { margin-top: 10px; }
