/* ============================================================================
 * PILOTO — shared/design.css
 * ----------------------------------------------------------------------------
 * FONTE ÚNICA DO DESIGN SYSTEM. Cópia do DS portável (modelo-base, versão de
 * 22/10/2026: densidade da ferramenta-mãe EncarteLab 7.2.0 + padrão do
 * Relatórios 0.11.0), adaptada ao Piloto em só três pontos:
 *   • Tema: data-theme="light|dark" no <html> (o DS usa data-tema="claro|
 *     escuro"). Todo [data-tema="escuro"] do DS virou [data-theme="dark"].
 *   • Fonte: DM Sans / DM Mono (Google Fonts) — identidade tipográfica do
 *     Piloto. O DS usa Geist.
 *   • A raiz do Piloto fica em 16px (base.css) para as medidas em rem do DS
 *     valerem o que dizem (32px = 2rem); o texto corrido continua 15px no body.
 * Ao atualizar o DS, copie o arquivo novo e refaça só estes três pontos.
 *
 * O resto é o DS como está. Norma completa: docs/CLAUDE.md §9 (Piloto) e a
 * §19 do CLAUDE.md do modelo-base (Dev/Design System). Vitrine para consulta:
 * referencias/design-system.html.
 *
 * O QUE ESTE ARQUIVO CONTÉM:
 *   • TOKENS e VARIÁVEIS DE COMPONENTE (a régua: 26/32/40px, foco, marca de
 *     seleção, botão primário, barra de filtros compacta, janelas…).
 *   • ÍCONES (.icone) e os COMPONENTES opt-in: estrutura de tela, botões,
 *     link, campos, grupos de campos, opções, barra de filtros (.filtros),
 *     seleção múltipla, card, ficha, indicadores, janela (.modal), toast,
 *     menu suspenso, dica, faixa de aviso, badges, abas e tabela; a navegação
 *     lateral (.sidebar, que o Piloto não usa: a navegação é por abas).
 *   Tudo é OPT-IN: só afeta quem tem a classe.
 *
 * O QUE NÃO CONTÉM: reset global e estilo em elemento nu (body, h1, a…).
 * O shell do Piloto (cabeçalho com abas, cabeçalho de tela .page-header,
 * filtros .filters, janelas .modal-overlay, paginação, toasts empilhados)
 * mora no base.css e LÊ as variáveis daqui.
 *
 * REGRA DE OURO: valor bruto (cor, espaço, raio, tempo) só existe nos TOKENS;
 * medida de componente que se repete vive nas VARIÁVEIS DE COMPONENTE.
 * ========================================================================== */


/* ============================================================================
 * 1. TOKENS — tema claro (raiz)
 * ========================================================================== */
:root {
  /* ---------- Tipografia (DM Sans / DM Mono — Google Fonts) ---------- */
  --fam-sans: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI',
              system-ui, sans-serif;
  --fam-mono: 'DM Mono', ui-monospace, 'SF Mono', Menlo, Consolas,
              'Liberation Mono', monospace;

  --fs-xs:    0.75rem;    /* 12px — auxiliar */
  --fs-sm:    0.875rem;   /* 14px — corpo secundário */
  --fs-base:  1rem;       /* 16px — corpo (e texto dos controles) */
  --fs-md:    1.125rem;   /* 18px — destaque */
  --fs-lg:    1.25rem;    /* 20px — subtítulo */
  --fs-xl:    1.5rem;     /* 24px — título de página */
  --fs-2xl:   1.875rem;   /* 30px — título grande */

  --lh-tight:    1.25;
  --lh-normal:   1.5;
  --lh-relaxed:  1.625;

  --ls-tight:   -0.01em;
  --ls-normal:   0;
  --ls-wide:     0.02em;

  /* ---------- Cores: neutros (tema claro) ---------- */
  --c-bg:           #ffffff;   /* fundo base */
  --c-bg-elev:      #fafafa;   /* superfície elevada (card, modal, toast) */
  --c-bg-muted:     #f4f4f5;   /* fundo sutil (campo, cabeçalho de tabela) */
  --c-bg-hover:     #f0f0f1;   /* hover de linha/superfície */
  --c-borda:        #e4e4e7;   /* borda padrão */
  --c-borda-forte:  #d4d4d8;   /* borda de ênfase (botão secundário, campo) */
  --c-texto:        #18181b;   /* texto primário */
  --c-texto-2:      #52525b;   /* texto secundário — todo texto que INFORMA */
  --c-texto-3:      #a1a1aa;   /* terciário — SÓ placeholder, desabilitado e "—" */

  /* ---------- Cores: acento (ÚNICO acento do sistema) ----------
   * Terracota. Um sistema, um acento. Para outra marca, troque SÓ estes 6
   * valores (e os 6 do tema escuro) — o resto do DS acompanha.
   * O --c-acento-ativo é também o fundo do botão primário no tema claro e a
   * cor da marca de seleção e do foco (ver 1b). */
  --c-acento:        #e87a3e;
  --c-acento-hover:  #d96a2c;
  --c-acento-ativo:  #c45a20;
  --c-acento-bg:     #fef3ec;  /* fundo tênue de acento (badge/realce/item ativo) */
  --c-acento-borda:  #f4cdb0;  /* borda de acento */
  --c-acento-texto:  #ffffff;  /* texto sobre fundo de acento */

  /* ---------- Cores: semânticas (uso pontual, contido) ---------- */
  --c-sucesso:     #16a34a;   --c-sucesso-bg:  #f0fdf4;
  --c-aviso:       #d97706;   --c-aviso-bg:    #fffbeb;
  --c-erro:        #dc2626;   --c-erro-bg:     #fef2f2;

  /* ---------- Espaçamento (base 4px) ----------
   * (Tokens — não aplicam espaço em nada sozinhos; os componentes os consomem.) */
  --esp-1:   0.25rem;   /*  4px */
  --esp-2:   0.5rem;    /*  8px */
  --esp-3:   0.75rem;   /* 12px */
  --esp-4:   1rem;      /* 16px */
  --esp-5:   1.25rem;   /* 20px */
  --esp-6:   1.5rem;    /* 24px */
  --esp-8:   2rem;      /* 32px */
  --esp-10:  2.5rem;    /* 40px */
  --esp-12:  3rem;      /* 48px */
  --esp-16:  4rem;      /* 64px */

  /* ---------- Raios (arredondamento das bordas — cantos sutis) ---------- */
  --raio-sm:    3px;
  --raio-md:    4px;
  --raio-lg:    6px;
  --raio-xl:    8px;
  --raio-full:  9999px;   /* pílula (badge) */

  /* ---------- Sombras (tema claro — discretas) ---------- */
  --sombra-sm:   0 1px 2px rgba(0, 0, 0, 0.04);
  --sombra-md:   0 2px 4px rgba(0, 0, 0, 0.05),
                 0 1px 2px rgba(0, 0, 0, 0.03);
  --sombra-lg:   0 8px 16px rgba(0, 0, 0, 0.06),
                 0 2px 4px  rgba(0, 0, 0, 0.04);
  --sombra-foco: 0 0 0 3px var(--c-acento-borda);   /* halo antigo (1,48:1 no branco). Token
                                                       mantido (travado), mas o DS não o usa
                                                       mais: foco = contorno --foco-cor (1b) */

  /* ---------- Transições ---------- */
  --t-rapida:  120ms ease-out;
  --t-padrao:  180ms ease-out;
  --t-lenta:   240ms ease-out;

  /* ---------- Z-index ---------- */
  --z-dropdown:  100;
  --z-sticky:    200;    /* (o cabeçalho fixo da tabela usa z-index 1: com 200 cobriria menus) */
  --z-modal:    1000;
  --z-toast:    1100;
  --z-tooltip:  1200;
}

/* ---------- TOKENS — tema escuro (override) ----------
 * Mesmas variáveis reescritas. O acento clareia (#f08552) e o texto sobre o
 * acento fica ESCURO para preservar contraste. Aplique com data-theme="dark"
 * no <html>. */
[data-theme="dark"] {
  --c-bg:           #0a0a0b;
  --c-bg-elev:      #141416;
  --c-bg-muted:     #1c1c1f;
  --c-bg-hover:     #232327;
  --c-borda:        #2a2a2e;
  --c-borda-forte:  #3f3f46;
  --c-texto:        #fafafa;
  --c-texto-2:      #a1a1aa;
  --c-texto-3:      #71717a;

  --c-acento:        #f08552;
  --c-acento-hover:  #e87a3e;
  --c-acento-ativo:  #d96a2c;
  --c-acento-bg:     #2a1810;
  --c-acento-borda:  #5a3a25;
  --c-acento-texto:  #0a0a0b;  /* preto sobre laranja claro = melhor contraste */

  --c-sucesso:     #22c55e;   --c-sucesso-bg:  #0a1f12;
  --c-aviso:       #f59e0b;   --c-aviso-bg:    #1f1608;
  --c-erro:        #ef4444;   --c-erro-bg:     #1f0d0d;

  /* Sombras mais opacas para serem perceptíveis em fundo escuro */
  --sombra-sm:   0 1px 2px rgba(0, 0, 0, 0.30);
  --sombra-md:   0 2px 4px rgba(0, 0, 0, 0.35),
                 0 1px 2px rgba(0, 0, 0, 0.25);
  --sombra-lg:   0 8px 16px rgba(0, 0, 0, 0.45),
                 0 2px 4px  rgba(0, 0, 0, 0.30);
}


/* ============================================================================
 * 1b. VARIÁVEIS DE COMPONENTE — densidade (a régua)
 * ----------------------------------------------------------------------------
 * NÃO são tokens. Os tokens acima continuam travados; estas variáveis só dão
 * NOME às medidas e às cores de estado que os componentes repetem, para a
 * régua ficar num lugar só.
 *   - Quase todas apontam para um token; valor bruto novo só aqui, comentado.
 *   - Mudar um valor aqui muda TODO componente que o lê.
 *   - Todo cálculo que depende de uma medida daqui LÊ a variável (ex.: o
 *     max-height do .modal usa --modal-moldura), nunca repete o número.
 *   - A versão escura vem logo abaixo, só quando o PAPEL da cor muda no escuro
 *     (referência a token já acompanha o tema sozinha).
 *   - CSS de módulo pode LER estas variáveis (para alinhar um controle próprio
 *     com o DS); não pode redefini-las.
 *   - [SE EDITOR] a ARTE (o que é exportado/impresso) não lê nenhuma delas.
 * Entre parênteses, contrastes medidos no tema claro (fórmula da WCAG).
 * ========================================================================== */
:root {
  /* ---------- Controles: grade de 4px; a fonte continua 16px ----------
     (exceção: a barra de filtros do computador — ver "Barra de filtros", abaixo) */
  --ctrl-altura:        2rem;       /* 32px — .btn, .input, .select, .btn-icone, .sidebar__item */
  --ctrl-altura-p:      1.625rem;   /* 26px — .btn-pequeno, "⋮" de linha, pílula */
  --ctrl-altura-g:      2.5rem;     /* 40px — .btn-grande (telas de acesso) */
  --ctrl-altura-toque:  2rem;       /* 32px — piso do botão de ícone pequeno em tela de toque */

  /* ---------- Campos (.input/.select/.textarea) ---------- */
  --campo-borda:        var(--c-borda-forte);   /* repouso = borda do .btn-secundario (1,34:1) */
  --campo-borda-hover:  var(--c-texto-3);       /* hover escurece */
  --campo-borda-foco:   var(--c-acento-ativo);  /* foco: borda + 1px de sombra = 2px efetivos (4,35:1) */
  --campo-placeholder:  color-mix(in srgb, var(--c-texto-3) 30%, var(--c-texto-2));  /* 4,87:1; bem mais claro que o texto digitado */

  /* ---------- Foco de teclado (contorno; não ocupa espaço) ---------- */
  --foco-cor:           var(--c-acento-ativo);  /* 4,35:1 no branco (o halo --sombra-foco tinha 1,48:1) */
  --foco-largura:       2px;
  --foco-folga:         2px;

  /* ---------- Marca de seleção: item escolhido/ativo; nunca some no hover ---------- */
  --selecao-cor:        var(--c-acento-ativo);  /* 4,35:1 claro · 5,7:1 escuro */
  --selecao-filete:     3px;                    /* filete à esquerda: item ativo do menu, linha sob o mouse/foco */
  --selecao-contorno:   2px;                    /* contorno do escolhido (1px de borda + 1px de sombra) e sublinhado da aba */

  /* ---------- Botão primário: laranja escuro no claro ---------- */
  --btn-primario-fundo: var(--c-acento-ativo);                               /* texto branco 4,35:1 (no --c-acento: 2,88:1) */
  --btn-primario-hover: color-mix(in srgb, var(--c-acento-ativo) 88%, black);
  --btn-primario-ativo: color-mix(in srgb, var(--c-acento-ativo) 76%, black);

  /* ---------- Hover de item de menu ----------
     Itens da navegação lateral, do submenu flutuante e o botão de recolher.
     O --c-bg-hover some sobre --c-bg-elev (1,09:1); a borda dá 1,22:1. */
  --item-hover:         var(--c-borda);
  --item-hover-perigo:  color-mix(in srgb, var(--c-erro) 12%, var(--c-bg-elev));

  /* ---------- Tela ---------- */
  --moldura-tela:       var(--esp-6);   /* recuo da área de conteúdo que rola: 24px (16px no celular) */
  --tela-media:         60rem;          /* 960px — .tela--media (formulários de configuração) */
  --tela-estreita:      45rem;          /* 720px — .tela--estreita (uma coluna de cards) */

  /* ---------- Tabela ---------- */
  --tabela-respiro-v:   var(--esp-2);   /* 8px → linha de texto com 38px, cabeçalho 35px */
  --tabela-respiro-h:   var(--esp-3);   /* 12px (8px em área estreita, ver .tabela-area) */
  --lista-mini-linha:   49px;           /* linha ÚNICA das listas com miniatura: 4 + 40 + 4 + 1 da divisória */
  --lista-mini-respiro: var(--esp-1);   /* 4px acima e abaixo da miniatura */
  --lista-mini-altura:  2.5rem;         /* 40px — teto de altura da miniatura */

  /* ---------- Janelas (.modal) ---------- */
  --modal-moldura:      var(--esp-4);   /* fundo escuro em volta: 16px (8px no celular) */
  --modal-recuo:        var(--esp-5);   /* recuo interno: 20px (16px no celular) */
  --modal-respiro-acoes: var(--esp-5);  /* 20px antes dos botões (margens colapsam: vale a maior) */

  /* ---------- Zona de envio de arquivo ---------- */
  --zona-borda:         color-mix(in srgb, var(--c-texto-3) 70%, var(--c-texto-2));  /* tracejado 3,15:1 */
  --zona-previa:        5rem;           /* 80px — lado da prévia (xadrez com 5 quadrados) */

  /* ---------- Link de texto (.link; e o <a> da BASE, se a ferramenta estilizar) ----------
     O --c-acento dá 2,88:1 no branco (reprova para texto de 14–16px). A cor do
     .badge-acento dá 5,8:1 no branco (5,3:1 no --c-bg-muted); o sublinhado do
     hover é a pista, a cor não muda. */
  --link-cor:           color-mix(in srgb, var(--c-acento-ativo) 80%, var(--c-texto));

  /* ---------- Barra de filtros compacta (.filtros) ----------
     Só no COMPUTADOR (≥768px com ponteiro fino: mouse ou trackpad) os
     controles da barra têm --ctrl-altura-p (26px) com estas fontes. No toque
     (celular, tablet) continuam 32px com 16px: abaixo de 16px o iPhone dá zoom
     ao focar o campo. Decisão do dono (22/10/2026), vinda do Relatórios. */
  --ctrl-fonte-compacta:   var(--fs-sm);   /* 14px — texto dos controles da barra */
  --rotulo-fonte-compacta: var(--fs-xs);   /* 12px — rótulo dos filtros */
  --filtro-base:           9rem;           /* 144px — largura de partida de cada filtro (eles dividem a linha) */
  --filtro-teto:           15rem;          /* 240px — nenhum filtro passa disso: a linha não vira um campo enorme */

  /* ---------- Painéis que flutuam sobre a tela ---------- */
  --menu-largura:          16rem;          /* 256px — mínimo do menu suspenso (rótulo + detalhe numa linha) */
  --painel-teto:           24rem;          /* 384px — teto de largura da seleção múltipla e da dica (frase curta) */
  --painel-lista-teto:     16rem;          /* 256px — lista longa rola dentro do painel (seleção múltipla) */

  /* ---------- Gráficos ----------
     Uma série: --grafico-cor (o laranja escuro, 4,35:1). Várias: a paleta
     categórica, SEMPRE nesta ordem (validada para daltonismo; a do escuro é a
     mesma sequência ajustada para o fundo escuro). Nunca em texto: rótulo e
     valor vão em --c-texto / --c-texto-2. Mais de 8 séries: agrupe em "Outros". */
  --grafico-cor: var(--c-acento-ativo);
  --serie-1: #2a78d6;   /* azul */
  --serie-2: #eb6834;   /* laranja */
  --serie-3: #1baf7a;   /* verde-água */
  --serie-4: #eda100;   /* amarelo */
  --serie-5: #e87ba4;   /* rosa */
  --serie-6: #008300;   /* verde */
  --serie-7: #4a3aa7;   /* roxo */
  --serie-8: #e34948;   /* vermelho */
}

[data-theme="dark"] {
  --foco-cor:           var(--c-acento);        /* 7,7:1 no #0a0a0b */
  --zona-borda:         var(--c-texto-3);       /* 3,5:1; a mistura do claro pesaria no escuro */
  /* O primário escuro fica como sempre foi: acento claro com texto escuro (7,7:1). */
  --btn-primario-fundo: var(--c-acento);
  --btn-primario-hover: var(--c-acento-hover);
  --btn-primario-ativo: var(--c-acento-ativo);
  --link-cor:           var(--c-acento);        /* 7,7:1 no #0a0a0b */
  --grafico-cor:        var(--c-acento);
  --serie-1: #3987e5;
  --serie-2: #d95926;
  --serie-3: #199e70;
  --serie-4: #c98500;
  --serie-5: #d55181;
  --serie-6: #008300;
  --serie-7: #9085e9;
  --serie-8: #e66767;
}

/* Celular (≤767px): moldura da tela e das janelas menores. */
@media (max-width: 767px) {
  :root {
    --moldura-tela:   var(--esp-4);   /* 16px: a 375px, +32px de largura útil */
    --modal-moldura:  var(--esp-2);   /* 8px */
    --modal-recuo:    var(--esp-4);   /* 16px */
  }
}


/* ============================================================================
 * 1c. CONTROLES NATIVOS NO TEMA DA FERRAMENTA (color-scheme)
 * ----------------------------------------------------------------------------
 * Caixa de marcar, rádio, campo de data, lista do select e barra de rolagem
 * seguem o tema DA FERRAMENTA (o data-theme), não o do sistema operacional: com
 * o <meta name="color-scheme" content="light dark">, a ferramenta clara num
 * macOS escuro mostrava caixas de marcar escuras (e a escura num sistema
 * claro, brancas). É regra de SELETOR DE TEMA — a mesma que troca os tokens —,
 * não de elemento; declara só o color-scheme. Não mexe em token nem em cor da
 * arte. Não escreva color-scheme em módulo: herda daqui.
 * ========================================================================== */
:root {
  color-scheme: light;
}
[data-theme="dark"] {
  color-scheme: dark;
}


/* ============================================================================
 * 2. ÍCONES — a regra "sem emojis"
 * ----------------------------------------------------------------------------
 * A interface NÃO usa emojis. Todo ícone é um SVG inline no estilo
 * Feather/Lucide, padronizado:
 *
 *   viewBox="0 0 24 24"  fill="none"  stroke="currentColor"
 *   stroke-width="1.75"  stroke-linecap="round"  stroke-linejoin="round"
 *
 * `stroke="currentColor"` faz o ícone herdar a cor do texto — vira theme-aware
 * sozinho (claro/escuro, estado ativo, hover). Sem CDN, sem icon-font: combina
 * com CSP estrita. Fonte dos traçados: lucide.dev (ISC) — copie o SVG e ajuste
 * stroke-width para 1.75.
 *
 *   <span class="icone">
 *     <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
 *          stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
 *       <path d="…"/>
 *     </svg>
 *   </span>
 *
 * Tamanho padrão 20px; modificadores --sm (16px) e --lg (24px). Em botão e no
 * menu lateral os próprios componentes já dimensionam o SVG (.btn-icone svg,
 * .sidebar__item-icone); .icone é o uso avulso.
 * ========================================================================== */
.icone {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
  color: currentColor;
}
.icone svg { display: block; width: 100%; height: 100%; }
.icone--sm { width: 1rem;   height: 1rem;   }
.icone--lg { width: 1.5rem; height: 1.5rem; }


/* ============================================================================
 * Caixa: todos os componentes assumem box-sizing: border-box, declarado aqui,
 * classe por classe, para não depender de um reset global — é isso que torna
 * o DS colável sem quebrar a ferramenta.
 * ========================================================================== */
.tela, .tela-barra__busca, .paginacao__info, .empty-state,
.btn, .input, .select, .textarea, .campo, .opcao-cartao, .card, .ficha,
.upload-zona, .upload-zona__previa, .modal-backdrop, .modal, .toast, .aviso,
.badge, .aba, .tabela, .tabela th, .tabela td,
.sidebar, .sidebar__marca, .sidebar__lista, .sidebar__item, .sidebar__rodape,
.sidebar__flutuante, .sidebar__recolher,
.filtros, .multi__painel, .menu-suspenso__painel, .menu-suspenso__item, .dica,
.indicador, .modal__corpo, .tecla {
  box-sizing: border-box;
}


/* ============================================================================
 * 3. ESTRUTURA DE TELA
 * ----------------------------------------------------------------------------
 * Toda tela comum (fora de um editor visual) é montada com as mesmas peças:
 *
 * <section class="tela pilha" aria-labelledby="x-titulo">      ← largura + 16px entre blocos
 *   <header class="tela-topo">
 *     <div class="tela-topo__texto">
 *       <h1 class="tela-topo__titulo" id="x-titulo">Clientes</h1>
 *       <p class="tela-topo__legenda">Frase curta opcional.</p>
 *     </div>
 *     <div class="tela-barra">                                  ← opcional: busca na linha do título
 *       <div class="campo tela-barra__busca">
 *         <input class="input" type="search" aria-label="Buscar clientes" placeholder="Buscar…">
 *       </div>
 *     </div>
 *     <div class="tela-topo__acoes"><button class="btn btn-primario">+ Novo cliente</button></div>
 *   </header>
 *   <div class="pilha pilha--interna">                          ← 12px: busca → lista → paginação
 *     <div class="tabela-area">…tabela…</div>
 *     <nav class="paginacao" aria-label="Paginação">…</nav>
 *   </div>
 * </section>
 *
 * A área de conteúdo que rola (layout da FERRAMENTA) usa padding
 * var(--moldura-tela): 24px, 16px no celular.
 *
 * QUEBRA PELA LARGURA DA ÁREA: .tela-topo e .paginacao (e, adiante, .aviso e
 * .tabela-area) são containers (container-type: inline-size) e quebram por
 * @container, medindo a própria largura — não a da janela. Com o menu aberto
 * numa janela média, o topo já é estreito e se arruma; com o menu recolhido,
 * volta. Consequência: nunca ponha um desses dentro de um contêiner que
 * encolhe até o conteúdo (flex sem crescer, inline-block, célula de grade
 * "auto"): a contenção de largura faz ele valer ZERO. Eles são sempre bloco de
 * largura cheia. O limite do @container não lê variável: o número fica
 * escrito na regra, com a conta ao lado.
 * ========================================================================== */

/* ---------- .tela — largura da tela, sempre alinhada à esquerda ----------
 * .tela            sem teto (listas largas)
 * .tela--media     960px  (formulários de configuração)
 * .tela--estreita  720px  (uma coluna de cards)
 * Nenhuma tela é centralizada: o título começa sempre logo depois da moldura.
 * Nunca ponha teto numa lista larga que hoje não tem (ela ficaria mais
 * estreita com o menu recolhido).
 */
.tela {
  width: 100%;
  min-width: 0;
  margin-inline: 0;
}
.tela--media    { max-width: var(--tela-media); }
.tela--estreita { max-width: var(--tela-estreita); }

/* ---------- .tela-topo — cabeçalho de tela único ----------
 * Título 24px/600 com a altura do controle (32px: alinha com os botões ao
 * lado), legenda de 14px em --c-texto-2 a 4px do título, ações à direita.
 * Sem margem própria: os 16px até o conteúdo vêm da .pilha da tela.
 *
 * Quebra de linha: o bloco do texto parte da largura do TÍTULO e cresce; a
 * legenda não empurra as ações para baixo (ela quebra dentro do bloco, que
 * reserva 15rem de leitura para ela). Se o título e as ações não cabem lado a
 * lado, as ações descem; sozinho na linha de baixo, o grupo encolhe até a
 * largura da tela e os botões quebram entre si (nenhum botão sai da tela).
 * O .tela-topo é container ("tela-topo"): a .tela-barra desce pela largura
 * dele (ver .tela-barra).
 *
 * Modificadores:
 *   .tela-topo--saudacao     — painel de indicadores: saudação em 30px (os
 *                              números logo abaixo também têm 30px; em 24px
 *                              eles "venceriam" o título).
 *   .tela-topo__texto--linha — botão de voltar na mesma linha do título:
 *     <div class="tela-topo__texto tela-topo__texto--linha">
 *       <button class="btn btn-discreto btn-pequeno" aria-label="Voltar para Clientes">← Clientes</button>
 *       <h1 class="tela-topo__titulo">Categorias</h1>
 *     </div>
 *   (a seta fica: sem ela o botão discreto parece trilha, não botão)
 */
.tela-topo {
  container: tela-topo / inline-size;   /* a .tela-barra desce pela largura do topo, não da janela */
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--esp-3) var(--esp-4);
}
.tela-topo__texto {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-width: 0;
}
.tela-topo__texto--linha {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--esp-2);
}
.tela-topo__titulo {
  display: flex;
  align-items: center;
  min-height: var(--ctrl-altura);
  margin: 0;
  font-size: var(--fs-xl);
  font-weight: 600;
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-tight);
  color: var(--c-texto);
}
.tela-topo--saudacao .tela-topo__titulo {
  font-size: var(--fs-2xl);
}
.tela-topo__legenda {
  /* A largura natural da frase (até 80ch) não conta na quebra de linha do
     topo: conta 15rem, a leitura mínima (sem isso, uma legenda longa jogava as
     ações para baixo dela, e uma curta deixava a frase espremida ao lado dos
     botões no celular). Na tela, a frase ocupa a largura do bloco. */
  contain: inline-size;
  contain-intrinsic-inline-size: 15rem;
  margin: var(--esp-1) 0 0;
  max-width: 80ch;          /* linha de leitura confortável: a frase não atravessa a tela larga */
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  color: var(--c-texto-2);
}
.tela-topo__acoes {
  display: flex;
  flex: 0 1 auto;           /* sozinho na linha, encolhe até a largura da tela e os botões quebram */
  flex-wrap: wrap;
  align-items: center;
  gap: var(--esp-2);
}

/* ---------- .tela-barra — busca na linha do título ----------
 * Só em telas com UMA ação no topo: [Título] … [Buscar…] [+ Novo].
 * Com filtros além da busca, ela fica numa linha própria (cinco controles
 * numa linha quebram de forma imprevisível, e o botão principal poderia
 * descer sozinho).
 * A busca encolhe até 10rem; quando o TOPO (não a janela) tem até 36rem, a
 * barra desce para a 2ª linha e a busca ocupa a largura toda, e o título e o
 * botão ficam juntos na 1ª. O botão nunca desce sozinho.
 * 36rem = texto de até 15rem (título, ou a leitura mínima da legenda) +
 * busca de 10rem + botão de até 9rem + 2 vãos de 1rem. Título ou botão maior
 * que isso numa tela com barra pede revisão do limite.
 */
.tela-barra {
  display: flex;
  flex: 1 1 10rem;          /* conta 10rem (a busca mínima) na quebra do topo */
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--esp-3);
  min-width: 0;
}
.tela-barra > .campo {
  margin-bottom: 0;
}
.tela-barra__busca {
  flex: 1 1 15rem;          /* 240px de base; encolhe até a largura da barra (mín. 10rem) */
  max-width: 22.5rem;       /* 360px */
}
/* Container query não lê variável: 36rem é o valor explicado acima. */
@container tela-topo (max-width: 36rem) {
  .tela-topo > .tela-barra {
    order: 1;
    flex-basis: 100%;
  }
  .tela-barra__busca {
    max-width: none;
  }
}

/* ---------- .pilha — o espaço entre blocos vem SÓ daqui ----------
 * Escala única (nenhum número solto nas telas):
 *   .pilha              16px — entre blocos da tela e entre cards (piso: é o
 *                              vão que separa um card do outro)
 *   .pilha--secoes      24px — entre seções com título
 *   .pilha--interna     12px — dentro do card; busca → lista → paginação
 *   .pilha--junta        8px — título de seção → conteúdo; barra de lote →
 *                              grade; [SE EDITOR] caixas do painel de ferramenta
 *   .pilha--painel      32px — EXCEÇÃO: painel de indicadores (dashboard) com
 *                              seções sem título visível (o espaço é o que
 *                              separa). Não é o "painel de ferramenta".
 * Os modificadores só trocam o vão: escreva SEMPRE com a base
 * ("pilha pilha--secoes"). Filho DIRETO não tem margem vertical e, com
 * [hidden], some de verdade. As duas regras têm peso (0,2,0): vencem a regra
 * de módulo de UMA classe (0,1,0), mas o CSS do módulo carrega depois deste
 * arquivo, então um seletor de módulo com duas classes que ponha margem ou
 * display num filho da pilha VENCE. No módulo, não faça isso.
 */
.pilha {
  --pilha-gap: var(--esp-4);
  display: flex;
  flex-direction: column;
  gap: var(--pilha-gap);
}
.pilha--secoes  { --pilha-gap: var(--esp-6); }
.pilha--painel  { --pilha-gap: var(--esp-8); }
.pilha--interna { --pilha-gap: var(--esp-3); }
.pilha--junta   { --pilha-gap: var(--esp-2); }
.pilha.pilha > * {
  margin-block: 0;
}
.pilha > [hidden] {
  display: none;
}

/* ---------- .paginacao — paginação única, com o total ----------
 * <nav class="paginacao" aria-label="Paginação">
 *   <button class="btn btn-secundario btn-pequeno" type="button">‹ Anterior</button>
 *   <span class="paginacao__info">Página 2 de 3 · 37 clientes</span>
 *   <button class="btn btn-secundario btn-pequeno" type="button">Próxima ›</button>
 * </nav>
 * Sem margem própria: os 12px até a lista vêm da .pilha--interna que agrupa
 * busca + lista + paginação. Vazia (uma página só), some.
 * Estreita: com até 26rem de largura (celular), o total vai para uma linha
 * própria em cima e os dois botões ficam juntos embaixo — sem isso o total
 * não cabia entre eles e o "Próxima" caía sozinho para a 2ª linha.
 */
.paginacao {
  container: paginacao / inline-size;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--esp-3);
}
.paginacao:empty {
  display: none;
}
.paginacao__info {
  min-width: 7.5rem;        /* 120px: os botões não "andam" quando o número muda */
  text-align: center;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--c-texto-2);
  font-variant-numeric: tabular-nums;
}
/* 26rem ≈ 2 botões de 79px + total de até 230px ("Página 10 de 12 · 1234
   registros") + 2 vãos de 12px. O limite de container query não lê variável. */
@container paginacao (max-width: 26rem) {
  .paginacao__info {
    order: -1;
    flex-basis: 100%;
  }
}

/* ---------- .lista-corte — aviso de lista cortada ----------
 * Lista que mostra só os primeiros N (sem paginação) TEM de avisar, logo
 * acima dela: "Mostrando 50 de 312 clientes — use a busca para achar os
 * demais". 14px em --c-texto-2.
 * O <p> fica SEMPRE no markup com role="status" (precisa existir antes da
 * frase para ela ser anunciada) e o JS só troca o texto. Vazio (a lista coube
 * inteira), sai do fluxo da pilha sem sair da árvore de acessibilidade —
 * [hidden] tiraria dela. Sem margem própria (a .pilha dá o espaço).
 *
 * <p id="x-corte" class="lista-corte" role="status"></p>
 */
.lista-corte {
  margin: 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  color: var(--c-texto-2);
}
.lista-corte:empty {
  position: absolute;
}

/* ---------- .empty-state — estado vazio ----------
 * Lista vazia, "Carregando…" e erro de carga.
 * <p class="empty-state">Nenhum cliente por aqui ainda.</p>
 * Em tabela: <tr><td colspan="5"><div class="empty-state">Carregando…</div></td></tr>
 * 32/16px de respiro (24/16px em tabela e janela), texto em --c-texto-2
 * (legível: 7,7:1) e, dentro de grade, ocupa a linha inteira (sem efeito
 * fora de grid).
 */
.empty-state {
  grid-column: 1 / -1;
  margin: 0;
  padding: var(--esp-8) var(--esp-4);
  text-align: center;
  color: var(--c-texto-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
}
.tabela .empty-state,
.modal .empty-state {
  padding: var(--esp-6) var(--esp-4);
}


/* ---------- .secao-titulo — título de uma seção solta da tela ----------
 * Para um grupo SEM card (ex.: os indicadores de um painel), com o conteúdo
 * logo abaixo pela pilha--junta (8px):
 * <section class="pilha pilha--junta">
 *   <h2 class="secao-titulo">Resumo do mês</h2>
 *   <div class="indicadores">…</div>
 * </section>
 * 18px/600, o tamanho do .card__titulo — abaixo dos 24px do título da tela.
 */
.secao-titulo {
  margin: 0;
  font-size: var(--fs-md);
  font-weight: 600;
  line-height: var(--lh-tight);
  color: var(--c-texto);
}

/* ---------- .resultado — o que uma busca devolve, com a linha de status ----------
 * Tela de consulta que só busca quando a pessoa pede (botão "Buscar" da barra
 * de filtros) — consultar uma API lenta sem querer custa tempo e chamadas:
 * <form class="filtros">…</form>
 * <p class="resultado__status" role="status">Atualizado às 14:32 · consulta em 0,4 s</p>
 * <div class="resultado pilha">…blocos…</div>
 *   - A tela abre SEM consultar: no lugar dos blocos, um .empty-state
 *     ("Escolha os filtros e clique em Buscar"). Nem filtros vindos do
 *     endereço (favorito, voltar) disparam a busca.
 *   - A linha de status diz de QUANDO é o que está na tela (12px,
 *     --c-texto-2). Enquanto busca, conta o tempo ("Buscando os dados… 12 s").
 *     Vazia, sai do fluxo sem sair da árvore de acessibilidade (como a
 *     .lista-corte: o role="status" precisa existir antes da frase).
 *   - .resultado__status--alterado: mexeram num filtro depois da busca e o que
 *     está na tela é de outros filtros ("Os filtros mudaram — clique em Buscar
 *     para atualizar"). Mexer em filtro NUNCA consulta sozinho.
 *   - .resultado--carregando: a nova busca está a caminho. O resultado
 *     anterior FICA, apagado e sem clique — a tela não pula nem fica vazia.
 */
.resultado__status {
  margin: 0;
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
  color: var(--c-texto-2);
}
.resultado__status:empty {
  position: absolute;
}
.resultado__status--alterado {
  font-weight: 600;
  color: color-mix(in srgb, var(--c-aviso) 65%, var(--c-texto));   /* a mesma mistura do .badge-aviso */
}
.resultado {
  transition: opacity var(--t-padrao);
}
.resultado--carregando {
  opacity: 0.5;                     /* apagado, mas legível: "isto é o que havia antes" */
  pointer-events: none;
}

/* ============================================================================
 * 4. COMPONENTES
 * ========================================================================== */

/* ---------- Botões ----------
 * <button type="button" class="btn btn-primario">Salvar</button>
 * <button class="btn btn-secundario">Cancelar</button>
 * <button class="btn btn-discreto">Voltar</button>
 * <button class="btn btn-perigo">Excluir</button>
 * <button class="btn btn-primario btn-grande btn-bloco">Entrar</button>
 * <button class="btn btn-secundario btn-pequeno">Filtro</button>
 * <button class="btn btn-discreto btn-icone" aria-label="…">[svg]</button>
 * <a class="btn btn-primario" href="…">Abrir a fatura</a>   ← link com cara de botão
 *
 * Botão "⋮" de linha/card (menu de ações) — o único formato:
 * <button type="button" class="btn btn-discreto btn-pequeno btn-icone"
 *         aria-label="Ações de <nome do item>" aria-haspopup="menu">
 *   <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75"
 *        stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 *     <circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/>
 *   </svg>
 * </button>
 * → 26×26px; 32×32px em tela de toque (pointer: coarse). Dentro de um flex
 *   que estica os botões, dar flex: none ao "⋮".
 *
 * Hierarquia: só UM primário por tela. Alturas da régua (32 / 26 / 40px), fonte
 * 16px (o pequeno, 14px) — nunca diminuir a letra para ganhar espaço. Primário
 * em laranja ESCURO no tema claro (texto branco 4,35:1). Foco de teclado =
 * contorno de 2px na --foco-cor com 2px de folga (não ocupa espaço).
 * Botão com [hidden]: o display do .btn vence o atributo — ver .pilha e
 * .upload-zona, que já corrigem; em outro contêiner, corrija no escopo dele.
 */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--esp-2);
  padding: var(--esp-1) var(--esp-3);
  height: var(--ctrl-altura);   /* 32px */
  font-family: inherit;
  font-size: var(--fs-base);
  font-weight: 500;
  line-height: 1.2;
  color: var(--c-texto);
  text-decoration: none;
  background: none;
  border: 1px solid transparent;
  border-radius: var(--raio-md);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  transition:
    background var(--t-rapida),
    border-color var(--t-rapida),
    color var(--t-rapida),
    box-shadow var(--t-rapida);
}
.btn:focus-visible {
  outline: var(--foco-largura) solid var(--foco-cor);
  outline-offset: var(--foco-folga);
  box-shadow: none;
}
.btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Primário: laranja escuro no claro; no escuro, acento claro + texto escuro (1b). */
.btn-primario {
  background: var(--btn-primario-fundo);
  color: var(--c-acento-texto);
}
.btn-primario:hover:not(:disabled)  { background: var(--btn-primario-hover); }
.btn-primario:active:not(:disabled) { background: var(--btn-primario-ativo); }

.btn-secundario {
  background: var(--c-bg);
  color: var(--c-texto);
  border-color: var(--c-borda-forte);
}
.btn-secundario:hover:not(:disabled) { background: var(--c-bg-hover); }

.btn-discreto {
  background: transparent;
  color: var(--c-texto-2);
}
.btn-discreto:hover:not(:disabled) {
  background: var(--c-bg-hover);
  color: var(--c-texto);
}

.btn-perigo {
  background: var(--c-erro);
  color: #ffffff;
}
.btn-perigo:hover:not(:disabled) {
  background: color-mix(in srgb, var(--c-erro) 88%, black);
}

/* Link com cara de botão (<a class="btn …">): o botão nunca herda o sublinhado
   do hover do link. Com a base recomendada (a:hover só sublinha, cabeçalho
   deste arquivo) basta a 1ª regra — é o que a ferramenta-mãe mantém. As outras
   três (peso 0,2,1) protegem a ferramenta JÁ EXISTENTE cujo a:hover/a:active
   troca a COR (peso 0,1,1 vence o .btn-*, 0,1,0, e pintaria o texto da cor do
   fundo); com a base recomendada, elas não mudam nada. */
a.btn:is(:hover, :active)            { text-decoration: none; }
a.btn-primario:is(:hover, :active)   { color: var(--c-acento-texto); }
a.btn-secundario:is(:hover, :active),
a.btn-discreto:is(:hover, :active)   { color: var(--c-texto); }
a.btn-perigo:is(:hover, :active)     { color: #ffffff; }

/* Tamanhos (régua da seção 1b) */
.btn-pequeno {
  height: var(--ctrl-altura-p);   /* 26px */
  padding: var(--esp-1) var(--esp-2);
  font-size: var(--fs-sm);
  border-radius: var(--raio-sm);
}
.btn-grande {
  height: var(--ctrl-altura-g);   /* 40px, fonte 16px */
  padding: var(--esp-2) var(--esp-4);
  font-size: var(--fs-base);
}
.btn-icone {
  padding: var(--esp-1);
  aspect-ratio: 1;                /* quadrado */
  width: var(--ctrl-altura);
}
.btn-icone svg { width: 16px; height: 16px; }
.btn-pequeno.btn-icone { width: var(--ctrl-altura-p); }
.btn-grande.btn-icone  { width: var(--ctrl-altura-g); }
/* Toque: o botão de ícone pequeno (o "⋮") sobe para 32px — é a única porta
   para as ações da linha e fica ao lado de outros alvos clicáveis. */
@media (pointer: coarse) {
  .btn-pequeno.btn-icone {
    width: var(--ctrl-altura-toque);
    height: var(--ctrl-altura-toque);
  }
}
.btn-bloco { display: flex; width: 100%; }

/* ---------- .link — link de texto ----------
 * <a class="link" href="…">Esqueci minha senha</a>
 * <p>Ao continuar, você aceita os <a class="link link--sublinhado" href="…">termos de uso</a>.</p>
 * <button type="button" class="link">Reenviar o código</button>   ← ação com cara de link
 *
 * Cor --link-cor: laranja escuro no claro (5,8:1 no branco) e o acento no
 * escuro (7,7:1) — nunca o --c-acento no claro (2,88:1). Sem sublinhado em
 * repouso; no hover só o sublinhado aparece (a cor não muda).
 * .link--sublinhado (sublinhado sempre) para link DENTRO de uma frase: ali a
 * cor sozinha não basta para achá-lo (WCAG 1.4.1) — contra o --c-texto dá
 * 3,0:1 no claro e 2,5:1 no escuro, e ao lado do --c-texto-2 some.
 * Foco de teclado = o contorno de sempre. O DS não estiliza <a> nu: numa
 * ferramenta que estiliza, ver o passo 2 do cabeçalho.
 */
.link {
  padding: 0;
  font: inherit;                    /* igual ao texto em volta (vale no <button>) */
  color: var(--link-cor);
  text-decoration: none;
  background: none;
  border: 0;
  cursor: pointer;
}
.link:hover,
.link--sublinhado {
  text-decoration: underline;
}
.link:focus-visible {
  outline: var(--foco-largura) solid var(--foco-cor);
  outline-offset: var(--foco-folga);
  border-radius: var(--raio-sm);
}

/* ---------- Campos: input / select / textarea ----------
 * <input class="input" type="email">
 * <select class="select"><option>…</option></select>
 * <textarea class="textarea" rows="4"></textarea>
 *
 * Estado inválido: aria-invalid="true" no campo E a mensagem escrita
 * (.campo__erro) — a cor sozinha não basta.
 *
 * Estados, todos sem mudar o tamanho da caixa (a BORDA é sempre 1px; o
 * reforço vem de sombra):
 *   repouso  borda --campo-borda (= .btn-secundario)
 *   hover    borda --campo-borda-hover (mais escura)
 *   foco     borda --campo-borda-foco + 1px de sombra = 2px de laranja escuro
 *   erro     borda --c-erro + 1px de sombra = 2px de vermelho (+ halo no foco)
 * Altura --ctrl-altura (32px) com fonte de 16px (abaixo disso o iPhone dá zoom).
 * Alternativa anotada, se alguém tiver dificuldade de achar os campos: borda
 * mais escura, #898992 (3,15:1).
 */
.input, .select, .textarea {
  display: block;
  width: 100%;
  padding: var(--esp-1) var(--esp-3);
  height: var(--ctrl-altura);     /* 32px, igual ao .btn */
  margin: 0;
  font-family: inherit;
  font-size: var(--fs-base);
  color: var(--c-texto);
  background: var(--c-bg-muted);
  border: 1px solid var(--campo-borda);
  border-radius: var(--raio-md);
  transition: border-color var(--t-rapida), box-shadow var(--t-rapida);
}
.input::placeholder,
.textarea::placeholder {
  color: var(--campo-placeholder);
  opacity: 1;
}
.input:hover:not(:disabled):not(:focus):not([aria-invalid="true"]),
.select:hover:not(:disabled):not(:focus):not([aria-invalid="true"]),
.textarea:hover:not(:disabled):not(:focus):not([aria-invalid="true"]) {
  border-color: var(--campo-borda-hover);
}
.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--campo-borda-foco);
  box-shadow: 0 0 0 1px var(--campo-borda-foco);
}
.input:disabled,
.select:disabled,
.textarea:disabled { opacity: 0.55; cursor: not-allowed; }
.input[aria-invalid="true"],
.select[aria-invalid="true"],
.textarea[aria-invalid="true"] {
  border-color: var(--c-erro);
  box-shadow: 0 0 0 1px var(--c-erro);
}
.input[aria-invalid="true"]:focus,
.select[aria-invalid="true"]:focus,
.textarea[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 1px var(--c-erro),
              0 0 0 4px color-mix(in srgb, var(--c-erro) 25%, transparent);
}

.textarea {
  min-height: 6rem;
  height: auto;
  resize: vertical;
  line-height: var(--lh-normal);
  padding: var(--esp-3);
}

/* Seta do select desenhada como SVG data-URI (sem imagem externa). */
.select {
  appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M3 4.5L6 7.5L9 4.5' stroke='%2352525b' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right var(--esp-3) center;
  background-size: 12px;
  padding-right: var(--esp-8);
  cursor: pointer;
}
[data-theme="dark"] .select {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M3 4.5L6 7.5L9 4.5' stroke='%23a1a1aa' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>");
}

/* ---------- Rótulo e campo (agrupador) ----------
 * <div class="campo">
 *   <label class="label" for="email">E-mail</label>
 *   <input class="input" id="email" type="email">
 *   <p class="campo__erro" role="alert"></p>          [opcional]
 *   <p class="campo__ajuda">Dica de preenchimento.</p> [opcional]
 * </div>
 *
 *   .label        14px/500, entrelinha justa (1,25); 4px até a caixa.
 *   .campo        12px abaixo (zerado dentro de .campos, .tela-barra e .pilha).
 *   .campo__erro  14px em --c-erro. Reserva 1 linha vazia para o botão não
 *                 pular (telas de acesso: "Entrar" não pode andar quando a
 *                 senha erra). DENTRO de janela (.modal) a reserva some quando
 *                 está vazio — só lá. Sob um campo, fica a 4px dele; o erro
 *                 GERAL do formulário, logo depois do .campos, fica a 12px
 *                 do grupo (ver .campos).
 *   .campo__ajuda dica de preenchimento em 12px (entrelinha 1,4), --c-texto-2.
 *   .campo__ajuda--msg  MENSAGEM DE RESULTADO que usa o lugar da ajuda e
 *                 precisa continuar em 14px (ex.: "Enviamos o link para o seu
 *                 e-mail"). Dica comum NÃO usa.
 *     <p class="campo__ajuda campo__ajuda--msg" role="status" hidden></p>
 */
.label {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: var(--lh-tight);
  color: var(--c-texto);
  margin-bottom: var(--esp-1);
}
.campo {
  display: flex;
  flex-direction: column;
  margin-bottom: var(--esp-3);
}
.campo__erro {
  margin: var(--esp-1) 0 0;
  min-height: 1.2em;
  color: var(--c-erro);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
}
.modal .campo__erro:empty {
  min-height: 0;
  margin-top: 0;
}
/* Erro do formulário, que fica FORA do .campos: 12px do grupo (os 4px do
   .campo__erro são do erro sob um campo; a 4px da zona de envio ou dos botões,
   a frase parecia falar deles). Fora de janela ele já reserva a linha vazia,
   então o espaço não pula quando o erro aparece. Peso (0,1,0), o do
   .campo__erro (vence por vir depois): vazio na janela, a regra de cima zera;
   filho de .pilha, o vão é o da pilha. */
:where(.campos) + .campo__erro {
  margin-top: var(--esp-3);
}
.campo__ajuda {
  margin: var(--esp-1) 0 0;
  color: var(--c-texto-2);
  font-size: var(--fs-xs);
  line-height: 1.4;                 /* 16,8px por linha: ajuda de 2–3 linhas continua arejada */
}
.campo__ajuda--msg {
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
}

/* ---------- .campos — grupo de campos ----------
 * 12px entre os campos (o gap substitui a margem do .campo, que é zerada) e
 * 16px até as ações do formulário de página. Em janela, o .modal__acoes vem
 * DEPOIS do .campos e ganha os 20px da janela.
 *
 * <div class="campos">
 *   <div class="campo">…</div>
 *   <div class="campos-linha">                     ← campos curtos lado a lado
 *     <div class="campo">…Telefone…</div>
 *     <div class="campo">…WhatsApp…</div>
 *   </div>
 *   <label class="opcao"><input class="checkbox" type="checkbox"><span>Ativo</span></label>
 *   <div class="campos__acoes"><button class="btn btn-primario">Salvar</button></div>
 * </div>
 * <p class="campo__erro" role="alert"></p>        ← erro geral do formulário
 *
 * Um .campo__erro de formulário fica FORA do .campos (vazio, ele viraria um
 * item do flex e somaria um vão de 12px); logo depois do grupo, ele fica a
 * 12px dele (ver .campo__erro). Em janela: .campos → erro → .modal__acoes.
 * Caixa de marcar solta no grupo (.campos > .opcao, ex.: "Ativo") não estica
 * na largura e mantém o alvo de 24px.
 */
.campos {
  display: flex;
  flex-direction: column;
  gap: var(--esp-3);
}
.campos > .campo,
.campos-linha > .campo {
  margin-bottom: 0;
}
/* Sem isto a opção esticava na largura do grupo e um clique no vazio à direita
   marcava/desmarcava sem a pessoa perceber. */
.campos > .opcao {
  align-self: flex-start;
  min-height: 1.5rem;               /* 24px, como no .opcoes */
}
.campos__acoes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--esp-2);
  margin-top: var(--esp-1);         /* 12 do gap + 4 = 16px do último campo */
}

/* ---------- .campos-linha — campos curtos lado a lado ----------
 * Colunas automáticas de no mínimo 11rem (176px): 2 ou 3 por linha conforme a
 * largura; uma coluna só quando não cabe e sempre no celular. 12px entre
 * linhas, 16px entre colunas.
 *   .campos-linha--curtos  mínimo 7,5rem, SÓ para valores curtos e de tamanho
 *                          previsível (CEP, UF, números) — nunca @, e-mail,
 *                          endereço ou URL, que rolariam dentro da caixa.
 */
.campos-linha {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: var(--esp-3) var(--esp-4);
}
.campos-linha--curtos {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 7.5rem), 1fr));
}
@media (max-width: 767px) {
  .campos-linha,
  .campos-linha--curtos {
    grid-template-columns: 1fr;
  }
}

/* ---------- Opções: checkbox / radio ----------
 * <label class="opcao"><input class="checkbox" type="checkbox"><span>Texto</span></label>
 * <label class="opcao"><input class="radio" type="radio" name="g"><span>Texto</span></label>
 * Inputs nativos estilizados via accent-color — sem hack de sobreposição,
 * mantém acessibilidade e comportamento do navegador.
 */
.opcao {
  display: inline-flex;
  align-items: center;
  gap: var(--esp-2);
  cursor: pointer;
  font-size: var(--fs-base);
  color: var(--c-texto);
  user-select: none;
  line-height: 1.2;
}
.checkbox, .radio {
  accent-color: var(--c-acento);
  width: 1rem;
  height: 1rem;
  margin: 0;
  cursor: pointer;
}
.checkbox:focus-visible,
.radio:focus-visible {
  outline: var(--foco-largura) solid var(--foco-cor);
  outline-offset: var(--foco-folga);
}
.checkbox:disabled + span,
.radio:disabled + span,
.opcao:has(.checkbox:disabled),
.opcao:has(.radio:disabled) { opacity: 0.55; cursor: not-allowed; }
/* As partes nativas (caixa e bolinha vazias, ícone de calendário, lista do
   select, barra de rolagem) acompanham o tema pelo color-scheme da raiz
   (seção 1c): nenhuma regra aqui. */

/* ---------- .opcoes — caixas de marcar em colunas ----------
 * <fieldset class="opcoes-grupo">
 *   <legend class="label">Pode acessar</legend>
 *   <div class="opcoes">
 *     <label class="opcao"><input class="checkbox" type="checkbox"><span>Relatórios</span></label>
 *     <label class="opcao"><input class="checkbox" type="checkbox"><span>Cobrança</span></label>
 *   </div>
 * </fieldset>
 * Colunas automáticas de no mínimo 8rem (14rem com .opcoes--largas, para
 * rótulos longos); 4px entre linhas e 16px entre colunas. Cada opção tem
 * altura mínima de 24px (alvo mínimo, WCAG 2.5.8): a grade tira a folga que
 * antes garantia o alvo.
 */
.opcoes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 8rem), 1fr));
  gap: var(--esp-1) var(--esp-4);
}
.opcoes--largas {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 14rem), 1fr));
}
.opcoes > .opcao {
  min-height: 1.5rem;               /* 24px */
}
.opcoes-grupo {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}
.opcoes-grupo > legend {
  padding: 0;
}

/* ---------- .opcao-cartao — opção em cartão ----------
 * Rádio (ou caixa de marcar) dentro de um cartão de 42px de altura mínima.
 * O ESCOLHIDO leva a marca de seleção: contorno de 2px em --selecao-cor
 * (1px de borda + 1px de sombra, sem mudar o tamanho) — não só a bolinha de
 * 16px. A marca não some no hover. Foco de teclado no cartão.
 * .opcao-cartao--atual marca o item vigente sem rádio (ex.: "Seu plano").
 * O rádio tem de ser FILHO DIRETO do label.
 *
 * <div class="opcoes-cartao" role="radiogroup" aria-labelledby="x-rotulo">
 *   <label class="opcao-cartao">
 *     <input type="radio" class="radio" name="plano" value="basico" checked>
 *     <span class="opcao-cartao__corpo">
 *       <span class="opcao-cartao__topo">
 *         <span class="opcao-cartao__nome">Básico</span>
 *         <span class="opcao-cartao__preco">R$ 49,90 <span class="opcao-cartao__periodo">por mês</span></span>
 *       </span>
 *       <span class="opcao-cartao__desc">Até 3 usuários e 10 GB</span>
 *     </span>
 *   </label>
 * </div>
 * Só o nome: <label class="opcao-cartao"><input type="radio" class="radio" …>
 *              <span class="opcao-cartao__corpo"><span class="opcao-cartao__nome">Quadrado</span></span></label>
 */
.opcoes-cartao {
  display: flex;
  flex-direction: column;
  gap: var(--esp-2);
}
.opcao-cartao {
  display: flex;
  align-items: stretch;
  gap: var(--esp-2);
  min-height: 2.625rem;             /* 42px = 8 + 24 (linha) + 8 + 2 de borda */
  padding: var(--esp-2) var(--esp-3);
  background: var(--c-bg);
  color: var(--c-texto);
  border: 1px solid var(--campo-borda);
  border-radius: var(--raio-md);
  line-height: var(--lh-normal);
  transition: border-color var(--t-rapida), box-shadow var(--t-rapida);
}
label.opcao-cartao {
  cursor: pointer;
}
label.opcao-cartao:hover:not(:has(> :checked)):not(.opcao-cartao--atual) {
  border-color: var(--campo-borda-hover);
}
.opcao-cartao > .radio,
.opcao-cartao > .checkbox {
  flex: none;
  align-self: flex-start;
  margin-top: var(--esp-1);         /* 16px centrados na 1ª linha de 24px */
}
.opcao-cartao:has(> :checked),
.opcao-cartao--atual {
  border-color: var(--selecao-cor);
  box-shadow: inset 0 0 0 1px var(--selecao-cor);
}
.opcao-cartao:has(> :focus-visible) {
  outline: var(--foco-largura) solid var(--foco-cor);
  outline-offset: var(--foco-folga);
}
.opcao-cartao > :focus-visible {
  outline: none;                    /* o contorno vai no cartão, não na bolinha */
}
.opcao-cartao__corpo {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--esp-1);
}
.opcao-cartao__topo {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0 var(--esp-2);
}
.opcao-cartao__nome,
.opcao-cartao__preco {
  font-weight: 600;
  color: var(--c-texto);
}
.opcao-cartao__preco {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.opcao-cartao__periodo {
  font-size: var(--fs-sm);
  font-weight: 400;
  color: var(--c-texto-2);
}
.opcao-cartao__desc {
  font-size: var(--fs-sm);
  color: var(--c-texto-2);
}

/* ---------- .filtros — barra de filtros compacta ----------
 * A faixa de filtros de uma tela de consulta (relatório, lista grande): os
 * filtros dividem UMA linha e o botão de buscar fica no fim dela.
 *
 * <form class="filtros" aria-label="Filtros" novalidate>
 *   <div class="campo">
 *     <label class="label" id="f-lojas-r" for="f-lojas">Lojas</label>
 *     <div class="multi">…seleção múltipla…</div>
 *     <p class="campo__erro" id="f-lojas-erro" role="alert"></p>
 *   </div>
 *   <div class="campo">
 *     <label class="label" for="f-dep">Departamento</label>
 *     <select class="select" id="f-dep">…</select>
 *     <p class="campo__erro" role="alert"></p>
 *   </div>
 *   <div class="campo campo--livre">…período: atalho + duas datas…</div>
 *   <div class="filtros__acoes"><button type="submit" class="btn btn-primario">Buscar</button></div>
 *   <div class="campo filtros__linha">…"Comparar com", numa linha própria…</div>
 * </form>
 *
 * COMPACTA (decisão do dono, 22/10/2026 — padrão do Relatórios): no
 * COMPUTADOR (≥768px com ponteiro fino), os controles da barra têm 26px
 * (--ctrl-altura-p), texto de 14px e rótulo de 12px, e o respiro cai para
 * 8/12px. É a ÚNICA exceção à fonte de 16px nos controles: com mouse não há o
 * zoom do iPhone. No toque (celular, tablet) a barra volta a 32px/16px.
 * Botões e campos da barra mudam JUNTOS (lado a lado, mesma altura).
 *
 * LARGURA: cada filtro parte de --filtro-base (9rem) e cresce até
 * --filtro-teto (15rem); quebram de linha só quando não cabem. Campo composto
 * (período: atalho + duas datas) leva .campo--livre e fica na largura natural.
 * .filtros__linha ocupa uma linha inteira, ABAIXO dos filtros e do botão,
 * separada por um filete (ex.: "Comparar com"). No celular, um filtro por
 * linha e o botão na largura toda.
 *
 * ERRO: o .campo__erro vazio não ocupa linha (a barra não fica com buracos);
 * com erro, aparece embaixo do campo sem empurrar os vizinhos. O botão se
 * alinha com os CONTROLES, não com os rótulos. Ajuda (.campo__ajuda) de UMA
 * linha curta ("Ignora departamento, seções e status."): ajuda longa estica
 * a barra inteira. Um primário só: o "Buscar".
 * A busca só roda no botão (ver .resultado). Sem margem própria (a .pilha da
 * tela dá o espaço).
 */
.filtros {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;          /* um erro embaixo de um campo não empurra os vizinhos */
  gap: var(--esp-3) var(--esp-4);
  margin: 0;
  padding: var(--esp-3) var(--esp-4);
  background: var(--c-bg-elev);
  border: 1px solid var(--c-borda);
  border-radius: var(--raio-lg);
}
.filtros > .campo {
  margin: 0;
  min-width: 0;
}
.filtros .campo__erro:empty {
  display: none;                    /* só ocupa linha quando há erro */
}
/* O botão e a caixa de marcar ficam na linha dos CONTROLES: altura do .label + a margem dele. */
.filtros__acoes,
.filtros > .opcao {
  margin-top: calc(var(--fs-sm) * var(--lh-tight) + var(--esp-1));
}
.filtros__acoes {
  order: 1;
  display: flex;
  gap: var(--esp-2);
}
.filtros > .opcao {
  min-height: var(--ctrl-altura);
}
.filtros__linha {
  order: 2;
  flex: 1 1 100%;
  padding-top: var(--esp-3);
  border-top: 1px solid var(--c-borda);
}
@media (min-width: 768px) {
  .filtros > .campo:not(.campo--livre, .filtros__linha) {
    flex: 1 1 var(--filtro-base);
    max-width: var(--filtro-teto);
  }
  .filtros > .campo:not(.campo--livre, .filtros__linha) :is(.input, .select, .multi) {
    width: 100%;
  }
}
/* Compacta: só com ponteiro fino (mouse ou trackpad); no toque fica a régua de 32px/16px. */
@media (min-width: 768px) and (pointer: fine) {
  .filtros {
    gap: var(--esp-2) var(--esp-3);
    padding: var(--esp-2) var(--esp-3);
  }
  .filtros .label {
    font-size: var(--rotulo-fonte-compacta);
  }
  .filtros :is(.input, .select) {
    height: var(--ctrl-altura-p);
    padding: 0 var(--esp-2);
    font-size: var(--ctrl-fonte-compacta);
    border-radius: var(--raio-sm);
  }
  .filtros .select {
    padding-right: var(--esp-6);
    background-position: right var(--esp-2) center;
  }
  .filtros .btn {
    height: var(--ctrl-altura-p);
    padding: var(--esp-1) var(--esp-2);
    font-size: var(--ctrl-fonte-compacta);
    border-radius: var(--raio-sm);
  }
  .filtros .btn-icone {
    width: var(--ctrl-altura-p);
  }
  .filtros__acoes,
  .filtros > .opcao {
    margin-top: calc(var(--rotulo-fonte-compacta) * var(--lh-tight) + var(--esp-1));
  }
  .filtros > .opcao {
    min-height: var(--ctrl-altura-p);
    font-size: var(--ctrl-fonte-compacta);
  }
}
@media (max-width: 767px) {
  .filtros > .campo,
  .filtros__acoes {
    flex: 1 1 100%;
  }
  .filtros__acoes,
  .filtros > .opcao {
    margin-top: 0;
  }
  .filtros :is(.input, .select, .multi) {
    width: 100%;
  }
  .filtros__acoes .btn {
    flex: 1;
  }
}

/* ---------- .intervalo — período: atalho + data inicial + data final ----------
 * O filtro composto mais comum (vai num .campo--livre da barra):
 * <div class="campo campo--livre" role="group" aria-labelledby="f-per-r">
 *   <span class="label" id="f-per-r">Período</span>
 *   <div class="intervalo">
 *     <select class="select" aria-label="Período: atalho">…Este mês…Personalizado</select>
 *     <input class="input" type="date" aria-label="Período: de">
 *     <span class="intervalo__ate" aria-hidden="true">a</span>
 *     <input class="input" type="date" aria-label="Período: até">
 *   </div>
 * </div>
 * O atalho ("Hoje", "Este mês", "Últimos 30 dias") preenche as datas; mexer
 * nas datas vira "Personalizado". No celular: o atalho numa linha, as duas
 * datas na de baixo, dividindo a largura.
 */
.intervalo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--esp-2);
}
.intervalo__ate {
  font-size: var(--fs-sm);
  color: var(--c-texto-2);
}
.intervalo > .select {
  width: auto;                      /* a largura da opção mais longa ("Mesmo período do ano passado") */
  min-width: 11.5rem;               /* 184px: atalhos curtos não deixam a lista estreita demais */
}
.intervalo > .input {
  width: 10rem;                     /* 160px: a data com o ícone do calendário */
}
@media (min-width: 768px) and (pointer: fine) {
  .filtros .intervalo > .select { min-width: 10rem; }   /* os mesmos textos em 14px */
  .filtros .intervalo > .input  { width: 8.5rem; }
}
@media (max-width: 767px) {
  .intervalo > .select {
    flex: 1 1 100%;
  }
  .intervalo > .input {
    flex: 1 1 0;
    min-width: 0;
  }
}

/* ---------- .multi — seleção múltipla ----------
 * Para escolher VÁRIAS opções de uma lista (lojas, seções, situações): um
 * botão com cara de .select que abre um painel com caixas de marcar.
 *
 * <div class="multi">
 *   <button type="button" class="select multi__botao" id="f-lojas"
 *           aria-labelledby="f-lojas-r f-lojas" aria-haspopup="true"
 *           aria-expanded="false" aria-controls="f-lojas-p">Todas as lojas</button>
 *   <div class="multi__painel" id="f-lojas-p" role="group" aria-label="Lojas" hidden>
 *     <input class="input multi__busca" type="search" aria-label="Buscar loja" placeholder="Buscar loja…">  ← só com mais de 8 opções
 *     <label class="opcao multi__item multi__todas"><input class="checkbox" type="checkbox"><span>Todas as lojas</span></label>
 *     <hr class="multi__separador">
 *     <div class="multi__lista">
 *       <label class="opcao multi__item"><input class="checkbox" type="checkbox" value="1"><span>Loja Centro</span></label>
 *       …
 *       <p class="multi__nada" hidden>Nenhuma loja encontrada.</p>
 *     </div>
 *   </div>
 * </div>
 *
 * O BOTÃO resume a escolha: todas → "Todas as lojas"; nenhuma → "Nenhuma
 * loja"; uma ou duas → os nomes; mais → "5 lojas" (a lista inteira no title).
 * "Selecionar todas" fica MARCADA quando todas estão e em estado misto
 * (indeterminate) quando só algumas. Com a busca digitada, ela vale só para
 * as encontradas ("Todas as encontradas (3)"), como o filtro do Excel.
 * Comportamento (JS da ferramenta; o CSS só desenha): o botão abre e fecha;
 * ao abrir, foco na busca (ou no "todas"); Esc fecha e devolve o foco ao
 * botão; clique fora e Tab para fora fecham; Enter na busca não envia o
 * formulário. Mexer não consulta: vale no "Buscar". Nenhuma marcada é erro
 * escrito no campo ("Escolha pelo menos 1 loja.").
 * Lista que depende de outra (ex.: Seções de um Departamento): o painel
 * mostra só as opções do pai escolhido; trocar o pai marca todas as dele.
 * Mesmo componente para TODA escolha de várias opções da ferramenta: a pessoa
 * aprende um seletor só.
 */
.multi {
  position: relative;
  width: 17rem;                     /* 272px fora da barra de filtros (nela, a largura é a do filtro) */
  max-width: 100%;
}
.multi__botao {
  overflow: hidden;
  text-align: left;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.multi__painel {
  position: absolute;
  top: calc(100% + var(--esp-1));
  left: 0;
  z-index: var(--z-dropdown);
  display: flex;
  flex-direction: column;
  gap: var(--esp-1);
  width: max-content;
  min-width: 100%;
  max-width: min(var(--painel-teto), calc(100vw - 2 * var(--moldura-tela)));
  padding: var(--esp-2);
  background: var(--c-bg-elev);
  border: 1px solid var(--c-borda);
  border-radius: var(--raio-lg);
  box-shadow: var(--sombra-lg);
}
.multi__painel[hidden] {
  display: none;
}
.multi__busca {
  margin-bottom: var(--esp-1);
}
.multi__lista {
  display: flex;
  flex-direction: column;
  max-height: var(--painel-lista-teto);   /* lista longa rola dentro do painel */
  overflow-y: auto;
}
.multi__item {
  display: flex;
  min-height: var(--ctrl-altura);
  padding: 0 var(--esp-2);
  font-size: var(--fs-sm);
  border-radius: var(--raio-md);
}
.multi__item[hidden] {
  display: none;                    /* o display do item vence o atributo: escondido pela busca */
}
.multi__item:hover {
  background: var(--item-hover);
}
.multi__todas {
  font-weight: 600;
}
.multi__separador {
  margin: 0;
  border: none;
  border-top: 1px solid var(--c-borda);
}
.multi__nada {
  margin: 0;
  padding: var(--esp-2);
  font-size: var(--fs-sm);
  color: var(--c-texto-2);
}

/* ---------- .card ----------
 * <article class="card">
 *   <h3 class="card__titulo">Título</h3>
 *   <p>Conteúdo do card.</p>
 * </article>
 *
 * .card__titulo tem tamanho PRÓPRIO — 18px/600, seja h2 ou h3 — abaixo dos
 * 24px do título da tela (título de tela e de card nunca empatam).
 * Card com várias partes: "card pilha pilha--interna" (12px entre elas; a
 * margem do título é zerada pela pilha).
 */
.card {
  background: var(--c-bg-elev);
  border: 1px solid var(--c-borda);
  border-radius: var(--raio-lg);
  padding: var(--esp-4);            /* 16px */
  box-shadow: var(--sombra-sm);
}
.card__titulo {
  margin: 0 0 var(--esp-2);
  font-size: var(--fs-md);
  font-weight: 600;
  line-height: var(--lh-tight);
  color: var(--c-texto);
}

/* ---------- .card__cabeca — título do card + selo + ação na mesma linha ----------
 * Só sobem para cá ações que valem para o card inteiro ("Histórico de
 * faturas", "Configurar pagamento"); enviar formulário continua no fim.
 * A legenda opcional ocupa a linha de baixo. Mesma altura com ou sem ação.
 *
 * <div class="card__cabeca">
 *   <div class="card__cabeca-titulo">
 *     <h2 class="card__titulo">Plano Básico</h2>
 *     <span class="badge badge-sucesso">Ativo</span>
 *   </div>
 *   <button type="button" class="btn btn-secundario btn-pequeno">Histórico de faturas</button>
 *   <p class="card__legenda">Frase curta opcional.</p>
 * </div>
 * Substitui o .card__titulo solto e, como ele, tem margem abaixo (12px) no
 * fluxo de bloco do card; dentro de .pilha a margem é zerada (o gap manda).
 */
.card__cabeca {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--esp-1) var(--esp-3);
  min-height: var(--ctrl-altura-p);
  margin-bottom: var(--esp-3);
}
.card__cabeca-titulo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--esp-2);
  min-width: 0;
}
.card__cabeca .card__titulo {
  margin: 0;
}
.card__legenda {
  flex-basis: 100%;
  margin: 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  color: var(--c-texto-2);
}

/* ---------- .ficha — dados curtos "rótulo: valor" ----------
 * Rótulo de 12px colado ACIMA do valor (4px) e itens lado a lado (24px entre
 * eles) — nunca o rótulo numa ponta da tela e o valor na outra. Em área
 * estreita (≤540px: corte do próprio componente, abaixo do celular de 767px,
 * porque até ali os itens ainda cabem lado a lado) cada item vira uma linha,
 * rótulo à esquerda e valor à direita: o rótulo (curto por definição) não
 * encolhe nem quebra, e o valor longo que quebra fica alinhado à direita.
 *
 * <dl class="ficha">
 *   <div class="ficha__item"><dt>Valor</dt><dd>R$ 49,90 <span class="ficha__sufixo">por mês</span></dd></div>
 *   <div class="ficha__item"><dt>Próxima cobrança</dt><dd>15/10/2026</dd></div>
 * </dl>
 * O valor aceita um .badge dentro. Sem valor: <dd><span class="ficha__vazio">—</span></dd>.
 */
.ficha {
  display: flex;
  flex-wrap: wrap;
  gap: var(--esp-3) var(--esp-6);
  margin: 0;
}
.ficha__item {
  display: flex;
  flex-direction: column;
  gap: var(--esp-1);
  min-width: 0;
}
.ficha dt {
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: var(--lh-tight);
  color: var(--c-texto-2);
}
.ficha dd {
  margin: 0;
  font-size: var(--fs-base);
  font-weight: 600;
  line-height: var(--lh-tight);
  color: var(--c-texto);
  font-variant-numeric: tabular-nums;
}
.ficha__sufixo {
  font-size: var(--fs-sm);
  font-weight: 400;
  color: var(--c-texto-2);
}
/* Valor ausente: o traço "—" em --c-texto-3 e sem negrito (regra do traço
   vazio), no lugar do valor. */
.ficha__vazio {
  font-weight: 400;
  color: var(--c-texto-3);
}
@media (max-width: 540px) {
  .ficha {
    flex-direction: column;
    gap: var(--esp-1);
  }
  .ficha__item {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--esp-3);
  }
  .ficha dt {
    flex-shrink: 0;                 /* o rótulo não encolhe nem quebra */
    font-size: var(--fs-sm);
  }
  .ficha dd {
    text-align: right;              /* o valor longo que quebra fica junto da borda */
  }
}

/* ---------- .indicadores — os números de destaque de um painel ----------
 * <div class="indicadores">
 *   <div class="indicador">
 *     <p class="indicador__rotulo">Faturamento</p>
 *     <p class="indicador__valor">R$ 1.234.567,89</p>
 *     <p class="indicador__variacao indicador__variacao--boa">
 *       <span class="icone indicador__seta" aria-hidden="true">[svg trending-up]</span>
 *       <span>+12,3%</span><span class="indicador__comparacao">vs. mês passado</span>
 *     </p>
 *     <p class="indicador__ajuda">01/10 a 21/10 · 14 lojas com venda</p>
 *   </div>
 * </div>
 * Cartões numa grade que se arruma sozinha (mínimo 13rem; um por linha
 * quando não cabe), 16px entre eles e de recuo — o ritmo do card. Rótulo de
 * 14px/500 em --c-texto-2; valor de 30px (o tamanho da saudação do painel,
 * .tela-topo--saudacao) que ENCOLHE com o cartão (container query, cqi) até
 * 20px, sem quebrar o número no meio ("R$" pode ir para a linha de cima, os
 * algarismos não). Valor em texto (ex.: o nome da loja que mais vendeu):
 * .indicador__valor--texto (24px, até 18px).
 * VARIAÇÃO: cor = direção × "subir é bom" — --boa (verde), --ruim
 * (vermelho), --neutra (cinza) —, sempre com a seta e o sinal (a cor sozinha
 * não basta). Métrica em que subir é ruim (ruptura, devolução, prazo) inverte
 * a cor. Texto escurecido pela mistura dos selos (≥4,5:1).
 * Ajuda de 12px em --c-texto-2 (o período, a base da conta). Painel com
 * seções sem título: pilha--painel (32px).
 */
.indicadores {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: var(--esp-4);
}
.indicador {
  container-type: inline-size;      /* o valor encolhe com o cartão (cqi), não com a janela */
  display: flex;
  flex-direction: column;
  gap: var(--esp-1);
  min-width: 0;
  padding: var(--esp-4);
  background: var(--c-bg-elev);
  border: 1px solid var(--c-borda);
  border-radius: var(--raio-lg);
  box-shadow: var(--sombra-sm);
}
.indicador p {
  margin: 0;
}
.indicador__rotulo {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--c-texto-2);
}
.indicador__valor {
  font-size: clamp(var(--fs-lg), 12cqi, var(--fs-2xl));   /* 30px; menos só em cartão estreito */
  font-weight: 600;
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-tight);
  color: var(--c-texto);
  font-variant-numeric: tabular-nums;
  overflow-wrap: normal;            /* quebra só no espaço ("R$" | "3.556.470,68"), nunca no meio */
}
.indicador__valor--texto {
  font-size: clamp(var(--fs-md), 10cqi, var(--fs-xl));
}
.indicador__variacao {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 var(--esp-1);
  font-size: var(--fs-sm);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.indicador__seta {
  width: 1rem;
  height: 1rem;
}
.indicador__variacao--boa {
  color: color-mix(in srgb, var(--c-sucesso) 65%, var(--c-texto));
}
.indicador__variacao--ruim {
  color: color-mix(in srgb, var(--c-erro) 65%, var(--c-texto));
}
.indicador__variacao--neutra {
  color: var(--c-texto-2);
}
.indicador__comparacao {
  font-weight: 400;
  color: var(--c-texto-2);
}
.indicador__ajuda {
  font-size: var(--fs-xs);
  line-height: 1.4;                 /* a mesma da .campo__ajuda: duas linhas continuam arejadas */
  color: var(--c-texto-2);
}

/* ---------- .upload-zona — área de envio de arquivo/imagem ----------
 * Prévia de 80px à esquerda; à direita a ajuda (12px, DENTRO da caixa) e os
 * botões em linha. Tracejado que se enxerga (--zona-borda, ≥3:1). O tracejado
 * PROMETE "arraste aqui": ligue o arrastar e soltar — enquanto um arquivo
 * passa por cima, o JS põe .upload-zona--arrastando (marca de seleção:
 * contorno de 2px) e tira no dragleave/drop. Sem arrastar, use borda sólida.
 * Prévia vazia: fundo liso e "Sem foto" legível (vence o .previa-xadrez).
 *
 * <div class="upload-zona">
 *   <span class="upload-zona__previa previa-xadrez">
 *     <img src="…" alt="Prévia da imagem">
 *   </span>
 *   <p class="upload-zona__ajuda" id="x-ajuda">JPG, PNG ou WebP, até 10 MB. Arraste o arquivo para cá ou use o botão.</p>
 *   <div class="upload-zona__acoes">
 *     <button type="button" class="btn btn-secundario btn-pequeno" aria-describedby="x-ajuda">Enviar imagem</button>
 *     <button type="button" class="btn btn-discreto btn-pequeno" hidden>Remover imagem</button>
 *   </div>
 * </div>
 * Vazia: <span class="upload-zona__previa upload-zona__previa--vazia previa-xadrez"><span aria-hidden="true">Sem foto</span></span>
 * Coluna (logotipo): .upload-zona--coluna — prévia em cima (até 120px de
 * altura, largura livre), botões e ajuda embaixo, centralizados. Vazia, a
 * prévia da coluna volta ao quadro de 80px ("Sem logo").
 * Botão com [hidden] dentro da zona some de verdade (o display do .btn vencia).
 */
.upload-zona {
  display: grid;
  grid-template-columns: var(--zona-previa) minmax(0, 1fr);
  grid-template-areas:
    'previa ajuda'
    'previa acoes';
  gap: var(--esp-2) var(--esp-3);
  padding: var(--esp-3);
  background: var(--c-bg-muted);
  border: 1px dashed var(--zona-borda);
  border-radius: var(--raio-md);
  transition: border-color var(--t-rapida), background var(--t-rapida);
}
.upload-zona--arrastando {
  border-style: solid;
  border-color: var(--selecao-cor);
  box-shadow: inset 0 0 0 1px var(--selecao-cor);
  background: var(--c-acento-bg);
}
.upload-zona [hidden] {
  display: none;
}
.upload-zona__previa {
  grid-area: previa;
  width: var(--zona-previa);
  height: var(--zona-previa);
  display: grid;
  place-items: center;
  overflow: hidden;
  border: 1px solid var(--c-borda);
  border-radius: var(--raio-sm);
}
.upload-zona__previa img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
/* Duas classes (0,2,0): vence o .previa-xadrez (0,1,0), que vem depois no arquivo. */
.upload-zona__previa.upload-zona__previa--vazia {
  background-color: var(--c-bg);
  background-image: none;
  border-color: var(--c-borda-forte);
  color: var(--c-texto-2);
  font-size: var(--fs-xs);
  text-align: center;
}
.upload-zona__ajuda {
  grid-area: ajuda;
  align-self: end;
  margin: 0;
  font-size: var(--fs-xs);
  line-height: 1.4;                 /* igual à .campo__ajuda */
  color: var(--c-texto-2);
}
.upload-zona__acoes {
  grid-area: acoes;
  align-self: start;
  display: flex;
  flex-wrap: wrap;
  gap: var(--esp-2);
}
.upload-zona--coluna {
  --zona-previa-teto: 7.5rem;       /* 120px: confere a marca sem dominar o card */
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    'previa'
    'acoes'
    'ajuda';
  justify-items: center;
  text-align: center;
}
.upload-zona--coluna .upload-zona__previa {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: var(--zona-previa-teto);
  border: 0;
}
/* Vazia, a prévia da coluna volta ao quadro de 80px da zona comum (solta, ela
   encolheria até o tamanho do texto "Sem logo"). Vem depois da regra de cima,
   com o mesmo peso (0,2,0). */
.upload-zona--coluna .upload-zona__previa--vazia {
  width: var(--zona-previa);
  height: var(--zona-previa);
  border: 1px solid var(--c-borda-forte);
}
.upload-zona--coluna .upload-zona__previa img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: var(--zona-previa-teto);
}
.upload-zona--coluna .upload-zona__acoes {
  justify-content: center;
}
/* Área estreita (≤540px, o mesmo corte da .ficha): a ajuda desce para baixo da
   prévia e dos botões, ocupando a largura toda. */
@media (max-width: 540px) {
  .upload-zona:not(.upload-zona--coluna) {
    grid-template-areas:
      'previa acoes'
      'ajuda  ajuda';
  }
}

/* ---------- .modal — janela ----------
 * <div class="modal-backdrop">
 *   <div class="modal" role="dialog" aria-modal="true" aria-labelledby="m-titulo"
 *        aria-describedby="m-msg">
 *     <h2 class="modal__titulo" id="m-titulo">Apagar cliente?</h2>
 *     <p class="modal__mensagem" id="m-msg">Esta ação não pode ser desfeita.</p>
 *     <div class="modal__acoes">
 *       <button class="btn btn-secundario">Cancelar</button>
 *       <button class="btn btn-perigo">Apagar</button>
 *     </div>
 *   </div>
 * </div>
 * Toda janela tem NOME: role="dialog", aria-modal="true" e aria-labelledby
 * apontando o id do título (aria-describedby para a mensagem, quando houver).
 *
 * Ritmo da janela:
 *   fundo escuro em volta  --modal-moldura (16px; 8px no celular)
 *   recuo interno          --modal-recuo   (20px; 16px no celular)
 *   título                 20px (--fs-lg), 8px até o conteúdo
 *   mensagem → conteúdo    12px (a mensagem não tem margem própria; o que vem
 *                          depois dela, se não tiver margem, ganha 12px)
 *   antes dos botões       20px (margin-top do .modal__acoes; o .modal é bloco,
 *                          então colapsa com a margem do último campo e vale
 *                          a maior)
 * Em janela cujo corpo é flex/grid com gap, a margem do .modal__acoes SOMA ao
 * gap — zere-a no módulo ou use um .campos interno.
 * Larguras: max-width 480px; janela mais larga muda o max-width (o width
 * sozinho não vale). Nunca maior que a tela: conteúdo alto rola por dentro.
 * Erro geral do formulário na janela: .campos → .campo__erro (12px) →
 * .modal__acoes (20px).
 *
 * Esc e clique fora (comportamento — JS da ferramenta; o CSS só desenha):
 *   - CONFIRMAÇÃO com botão "Cancelar": Esc e o clique no fundo escuro valem
 *     o "Cancelar" (resolvem com o valor dele) e fecham. Quem cria confirmação
 *     nova chama o botão de desistir de "Cancelar".
 *   - Confirmação SEM "Cancelar" (ex.: "Recarregar", ou duas ações em que
 *     nenhuma é desistir, como "Sem foto" / "Com foto"): exige um dos botões;
 *     Esc e clique fora não fazem nada — ali "não" também é uma ação.
 *   - Formulário: Esc não fecha sem perguntar (um Esc acidental apagaria o
 *     que foi digitado).
 *   - Esc só na janela de CIMA (a última .modal-backdrop): escute na fase de
 *     captura do document, com stopPropagation, para não fechar também a de
 *     baixo nem chegar aos atalhos da tela.
 *   - Clique fora no mousedown do fundo, com preventDefault: o foco não vai
 *     para o <body>, e quem abriu a janela devolve o foco ao botão de origem.
 */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  display: grid;
  place-items: center;
  padding: var(--modal-moldura);
  z-index: var(--z-modal);
  animation: fade-in var(--t-padrao);
}
.modal {
  background: var(--c-bg-elev);
  color: var(--c-texto);
  border: 1px solid var(--c-borda);
  border-radius: var(--raio-lg);
  padding: var(--modal-recuo);
  max-width: 480px;
  width: 100%;
  box-shadow: var(--sombra-lg);
  animation: modal-in var(--t-padrao);
  /* Amarrado à moldura do fundo pela MESMA variável; a 2ª linha usa 100dvh
     (altura com a barra do navegador do celular à mostra), ignorada por quem
     não a conhece. */
  max-height: calc(100vh - 2 * var(--modal-moldura));
  max-height: calc(100dvh - 2 * var(--modal-moldura));
  overflow-y: auto;
  overscroll-behavior: contain;
}
.modal__titulo {
  margin: 0 0 var(--esp-2);
  font-size: var(--fs-lg);
  font-weight: 600;
  line-height: var(--lh-tight);
  color: var(--c-texto);
}
.modal__mensagem {
  margin: 0;
  color: var(--c-texto-2);
  line-height: var(--lh-normal);
}
/* Peso zero (:where): qualquer margem posta pelo módulo no elemento vence. */
:where(.modal__mensagem + :not(.modal__acoes)) {
  margin-top: var(--esp-3);
}
.modal__acoes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--esp-2);
  justify-content: flex-end;
  margin-top: var(--modal-respiro-acoes);
}
@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes modal-in {
  from { opacity: 0; transform: translateY(-8px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}

/* ---------- .modal--larga / --ampla — janela de leitura ou de detalhe ----------
 * Para o que não cabe nos 480px: o texto de ajuda de uma tela, uma tabela de
 * detalhe ("de onde vem este número").
 * <div class="modal modal--larga" role="dialog" aria-modal="true" aria-labelledby="j-t">
 *   <div class="modal__cabeca">
 *     <h2 class="modal__titulo" id="j-t">Pedidos pendentes — Café 500 g</h2>
 *     <button type="button" class="btn btn-discreto btn-icone" aria-label="Fechar">[svg x]</button>
 *   </div>
 *   <div class="modal__corpo leitura" tabindex="0">…conteúdo que rola…</div>
 *   <div class="modal__acoes"><button type="button" class="btn btn-secundario">Fechar</button></div>
 * </div>
 *   .modal--larga  52rem (832px) — texto: linha de leitura confortável.
 *   .modal--ampla  72rem (1152px) — tabelas de detalhe com muitas colunas.
 * Cabeçalho (título + "×") e botões ficam FIXOS; só o .modal__corpo rola
 * (tabindex="0" e o contorno de foco: dá para rolar pelo teclado). Janela de
 * LEITURA não tem o que perder: Esc, clique fora, "×" e "Fechar" fecham.
 */
.modal.modal--larga,
.modal.modal--ampla {
  display: flex;
  flex-direction: column;
  overflow: hidden;                 /* quem rola é o .modal__corpo */
}
.modal.modal--larga {
  max-width: 52rem;                 /* 832px: texto em linha de leitura confortável */
}
.modal.modal--ampla {
  max-width: 72rem;                 /* 1152px: tabelas de detalhe precisam de largura */
}
.modal__cabeca {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--esp-3);
}
.modal__cabeca .modal__titulo {
  margin: 0;
}
.modal__corpo {
  flex: 1 1 auto;
  min-height: 0;
  margin-top: var(--esp-3);
  padding-right: var(--esp-2);      /* a barra de rolagem não encosta no texto */
  overflow-y: auto;
  border-radius: var(--raio-sm);
}
.modal__corpo:focus-visible {
  outline: var(--foco-largura) solid var(--foco-cor);
  outline-offset: var(--foco-folga);
}

/* ---------- .leitura — texto longo (ajuda, documentação, Markdown) ----------
 * Um bloco de texto corrido com títulos, listas, tabelas e código (ex.: o
 * README de uma tela na janela de leitura). Zera as margens do navegador e dá
 * o ritmo: 12px entre blocos, 24px antes de um título e 8px depois dele.
 * Títulos h2 20px · h3 18px · h4 16px, 600. Parágrafo e item de lista com a
 * entrelinha folgada (1,625). Tabela dentro: a .tabela do DS, com as células
 * alinhadas em cima. Código em mono, num fundo sutil; citação com filete de
 * 3px à esquerda.
 */
.leitura > * {
  margin: 0;
}
.leitura > * + * {
  margin-top: var(--esp-3);
}
.leitura > * + :is(h2, h3, h4, h5, h6) {
  margin-top: var(--esp-6);
}
.leitura > :is(h2, h3, h4, h5, h6) + * {
  margin-top: var(--esp-2);
}
.leitura :is(h2, h3, h4, h5, h6) {
  font-weight: 600;
  line-height: var(--lh-tight);
  color: var(--c-texto);
}
.leitura h2 { font-size: var(--fs-lg); }
.leitura h3 { font-size: var(--fs-md); }
.leitura :is(h4, h5, h6) { font-size: var(--fs-base); }
.leitura :is(p, li) {
  line-height: var(--lh-relaxed);
}
.leitura :is(ul, ol) {
  padding-left: var(--esp-6);
}
.leitura li + li,
.leitura li > :is(ul, ol) {
  margin-top: var(--esp-1);
}
.leitura code {
  padding: 0 var(--esp-1);
  font-family: var(--fam-mono);
  font-size: 0.875em;               /* relativo ao texto em volta (vale em título, tabela e parágrafo) */
  background: var(--c-bg-muted);
  border: 1px solid var(--c-borda);
  border-radius: var(--raio-sm);
}
.leitura pre {
  padding: var(--esp-3);
  overflow-x: auto;
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  background: var(--c-bg-muted);
  border: 1px solid var(--c-borda);
  border-radius: var(--raio-md);
}
.leitura pre code {
  padding: 0;
  font-size: inherit;
  background: none;
  border: 0;
}
.leitura blockquote {
  padding-left: var(--esp-3);
  color: var(--c-texto-2);
  border-left: var(--selecao-filete) solid var(--c-borda-forte);
}
.leitura hr {
  border: 0;
  border-top: 1px solid var(--c-borda);
}
.leitura .tabela :is(th, td) {
  vertical-align: top;
}

/* ---------- Toasts ----------
 * <div class="toast toast--visivel" data-tipo="sucesso" role="status">Mensagem</div>
 * data-tipo: info | sucesso | aviso | erro (muda só a barra lateral esquerda).
 * Posição fixa no rodapé central; anima opacidade + deslize. Flutua e some
 * sozinho: não devolve espaço à tela, então NÃO encolhe por densidade. Para o
 * que precisa ficar na tela, use a faixa de aviso (.aviso).
 */
.toast {
  position: fixed;
  left: 50%;
  bottom: var(--esp-6);
  transform: translateX(-50%) translateY(12px);
  background: var(--c-bg-elev);
  color: var(--c-texto);
  border: 1px solid var(--c-borda);
  border-left: 3px solid var(--c-texto-3);
  border-radius: var(--raio-md);
  padding: var(--esp-3) var(--esp-4);
  box-shadow: var(--sombra-lg);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-padrao), transform var(--t-padrao);
  max-width: 80vw;
  z-index: var(--z-toast);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
}
.toast--visivel { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast[data-tipo="info"]    { border-left-color: var(--c-acento); }
.toast[data-tipo="sucesso"] { border-left-color: var(--c-sucesso); }
.toast[data-tipo="aviso"]   { border-left-color: var(--c-aviso); }
.toast[data-tipo="erro"]    { border-left-color: var(--c-erro); }

/* ---------- .menu-suspenso — menu que abre de um botão ----------
 * Ações agrupadas num botão do topo da tela ("Exportar": Excel · PDF) ou o
 * menu do nome da pessoa (Minha conta · Sair). Abre logo ABAIXO do botão.
 *
 * <div class="menu-suspenso">
 *   <button type="button" class="btn btn-secundario" aria-haspopup="menu"
 *           aria-expanded="false" aria-controls="m-exp">
 *     <span class="icone icone--sm" aria-hidden="true">[svg download]</span>Exportar
 *     <span class="icone icone--sm menu-suspenso__seta" aria-hidden="true">[svg chevron-down]</span>
 *   </button>
 *   <div class="menu-suspenso__painel" id="m-exp" role="menu" aria-label="Exportar" hidden>
 *     <button type="button" class="menu-suspenso__item" role="menuitem" tabindex="-1">
 *       <span class="icone icone--sm" aria-hidden="true">[svg]</span>
 *       <span class="menu-suspenso__texto"><span>Excel</span>
 *         <span class="menu-suspenso__detalhe">planilha .xlsx, com os números para somar e filtrar</span></span>
 *     </button>
 *     …
 *   </div>
 * </div>
 *
 * Itens de 14px/500 (37px: 8 + 21 + 8) com ícone de 16px e, quando ajuda a escolher, uma linha
 * de detalhe de 12px em --c-texto-2 (o que o item faz). Cabeçalho opcional
 * (.menu-suspenso__cabeca: nome e login no menu da conta), separado por um
 * filete. Hover e foco = --item-hover; o foco é o contorno POR DENTRO.
 * O painel abre alinhado à DIREITA do botão (botão no canto direito do topo);
 * .menu-suspenso--esquerda alinha à esquerda. Nunca sai da janela: o JS
 * confere ao abrir e troca o lado quando não cabe (ex.: no celular o botão
 * desce para a esquerda da tela).
 * Comportamento (JS da ferramenta; o mesmo teclado do menu flutuante do menu
 * lateral, §19.14): clique ou ↓ abre com foco no 1º item; ↑/↓ circulares,
 * Home/End; Esc fecha e devolve o foco ao botão; Tab, clique fora e escolher
 * um item fecham; só um aberto por vez. O botão leva aria-haspopup,
 * aria-expanded e aria-controls. Ação que ainda não pode (ex.: exportar antes
 * de buscar): o botão fica disabled com um title que diz o que falta.
 */
.menu-suspenso {
  position: relative;
  display: inline-flex;
}
.menu-suspenso__seta {
  margin-right: calc(-1 * var(--esp-1));   /* a seta encosta no fim do botão, como no .select */
}
.menu-suspenso__painel {
  position: absolute;
  top: calc(100% + var(--esp-1));
  right: 0;
  z-index: var(--z-dropdown);
  display: flex;
  flex-direction: column;
  gap: var(--esp-1);
  min-width: var(--menu-largura);
  max-width: calc(100vw - 2 * var(--moldura-tela));
  padding: var(--esp-1);
  background: var(--c-bg-elev);
  border: 1px solid var(--c-borda);
  border-radius: var(--raio-lg);
  box-shadow: var(--sombra-lg);
}
.menu-suspenso__painel[hidden] {
  display: none;
}
.menu-suspenso--esquerda > .menu-suspenso__painel {
  right: auto;
  left: 0;
}
.menu-suspenso__cabeca {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: var(--esp-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  color: var(--c-texto-2);
  border-bottom: 1px solid var(--c-borda);
  overflow-wrap: anywhere;
}
.menu-suspenso__cabeca strong {
  font-weight: 600;
  color: var(--c-texto);
}
.menu-suspenso__item {
  display: flex;
  align-items: flex-start;
  gap: var(--esp-2);
  width: 100%;
  margin: 0;
  padding: var(--esp-2);
  font: inherit;
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  text-align: left;
  color: var(--c-texto);
  background: none;
  border: 0;
  border-radius: var(--raio-md);
  cursor: pointer;
}
.menu-suspenso__item:hover,
.menu-suspenso__item:focus-visible {
  background: var(--item-hover);
}
.menu-suspenso__item:focus-visible {
  outline: var(--foco-largura) solid var(--foco-cor);
  outline-offset: calc(-1 * var(--foco-largura));
}
.menu-suspenso__item .icone {
  margin-top: 2px;                  /* centra o ícone de 16px na 1ª linha (14px × 1,5 = 21px) */
  color: var(--c-texto-2);
}
.menu-suspenso__texto {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-weight: 500;
}
.menu-suspenso__detalhe {
  font-size: var(--fs-xs);
  font-weight: 400;
  color: var(--c-texto-2);
}

/* ---------- .dica — balão de dica ----------
 * Explica algo SEM ocupar a tela: a descrição de uma tela no "?" ao lado do
 * título, o valor de um ponto do gráfico.
 *
 * <span class="dica-ancora">
 *   <button type="button" class="btn btn-discreto btn-pequeno btn-icone"
 *           aria-label="O que esta tela mostra" aria-describedby="d-1">[svg circle-help]</button>
 *   <span class="dica" id="d-1" role="tooltip" hidden>Unidades a receber de pedidos de compra…</span>
 * </span>
 *
 * Abre ao passar o mouse E ao focar pelo teclado (o texto também é a
 * descrição acessível do botão, pelo aria-describedby); no toque, o toque
 * abre e fecha; Esc fecha. Fica DENTRO da janela: o JS ajusta a posição na
 * horizontal (16px de folga da borda). Frase curta, 14px, até --painel-teto
 * (24rem). Flutua por cima: não encolhe por densidade.
 * Dica de gráfico (valores): .dica__titulo (12px, --c-texto-2) e uma
 * .dica__linha por série — a chave de cor (.dica__chave), o valor em negrito
 * e o nome em --c-texto-2.
 */
.dica-ancora {
  position: relative;
  display: inline-flex;
}
.dica {
  position: absolute;
  z-index: var(--z-tooltip);
  display: flex;
  flex-direction: column;
  gap: var(--esp-1);
  width: max-content;
  max-width: min(var(--painel-teto), calc(100vw - 2 * var(--moldura-tela)));
  margin: 0;
  padding: var(--esp-2) var(--esp-3);
  font-size: var(--fs-sm);
  font-weight: 400;
  line-height: var(--lh-normal);
  text-align: left;
  color: var(--c-texto);
  background: var(--c-bg);
  border: 1px solid var(--c-borda);
  border-radius: var(--raio-md);
  box-shadow: var(--sombra-lg);
  pointer-events: none;
}
.dica[hidden] {
  display: none;
}
.dica-ancora > .dica {
  top: calc(100% + var(--esp-1));
  left: 0;
}
.dica__titulo {
  font-size: var(--fs-xs);
  color: var(--c-texto-2);
}
.dica__linha {
  display: flex;
  align-items: center;
  gap: var(--esp-2);
  line-height: var(--lh-tight);
  white-space: nowrap;
}
.dica__linha strong {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.dica__linha > :last-child:not(strong) {
  color: var(--c-texto-2);
}
.dica__chave {
  flex: none;
  width: 0.75rem;
  height: 2px;                      /* a linha da série; barra: dê altura de 0,625rem */
  border-radius: 1px;
}

/* ---------- .aviso — faixa de aviso ----------
 * Para o que pede atenção DENTRO da tela e precisa ficar nela (conta vencida,
 * limite do plano, mudança aguardando pagamento). Ícone (obrigatório) +
 * título em negrito + frase que diz o que aconteceu, o que está pausado e
 * qual é a saída; ações à direita, que descem para baixo do texto quando a
 * FAIXA (não a janela) tem até 36rem: com o menu aberto numa janela média,
 * dois botões à direita deixavam ~130px para o texto, em 6 linhas. A faixa é
 * sempre bloco de largura cheia (container: não a ponha num flex/grid que a
 * encolha até o conteúdo).
 * Contorno de 1px na cor do tipo (sem ele a faixa parece texto comum) e
 * fundo *-bg. Respiro 8px 12px (1 linha = 39px); sem margem própria (a .pilha
 * dá o espaço). Tipos com os MESMOS nomes do toast: data-tipo = info |
 * sucesso | aviso | erro (sem data-tipo: neutro, contorno cinza).
 *
 * <div class="aviso" data-tipo="aviso" role="status">
 *   <span class="aviso__icone icone icone--sm" aria-hidden="true">[svg Lucide 16px]</span>
 *   <p class="aviso__texto"><strong>Mensalidade vencida.</strong> Os envios ficam pausados até o pagamento. Nada foi apagado.</p>
 *   <div class="aviso__acoes"><a class="btn btn-primario btn-pequeno" href="…">Pagar fatura</a></div>
 * </div>
 * Montado por createElement ou innerHTML com esc(); ícone SVG constante, sem
 * style="". Use role="alert" só quando surgir por causa de uma ação da pessoa.
 */
.aviso {
  container: aviso / inline-size;   /* a largura vem de fora (bloco de largura cheia), nunca do texto */
  --aviso-cor: var(--c-borda-forte);
  --aviso-fundo: var(--c-bg-muted);
  --aviso-icone: var(--c-texto-2);
  /* Grade: [ícone][texto][ações]. Ícone e texto nunca se separam; só as ações
     descem (faixa estreita). */
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--esp-2);
  padding: var(--esp-2) var(--esp-3);
  background: var(--aviso-fundo);
  color: var(--c-texto);
  border: 1px solid var(--aviso-cor);
  border-radius: var(--raio-md);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
}
.aviso[data-tipo="info"]    { --aviso-cor: var(--c-acento-ativo); --aviso-fundo: var(--c-acento-bg);  --aviso-icone: var(--c-acento-ativo); }
.aviso[data-tipo="sucesso"] { --aviso-cor: var(--c-sucesso);      --aviso-fundo: var(--c-sucesso-bg); --aviso-icone: var(--c-sucesso); }
.aviso[data-tipo="aviso"]   { --aviso-cor: var(--c-aviso);        --aviso-fundo: var(--c-aviso-bg);   --aviso-icone: var(--c-aviso); }
.aviso[data-tipo="erro"]    { --aviso-cor: var(--c-erro);         --aviso-fundo: var(--c-erro-bg);    --aviso-icone: var(--c-erro); }
.aviso__icone {
  grid-column: 1;
  /* centra o ícone na 1ª linha de texto (14px × 1,5); o 1rem é o lado do
     .icone--sm (16px), que o .aviso__icone sempre usa */
  margin-top: calc((var(--fs-sm) * var(--lh-normal) - 1rem) / 2);
  color: var(--aviso-icone);
}
.aviso__texto {
  grid-column: 2;
  min-width: 0;
  margin: 0;
}
.aviso__texto strong {
  font-weight: 600;
}
.aviso__acoes {
  grid-column: 3;
  grid-row: 1;
  align-self: center;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--esp-2);
}
/* 36rem: o limite de container query não lê variável. */
@container aviso (max-width: 36rem) {
  .aviso__acoes {
    grid-column: 2;                 /* abaixo do texto, alinhadas a ele */
    grid-row: auto;
    align-self: start;
  }
}

/* ---------- Badges ----------
 * <span class="badge">Padrão</span>
 * <span class="badge badge-acento">Ativo</span>
 * <span class="badge badge-sucesso">OK</span>
 * <span class="badge badge-aviso">Atenção</span>
 * <span class="badge badge-erro">Falhou</span>
 * Selo de 20px (1 + 16 + 1 + borda), peso 600 e texto semântico ESCURECIDO
 * por mistura com --c-texto (≥5,3:1 no claro). No escuro a mistura clareia e
 * o contraste só sobe.
 */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 1px var(--esp-2);        /* 1px: fecha os 20px com a linha de 16px */
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1rem;
  border-radius: var(--raio-full);
  background: var(--c-bg-muted);
  color: var(--c-texto-2);
  border: 1px solid var(--c-borda);
  white-space: nowrap;
}
.badge-acento {
  background: var(--c-acento-bg);
  color: color-mix(in srgb, var(--c-acento-ativo) 80%, var(--c-texto));
  border-color: var(--c-acento-borda);
}
.badge-sucesso {
  background: var(--c-sucesso-bg);
  color: color-mix(in srgb, var(--c-sucesso) 65%, var(--c-texto));
  border-color: transparent;
}
.badge-aviso {
  background: var(--c-aviso-bg);
  color: color-mix(in srgb, var(--c-aviso) 65%, var(--c-texto));
  border-color: transparent;
}
.badge-erro {
  background: var(--c-erro-bg);
  color: color-mix(in srgb, var(--c-erro) 65%, var(--c-texto));
  border-color: transparent;
}

/* ---------- .abas — abas (e pílulas) ----------
 * <div class="abas" role="tablist" aria-label="Situação">
 *   <button type="button" class="aba" role="tab" aria-selected="true">Ativos</button>
 *   <button type="button" class="aba" role="tab" aria-selected="false">Arquivados</button>
 * </div>
 * O ESTADO é o atributo aria-selected="true" (o leitor de tela anuncia a aba
 * ativa; não há classe de "ativa") — o JS de quem usa alterna o atributo.
 * Aba de 36px, 14px. A ativa leva a marca de seleção: sublinhado de 2px em
 * --selecao-cor, texto escuro e peso 600 (duas pistas além da cor); a marca
 * não some no hover.
 *
 * Variante pílulas (filtros de situação):
 * <div class="abas abas--pilulas" role="tablist" aria-label="Filtrar por situação">…</div>
 *   → pílula de 26px com contorno; a ativa com texto escuro, fundo
 *     --c-acento-bg e contorno de 2px em --selecao-cor (nunca texto branco
 *     sobre o creme: 1,09:1).
 */
.abas {
  display: flex;
  gap: var(--esp-1);
  border-bottom: 1px solid var(--c-borda);
}
.aba {
  display: inline-flex;
  align-items: center;
  min-height: 2.25rem;              /* 36px = 8 + 17,5 + 8 + 2 do sublinhado, arredondado */
  padding: var(--esp-2) var(--esp-3);
  margin: 0 0 -1px;                 /* o sublinhado cobre a linha da barra */
  background: none;
  border: none;
  border-bottom: var(--selecao-contorno) solid transparent;
  border-radius: 0;
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: var(--lh-tight);
  color: var(--c-texto-2);
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--t-rapida), border-color var(--t-rapida), background var(--t-rapida);
}
.aba:hover {
  color: var(--c-texto);
}
.aba[aria-selected="true"] {
  color: var(--c-texto);
  font-weight: 600;
  border-bottom-color: var(--selecao-cor);
}
.aba:focus-visible {
  outline: var(--foco-largura) solid var(--foco-cor);
  outline-offset: calc(-1 * var(--foco-largura));   /* por dentro: a barra não corta o contorno */
}
.abas--pilulas {
  flex-wrap: wrap;
  gap: var(--esp-2);
  border-bottom: none;
}
.abas--pilulas .aba {
  min-height: var(--ctrl-altura-p);
  padding: 0 var(--esp-3);
  margin-bottom: 0;
  background: var(--c-bg);
  border: 1px solid var(--c-borda-forte);
  border-radius: var(--raio-full);
}
.abas--pilulas .aba:hover:not([aria-selected="true"]) {
  background: var(--c-bg-hover);
}
.abas--pilulas .aba[aria-selected="true"] {
  background: var(--c-acento-bg);
  border-color: var(--selecao-cor);
  box-shadow: inset 0 0 0 1px var(--selecao-cor);
}
.abas--pilulas .aba:focus-visible {
  outline-offset: var(--foco-folga);
}

/* ---------- Tabela ----------
 * <div class="tabela-area">
 *   <table class="tabela tabela--zebra tabela--sticky">
 *     <thead><tr><th>Nome</th><th class="tabela__apoio">Cód. interno</th><th class="num">Preço</th></tr></thead>
 *     <tbody>
 *       <tr><td>Item A</td><td class="tabela__apoio">10230</td><td class="num">R$ 4,99</td></tr>
 *     </tbody>
 *   </table>
 * </div>
 *
 * Linha de texto com 38px (respiro 8px em cima e embaixo, 12px nas laterais;
 * cabeçalho 35px, linha com .btn-pequeno 43px). A linha baixa vem com as
 * compensações que impedem "escorregar" de linha (reforçar antes de apertar):
 *   - linha sob o cabeçalho em --c-borda-forte;
 *   - zebra nas linhas PARES em --c-bg-muted (a 1ª linha fica clara e se
 *     separa do cabeçalho);
 *   - marca de seleção: filete de 3px à esquerda da linha sob o mouse ou com
 *     o foco do teclado (nunca nas linhas de mensagem com colspan);
 *   - th.num alinhado à direita, como o número.
 *
 * Modificadores:
 *   --zebra      linhas alternadas.
 *   --sticky     cabeçalho fixo ao rolar. Só com a tabela dentro da área de
 *                conteúdo que rola e cujo padding é --moldura-tela, sem outro
 *                contêiner com overflow no caminho (ele viraria o rolador).
 *   --miniatura  lista com miniatura: linha ÚNICA de 49px (--lista-mini-linha;
 *                4px de respiro, miniatura de até 40px de altura). A imagem
 *                leva .tabela__miniatura (teto de 40px); a largura é do módulo.
 * td.num / th.num: coluna numérica (mono, à direita, tabular-nums).
 * Área estreita: o contêiner .tabela-area mede a LARGURA DISPONÍVEL (não a da
 * janela). Com até 720px, laterais de 8px e as colunas .tabela__apoio somem
 * (o dado continua acessível ao abrir o item).
 * Ações da linha: .btn-pequeno (texto) ou o "⋮" (.btn-icone) — ver .btn.
 * Título da linha que abre o item: cor de texto (600), nunca laranja claro
 * (2,88:1); no hover, sublinhado em --c-acento-ativo. Foco de teclado no
 * título e na miniatura clicáveis = o contorno de sempre (--foco-cor, com
 * folga), igual em todas as listas — nunca o halo --sombra-foco (1,48:1).
 * Lista cortada sem paginação: .lista-corte logo acima dela.
 */
.tabela {
  width: 100%;
  border-collapse: collapse;
  border-spacing: 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  color: var(--c-texto);
}
.tabela th,
.tabela td {
  padding: var(--tabela-respiro-v) var(--tabela-respiro-h);
  text-align: left;
  border-bottom: 1px solid var(--c-borda);
}
.tabela th {
  font-weight: 600;
  color: var(--c-texto-2);
  background: var(--c-bg-muted);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-wide);
}
.tabela thead th {
  border-bottom-color: var(--c-borda-forte);
}
.tabela th.num {
  text-align: right;
}
/* Botão na célula no meio da linha (sem a sobra da linha de base do texto). */
.tabela td .btn {
  vertical-align: middle;
}
.tabela tbody tr {
  transition: background var(--t-rapida);
}
.tabela tbody tr:hover {
  background: var(--c-bg-hover);
}
.tabela tbody tr:is(:hover, :focus-within) > td:first-child:not([colspan]) {
  box-shadow: inset var(--selecao-filete) 0 0 var(--selecao-cor);
}
.tabela--zebra tbody tr:nth-child(even) {
  background: var(--c-bg-muted);
}
.tabela--zebra tbody tr:nth-child(even):hover {
  background: var(--c-bg-hover);
}
/* Fixo no topo da área que rola (a moldura da área fica acima do ponto de
   parada, por isso o topo negativo). z-index 1: acima das linhas e abaixo dos
   menus (--z-dropdown). Com border-collapse a borda não acompanha o th fixo —
   a linha de baixo é desenhada pela sombra. */
.tabela--sticky thead th {
  position: sticky;
  top: calc(-1 * var(--moldura-tela));
  z-index: 1;
  box-shadow: inset 0 -1px 0 var(--c-borda-forte);
}
.tabela--miniatura tbody tr {
  height: var(--lista-mini-linha);
}
.tabela--miniatura td {
  padding-block: var(--lista-mini-respiro);
}
.tabela__miniatura {
  display: block;
  /* Não encolhe: com o `img { max-width: 100% }` que quase toda ferramenta tem
     na base, a foto não segura a largura de uma coluna estreita (ex.: 1%) e,
     quando TODA linha tem foto, a coluna encolhe até o padding e as fotos
     somem (0px) — defeito real da mãe (EncarteLab 7.2.0, 25/09). */
  max-width: none;
  max-height: var(--lista-mini-altura);
}
.tabela td.num {
  font-family: var(--fam-mono);
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;              /* o número não quebra ("R$ 1.234,56", "+12,3%") */
}

/* ---------- Tabela: ordenação, linha de total e valor ausente ----------
 * Ordenação pelo cabeçalho: um botão por título de coluna e o estado no
 * atributo aria-sort do <th> ("ascending" | "descending" | "none").
 *   <th aria-sort="none"><button type="button" class="tabela__ordenar">Preço
 *     <span class="icone tabela__ordem" aria-hidden="true">[svg chevrons-up-down]</span></button></th>
 *   - a seta da coluna que ordena fica no laranja escuro (marca de seleção:
 *     "é por ela"); as outras, apagadas. Número ordena do maior para o menor
 *     no 1º clique; texto, de A a Z. Vazios sempre no fim.
 * Linha de total: <tfoot><tr><td>Total</td>…</tr></tfoot> — peso 600, fundo
 *   sutil e o filete forte em cima (separa a soma das linhas).
 * Valor ausente: <span class="vazio">—</span> (--c-texto-3, como na ficha).
 *   Quando a AUSÊNCIA é informação (ex.: "null" = nenhum pedido), dê cor de
 *   estado: .vazio--erro / .vazio--aviso (escurecida e 600, como os selos).
 * Valor que abre um detalhe (ex.: o número de pedidos abre a lista deles):
 *   <button type="button" class="link link--sublinhado">724</button> na
 *   célula — o .link do DS, com algarismos de mesma largura.
 */
.tabela tfoot td {
  font-weight: 600;
  background: var(--c-bg-muted);
  border-top: 1px solid var(--c-borda-forte);
  border-bottom: 0;
}
.tabela__ordenar {
  display: inline-flex;
  align-items: center;
  gap: var(--esp-1);
  padding: 0;
  margin: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}
.tabela__ordenar:hover {
  color: var(--c-texto);
}
.tabela__ordenar:focus-visible {
  outline: var(--foco-largura) solid var(--foco-cor);
  outline-offset: var(--foco-folga);
  border-radius: var(--raio-sm);
}
.tabela__ordem {
  width: 0.875rem;                  /* 14px: acompanha o título de 12px em maiúsculas */
  height: 0.875rem;
  opacity: 0.5;
}
.tabela th[aria-sort="ascending"] .tabela__ordem,
.tabela th[aria-sort="descending"] .tabela__ordem {
  opacity: 1;
  color: var(--selecao-cor);        /* marca de seleção: a coluna que ordena */
}
.tabela td .link {
  font-variant-numeric: tabular-nums;
  text-align: inherit;              /* nome longo quebra alinhado como o resto da coluna */
}
.vazio {
  font-weight: 400;
  color: var(--c-texto-3);          /* o traço "—": SÓ ele usa o terciário */
}
.vazio--erro {
  font-weight: 600;
  color: color-mix(in srgb, var(--c-erro) 65%, var(--c-texto));
}
.vazio--aviso {
  font-weight: 600;
  color: color-mix(in srgb, var(--c-aviso) 65%, var(--c-texto));
}
/* position: relative segura o .visually-hidden do th (absoluto): sem ancestral
   posicionado ele escapava da área que rola e alargava a página no celular. */
.tabela-area {
  container: tabela / inline-size;
  position: relative;
  min-width: 0;
}
/* 720px: o limite de container query não lê variável. */
@container tabela (max-width: 720px) {
  .tabela th,
  .tabela td {
    padding-inline: var(--esp-2);
  }
  .tabela .tabela__apoio {
    display: none;
  }
}


/* ============================================================================
 * 5. NAVEGAÇÃO LATERAL — .sidebar (opt-in)
 * ----------------------------------------------------------------------------
 * O componente cuida do MIOLO do menu lateral: marca, lista de itens com a
 * marca de seleção, grupo no fim da lista, rodapé sempre visível, submenu
 * flutuante e o estado recolhido.
 *
 * NÃO IMPÕE O LAYOUT DA PÁGINA. O grid menu + conteúdo, a LARGURA do menu (a
 * mãe usa 240px expandido e 64px recolhido), a altura da página e quem rola
 * continuam decisão de cada ferramenta. O .sidebar só ocupa a altura do lugar
 * que a ferramenta reservou para ele (height: 100%) e rola a própria lista.
 * [SE EDITOR] a largura do menu define a área do editor: não muda por
 * densidade.
 *
 * Exemplo de layout (fica NA FERRAMENTA, não neste arquivo):
 *   .app       { display: grid; grid-template-columns: 15rem minmax(0, 1fr); height: 100vh; }
 *   [data-sidebar="recolhida"] .app { grid-template-columns: 4rem minmax(0, 1fr); }
 *   .app__main { padding: var(--moldura-tela); overflow-y: auto; }
 *
 * <aside class="sidebar" aria-label="Navegação principal">
 *   <div class="sidebar__marca">
 *     <span class="sidebar__marca-mono" aria-hidden="true">F</span>
 *     <span class="sidebar__marca-nome">Ferramenta</span>
 *   </div>                                                  (o selo de versão fica no menu da conta)
 *   <nav class="sidebar__lista" aria-label="Módulos">
 *     <button type="button" class="sidebar__item sidebar__item--ativo" aria-current="page">
 *       <span class="sidebar__item-icone" aria-hidden="true">[svg Lucide]</span>
 *       <span class="sidebar__item-rotulo">Início</span>
 *     </button>
 *     <button type="button" class="sidebar__item">…</button>
 *     <div class="sidebar__lista-fim">                       ← grupo no FIM da lista
 *       <button type="button" class="sidebar__item">…</button>
 *     </div>
 *   </nav>
 *   <div class="sidebar__rodape">                             ← sempre visível
 *     <button type="button" class="sidebar__item sidebar__rodape-item" id="alternador-tema">
 *       <span class="sidebar__item-icone" data-tema-icone aria-hidden="true">[svg lua]</span>
 *       <span class="sidebar__item-rotulo" data-tema-rotulo>Modo escuro</span>
 *     </button>                                              ← botão de tema: mostra a AÇÃO
 *     <div class="sidebar__submenu">…(ver submenu flutuante)…</div>
 *     <div class="sidebar__submenu">…menu da conta (mesmo painel)…</div>
 *     <button type="button" class="sidebar__recolher" aria-label="Recolher menu"
 *             aria-expanded="true">[svg ‹ 16px]</button>
 *   </div>
 * </aside>
 *
 * Itens de 32px (--ctrl-altura), ícone de 20px e rótulo de 14px/500 em
 * --c-texto-2; hover --item-hover. Itens podem ser <button> (roteador em JS)
 * ou <a href>: o visual é o mesmo.
 * BOTÃO DE TEMA = mostra a AÇÃO: no tema claro, lua + "Modo escuro"; no
 * escuro, sol + "Modo claro". O JS troca o ícone ([data-tema-icone]) e o texto
 * ([data-tema-rotulo]) a cada clique. O nome acessível é o próprio texto: sem
 * aria-label e SEM aria-pressed (botão cujo texto muda com o estado não usa
 * aria-pressed). Com o menu recolhido, a dica (title) acompanha a troca.
 * ITEM ATIVO = marca de seleção: .sidebar__item--ativo SEMPRE junto com
 * aria-current="page" — fundo --c-acento-bg, texto --c-texto, filete de 3px
 * e ícone em --selecao-cor, SEM negrito (o negrito corta o rótulo longo
 * justamente quando ele é a tela atual). O hover não vale no ativo. Numa
 * janela baixa, role a lista só o necessário até o item atual, mexendo SÓ no
 * scrollTop da .sidebar__lista (conta com getBoundingClientRect; nada a fazer
 * se a lista não rola ou está oculta). Não use scrollIntoView: além de rolar,
 * ele leva o ponto de partida do Tab para o item, e o 1º Tab da tela pula o
 * começo do menu.
 * ========================================================================== */
.sidebar {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  overflow: hidden;
  background: var(--c-bg-elev);
  border-right: 1px solid var(--c-borda);
  color: var(--c-texto);
}

/* ---------- Marca no topo: monograma + nome (+ selo de versão) ----------
   48px: 12px em cima, 8px embaixo (o respiro de 8px da lista completa a
   distância até o 1º item). Recuo esquerdo de 24px = 12 da lista + 12 do
   item: o monograma alinha com os ícones do menu. */
.sidebar__marca {
  display: flex;
  align-items: center;
  gap: var(--esp-2);
  min-height: 3rem;
  padding: var(--esp-3) var(--esp-3) var(--esp-2) var(--esp-6);
}
.sidebar__marca-mono {
  flex: none;
  width: 1.75rem;
  height: 1.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--raio-md);
  background: var(--c-acento);
  color: var(--c-acento-texto);
  font-weight: 800;
  font-size: var(--fs-sm);
  line-height: 1;
}
.sidebar__marca-nome {
  font-weight: 700;
  font-size: var(--fs-md);
  letter-spacing: var(--ls-tight);
  color: var(--c-texto);
  white-space: nowrap;
}

/* ---------- Lista: rola quando a janela é baixa; o rodapé nunca some ---------- */
.sidebar__lista {
  position: relative;         /* contém o rótulo oculto da sidebar recolhida: sem isto ele
                                 escapava da lista que rola e fazia a PÁGINA rolar */
  display: flex;
  flex-direction: column;
  gap: var(--esp-1);
  padding: var(--esp-2) var(--esp-3);
  flex: 1;
  min-height: 0;              /* deixa a lista encolher e rolar dentro do menu */
  overflow-y: auto;
}
/* Grupo no FIM da lista, logo acima da linha do rodapé (sem linha nova entre
   os grupos). Quando a lista rola, a margem vira 0 e o grupo vem logo depois. */
.sidebar__lista-fim {
  display: flex;
  flex-direction: column;
  gap: var(--esp-1);
  margin-top: auto;
}

.sidebar__item {
  display: flex;
  align-items: center;
  gap: var(--esp-3);
  width: 100%;
  min-height: var(--ctrl-altura);   /* 32px */
  /* 12px à esquerda (alinha o ícone com a marca) e 8px à direita: sobra mais
     espaço para o rótulo nos 240px. */
  padding: var(--esp-1) var(--esp-2) var(--esp-1) var(--esp-3);
  margin: 0;
  border: none;
  background: transparent;
  border-radius: var(--raio-md);
  color: var(--c-texto-2);
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: var(--lh-tight);
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-rapida), color var(--t-rapida);
}
/* Item escondido por permissão com o atributo hidden (o display:flex venceria). */
.sidebar__item[hidden] { display: none; }
/* Hover que se enxerga e que NÃO vale no item ativo: a marca não some no hover. */
.sidebar__item:hover:not(:disabled):not(.sidebar__item--ativo) {
  background: var(--item-hover);
  color: var(--c-texto);
  text-decoration: none;
}
.sidebar__item:disabled {
  color: var(--c-texto-3);
  cursor: not-allowed;
}
/* Foco de teclado por DENTRO do item: a lista rola (overflow) e cortaria um
   contorno de fora. */
.sidebar__item:focus-visible {
  outline: var(--foco-largura) solid var(--foco-cor);
  outline-offset: calc(-1 * var(--foco-largura));
}
/* Item ativo = marca de seleção (duas classes: vence o a:hover da base). */
.sidebar__item.sidebar__item--ativo {
  background: var(--c-acento-bg);
  color: var(--c-texto);
  box-shadow: inset var(--selecao-filete) 0 0 var(--selecao-cor);
}
.sidebar__item--ativo .sidebar__item-icone {
  color: var(--selecao-cor);
}

.sidebar__item-icone {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
}
.sidebar__item-icone svg { display: block; width: 100%; height: 100%; }

/* Rótulo em bloco: nome longo termina em "…" em vez de ser cortado seco (rede
   de segurança; os nomes devem caber). */
.sidebar__item-rotulo {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------- Rodapé: sempre visível, separado por uma linha ---------- */
.sidebar__rodape {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--esp-1);
  padding: var(--esp-2) var(--esp-3);
  border-top: 1px solid var(--c-borda);
}
/* Itens do rodapé com ícone de 24px (cabe um avatar). Com 4px em cima e
   embaixo ficam nos mesmos 32px dos itens da lista; a margem negativa de 2px
   de cada lado faz o ícone ocupar o lugar de um de 20px — centro do ícone e
   início do rótulo alinham com os da lista. */
.sidebar__rodape-item .sidebar__item-icone {
  width: 1.5rem;
  height: 1.5rem;
  margin-inline: calc((1.25rem - 1.5rem) / 2);   /* (20 − 24) / 2 = −2px */
}

/* Recolher/expandir: 28px (valor aprovado na mãe: 2px acima do .btn-pequeno,
   porque é o único botão que reabre o menu recolhido). */
.sidebar__recolher {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 1.75rem;
  margin: 0;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: var(--raio-md);
  color: var(--c-texto-2);
  cursor: pointer;
  transition: background var(--t-rapida), color var(--t-rapida);
}
.sidebar__recolher:hover {
  background: var(--item-hover);
  color: var(--c-texto);
}
.sidebar__recolher:focus-visible {
  outline: var(--foco-largura) solid var(--foco-cor);
  outline-offset: calc(-1 * var(--foco-largura));
}
.sidebar__recolher svg {
  display: block;
  width: 16px;
  height: 16px;
  transition: transform var(--t-padrao);
}

/* ---------- Submenu flutuante (.sidebar__submenu + .sidebar__flutuante) ----------
 * Um grupo de telas (ex.: Configurações → Empresa, Usuários, Plano) NÃO vira
 * acordeão que empurra a lista para baixo: vira um MENU FLUTUANTE IGUAL ao
 * menu da conta ("Minha conta") — decisão da mãe (EncarteLab 7.2.0, 25/09).
 * Os dois menus do rodapé são o mesmo componente, no mesmo lugar (logo ACIMA
 * do próprio botão, alinhado à esquerda dele) e com os mesmos itens: SÓ TEXTO
 * (8px 12px, 14px/400, 33,5px), sem ícone nos itens e sem seta no botão.
 * Quando a tela atual é FILHA do submenu, o item dentro do painel E o próprio
 * botão recebem a marca de item ativo (.sidebar__item--ativo; no botão, com
 * aria-current="true") — com o painel fechado, o botão é a pista de onde a
 * pessoa está.
 *
 * <div class="sidebar__submenu">
 *   <button type="button" class="sidebar__item sidebar__rodape-item" id="cfg-botao"
 *           aria-haspopup="menu" aria-expanded="false" aria-controls="cfg-painel">
 *     <span class="sidebar__item-icone" aria-hidden="true">[svg engrenagem]</span>
 *     <span class="sidebar__item-rotulo">Configurações</span>
 *   </button>
 *   <div class="sidebar__flutuante" id="cfg-painel" role="menu" aria-label="Configurações" hidden>
 *     <button type="button" class="sidebar__item" role="menuitem">
 *       <span class="sidebar__item-rotulo">Empresa</span>
 *     </button>
 *   </div>
 * </div>
 *
 * Menu da conta — o mesmo painel, com um cabeçalho (nome, e-mail e o SELO DE
 * VERSÃO da ferramenta) e um separador antes dos itens:
 * <div class="sidebar__submenu">
 *   <button type="button" class="sidebar__item sidebar__rodape-item" id="conta-botao"
 *           aria-haspopup="menu" aria-expanded="false" aria-controls="conta-painel">…Minha conta…</button>
 *   <div class="sidebar__flutuante" id="conta-painel" role="menu" aria-label="Minha conta" hidden>
 *     <div class="sidebar__conta">
 *       <strong class="sidebar__conta-nome">Nome da pessoa</strong>
 *       <span class="sidebar__conta-email">pessoa@empresa.com.br</span>
 *       <span class="sidebar__conta-versao">Versão <span class="badge badge-acento">12</span></span>
 *     </div>
 *     <hr class="sidebar__flutuante-separador">
 *     <button type="button" class="sidebar__item" role="menuitem">
 *       <span class="sidebar__item-rotulo">Alterar senha</span>
 *     </button>
 *   </div>
 * </div>
 *
 * Comportamento (JS da ferramenta; o CSS só desenha):
 *   - position: fixed (escapa da rolagem do menu); o JS posiciona pelo CSSOM
 *     (painel.style.left / .bottom — permitido pela CSP): left = borda
 *     esquerda do botão; bottom = altura da janela − topo do botão + 6px (o
 *     painel abre para cima). Nunca sai da janela (8px de folga, a mesma do
 *     max-height).
 *   - clique no botão abre/fecha; ao abrir, foco no 1º item; ↑/↓ circulares,
 *     Home/End; Esc fecha e devolve o foco ao botão; Tab e clique fora fecham;
 *     escolher um item fecha; trocar de tela fecha; só um aberto por vez;
 *     aria-expanded acompanha o estado.
 *   - dentro do painel os itens aparecem com o nome e em --c-texto, mesmo com
 *     o menu recolhido.
 */
.sidebar__flutuante {
  position: fixed;
  z-index: var(--z-dropdown);
  min-width: 14rem;
  max-width: calc(100vw - 2 * var(--esp-2));
  max-height: calc(100vh - 2 * var(--esp-2));
  overflow-y: auto;
  padding: var(--esp-1);
  background: var(--c-bg-elev);
  border: 1px solid var(--c-borda);
  border-radius: var(--raio-lg);
  box-shadow: var(--sombra-lg);
  display: flex;
  flex-direction: column;
  gap: var(--esp-1);
}
.sidebar__flutuante[hidden] { display: none; }
/* Itens do painel: só texto, nas mesmas medidas nos dois menus do rodapé. */
.sidebar__flutuante .sidebar__item {
  min-height: 0;
  padding: var(--esp-2) var(--esp-3);   /* 8 + 17,5 + 8 = 33,5px */
  font-weight: 400;
  color: var(--c-texto);
}
.sidebar__flutuante-separador {
  margin: var(--esp-1) 0;
  border: none;
  border-top: 1px solid var(--c-borda);
}
/* Cabeçalho do menu da conta: nome, e-mail e o selo de versão. */
.sidebar__conta {
  display: flex;
  flex-direction: column;
  gap: var(--esp-1);
  padding: var(--esp-2) var(--esp-3);
}
.sidebar__conta-nome {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--c-texto);
}
.sidebar__conta-email {
  font-size: var(--fs-xs);
  color: var(--c-texto-2);
  word-break: break-all;
}
.sidebar__conta-versao {
  display: flex;
  align-items: center;
  gap: var(--esp-2);
  font-size: var(--fs-xs);
  color: var(--c-texto-2);
}

/* ---------- Recolhida ----------
 * data-sidebar="recolhida" no <html> (recomendado: um script síncrono no
 * <head> aplica antes do 1º paint, sem piscar) ou no próprio .sidebar.
 * O item centraliza o ícone (marca, lista e rodapé no MESMO eixo) e o rótulo
 * fica VISUALMENTE oculto — mesmo padrão do .visually-hidden, nunca
 * display:none: continua dando nome ao botão para leitor de tela e comando
 * de voz. A dica ao passar o mouse é o title com o nome, que o JS da
 * ferramenta põe em cada item (fora do painel) e no botão de recolher. A marca
 * fica só com o monograma. Dentro do painel flutuante o nome aparece.
 */
[data-sidebar="recolhida"] .sidebar__marca {
  justify-content: center;
  padding-left: 0;
  padding-right: 0;
}
[data-sidebar="recolhida"] .sidebar__marca > :not(.sidebar__marca-mono) {
  display: none;
}
[data-sidebar="recolhida"] .sidebar__item:not(.sidebar__flutuante *) {
  justify-content: center;
  padding-inline: var(--esp-3);   /* recuo simétrico: o ícone fica no eixo da coluna */
}
[data-sidebar="recolhida"] .sidebar__item-rotulo:not(.sidebar__flutuante *) {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
[data-sidebar="recolhida"] .sidebar__recolher svg {
  transform: rotate(180deg);
}


/* ============================================================================
 * 6. UTILITÁRIOS
 * ========================================================================== */

/* ---------- .visually-hidden — texto só para leitor de tela ----------
 * <th><span class="visually-hidden">Miniatura</span></th> */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- .previa-xadrez ----------
 * Fundo quadriculado para prévias de imagem com TRANSPARÊNCIA. Aplicar atrás
 * de um <img object-fit: contain>. Quando a prévia está VAZIA, a
 * .upload-zona__previa--vazia (peso 0,2,0) tira o xadrez e mostra "Sem foto". */
.previa-xadrez {
  background-color: var(--c-bg);
  background-image:
    linear-gradient(45deg, var(--c-bg-muted) 25%, transparent 25% 75%, var(--c-bg-muted) 75%),
    linear-gradient(45deg, var(--c-bg-muted) 25%, transparent 25% 75%, var(--c-bg-muted) 75%);
  background-size: 16px 16px;
  background-position: 0 0, 8px 8px;
}


/* ---------- .tecla — tecla de atalho ----------
 * <kbd class="tecla">/</kbd> — ex.: o atalho da busca, dentro do campo. */
.tecla {
  display: inline-block;
  padding: 1px var(--esp-1);
  font-family: var(--fam-mono);
  font-size: var(--fs-xs);
  line-height: 1rem;
  color: var(--c-texto-2);
  background: var(--c-bg);
  border: 1px solid var(--c-borda-forte);
  border-bottom-width: 2px;         /* a "altura" da tecla */
  border-radius: var(--raio-sm);
}

/* ============================================================================
 * 7. MOVIMENTO REDUZIDO
 * ----------------------------------------------------------------------------
 * Sem regra global: só os componentes deste arquivo que animam param de
 * animar quando a pessoa pede menos movimento no sistema.
 * ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .btn, .input, .select, .textarea, .opcao-cartao, .upload-zona, .aba,
  .tabela tbody tr, .toast, .modal-backdrop, .modal, .resultado,
  .sidebar__item, .sidebar__recolher, .sidebar__recolher svg {
    transition: none;
    animation: none;
  }
}
