/* ============================================================================
   Portal — estilos de produto sobre os tokens Warm Clean (tokens.css).
   Nunca usar cor crua aqui: sempre var(--...).
   ========================================================================== */

/* Nome do produto ainda não definido (escopo §3.6) — troca em um lugar só. */
:root {
  --nome-produto: 'Portal';
}

/* ---------------------------------------------------------------------------
   Transição entre documentos.

   O Portal é multipágina: cada tela é um HTML próprio e clicar no menu troca o
   documento inteiro. Sem isto, a troca é um branco entre uma página e outra —
   no navegador se lê como "carregando"; instalado como aplicativo, sem barra
   de endereço e sem indicador de carga, se lê como "travou".

   Com `navigation: auto`, o navegador segura a página atual até a próxima
   estar pronta e faz a passagem por esmaecimento. Não vira SPA: o documento
   continua sendo trocado. Some é o branco.

   `view-transition-name` na barra e no cabeçalho marca os dois como o MESMO
   elemento nos dois documentos — em vez de esmaecerem junto com o resto, eles
   ficam parados enquanto o conteúdo troca. É o que dá a impressão de casca fixa.

   Quem não suporta simplesmente navega como antes.
   --------------------------------------------------------------------------- */
@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) { animation-duration: var(--t, 160ms); }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
html, body { margin: 0; padding: 0; }
html { overflow-x: hidden; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-base);
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

a { color: inherit; }
h1, h2, h3, h4, p, ul, figure { margin: 0; padding: 0; }
ul { list-style: none; }
img { max-width: 100%; display: block; }

/* Foco visível em todo lugar — navegação por teclado. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

.container {
  width: 100%;
  max-width: var(--content-max);
  margin: 0 auto;
  padding-inline: var(--sp-6);
}

@media (max-width: 640px) {
  .container { padding-inline: var(--sp-4); }
}

/* ============================================================================
   Cabeçalho comum
   ========================================================================== */
.topo {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--surface);
  background: color-mix(in oklab, var(--surface) 92%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
  /* Casca fixa na troca de página — ver o bloco de transição no topo. */
  view-transition-name: topo;
}
.topo .container {
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
}
.marca {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  text-decoration: none;
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
  letter-spacing: var(--ls-tight);
  font-size: var(--fs-h2);
}
/*
  O selo da marca. Dois estados, e a troca entre eles é feita por CSS puro:

    sem logo  -> quadrado de acento com a letra 'P'
    com logo  -> a imagem da empresa, sem fundo nem letra

  `/marca.css` (servido pelo módulo `src/marca`) declara `--logo` e
  `--logo-selo` quando existe logo. Nada de JavaScript: o logo entra na MESMA
  pintura que o resto da página, em vez de substituir o 'P' depois que a tela
  já apareceu.

  `--logo-selo` é o truque que dispensa um `@if` que o CSS não tem: o valor
  padrão do `var()` só vale quando a variável NÃO está declarada, então basta
  a folha declará-la como string vazia para o 'P' sumir.
*/
.marca .selo {
  width: 30px;
  height: 30px;
  border-radius: var(--r-sm);
  /* Fundo de acento é o estado SEM logo. Com logo, `--logo-fundo:transparent`
     vindo de `/marca.css` o apaga — a maioria dos logos vem em PNG com
     transparência e ficaria ilegível sobre terracota. */
  background-color: var(--logo-fundo, var(--accent));
  /* `contain` e não `cover`: logo é forma, não foto. Cortar a borda de um
     símbolo o descaracteriza; sobrar espaço ao redor, não. */
  background-image: var(--logo, none);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  color: var(--text-on-accent);
  display: grid;
  place-items: center;
  font-weight: var(--fw-bold);
  font-size: var(--fs-sm);
  flex: none;
}
.marca .selo::before { content: var(--logo-selo, 'P'); }
.marca small {
  display: block;
  font-weight: var(--fw-regular);
  color: var(--text-muted);
  font-size: var(--fs-xs);
  letter-spacing: var(--ls-normal);
}

.nav-principal {
  display: flex;
  align-items: center;
  gap: var(--sp-6);
}
.nav-principal a {
  text-decoration: none;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  transition: color var(--t-fast);
}
.nav-principal a:hover { color: var(--text-strong); }

.acoes-topo {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
/* UMA altura para tudo que vive no cabeçalho.
   O alternador de tema era 40px e o Sair era `btn--sm` (32px), lado a lado:
   alinhados no centro, mas com 8px de diferença de altura — um quadrado grande
   ao lado de um botão baixinho. 36px é a altura do `.theme-btn` do styleguide,
   e cabe com folga nos 56px do cabeçalho. */
.acoes-topo .btn,
.acoes-topo .tema-btn { height: 36px; }
.acoes-topo .tema-btn { width: 36px; }

@media (max-width: 860px) {
  .nav-principal { display: none; }
}

/* ============================================================================
   Ícones — sprite Lucide embutido pelo servidor (ver lib/estaticos.ts).

   O <symbol> guarda só a geometria: traço, espessura e tamanho vêm daqui e são
   herdados pelo conteúdo do <use>. Ícone nunca traz cor própria — herda
   `currentColor` de quem o contém, e por isso funciona igual dentro de um botão
   de acento, de um alerta de erro ou de um item de menu apagado.
   ========================================================================== */
.ico {
  width: 16px;
  height: 16px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.ico--md { width: 18px; height: 18px; }
.ico--xl { width: 40px; height: 40px; stroke-width: 1.5; }

/* ============================================================================
   Botões, campos, badges (reuso do vocabulário do styleguide)
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  height: 40px;
  padding: 0 var(--sp-5);
  border-radius: var(--r-md);
  font: inherit;
  font-weight: var(--fw-medium);
  cursor: pointer;
  border: 1px solid transparent;
  transition: background var(--t), border-color var(--t), color var(--t), transform var(--t-fast);
  white-space: nowrap;
  text-decoration: none;
}
.btn:active { transform: translateY(1px); }
.btn--sm { height: 32px; padding: 0 var(--sp-3); font-size: var(--fs-sm); }
.btn--lg { height: 48px; padding: 0 var(--sp-6); font-size: var(--fs-h3); }
.btn--primary { background: var(--accent); color: var(--text-on-accent); }
.btn--primary:hover { background: var(--accent-hover); }
.btn--primary:active { background: var(--accent-active); }
.btn--secondary { background: var(--surface); color: var(--text); border-color: var(--border-input); }
.btn--secondary:hover { background: var(--bg-subtle); border-color: var(--border-strong); }
.btn--ghost { background: transparent; color: var(--accent-text); }
.btn--ghost:hover { background: var(--accent-soft); }
/* `--text-on-danger`, e não `#fff`: `--danger` clareia no modo escuro (para
   ter contraste contra o fundo escuro), e branco sobre esse vermelho claro cai
   para 2,8:1. O token acompanha; a cor cravada não acompanhava. */
.btn--danger { background: var(--danger); color: var(--text-on-danger); }
.btn--danger:hover { filter: brightness(0.94); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
.btn:disabled:hover { background: inherit; }

.link { color: var(--accent-text); text-decoration: none; }
.link:hover { text-decoration: underline; }

.field { display: flex; flex-direction: column; gap: 6px; }
.field > label { font-size: var(--fs-sm); color: var(--text); font-weight: var(--fw-medium); }
.input, .select, textarea.input {
  height: 40px;
  padding: 0 var(--sp-3);
  width: 100%;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-input);
  border-radius: var(--r-md);
  font: inherit;
  transition: border-color var(--t), box-shadow var(--t);
}
textarea.input { height: auto; padding: var(--sp-3); resize: vertical; min-height: 88px; }
.input::placeholder { color: var(--text-faint); }
.input:focus, .select:focus, textarea.input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--ring);
}
.input.is-error { border-color: var(--danger); }
/* Campo só de leitura: precisa PARECER só de leitura antes de a pessoa tentar
   digitar. Sem fundo próprio, ele é idêntico a um campo editável e a única
   pista é o cursor não piscar — o que só se descobre clicando. */
.field--somente-leitura .input {
  background: var(--bg-subtle);
  color: var(--text-muted);
  border-style: dashed;
  cursor: default;
}
.field--somente-leitura .input:focus {
  border-color: var(--border-strong);
  box-shadow: none;
}
.field--somente-leitura > label { color: var(--text-muted); }
.hint { font-size: var(--fs-xs); color: var(--text-faint); }
.hint--error { color: var(--danger-text); }
.select { appearance: none; cursor: pointer; padding-right: 36px; }
.select-wrap { position: relative; }
/* A seta era um quadrado com duas bordas girado 45°. Agora é o chevron do
   Lucide, como no styleguide — mesma família de traço do resto da tela. */
.select-wrap > .ico {
  position: absolute;
  right: var(--sp-3);
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-faint);
  pointer-events: none;
}

.ctl { display: inline-flex; align-items: center; gap: var(--sp-2); cursor: pointer; font-size: var(--fs-sm); color: var(--text); }
.ctl input { width: 18px; height: 18px; accent-color: var(--accent); }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 22px;
  padding: 0 10px;
  border-radius: var(--r-pill);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  white-space: nowrap;
}
/* Ponto de status opcional dentro do badge — herda a cor do próprio badge. */
.badge .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.badge--neutral { background: var(--bg-subtle); color: var(--text-muted); border: 1px solid var(--border); }
.badge--success { background: var(--success-soft); color: var(--success-text); }
.badge--warning { background: var(--warning-soft); color: var(--warning-text); }
.badge--danger  { background: var(--danger-soft); color: var(--danger-text); }
.badge--info    { background: var(--info-soft); color: var(--info); }
.badge--promo   { background: var(--accent-soft); color: var(--accent-text); }

/* Casca de cartão — spec do styleguide, declarada UMA vez. Toda superfície
   elevada do produto entra aqui; as regras próprias de cada uma cuidam só do
   que é específico (padding, layout, sticky). Antes eram sete cópias do mesmo
   trio superfície/borda/raio, e um ajuste de raio exigia caçar as sete. */
.card,
.app-catalogo,
.carrinho-caixa,
.lista-cartao,
.tabela-wrap,
.resumo-lateral,
.resumo-card,
.painel-secao,
.bento-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}

/* Partes do cartão (styleguide): cabeçalho e rodapé separados por hairline. */
.card-head {
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
}
.card-body { padding: var(--sp-5); color: var(--text-muted); }
.card-foot {
  padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-2);
}

.aviso {
  display: flex;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid transparent;
  background: var(--accent-soft);
  color: var(--text);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}
.aviso strong { color: var(--text-strong); }
/* Spec `.alert` do styleguide: o fundo já carrega o significado, então a borda
   colorida sai. Duas camadas de cor na mesma peça pesavam a tela de erro. */
.aviso--erro { border-color: transparent; background: var(--danger-soft); color: var(--danger-text); }
.aviso--ok { border-color: transparent; background: var(--success-soft); color: var(--success-text); }
.aviso--aviso { border-color: transparent; background: var(--warning-soft); color: var(--warning-text); }
.aviso ul { margin: var(--sp-2) 0 0; padding-left: 1.1em; list-style: disc; }
.hint--aviso { color: var(--warning-text); }

/* Um único giro no produto inteiro (spec do styleguide): trilho na cor da
   borda forte, topo no acento. Antes existiam três — este, o `.busca-status-giro`
   e o do carregamento —, cada um com tamanho, cor e keyframe próprios. */
.spinner {
  width: 18px; height: 18px;
  border: 2px solid var(--border-strong);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: girar 0.7s linear infinite;
  display: inline-block;
  flex: none;
}
@keyframes girar { to { transform: rotate(360deg); } }

/* Alternador de tema */
.tema-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  background: var(--surface);
  color: var(--text-muted);
  border: 1px solid var(--border-input);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background var(--t), color var(--t), border-color var(--t);
  flex: none;
}
.tema-btn:hover { background: var(--bg-subtle); color: var(--text); border-color: var(--border-strong); }
.tema-btn svg { width: 18px; height: 18px; }

/* ============================================================================
   Rodapé comum
   ========================================================================== */
.rodape {
  border-top: 1px solid var(--border);
  background: var(--bg-subtle);
  padding-block: var(--sp-8);
  margin-top: var(--sp-12);
}
.rodape .container {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  justify-content: space-between;
  align-items: center;
  color: var(--text-faint);
  font-size: var(--fs-sm);
}
.rodape a { color: var(--text-muted); text-decoration: none; }
.rodape a:hover { color: var(--text-strong); }

/* Skip link — acessibilidade de teclado */
.pular-para-conteudo {
  position: absolute;
  left: -9999px;
  top: var(--sp-2);
  z-index: 100;
  background: var(--accent);
  color: var(--text-on-accent);
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--r-md);
}
.pular-para-conteudo:focus {
  left: var(--sp-4);
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

.nav-principal a.is-ativo { color: var(--text-strong); }

/* ============================================================================
   Landing — hero
   ========================================================================== */
.hero { padding-block: clamp(var(--sp-8), 8vw, 96px) clamp(var(--sp-8), 6vw, 72px); }
.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: clamp(var(--sp-8), 6vw, 80px);
  align-items: center;
}
@media (max-width: 960px) {
  .hero-grid { grid-template-columns: 1fr; }
}

.hero-kicker {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--accent-text);
  font-weight: var(--fw-semibold);
  margin-bottom: var(--sp-4);
}
.hero-texto h1 {
  font-family: var(--font-serif);
  font-weight: var(--fw-medium);
  font-size: clamp(2rem, 1.3rem + 3vw, 3.4rem);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-tight);
  color: var(--text-strong);
}
.hero-destaque { color: var(--accent-text); }
.hero-sub {
  margin-top: var(--sp-5);
  max-width: 52ch;
  color: var(--text-muted);
  font-size: var(--fs-h3);
  line-height: var(--lh-loose);
}
.hero-cta { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-8); }
.hero-nota { margin-top: var(--sp-4); color: var(--text-faint); font-size: var(--fs-sm); max-width: 48ch; }

/* Prévia do produto — não é um blob de gradiente, é uma janela de UI. */
.hero-visual { display: flex; justify-content: center; }
.mock-janela {
  width: 100%;
  max-width: 420px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  transform: rotate(-1.2deg);
}
.mock-barra { display: flex; gap: 6px; padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--border); }
.mock-barra span { width: 9px; height: 9px; border-radius: 50%; background: var(--border-strong); }
.mock-busca {
  margin: var(--sp-4);
  height: 40px;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0 var(--sp-3);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}
.mock-busca .ico { color: var(--text-faint); }
.mock-lista { display: flex; flex-direction: column; }
.mock-lista li { padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--border); }
.mock-linha-topo { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.mock-linha-topo strong { font-size: var(--fs-sm); color: var(--text-strong); }
.mock-lista p { font-size: var(--fs-xs); color: var(--text-faint); margin-top: 2px; }
.mock-linha-preco { display: flex; justify-content: space-between; align-items: baseline; margin-top: var(--sp-2); }
.mock-preco { font-family: var(--font-mono); font-weight: var(--fw-semibold); color: var(--text-strong); }
.mock-qtd { font-size: var(--fs-xs); color: var(--text-faint); }
.mock-linha-consulta { opacity: 0.75; }
.mock-total {
  display: flex;
  justify-content: space-between;
  padding: var(--sp-4);
  background: var(--bg-subtle);
  border-top: 1px solid var(--border);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}
.mock-total strong { font-family: var(--font-mono); color: var(--text-strong); font-size: var(--fs-h3); }

/* ============================================================================
   Seções gerais
   ========================================================================== */
.secao-kicker {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--text-faint);
  font-weight: var(--fw-semibold);
}
.secao-titulo {
  margin-top: var(--sp-2);
  font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2.1rem);
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
  letter-spacing: var(--ls-tight);
  max-width: 32ch;
}

.secao-problema { padding-block: clamp(var(--sp-8), 6vw, 88px); border-top: 1px solid var(--border); background: var(--bg-subtle); }
.lista-editorial { margin-top: var(--sp-8); display: grid; gap: var(--sp-6); }
.lista-editorial article { display: grid; grid-template-columns: 64px 1fr; gap: var(--sp-5); padding-bottom: var(--sp-6); border-bottom: 1px dashed var(--border); }
.lista-editorial article:last-child { border-bottom: none; padding-bottom: 0; }
.lista-editorial .numero {
  font-family: var(--font-serif);
  font-size: 2rem;
  color: var(--accent-border);
  line-height: 1;
}
.lista-editorial h3 { font-size: var(--fs-h2); color: var(--text-strong); font-weight: var(--fw-semibold); }
.lista-editorial p { margin-top: var(--sp-2); color: var(--text-muted); max-width: 60ch; }
@media (max-width: 640px) {
  .lista-editorial article { grid-template-columns: 1fr; gap: var(--sp-2); }
}

/* Vantagens — bento assimétrico */
.secao-vantagens { padding-block: clamp(var(--sp-8), 6vw, 88px); }
.bento {
  margin-top: var(--sp-8);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: minmax(140px, auto);
  gap: var(--sp-4);
}
.bento-item {
  padding: var(--sp-5);
  grid-column: span 2;
  transition: border-color var(--t), box-shadow var(--t), transform var(--t);
}
.bento-item:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); transform: translateY(-2px); }
.bento-item--grande { grid-column: span 2; grid-row: span 2; background: var(--accent-soft); border-color: var(--accent-border); }
.bento-item--largo { grid-column: span 4; }
.bento-item h3 { font-size: var(--fs-h2); color: var(--text-strong); font-weight: var(--fw-semibold); }
.bento-item p { margin-top: var(--sp-2); color: var(--text-muted); }
.bento-item--grande h3 { font-size: var(--fs-h1); }
@media (max-width: 860px) {
  .bento { grid-template-columns: repeat(2, 1fr); }
  .bento-item, .bento-item--largo { grid-column: span 2; }
  .bento-item--grande { grid-row: span 1; }
}
@media (max-width: 480px) {
  .bento { grid-template-columns: 1fr; }
  .bento-item, .bento-item--largo, .bento-item--grande { grid-column: span 1; }
}

/* Como funciona — passos conectados */
.secao-passos { padding-block: clamp(var(--sp-8), 6vw, 88px); border-top: 1px solid var(--border); background: var(--bg-subtle); }
.passos {
  margin-top: var(--sp-8);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-6);
  position: relative;
}
.passos li { position: relative; padding-top: var(--sp-2); }
.passo-numero {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--text-on-accent);
  font-weight: var(--fw-semibold);
  margin-bottom: var(--sp-4);
}
.passos h3 { font-size: var(--fs-h3); color: var(--text-strong); font-weight: var(--fw-semibold); }
.passos p { margin-top: var(--sp-2); color: var(--text-muted); font-size: var(--fs-sm); }
@media (max-width: 860px) {
  .passos { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
  .passos { grid-template-columns: 1fr; }
}

/* CTA final */
.cta-final { padding-block: clamp(var(--sp-10), 8vw, 112px); background: var(--accent); }
.cta-final-conteudo { text-align: center; display: flex; flex-direction: column; align-items: center; gap: var(--sp-4); }
.cta-final h2 {
  font-family: var(--font-serif);
  font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.4rem);
  color: var(--text-on-accent);
  max-width: 24ch;
}
.cta-final p { color: var(--text-on-accent); opacity: 0.9; }
.cta-final .btn--primary { background: var(--text-on-accent); color: var(--accent-active); }
.cta-final .btn--primary:hover { background: var(--surface); }

/* ============================================================================
   Entrar (login + cadastro)
   ========================================================================== */
.pagina-entrar { display: flex; flex-direction: column; min-height: 100vh; }
.topo--simples .container { justify-content: space-between; }

.entrar-layout {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr);
}
@media (max-width: 860px) {
  .entrar-layout { grid-template-columns: 1fr; }
}

.entrar-lateral {
  background: var(--surface-nav);
  border-right: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-10);
}
@media (max-width: 860px) { .entrar-lateral { display: none; } }
.entrar-lateral blockquote {
  max-width: 34ch;
  font-family: var(--font-serif);
  font-size: 1.6rem;
  line-height: var(--lh-loose);
  color: var(--text-strong);
}
.entrar-lateral footer {
  margin-top: var(--sp-5);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  color: var(--text-faint);
}

.entrar-painel {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: clamp(var(--sp-6), 6vw, 96px) var(--sp-5);
}
.entrar-caixa { width: 100%; max-width: 440px; }

.tabs { display: flex; gap: var(--sp-5); border-bottom: 1px solid var(--border); margin-bottom: var(--sp-6); }
.tab {
  padding: 10px 2px;
  color: var(--text-muted);
  cursor: pointer;
  border: none;
  background: transparent;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  font: inherit;
}
.tab.is-active { color: var(--text-strong); border-bottom-color: var(--accent); font-weight: var(--fw-medium); }

.entrar-titulo {
  font-family: var(--font-serif);
  font-size: var(--fs-display);
  font-weight: var(--fw-medium);
  color: var(--text-strong);
  margin-bottom: var(--sp-6);
}
.entrar-form { display: flex; flex-direction: column; gap: var(--sp-5); }
.entrar-form .aviso ul { margin: var(--sp-2) 0 0; padding-left: 1.1em; list-style: disc; }
.entrar-botao { width: 100%; margin-top: var(--sp-2); }
.campo-honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.visualmente-oculto {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ============================================================================
   App (catálogo + carrinho)
   ========================================================================== */
.pagina-app { background: var(--bg-subtle); min-height: 100vh; }
.pagina-app .topo { background: var(--surface); }
.nome-usuario { color: var(--text-muted); font-size: var(--fs-sm); margin-right: var(--sp-1); }

.app-layout {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--sp-6);
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: var(--sp-6);
  align-items: start;
}
@media (max-width: 960px) {
  .app-layout { grid-template-columns: 1fr; }
}

.app-catalogo { padding: var(--sp-6); }
.app-catalogo-topo { display: flex; flex-direction: column; gap: var(--sp-4); }
.app-titulo { font-size: var(--fs-h1); font-weight: var(--fw-semibold); color: var(--text-strong); }

.barra-busca {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 200px auto;
  gap: var(--sp-3);
  align-items: center;
}
@media (max-width: 720px) {
  .barra-busca { grid-template-columns: 1fr; }
}
.campo-busca { display: block; }
.input-icone { position: relative; }
.input-icone .input { padding-left: 36px; }
/* A lupa era um círculo com um traço girado; agora é o `search` do Lucide. */
.input-icone > .ico {
  position: absolute;
  left: var(--sp-3);
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-faint);
  pointer-events: none;
}

.lista-resultados {
  margin-top: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
/* Estado vazio — spec `.empty` do styleguide: respiro generoso, título forte
   opcional (o <strong>) e o texto de apoio em muted, não em faint. */
.estado-vazio { color: var(--text-muted); padding: var(--sp-10) var(--sp-5); text-align: center; }
.estado-vazio strong {
  display: block;
  color: var(--text-strong);
  font-size: var(--fs-h2);
  font-weight: var(--fw-semibold);
  margin-bottom: 6px;
}

/* Estado de busca em andamento ---------------------------------------------
   Duas peças com papéis diferentes: o giro diz "recebi o que você digitou" e
   aparece na hora; o esqueleto diz "o resultado vem aqui" e só entra quando a
   espera passa do limiar, para busca rápida não piscar. */
.busca-status {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}
.busca-status[hidden] { display: none; }
/* O giro é o `.spinner` do styleguide — não há mais um giro só da busca. */

/* Resultado anterior continua legível, só recuado — quem estava comparando
   itens não perde o que estava lendo enquanto a busca nova não chega. */
.lista-resultados--buscando .resultado-card:not(.resultado-card--esqueleto) {
  opacity: 0.55;
  transition: opacity var(--t);
}

.resultado-card--esqueleto { pointer-events: none; }
.resultado-card--esqueleto .resultado-info { display: flex; flex-direction: column; gap: var(--sp-2); }

.esqueleto {
  display: block;
  height: 0.75rem;
  border-radius: var(--r-xs);
  background: var(--skeleton);
  position: relative;
  overflow: hidden;
}
/* O brilho é uma camada separada para o bloco manter cor sólida quando a
   animação estiver desligada por preferência do sistema. */
.esqueleto::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, var(--skeleton-brilho), transparent);
  animation: esqueleto-brilho 1200ms ease-in-out infinite;
}
.esqueleto--titulo { height: 1rem; width: 42%; }
.esqueleto--linha { width: 68%; }
.esqueleto--meta { width: 30%; }
.esqueleto--preco { height: 1rem; width: 88px; }
.esqueleto--botao { height: 2rem; width: 140px; border-radius: var(--r-sm); }

@keyframes esqueleto-brilho { to { transform: translateX(100%); } }

/* A regra global de reduced-motion zera a DURAÇÃO das animações, o que deixaria
   um anel parado e um brilho congelado no meio do bloco — formas sem sentido.
   Aqui eles somem de vez: o texto "Buscando…" já carrega a informação. */
@media (prefers-reduced-motion: reduce) {
  .busca-status .spinner { display: none; }
  .esqueleto::after { display: none; }
}
.estado-vazio--erro { color: var(--danger-text); }

.resultado-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-4);
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: border-color var(--t), background var(--t);
}
.resultado-card:hover { border-color: var(--border-strong); background: var(--bg-subtle); }
.resultado-topo { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); }
.resultado-descricao { font-size: var(--fs-h3); color: var(--text-strong); font-weight: var(--fw-semibold); }
.resultado-meta { margin-top: var(--sp-2); display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; }
/* Código e referência com o MESMO tratamento: são identificadores irmãos, um da
   casa e outro do fabricante. Tratamentos diferentes fariam parecer que um vale
   mais que o outro. */
.resultado-codigo,
.resultado-referencia { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-faint); }

/* ---------------------------------------------------------------------------
   Linhas de detalhe do item — spec do styleguide (.item-tax / .item-saldo /
   .item-loc / .item-cost). Todas em `fs-xs` e `muted`: são metadados, não
   podem competir com a descrição nem com o preço. Cada uma só existe quando o
   dado veio na resposta; o corte de quem pode ver está no servidor.
   --------------------------------------------------------------------------- */
.item-tax,
.item-avail,
.item-saldo,
.item-loc,
.item-cost {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-top: 2px;
  font-size: var(--fs-xs);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.item-tax { align-items: baseline; gap: 6px; }
/* Disponibilidade é a única linha com peso: é a resposta a "quando chega". */
.item-avail { font-weight: var(--fw-semibold); }
.item-avail.is-ok { color: var(--success-text); }
.item-avail.is-warn { color: var(--text-muted); }
.item-tax .tax-sep { color: var(--text-faint); }
.item-saldo .ico,
.item-loc .ico { width: 13px; height: 13px; color: var(--accent); }

/* Custo é o único que nasce oculto: o olho revela sob clique. Ver na tela um
   número de custo por acidente, com o cliente ao lado, é o risco que a máscara
   evita — a flag decide se ele existe, o olho decide se ele aparece agora. */
.item-cost-toggle {
  flex: none;
  box-sizing: content-box;
  width: 13px;
  height: 13px;
  padding: 4px;
  margin: -4px;
  border: none;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--accent);
  display: inline-grid;
  place-items: center;
  cursor: pointer;
  transition: color var(--t-fast), background var(--t-fast);
}
.item-cost-toggle .ico { width: 13px; height: 13px; }
.item-cost-toggle:hover { color: var(--accent-text); background: var(--accent-soft); }
.item-cost-toggle:active { color: var(--accent); background: var(--accent-soft); }
.item-cost-value { font-family: var(--font-mono); }
.item-cost-mask { letter-spacing: 1.5px; color: var(--text-faint); }
.item-cost.is-revealed .item-cost-value { color: var(--text-strong); font-weight: var(--fw-semibold); }

.resultado-acao {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-2);
  min-width: 140px;
}
.resultado-preco { font-family: var(--font-mono); font-weight: var(--fw-semibold); font-size: var(--fs-h3); color: var(--text-strong); }
.resultado-preco--consulta { font-family: var(--font-sans); font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--text-faint); }
/* Seletor de quantidade — spec `.stepper` do styleguide. Antes era um
   `<input type="number">` cru: as setinhas nativas do navegador (que não seguem
   tema, nem tamanho, nem traço de nada) eram os únicos "botões" ali, e o campo
   tinha 36px de altura contra 32px do botão Adicionar ao lado. Grudados na
   mesma linha, os 4px de diferença apareciam.

   No styleguide o stepper (36px) convive com `.btn--sm` (32px) porque estão em
   grupos separados da linha, com o total entre eles. Aqui são adjacentes, então
   têm de ter a MESMA altura — e a do stepper é a que manda, porque 32px de alvo
   de toque para um botão de 34px de largura é pequeno demais no celular. */
.resultado-adicionar { display: flex; align-items: center; gap: var(--sp-2); }
.resultado-adicionar .btn { height: 36px; }

.stepper {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--border-input);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface);
  flex: none;
}
.step-btn {
  width: 34px;
  height: 36px;
  display: inline-grid;
  place-items: center;
  border: none;
  background: transparent;
  color: var(--text);
  cursor: pointer;
  transition: background var(--t-fast);
}
.step-btn:hover { background: var(--bg-subtle); }
.step-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.step-input {
  width: 46px;
  height: 36px;
  border: none;
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  text-align: center;
  background: var(--surface);
  color: var(--text-strong);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-body);
  outline: none;
}
.step-input:disabled { color: var(--text-faint); }
/* Sem anel de foco aqui: o campo já está dentro de uma moldura, e o anel
   desenharia um retângulo por cima da borda do stepper. */
.step-input:focus-visible { box-shadow: none; }

.paginacao {
  margin-top: var(--sp-6);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-4);
}
.paginacao-info { color: var(--text-muted); font-size: var(--fs-sm); }

/* Carrinho lateral */
.app-carrinho { position: sticky; top: calc(var(--header-h) + var(--sp-4)); }
.carrinho-caixa {
  padding: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.carrinho-titulo { font-size: var(--fs-h2); font-weight: var(--fw-semibold); color: var(--text-strong); }
.carrinho-itens { display: flex; flex-direction: column; gap: var(--sp-3); max-height: 46vh; overflow-y: auto; }
.carrinho-vazio { color: var(--text-faint); font-size: var(--fs-sm); padding: var(--sp-3) 0; }
/* ---------------------------------------------------------------------------
   Item do carrinho — spec `.cart-item` do styleguide.

   Recolhido: descrição + "N un × R$ valor" à esquerda, subtotal e setinha à
   direita. Expandido: quantidade, Excluir e Confirmar. A setinha é a pista de
   que há mais coisa ali — sem ela, controles permanentes em cada linha enchiam
   uma barra lateral de 298px e ainda assim não davam onde ajustar direito.
   --------------------------------------------------------------------------- */
.carrinho-item {
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--border);
}
.cart-item {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  cursor: pointer;
}
.cart-item .item-main { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
.cart-item .item-price {
  flex: none;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
  font-size: var(--fs-sm);
  white-space: nowrap;
}
.cart-qty { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--fs-xs); color: var(--text-muted); }
.cart-toggle {
  flex: none;
  width: 28px;
  height: 28px;
  border: none;
  background: transparent;
  color: var(--text-muted);
  display: inline-grid;
  place-items: center;
  cursor: pointer;
  border-radius: var(--r-sm);
  transition: transform var(--t), background var(--t);
}
.cart-toggle:hover { background: var(--bg-subtle); color: var(--text); }
.carrinho-item.is-open .cart-toggle { transform: rotate(180deg); }

/* Altura animada por grid-template-rows: 0fr → 1fr. Anima sem precisar saber
   a altura do conteúdo de antemão, e sem mexer em `height` (que o compositor
   não acelera). */
.item-detail {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--t-slow);
}
.carrinho-item.is-open .item-detail { grid-template-rows: 1fr; }
.item-detail > .detail-inner { overflow: hidden; }
.detail-pad {
  padding-top: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.qty { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.qty-label { font-size: var(--fs-sm); color: var(--text-muted); }
.detail-actions { display: flex; gap: var(--sp-2); justify-content: flex-end; }

.carrinho-total {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
  font-size: var(--fs-h3);
  color: var(--text-strong);
}
.carrinho-total strong { font-family: var(--font-mono); font-size: var(--fs-h1); }
.carrinho-acoes { display: flex; flex-direction: column; gap: var(--sp-2); }
.form-cotacao { display: flex; flex-direction: column; gap: var(--sp-3); border-top: 1px solid var(--border); padding-top: var(--sp-4); }
.form-cotacao-acoes { display: flex; justify-content: flex-end; gap: var(--sp-2); }

/* A navegação das páginas autenticadas mora agora na barra lateral
   (nav.js / nav.css) — o cabeçalho aqui só cuida de marca, nome do usuário,
   tema e sair, então só precisa quebrar linha se isso não couber. */
@media (max-width: 760px) {
  .pagina-app .topo .container,
  .pagina-secao .topo .container {
    flex-wrap: wrap;
    height: auto;
    padding-block: var(--sp-3);
    row-gap: var(--sp-2);
  }
}

/* ============================================================================
   Páginas internas (cotações, pedidos, painel) — layout comum
   ========================================================================== */
.pagina-secao { background: var(--bg-subtle); min-height: 100vh; }
.pagina-secao .topo { background: var(--surface); }

.secao-conteudo {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--sp-6);
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}

.secao-cabecalho {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
}
.secao-cabecalho h1 {
  font-family: var(--font-serif);
  font-size: var(--fs-display);
  font-weight: var(--fw-medium);
  color: var(--text-strong);
}
.secao-cabecalho p { color: var(--text-muted); margin-top: var(--sp-1); max-width: 60ch; }

.filtros-barra {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  /* Alinhado pela BASE, não pelo centro. O campo é rótulo + caixa e fica mais
     alto que o botão; centralizar punha o botão no meio dessa altura total, ou
     seja, uns 10px ACIMA da linha das caixas. Pela base, a caixa e o botão
     dividem a mesma borda inferior. */
  align-items: flex-end;
  /* A barra precisa de ar dos dois lados: colada no texto acima ela parecia
     parte do subtítulo, e colada na lista abaixo parecia o cabeçalho dela. */
  margin-block: var(--sp-5) var(--sp-6);
}
.filtros-barra .select-wrap { min-width: 180px; }
/* Filtros do histórico: campos rasos lado a lado, a descrição mais larga
   porque é a única que recebe texto livre. */
.filtros-barra .field { min-width: 150px; }
.filtros-barra .field--largo { flex: 1 1 240px; }
.filtros-barra .field > label { font-size: var(--fs-xs); color: var(--text-muted); }
.filtros-acoes { display: flex; align-items: center; gap: var(--sp-2); }
/* Ação com a MESMA altura da caixa (40px). Com `btn--sm` de 32px o botão
   flutuava dentro da faixa dos campos em vez de ocupá-la. */
.filtros-barra .btn { height: 40px; }
/* Campo de data encolhia a ~24px dentro do flex e virava um quadradinho vazio
   ao lado dos outros filtros. `type=date` não tem largura intrínseca útil. */
.filtros-barra input[type='date'] { min-width: 150px; }
/* Marcadores não são caixas de digitar: sem esta altura eles alinhavam pela
   base do próprio texto, uns 12px abaixo da linha das caixas. Ocupar a mesma
   altura de uma caixa põe o marcador no centro dela. */
.filtros-marcadores {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  min-height: 40px;
}
/* Barra encaixada no cabeçalho da seção — ali o respiro vem do próprio
   cabeçalho, e a margem própria empurrava o título para fora do centro. */
.painel-secao-cabecalho .filtros-barra { margin-block: 0; }

/* ---------------------------------------------------------------------------
   Barra de filtro em MAIS DE UMA LINHA (aba Pedidos do painel)

   Depois das regras de uma linha só, de propósito: `.filtros-linha .field` e
   `.filtros-barra .field` têm a mesma especificidade, então quem vem por
   último manda. Declaradas antes, o `min-width: 150px` da barra simples
   vencia todas as larguras daqui e a linha estourava.
   --------------------------------------------------------------------------- */
.filtros-barra:has(.filtros-linha) {
  flex-direction: column;
  align-items: stretch;
  gap: var(--sp-4);
}
/* `nowrap` de propósito, e é a correção de um defeito real.
 *
 * Com `wrap`, a soma das larguras dos campos batia EXATAMENTE na largura da
 * linha; o arredondamento de sub-pixel estourava por décimos e a linha inteira
 * caía para baixo, deixando uma faixa vazia de 75px sob o título. Sem wrap os
 * campos ENCOLHEM (todos têm `flex-shrink`), que é uma degradação contínua e
 * previsível em vez de um salto.
 *
 * A quebra volta por consulta de mídia, onde ela é uma decisão e não um
 * acidente de meio pixel. */
.filtros-linha {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--sp-3);
  align-items: flex-end;
}
@media (max-width: 1080px) {
  .filtros-linha { flex-wrap: wrap; }
}
/* LARGURA DECLARADA, nunca derivada do conteúdo.
 *
 * Com `flex-basis: auto` cada campo media o próprio rótulo, dava um número
 * fracionário, e a soma dos quatro batia exatamente na largura da linha. O
 * arredondamento de sub-pixel estourava por décimos e o `flex-wrap` jogava a
 * linha INTEIRA para baixo — o que na tela aparecia como um vão de 75px sob o
 * título, e não como um campo fora do lugar. */
.filtros-linha .field { flex: 0 1 164px; min-width: 0; }
.filtros-linha .field--largo { flex: 1 1 200px; }
.filtros-linha .field--curto { flex: 0 1 126px; }
/* `type=date` não tem largura intrínseca útil; sem medida vira um quadradinho. */
.filtros-linha .field--data { flex: 0 0 142px; }
/* "Em processamento" é a opção mais longa e define a medida deste select. */
.filtros-linha .field--situacao { flex: 0 1 178px; }
.filtros-linha .field > label { font-size: var(--fs-xs); color: var(--text-muted); }
/* O piso de 180px é da barra de uma linha só; aqui quem mede é o campo. */
.filtros-linha .select-wrap { min-width: 0; }
.filtros-linha input[type='date'] { min-width: 0; }
/* Empurradas para a direita: quando a linha comporta tudo, elas fecham a
   sequência; quando não comporta, caem para baixo alinhadas à borda direita,
   onde continuam se lendo como o fim da barra e não como uma linha órfã. */
.filtros-linha .filtros-acoes { margin-left: auto; }

/* Lista em cartão — cotações e pedidos */
.lista-cartao { overflow: hidden; }
.linha-lista {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) auto auto;
  gap: var(--sp-4);
  align-items: center;
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  color: inherit;
  transition: background var(--t-fast);
}
a.linha-lista { cursor: pointer; }
.linha-lista:last-child { border-bottom: none; }
.linha-lista:hover, .linha-lista:focus-visible { background: var(--bg-subtle); }
.linha-lista-titulo { font-weight: var(--fw-semibold); color: var(--text-strong); font-size: var(--fs-h3); }
.linha-lista-sub { color: var(--text-faint); font-size: var(--fs-xs); margin-top: 2px; }
.linha-lista-valor { font-family: var(--font-mono); text-align: right; color: var(--text-strong); font-weight: var(--fw-medium); }
.linha-lista-valor small { display: block; font-family: var(--font-sans); color: var(--text-faint); font-size: var(--fs-xs); font-weight: var(--fw-regular); }
.linha-lista-valor .valor-riscado { text-decoration: line-through; color: var(--text-faint); font-size: var(--fs-xs); display: block; }
@media (max-width: 720px) {
  .linha-lista { grid-template-columns: 1fr auto; }
  .linha-lista-valor { grid-column: 1 / -1; text-align: left; }
}

/* ---------------------------------------------------------------------------
   Consulta de pedidos — spec `.orders` do styleguide: acordeão. Cada pedido é
   um cartão com data e status; abrir mostra os itens ali mesmo, sem trocar de
   tela. A versão anterior era uma lista que levava a uma página de detalhe —
   comparar dois pedidos exigia ir e voltar duas vezes.
   --------------------------------------------------------------------------- */
.orders { display: flex; flex-direction: column; gap: var(--sp-3); }
/* Consulta em andamento: o resultado ANTERIOR fica na tela, esmaecido.
   Esvaziá-lo antes da resposta encolhia a página e a devolvia depois — o
   vai-e-vem que se lê como a tela piscando. `opacity` é do compositor, então
   o esmaecer não custa relayout. */
.orders--carregando {
  opacity: 0.5;
  pointer-events: none;
  transition: opacity var(--t);
}
.order { border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--surface); overflow: hidden; }
.order-head {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: transparent;
  border: none;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
}
.order-head:hover { background: var(--bg-subtle); }
.order-title { font-weight: var(--fw-semibold); color: var(--text-strong); display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.order-date { font-size: var(--fs-sm); color: var(--text-muted); font-weight: var(--fw-regular); }
/* Valor e status ficam juntos, encostados à direita. */
.order-head .oi-valor { margin-left: auto; }
.order-head .badge { flex: none; }
.order-chevron { color: var(--text-muted); transition: transform var(--t); flex: none; }
.order.is-open .order-chevron { transform: rotate(180deg); }
.order-body { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--t-slow); }
.order.is-open .order-body { grid-template-rows: 1fr; }
.order-body > .ob-inner { overflow: hidden; }
.order-item {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: 10px var(--sp-4);
  border-top: 1px solid var(--border);
}
.oi-desc { display: flex; align-items: baseline; gap: var(--sp-3); color: var(--text); font-size: var(--fs-sm); min-width: 0; }
/* Código do produto na frente, em coluna de largura fixa e alinhado à direita:
   os códigos empilham em coluna e todas as descrições começam no mesmo ponto.
   Sem isso a descrição arrasta o código para uma posição diferente em cada
   linha e a lista deixa de ser varrível pelo código. */
.oi-cod {
  flex: none;
  min-width: 5ch;
  text-align: right;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.oi-nome { min-width: 0; overflow-wrap: anywhere; }
.oi-meta { display: flex; align-items: center; gap: 10px; flex: none; flex-wrap: wrap; justify-content: flex-end; }
.oi-qty { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--text-muted); font-size: var(--fs-sm); }
/* A direita da linha é uma TABELA sem cabeçalho: quantidade × unitário, total,
   nota. Cada uma com largura mínima e alinhada à direita, senão a largura do
   texto de uma linha empurra a coluna da linha seguinte — `150 un × R$ 0,15` e
   `8 un × R$ 1,47` saíam em posições diferentes e nada batia na vertical. */
.order-item .oi-qty { min-width: 16ch; text-align: right; }
.order-item .oi-valor { min-width: 10ch; text-align: right; }
.order-item .oi-nf { min-width: 10ch; justify-content: flex-end; }
.oi-valor { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--text-strong); font-size: var(--fs-sm); font-weight: var(--fw-medium); }
/* Endereço de armazém no item do pedido — é o que a expedição lê para separar. */
.oi-local { display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs-xs); color: var(--text-muted); white-space: nowrap; }
.oi-local .ico { width: 13px; height: 13px; color: var(--accent); }
/* Nota fiscal DO ITEM — spec `.oi-nf` do styleguide. Fica no item porque
   faturamento parcial gera uma nota por remessa; no cabeçalho só caberia a
   primeira, e ela pareceria valer pelo pedido inteiro. */
.oi-nf {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-xs);
  color: var(--accent-text);
  font-family: var(--font-mono);
  white-space: nowrap;
}
.oi-nf .ico { width: 13px; height: 13px; }
/* Ainda sem nota: continua ocupando a linha, apagado. Sumir faria a coluna
   dançar entre itens faturados e não faturados do mesmo pedido. */
.oi-nf--pending { color: var(--text-faint); font-family: var(--font-sans); }
/* Linha de associação com o ERP, dentro do pedido aberto. */
.vinculo-sistema { align-items: center; background: var(--bg-subtle); }
.vinculo-sistema .oi-desc { font-weight: var(--fw-medium); }
.vinculo-sistema .oi-meta { flex-direction: column; align-items: flex-end; gap: 2px; }
.vinculo-sistema .input { width: 220px; height: 32px; font-family: var(--font-mono); }

.order-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--border);
  background: var(--bg-subtle);
}
.order-foot .oi-valor { font-size: var(--fs-h3); }

/* No estreito a linha do item empilha: descrição em cima, quantidade, nota e
   valor embaixo, alinhados à esquerda. Espremidos lado a lado, o chip da nota e
   o valor quebravam no meio do número. */
@media (max-width: 560px) {
  .order-item { flex-direction: column; gap: var(--sp-2); }
  .oi-meta { justify-content: flex-start; }
}

/* Detalhe (cotação/pedido) */
.detalhe-voltar { display: inline-flex; align-items: center; gap: var(--sp-2); color: var(--text-muted); font-size: var(--fs-sm); text-decoration: none; }
.detalhe-voltar:hover { color: var(--text-strong); }
.detalhe-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: var(--sp-6);
  align-items: start;
}
@media (max-width: 960px) { .detalhe-grid { grid-template-columns: 1fr; } }

.tabela-wrap { overflow-x: auto; }
/* Tabela — spec `.tbl` do styleguide. As três peças que faltavam e que fazem a
   leitura de uma grade larga: zebra, realce da linha sob o cursor e cabeçalho
   que gruda no topo ao rolar. Sem o cabeçalho fixo, rolar a grade de produtos
   deixava o leitor sem saber qual coluna estava lendo. */
.tabela { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.tabela th {
  text-align: left;
  color: var(--text-muted);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  position: sticky;
  top: 0;
  background: var(--surface);
  z-index: 1;
}
.tabela td { padding: 11px var(--sp-4); border-bottom: 1px solid var(--border); color: var(--text); vertical-align: middle; }
.tabela tbody tr:nth-child(even) { background: var(--bg-subtle); }
.tabela tbody tr:hover { background: var(--accent-soft-hover); }
.tabela tbody tr.is-selected { background: var(--accent-soft); }
.tabela tbody tr:last-child td { border-bottom: none; }
.tabela td.num, .tabela th.num { text-align: right; font-family: var(--font-mono); }
/* Localização no detalhe do pedido — é o que a expedição lê para separar. */
.tabela .celula-localizacao { white-space: nowrap; }
.tabela .celula-localizacao .ico { width: 13px; height: 13px; color: var(--accent); vertical-align: -2px; margin-right: 5px; }
.tabela .celula-localizacao.sem-localizacao { color: var(--text-faint); }

/* ---------------------------------------------------------------------------
   Tabela de pedidos do painel — crua, sem recolher

   Todo item de todo pedido exposto, com o número do pedido repetido em cada
   linha. O que fecha cada pedido é uma linha de RODAPÉ que faz três coisas de
   uma vez: separa do próximo, identifica (cliente, data, situação) e fecha a
   conta. O total cai na MESMA coluna dos subtotais dos itens — é o que permite
   descer a vista por uma coluna só.
   --------------------------------------------------------------------------- */
/* Sem a caixa de rolagem no desktop: `overflow-x: auto` transforma o container
   em área de rolagem própria, e aí o `position: sticky` do cabeçalho passa a se
   referir a ELA — que nunca rola — em vez da janela. O cabeçalho simplesmente
   não grudava. A rolagem horizontal volta onde é necessária, na tela estreita.

   O CORTE É 1320px, não 900. Com `overflow-x: visible`, tabela maior que o
   container não rola: ela VAZA por fora do cartão — foi o que apareceu na tela,
   com a coluna "Nota fiscal" pendurada fora da borda.

   A conta, toda medida: as linhas de ITEM têm piso de 932px, e o cromo em volta
   (barra lateral 232 + respiro 48 + cartão 42) come 322. Logo a tabela só cabe
   com janela acima de 1254px, e com o corte em 900 a faixa de 901 a 1254 vazava
   em silêncio.

   1320 e não 1254 de propósito: 1254 é ajuste EXATO, e ajuste exato é o defeito
   que já mordeu esta base duas vezes — basta uma barra de rolagem ou um zoom
   diferente para estourar por décimos. 1320 dá 66px de folga.

   O preço é perder o cabeçalho grudado nessa faixa. Vale: conteúdo escapando do
   cartão é defeito, cabeçalho que não gruda é só uma comodidade a menos. */
.tabela-wrap--pedidos { overflow-x: visible; }
@media (max-width: 1320px) {
  .tabela-wrap--pedidos { overflow-x: auto; }
}
.tabela-pedidos th { top: var(--header-h); }
/* Zebra por LINHA não serve aqui: ela alternaria itens e rodapé sem relação com
   o agrupamento. Quem separa um pedido do outro é o rodapé. */
.tabela-pedidos tbody tr:nth-child(even) { background: none; }
.tabela-pedidos .pedido-item:hover { background: var(--accent-soft-hover); }

/* Número do pedido repetido: apagado de propósito. Ele precisa estar em toda
   linha para que qualquer uma se leia sozinha, mas não é o que se lê primeiro —
   se gritasse, competiria com a descrição da peça em cada linha da tela. */
.tabela-pedidos .pi-pedido {
  font-family: var(--font-mono);
  color: var(--text-faint);
  white-space: nowrap;
}
.tabela-pedidos .pedido-item td { color: var(--text-muted); }
.tabela-pedidos .pedido-item .pi-descricao { color: var(--text); }
.tabela-pedidos .pi-codigo { font-family: var(--font-mono); color: var(--text-faint); white-space: nowrap; }
.tabela-pedidos .pi-nota { white-space: nowrap; }
/* Coluna de endereço: não pode roubar espaço da descrição, que é o que se lê. */
.tabela-pedidos .celula-localizacao { font-size: var(--fs-xs); }
/* Linha que casou com o filtro de item: com tudo exposto, achar a peça no meio
   de trezentas linhas seria o trabalho todo. */
.tabela-pedidos .pedido-item.casou td { background: var(--warning-soft); }
.tabela-pedidos .pedido-item.casou .pi-descricao { color: var(--warning-text); font-weight: var(--fw-medium); }

/* O rodapé do pedido — separador, identificação e total numa linha só. */
.tabela-pedidos .pedido-rodape > td {
  background: var(--bg-subtle);
  border-bottom: 2px solid var(--border-strong);
  padding-block: var(--sp-3);
}
.tabela-pedidos tbody:last-child .pedido-rodape > td { border-bottom: none; }
.tabela-pedidos .pr-total {
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
}
/* UMA LINHA, sempre — e é a correção de um defeito real.
 *
 * Com `flex-wrap: wrap`, um cliente de nome longo fazia a soma bater EXATAMENTE
 * na largura da linha (883px de conteúdo em 883px de célula) e o arredondamento
 * de sub-pixel derrubava o bloco de ações para uma segunda linha. O total, que
 * mora noutra célula, ficava centralizado na altura dobrada — e nada alinhava
 * com nada.
 *
 * Sem quebra, quem cede espaço é o nome do cliente, que trunca com reticências
 * (o nome inteiro continua no `title`). É degradação contínua em vez de um
 * salto, e o alinhamento passa a valer para qualquer tamanho de nome. */
/* A célula do rodapé NÃO PODE mandar na largura da tabela.
   
   Ela tem `colspan` e conteúdo que não encolhe (campo, botões), então o
   algoritmo da tabela usava o min-content dela como piso: ao ganhar o botão
   "Cancelar", a tabela saltou para 1247px dentro de um container de 1150 e
   vazou por fora do cartão. `max-width: 0` tira a célula da conta — ela passa a
   receber a largura que as linhas de ITEM definiram, e quem cede espaço lá
   dentro é o nome do cliente, que já trunca com reticências. */
.tabela-pedidos .pedido-rodape > td:first-child { max-width: 0; }
.pr-linha { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: nowrap; }
.pr-cliente {
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pr-data { color: var(--text-faint); font-size: var(--fs-xs); white-space: nowrap; }
/* Empurradas para a direita da própria célula: associar e detalhar são ação,
   não identificação. `flex: none` porque encolher um campo e dois botões só
   deixaria os três ilegíveis — quem cede é o nome. */
.pr-acoes { margin-left: auto; flex: none; display: flex; align-items: center; gap: var(--sp-2); }
.pr-acoes .input { width: 160px; height: 32px; font-family: var(--font-mono); font-size: var(--fs-sm); }
.pr-acoes .btn { height: 32px; }
.pr-aviso { font-size: var(--fs-xs); color: var(--text-faint); }
.pr-aviso--erro { color: var(--danger-text); }

/* Cabeçalho ordenável: rótulo + chevron do sentido. */
.tabela th .sort { display: inline-flex; align-items: center; gap: 4px; }
.tabela th .sort .ico { width: 12px; height: 12px; color: var(--text-faint); }
.tabela .preco-riscado { text-decoration: line-through; color: var(--text-faint); margin-right: var(--sp-2); }
/* Código do produto sob a descrição, no detalhe do pedido — mono para bater com o do catálogo. */
.tabela .item-codigo {
  display: block;
  margin-top: 2px;
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
}

/* Linha do tempo da negociação */
.linha-do-tempo { display: flex; flex-direction: column; }
.evento-tempo { display: grid; grid-template-columns: 20px 1fr; gap: var(--sp-3); position: relative; padding-bottom: var(--sp-5); }
.evento-tempo:last-child { padding-bottom: 0; }
.evento-marcador { width: 10px; height: 10px; border-radius: 50%; background: var(--accent); margin-top: 5px; position: relative; z-index: 1; }
.evento-tempo:not(:last-child)::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 16px;
  bottom: -4px;
  width: 2px;
  background: var(--border);
}
.evento-cabecalho { display: flex; justify-content: space-between; gap: var(--sp-3); align-items: baseline; flex-wrap: wrap; }
.evento-tipo { font-weight: var(--fw-semibold); color: var(--text-strong); font-size: var(--fs-sm); }
.evento-data { font-size: var(--fs-xs); color: var(--text-faint); white-space: nowrap; }
.evento-mensagem { margin-top: 4px; color: var(--text-muted); font-size: var(--fs-sm); }

.resumo-lateral { padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-4); position: sticky; top: calc(var(--header-h) + var(--sp-4)); }
.resumo-lateral h2 { font-size: var(--fs-h2); font-weight: var(--fw-semibold); color: var(--text-strong); }
.resumo-linha { display: flex; justify-content: space-between; font-size: var(--fs-sm); color: var(--text-muted); }
.resumo-linha strong { color: var(--text-strong); font-family: var(--font-mono); }
.resumo-total { display: flex; justify-content: space-between; padding-top: var(--sp-3); border-top: 1px solid var(--border); font-size: var(--fs-h3); color: var(--text-strong); }
.resumo-total strong { font-family: var(--font-mono); font-size: var(--fs-h1); }
.resumo-acoes { display: flex; flex-direction: column; gap: var(--sp-2); }

/* Números da tela inicial do painel */
/* 280px de mínimo, não 180: o cartão foi dimensionado quando o número era "11"
   e agora carrega "R$ 1.300.761,69", que ocupa 226px nos 28px do KPI.
   `Intl` cola o "R$" ao número com espaço INQUEBRÁVEL, então a string é um
   bloco só — não quebrava em duas linhas, era CORTADA. Com 180 o defeito
   aparecia em toda a faixa de 400 a 720px de largura. */
.resumo-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--sp-4); }
/* KPI — spec `.kpi` do styleguide: rótulo em caixa-alta ACIMA do número, e o
   número em 28px tabular. O rótulo vem primeiro porque num painel de quatro
   cartões o que se lê antes é o que cada número significa, não o número. */
.resumo-card { padding: var(--sp-5); }
.resumo-card .resumo-card-rotulo {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--text-muted);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
}
.resumo-card .resumo-card-valor {
  margin-top: 6px;
  font-size: 28px;
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
  font-variant-numeric: tabular-nums;
  line-height: var(--lh-tight);
  /* Rede, não solução: a largura do cartão acima é quem resolve. Se um dia um
     número maior não couber assim mesmo, ele quebra em duas linhas — feio, mas
     inteiro. Valor de dinheiro cortado não fica feio: fica ERRADO, e ninguém
     tem como notar que falta um dígito. */
  overflow-wrap: anywhere;
}
/* Linha de procedência sob o número. Existe porque o cartão passou a somar ERP
   e Portal: sem ela, "1.617" não diz de onde veio, e o número que a tela dava
   antes (só o do Portal) desapareceria sem aviso. */
.resumo-card .resumo-card-nota {
  margin-top: var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--text-faint);
  line-height: var(--lh-snug);
}
.resumo-card--alerta { background: var(--warning-soft); border-color: var(--warning); }
.resumo-card--alerta .resumo-card-valor { color: var(--warning-text); }

/* Faixa do cliente assumido — precisa ser MUITO visível: é o que decide o preço.
 *
 * DUAS FAIXAS EMPILHADAS, não uma linha só. Antes o nome do cliente e as ações
 * dividiam a mesma linha com `justify-content: space-between`: o nome tem 60
 * caracteres e empurrava a busca contra a borda direita, onde ela ficava
 * espremida ao lado de um botão de outra altura. Agora quem identifica fica em
 * cima, quem age fica embaixo — separados por um filete, dentro do mesmo
 * cartão. */
/*
  Faixa de "cliente assumido" — contexto, não alerta.

  Era um bloco inteiro preenchido com `--accent-soft`. No tema argila isso é um
  bege discreto; no cobalto, cujo acento é laranja, o mesmo token vira uma
  tarja que grita — e passava a ser o elemento mais chamativo da tela, mais até
  que o cartão de "cadastros aguardando aprovação", que é o aviso de verdade.
  Laranja carrega significado de alerta, e usar a cor de destaque para pintar
  uma área grande empresta esse significado a quem não deveria ter.

  Agora: superfície de card com uma barra de acento à ESQUERDA. Marcar a borda
  em vez de preencher a área diz "isto é diferente" sem disputar urgência —
  e a barra funciona igual em qualquer paleta, porque um traço fino de cor
  saturada não pesa como um bloco.

  Continua impossível não ver que há um cliente assumido, que é o requisito
  real: esquecer disso faz o administrador operar em nome de outra empresa.
*/
.cliente-ativo-faixa {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
}
/* Sem cliente assumido não há contexto para marcar: a barra sai, e a faixa
   recolhe para o tom de seção apagada. */
.cliente-ativo-faixa--vazio {
  background: var(--bg-subtle);
  border-color: var(--border);
  border-left-color: var(--border-strong);
}
.cliente-ativo-info { display: flex; align-items: center; gap: var(--sp-3); }
.cliente-ativo-rotulo { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: var(--ls-caps); color: var(--accent-text); font-weight: var(--fw-semibold); }
.cliente-ativo-faixa--vazio .cliente-ativo-rotulo { color: var(--text-faint); }
.cliente-ativo-nome { font-size: var(--fs-h2); font-weight: var(--fw-semibold); color: var(--text-strong); }

/* Segunda faixa: trocar de cliente e encerrar.
   Alinhada pela BASE — o campo tem rótulo em cima e o botão não; centralizar
   punha o botão no meio da altura total, ou seja, acima da linha das caixas.
   É a mesma regra da `.filtros-barra`. */
.cliente-ativo-acoes {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding-top: var(--sp-4);
  border-top: 1px solid var(--accent-border);
}
.cliente-ativo-faixa--vazio .cliente-ativo-acoes { border-top-color: var(--border); }
/* METADE da faixa, proporcional à tela — as "seis colunas de doze".
   `flex-basis: 50%` mede sobre a largura do container, então o campo cresce e
   encolhe junto com a janela; `grow: 0` o impede de engolir a sobra e virar
   uma caixa de 900px num monitor largo. O piso é o ponto em que "ANTONELLO
   INDUSTRIA MECANICA" deixaria de caber enquanto se digita. */
.cliente-ativo-acoes .field { flex: 0 1 50%; min-width: 260px; }
.cliente-ativo-acoes .field > label { font-size: var(--fs-xs); color: var(--text-muted); }
/* Mesma altura da caixa (40px). Com `btn--sm` o Encerrar flutuava ao lado da
   busca em vez de fechar a linha com ela. */
.cliente-ativo-acoes .btn { height: 40px; }

/* Busca de cliente (combobox simples) */
.busca-cliente { position: relative; }
.busca-cliente-resultados {
  position: absolute;
  top: calc(100% + 4px);
  left: 0; right: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-md);
  max-height: 260px;
  overflow-y: auto;
  z-index: 30;
}
.busca-cliente-resultados button {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--sp-3);
  background: none;
  border: none;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  color: var(--text);
  font: inherit;
}
.busca-cliente-resultados button:last-child { border-bottom: none; }
.busca-cliente-resultados button:hover,
.busca-cliente-resultados button:focus-visible { background: var(--bg-subtle); }
.busca-cliente-resultados .item-nome { font-weight: var(--fw-medium); color: var(--text-strong); display: block; }
.busca-cliente-resultados .item-doc { font-size: var(--fs-xs); color: var(--text-faint); }

/* Painel — seções em abas */
.painel-secoes { display: flex; flex-direction: column; gap: var(--sp-6); }
.painel-secao { padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-4); }
.painel-secao-cabecalho { display: flex; justify-content: space-between; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.painel-secao-cabecalho h2 { font-size: var(--fs-h1); font-weight: var(--fw-semibold); color: var(--text-strong); }

/* Quatro colunas desde que a quantidade virou negociável: descrição, o preço
   do turno atual, o volume e o preço proposto. Larguras em px, nunca em %:
   porcentagens somando 100 exatos quebram no arredondamento sub-pixel. */
.item-resposta-cotacao {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 120px 96px 132px;
  gap: var(--sp-3);
  align-items: end;
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border);
}
.item-resposta-cotacao:last-child { border-bottom: none; }
.item-resposta-cotacao .desc { color: var(--text-strong); font-size: var(--fs-sm); }
.item-resposta-cotacao .desc small { display: block; color: var(--text-faint); font-size: var(--fs-xs); font-weight: var(--fw-regular); }
.item-resposta-cotacao .campo-rotulado { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.item-resposta-cotacao .campo-rotulado > span {
  font-size: var(--fs-xs);
  color: var(--text-faint);
  font-weight: var(--fw-medium);
}
/* No estreito, os dois CAMPOS ficam lado a lado e o resto ocupa a linha
   inteira. Deixar o texto "Atual: …" dividir a linha com a Quantidade embaralha
   a leitura: o rótulo de um campo encosta na informação do outro. */
@media (max-width: 640px) {
  .item-resposta-cotacao { grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
  .item-resposta-cotacao .desc,
  .item-resposta-cotacao .hint { grid-column: 1 / -1; }
}

/* ---------------------------------------------------------------------------
   Reserva de atendimento — quem está respondendo esta cotação agora.
   Sempre visível no topo do detalhe, porque a resposta do vendedor depende
   dela: sem reserva, o formulário nem aparece.
   --------------------------------------------------------------------------- */
.barra-atendimento {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-2);
}
.barra-atendimento__texto { flex: 1 1 260px; min-width: 0; font-size: var(--fs-sm); color: var(--text); }
.barra-atendimento__texto strong { color: var(--text-strong); }
.barra-atendimento__texto small { display: block; color: var(--text-faint); font-size: var(--fs-xs); }
/* Ocupada por outro: a cor faz o vendedor parar antes de ler. */
.barra-atendimento--ocupada { border-color: var(--warning); background: var(--warning-soft); }
.barra-atendimento--sua { border-color: var(--success); background: var(--success-soft); }

/* Quem está atendendo, na LISTA — para o vendedor não abrir o que já é de um
   colega. Discreto de propósito: é aviso de rota, não alarme. */
.linha-lista-atendimento {
  font-size: var(--fs-xs);
  color: var(--text-faint);
  display: block;
}

/* Autor do turno na linha do tempo. Sem isto a negociação era uma sequência de
   horários sem gente: não dava para saber qual comprador falou nem qual colega
   respondeu. */
.evento-autor { color: var(--text-faint); font-size: var(--fs-xs); }

/* Contato de quem abriu a cotação, no cabeçalho do vendedor. */
.contato-solicitante { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); margin-top: var(--sp-1); }
.contato-solicitante a { color: inherit; }

/* Volume alterado no turno: o comprador precisa VER que mudou antes de aceitar,
   porque aceitar é o que autoriza. */
.qtd-alterada { color: var(--text-strong); font-weight: var(--fw-semibold); }
.qtd-alterada small { display: block; font-weight: var(--fw-regular); color: var(--text-faint); font-size: var(--fs-xs); }

/* ---------------------------------------------------------------------------
   Escolha de itens da cotação, no carrinho.
   Item já em negociação não vira caixa marcável: vira linha explicando onde ele
   está. Opção que não existe não ocupa espaço de opção.
   --------------------------------------------------------------------------- */
.cotacao-itens { border: none; padding: 0; margin: 0 0 var(--sp-3); min-width: 0; }
.cotacao-itens legend {
  padding: 0;
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--text-faint);
  margin-bottom: var(--sp-2);
}
.cotacao-item {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-1) 0;
  font-size: var(--fs-sm);
  cursor: pointer;
}
.cotacao-item input { margin-top: 0.2em; flex: none; }
.cotacao-item span { min-width: 0; overflow-wrap: anywhere; }
.cotacao-item-bloqueado { padding: var(--sp-1) 0; overflow-wrap: anywhere; }

/* Quantidades ajustáveis na contraproposta do comprador. */
.contraproposta-itens { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.contraproposta-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 96px;
  gap: var(--sp-3);
  align-items: center;
  font-size: var(--fs-sm);
}
.contraproposta-item > span { overflow-wrap: anywhere; }

.acoes-linha { display: flex; gap: var(--sp-2); flex-wrap: wrap; }

.estado-carregando { color: var(--text-faint); padding: var(--sp-6) 0; text-align: center; display: flex; align-items: center; justify-content: center; gap: var(--sp-2); }

/* ---------------------------------------------------------------------------
   Faixa de cliente assumido (administrador operando em nome de um cliente).
   Só aparece nesse caso, e é deliberadamente chamativa: é a confirmação de
   para QUEM o pedido vai sair.
   --------------------------------------------------------------------------- */
.faixa-assuncao {
  background: var(--accent);
  color: var(--on-accent, #fff);
  font-size: 0.9rem;
  padding: 0.5rem 0;
  position: sticky;
  top: 0;
  z-index: 30;
}

.faixa-assuncao .container {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.faixa-assuncao__rotulo {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.72rem;
  opacity: 0.85;
}

.faixa-assuncao__cliente {
  font-weight: 600;
}

.faixa-assuncao__acoes {
  margin-left: auto;
  display: flex;
  gap: 1rem;
  align-items: center;
}

.faixa-assuncao__acoes a,
.faixa-assuncao .btn-link {
  color: inherit;
  text-decoration: underline;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  cursor: pointer;
}

.faixa-assuncao__acoes a:hover,
.faixa-assuncao .btn-link:hover {
  text-decoration: none;
}

.faixa-assuncao__acoes a:focus-visible,
.faixa-assuncao .btn-link:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   Fila de cancelamento (painel do administrador)

   A peça é um `.linha-lista`, mas o conteúdo é diferente do resto: aqui o que
   pesa é o TEXTO que o cliente escreveu — é com ele que se decide. Por isso a
   justificativa ganha tratamento de citação, e não de metadado.
   --------------------------------------------------------------------------- */
.cancelamento-card { display: flex; flex-direction: column; gap: var(--sp-3); align-items: stretch; }
.cancelamento-topo { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.cancelamento-titulo { font-weight: var(--fw-semibold); color: var(--text-strong); }

.cancelamento-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}
.cancelamento-meta .cancelamento-quem { font-weight: var(--fw-medium); color: var(--text); }
.cancelamento-meta .cancelamento-quando { color: var(--text-faint); }
/* Marca discreta, não selo: quem abriu importa, mas não compete com o motivo. */
.cancelamento-meta .cancelamento-origem { color: var(--text-faint); font-style: italic; }

/* O motivo do cliente é o dado central desta tela — a barra à esquerda o separa
   do relato do sistema em volta. */
.cancelamento-justificativa {
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  border-left: 3px solid var(--accent);
  background: var(--bg-subtle);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  color: var(--text-strong);
}

.cancelamento-aviso { margin: 0; }
.cancelamento-desfecho { margin: 0; font-size: var(--fs-sm); color: var(--text-muted); }

.cancelamento-acoes { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.cancelamento-motivo { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-3); }
.cancelamento-motivo label { font-size: var(--fs-sm); color: var(--text-muted); }
/* `textarea` não herda a altura fixa do `.input`, que é de campo de uma linha. */
.cancelamento-motivo textarea.input { height: auto; padding: var(--sp-3); resize: vertical; }
.cancelamento-motivo .btn { align-self: flex-start; }

/* ---------------------------------------------------------------------------
   Cancelamento no pedido do comprador

   Mora no fim do acordeão aberto, separado dos itens por uma linha: é outra
   conversa. A borda superior faz esse corte sem exigir um título.
   --------------------------------------------------------------------------- */
.pedido-cancelamento {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}
.pedido-cancelamento-topo { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.pedido-cancelamento-data { font-size: var(--fs-sm); color: var(--text-faint); }
.pedido-cancelamento-frase { margin: 0; font-size: var(--fs-sm); color: var(--text-muted); }
/* O motivo da recusa é o que a pessoa mais quer ler — destacado como citação,
   igual à justificativa na fila do administrador. */
.pedido-cancelamento-motivo {
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  border-left: 3px solid var(--danger);
  background: var(--danger-soft);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  color: var(--danger-text);
}
.pedido-cancelamento-form { display: flex; flex-direction: column; gap: var(--sp-2); }
.pedido-cancelamento-form textarea.input { height: auto; padding: var(--sp-3); resize: vertical; }
.pedido-cancelamento-acoes { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
/* O bloco inteiro alinha à esquerda dentro do pedido, sem esticar os botões. */
.pedido-cancelamento > .btn { align-self: flex-start; }

/* Diálogo do cancelamento direto — o pedido em foco, antes do motivo. */
.cancelar-pedido-alvo {
  margin: 0 0 var(--sp-3);
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
}
#cancelar-pedido-dialogo .dialogo-corpo { display: flex; flex-direction: column; gap: var(--sp-3); }
#cancelar-pedido-dialogo textarea.input { height: auto; padding: var(--sp-3); resize: vertical; }
/* O botão de cancelar no rodapé do pedido não pode competir com "Detalhar":
   é ação destrutiva, então fica em texto até o hover. */
.tabela-pedidos .pr-cancelar:hover { color: var(--danger); }

/* ---------------------------------------------------------------------------
   Diálogo modal — veio de `admin.css` em 06/08/2026.

   Estava lá porque nasceu na tela de produtos, mas é PRIMITIVO: o painel do
   administrador não carrega `admin.css`, e o diálogo de cancelamento aparecia
   como bloco solto no fim da página — sem overlay, sem centralização, sem nada
   que dissesse "decida isto agora".

   Os keyframes mantêm o prefixo `admin-` de propósito: renomear exigiria varrer
   os quatro diálogos que já existem, sem ganho nenhum.
   --------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------------
   7) Diálogo modal — exportar produtos, criar/editar usuário, problemas da
      carga. Overlay cobre a tela inteira; o painel é o cartão centralizado.
   ---------------------------------------------------------------------------- */
.dialogo-overlay {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-5);
  background: var(--overlay);
  animation: admin-entrar-overlay 160ms ease-out;
}
.dialogo-painel {
  width: 100%;
  max-width: 520px;
  max-height: min(88vh, 720px);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  animation: admin-entrar-modal 180ms ease-out;
}
.dialogo-painel--largo { max-width: 760px; }
.dialogo-cabecalho {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
  flex: none;
}
.dialogo-cabecalho h2 { font-size: var(--fs-h2); font-weight: var(--fw-semibold); color: var(--text-strong); }
.dialogo-fechar {
  width: 32px;
  height: 32px;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-muted);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}
.dialogo-fechar:hover { background: var(--bg-subtle); color: var(--text-strong); }
.dialogo-corpo {
  padding: var(--sp-5);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
/* `.dialogo-corpo` e `.form-grade` convivem no mesmo elemento, e o `display:
   flex` daqui vencia o `display: grid` de lá por vir depois no arquivo — o
   diálogo de usuário PARECIA uma grade e nunca foi uma: os campos empilhavam em
   coluna única e os blocos ficavam com metade da largura. É por isso que nome e
   e-mail nunca ficaram lado a lado. */
.dialogo-corpo.form-grade { display: grid; }
/* Com o corpo virando grade, o rodapé passou a ser um item dela e ficou preso a
   uma coluna — o `justify-content: flex-end` alinhava os botões à direita de
   METADE do diálogo. Ocupando a linha inteira, eles voltam para a borda direita
   de verdade, como o "Novo usuário" da tela de trás. */
.dialogo-corpo.form-grade > .dialogo-rodape { grid-column: 1 / -1; }

.dialogo-rodape {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-2);
  padding: var(--sp-4) var(--sp-5);
  border-top: 1px solid var(--border);
  flex: none;
}
@keyframes admin-entrar-modal {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: none; }
}
@keyframes admin-entrar-overlay {
  from { opacity: 0; }
  to   { opacity: 1; }
}
