/* =========================================================================
   SPKR PDV: sistema visual
   -------------------------------------------------------------------------
   Restrições que vieram da spec e moldaram as decisões daqui:

   §17  operável integralmente por teclado; contraste mínimo AA; alvos de
        toque de 44px. Por isso todo controle tem estado :focus-visible
        explícito e altura mínima de 44px.
   §4.1 a tela tem quatro regiões fixas (identidade, barra da venda, wizard,
        fila lateral) e um rodapé sempre visível com Total e Finalizar.
   §4.6 os atalhos são remapeáveis, então a tecla exibida vem do servidor e
        nunca é escrita à mão no HTML.

   A leitura acontece a um braço de distância, sob luz de loja, muitas vezes
   por alguém que não olha para a tela enquanto passa o leitor. Daí o corpo
   maior que o usual, o número tabular no dinheiro e o contraste alto.
   ========================================================================= */

:root {
  color-scheme: dark;

  --bg: #090c11;
  --surface: #11151c;
  --surface-2: #161b23;
  --surface-3: #1d2430;
  --line: #29313e;
  --line-strong: #3a4656;

  --text: #edf1f6;
  --muted: #a7b0bf;
  --faint: #7f899a;

  /* Preenchimento e texto são tokens diferentes de propósito: o mesmo
     azul não alcança 4.5:1 nos dois papéis. `--accent` é fundo, com
     branco por cima; `--accent-text` é texto, sobre o fundo escuro. */
  --accent: #2868c7;
  /* Tom de hover explícito, e não `filter`. Um filtro não declara
     `background`, e a regra genérica de hover acabava pintando o botão
     de cinza claro por baixo do texto branco. */
  --accent-hover: #2258a9;
  --accent-text: #82b6f7;
  --accent-soft: rgba(40, 104, 199, 0.16);
  --accent-line: rgba(75, 139, 231, 0.52);

  --money: #24a97b;
  --money-hover: #1d8f68;
  /* O botão Finalizar é o verde cheio com texto escuro: no tema escuro
     essa é a combinação que passa em AA. */
  --money-btn-text: #04241a;
  --money-soft: rgba(36, 169, 123, 0.14);
  /* Token de texto, separado do de superfície: escurecer `--money` para
     atingir 4.5:1 em texto quebraria o botão Finalizar, que usa a mesma
     cor como preenchimento. */
  --money-text: #35c08f;

  --danger: #d9435a;
  --danger-soft: rgba(217, 67, 90, 0.14);
  --danger-text: #f07185;

  --warn: #c98a10;
  --warn-soft: rgba(201, 138, 16, 0.14);
  --warn-text: #e0a72e;

  /* Canto quase reto. O arredondamento forte é o que mais dava aparência
     de aplicativo de celular a uma tela que passa o dia aberta num
     balcão. */
  --radius: 6px;
  --radius-sm: 4px;
  --radius-lg: 8px;

  /* A separação vem da linha, não da sombra. Sombra grande simula
     profundidade que não existe e some no monitor sem contraste da
     loja. */
  --shadow: none;
  --shadow-lg: 0 4px 16px rgba(0, 0, 0, 0.45);

  --font: "Inter", "Segoe UI Variable", "Segoe UI", system-ui, -apple-system,
    sans-serif;
  --mono: "JetBrains Mono", "Cascadia Mono", ui-monospace, "SF Mono", monospace;

  --bar-h: 58px;
  --sale-h: 54px;
  --foot-h: 78px;
}

:root[data-theme="light"] {
    color-scheme: light;
    --bg: #f1f3f6;
    --surface: #ffffff;
    --surface-2: #f8f9fb;
    --surface-3: #edf0f4;
    --line: #dce1e8;
    --line-strong: #c5ccd6;
    --text: #12151c;
    --muted: #545c6b;
    --faint: #6b7382;
    --accent: #1f5aa8;
    --accent-hover: #17457f;
    --accent-text: #1f5aa8;
    --accent-soft: rgba(31, 90, 168, 0.10);
    --accent-line: rgba(31, 90, 168, 0.34);
    --money: #0a7a53;
    --money-hover: #075f41;
    /* Invertido em relação ao tema escuro: aqui o verde é escuro, e quem
       tem contraste por cima dele é o branco. */
    --money-btn-text: #ffffff;
    --money-soft: rgba(10, 122, 83, 0.10);
    --money-text: #06603f;
    --danger: #c0243c;
    --danger-soft: rgba(192, 36, 60, 0.09);
    --danger-text: #a51c31;
    --warn: #9a5c00;
    --warn-soft: rgba(154, 92, 0, 0.10);
    --warn-text: #7a4800;
    --shadow: none;
    --shadow-lg: 0 4px 16px rgba(16, 24, 40, 0.18);
}

* {
  box-sizing: border-box;
}

/* Sem animação e sem transição, em lugar nenhum.
   A tela é ferramenta de trabalho: o operador olha para ela centenas de
   vezes por dia e precisa que o estado seja o mesmo no instante em que
   ele olha. Movimento atrasa a leitura e não informa nada que a cor e o
   texto já não digam. Fica aqui, numa regra só, para não voltar aos
   poucos em cada componente novo. */
*,
*::before,
*::after {
  transition: none !important;
  animation: none !important;
}

/* O atributo `hidden` precisa vencer o `display` de qualquer classe.
   O navegador aplica `[hidden] { display: none }` na folha de estilo dele,
   que perde para qualquer seletor de classe nosso: `.btn` é inline-flex,
   `.stack` é grid, `.navmore-menu` é flex. O resultado é um elemento
   marcado como oculto que continua na tela, e foi exatamente o que
   deixou o menu "Mais" aberto para sempre e os botões "Carregar mais"
   visíveis sem ter próxima página. */
[hidden] {
  display: none !important;
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

/* Dinheiro e quantidade usam algarismo tabular: sem isso a coluna de
   valores "dança" a cada dígito e a conferência fica mais lenta. */
.money,
.num,
input[inputmode="decimal"],
input[inputmode="numeric"] {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}

::selection {
  background: var(--accent-soft);
}

/* ---------- Barras ------------------------------------------------------ */

.app {
  display: grid;
  grid-template-rows: var(--bar-h) var(--sale-h) 1fr var(--foot-h);
  height: 100vh;
}

.identity {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 0 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  /* A barra é uma linha só. Sem isto ela quebrava em duas quando o
     espaço apertava, e o item ativo da navegação, arredondado, virava um
     círculo espremido em volta da palavra. */
  flex-wrap: nowrap;
  overflow: hidden;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  /* Encolhe antes da navegação: o nome da empresa pode ser cortado com
     reticências, um item de menu não. */
  flex: 0 1 auto;
  min-width: 0;
}

.mark {
  width: 32px;
  height: 32px;
  border-radius: 6px;
  display: grid;
  place-items: center;
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0;
  color: #fff;
  background: var(--accent);
  flex: none;
}

.brand-name {
  font-weight: 600;
  letter-spacing: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.brand-sub {
  font-size: 11.5px;
  color: var(--faint);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.spacer {
  flex: 1;
}

/* Seletor combinado de Loja e Unidade de Negócio (§4.1) */
.scope {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 36px;
  flex: none;
  white-space: nowrap;
  padding: 0 8px 0 13px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.scope:hover {
  border-color: var(--line-strong);
  background: var(--surface-3);
}

.scope-store {
  font-weight: 600;
  font-size: 14px;
}

.scope-unit {
  color: var(--muted);
  font-size: 13px;
}

.scope-key {
  margin-left: 2px;
}

/* Navegação em abas, alinhadas à base da barra. A pastilha flutuante
   dependia de sombra e de canto redondo para se distinguir; a aba marca
   a tela atual com uma linha, que é legível em qualquer contraste. */
/* `overflow: hidden` no próprio nav, e não só no cabeçalho.

   Com o recorte só no pai, o conteúdo do nav que não coubesse era desenhado
   por cima do bloco do usuário: o "Mais" aparecia escrito em cima do nome
   de quem está logado. Recortando aqui, o excesso some na borda do próprio
   nav, que é onde ele pertence.

   O menu suspenso não é afetado porque ele é `position: fixed` e sai do
   fluxo: essa foi outra razão para tirá-lo de `absolute`. */
.nav-shell {
  display: flex;
  align-self: stretch;
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
}

.nav {
  display: flex;
  align-items: stretch;
  min-width: 0;
  overflow: hidden;
}

.nav a {
  display: flex;
  align-items: center;
  padding: 0 14px;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
}

.nav a:hover {
  color: var(--text);
  background: var(--surface-2);
}

.nav a.on {
  color: var(--accent-text);
  font-weight: 600;
  border-bottom-color: var(--accent);
}

@media (max-width: 1280px) {
  .brand-sub,
  .scope-key {
    display: none;
  }
}

@media (max-width: 1100px) {
  .scope-unit,
  .user > div:not(.avatar) {
    display: none;
  }
}

@media (max-width: 900px) {
  .brand-name {
    display: none;
  }
}

/* Menu de transbordo da navegação. Existe para a barra não quebrar em
   linha dupla no notebook do balcão, que é onde o sistema roda. */
.navmore {
  position: relative;
  display: flex;
  align-items: stretch;
  flex: none;
  background: var(--surface);
}

.navmore-btn {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 0 14px;
  border: 0;
  border-bottom: 2px solid transparent;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
}

.navmore-btn:hover {
  color: var(--text);
  background: var(--surface-2);
}

.navmore-btn.on {
  color: var(--text);
  font-weight: 600;
  border-bottom-color: var(--accent);
}

/* `fixed`, e não `absolute`: `absolute` prende o menu ao cabeçalho, que é
   `overflow: hidden` e tem 60px de altura. O menu abre abaixo disso e era
   recortado por inteiro. Quem posiciona é o JS, com as coordenadas do
   botão. */
.navmore-menu {
  position: fixed;
  z-index: 60;
  min-width: 210px;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}

.navmore-menu a {
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  color: var(--text);
  text-decoration: none;
  font-size: 13.5px;
  white-space: nowrap;
}

.navmore-menu a:hover {
  background: var(--surface-2);
}

.navmore-menu a.on {
  background: var(--accent-soft);
  color: var(--accent-text);
  font-weight: 600;
}

/* Voltar das telas de segundo nível. */
.backbtn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  padding: 0 13px 0 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--muted);
  text-decoration: none;
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
}

.backbtn:hover {
  background: var(--surface-3);
  color: var(--text);
}

.backbtn span[aria-hidden] {
  font-size: 15px;
  line-height: 1;
}

@media (max-width: 1100px) {
  .backbtn-label {
    display: none;
  }
}

.user {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
  white-space: nowrap;
  /* Fundo próprio e um degrau de empilhamento: mesmo que algo escape do
     recorte do nav, o nome de quem está logado nunca fica ilegível. */
  position: relative;
  z-index: 1;
  background: var(--surface);
  padding-left: 8px;
}

.avatar {
  width: 32px;
  height: 32px;
  border-radius: 6px;
  display: grid;
  place-items: center;
  background: var(--surface-3);
  border: 1px solid var(--line);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted);
}

/* Barra da venda (§4.1) */
.salebar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.sale-title {
  font-weight: 600;
  font-size: 15px;
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 190px;
  padding-right: 14px;
  border-right: 1px solid var(--line);
}

.sale-id {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--faint);
  padding: 3px 8px;
  background: var(--surface-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

/* ---------- Pílulas de estado ------------------------------------------ */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 32px;
  padding: 0 12px;
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  font-weight: 600;
  white-space: nowrap;
  border: 1px solid transparent;
}

.pill.ok {
  background: var(--money-soft);
  color: var(--money-text);
  border-color: var(--money-soft);
}

.pill.off {
  background: var(--danger-soft);
  color: var(--danger-text);
  border-color: var(--danger-soft);
}

.pill.neutral {
  background: var(--surface-3);
  color: var(--muted);
  border-color: var(--line);
}

.dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

.pill.ok .dot {
  box-shadow: none;
}

/* ---------- Botões ------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: 44px; /* §17: alvo de toque */
  padding: 0 18px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
}

.btn:hover:not(:disabled) {
  background: var(--surface-3);
  border-color: var(--line-strong);
}

.btn:disabled {
  opacity: 0.42;
  cursor: not-allowed;
}

.btn.sm {
  min-height: 36px;
  padding: 0 13px;
  font-size: 13px;
}

.btn.primary {
  background: var(--accent);
  border-color: transparent;
  color: #fff;
}

.btn.primary:hover:not(:disabled) {
  background: var(--accent-hover);
  border-color: transparent;
  color: #fff;
}

.btn.money {
  background: var(--money);
  border-color: transparent;
  color: var(--money-btn-text);
  font-weight: 700;
}

.btn.money:hover:not(:disabled) {
  background: var(--money-hover);
  border-color: transparent;
  color: var(--money-btn-text);
}

.btn.danger {
  color: var(--danger-text);
  border-color: var(--danger-soft);
  background: var(--danger-soft);
}

.btn.danger:hover:not(:disabled) {
  background: var(--danger-soft);
  border-color: var(--danger);
  color: var(--danger-text);
}

.btn.ghost {
  background: transparent;
  border-color: transparent;
  color: var(--muted);
}

.btn.ghost:hover:not(:disabled) {
  background: var(--surface-3);
  color: var(--text);
}

.btn.wide {
  width: 100%;
}

/* A tecla de atalho vive no próprio botão. O operador aprende o atalho
   usando o mouse: que é como a migração de mouse para teclado acontece
   de fato no balcão. */
.key {
  display: inline-grid;
  place-items: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  color: var(--faint);
  letter-spacing: 0.02em;
}

.btn.primary .key,
.btn.money .key {
  background: rgba(0, 0, 0, 0.18);
  border-color: rgba(0, 0, 0, 0.16);
  color: inherit;
  opacity: 0.72;
}

/* ---------- Campos ------------------------------------------------------ */

.field {
  display: flex;
  flex-direction: column;
  gap: 7px;
  min-width: 0;
}

.label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.02em;
}

.input,
select.input,
textarea.input {
  height: 44px;
  padding: 0 14px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--text);
  width: 100%;
}

textarea.input {
  height: auto;
  padding: 11px 14px;
  resize: vertical;
}

.input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.input::placeholder {
  color: var(--faint);
}

.input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Campo de leitura: é onde o foco mora o tempo todo (§10.4). */
.scan {
  position: relative;
}

.scan .input {
  height: 58px;
  font-size: 17px;
  padding-left: 48px;
  padding-right: 132px;
  background: var(--bg);
  border-color: var(--line-strong);
  box-shadow: inset 3px 0 0 var(--accent);
}

.scan .input:focus {
  border-color: var(--accent);
}

.scan-icon {
  position: absolute;
  left: 16px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--faint);
  pointer-events: none;
  display: grid;
  place-items: center;
}

.scan-mode {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
}

.toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 13px;
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  border: 1px solid var(--line);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  user-select: none;
}

.toggle.on {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--accent-text);
}

.switch {
  width: 30px;
  height: 17px;
  border-radius: var(--radius-sm);
  background: var(--line-strong);
  position: relative;
  flex: none;
}

.switch::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--faint);
}

.toggle.on .switch {
  background: var(--accent);
}

.toggle.on .switch::after {
  transform: translateX(13px);
  background: #fff;
}

/* ---------- Wizard ------------------------------------------------------ */

.main {
  display: grid;
  /* `minmax(0, 1fr)` e não `1fr`.
     Item de grid tem `min-width: auto`, então uma trilha `1fr` se recusa a
     encolher abaixo do min-content do conteúdo: o painel estoura para
     fora da viewport e leva junto o TOTAL, o Finalizar venda e a coluna de
     vendas em espera, sem sequer mostrar barra de rolagem. Em 1366×768,
     que é a resolução típica de terminal de PDV, isso escondia o botão
     mais importante da tela. */
  grid-template-columns: minmax(0, 1fr) 310px;
  min-height: 0;
  overflow: hidden;
}

.work {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(370px, 430px);
  min-height: 0;
  border-right: 1px solid var(--line);
}

.panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

.steps {
  display: flex;
  gap: 0;
  min-height: 62px;
  padding: 0 20px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.step {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 11px;
  min-height: 61px;
  padding: 0 14px;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.step:hover {
  background: var(--surface-2);
}

.step.on {
  border-bottom-color: var(--accent);
  background: var(--accent-soft);
}

.step-n {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--surface-3);
  border: 1px solid var(--line);
  font-size: 12px;
  font-weight: 700;
  color: var(--muted);
  flex: none;
}

.step.on .step-n {
  background: var(--accent);
  border-color: transparent;
  color: #fff;
}

.step.done .step-n {
  background: var(--money-soft);
  border-color: var(--money);
  color: var(--money-text);
}

.step-label {
  font-weight: 600;
  font-size: 14px;
}

.step-hint {
  font-size: 11.5px;
  color: var(--faint);
}

.step-body {
  flex: 1;
  overflow-y: auto;
  padding: 22px 20px 26px;
  min-height: 0;
}

.step-body[hidden] {
  display: none;
}

/* ---------- Resultados da busca ---------------------------------------- */

.results {
  margin-top: 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

.result {
  display: grid;
  /* A foto entra como primeira faixa, de largura fixa: a descrição
     continua sendo a coluna que estica. */
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 16px;
  padding: 12px 16px;
  min-height: 64px;
  cursor: pointer;
  border-bottom: 1px solid var(--line);
}

.result:last-child {
  border-bottom: 0;
}

.result:hover,
.result.cursor {
  background: var(--surface-3);
}

.result.cursor {
  box-shadow: inset 3px 0 0 var(--accent);
  background: var(--accent-soft);
}

.result-name {
  font-weight: 550;
  font-size: 14.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.result-meta {
  display: flex;
  gap: 10px;
  font-size: 12px;
  color: var(--faint);
  margin-top: 3px;
}

.result-meta .sku {
  font-family: var(--mono);
}

.stock {
  font-size: 12.5px;
  font-weight: 600;
  padding: 3px 9px;
  border-radius: 3px;
  background: var(--surface-3);
  color: var(--muted);
}

.stock.zero {
  background: var(--danger-soft);
  color: var(--danger-text);
}

.result-price {
  font-weight: 650;
  font-size: 15px;
}

/* ---------- Carrinho ---------------------------------------------------- */

.cart {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--surface);
  border-left: 1px solid var(--line);
}

.cart-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 62px;
  padding: 0 18px;
  border-bottom: 1px solid var(--line);
}

.cart-title {
  font-weight: 700;
  font-size: 14.5px;
  letter-spacing: 0;
}

.count {
  padding: 2px 7px;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--surface-2);
  font-size: 11.5px;
  color: var(--muted);
}

.cart-items {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
  padding: 8px 10px;
}

.line {
  display: grid;
  /* Foto, descrição e total. A linha de baixo (quantidade, preço,
     etiquetas) atravessa as duas últimas colunas. */
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 6px 12px;
  padding: 13px 10px;
  border-radius: var(--radius-sm);
}

.line-thumb {
  grid-row: span 2;
  align-self: start;
}

.line:hover {
  background: var(--surface-3);
}

.line + .line {
  border-top: 1px solid var(--line);
}

.line-name {
  font-size: 14px;
  font-weight: 550;
  line-height: 1.35;
}

.line-total {
  font-weight: 650;
  font-size: 14.5px;
  text-align: right;
  white-space: nowrap;
}

.line-meta {
  grid-column: 2 / -1;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12.5px;
  color: var(--muted);
}

.qty {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface);
}

.qty button {
  width: 30px;
  height: 30px;
  border: 0;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
}

.qty button:hover {
  background: var(--surface-3);
  color: var(--text);
}

.qty span {
  min-width: 34px;
  text-align: center;
  font-size: 13px;
  font-weight: 600;
}

.line-drop {
  margin-left: auto;
  border: 0;
  background: transparent;
  color: var(--faint);
  cursor: pointer;
  padding: 5px 7px;
  border-radius: var(--radius-sm);
}

.line-drop:hover {
  color: var(--danger);
  background: var(--danger-soft);
}

/* ---------- Totais ------------------------------------------------------ */

.totals {
  border-top: 1px solid var(--line-strong);
  padding: 15px 18px;
  display: grid;
  gap: 9px;
}

.trow {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 13.5px;
  color: var(--muted);
}

.trow strong {
  color: var(--text);
  font-weight: 600;
}

.trow.discount strong {
  color: var(--warn-text);
}

.trow.change strong {
  color: var(--money-text);
}

/* O saldo devedor é o número que o operador procura na etapa de
   pagamento; ele ganha peso próprio. */
.trow.due {
  font-size: 15px;
}

.trow.due strong {
  color: var(--warn-text);
  font-size: 17px;
  font-weight: 700;
}

/* ---------- Fila de vendas em espera (§4.1) ----------------------------- */

.queue {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--surface);
}

.queue-head {
  min-height: 62px;
  padding: 0 16px;
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.queue-list {
  flex: 1;
  overflow-y: auto;
  padding: 12px;
  display: grid;
  gap: 8px;
  align-content: start;
}

.qcard {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 12px 13px;
  background: var(--surface);
  cursor: pointer;
}

.qcard:hover {
  border-color: var(--accent-line);
  background: var(--surface-3);
}

.qcard-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
}

.qcard-name {
  font-size: 13.5px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.qcard-total {
  font-weight: 650;
  font-size: 13.5px;
  white-space: nowrap;
}

.qcard-meta {
  font-size: 11.5px;
  color: var(--faint);
  margin-top: 4px;
}

/* Estado vazio: o texto é o mesmo do sistema de referência (§4.1). */
.empty {
  display: grid;
  place-items: center;
  gap: 10px;
  padding: 48px 20px;
  text-align: center;
  color: var(--faint);
  font-size: 13.5px;
}

.empty svg {
  opacity: 0.4;
}

/* ---------- Rodapé fixo (§4.1) ------------------------------------------ */

.foot {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 16px;
  background: var(--surface-2);
  border-top: 1px solid var(--line-strong);
}

.grand {
  margin-left: auto;
  display: flex;
  align-items: baseline;
  gap: 12px;
  min-width: 250px;
  padding: 0 18px;
  border-left: 1px solid var(--line);
}

.grand-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.grand-value {
  font-size: 32px;
  font-weight: 700;
  letter-spacing: 0;
  line-height: 1;
}

.foot .btn {
  min-height: 52px;
  font-size: 15px;
}

.foot .btn.money {
  min-width: 210px;
  padding: 0 26px;
}

/* Linha vencida e lançamento estornado. A cor sinaliza; o texto ao lado
   continua sendo quem informa, porque cor sozinha não é acessível. */
.vencida td {
  background: var(--danger-soft);
}

.estornado {
  opacity: 0.65;
}

.estornado td:nth-child(3) {
  text-decoration: line-through;
}

/* Miniatura do produto. O espaço reservado ocupa exatamente a mesma
   área da foto, para a altura da linha não mudar conforme o cadastro
   tenha ou não imagem: tabela que "pula" atrapalha a conferência. */
.thumb-cell {
  display: inline-grid;
  place-items: center;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  color: var(--faint);
  vertical-align: middle;
  flex: none;
}

.thumb-cell img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.thumb-ph {
  display: grid;
  place-items: center;
  color: var(--faint);
}

.thumb-cell-edit {
  cursor: pointer;
}

.thumb-cell-edit:hover {
  border-color: var(--accent);
  color: var(--accent-text);
}

/* Marcas na linha do carrinho: desconto aplicado e observação. Ficam na
   própria linha porque o operador confere o carrinho com o cliente ao
   lado, e abrir um painel por item para conferir não é opção. */
.line-tag {
  padding: 1px 7px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  color: var(--muted);
  font-size: 11.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 180px;
}

.line-edit {
  padding: 2px 9px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  font-size: 11.5px;
  cursor: pointer;
}

.line-edit:hover {
  color: var(--text);
  border-color: var(--line-strong);
  background: var(--surface-2);
}

/* Rascunho sem item na fila. Ele fica visível de propósito: é o que
   segura o fechamento do caixa, e escondê-lo criava um beco sem saída. */
.qcard-empty {
  border-style: dashed;
  opacity: 0.8;
}

.qempty-note {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 12px;
  margin-bottom: 8px;
  border: 1px solid var(--warn);
  border-radius: var(--radius-sm);
  background: var(--warn-soft);
  color: var(--warn-text);
  font-size: 12.5px;
}

/* ---------- Modal ------------------------------------------------------- */

.scrim {
  position: fixed;
  inset: 0;
  background: rgba(4, 6, 10, 0.6);
  display: grid;
  place-items: center;
  padding: 24px;
  z-index: 60;
}

.scrim[hidden] {
  display: none;
}

.modal {
  width: min(680px, 100%);
  max-height: 86vh;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.modal.wide {
  width: min(1000px, 100%);
}

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 22px;
  border-bottom: 1px solid var(--line);
}

.modal-title {
  font-size: 16.5px;
  font-weight: 650;
  letter-spacing: 0;
}

.modal-body {
  padding: 20px 22px;
  overflow-y: auto;
}

.modal-foot {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  padding: 16px 22px;
  border-top: 1px solid var(--line);
  background: var(--surface-2);
}

.x {
  width: 34px;
  height: 34px;
  border-radius: 8px;
  border: 0;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  display: grid;
  place-items: center;
}

.x:hover {
  background: var(--surface-3);
  color: var(--text);
}

/* ---------- Grades e utilitários --------------------------------------- */

.grid {
  display: grid;
  gap: 14px;
}

.grid.c2 {
  grid-template-columns: 1fr 1fr;
}

.grid.c3 {
  grid-template-columns: repeat(3, 1fr);
}

.grid.c4 {
  grid-template-columns: repeat(4, 1fr);
}

.row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.stack {
  display: grid;
  gap: 14px;
}

.section {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

.section-head {
  padding: 14px 18px;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
  font-weight: 650;
  letter-spacing: 0.02em;
  color: var(--muted);
  text-transform: uppercase;
  background: var(--surface-2);
}

.section-body {
  padding: 18px;
}

/* Visível só para leitor de tela. A página precisa de hierarquia
   semântica mesmo quando o desenho não pede título visível. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.muted {
  color: var(--muted);
}

.faint {
  color: var(--faint);
}

.tiny {
  font-size: 12px;
}

.right {
  text-align: right;
}

/* Cartões de forma de pagamento (§4.4) */
.methods {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
  gap: 10px;
}

.method {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-height: 74px;
  padding: 13px 15px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface);
  cursor: pointer;
  text-align: left;
}

.method:hover:not(:disabled) {
  border-color: var(--accent-line);
  background: var(--surface-3);
}

.method.on {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.method:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.method-name {
  font-weight: 600;
  font-size: 14px;
}

.method-kind {
  font-size: 11.5px;
  color: var(--faint);
}

/* Escolha crítica merece confirmação visível, não só uma borda de 1px. */
.method-check {
  float: right;
  color: var(--accent-text);
  font-weight: 700;
}

.method.on {
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* O motivo de estar desabilitada, em cada cartão: melhor que uma nota de
   rodapé que não diz qual das formas está fora. */
.method-badge {
  margin-top: auto;
  align-self: flex-start;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--warn-text);
  background: var(--warn-soft);
  border-radius: 5px;
  padding: 2px 6px;
}

/* Tabelas.
   A `.section` que envolve uma tabela rola sozinha no eixo X. Sem isto,
   uma tabela larga empurra a página inteira e o corpo ganha rolagem
   horizontal: o conteúdo à direita some da tela. */
.section:has(> table.data),
.section:has(> .section-body > table.data) {
  overflow-x: auto;
}

table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}

/* Escopado ao `thead` de propósito. A descrição do produto é cabeçalho da
   própria linha (`th scope="row"`), para que o leitor de tela anuncie de
   quem é o preço em vez de ler "R$ 49,90" solto; sem o escopo, ela herdaria
   caixa alta, cor apagada e, pior, `position: sticky`. */
table.data thead th {
  text-align: left;
  font-size: 11.5px;
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--faint);
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
  position: sticky;
  top: 0;
}

table.data td,
table.data tbody th {
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
}

table.data tbody th {
  text-align: left;
  font-weight: inherit;
}

table.data tbody tr:hover {
  background: var(--surface-2);
}

table.data td.num,
table.data th.num {
  text-align: right;
}

/* Barra de progresso do relatório de grupos */
.bar {
  height: 6px;
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  overflow: hidden;
}

.bar > i {
  display: block;
  height: 100%;
  background: var(--accent);
}

/* ---------- Página de conteúdo (admin) --------------------------------- */

.page {
  display: grid;
  grid-template-rows: var(--bar-h) 1fr;
  height: 100vh;
}

.page-body {
  overflow-y: auto;
  padding: 26px 28px 60px;
}

.page-title {
  font-size: 24px;
  font-weight: 700;
  letter-spacing: 0;
  margin: 0 0 4px;
}

.page-sub {
  color: var(--muted);
  font-size: 13.5px;
  margin: 0 0 22px;
}

.wrap {
  max-width: 1180px;
  margin: 0 auto;
}

/* ---------- Login ------------------------------------------------------- */

.login {
  height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
  overflow: auto;
  background: var(--bg);
}

.login-card {
  width: min(410px, 100%);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 34px 32px;
  box-shadow: var(--shadow-lg);
}

.login h1 {
  font-size: 21px;
  font-weight: 700;
  letter-spacing: 0;
  margin: 18px 0 5px;
}

.login p.sub {
  color: var(--muted);
  font-size: 13.5px;
  margin: 0 0 26px;
}

.hint {
  margin-top: 22px;
  padding: 13px 15px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--line);
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.65;
}

.hint code {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--text);
}

.alert {
  padding: 12px 15px;
  border-radius: var(--radius-sm);
  font-size: 13.5px;
  margin-bottom: 18px;
  border: 1px solid;
}

.alert.err {
  background: var(--danger-soft);
  border-color: var(--danger);
  color: var(--danger-text);
}

.alert.warn {
  background: var(--warn-soft);
  border-color: var(--warn);
  color: var(--warn-text);
}

/* Explicação de como a tela funciona, não um problema. Fica no tom do
   sistema em vez do amarelo de aviso, que faria o usuário procurar o que
   está errado. */
.alert.info {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--text);
}

/* ---------- Aviso flutuante -------------------------------------------- */

.toasts {
  position: fixed;
  right: 20px;
  bottom: 20px;
  display: grid;
  gap: 10px;
  /* Acima de qualquer modal (z-index 60): o aviso costuma ser *sobre* o
     que acabou de acontecer no modal, e precisa ser lido. */
  z-index: 200;
  width: min(420px, calc(100vw - 40px));
}

.toast {
  display: grid;
  grid-template-columns: 3px minmax(0, 1fr) auto;
  gap: 0 14px;
  align-items: start;
  padding: 0;
  border-radius: var(--radius-sm);
  /* Fundo OPACO. A versão anterior usava color-mix sobre uma cor com
     alpha, e o resultado era translúcido: dava para ler o botão do modal
     através do texto do erro. */
  background: var(--surface);
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

/* A faixa colorida à esquerda carrega o significado; o fundo permanece
   neutro e o texto mantém o contraste em qualquer tema. */
.toast::before {
  content: "";
  display: block;
  width: 3px;
  height: 100%;
  background: var(--line-strong);
}

.toast.err::before { background: var(--danger); }
.toast.ok::before { background: var(--money); }
.toast.err { border-color: var(--danger); }
.toast.ok { border-color: var(--money); }

.toast-body {
  padding: 13px 0 14px;
  min-width: 0;
}

.toast-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.toast-title {
  font-weight: 650;
  font-size: 14px;
  color: var(--text);
  line-height: 1.35;
}

.toast.err .toast-title { color: var(--danger-text); }
.toast.ok .toast-title { color: var(--money-text); }

.toast-count {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--muted);
  background: var(--surface-3);
  border-radius: var(--radius-sm);
  padding: 1px 7px;
  flex: none;
}

.toast-detail {
  margin-top: 4px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
  opacity: 0.85;
}

.toast-list {
  margin: 8px 0 0;
  padding-left: 18px;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--text);
  opacity: 0.8;
}

/* A instrução do que fazer. Destacada de propósito: é a parte acionável,
   e ela é o motivo de o aviso existir. */
.toast-hint {
  margin-top: 10px;
  padding: 9px 11px;
  border-radius: 8px;
  background: var(--surface-3);
  border-left: 2px solid var(--accent);
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text);
}

.toast-close {
  border: 0;
  background: transparent;
  color: var(--faint);
  cursor: pointer;
  font-size: 13px;
  padding: 12px 13px 0 0;
  line-height: 1;
}

.toast-close:hover { color: var(--text); }

/* Lista de pedidos impeditivos do fechamento (RN-10) */
.blocking {
  margin-top: 10px;
  display: grid;
  gap: 6px;
}

.blocking li {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border-radius: 8px;
  background: var(--surface-3);
  font-size: 13px;
  list-style: none;
}

ul.blocking {
  padding: 0;
  margin: 10px 0 0;
}

/* Barra de rolagem discreta */
::-webkit-scrollbar {
  width: 11px;
  height: 11px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border-radius: 99px;
  border: 3px solid var(--bg);
}

::-webkit-scrollbar-thumb:hover {
  background: var(--faint);
}

@media (max-width: 1200px) {
  .main {
    grid-template-columns: minmax(0, 1fr) 290px;
  }
  .work {
    grid-template-columns: minmax(0, 1fr) minmax(350px, 400px);
  }
}

@media (max-width: 1100px) {
  .main {
    grid-template-columns: minmax(0, 1fr);
  }

  /* A fila vira gaveta, e não `display: none`.
     Escondê-la tornava as vendas em espera inalcançáveis em tablet, e
     venda suspensa que não pode ser retomada é venda perdida. */
  .queue {
    position: fixed;
    top: calc(var(--bar-h) * 2);
    right: 0;
    bottom: var(--foot-h);
    width: min(340px, 88vw);
    z-index: 70;
    border-left: 1px solid var(--line);
    box-shadow: var(--shadow-lg);
    transform: translateX(100%);
  }

  body.queue-open .queue {
    transform: translateX(0);
  }

  body.queue-open .queue-scrim {
    display: block;
  }

  .queue-toggle {
    display: inline-flex !important;
  }

  .salebar {
    overflow-x: auto;
    overscroll-behavior-x: contain;
  }

  .salebar .sale-title {
    min-width: 142px;
    white-space: nowrap;
  }

  .salebar .sale-id,
  .salebar #helpBtn {
    display: none;
  }
}

/* Fundo que fecha a gaveta ao toque. Só existe no modo gaveta. */
.queue-scrim {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(4, 6, 10, 0.5);
  z-index: 65;
}

.queue-toggle {
  display: none;
}

/* Em telas estreitas o PDV vira uma coluna de trabalho. A fila continua
   como gaveta e o carrinho permanece acessivel abaixo do lancamento. */
@media (max-width: 760px) {
  body:has(> .app) {
    height: auto;
    min-height: 100%;
    overflow: auto;
  }

  .app {
    height: auto;
    min-height: 100dvh;
    grid-template-rows: auto auto auto auto;
  }

  .identity {
    min-height: var(--bar-h);
    gap: 8px;
    padding: 0 10px;
  }

  .brand-name,
  .brand-sub,
  .identity .nav-shell,
  .identity #cashPill,
  .user .avatar,
  .user > div:not(.avatar) {
    display: none;
  }

  .scope {
    max-width: 190px;
    overflow: hidden;
  }

  .scope-store {
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .user {
    padding-left: 0;
  }

  .salebar {
    min-height: var(--sale-h);
    overflow-x: auto;
    overscroll-behavior-x: contain;
  }

  .salebar > * {
    flex: none;
  }

  .salebar > .spacer {
    display: none;
  }

  .sale-title {
    min-width: 160px;
  }

  .main,
  .work {
    display: block;
    overflow: visible;
  }

  .work {
    border-right: 0;
  }

  .panel {
    min-height: 620px;
  }

  .steps {
    padding: 0 10px;
    overflow-x: auto;
  }

  .step {
    min-width: 112px;
    padding: 0 10px;
  }

  .step-hint,
  .step .key {
    display: none;
  }

  .step-body {
    padding: 16px 12px 22px;
    overflow: visible;
  }

  .scan .input {
    padding-right: 48px;
    font-size: 15px;
  }

  .scan-mode {
    width: 42px;
    padding: 0;
    font-size: 0;
  }

  .scan-mode .switch {
    width: 30px;
  }

  .cart {
    min-height: 360px;
    border-top: 1px solid var(--line-strong);
    border-left: 0;
  }

  .queue {
    top: calc(var(--bar-h) + var(--sale-h));
  }

  .foot {
    position: static;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 8px;
    padding: 8px 10px;
  }

  .foot .btn {
    width: 100%;
    min-height: 44px;
    padding: 0 10px;
    font-size: 13px;
  }

  .grand {
    min-width: 0;
    margin: 0;
    padding: 0 8px;
    border-left: 0;
    justify-content: space-between;
  }

  .grand-value {
    font-size: 23px;
  }

  .foot .btn.money {
    min-width: 0;
    padding: 0 10px;
  }
}


/* =========================================================================
   Impressão: comprovante não fiscal.

   Sem estas regras, apertar Imprimir mandava a aplicação inteira para o
   papel: barra de identidade, wizard, carrinho e rodapé. O que vai para a
   impressora é só `#printArea`, montado no momento da impressão.

   Isto é o caminho de degradação do §10.5, para quando o Bridge não
   responde. Com o Bridge, quem imprime é a térmica em ESC/POS e nada disto
   é usado.
   ========================================================================= */

#printArea { display: none; }

/* ---------- Cartão de indicador e controles auxiliares ---------------- */

/* Números do topo das telas de gestão. O rótulo vem antes do valor porque
   quem lê o painel procura a métrica, não o número solto. */
.kpi {
  padding: 16px 18px;
}

.kpi-label {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
}

.kpi-value {
  margin-top: 4px;
  font-size: 26px;
  font-weight: 650;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}

.kpi-value.money {
  color: var(--money-text);
}

.kpi-sub {
  margin-top: 2px;
  font-size: 12.5px;
  color: var(--muted);
}

/* A caixa de seleção precisa dos mesmos 44px de alvo dos demais controles
   (§17), e a etiqueta inteira tem de ser clicável. */
.check {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: 13.5px;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}

.check:hover {
  border-color: var(--line-strong);
}

.check input {
  width: 17px;
  height: 17px;
  accent-color: var(--accent);
  cursor: pointer;
}

.input.sm {
  min-height: 36px;
  padding: 0 10px;
  font-size: 13.5px;
}

/* Texto colorido. Usa os tokens de texto, e não os de superfície: estes
   últimos não alcançam 4.5:1 sobre o fundo claro. */
.danger-text { color: var(--danger-text); }
.warn-text { color: var(--warn-text); }
.money-text { color: var(--money-text); }

/* Abas das telas de gestão. */
.tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 18px;
  overflow-x: auto;
}

.tab {
  padding: 11px 16px;
  border: 0;
  border-bottom: 2px solid transparent;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
}

.tab:hover {
  color: var(--text);
}

.tab.on {
  color: var(--text);
  border-bottom-color: var(--accent);
  font-weight: 600;
}

/* ---------- Catálogo: lista, grade e amostra ---------------------------- */

/* A rolagem horizontal vive num invólucro próprio. Antes ela estava em
   `.section`, que virava o contêiner de rolagem mais próximo e roubava o
   `position: sticky` do cabeçalho: ele subia e não voltava. */
.table-scroll {
  overflow-x: auto;
}

/* Largura fixa, e não automática. Com `table-layout: auto`, uma variação
   de nome comprido alargava a coluna Descrição, e quem saía da tela do
   outro lado era Estoque e o botão Editar, que são o motivo de a linha
   existir. Agora a coluna declarada é a coluna real, e o texto que não
   couber trunca dentro dela. */
.catalog-table {
  table-layout: fixed;
  min-width: 1040px;
}

/* A coluna de ações fica presa à direita. Quando a tabela não couber e
   precisar rolar de lado, Editar e o menu continuam no lugar: procurar o
   botão de editar rolando a tabela é trabalho que ninguém deveria ter, e
   menos ainda no balcão. */
.catalog-table > thead th:last-child,
.catalog-table > tbody > tr > *:last-child {
  position: sticky;
  right: 0;
  z-index: 1;
}

.catalog-table > thead th:last-child {
  z-index: 2;
}

.grupo-pai > *:last-child,
tbody > tr:not(.grupo-filha) > *:last-child {
  background: var(--surface);
}

.grupo-filha > *:last-child {
  background: var(--surface-2);
}

/* Só a Descrição corta: as outras têm largura declarada e conteúdo curto,
   e recortar todas esconderia o editor de preço, que é mais alto que a
   célula enquanto está aberto. */
.catalog-table > thead th:nth-child(3),
.catalog-table > tbody > tr > *:nth-child(3) {
  overflow: hidden;
}

/* Nome longo trunca em vez de esticar a coluna. Sem isto, um nome de 40
   caracteres empurrava Preço, Estoque e as ações para trás de uma barra
   de rolagem, justamente no notebook de 13 polegadas do balcão. */
.nome-produto {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.nome-texto {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 550;
}

/* O nome do produto é o texto mais forte da tabela. Ele é a âncora: tudo
   que vem abaixo dele até o próximo é a mesma peça. */
.nome-pai {
  font-size: 14.5px;
  font-weight: 650;
}

/* A linha da variação repete o nome do produto inteiro, e não só "Tamanho:
   G". Ela é copiada para marketplace, lida em conferência e aparece em
   busca, situações em que a linha de cima não está por perto para dar o
   contexto.

   O nome repetido pesa menos que o do pai: é contexto, e o que diferencia
   uma linha da outra é o atributo. */
/* O nome repetido é contexto, e contexto não pode competir com o nome do
   pai. Ele desce de tamanho e de cor; quem fica forte é o atributo, que é
   o que diferencia esta linha das outras quatro logo abaixo.

   Sem esta diferença, pai e variação viravam a mesma linha: o olho perdia
   onde um produto termina e o próximo começa. */
/* Duas linhas: o atributo em cima, porque é o que diferencia esta linha
   das outras quatro e o que o olho compara descendo a coluna; o nome do
   produto embaixo, apagado, porque é contexto.

   Inline os dois não cabiam: numa coluna de 260px o atributo tomava tudo
   e do nome sobravam três letras. */
.var-bloco {
  display: block;
  min-width: 0;
}

.var-linha {
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
}

.var-nome {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 11.5px;
  font-weight: 400;
  color: var(--faint);
}

/* O atributo nunca trunca. Com o nome repetido, ele é a última coisa da
   linha, e é justamente o que as reticências comeriam primeiro: quatro
   variações viravam quatro linhas idênticas terminando em "...". */
/* Quebra em duas linhas antes de truncar. O atributo é o que separa esta
   variação das outras cinco: cortá-lo transforma a coluna inteira em seis
   linhas iguais terminando em reticências, que é pior do que não mostrar
   nada. Ele é o único texto da tabela com esse privilégio. */
.var-attr {
  font-size: 13px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text);
  overflow-wrap: anywhere;
}

/* O código trunca em vez de quebrar em três linhas. Antes, "13914-MARINHO-
   PP" mais o botão de copiar levantavam a linha para 100px de altura, e
   uma tabela de conferência perdia metade das linhas visíveis por causa
   disso. O valor inteiro fica no `title` e no botão de copiar. */
.catalog-table td.mono {
  font-family: var(--mono);
  font-size: 12.5px;
}

.codigo-linha {
  display: flex;
  align-items: center;
  gap: 2px;
  min-width: 0;
}

.codigo-sku {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.codigo-gtin {
  display: block;
  font-size: 11px;
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Copiar o código sem selecionar com o mouse. Quem anuncia em marketplace
   faz isso dezenas de vezes por dia, e um SKU com um caractere a mais na
   seleção vira anúncio sem estoque vinculado. */
.copy-btn {
  display: inline-grid;
  place-items: center;
  width: 24px;
  height: 24px;
  margin-left: 4px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--faint);
  cursor: pointer;
  vertical-align: -6px;
}

.copy-btn:hover {
  border-color: var(--line-strong);
  background: var(--surface-3);
  color: var(--text);
}

.copy-btn.feito {
  color: var(--money-text);
}

.catalog-table td.acoes {
  white-space: nowrap;
}

.empty-cell {
  padding: 28px 16px;
  text-align: center;
  color: var(--muted);
}

.empty-cell .btn {
  margin-left: 10px;
}

/* A amostra de cor. Numa loja de roupa a cor é a chave de busca mais
   rápida que existe; escrever "Azul" desperdiça isso. A borda existe
   porque branco e off white desapareceriam sobre a superfície clara. */
.swatch {
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-right: 6px;
  border: 1px solid var(--line-strong);
  border-radius: 3px;
  vertical-align: -2px;
  flex: none;
}

.preco-herda {
  margin-right: 6px;
}

/* A barra de identidade tem itens demais para 1440px: nove links, o
   seletor de loja e o bloco de usuário. Como ela é `overflow: hidden`, o
   que sobrava era o "Mais" cortado no meio da palavra.

   O que cede primeiro é o que se repete em outro lugar da própria barra:
   "Frente de loja" está no título da aba, e a tecla de atalho do seletor
   de loja continua funcionando sem o selo. */
@media (max-width: 1520px) {
  .nav a,
  .navmore-btn {
    padding: 0 10px;
  }

  .brand-sub,
  .scope-key {
    display: none;
  }
}

@media (max-width: 1440px) {
  .nav a,
  .navmore-btn {
    padding: 0 7px;
    font-size: 13.5px;
  }

  /* Sobra o avatar com as iniciais, que continua identificando quem
     esta logado. O nome por extenso e o que cede. */
  .user > div:not(.avatar) {
    display: none;
  }
}

/* A saída do erro de login. Separada do texto do aviso por uma linha, e não
   por cor: numa conta suspensa ela é a única das três linhas em que o
   lojista pode agir, e ela precisa sobreviver a quem lê só o começo. */
.alert-saida {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--line-strong);
  font-size: 12.5px;
  line-height: 1.5;
}

/* ---------- Painel de ações em massa ------------------------------------ */

/* A lista e o painel dividem a largura, e a lista vence: ela é o trabalho.
   O painel tem largura fixa porque é uma coluna de rótulos, e rótulo que
   estica só ganha espaço em branco à direita. */
/* O `.wrap` padrão tem teto de 1180px, que serve a tela de formulário. O
   catálogo tem nove colunas mais um painel: com 1180px sobravam 908px para
   a tabela, que pede 940px, e a página inteira passou a rolar de lado. */
.catalogo-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 240px;
  gap: 20px;
  align-items: start;
  max-width: 1560px;
}

.catalogo-main {
  min-width: 0;
}

/* A rolagem lateral, quando existir, pertence à tabela e não à página:
   rolar a página de lado leva embora o painel e o cabeçalho junto. */
.catalogo-main .table-scroll {
  min-width: 0;
  max-width: 100%;
}

/* Abaixo disto a tabela já usa a largura inteira e o painel espremeria as
   colunas de dinheiro. Ele desce para baixo da lista, onde continua
   alcançável sem competir por espaço. */
@media (max-width: 1340px) {
  .catalogo-layout {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Rolagem própria: com todas as ações abertas o painel passa da altura da
   tela em notebook, e sem isto as últimas ficariam inalcançáveis enquanto
   a lista, que é o trabalho, rola sozinha atrás. */
.bulk-rail {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: calc(100vh - var(--bar-h) - 52px);
  overflow-y: auto;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.rail-primary {
  width: 100%;
  justify-content: center;
}

/* O escopo fica logo abaixo do botão principal e acima de qualquer ação,
   porque quem lê "Reajuste de preços" precisa já saber sobre o que ele
   vai cair. */
.rail-scope {
  margin: 0;
  padding: 9px 10px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--line);
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--muted);
}

.rail-group {
  display: flex;
  flex-direction: column;
}

.rail-head {
  margin: 4px 0 2px;
  font-size: 10.5px;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
}

/* Alvo de 44px como a §17 manda, mesmo sendo uma lista de texto: o painel
   também é usado no notebook do balcão, com trackpad. */
.rail-item {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}

.rail-item:hover:not(:disabled) {
  background: var(--surface-3);
}

.rail-item:disabled {
  color: var(--faint);
  cursor: not-allowed;
}

.rail-nota {
  margin: 2px 0 0 10px;
  line-height: 1.4;
}

.rail-group + .rail-group {
  border-top: 1px solid var(--line);
  padding-top: 6px;
}

.rail-counts {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.rail-counts > div {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  font-size: 12.5px;
}

.rail-counts dt {
  color: var(--muted);
}

.rail-counts dd {
  margin: 0;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

/* Botão que se comporta como link dentro de um parágrafo. Existe porque
   "Limpar" no meio de uma frase não é uma ação de barra: é uma correção
   do que a frase acabou de dizer. */
.linkish {
  border: 0;
  padding: 0;
  background: none;
  color: var(--accent-text);
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}

/* ---------- Seleção e diálogo em massa ---------------------------------- */

.col-check {
  width: 38px;
  padding-right: 0 !important;
}

.catalog-table input[type="checkbox"] {
  width: 17px;
  height: 17px;
  accent-color: var(--accent);
  cursor: pointer;
}

/* O número do escopo é a última coisa lida antes de aplicar. Acima de
   cinquenta produtos ele muda de cor, porque a partir daí o erro deixa de
   ser corrigível a mão. */
.bulk-escopo {
  margin: 0;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-2);
  font-size: 13px;
}

.bulk-escopo.muitos {
  border-color: var(--warn);
  background: var(--warn-soft);
  color: var(--warn-text);
}

.bulk-previa {
  margin-top: 10px;
  font-size: 12.5px;
}

.bulk-previa th,
.bulk-previa td {
  padding: 6px 8px;
}

/* ---------- Produto e suas variações na mesma lista --------------------- */

/* A barra à esquerda amarra o grupo visualmente. Sem ela, com a lista
   longa, não dá para saber onde termina uma grade e começa a próxima. */
.grupo-pai > * {
  background: var(--surface);
  border-top: 1px solid var(--line-strong);
}

.grupo-pai td:first-child {
  box-shadow: inset 3px 0 0 var(--accent);
}

/* A filha entra deslocada do fio do pai, e não embaixo dele. O degrau é o
   que diz, sem escrever, que aquela linha pertence à de cima; alinhados,
   os dois fios viravam uma cerca contínua onde produto e variação tinham
   o mesmo peso.

   O deslocamento é feito com duas sombras internas: a de cima, na cor da
   linha, cobre os primeiros 16px, e a de baixo aparece só na faixa que
   sobra. Não dá para dar offset a uma sombra interna de outro jeito. */
.grupo-filha td:first-child {
  padding-left: 44px;
  box-shadow: inset 30px 0 0 var(--surface-2), inset 33px 0 0 var(--accent-line);
}

.grupo-filha > * {
  background: var(--surface-2);
}

/* O degrau tem que cair no texto, e não na célula.

   Medido no navegador, o recuo anterior fazia o contrário do que parecia:
   o nome do pai começa depois do botão de expandir, que ocupa 32px, e o
   da variação começava depois de 22px de recuo. Resultado, a variação
   nascia 16px à ESQUERDA do produto dela. A lista lida como uma coisa só
   porque era uma coisa só.

   O recuo vai no container do nome, e não na célula, para o cálculo não
   depender de a variação ter ou não amostra de cor antes do texto. */
.grupo-filha .nome-produto {
  padding-left: 62px;
}

.grupo-filha.inativa > * {
  opacity: 0.6;
}

.grupo-toggle {
  display: inline-grid;
  place-items: center;
  width: 32px;
  height: 32px;
  margin-right: 2px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  font-size: 12px;
  cursor: pointer;
  flex: none;
}

.grupo-toggle:hover {
  border-color: var(--line);
  background: var(--surface-2);
  color: var(--text);
}

.grupo-toggle-vazio {
  display: inline-block;
  width: 32px;
  flex: none;
}

.grupo-toggle:hover {
  color: var(--text);
}

/* ---------- Ações da linha e edição no lugar ---------------------------- */

/* Menu de três pontos. Fica no `body`, e não dentro da célula, porque o
   `overflow` da tabela cortaria o menu da última linha pela metade. */
.rowmenu-btn {
  /* 44px é o mínimo que o cabeçalho deste arquivo declara (§17). O botão
     tinha 30px: alvo pequeno demais para o dedo e para quem tem tremor. */
  width: 44px;
  height: 44px;
  margin-left: 4px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  vertical-align: middle;
}

.rowmenu-btn:hover {
  border-color: var(--line);
  background: var(--surface-2);
  color: var(--text);
}

.rowmenu {
  /* Fixo, e não absoluto: as coordenadas vêm de `getBoundingClientRect`,
     que é relativa ao viewport. Com `absolute` o menu ficaria deslocado
     em qualquer página rolada. */
  position: fixed;
  z-index: 80;
  min-width: 200px;
  padding: 5px;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}

.rowmenu button {
  padding: 10px 12px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
}

.rowmenu button:hover {
  background: var(--surface-2);
}

.rowmenu button.perigo {
  color: var(--danger-text);
}

.rowmenu button.perigo:hover {
  background: var(--danger-soft);
}

/* Preço editável direto na lista. O botão parece texto até o mouse
   chegar: a linha continua legível como tabela, e a edição se anuncia
   sem poluir. */
.price-cell {
  min-height: 32px;
  padding: 5px 8px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--money-text);
  font: inherit;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  cursor: pointer;
}

.price-cell:hover {
  border-color: var(--line-strong);
  background: var(--surface-2);
}

.price-cell.warn-text {
  color: var(--warn-text);
}

.price-edit {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 4px;
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--surface);
}

.price-prefix {
  padding: 0 4px;
  color: var(--faint);
  font-size: 12.5px;
}

.price-input {
  width: 92px;
  min-height: 30px;
  border: 0;
  background: transparent;
  color: inherit;
  outline: none;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.price-ok,
.price-x {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  cursor: pointer;
  font-size: 13px;
}

.price-ok {
  color: var(--money-text);
}

.price-ok:hover {
  background: var(--money-soft);
}

.price-x {
  color: var(--danger-text);
}

.price-x:hover {
  background: var(--danger-soft);
}

/* ---------- Folha de etiquetas ----------------------------------------- */

.label-sheet {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.label-sheet-item {
  border: 1px dashed var(--line-strong);
  border-radius: 2px;
  background: #fff;
  line-height: 0;
}

@media print {
  /* Impressão de etiquetas: a folha ocupa a página inteira e o resto da
     aplicação desaparece. Sem isto a impressora cospe o cabeçalho, o
     menu e a tabela junto das etiquetas. */
  body.printing-labels .page,
  body.printing-labels .scrim .modal-head,
  body.printing-labels .scrim .modal-foot,
  body.printing-labels .toasts {
    display: none !important;
  }

  body.printing-labels .scrim {
    position: static;
    padding: 0;
    background: none;
  }

  body.printing-labels .modal {
    width: 100%;
    max-height: none;
    border: 0;
    box-shadow: none;
  }

  body.printing-labels .label-sheet-item {
    border: 0;
    break-inside: avoid;
  }

  body.printing-labels .row,
  body.printing-labels #labelVariants {
    display: none !important;
  }

  @page { margin: 12mm; }

  html, body {
    height: auto;
    overflow: visible;
    background: #fff;
    color: #000;
    font-size: 12px;
  }

  /* Esconde a aplicação inteira e revela apenas o comprovante. */
  /* A regra geral esconde tudo que não é o comprovante. Ela precisa
     abrir exceção para a impressão de etiquetas, que é outro tipo de
     impressão: sem o `:not`, o `.scrim` do modal, que é filho direto do
     body, era escondido e a folha saía em branco. */
  body:not(.printing-labels) > *:not(#printArea) { display: none !important; }

  body.printing-labels > *:not(#labelModal) { display: none !important; }
  body.printing-labels #labelModal { display: block !important; }

  #printArea {
    display: block;
    max-width: 80mm;
    margin: 0 auto;
    font-family: var(--mono);
  }

  #printArea h1 {
    font-size: 14px;
    text-align: center;
    margin: 0 0 4px;
    text-transform: uppercase;
  }

  #printArea .sub {
    text-align: center;
    margin: 0 0 2px;
    font-size: 11px;
  }

  #printArea table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 10px;
  }

  #printArea th,
  #printArea td {
    padding: 3px 0;
    text-align: left;
    vertical-align: top;
  }

  #printArea thead th { border-bottom: 1px dashed #000; }
  #printArea tfoot { border-top: 1px dashed #000; }
  #printArea .r { text-align: right; white-space: nowrap; }
  #printArea .total td { font-weight: 700; font-size: 13px; padding-top: 6px; }
  #printArea small { font-size: 10px; }
}

/* -------------------------------------------------------------------------
   Suporte da SPKR dentro da conta

   Faixa no topo de tudo, e não um item escondido em Configurações: quem
   precisa da informação é o dono da loja, e ele precisa dela ENQUANTO
   acontece. O botão fica na própria faixa porque "você pode cortar" só é
   verdade se a saída estiver onde o aviso está.

   Âmbar e não vermelho: não é erro nem invasão. É uma visita autorizada
   que a pessoa tem o direito de acompanhar e de terminar.
   ------------------------------------------------------------------------- */
.suporte-dentro {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 16px;
  background: rgba(201, 138, 16, 0.14);
  border-bottom: 1px solid rgba(201, 138, 16, 0.45);
  color: var(--text);
  font-size: 13.5px;
}

.alert.ok {
  background: var(--money-soft);
  border-color: var(--money);
  color: var(--money-text);
}
.suporte-dentro .suporte-ponto {
  width: 9px;
  height: 9px;
  border-radius: 4px;
  background: var(--warn);
  flex: none;
}
.suporte-dentro .tiny { color: var(--muted); }
