/* ==========================================================================
   Odara UI — folha de componentes
   --------------------------------------------------------------------------
   Camada de componente do design system. Fica ACIMA do odara-tokens.css e não
   redeclara nenhum token de marca: cor, fonte, raio, sombra e espaço vêm de lá.

   Uso:
     <link rel="stylesheet" href="odara-tokens.css">
     <link rel="stylesheet" href="odara-ui.css">
   ou, num app com bundler:
     import 'odara-tokens.css'; import 'odara-ui.css';

   Toda classe é prefixada `od-`, e a folha não tem reset nem regra de elemento
   solto (o único seletor global é o de prefers-reduced-motion, no fim). Ou
   seja: importar isto num app existente não muda um pixel até alguém usar uma
   classe. É de propósito, porque os oito apps já têm CSS próprio e o plano é
   migrar tela a tela, não num big bang.

   As medidas vêm de arquitetura/design.md, seção 8, "Medidas de interface".
   Não invente cor nem fonte aqui: se faltar alguma, ela entra no design.md
   primeiro.

   Fundo tingido (selo, foco do campo) vai como rgba() do valor institucional,
   não como color-mix() do token. É feio e duplica o hex, mas um navegador sem
   color-mix descarta a declaração inteira e o selo fica sem preenchimento
   nenhum, que é pior do que duplicado. Os três valores que aparecem são o
   vermelho #EE2737, o verde provisório #2E7D5C e preto puro.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens de interface
   Estes não são de marca, e por isso não moram no odara-tokens.css (aquela
   folha é espelho do Claude Design e a sincronização é de lá pra cá).
   -------------------------------------------------------------------------- */
:root {
  /* Camada. Nunca escreva z-index cru num componente: a ordem é esta e mais
     nenhuma. Um `z-index: 9999` perdido num arquivo é o que faz o autocomplete
     sumir atrás do modal três meses depois. */
  --z-dropdown: 20;
  --z-tooltip:  30;
  --z-sidebar:  40;
  --z-header:   50;
  --z-overlay:  55;
  --z-modal:    60;
  --z-dialogo:  65;
  --z-toast:    70;

  /* Alvo de toque. Chão de fábrica opera de luva, com o tablet apoiado. */
  --toque: 44px;

  /* Teto único da coluna de conteúdo. Um app que precise de outro valor
     redeclara ESTE token, e não empilha um max-width por dentro. */
  --teto-conteudo: 1080px;

  /* Largura mínima de um tile de KPI: é onde um rótulo eyebrow e um número
     condensado ainda cabem sem quebrar linha. */
  --kpi-min: 220px;

  /* Duração por tipo de interação (design.md seção 5). Refina os --dur-1/2/3
     do odara-tokens.css, que são numerados e não dizem para quê servem. */
  --dur-toque:  80ms;   /* clique, toggle, marcar */
  --dur-hover:  200ms;  /* hover, tooltip, dropdown abrindo */
  --dur-painel: 320ms;  /* painel deslizando, transição de card */
  --dur-pagina: 500ms;  /* troca de página */

  /* Texto apagado (placeholder, valor ausente). Falta no odara-tokens.css, que
     para no --fg3; os apps inventaram este quarto nível por conta própria. */
  --fg4: #A79C8B;

  /* Corpo em Medium 500, não Light 300: legibilidade industrial (design.md
     seção 8). Painel lido em pé, sob luz forte, não sustenta o Light. */
  --peso-corpo: var(--w-medium);
}

/* --------------------------------------------------------------------------
   2. Estrutura
   -------------------------------------------------------------------------- */

/* Teto único de largura. Não aninhe dois destes, e não ponha um max-width
   dentro: quando os dois existem, ninguém sabe qual está mandando, e a coluna
   muda de largura entre telas do mesmo app sem motivo aparente. */
.od-conteudo {
  max-width: var(--teto-conteudo);
  margin: 0 auto;
  padding: var(--s-6);
}
@media (max-width: 1100px) {
  .od-conteudo { padding: var(--s-4); max-width: none; }
}

/* --------------------------------------------------------------------------
   3. Botão
   Primário é vermelho sobre areia, a combinação mais Odara. A forma é pill,
   que ecoa o círculo do sol. Hover é opacidade, press é escala: nunca mudança
   de matiz (design.md seção 5).
   -------------------------------------------------------------------------- */
.od-btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--s-2);
  min-height: var(--toque);
  padding: 0 var(--s-5);
  border: none; border-radius: var(--radius-pill);
  font-family: var(--font-body); font-weight: var(--w-demibold);
  font-size: var(--fs-body-s); line-height: 1;
  cursor: pointer;
  transition: opacity var(--dur-hover) var(--ease),
              background var(--dur-hover) var(--ease),
              transform var(--dur-toque) var(--ease);
}
.od-btn:active { transform: scale(.98); }
.od-btn:disabled { opacity: .5; cursor: not-allowed; }
.od-btn:disabled:active { transform: none; }

.od-btn--primario { background: var(--od-vermelho); color: var(--fg-on-loud); }
.od-btn--primario:hover { opacity: .85; }

.od-btn--secundario {
  background: transparent; color: var(--fg1);
  border: 1px solid var(--line-strong);
}
.od-btn--secundario:hover { background: rgba(0, 0, 0, .05); }

/* Ação discreta, sem borda. Nasce na cor de texto da casa: sobre areia, um
   discreto em branco ou em cor clara simplesmente some. */
.od-btn--discreto {
  background: transparent; color: var(--fg1);
  padding: 0 var(--s-3);
}
.od-btn--discreto:hover { text-decoration: underline; }

/* Painel de operação: 1 número grande por tela, 1 ação possível. */
.od-btn--grande {
  min-height: 64px; padding: 0 var(--s-6);
  font-size: var(--fs-body-l);
}

/* --------------------------------------------------------------------------
   4. Campo
   O campo é o poço mais claro sobre o card: areia sobre areia-2. Branco puro
   lê frio e está fora do sistema.
   -------------------------------------------------------------------------- */
.od-rotulo {
  display: block;
  font-family: var(--font-body); font-weight: var(--w-demibold);
  font-size: var(--fs-body-s); color: var(--fg2);
  margin-bottom: var(--s-1);
}
.od-rotulo--obrigatorio::after { content: " *"; color: var(--st-erro); font-weight: var(--w-bold); }

/* Rótulo miúdo de ficha e de KPI: é o eyebrow do design system, e é a única
   caixa alta legítima da interface. */
.od-rotulo-mini {
  display: block;
  font-family: var(--font-body); font-weight: var(--w-demibold);
  font-size: var(--fs-eyebrow); letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase; color: var(--fg3);
}

.od-campo {
  width: 100%;
  min-height: var(--toque);
  background: var(--bg); color: var(--fg1);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: var(--s-2) var(--s-4);
  font-family: var(--font-body); font-weight: var(--peso-corpo);
  font-size: var(--fs-body);
  transition: border-color var(--dur-hover) var(--ease),
              box-shadow var(--dur-hover) var(--ease);
}
.od-campo:focus {
  outline: none;
  border-color: var(--line-strong);
  box-shadow: 0 0 0 3px rgba(238, 39, 55, .22);
}
.od-campo::placeholder { color: var(--fg4); }
.od-campo:disabled { opacity: .55; cursor: not-allowed; }

/* Campo numérico sem as setinhas de incremento: no toque elas ficam coladas no
   número e um encostão muda a quantidade sem ninguém ver. Digitar continua
   igual, e o teclado numérico do celular também. */
.od-campo[type="number"] { -moz-appearance: textfield; appearance: textfield; }
.od-campo[type="number"]::-webkit-outer-spin-button,
.od-campo[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* --------------------------------------------------------------------------
   5. Card
   Nunca card branco elevado sobre branco, que lê frio: areia mais fundo com
   fio de 1px, ou a sombra quente. 24px de padding (design.md seção 4).
   -------------------------------------------------------------------------- */
.od-card {
  background: var(--bg-alt);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: var(--s-5);
}
.od-card--flutua {
  border-color: transparent;
  box-shadow: var(--shadow-md);
}

/* --------------------------------------------------------------------------
   6. Grade de KPI
   Por largura, nunca por número fixo de colunas: grade cravada em três ou
   quatro quebra no tablet em pé, que é boa parte dos nossos painéis, e obriga
   a inventar breakpoint pra cada tela.
   O tile vai com 16px, não 24px: é rótulo mais número, e o padding de card
   cheio só empurra o vizinho pra fora da tela. Vem da grade, não card a card,
   senão vira exceção manual em todo lugar.
   -------------------------------------------------------------------------- */
.od-kpis {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: repeat(auto-fit, minmax(var(--kpi-min), 1fr));
}
.od-kpis > .od-card { padding: var(--s-4); }

.od-kpi { display: flex; flex-direction: column; gap: var(--s-1); }

/* Numeral grande em condensada Heavy com tabular-nums (design.md seção 2). */
.od-kpi-valor {
  font-family: var(--font-condensed); font-weight: var(--w-heavy);
  font-size: 46px; line-height: 1; letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
  color: var(--fg1);
}
@media (max-width: 820px) {
  .od-kpi-valor { font-size: 36px; }
}

/* Faixa de estado no topo do tile. A cor nunca vem sozinha: o rótulo do KPI
   tem que dizer a mesma coisa por escrito (design.md seção 8). */
.od-kpi--ok     { border-top: 3px solid var(--st-sucesso); }
.od-kpi--alerta { border-top: 3px solid var(--st-atencao); }
.od-kpi--erro   { border-top: 3px solid var(--st-erro); }

/* --------------------------------------------------------------------------
   7. Número
   Todo valor é tabular, em qualquer tamanho, inclusive dentro de tabela. Com
   numeral proporcional a coluna deixa de alinhar e o olho perde a grandeza.
   -------------------------------------------------------------------------- */
.od-num {
  font-family: var(--font-condensed); font-weight: var(--w-demibold);
  font-variant-numeric: tabular-nums;
}
/* Mono é pra código, não pra número: lote, chave de NF-e, SKU, CNPJ. */
.od-mono {
  font-family: var(--font-mono); font-weight: var(--w-regular);
  font-size: var(--fs-body-s);
}

/* --------------------------------------------------------------------------
   8. Tabela
   Separação por espaço, nunca por zebra. Cabeçalho em eyebrow.
   -------------------------------------------------------------------------- */
.od-tabela { width: 100%; border-collapse: collapse; font-size: var(--fs-body-s); }
.od-tabela th, .od-tabela td {
  text-align: left; vertical-align: top;
  padding: var(--s-3);
  border-bottom: 1px solid var(--line);
}
.od-tabela th {
  font-family: var(--font-body); font-weight: var(--w-demibold);
  font-size: var(--fs-eyebrow); letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase; color: var(--fg3);
  background: var(--bg-alt);
}
.od-tabela tbody tr:hover { background: rgba(0, 0, 0, .04); }
.od-tabela tfoot td { border-top: 2px solid var(--line-strong); background: var(--bg-alt); }
/* Coluna de número alinha à direita e carrega o tabular. */
.od-tabela td.od-num, .od-tabela th.od-num { text-align: right; }

/* --------------------------------------------------------------------------
   9. Selo de estado
   O texto do selo É o portador do estado; a cor só reforça. Um selo sem
   palavra (só bolinha, só tinta) não passa no daltonismo nem no preto e
   branco, e o design system proíbe.
   -------------------------------------------------------------------------- */
.od-selo {
  display: inline-block;
  padding: 3px 11px;
  border-radius: var(--radius-pill);
  font-family: var(--font-body); font-weight: var(--w-demibold);
  font-size: var(--fs-caption);
}
.od-selo--ok     { background: rgba(46, 125, 92, .15); color: var(--st-sucesso); }
.od-selo--erro   { background: rgba(238, 39, 55, .12); color: var(--st-erro); }
/* Amarelo como cor de TEXTO sobre areia não tem contraste: atenção é sempre
   preenchida, com preto por cima (design.md seção 8). */
.od-selo--alerta { background: var(--st-atencao); color: var(--fg-on-sun); }
/* Estado sem carga (encerrado, arquivado): neutro. Nunca azul de interface. */
.od-selo--neutro { background: rgba(0, 0, 0, .06); color: var(--fg2); }

/* --------------------------------------------------------------------------
   10. Carregamento
   Skeleton, não spinner: já mostra a forma do que vem e não fica girando pra
   sempre quando a requisição morre, que é justamente quando o usuário mais
   precisa entender o que houve.
   -------------------------------------------------------------------------- */
.od-esqueleto {
  display: block;
  background: rgba(0, 0, 0, .06);
  border-radius: var(--radius-sm);
  min-height: 1em;
  animation: od-esqueleto-pulso 1.4s var(--ease) infinite;
}
.od-esqueleto--linha  { height: 1em; margin: var(--s-2) 0; }
.od-esqueleto--titulo { height: 1.6em; width: 40%; margin-bottom: var(--s-3); }
.od-esqueleto--bloco  { height: 120px; }
@keyframes od-esqueleto-pulso {
  0%, 100% { opacity: 1; }
  50%      { opacity: .55; }
}

/* --------------------------------------------------------------------------
   11. Popup
   Regras em design.md, seção 8, "Popup". Em resumo: fecha pelo X redondo no
   canto superior direito, o fundo escuro NÃO fecha, o cabeçalho fica parado e
   quem rola é o corpo, e o aviso de descarte cobre o popup inteiro.

   O comportamento (X, Esc, guarda de saída) está em odara-popup.js, ao lado.
   Esta seção é só a forma.

   Marcação mínima:

     <div class="od-popup-fundo">
       <div class="od-popup" role="dialog" aria-modal="true" aria-label="...">
         <div class="od-popup-painel">
           <div class="od-popup-topo">
             <div class="od-popup-topo-txt">
               <h3 class="od-popup-titulo">Título</h3>
               <p class="od-popup-sub">Subtítulo opcional</p>
             </div>
             <button type="button" class="od-popup-x" aria-label="Fechar">…</button>
           </div>
           <div class="od-popup-corpo">…</div>
         </div>
       </div>
     </div>
   -------------------------------------------------------------------------- */
.od-popup-fundo {
  position: fixed; inset: 0; z-index: var(--z-modal);
  background: rgba(0, 0, 0, .45);
  display: flex; align-items: center; justify-content: center;
  padding: var(--s-4);
}
.od-popup {
  position: relative;
  width: 100%; max-width: 560px; max-height: 90vh;
  background: var(--bg-alt); border-radius: var(--radius-lg);
  display: flex; flex-direction: column;
  overflow: hidden;
}
.od-popup--largo  { max-width: 860px; }
.od-popup--enorme { max-width: 1040px; }

.od-popup-painel { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }

.od-popup-topo {
  flex: 0 0 auto;
  display: flex; align-items: flex-start; gap: var(--s-3);
  padding: var(--s-5) var(--s-5) var(--s-4) var(--s-6);
  border-bottom: 1px solid var(--line);
}
.od-popup-topo-txt { flex: 1 1 auto; min-width: 0; }
.od-popup-acoes { flex: 0 0 auto; display: flex; align-items: center; gap: var(--s-3); }

.od-popup-titulo {
  margin: 0; color: var(--fg1);
  font-family: var(--font-body); font-weight: var(--w-demibold);
  font-size: var(--fs-h4); letter-spacing: -.02em; line-height: 1.2;
}
.od-popup-sub { margin: var(--s-1) 0 0; color: var(--fg3); font-size: var(--fs-body-s); }

/* O corpo é a caixa que rola. `min-height: 0` é o que deixa ela encolher dentro
   do flex: sem isso o painel passa dos 90vh e o rodapé sai da tela. */
.od-popup-corpo { flex: 1 1 auto; min-height: 0; overflow: auto; padding: var(--s-5) var(--s-6) var(--s-6); }

/* O X: círculo, que é a forma-assinatura da marca, no alvo de toque de 44px.
   Dentro dele vai o ícone Lucide `x` em stroke 2, nunca o glifo digitado. */
.od-popup-x {
  flex: 0 0 auto; width: var(--toque); height: var(--toque);
  margin-top: calc(-1 * var(--s-2));
  display: flex; align-items: center; justify-content: center;
  background: transparent; color: var(--fg1);
  border: 1px solid var(--line); border-radius: var(--radius-pill);
  cursor: pointer; transition: background var(--dur-hover) var(--ease);
}
.od-popup-x:hover { background: rgba(0, 0, 0, .06); }
.od-popup-x:active { transform: scale(.94); }
.od-popup-x:disabled { opacity: .4; cursor: not-allowed; }

/* Guarda de saída: cobre o popup inteiro, inclusive o X, pra que a pergunta
   seja respondida e não contornada. */
.od-popup-guarda {
  position: absolute; inset: 0; z-index: var(--z-dialogo);
  background: rgba(0, 0, 0, .45); border-radius: var(--radius-lg);
  display: flex; align-items: center; justify-content: center; padding: var(--s-4);
}
.od-popup-guarda-cx {
  max-width: 420px; padding: var(--s-5);
  background: var(--bg); border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
}
.od-popup-guarda-cx h4 {
  margin: 0 0 var(--s-2); color: var(--fg1);
  font-family: var(--font-body); font-weight: var(--w-demibold); font-size: var(--fs-body-l);
}
.od-popup-guarda-cx p { margin: 0 0 var(--s-5); color: var(--fg3); font-size: var(--fs-body-s); }
/* Lado a lado quando cabe, empilhados e da largura toda quando não cabe: no
   estreito, dois botões meio a meio viram alvo pequeno. */
.od-popup-guarda-bt { display: grid; gap: var(--s-3); grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }

/* Mesmo degrau de tablet do `.od-conteudo`: o popup come a largura toda, porque
   com 32px de folga de cada lado sobra pouco pro campo e o dedo não precisa de
   moldura. */
@media (max-width: 1100px) {
  .od-popup-topo { padding: var(--s-4) var(--s-3) var(--s-3) var(--s-4); }
  .od-popup-corpo { padding: var(--s-4); }
  .od-popup-guarda-cx { padding: var(--s-4); }
}

/* --------------------------------------------------------------------------
   12. Movimento sereno também quer dizer respeitar quem pediu menos movimento.
   Único seletor global desta folha.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ==========================================================================
   Compatibilidade com os nomes que os apps usam hoje
   --------------------------------------------------------------------------
   O odara-producao declara a própria cópia dos tokens com nomes curtos, e o
   comentário no topo daquele arquivo diz que "os nomes aqui são os mesmos de
   lá". Não são todos, e é bom saber antes de trocar um pelo outro:

     --r-sm/md/lg/pill   <->  --radius-sm/md/lg/pill
     --font-cond         <->  --font-condensed
     --sombra            <->  --shadow-md
     --sombra-alta       <->  --shadow-lg
     --space-N           <->  --s-N    ATENÇÃO: as escalas DIVERGEM.
                              --space-:  4 8 12 16 20 24 32 48 64
                              --s-:      4 8 12 16 24 32 48 64 96 128
                              Do quinto em diante os números não batem. Trocar
                              um pelo outro sem olhar muda espaçamento em massa.

   O bloco abaixo faz a ponte só dos que são equivalentes de verdade, pra que
   um app consiga importar esta folha antes de renomear nada. Os --space-N
   ficam de fora de propósito: aquilo não é apelido, é outra escala, e tem que
   ser convertido à mão.
   ========================================================================== */
:root {
  --r-sm:   var(--radius-sm);
  --r-md:   var(--radius-md);
  --r-lg:   var(--radius-lg);
  --r-pill: var(--radius-pill);
  --font-cond:  var(--font-condensed);
  --sombra:     var(--shadow-md);
  --sombra-alta: var(--shadow-lg);
}
