/* ===========================================================================
   PORTAL — a tela número-primeiro
   ---------------------------------------------------------------------------
   A unidade de trabalho não é "uma conta com N instâncias", é UMA LINHA. Quem
   opera pensa "o Vendas caiu", não "a instância 3 da conta X". Por isso a
   coluna esquerda é a frota e todo o resto é o contexto de uma linha só.

   Herda os tokens --ui-* de app-ui.css. Nada de cor crua aqui.
   Profundidade: borders-only, como o resto do sistema.
   =========================================================================== */

.portal {
  display: grid;
  grid-template-columns: 264px minmax(0, 1fr);
  gap: 0;
  min-height: calc(100vh - 60px);
  align-items: stretch;
}

/* --- Frota ---------------------------------------------------------------- */

.fleet {
  border-right: 1px solid var(--ui-line);
  background: var(--ui-surface);
  display: flex;
  flex-direction: column;
  /* Gruda abaixo do cabeçalho: a frota é o índice, some do alcance se rolar
     junto com o painel de detalhe, que é bem mais alto. */
  position: sticky;
  top: 60px;
  height: calc(100vh - 60px);
}

.fleet__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: var(--zap-4) var(--zap-4) var(--zap-2);
}

.fleet__title {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ui-faint);
}

.fleet__count {
  font-family: var(--zap-mono);
  font-size: 11px;
  color: var(--ui-faint);
}

.fleet__list {
  flex: 1;
  overflow-y: auto;
  padding: 0 var(--zap-2) var(--zap-2);
}

/* Item da frota: ponto de estado + nome + número. O ponto vem primeiro
   porque a pergunta é sempre "está no ar?" antes de "qual é mesmo?". */
.fleet__item {
  width: 100%;
  display: grid;
  /* 32px: os 28 do avatar mais a folga do anel, que é box-shadow e não ocupa
     espaço de layout. */
  grid-template-columns: 32px minmax(0, 1fr);
  align-items: center;
  gap: var(--zap-2);
  padding: 9px var(--zap-3);
  border: 0;
  border-radius: var(--zap-r-sm);
  background: transparent;
  color: var(--ui-text);
  text-align: left;
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease;
}

.fleet__item:hover { background: var(--ui-surface-2); }

.fleet__item.is-active {
  background: var(--ui-accent-soft);
  color: var(--ui-accent);
}

.fleet__item:focus-visible {
  outline: 2px solid var(--ui-accent-fill);
  outline-offset: -2px;
}

.fleet__dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--ui-faint);
  justify-self: center;
}

.fleet__item.is-on .fleet__dot {
  background: var(--ui-accent-fill);
  box-shadow: 0 0 0 3px var(--ui-accent-soft);
}

.fleet__item.is-pairing .fleet__dot {
  background: var(--ui-amber-fill);
  box-shadow: 0 0 0 3px var(--ui-amber-soft);
}

/* Bloco de propósito: são dois <span> dentro de um <span>, e inline eles
   ficariam na mesma linha ("Atendimentofora do ar"). */
.fleet__name,
.fleet__sub { display: block; }

.fleet__name {
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fleet__sub {
  font-family: var(--zap-mono);
  font-size: 11px;
  color: var(--ui-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fleet__new {
  margin: var(--zap-2) var(--zap-3) var(--zap-3);
  padding: 10px;
  border: 1px dashed var(--ui-line-strong);
  border-radius: var(--zap-r-sm);
  background: transparent;
  color: var(--ui-muted);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 150ms ease, color 150ms ease;
}

.fleet__new:hover:not(:disabled) { border-color: var(--ui-accent-fill); color: var(--ui-accent); }
.fleet__new:disabled { opacity: 0.5; cursor: not-allowed; }

/* Plano no rodapé da coluna: contexto permanente, nunca manchete. */
.fleet__plan {
  border-top: 1px solid var(--ui-line);
  padding: var(--zap-3) var(--zap-4);
  display: grid;
  gap: 6px;
}

.fleet__plan-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--zap-2);
}

.fleet__plan-name { font-size: 12.5px; font-weight: 700; }

.fleet__plan-use {
  font-family: var(--zap-mono);
  font-size: 11px;
  color: var(--ui-muted);
}

.fleet__bar {
  height: 3px;
  border-radius: 999px;
  background: var(--ui-surface-3);
  overflow: hidden;
}

.fleet__bar i {
  display: block;
  height: 100%;
  background: var(--ui-accent-fill);
  transition: width 260ms ease;
}

.fleet__plan.at-limit .fleet__bar i { background: var(--ui-amber-fill); }

/* --- Painel da linha ------------------------------------------------------ */

.line {
  min-width: 0;
  padding: var(--zap-5) var(--zap-6) var(--zap-7);
}

.line__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--zap-4);
  flex-wrap: wrap;
}

.line__name {
  display: flex;
  align-items: center;
  gap: var(--zap-2);
}

.line__name h1 {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0;
}

/* Lápis, não a palavra "renomear".
   
   Renomear é ação rara — talvez uma vez na vida da conexão. O ícone marca
   presença sem disputar leitura com o nome, que é o que se lê o tempo todo.

   Mas o botão NÃO fica invisível como antes (opacity 0 até o hover do
   cabeçalho): texto escondido ainda podia ser reconhecido ao aparecer; um
   ícone que ninguém sabe que existe não é descoberto, porque ninguém passa o
   mouse no vazio. Fica esmaecido e presente, e acende ao aproximar. */
.line__edit {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 0;
  background: transparent;
  color: var(--ui-faint);
  cursor: pointer;
  padding: 0;
  border-radius: var(--zap-r-sm);
  opacity: 0.45;
  transition: opacity 150ms ease, color 150ms ease, background 150ms ease;
}

/* Mesma gramática de traço dos ícones da barra superior: contorno, sem
   preenchimento. Um lápis sólido no meio de um conjunto contornado lê como
   peça de outro sistema. */
.line__edit svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.line__head:hover .line__edit { opacity: 0.8; }

.line__edit:hover {
  opacity: 1;
  color: var(--ui-accent);
  background: var(--ui-surface-2);
}

.line__edit:focus-visible {
  opacity: 1;
  outline: 2px solid var(--ui-accent-fill);
  outline-offset: 2px;
}

/* 44px de alvo sem inflar os 28px desenhados — mesma técnica do X do véu.
   Em ::before porque ::after é da bolha da tooltip, logo abaixo. */
.line__edit::before {
  content: "";
  position: absolute;
  inset: -8px;
}

.line__meta {
  display: flex;
  align-items: center;
  gap: var(--zap-3);
  font-family: var(--zap-mono);
  font-size: 12px;
  color: var(--ui-muted);
  margin-top: 4px;
}

/* --- Faixa de plantão: a assinatura -----------------------------------------
   Cada segmento é um trecho contínuo no mesmo estado, largura proporcional à
   duração. Responde "caiu enquanto eu dormia?" sem ler um número. */

.duty { margin: var(--zap-4) 0 var(--zap-5); }

.duty__bar {
  display: flex;
  height: 26px;
  border-radius: var(--zap-r-sm);
  overflow: hidden;
  background: var(--ui-surface-3);
  border: 1px solid var(--ui-line);
}

.duty__seg {
  height: 100%;
  min-width: 1px;
  transition: filter 150ms ease;
}

/* Piso de 3px na interrupção. Uma queda de 20 minutos em 30 dias vale 0,05%
   da largura — some. A faixa existe para mostrar queda, então ela não pode
   ser justamente o que desaparece: aqui a legibilidade ganha da proporção
   exata, e a duração real fica no title de cada segmento. */
.duty__seg[data-state="disconnected"],
.duty__seg[data-state="pairing"],
.duty__seg[data-state="connected"] { min-width: 3px; }

.duty__seg[data-state="connected"]    { background: var(--ui-accent-fill); }
.duty__seg[data-state="pairing"]      { background: var(--ui-amber-fill); }
.duty__seg[data-state="disconnected"] { background: var(--ui-red); opacity: 0.55; }

/* O trecho sem observação usa a mesma hachura, dentro de uma faixa que no
   resto tem dado: diz "aqui não sei" sem competir com o verde e o vermelho. */
.duty__seg[data-state="unknown"] {
  background: repeating-linear-gradient(
    -45deg,
    var(--ui-surface-3) 0 6px,
    var(--ui-surface-2) 6px 12px
  );
}

/* Sem histórico ≠ trinta dias fora do ar. Uma linha recém-criada não teve
   queda nenhuma; pintá-la de vermelho inteiro seria inventar um incidente.
   Hachura neutra diz "não sei", que é a verdade. */
.duty__bar.is-unknown .duty__seg {
  background: repeating-linear-gradient(
    -45deg,
    var(--ui-surface-3) 0 6px,
    var(--ui-surface-2) 6px 12px
  );
  opacity: 1;
}
.duty__seg:hover { filter: brightness(1.15); }

.duty__legend {
  display: flex;
  justify-content: space-between;
  gap: var(--zap-3);
  margin-top: 6px;
  font-size: 11.5px;
  color: var(--ui-faint);
}

.duty__legend b {
  font-family: var(--zap-mono);
  color: var(--ui-muted);
  font-weight: 600;
}

/* --- Abas ----------------------------------------------------------------- */

.tabs-line {
  display: flex;
  gap: var(--zap-1);
  border-bottom: 1px solid var(--ui-line);
  margin-bottom: var(--zap-5);
  overflow-x: auto;
  scrollbar-width: none;
}

.tabs-line::-webkit-scrollbar { display: none; }

.tabs-line button {
  position: relative;
  border: 0;
  background: transparent;
  color: var(--ui-muted);
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 600;
  padding: 10px var(--zap-3);
  cursor: pointer;
  white-space: nowrap;
  transition: color 150ms ease;
}

.tabs-line button::after {
  content: "";
  position: absolute;
  left: var(--zap-3);
  right: var(--zap-3);
  bottom: -1px;
  height: 2px;
  background: var(--ui-accent-fill);
  transform: scaleX(0);
  transition: transform 180ms ease;
}

.tabs-line button:hover { color: var(--ui-text); }
.tabs-line button.is-active { color: var(--ui-accent); }
.tabs-line button.is-active::after { transform: scaleX(1); }

/* --- Blocos de conteúdo --------------------------------------------------- */

.panel {
  border: 1px solid var(--ui-line);
  border-radius: var(--zap-r-lg);
  background: var(--ui-surface);
  padding: var(--zap-4);
  margin-bottom: var(--zap-4);
}

.panel__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--zap-3);
  margin-bottom: var(--zap-3);
}

.panel__title {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.panel__hint {
  font-size: 12px;
  color: var(--ui-faint);
  line-height: 1.5;
}

.grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--zap-4);
}

/* --- Métrica: número que significa algo, não caixinha com ícone ------------ */

.figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: var(--zap-4);
}

.figure__n {
  font-family: var(--zap-mono);
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

.figure__k {
  font-size: 11px;
  color: var(--ui-faint);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-top: 2px;
}

.figure.is-warn .figure__n { color: var(--ui-amber); }
.figure.is-bad  .figure__n { color: var(--ui-red); }

/* --- Sparkline de volume: colunas empilhadas in/out ------------------------ */

.spark {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 64px;
  margin-top: var(--zap-2);
}

.spark__day {
  flex: 1;
  min-width: 3px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 1px;
  height: 100%;
  border-radius: 2px;
}

.spark__in  { background: var(--ui-accent-fill); border-radius: 2px 2px 0 0; }
.spark__out { background: var(--ui-amber-fill); border-radius: 0 0 2px 2px; opacity: 0.85; }

.spark__axis {
  display: flex;
  justify-content: space-between;
  font-family: var(--zap-mono);
  font-size: 10px;
  color: var(--ui-faint);
  margin-top: 4px;
}

.key {
  display: flex;
  gap: var(--zap-3);
  font-size: 11.5px;
  color: var(--ui-muted);
  margin-top: var(--zap-2);
}

.key span { display: inline-flex; align-items: center; gap: 5px; }
.key i { width: 8px; height: 8px; border-radius: 2px; display: inline-block; }
.key .k-in  { background: var(--ui-accent-fill); }
.key .k-out { background: var(--ui-amber-fill); }

/* --- Tail de eventos ------------------------------------------------------ */

.tail {
  border: 1px solid var(--ui-line);
  border-radius: var(--zap-r-md);
  background: var(--ui-surface-2);
  max-height: 460px;
  overflow-y: auto;
}

.ev {
  border-bottom: 1px solid var(--ui-line);
  padding: var(--zap-3);
}

.ev:last-child { border-bottom: 0; }

.ev__top {
  display: flex;
  align-items: center;
  gap: var(--zap-2);
  flex-wrap: wrap;
  cursor: pointer;
}

.ev__type {
  font-family: var(--zap-mono);
  font-size: 11px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--ui-surface-3);
  color: var(--ui-muted);
}

.ev[data-type="ReceivedCallback"]      .ev__type { background: var(--ui-accent-soft); color: var(--ui-accent); }
.ev[data-type="MessageStatusCallback"] .ev__type { background: var(--ui-amber-soft); color: var(--ui-amber); }

.ev__at {
  font-family: var(--zap-mono);
  font-size: 11px;
  color: var(--ui-faint);
  margin-left: auto;
}

.ev__deliv {
  font-family: var(--zap-mono);
  font-size: 11px;
  padding: 2px 7px;
  border-radius: 999px;
}

.ev__deliv.ok  { background: var(--ui-accent-soft); color: var(--ui-accent); }
.ev__deliv.bad { background: var(--ui-red-soft); color: var(--ui-red); }

.ev__body {
  margin: var(--zap-2) 0 0;
  padding: var(--zap-3);
  border-radius: var(--zap-r-sm);
  background: var(--ui-bg);
  border: 1px solid var(--ui-line);
  font-family: var(--zap-mono);
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--ui-muted);
  overflow-x: auto;
  white-space: pre;
}

/* --- Tabela de registro --------------------------------------------------- */

.tbl-wrap { overflow-x: auto; }

.tbl {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
}

.tbl th {
  text-align: left;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ui-faint);
  font-weight: 700;
  padding: 0 var(--zap-3) 8px;
  white-space: nowrap;
}

.tbl td {
  padding: 9px var(--zap-3);
  border-top: 1px solid var(--ui-line);
  white-space: nowrap;
}

.tbl td.mono { font-family: var(--zap-mono); font-size: 11.5px; color: var(--ui-muted); }

.dir {
  font-family: var(--zap-mono);
  font-size: 11px;
  font-weight: 600;
}

.dir.in  { color: var(--ui-accent); }
.dir.out { color: var(--ui-amber); }

.status-chip {
  font-family: var(--zap-mono);
  font-size: 10.5px;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--ui-surface-3);
  color: var(--ui-muted);
}

.status-chip[data-s="READ"],
.status-chip[data-s="PLAYED"] { background: var(--ui-accent-soft); color: var(--ui-accent); }
.status-chip[data-s="RECEIVED"] { background: var(--ui-amber-soft); color: var(--ui-amber); }

/* --- Console de envio ----------------------------------------------------- */

.console__out {
  margin-top: var(--zap-3);
  border-radius: var(--zap-r-sm);
  border: 1px solid var(--ui-line);
  background: var(--ui-bg);
  padding: var(--zap-3);
  font-family: var(--zap-mono);
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--ui-muted);
  overflow-x: auto;
  white-space: pre;
}

.console__out.is-ok  { border-color: var(--ui-accent-fill); }
.console__out.is-bad { border-color: var(--ui-red); }

/* --- Switch --------------------------------------------------------------- */

.switch {
  display: flex;
  align-items: flex-start;
  gap: var(--zap-3);
  cursor: pointer;
  padding: var(--zap-2) 0;
}

.switch input { position: absolute; opacity: 0; pointer-events: none; }

.switch__track {
  flex: none;
  width: 34px;
  height: 20px;
  border-radius: 999px;
  background: var(--ui-surface-3);
  border: 1px solid var(--ui-line-strong);
  position: relative;
  transition: background 150ms ease, border-color 150ms ease;
  margin-top: 1px;
}

.switch__track::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  border-radius: 999px;
  background: var(--ui-faint);
  transition: transform 150ms ease, background 150ms ease;
}

.switch input:checked + .switch__track {
  background: var(--ui-accent-soft);
  border-color: var(--ui-accent-fill);
}

.switch input:checked + .switch__track::after {
  transform: translateX(14px);
  background: var(--ui-accent-fill);
}

.switch input:focus-visible + .switch__track {
  outline: 2px solid var(--ui-accent-fill);
  outline-offset: 2px;
}

/* Bloco pelo mesmo motivo do item da frota: são dois <span> irmãos dentro
   de um <span>, e inline eles emendam numa linha só. */
.switch__label,
.switch__desc { display: block; }

.switch__label { font-size: 13px; font-weight: 600; line-height: 1.35; }
.switch__desc { font-size: 12px; color: var(--ui-faint); line-height: 1.5; margin-top: 2px; }

/* --- Estado vazio dentro de aba ------------------------------------------- */

.void {
  text-align: center;
  padding: var(--zap-6) var(--zap-4);
  color: var(--ui-faint);
}

.void h4 { font-size: 14px; color: var(--ui-text); margin: 0 0 6px; font-weight: 700; }
.void p { font-size: 12.5px; line-height: 1.6; margin: 0; max-width: 46ch; margin-inline: auto; }

/* --- Responsivo ------------------------------------------------------------
   Abaixo de 900px a coluna vira uma faixa horizontal rolável no topo: a frota
   continua sempre visível (é a navegação), mas deitada. */

/* --- Trocador de conexão (celular) -------------------------------------------
   O gatilho da gaveta É a conexão atual, com o ponto de estado. Responde
   "qual estou vendo e ela está no ar?" sem abrir nada — a pergunta de quem
   pega o celular longe da mesa. Um hamburger não responderia nenhuma das duas. */

.switcher { display: none; }

.fleet__scrim { display: none; }

@media (max-width: 900px) {
  .switcher {
    display: inline-flex;
    align-items: center;
    gap: var(--zap-2);
    min-height: 44px;
    max-width: 58vw;
    padding: 6px 10px;
    border: 1px solid var(--ui-line);
    border-radius: 999px;
    background: var(--ui-surface-2);
    color: var(--ui-text);
    font-family: inherit;
    cursor: pointer;
    transition: border-color 150ms ease, background 150ms ease;
  }

  .switcher:hover { border-color: var(--ui-line-strong); }

  .switcher:focus-visible {
    outline: 2px solid var(--ui-accent-fill);
    outline-offset: 2px;
  }

  .switcher__dot {
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 999px;
    background: var(--ui-faint);
  }

  .switcher__dot.is-on {
    background: var(--ui-accent-fill);
    box-shadow: 0 0 0 3px var(--ui-accent-soft);
  }

  .switcher__dot.is-conta { background: var(--ui-muted); }

  .switcher__name {
    font-size: 13.5px;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .switcher__chev {
    flex: none;
    width: 15px;
    height: 15px;
    color: var(--ui-faint);
    transition: transform 180ms ease;
  }

  .switcher[aria-expanded="true"] .switcher__chev { transform: rotate(180deg); }

  /* --- A gaveta --------------------------------------------------------- */

  .portal { grid-template-columns: minmax(0, 1fr); }

  .fleet {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    /* Não cobre a tela inteira: a faixa de conteúdo que sobra à direita é a
       âncora que diz "você ainda está no painel, isto é uma camada". */
    width: min(300px, 84vw);
    height: auto;
    z-index: 60;
    border-right: 1px solid var(--ui-line);
    border-bottom: 0;
    box-shadow: var(--ui-shadow-lg);
    transform: translateX(-100%);
    transition: transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1);
  }

  .fleet.is-open { transform: none; }

  .fleet__scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 55;
    background: var(--ui-overlay);
    opacity: 0;
    /* Invisível NÃO é ausente. Sem isto, a camada continua interceptando
       cada toque da tela — o painel inteiro fica morto sem nada à vista que
       explique. É a segunda trava: vale mesmo no intervalo entre sair do
       hidden e ganhar .is-on. */
    pointer-events: none;
    transition: opacity 220ms ease;
  }

  .fleet__scrim.is-on {
    opacity: 1;
    pointer-events: auto;   /* só aqui ele existe para o toque: é o fechar-ao-tocar-fora */
  }

  /* `display: block` acima vence o atributo `hidden`, que o navegador aplica
     por uma regra de especificidade mínima ([hidden] { display: none }).
     Sem esta linha o atributo vira decoração — e foi exatamente assim que a
     tela inteira ficou sem clique. Ao dar `display` a um elemento que também
     usa `hidden`, devolva o par. */
  .fleet__scrim[hidden] { display: none; }

  /* Trava a rolagem de fundo: sem isso, arrastar na gaveta rola a página
     atrás e a lista parece presa. */
  body.sem-rolagem { overflow: hidden; }

  .line { padding: var(--zap-4) var(--zap-4) var(--zap-6); }
  .line__name h1 { font-size: 19px; }
  .line__edit { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .fleet,
  .fleet__scrim,
  .switcher,
  .switcher__chev,
  .fleet__bar i,
  .tabs-line button::after,
  .switch__track,
  .switch__track::after { transition: none; }
}

/* O bloco de identidade no topo virou botão (abre a Conta). Precisa perder
   a aparência de botão do navegador e manter o alinhamento que tinha como
   <div>, senão a barra inteira desalinha. */
.topbar .u {
  border: 0;
  background: transparent;
  font: inherit;
  color: inherit;
  text-align: right;
  cursor: pointer;
  padding: 4px 6px;
  border-radius: var(--zap-r-sm);
  transition: background 150ms ease;
}

.topbar .u:hover { background: var(--ui-surface-2); }

.topbar .u:focus-visible {
  outline: 2px solid var(--ui-accent-fill);
  outline-offset: 2px;
}

/* --- Alternador de método de pareamento -------------------------------------
   Dois caminhos para a mesma coisa, então segmentado e não abas: abas sugerem
   conteúdos diferentes; aqui o destino é idêntico, muda só o caminho. */

.pair-switch {
  display: flex;
  gap: 2px;
  padding: 3px;
  margin: 0 0 var(--zap-4);
  border-radius: var(--zap-r-md);
  background: var(--ui-surface-2);
  border: 1px solid var(--ui-line);
}

.pair-switch button {
  flex: 1;
  border: 0;
  border-radius: var(--zap-r-sm);
  background: transparent;
  color: var(--ui-muted);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  padding: 8px 10px;
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease;
}

.pair-switch button:hover { color: var(--ui-text); }

.pair-switch button.is-active {
  background: var(--ui-surface);
  color: var(--ui-accent);
  box-shadow: var(--ui-shadow);
}

.pair-switch button:focus-visible {
  outline: 2px solid var(--ui-accent-fill);
  outline-offset: -2px;
}

/* --- Código de pareamento ---------------------------------------------------
   Em 4+4 porque oito caracteres corridos são digitados errado, e é assim que
   o WhatsApp desenha a caixa do outro lado. */

.pair-code {
  display: flex;
  justify-content: center;
  gap: var(--zap-3);
  margin: var(--zap-5) 0 var(--zap-3);
}

.pair-code span {
  font-family: var(--zap-mono);
  font-size: clamp(24px, 6vw, 34px);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-indent: 0.22em;
  padding: 12px 16px;
  border-radius: var(--zap-r-md);
  background: var(--ui-surface-2);
  border: 1px solid var(--ui-line);
  color: var(--ui-text);
}

@media (prefers-reduced-motion: reduce) {
  .pair-switch button { transition: none; }
}

/* --- Véu de conexão caída ---------------------------------------------------
   Cobre o conteúdo da aba Conexão quando o número está fora do ar. O escopo é
   deliberado: o cabeçalho, a faixa de plantão e as abas ficam de fora e
   seguem clicáveis — o histórico explica a queda, e configurar webhook
   funciona com a linha muda.

   Não é <dialog>: não deve prender o foco nem bloquear o resto da tela. É uma
   camada sobre uma região, não um modal sobre a página. */

#line-body { position: relative; }

/* Garante área para o cartão respirar mesmo quando o conteúdo abaixo é curto. */
#line-body.has-veil { min-height: 340px; }

.offline {
  position: absolute;
  inset: 0;
  display: flex;
  justify-content: center;
  /* Ancorado no topo, não centralizado: em painel alto, centralizar joga o
     cartão para fora da dobra e o véu vira uma tela cinza sem explicação. */
  align-items: flex-start;
  padding: clamp(16px, 5vh, 56px) var(--zap-4);
  z-index: 5;

  /* O véu deixa o conteúdo entrever: some o suficiente para não competir,
     o bastante para o X ter sentido — dá para ver que há algo embaixo. */
  background: color-mix(in srgb, var(--ui-bg) 82%, transparent);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);

  animation: veu-entra 180ms ease both;
}

/* color-mix não chegou em todo lugar; sem ele o véu ficaria transparente e o
   cartão flutuaria sobre o texto. O fallback abre mão do vidro, não da
   legibilidade. */
@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .offline { background: var(--ui-bg); }
}

.offline.is-out { animation: veu-sai 160ms ease both; }

.offline__card {
  position: relative;
  width: min(440px, 100%);
  text-align: center;
  padding: var(--zap-5) var(--zap-5) var(--zap-4);
  border: 1px solid var(--ui-line);
  border-radius: var(--zap-r-lg);
  background: var(--ui-surface);
  /* Única sombra do portal: o cartão está ACIMA do painel, e sem ela o véu
     e o cartão leriam como a mesma camada. */
  box-shadow: var(--ui-shadow-lg);
  animation: veu-cartao 220ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

.offline__x {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--zap-r-sm);
  background: transparent;
  /* --ui-muted e não --ui-faint: este X é a válvula de escape inteira do
     componente. Em faint ele media 3.95:1 — presente, mas não achável, o que
     transforma a saída em pegadinha. */
  color: var(--ui-muted);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease;
}

/* Área de toque de 44px sem inflar o desenho: o quadrado visível continua
   com 32px, o alvo cresce por fora. Aumentar o botão de verdade colocaria
   um bloco cinza pesado no canto do cartão. */
.offline__x::after {
  content: "";
  position: absolute;
  inset: -6px;
}

.offline__x:hover { background: var(--ui-surface-2); color: var(--ui-text); }

.offline__x:focus-visible {
  outline: 2px solid var(--ui-accent-fill);
  outline-offset: -2px;
}

/* O ponto morto: mesma linguagem do status-dot da frota, sem o pulso e sem o
   halo. Cinza e não vermelho — fora do ar é estado, não falha. O vermelho
   está reservado para erro de entrega, e gastá-lo aqui o desvaloriza lá. */
.offline__dot {
  display: block;
  width: 9px;
  height: 9px;
  margin: 0 auto var(--zap-3);
  border-radius: 999px;
  background: var(--ui-faint);
  box-shadow: 0 0 0 4px var(--ui-surface-2);
}

.offline__title {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 6px;
  color: var(--ui-text);
}

.offline__desc {
  font-size: 13px;
  line-height: 1.6;
  color: var(--ui-muted);
  margin: 0 auto;
  max-width: 38ch;
}

.offline__acts { margin: var(--zap-4) 0 var(--zap-3); }

/* Em --ui-muted, não --ui-faint: esta linha é o que explica POR QUE dá para
   fechar. Se ela não for lida, o X vira um botão de função desconhecida. */
.offline__note {
  font-size: 12px;
  line-height: 1.5;
  color: var(--ui-muted);
  margin: 0 auto;
  max-width: 40ch;
}

@keyframes veu-entra { from { opacity: 0; } to { opacity: 1; } }
@keyframes veu-sai   { from { opacity: 1; } to { opacity: 0; } }

@keyframes veu-cartao {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .offline,
  .offline.is-out,
  .offline__card { animation: none; }
  .offline__x { transition: none; }
}

/* --- Resultado do teste de webhook ------------------------------------------
   Fica no painel e não em toast: quem está depurando precisa comparar esta
   tentativa com a anterior, e toast some antes de servir para isso.

   O status em mono à esquerda funciona como carimbo — a mesma leitura de
   coluna do registro de mensagens, então o olho já sabe onde procurar. */

.teste {
  display: flex;
  align-items: flex-start;
  gap: var(--zap-3);
  padding: 10px var(--zap-3);
  border: 1px solid var(--ui-line);
  border-radius: var(--zap-r-md);
  background: var(--ui-surface-2);
  /* Respiro simétrico: o mesmo degrau em cima e embaixo. Sem o de baixo, o
     veredito encostava nos contadores de entrega e os dois blocos liam como
     um só — e eles dizem coisas diferentes (esta tentativa x o acumulado).

     As margens adjacentes colapsam com a dica de falha que vem logo abaixo
     (margin-top 8px), então o espaço fica 12 e não 20. */
  margin-top: var(--zap-3);
  margin-bottom: var(--zap-3);
}

.teste__st {
  flex: none;
  font-family: var(--zap-mono);
  font-size: 11.5px;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--ui-surface-3);
  color: var(--ui-muted);
}

.teste__msg {
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ui-muted);
  min-width: 0;
  word-break: break-word;
}

/* A borda esquerda carrega o veredito. Pintar o bloco inteiro competiria com
   os números da própria entrega logo acima. */
.teste.is-ok  { border-left: 3px solid var(--ui-accent-fill); }
.teste.is-bad { border-left: 3px solid var(--ui-red); }
.teste.is-voo { border-left: 3px solid var(--ui-amber-fill); }

.teste.is-ok  .teste__st { background: var(--ui-accent-soft); color: var(--ui-accent); }
.teste.is-bad .teste__st { background: var(--ui-red-soft);    color: var(--ui-red); }
.teste.is-voo .teste__st { background: var(--ui-amber-soft);  color: var(--ui-amber); }

/* Pulso só enquanto está em voo: movimento aqui significa "esperando", e
   deixá-lo ligado depois da resposta mentiria. */
.teste.is-voo .teste__st { animation: teste-pulso 1.1s ease-in-out infinite; }

@keyframes teste-pulso {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}

@media (prefers-reduced-motion: reduce) {
  .teste.is-voo .teste__st { animation: none; }
}

/* --- Paginação do registro --------------------------------------------------
   Cursor, não deslocamento: o log recebe linhas pelo topo, e página numerada
   por offset entrega conjuntos diferentes a cada minuto.

   Por isso o rodapé mostra o INTERVALO DE TEMPO em vez de "3 de 40": num log
   cronológico é "quando" que orienta, e o total só se saberia com um COUNT
   sobre 30 dias a cada clique. */

.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--zap-3);
  flex-wrap: wrap;
  margin-top: var(--zap-3);
  padding-top: var(--zap-3);
  border-top: 1px solid var(--ui-line);
}

.pager__range {
  font-family: var(--zap-mono);
  font-size: 11.5px;
  color: var(--ui-faint);
  white-space: nowrap;
}

.pager__nav {
  display: flex;
  align-items: center;
  gap: var(--zap-2);
  margin-left: auto;
}

.pager__pg {
  font-family: var(--zap-mono);
  font-size: 11.5px;
  color: var(--ui-muted);
  margin-right: var(--zap-1);
}

.pager__btn {
  border: 1px solid var(--ui-line);
  border-radius: var(--zap-r-sm);
  background: var(--ui-surface);
  color: var(--ui-text);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  /* 12px de altura de linha + 2×10 de padding = 32px de alvo no desktop;
     o bloco @media abaixo leva para 44 no toque. */
  padding: 9px var(--zap-3);
  cursor: pointer;
  transition: border-color 150ms ease, color 150ms ease, background 150ms ease;
}

.pager__btn:hover:not(:disabled) {
  border-color: var(--ui-accent-fill);
  color: var(--ui-accent);
}

.pager__btn:focus-visible {
  outline: 2px solid var(--ui-accent-fill);
  outline-offset: 2px;
}

/* Desabilitado fica visível, não some: o fim da lista é informação. Um botão
   que desaparece faz a pessoa procurar o que ela já encontrou. */
.pager__btn:disabled {
  opacity: 0.42;
  cursor: not-allowed;
}

@media (max-width: 560px) {
  .pager { flex-direction: column; align-items: stretch; }
  .pager__range { text-align: center; white-space: normal; }
  .pager__nav { margin-left: 0; justify-content: center; }
  .pager__btn { flex: 1; padding: 12px var(--zap-3); }
}

@media (prefers-reduced-motion: reduce) {
  .pager__btn { transition: none; }
}

/* --- Tooltip ----------------------------------------------------------------
   Utilitário, não peça de um botão só: o portal tem outros controles que são
   só ícone, e um balão feito à mão para cada um seria retrabalho.

   Por que não o `title` nativo: ele demora 1–2s para aparecer, não aceita
   estilo nenhum e simplesmente não existe no toque. Quando o ícone é a única
   pista do que o botão faz, essa demora é a diferença entre descobrir e
   desistir.

   A tooltip é reforço, nunca a única fonte: o `aria-label` carrega o nome
   acessível, e no toque (onde ela não aparece) o ícone fica sempre visível. */

.tip { position: relative; }

.tip::after {
  content: attr(data-tip);
  position: absolute;
  /* Abaixo e não acima: estes botões vivem no topo do painel, e um balão
     acima sairia pela borda da região. */
  top: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%) translateY(-2px);

  padding: 5px 9px;
  border-radius: var(--zap-r-sm);
  /* Superfície sólida e um degrau acima: ela flutua sobre conteúdo, e
     translúcida ficaria ilegível em cima de texto. */
  background: var(--ui-surface-3);
  border: 1px solid var(--ui-line);
  box-shadow: var(--ui-shadow);
  color: var(--ui-text);

  font-family: var(--zap-sans, inherit);
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;

  opacity: 0;
  pointer-events: none;   /* nunca rouba o clique do botão que descreve */
  z-index: 20;
  transition: opacity 140ms ease, transform 140ms ease;
}

.tip:hover::after,
.tip:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Variante lateral: para ícones cujo espaço de baixo já está ocupado.
   
   No cabeçalho da conexão, "abaixo" caía exatamente sobre a pílula de estado e
   o número — a informação mais importante da tela. À direita o espaço está
   vazio e a leitura segue a direção natural do texto. */
.tip--right::after {
  top: 50%;
  left: calc(100% + 6px);
  transform: translateY(-50%) translateX(-2px);
}

.tip--right:hover::after,
.tip--right:focus-visible::after {
  transform: translateY(-50%) translateX(0);
}

/* No toque não existe hover: a tooltip nunca apareceria, e mantê-la no DOM só
   criaria um balão fantasma no primeiro toque (que o navegador trata como
   hover). Some de vez — lá o ícone já fica sempre visível. */
@media (hover: none) {
  .tip::after { display: none; }
  .line__edit { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .tip::after { transition: opacity 140ms ease; transform: translateX(-50%); }
  .tip:hover::after,
  .tip:focus-visible::after { transform: translateX(-50%); }

  .tip--right::after,
  .tip--right:hover::after,
  .tip--right:focus-visible::after { transform: translateY(-50%); }
}

/* --- Busca no registro ------------------------------------------------------
   A pergunta do suporte é sempre sobre UM cliente. Com 30 dias de log, achar
   isso clicando "Próxima" não é busca, é sorte — então o campo fica no topo
   do painel, antes da tabela, e não escondido atrás de um menu de filtros. */

.logbar {
  display: flex;
  align-items: center;
  gap: var(--zap-3);
  flex-wrap: wrap;
  margin-bottom: var(--zap-3);
}

.logbar__find {
  position: relative;
  display: flex;
  align-items: center;
  flex: 1 1 260px;
  min-width: 0;
}

.logbar__find svg {
  position: absolute;
  left: 10px;
  width: 15px;
  height: 15px;
  fill: none;
  stroke: var(--ui-faint);
  stroke-width: 1.8;
  pointer-events: none;
}

.logbar__find input {
  width: 100%;
  /* Mono porque quem usa este campo COLA um número — e dígito colado em fonte
     proporcional é difícil de conferir contra o que está na tabela, que já é
     mono. As duas colunas têm que bater à vista. */
  font-family: var(--zap-mono);
  font-size: 12.5px;
  padding: 9px 10px 9px 31px;
  border: 1px solid var(--ui-line);
  border-radius: var(--zap-r-sm);
  background: var(--ui-surface-2);
  color: var(--ui-text);
  transition: border-color 150ms ease, background 150ms ease;
}

.logbar__find input::placeholder { font-family: var(--zap-sans, inherit); color: var(--ui-faint); }

.logbar__find input:focus {
  outline: none;
  border-color: var(--ui-accent-fill);
  background: var(--ui-surface);
}

/* Segmentado e não <select>: são três opções mutuamente exclusivas, e o
   estado atual fica legível sem abrir nada. */
.seg {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--ui-line);
  border-radius: var(--zap-r-md);
  background: var(--ui-surface-2);
}

.seg button {
  border: 0;
  border-radius: var(--zap-r-sm);
  background: transparent;
  color: var(--ui-muted);
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  padding: 7px 11px;
  cursor: pointer;
  white-space: nowrap;
  transition: background 150ms ease, color 150ms ease;
}

.seg button:hover { color: var(--ui-text); }

.seg button.is-on {
  background: var(--ui-surface);
  color: var(--ui-accent);
  box-shadow: var(--ui-shadow);
}

.seg button:focus-visible {
  outline: 2px solid var(--ui-accent-fill);
  outline-offset: -2px;
}

/* --- Tooltip do gráfico de volume -------------------------------------------
   Um elemento posicionado por JS, não um balão CSS por coluna: com 14 colunas,
   a primeira e a última — "28/08" e "hoje", as mais olhadas — sairiam cortadas
   pela borda do painel. A posição é presa ao intervalo do gráfico. */

.spark-wrap { position: relative; }

.spark__tip {
  position: absolute;
  /* Acima das barras, não sobre elas: dentro do gráfico o balão tapava
     justamente as colunas vizinhas que se está comparando. Sobrepor a linha
     do título por um instante custa menos do que esconder o dado. */
  bottom: calc(100% + 4px);
  transform: translateX(-50%) translateY(-4px);
  display: flex;
  align-items: center;
  gap: var(--zap-2);
  padding: 6px 10px;
  border-radius: var(--zap-r-sm);
  background: var(--ui-surface-3);
  border: 1px solid var(--ui-line);
  box-shadow: var(--ui-shadow);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;   /* não pode roubar o hover da coluna que descreve */
  transition: opacity 140ms ease, transform 140ms ease;
  z-index: 10;
}

.spark__tip.is-on { opacity: 1; transform: translateX(-50%) translateY(0); }

.spark__tip-d {
  font-family: var(--zap-mono);
  font-size: 11px;
  color: var(--ui-faint);
}

/* Os números carregam a cor da própria barra: assim dá para atribuí-los sem
   voltar na legenda a cada hover. */
.spark__tip-l {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--zap-mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--ui-text);
}

.spark__tip-l i { width: 8px; height: 8px; border-radius: 2px; display: inline-block; }

/* A coluna sob o cursor se destaca; as outras não são apagadas. Escurecer o
   resto faria o gráfico piscar inteiro a cada movimento do mouse. */
.spark__day { transition: opacity 140ms ease; }
.spark__day.is-hover .spark__in,
.spark__day.is-hover .spark__out { filter: brightness(1.12); }
.spark__day.is-hover { outline: 1px solid var(--ui-line-strong); outline-offset: 1px; border-radius: 3px; }

@media (prefers-reduced-motion: reduce) {
  .spark__tip, .spark__day, .seg button, .logbar__find input { transition: none; }
  .spark__tip.is-on { transform: translateX(-50%); }
}

/* --- Busca dentro da coluna -------------------------------------------------
   Saiu da barra superior: lá ela ficava longe dos resultados e sumia junto com
   a barra ao rolar — exatamente quando a lista está longa e procurar importa.

   Herda .search de app-ui.css e só desfaz o que era do contexto anterior: o
   flex de 420px e o teto de 460px, que na coluna de 264px não fazem sentido. */

.fleet__search {
  order: 0;              /* trava a ordem do DOM: ver nota em app-ui.css */
  flex: none;
  max-width: none;
  margin: 0 var(--zap-3) var(--zap-2);
}

.fleet__search input {
  height: 34px;
  font-size: 13px;
  padding: 0 34px 0 34px;
  border-radius: var(--zap-r-sm);
}

/* O `top` de .search é um valor absoluto calibrado para o campo de 38px da
   barra superior. Com 34px aqui, ícone e tecla ficariam 2px fora de centro —
   então centralizo de verdade em vez de recalcular outra constante. */
.fleet__search svg {
  width: 15px;
  height: 15px;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
}

.fleet__search kbd {
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
}

/* --- Barra superior no celular ----------------------------------------------
   Com o trocador ocupando o meio, e-mail e "Sair" por extenso não cabem. O
   e-mail sai (o nome já identifica a conta) e o resto vira só ícone. */

@media (max-width: 900px) {
  .topbar__in { flex-wrap: nowrap; gap: var(--zap-2); }

  /* A marca fica: é a âncora de onde você está, e o ícone custa 22px. Só o
     letreiro sai, e apenas quando o trocador precisa da largura. */
  .topbar .who #who-email { display: none; }

  .switcher { margin-right: auto; }

  .topbar .who .u { padding: 4px; }
  .topbar .who #who-name { font-size: 13px; }

  /* Alvo de 44px nos ícones da barra: eles têm 36px, o que passa no mouse e
     erra no polegar. Cresce por fora, o desenho fica igual.

     Em ::before, não ::after: ::after é da bolha da tooltip (.tip), e os dois
     disputando o mesmo pseudo-elemento produziriam um deles quebrado.
     (A regra antiga também cobria #logout-btn, que hoje vive dentro do menu
     da conta e não na barra — saiu junto.) */
  .topbar .icon-btn { position: relative; }

  .topbar .icon-btn::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
  }
}

/* Telas estreitas de verdade: some o letreiro, não o ícone. */
@media (max-width: 520px) {
  .brand__word { display: none; }
  .brand { gap: 0; }
  .switcher { max-width: 44vw; }
  .topbar .who #who-name { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .fleet { transition: none; }
  .fleet__scrim { transition: none; }
  .switcher__chev { transition: none; }
}

/* --- Inicial da conta -------------------------------------------------------
   O botão de conta guarda nome e e-mail. Abaixo de 520px os dois saem por
   falta de espaço, e sem nada dentro ele vira um botão de largura zero:
   invisível, inalcançável, e a tela de plano e senha some do celular.

   A inicial custa 26px e ainda carrega identidade — é o que um avatar faria,
   sem pedir upload de imagem nem inventar uma cor por usuário. */

.who__ini { display: none; }

@media (max-width: 520px) {
  .who__ini {
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    border-radius: 999px;
    background: var(--ui-accent-soft);
    color: var(--ui-accent);
    font-size: 12px;
    font-weight: 700;
    line-height: 1;
  }

  /* Alvo de 44px por fora, sem inflar o círculo de 26px. */
  .topbar .who .u {
    position: relative;
    min-width: 44px;
    min-height: 44px;
    display: grid;
    place-items: center;
  }
}

/* --- Avatar da conexão ------------------------------------------------------
   Foto de perfil do número, re-hospedada por nós (a URL da CDN do WhatsApp
   expira). Substitui o ponto de estado em vez de acompanhá-lo: identidade e
   liveness são lidas juntas, então são um objeto só.

   O anel aparece SÓ quando há o que dizer. Conexão caída não ganha anel cinza
   — viraria ruído de borda em toda linha offline — e sim dessaturação: a foto
   apagada parece morta, que é exatamente o sentimento.

   Nenhuma cor por conexão no fallback: a foto já traz cor própria, e inventar
   uma paleta por linha competiria com o único sinal que importa. */

.av {
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  width: var(--av, 28px);
  height: var(--av, 28px);
  border-radius: 999px;
  overflow: hidden;
  background: var(--ui-surface-3);
  /* Sem foto e sem anel, o círculo sumiria no fundo do item. */
  border: 1px solid var(--ui-line);
  /* Caída: apagada. */
  filter: grayscale(1);
  opacity: 0.55;
  transition: filter 180ms ease, opacity 180ms ease, box-shadow 180ms ease;
}

.av img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* A inicial fica ATRÁS da foto, não no lugar dela: se a imagem falhar e o
   onerror a remover, a letra já está desenhada embaixo — sem pisca-pisca e
   sem segundo caminho de renderização. */
.av__ini {
  font-weight: 700;
  line-height: 1;
  color: var(--ui-muted);
  user-select: none;
}

.av.is-on {
  filter: none;
  opacity: 1;
  border-color: transparent;
  box-shadow: 0 0 0 2px var(--ui-accent-fill);
}

.av.is-pairing {
  filter: none;
  opacity: 1;
  border-color: transparent;
  box-shadow: 0 0 0 2px var(--ui-amber-fill);
}

/* Tamanhos. O anel vive em box-shadow, então a caixa não muda de tamanho e
   nada reflui quando a conexão sobe ou cai. */
.av--xs { --av: 20px; }
.av--xs .av__ini { font-size: 9px; }

.av--sm { --av: 28px; }
.av--sm .av__ini { font-size: 11.5px; }

.av--lg { --av: 40px; }
.av--lg .av__ini { font-size: 16px; }

/* O cabeçalho da conexão passa a ser avatar + bloco de texto. */
.line__id {
  display: flex;
  align-items: center;
  gap: var(--zap-3);
  min-width: 0;
}

/* O anel precisa de folga para não encostar no vizinho: box-shadow não ocupa
   espaço de layout, então o espaçamento é dado aqui. */
.fleet__item { column-gap: var(--zap-3); }
.fleet__item .av { margin-left: 2px; }

@media (prefers-reduced-motion: reduce) {
  .av { transition: none; }
}

/* --- Aba Perfil -------------------------------------------------------------
   Como o número se apresenta aos contatos. Tudo aqui fala com o WhatsApp, não
   com o nosso banco — por isso exige a linha no ar. */

.av--xl { --av: 72px; }
.av--xl .av__ini { font-size: 28px; }

.perfil__id {
  display: flex;
  align-items: center;
  gap: var(--zap-4);
  flex-wrap: wrap;
}

.perfil__id-acoes {
  display: flex;
  align-items: center;
  gap: var(--zap-2);
  flex-wrap: wrap;
  min-width: 0;
}

.perfil__id-acoes .panel__hint { flex: 1 1 100%; margin: 0; }

#perfil-recado {
  width: 100%;
  resize: vertical;
  min-height: 60px;
  font-family: inherit;
  /* 14px e não 12.5: o recado é texto que se lê, não dado que se confere —
     e é o mesmo tamanho em que o contato vai vê-lo. */
  font-size: 14px;
  line-height: 1.5;
  padding: 10px 12px;
  border: 1px solid var(--ui-line);
  border-radius: var(--zap-r-sm);
  background: var(--ui-surface-2);
  color: var(--ui-text);
  transition: border-color 150ms ease, background 150ms ease;
}

#perfil-recado:focus {
  outline: none;
  border-color: var(--ui-accent-fill);
  background: var(--ui-surface);
}

/* --- Privacidade ------------------------------------------------------------
   Rótulo + explicação à esquerda, opções à direita. A explicação não é enfeite:
   "Confirmação de leitura" desligada também esconde a leitura DAS mensagens
   recebidas, e quem não souber disso vai desligar sem querer. */

.priv { display: grid; }

.priv__linha {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--zap-4);
  padding: var(--zap-3) 0;
  border-top: 1px solid var(--ui-line);
  flex-wrap: wrap;
}

.priv__linha:first-child { border-top: 0; }

.priv__texto { min-width: 0; flex: 1 1 220px; }

.priv__nome {
  display: block;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.3;
}

.priv__desc {
  display: block;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ui-faint);
  margin-top: 2px;
}

.priv__seg { flex: none; }
.priv__seg button { font-size: 11.5px; padding: 6px 9px; }

/* Em voo: a chamada ao WhatsApp leva quase um segundo. Sem sinal, a marcação
   otimista pareceria instantânea e a falha viria do nada. */
.priv__seg.is-saving { opacity: 0.55; pointer-events: none; }

@media (max-width: 640px) {
  .priv__linha { flex-direction: column; align-items: stretch; }
  .priv__seg { display: flex; }
  .priv__seg button { flex: 1; }
}

@media (prefers-reduced-motion: reduce) {
  #perfil-recado { transition: none; }
}

/* O segmentado de mensagens temporárias em linha própria: .seg é inline-flex,
   e o botão "Aplicar" ao lado entraria no mesmo bloco visual, lendo como uma
   quinta opção em vez da ação que confirma as quatro. */
.temp-linha { margin: var(--zap-3) 0; }

/* --- Menu da conta ----------------------------------------------------------
   Um avatar no topo, e atrás dele tudo que é de uso eventual: identidade,
   documentação, tema e sair.

   A barra superior existe para dizer ONDE VOCÊ ESTÁ — marca, e no celular qual
   conexão. Nome e e-mail permanentes ali eram espaço fixo comprado com uso
   semanal; agora aparecem no cabeçalho do menu, lidos quando importam. */

.acct { position: relative; }

.acct__btn {
  display: grid;
  place-items: center;
  width: 44px;              /* alvo de 44 sem inflar o avatar de 28 */
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  cursor: pointer;
  transition: background 150ms ease;
}

.acct__btn:hover { background: var(--ui-surface-2); }

.acct__btn:focus-visible {
  outline: 2px solid var(--ui-accent-fill);
  outline-offset: -2px;
}

/* O avatar da conta reusa .av, mas ele é identidade e não estado de conexão:
   sem anel verde e sem dessaturação. O modificador is-on só existe ali para
   desligar o cinza — aqui não há linha para estar no ar. */
.acct .av {
  box-shadow: none;
  border-color: var(--ui-line);
  background: var(--ui-accent-soft);
}

.acct .av__ini { color: var(--ui-accent); }

.acct__menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  width: 260px;
  padding: var(--zap-2);
  border: 1px solid var(--ui-line);
  border-radius: var(--zap-r-md);
  background: var(--ui-surface);
  box-shadow: var(--ui-shadow-lg);   /* flutua: mesma exceção do véu e da tooltip */
  z-index: 50;
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 150ms ease, transform 150ms ease;
}

.acct__menu.is-on { opacity: 1; transform: none; }

/* `hidden` precisa do par explícito: a regra do navegador tem especificidade
   mínima e qualquer `display` daqui a venceria — foi assim que o scrim da
   gaveta comeu a tela inteira. */
.acct__menu[hidden] { display: none; }

.acct__head {
  display: flex;
  align-items: center;
  gap: var(--zap-3);
  padding: var(--zap-3);
  border-bottom: 1px solid var(--ui-line);
  margin-bottom: var(--zap-2);
}

.acct__quem { min-width: 0; }

.acct__quem strong {
  display: block;
  font-size: 13.5px;
  font-weight: 700;
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.acct__quem span {
  display: block;
  font-size: 12px;
  color: var(--ui-muted);
  line-height: 1.35;
  margin-top: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.acct__item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 10px var(--zap-3);
  border: 0;
  border-radius: var(--zap-r-sm);
  background: transparent;
  color: var(--ui-text);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease;
}

.acct__item:hover { background: var(--ui-surface-2); }

.acct__item:focus-visible {
  outline: 2px solid var(--ui-accent-fill);
  outline-offset: -2px;
}

/* Sair fica vermelho só no hover: é saída, não perigo — pintá-lo o tempo todo
   gastaria o vermelho que o painel reserva para falha de entrega. */
.acct__sair {
  border-top: 1px solid var(--ui-line);
  border-radius: 0 0 var(--zap-r-sm) var(--zap-r-sm);
  margin-top: var(--zap-2);
  padding-top: var(--zap-3);
}

.acct__sair:hover { color: var(--ui-red); background: var(--ui-red-soft); }

@media (prefers-reduced-motion: reduce) {
  .acct__menu, .acct__btn, .acct__item { transition: none; }
  .acct__menu.is-on { transform: none; }
}
