/*
  Skirret — Tema "Pedra Bruta": COMPONENTES do produto
  ===================================================
  Todas as cores vivem em variáveis CSS (custom properties), nunca em
  valores fixos espalhados pelas regras abaixo. Isso é proposital: um
  Tema publicado (`docs/37` §5) sobrescreve tokens e a interface inteira
  se adapta, sem tocar em nenhum componente individual.

  **O bloco `:root` NÃO mora mais aqui** — saiu para `tokens.css` em
  26/08/2026 (Prompt #201, R11 do `docs/59`). Este arquivo traz os
  COMPONENTES DO PRODUTO: as telas autenticadas, com tema, escala de
  fonte e densidade. O site público tem os seus em `landing.css`, e os
  dois consomem os MESMOS tokens.

  A separação é de contexto, não de estilo: o visitante não está
  autenticado, não tem tema nem preferência, e a cadeia de herança de
  quatro níveis do `docs/37` é peso morto para ele.

  Ver `docs/Brand_Guidelines_Skirret.md` para o simbolismo de cada cor.
*/

/* BASE TIPOGRÁFICA: 20px, não 16px (Prompt #147 — decisão de Wagner de
   17/08/2026).

   O zoom de 125% era o tamanho em que Wagner validava todas as telas, e
   passou a ser o padrão. A conta é direta: 16px × 125% = **20px**. Com a
   base em 20px, a escala de 100% renderiza exatamente o que hoje se
   obtém em 125%.

   O QUE NÃO SE FEZ, e o motivo. A saída fácil seria renomear o rótulo —
   fazer o controle exibir "100%" enquanto aplica o fator 125. Isso
   quebraria a semântica de tudo o que depende do número: o valor gravado
   em `Usuario.escala_fonte` deixaria de significar o que diz, e a próxima
   pessoa a ler `--sk-escala-fonte: 100` no DOM concluiria que está no
   tamanho de fábrica. Aqui a escala continua sendo multiplicação sobre a
   base; **só a base cresceu**.

   POR QUE O ESPAÇAMENTO EM px NÃO FOI CONVERTIDO JUNTO. Padding, gap,
   margin e bordas continuam em px de propósito. A referência visual é o
   125% de HOJE, onde esses mesmos px já convivem com texto de 20px — a
   base nova reproduz aquele rendering pixel por pixel. Converter o
   espaçamento para `rem` agora mudaria justamente o que foi validado.
   Bordas de 0,5–1px, então, nunca escalam: uma linha de 1,25px é uma
   linha borrada.

   EMENDA DO PROMPT #177 — a base virou TOKEN. O `20px` fixo saiu daqui e
   virou `--sk-base-fonte`, parametrizável por Tema na MASTER-08. O
   mecanismo já era este desde o #147; o que mudou foi a constante virar
   variável. **O fallback `20px` fica de propósito:** um Tema antigo que
   não traga o token continua renderizando exatamente como hoje, em vez
   de colapsar para o `font-size` do navegador.

   E a composição é de UM eixo só: o Tema dá a base, o usuário multiplica
   por cima dela. Os dois nunca se multiplicam entre si — `docs/37` §8.1
   registra o que foi recusado e por quê. */
html {
  font-size: calc(var(--sk-base-fonte, 20px) * var(--sk-escala-fonte) / 100);
}

* {
  box-sizing: border-box;
}

/* Cabeçalho/rodapé fixos, rolagem só em .sk-main (docs/14, Prompt #60) —
   flexbox em coluna, com só o miolo (.sk-main) rolável, é o único jeito de
   garantir as duas exigências ao mesmo tempo: cabeçalho/rodapé nunca se
   movem (nem "sticky", que só gruda ao rolar — aqui eles não fazem parte
   de nenhuma área rolável pra começo de conversa) E o rodapé permanece no
   fim da viewport mesmo com conteúdo mais curto que a tela (um `position:
   sticky`/`fixed` isolado não resolveria esse segundo caso sem o mesmo
   truque de flex/grid por baixo). Revertido em @media print, abaixo — um
   `.sk-artigo-para-imprimir` mais alto que 100vh não pode ficar cortado
   pelo `overflow: hidden` daqui. */
body {
  background: var(--sk-bg);
  color: var(--sk-fg);
  font-family: var(--sk-font-body);
  font-size: 0.875rem;
  line-height: 1.6;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
}

a {
  color: var(--sk-gold);
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}

h1, h2, h3 {
  font-family: var(--sk-font-display);
  font-weight: 500;
  margin: 0 0 0.5em;
}

/* Componentes nativos do navegador (<select>/<option>) — o navegador nem
   sempre herda o tema da página ao renderizar a lista de opções aberta,
   caindo de volta no padrão do SO (geralmente claro), o que quebra a
   legibilidade sobre o tema escuro. Regra global (não pontual a nenhuma
   tela) e com cor sólida (nunca `rgba` translúcido, que não compõe
   corretamente com o popup nativo) — docs/14, princípio 10. */
select {
  background-color: var(--sk-surface-solid);
  color: var(--sk-fg);
}
select option {
  background-color: var(--sk-surface-solid);
  color: var(--sk-fg);
}

/* ---------- Layout ---------- */

/* Cabeçalho em 2 colunas (docs/14, Prompt #60) — coluna 1 (hambúrguer +
   logomarca) e coluna 2 (a partir da metade do cabeçalho: avisos/alertas
   + "Sair" na extrema direita) via grid 1fr/1fr, nunca flex+space-between
   puro — isso garante que a coluna 2 sempre começa exatamente na metade
   do cabeçalho, mesmo quando a coluna 1 é bem mais estreita que ela. */
.sk-header {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: var(--e4);
  padding: var(--e4) var(--e6);
  border-bottom: 0.5px solid var(--sk-border);
  flex: 0 0 auto;
}

.sk-logo {
  height: 40px;
  width: auto;
  display: block;
}

.sk-logo-link {
  display: block;
  line-height: 0;
}
.sk-logo-link:focus-visible {
  outline: 2px solid var(--sk-gold);
  outline-offset: 2px;
}

.sk-header-esquerda {
  display: flex;
  align-items: center;
  gap: var(--e4);
}

/* Coluna 2 — avisos/alertas (à esquerda desta coluna, crescendo) + "Sair"
   sempre colado na extrema direita do cabeçalho. */
.sk-header-direita {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e4);
}

.sk-header-avisos {
  display: flex;
  flex-direction: column;
  gap: var(--e1);
  flex: 1 1 auto;
  min-width: 0;
}
.sk-header-aviso {
  display: flex;
  align-items: center;
  gap: var(--e2);
  font-size: 0.75rem;
  padding: var(--e2) var(--e3);
  border-radius: var(--sk-radius-sm);
  background: rgba(99, 153, 34, 0.1);
  border: 0.5px solid rgba(99, 153, 34, 0.3);
  color: var(--sk-success-fg);
  opacity: 1;
  /* Restauração RÁPIDA (esta) x esmaecimento LENTO (na classe abaixo):
     quem aponta para a mensagem quer lê-la agora, então voltar à nitidez
     é quase imediato; o desaparecer continua suave para não piscar
     (Prompt #112). */
  transition: opacity 150ms ease;
}
.sk-header-aviso-texto {
  flex: 1 1 auto;
  min-width: 0;
}
.sk-header-aviso--esmaecido {
  opacity: 0.35;
  transition: opacity 1s ease;
}
/* Apontar ou focar restaura a nitidez plena (Prompt #112). O JS também
   remove a classe e congela o cronômetro — estas regras são a defesa em
   profundidade: sem elas, um segundo de transição pendente ainda deixaria
   a mensagem apagada sob o cursor. `:focus-within` cobre a navegação por
   teclado, inclusive quando o foco está no botão de fechar. */
.sk-header-aviso--esmaecido:hover,
.sk-header-aviso--esmaecido:focus-within {
  opacity: 1;
  transition: opacity 150ms ease;
}
/* Renomeadas de ".error"/".warning" (achado do Catálogo Vivo, MASTER-24,
   Prompt #185/#186): a mesma classe bare ".error" também é o seletor de
   erro de validação do abas-form.js (SELETORES_DE_ERRO, docs/14
   Princípio 19) — um aviso de topo com essa classe, se algum dia caísse
   dentro de um `.sk-aba-form-conteudo`, seria lido como erro de
   formulário sem ter nada a ver com validação. Investigado (Prompt #186):
   nenhuma tela real combina as duas coisas hoje (o aviso de cabeçalho
   vive sempre no <header>, fora de qualquer `.sk-aba-form-conteudo`) —
   defeito latente, não em produção. Corrigido pelo lado de MENOR risco:
   o mecanismo de validação (abas-form.js) é código compartilhado,
   testado e com histórico (Prompt #126); o aviso de cabeçalho é decoração
   de uma faixa, e já tinha precedente de nome namespaced no mesmo
   componente (`sk-header-aviso--esmaecido`, algumas linhas acima) — só
   faltava estender o mesmo padrão a estes dois. */
.sk-header-aviso--error {
  background: rgba(192, 57, 43, 0.1);
  border-color: rgba(192, 57, 43, 0.3);
  color: var(--sk-danger-fg);
}
.sk-header-aviso--warning {
  background: rgba(201, 168, 76, 0.12);
  border-color: rgba(201, 168, 76, 0.35);
  color: var(--sk-warning-fg);
}
/* Fechar manual — erro/aviso não esmaecem sozinhos (decisão de
   13/08/2026, Prompt #60), então precisam de uma saída explícita. Mesmo
   glyph "×" do botão de fechar do modal de Help (`sk-help-modal-fechar`). */
.sk-header-aviso-fechar {
  flex: 0 0 auto;
  background: none;
  border: none;
  color: inherit;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
}
.sk-header-aviso-fechar:hover {
  opacity: 0.7;
}

.sk-header-sair-form {
  flex: 0 0 auto;
}
.sk-header-sair-btn {
  background: none;
  border: none;
  color: var(--sk-fg);
  font-size: 0.8125rem;
  cursor: pointer;
  padding: var(--e1) var(--e2);
}
.sk-header-sair-btn:hover {
  color: var(--sk-gold);
}

/* Painel do sino de Notificações (docs/60 §6.1, Prompt #196). Nenhum
   primitivo de painel flutuante/popover existia no docs/59 no momento
   desta tarefa (só o menu do Combobox, que é um caso mais estreito) —
   construído LOCAL de propósito, sem virar primitivo novo. */
.sk-notificacoes {
  position: relative;
  flex: 0 0 auto;
}
.sk-notificacoes-sino {
  position: relative;
  background: none;
  border: none;
  color: var(--sk-fg);
  font-size: 1.125rem;
  line-height: 1;
  cursor: pointer;
  padding: var(--e1) var(--e2);
}
.sk-notificacoes-sino:hover {
  color: var(--sk-gold);
}
.sk-notificacoes-contador {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 16px;
  height: 16px;
  padding: 0 var(--e1);
  border-radius: 999px;
  background: var(--sk-orange);
  color: var(--sk-fg);
  font-size: 0.625rem;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}

/* Ancorado no sino (docs/60 §6.1) — nunca gaveta nem tela cheia. O
   `overflow-y` fica no CORPO, não neste invólucro: a lição do #183 foi
   que `overflow` num ancestral mata `position: sticky`/comportamento
   fixo do que está dentro — aqui não há `sticky`, mas o cabeçalho do
   painel precisa continuar fixo enquanto só o corpo rola, e isso exige a
   mesma separação de responsabilidade entre invólucro e área que rola. */
.sk-notificacoes-painel {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 30;
  margin-top: var(--e2);
  width: 340px;
  max-width: calc(100vw - 24px);
  max-height: 420px;
  display: flex;
  flex-direction: column;
  background: var(--sk-surface-solid);
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
}
/* `display: flex` acima bate em especificidade com o `[hidden] {
   display: none }` do UA stylesheet (mesma especificidade, autor vence)
   — sem esta regra, o atributo `hidden` do JS não escondia nada. */
.sk-notificacoes-painel[hidden] {
  display: none;
}
.sk-notificacoes-painel-cabecalho {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e2);
  padding: var(--e3) var(--e4);
  border-bottom: 0.5px solid var(--sk-border);
}
.sk-notificacoes-painel-titulo {
  font-family: var(--sk-font-display);
  font-size: 0.9375rem;
  color: var(--sk-fg);
}
.sk-notificacoes-marcar-todas-form {
  flex: 0 0 auto;
}
.sk-notificacoes-marcar-todas-btn {
  background: none;
  border: none;
  color: var(--sk-gold);
  font-size: 0.6875rem;
  cursor: pointer;
  padding: 2px;
}
.sk-notificacoes-marcar-todas-btn:hover {
  text-decoration: underline;
}

/* A lista rola DENTRO do painel — o `overflow-y` vive só aqui, nunca no
   `.sk-notificacoes-painel` acima, para o cabeçalho ficar fixo. */
.sk-notificacoes-painel-corpo {
  flex: 1 1 auto;
  overflow-y: auto;
}
.sk-notificacoes-grupo-titulo {
  padding: var(--e3) var(--e4) var(--e1);
  font-size: 0.625rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--sk-muted);
}
.sk-notificacao {
  display: flex;
  align-items: flex-start;
  gap: var(--e2);
  padding: var(--e2) var(--e4);
  text-decoration: none;
  color: var(--sk-fg);
}
.sk-notificacao:hover {
  background: color-mix(in srgb, var(--sk-fg) 6%, var(--sk-bg));
}
/* Duas pistas para o mesmo estado (docs/60 §6.1) — cor sozinha falha
   para quem não a distingue. A bolinha é a primeira pista; o negrito do
   título (abaixo) é a segunda. */
.sk-notificacoes-bolinha {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  margin-top: var(--e1);
  border-radius: 50%;
  background: var(--sk-orange);
}
.sk-notificacao-corpo {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.sk-notificacao-titulo {
  font-size: 0.8125rem;
  color: var(--sk-fg);
}
.sk-notificacao--nao-lida .sk-notificacao-titulo {
  font-weight: 700;
}
.sk-notificacao-texto {
  font-size: 0.75rem;
  color: var(--sk-muted);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.sk-notificacao-tempo {
  flex: 0 0 auto;
  font-size: 0.625rem;
  color: var(--sk-muted);
  white-space: nowrap;
}

.sk-notificacoes-vazio {
  padding: var(--e6) var(--e5);
  text-align: center;
}
.sk-notificacoes-vazio-titulo {
  margin: 0 0 var(--e1);
  color: var(--sk-fg);
  font-size: 0.8125rem;
}
.sk-notificacoes-vazio-prazo {
  margin: 0;
  color: var(--sk-muted);
  font-size: 0.6875rem;
}

/* Prévia de alcance da tela de envio (docs/60 §6.2 R9, Prompt #197) — "é
   o único freio entre um clique e a tela de todo mundo", e por isso em
   destaque visual, nunca como texto corrido junto dos outros campos.
   Classe própria, não `.sk-faixa-estado`: aquela é o link de bloqueio de
   Loja (posição fixa entre header/main, semântica de aviso) — reaproveitá-
   la aqui seria o mesmo erro que construir primitivo novo sem precisar. */
.sk-notificacoes-prevista {
  margin: var(--e4) 0;
  padding: var(--e4) var(--e5);
  border: 0.5px solid var(--sk-gold);
  border-radius: var(--sk-radius);
  background: color-mix(in srgb, var(--sk-gold) 10%, var(--sk-bg));
  color: var(--sk-fg);
}
.sk-notificacoes-prevista p {
  margin: var(--e1) 0 0;
  color: var(--sk-muted);
  font-size: 0.8125rem;
}

/* Ícone hambúrguer do Menu Principal (docs/20, seção 7). */
.sk-menu-hamburguer {
  background: none;
  border: none;
  color: var(--sk-fg);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  padding: var(--e1) var(--e2);
}
.sk-menu-hamburguer:hover {
  color: var(--sk-gold);
}

/* Painel do Menu Principal (docs/20) — <dialog> ancorado à esquerda, altura
   cheia, ao invés de centralizado na viewport (esse é o comportamento do
   componente de Diálogo/MessageBox, docs/18 — um uso diferente do mesmo
   elemento nativo <dialog>, não o mesmo componente). */
.sk-menu-principal {
  position: fixed;
  inset: 0 auto 0 0;
  margin: 0;
  height: 100%;
  max-height: 100%;
  width: 380px;
  max-width: 92vw;
  padding: 0;
  border: none;
  border-right: 0.5px solid var(--sk-border-strong);
  border-radius: 0;
  background: var(--sk-bg);
  color: var(--sk-fg);
}
.sk-menu-principal[open] {
  display: flex;
  flex-direction: column;
}
.sk-menu-principal::backdrop {
  background: rgba(0, 0, 0, 0.6);
}
.sk-menu-principal-corpo {
  overflow-y: auto;
  padding: var(--e4) var(--e5) var(--e6);
}
.sk-menu-principal-cabecalho {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--e2);
}
.sk-menu-principal-titulo {
  font-family: var(--sk-font-display);
  font-size: 1.125rem;
}
.sk-menu-principal-logo {
  height: 28px;
  width: auto;
  display: block;
}
.sk-menu-principal-categoria {
  border-top: 0.5px solid var(--sk-border);
  padding: var(--e3) 0;
}
.sk-menu-principal-categoria-titulo {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--sk-muted);
  cursor: pointer;
}
.sk-menu-principal-itens {
  list-style: none;
  margin: var(--e2) 0 0;
  padding: 0;
}
.sk-menu-principal-itens a {
  display: block;
  color: var(--sk-fg);
  font-size: 0.875rem;
}

/* Realce por FUNDO no menu (docs/20 §7.1, Prompt #107) — substitui o
   sublinhado/troca de cor do hover pelo padrão de menu de aplicação: a
   linha inteira acende. Vale igualmente para a categoria-mãe (primeiro
   nível), para os itens no flyout do desktop e para os mesmos itens no
   acordeão do touch — a regra é uma só, os três contextos compartilham
   estes seletores.

   O tom vem de color-mix sobre os tokens do Tema (Prompt #106), nunca de
   cor fixa: em Tema escuro clareia, em Tema claro escurece, sempre no
   mesmo passo relativo. Três intensidades, para que hover, foco e item
   ativo permaneçam distinguíveis entre si:
     hover  8%  ·  foco 8% + outline  ·  ativo 14% + peso 600           */
.sk-menu-principal-categoria-titulo,
.sk-menu-principal-itens a {
  padding: var(--e2) var(--e3);
  border-radius: var(--sk-radius-sm);
  transition: background-color 120ms ease;
}
.sk-menu-principal-categoria-titulo:hover,
.sk-menu-principal-itens a:hover {
  background: color-mix(in srgb, var(--sk-fg) 8%, var(--sk-bg));
  /* Sem sublinhado: o fundo é o afordance agora (a regra global de
     `a:hover` continua valendo para links de texto corrido). */
  text-decoration: none;
}
/* Foco de teclado (docs/14, princípio 4 — paridade entre apontar e
   navegar): mesmo realce de fundo do hover, MAIS o indicador de foco
   próprio. O outline nunca é removido em favor do fundo — quem navega
   por Tab precisa distinguir "onde estou" de "onde o mouse passou". */
.sk-menu-principal-categoria-titulo:focus-visible,
.sk-menu-principal-itens a:focus-visible {
  background: color-mix(in srgb, var(--sk-fg) 8%, var(--sk-bg));
  outline: 2px solid var(--sk-gold);
  outline-offset: -2px;
  text-decoration: none;
}
/* Localização (docs/20 §7.1, Prompt #101) — categoria da tela ativa
   marcada (nunca auto-expandida) e item ativo destacado no flyout. O
   ativo é PERMANENTE, então precisa se distinguir do hover, que é
   transitório: fundo mais intenso + peso, além da cor de destaque. */
.sk-menu-categoria-ativa > .sk-menu-principal-categoria-titulo {
  color: var(--sk-gold);
  border-left: 2px solid var(--sk-gold);
  background: color-mix(in srgb, var(--sk-fg) 14%, var(--sk-bg));
}
.sk-menu-principal-itens a.sk-menu-item-ativo {
  color: var(--sk-gold);
  font-weight: 600;
  background: color-mix(in srgb, var(--sk-fg) 14%, var(--sk-bg));
}
/* Passar o mouse sobre o item já ativo não pode ESCURECER o realce (o
   hover é mais fraco que o ativo) — sobe mais um passo. */
.sk-menu-categoria-ativa > .sk-menu-principal-categoria-titulo:hover,
.sk-menu-principal-itens a.sk-menu-item-ativo:hover {
  background: color-mix(in srgb, var(--sk-fg) 20%, var(--sk-bg));
}

/* Flyout de categorias no desktop (docs/20 §7.1, Prompt #101) — só com
   ponteiro fino e hover de verdade (media query, nunca user-agent): as
   filhas da categoria aberta saem do fluxo e flutuam à direita do
   painel. No touch, nada disso se aplica — o <details> nativo expande
   como acordeão abaixo da categoria. */
@media (hover: hover) and (pointer: fine) {
  /* O flyout precisa escapar da caixa do drawer — sem isso, o
     overflow-y:auto do corpo o cortaria na borda direita. A rolagem
     vertical fica no próprio <dialog> (altura cheia; conteúdo do menu é
     curto no desktop). */
  .sk-menu-principal {
    overflow: visible;
  }
  .sk-menu-principal-corpo {
    overflow: visible;
  }
  .sk-menu-principal-categoria {
    position: relative;
  }
  .sk-menu-principal-categoria > .sk-menu-principal-itens {
    position: absolute;
    left: 100%;
    top: 0;
    min-width: 240px;
    margin: 0;
    /* Padding lateral enxuto (era 16px) desde o Prompt #107: o realce de
       fundo de cada item já tem respiro próprio, e um recuo grande no
       container deixaria a faixa acesa estreita demais dentro do
       flyout. */
    padding: var(--e3) var(--e2);
    background: var(--sk-bg);
    border: 0.5px solid var(--sk-border-strong);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
    z-index: 5;
  }
  /* O "›" da categoria acompanha o padding do título (Prompt #107) —
     sem isso ele encostaria na borda do realce de fundo. */
  .sk-menu-principal-categoria-titulo::after {
    margin-right: 2px;
  }
  .sk-menu-principal-categoria-titulo::after {
    content: "›";
    float: right;
    color: var(--sk-muted);
  }
  /* O marcador nativo do <details> (triângulo) perde o sentido no modo
     flyout — o "›" acima assume o papel de affordance. */
  .sk-menu-principal-categoria-titulo {
    list-style: none;
  }
  .sk-menu-principal-categoria-titulo::-webkit-details-marker {
    display: none;
  }
}

@media (max-width: 640px) {
  .sk-menu-principal {
    width: 100vw;
    max-width: 100vw;
  }

  /* Cabeçalho em 2 colunas (Prompt #60) empilha em telas estreitas — meia
     largura cada não sobra espaço para avisos + "Sair" ao lado de
     hambúrguer + logomarca. */
  .sk-header {
    grid-template-columns: 1fr;
    gap: var(--e2);
  }
}

.sk-nav {
  display: flex;
  gap: 0;
  padding: 0 var(--e6);
  border-bottom: 0.5px solid var(--sk-border);
  overflow-x: auto;
}
.sk-nav a {
  padding: var(--e4) var(--e5);
  font-size: 0.8125rem;
  color: var(--sk-muted);
  white-space: nowrap;
}
.sk-nav a.active {
  color: var(--sk-orange);
  border-bottom: 2px solid var(--sk-orange);
}

.sk-main {
  padding: var(--e6);
  /* Prompt #226 — o padding-TOP some do bloco uniforme e vira --e4: o
     título logo abaixo já ganhou entrelinhamento apertado (1.15) e
     margem menor (--e3, ver .sk-page-header h1) — manter --e6 aqui em
     cima duplicaria o respiro que as outras duas mudanças já deram. Os
     outros três lados continuam --e6, intocados. */
  padding-top: var(--e4);
  /* docs/14, Princípio 27 — 80% da viewport até um teto de 1440px, nunca
     esticando além disso em telas muito largas; nunca formalizado antes
     (960px era valor implícito herdado do início do projeto). */
  width: min(80%, 1440px);
  margin: 0 auto;
  flex: 1 1 auto;
  /* min-height:0 é necessário num item de flex-column para ele aceitar
     encolher abaixo do seu conteúdo e realmente rolar internamente
     (docs/14, Prompt #60) — sem isso, o item cresce para caber todo o
     conteúdo e quem rola acaba sendo a página inteira de novo. */
  min-height: 0;
  overflow-y: auto;
}
.sk-main--narrow {
  max-width: 480px;
}

/* ---------------------------------------------------------------------
   FAIXA PERSISTENTE DE ESTADO (docs/14, Princípio 35 — Prompt #141)

   Terceira categoria de comunicação: o Aviso Urgente interrompe e é
   dispensável; a mensagem comum passa; esta é ESTADO — fica enquanto o
   estado durar.

   `flex: 0 0 auto` e não `position: fixed`: o `body` já é uma coluna flex
   em que só o `.sk-main` rola (Prompt #135), então um irmão entre header
   e main é permanentemente visível PARTICIPANDO do layout, sem flutuar
   por cima nem cobrir a primeira linha da tela.

   Cor de aviso, não de erro: o bloqueio é um estado deliberado — alguém o
   ligou de propósito —, não uma falha. `--sk-warning-fg` sobre a
   superfície de aviso é o par já calibrado por tema desde o #106, então a
   faixa nasce legível nos três temas sem calibragem própria. */
.sk-faixa-estado {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--e3);
  padding: var(--e3) var(--e6);
  background: color-mix(in srgb, var(--sk-warning) 18%, var(--sk-bg));
  border-bottom: 0.5px solid var(--sk-warning);
  color: var(--sk-warning-fg);
  font-size: 0.8125rem;
  text-decoration: none;
}
.sk-faixa-estado:hover {
  background: color-mix(in srgb, var(--sk-warning) 28%, var(--sk-bg));
  text-decoration: none;
}
/* O foco precisa aparecer: a faixa é um link e alguém chega nela por
   teclado antes de chegar ao conteúdo da página. */
.sk-faixa-estado:focus-visible {
  outline: 2px solid var(--sk-warning-fg);
  outline-offset: -2px;
}
.sk-faixa-estado-texto strong {
  font-weight: 700;
}
/* A ação é convite, não botão: a faixa informa e OFERECE — não é
   dispensável nem obrigatória, então nada aqui pode se parecer com algo
   que precise ser resolvido antes de seguir. */
.sk-faixa-estado-acao {
  white-space: nowrap;
  text-decoration: underline;
}

.sk-footer {
  border-top: 0.5px solid var(--sk-border);
  padding: var(--e4) var(--e6);
  display: flex;
  align-items: center;
  gap: var(--e5);
  font-size: 0.6875rem;
  color: var(--sk-gray);
  flex: 0 0 auto;
  flex-wrap: wrap;
}

/* Abas da tela de Tabelas Gerais (docs/19) — mesma linguagem visual de
   `.sk-nav` (ativa = laranja com borda inferior), mas com `flex-wrap` porque
   são 11 abas, não cabendo em uma única linha em telas estreitas. */
.sk-abas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e1);
  border-bottom: 0.5px solid var(--sk-border);
  margin-bottom: var(--e4);
}
.sk-abas a {
  padding: var(--e3) var(--e4);
  font-size: 0.8125rem;
  color: var(--sk-muted);
  white-space: nowrap;
}
.sk-abas a.active {
  color: var(--sk-orange);
  border-bottom: 2px solid var(--sk-orange);
}

/* Ações de linha de tabela (ex: Editar + Excluir lado a lado em Tabelas
   Gerais, docs/19) — `<form>` é um elemento de bloco por padrão, quebrando a
   linha se não for colocado num container flex junto com o link/botão
   irmão. */
.sk-acoes-inline {
  display: flex;
  gap: var(--e2);
  align-items: center;
}

/* ---------- Componentes ---------- */

.sk-card {
  background: var(--sk-surface);
  border: 0.5px solid var(--sk-border);
  border-radius: 10px;
  padding: var(--e4);
}
.sk-card + .sk-card {
  margin-top: var(--e4);
}

.sk-btn {
  display: inline-block;
  font-family: var(--sk-font-body);
  font-size: 0.8125rem;
  font-weight: 500;
  padding: var(--e3) var(--e5);
  border-radius: var(--sk-radius-sm);
  border: none;
  cursor: pointer;
  text-decoration: none;
  /* Um <button> mantém "appearance: auto" por padrão — o navegador pinta
     o widget nativo do SO (chrome/hover/estado pressionado) por cima do
     CSS, numa camada que getComputedStyle nem expõe. Um <a> já é
     "appearance: none" nativamente. Sem isto, um <button class="sk-btn">
     e um <a class="sk-btn"> ficam com text-decoration/color/background
     computados idênticos e, mesmo assim, visivelmente diferentes no hover
     (confirmado inspecionando os dois no Chrome) — a causa raiz não era
     "text-decoration", era o widget nativo do <button> desenhando por
     cima. "appearance: none" remove essa camada nativa, garantindo que
     ambos os elementos sejam pintados só pelas regras deste arquivo, em
     todos os estados (docs/14, princípio 4). */
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
}
.sk-btn-primary {
  background: var(--sk-orange);
  color: var(--sk-btn-primary-fg);
}
.sk-btn-secondary {
  background: transparent;
  color: var(--sk-gold);
  border: 0.5px solid var(--sk-gold);
}
.sk-btn-tertiary {
  background: transparent;
  color: var(--sk-gray);
  border: 0.5px solid var(--sk-gray);
}
/* Botão só-ícone (mesmo padrão de .sk-help-imprimir-btn) — usado quando o
   rótulo textual do botão dá lugar a um ícone com title/aria-label
   equivalente (ex: engrenagem "Personalizar" no Dashboard, LOJA-01). */
.sk-btn-icone {
  display: inline-block;
  flex: none;
  background: none;
  border: 0.5px solid var(--sk-gray);
  color: var(--sk-gray);
  border-radius: var(--sk-radius-sm);
  /* CAIXA ELÁSTICA, não fixa (Prompt #147). O `em` é relativo ao
     `font-size` DESTE elemento, então a caixa acompanha o próprio glifo:
     no padrão (100% = base 20px) o resultado é exatamente o mesmo px de
     antes, e nos extremos da faixa nova a caixa cresce junto em vez de
     cortar o conteúdo.

     Por que era preciso: a base subiu para 20px e o teto da escala
     continua em 150%, ou seja 30px de raiz — terreno que nunca existiu
     (o máximo antigo eram 24px). Com a caixa cravada em px, o glifo
     passava a caixa lá em cima e o botão ficava com o símbolo
     transbordando. Nada muda no tamanho que Wagner valida. */
  width: 1.6em;
  height: 1.6em;
  line-height: 1.48;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  font-size: 0.8125rem;
  padding: 0;
}
.sk-btn-icone:hover {
  color: var(--sk-gold);
  border-color: var(--sk-gold);
  text-decoration: none;
}
/* Nível 4 (docs/14, princípio 1) — ações destrutivas/irreversíveis, ex:
   "Excluir versão". Sólido (não contornado, ao contrário do Nível 3) para
   pesar visualmente tanto quanto o Nível 1 — a seriedade da ação exige
   destaque, não discrição. Sempre acompanhado de confirmação explícita
   antes de executar (ver .sk-btn-danger[data-confirmar] em base.html). */
.sk-btn-danger {
  background: var(--sk-danger);
  color: #fff;
}
/* Paridade de comportamento entre opções de mesmo nível (docs/14, princípio
   4): sem esta regra, um <a class="sk-btn"> herda o sublinhado de "a:hover"
   (regra global mais abaixo) enquanto um <button class="sk-btn"> não tem
   como herdá-lo — duas opções visualmente idênticas passavam a divergir só
   no hover, dependendo do elemento HTML por trás. Especificidade de
   ".sk-btn:hover" (0,2,0) já vence "a:hover" (0,1,1) independente da ordem
   das regras no arquivo. */
.sk-btn:hover {
  text-decoration: none;
  /* Retorno visual de hover (docs/14, princípio 1/4 — antes desta regra
     .sk-btn:hover só mudava text-decoration, sem NENHUM realce de estado).
     Fundo sutil para os níveis com fundo transparente (Secundário,
     Terciário): mesmo `color-mix` do hover do menu principal (Prompt #106,
     acima) — sobre --sk-fg/--sk-bg do Tema ativo, nunca cor fixa, então
     clareia em Tema escuro e escurece em Tema claro, sempre no mesmo passo
     relativo. Níveis 1 e 4 (fundo sólido) SOBRESCREVEM este valor logo
     abaixo — clarear o elemento mais luminoso da tela reduziria o
     contraste com o texto claro por cima; eles escurecem, não usam este
     mecanismo. */
  background: color-mix(in srgb, var(--sk-fg) 8%, var(--sk-bg));
}
/* Nível 1 e 4 (docs/14, princípio 1) — achado do #184: misturar com
   `black` parte do pressuposto de que o fundo do botão é sempre escuro,
   e no Pavimento Mosaico não é — --sk-orange lá já é #0A0A0A (quase
   preto), então "escurecer mais" pede um passo a partir de um valor já
   no piso, e fica imperceptível. Não é limite do color-mix, é direção
   errada.

   A direção certa é RELATIVA AO FUNDO DO TEMA, não a um extremo fixo:
   misturar com var(--sk-bg), não com black. --sk-bg é o oposto da ação
   principal por construção — é dele que o botão tira contraste —, então
   misturar com ele sempre move na direção que tem margem: escurece no
   Pedra Bruta e na Abóbada Celeste (--sk-bg escuro nos dois), clareia no
   Pavimento Mosaico (--sk-bg claro).

   90% É CALIBRADO, NÃO PALPITE (Prompt #185): a mistura desloca o fundo
   em direção ao texto do próprio botão (--sk-btn-primary-fg / branco em
   .sk-btn-danger) — misturar demais fecha esse contraste, de menos não
   sai do piso em Pavimento Mosaico. Varrido 60–94% checando as 3
   combinações de fundo × os 2 textos nos 3 Temas de fábrica (6
   pontos): 90% é o menor passo em que os 6 ainda passam WCAG AA
   (>= 4,5:1) — o ponto de menor movimento visual que ainda garante
   contraste em todos, não o de maior efeito. Um único número serve aos
   três Temas; não precisou de token por Tema. Confirmado também por
   captura real (Playwright, hover de mouse) nos três. */
.sk-btn-primary:hover {
  background: color-mix(in srgb, var(--sk-orange) 90%, var(--sk-bg));
}
.sk-btn-danger:hover {
  background: color-mix(in srgb, var(--sk-danger) 90%, var(--sk-bg));
}
/* Fora do escopo desta correção (docs/14, princípio 1) — .sk-btn-icone já
   tinha hover próprio (cor + borda) antes de .sk-btn ganhar fundo; sem
   esta linha, os dois casos que combinam "sk-btn sk-btn-tertiary
   sk-btn-icone" (configuracao_visual.html) herdariam o fundo novo por
   acidente de especificidade igual + ordem no arquivo. */
.sk-btn-icone:hover {
  background: none;
}
/* Botão desabilitado (docs/14, princípio 1/4 — achado do Catálogo Vivo,
   MASTER-24, Prompt #185): até aqui `.sk-btn:disabled` não tinha estilo
   PRÓPRIO nenhum — indistinguível de um botão ativo. Isso não era só
   estética: a decisão de trocar a paginação do Datagrid por chevrons
   (docs/59, P3) foi sustentada pelo argumento "com seta, o estado
   desabilitado se lê de imediato", que pressupõe um desabilitado
   legível — e ele não existia.

   `opacity`/`cursor`, nunca cor literal — funcionam sobre QUALQUER fundo
   de Tema sem token novo, mesmo raciocínio de abertura do arquivo. `.4`
   verificado nos três Temas de fábrica (Prompt #186): serviu aos três,
   inclusive o Pavimento Mosaico (fundo claro), sem precisar de ajuste —
   ver nota de calibração no relato do Prompt #186. */
.sk-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
/* Sem esta regra, o hover que o #185 deu a .sk-btn (linha ~793) continua
   respondendo em cima de um elemento desabilitado — o cursor do
   navegador já indicaria "não clicável", mas o FUNDO mudaria como se
   fosse, contradizendo o próprio cursor.

   `transparent` é certo para os níveis de fundo transparente (Secundário/
   Terciário, cujo `.sk-btn:hover` genérico é a origem do tingimento) —
   mas ERRADO para os de fundo sólido: `.sk-btn:disabled:hover` (0,3,0)
   tem especificidade MAIOR que `.sk-btn-primary`/`.sk-btn-danger`
   (0,1,0), então sem as duas regras abaixo ele apagaria o preenchimento
   inteiro do botão ao passar o mouse — não só cancelaria o hover, como
   faria o botão desabilitado desaparecer visualmente (achado ao
   verificar nos três Temas, Prompt #186). Cada nível sólido recupera o
   PRÓPRIO fundo de repouso, nunca `transparent`. */
.sk-btn:disabled:hover {
  background: transparent;
}
.sk-btn-primary:disabled:hover {
  background: var(--sk-orange);
}
.sk-btn-danger:disabled:hover {
  background: var(--sk-danger);
}

.sk-field {
  margin-bottom: var(--e4);
}

/* ---------------------------------------------------------------------
   GRID DE FORMULÁRIO (docs/14, Princípio 33 — Prompt #139)

   Até aqui TODO campo do sistema ocupava a linha inteira, em toda tela. A
   LOJA-03 tem 27 campos; MASTER-11 tem 21, CONTA-02 24, LOJA-25 20 e
   CAD-03 19 — e o Prompt #124, ao devolver ao rótulo a tipografia do
   corpo (Princípio 29), tornou esses formulários ainda mais altos. Um
   campo de 3 caracteres ("Ramal", "Número") gastando 100% da largura não
   é decisão de layout, é ausência dela.

   DOZE COLUNAS, e não uma classe por combinação (`--7-3`, `--4-4-4`…):
   com 12 colunas qualquer proporção útil se expressa somando inteiros, e
   o utilitário não precisa crescer a cada tela nova. É o mesmo motivo de
   `tipo_exibicao` no Datagrid ser um vocabulário fechado em vez de CSS
   por tela.

   O `gap` substitui a margem do `.sk-field` DENTRO da linha — mantê-la
   somaria com o `row-gap` e a linha ficaria mais espaçada que as demais.
   Fora da linha, `.sk-field` segue exatamente como antes: uma tela que
   não usa o utilitário renderiza o mesmo HTML e o mesmo CSS de sempre. */
.sk-form-linha {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--e4) var(--e3);
  margin-bottom: var(--e4);
  /* Campos de uma mesma linha alinham pelo TOPO, nunca esticando: um
     campo com dica ou erro embaixo é mais alto que o vizinho, e
     `stretch` (padrão do grid) deformaria o input do menor para
     acompanhá-lo. */
  align-items: start;
}
.sk-form-linha > .sk-field {
  margin-bottom: 0;
  /* `min-width: 0` porque um item de grid tem `min-width: auto` por
     padrão e se recusa a encolher abaixo do próprio conteúdo — um input
     com `size` grande estouraria a coluna em vez de caber nela. */
  min-width: 0;
}
.sk-col-1 { grid-column: span 1; }
.sk-col-2 { grid-column: span 2; }
.sk-col-3 { grid-column: span 3; }
.sk-col-4 { grid-column: span 4; }
.sk-col-5 { grid-column: span 5; }
.sk-col-6 { grid-column: span 6; }
.sk-col-7 { grid-column: span 7; }
.sk-col-8 { grid-column: span 8; }
.sk-col-9 { grid-column: span 9; }
.sk-col-10 { grid-column: span 10; }
.sk-col-11 { grid-column: span 11; }
.sk-col-12 { grid-column: span 12; }

/* Espaçador que ocupa a altura de um rótulo, para alinhar com os vizinhos
   um item que não tem rótulo próprio — o caso real é o botão "Consultar
   CEP" ao lado do campo CEP.

   É um `<label>` VAZIO, não uma margem em pixels: assim ele herda a mesma
   regra tipográfica dos rótulos reais e a altura casa POR CONSTRUÇÃO,
   inclusive se o tamanho do rótulo mudar de novo (mudou no Prompt #124).

   A alternativa óbvia — `align-self: end` na célula do botão — resolve o
   caso feliz e quebra o real: basta o campo vizinho ter um erro de
   validação para a célula dele crescer para baixo, e o botão colado na
   base desce junto, desencontrado do input. */
.sk-rotulo-espacador {
  user-select: none;
}

/* Empilhamento automático (Princípio 33). O Skirret é de uso
   predominantemente desktop e isto NÃO é esforço de design mobile: é a
   media query que o grid dá de graça, para o formulário não entregar três
   campos espremidos numa tela de 6 polegadas. 700px é o mesmo breakpoint
   já usado no arquivo, não um valor novo. */
@media (max-width: 700px) {
  .sk-form-linha {
    grid-template-columns: 1fr;
  }
  .sk-form-linha > [class*="sk-col-"] {
    grid-column: span 1;
  }
  /* Empilhado, o espaçador só criaria uma linha em branco entre os
     campos — não há mais vizinho lateral com quem alinhar. */
  .sk-rotulo-espacador {
    display: none;
  }
}
/* Rótulo de campo usa a tipografia do CORPO, não a de legenda (docs/14,
   princípio 29 — Prompts #108 e #124).

   O seletor cobre as DUAS formas de renderizar campo que o sistema usa:
   `.sk-field` (widgets próprios) e o `<p>` que `form.as_p` gera dentro de
   um `sk-card`. Antes eram duas regras separadas, e a segunda usava `>`
   (filho DIRETO de form) — rótulos aninhados numa `<div>` de aba
   escapavam dela e herdavam o corpo por acidente. Era exatamente esse
   acidente que o #108 identificou ao investigar por que os rótulos de
   CAD-03 pareciam melhores que os do resto do sistema.

   Agora o seletor é DESCENDENTE, então o princípio vale por construção:
   não existe aninhamento que escape. `.sk-field-dica` continua menor e
   esmaecida de propósito — a distinção entre rótulo e dica é essa. */
.sk-field label:not(.sk-btn),
.sk-card form p label:not(.sk-btn),
.sk-card fieldset p label:not(.sk-btn) {
  display: block;
  font-size: 0.875rem;
  color: var(--sk-fg);
  margin-bottom: var(--e2);
}
/* `:not(.sk-btn)` acima não é firula: os widgets de upload usam
   `<label class="sk-btn sk-btn-tertiary">` como gatilho de arquivo
   (`sk_logomarca_input.html`, `sk_foto_obreiro_input.html`), e a regra de
   rótulo — mais específica (0,1,1) que `.sk-btn` (0,1,0) — vencia,
   degradando aqueles BOTÕES a texto de rótulo com `display:block`. O
   defeito já existia antes do princípio 29; a unificação só o tornaria
   mais visível, então foi corrigido junto.

   `.helptext` é a dica que `form.as_p` gera (56 usos no projeto) e nunca
   teve regra nenhuma: herdava o corpo e ficava MAIOR e mais contrastada
   que o rótulo ao lado — o inverso exato do que o princípio 29 pede. Ela
   recebe aqui o mesmo tratamento de `.sk-field-dica`, que é o seu
   equivalente nos formulários de widget próprio. */
.helptext {
  display: block;
  font-size: 0.6875rem;
  color: var(--sk-muted);
  margin-top: var(--e1);
}
.sk-field input,
.sk-field select,
.sk-field textarea {
  width: 100%;
  box-sizing: border-box;
  background: color-mix(in srgb, var(--sk-fg) 4%, var(--sk-bg));
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius-sm);
  padding: var(--e2) var(--e3);
  color: var(--sk-fg);
  font-size: 0.8125rem;
  font-family: var(--sk-font-body);
}
.sk-field input[type="checkbox"] {
  width: auto;
}
.sk-field input:disabled,
.sk-field select:disabled,
.sk-field textarea:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
/* Checkbox sempre adjacente ao rótulo, imediatamente à direita dele
   (docs/14, princípio 12) — sobrepõe o "display: block" padrão de
   .sk-field label, que empurraria o checkbox para a linha de baixo. */
.sk-field-checkbox {
  display: flex;
  align-items: center;
  gap: var(--e2);
}
.sk-field-checkbox label {
  display: inline;
  margin-bottom: 0;
}
/* Checkbox dentro do GRID de formulário (Prompt #187, docs/59 §6 fase 3,
   primitivo "bloco de campo") — alinhado com a BASE dos campos vizinhos,
   nunca com o topo. Os vizinhos têm rótulo (uma linha, ~19px + 6px de
   margem) ACIMA do widget; o checkbox não tem rótulo acima, então sem
   este respiro ele nasceria mais alto na célula, desalinhado com a caixa
   dos inputs ao lado. Valor calibrado por medição real (Playwright,
   `bounding_box()` do input vs. do checkbox numa página fixa carregando
   este CSS) até os dois centros verticais coincidirem — não é herdado de
   `.sk-field-valor` (aquele usa `padding: 9px 0`, problema geométrico
   diferente). */
.sk-form-linha > .sk-field-checkbox {
  padding-top: 41px; /* sk-excecao: constante geométrica calibrada por medição (comentário acima), não espaçamento de escala */
}
/* Obrigatório — asterisco no rótulo, nunca a palavra (Prompt #187,
   docs/59 §6 fase 3). Cor de AÇÃO (--sk-orange), não de erro: obrigatório
   não é problema, é informação neutra sobre o que preencher. */
.sk-obrigatorio {
  color: var(--sk-orange);
  margin-left: 2px;
}
/* Campo com erro — borda de perigo no widget (Prompt #187). Decidido pela
   presença de `campo.errors` NO TEMPLATE (classe `.sk-field--erro`),
   nunca por `:has()` — o projeto evita depender dele (ver nota de
   `.sk-loja-cabecalho`, Prompt #171/#186). */
.sk-field--erro input,
.sk-field--erro select,
.sk-field--erro textarea {
  border-color: var(--sk-danger);
}
/* Ícone ao lado da mensagem de erro (Prompt #187) — erro que depende só
   de cor falha para quem não a distingue (docs/59 §6). `::before` em vez
   de mexer no HTML que o Django gera: `.errorlist li` já existe e já
   carrega a cor/peso corretos (`--sk-danger-fg`, Prompt #123) — só falta
   o símbolo. SVG embutido (não glifo de texto) para nitidez em qualquer
   escala de fonte, com `currentColor` herdando a cor do próprio erro.

   `display:flex` etc. entram na regra ORIGINAL do item de lista de erro
   (adiante neste arquivo), não aqui — uma segunda regra para o mesmo
   seletor já produziu um achado real (Prompt #187: um teste de guarda
   procurava a cor do texto pela primeira ocorrência LITERAL do seletor
   no arquivo, e achava esta cópia, sem a cor — corrigido consolidando
   numa regra só). Só o `::before` mora aqui. */
.errorlist li::before {
  content: "";
  flex: none;
  width: 11px;
  height: 11px;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round'><circle cx='8' cy='8' r='6.4'/><path d='M8 4.8v3.6'/><path d='M8 11.2v.01'/></svg>") center / contain no-repeat;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round'><circle cx='8' cy='8' r='6.4'/><path d='M8 4.8v3.6'/><path d='M8 11.2v.01'/></svg>") center / contain no-repeat;
}
/* Área de texto — altura mínima de dois campos, redimensionável só na
   vertical (Prompt #187). `--sk-btn-height` já é a altura de referência
   de UM campo de texto (docs/14, princípio 23) — dobrada aqui, não um
   valor novo. */
.sk-field textarea {
  min-height: calc(var(--sk-btn-height) * 2);
  resize: vertical;
}
/* Combobox — chevron indicando lista (Prompt #187, docs/59 §6 fase 3).
   `.sk-combobox` é o invólucro que combobox.js cria em volta do
   `<input>` (Prompt #111) — o chevron entra nele, nunca no input, para
   não competir com o texto digitado. `padding-right` no input abre
   espaço para o glifo não sobrepor o fim do texto. */
.sk-combobox input {
  padding-right: var(--e6);
}
.sk-combobox::after {
  content: "▾";
  position: absolute;
  right: 11px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.7rem;
  color: var(--sk-muted);
  pointer-events: none;
}
/* Seleção de Widgets (LOJA-12/LOJA-13, SelecaoWidgetsForm, campo
   "widgets") — Django renderiza CheckboxSelectMultiple como
   <label><input>Nome</label> sem nenhum alinhamento; mesmo tratamento de
   .sk-field-checkbox acima, mas por id (form.as_p não passa por nenhuma
   classe própria do app). Mesmo id nas duas telas, então o mesmo fix
   corrige as duas de uma vez. */
#id_widgets label {
  display: flex;
  align-items: center;
  gap: var(--e2);
}
/* .sk-card form input (acima) dá width:100% a QUALQUER <input>, sem
   excluir checkbox (diferente de .sk-field input[type="checkbox"], que já
   tem essa exclusão) — dentro do label em flex acima, isso infla a
   "flex-basis" do checkbox pro tamanho da linha toda (item de flex fica
   enorme, mesmo o desenho nativo do checkbox continuando pequeno),
   empurrando o texto do nome do widget pra fora do alinhamento. */
#id_widgets input[type="checkbox"] {
  width: auto;
  flex: none;
}
/* Valor somente-leitura dentro de um .sk-field (ex: LOJA-14, espelho de
   MASTER-11 sem nenhum controle de edição) — mesma tipografia de
   .sk-field input, sem a caixa/borda de campo editável. */
/* VALOR EM LEITURA dentro de um `.sk-field` — rótulo + texto, sem caixa
   de campo (docs/29 §2.1).

   O PADDING VERTICAL NÃO É ESTÉTICA: é o que alinha a linha de base
   deste texto com a dos campos EDITÁVEIS da mesma linha do grid
   (Prompt #178, docs/14 Princípio 38). Sem ele, o valor encostava no
   topo da célula enquanto os vizinhos tinham a altura do input, e a
   linha inteira lia como desalinhada — visto na LOJA-03 (CPF /
   Nascimento / Idade), mas presente em toda tela que mistura os dois.

   Os números são os do input, copiados de propósito: `padding: 9px` e
   `border: 0.5px` (aqui transparente, só para ocupar a mesma altura de
   caixa). `font-size` já era igual. O padding HORIZONTAL fica em zero —
   o texto se alinha ao próprio rótulo, e indentá-lo 11px o descolaria
   dele sem ganhar nada. */
.sk-field-valor {
  margin: 0;
  color: var(--sk-fg);
  font-size: 0.8125rem;
  white-space: pre-line;
  padding: var(--e2) 0;
  border: 0.5px solid transparent;
}
.sk-field-dica {
  display: block;
  font-size: 0.6875rem;
  color: var(--sk-muted);
  margin-top: var(--e1);
}
/* Campo + botão "Testar link" lado a lado (docs/17, item 2.1 — video_url/
   audio_url). */
.sk-field-com-teste {
  display: flex;
  gap: var(--e2);
  align-items: center;
}
.sk-field-com-teste input {
  flex: 1;
}
.sk-help-imagem-atual {
  display: flex;
  align-items: center;
  gap: var(--e3);
}
.sk-help-imagem-atual img {
  width: 64px;
  height: 64px;
  object-fit: cover;
  border-radius: var(--sk-radius-sm);
  border: 0.5px solid var(--sk-border-strong);
}
/* Espaçamento entre o formset de imagens e a linha de botões de ação logo
   abaixo — sem isto ficam colados (docs/14, princípio 9 ampliado). */
.sk-help-imagens-formset {
  margin-bottom: var(--e5);
}

/* Preview da logomarca atual da Loja (MASTER-11, docs/05 seção 2.5) —
   object-fit: contain (não cover) porque ~50% das Lojas têm logomarca em
   proporção 4:3 vertical, não quadrada (docs/05, item 2.2.1) — nunca
   recortar, só limitar o tamanho de exibição. A remoção em si usa o
   checkbox "Clear" nativo do ClearableFileInput do Django, escondido
   visualmente dentro do botão "Remover logomarca atual"
   (`apps.core.widgets.LogomarcaClearableFileInput`, `.sk-visualmente-
   oculto` abaixo) — nunca o texto/link cru padrão do widget. */
.sk-logomarca-preview {
  display: block;
  max-width: 200px;
  max-height: 200px;
  object-fit: contain;
  border-radius: var(--sk-radius-sm);
  border: 0.5px solid var(--sk-border-strong);
  background: color-mix(in srgb, var(--sk-fg) 4%, var(--sk-bg));
  padding: var(--e2);
}

/* Preview da Foto do obreiro (LOJA-03, docs/29 §2.1, Prompt #64) —
   circular (border-radius: 50%), tamanho de exibição menor que a
   logomarca. object-fit: cover (diferente de .sk-logomarca-preview, que
   usa contain) — um retrato de pessoa é sempre esperado preencher o
   círculo todo (padrão universal de avatar), diferente de uma logomarca
   institucional, onde qualquer recorte é inaceitável. */
.sk-foto-obreiro-preview {
  display: block;
  width: 160px;
  height: 160px;
  object-fit: cover;
  border-radius: 50%;
  border: 0.5px solid var(--sk-border-strong);
  background: color-mix(in srgb, var(--sk-fg) 4%, var(--sk-bg));
}

/* Esconde visualmente um elemento sem tirá-lo da árvore de acessibilidade
   (nunca display:none/visibility:hidden, que também some para leitores de
   tela) — ex: o checkbox nativo "Clear" do ClearableFileInput, envolvido
   por um <label> estilizado como botão (`.sk-btn`). */
.sk-visualmente-oculto {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px; /* sk-excecao: padrão visualmente-oculto de acessibilidade — o -1px é parte do clip, não espaçamento */
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------------
   CAMPO DE ARQUIVO COM RÓTULO PRÓPRIO (Prompt #139)

   "Choose File"/"No file chosen" vêm do widget nativo do navegador e não
   aceitam tradução por CSS nem por Django. O input fica visualmente
   oculto (`.sk-visualmente-oculto`, acima — nunca `display:none`, que o
   tiraria do teclado e dos leitores de tela) e um `<label class="sk-btn">`
   faz o papel de gatilho.

   ESTADO VISÍVEL DA REMOÇÃO. Antes o checkbox "Limpar" era FILHO do
   label: clicar não mudava nada na tela, e a marcação só se revelava ao
   salvar. Agora ele é IRMÃO, o que permite `:checked + label` em CSS
   puro — sem JS, e sem depender de `:has()`. O rótulo troca para dizer o
   que vai acontecer E QUANDO ("ao salvar"), porque a remoção não é
   imediata e um "✓" sozinho deixaria isso ambíguo. */
.sk-remover-arquivo-marcado {
  display: none;
}
.sk-remover-arquivo-controle:checked + .sk-remover-arquivo .sk-remover-arquivo-ocioso {
  display: none;
}
.sk-remover-arquivo-controle:checked + .sk-remover-arquivo .sk-remover-arquivo-marcado {
  display: inline;
}
/* Marcado, o botão deixa de ser neutro: a cor de ação destrutiva
   (`--sk-danger`) é o que diferencia "posso remover" de "vou remover". */
.sk-remover-arquivo-controle:checked + .sk-remover-arquivo {
  background: var(--sk-danger);
  color: #fff;
}
/* O foco do checkbox oculto precisa aparecer NO LABEL, senão navegar por
   teclado até ele não mostra nada. */
.sk-remover-arquivo-controle:focus-visible + .sk-remover-arquivo {
  outline: 2px solid var(--sk-gold);
  outline-offset: 2px;
}
.sk-arquivo-nome {
  display: inline-block;
  margin-left: var(--e2);
  font-size: 0.75rem;
  color: var(--sk-muted);
  vertical-align: middle;
}

/* Avatar clicável (Prompt #187, LOJA-03, docs/59 §6 fase 3) — variante do
   campo de arquivo acima em que a IMAGEM é o gatilho. Mesmo mecanismo de
   remoção (`.sk-remover-arquivo*`), só reposicionado abaixo da imagem em
   vez de ao lado de um botão de texto. */
.sk-avatar-clicavel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--e2);
}
.sk-avatar-clicavel-gatilho {
  position: relative;
  display: block;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  cursor: pointer;
  /* `.sk-field label:not(.sk-btn)` é global mas escopado a `.sk-field` —
     este gatilho fica fora dele, então não herda `display:block`/
     `margin-bottom` de propósito; declarado aqui para não depender de
     onde o widget for colocado no futuro. */
  margin: 0;
}
.sk-avatar-clicavel-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  border: 0.5px solid var(--sk-border-strong);
  background: color-mix(in srgb, var(--sk-fg) 4%, var(--sk-bg));
}
/* Véu "Trocar" — só no hover/foco, mesmo padrão de affordance sob
   demanda já usado no botão de ações do Datagrid (docs/38 §2.16). */
.sk-avatar-clicavel-veu {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-size: 0.625rem;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 120ms ease;
  /* O clique precisa alcançar o <label> por baixo, não o véu. */
  pointer-events: none;
}
.sk-avatar-clicavel-gatilho:hover .sk-avatar-clicavel-veu,
.sk-avatar-clicavel-gatilho:focus-visible .sk-avatar-clicavel-veu {
  opacity: 1;
}
.sk-avatar-clicavel-gatilho:focus-visible {
  outline: 2px solid var(--sk-gold);
  outline-offset: 2px;
}
/* Link de remoção MENOR que o botão padrão — é um acessório abaixo do
   avatar, não uma ação de mesmo peso que "Salvar"/"Cancelar". */
.sk-avatar-clicavel-remover {
  height: auto;
  padding: 3px var(--e3);
  font-size: 0.6875rem;
}

/* QUAL REGISTRO ESTÁ SENDO EDITADO (docs/14, Princípio 34 — Prompt #139).

   Nasceu como cabeçalho do MASTER-11 (docs/05, seção 2.5.1: logomarca à
   esquerda + nome completo da Loja) e foi GENERALIZADO, não recriado: o
   #139 precisava do mesmo tratamento na LOJA-03 (foto + nome do obreiro),
   e um segundo par de classes dizendo a mesma coisa divergiria na primeira
   mudança de estilo.

   `.sk-loja-cabecalho*` permanece como ALIAS dos nomes genéricos — a
   MASTER-11 continua com o HTML que sempre teve, e nenhum teste ou
   template dela precisou mudar por causa desta generalização. */
.sk-registro-cabecalho,
.sk-loja-cabecalho {
  display: flex;
  align-items: center;
  gap: var(--e4);
  margin-bottom: var(--e5);
}
.sk-loja-cabecalho-logo {
  height: 56px;
  width: auto;
  max-width: 120px;
  object-fit: contain;
  border-radius: var(--sk-radius-sm);
}
/* A foto do obreiro é redonda (mesmo recorte do preview em
   `.sk-foto-obreiro-preview`) e menor que a logomarca da Loja: aqui ela
   identifica, não é o objeto da tela. */
.sk-registro-cabecalho-foto {
  height: 56px;
  width: 56px;
  object-fit: cover;
  border-radius: 50%;
  border: 0.5px solid var(--sk-border-strong);
  background: color-mix(in srgb, var(--sk-fg) 4%, var(--sk-bg));
}
.sk-registro-cabecalho-nome,
.sk-loja-cabecalho-nome {
  font-family: var(--sk-font-display);
  margin: 0;
}
/* Linha de identificação sob o nome (Prompt #187, LOJA-03) — "Cadastro
   28931 · Mestre · Ativo (Regular)". Mesma tipografia de
   `.sk-field-dica`: é contexto, não conteúdo. */
.sk-registro-cabecalho-meta {
  display: block;
  font-size: 0.75rem;
  color: var(--sk-muted);
  margin-top: 2px;
}

.sk-table {
  width: 100%;
  border-collapse: collapse;
  border: 0.5px solid var(--sk-border-strong);
  border-radius: 10px;
  overflow: hidden;
}
/* Cabeçalho de coluna (docs/38 §2.8 item 4, Prompt #109) — negrito e
   levemente MAIOR que a célula de dado, com contraste pleno. Até aqui era
   o inverso (0.6875rem, --sk-muted, peso 500 contra 0.8125rem da célula):
   o cabeçalho lia-se como legenda de rodapé, não como cabeçalho. Regra
   fixa do componente, nunca parametrizável por Tema (§2.6) — é
   legibilidade estrutural, não estética. */
.sk-table th {
  background: color-mix(in srgb, var(--sk-fg) 4%, var(--sk-bg));
  text-align: left;
  font-size: 0.875rem;
  color: var(--sk-fg);
  padding: var(--e3) var(--e4);
  font-weight: 700;
}
.sk-table td {
  padding: var(--e3) var(--e4);
  border-top: 0.5px solid var(--sk-border);
  font-size: 0.8125rem;
}
/* Alinhamento por tipo_exibicao TAMBÉM no cabeçalho (docs/38 §2.6,
   corrigido no Prompt #109). O `<th>` sempre recebeu a classe da coluna,
   mas ela perdia na cascata: `.sk-table th` (0-1-1) vence
   `.sk-col-numerico` (0-1-0), então o cabeçalho de coluna numérica ficava
   à esquerda enquanto os números ficavam à direita — a spec descrevia um
   comportamento que o CSS não entregava. Estas regras (0-2-1) restauram o
   que o §2.6 sempre afirmou. */
.sk-table th.sk-col-numerico {
  text-align: right;
}
.sk-table th.sk-col-status,
.sk-table th.sk-col-data,
.sk-table th.sk-col-imagem {
  text-align: center;
}
/* Linha de tabela navegável ao clicar (ex: LOJA-15 "Obreiros", Prompt #24)
   — só aplicada quando a linha tem `data-href` (JS cuida da navegação);
   ausente para quem não pode gerenciar, então a linha nunca fica com
   aparência clicável sem realmente ser. */
.sk-table tr[data-href] {
  cursor: pointer;
}
/* Realce de INTERAÇÃO da linha (docs/38 §2.8.3, Prompt #109) — sobe de 4%
   para 12%. A 4% ele perdia para o zebrado de 6%: passar o mouse sobre
   uma linha par *reduzia* o realce. Vale para qualquer `.sk-table`,
   dentro ou fora do Datagrid — o realce de interação é o mesmo no sistema
   inteiro. O degrau da linha zebrada vem logo abaixo, junto do zebrado. */
.sk-table tr[data-href]:hover {
  background: color-mix(in srgb, var(--sk-fg) 12%, var(--sk-bg));
}
.sk-table tr[data-href]:focus-visible {
  outline: 2px solid var(--sk-gold);
  outline-offset: -2px;
}
/* Lançamento em Rascunho no extrato (docs/47 §3.4, Prompt #100) — visão
   do Financeiro: linha esmaecida + selo, nunca misturado silenciosamente
   aos oficiais. */
.sk-linha-rascunho td {
  opacity: 0.55;
  font-style: italic;
}
.sk-selo-rascunho {
  border: 1px solid var(--sk-gray);
  border-radius: 3px;
  padding: 1px var(--e2);
  font-size: 0.6875rem;
  font-style: normal;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--sk-gray);
}
/* Porta 2 do vínculo (docs/48 §2.2, Prompt #103) — link discreto dentro
   da linha clicável do Datagrid de registros (LOJA-19). */
.sk-registro-vincular-quitar {
  margin-left: var(--e2);
  font-size: 0.75rem;
  color: var(--sk-gold);
  white-space: nowrap;
}

/* Componente Datagrid Compartilhado (docs/38) — busca, cabeçalho
   ordenável, paginação. `.sk-tabela-scroll` evita que a tabela quebre o
   layout em telas estreitas (scroll horizontal só na tabela, nunca a
   página inteira). */
.sk-datagrid-barra {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--e3);
  margin-bottom: var(--e3);
}
.sk-datagrid-busca-campo {
  width: 100%;
  max-width: 320px;
  box-sizing: border-box;
  background: color-mix(in srgb, var(--sk-fg) 4%, var(--sk-bg));
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius-sm);
  padding: var(--e2) var(--e3);
  color: var(--sk-fg);
}
.sk-datagrid-exportar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e2);
}
.sk-datagrid-filtros {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e3);
  margin-bottom: var(--e3);
}
.sk-datagrid-filtro-acesso-sistema,
.sk-datagrid-filtro-situacao-cadastral {
  max-width: 220px;
}

/* Filtros da LOJA-36 (docs/61, Prompt #225) — dois intervalos de data,
   um intervalo numérico, dois campos de digitação com filtro e um
   seletor. Fundo/borda/padding já vêm de `.sk-field input`/`select`
   acima (regra genérica, por descendência) — aqui só a largura, que
   precisa ser ESTREITA (um <input> de data/número não deve esticar
   como o campo de busca). */
.sk-datagrid-filtro-obreiro,
.sk-datagrid-filtro-status,
.sk-datagrid-filtro-categoria {
  max-width: 220px;
}
.sk-datagrid-filtro-intervalo-campos {
  display: flex;
  align-items: center;
  gap: var(--e1);
}
.sk-datagrid-filtro-intervalo-campos input {
  width: 130px;
}
.sk-datagrid-filtro-intervalo-campos input[type="number"] {
  width: 100px;
}

/* Painel de busca e filtros recolhível (docs/38 §2.20, Prompt #224) —
   `<details>` nativo: clique/toggle e acessibilidade de teclado de
   graça, sem JS. Sempre no topo da grade, independente dos pilotos do
   §2.16. */
.sk-datagrid-painel-filtros {
  border: 0.5px solid var(--sk-border);
  border-radius: var(--sk-radius-sm);
  margin-bottom: var(--e3);
  padding: 0 var(--e3);
}
.sk-datagrid-painel-filtros-cabecalho {
  display: flex;
  align-items: center;
  gap: var(--e2);
  padding: var(--e2) 0;
  cursor: pointer;
  font-size: 0.875rem;
  font-weight: 600;
  list-style: none;
}
.sk-datagrid-painel-filtros-cabecalho::-webkit-details-marker {
  display: none;
}
/* Seta própria, no lugar do marcador nativo removido acima — aponta para
   baixo fechado, para cima aberto (mesmo idioma visual do menu principal,
   docs/20 §7.1). */
.sk-datagrid-painel-filtros-cabecalho::before {
  content: "▸";
  color: var(--sk-muted);
}
.sk-datagrid-painel-filtros[open] > .sk-datagrid-painel-filtros-cabecalho::before {
  content: "▾";
}
/* O selo é OBRIGATÓRIO (docs/59 §6, docs/38 §2.20) — sem ele, um painel
   fechado com filtro ativo por padrão (ex: Situação Cadastral = Ativo na
   LOJA-15) mostraria uma contagem parcial como se fosse o total, sem
   nenhum sinal de que há filtro escondendo registros. */
.sk-selo-filtros-ativos {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25em;
  height: 1.25em;
  padding: 0 0.35em;
  border-radius: 999px;
  background: var(--sk-gold);
  color: var(--sk-bg);
  font-size: 0.6875rem;
  font-weight: 700;
}
.sk-datagrid-painel-filtros-conteudo {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--e3);
  padding-bottom: var(--e3);
}
.sk-datagrid-painel-filtros-conteudo .sk-datagrid-filtros {
  margin-bottom: 0;
}
/* ---------------------------------------------------------------------
   Pilotos do Datagrid (docs/38 §2.16, Prompt #135) — em piloto na LOJA-19.
   Todos ligados por classe no contêiner, derivada de flag na config: uma
   grade sem a classe renderiza exatamente como antes.

   ACHADO que definiu a implementação do cabeçalho fixo: neste layout o
   cabeçalho do sistema NÃO sobrepõe o conteúdo. Quem rola é `.sk-main`
   (`overflow-y: auto`), que fica ENTRE o header e o footer — os dois já
   estão fora da área que rola. Não há, portanto, altura de cabeçalho a
   medir nem a descontar: "parar abaixo do cabeçalho" é onde o conteúdo já
   começa.

   O obstáculo real era outro: `.sk-tabela-scroll` declara
   `overflow-x: auto`, e pela especificação isso faz o eixo Y computar
   `auto` também — o elemento vira o scrollport mais próximo, e um
   `position: sticky` dentro dele passa a se ancorar numa caixa que não
   rola verticalmente, ficando parado sem nunca "grudar". Daí o piloto dar
   à grade a sua PRÓPRIA área de rolagem vertical: assim o `<thead>` gruda
   no topo dela, o scroll horizontal continua existindo, e a solução não
   depende de medir nada. */
.sk-datagrid--cabecalho-fixo .sk-tabela-scroll {
  max-height: 60vh;
  overflow: auto;
  /* O recorte dos cantos arredondados passa para cá — ver a regra
     seguinte, que precisa tirá-lo da própria <table>. */
  border-radius: 10px;
}
/* A CAUSA REAL de o sticky não funcionar (Prompt #136).

   `.sk-table` declara `overflow: hidden` (para o `border-radius` recortar
   os cantos). `overflow` diferente de `visible` cria um scrollport, e um
   `position: sticky` se ancora ao scrollport MAIS PRÓXIMO — que passava a
   ser a própria <table>, não o wrapper com a área de rolagem. Como a
   tabela nunca rola dentro de si mesma, o cabeçalho não tinha do que
   grudar: rolava junto e era recortado pela borda do wrapper, que é
   exatamente o sintoma relatado.

   O Prompt #135 achou um obstáculo verdadeiro (`.sk-tabela-scroll` com
   `overflow-x: auto`) e o removeu, mas parou no wrapper e não olhou a
   própria tabela — havia DOIS ancestrais com overflow, e neutralizar um
   só não muda nada. */
.sk-datagrid--cabecalho-fixo .sk-table {
  overflow: visible;
  /* Sem o recorte, o raio na própria tabela deixaria o fundo do <th>
     quadrado sobrando por cima da borda arredondada. O raio vive no
     wrapper agora. */
  border-radius: 0;
}
.sk-datagrid--cabecalho-fixo thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  /* Fundo OPACO obrigatório: sem ele as linhas passariam por trás do
     cabeçalho e continuariam legíveis através dele.

     ATENÇÃO (Prompt #148): DENTRO do Datagrid esta declaração NÃO é a que
     vence. `.sk-datagrid .sk-table th` (0-2-1) sobrepõe esta regra
     (0-1-2), e era lá que o alfa entrava — o defeito viveu meses atrás de
     um comentário que afirmava a garantia no lugar errado. A opacidade do
     componente está garantida lá, em camadas; esta declaração serve à
     tabela que use `--cabecalho-fixo` FORA de um `.sk-datagrid`.

     `color-mix` só resulta opaco porque `--sk-fg` e `--sk-bg` são opacos
     nos quatro temas — se um dia um deles ganhar alfa, o resultado herda
     o alfa, e há teste cobrindo isso. */
  background: color-mix(in srgb, var(--sk-fg) 4%, var(--sk-bg));
}

/* Controles no rodapé. Busca e filtros à esquerda, contagem no meio,
   paginação à direita — `space-between` já entrega isso com três filhos.
   `flex-wrap` mantido: quando não couber, quebra em duas linhas sozinho,
   que é o comportamento pedido em vez de espremer. */
.sk-datagrid-paginacao--completa {
  border-top: 0.5px solid var(--sk-border);
  padding-top: var(--e3);
}
.sk-datagrid-rodape-controles {
  display: flex;
  align-items: center;
  gap: var(--e3);
  flex-wrap: wrap;
}
/* Os filtros da tela vêm de um parcial próprio, que traz o seu próprio
   invólucro de bloco — no rodapé ele precisa se comportar como item de
   linha, não como faixa. */
.sk-datagrid-rodape-controles .sk-datagrid-filtros {
  display: flex;
  align-items: center;
  gap: var(--e3);
  margin: 0;
}
.sk-datagrid-rodape-controles .sk-field {
  margin: 0;
}

/* Ação de criação da tela (docs/38 §2.17, Prompt #138) — mora no mesmo
   grupo da busca, no rodapé (padrão) ou na barra superior quando
   `controles_no_rodape` está desligado. `flex: none` porque o grupo é
   flex e o campo de busca ao lado tem `width: 100%`: sem isto o botão
   seria o item que cede espaço, e o rótulo quebraria em duas linhas antes
   de a busca encolher um pixel.

   `white-space: nowrap` pela mesma razão, para o caso de a barra quebrar:
   "Gerar novo lote" partido ao meio muda a altura da linha inteira. */
.sk-datagrid-acao-criar {
  flex: none;
  white-space: nowrap;
}
/* Barra superior: agrupa ação de criação + busca do mesmo jeito que o
   rodapé, para o `space-between` da barra continuar separando controles
   (esquerda) de exportação (direita) — com os dois soltos, seriam três
   filhos e a busca acabaria no meio. */
.sk-datagrid-barra-controles {
  display: flex;
  align-items: center;
  gap: var(--e3);
  flex-wrap: wrap;
}

/* Ações por linha só em evidência. `visibility`, nunca `display: none`:
   o espaço fica RESERVADO, senão a linha mudaria de largura ao passar o
   mouse e a tabela inteira dançaria.

   `:focus-within` não é refinamento — sem ele a ação simplesmente não
   existe para quem navega por teclado, já que o foco chega ao link sem
   que ponteiro nenhum passe por ali. */
.sk-datagrid--acoes-em-evidencia tbody td .sk-registro-vincular-quitar {
  visibility: hidden;
  opacity: 0;
  transition: opacity 120ms ease-in-out;
}
.sk-datagrid--acoes-em-evidencia tbody tr:hover .sk-registro-vincular-quitar,
.sk-datagrid--acoes-em-evidencia tbody tr:focus-within .sk-registro-vincular-quitar {
  visibility: visible;
  opacity: 1;
}

.sk-tabela-scroll {
  overflow-x: auto;
}
/* LOJA-19 — pacote de produtividade (Prompt #134). */

/* Item 2: bloco de edição em três linhas de dois campos. Grade de duas
   colunas; numa tela estreita colapsa para uma, porque dois campos lado a
   lado em 360px não são duas colunas, são dois campos espremidos. */
.sk-form-grade-dupla {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 var(--e4);
  align-items: start;
}
@media (max-width: 700px) {
  .sk-form-grade-dupla {
    grid-template-columns: 1fr;
  }
}
/* Categoria e "Transferir para" dividem a MESMA célula (só um dos dois
   fica visível por vez): sem o invólucro, alternar a aba de Operação
   deslocaria os campos seguintes. */
.sk-form-grade-celula > [hidden] {
  display: none;
}
/* Memo em uma linha de altura — o campo é de anotação curta, e três
   linhas empurravam o botão de salvar para fora da vista. */
.sk-form-grade-dupla textarea {
  min-height: 0;
  height: calc(1.5em + 16px);
  resize: vertical;
}

/* Item 1: "Dados Cadastrais" no cabeçalho da tela. O painel abre por
   cima do conteúdo, ancorado à direita — empurrar a página inteira para
   baixo ao abrir um disclosure de consulta seria pior. */
.sk-dados-cadastrais {
  position: relative;
  margin-left: auto;
}
.sk-dados-cadastrais-painel {
  position: absolute;
  right: 0;
  z-index: 30;
  width: 420px;
  max-width: 90vw;
  margin-top: var(--e2);
  background: var(--sk-surface-solid);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
}
.sk-conta-subtitulo {
  margin-top: -8px; /* sk-excecao: compensação negativa aproxima o subtítulo do título — a escala não tem passo negativo */
}

.sk-saldo-destaque {
  font-size: 1.75rem;
  font-weight: 600;
  color: var(--sk-gold);
  margin: var(--e1) 0;
}
.sk-datagrid-th-botao {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-transform: inherit;
  letter-spacing: inherit;
}
.sk-datagrid-th-botao:hover {
  color: var(--sk-datagrid-cabecalho-hover-fg);
}
.sk-datagrid-th-botao:focus-visible {
  outline: 2px solid var(--sk-gold);
  outline-offset: 2px;
}
.sk-datagrid-paginacao {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--e3);
  margin-top: var(--e3);
}
.sk-datagrid-paginacao-texto {
  font-size: 0.75rem;
  color: var(--sk-muted);
}
.sk-datagrid-paginacao-botoes {
  display: flex;
  gap: var(--e2);
}
.sk-datagrid-paginacao-botoes .sk-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
/* Chevron em vez de texto (docs/38 §2.21, Prompt #224) — mesmo botão,
   mesma URL/estado desabilitado; só a forma muda. Fonte maior porque "‹"/
   "›" desenhados no tamanho de texto normal ficam pequenos demais para
   ler como seta. */
.sk-datagrid-paginacao-botoes .sk-btn {
  font-size: 1.125rem;
  line-height: 1;
  padding-left: var(--e2);
  padding-right: var(--e2);
}

/* Seletor de registros por página (docs/38 §2.21, Prompt #224) —
   preferência GLOBAL do usuário (`Usuario.registros_por_pagina`), gravada
   pelo próprio ato de trocar o seletor. */
.sk-datagrid-paginacao-registros {
  display: flex;
  align-items: center;
  gap: var(--e2);
  font-size: 0.75rem;
  color: var(--sk-muted);
}
.sk-datagrid-paginacao-registros select {
  background: color-mix(in srgb, var(--sk-fg) 4%, var(--sk-bg));
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius-sm);
  padding: 0.2em 0.5em;
  color: var(--sk-fg);
}

/* Menu de exportação agrupado (docs/38 §2.21, Prompt #224) — substitui os
   três botões separados por um único botão-ícone com flyout, mesmo
   comportamento hover-intent do menu principal (`menu-flyout.js`,
   generalizado para aceitar este seletor). */
.sk-datagrid-exportar-menu {
  position: relative;
}
.sk-datagrid-exportar-botao {
  cursor: pointer;
  list-style: none;
}
.sk-datagrid-exportar-botao::-webkit-details-marker {
  display: none;
}
.sk-datagrid-exportar-conteudo {
  position: absolute;
  right: 0;
  top: 100%;
  z-index: 5;
  margin-top: var(--e1);
  min-width: 140px;
  display: flex;
  flex-direction: column;
  background: var(--sk-surface-solid);
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius-sm);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
  padding: var(--e2);
  gap: 2px;
}
.sk-datagrid-exportar-titulo {
  margin: 0 0 var(--e1);
  padding: 0 var(--e2);
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--sk-muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.sk-datagrid-exportar-conteudo a {
  padding: var(--e2);
  border-radius: var(--sk-radius-sm);
  color: var(--sk-fg);
}
.sk-datagrid-exportar-conteudo a:hover,
.sk-datagrid-exportar-conteudo a:focus-visible {
  background: color-mix(in srgb, var(--sk-fg) 8%, var(--sk-bg));
  text-decoration: none;
}

/* docs/38 §2.7 — cabeçalho de coluna do Datagrid usa o token dedicado
   (não o fundo genérico de .sk-table th, usado por tabelas comuns fora do
   componente) — maior especificidade (.sk-datagrid + .sk-table) sobrepõe
   a regra genérica só dentro do Datagrid.

   OPACIDADE É REQUISITO FUNCIONAL, NÃO ACABAMENTO (Prompt #148). Desde
   que o cabeçalho virou `sticky` (#136), o conteúdo rola POR BAIXO dele —
   e com qualquer canal alfa no fundo as linhas de dados continuam
   legíveis através do cabeçalho. Era o defeito relatado por Wagner em
   19/08/2026 no Pedra Bruta e no Pavimento Mosaico (e presente também no
   Cinzas, que ninguém estava usando).

   O #136 escreveu "fundo opaco obrigatório" na regra do sticky
   (`.sk-datagrid--cabecalho-fixo thead th`, mais abaixo) e a garantia
   nunca valeu, por CASCATA: aquela regra tem especificidade 0-1-2 e esta
   tem 0-2-1 — classe vence elemento, então quem pinta o cabeçalho dentro
   do Datagrid é ESTA, com um token que trazia alfa. A lição vale além
   deste caso: *garantia declarada na regra errada não é garantia*.

   A correção não confia no VALOR do token. As camadas abaixo tornam a
   opacidade uma propriedade da REGRA, então nem um Tema novo, nem um
   Master editando a cor na MASTER-08 conseguem reintroduzir o vazamento:

   - `background-color` opaco no fundo de tudo;
   - o `--sk-surface` do card por cima dele (o cabeçalho vive dentro de um
     `.sk-card`, e sem esta camada o tom ficaria 3% mais escuro que hoje);
   - o tom do token no topo, agora composto sobre base opaca.

   Camadas de `background-image` empilham da PRIMEIRA (topo) para a
   última — daí a ordem invertida em relação à leitura natural. */
.sk-datagrid .sk-table th {
  background-color: var(--sk-bg);
  background-image:
    linear-gradient(
      var(--sk-datagrid-cabecalho-bg),
      var(--sk-datagrid-cabecalho-bg)
    ),
    linear-gradient(var(--sk-surface), var(--sk-surface));
}
/* Linha de cabeçalho de grupo (Manutenção de Sementes, docs/45 §7 —
   seções fixas por tipo de Lembrete dentro de um único Datagrid): mesmo
   fundo do cabeçalho de colunas, regra fixa do componente (nunca por
   Tema — mesma decisão de docs/38 §2.6). */
.sk-datagrid .sk-table tr.sk-datagrid-grupo td {
  background: var(--sk-datagrid-cabecalho-bg);
}
/* Zebrado de linhas alternadas — deriva do fundo base via color-mix()
   (docs/38 §2.7), nunca um token dedicado: mistura --sk-fg em --sk-bg a
   6%, o que sempre resulta num passo sutil e legível em qualquer Tema,
   claro ou escuro (diferente de um rgba(255,255,255,...) fixo, que só
   funciona em fundos escuros). */
.sk-datagrid tbody tr:nth-child(even) {
  background: color-mix(in srgb, var(--sk-fg) 6%, var(--sk-bg));
}
/* Degrau do hover sobre linha JÁ zebrada (docs/38 §2.8.3, Prompt #109) —
   mesma mecânica do menu (docs/20 §7.1.1, Prompt #107): o realce de
   interação nunca pode ficar abaixo do realce de estado, e cada linha
   sobe o MESMO delta ao receber o ponteiro (12 pontos), o que preserva o
   zebrado durante o hover em vez de achatá-lo. Escala do Datagrid:
     repouso ímpar 0% · repouso par 6% · hover ímpar 12% · hover par 18%  */
.sk-datagrid tbody tr:nth-child(even)[data-href]:hover {
  background: color-mix(in srgb, var(--sk-fg) 18%, var(--sk-bg));
}

/* Linha totalizadora opcional (<tfoot>, docs/38 §2.5, Prompt #71) — borda
   mais forte e negrito para se distinguir claramente das linhas normais
   de dado, sem token de cor próprio (reaproveita --sk-border-strong, já
   usado na moldura externa de .sk-table). */
.sk-datagrid tfoot td {
  border-top: 0.5px solid var(--sk-border-strong);
  font-weight: 600;
}

/* docs/38 §2.6 — tipo_exibicao por coluna: alinhamento e fonte são regra
   FIXA do componente (nunca parametrizável por Tema, diferente da cor
   acima) — aplicada tanto no cabeçalho (th, via apps.core.datagrid) quanto
   na célula de dado (td, marcada manualmente por cada linha_template). */
.sk-col-numerico {
  text-align: right;
}
.sk-col-status {
  text-align: center;
  font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
}
/* DATA (Prompt #62) — mesmo centro de STATUS, mas sem monoespaçada: uma
   data (ex: Nascimento, LOJA-15) não é "símbolo de 1 caractere". */
/* Coluna de IMAGEM do Datagrid (docs/38 §2.18, Prompt #156) — a primeira
   coluna que o componente ganhou desde o §2.6, e a única cujo conteúdo não
   é texto.

   Largura fixa e mínima: uma miniatura não deve competir por espaço com as
   colunas que carregam informação. `width` numa célula de tabela é
   sugestão, não ordem — daí o par com `white-space: nowrap`, que impede a
   coluna de esticar para acomodar quebra. */
.sk-col-imagem {
  text-align: center;
  width: 3em;
  white-space: nowrap;
}
/* A miniatura em si. Circular e `object-fit: cover` pelo mesmo motivo do
   `.sk-foto-obreiro-preview` (§ acima): retrato de pessoa preenche o
   círculo; recorte é esperado, distorção não.

   `vertical-align: middle` porque a imagem divide a linha com células de
   texto — sem ele, a linha de base do texto alinharia com o pé da imagem e
   a linha inteira ficaria alta demais. */
.sk-datagrid-miniatura {
  display: inline-block;
  width: 2em;
  height: 2em;
  object-fit: cover;
  border-radius: 50%;
  vertical-align: middle;
  border: 0.5px solid var(--sk-border-strong);
  background: color-mix(in srgb, var(--sk-fg) 4%, var(--sk-bg));
}
.sk-col-data {
  text-align: center;
}

.sk-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--e2);
  font-size: 0.6875rem;
}
.sk-badge-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  display: inline-block;
}
.sk-badge-dot--ok { background: var(--sk-success); }
.sk-badge-dot--warn { background: var(--sk-warning); }
.sk-badge-dot--danger { background: var(--sk-danger); }
.sk-badge-dot--muted { background: var(--sk-gray); }

/* Valor com sinal (LOJA-36, docs/61 §6 R3) — a cor é REFORÇO, nunca o
   único portador: o sinal (+/−) já está no número em si; isto só
   reforça visualmente o que o sinal já diz. Reaproveita os tokens de
   sucesso/perigo já existentes (nenhuma cor nova inventada) — mesmos
   usados em `.sk-badge-dot--ok`/`--danger` acima. */
.sk-valor-credito { color: var(--sk-success-fg); }
.sk-valor-debito { color: var(--sk-danger-fg); }

.sk-messages {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--e5);
}
.sk-messages li {
  font-size: 0.8125rem;
  padding: var(--e3) var(--e4);
  border-radius: var(--sk-radius-sm);
  background: rgba(99, 153, 34, 0.1);
  border: 0.5px solid rgba(99, 153, 34, 0.3);
  color: var(--sk-success-fg);
  margin-bottom: var(--e2);
}
.sk-messages li.error {
  background: rgba(192, 57, 43, 0.1);
  border-color: rgba(192, 57, 43, 0.3);
  color: var(--sk-danger-fg);
}
/* Aviso usa --sk-warning-fg, não --sk-gold: o dourado é token de CHROME
   (botão de Nível 2, ícones de destaque) e num Tema monocromático vira
   neutro — a mensagem de aviso perderia a sinalização. O valor de fábrica
   é o mesmo dourado, então "Pedra Bruta" não muda. */
.sk-messages li.warning {
  background: rgba(201, 168, 76, 0.12);
  border-color: rgba(201, 168, 76, 0.35);
  color: var(--sk-warning-fg);
}

/* Erros de validação de formulário (docs/14, princípio 19) — Django gera
   ul.errorlist sem nenhuma classe própria por campo, herdando a cor de texto
   padrão; contra o tema escuro isso passa despercebido. Global (não restrito
   a .sk-card) porque telas pré-login (ex: login.html) também renderizam
   formulários fora de um card. */
.errorlist {
  list-style: none;
  margin: 0 0 var(--e2);
  padding: 0;
}
/* `--sk-danger-fg`, não `--sk-danger` (Prompt #123, docs/37 §10.3.1).

   `--sk-danger` tem dois papéis incompatíveis: é o FUNDO de
   `.sk-btn-danger` (que fixa `color:#fff`, exigindo cor escura) e era a
   cor deste TEXTO sobre o fundo do Tema (exigindo cor clara). O Prompt
   #118 provou que os intervalos de luminância exigidos pelos dois não se
   intersectam em tema escuro — nenhum valor de token resolvia, então a
   correção tinha de ser aqui.

   `--sk-danger-fg` existe desde o Prompt #106 exatamente para "texto
   legível de erro", e `.errorlist.nonfield li` já o usava. O texto de
   erro por campo é `font-weight: 700` a `0.75rem`, portanto sem direito
   ao limiar de "texto grande" — precisa de 4,5:1 cheios.

   `display:flex`/`gap` (Prompt #187) alinham o ícone de erro ao lado do
   texto — ver `.errorlist li::before`, onde o símbolo em si mora. */
.errorlist li {
  display: flex;
  align-items: center;
  gap: var(--e1);
  color: var(--sk-danger-fg);
  font-weight: 700;
  font-size: 0.75rem;
}
.errorlist.nonfield {
  background: rgba(192, 57, 43, 0.1);
  border: 0.5px solid rgba(192, 57, 43, 0.3);
  border-radius: var(--sk-radius-sm);
  padding: var(--e3) var(--e4);
  margin: 0 0 var(--e4);
}
.errorlist.nonfield li {
  color: var(--sk-danger-fg);
}

/* Estilo padrão para campos renderizados via {{ form.as_p }} — os módulos
   ainda não têm widgets custom para usar .sk-field diretamente, então esta
   regra dá a mesma aparência a qualquer <p> gerado pelo Django dentro de um
   sk-card, sem exigir mudança nos formulários. */
.sk-card form > p,
.sk-card fieldset > p {
  margin: 0 0 var(--e4);
}
/* A regra de rótulo destes `<p>` foi UNIFICADA com `.sk-field label` lá
   em cima (docs/14, princípio 29) — ver a nota de lá sobre o `>` que
   deixava rótulos aninhados escaparem. Só o espaçamento do `<p>` fica
   aqui, porque é layout e não tipografia. */
.sk-card form input,
.sk-card form select,
.sk-card form textarea,
.sk-card fieldset input,
.sk-card fieldset select,
.sk-card fieldset textarea {
  width: 100%;
  box-sizing: border-box;
  background: color-mix(in srgb, var(--sk-fg) 4%, var(--sk-bg));
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius-sm);
  padding: var(--e2) var(--e3);
  color: var(--sk-fg);
  font-size: 0.8125rem;
  font-family: var(--sk-font-body);
}
.sk-card fieldset {
  border: 0.5px solid var(--sk-border);
  border-radius: var(--sk-radius);
  padding: var(--e3) var(--e4) var(--e1);
  margin: 0 0 var(--e4);
}
.sk-card fieldset legend {
  padding: 0 var(--e2);
  font-size: 0.75rem;
  color: var(--sk-gold);
}

.sk-page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e4);
  margin-bottom: var(--e4);
}
/* Prompt #226 (docs/59 P2 — "entrelinhamento por escala tipográfica,
   nunca valor único"). O `line-height: 1.5` herdado do `body` serve a
   texto corrido; num glifo de título ele reserva quase meia linha de
   vazio DENTRO da caixa do <h1> — espaço que nenhuma margem explica e
   que ninguém acha procurando por `margin`. `1.15` é o ganho maior, e
   o menos óbvio, dos três. `margin-bottom` some da regra genérica
   `h1,h2,h3{margin:0 0 0.5em}` (que dava ~21px, o equivalente a
   `--e5`) e vira `--e3` explícito, mais próximo do respiro que o
   entrelinhamento apertado já deixa. */
.sk-page-header h1 {
  line-height: 1.15;
  margin-bottom: var(--e3);
}
/* Mesma ideia de .sk-page-header (título + ação lado a lado), mas para um
   subtítulo dentro de um grupo de campos (ex: "Endereço de Cobrança" + o
   botão "Copiar dados do endereço institucional", docs/05 item 2.1,
   Prompt #35) — nunca reaproveita .sk-page-header diretamente porque esse
   nome já é específico de <h1>/topo de página. */
.sk-subtitulo-com-acao {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e3);
}
.sk-subtitulo-com-acao h3 {
  margin: 0;
}

.sk-empty {
  color: var(--sk-muted);
  font-style: italic;
}

.sk-pagination {
  display: flex;
  align-items: center;
  gap: var(--e3);
  font-size: 0.75rem;
  color: var(--sk-muted);
  margin-top: var(--e4);
}

.sk-login-erro {
  color: var(--sk-danger-fg);
  font-size: 0.8125rem;
  margin: 0 0 var(--e4);
}

/* Navegação "Voltar" — sempre ícone de seta + texto, nunca um sem o outro
   (docs/14-Diretrizes_de_Interface_Skirret.md, princípio 2). O ícone é
   injetado via ::before para que a classe sozinha já garanta o padrão,
   sem exigir que cada template repita o caractere no texto. Nível 3
   (navegação/dispensar) é sempre um botão real (sk-btn-tertiary), nunca um
   link de texto (docs/14, changelog 02/08/2026). */
.sk-btn-tertiary--voltar::before {
  content: "←";
  margin-right: var(--e2);
}

/* Linha de ações lado a lado, para qualquer par de botões relacionados
   (ação principal + navegação) — Etapa 1 ("Continuar" + "Outras formas de
   acesso"), Etapa 2 ("Confirmar" + "Voltar") e telas de confirmação OAuth
   ("Continuar" + "Voltar") (docs/14, princípio 9). */
.sk-login-step-actions {
  display: flex;
  align-items: center;
  gap: var(--e3);
}
.sk-login-step-actions form {
  margin: 0;
}
/* Etapa 1 do login (docs/06, seção 3.1): "Continuar" fica à esquerda, o
   grupo dos 3 botões-ícone (Magic Link/Google/Microsoft) fica à direita —
   scoped a #sk-step-1 para não afetar outras telas que reaproveitam
   .sk-login-step-actions (Etapa 2, Etapa 4, confirmação OAuth), onde o par
   de botões continua colado como antes. */
#sk-step-1 .sk-login-step-actions {
  justify-content: space-between;
}
.sk-login-icones-grupo {
  display: flex;
  align-items: center;
  gap: var(--e3);
  flex-shrink: 0;
}

/* Tela de login: logomarca centralizada no lugar do sk-header padrão. */
.sk-login-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--e4);
  padding: 48px var(--e6) var(--e6); /* sk-excecao: o 48px é o respiro solitário sobre a logomarca do login — a exceção registrada do docs/59 §3, fora da escala de propósito */
}
/* Avisos na tela de login (Prompt #107) — mesmo componente visual do
   cabeçalho interno (.sk-header-aviso), mas empilhado e centrado sob a
   logomarca, já que aqui não existe a grade de duas colunas do header
   autenticado. Só ocupa espaço quando há mensagem. */
.sk-login-avisos {
  display: flex;
  flex-direction: column;
  gap: var(--e2);
  width: 100%;
  max-width: 420px;
}
.sk-login-avisos:empty {
  display: none;
}
.sk-login-logo-link {
  display: block;
  line-height: 0;
}
.sk-login-logo {
  height: 128px;
  width: auto;
}
.sk-login-providers {
  display: flex;
  flex-direction: column;
  gap: var(--e3);
}
.sk-login-providers .sk-btn {
  text-align: center;
  width: 100%;
}
/* Espaçamento entre a última opção empilhada (Nível 2) e um botão de
   Nível 3 que venha em seguida (ex: "Voltar") — sem isto ficam colados
   (docs/14, princípio 9). */
.sk-login-providers + .sk-btn {
  margin-top: var(--e4);
}

/* Botões quadrados só de ícone (Etapa 1 do login, docs/06 seção 3.1: Magic
   Link, Google, Microsoft) — o fundo (laranja para Magic Link, claro para
   Google/Microsoft) já vem embutido no PNG (src/static/img/auth/), então o
   botão em si não tem chrome próprio, só molda tamanho/cantos e o estado
   de foco/hover. Sem texto visível (title + aria-label cobrem tooltip e
   leitor de tela — docs/14, princípio 2, exceção documentada no template
   para logotipos de marca já reconhecíveis). */
/* Altura/largura fixas via --sk-btn-height (docs/14, princípio 23) — nunca
   o tamanho natural do PNG, para ficar exatamente igual à altura real do
   ".sk-btn" de texto ao lado ("Continuar"), no mesmo grupo de ações.
   ``cursor: pointer`` explícito porque este botão não estende ``.sk-btn``
   (que já declara isso) e o <button> nativo do navegador, ao contrário do
   <a>, não usa "pointer" por padrão. */
.sk-login-icone-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--sk-btn-height);
  height: var(--sk-btn-height);
  padding: 3px;
  border: none;
  border-radius: var(--sk-radius-sm);
  background: transparent;
  cursor: pointer;
  overflow: hidden;
  flex-shrink: 0;
}
.sk-login-icone-btn img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
}
.sk-login-icone-btn:hover,
.sk-login-icone-btn:focus-visible {
  outline: 2px solid var(--sk-gold);
  outline-offset: 2px;
}

/* Código da tela do catálogo (docs/10 e docs/14, princípio 3) — discreto,
   canto direito do sk-footer. */
.sk-tela-codigo {
  font-size: 0.6875rem;
  color: var(--sk-gray);
}
/* Navegação rápida (docs/14, princípio 3 — Prompt #129): quando há telas
   a oferecer, o código deixa de ser texto morto e passa a ser um gatilho
   de duplo clique. O tracejado inferior é o único sinal permanente — o
   `title` só aparece no hover, e um código que não anuncia nada nunca
   seria descoberto. `user-select: none` evita que o duplo clique, que no
   navegador seleciona a palavra, deixe o código realçado por baixo do
   diálogo que acabou de abrir. */
.sk-tela-codigo--navegavel {
  cursor: pointer;
  border-bottom: 1px dotted var(--sk-gray);
  user-select: none;
}
.sk-tela-codigo--navegavel:hover {
  color: var(--sk-fg);
  border-bottom-color: var(--sk-fg);
}
/* Agrupa código da tela + ícone de Help contextual como um único item de
   flex do rodapé — sem isto, "justify-content: space-between" trata cada
   um como item separado e empurra o código da tela para o meio do rodapé
   em vez de ficar colado ao ícone, à direita (docs/14, princípio 3; bug
   corrigido em 02/08/2026).

   O `margin-left: auto` do Prompt #71 SAIU daqui na terceira reforma
   (#141): quem empurra para a direita agora é `.sk-footer-direita`, o
   elemento que envolve os três controles. Ver o comentário lá. */
.sk-footer-tela-grupo {
  display: flex;
  align-items: center;
  gap: var(--e2);
}

/* Novo conteúdo do rodapé (docs/14, Prompt #60) — Apelido/e-mail (title) e
   Nome da Loja atual na extrema esquerda; Controle de Zoom, código da
   tela e ícone de Ajuda na extrema direita (reposicionados no Prompt #71
   — antes, tudo ficava alinhado à esquerda numa única linha). A Mensagem/
   `rodape_texto` do Tema deixou de ser exibida aqui desde o Prompt #60
   (continua existindo em ConfiguracaoVisual, só não é mais renderizada
   neste local). */
/* ---------------------------------------------------------------------
   TERCEIRA REFORMA DO RODAPÉ (docs/14 — Prompt #141), depois do #60
   (conteúdo) e do #71 (dois grupos).

   As duas zonas passam a ser ELEMENTOS, em vez de dois `margin-left: auto`
   competindo entre si. O arranjo do #71 funcionava enquanto tudo coubesse
   numa linha: o rodapé tem `flex-wrap: wrap`, e quando os itens quebram
   para a segunda linha a margem automática passa a agir POR LINHA — a
   "extrema direita" vira a extrema direita da linha em que o item caiu.
   Com um elemento por zona, o `space-between` do rodapé resolve a
   distribuição e a quebra leva a zona inteira junto. */
.sk-footer-esquerda,
.sk-footer-direita {
  display: flex;
  align-items: center;
  /* 10px, não os 20px do rodapé: dentro de uma zona os itens são partes
     de um mesmo bloco de informação; entre as zonas, o espaço é o vão. */
  gap: var(--e3);
  flex-wrap: wrap;
}
.sk-footer-direita {
  margin-left: auto;
}
/* O pipe é o separador explícito da zona esquerda (Loja | Usuário). Mais
   apagado que os dois lados que separa — é pontuação, não informação. */
.sk-footer-separador {
  color: var(--sk-border-strong);
  user-select: none;
}
.sk-footer-usuario {
  cursor: default;
}
.sk-footer-loja {
  color: var(--sk-muted);
}

/* Escala de fonte por usuário (docs/14, princípio 15) — só renderizado em
   telas autenticadas (ver base.html).

   O `margin-left: auto` do Prompt #71 SAIU daqui na terceira reforma
   (#141): este controle é agora um item de `.sk-footer-direita`, e é a
   zona que se posiciona. Ter a margem aqui grudaria o zoom no vão e
   deixaria os outros dois colados à direita — o oposto do "três
   controles distintos, com espaçamento entre si" que a reforma pede. */
.sk-escala-fonte {
  display: inline-flex;
  align-items: center;
  gap: var(--e1);
  user-select: none;
}
.sk-escala-fonte-btn {
  background: none;
  border: 0.5px solid var(--sk-gray);
  color: var(--sk-gray);
  border-radius: var(--sk-radius-sm);
  /* CAIXA ELÁSTICA, não fixa (Prompt #147). O `em` é relativo ao
     `font-size` DESTE elemento, então a caixa acompanha o próprio glifo:
     no padrão (100% = base 20px) o resultado é exatamente o mesmo px de
     antes, e nos extremos da faixa nova a caixa cresce junto em vez de
     cortar o conteúdo.

     Por que era preciso: a base subiu para 20px e o teto da escala
     continua em 150%, ou seja 30px de raiz — terreno que nunca existiu
     (o máximo antigo eram 24px). Com a caixa cravada em px, o glifo
     passava a caixa lá em cima e o botão ficava com o símbolo
     transbordando. Nada muda no tamanho que Wagner valida. */
  width: 1.4545em;
  height: 1.4545em;
  line-height: 1;
  cursor: pointer;
  font-size: 0.6875rem;
  padding: 0;
}
.sk-escala-fonte-btn:hover {
  color: var(--sk-gold);
  border-color: var(--sk-gold);
}
.sk-escala-fonte-valor {
  font-size: 0.6875rem;
  color: var(--sk-gray);
  min-width: 30px;
  text-align: center;
}

/* Densidade de espaçamento por usuário (docs/59 §4) — três ícones de
   três traços, e o afastamento entre os traços de cada ícone é a
   densidade que ele aplica. Sem rótulo textual de propósito: "Padrão"
   prometeria valor absoluto quando o valor é relativo ao Tema (os dois
   níveis se multiplicam). Caixa elástica em `em`, como o controle de
   escala de fonte acima, pelos mesmos motivos do Prompt #147. O ativo
   se marca por aria-pressed — o estado É o atributo de acessibilidade,
   sem classe paralela que pudesse divergir dele. */
.sk-densidade {
  display: inline-flex;
  align-items: center;
  gap: var(--e1);
  user-select: none;
}
.sk-densidade-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0.5px solid var(--sk-gray);
  color: var(--sk-gray);
  border-radius: var(--sk-radius-sm);
  width: 1.4545em;
  height: 1.4545em;
  font-size: 0.6875rem;
  padding: 0;
  cursor: pointer;
}
.sk-densidade-btn svg {
  width: 0.9em;
  height: 0.9em;
}
.sk-densidade-btn:hover {
  color: var(--sk-gold);
  border-color: var(--sk-gold);
}
.sk-densidade-btn[aria-pressed="true"] {
  color: var(--sk-gold);
  border-color: var(--sk-gold);
}

/* Help Contextual (docs/17, seção 3.1) — ícone "?" discreto no rodapé, ao
   lado do código da tela; abre um modal nativo (<dialog>) com altura
   máxima e rolagem interna própria — comportamento único e consistente
   independente do tamanho do conteúdo, sem lógica condicional de
   truncamento (substituiu o painel expansível via <details>, que
   truncava conteúdos longos — atualizado em 02/08/2026). */
.sk-help-contextual {
  display: inline-block;
}
.sk-help-icone {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* CAIXA ELÁSTICA, não fixa (Prompt #147). O `em` é relativo ao
     `font-size` DESTE elemento, então a caixa acompanha o próprio glifo:
     no padrão (100% = base 20px) o resultado é exatamente o mesmo px de
     antes, e nos extremos da faixa nova a caixa cresce junto em vez de
     cortar o conteúdo.

     Por que era preciso: a base subiu para 20px e o teto da escala
     continua em 150%, ou seja 30px de raiz — terreno que nunca existiu
     (o máximo antigo eram 24px). Com a caixa cravada em px, o glifo
     passava a caixa lá em cima e o botão ficava com o símbolo
     transbordando. Nada muda no tamanho que Wagner valida. */
  width: 1.3091em;
  height: 1.3091em;
  border-radius: 50%;
  border: 0.5px solid var(--sk-gray);
  background: none;
  color: var(--sk-gray);
  font-size: 0.6875rem;
  font-family: var(--sk-font-body);
  padding: 0;
  cursor: pointer;
}
.sk-help-icone:hover {
  color: var(--sk-gold);
  border-color: var(--sk-gold);
}
.sk-help-modal {
  padding: 0;
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius);
  background: var(--sk-bg);
  color: var(--sk-fg);
  width: min(480px, calc(100vw - 48px));
  max-height: min(70vh, 560px);
}
.sk-help-modal[open] {
  display: flex;
  flex-direction: column;
}
.sk-help-modal::backdrop {
  background: rgba(0, 0, 0, 0.6);
}
.sk-help-modal-cabecalho {
  display: flex;
  justify-content: flex-end;
  flex: none;
  padding: var(--e2) var(--e3) 0;
}
.sk-help-modal-fechar {
  background: none;
  border: none;
  color: var(--sk-muted);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  padding: var(--e1) var(--e2);
}
.sk-help-modal-fechar:hover {
  color: var(--sk-gold);
}
.sk-help-modal-corpo {
  overflow-y: auto;
  padding: var(--e1) var(--e5) var(--e5);
  font-size: 0.8125rem;
  text-align: left;
}
.sk-help-titulo {
  margin-top: 0;
}
/* Título + ícone de impressão lado a lado (docs/17, item 3.1). */
.sk-help-artigo-cabecalho {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e3);
}
.sk-help-artigo-cabecalho .sk-help-titulo {
  flex: 1;
}
.sk-help-imprimir-btn {
  flex: none;
  background: none;
  border: 0.5px solid var(--sk-gray);
  color: var(--sk-gray);
  border-radius: var(--sk-radius-sm);
  /* Caixa elástica — ver a nota em `.sk-btn-icone` (Prompt #147). */
  width: 1.6em;
  height: 1.6em;
  line-height: 1;
  cursor: pointer;
  font-size: 0.8125rem;
  padding: 0;
}
.sk-help-imprimir-btn:hover {
  color: var(--sk-gold);
  border-color: var(--sk-gold);
}
.sk-help-imagem {
  margin: var(--e3) 0;
}
.sk-help-imagem img {
  display: block;
  max-width: 100%;
  border-radius: var(--sk-radius-sm);
}
.sk-help-imagem figcaption {
  font-size: 0.6875rem;
  color: var(--sk-muted);
  margin-top: var(--e1);
}

/* Feedback 👍/👎 (docs/17, item 2.4) — discreto, ao final do conteúdo. */
.sk-help-feedback {
  display: flex;
  align-items: center;
  gap: var(--e2);
  margin-top: var(--e4);
  padding-top: var(--e3);
  border-top: 0.5px solid var(--sk-border);
}
.sk-help-feedback-label {
  font-size: 0.6875rem;
  color: var(--sk-muted);
}
.sk-help-feedback-btn {
  background: none;
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius-sm);
  cursor: pointer;
  padding: var(--e1) var(--e2);
  font-size: 0.8125rem;
}
.sk-help-feedback-btn:hover {
  border-color: var(--sk-gold);
}
/* Voto enviado via fetch (docs/17, regra 12) — destaca o botão escolhido,
   sem depender de reload/mensagem de confirmação. */
.sk-help-feedback-btn--selecionado {
  background: rgba(201, 168, 76, 0.15);
  border-color: var(--sk-gold);
}

/* Componente de Diálogo (docs/18) — substitui confirm()/alert() nativos
   (docs/14, princípio 16). Reaproveita o mesmo mecanismo de <dialog> +
   ::backdrop já usado no Help (docs/17), sempre centralizado na viewport
   (comportamento nativo de showModal(), não um posicionamento manual —
   funciona mesmo com a página rolada, docs/18 cenário 8) e com rolagem
   interna própria para mensagens longas (docs/18 cenário 7). Estrutura
   definida pelo núcleo genérico (dialogo-core.js); só as cores/tamanhos
   abaixo são específicos do tema Pedra Bruta. */
.dialogo-modal {
  padding: 0;
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius);
  background: var(--sk-bg);
  color: var(--sk-fg);
  width: min(440px, calc(100vw - 32px));
  max-height: min(80vh, 640px);
}
.dialogo-modal[open] {
  display: flex;
  flex-direction: column;
}
.dialogo-modal::backdrop {
  background: rgba(0, 0, 0, 0.6);
}
.dialogo-modal-corpo {
  overflow-y: auto;
  padding: var(--e5);
  font-size: 0.8125rem;
  text-align: left;
}
/* Ícone à esquerda, título+mensagem à direita, lado a lado (docs/14,
   princípio 2) — antes eram blocos empilhados sem nenhum wrapper flex. */
.dialogo-modal-cabecalho {
  display: flex;
  align-items: flex-start;
  gap: var(--e3);
  margin-bottom: var(--e4);
}
.dialogo-modal-textos {
  flex: 1;
  min-width: 0;
}
.dialogo-modal-icone {
  font-size: 1.75rem;
  line-height: 1;
  flex-shrink: 0;
}
/* ------------------------------------------------------------------
   Variante ALERTA — o Aviso Urgente (docs/24 §6, Prompt #158)
   ------------------------------------------------------------------
   O Aviso Urgente é a comunicação que INTERROMPE e é dispensável (docs/14,
   ao lado do Princípio 35). Até aqui ele usava o mesmo fundo do chrome da
   interface, e era visualmente "mais um card" — um aviso urgente que não se
   distingue do resto falhou no seu único propósito.

   **Derivado de TOKEN, nunca hex fixo.** O #106 e o #118 mostraram que cor
   fixa produz resultado imprevisível num tema de base clara ou
   monocromático: o mesmo vermelho que alerta sobre preto some sobre branco.
   `color-mix` sobre `--sk-danger` resolve nos três de fábrica e em qualquer
   tema futuro, porque a mistura acompanha o `--sk-bg` de cada um.

   **18% é o ponto medido**, não escolhido no olho: abaixo disso a diferença
   contra o fundo normal é imperceptível no Pavimento Mosaico; acima, o
   ganho de separação é marginal e o fundo começa a competir com o texto.
   Com 18%, o texto fica entre 14,19:1 e 15,07:1 nos três temas. */
.dialogo-modal--alerta {
  background: color-mix(in srgb, var(--sk-danger) 18%, var(--sk-bg));
  border-color: var(--sk-danger);
}
/* O ícone da variante usa `--sk-danger-fg`, e não `--sk-warning` como os
   demais diálogos de aviso. Dois motivos, e o segundo foi medido:

   1. Semântica: isto é um ALERTA, não um aviso.
   2. `--sk-warning` (#d9a441) sobre o fundo claro do Pavimento Mosaico dá
      **2,25:1** — abaixo do AA, e já era assim ANTES desta mudança. Sobre o
      fundo de alerta cairia para 1,71:1. Com `--sk-danger-fg`, sobe para
      6,14:1 ali, e fica em 7,27:1 / 6,18:1 nos outros dois. */
.dialogo-modal--alerta .dialogo-modal-icone {
  color: var(--sk-danger-fg);
  /* 50% maior que o 1.75rem padrão (Prompt #158). */
  font-size: 2.625rem;
}
/* Ícone centralizado em relação ao BLOCO de título+mensagem, só nesta
   variante. Com `align-items: flex-start` (o padrão dos demais diálogos),
   um título de duas linhas deixava o ícone pendurado no topo, parecendo
   encolhido ao lado do texto. Centralizar dá a ele o peso de coluna que um
   alerta pede. */
.dialogo-modal--alerta .dialogo-modal-cabecalho {
  align-items: center;
}
.dialogo-modal-icone--critico { color: var(--sk-danger); }
.dialogo-modal-icone--pergunta { color: var(--sk-gold); }
.dialogo-modal-icone--aviso { color: var(--sk-warning); }
.dialogo-modal-icone--informacao { color: var(--sk-gold); }
.dialogo-modal-titulo {
  margin: 0 0 var(--e2);
}
.dialogo-modal-mensagem {
  margin: 0;
  white-space: pre-line;
}
/* Checkbox adjacente ao rótulo (docs/14, princípio 12), mesmo padrão de
   .sk-field-checkbox. */
.dialogo-modal-campo-checkbox {
  display: flex;
  align-items: center;
  gap: var(--e2);
  margin-bottom: var(--e4);
  font-size: 0.75rem;
  color: var(--sk-muted);
}
.dialogo-modal-campo-checkbox label {
  margin-bottom: 0;
}
/* Botões lado a lado (docs/14, princípio 9); quebra em telas estreitas. */
.dialogo-modal-botoes {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--e3);
}
@media (max-width: 480px) {
  .dialogo-modal {
    width: calc(100vw - 24px);
  }
  .dialogo-modal-botoes {
    justify-content: stretch;
  }
  .dialogo-modal-botoes button {
    flex: 1;
  }
}

/* Calculadora de Multa e Juros — LOJA-10 (docs/33 §4, botão
   "Calculadora", Prompt #28). Mesmo mecanismo de <dialog> + ::backdrop
   de docs/18/docs/17, mas com campos de entrada próprios — fora do
   escopo do componente genérico de Diálogo nesta fase (docs/18 §3). */
.calc-multa-juros-modal {
  padding: 0;
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius);
  background: var(--sk-bg);
  color: var(--sk-fg);
  width: min(420px, calc(100vw - 32px));
  max-height: min(85vh, 640px);
}
.calc-multa-juros-modal[open] {
  display: flex;
  flex-direction: column;
}
.calc-multa-juros-modal::backdrop {
  background: rgba(0, 0, 0, 0.6);
}
.calc-multa-juros-modal-cabecalho {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: none;
  padding: var(--e4) var(--e5) 0;
}
.calc-multa-juros-modal-cabecalho h2 {
  margin: 0;
  font-size: 1rem;
}
.calc-multa-juros-modal-fechar {
  background: none;
  border: none;
  color: var(--sk-muted);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  padding: var(--e1) var(--e2);
}
.calc-multa-juros-modal-fechar:hover {
  color: var(--sk-gold);
}
.calc-multa-juros-modal-corpo {
  overflow-y: auto;
  padding: var(--e3) var(--e5) var(--e5);
  font-size: 0.8125rem;
  text-align: left;
}
.calc-multa-juros-modal-aviso {
  color: var(--sk-muted);
  font-size: 0.75rem;
  margin-top: 0;
}
.calc-multa-juros-modal-erro {
  color: var(--sk-danger);
  font-size: 0.75rem;
}
.calc-multa-juros-modal-botoes {
  display: flex;
  justify-content: flex-end;
  margin: var(--e3) 0;
}
.calc-multa-juros-resultado {
  margin: 0;
  padding-top: var(--e3);
  border-top: 0.5px solid var(--sk-border);
}
.calc-multa-juros-resultado dt {
  color: var(--sk-muted);
  font-size: 0.75rem;
}
.calc-multa-juros-resultado dd {
  margin: 0 0 var(--e3);
  font-size: 0.9375rem;
}
@media (max-width: 480px) {
  .calc-multa-juros-modal {
    width: calc(100vw - 24px);
  }
}

/* Central de Ajuda (docs/17, seção 3.2). */
.sk-help-busca {
  display: flex;
  gap: var(--e3);
  margin-top: var(--e3);
}
.sk-help-busca input {
  flex: 1;
  background: color-mix(in srgb, var(--sk-fg) 4%, var(--sk-bg));
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius-sm);
  padding: var(--e2) var(--e3);
  color: var(--sk-fg);
  font-size: 0.8125rem;
  font-family: var(--sk-font-body);
}
.sk-help-artigo + .sk-help-artigo {
  margin-top: var(--e5);
  padding-top: var(--e5);
  border-top: 0.5px solid var(--sk-border);
}

/* Impressão de conteúdo marcado ".sk-imprimivel" (docs/17, item 3.1;
   generalizado para qualquer tela em 03/08/2026 — primeiro reaproveitado
   por MASTER-11, docs/05 seção 2.5) — nunca o fundo escuro do tema Pedra
   Bruta no papel: fundo branco, texto escuro, sempre, independente do tema
   ativo. Acionada por window.print() no ícone 🖨 (data-help-imprimir em
   base.html).

   Técnica "imprime só este elemento" via visibility (não display): esconde
   tudo em <body> e revela só o elemento marcado + seus descendentes — mais
   robusta que listar seletores de chrome um a um (header/nav/footer têm
   classes diferentes em telas diferentes, ex: o cabeçalho do login usa
   .sk-login-header, não .sk-header) e funciona em qualquer tela que tenha
   um container ".sk-imprimivel", sem precisar conhecer sua estrutura de
   antemão. O botão base.html adiciona "sk-imprimindo" ao <body> e
   "sk-artigo-para-imprimir" ao elemento clicado antes de chamar
   window.print(); ambos são removidos no evento "afterprint". */
@media print {
  body {
    background: #fff !important;
    color: #111 !important;
    /* Desfaz o truque de layout fixo (Prompt #60, ver comentário na regra
       `body` acima) — sem isso, `.sk-artigo-para-imprimir` mais alto que
       100vh ficaria cortado pelo `overflow: hidden` da tela. */
    height: auto !important;
    overflow: visible !important;
  }
  .sk-main {
    overflow: visible !important;
    height: auto !important;
  }

  body.sk-imprimindo * {
    visibility: hidden !important;
  }
  body.sk-imprimindo .sk-artigo-para-imprimir,
  body.sk-imprimindo .sk-artigo-para-imprimir * {
    visibility: visible !important;
  }
  body.sk-imprimindo .sk-artigo-para-imprimir {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    background: #fff;
    color: #111;
  }
  /* Botão de imprimir e widget de feedback nunca fazem sentido no papel —
     mesmo sendo descendentes do elemento marcado (portanto "visíveis" pela
     regra acima), display:none sempre vence sobre visibility:visible. */
  body.sk-imprimindo [data-help-imprimir],
  body.sk-imprimindo .sk-help-feedback {
    display: none !important;
  }

  /* O modal do Help Contextual é fixed/limitado em altura com rolagem
     interna e teria fundo escuro — neutraliza tudo isso para não virar o
     contexto de posicionamento do artigo (que usa position:absolute) nem
     cortar o conteúdo em páginas de papel. */
  .sk-help-modal {
    position: static !important;
    max-height: none !important;
    width: auto !important;
    margin: 0 !important;
    border: none !important;
    background: transparent !important;
  }
  .sk-help-modal::backdrop {
    display: none !important;
  }
  .sk-help-modal-corpo {
    overflow: visible !important;
    max-height: none !important;
  }

  .sk-help-imagem img {
    max-width: 100%;
  }

  /* Abas de formulário (docs/05, seção 2.5.2) — no papel, mostra todas as
     abas de uma vez (não só a ativa) e esconde a navegação de abas em si,
     que não faz sentido impresso. [hidden] tem display:none como padrão do
     navegador, sempre vencendo visibility:visible sozinho — precisa do
     display:block explícito aqui. */
  .sk-aba-form-conteudo[hidden],
  .sk-sub-aba-conteudo[hidden] {
    display: block !important;
  }
  .sk-abas-form,
  .sk-sub-abas {
    display: none !important;
  }
}

/* Abas de formulário (docs/05, seção 2.5.2) — CAD-03/MASTER-11: Dados
   Gerais, Endereços, Dados Jurídicos, Responsáveis, Sessões. Mecanismo
   puramente client-side (todos os campos continuam no DOM e são enviados
   juntos no POST — só a exibição alterna), então nenhuma aba perde dado
   ao trocar de outra antes de salvar. */
.sk-abas-form {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e1);
  border-bottom: 0.5px solid var(--sk-border);
  margin-bottom: var(--e4);
}
/* Realce por FUNDO na aba (docs/14, Princípio 37 — Prompt #177), mesma
   lógica de degraus já usada no menu (#107) e no Datagrid (#109): não é
   uma terceira mecânica, é a mesma.

   O DEFEITO QUE ISTO CORRIGE. Até 21/08/2026 o `:hover` daqui mudava só
   a COR do texto — e `.sk-aba-form-botao.active`, com a mesma
   especificidade (0-2-0) e vindo depois no arquivo, vencia. Resultado:
   passar o mouse sobre a aba já ativa não produzia **nenhuma** mudança
   visual (achado do #109, registrado no #110).

   POR QUE FUNDO, e não um tom de cor. Os dois realces passam a viver em
   CANAIS DIFERENTES: o **estado** ativo é cor do texto + borda inferior
   em gold; a **interação** é fundo. Sem disputa de especificidade — não
   é o hover "ganhando" do ativo, é cada um marcando o que lhe cabe.

   Isto é de natureza diferente do `docs/38` §2.8.3, que trata de realce
   de interação ficando ABAIXO do realce de estado: lá havia redução,
   aqui havia AUSÊNCIA. */
.sk-aba-form-botao {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: var(--e2) var(--e4);
  color: var(--sk-muted);
  font-size: 0.875rem;
  cursor: pointer;
  border-radius: var(--sk-radius-sm) var(--sk-radius-sm) 0 0;
  transition: background-color 120ms ease;
}
.sk-aba-form-botao:hover {
  color: var(--sk-fg);
  background: color-mix(in srgb, var(--sk-fg) 8%, var(--sk-bg));
}
.sk-aba-form-botao.active {
  color: var(--sk-gold);
  border-bottom-color: var(--sk-gold);
}
/* A aba ATIVA sob o ponteiro: mantém o gold do estado e ganha o mesmo
   fundo do hover. Escrita separada, com especificidade maior (0-3-0), de
   propósito — se um dia `.active` passar a definir `background`, esta
   regra continua vencendo e o feedback não desaparece de novo em
   silêncio. É a defesa contra a repetição exata do defeito do #110. */
.sk-aba-form-botao.active:hover {
  background: color-mix(in srgb, var(--sk-fg) 8%, var(--sk-bg));
}
/* Foco de teclado (docs/14, princípio 4 — paridade entre apontar e
   navegar): mesmo fundo do hover, MAIS o indicador de foco próprio. */
.sk-aba-form-botao:focus-visible {
  background: color-mix(in srgb, var(--sk-fg) 8%, var(--sk-bg));
  outline: 2px solid var(--sk-gold);
  outline-offset: -2px;
}
.sk-aba-form-conteudo {
  margin-bottom: var(--e4);
}

.sk-sub-abas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e1);
  margin-bottom: var(--e3);
}
.sk-sub-aba-botao {
  padding: var(--e2) var(--e3);
  font-size: 0.8125rem;
}
.sk-sub-aba-conteudo {
  border-top: 0.5px solid var(--sk-border);
  padding-top: var(--e3);
}

/* Gestão de Temas (docs/37) — MASTER-08. */
.sk-tema-seletor {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e3);
  margin-bottom: var(--e4);
}
.sk-tema-seletor select {
  min-width: 220px;
}
.sk-tema-acoes {
  align-items: flex-start;
  margin-bottom: var(--e4);
}
.sk-tema-acoes > details {
  border: 0.5px solid var(--sk-border);
  border-radius: var(--sk-radius-sm);
  padding: var(--e2) var(--e3);
}
.sk-tema-acoes summary {
  cursor: pointer;
  color: var(--sk-gold);
  font-size: 0.8125rem;
}
.sk-tema-acao-form {
  margin-top: var(--e3);
  min-width: 220px;
}
/* Restaurar tema para o padrão (docs/37 §14, Prompt #177). O selo
   "personalizado" e o ↻ por token só existem quando o valor difere do
   `valor_padrao` do catálogo — o próprio par é o indicador do que foi
   customizado, então ele não pode competir com o campo: fica miúdo, em
   `--sk-muted`, à direita. */
/* Destinos de âncora do ↻ (Prompt #178). O `scroll-margin-top` existe
   porque `.sk-main` rola sob um cabeçalho fixo (docs/14, Prompt #60):
   sem ele, o navegador encosta o alvo no topo do container e o elemento
   fica PARCIALMENTE ESCONDIDO atrás do cabeçalho — o campo restaurado
   seria justamente o que não se vê. */
#sk-tokens-de-design,
[data-tema-form-tokens] .sk-field {
  scroll-margin-top: 96px;
}
.sk-tema-tokens-cabecalho {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e3);
}
.sk-tema-restaurar-global {
  margin: 0;
}
.sk-tema-restaurar-token {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--e2);
  margin-top: -8px; /* sk-excecao: compensação negativa cola o controle no bloco acima — a escala não tem passo negativo */
  margin-bottom: var(--e3);
}
.sk-tema-customizado {
  font-size: 0.6875rem;
  color: var(--sk-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.sk-tema-categoria {
  margin: var(--e5) 0 var(--e2);
  font-size: 0.9375rem;
  color: var(--sk-gold);
  border-bottom: 0.5px solid var(--sk-border);
  padding-bottom: var(--e2);
}
.sk-tema-categoria:first-of-type {
  margin-top: 0;
}
/* Campo de Cor: input de texto (aceita rgba(), que <input type="color">
   não representa) + swatch nativo companheiro, sincronizados via JS
   (telefone-mascara.js/cpf-cnpj-mascara.js são o precedente de máscara
   client-side deste projeto; aqui o "sincronizar dois campos" é o
   equivalente para cor). */
.sk-tema-campo-cor {
  display: flex;
  gap: var(--e2);
  align-items: center;
}
.sk-tema-campo-cor input[type="text"] {
  flex: 1;
}
.sk-tema-campo-cor input[type="color"] {
  width: 37px;
  height: 37px;
  padding: 2px;
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius-sm);
  background: var(--sk-surface);
  cursor: pointer;
}

.sk-tema-layout {
  display: flex;
  gap: var(--e6);
  align-items: flex-start;
  flex-wrap: wrap;
}
.sk-tema-layout > .sk-tema-form-coluna {
  flex: 1 1 360px;
  min-width: 0;
}
.sk-tema-preview {
  flex: 1 1 320px;
  min-width: 0;
  position: sticky;
  top: 16px;
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius);
  padding: var(--e4);
  background: var(--sk-bg);
}
.sk-tema-preview-titulo {
  font-size: 0.8125rem;
  color: var(--sk-muted);
  margin: 0 0 var(--e3);
}
.sk-tema-preview-corpo > * {
  margin-bottom: var(--e4);
}
.sk-tema-preview-botoes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e2);
}
.sk-tema-preview-dialogo {
  position: static;
  display: block;
  width: auto;
  max-width: none;
  margin: 0;
  padding: 0;
  border: none;
  background: transparent;
  color: inherit;
}
.sk-tema-preview-dialogo .dialogo-modal-corpo {
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius);
  padding: var(--e4);
  background: var(--sk-surface-solid);
}

/* Combobox Editável com Typeahead (docs/49 §2, Prompt #111) — substitui o
   <datalist> nativo, que só oferecia lista filtrada, sem typeahead inline
   nem controle de teclado. O invólucro é criado pelo próprio JS
   (combobox.js), então nenhuma tela precisa mudar de estrutura. */
.sk-combobox {
  position: relative;
}
.sk-combobox-menu {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 20;
  max-height: 260px;
  overflow-y: auto;
  margin: 2px 0 0;
  padding: var(--e1);
  list-style: none;
  background: var(--sk-surface-solid);
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius-sm);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
}
.sk-combobox-item {
  padding: var(--e2) var(--e3);
  border-radius: var(--sk-radius-sm);
  font-size: 0.8125rem;
  cursor: pointer;
}
/* Mesma escala de realce do menu (docs/20 §7.1.1) e do Datagrid (docs/38
   §2.8.3): o item destacado pelo teclado é o "estado", o hover é a
   "interação" e fica acima dele — nunca abaixo. */
.sk-combobox-item:hover {
  background: color-mix(in srgb, var(--sk-fg) 12%, var(--sk-bg));
}
.sk-combobox-item--ativo {
  background: color-mix(in srgb, var(--sk-fg) 8%, var(--sk-bg));
}
.sk-combobox-item--ativo:hover {
  background: color-mix(in srgb, var(--sk-fg) 18%, var(--sk-bg));
}
.sk-combobox-vazio {
  padding: var(--e2) var(--e3);
  font-size: 0.75rem;
  color: var(--sk-muted);
}

/* Diálogo da navegação rápida por código de tela (docs/14, princípio 3 —
   Prompt #129). `<dialog>` nativo pelo mesmo motivo do Menu Principal e
   do Help Contextual: foco preso e fechar com Esc de graça.

   Ancorado no ALTO da viewport, não centralizado: o gatilho está no
   rodapé, e um diálogo centralizado com um menu de até 260px abrindo
   para baixo encostaria na borda inferior justamente nas telas baixas. */
.sk-navegar-tela {
  margin: 12vh auto auto;
  padding: 0;
  width: 460px;
  max-width: 92vw;
  border: 0.5px solid var(--sk-border-strong);
  border-radius: var(--sk-radius);
  background: var(--sk-surface-solid);
  color: var(--sk-fg);
  /* O menu do combobox é `position: absolute` e cresce para fora do
     corpo do diálogo — qualquer recorte aqui o cortaria pela metade. */
  overflow: visible;
}
.sk-navegar-tela::backdrop {
  background: rgba(0, 0, 0, 0.6);
}
.sk-navegar-tela-corpo {
  padding: var(--e4) var(--e5) var(--e5);
}
.sk-navegar-tela-rotulo {
  display: block;
  font-size: 0.75rem;
  color: var(--sk-muted);
  margin-bottom: var(--e2);
}
.sk-navegar-tela-campo {
  width: 100%;
}
.sk-navegar-tela-dica {
  margin: var(--e2) 0 0;
  font-size: 0.75rem;
  color: var(--sk-muted);
}
.sk-navegar-tela-dica code {
  font-size: 0.75rem;
  color: var(--sk-fg);
}
.sk-navegar-tela-acoes {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--e4);
}

/* Campo preenchido por sugestão do sistema (docs/49 §5, Prompt #122) —
   o auto-preenchimento contextual marca com data-sugerido, e o realce
   some ao primeiro toque do usuário (o JS remove o atributo).

   Realce DISCRETO, como a §5 pede: uma borda à esquerda e um fundo
   levemente destacado, derivados dos tokens do Tema via color-mix (o
   mesmo padrão do zebrado do Datagrid, docs/38 §2.7) — funciona em Tema
   claro e escuro, diferente de um rgba fixo. Nunca a cor de erro nem a
   de aviso: o valor está correto, só não foi digitado pela pessoa. */
[data-sugerido] {
  background: color-mix(in srgb, var(--sk-gold) 8%, var(--sk-bg));
  border-left: 2px solid var(--sk-gold);
}

/* Aba de formulário que contém erro de validação (docs/14, princípio 19 —
   Prompt #126). Marcador DISCRETO: um ponto antes do rótulo, na cor de
   erro, sem mudar o peso nem o tamanho do texto — a aba com erro precisa
   ser notada, não gritar.

   Vem DEPOIS de `.sk-aba-form-botao.active` de propósito: com a mesma
   especificidade (0-2-0), a ordem no arquivo é o que decide, e a aba
   ativa que contém erro deve continuar mostrando o marcador. */
.sk-aba-form-botao--com-erro::before {
  content: "•";
  color: var(--sk-danger-fg);
  margin-right: var(--e2);
  font-weight: 700;
}


/* ---------------------------------------------------------------------
   Gráfico em tela (docs/54, docs/55 §4.2) — o primeiro consumidor real do
   componente, a guia "Lançamentos" da LOJA-34.

   Nada de cor aqui: TODA cor do gráfico vem de token, lida pelo glue em
   `--sk-grafico-serie-*` (docs/54 §5.1). O que este bloco resolve é
   GEOMETRIA, que é o que o canvas não resolve sozinho.
   --------------------------------------------------------------------- */
.sk-grafico-cabecalho {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e3);
}

/* A engrenagem é um `<details>`; sem `position: relative` o painel dela
   empurraria o gráfico para baixo ao abrir, em vez de flutuar sobre ele. */
.sk-grafico-config {
  position: relative;
}
.sk-grafico-config > summary {
  list-style: none;
  cursor: pointer;
}
/* O triângulo nativo do <summary> ao lado de um ícone de engrenagem são
   dois indicadores para a mesma coisa. */
.sk-grafico-config > summary::-webkit-details-marker {
  display: none;
}
.sk-grafico-config-form {
  position: absolute;
  right: 0;
  z-index: 5;
  min-width: 220px;
  padding: var(--e3);
  border: 1px solid var(--sk-border);
  border-radius: var(--sk-radius-sm);
  background: var(--sk-surface-solid, var(--sk-bg));
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.28);
}

/* ALTURA EXPLÍCITA, e é obrigatória: o componente configura a biblioteca
   com `responsive: true` + `maintainAspectRatio: false` (docs/54 §3), e
   nessa combinação o canvas assume a altura do PAI. Sem altura no pai, o
   pai mede a do canvas, o canvas mede a do pai, e o gráfico colapsa para
   zero — some sem erro nenhum no console. */
.sk-grafico-area {
  position: relative;
  height: 320px;
  margin: var(--e4) 0 var(--e6);
}

/* Texto de estado vazio — mesma família visual de `.sk-field-dica`, sem
   ser dica de campo nenhum. */
.sk-vazio {
  color: var(--sk-muted);
  font-style: italic;
}


/* ---------------------------------------------------------------------
   Grade HIERÁRQUICA (LOJA-09, Prompt #146) — categoria em nível zero,
   subcategoria indentada logo abaixo da mãe.

   O recuo é do CONTEÚDO da primeira célula, nunca da linha inteira: uma
   linha deslocada quebraria o alinhamento das demais colunas, e a grade
   deixaria de se ler como tabela.

   O hífen (`.sk-hierarquia-marca`) é `aria-hidden`: para quem ouve a
   tela ele seria ruído, e o nível já é dito pela ordem de leitura.
   --------------------------------------------------------------------- */
.sk-linha-filha > td:first-child {
  padding-left: var(--e6);
}
.sk-hierarquia-marca {
  color: var(--sk-muted);
  user-select: none;
}

/* Listbox do mestre-detalhe (LOJA-09) — aparência de caixa de seleção,
   comportamento de lista de links: navegar no `change` de um `<select>`
   levaria embora quem só estivesse percorrendo as opções pelo teclado. */
.sk-mestre-detalhe {
  margin-top: var(--e5);
}
.sk-listbox {
  list-style: none;
  margin: var(--e2) 0 var(--e3);
  padding: var(--e1);
  max-height: 220px;
  overflow-y: auto;
  border: 1px solid var(--sk-border);
  border-radius: var(--sk-radius-sm);
  background: var(--sk-surface);
}
.sk-listbox li {
  margin: 0;
}
.sk-listbox a {
  display: block;
  padding: var(--e2) var(--e3);
  border-radius: var(--sk-radius-sm);
  text-decoration: none;
  color: var(--sk-fg);
}
.sk-listbox a:hover,
.sk-listbox a:focus-visible {
  background: color-mix(in srgb, var(--sk-gold) 14%, transparent);
}
.sk-listbox-vazio {
  padding: var(--e2) var(--e3);
  color: var(--sk-muted);
  font-style: italic;
}

/* ---------------------------------------------------------------------
   Catálogo Vivo (MASTER-24, docs/59 §9 fase 1, Prompt #185).
   --------------------------------------------------------------------- */
/* Amostra ESTÁTICA da família "Abas" — mesmo layout de `.sk-abas-form`,
   mas sem ser a classe em si: o mecanismo de abas-form.js opera
   GLOBALMENTE sobre `.sk-abas-form > .sk-aba-form-botao`, e esta amostra
   não pode disparar aquele mecanismo (ver comentário no template). Os
   BOTÕES usam a classe real `.sk-aba-form-botao` — só o contêiner é
   próprio. */
.sk-abas-form-amostra {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e1);
  border-bottom: 0.5px solid var(--sk-border);
  margin-bottom: var(--e4);
}
.sk-catalogo-cores-grade {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--e3);
}
.sk-catalogo-cor-amostra {
  display: flex;
  align-items: center;
  gap: var(--e2);
}
.sk-catalogo-cor-swatch {
  display: inline-block;
  width: 28px;
  height: 28px;
  border-radius: var(--sk-radius-sm);
  border: 0.5px solid var(--sk-border-strong);
  flex: none;
}
