/* ACM Sistema — componentes: botão, campo, tabela, alerta, abas, badge */

/* ---------------------------------------------------------------
   Botões
   --------------------------------------------------------------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 38px;
    padding: 8px 16px;
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    background: var(--superficie);
    color: var(--texto);
    font-weight: 600;
    font-size: .93rem;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
}
.btn:hover { background: var(--cinza-claro); text-decoration: none; color: var(--texto); }
.btn:disabled { opacity: .55; cursor: not-allowed; }

.btn--primario { background: var(--acao); border-color: var(--acao); color: #fff; }
.btn--primario:hover { background: var(--acao-hover); border-color: var(--acao-hover); color: #fff; }

.btn--perigo { background: var(--erro); border-color: var(--erro); color: #fff; }
.btn--perigo:hover { background: var(--erro-forte); border-color: var(--erro-forte); color: #fff; }

.btn--texto { border-color: transparent; background: none; color: var(--texto-suave); }
.btn--texto:hover { background: var(--cinza-claro); color: var(--texto); }

.btn--bloco { width: 100%; }

.btn--icone {
    width: 34px;
    min-height: 34px;
    padding: 0;
    color: var(--texto-suave);
}
.btn--icone:hover { color: var(--azul); border-color: var(--azul); }

/* ---------------------------------------------------------------
   Campos
   --------------------------------------------------------------- */
.campo { display: flex; flex-direction: column; gap: 5px; }

.campo__rotulo { font-size: .87rem; font-weight: 600; color: var(--texto-suave); }
.campo__rotulo::after { content: ""; }
.campo__rotulo--obrigatorio::after { content: " *"; color: var(--erro); }

.campo__entrada {
    width: 100%;
    min-height: 38px;
    padding: 8px 10px;
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    background: var(--superficie);
}
.campo__entrada:focus { border-color: var(--azul); outline: 2px solid var(--azul-suave); outline-offset: 0; }
.campo__entrada:disabled, .campo__entrada[readonly] { background: var(--cinza-claro); color: var(--texto-suave); }
.campo__entrada--erro { border-color: var(--erro); }

.campo__erro { color: var(--erro); font-size: .82rem; }
.campo__ajuda { color: var(--texto-suave); font-size: .82rem; }

/* Checkbox solto num formulário: a caixa e o texto são um alvo de clique só,
   e o alvo tem altura de dedo — a tela fiscal é usada em tablet no balcão. */
.campo__caixa {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 38px;
    font-size: .93rem;
    cursor: pointer;
}

.campo__caixa input[type="checkbox"] {
    width: 18px;
    height: 18px;
    accent-color: var(--azul);
    cursor: pointer;
    flex: 0 0 auto;
}

/* Linha de registro inativo: apagada, mas ainda legível — some do foco sem
   sumir da tela. */
.linha--inativa { opacity: .55; }

.campo__senha { position: relative; display: flex; }
.campo__senha .campo__entrada { padding-right: 42px; }
.campo__olho {
    position: absolute;
    right: 4px; top: 50%;
    transform: translateY(-50%);
    display: grid;
    place-items: center;
    width: 32px; height: 32px;
    border: 0;
    background: none;
    color: var(--texto-suave);
    cursor: pointer;
}

textarea.campo__entrada { min-height: 84px; resize: vertical; }

.linha-campos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 14px;
}

/* ---------------------------------------------------------------
   Abas do formulário (docs/15-padrao-telas.md)
   --------------------------------------------------------------- */
.abas {
    display: flex;
    gap: 2px;
    border-bottom: 1px solid var(--cinza);
    overflow-x: auto;
}

/* O `a` entra junto porque existe um caso em que a aba é ENDEREÇO, e não
   painel escondido: em Aparelhos cada aba carrega a própria consulta, os
   próprios contadores e a própria paginação (docs/29-dispositivos.md). Ali a
   aba precisa poder ser recarregada e aberta em outra janela — coisa que um
   botão de JavaScript não faz. Mesma fita, mesma aparência. */
.abas button,
.abas a {
    position: relative;
    padding: 10px 18px;
    border: 0;
    border-bottom: 3px solid transparent;
    background: none;
    color: var(--texto-suave);
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
}
.abas a {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    text-decoration: none;
}
.abas button:hover,
.abas a:hover { color: var(--texto); text-decoration: none; }
.abas button[aria-selected="true"],
.abas a[aria-selected="true"] { color: var(--azul); border-bottom-color: var(--azul); }

/* Ponto vermelho: a aba tem campo com erro */
.abas button[data-erro="1"]::after {
    content: "";
    position: absolute;
    top: 8px; right: 8px;
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--erro);
}

.aba { display: none; padding: 20px 0; }

/* Flex em coluna, e não block: é o `gap` que separa um campo do outro dentro
   da aba. A troca de aba é feita por classe, nunca por `style.display`, então
   mudar o display aqui não atrapalha o JS. */
.aba--ativa {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

/* ---------------------------------------------------------------
   Cartão / painel de conteúdo
   --------------------------------------------------------------- */
.caixa {
    background: var(--superficie);
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    box-shadow: var(--sombra);
}
/* Respiro dentro da caixa: título, texto, formulário e botões encostavam uns
   nos outros — o reset zera a margem de tudo e nenhum deles trazia a sua.
   O `gap` some sozinho quando o bloco não é renderizado, coisa que
   `margin-bottom` no filho não faz. */
.caixa__corpo {
    padding: var(--espaco);
    display: flex;
    flex-direction: column;
    gap: 14px;
}

/* Formulário empilhado direto na caixa: sem isso um campo cola no seguinte,
   e o último cola na fileira de botões logo abaixo.

   O `:not([hidden])` é obrigatório: existe o form auxiliar que só carrega uma
   action para um botão ligado por `form=`, e `display: flex` aqui venceria o
   `[hidden]` do navegador — o form invisível voltaria a ocupar uma linha. */
.caixa__corpo:not(.acoes-venda) > form:not([hidden]) {
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.caixa__rodape {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    padding: 12px var(--espaco);
    border-top: 1px solid var(--cinza);
    background: var(--fundo);
    border-radius: 0 0 var(--raio) var(--raio);
}

/* ---------------------------------------------------------------
   Filtros da listagem
   --------------------------------------------------------------- */
.filtros {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    align-items: flex-end;
    padding: 12px var(--espaco);
    border-bottom: 1px solid var(--cinza);
}
.filtros .campo { flex: 1; min-width: 200px; }

/* ---------------------------------------------------------------
   Tabela
   --------------------------------------------------------------- */
.tabela-rolagem { overflow-x: auto; }

/* A janela do troco (public/assets/js/alerta.js).

   Mesma coluna da janela do estoque: o SweetAlert2 não alinha nada sozinho. */
.troco-modal { display: flex; flex-direction: column; gap: 12px; text-align: left; }

.troco-modal__valor { margin: 0; text-align: center; }

.troco-modal__campo { display: flex; flex-direction: column; gap: 4px; }

.troco-modal__campo > span {
    font-size: .82rem;
    font-weight: 600;
    color: var(--texto-suave);
}

.troco-modal .swal2-input {
    margin: 0;
    width: 100%;
    box-sizing: border-box;
    font-size: 1.35rem;
    text-align: right;
}

/* O troco em corpo grande: é o número que a pessoa vai contar da gaveta. */
.troco-modal__saida {
    margin: 0;
    text-align: center;
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--sucesso);
}

.troco-modal__saida--erro { color: var(--erro); font-weight: 600; font-size: .95rem; }

/* A janela de movimentação do estoque (public/assets/js/alerta.js).

   O SweetAlert2 empilha o que vier no `html` sem alinhar nada: cada
   `swal2-input` traz margem própria e largura automática, e o resultado era o
   saldo na mesma linha da quantidade e o motivo mais estreito, um degrau
   abaixo. Aqui a coluna é declarada, e os dois campos têm a mesma largura. */
.estoque-modal { display: flex; flex-direction: column; gap: 14px; text-align: left; }

.estoque-modal__saldo { margin: 0; text-align: center; }

.estoque-modal__campo { display: flex; flex-direction: column; gap: 4px; }

.estoque-modal__campo > span {
    font-size: .82rem;
    font-weight: 600;
    color: var(--texto-suave);
}

.estoque-modal__campo > span em { font-style: normal; font-weight: 400; }

/* Os dois depósitos dentro da janela do estoque — Loja e Fábrica (30/08/2026).

   É o `.opcoes-botao` do faturamento, e não um componente novo: mesma escolha
   de uma opção entre poucas, mesmo alvo de dedo, mesmo rádio por baixo. Só
   muda o formato — aqui cada opção divide a largura e carrega o SALDO embaixo
   do nome, porque é esse número que decide qual escolher. Um `select`
   esconderia o segundo saldo atrás de um clique, e é o par que informa. */
.opcoes-botao--depositos { flex-wrap: nowrap; margin-top: 0; }

.opcoes-botao--depositos .opcoes-botao__item { flex: 1; }

/* `display: flex` e não o `inline-flex` que o componente traz: em linha, o
   quadrado encolhe até o texto e encosta na borda esquerda da metade dele — as
   duas opções saíam de tamanhos diferentes e desencontradas no meio da janela.
   Preenchendo o `label`, as duas ficam do mesmo tamanho e simétricas. */
.opcoes-botao--depositos .opcoes-botao__item span {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 2px;
    padding: 9px 8px;
    text-align: center;
    font-size: .85rem;
}

.opcoes-botao--depositos .opcoes-botao__item b { font-size: 1rem; }

/* Zera o que o SweetAlert2 põe por conta própria: a margem vira o `gap` da
   coluna, e a largura passa a ser a da caixa. */
.estoque-modal .swal2-input {
    margin: 0;
    width: 100%;
    box-sizing: border-box;
    font-size: 1rem;
}

/* Estoque no ou abaixo do mínimo, na lista de produtos.

   Vermelho e negrito, sem ícone: a coluna é de números, e um alerta que muda a
   largura da célula faria a coluna inteira dançar a cada página. */
.estoque-baixo { color: var(--erro); font-weight: 700; }

/* O modal da etiqueta de gôndola: qual modelo e quantas (alerta.js, 16/09/2026).

   Rádios em coluna, à esquerda, como uma lista: o modal vai crescer conforme
   o cliente cadastra modelos, e opções lado a lado quebrariam torto na
   terceira. Com um modelo só o rádio nem é desenhado. */
.swal-etiqueta { display: flex; flex-direction: column; gap: 10px; text-align: left; }
.swal-etiqueta__rotulo { margin: 0; font-weight: 600; color: var(--marinho); }
.swal-etiqueta__opcoes { display: flex; flex-direction: column; gap: 6px; }
.swal-opcao { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.swal-etiqueta .swal2-input { margin: 0; width: 100%; box-sizing: border-box; font-size: 1rem; }

.tabela { width: 100%; border-collapse: collapse; font-size: .93rem; }

.tabela caption { text-align: left; padding: 12px var(--espaco); color: var(--texto-suave); }

.tabela th, .tabela td {
    padding: 10px var(--espaco);
    border-bottom: 1px solid var(--cinza);
    text-align: left;
    vertical-align: middle;
}

/* `top: 0` e não `var(--topo)`.
 *
 * O pai `.tabela-rolagem` tem `overflow-x: auto`, e overflow diferente de
 * `visible` faz o elemento virar o containing block do `sticky`. Ou seja: o
 * cabeçalho não gruda na barra do topo da página — ele gruda no container, e
 * o `top: 56px` empurrava o cabeçalho 56px para baixo DENTRO da tabela,
 * cobrindo a primeira linha.
 *
 * Com muitas linhas some só a primeira; com uma linha só, a tabela parece
 * vazia. Foi assim que uma empresa cadastrada "sumiu" da lista.
 */
.tabela thead th {
    position: sticky;
    top: 0;
    background: var(--cinza-claro);
    color: var(--marinho);
    font-size: .82rem;
    text-transform: uppercase;
    letter-spacing: .02em;
    z-index: 1;
}

.tabela thead th a { color: inherit; display: inline-flex; align-items: center; gap: 4px; }

.tabela tbody tr:hover { background: var(--azul-suave); }
.tabela tbody tr.inativo { color: var(--texto-suave); background: var(--fundo); }

.tabela__acoes { width: 1%; white-space: nowrap; text-align: right; }
.tabela__acoes form { display: inline; }

.tabela-vazia { padding: 40px var(--espaco); text-align: center; color: var(--texto-suave); }

/* Lista de pedidos: a linha inteira em negrito e na cor cheia — pedido do
   cliente em 08/09/2026.

   Quem opera esta tela tem dificuldade de enxergar, e ali a hierarquia por tom
   custava caro: o documento, a hora e a contagem de itens vinham em
   `texto-suave`, que no monitor do balcão simplesmente sumia. Aqui o segundo
   plano passa a ser só o tamanho da letra — o contraste é o mesmo em tudo.

   A coluna Ações fica de fora: são botões de ícone, e o cinza deles é o estado
   de repouso, não texto para ler. O badge também: a cor dele carrega a situação
   do pedido (docs/25-tres-status-do-pedido.md) e não pode virar tudo igual. */
.tabela--pedidos tbody td:not(.tabela__acoes),
.tabela--pedidos tbody td:not(.tabela__acoes) :not(.badge) {
    color: var(--texto);
    font-weight: 700;
}

/* O `small` da hora continua menor que a data, mas deixa de ser miúdo. */
.tabela--pedidos tbody small { font-size: .85rem; }

.tabela--pedidos tbody .badge { font-weight: 700; }
.tabela--pedidos tbody .badge--inativo { color: var(--texto); }

/* ---------------------------------------------------------------
   Paginação
   --------------------------------------------------------------- */
.paginacao {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 12px var(--espaco);
    border-top: 1px solid var(--cinza);
}
.paginacao__total { color: var(--texto-suave); font-size: .87rem; margin-right: auto; }
.paginacao__paginas { display: flex; gap: 4px; }
.paginacao__paginas a, .paginacao__paginas span {
    display: grid;
    place-items: center;
    min-width: 34px; height: 34px;
    padding: 0 8px;
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    color: var(--texto);
}
.paginacao__paginas a:hover { background: var(--cinza-claro); text-decoration: none; }
.paginacao__paginas .atual { background: var(--acao); border-color: var(--acao); color: #fff; }

/* ---------------------------------------------------------------
   Alerta em faixa (o modal é SweetAlert2)
   --------------------------------------------------------------- */
.alerta {
    padding: 10px 14px;
    border: 1px solid;
    border-radius: var(--raio);
    font-size: .9rem;
    margin-bottom: 14px;
}
.alerta--sucesso { background: var(--sucesso-fundo); border-color: var(--sucesso-borda); color: var(--sucesso); }
.alerta--erro    { background: var(--erro-fundo); border-color: var(--erro-borda); color: var(--erro); }
.alerta--aviso   { background: var(--alerta-fundo); border-color: var(--alerta-borda); color: var(--alerta); }
.alerta--info    { background: var(--info-fundo); border-color: var(--info-borda); color: var(--info-texto); }

/* Fila de botões que não é o rodapé do formulário: testar conexão, registrar
   webhook. Quebra em telas estreitas em vez de sair da caixa. */
.acoes-linha {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
    margin: 12px 0;
}

/* Campo estreito — porta, conta, código. Encolhe até o limite e para. */
.campo--curto { flex: 0 0 180px; }

/* ---------------------------------------------------------------
   Badge de status — cor + TEXTO, nunca só cor
   --------------------------------------------------------------- */
.badge {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: .78rem;
    font-weight: 600;
    border: 1px solid;
}
.badge--ativo    { background: var(--sucesso-fundo); border-color: var(--sucesso-borda); color: var(--sucesso); }
.badge--inativo  { background: var(--cinza-claro); border-color: var(--cinza); color: var(--texto-suave); }
.badge--atencao  { background: var(--alerta-fundo); border-color: var(--alerta-borda); color: var(--alerta); }
.badge--erro     { background: var(--erro-fundo); border-color: var(--erro-borda); color: var(--erro); }
.badge--info     { background: var(--azul-suave); border-color: var(--info-borda); color: var(--azul); }

/*
 * DEVOLUÇÃO — marrom com escrita branca, escolha do cliente em 01/10/2026:
 * *"o badge vermelho diferente do cancelado, ou marrom com escrita branca,
 * Devolução"* (docs/48-devolucao.md).
 *
 * É o único badge de fundo cheio: os outros cinco são tom suave com texto
 * colorido, e é essa diferença que faz a devolução se destacar na lista sem
 * disputar atenção com o vermelho do cancelado, que está ao lado dela.
 *
 * O marrom é fixo e não vem dos tokens de tema: nenhum dos dois temas tem
 * marrom na paleta, e ele lê bem nos dois — escuro o bastante para o texto
 * branco no claro, claro o bastante para não virar borrão no escuro.
 */
.badge--devolucao {
    background: #6B4423;
    border-color: #6B4423;
    color: #FFF;
}

/* ---------------------------------------------------------------
   Célula de tabela com várias informações

   Aparelhos e impressões põem nome, selo, código e data na mesma
   célula. Feito com `<br>` entre `<span class="badge">`, o resultado
   se encavala: o badge é `inline-block` e tem altura maior que a
   linha de texto, então a linha seguinte sobe por cima dele.

   Empilhar com flex dá o espaçamento certo sem depender de
   `line-height` — e a primeira linha permite quebrar os selos ao lado
   do nome quando a coluna aperta, em vez de estourar a largura.
   --------------------------------------------------------------- */
.celula-empilhada {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.celula-empilhada__titulo {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}

/* Célula com várias linhas alinha pelo topo: `middle` deixa a linha
   curta boiando no meio de uma célula alta ao lado. */
.tabela td.alinha-topo { vertical-align: top; }

/* SweetAlert2: só o mínimo para casar com a marca — e com o tema: o fundo
   vem do token, senão o modal fica branco no escuro. */
.swal2-popup { border-radius: var(--raio); font-family: inherit; background: var(--superficie); color: var(--texto); }
.swal2-title { color: var(--marinho); font-size: 1.15rem; }
.swal2-html-container { color: var(--texto); font-size: .95rem; }

/* ---------------------------------------------------------------
   Grade de permissões (docs/10-acessos.md)

   Módulo por bloco, ações dentro dele. Grade rígida de colunas não
   serve aqui: cada módulo tem um conjunto próprio de ações, e as
   colunas viram célula vazia na maioria das linhas.
   --------------------------------------------------------------- */
.grade-tags {
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    margin-bottom: 12px;
    overflow: hidden;
}

.grade-tags__cabecalho {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding: 10px 14px;
    background: var(--cinza-claro);
    border-bottom: 1px solid var(--cinza);
}

.grade-tags__titulo { font-size: .95rem; }

.grade-tags__mestre {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .85rem;
    color: var(--texto-suave);
    cursor: pointer;
}

.grade-tags__atalhos { display: flex; gap: 4px; flex-wrap: wrap; }
.grade-tags__atalhos .btn { padding: 2px 8px; font-size: .8rem; }

.grade-tags__acoes {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 4px 12px;
    padding: 12px 14px;
}

.grade-tags__item {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 6px 8px;
    border-radius: var(--raio);
    cursor: pointer;
    line-height: 1.3;
}

.grade-tags__item:hover { background: var(--azul-suave); }
.grade-tags__item input { margin-top: 3px; flex: 0 0 auto; }

.grade-tags__chave {
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: .75rem;
}

.grade-tags__tabela { margin: 0; }
.grade-tags__tabela td { vertical-align: middle; }
.grade-tags__tabela input[type="radio"] { width: 18px; height: 18px; cursor: pointer; }

/* Escolha de poucas opções em forma de botão — o documento fiscal do
   faturamento (docs/22-fluxo-pedido-unico.md).

   O rádio continua sendo o input (teclado e leitor de tela seguem funcionando);
   o que muda é o tamanho do alvo: no balcão a escolha é com o dedo, e uma
   bolinha de 18 px não é alvo. */
.opcoes-botao { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }

.opcoes-botao__item { cursor: pointer; }

.opcoes-botao__item input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
}

.opcoes-botao__item span {
    display: inline-flex;
    align-items: center;
    padding: 9px 18px;
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    background: var(--superficie);
    color: var(--texto);
    font-weight: 600;
}

.opcoes-botao__item input:checked + span {
    background: var(--acao);
    border-color: var(--acao);
    color: #fff;
}

.opcoes-botao__item input:focus-visible + span {
    outline: 2px solid var(--azul);
    outline-offset: 2px;
}

/* Fieldset desabilitado (perfil de sistema) continua legível: só não edita. */
fieldset[disabled] .grade-tags__item,
fieldset[disabled] .campo__entrada { opacity: .75; cursor: default; }

/* ---------------------------------------------------------------
   Venda (docs/13-vendas.md)
   --------------------------------------------------------------- */

/* Busca com sugestões — cliente e produto */
.campo { position: relative; }

.sugestoes {
    position: absolute;
    z-index: 30;
    top: 100%;
    left: 0;
    right: 0;
    max-height: 280px;
    overflow-y: auto;
    margin: 2px 0 0;
    padding: 0;
    background: var(--superficie);
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    box-shadow: var(--sombra-alta);
}

.sugestoes__item {
    padding: 8px 12px;
    cursor: pointer;
    line-height: 1.35;
    border-bottom: 1px solid var(--cinza-claro);
}

.sugestoes__item:last-child { border-bottom: 0; }
.sugestoes__item:hover,
.sugestoes__item--ativo { background: var(--azul-suave); }

/* Linha de lançamento do item: o balcão trabalha aqui */
.lancamento {
    display: flex;
    gap: 12px;
    align-items: flex-end;
    flex-wrap: wrap;
    padding: 12px;
    margin-bottom: 12px;
    background: var(--cinza-claro);
    border-radius: var(--raio);
}

.lancamento .campo { margin: 0; }

/* Totais */
.totais { display: flex; flex-direction: column; gap: 6px; }

.totais__linha {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.totais__linha .campo__entrada { max-width: 140px; }

.totais__linha--destaque {
    padding-top: 8px;
    margin-top: 4px;
    border-top: 2px solid var(--marinho);
    font-size: 1.15rem;
    color: var(--marinho);
}

/* `flex-direction` explícito porque há caixa que é `caixa__corpo acoes-venda`
   ao mesmo tempo, e o corpo empilha em coluna: sem declarar a linha aqui, os
   botões dessa caixa cairiam um debaixo do outro. */
.acoes-venda { display: flex; flex-direction: row; gap: 12px; flex-wrap: wrap; align-items: center; }
.acoes-venda form { margin: 0; }

.lista-problemas { margin: 8px 0 0; padding-left: 1.1rem; }
.lista-problemas li { list-style: disc; margin-bottom: 4px; }

/* ---------------------------------------------------------------
   Folha de impressão — orçamento e pedido
   Não é documento fiscal: o DANFE sai da API na fase de emissão.
   --------------------------------------------------------------- */
.folha {
    max-width: 210mm;
    margin: 0 auto;
    padding: 24px;
    background: var(--superficie);
    color: var(--texto);
}

.folha__cabecalho {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 24px;
    padding-bottom: 12px;
    border-bottom: 2px solid var(--marinho);
}

.folha__identificacao { text-align: right; }
.folha__identificacao h1 { font-size: 1.3rem; margin-bottom: 4px; }
.folha__identificacao p { font-size: .85rem; line-height: 1.5; }

.folha__bloco { margin-top: 18px; }
.folha__bloco h2 {
    font-size: .8rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--texto-suave);
    margin-bottom: 6px;
}

.folha__dados,
.folha__itens,
.folha__totais { width: 100%; border-collapse: collapse; font-size: .88rem; }

.folha__dados th {
    text-align: left;
    font-weight: 600;
    color: var(--texto-suave);
    width: 110px;
    padding: 4px 8px 4px 0;
    vertical-align: top;
}

.folha__dados td { padding: 4px 12px 4px 0; }

.folha__itens thead th {
    text-align: left;
    border-bottom: 1.5px solid var(--marinho);
    padding: 6px 6px;
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .03em;
}

.folha__itens tbody td { padding: 6px; border-bottom: 1px solid var(--cinza-claro); }

.folha__rodape {
    display: flex;
    justify-content: space-between;
    gap: 32px;
    margin-top: 20px;
}

.folha__observacao { flex: 1; font-size: .85rem; }
.folha__condicoes { margin-top: 10px; line-height: 1.6; }

.folha__totais { width: 260px; flex: 0 0 260px; }
.folha__totais th { text-align: left; padding: 4px 8px; color: var(--texto-suave); font-weight: 600; }
.folha__totais td { text-align: right; padding: 4px 8px; }

.folha__totais--destaque th,
.folha__totais--destaque td {
    border-top: 2px solid var(--marinho);
    padding-top: 8px;
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--marinho);
}

.folha__aviso {
    margin-top: 20px;
    padding-top: 10px;
    border-top: 1px solid var(--cinza);
    font-size: .78rem;
    color: var(--texto-suave);
}

.folha__acoes { display: flex; gap: 12px; margin-top: 24px; }

/* ---------------------------------------------------------------
   Seletor de empresa no topo (docs/14-configuracoes.md)

   Fica sempre à vista: quem lanca uma venda precisa enxergar em qual
   CNPJ esta lancando, e nao descobrir depois na nota.
   --------------------------------------------------------------- */
.topo__empresa {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
    margin-right: 16px;
    min-width: 0;
}

.topo__empresa-select {
    max-width: 260px;
    padding: 5px 10px;
    background: var(--superficie);
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    font-size: .88rem;
    color: var(--texto);
    cursor: pointer;
}

.topo__empresa-select:hover { border-color: var(--azul); }

.topo__empresa-nome {
    max-width: 260px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 5px 10px;
    background: var(--cinza-claro);
    border-radius: var(--raio);
    font-size: .88rem;
    color: var(--texto-suave);
}

.topo__empresa--vazia {
    padding: 5px 12px;
    background: var(--alerta);
    border-radius: var(--raio);
    color: #fff;
    font-size: .85rem;
    text-decoration: none;
}

.topo__empresa--vazia:hover { color: #fff; text-decoration: underline; }

@media (max-width: 720px) {
    .topo__empresa-select,
    .topo__empresa-nome { max-width: 140px; }
}

/* Emitente no cabecalho da folha impressa */
.folha__emitente { display: flex; flex-direction: column; gap: 8px; }
.folha__emitente p { font-size: .78rem; line-height: 1.45; color: var(--texto-suave); }

.folha__homologacao {
    display: inline-block;
    margin-top: 4px;
    padding: 2px 6px;
    background: var(--alerta);
    border-radius: 3px;
    color: #fff;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .03em;
}

/* ---------------------------------------------------------------
   Foto do produto (docs/11-produtos.md)

   A miniatura tem tamanho fixo: linha de tabela que muda de altura
   conforme a foto faz a lista inteira "pular" ao rolar.
   --------------------------------------------------------------- */
.miniatura {
    display: block;
    width: 40px;
    height: 40px;
    object-fit: cover;
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    background: var(--cinza-claro);
}

.miniatura--vazia {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--texto-suave);
    font-size: .8rem;
}

/* Sugestão de produto na venda: foto à esquerda, texto à direita */
.sugestoes__item { display: flex; align-items: center; gap: 10px; }
.sugestoes__foto { flex: 0 0 40px; }
.sugestoes__texto { flex: 1; min-width: 0; }

/* Bloco da foto no cadastro */
.foto-produto { display: flex; gap: 20px; align-items: flex-start; flex-wrap: wrap; }

/* Altura fixa em vez de `aspect-ratio`: dentro de um flex container o
   aspect-ratio depende de como a base é resolvida e a caixa mudava de altura
   conforme a foto. Quadrado de 180px, sempre igual, com ou sem imagem. */
.foto-produto__atual {
    flex: 0 0 180px;
    width: 180px;
    height: 180px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    background: var(--cinza-claro);
    overflow: hidden;
}

/* `contain` para a etiqueta aparecer inteira: `cover` cortaria justamente a
   borda, que é o que diferencia um modelo do outro. */
.foto-produto__atual img {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
}

.foto-produto__vazia {
    color: var(--texto-suave);
    font-size: .85rem;
    text-align: center;
    padding: 0 8px;
}
.foto-produto__acoes { flex: 1; min-width: 260px; display: flex; flex-direction: column; gap: 12px; }
.foto-produto__acoes form { margin: 0; }

/* Campo com botão colado — CNPJ + Buscar */
.campo__com-acao { display: flex; gap: 6px; align-items: stretch; }
.campo__com-acao .campo__entrada { flex: 1; min-width: 0; }
.campo__com-acao .btn { flex: 0 0 auto; white-space: nowrap; }

/* Totais no rodapé da venda: em linha, para caber sem empurrar a tela */
.totais--rodape {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 20px;
}

.totais--rodape .totais__linha {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    justify-content: flex-start;
}

.totais--rodape .totais__linha span,
.totais--rodape .totais__linha label {
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--texto-suave);
}

.totais--rodape .totais__linha b { font-size: 1.05rem; }

.totais--rodape .totais__linha--destaque {
    margin-left: auto;
    padding: 6px 0 0 20px;
    border-top: 0;
    border-left: 2px solid var(--marinho);
    padding-left: 20px;
    align-items: flex-end;
}

.totais--rodape .totais__linha--destaque b { font-size: 1.5rem; }
.totais--rodape .campo__entrada { max-width: 130px; }

/* A linha da dica fica RESERVADA, cheia ou vazia (docs/13-vendas.md).

   Em %, o valor em dinheiro aparece embaixo do campo — "R$ 21,48" — e some
   quando o campo zera ou volta para R$. Como o rodapé alinha as colunas pelo PÉ
   (`align-items: flex-end`), a coluna que ganhava a dica crescia uma linha e
   subia em relação às vizinhas: digitar "5" no desconto deixava o acréscimo um
   degrau abaixo, e a tela pulava a cada tecla.

   Reservar é melhor do que alinhar pelo topo: pelo topo, o TOTAL e o subtotal
   deixariam de fechar na mesma base dos campos, que é o que faz a linha ser
   lida como uma conta.

   Subtotal e TOTAL não têm dica, e reservam o mesmo espaço no `padding` para
   continuarem no mesmo pé — o `+ 2px` é o `gap` da coluna, que a dica também
   traz consigo. */
.totais--rodape [data-calculado-de] {
    display: block;
    min-height: 1rem;
    line-height: 1rem;
}

.totais--rodape .totais__linha:first-child,
.totais--rodape .totais__linha--destaque {
    padding-bottom: calc(1rem + 2px);
}

/* ---------------------------------------------------------------------------
   Tarja de produto comissionado (docs/11-produtos.md)

   Vermelha e em caixa alta porque o que ela avisa é que **aquele preço não veio
   do cadastro** — foi combinado na hora. Quem confere o pedido depois precisa
   ver isso sem procurar.

   Vive só na TELA. Na nota e no cupom o item sai como qualquer outro.
   --------------------------------------------------------------------------- */
.tarja-comissionado {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 7px;
    border-radius: 3px;
    background: var(--erro);
    color: #fff;
    font-size: .68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    vertical-align: middle;
    white-space: nowrap;
}

/* A folha impressa é o espelho interno do pedido, e lá a tarja continua
   valendo — o que não a leva é o documento fiscal, que sai da API. */
@media print {
    .tarja-comissionado {
        background: transparent;
        color: var(--erro);
        border: 1px solid var(--erro);
    }
}

/* ---------------------------------------------------------------------------
   A variação que falta escolher na linha do item (docs/34-empenho-e-variacao.md)

   Item de produto com variação lançado ANTES da regra ficou sem cor. O `select`
   entra na própria linha, em âmbar: não é erro de quem lançou, é pergunta que
   passou a existir — mas o pedido não salva mais sem a resposta.
   --------------------------------------------------------------------------- */
.campo--compacto { margin: 0; }
.campo--compacto .campo__entrada { padding: 4px 8px; font-size: .85rem; }
.campo__entrada--atencao { border-color: var(--alerta); background: var(--atencao-fundo); }

/* ---------------------------------------------------------------------------
   As variações na lista de produtos (docs/34-empenho-e-variacao.md)

   Pedido do cliente em 10/09/2026: a lista só mostrava a descrição, e um
   produto com seis cores não dizia qual era qual. Um chip por cor, embaixo da
   descrição, com o saldo da Loja em negrito e a Fábrica só quando tem.

   Texto na cor cheia, e não em `texto-suave`: quem opera a tela tem
   dificuldade de enxergar (08/09/2026), e o chip existe para ser lido.
   --------------------------------------------------------------------------- */
.variacoes-lista {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 6px;
    margin-top: 5px;
}

.variacao-chip {
    display: inline-flex;
    align-items: baseline;
    gap: 5px;
    padding: 1px 8px;
    border: 1px solid var(--cinza);
    border-radius: 999px;
    background: var(--fundo, #fff);
    color: var(--texto);
    font-size: .78rem;
    line-height: 1.5;
    white-space: nowrap;
}

.variacao-chip b { font-weight: 700; }

.variacao-chip i {
    font-style: normal;
    font-size: .72rem;
    color: var(--texto);
}

/* Cor sem saldo em lugar nenhum: fica visível — é a resposta "acabou" —,
   mas o número vai em vermelho, como o estoque baixo das colunas. */
.variacao-chip--zerada b { color: var(--erro); }

@media print {
    .variacao-chip { border-color: #999; background: transparent; }
}

/* Os totais agora fecham a aba Produtos, logo abaixo da grade de itens. A
   linha separa o que se soma do resultado da soma — sem ela, o TOTAL parece
   mais uma linha da tabela. */
.totais--fecha-itens {
    margin-top: 4px;
    padding-top: 18px;
    border-top: 1px solid var(--cinza);
}

/* Aba com contador de itens não pode pular de largura ao mudar o número */
.abas button { white-space: nowrap; }

/* Campo com seletor R$ / % ao lado (docs/13-vendas.md).

   O seletor é estreito de propósito: ele é um qualificador do número, não um
   campo por si. Largo demais competiria com o valor pela atenção. */
.valor-ou-taxa {
    display: flex;
    gap: 6px;
    align-items: center;
}

.valor-ou-taxa select {
    flex: 0 0 62px;
    padding-left: 8px;
    padding-right: 4px;
}

.valor-ou-taxa input { flex: 1 1 auto; min-width: 0; }

/* Linha que acabou de receber soma de quantidade (docs/13-vendas.md).

   Sem o destaque, lançar o mesmo produto de novo parece que não funcionou — a
   grade continua com o mesmo número de linhas — e a pessoa clica outra vez. */
.linha-somada > td { animation: somou 900ms ease-out; }

@keyframes somou {
    0%   { background: var(--azul-suave); }
    100% { background: transparent; }
}

/* Quem prefere menos movimento vê só o realce, sem a transição. */
@media (prefers-reduced-motion: reduce) {
    .linha-somada > td { animation: none; background: var(--azul-suave); }
}

/* -------------------------------------------------------------------------
   Linha do tempo — o log do pedido (docs/22-fluxo-pedido-unico.md)

   A borda à esquerda é o fio da história; cada item pendura nela um ponto.
   Sem ícone e sem cor de estado de propósito: o log é para ser lido, não
   para chamar atenção.
   ------------------------------------------------------------------------- */
.linha-tempo {
    list-style: none;
    margin: 16px 0 0;
    padding: 0 0 0 20px;
    border-left: 2px solid var(--cinza-claro);
}

.linha-tempo__item {
    position: relative;
    padding: 0 0 18px;
}

.linha-tempo__item::before {
    content: '';
    position: absolute;
    left: -26px;
    top: 6px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--azul);
}

.linha-tempo__item:last-child { padding-bottom: 0; }

.linha-tempo__topo {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 10px;
    align-items: baseline;
}

.linha-tempo__detalhe {
    margin: 6px 0 0;
    padding-left: 18px;
    color: var(--texto-suave);
    font-size: .92rem;
}

.linha-tempo__detalhe li { margin: 2px 0; }

/* A linha do pedido abre o modal das duas saídas: o cursor avisa antes do
   clique (docs/22-fluxo-pedido-unico.md). */
tr[data-pedido] { cursor: pointer; }
tr[data-pedido]:hover { background: var(--azul-suave); }
tr[data-pedido] a,
tr[data-pedido] button { cursor: pointer; }

/* -------------------------------------------------------------------------
   O pedido que acabou de ser salvo, em evidência na lista
   (docs/22-fluxo-pedido-unico.md)

   A tarja à esquerda fica; o fundo desbota em dois segundos. O realce serve
   para achar a linha ao chegar, não para marcá-la o dia todo.
   ------------------------------------------------------------------------- */
tr[data-destaque] > td {
    animation: pedido-salvo 2s ease-out;
}

tr[data-destaque] > td:first-child {
    box-shadow: inset 3px 0 0 var(--azul);
}

@keyframes pedido-salvo {
    0%   { background: var(--azul-suave); }
    60%  { background: var(--azul-suave); }
    100% { background: transparent; }
}

@media (prefers-reduced-motion: reduce) {
    tr[data-destaque] > td { animation: none; background: var(--azul-suave); }
}

/* O aviso da gravação automática do rascunho
   (docs/22-fluxo-pedido-unico.md). Discreto de propósito: ele confirma, não
   pede atenção. Só o erro puxa o olho. */
.aviso-rascunho {
    margin-left: 8px;
    font-size: .85rem;
    color: var(--texto-suave);
}

.aviso-rascunho--erro {
    color: var(--erro);
    font-weight: 600;
}

/* PIX da guia de GNRE: QR à esquerda, copia e cola à direita.
   Em tela estreita o QR vai para cima, porque quem paga pelo celular usa a
   câmera e não o texto. */
.pix {
    display: flex;
    gap: 20px;
    align-items: flex-start;
    flex-wrap: wrap;
    margin-top: 16px;
}

.pix__codigo {
    flex: 0 0 auto;
    width: 180px;
    /* O QR precisa de fundo branco para ler: o leitor espera contraste entre
       módulo escuro e claro, e fundo cinza derruba a leitura em papel. */
    background: #fff;
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    padding: 8px;
}

.pix__codigo svg { display: block; width: 100%; height: auto; }

.pix__texto { flex: 1 1 280px; min-width: 0; }

/* O BR Code é uma linha só e longa: quebra no campo em vez de rolar, senão
   ninguém confere o que está copiando. */
.pix__payload {
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: 12px;
    line-height: 1.45;
    resize: vertical;
    word-break: break-all;
}

@media (max-width: 560px) {
    .pix { gap: 14px; }
    .pix__codigo { width: 100%; max-width: 220px; margin: 0 auto; }
}

/* Resumo dos pendentes: o texto de um lado, o botão de enviar do outro.
   Em tela estreita empilha — o botão fecha o mês e não pode ficar espremido. */
.lote-resumo {
    display: flex;
    gap: 14px;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
}

.lote-resumo > p { margin: 0; }
.lote-resumo form { flex: 0 0 auto; }

/* Variações do produto (docs/34-empenho-e-variacao.md) — 30/08/2026.

   Uma linha por variação: nome, "Ativa" e o × de remover. Lista e não grade
   porque a variação tem UM campo — grade de uma coluna é grade à toa.

   O saldo não aparece aqui de propósito: ele é da empresa aberta e de cada
   depósito, e mostrar um número no cadastro do grupo faria a pessoa achar que
   dá para digitá-lo. Quem mexe é o ⇅ da lista. */
.variacoes { display: flex; flex-direction: column; gap: 8px; }

.variacoes__linha {
    display: flex;
    align-items: flex-end;
    gap: 10px;
    padding: 8px;
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    background: var(--fundo);
}

.variacoes__nome { flex: 1; min-width: 0; }

/* O rótulo "Nome" só faz sentido na primeira linha: repetido em dez linhas
   vira ruído que empurra o campo para baixo. */
.variacoes__linha:not(:first-child) .variacoes__nome .campo__rotulo { display: none; }

.variacoes__ativo { flex: 0 0 auto; white-space: nowrap; }

.variacoes__linha .btn--icone { flex: 0 0 auto; font-size: 1.2rem; line-height: 1; }
.variacoes__linha .btn--icone:hover { color: var(--erro); border-color: var(--erro); }

@media (max-width: 600px) {
    .variacoes__linha { flex-wrap: wrap; }
    .variacoes__nome { flex: 1 0 100%; }
    .variacoes__linha .campo__rotulo { display: block; }
}

/* A miniatura vira botão: clicar abre a foto grande (docs/11-produtos.md).

   Botão sem cara de botão — zera o que o `.btn` traria e deixa só o alvo. O
   cursor de lupa é o que anuncia que dá para clicar, porque uma borda ali
   competiria com a borda que a própria miniatura já tem. */
.miniatura-botao {
    display: block;
    padding: 0;
    border: 0;
    background: none;
    cursor: zoom-in;
    line-height: 0;
    border-radius: var(--raio);
}

.miniatura-botao:hover .miniatura { border-color: var(--azul); }

/* O foco tem de aparecer: sem isto quem navega por Tab não veria onde está. */
.miniatura-botao:focus-visible {
    outline: 2px solid var(--azul);
    outline-offset: 2px;
}

/* A foto no modal não pode estourar a tela: sem limite, o SweetAlert2 usa o
   tamanho natural do arquivo, e foto de celular tem 3.000 px de largura. */
.swal2-image { max-width: 100%; max-height: 70vh; object-fit: contain; }

/* A galeria de fotos do produto (docs/11-produtos.md) — 30/08/2026.

   Fila de miniaturas embaixo da principal, que fica grande logo acima. Ver as
   duas com o mesmo peso faria a pessoa perder qual é a que aparece na venda. */
.galeria {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.galeria__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    margin: 0;
    padding: 8px;
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    background: var(--fundo);
}

/* A principal se anuncia pela borda, e não só pela etiqueta: quem bate o olho
   na fila precisa achá-la sem ler. */
.galeria__item--principal { border-color: var(--azul); background: var(--azul-suave); }

.galeria__foto img {
    display: block;
    width: 76px;
    height: 76px;
    object-fit: cover;
    border-radius: var(--raio);
    background: var(--cinza-claro);
}

.galeria__acoes {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: .78rem;
}

.galeria__acoes .btn--texto { padding: 2px 6px; min-height: 0; font-size: .78rem; }

.galeria__remover { width: 26px; min-height: 26px; font-size: 1rem; line-height: 1; }
.galeria__remover:hover { color: var(--erro); border-color: var(--erro); }

/* ---------------------------------------------------------------
   A ficha do produto (docs/11-produtos.md) — 05/09/2026

   Foto à esquerda, dados à direita, e abaixo uma caixa por assunto. A foto é
   maior que a do cadastro (240 contra 180) porque aqui ela é o conteúdo, e
   não o campo que se troca.
   --------------------------------------------------------------- */
.ficha { display: flex; gap: 24px; align-items: flex-start; flex-wrap: wrap; }

/* Quadrado fixo, com ou sem imagem: altura que muda conforme a foto faria o
   bloco de dados dançar de posição a cada produto aberto. */
.ficha__foto {
    flex: 0 0 240px;
    width: 240px;
    height: 240px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    background: var(--cinza-claro);
    overflow: hidden;
}

/* Botão, e não `img` com clique: o alvo tem de ser alcançável por teclado e
   anunciado como acionável (docs/06-frontend.md). */
.ficha__foto-botao {
    width: 100%;
    height: 100%;
    padding: 0;
    border: 0;
    background: none;
    cursor: zoom-in;
}

/* `contain` para a etiqueta aparecer inteira: `cover` cortaria justamente a
   borda, que é o que diferencia um modelo do outro. */
.ficha__foto-botao img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.ficha__foto-botao:focus-visible { outline: 2px solid var(--azul); outline-offset: 2px; }

.ficha__sem-foto { color: var(--texto-suave); font-size: .85rem; }

.ficha__dados { flex: 1; min-width: 280px; display: flex; flex-direction: column; gap: 16px; }

/* O preço é o que se abre a ficha para ver — e é o único número da tela que
   pode ser lido de longe, do outro lado do balcão. */
.ficha__preco { font-size: 1.5rem; font-weight: 700; line-height: 1.2; }

/* Valor lido, em oposição ao rótulo: existia em cinco telas (estoque, produção,
   transferência, faturar e finalizar) sem nunca ter sido definido, e por isso
   saía com o peso de um parágrafo comum. */
.valor-forte { font-weight: 600; font-size: 1.02rem; }

@media (max-width: 620px) {
    /* No celular a foto ocupa a largura: 240px fixos ao lado de um bloco de
       dados espremido é pior que os dois empilhados. */
    .ficha__foto { flex-basis: 100%; width: 100%; }
}
/* A galeria dentro do modal: a foto grande e a barra de navegação. */
.foto-galeria { display: flex; flex-direction: column; gap: 10px; align-items: center; }

.foto-galeria img {
    max-width: 100%;
    max-height: 65vh;
    object-fit: contain;
    border-radius: var(--raio);
}

.foto-galeria__barra {
    display: flex;
    align-items: center;
    gap: 12px;
    color: var(--texto-suave);
    font-size: .85rem;
}

.foto-galeria__barra .btn--icone { font-size: 1.4rem; line-height: 1; }

/* A fila da fábrica (docs/35-ordem-de-producao.md) — 30/08/2026.

   Cartões, e não tabela. Quem está na máquina lê de longe e clica com a mão
   suja: número grande, um botão de largura inteira e nada de coluna estreita.
   É a mesma lição da janela do ⇅ — a tela segue o que a pessoa está fazendo. */
.fila-producao {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 14px;
}

.fila-producao__cartao {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: var(--espaco);
    border: 1px solid var(--cinza);
    border-left: 4px solid var(--cinza);
    border-radius: var(--raio);
    background: var(--superficie);
    box-shadow: var(--sombra);
}

/* A que já está na máquina, e a que passou do prazo. As duas se anunciam pela
   BORDA: quem varre a fila com o olho não lê badge, vê cor. */
.fila-producao__cartao--fazendo  { border-left-color: var(--alerta); }
.fila-producao__cartao--atrasada { border-left-color: var(--erro); }

.fila-producao__topo { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.fila-producao__numero {
    font-size: 1.15rem;
    font-weight: 700;
    text-decoration: none;
}

.fila-producao__cliente { margin: 0; font-weight: 600; }

.fila-producao__produto { margin: 0; font-size: .93rem; }

/* As especificações do papel, em linha: são curtas e cabem lado a lado. Uma
   por linha faria o cartão dobrar de altura para dizer o mesmo. */
.fila-producao__specs {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 12px;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: .82rem;
    color: var(--texto-suave);
}

.fila-producao__obs {
    margin: 0;
    padding: 8px;
    border-radius: var(--raio);
    background: var(--fundo);
    font-size: .85rem;
}

/* O botão encosta no fim do cartão, e todos os cartões da linha terminam
   juntos — sem isto, cartão com observação empurraria o botão para baixo e a
   fileira ficaria desalinhada. */
.fila-producao__acao { margin-top: auto; }

/* Cancelar em vermelho — pedido do cliente em 30/08/2026.

   Contorno, e não preenchido: o `.btn--perigo` (vermelho cheio) é de ação
   DESTRUTIVA — inativar, cancelar a venda —, e Cancelar num formulário só sai
   da tela sem gravar. Pintados iguais, os dois deixariam de se distinguir
   justamente onde a diferença importa.

   Vermelho de contorno é inconfundivelmente vermelho e não compete com o
   Salvar, que continua sendo a ação em destaque. */
.btn--cancelar {
    border-color: var(--erro);
    background: var(--superficie);
    color: var(--erro);
}

.btn--cancelar:hover {
    background: var(--erro-fundo);
    border-color: var(--erro);
    color: var(--erro);
}

.btn--cancelar:focus-visible {
    outline: 2px solid var(--erro);
    outline-offset: 2px;
}

/* ------------------------------------------------------------------
   Requisição de transferência — 31/08/2026
   (docs/37-requisicao-de-transferencia.md)

   A tela de quem recebe reusa os cartões da fila da fábrica: o formato
   já resolveu o mesmo problema — mostrar em letra grande o que precisa
   de uma decisão agora. O que ela acrescenta é a tabela de conferência
   DENTRO do cartão, e ela precisa caber sem virar rolagem.
   ------------------------------------------------------------------ */
.tabela--compacta { font-size: .9rem; margin: 4px 0 12px; }
.tabela--compacta th,
.tabela--compacta td { padding: 6px 8px; }

/* O campo do "chegou" fica do tamanho do número que vai receber: largo demais,
   ele parece pedir um texto; estreito demais, esconde o que foi digitado. */
.campo__entrada--curto { width: 90px; display: inline-block; }

/* A rejeição fica fechada porque é a exceção — e o vermelho só aparece depois
   de aberta, para não competir com o Confirmar, que é o caminho normal. */
.detalhe-recusa { margin-top: 10px; }

.detalhe-recusa > summary {
    cursor: pointer;
    color: var(--erro);
    font-size: .9rem;
    padding: 4px 0;
}

.detalhe-recusa[open] > summary { margin-bottom: 6px; }

/* ---------------------------------------------------------------
   No celular a tabela vira cartão (docs/06-frontend.md)

   Pedido do cliente em 02/09/2026: *"para ver o caixa fiquei rolando na
   horizontal os dados pelo tamanho da tela"*. A `.tabela-rolagem` resolvia o
   estouro empurrando a linha para fora da tela — metade do dado ficava
   escondida atrás de um gesto que ninguém adivinha.

   Abaixo de 720px cada linha vira um cartão empilhado: o nome da coluna à
   esquerda, o valor à direita, um embaixo do outro. Vale para TODA tabela do
   painel de uma vez, e não tela a tela — são 45 listas, e a regra que mora em
   45 arquivos é a regra que a próxima lista esquece.

   O rótulo sai de `data-rotulo`, que o `app.js` copia do `<thead>`: CSS não lê
   o conteúdo de outro elemento, e repetir o nome da coluna em cada `<td>` do
   PHP seria a mesma regra espalhada por 45 arquivos, com outro nome.
   --------------------------------------------------------------- */

/* A linha de fecho de uma tabela de conta — o total do relatório de
   comissões é o primeiro caso. Fica no `tbody` de propósito: é de lá que o
   `app.js` faz o cartão do celular, com o nome da coluna ao lado do valor. */
.tabela__total > th,
.tabela__total > td {
    border-top: 2px solid var(--cinza);
    background: var(--cinza-claro);
    font-weight: 600;
}

/* Fora do celular o invólucro do valor não existe para o layout: `contents`
   faz a célula continuar sendo exatamente o que ela era antes do JS passar. */
.tabela__valor { display: contents; }

@media (max-width: 720px) {
    /* A rolagem lateral era o problema — aqui ela deixa de existir. */
    .tabela-rolagem { overflow-x: visible; }

    .tabela,
    .tabela tbody,
    .tabela tr,
    .tabela td { display: block; width: auto; }

    /* O cabeçalho vira o rótulo de cada célula, então some da tela — mas não
       do leitor de tela, que continua precisando dele para anunciar a coluna.
       `display: none` o tiraria dos dois. */
    .tabela thead {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }

    .tabela tbody tr {
        margin: 0 0 10px;
        border: 1px solid var(--cinza);
        border-radius: var(--raio);
        background: var(--superficie);
        overflow: hidden;
    }

    .tabela tbody tr:last-child { margin-bottom: 0; }

    .tabela tbody td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 12px;
        padding: 8px 12px;
        border-bottom: 1px solid var(--cinza-claro);
        text-align: right;

        /* `sem-quebra` existe para o valor não partir no meio da LINHA. No
           cartão não há linha para caber: mantê-lo faria a data escapar pela
           direita, que é justamente o defeito que este bloco veio consertar. */
        white-space: normal;
        overflow-wrap: anywhere;
    }

    .tabela tbody td:last-child { border-bottom: 0; }

    /* Célula sem nada dentro não vira linha do cartão: "Vendedor:" seguido de
       vazio é ruído que empurra o que importa para baixo. */
    .tabela tbody td[data-vazio] { display: none; }

    .tabela tbody td[data-rotulo]::before {
        content: attr(data-rotulo);
        flex: 0 0 auto;
        max-width: 45%;
        font-size: .74rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .02em;
        color: var(--texto-suave);
        text-align: left;
    }

    .tabela__valor {
        display: block;
        min-width: 0;
        text-align: right;
    }

    /* Célula que já ocupava a linha inteira (lista vazia, aviso) continua
       ocupando, e sem rótulo nenhum. */
    .tabela tbody td[colspan],
    .tabela tbody td[colspan] .tabela__valor { text-align: center; }

    /* A coluna de ações vira o rodapé do cartão: os botões lado a lado, no
       canto que o polegar alcança. */
    .tabela tbody td.tabela__acoes {
        justify-content: flex-end;
        width: auto;
        padding: 8px 12px;
        background: var(--cinza-claro);
    }

    .tabela tbody td.tabela__acoes .tabela__valor {
        display: flex;
        flex-wrap: wrap;
        justify-content: flex-end;
        align-items: center;
        gap: 6px;
    }

    /* Alvo de toque: o ícone de 16px dentro de um botão apertado é acerto de
       sorte no telefone. */
    .tabela tbody td.tabela__acoes .btn--icone {
        min-width: 38px;
        min-height: 38px;
    }

    /* A grade de permissões é o caso de fora da curva: as três colunas de
       estado (herdado, extra, negada) são uma pergunta só, e viram três linhas
       de cartão dizendo "◯" cada uma. Aqui elas voltam a ficar lado a lado. */
    .grade-tags__tabela tbody tr {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
    }

    .grade-tags__tabela tbody td { flex: 0 0 auto; border-bottom: 0; }

    .grade-tags__tabela tbody td:first-child {
        flex: 1 0 100%;
        border-bottom: 1px solid var(--cinza-claro);
    }

    .grade-tags__tabela tbody td[data-rotulo]::before {
        max-width: none;
        font-size: .68rem;
    }

    .grade-tags__tabela tbody td,
    .grade-tags__tabela tbody td .tabela__valor { text-align: left; }

    .grade-tags__atalhos { flex-wrap: wrap; }
}

/* ---------------------------------------------------------------
   O que mais estourava a largura no celular, fora as tabelas
   --------------------------------------------------------------- */
@media (max-width: 720px) {
    /* Três botões de rótulo longo no cabeçalho não cabem em 360px, e sem
       quebra o último sai pela direita levando a página junto. */
    .pagina__acoes { flex-wrap: wrap; }

    /* O rodapé da folha punha observação e totais lado a lado, com os totais
       travados em 260px: em tela estreita a soma do pedido — que é o que o
       cliente abre o link para ver — ficava fora da tela. */
    .folha__rodape { flex-direction: column; gap: 16px; }
    .folha__totais { width: 100%; flex: 1 1 auto; }

    /* Os itens da folha pública viram cartão pelo mesmo motivo das listas do
       painel. O rótulo aqui vem do próprio HTML (`data-rotulo` em
       publico/documentos.php): esta página não carrega o app.js. */
    .folha__itens,
    .folha__itens tbody,
    .folha__itens tr,
    .folha__itens td { display: block; width: auto; }

    .folha__itens thead {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }

    .folha__itens tbody tr {
        margin-bottom: 10px;
        border: 1px solid var(--cinza);
        border-radius: var(--raio);
        overflow: hidden;
    }

    .folha__itens tbody td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 12px;
        padding: 6px 10px;
        border-bottom: 1px solid var(--cinza-claro);
        text-align: right;
        white-space: normal;
        overflow-wrap: anywhere;
    }

    .folha__itens tbody td:last-child { border-bottom: 0; }

    .folha__itens tbody td[data-rotulo]::before {
        content: attr(data-rotulo);
        flex: 0 0 auto;
        max-width: 45%;
        text-align: left;
        font-size: .72rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .02em;
        color: var(--texto-suave);
    }

    /* "Nenhum item." atravessa as oito colunas: sem rótulo e no meio. */
    .folha__itens tbody td[colspan] { text-align: center; }
}

/* ---------------------------------------------------------------
   Catálogo de personalizadas — 12/09/2026
   (docs/41-catalogo-de-personalizadas.md)

   O caderno do cliente em cartões: foto à esquerda, os dados do lado, como
   na página do caderno. Uma coluna no celular, duas quando cabe.
   --------------------------------------------------------------- */
.personalizadas-grade {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
    gap: 14px;
    margin-top: 14px;
}

.personalizada {
    display: grid;
    grid-template-columns: 120px 1fr;
    grid-template-areas: "foto corpo" "acoes acoes";
    gap: 10px 14px;
    padding: 12px;
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    background: var(--fundo);
    box-shadow: var(--sombra);
}

.personalizada--inativa { opacity: .6; }

.personalizada__foto { grid-area: foto; }

.personalizada__foto img,
.personalizada__sem-foto {
    display: block;
    width: 120px;
    height: 120px;
    object-fit: cover;
    border-radius: var(--raio);
    background: var(--cinza-claro);
}

.personalizada__sem-foto {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--texto-suave);
    font-size: .85rem;
}

.personalizada__corpo { grid-area: corpo; min-width: 0; }

.personalizada__titulo { margin: 0 0 4px; font-size: 1.02rem; }

.personalizada__linha { margin: 0 0 4px; font-size: .9rem; }

.personalizada__obs {
    margin: 6px 0 0;
    padding: 6px 8px;
    border-left: 3px solid var(--cinza);
    font-size: .88rem;
    color: var(--texto-suave);
    white-space: pre-line;
}

.personalizada__acoes {
    grid-area: acoes;
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    border-top: 1px solid var(--cinza-claro);
    padding-top: 8px;
}

.personalizada__acoes form { margin: 0; }

@media (max-width: 480px) {
    .personalizadas-grade { grid-template-columns: 1fr; }
}

/* -----------------------------------------------------------------
   Contatos do cliente: e-mails e telefones de sobra (docs/47)
   Mesma família visual das variações do produto — linha em caixa, X no fim.
   ----------------------------------------------------------------- */
.contatos { margin-bottom: 18px; }
.contatos__linhas { display: flex; flex-direction: column; gap: 8px; }
.contatos__linhas:empty { display: none; }

.contatos__linha {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    background: var(--fundo);
}

.contatos__valor { flex: 2 1 220px; min-width: 0; }
.contatos__rotulo { flex: 1 1 160px; min-width: 0; }
.contatos__linha .btn { flex: 0 0 auto; white-space: nowrap; }
.contatos__linha .btn--icone { font-size: 1.2rem; line-height: 1; }
.contatos__linha .btn--icone:hover { color: var(--erro); border-color: var(--erro); }

@media (max-width: 600px) {
    .contatos__linha { flex-wrap: wrap; }
    .contatos__valor, .contatos__rotulo { flex: 1 0 100%; }
}

/* -----------------------------------------------------------------
   Modal "para qual e-mail?" — pedido, nota e boleto (docs/47)
   ----------------------------------------------------------------- */
.envio-email { display: flex; flex-direction: column; gap: 6px; text-align: left; margin: 4px 0 0; }
.envio-email__texto { margin: 0 0 10px; }

.envio-email__opcao {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 12px;
    border: 1px solid var(--cinza);
    border-radius: var(--raio);
    cursor: pointer;
}

.envio-email__opcao:has(input:checked) { border-color: var(--azul); background: var(--azul-suave, #E8EFFB); }
.envio-email__valor { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.envio-email__marca { font-weight: 700; color: var(--azul); }
.envio-email__rotulo { color: var(--texto-suave, #5A6672); }
.envio-email__outro.swal2-input { width: 100%; margin: 4px 0 0; box-sizing: border-box; }
.envio-email__ajuda { margin: 12px 0 0; font-size: .85rem; color: var(--texto-suave, #5A6672); text-align: left; }

/* Envio de e-mail que falhou (tela do Desenvolvedor, migration 084): a linha
   inteira avisa, porque é ela que a pessoa veio procurar. */
.tabela tbody tr.linha--erro { background: var(--erro-fundo); }
.tabela tbody tr.linha--erro td:first-child { box-shadow: inset 3px 0 0 var(--erro); }
