/* Sistema visual.
 *
 * Três decisões que sustentam o resto:
 *
 * 1. **Tipografia é o produto.** Nunito Sans variável servida do nosso domínio.
 *    A CSP é `style-src 'self'; font-src 'self'`, então o `<link>` do Google
 *    Fonts seria bloqueado pelo navegador, e mesmo sem CSP, CDN de fonte põe
 *    um terceiro no caminho crítico do primeiro render. Escala com contraste
 *    real: título grande, corpo confortável, nada no meio.
 *
 * 2. **Cor é sinal, não decoração.** A interface é quase monocromática; o verde
 *    aparece só onde significa fidelidade. Botão primário é PRETO, botão verde
 *    em toda ação é o que faz uma tela parecer template.
 *
 * 3. **Estrutura por fio, não por sombra.** Sombra fica reservada ao que
 *    realmente flutua (gaveta, modal, torrada). O resto se organiza com
 *    hairline de 1px, que é o que dá o ar de coisa bem desenhada.
 *
 * Nada aqui usa `style=` no markup: a CSP `style-src 'self'` bloqueia atributo
 * de estilo, então valor dinâmico vai por CSSOM no JS.
 */

@font-face {
  font-family: 'Nunito Sans';
  font-style: normal;
  font-weight: 200 1000;
  font-display: swap;
  src: url('/static/assets/fontes/NunitoSans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Nunito Sans';
  font-style: normal;
  font-weight: 200 1000;
  font-display: swap;
  src: url('/static/assets/fontes/NunitoSans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Neutros em ardósia, derivados de #0F172A e #334155 da identidade. Cinza
     neutro brigaria com o azul da marca; a rampa inteira puxa para o frio. */
  --n-0:  #ffffff;
  --n-25: #fbfcfd;
  --n-50: #f8fafc;
  --n-100:#f1f5f9;
  --n-150:#e8eef4;
  --n-200:#e2e8f0;
  --n-300:#cbd5e1;
  --n-400:#94a3b8;
  --n-500:#64748b;
  --n-600:#475569;
  --n-700:#334155;   /* azul ardósia da identidade */
  --n-800:#1e293b;
  --n-900:#0f172a;   /* azul petróleo da identidade */
  --n-950:#020617;

  /* Verde da marca. #22C55E é a cor oficial e é usada em PREENCHIMENTO,     símbolo, selo cheio, barra. Para TEXTO sobre branco ela dá 2,3:1, abaixo
     do mínimo de 4,5:1 da WCAG AA, então texto em verde usa #15803D (4,9:1).
     A distinção está documentada em web/assets/marca/LEIA-ME.md. */
  --verde-vivo:  #22C55E;
  --verde-esmeralda: #10B981;
  --verde-texto: #15803D;
  --verde-forte: #166534;
  --verde-fraco: #ecfdf3;

  --ok-fundo:#ecfdf3;     --ok-tinta:#15803D;
  --alerta-fundo:#fdf4e3; --alerta-tinta:#8a5a08;
  --erro-fundo:#fdecec;   --erro-tinta:#b42318;
  --info-fundo:#eef2ff;   --info-tinta:#3538cd;

  --fundo:    var(--n-50);
  --papel:    var(--n-0);
  --papel-2:  var(--n-25);
  --realce:   var(--n-100);
  --linha:    var(--n-150);
  --linha-forte: var(--n-300);
  --tinta:    var(--n-900);
  --tinta-2:  var(--n-600);
  --tinta-3:  var(--n-400);

  --acento:   var(--verde-texto);
  --acento-vivo: var(--verde-vivo);
  --acento-forte: var(--verde-forte);
  --acento-fraco: var(--verde-fraco);
  --acento-contraste: #ffffff;

  /* Ação primária em azul petróleo, não preto: é a cor de contraste da
     identidade, e verde em toda ação tiraria do verde o papel de sinal. */
  --acao:     var(--n-900);
  --acao-hover: var(--n-800);
  --acao-tinta: #ffffff;

  --e1: 4px; --e2: 8px; --e3: 12px; --e4: 16px; --e5: 24px;
  --e6: 32px; --e7: 48px; --e8: 72px; --e9: 112px;

  --r1: 6px; --r2: 8px; --r3: 12px; --r4: 18px; --r-pill: 999px;

  --sombra-2: 0 1px 2px rgba(15,23,42,.05), 0 12px 28px -14px rgba(15,23,42,.18);
  --sombra-3: 0 24px 60px -18px rgba(15,23,42,.30), 0 2px 8px rgba(15,23,42,.07);

  --fonte: 'Nunito Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  /* Nunito Sans não tem corte de display separado, tem eixo óptico (opsz
     6..12), e `font-optical-sizing: auto` já escolhe o desenho certo por
     tamanho. O token continua existindo para os títulos poderem divergir do
     corpo sem que cada regra saiba de qual família se trata. */
  --display: 'Nunito Sans', ui-sans-serif, system-ui, sans-serif;
  --mono: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas, monospace;

  --lateral: 240px;
  --curva: cubic-bezier(.2, .7, .3, 1);
}

@media (prefers-color-scheme: dark) {
  :root {
    --fundo:   #060b16;
    --papel:   #0f172a;
    --papel-2: #131d33;
    --realce:  #1e293b;
    --linha:   #1e293b;
    --linha-forte: #334155;
    --tinta:   #f1f5f9;
    --tinta-2: #94a3b8;
    --tinta-3: #64748b;

    /* No escuro o verde vivo já passa em contraste, então texto e
       preenchimento voltam a ser a mesma cor da marca. */
    --acento: #4ade80;
    --acento-vivo: #22c55e;
    --acento-forte: #86efac;
    --acento-fraco: #0d2b1a;
    --acento-contraste: #052e16;

    --acao: #f1f5f9;
    --acao-hover: #ffffff;
    --acao-tinta: #0f172a;

    --ok-fundo:#0d2b1a;     --ok-tinta:#6ee7a0;
    --alerta-fundo:#2b2312; --alerta-tinta:#e0b568;
    --erro-fundo:#2e1518;   --erro-tinta:#fda29b;
    --info-fundo:#171d3d;   --info-tinta:#a5b4fc;

    --sombra-2: 0 1px 2px rgba(0,0,0,.5), 0 12px 28px -14px rgba(0,0,0,.7);
    --sombra-3: 0 24px 60px -18px rgba(0,0,0,.8), 0 2px 8px rgba(0,0,0,.5);
  }
}

/* --------------------------------------------------------------- base -- */

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  font-family: var(--fonte);
  font-size: 15px;
  line-height: 1.55;
  color: var(--tinta);
  background: var(--fundo);
  font-optical-sizing: auto;
  font-variation-settings: 'wdth' 100, 'YTLC' 500;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--tinta); color: var(--papel); }

h1, h2, h3, h4 {
  margin: 0; font-family: var(--display); font-weight: 700;
  letter-spacing: -.015em; line-height: 1.2;
}
h1 { font-size: 27px; letter-spacing: -.02em; }
h2 { font-size: 18px; }
h3 { font-size: 15px; letter-spacing: -.01em; }
p  { margin: 0; }

a { color: inherit; text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }

:focus-visible { outline: 2px solid var(--acento); outline-offset: 2px; border-radius: var(--r1); }
/* Campos já têm indicador próprio de foco (borda + halo). O contorno por cima
   soma dois anéis concêntricos e fica pesado, tirar aqui não custa
   acessibilidade porque o indicador continua existindo. */
input:focus-visible, select:focus-visible, textarea:focus-visible { outline: none; }

.oculto { display: none !important; }

/* O atributo `hidden` do HTML vale `display: none` na folha do navegador, que
   tem especificidade zero: QUALQUER regra de classe com `display` o atropela.
   Foi assim que `.imagem-qr { display: block }` deixou visível um <img> sem
   endereço, e o navegador desenhou o ícone de imagem quebrada.
   Como `hidden` significa "não está aqui", a exceção é legítima. */
[hidden] { display: none !important; }
.pilha  { display: flex; flex-direction: column; }
.linha  { display: flex; align-items: center; gap: var(--e3); }
.espaco { flex: 1; }
.g1 { gap: var(--e1); } .g2 { gap: var(--e2); } .g3 { gap: var(--e3); }
.g4 { gap: var(--e4); } .g5 { gap: var(--e5); } .g6 { gap: var(--e6); }
.fraco { color: var(--tinta-2); }
.mini  { font-size: 13.5px; color: var(--tinta-2); line-height: 1.5; }
.mono  { font-family: var(--mono); font-size: .92em; font-variant-numeric: tabular-nums; }
.centro { text-align: center; }

/* ---------------------------------------------------------- app shell -- */

.shell { display: grid; grid-template-columns: var(--lateral) 1fr; min-height: 100vh; }

.lateral {
  background: var(--papel); border-right: 1px solid var(--linha);
  padding: var(--e5) var(--e4);
  display: flex; flex-direction: column; gap: var(--e5);
  position: sticky; top: 0; height: 100dvh;
  /* `align-self: start` é o que faz o `sticky` funcionar aqui. Item de grade
     nasce esticado até a altura da linha; esticado, ele já ocupa tudo e não
     sobra percurso para grudar, a lateral descia junto com a página. */
  align-self: start;
  /* A lateral inteira NÃO rola: quem rola é só a lista de seções. Assim a
     marca fica no topo e a conta no rodapé, sempre visíveis, em vez de
     desaparecerem junto com o menu numa tela baixa.
     `overflow: hidden` aqui também impede que qualquer coisa passando da borda
     vire barra horizontal, `overflow-y: auto` força `overflow-x: auto` junto,
     e não existe rolar num eixo e ser visível no outro. */
  overflow: hidden;
}

.marca {
  display: inline-flex; align-items: center; gap: var(--e2);
  font-family: var(--display); font-weight: 700; font-size: 15px; letter-spacing: -.012em;
}
.marca .selo {
  width: 26px; height: 26px; border-radius: 8px; flex: none;
  background: var(--acao); color: var(--acao-tinta);
  display: grid; place-items: center; font-size: 13px;
}

.nav {
  display: flex; flex-direction: column; gap: 1px;
  /* Ocupa o espaço entre a marca e o rodapé, e rola só quando não couber. */
  flex: 1; min-height: 0; overflow-y: auto; overflow-x: clip;
  margin-inline: calc(var(--e2) * -1); padding-inline: var(--e2);
  scrollbar-width: thin; scrollbar-color: transparent transparent;
}
/* Barra fina e discreta, que só ganha cor quando o ponteiro está por perto,   barra de rolagem permanente numa lateral de 240px rouba largura e atenção. */
.nav:hover { scrollbar-color: var(--linha-forte) transparent; }
.nav::-webkit-scrollbar { width: 6px; }
.nav::-webkit-scrollbar-track { background: transparent; }
.nav::-webkit-scrollbar-thumb { background: transparent; border-radius: 3px; }
.nav:hover::-webkit-scrollbar-thumb { background: var(--linha-forte); }
.nav .grupo {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .1em;
  color: var(--tinta-3); font-weight: 600; padding: var(--e3) var(--e3) var(--e1);
}
.nav button {
  display: flex; align-items: center; gap: var(--e3);
  width: 100%; text-align: left; padding: 8px var(--e3);
  border: 0; border-radius: var(--r2); background: transparent;
  color: var(--tinta-2); font: inherit; font-size: 14px; font-weight: 450;
  cursor: pointer; transition: background .14s var(--curva), color .14s var(--curva);
}
.nav button:hover { background: var(--realce); color: var(--tinta); }
.nav button[aria-current="page"] { background: var(--realce); color: var(--tinta); font-weight: 550; }
.nav button .icone { width: 16px; text-align: center; flex: none; opacity: .65; font-size: 13px; }
.nav button[aria-current="page"] .icone { opacity: 1; }

.rodape-lateral {
  flex: none; border-top: 1px solid var(--linha); padding-top: var(--e3);
  display: flex; flex-direction: column; gap: var(--e1);
}

/* Atalho para a outra console: mesma gramática dos itens de menu, para não
   parecer um botão perdido no rodapé. */
.atalho-lateral {
  display: flex; align-items: center; gap: var(--e3);
  padding: 8px var(--e3); border-radius: var(--r2);
  font-size: 13.5px; font-weight: 500; color: var(--tinta-2);
  transition: background .14s var(--curva), color .14s var(--curva);
}
.atalho-lateral:hover { background: var(--realce); color: var(--tinta); text-decoration: none; }
.atalho-lateral .icone { width: 18px; height: 18px; flex: none; display: grid; place-items: center; opacity: .75; }
.atalho-lateral .icone svg { width: 16px; height: 16px; }

/* Bloco da conta: quem está logado, em que papel, e a saída. Três informações
   que antes eram uma linha de texto solta e dois botões empilhados. */
.conta-lateral {
  display: flex; align-items: center; gap: var(--e2);
  padding: 7px var(--e2) 7px 7px; border-radius: var(--r2);
  transition: background .14s var(--curva);
}
.conta-lateral:hover { background: var(--realce); }
.avatar-conta {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  display: grid; place-items: center; overflow: hidden;
  background: var(--acao); color: var(--acao-tinta);
  font-size: 11.5px; font-weight: 700; letter-spacing: .02em;
}
.conta-dados { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.conta-dados strong {
  font-size: 13px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.conta-dados span { font-size: 11.5px; color: var(--tinta-3); }
.sair-conta {
  margin-left: auto; flex: none; width: 28px; height: 28px;
  display: grid; place-items: center; cursor: pointer;
  border: 0; border-radius: var(--r2); background: transparent; color: var(--tinta-3);
  transition: background .14s var(--curva), color .14s var(--curva);
}
.sair-conta:hover { background: var(--papel); color: var(--erro-tinta); }
.sair-conta svg { width: 16px; height: 16px; }

/* Recolhida: sobra o avatar e a saída, empilhados e centrados. */
.shell.rail .rodape-lateral { align-items: center; }
.shell.rail .atalho-lateral { justify-content: center; padding-inline: 0; }
.shell.rail .atalho-lateral .rotulo-nav { max-width: 0; opacity: 0; overflow: hidden; }
.shell.rail .conta-lateral { flex-direction: column; gap: var(--e1); padding: var(--e2) 0; }
.shell.rail .conta-dados { display: none; }
.shell.rail .sair-conta { margin-left: 0; }

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

.barra {
  display: flex; align-items: center; gap: var(--e3);
  padding: 0 var(--e6); height: 58px; flex: none;
  border-bottom: 1px solid var(--linha); background: var(--papel);
  position: sticky; top: 0; z-index: 20;
}
/* Nome da loja na barra. Com um restaurante só o seletor não aparece, e sem
   isto a barra ficava vazia à esquerda. */
.marca-barra { font-weight: 600; font-size: 14px; letter-spacing: -.005em; }

.corpo {
  padding: var(--e7) var(--e6) var(--e9);
  display: flex; flex-direction: column; gap: var(--e6);
  /* Console é tela de dado: tabela com oito colunas agradece largura. O teto
     existe só para a linha de texto não ficar quilométrica em monitor grande,
     e `margin: auto` reparte a sobra dos dois lados em vez de empilhar tudo
     contra a esquerda. */
  width: 100%; max-width: 1560px; margin-inline: auto;
}

/* Sobra do layout antigo, quando o menu no celular era uma faixa horizontal
   rolável em vez de gaveta. Quase tudo aqui era desfeito mais abaixo, menos
   `align-items: center`, que ninguém redeclarou: numa coluna flex ele faz o
   filho encolher até o conteúdo em vez de esticar, e `.topo-lateral` (cujo
   único filho é absoluto) virava largura ZERO. Era por isso que a gaveta abria
   com um vazio branco no topo em vez da marca. */
@media (max-width: 900px) {
  .corpo { padding: var(--e5) var(--e4) var(--e8); gap: var(--e5); }
}

/* ------------------------------------------------------------ cartões -- */

.cartao {
  background: var(--papel); border: 1px solid var(--linha);
  border-radius: var(--r4); overflow: hidden;
}
.cartao > header {
  padding: var(--e5) var(--e5) var(--e4);
  display: flex; align-items: flex-start; gap: var(--e3);
}
.cartao > header + .miolo { padding-top: 0; }
.cartao > header .mini { margin-top: 3px; }
.cartao > .miolo { padding: var(--e5); }
.cartao > .miolo.rente { padding: 0; }
/* Primeira e última coluna alinham com o respiro do cartão. */
.miolo.rente table th:first-child, .miolo.rente table td:first-child { padding-left: var(--e5); }
.miolo.rente table th:last-child, .miolo.rente table td:last-child { padding-right: var(--e5); }
/* Linha secundária dentro da célula: evita uma coluna só para o endereço. */
td .sub { display: block; font-size: 11.5px; color: var(--tinta-3); margin-top: 1px; }
.cartao > header + .miolo.rente { padding-top: 0; border-top: 1px solid var(--linha); }

.grade { display: grid; gap: var(--e4); }
.grade.k2 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.grade.k3 { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.grade.k4 { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
/* Por padrão os cartões de uma fileira se igualam em altura, que é o certo
   quando têm a mesma estrutura. `.natural` desliga isso para a fileira em que
   um cartão tem metade do conteúdo do outro e sobraria um vazio embaixo. */
.grade.natural { align-items: start; }

/* Indicador. `numero` é grande porque é o que se lê de longe; `.texto` devolve
   o tamanho ao normal quando o valor é palavra, no corpo do número, "código do
   caixa" quebra em duas linhas e estica a fileira inteira. */
.indicador { padding: var(--e5); }
.indicador .rotulo {
  font-size: 11px; text-transform: uppercase; letter-spacing: .09em;
  color: var(--tinta-3); font-weight: 600;
}
.indicador .numero {
  font-family: var(--display); font-size: 38px; font-weight: 600;
  letter-spacing: -.026em; line-height: 1.08;
  font-variant-numeric: tabular-nums; margin: var(--e3) 0 var(--e1);
}
.indicador .numero.texto { font-size: 19px; letter-spacing: -.012em; line-height: 1.3; }
.indicador .nota { font-size: 12.5px; color: var(--tinta-2); }

/* --------------------------------------------------------- controles -- */

label { display: block; font-size: 13px; font-weight: 550; margin-bottom: var(--e2); }
label .mini { font-weight: 400; display: block; margin-top: 3px; }

input, select, textarea {
  width: 100%; padding: 9px var(--e3); font: inherit; font-size: 14px;
  color: var(--tinta); background: var(--papel);
  border: 1px solid var(--linha-forte); border-radius: var(--r2);
  outline: none; transition: border-color .14s var(--curva), box-shadow .14s var(--curva);
}
input::placeholder, textarea::placeholder { color: var(--tinta-3); }
input:focus, select:focus, textarea:focus {
  border-color: var(--tinta); box-shadow: 0 0 0 3px var(--realce);
}
input[type="checkbox"] { width: auto; accent-color: var(--acao); }
input[type="color"] { padding: 4px; height: 38px; }
textarea { resize: vertical; min-height: 78px; }
.campo + .campo { margin-top: var(--e4); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--e2);
  font: inherit; font-size: 13.5px; font-weight: 550; white-space: nowrap;
  padding: 8px var(--e4); border-radius: var(--r-pill); cursor: pointer;
  border: 1px solid var(--linha-forte); background: var(--papel); color: var(--tinta);
  transition: background .16s var(--curva), border-color .16s var(--curva),
              color .16s var(--curva), box-shadow .16s var(--curva);
}
.btn:hover { background: var(--realce); text-decoration: none; }
/* Ação primária.
 *
 * Cor sólida, gradiente com fio de luz é o acabamento que lê como enfeite
 * genérico. O que tira o ar de retângulo colado na página é **profundidade
 * parada**: uma sombra curta e apoiada, que existe antes de qualquer interação
 * e não cresce nem levanta o botão. Nada de `transform` aqui: botão que sobe
 * ao passar o mouse é o truque que envelhece mais rápido.
 */
.btn.primario {
  background: var(--acao);
  border-color: var(--acao);
  color: var(--acao-tinta);
  box-shadow: 0 1px 1px rgba(15,23,42,.16), 0 3px 10px -4px rgba(15,23,42,.35);
}
.btn.primario:hover {
  background: var(--acao-hover); border-color: var(--acao-hover);
  box-shadow: 0 1px 1px rgba(15,23,42,.18), 0 5px 14px -5px rgba(15,23,42,.42);
}
/* Pressionado, a sombra encolhe: a leitura de "afundou" vem do apoio sumir,
   não de o botão se mover. */
.btn.primario:active {
  background: var(--acao); border-color: var(--acao);
  box-shadow: 0 0 0 rgba(15,23,42,.2), inset 0 1px 3px rgba(0,0,0,.22);
}
.btn.primario:disabled { box-shadow: none; }
.btn.primario:focus-visible { outline-color: var(--acao); outline-offset: 3px; }

.btn.perigo { color: var(--erro-tinta); }
.btn.perigo:hover { background: var(--erro-fundo); border-color: var(--erro-fundo); }
.btn.fantasma { border-color: transparent; background: transparent; color: var(--tinta-2); }
.btn.fantasma:hover { background: var(--realce); color: var(--tinta); }
/* Botão de largura total sai da pílula: em linha inteira o raio completo
   arredonda demais. Raio curto é o que se espera de um envio de formulário. */
.btn.largo {
  width: 100%; height: 48px; padding-inline: var(--e5);
  font-size: 15px; font-weight: 650; border-radius: 11px; letter-spacing: .002em;
}
.btn.mini { padding: 4px 11px; font-size: 12.5px; }
.btn.grande { padding: 12px var(--e5); font-size: 15px; }
.btn:disabled { opacity: .45; cursor: not-allowed; }

/* ----------------------------------------------------------- tabelas -- */

.rolagem { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td {
  /* 24px de cada lado somam 48px por coluna; com oito colunas isso é 384px só
     de respiro, e a tabela transborda o cartão numa tela de 1440. */
  text-align: left; padding: 11px var(--e4); border-bottom: 1px solid var(--linha);
  /* Sem isto, nome e telefone quebram em três linhas mesmo sobrando largura: o
     navegador prefere espremer a coluna a alargar a tabela. Quem rola quando
     não cabe é `.rolagem`, não a célula. */
  white-space: nowrap;
}
td.quebra { white-space: normal; min-width: 22ch; }
thead th {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .09em;
  color: var(--tinta-3); font-weight: 600; padding-block: 9px;
  background: var(--papel); position: sticky; top: 0;
}
tbody tr:last-child td { border-bottom: 0; }
tbody tr.clicavel { cursor: pointer; }
tbody tr { transition: background .12s var(--curva); }
tbody tr.clicavel:hover { background: var(--realce); }
/* O cabeçalho tem que acompanhar o alinhamento do dado. Sem `th.num` o
   rótulo ficava colado à esquerda e o número à direita da mesma coluna: a
   tabela parecia desmontada mesmo com todos os valores certos. */
th.num, td.num { text-align: right; font-variant-numeric: tabular-nums; }
/* Coluna de número não precisa de largura: ela encolhe até o conteúdo e
   devolve o espaço para nome e responsável, que é onde a leitura acontece. */
th.num, td.num { width: 1%; white-space: nowrap; }
td.num { font-weight: 600; }

/* Texto longo numa tabela de largura fixa: corta com reticências em vez de
   esticar a coluna. O valor inteiro fica no `title`. */
.truncar {
  max-width: 0; width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Coluna de ações: a célula continua célula, quem organiza os botões é o
   invólucro. `display: flex` no próprio <td> tira a coluna do algoritmo de
   largura da tabela, e o conteúdo vaza para fora do cartão. */
th.acoes, td.acoes { text-align: right; width: 1%; }
.acoes-linha { display: inline-flex; align-items: center; gap: 6px; }

.vazio { padding: var(--e8) var(--e5); text-align: center; color: var(--tinta-2); }
.vazio .icone {
  display: grid; place-items: center; width: 42px; height: 42px; margin: 0 auto var(--e3);
  border-radius: 50%; background: var(--realce); color: var(--tinta-3); font-size: 17px;
}

/* --------------------------------------------------------- etiquetas -- */

.tag {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px; border-radius: var(--r-pill);
  font-size: 11.5px; font-weight: 550; line-height: 1.75;
  background: var(--realce); color: var(--tinta-2); white-space: nowrap;
}
.tag.ok     { background: var(--ok-fundo);     color: var(--ok-tinta); }
.tag.alerta { background: var(--alerta-fundo); color: var(--alerta-tinta); }
.tag.erro   { background: var(--erro-fundo);   color: var(--erro-tinta); }
.tag.info   { background: var(--info-fundo);   color: var(--info-tinta); }
.pilha > .tag { align-self: flex-start; }

/* ------------------------------------------------------------ avisos -- */

.aviso {
  padding: var(--e3) var(--e4); border-radius: var(--r3); font-size: 13.5px;
}
.aviso.erro   { background: var(--erro-fundo);   color: var(--erro-tinta); }
.aviso.ok     { background: var(--ok-fundo);     color: var(--ok-tinta); }
.aviso.info   { background: var(--info-fundo);   color: var(--info-tinta); }
.aviso.alerta { background: var(--alerta-fundo); color: var(--alerta-tinta); }
.aviso:empty  { display: none; }

.torradeira {
  position: fixed; right: var(--e5); bottom: var(--e5); z-index: 100;
  display: flex; flex-direction: column; gap: var(--e2); max-width: min(380px, 90vw);
}
.torrada {
  padding: var(--e3) var(--e4); border-radius: var(--r3);
  background: var(--n-950); color: var(--n-0); font-size: 13.5px; font-weight: 450;
  box-shadow: var(--sombra-3); animation: sobe .22s var(--curva);
}
.torrada.erro { background: var(--erro-tinta); color: #fff; }
@keyframes sobe { from { opacity: 0; transform: translateY(10px); } }

/* ------------------------------------------------------------ camadas -- */

.fundo-modal {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(11,11,10,.42);
  backdrop-filter: blur(3px);
  display: grid; justify-items: end;
  animation: aparece .18s var(--curva);
}
@keyframes aparece { from { opacity: 0; } }

.gaveta {
  background: var(--papel); width: min(560px, 100%); height: 100%;
  overflow-y: auto; box-shadow: var(--sombra-3);
  animation: entra .26s var(--curva);
}
@keyframes entra { from { transform: translateX(32px); opacity: 0; } }
.gaveta > header {
  position: sticky; top: 0; z-index: 1; background: var(--papel);
  padding: var(--e5) var(--e5) var(--e4); border-bottom: 1px solid var(--linha);
  display: flex; align-items: flex-start; gap: var(--e3);
}
.gaveta > .miolo { padding: var(--e5); display: flex; flex-direction: column; gap: var(--e6); }

/* O modal nunca passa da altura da janela.
 *
 * O formulário de campanha cresceu (escolha de clientes, intervalo,
 * agendamento) e passou a estourar a tela em notebook: os botões ficavam
 * abaixo da dobra, sem rolagem nenhuma para alcançá-los. Agora o miolo rola
 * por dentro e o rodapé de ações fica grudado embaixo, sempre visível. */
.caixa-modal {
  background: var(--papel); border-radius: var(--r4); box-shadow: var(--sombra-3);
  width: min(460px, 100%); margin: auto; animation: sobe .2s var(--curva);
  display: flex; flex-direction: column;
  max-height: calc(100vh - var(--e6));
  /* `overflow: hidden` respeita o arredondamento das quinas quando o conteúdo
     rola por baixo delas. */
  overflow: hidden;
}
.caixa-modal > .corpo-modal {
  overflow-y: auto; overflow-x: clip;
  /* Sem isto o filho de flex nunca encolhe abaixo do tamanho do conteúdo, e a
     rolagem simplesmente não acontece. */
  min-height: 0;
}
/* O rodapé acompanha a rolagem colado embaixo: quem rola até o meio de uma
   lista longa continua a um clique de cancelar ou confirmar. */
.corpo-modal > .acoes-modal {
  position: sticky; bottom: calc(var(--e5) * -1);
  margin-bottom: calc(var(--e5) * -1);
  padding-bottom: var(--e5);
  background: var(--papel); z-index: 1;
}
.fundo-modal.centrado { place-items: center; padding: var(--e4); }

.dados { display: grid; grid-template-columns: auto 1fr; gap: var(--e3) var(--e5); font-size: 13.5px; }
.dados dt { color: var(--tinta-3); white-space: nowrap; }
.dados dd { margin: 0; }

/* --------------------------------------------------------- progresso -- */

.barra-progresso { height: 6px; border-radius: var(--r-pill); background: var(--realce); overflow: hidden; }
.barra-progresso > span {
  display: block; height: 100%; background: var(--acento-vivo); border-radius: inherit;
  transition: width .5s var(--curva);
}

.selos { display: flex; flex-wrap: wrap; gap: var(--e2); }
.selos i {
  width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center;
  border: 1px dashed var(--linha-forte); color: var(--tinta-3);
  font-style: normal; font-size: 11.5px; font-weight: 550;
}
.selos i.cheio {
  background: var(--acento-vivo); border-style: solid; border-color: var(--acento-vivo);
  color: var(--acento-contraste);
}

.linha-tempo { display: flex; flex-direction: column; }
.linha-tempo .item {
  display: grid; grid-template-columns: 24px 1fr auto; gap: var(--e3);
  padding: var(--e3) 0; border-bottom: 1px solid var(--linha); font-size: 13.5px;
}
.linha-tempo .item:last-child { border-bottom: 0; }
.linha-tempo .bolha {
  width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center;
  background: var(--acento-fraco); color: var(--acento-forte);
  font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums;
}
.linha-tempo .bolha.neg { background: var(--erro-fundo); color: var(--erro-tinta); }

/* -------------------------------------------------------- utilidades -- */

/* Estas classes existem por causa da CSP: `style-src 'self'` faz o navegador
 * BLOQUEAR atributo `style=` no markup. Valor que só se conhece em execução
 * (largura de barra) é aplicado por CSSOM no JS, que a CSP não restringe. */

.tela-centro { min-height: 100vh; display: grid; place-items: center; padding: var(--e5); }
.centrado-h  { justify-content: center; }

.larg-400 { width: min(400px, 100%); }
.larg-420 { width: min(420px, 100%); }
.larg-440 { width: min(440px, 100%); margin: 0 auto; }
.teto-380 { max-width: 380px; }
.teto-420 { max-width: 420px; }
.teto-460 { max-width: 460px; }

.mt1 { margin-top: var(--e1); }
.mt3 { margin-top: var(--e3); }
.mt4 { margin-top: var(--e4); }
.mt5 { margin-top: var(--e5); }
.corpo-modal { padding: var(--e5); }
.pilha-caixa { padding: var(--e5) var(--e4) var(--e8); }

.imagem-qr { display: block; width: 100%; max-width: 220px; margin: 0 auto; height: auto; }
.imagem-qr.grande { max-width: 268px; }

.titulo-publico { font-size: 25px; }
.emoji { font-size: 30px; line-height: 1; }

/* Código do caixa: é ditado em voz alta e digitado por outra pessoa, às vezes
   de longe. Tamanho grande aqui é requisito, não estética. */
.caixa-codigo {
  display: flex; flex-direction: column; gap: var(--e2); text-align: center;
  background: var(--acento-fraco); border-radius: var(--r4); padding: var(--e6) var(--e3);
}
.caixa-codigo .valor {
  font-family: var(--mono); font-weight: 600; letter-spacing: .14em;
  font-size: clamp(36px, 12vw, 56px); color: var(--acento-forte); line-height: 1.1;
}

.item-fila {
  display: flex; align-items: center; gap: var(--e3);
  padding: var(--e3) 0; border-bottom: 1px solid var(--linha);
}
.item-fila:last-child { border-bottom: 0; }

.aceite { font-weight: 400; align-items: flex-start; }
.aceite input { margin-top: 3px; }

/* Título de seção do console: chapéu pequeno + título grande. */
.titulo-secao h1 { font-size: 30px; letter-spacing: -.024em; }
.titulo-secao .chapeu {
  font-size: 11px; text-transform: uppercase; letter-spacing: .11em;
  color: var(--tinta-3); font-weight: 600; margin-bottom: var(--e2);
}

/* ------------------------------------------------------------- marca --- */

.logo-link { display: inline-flex; align-items: center; }
.logo-link:hover { text-decoration: none; }
/* Altura fixa e largura automática: a arte é @2x, então metade da altura
   nativa é o tamanho lógico correto e o navegador não reamostra à toa. */
/* A classe pode cair no <img> ou no <picture> que o envolve. Quando cai no
   <picture>, a imagem de dentro continua sem regra e renderiza no tamanho
   natural (619px), foi assim que o logo vazou pela lateral. Dimensionar os
   dois cobre as duas formas. */
.logo-marca { display: block; height: 26px; width: auto; }
.logo-marca img { display: block; height: 100%; width: auto; }
.logo-marca.pequeno { height: 22px; }
.selo-admin { margin-left: var(--e2); }
@media (max-width: 900px) { .lateral .logo-marca { height: 22px; } }

/* Denominador do indicador: menor e apagado, para o numerador continuar sendo
   o que se lê de longe. */
.indicador .numero .de { font-size: .5em; font-weight: 600; color: var(--tinta-3); letter-spacing: 0; }

/* ================================================== console: componentes === */

/* --- carregamento -------------------------------------------------------- */

/* Esqueleto no lugar de tela em branco. Não é enfeite: a diferença entre
   "está carregando" e "está vazio" é a pergunta que o usuário faz primeiro, e
   um bloco cinza pulsando responde antes de ele perguntar. */
.esqueleto {
  border-radius: var(--r2);
  background: linear-gradient(90deg, var(--realce) 25%,
              color-mix(in srgb, var(--realce) 55%, var(--papel)) 37%, var(--realce) 63%);
  background-size: 400% 100%;
  animation: brilha 1.4s ease-in-out infinite;
}
@keyframes brilha { from { background-position: 100% 0; } to { background-position: -100% 0; } }
.esqueleto.linha { height: 13px; }
.esqueleto.linha + .esqueleto.linha { margin-top: 10px; }
/* Segunda linha mais curta: bloco uniforme parece caixa cinza; irregular
   parece texto. A CSP proíbe style= no markup, então a variação vira classe. */
.esqueleto.linha.curta { width: 62%; }
.esqueleto.bloco { height: 78px; }
.esqueleto-tabela { padding: var(--e5); display: flex; flex-direction: column; gap: var(--e4); }
@media (prefers-reduced-motion: reduce) { .esqueleto { animation: none; } }

/* --- erro de seção ------------------------------------------------------- */

/* Falha de carregamento vira estado com saída, não torrada que some. Erro que
   desaparece sozinho deixa a tela vazia sem explicação. */
.secao-erro {
  padding: var(--e7) var(--e5); text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: var(--e3);
}
.secao-erro .icone {
  width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center;
  background: var(--erro-fundo); color: var(--erro-tinta); font-size: 17px;
}

/* --- primeiros passos ---------------------------------------------------- */

.arranque { border-color: var(--linha-forte); }
.arranque > header { align-items: center; }
.arranque .progresso-topo {
  display: flex; align-items: center; gap: var(--e3); margin-left: auto;
  font-size: 12.5px; color: var(--tinta-2); white-space: nowrap;
}
.arranque .progresso-topo .barra-progresso { width: 92px; }

.passo-lista { display: flex; flex-direction: column; }
.passo-lista > li {
  display: grid; grid-template-columns: 24px 1fr auto; gap: var(--e3);
  align-items: center; padding: 10px 0;
  border-top: 1px solid var(--linha); list-style: none;
}
.passo-lista > li:first-child { border-top: 0; }
.passo-marca {
  width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center;
  border: 1.5px solid var(--linha-forte); color: var(--tinta-3);
  font-size: 11px; font-weight: 650;
}
.passo-lista li.feito .passo-marca {
  background: var(--acento-vivo); border-color: var(--acento-vivo);
  color: var(--acento-contraste);
}
.passo-lista li.feito .passo-titulo { color: var(--tinta-3); text-decoration: line-through; }
.passo-titulo { font-size: 14px; font-weight: 550; }
.passo-lista .mini { margin-top: 1px; }

/* No celular a grade de três colunas espreme o texto entre a marca e o botão,
   e cada linha vira quatro. Empilhado, o passo cabe em duas. */
@media (max-width: 640px) {
  .arranque > header { flex-wrap: wrap; }
  .arranque .progresso-topo { margin-left: 0; width: 100%; }
  .arranque .progresso-topo .barra-progresso { flex: 1; width: auto; }
  /* Alinhado ao topo: com o texto quebrando em duas linhas, a marca
     centralizada flutua entre título e nota, sem pertencer a nenhum. */
  .passo-lista > li { grid-template-columns: 24px 1fr; row-gap: var(--e2); align-items: start; }
  .passo-lista > li .passo-marca { margin-top: 1px; }
  .passo-lista > li > :last-child { grid-column: 2; justify-self: start; }
  /* O `<span>` vazio de quem não tem ação viraria uma linha em branco. */
  .passo-lista > li > span:empty { display: none; }
}

/* --- ações rápidas ------------------------------------------------------- */

.acoes-rapidas { display: grid; gap: var(--e3); grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.acao-rapida {
  display: flex; align-items: center; gap: var(--e3); text-align: left;
  padding: var(--e4); border: 1px solid var(--linha); border-radius: var(--r3);
  background: var(--papel); color: var(--tinta); cursor: pointer; font: inherit;
  transition: border-color .16s var(--curva), background .16s var(--curva);
}
.acao-rapida:hover { border-color: var(--linha-forte); background: var(--papel-2); }
.acao-rapida .simbolo {
  width: 34px; height: 34px; border-radius: 10px; flex: none; display: grid; place-items: center;
  background: var(--acento-fraco); color: var(--acento); font-size: 15px;
}
.acao-rapida strong { display: block; font-size: 14px; font-weight: 600; }
.acao-rapida span { font-size: 12.5px; color: var(--tinta-2); }

/* --- filtros em pastilha ------------------------------------------------- */

.chips { display: flex; flex-wrap: wrap; gap: var(--e2); }
.chips button {
  font: inherit; font-size: 13px; font-weight: 540; cursor: pointer;
  padding: 5px 12px; border-radius: var(--r-pill);
  border: 1px solid var(--linha); background: var(--papel); color: var(--tinta-2);
  transition: background .14s var(--curva), color .14s var(--curva), border-color .14s var(--curva);
}
.chips button:hover { background: var(--realce); color: var(--tinta); }
.chips button[aria-pressed="true"] {
  background: var(--acao); border-color: var(--acao); color: var(--acao-tinta);
}
.chips .conta { opacity: .65; margin-left: 5px; font-variant-numeric: tabular-nums; }

/* --- contagem ao lado do título ----------------------------------------- */

.contagem {
  display: inline-block; margin-left: var(--e2); padding: 1px 8px;
  border-radius: var(--r-pill); background: var(--realce); color: var(--tinta-2);
  font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums;
  vertical-align: middle;
}

/* --- indicador clicável -------------------------------------------------- */

/* Número que leva a algum lugar precisa parecer que leva. */
.indicador.leva { cursor: pointer; transition: border-color .16s var(--curva); }
.indicador.leva:hover { border-color: var(--linha-forte); }
.indicador.leva .rotulo::after { content: ' ›'; opacity: .5; }
.indicador.destaque { border-color: color-mix(in srgb, var(--acento-vivo) 45%, var(--linha)); }
.indicador.destaque .numero { color: var(--acento); }

/* --- barra de ferramentas de tabela -------------------------------------- */

.ferramentas {
  display: flex; align-items: center; gap: var(--e3); flex-wrap: wrap;
  padding: var(--e4) var(--e5); border-bottom: 1px solid var(--linha);
}
.ferramentas .busca { position: relative; flex: 1 1 220px; min-width: 180px; }
.ferramentas .busca input { padding-left: 34px; height: 38px; }
.ferramentas .busca svg {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  width: 15px; height: 15px; color: var(--tinta-3); pointer-events: none;
}
.ferramentas .busca kbd {
  position: absolute; right: 9px; top: 50%; transform: translateY(-50%);
  font-family: var(--mono); font-size: 10.5px; color: var(--tinta-3);
  border: 1px solid var(--linha); border-radius: 5px; padding: 1px 5px;
  background: var(--papel-2);
}
.ferramentas select { width: auto; height: 38px; }

/* --- menu lateral no celular --------------------------------------------- */

/* No computador o menu está sempre à vista, então o botão não existe. */
.abre-menu { display: none; }

/* Rótulo curto e longo da mesma etiqueta. O padrão é o longo, e o bloco de
   celular mais abaixo inverte. A ordem importa: os dois seletores têm a mesma
   especificidade, então o que vier por último vence, e com o padrão escrito
   DEPOIS da media query o rótulo curto ficava escondido nas duas larguras e a
   etiqueta aparecia vazia no telefone. */
.rotulo-curto { display: none; }

@media (max-width: 900px) {
  .shell { grid-template-columns: 1fr; }

  /* Gaveta em vez de faixa rolável: com sete itens, a faixa horizontal esconde
     metade do menu fora da tela e não há nada que indique isso. */
  .lateral {
    position: fixed; inset: 0 auto 0 0; z-index: 70;
    width: 268px; height: 100dvh; flex-direction: column;
    border-right: 1px solid var(--linha); border-bottom: 0;
    transform: translateX(-100%); transition: transform .26s var(--curva);
    box-shadow: var(--sombra-3);
    overflow-y: auto; overflow-x: clip;
  }
  .shell.menu-aberto .lateral { transform: none; }
  .nav { flex-direction: column; }
  /* `display: block` aqui desfazia a coluna do rodapé e jogava os botões lado
     a lado, `.pilha` é flex, e block sobrescreve isso. */
  .nav .grupo { display: block; }
  .rodape-lateral { display: flex; }

  .veu {
    position: fixed; inset: 0; z-index: 65; background: rgba(2,6,23,.45);
    backdrop-filter: blur(2px); animation: aparece .18s var(--curva);
  }

  /* A barra continua, com o botão do menu na frente. Escondê-la era o que
     tirava do telefone o nome da loja e o seletor. */
  .barra { padding: 0 var(--e4); gap: var(--e2); }
  .abre-menu {
    /* 44px é o alvo de toque confortável para o dedo. Tinha 36, e este é o
       controle mais usado da tela pequena: é por ele que se chega a tudo. */
    display: grid; place-items: center; width: 44px; height: 44px; flex: none;
    margin-left: calc(var(--e2) * -1);
    border: 0; border-radius: var(--r2);
    background: transparent; color: var(--tinta); cursor: pointer;
  }
  .abre-menu:active { background: var(--realce); }
  .abre-menu svg { width: 20px; height: 20px; }
  /* O seletor fica com a sobra da barra. `.espaco` some porque no telefone não
     existe sobra para distribuir: os três itens já disputam 390px, e mantê-lo
     espremia o nome da loja até "L.". */
  .barra .espaco { display: none; }
  .barra .sel, .barra #troca-loja { min-width: 0; flex: 1 1 auto; max-width: none; }
  .barra > .tag { flex: none; }
  /* Maior que no computador, de propósito: aqui ele é o assunto da barra, e
     é alvo de dedo. 44px de altura é o mínimo confortável para tocar. */
  .barra .troca-botao {
    width: 100%; height: 44px; font-size: 15px; padding: 0 12px 0 8px;
  }
  .barra .troca-selo { width: 30px; height: 30px; font-size: 13px; }

  /* A etiqueta do WhatsApp encurta. "WhatsApp conectado" ocupava 262 dos 390px
     da barra para dizer que está tudo bem, e o nome da loja, que é a
     informação que muda, ficava sem espaço. */
  .rotulo-longo { display: none; }
  .rotulo-curto { display: inline; }
}

/* ------------------------------------------------- lateral: ícones e rail --- */

/* Ícones em SVG, não em caractere unicode. Glifo tipográfico depende da fonte
   instalada, muda de tamanho e de peso entre sistemas, e alguns nem existem,   é o tipo de detalhe que faz uma interface parecer improvisada. */
.nav button .icone {
  width: 18px; height: 18px; flex: none; display: grid; place-items: center;
  opacity: .75; transition: opacity .18s var(--curva), color .18s var(--curva);
}
.nav button .icone svg { width: 17px; height: 17px; }
.nav button[aria-current="page"] .icone { opacity: 1; color: var(--acento); }

.topo-lateral { display: flex; align-items: center; }

/* Lockup e símbolo ocupam o MESMO espaço, um sobre o outro: assim a troca é
   dissolução, e não um sumindo enquanto o outro aparece noutro lugar. */
.marca-slot {
  position: relative; display: block; height: 28px; flex: 1; min-width: 0;
  /* O lockup fica absoluto e continua com os seus ~126px mesmo invisível no
     modo recolhido. Sem o corte, ele soma largura interna à lateral sem razão
     nenhuma, não aparece, mas conta. */
  overflow: clip;
}
.marca-slot .logo-marca,
.marca-slot .marca-simbolo {
  position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  transition: opacity .22s var(--curva);
}
.marca-slot .logo-marca { height: 26px; opacity: 1; }
.marca-slot .marca-simbolo { width: 28px; height: 28px; opacity: 0; }

/* Botão na borda da lateral, meio para dentro e meio para fora. Fica no mesmo
   lugar nos dois estados, dentro do cabeçalho ele disputaria os 64px do modo
   recolhido com o símbolo. A seta gira 180°, que é a única pista de direção
   que o controle precisa. */
.recolhe {
  position: absolute; top: 24px; right: 12px; z-index: 5;
  width: 26px; height: 26px; display: grid; place-items: center; cursor: pointer;
  border: 1px solid var(--linha); border-radius: var(--r2);
  background: var(--papel); color: var(--tinta-3);
  /* Visível sempre. Escondê-lo até o apontamento economiza um detalhe visual e
     custa a função inteira: quem não sabe que o controle existe não procura
     por ele. Fica discreto, não invisível. */
  opacity: .55;
  transition: opacity .18s var(--curva), background .16s var(--curva),
              color .16s var(--curva), border-color .16s var(--curva);
}
.lateral:hover .recolhe, .recolhe:focus-visible { opacity: 1; }
.recolhe:hover { background: var(--realce); color: var(--tinta); border-color: var(--linha-forte); }
.recolhe svg { width: 15px; height: 15px; transition: transform .28s var(--curva); }
.shell.rail .recolhe svg { transform: rotate(180deg); }
/* Recolhida, ele desce para baixo do símbolo: em 68px de largura os dois não
   cabem lado a lado. */
.shell.rail .recolhe { position: static; margin: var(--e3) auto 0; opacity: .7; }
.shell.rail .topo-lateral { flex-direction: column; }
@media (max-width: 900px) { .recolhe { display: none; } }

/* --- a transição -------------------------------------------------------- */

/* A largura é animada na própria grade do shell. O rótulo não some com
   `display: none`, isso não anima, só pisca: ele encolhe a largura e some por
   opacidade, e volta com um atraso curto, depois que já existe espaço para
   ele. É essa defasagem que faz a coisa parecer um painel deslizando em vez de
   dois estados alternando. */
.shell { transition: grid-template-columns .3s var(--curva); }
/* Sem `position` aqui: a lateral já é `sticky`, e `sticky` estabelece o
   contexto de posicionamento que o botão de recolher precisa. Declarar
   `relative` de novo, depois, trocava o `sticky` por `relative`, e a lateral
   passava a descer junto com a página. */
.lateral { transition: padding .3s var(--curva); }

.nav button .rotulo-nav {
  white-space: nowrap; overflow: hidden;
  max-width: 180px; opacity: 1;
  transition: max-width .3s var(--curva), opacity .2s var(--curva) .1s;
}
.nav .grupo {
  overflow: hidden; height: 28px; opacity: 1;
  transition: height .28s var(--curva), opacity .18s var(--curva),
              padding .28s var(--curva);
}

.shell.rail { grid-template-columns: 68px 1fr; }
.shell.rail .lateral { padding-inline: 14px; }
.shell.rail .marca-slot .logo-marca { opacity: 0; }
.shell.rail .marca-slot .marca-simbolo { opacity: 1; left: 50%; margin-left: -14px; }
.shell.rail .nav button { gap: 0; padding-inline: 0; justify-content: center; }
.shell.rail .nav button .rotulo-nav {
  max-width: 0; opacity: 0;
  transition: max-width .3s var(--curva), opacity .14s var(--curva);
}
.shell.rail .nav .grupo { height: 8px; opacity: 0; padding-block: 0; }
.shell.rail .rodape-lateral { align-items: center; }




/* Dica da lateral recolhida.
 *
 * Vive no <body>, com posição fixa, e não dentro da lateral: elemento
 * absoluto ancorado fora da caixa faria voltar a barra horizontal, e dentro
 * dela seria cortado pelo `overflow-x: clip`. Quem posiciona é o JS, no
 * momento do apontamento. */
.dica-lateral {
  position: fixed; z-index: 90; pointer-events: none;
  background: var(--n-900); color: var(--n-0);
  font-size: 12.5px; font-weight: 500; white-space: nowrap;
  padding: 6px 10px; border-radius: var(--r2); box-shadow: var(--sombra-2);
  opacity: 0; transform: translateX(-4px);
  transition: opacity .14s var(--curva), transform .14s var(--curva);
}
.dica-lateral.vista { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .shell, .lateral, .nav button .rotulo-nav, .nav .grupo,
  .marca-slot .logo-marca, .marca-slot .marca-simbolo, .recolhe svg {
    transition: none;
  }
}

@media (max-width: 900px) {
  .shell.rail { grid-template-columns: 1fr; }
  .shell.rail .lateral { padding: var(--e5) var(--e4); align-items: stretch; }
  .shell.rail .marca-slot .logo-marca { opacity: 1; }
  .shell.rail .marca-slot .marca-simbolo { opacity: 0; }
  .shell.rail .nav .grupo { height: 28px; opacity: 1; padding: var(--e3) var(--e3) var(--e1); }
  .shell.rail .nav button { justify-content: flex-start; padding: 8px var(--e3); gap: var(--e3); }
  .shell.rail .nav button .rotulo-nav { max-width: 180px; opacity: 1; }
  .shell.rail .nav button::after { display: none; }
  .shell.rail .rodape-lateral { align-items: flex-start; }
  .shell.rail .rodape-lateral .mini,
  .shell.rail .rodape-lateral > .btn { display: block; }
  .shell.rail 
}

/* Contador de quantidade: botões grandes para o dedo do atendente, e o campo
   continua digitável para quem precisa pôr 12 de uma vez. */
.contador { display: flex; align-items: stretch; gap: var(--e2); }
.contador input {
  flex: 1; text-align: center; font-size: 18px; font-weight: 650;
  font-variant-numeric: tabular-nums; height: 46px;
  -moz-appearance: textfield;
}
.contador input::-webkit-outer-spin-button,
.contador input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.contador .btn {
  width: 46px; height: 46px; padding: 0; font-size: 20px; font-weight: 500;
  border-radius: var(--r2); flex: none;
}

/* ---------------------------------------------------------- tela do caixa --- */

.barra-caixa {
  display: flex; align-items: center; gap: var(--e3);
  padding: 0 var(--e4); height: 58px;
  border-bottom: 1px solid var(--linha); background: var(--papel);
  position: sticky; top: 0; z-index: 20;
}
.tela-caixa {
  min-height: calc(100dvh - 58px);
  display: grid; place-items: start center;
  padding: var(--e6) var(--e4) var(--e8);
}
.tela-caixa .titulo-secao { margin-bottom: var(--e2); }
.tela-caixa .titulo-secao h1 { font-size: 27px; }

/* Campo de código: monoespaçado e espaçado, porque ele é conferido caractere a
   caractere contra um papel ou contra o que o atendente falou. */
.campo-codigo {
  font-family: var(--mono); font-size: 20px; font-weight: 600;
  letter-spacing: .28em; text-align: center; text-transform: uppercase;
  height: 52px;
}
.selos.centro-selos { justify-content: center; }

/* Rodapé de ação do modal: as duas escolhas lado a lado, e a principal com o
   dobro da largura. Peso igual entre "fazer" e "desistir" faz a pessoa parar
   para ler qual é qual; a diferença de tamanho já responde antes da leitura. */
.acoes-modal {
  display: grid; grid-template-columns: 1fr 2fr; gap: var(--e3);
  padding-top: var(--e4); border-top: 1px solid var(--linha);
}
.acoes-modal .btn { width: 100%; height: 42px; border-radius: var(--r2); font-size: 14px; }
.acoes-modal > span:empty { display: none; }
/* Sozinho, o "Fechar" não precisa ocupar um terço da largura. */
.acoes-modal:has(> span:empty) { grid-template-columns: 1fr; }
.largura-cheia { width: 100%; }

/* Espera de pareamento: o QR fica parado e só o indicador se mexe. Antes a
   tela inteira era redesenhada a cada consulta, e o botão sumia e voltava. */
.qr-pareando { display: flex; flex-direction: column; gap: var(--e3); }

/* Recado discreto dentro do painel de pareamento: o parceiro tropeçou, mas a
   tela continua de pé e a consulta continua. Fica vazio no caminho normal, e
   por isso não pode reservar altura nem empurrar o QR quando aparece. */
.atencao {
  color: var(--aviso-texto, #92400e);
  min-height: 1.2em;
}

/* Tela estreita: a tabela rola, e quem sai da vista primeiro são os botões de
   ação, justamente o que a pessoa foi ali fazer. Esconder antes a coluna de
   responsável devolve a largura para o que importa. O dado não some do
   sistema, só desta vista. */
@media (max-width: 1180px) {
  .some-estreito { display: none; }
  /* Esconder a coluna sozinho deixava a tabela 11px maior que o cartão, e 11px
     bastam para cortar o botão de ação. Menos respiro lateral por célula
     devolve espaço de sobra sem espremer a leitura. */
  th, td { padding-inline: var(--e3); }
  /* A coluna do nome é a única que pode ceder largura sem perder função: o
     nome continua legível e o caminho da página vira reticências. Esconder
     mais uma coluna seria tirar informação; aqui só encurta o que sobra.
     `max-width: 0` é o que autoriza a célula a encolher, sem isso o
     algoritmo da tabela respeita o conteúdo e ignora o overflow. */
  td.col-principal { max-width: 0; width: 100%; }
  td.col-principal, td.col-principal .sub {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
}

/* ------------------------------------------------------------- select -- */
/* O nativo continua no DOM como fonte da verdade. Ele some da vista sem sair
   do fluxo de foco por acidente: `clip-path` e tamanho zero em vez de
   `display: none`, que tiraria o campo do formulário em alguns navegadores. */
.sel { position: relative; width: 100%; }
.sel-nativo {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); border: 0; opacity: 0;
  pointer-events: none;
}

.sel-botao {
  display: flex; align-items: center; justify-content: space-between; gap: var(--e3);
  width: 100%; padding: 9px var(--e3); font: inherit; font-size: 14px;
  text-align: left; cursor: pointer;
  color: var(--tinta); background: var(--papel);
  border: 1px solid var(--linha-forte); border-radius: var(--r2);
  transition: border-color .14s var(--curva), box-shadow .14s var(--curva);
}
.sel-botao:hover { border-color: var(--tinta-2); }
.sel-botao:focus-visible,
.sel-botao[aria-expanded="true"] {
  border-color: var(--tinta); box-shadow: 0 0 0 3px var(--realce); outline: none;
}
.sel-botao:disabled { opacity: .55; cursor: not-allowed; }
.sel-valor { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Sem valor escolhido o texto é um convite, não um dado: cor de espaço vazio,
   igual ao placeholder dos campos de texto ao lado. O nome é prefixado porque
   `.vazio` já existe neste arquivo, para estado vazio de lista, e traz um
   `padding` grande junto: a colisão esticava o campo para 186px de altura. */
.sel-valor.sel-sem-escolha { color: var(--tinta-3); }

/* A seta é desenhada, não é caractere: glifo de fonte muda de tamanho e de
   linha de base entre sistemas, e era isso que fazia o controle nativo
   destoar. */
.sel-seta {
  flex: none; width: 9px; height: 9px; margin-right: 1px;
  border-right: 1.5px solid var(--tinta-3);
  border-bottom: 1.5px solid var(--tinta-3);
  transform: translateY(-2px) rotate(45deg);
  transition: transform .18s var(--curva), border-color .18s var(--curva);
}
.sel-botao[aria-expanded="true"] .sel-seta {
  transform: translateY(1px) rotate(-135deg);
  border-color: var(--tinta);
}

/* Presa ao <body>: dentro de um modal a lista seria cortada pelo recorte do
   cartão. Posição vem do script, que a calcula a partir do botão. */
.sel-lista {
  position: fixed; z-index: 90; max-height: 280px; overflow-y: auto;
  overflow-x: clip; padding: 5px;
  background: var(--papel); border: 1px solid var(--linha-forte);
  border-radius: var(--r2);
  box-shadow: 0 1px 2px rgba(15,23,42,.06), 0 12px 28px -8px rgba(15,23,42,.28);
  animation: sel-entra .13s var(--curva);
}
@keyframes sel-entra {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .sel-lista { animation: none; }
}

.sel-item {
  display: flex; align-items: center; justify-content: space-between; gap: var(--e3);
  padding: 8px var(--e3); border-radius: calc(var(--r2) - 3px);
  font-size: 14px; cursor: pointer; overflow: hidden;
}
/* O corte com reticências mora aqui, e não no `.sel-item`: texto solto dentro
   de um container flex vira item anônimo e não obedece `text-overflow`. */
.sel-item-texto { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* `sob` é o item sob o cursor ou sob a navegação por teclado: os dois pintam
   igual, senão o teclado vira cidadão de segunda classe. */
.sel-item.sob { background: var(--realce); }
.sel-item[aria-selected="true"] { font-weight: 600; }
/* A marca do escolhido é um tique desenhado, pelo mesmo motivo da seta. */
.sel-item[aria-selected="true"]::after {
  content: ''; flex: none; width: 5px; height: 9px;
  border-right: 1.6px solid var(--acao); border-bottom: 1.6px solid var(--acao);
  transform: rotate(45deg) translateY(-1px);
}
.sel-item[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }

/* Barra de ferramentas: o campo acompanha o conteúdo em vez de esticar. */
.ferramentas .sel { width: auto; min-width: 150px; }
.ferramentas .sel-botao { height: 38px; padding-block: 0; }
/* No telefone o mesmo controle é alvo de dedo, e 38px fica abaixo do
   confortável. Precisa vir DEPOIS da regra acima: mesma especificidade, quem
   aparece por último vence, e escrita antes ela não tinha efeito nenhum. */
@media (max-width: 640px) { .ferramentas .sel-botao { height: 44px; } }

/* Seletor de restaurante na barra do topo.
   Ele só aparece para quem cuida de mais de uma casa. Duas correções aqui:
   `width: 100%` fazia o controle atravessar a barra inteira, e o nome ficava
   escrito duas vezes, uma no rótulo fixo à esquerda e outra dentro do próprio
   seletor. Quando o seletor está na tela, ele passa a ser o nome. */
.barra .sel, .barra-caixa .sel { width: auto; min-width: 190px; max-width: 320px; }
.barra .sel-botao, .barra-caixa .sel-botao { height: 36px; padding-block: 0; }
.barra:has(.sel:not(.oculto)) .marca-barra { display: none; }

/* Etiqueta de estado que também é atalho. Ela já dizia se o WhatsApp está no
   ar; agora leva ao painel de conexão, que é o que a pessoa quer fazer logo
   depois de ler "Sem WhatsApp". */
.tag-acao { cursor: pointer; transition: box-shadow .14s var(--curva), filter .14s var(--curva); }
.tag-acao:hover { filter: brightness(.96); }
.tag-acao:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--realce); }

/* Linha de resumo do cartão: a etiqueta não deve esticar junto com o texto. */
.alinha-topo { align-items: flex-start; }
.alinha-topo > .tag { flex: none; margin-top: 1px; }

/* ------------------------------------------------- saída das camadas -- */
/* A entrada já existia; a saída faltava, e o corte seco tirava a noção de para
   onde o painel foi. Cada peça sai pelo caminho por onde entrou: a gaveta
   desliza de volta para a direita, o modal desce, o escurecido desvanece.

   Um pouco mais rápido que a entrada de propósito. Abrir é o que a pessoa
   pediu e merece o tempo de se anunciar; fechar já foi decidido, e demorar
   nisso vira espera. */
.fundo-modal.saindo {
  animation: fundo-sai .2s var(--curva) forwards;
  /* Painel em retirada não recebe mais clique nem toque. */
  pointer-events: none;
}
@keyframes fundo-sai { to { opacity: 0; } }

.fundo-modal.saindo > .gaveta { animation: gaveta-sai .2s var(--curva) forwards; }
@keyframes gaveta-sai { to { transform: translateX(32px); opacity: 0; } }

.fundo-modal.saindo > .caixa-modal { animation: modal-sai .18s var(--curva) forwards; }
@keyframes modal-sai { to { transform: translateY(6px) scale(.99); opacity: 0; } }

/* Sem movimento para quem pediu sem movimento: a camada some na hora, e o
   script nem espera pelo fim da animação. */
@media (prefers-reduced-motion: reduce) {
  .fundo-modal, .fundo-modal > .gaveta, .fundo-modal > .caixa-modal,
  .fundo-modal.saindo, .fundo-modal.saindo > .gaveta,
  .fundo-modal.saindo > .caixa-modal { animation: none; }
}

/* ------------------------------------------------ confirmar o estrago -- */
/* A ação destrutiva precisa parecer destrutiva antes do clique, não depois.
   O vermelho vive onde ele conta alguma coisa: no chapéu, na lista de
   consequências e no botão que destrói. O cartão fica igual a qualquer outro
   modal, moldura tingida vira decoração, e decoração compete com a leitura
   da lista, que é a parte que realmente faz alguém parar. */
.perigo-chapeu { color: var(--erro-tinta); }

.lista-perigo {
  margin: 0; padding: var(--e3) var(--e4) var(--e3) calc(var(--e4) + 14px);
  list-style: disc; border-radius: var(--r2);
  background: var(--erro-fundo); color: var(--erro-tinta);
  font-size: 13.5px; line-height: 1.65;
}
.lista-perigo li + li { margin-top: 2px; }

/* O botão de confirmar é sólido aqui: no rodapé de um modal de remoção, o
   contorno vazado some ao lado do Cancelar e o olho escolhe errado. */
.acoes-modal .btn.perigo {
  background: var(--erro-tinta); border-color: var(--erro-tinta); color: #fff;
}
.acoes-modal .btn.perigo:hover { filter: brightness(1.08); }
.acoes-modal .btn.perigo:disabled { opacity: .6; cursor: progress; }

/* Confirmar à direita e maior, cancelar à esquerda e menor: a mesma proporção
   dos outros modais, com a ordem trocada porque aqui o botão grande é o que
   destrói e ele não pode cair sob o polegar por acidente no canto do hábito. */
.acoes-modal.invertido { grid-template-columns: 1fr 1.6fr; }
.acoes-modal.invertido > .btn.perigo { order: 2; }
.acoes-modal.invertido > .btn.secundaria { order: 1; }

/* O aviso do modal só ocupa espaço quando tem o que dizer. */
#perigo-aviso:empty { display: none; }

/* Aviso logo abaixo de um campo: sem margem ele encosta na borda do input e os
   dois viram um bloco só. A margem existe para o olho separar "o que eu
   escrevo" de "o que o sistema me conta". */
.campo > .aviso { margin-top: var(--e3); }

/* Fichas de marcador: pequenas, clicáveis, e claramente um atalho e não um
   botão de ação. Elas inserem `{nome}` e afins no ponto do cursor.

   A fileira é flex, e não texto corrido, por um motivo prático: a ficha tem
   24px de altura dentro de uma linha de 20px, então dentro de um parágrafo ela
   estourava a caixa de linha e encostava no campo acima. Com `gap` o respiro é
   explícito e igual dos quatro lados, inclusive quando a fileira quebra. */
.fichas {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 6px; margin-top: var(--e3);
}
.fichas-rotulo { flex: none; }
.ficha {
  font: inherit; font-size: 12px; font-family: var(--mono, monospace);
  padding: 3px 8px; cursor: pointer;
  border: 1px solid var(--linha-forte); border-radius: var(--r-pill);
  background: var(--papel); color: var(--tinta-2);
  transition: background .14s var(--curva), color .14s var(--curva);
}
.ficha:hover { background: var(--realce); color: var(--tinta); }
.ficha:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--realce); }

/* Campo que não vale para a escolha atual: fica discreto em vez de sumir.
   Sumir faria a pessoa achar que perdeu o que tinha escrito.

   A opacidade é só o aviso visual. Quem realmente impede a interação é o
   `disabled` no controle, posto pelo script, sem ele o campo continuaria
   clicável, alcançável pelo Tab e anunciado por leitor de tela como se
   estivesse valendo. */
.apagado { opacity: .55; }
.apagado:focus-within { opacity: 1; }
/* Rótulo de campo desativado acompanha o cursor de "não dá para usar". */
.apagado:has(:disabled) label { cursor: not-allowed; }

/* Lugar do QR enquanto ele não chegou. O retângulo tem o tamanho final para a
   caixa não pular de altura quando a imagem entra, e respira devagar para dizer
   "estou buscando" sem competir com o pulso de "esperando a leitura" logo
   abaixo. */
.qr-caixa {
  display: grid; place-items: center;
  width: 260px; height: 260px; margin: 0 auto;
}
.qr-caixa > .imagem-qr { grid-area: 1 / 1; width: 100%; height: 100%; }
.qr-esperando {
  grid-area: 1 / 1; width: 100%; height: 100%;
  border-radius: var(--r2); background: var(--realce);
}

/* ------------------------------------------------ troca de restaurante -- */
/* Não é um campo de formulário: é a troca de contexto que muda tudo o que a
   tela mostra depois. Por isso tem cara de identidade (selo com a inicial e o
   nome) em vez de cara de <select>. */
.troca-botao {
  display: inline-flex; align-items: center; gap: var(--e2);
  /* Largura fixa, e a mesma do painel que abre. Antes o botão tinha 164px e o
     painel 300px: a lista pulava para fora do gatilho ao abrir, e o olho lê
     isso como coisa fora do lugar. */
  width: 260px; height: 38px; padding: 0 10px 0 6px;
  font: inherit; font-size: 13.5px; font-weight: 550; cursor: pointer;
  color: var(--tinta); background: var(--papel);
  border: 1px solid var(--linha-forte); border-radius: var(--r-pill);
  transition: background .14s var(--curva), border-color .14s var(--curva);
}
.troca-botao:hover { background: var(--realce); }
.troca-botao:focus-visible,
.troca-botao[aria-expanded="true"] {
  outline: none; border-color: var(--tinta); box-shadow: 0 0 0 3px var(--realce);
}
/* O nome ocupa o espaço que sobra, e é isso que empurra a seta para a borda
   direita. Sem `flex: 1` ela ficava colada no fim do texto, a 93px da borda,
   e o botão parecia ter largura sobrando à toa. */
.troca-nome {
  flex: 1; min-width: 0; text-align: left;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Selo com a inicial: dá ao restaurante um rosto que o olho reconhece antes de
   ler o nome, que é o que resolve o caso de duas casas com nome parecido. */
.troca-marca { display: flex; flex: none; }
.troca-selo {
  flex: none; display: grid; place-items: center; overflow: hidden;
  width: 26px; height: 26px; border-radius: 7px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .02em;
  background: var(--acao); color: var(--acao-tinta);
}
/* Com logo, o quadrado vira moldura clara: fundo escuro atrás de uma marca
   com fundo próprio suja a leitura dela. `contain` porque logo cortada perde
   justamente o que identifica. */
.troca-selo.com-logo { background: var(--papel); border: 1px solid var(--linha); }
.troca-selo img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; }
.troca-seta {
  flex: none; width: 7px; height: 7px; margin-left: 1px;
  border-right: 1.5px solid var(--tinta-3); border-bottom: 1.5px solid var(--tinta-3);
  transform: translateY(-2px) rotate(45deg);
  transition: transform .18s var(--curva);
}
.troca-botao[aria-expanded="true"] .troca-seta { transform: translateY(1px) rotate(-135deg); }

.troca-painel {
  position: fixed; z-index: 90; overflow-y: auto; overflow-x: clip;
  padding: 6px; background: var(--papel);
  border: 1px solid var(--linha-forte); border-radius: var(--r3);
  box-shadow: 0 1px 2px rgba(15,23,42,.06), 0 16px 36px -10px rgba(15,23,42,.3);
  animation: sel-entra .14s var(--curva);
}
@media (prefers-reduced-motion: reduce) { .troca-painel { animation: none; } }

.troca-cabeca { padding: 6px 8px 8px; display: grid; gap: 6px; }
.troca-busca { height: 34px; font-size: 13.5px; }
.troca-lista { display: grid; gap: 2px; }
.troca-vazio { padding: var(--e4) 0; }

.troca-item {
  display: flex; align-items: center; gap: var(--e3); width: 100%;
  padding: 8px; border: 0; border-radius: var(--r2);
  font: inherit; text-align: left; cursor: pointer;
  background: transparent; color: var(--tinta);
}
.troca-item.sob { background: var(--realce); }
.troca-item.atual .troca-item-nome { font-weight: 650; }
.troca-texto { display: grid; gap: 1px; min-width: 0; }
.troca-item-nome, .troca-texto .mini {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* O selo do item é discreto: o do botão identifica o contexto atual, o da
   lista só ajuda a varrer. */
.troca-item .troca-selo { width: 30px; height: 30px; }
.troca-item .troca-selo:not(.com-logo) { background: var(--realce); color: var(--tinta-2); }
.troca-item.atual .troca-selo:not(.com-logo) { background: var(--acao); color: var(--acao-tinta); }

/* Ponto de estado do WhatsApp: a informação que decide se aquela casa está
   operando de verdade, e que o nome sozinho não conta. */
.ponto {
  flex: none; margin-left: auto; width: 8px; height: 8px; border-radius: 50%;
}
.ponto.ok  { background: var(--ok-tinta); }
.ponto.off { background: var(--linha-forte); }

/* ------------------------------------------------------ foto de perfil -- */
/* O mesmo elemento mostra iniciais ou imagem, e a troca não pode mexer no
   layout: o quadrado tem tamanho fixo e a imagem preenche por dentro. */
.avatar-conta img, .avatar-grande img {
  width: 100%; height: 100%; object-fit: cover; border-radius: inherit;
  display: block;
}
/* Círculo, e não retângulo arredondado: é assim que o avatar aparece na barra
   lateral e no cabeçalho. Duas formas para a mesma coisa faz a prévia parecer
   outro elemento em vez da mesma foto em tamanho maior. */
.avatar-grande {
  flex: none; display: grid; place-items: center; overflow: hidden;
  width: 96px; height: 96px; border-radius: 50%;
  font-size: 30px; font-weight: 700; letter-spacing: .01em;
  background: var(--acao); color: var(--acao-tinta);
}
.alinha-centro { align-items: center; }
#aviso-foto:empty { display: none; }

/* ------------------------------------------------------------- telão -- */
/* Tela virada para o salão. Duas decisões governam o resto:
 *
 * A marca é a do RESTAURANTE. Quem olha é cliente da casa e nunca ouviu falar
 * da plataforma; ver a marca de um fornecedor ali quebra a experiência.
 *
 * O fundo NÃO muda de cor com o estado. Pintar a tela inteira de verde a cada
 * selo vira enfeite piscando no meio do salão, e depois da terceira vez
 * ninguém repara mais. O estado é dito por um cartão sóbrio no centro, com um
 * fio de cor e um ícone, o suficiente para ler de longe sem virar festa. */
.telao {
  min-height: 100vh; display: flex; flex-direction: column;
  gap: var(--e4); padding: var(--e5);
  background: var(--fundo);
}
.telao-topo { display: flex; justify-content: center; align-items: center; min-height: 52px; }
.telao-rodape { text-align: center; }
.telao-marca { display: grid; place-items: center; max-width: min(420px, 70vw); }
.telao-marca img { max-height: 52px; max-width: 100%; object-fit: contain; display: block; }
.telao-marca.so-texto {
  font-size: clamp(17px, 2.6vh, 23px); font-weight: 700; letter-spacing: -.01em;
  color: var(--tinta);
}

.telao-miolo {
  flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: var(--e4); text-align: center;
}

/* Cartão de estado: mesma caixa para repouso, lido, pronto e recusado. Só o
   fio superior e a cor do ícone mudam. */
.telao-cartao {
  display: flex; flex-direction: column; align-items: center; gap: var(--e3);
  width: min(520px, 88vw); padding: clamp(24px, 5vh, 44px) var(--e5);
  background: var(--papel); border-radius: var(--r4);
  /* O fio do topo só existe para dizer o estado. No repouso ele não diz nada,
     então fica transparente em vez de cinza: some da vista sem mudar a
     geometria do cartão, e a tela não pula 3px quando o estado troca. */
  border-top: 3px solid transparent;
  box-shadow: var(--sombra-2);
}
.telao-cartao h1 { font-size: clamp(22px, 3.8vh, 34px); }
.telao-cartao p { font-size: clamp(14px, 2vh, 18px); color: var(--tinta-2); }
.telao-destaque {
  font-size: clamp(17px, 2.8vh, 24px) !important; font-weight: 650;
  color: var(--tinta) !important;
}

.telao-simbolo {
  display: grid; place-items: center;
  width: clamp(52px, 9vh, 76px); aspect-ratio: 1;
  border-radius: 50%; background: var(--realce); color: var(--tinta-2);
}
.telao-simbolo svg { width: 50%; height: 50%; display: block; }
.telao-simbolo.pulsa { animation: pulso-telao 1.8s ease-in-out infinite; }
@keyframes pulso-telao { 50% { opacity: .6; } }
@media (prefers-reduced-motion: reduce) { .telao-simbolo.pulsa { animation: none; } }

/* Um fio de cor por estado. É o que se lê de longe, e é só isso que precisa. */
.telao.lido     .telao-cartao { border-top-color: var(--alerta-tinta); }
.telao.lido     .telao-simbolo { background: var(--alerta-fundo); color: var(--alerta-tinta); }
.telao.pronto   .telao-cartao { border-top-color: var(--ok-tinta); }
.telao.pronto   .telao-simbolo { background: var(--ok-fundo); color: var(--ok-tinta); }
.telao.recusado .telao-cartao { border-top-color: var(--erro-tinta); }
.telao.recusado .telao-simbolo { background: var(--erro-fundo); color: var(--erro-tinta); }

/* O QR é o único elemento que pode ser grande: é o que a pessoa mira. */
.telao-selo { display: flex; align-items: baseline; gap: 7px; }
.telao-numero {
  font-size: clamp(30px, 6vh, 54px); font-weight: 750; line-height: 1;
  color: var(--tinta);
}
.telao-unidade { font-size: clamp(14px, 2.2vh, 20px); color: var(--tinta-2); }

.telao-qr {
  display: grid; place-items: center;
  width: min(50vh, 82vw); aspect-ratio: 1;
  padding: var(--e4); border-radius: var(--r4);
  background: var(--papel); box-shadow: var(--sombra-2);
}
.telao-qr img, .telao-qr .qr-esperando { width: 100%; height: 100%; }
.telao-instrucao { font-size: clamp(14px, 2.2vh, 20px); color: var(--tinta-2); }
.telao-nota { font-size: clamp(12px, 1.8vh, 15px); color: var(--tinta-3); }

.telao-barra {
  width: min(50vh, 82vw); height: 4px; border-radius: var(--r-pill);
  background: var(--linha); overflow: hidden;
}
.telao-barra > span {
  display: block; height: 100%; width: 100%;
  background: var(--tinta-3); border-radius: inherit;
}
/* QR de valor alto: um fio no lugar de uma moldura berrante. */
.telao.multiplo .telao-qr { box-shadow: 0 0 0 2px var(--tinta), var(--sombra-2); }
.telao.multiplo .telao-numero { color: var(--tinta); }

/* Marca de conclusão da página de resgate. */
.marca-pronto {
  display: grid; place-items: center; width: 56px; height: 56px;
  border-radius: 50%;
  background: var(--ok-fundo); color: var(--ok-tinta);
}
.marca-pronto svg { width: 26px; height: 26px; display: block; }

/* Largura para o cartão do QR rotativo no painel: precisa caber o código, a
   fileira de atalhos de selos e o botão de cancelar sem quebrar linha. */
.teto-520 { max-width: 520px; }

/* Fila de botões centralizada, para a barra de atalhos de selos do caixa. */
.centro-linha { justify-content: center; flex-wrap: wrap; }

/* Espera pela confirmação do caixa: mesma marca circular do "pronto", em tom
   de atenção. A cor diz "falta um passo" antes de a pessoa ler qualquer coisa. */
.marca-pronto.esperando-caixa { background: var(--alerta-fundo); color: var(--alerta-tinta); }
/* Confirmar e recusar dentro do cartão do QR, sem a borda do rodapé de modal. */
.miolo .acoes-modal { border-top: 0; padding-top: 0; }

/* Moldura da logo: a imagem pode ser larga, quadrada ou estreita, e a caixa
   precisa aceitar as três sem esticar nenhuma. `object-fit: contain` mantém a
   proporção; o fundo neutro dá o mesmo enquadramento para todas. */
/* Moldura da logo.
 *
 * `grid-template: 1fr / 1fr` não é enfeite: numa grade com linha `auto`, o
 * `max-height: 100%` da imagem não tem contra o que resolver e o navegador
 * ignora. Era isso que cortava a logo alta, a largura obedecia, a altura
 * passava direto e o `overflow: hidden` cortava o resto. Com a trilha em `1fr`
 * dentro de uma caixa de altura fixa, a porcentagem passa a ter base.
 *
 * A caixa é maior que antes porque a logo precisa ser conferida aqui: 160x88
 * cabia, mas deixava marca alta do tamanho de uma unha. */
/* Moldura da logo.
 *
 * A imagem PREENCHE a área e quem enquadra é o `object-fit: contain`. Foi a
 * segunda tentativa: com `max-height: 100%` a altura simplesmente não era
 * respeitada, porque porcentagem precisa de uma base definida e a linha da
 * grade era `auto`. Logo alta renderizava a 424px numa caixa de 130 e o
 * `overflow` cortava o resto.
 *
 * `min-width/min-height: 0` são obrigatórios: item de grade tem tamanho mínimo
 * automático igual ao do conteúdo, e sem zerar isso a imagem volta a esticar a
 * caixa por dentro. */
.moldura-logo {
  flex: none; display: grid; overflow: hidden;
  width: 210px; height: 130px; padding: 10px;
  border: 1px dashed var(--linha-forte); border-radius: var(--r2);
  background: var(--realce);
}
.moldura-logo img {
  width: 100%; height: 100%; min-width: 0; min-height: 0;
  object-fit: contain; display: block;
}
/* O vazio é o alvo do clique, e por isso se comporta como botão: muda no
   passar do mouse e diz o que fazer em vez de constatar a ausência. */
.moldura-logo > span { place-self: center; }
.moldura-logo.vazia {
  cursor: pointer; background: var(--papel);
  transition: background .16s var(--curva), border-color .16s var(--curva);
}
.moldura-logo.vazia:hover { background: var(--realce); border-color: var(--tinta-3); }
.alvo-envio {
  display: grid; justify-items: center; gap: 6px; color: var(--tinta-3);
  text-align: center;
}
.alvo-envio svg { width: 28px; height: 28px; }
.moldura-logo.vazia:hover .alvo-envio { color: var(--tinta-2); }

/* Iniciais no lugar da foto: fundo e tinta vêm do nome (ver Fid.corDoNome), e
   não do azul-marinho da marca. Numa lista de contas, todo mundo com o mesmo
   círculo escuro é o mesmo que ninguém ter rosto. */
.avatar-conta.sem-foto, .avatar-grande.sem-foto {
  box-shadow: inset 0 0 0 1px rgba(15, 23, 42, .06);
}
#aviso-logo:empty { display: none; }

/* Barra de progresso dentro de célula de tabela: ela precisa ocupar o espaço
   que sobra, senão encolhe até virar um traço. */
.barra-progresso.crescer { flex: 1; min-width: 60px; }

/* Modal mais largo, para o editor de mensagem: escrever texto de campanha numa
   coluna de 460px é escrever espiando por uma fresta. */
.caixa-modal.largo { width: min(680px, 100%); }

/* Passo do modelo de mensagem. A moldura separa um passo do outro sem pesar,
   porque a leitura aqui é vertical e sequencial. */
.passo-msg {
  display: grid; gap: var(--e2);
  padding: var(--e3); border-radius: var(--r2);
  border: 1px solid var(--linha); background: var(--realce);
}
.passo-msg textarea { min-height: 88px; background: var(--papel); }
.passo-msg .moldura-logo { width: 130px; height: 84px; }
#aviso-t:empty, #aviso-c:empty { display: none; }

/* Escolha de clientes para a campanha. Rola por dentro: a lista pode ter
   centenas de linhas, e deixar o modal crescer junto tira o botão de disparar
   da vista. */
.lista-escolha {
  max-height: 240px; overflow-y: auto; overflow-x: clip;
  margin-top: var(--e2); padding: 4px;
  border: 1px solid var(--linha); border-radius: var(--r2);
  background: var(--papel);
}
.item-escolha {
  display: flex; align-items: center; gap: var(--e3);
  padding: 7px var(--e2); border-radius: calc(var(--r2) - 3px);
  font-weight: 400; cursor: pointer; margin: 0;
}
.item-escolha:hover { background: var(--realce); }
.item-escolha input { flex: none; }
.pilha.g0 { display: grid; gap: 1px; }
.campo.crescer { flex: 1; }
#c-intervalo { width: 90px; }

/* =========================================================================
   O QUE MUDA NO TELEFONE

   Este bloco fica no FIM do arquivo de propósito. Media query não tem
   prioridade nenhuma sobre regra comum: com a mesma especificidade vence quem
   aparece por último. Escrito no meio da folha, ele era desfeito por cada
   componente declarado abaixo, e o ajuste simplesmente não acontecia.
   ========================================================================= */

/* --- o que muda no telefone ---------------------------------------------- */

/* `.linha` é uma fileira sem quebra, o que é certo numa tela larga e vira
   recorte numa estreita: em Configurações a moldura da logo tem 210px fixos, e
   ao lado dela sobravam 100px para um botão e um parágrafo. O resultado era
   texto cortado na borda da tela ("PNG, JPEG ou We…") e o botão Remover fora
   dela, sem rolagem nenhuma que o alcançasse.

   Quebrar é a resposta certa aqui: o conteúdo continua inteiro, só empilha. */
@media (max-width: 640px) {
  .linha { flex-wrap: wrap; }

  /* A moldura deixa de ter largura fixa e passa a ocupar a linha inteira: numa
     coluna de ~310px, 210px fixos ainda deixariam o texto espremido. */
  .moldura-logo { width: 100%; max-width: 320px; height: 150px; }

  /* Botão de largura mínima confortável para o dedo, e sem espremer o rótulo
     quando dois deles dividem a mesma linha. */
  .btn { min-height: 40px; }
  .acoes-modal .btn, .miolo > .linha > .btn { flex: 1 1 auto; }

  /* Rótulos e legendas paravam em 10,5px, que é menor que o corpo de texto do
     próprio sistema operacional. 12px é o piso do que se lê sem aproximar. */
  .mini { font-size: 13px; }
  /* O chapéu do título é caixa alta com espaçamento largo, e a 11px isso vira
     um risco cinza em vez de palavra. `.titulo-secao .chapeu` é mais
     específico que `.chapeu` sozinho, então o seletor precisa acompanhar. */
  .titulo-secao .chapeu, .chapeu, th { font-size: 12px; letter-spacing: .08em; }
  /* Etiqueta: 11,5px é menor que o corpo de texto do próprio sistema. */
  .tag { font-size: 12.5px; }

  /* Barra de ferramentas da lista. Os dois seletores tinham 150px e ficavam
     encolhidos contra a esquerda numa tela de 390: metade da largura sobrando
     ao lado de um alvo de toque de 38px de altura. Aqui eles dividem a linha
     por igual e crescem para 44. */
  .ferramentas { padding: var(--e3) var(--e4); }
  .ferramentas .busca { flex: 1 1 100%; }
  .ferramentas .busca input { height: 44px; }
  .ferramentas .sel { flex: 1 1 140px; min-width: 0; }

  /* Pastilha de filtro: 5px de altura interna dá 32px de alvo, abaixo do
     confortável para o dedo. */
  .chips button { padding: 9px 14px; font-size: 13.5px; }
  /* Mesma razão para as fichas de variável ({nome}, {selos}): 27px de altura
     é alvo de mouse, não de dedo. */
  .ficha { padding: 8px 12px; font-size: 13px; }

  /* --- tabela vira lista ------------------------------------------------
     Cada linha passa a ser um cartão e cada célula ganha à esquerda o nome da
     própria coluna, que o JS copiou do <th>. O cabeçalho some porque agora ele
     está repetido em cada linha, que é o preço de não ter mais colunas fora da
     tela. Só vale para tabela já rotulada: sem rótulo, empilhar produziria uma
     coluna de valores sem dizer do que são. */
  table[data-rotulada] { display: block; font-size: 14.5px; }
  table[data-rotulada] thead { display: none; }
  table[data-rotulada] tbody { display: block; }
  table[data-rotulada] tbody tr {
    display: block; padding: var(--e3) var(--e4);
    border-bottom: 1px solid var(--linha);
  }
  table[data-rotulada] tbody tr:last-child { border-bottom: 0; }
  table[data-rotulada] tbody td {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: var(--e4); padding: 3px 0; border: 0;
    /* A célula da tabela larga não quebra de propósito; aqui ela precisa.
       `wrap` porque o valor pode ser uma frase inteira (o texto de uma
       campanha, por exemplo): sem quebrar, ele vira um item de flex que não
       encolhe e sai pela borda da tela. */
    white-space: normal; text-align: right; width: auto;
    flex-wrap: wrap; overflow-wrap: anywhere;
  }
  table[data-rotulada] tbody td::before {
    content: attr(data-rotulo);
    flex: none; text-align: left; font-size: 12px; font-weight: 600;
    color: var(--tinta-3); text-transform: uppercase; letter-spacing: .06em;
  }
  /* A primeira célula é o assunto do cartão: fica no topo, maior, e sem
     rótulo, porque "NOME: Maria" é dizer o óbvio duas vezes. */
  table[data-rotulada] tbody td:first-child {
    display: block; text-align: left; font-weight: 650; font-size: 15.5px;
    margin-bottom: var(--e2);
  }
  table[data-rotulada] tbody td:first-child::before { content: none; }
  table[data-rotulada] tbody td.num { width: auto; }
  table[data-rotulada] tbody td .sub { display: inline; margin-left: var(--e2); }
  /* Empilhada, a célula não é mais uma coluna que precisa caber: `max-width: 0`
     e as reticências foram feitos para a tabela larga e aqui atrapalham. O
     `nowrap` herdado deixava o texto de uma campanha correr 17px para fora da
     tela sem quebrar em lugar nenhum. */
  /* `.truncar` e `.col-principal` existem para caber numa COLUNA: cortam com
     reticências e proíbem quebra. Empilhado não há coluna para caber, e as
     duas regras juntas faziam um e-mail longo quebrar letra por letra, uma
     célula de 374px de altura dentro de um cartão. */
  table[data-rotulada] tbody td.col-principal,
  table[data-rotulada] tbody td.col-principal .sub,
  table[data-rotulada] tbody td.truncar {
    max-width: none; width: auto;
    overflow: visible; text-overflow: clip; white-space: normal;
  }
  /* A coluna escondida na tela estreita VOLTA quando a tabela vira lista: ela
     foi escondida por falta de largura, e empilhado não falta. Sem isto, a
     regra de célula aqui embaixo a trazia de volta de qualquer jeito, e mal:
     é mais específica que `.some-estreito` e vinha depois. */
  table[data-rotulada] tbody td.some-estreito { display: flex; }
  /* Ficha de variável: 38px passa perto, 40 é o alvo confortável. */
  .ficha { padding: 9px 12px; }
}
