/* ============================================
   Layout — Shell, Sidebar, Topbar, BottomNav
   ============================================ */

/* App shell */
.app {
  display: grid;
  min-height: 100vh;
  grid-template-rows: var(--topbar-h) 1fr;
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 768px) {
  .app {
    grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
    grid-template-rows: var(--topbar-h) 1fr;
    grid-template-areas:
      "sidebar topbar"
      "sidebar main";
  }
  .app .sidebar {
    grid-area: sidebar;
  }
  .app .topbar {
    grid-area: topbar;
  }
  .app .main {
    grid-area: main;
  }
}

/* Faixa de avisos do shell (JOT-377): linha própria entre o topbar e o
   main, fora do main porque as telas o limpam ao redesenhar. Linha `auto`:
   vazia, a faixa tem altura zero e o layout fica igual ao de antes. Só o
   shell normal tem a faixa (classe app-com-avisos); o do Studio não. */
.app.app-com-avisos {
  grid-template-rows: var(--topbar-h) auto 1fr;
}
@media (min-width: 768px) {
  .app.app-com-avisos {
    grid-template-rows: var(--topbar-h) auto 1fr;
    grid-template-areas:
      "sidebar topbar"
      "sidebar avisos"
      "sidebar main";
  }
  .app .shell-avisos {
    grid-area: avisos;
  }
}
/* Sem display:none quando vazia: no celular o grid não tem áreas nomeadas e
   a faixa precisa continuar ocupando a 2ª linha (com altura zero) para o
   main seguir na linha 1fr. */
.shell-avisos:not(:empty) {
  padding: var(--pv-s-3) var(--pv-s-4) 0;
}
/* Mesmo recuo lateral do .main em cada largura, e a mesma largura máxima do
   .main-wrap (apple.css), para o aviso alinhar com o conteúdo da tela. */
@media (min-width: 768px) {
  .shell-avisos:not(:empty) {
    padding: var(--pv-s-4) var(--pv-s-8) 0;
  }
}
@media (min-width: 1280px) {
  .shell-avisos:not(:empty) {
    padding: var(--pv-s-4) var(--pv-s-12) 0;
  }
}
.shell-aviso {
  align-items: center;
  flex-wrap: wrap;
  max-width: 1180px;
  margin: 0 auto;
}
.shell-aviso-texto {
  flex: 1 1 16rem;
}
.shell-aviso-extra {
  opacity: 0.85;
}
.shell-aviso-acao {
  font-weight: 600;
  color: inherit;
  text-decoration: underline;
  white-space: nowrap;
}

/* ---- Topbar ---- */
.topbar {
  background: var(--pv-bg-1);
  border-bottom: 1px solid var(--pv-line);
  display: flex;
  align-items: center;
  gap: var(--pv-s-4);
  padding: 0 var(--pv-s-4);
  height: var(--topbar-h);
  position: sticky;
  top: 0;
  z-index: 50;
}
.topbar-logo {
  width: 64px;
  flex-shrink: 0;
}
.topbar-logo svg,
.topbar-logo img {
  width: 100%;
  height: auto;
  display: block;
}
.topbar-tag {
  font-size: 11px;
  letter-spacing: 0;
  color: var(--pv-fg-2);
  text-transform: none;
  margin-top: 2px;
}
.topbar-client {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  line-height: 1.2;
}
.topbar-client-label {
  font-size: 11px;
  text-transform: none;
  letter-spacing: 0;
  color: var(--pv-fg-2);
}
.topbar-client-name {
  font-size: var(--t-sm);
  color: var(--pv-fg-0);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.topbar-total {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-sm);
  color: var(--pv-fg-0);
  white-space: nowrap;
}
.topbar-actions {
  display: flex;
  gap: var(--pv-s-2);
  align-items: center;
  flex-shrink: 0;
}
/* No mobile o topbar já disputa espaço com logo + cliente atual + total do
   carrinho — mantém só o ícone. A partir de 768px (mesmo corte usado no
   resto do shell) sobra espaço pro rótulo. */
.topbar-btn-label {
  display: none;
}
@media (min-width: 768px) {
  .topbar-btn-label {
    display: inline;
  }
}

/* ---- Hambúrguer + atalho de carrinho do topbar (mobile only, DEC-045) ----
   Substituem a bottom-nav + sheet "Mais": no celular o topbar vira
   [hambúrguer] [marca] [carrinho] — cliente atual/total/"Novo cliente" somem
   (mudaram de casa: vivem no bloco "Pedido em curso" do drawer) e o
   `.topbar-logo` (mesmo elemento do desktop) fica centralizado porque os dois
   ícones que o flanqueiam têm a MESMA largura (40px) — ver a matemática no
   comentário de `.topbar-hamburguer` abaixo. ≥768px eles somem e o topbar
   volta a ser exatamente o de sempre (spec: desktop intocado). */
.topbar-hamburguer,
.topbar-carrinho-mobile,
.topbar-spacer-mobile {
  display: none;
}
@media (max-width: 767px) {
  .topbar {
    justify-content: space-between;
  }
  .topbar-client,
  .topbar-total,
  .topbar-actions,
  .topbar-remover-cliente {
    display: none;
  }
  .topbar-hamburguer,
  .topbar-carrinho-mobile,
  .topbar-spacer-mobile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex-shrink: 0;
  }
}
.topbar-hamburguer {
  border: none;
  background: none;
  color: var(--pv-fg-0);
  border-radius: var(--pv-r-md);
  cursor: pointer;
}
.topbar-hamburguer:hover {
  background: var(--pv-bg-2);
}
.topbar-carrinho-mobile {
  position: relative;
  color: var(--pv-fg-0);
  text-decoration: none;
  border-radius: var(--pv-r-md);
}
.topbar-carrinho-mobile:hover {
  background: var(--pv-bg-2);
}
.topbar-carrinho-mobile .qty-badge {
  position: absolute;
  top: 2px;
  right: 2px;
  font-size: 9px;
  padding: 1px 5px;
  min-width: 14px;
}

/* ---- Sidebar (desktop only) ---- */
.sidebar {
  display: none;
  background: var(--pv-bg-1);
  border-right: 1px solid var(--pv-line);
  flex-direction: column;
  padding: 18px;
  gap: var(--pv-s-2);
  position: sticky;
  top: 0;
  height: 100dvh;
  overflow-y: auto;
}
@media (min-width: 768px) {
  .sidebar {
    display: flex;
  }
}
.sidebar-brand {
  display: flex;
  flex-direction: column;
  margin-bottom: var(--pv-s-5);
}
.sidebar-brand svg,
.sidebar-brand img {
  width: 86px;
  height: auto;
  display: block;
}
.sidebar-brand .topbar-tag {
  margin-top: var(--pv-s-2);
}
.sidebar-section-label {
  font-size: 11px;
  text-transform: none;
  letter-spacing: 0;
  color: var(--pv-fg-2);
  margin: var(--pv-s-4) var(--pv-s-2) var(--pv-s-2);
  font-weight: 600;
}
.sidebar-link {
  display: flex;
  align-items: center;
  gap: var(--pv-s-3);
  min-height: 44px;
  padding: 10px 12px;
  border-radius: var(--pv-r-md);
  color: var(--pv-fg-1);
  font-size: var(--t-sm);
  font-weight: 500;
  cursor: pointer;
  transition:
    background-color 140ms,
    color 140ms;
  position: relative;
  text-decoration: none;
}
.sidebar-link:hover {
  background: var(--pv-bg-2);
  color: var(--pv-fg-0);
}
.sidebar-link.is-active {
  background: var(--pv-selected);
  color: var(--pv-fg-0);
  font-weight: 600;
}
/* Rótulo do link (achado da revisão do #287): razão social longa (até 120
   caracteres, customerRegistrations.js) quebrava linha dentro do chip
   "Cliente atual" — o link só dividia espaço com o X ali (.sidebar-cliente-
   atual, flex:1/min-width:0), o resto da sidebar nunca precisou encolher.
   MESMO trio de truncamento de .topbar-client-name — nunca um jeito novo.
   min-width:0 é o que permite o span encolher abaixo do conteúdo dentro do
   .sidebar-link (também flex) para o ellipsis funcionar. */
.sidebar-link-label {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* "Nenhum cliente" (pedido em curso vazio) não é um item ativo de navegação:
   sem isto ele ganhava o mesmo pill escuro de "Início" e a sidebar abria com
   dois itens "ativos". Vira um slot tracejado, visivelmente vazio. */
.sidebar-link.is-placeholder,
.sidebar-link.is-placeholder .icon {
  color: var(--pv-fg-0);
}
.sidebar-link.is-placeholder {
  background: var(--pv-bg-2);
  border: 0;
}
.sidebar-link .qty-badge {
  margin-left: auto;
  background: var(--pv-gold);
  color: var(--pv-bg-0);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 10px;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: 999px;
  letter-spacing: 0;
}
/* Chip "Cliente atual" + X de remover (Issue #287) — sidebar E drawer mobile
   reusam o MESMO wrapper/botão (criarBlocoPedidoEmCurso/botaoRemoverCliente
   em shell.js), nunca duas versões que podem divergir. O link cresce
   (flex:1) e o X fica ao lado, do mesmo tamanho em qualquer superfície. */
.sidebar-cliente-atual {
  display: flex;
  align-items: center;
  gap: var(--pv-s-2);
}
.sidebar-cliente-atual .sidebar-link {
  flex: 1;
  min-width: 0;
}
/* Botão X compartilhado (sidebar, drawer mobile e topbar) — alvo de toque de
   40px (mesma medida do hambúrguer/carrinho do topbar mobile logo acima):
   o app é usado no celular, em visita, por representante na rua, nunca um
   "×" pequeno encostado no texto. */
.btn-remover-cliente {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  border-radius: var(--pv-r-md);
  color: var(--pv-fg-2);
  cursor: pointer;
}
.btn-remover-cliente:hover {
  background: var(--pv-bg-2);
  color: var(--pv-fg-0);
}
.sidebar-spacer {
  flex: 1;
}
.sidebar-divider {
  height: 1px;
  background: var(--pv-line);
  margin: var(--pv-s-3) 0;
}
.sidebar-user {
  display: flex;
  flex-direction: column;
  padding: var(--pv-s-3);
  background: var(--pv-bg-2);
  border-radius: var(--pv-r-md);
  gap: 2px;
}
.sidebar-user-name {
  font-size: var(--t-sm);
  color: var(--pv-fg-0);
  font-weight: 600;
}
.sidebar-user-filial {
  font-weight: 400;
  font-size: var(--t-xs);
  color: var(--pv-fg-2);
}
.sidebar-logout {
  margin-top: var(--pv-s-2);
  font-size: var(--t-xs);
  color: var(--pv-fg-2);
  text-align: left;
  padding: 4px 0;
}
.sidebar-logout:hover {
  color: var(--pv-danger);
}
/* Item "Alterar minha senha" (fatia 2 do módulo Usuários — DEC-033): mesma
   linguagem visual do "Sair" (.sidebar-logout), mas SEM o hover vermelho —
   não é uma ação destrutiva, então o hover usa o acento da marca. */
.sidebar-menu-item {
  margin-top: var(--pv-s-2);
  font-size: var(--t-xs);
  color: var(--pv-fg-2);
  text-align: left;
  padding: 4px 0;
}
.sidebar-menu-item:hover {
  color: var(--pv-gold);
}
/* Assinatura do produto (DEC-024): o Pvendas assina o sistema, discreto,
   no rodapé da sidebar — o tenant continua assinando o conteúdo no topo. */
.sidebar-assinatura {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: var(--pv-s-2);
  padding: 2px 2px 0;
  font-size: 12px;
  color: var(--pv-fg-mute);
}
.sidebar-assinatura img {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

/* ---- Menu drawer lateral (mobile only, DEC-045 — estilo ChatGPT) ----
   Substitui a antiga bottom-nav + bottom sheet "Mais" (ver histórico em
   docs/decisoes.md). Sempre no DOM (construído junto com o shell, como a
   sidebar) e alternado por classe — fechado usa visibility:hidden (não
   display:none) para permanecer fora da árvore de acessibilidade/do cálculo
   de "visível" do Playwright, mas continuar presente no DOM (testids
   "-mobile" sempre encontráveis via toHaveCount, mesmo com o menu fechado).
   Some ≥768px: desktop só tem a sidebar, sem drawer. */
.menu-drawer-backdrop {
  position: fixed;
  inset: 0;
  background: rgb(23 33 49 / 30%);
  z-index: 550; /* escala documentada no bloco Toast de components.css —
                   mesma camada do antigo sheet-backdrop que este substitui */
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 220ms ease,
    visibility 0s linear 220ms;
}
.menu-drawer-backdrop.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity 220ms ease;
}
@media (min-width: 768px) {
  .menu-drawer-backdrop {
    display: none;
  }
}
.menu-drawer {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: min(344px, calc(100% - 40px));
  background: var(--pv-bg-1);
  border-right: 1px solid var(--pv-line);
  display: flex;
  flex-direction: column;
  padding: var(--pv-s-4) var(--pv-s-4) max(var(--pv-s-5), env(safe-area-inset-bottom, 0px));
  gap: var(--pv-s-2);
  overflow-y: auto;
  box-shadow: var(--pv-shadow-lg);
  /* translateX (não display/left): transição interrompível — abrir e fechar
     rápido não trava a meio caminho (ver .app sem transform/filter ancestral,
     então position:fixed do backdrop funciona normalmente mesmo aninhado). */
  transform: translateX(-100%);
  transition: transform 220ms cubic-bezier(0.32, 0.72, 0, 1);
}
.menu-drawer-backdrop.is-open .menu-drawer {
  transform: translateX(0);
}
.drawer-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
}
.drawer-fechar {
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--pv-r-md);
  border: none;
  background: none;
  color: var(--pv-fg-2);
  cursor: pointer;
}
.drawer-fechar:hover {
  background: var(--pv-bg-2);
  color: var(--pv-fg-0);
}
.drawer-corpo {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--pv-s-2);
}
/* Trava o scroll do body por trás do drawer aberto (spec de acessibilidade).
   Escopado a <768px (achado I3 da revisão adversarial): o drawer nem existe
   ≥768px (.menu-drawer-backdrop vira display:none ali) — sem este escopo, um
   resize/rotação pra desktop com a classe ainda aplicada (JS só remove ela no
   clique de fechar, não num resize) travava a rolagem da tela mesmo sem
   nenhum drawer visível pra fechar. O JS (montarMenuDrawer) também fecha o
   drawer de verdade nesse cruzamento — isto aqui é o cinto, aquilo o
   suspensório. */
@media (max-width: 767px) {
  body.drawer-aberto {
    overflow: hidden;
  }
}

/* ---- Main content area ---- */
.main {
  padding: var(--pv-s-5) var(--pv-s-4) var(--pv-s-6);
  max-width: 100%;
  overflow-x: hidden;
}
/* Sem bottom-nav (DEC-045), o rodapé do conteúdo mobile só precisa respeitar
   a faixa gestual/home-indicator do aparelho. */
@media (max-width: 767px) {
  .main {
    padding-bottom: calc(var(--pv-s-6) + env(safe-area-inset-bottom, 0px));
  }
}
/* Quando a tela tem CTA fixo (mobile), soma a altura dele (--sticky-cta-h) ao
   padding — sem isso o conteúdo mais baixo nunca tinha rolagem suficiente
   pra ficar livre do botão (P0 do pente-fino de UX, jul/2026: "Iniciar
   pedido" sobrepondo os dados comerciais já na dobra em 390×844). Ver
   .sticky-cta abaixo — position:fixed, não sticky. */
@media (max-width: 767px) {
  .main:has(.sticky-cta) {
    padding-bottom: calc(var(--pv-s-6) + var(--sticky-cta-h) + env(safe-area-inset-bottom, 0px));
  }
}
/* Fallback para navegador sem suporte a :has() (ver regra acima): sem isso,
   .main nunca reserva o espaço do CTA fixo nesses navegadores — ~84px de
   conteúdo (--sticky-cta-h) ficam permanentemente cobertos pelo botão, em
   TODA tela com CTA, sempre, não só num scroll específico (achado da revisão
   adversarial, rodada 2, ago/2026). Reserva incondicional em <768px: nas
   telas sem .sticky-cta sobra um respiro extra no fim da página — aceitável
   perto de conteúdo permanentemente escondido, e este é só o fallback pra um
   navegador que hoje não suporta :has(). */
@supports not (selector(:has(*))) {
  @media (max-width: 767px) {
    .main {
      padding-bottom: calc(var(--pv-s-6) + var(--sticky-cta-h) + env(safe-area-inset-bottom, 0px));
    }
  }
}
@media (min-width: 768px) {
  .main {
    padding: var(--pv-s-8) var(--pv-s-8) var(--pv-s-10);
  }
}
/* Ao focar um input (ex.: campo de busca, quantidade da grade) com o teclado
   virtual aberto, o navegador auto-rola o elemento focado até a área visível
   — mas "visível" pra ele é o viewport inteiro, sem descontar o CTA fixo.
   Sem scroll-padding-bottom, o auto-scroll parava exatamente onde o CTA
   cobre o campo (achado da revisão adversarial, rodada 2, ago/2026). Reserva
   a mesma faixa do rodapé fixo pro cálculo do navegador. */
@media (max-width: 767px) {
  html {
    scroll-padding-bottom: calc(var(--sticky-cta-h) + env(safe-area-inset-bottom, 0px));
  }
}
@media (min-width: 1280px) {
  .main {
    padding: var(--pv-s-10) var(--pv-s-12) var(--pv-s-12);
  }
}

.main-wrap {
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--pv-s-5);
}

/* Page header */
.page-header {
  display: flex;
  flex-direction: column;
  gap: var(--pv-s-2);
  margin-bottom: var(--pv-s-3);
}
.page-header h1 {
  font-size: var(--t-2xl);
}
@media (min-width: 768px) {
  .page-header h1 {
    font-size: var(--t-3xl);
  }
}
.page-header .sub {
  color: var(--pv-fg-2);
  font-size: var(--t-sm);
}

/* Grid helpers */
.grid-2 {
  display: grid;
  gap: var(--pv-s-4);
  grid-template-columns: 1fr;
}
.grid-3 {
  display: grid;
  gap: var(--pv-s-4);
  grid-template-columns: 1fr;
}
.grid-4 {
  display: grid;
  gap: var(--pv-s-4);
  grid-template-columns: 1fr 1fr;
}
@media (min-width: 640px) {
  .grid-2 {
    grid-template-columns: 1fr 1fr;
  }
  .grid-3 {
    grid-template-columns: 1fr 1fr 1fr;
  }
  .grid-4 {
    grid-template-columns: repeat(4, 1fr);
  }
}
@media (min-width: 1024px) {
  .grid-3 {
    grid-template-columns: 2fr 1fr;
  }
}

.stack {
  display: flex;
  flex-direction: column;
  gap: var(--pv-s-4);
}
.stack-sm {
  display: flex;
  flex-direction: column;
  gap: var(--pv-s-2);
}
.row {
  display: flex;
  gap: var(--pv-s-3);
  align-items: center;
  flex-wrap: wrap;
}
.row-between {
  display: flex;
  gap: var(--pv-s-3);
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
}

/* CTA fixo (mobile) */
/* Altura real espelhada no token --sticky-cta-h (tokens.css) — o .toast-region
   e o .main:has(.sticky-cta) acima ancoram/reservam espaço a partir dela.
   Mudou padding/altura do botão? Atualize o token lá.
   position:fixed, não sticky: em telas curtas (conteúdo pouco mais alto que
   o viewport, ex.: ficha de cliente) o sticky já nascia "grudado" na posição
   errada — a rolagem residual era pequena demais pra ele se soltar da
   posição natural, sobrepondo o próprio conteúdo mesmo sem o usuário rolar
   (P0 do pente-fino de UX, jul/2026). fixed dá posição de tela previsível;
   left/right substituem a largura que antes vinha do fluxo normal do
   documento. Sem bottom-nav (DEC-045) o CTA agora ancora direto no rodapé do
   viewport, respeitando a faixa gestual/home-indicator do aparelho. */
.sticky-cta {
  position: fixed;
  left: var(--pv-s-4);
  right: var(--pv-s-4);
  bottom: env(safe-area-inset-bottom, 0px);
  background: linear-gradient(to top, var(--pv-bg-0) 60%, rgba(11, 11, 13, 0));
  padding: var(--pv-s-4) 0;
  z-index: 40; /* escala documentada no bloco Toast de components.css */
}
@media (min-width: 768px) {
  .sticky-cta {
    position: static;
    left: auto;
    right: auto;
    background: none;
    padding: 0;
  }
}

/* Catalog grid — densidade 2/3/4 (DEC-063, ajuste de spec 05/08: feedback da
   operação/Isadora pediu cards menores e mais densos). Mobile já nasce em 2
   colunas (não 1) — card ~170-180px em 390px de viewport, foto 4/5 +
   corpo compacto (ver .product-card-body/.product-card-name em
   components.css). min-width:0 no item de grid é OBRIGATÓRIO (mesmo achado
   da DEC-060 no link): sem ele, o track 1fr não encolhe abaixo do conteúdo
   mínimo do card e a grade "quebra" com colunas desiguais maiores que o
   viewport — aplicado em components.css (.product-card-outer, o item de
   grid de verdade desde a correção do item 3/nested-interactive da revisão
   pré-merge da DEC-063 — { min-width: 0 }). */
.catalog-grid {
  display: grid;
  gap: var(--pv-s-3);
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 768px) {
  .catalog-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--pv-s-4);
  }
}
@media (min-width: 1120px) {
  .catalog-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* Login layout */
.login-page {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 1fr;
}
@media (min-width: 900px) {
  .login-page {
    grid-template-columns: 1fr 1fr;
  }
}
.login-hero {
  display: none;
  background:
    radial-gradient(circle at 30% 20%, rgba(46, 156, 119, 0.18), transparent 50%),
    linear-gradient(180deg, #1a1d22 0%, #101216 100%);
  position: relative;
  overflow: hidden;
  padding: var(--pv-s-10);
  flex-direction: column;
  justify-content: space-between;
  color: var(--pv-fg-0);
}
.login-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'><path d='M0 20 L20 0 L40 20 L20 40 Z' stroke='%23C9A24B' stroke-opacity='0.04' fill='none'/></svg>");
  opacity: 0.8;
}
@media (min-width: 900px) {
  .login-hero {
    display: flex;
  }
}
.login-form {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--pv-s-8) var(--pv-s-5);
  max-width: 480px;
  width: 100%;
  margin: 0 auto;
}
/* Assinatura do produto no login (DEC-024): símbolo + nome + tagline —
   visível também no mobile, abaixo do formulário do tenant. */
.login-assinatura {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: var(--pv-s-10);
}
.login-assinatura img {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}
.login-assinatura-nome {
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--pv-fg-0);
}
.login-assinatura-tag {
  font-size: 13px;
  color: var(--pv-fg-2);
}
.login-hero h2 {
  font-size: var(--t-3xl);
  line-height: 1.15;
  font-weight: 500;
  color: var(--pv-fg-0);
  max-width: 380px;
  position: relative;
}
.login-hero .hero-meta {
  font-size: var(--t-sm);
  color: var(--pv-fg-2);
  position: relative;
}

/* Product detail layout */
.product-detail {
  display: grid;
  gap: var(--pv-s-5);
  grid-template-columns: 1fr;
}
/* Eyebrow (categoria · REF · SKU): quebra em ≥2 linhas em telas estreitas em
   vez de estourar a largura — a REF (pedido dos representantes) some do
   card mas nunca precisa disso na ficha; some com o .product-detail > *
   {min-width:0} abaixo, que garante que o pai encolhe até o track do grid. */
.product-eyebrow {
  overflow-wrap: break-word;
}
/* Sem isto, o item de grid ("right", a coluna com a grade de variantes)
   herda min-width:auto e cresce até o min-content da grade cor×tamanho
   (soma dos minmax das colunas) em vez de encolher pro track do grid —
   estourando o .main-wrap inteiro (clipado sem aviso por .main
   {overflow-x:hidden}), e o .variant-grid-wrap nunca chega a ficar mais
   estreito que seu próprio conteúdo, então nunca rola internamente.
   Confirmado medindo em Chromium headless (rectWidth de "right" > track do
   grid antes desta regra). Correção padrão do "min-width:auto" do CSS Grid. */
.product-detail > * {
  min-width: 0;
}
/* Breakpoint empurrado de 900px para 1280px (P0-5 da auditoria de layout):
   entre 900–1500px (a faixa mais comum de notebook) a coluna direita em
   1.2fr/1fr ficava estreita demais para a grade cor×tamanho (140px da coluna
   de cor + 5×64px mínimo de tamanho = 460px), cortando a última coluna
   (XGG) pela metade. Mantendo 1 coluna — e a grade cor×tamanho inteira —
   até 1280px, a grade sempre tem a largura completa do .product-detail para
   se acomodar antes de precisar do scroll horizontal (ver
   .variant-grid-outer.tem-mais-a-direita). */
/* Rodada 1 de UX: a galeria era 1.2fr — o hero 4/5 passava de 1000px de
   altura e empurrava a grade e o CTA "Adicionar ao pedido" pra fora da
   dobra em 1440×900. Trava a coluna da imagem em 460px (hero ~575px de
   altura) e devolve o restante à coluna de trabalho (grade + totais + CTA),
   que é onde o vendedor decide. */
@media (min-width: 1280px) {
  .product-detail {
    grid-template-columns: minmax(0, 460px) 1fr;
    align-items: start;
  }
}
/* F2 (DEC-024): hero 4:5; sem foto, a silhueta da categoria sobre areia
   (productArt.js) — sem gradiente escuro nem marca d'água de tenant. */
.product-hero-img {
  aspect-ratio: 4 / 5;
  border-radius: var(--pv-r-lg);
  border: 1px solid var(--pv-line);
  overflow: hidden;
  background: var(--pv-bg-3);
  display: grid;
  place-items: center;
  position: relative;
}
/* Hero com foto real é clicável (abre o lightbox — F2/PV-12); a arte
   vetorial de fallback nunca ganha esta classe (nada pra ampliar nela). */
.product-hero-clicavel {
  cursor: pointer;
}
/* No celular o hero 4/5 tomava a tela inteira antes de nome/preço/grade.
   1/1 mantém a foto protagonista e traz a informação de venda pra 1ª dobra. */
@media (max-width: 767px) {
  .product-hero-img {
    aspect-ratio: 1 / 1;
  }
}
/* Miniaturas da galeria (F2): fotos reais; a ativa ganha borda esmeralda
   (indicador de seleção = ação). */
.product-thumbs {
  display: flex;
  gap: var(--pv-s-2);
  margin-top: var(--pv-s-3);
  flex-wrap: wrap;
}
.product-thumb {
  width: 72px;
  height: 72px;
  padding: 0;
  border-radius: var(--pv-r-sm);
  border: 1px solid var(--pv-line);
  overflow: hidden;
  background: var(--pv-bg-2);
  cursor: pointer;
}
.product-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.product-thumb.is-active {
  border: 2px solid var(--pv-gold);
}

/* Cart layout */
.cart-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--pv-s-5);
}
@media (min-width: 1024px) {
  .cart-layout {
    grid-template-columns: 1.5fr 1fr;
    align-items: start;
  }
}
.cart-summary {
  position: sticky;
  top: calc(var(--topbar-h) + 16px);
}
.cart-item {
  display: grid;
  grid-template-columns: 64px 1fr auto;
  gap: var(--pv-s-3);
  padding: var(--pv-s-4);
  border: 1px solid var(--pv-line);
  border-radius: var(--pv-r-md);
  background: var(--pv-bg-1);
  align-items: center;
}
.cart-item-img {
  width: 64px;
  height: 80px;
  border-radius: var(--pv-r-sm);
  background: linear-gradient(135deg, #2a1f15, #1b1410);
  flex-shrink: 0;
  /* Mesmo fallback foto/silhueta do catálogo (aplicarFotoOuArteProduto) —
     precisa de position:relative pra hospedar a <img> absoluta quando existe
     foto real; overflow:hidden respeita o raio arredondado do card. */
  position: relative;
  overflow: hidden;
}
/* Rodada 1 de UX: o "Remover" ficava numa fileira própria abaixo de cada
   variante — dobrava a altura de cada linha e deixava ambíguo qual botão
   removia qual item. Agora a linha é um grid nomeado com tudo alinhado:
   cor+tamanho · quantidade · subtotal · remover. */
.cart-variant-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 64px 96px 36px;
  grid-template-areas: "label qty price remove";
  gap: var(--pv-s-3);
  align-items: center;
  padding: var(--pv-s-2) 0;
  border-top: 1px solid var(--pv-bg-3);
  font-size: var(--t-sm);
}
.cart-variant-row:first-child {
  border-top: 0;
}
/* Em telas estreitas a linha única estourava e quebrava torto; aqui a
   quebra é desenhada: variante em cima, quantidade × subtotal embaixo. */
@media (max-width: 560px) {
  .cart-variant-row {
    grid-template-columns: 72px minmax(0, 1fr) 36px;
    grid-template-areas:
      "label label remove"
      "qty price price";
    row-gap: var(--pv-s-2);
  }
}
.cart-variant-label {
  grid-area: label;
  display: flex;
  align-items: center;
  gap: var(--pv-s-2);
  min-width: 0;
}
.cart-variant-label > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cart-variant-price {
  grid-area: price;
  text-align: right;
}
.cart-variant-remove {
  grid-area: remove;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--pv-r-sm);
  color: var(--pv-fg-2);
  cursor: pointer;
  transition:
    color 150ms,
    background-color 150ms;
}
.cart-variant-remove:hover {
  color: var(--pv-danger);
  background: rgba(176, 70, 60, 0.08);
}
/* font-size ≥16px sempre (mesmo piso anti-zoom-iOS do .vg-qty-input da grade
   do produto — consistência entre as duas grades do fluxo, pente-fino de UX
   jul/2026). Altura sobe pra 44px no mobile abaixo; no desktop o mouse não
   tem esse piso e a linha compacta (36px) segue o padrão do resto do carrinho. */
.cart-variant-qty {
  grid-area: qty;
  width: 64px;
  height: 44px;
  background: var(--pv-bg-2);
  border: 1px solid var(--pv-bg-3);
  border-radius: var(--pv-r-sm);
  text-align: center;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-lg);
  color: var(--pv-fg-0);
}
@media (max-width: 767px) {
  .cart-variant-qty {
    height: 44px;
  }
}

/* Navegação C/D: grupos inline; filhos só texto; conta compartilhada. */
.shell-navigation {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.nav-icon {
  flex: 0 0 20px;
  width: 20px;
  height: 20px;
}
.nav-group {
  margin: 2px 0;
}
.nav-group-title {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding: 10px 12px;
  border-radius: var(--pv-r-md);
  cursor: pointer;
  list-style: none;
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--pv-fg-0);
}
.nav-group-title::-webkit-details-marker {
  display: none;
}
.nav-group-title > .icon {
  margin-left: auto;
  flex-shrink: 0;
  color: var(--pv-fg-2);
}
.nav-group:not([open]) > .nav-group-title > .icon {
  transform: rotate(-90deg);
}
.nav-group-title:hover {
  background: var(--pv-bg-2);
}
.nav-group-items .sidebar-link {
  padding-left: 26px;
  font-weight: 400;
}
.nav-group-items .sidebar-link-label {
  white-space: normal;
  overflow-wrap: anywhere;
}
.nav-group-items .sidebar-link.is-active {
  font-weight: 600;
}
.shell-sale-context {
  margin-bottom: 12px;
}
.shell-sale-context .sidebar-cliente-atual {
  gap: 0;
  background: var(--pv-bg-2);
  border-radius: var(--pv-r-md);
}
.shell-sale-context .sidebar-cliente-atual .sidebar-link {
  background: none;
}
.shell-account {
  margin-top: auto;
  padding-top: 24px;
}
.nav-profile {
  border-top: 1px solid var(--pv-line);
  padding-top: 14px;
}
.nav-profile[open] {
  background: var(--pv-bg-2);
  border-radius: var(--pv-r-md);
}
.profile-identity {
  display: flex;
  flex: 1;
  min-width: 0;
  flex-direction: column;
  gap: 2px;
}
.profile-label {
  color: var(--pv-fg-2);
  font-size: 11px;
  font-weight: 400;
}
.sidebar-user-name {
  overflow-wrap: anywhere;
}
.nav-profile .sidebar-menu-item,
.nav-profile .sidebar-logout {
  display: block;
  width: 100%;
  min-height: 44px;
  padding: 10px 12px;
  margin: 0;
  border: 0;
  border-radius: var(--pv-r-sm);
  background: none;
  font-size: var(--t-sm);
  text-align: left;
  cursor: pointer;
}
.nav-profile button:hover {
  background: var(--pv-selected);
}
.sidebar-assinatura {
  font-size: 11px;
  color: var(--pv-fg-2);
  padding-top: 12px;
}
.sidebar-assinatura img {
  display: none;
}
.nav-group-title:focus-visible,
.sidebar-link:focus-visible,
.nav-profile button:focus-visible,
.topbar-hamburguer:focus-visible,
.topbar-carrinho-mobile:focus-visible,
.drawer-fechar:focus-visible,
.btn-remover-cliente:focus-visible {
  outline: 2px solid var(--pv-gold);
  outline-offset: 2px;
}
@media (max-width: 767px) {
  .menu-drawer {
    background: var(--pv-bg-0);
  }
  .drawer-header .sidebar-brand {
    margin: 0;
  }
  .drawer-corpo {
    gap: 0;
  }
  .shell-navigation {
    gap: 0;
  }
  .shell-navigation > .sidebar-link,
  .nav-group {
    background: var(--pv-bg-1);
  }
  .shell-navigation > .sidebar-link:not(.nav-secondary) {
    font-weight: 600;
  }
  .shell-navigation > .sidebar-link.is-active {
    background: var(--pv-selected);
  }
  .shell-navigation > .sidebar-link:first-of-type {
    border-radius: 16px 16px 0 0;
  }
  .shell-navigation > .sidebar-link:nth-of-type(2) {
    border-radius: 0;
  }
  .shell-navigation > .nav-secondary {
    background: none;
    margin: 12px 0;
  }
  .nav-group {
    border-radius: 0 0 16px 16px;
    margin: 0;
  }
  .nav-group-items .sidebar-link {
    padding-left: 32px;
    color: var(--pv-gold);
  }
  .nav-group-items .sidebar-link:last-child {
    border-radius: 0 0 16px 16px;
  }
  .shell-account {
    padding-top: 20px;
  }
  .nav-profile {
    background: var(--pv-bg-1);
    border: 0;
    border-radius: 16px;
    padding: 4px;
  }
  .nav-profile[open] {
    background: var(--pv-bg-1);
  }
  .nav-profile .sidebar-menu-item,
  .nav-profile .sidebar-logout {
    color: var(--pv-gold);
    text-align: center;
    font-size: 15px;
  }
  .nav-group-title,
  .sidebar-link {
    font-size: 15px;
  }
  .shell-sale-context .sidebar-cliente-atual,
  .shell-sale-context .sidebar-link.is-placeholder {
    background: var(--pv-bg-1);
    min-height: 56px;
  }
  .shell-sale-context > .sidebar-link:last-child {
    margin-top: 8px;
    background: var(--pv-bg-1);
    border-radius: 999px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .menu-drawer,
  .menu-drawer-backdrop {
    transition: none;
  }
}
