/* ===== 04-lista.css — cards das listas, badges, painéis do /admin, botão de ícone, busca =====
   Fatia do antigo app.css (09/08/2026). O NÚMERO NO NOME É A POSIÇÃO NA CASCATA: é a ordem
   dos <link> no index.html, e trocá-la muda quem vence. Regra e política em 01-base.css. */

/* Cliente — lista/cartão */
.cliente-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .6rem;
}

.cliente-card {
    display: flex;
    flex-direction: column;
    gap: .6rem;
    padding: .85rem .9rem;
    border: 1px solid var(--line);
    border-radius: .7rem;
    background: #fff;
}

.cliente-card.is-inactive, .cliente-card.is-archived { opacity: .65; }

/* Destaque temporário ao voltar de outra tela posicionado neste card (ver scrollHelper.js) */
.cliente-card.is-focado { animation: cardFoco 2.2s ease-out; }
@keyframes cardFoco {
    0%, 55% { box-shadow: 0 0 0 3px var(--brand); }
    100% { box-shadow: 0 0 0 3px transparent; }
}
@media (prefers-reduced-motion: reduce) {
    .cliente-card.is-focado { animation: none; box-shadow: 0 0 0 3px var(--brand); }
}

.cliente-card-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: .5rem;
}

.cliente-info { display: flex; flex-direction: column; gap: .2rem; min-width: 0; flex: 1 1 auto; }
.cliente-info strong { font-size: 1rem; }

/* Coluna de horário à esquerda do card da Agenda — início sobre fim, empilhados (ver HorarioColuna) */
.agenda-card-horario {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    flex-shrink: 0;
    min-width: 2.8rem;
    line-height: 1.2;
}
.agenda-card-horario strong { font-size: .95rem; }
.agenda-card-horario-fim { font-size: .78rem; color: var(--muted); }

/* Nome do cliente no card da Agenda — maior que o padrão de .cliente-info strong (1rem): na lista
   do dia é por ele que se identifica a visita de relance, com o celular na mão e sol na tela.
   Classe própria em vez de mexer no global, que vale para Clientes/Orçamentos/OS/Recebimentos. */
.agenda-card-nome { font-size: 1.3rem; font-weight: 800; color: var(--ink); line-height: 1.2; }

/* Trunca com reticências em vez de quebrar linha — usado onde o título já é uma frase longa
   (hora + nome do cliente, Agenda) e o espaço lateral é disputado com badges. */
.truncate-line { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.cliente-name-row { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }

/* Linha de datas do card (hoje só /orcamentos). O ícone de calendário é o que faz "12/08/2026 ·
   vence 05/09/2026" ser lido como datas sem gastar largura escrevendo a palavra; quem não vê a tela
   recebe o mesmo pelo .sr-only que abre a linha, já que o <Icon> é aria-hidden. */
/* Menor que as demais linhas do card de propósito: a 390px, "12/08/2026 · vence 05/09/2026" no
   tamanho padrão quebra em duas linhas e cada card cresce uma linha inteira — data é referência, não
   identidade, e não vale esse espaço numa lista que se percorre rolando. */
.card-datas { display: flex; align-items: center; gap: .3rem; font-size: .82rem; }
.card-datas .icon { width: .9rem; height: .9rem; flex-shrink: 0; }

.cliente-info-line { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; }
.cliente-info-line-end { text-align: right; flex-shrink: 0; }

.cliente-card-actions { display: flex; gap: .25rem; flex-shrink: 0; align-self: flex-start; }

/* Puxa o botão de ações pra mais perto da borda direita do card (Agenda, Orçamentos, OS) — o alvo
   de toque de 2.75rem do icon-btn sobra bastante respiro em volta do ícone; a margem negativa
   compensa isso visualmente sem reduzir a área de toque. */
.cliente-card-actions.is-edge { margin-right: -.75rem; }

/* Faixa de badges do card, nas 5 listas — uma linha própria ABAIXO do bloco de texto, irmã do
   .cliente-card-header, nunca uma coluna à direita dele.
   Até 2026-08-04 era coluna dentro do header, com flex-shrink:0, e cobrava largura fixa de uma linha
   que já tinha o texto e os botões de ação (na Agenda, mais a coluna de horário). Uma badge
   "Orçamento" custa ~80px: em tela de 360px sobravam ~125px para nome, título, observação e
   endereço, e o endereço quebrava em duas linhas. Aqui a largura é toda do texto e o custo vai para
   a altura — barato numa lista que rola, e em card de 3+ badges a altura até diminui (elas deixam
   de empilhar). Três coisas que quebram em silêncio se esquecidas:
   (a) flex-wrap não é detalhe — cinco badges não cabem em 360px, e sem ele o pior caso espreme ou
       vaza em vez de virar duas linhas. Scroll horizontal está descartado de propósito: esconderia
       informação atrás de um gesto que ninguém descobre dentro de um card;
   (b) numa linha o olho lê da esquerda, então a ORDEM passa a valer — alerta → estado → financeiro
       → vínculo, ver docs/ui-padroes.md. Empilhada em coluna ela era quase invisível e por isso
       divergia entre as listas;
   (c) o container só deve ser emitido quando há ao menos uma badge (ver o @if de Lembretes e do card
       completo da Agenda): vazio ele ainda é item do flex em coluna do .cliente-card e consome o
       gap de .6rem, que aparece como sobra no pé do card.
   A margem negativa aproxima a faixa do bloco de texto: aquele gap de .6rem é dimensionado para
   separar blocos, não para uma fileira de rótulos do mesmo registro. */
.cliente-card-badges {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .3rem;
    margin-top: -.2rem;
}

/* Variante do cliente-card-header (Orçamentos) que centraliza o botão de ações verticalmente com o
   bloco de texto, em vez do padrão flex-start (que alinha tudo pelo topo). Valia também para as
   badges, até elas saírem do header (acima). */
.cliente-card-header-vcenter { align-items: center; }
.cliente-card-header-vcenter .cliente-card-actions { align-self: center; }

/* Badge de situação — só "Inativo" é exibido; "Ativo" é o padrão implícito */
.badge {
    display: inline-block;
    white-space: nowrap;
    font-size: .75rem;
    font-weight: 600;
    padding: .2rem .6rem;
    border-radius: 999px;
}

.badge-inactive, .badge-archived { background: var(--line); color: var(--ink-soft); }
.badge-principal { background: var(--brand-tint); color: var(--brand-dark); }

/* Badge de status do Orçamento */
.badge-rascunho { background: var(--line); color: var(--ink-soft); }
.badge-enviado { background: var(--wait-tint); color: var(--wait); }
.badge-aprovado { background: var(--ok-tint); color: var(--ok); }
.badge-recusado { background: var(--danger-tint); color: var(--danger); }

/* Badge de validade vencida (S5) — some quando o orçamento é reaberto/editado, nunca é o único sinal (também no texto do aviso da página pública) */
.badge-vencido { background: var(--danger-tint); color: var(--danger); }

.badge-agendamento { background: var(--wait-tint); color: var(--wait); }
.badge-os { background: var(--ok-tint); color: var(--ok); }

/* OS ainda Aberta — trabalho pendente, então tom de espera (mesmo do badge-agendamento), não o
   verde do badge-os. Um "OS" único pros dois estados fazia o card parecer mais adiantado do que
   está: OS aberta é justo o que segura o Concluído do orçamento (ADR 0007). */
.badge-os-aberta { background: var(--wait-tint); color: var(--wait); }

/* Badge de orçamento ligado (Agenda) — só indica o vínculo; a navegação é botão no BottomSheet.
   Tom de marca pra distinguir do badge-agendamento (wait) e do badge-os (ok). */
.badge-orcamento { background: var(--brand-tint); color: var(--brand-dark); }

/* Concluído (ADR 0007) — desfecho de sucesso, derivado de agenda/OS. Preenchido (não tint) pra
   ler como "selado/encerrado", distinto do Aprovado (tint) que ainda está no fluxo ativo. */
.badge-concluido { background: var(--ok); color: #fff; }

/* Badge de item ainda não sincronizado com o servidor (S9 — criado/alterado offline, na fila) */
.badge-pendente { background: var(--wait-tint); color: var(--wait); }

/* "Visto" — o cliente abriu o link público. Sinal positivo (o link chegou e a proposta foi lida),
   então tom de ok em tint, no mesmo nível do badge-aprovado; nunca preenchido, que é do Concluído.
   O par "Não abriu" reusa o .badge-rascunho (cinza neutro) de propósito: não é erro nem alerta —
   vermelho ali gritaria em todo orçamento recém-enviado e ensinaria o prestador a ignorar o badge. */
.badge-visto { background: var(--ok-tint); color: var(--ok); }

/* Código de convite (/admin) — monoespaçado e espaçado porque ele é DITADO por WhatsApp e conferido
   caractere a caractere. Na fonte de texto do app, um código lido de relance é onde "0" vira "O";
   o alfabeto do gerador já evita os pares ambíguos, e a tipografia faz a outra metade do trabalho. */
.convite-codigo {
    font-family: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, monospace;
    font-size: 1.05rem;
    letter-spacing: .08em;
}

/* Senha temporária recém-gerada (/admin, entrega 04). Bloco destacado e não mais uma linha da lista
   de ações: ela aparece UMA vez, e o que a distingue das outras linhas do sheet é justamente que
   perdê-la de vista custa outra rodada de reset. Reusa a tipografia do .convite-codigo — mesmo
   alfabeto, mesmo caminho (ditada/colada num WhatsApp). */
.senha-reset {
    display: flex;
    flex-direction: column;
    gap: .4rem;
    padding: .75rem;
    border: 1px solid var(--line);
    border-radius: .8rem;
    background: var(--bg);
}

/* Números da validação (/admin, entrega 06) — M1-M5 do PRD. Lista de "rótulo → valor", sem gráfico
   e sem tile: aqui os números não são atalho para lugar nenhum (não filtram, não abrem tela), e o
   que se faz com eles é comparar com o alvo escrito ao lado. O <dt>/<dd> é o que dá isso de graça
   para o leitor de tela: a relação entre o nome da métrica e o número é a estrutura, não a posição. */
.metricas-lista {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: .35rem .75rem;
    margin: 0;
    font-size: .9rem;
}

.metricas-lista dt { color: var(--ink-soft); }
/* Quebra de uma métrica nos tipos que a compõem (M5) — recuo em vez de outro nível de título:
   continua sendo a mesma lista, só que uma camada abaixo. */
.metricas-lista .metricas-detalhe { padding-left: .75rem; }
.metricas-lista dd { margin: 0; text-align: right; font-weight: 700; color: var(--ink); }
/* Segundo <dd> do mesmo termo: a explicação da métrica. Ocupa a linha inteira e desfaz o alinhamento
   à direita do valor — é frase, não número. */
.metricas-lista .metricas-sub {
    grid-column: 1 / -1;
    margin: -.15rem 0 .35rem;
    text-align: left;
    font-weight: 400;
}

/* "O que quebrou nos aparelhos" (/admin) — um bloco por assinatura de erro. Lista e não <dl> como as
   métricas acima: ali cada linha é rótulo → número, aqui cada item é um problema com quatro fatos
   sobre ele, e forçá-lo na grade de duas colunas espremeria a mensagem da exceção, que é justamente
   o que se lê primeiro. */
.lista-erros {
    list-style: none;
    margin: .5rem 0 0;
    padding: 0;
    display: grid;
    gap: .5rem;
}

.erro-grupo {
    border: 1px solid var(--line);
    border-radius: .6rem;
    padding: .6rem .7rem;
    /* Load-bearing: item de grade nasce com min-width:auto, então o <pre> da pilha (linhas de 300+
       caracteres, sem espaço onde quebrar) estica o <li> e a PÁGINA INTEIRA passa a rolar na
       horizontal — 3693px num viewport de 375. O overflow-x do <pre> só age depois disto. */
    min-width: 0;
}

.erro-grupo p { margin: 0; }

/* Sem space-between: com ele o selo espremia o nome do tipo contra a margem e
   "System.Text.Json.JsonException" quebrava em "JsonExcepti / on" num celular de 390px. O nome é
   identificador e precisa da linha inteira; o selo desce sozinho quando não couber. */
.erro-titulo {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: .35rem .5rem;
    font-size: .85rem;
    overflow-wrap: anywhere;
}

/* A mensagem é o que identifica o bug — fonte de código porque muitas trazem nome de tipo, caminho e
   aspas, e proporcional embaralha os três. */
.erro-mensagem {
    margin-top: .25rem !important;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .8rem;
    color: var(--ink);
    word-break: break-word;
}

/* Pilha: fechada por padrão (são ~4 KB e o painel se lê no celular). Rola na horizontal dentro do
   próprio bloco — quadro de pilha não se quebra em linhas sem virar sopa. */
.erro-pilha { margin-top: .35rem; font-size: .75rem; }
.erro-pilha summary { cursor: pointer; color: var(--ink-soft); }

.erro-pilha pre {
    margin: .35rem 0 0;
    padding: .4rem;
    overflow-x: auto;
    background: var(--line);
    border-radius: .4rem;
    font-size: .7rem;
    line-height: 1.35;
}

/* Botão só-ícone das ações de card (Editar/Endereços/Equipamentos) */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    color: var(--brand);
    background: transparent;
    border: none;
    border-radius: .5rem;
    text-decoration: none;
    cursor: pointer;
}

.icon-btn .icon { width: 1.25rem; height: 1.25rem; }

.icon-btn:active { background: var(--brand-tint); }

/* Ação destrutiva de card (Descartar, na bandeja de erros de sincronização). Cor de perigo no lugar
   da marca — o peso de "não dá pra desfazer" quem carrega é a confirmação, mas o botão não pode se
   parecer com o "Editar" do card ao lado. */
.icon-btn.is-danger { color: var(--danger); }
.icon-btn.is-danger:active { background: var(--danger-tint); }

/* Botão de busca por voz (protótipo) — pulsa em vermelho enquanto está ouvindo */
.icon-btn.is-listening { color: var(--danger); animation: pulse-listening 1.2s ease-in-out infinite; }

@keyframes pulse-listening {
    0%, 100% { opacity: 1; }
    50% { opacity: .45; }
}

/* Botão de atualizar lista (Orçamentos) — ícone gira enquanto a revalidação está em andamento */
.icon-btn.is-spinning .icon { animation: spin 0.9s linear infinite; }

@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

/* Campo de busca da lista */
.search-row { display: flex; align-items: center; gap: .5rem; margin-bottom: .75rem; }
.search-row .input { flex: 1; }

