/* Estrutura única de todas as rotas; carregada depois dos estilos da vista. */
body.bp-app { display: flex; flex-direction: column; min-height: 100dvh; padding: 0; }
.bp-app [hidden] { display: none !important; }
#bp-view { flex: 1; min-width: 0; width: 100%; min-height: 0; }
#bp-view > .bp-publico, #bp-view > .bp-shell { min-height: 100%; }
/* O miolo recebe o foco a cada troca de tela (nucleo.js) para o leitor de
   tela anunciar a região nova. É um destino de foco, não um controle: anel
   em volta da página inteira não diz nada a ninguém. */
#bp-view:focus { outline: none; }

/* ── Troca de tela por dentro do index ─────────────────────────────────────
   Um fio na cor da marca no alto enquanto a próxima tela carrega. Só aparece
   depois de 150ms: a troca de quem já visitou a tela é instantânea, e um fio
   piscando a cada clique rápido seria ruído, não resposta. */
.bp-navegando body::before {
  content: ""; position: fixed; inset: 0 0 auto; z-index: 300; height: 3px;
  background: var(--primary); transform-origin: left; pointer-events: none;
  animation: bp-fio 1.2s .15s ease-out both;
}
@keyframes bp-fio { from { transform: scaleX(0); } to { transform: scaleX(.85); } }
/* Menos movimento: o fio não corre, só aparece — depois da mesma espera. */
@keyframes bp-fio-seco { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .bp-navegando body::before { transform: scaleX(.85); animation: bp-fio-seco 1ms .15s both; }
}
/* Altura das abas do rodapé. Zero quando elas não existem (tela larga), para
   quem se empilha em cima delas — como a barra de compra da página do evento
   — poder usar `bottom: var(--altura-abas)` sem saber se elas estão lá. */
:root { --altura-topo: 70px; --altura-abas: 0px; }
.bp-app-topo { position: sticky; top: 0; z-index: 90; display: flex; align-items: center; gap: 12px; height: 70px; flex-shrink: 0; padding: 0 24px; border-bottom: 1px solid var(--border); background: var(--bg-fundo); }
.bp-app-topo__inicio { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* Em tela larga o topo alinha com a COLUNA do conteúdo, e não com a borda da
   janela. Em 1920px o logo e o ☰ ficavam a 24px dos cantos enquanto a página
   vivia numa coluna no meio — "está para a esquerda", nas palavras do dono
   em 30/09/2026. A coluna é a da home: 1240px + 24px (.lista e
   .capa__dentro em inicio.html). Abaixo dela, `max` devolve os 24px.
   O PAINEL USA A MESMA, e não a dele (82rem): o dono pediu o ☰ "no mesmo
   lugar que o menu de fora", e com colunas diferentes ele pulava ~13px ao
   passar do site para o painel. */
@media (min-width: 861px) {
  .bp-app-topo { padding-inline: max(24px, calc((100% - 1240px) / 2 + 24px)); }
}
/* Nenhuma página tem rodapé — pedido do dono, 30/09/2026: primeiro na home
   ("somente a barra fixa"), no mesmo dia em todas ("vamos usar só o menu na
   parte de baixo"; o contato vai para o menu lateral). No celular quem fecha
   a página é a barra de abas, e o miolo reserva a altura dela — pela
   PRESENÇA da barra, e não por `.com-barra`, que a página do evento também
   liga e desliga para a barra de compra dela. */
@media (max-width: 640px) {
  body:has(#bpAbas) #bp-view { padding-bottom: calc(var(--altura-abas) + 12px); }
}
/* No painel o cabeçalho é marca + ☰, e mais nada — pedido do dono no mesmo
   dia: "Minha conta" e "+ Criar evento" já estão dentro do menu. Sem o
   botão da conta, quem empurra o ☰ para a direita é o próprio ☰. */
/* `min-width: 0` e reticências são a REDE: sem eles o nome da marca não
   encolhe nem corta — ele simplesmente transborda, e o próximo item do
   cabeçalho é pintado por cima. Foi assim que o botão verde de check-in
   apareceu escrito sobre "BoomPass". Com isto, o pior caso vira um nome
   cortado com reticências; sobreposição deixa de ser possível. */
.bp-app-marca { display: flex; align-items: center; gap: 6px; white-space: nowrap; min-width: 0; }
.bp-app-marca img { display: block; width: auto; height: 38px; object-fit: contain; flex-shrink: 0; }
.bp-app-marca span { font-size: 18px; font-weight: 700; letter-spacing: -.02em; overflow: hidden; text-overflow: ellipsis; }
/* O botão "Meus Ingressos" do topo saiu em 01/10/2026 — pedido do dono:
   "remova definitivo o botão de meus ingressos da parte de cima da página;
   já tem no menu de baixo". Até 30/09 ele sumia só para quem tinha sessão, e
   sem sessão aparecia escrito "Meus Ingressos" levando ao login, que é o que
   o dono via no celular e tomava pelo botão que pediu para tirar. A porta da
   área do cliente agora é o menu inferior (no celular) e o ☰ (em toda
   largura); sem sessão, as duas abrem o login num modal (entrar-modal.js). */
.bp-app-voltar { display: grid; place-items: center; width: 32px; height: 44px; flex-shrink: 0; }
.bp-app-aviso { padding: 3rem 1rem; text-align: center; }
.bp-pular { position: fixed; top: -100px; left: 12px; z-index: 200; background: var(--card); padding: 8px; }
.bp-pular:focus { top: 8px; }
.bp-app .bp-sidebar { top: 70px; height: calc(100dvh - 70px); }
.bp-app .bp-sidebar__logo { object-fit: contain; }
#menuPainel, #acoesPainel { display: none; }
body[data-layout="entrada"] #bp-view { display: grid; place-items: start center; padding: 20px 16px; min-height: 0; }
body[data-layout="entrada"] .bp-app-topo__inicio { flex: 1; }
body[data-layout="entrada"] .bp-app-marca { position: absolute; left: 50%; transform: translateX(-50%); }
@media (max-width: 860px) {
  :root { --altura-topo: 60px; }
  .bp-app-topo { padding-inline: 12px; gap: 6px; height: 60px; }
  .bp-app .bp-main { padding-top: 0; }
  .bp-app .bp-sidebar { top: 0; height: 100dvh; }
  /* O topo do painel é marca + ☰ (e, na tela do evento, o Check-in) desde
     30/09/2026: "Minha conta" e "+ Criar evento" foram para o menu. Com isso
     caem as regras que espremiam o topo — escondiam o NOME da marca abaixo
     de 480px e o rótulo da ação abaixo de 432px, porque antes ali cabiam
     quatro coisas. Hoje tudo cabe com nome até ~320px. */
  /* A ação do topo (hoje, o Check-in do evento) fica CENTRALIZADA entre o fim
     da marca e o "Olá" — pedido do dono, 10/10/2026. Até então ela encostava
     no "Olá" (`margin-left: auto`) e sobrava um vão só do lado da marca.
     Agora a caixa dela ocupa todo o espaço livre entre os dois (`flex: 1`) e o
     botão fica no meio dela; o vão do cabeçalho (6px) é o mesmo dos dois
     lados, então o meio da caixa é o meio do espaço. O botão não encolhe: com
     `min-width` automático, a caixa nunca fica menor que ele. */
  /* Site e painel são um documento só desde 01/10/2026: a regra vale para
     qualquer tela que ponha uma ação no topo. */
  #acoesPainel:not(:empty) { display: flex; flex: 1; justify-content: center; }
  #acoesPainel:not(:empty) ~ .bp-menu-topo { margin-left: 0; }
  #acoesPainel .bp-btn { min-height: 34px; height: 34px; padding-inline: 10px; font-size: 12px; }
  @media (max-width: 21rem) {
    body[data-rota^="/painel"] .bp-app-marca span { display: none; }
  }
}
@media print { .bp-app-topo, .bp-pular { display: none; } }

/* ── A tela de carregamento ────────────────────────────────────────────────
   Pedido do dono em 30/09/2026: "criar uma tela de carregamento com a logo em
   vetor se montando, algo que rode na frente da página enquanto não carrega
   tudo, para ficar premium".

   A marca se monta em três tempos: o contorno do ingresso se DESENHA
   (stroke-dashoffset indo de 1536 — o comprimento real do traço, medido — a
   zero), o verde preenche por dentro, e o B sobe. Depois ela respira devagar
   até a página estar pronta, para não parecer travada numa espera longa.

   Tudo em CSS porque a CSP proíbe script inline; o SVG está no markup do
   index.html justamente para que cada parte possa ser animada em separado.

   A SAÍDA DE EMERGÊNCIA é a animação `bp-capa-desiste`: se o JavaScript não
   chegar (rede caiu no meio do módulo), a capa se apaga sozinha aos 8s. Uma
   tela cheia presa para sempre é pior do que uma página com defeito — ao
   menos dá para ler o erro e recarregar. */
.bp-capa {
  position: fixed; inset: 0; z-index: 9999;
  display: grid; place-items: center;
  background: var(--bg-fundo);
  transition: opacity .32s ease, visibility .32s;
  animation: bp-capa-desiste 0s linear 8s forwards;
}
.bp-capa--fora { opacity: 0; visibility: hidden; pointer-events: none; }

/* DA SEGUNDA PÁGINA EM DIANTE a capa continua cobrindo — é o que impede a
   tela de se remontar à vista — mas sem cerimônia: some a marca, fica o
   fundo liso, e a passagem é rápida. Ver capa-rapida.js: "se não fica
   cansativo toda hora a animação" foi o retorno do sócio, e ele estava
   certo. Abertura é para a chegada, não para cada clique no menu. */
:root[data-capa-vista] .bp-capa { display: none; }
@keyframes bp-capa-desiste { to { opacity: 0; visibility: hidden; pointer-events: none; } }

.bp-capa__marca { width: 96px; height: auto; animation: bp-capa-respira 2.4s ease-in-out 1.25s infinite; }
/* O traço que se desenha, e some assim que o preenchimento entra: deixá-lo
   por baixo engrossaria a silhueta em 14 unidades de todos os lados. */
.bp-capa__risco {
  fill: none; stroke: #02F780; stroke-width: 12; stroke-linejoin: round;
  stroke-dasharray: 1536; stroke-dashoffset: 1536;
  animation: bp-capa-risca .9s cubic-bezier(.65, 0, .35, 1) forwards,
             bp-capa-apaga .2s ease .92s forwards;
}
.bp-capa__ticket { fill: #02F780; opacity: 0; animation: bp-capa-entra .3s ease .85s forwards; }
/* O B é quase preto SOBRE o verde, não sobre o fundo da página: a cor vale
   nos dois temas, e é por isso que não sai de variável. */
.bp-capa__b {
  fill: #100F14; opacity: 0; transform: translateY(14px);
  animation: bp-capa-sobe .38s cubic-bezier(.2, .8, .2, 1) 1.05s forwards;
}
@keyframes bp-capa-risca  { to { stroke-dashoffset: 0; } }
@keyframes bp-capa-apaga  { to { opacity: 0; } }
@keyframes bp-capa-entra  { to { opacity: 1; } }
@keyframes bp-capa-sobe   { to { opacity: 1; transform: translateY(0); } }
@keyframes bp-capa-respira { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } }

/* Quem pediu menos movimento recebe a marca pronta, sem desenho e sem
   respiração — a capa continua cobrindo, que é a função dela. */
@media (prefers-reduced-motion: reduce) {
  .bp-capa__marca { animation: none; }
  .bp-capa__risco { display: none; }
  .bp-capa__ticket, .bp-capa__b { opacity: 1; transform: none; animation: none; }
}

/* ── O relógio da reserva, no cabeçalho ────────────────────────────────────
   Pedido do dono em 30/09/2026: "pode colocar o timer lá em cima pra não
   ocupar espaço de tela". Ele era um bloco largo no alto do checkout, e num
   celular isso é uma dobra inteira gasta antes de o formulário começar.

   Subir resolve de quebra um defeito que o bloco tinha: o cabeçalho é
   `sticky`, então a contagem PARA DE SUMIR ao rolar. Antes, quem estava
   preenchendo o nome dos titulares já não via quanto tempo faltava — e é
   justamente ali que o prazo acaba. */
.bp-relogio-topo:empty { display: none; }
.bp-relogio-topo {
  display: flex; align-items: center; gap: 6px; flex-shrink: 0;
  padding: 5px 10px; border-radius: 999px;
  background: color-mix(in srgb, var(--warning) 16%, var(--card));
  border: 1px solid color-mix(in srgb, var(--warning) 40%, transparent);
  font-size: 12px; line-height: 1;
}
.bp-relogio-topo svg { width: 14px; height: 14px; flex-shrink: 0; color: var(--warning); }
.bp-relogio-topo b { font-variant-numeric: tabular-nums; font-size: 13px; font-weight: 700; color: var(--warning); }
.bp-relogio-topo.urgente { background: color-mix(in srgb, var(--destructive) 16%, var(--card)); border-color: var(--destructive); }
.bp-relogio-topo.urgente svg, .bp-relogio-topo.urgente b { color: var(--destructive); }
/* A palavra só cabe em tela larga; no celular ficam o ícone e os números. O
   que a coisa é continua dito no `aria-label`, para quem não vê a tela. */
.bp-relogio-topo span { display: none; color: var(--muted-fg); }
@media (min-width: 30rem) { .bp-relogio-topo span { display: inline; } }

/* ── Barra de abas do rodapé ───────────────────────────────────────────────
   Só no celular: em tela grande a navegação já é o cabeçalho, e uma barra
   fixa no pé de um monitor rouba altura sem dar nada em troca. O ponto de
   corte é o mesmo 640px que a regra de `com-barra` acima já usava. */
.bp-barra-abas { display: none; }
@media (max-width: 640px) {
  :root { --altura-abas: calc(60px + env(safe-area-inset-bottom)); }
  .bp-barra-abas {
    position: fixed; inset: auto 0 0 0; z-index: 95;
    display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
    padding: 6px 4px calc(6px + env(safe-area-inset-bottom));
    background: var(--card); border-top: 1px solid var(--border);
    /* A sombra sobe: separa a barra do conteúdo que rola por baixo dela. */
    box-shadow: 0 -6px 18px -12px rgb(0 0 0 / .35);
  }
  .bp-barra-abas__item {
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    /* 48px é o alvo de toque mínimo; o rótulo cabe dentro disso. */
    min-height: 48px; padding: 4px 2px;
    color: var(--muted-fg); text-decoration: none;
    font-size: 11px; line-height: 1.15; text-align: center;
    border-radius: 10px;
    transition: color .15s;
  }
  .bp-barra-abas__item svg { width: 23px; height: 23px; flex-shrink: 0; }
  .bp-barra-abas__item[aria-current="page"] { color: var(--primary-texto); font-weight: 600; }
  .bp-barra-abas__item:active { background: var(--muted); }
  /* A aba que pede conta NÃO muda de cor sem sessão — pedido do dono,
     01/10/2026: as quatro com a mesma cor quando não selecionadas, "estando
     logado ou não". Apagada (era opacity .55), ela parecia quebrada; o toque
     abre o login num modal (ver abas.js), e é isso que avisa. */
  .bp-barra-abas__rotulo { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Onde existe o menu inferior, o ☰ não repete o que ele já tem à vista
     (hoje, "Eventos" — pedido do dono, 01/10/2026; ver menu-topo.js). */
  body:has(#bpAbas) .bp-gaveta__item--tem-aba { display: none; }

}

/* Só para leitor de tela. */
.bp-sr {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ── O topo flutuando sobre a capa, só na home ─────────────────────────────
   No mockup a marca e o botão de conta ficam SOBRE a foto, sem barra atrás.
   A capa sobe por baixo do topo com margem negativa e devolve o espaço em
   padding, para o título continuar na mesma altura de antes.

   Ao rolar, a barra volta a ser sólida: transparente o tempo todo, o logo
   ficaria por cima dos cartões brancos e sumiria. Quem liga e desliga é a
   classe `rolou`, posta por cabecalho-vitrine.js. */
body[data-rota="/"] .bp-app-topo {
  background: transparent; border-bottom-color: transparent; color: #fff;
  transition: background .2s, border-color .2s, color .2s;
}
body[data-rota="/"] .bp-app-marca span { color: #fff; }
body[data-rota="/"] .capa {
  margin-top: calc(-1 * var(--altura-topo));
  padding-top: calc(var(--altura-topo) + 30px);
}
body[data-rota="/"].rolou .bp-app-topo {
  background: var(--bg-fundo); border-bottom-color: var(--border); color: var(--fg);
}
body[data-rota="/"].rolou .bp-app-marca span { color: var(--fg-forte); }

@media (max-width: 40rem) {
  body[data-rota="/"] .capa { padding-top: calc(var(--altura-topo) + 22px); }
}
@media (prefers-reduced-motion: reduce) {
  body[data-rota="/"] .bp-app-topo { transition: none; }
}

/* ── A página rola só na vertical ──────────────────────────────────────────
   Pedido do dono, 30/09/2026: "a página não pode arrastar para as laterais,
   somente na vertical".

   A causa de hoje já foi corrigida na raiz (era `min-width: auto` no bloco de
   filtros), e esta regra é a trava para a próxima: qualquer elemento que
   passe da borda direita fica escondido em vez de esticar o documento.

   `clip`, e NÃO `hidden`: `hidden` transformaria o body num contêiner de
   rolagem, e o cabeçalho `position: sticky` deixaria de grudar no topo —
   trocaríamos um defeito por outro. `clip` recorta sem criar rolagem.

   Isto NÃO recorta as faixas que rolam de propósito: carrossel e chips têm
   `overflow-x: auto` próprio e continuam deslizando dentro da largura deles. */
html { overflow-x: clip; }
body.bp-app { overflow-x: clip; max-width: 100%; }

/* ── O botão ☰ e a gaveta do topo ──────────────────────────────────────────
   Na ponta direita do cabeçalho. Quem o empurrava para lá era o botão de
   conta, que saiu (01/10/2026): agora o empurrão é do próprio ☰. Sem sessão
   ele abre o login num modal em vez da gaveta (menu-topo.js). */
.bp-menu-topo { display: flex; align-items: center; flex-shrink: 0; margin-left: auto; }
/* "Olá, Pedro" ao lado do ☰ quando há sessão (menu-topo.js). Herda a cor do
   cabeçalho — branco sobre a foto da home, escuro no resto — e corta com
   reticências antes de empurrar a marca. */
.bp-menu-topo__ola {
  max-width: 9.5rem; margin-right: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: .8125rem; color: inherit; opacity: .9;
}
.bp-menu-topo__ola b { font-weight: 700; }
.bp-menu-topo__ola[hidden] { display: none; }
.bp-menu-topo__botao {
  display: grid; place-items: center; width: 40px; height: 40px;
  border: 0; border-radius: 12px; background: transparent;
  color: inherit; cursor: pointer;
}
.bp-menu-topo__botao svg { width: 24px; height: 24px; }
.bp-menu-topo__botao:hover { background: color-mix(in srgb, currentColor 12%, transparent); }
/* Na home o topo flutua sobre a foto: o ☰ é branco como a marca. */
body[data-rota="/"]:not(.rolou) .bp-menu-topo__botao { color: #fff; }

/* Véu e gaveta saem do ar por `visibility`, e não pelo atributo `hidden`.
   Os dois tiram o elemento do Tab e do leitor de tela; a diferença é que
   `display: none` não anima, e sem animação o arrasto (arrastar-gaveta.js)
   não teria para onde voltar quando a pessoa solta no meio do caminho. */
.bp-gaveta-veu {
  position: fixed; inset: 0; z-index: 110;
  background: rgb(8 12 10 / .5); backdrop-filter: blur(2px);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .26s ease, visibility .26s;
  /* Atrás do véu não há nada para rolar — o body está travado —, então todo
     gesto que nasce nele é para empurrar a gaveta de volta. */
  touch-action: none;
}
.bp-gaveta-veu--visivel { opacity: 1; visibility: visible; pointer-events: auto; }
.bp-gaveta {
  position: fixed; z-index: 111; top: 0; right: 0; bottom: 0;
  /* 86vw não deixava faixa de página à direita, e gaveta que cobre tudo lê
     como troca de tela: a pessoa procura um "voltar" em vez de tocar fora.
     Aqui cabem duas linhas por item (nome e descrição), por isso ela é mais
     larga que a lateral do painel — mas não a tela inteira. */
  width: min(14.5rem, 68vw);
  display: flex; flex-direction: column;
  background: var(--card); border-left: 1px solid var(--border);
  box-shadow: -18px 0 40px -24px rgb(0 0 0 / .5);
  overflow-y: auto; overscroll-behavior: contain;
  padding-bottom: env(safe-area-inset-bottom);
  transform: translateX(100%); visibility: hidden;
  transition: transform .26s ease, visibility .26s;
  /* Entrega o arrasto horizontal ao JS e deixa o vertical rolando a lista. */
  touch-action: pan-y;
}
.bp-gaveta--aberta { transform: translateX(0); visibility: visible; }
/* Enquanto a gaveta está aberta o fundo não rola: arrastar sobre o véu
   moveria a página atrás e a pessoa perderia o lugar onde estava. */
body.bp-gaveta-aberta { overflow: hidden; }
/* O fundo não rola atrás de um diálogo — o mesmo motivo, no celular (dono,
   10/10/2026: o diálogo de novo ingresso abria e "a página está sendo movida
   para os lados, para cima e para baixo"). O dedo que arrasta fora da caixa
   do diálogo rolava a página de trás. `:modal` pega só o diálogo aberto como
   modal (showModal), de qualquer tela. Só com o dedo: no computador, tirar a
   barra de rolagem faria a página de trás pular para o lado ao abrir. */
@media (hover: none), (pointer: coarse) {
  html:has(dialog:modal), html:has(dialog:modal) body { overflow: hidden; overscroll-behavior: none; }
}

.bp-gaveta__topo {
  display: flex; align-items: center; justify-content: space-between;
  padding: 13px 13px 10px; border-bottom: 1px solid var(--border);
}
.bp-gaveta__topo strong { font-size: .875rem; letter-spacing: -.01em; }
.bp-gaveta__fechar {
  display: grid; place-items: center; width: 32px; height: 32px;
  border: 0; border-radius: 10px; background: transparent; color: var(--muted-fg); cursor: pointer;
}
.bp-gaveta__fechar svg { width: 18px; height: 18px; }
@media (hover: hover) and (pointer: fine) { .bp-gaveta__fechar:hover { background: var(--muted); color: var(--fg); } }

/* `flex: 1` faz a lista ocupar a altura que sobra entre o topo e o rodapé —
   é o espaço onde o item de fundo (abaixo) consegue descer. */
.bp-gaveta__lista { display: flex; flex-direction: column; flex: 1 0 auto; padding: 6px; }
/* Os grupos "Admin BoomPass" e "Organizar evento" moram no FUNDO da lista,
   logo acima de "Sair da conta" (pedido do dono, 01/10/2026: são do
   organizador e da gestão, não de quem compra). Tocar num deles traz o bloco
   para cima, logo abaixo de "Favoritos", com uma linha entre os dois — a
   subida é animada em menu-topo.js (`alternarGrupo`). */
.bp-gaveta__fundo { margin-top: auto; display: flex; flex-direction: column; }
/* O grupo aberto mora aqui, logo abaixo de "Favoritos", com a linha antes. */
.bp-gaveta__subiu { display: flex; flex-direction: column; }
.bp-gaveta__subiu:not(:empty)::before {
  content: ""; height: 1px; margin: 6px 4px; background: var(--border);
  animation: bp-linha-surge .3s ease both;
}
/* E uma linha acima do ÚLTIMO grupo do pé da lista (dono, 01/10/2026): com
   "Organizar evento" aberto lá em cima, "Admin BoomPass" fica sozinho no pé
   e a linha o separa dos itens do grupo aberto; com os dois fechados, ela
   fica entre "Admin BoomPass" e "Organizar evento". */
.bp-gaveta__fundo > .bp-gaveta__bloco:last-child::before {
  content: ""; display: block; height: 1px; margin: 6px 4px; background: var(--border);
}
@keyframes bp-linha-surge { from { opacity: 0; } }
.bp-gaveta__abre .bp-gaveta__texto { flex: 1; }
.bp-gaveta__seta { display: grid; color: var(--muted-fg); transition: rotate .25s; }
.bp-gaveta__bloco[data-ativo="true"] .bp-gaveta__seta { rotate: 180deg; }
/* Os itens do grupo abrem para baixo: a altura anima por grid (0fr → 1fr),
   e cada item entra um instante depois do anterior. */
.bp-gaveta__sub { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .32s cubic-bezier(.2,.8,.2,1); }
/* `clip`, e não `hidden`: `hidden` faz da caixa um contêiner de rolagem, e
   aí o nome do evento fixado (sticky, abaixo) grudaria NELA, não na gaveta. */
.bp-gaveta__sub > div { overflow: clip; display: flex; flex-direction: column; min-height: 0; min-width: 0; }
/* `clip` não zera a largura mínima como `hidden` zerava: sem estes
   `min-width: 0`, o nome comprido do evento esticava a gaveta para o lado em
   vez de cortar com "…". */
.bp-gaveta__bloco, .bp-gaveta__sub, .bp-gaveta__eventos, .bp-gaveta__itens-evento { min-width: 0; }
.bp-gaveta__bloco[data-ativo="true"] .bp-gaveta__sub { grid-template-rows: 1fr; }
.bp-gaveta__subitem {
  opacity: 0; translate: 0 -6px;
  transition: opacity .25s ease, translate .25s ease; transition-delay: calc(var(--k, 0) * 45ms);
}
.bp-gaveta__bloco[data-ativo="true"] .bp-gaveta__subitem { opacity: 1; translate: 0 0; }
@media (prefers-reduced-motion: reduce) {
  .bp-gaveta__sub, .bp-gaveta__subitem, .bp-gaveta__seta { transition: none; }
}

/* ── O evento aberto dentro do ☰ (menu-topo.js, `pintarMeusEventos`) ───────
   Logo abaixo de "Meus eventos": o nome em VERDE, numa linha só, com "…" se
   não couber; a data reduzida e a cidade em letra bem pequena; e os itens do
   evento embaixo (dono, 01/10/2026). */
/* TRÊS NÍVEIS DE RECUO (dono, 01/10/2026): os títulos — Área do cliente,
   Organizar evento, Admin BoomPass — alinhados na margem; os itens de dentro
   deles ~2 letras para a direita (26px de recuo contra os 10px do título,
   em `.bp-gaveta__item.bp-gaveta__subitem`, abaixo); e o evento aberto sob
   "Meus eventos" mais ~1,5 letra (os ícones dos itens dele caem em 40px). */
.bp-gaveta__eventos { display: flex; flex-direction: column; margin: 2px 0 4px 30px; }
.bp-gaveta__eventos[hidden] { display: none; }
.bp-gaveta__fixado {
  display: flex; align-items: center; gap: 6px; padding: 6px 6px 6px 2px; min-width: 0;
  border-radius: 10px; background: color-mix(in srgb, var(--fg-forte) 5%, var(--card));
}

/* AO ROLAR A GAVETA — pedido do dono, 01/10/2026: trava o bloco que vai do
   título do grupo aberto ("Organizar evento") até o nome do evento fixado,
   com Criar evento e Meus eventos no meio; só os itens do evento rolam, POR
   BAIXO dele (por isso o fundo opaco). O título trava sempre; o resto do
   bloco recebe `.bp-gaveta__trava` e o `top` de menu-topo.js (`medirGrupo`),
   que soma as alturas de cima. */
.bp-gaveta__subiu > .bp-gaveta__bloco > .bp-gaveta__abre {
  position: sticky; top: var(--alto-cliente, 0px); z-index: 4; background: var(--card);
}
/* A Área do cliente trava no alto da gaveta, acima de tudo (dono,
   01/10/2026). O BLOCO inteiro é que trava, e não só o título: o título
   sozinho ficaria preso dentro do bloco, que tem a altura dele. */
.bp-gaveta__cliente { position: sticky; top: 0; z-index: 5; background: var(--card); }
/* Com um evento aberto sob "Meus eventos", o bloco congelado começa em
   "Organizar evento", e a Área do cliente rola para fora (menu-topo.js,
   `medirGrupo`). */
.bp-gaveta--com-evento .bp-gaveta__cliente { position: static; }
@media (hover: hover) and (pointer: fine) { .bp-gaveta__subiu > .bp-gaveta__bloco > .bp-gaveta__abre:hover { background: var(--muted); } }
/* Dois seletores de classe: `.bp-gaveta__item` (fundo transparente) vem
   depois no arquivo e, com o mesmo peso, venceria — e os itens que rolam
   apareceriam através do bloco travado. */
.bp-gaveta__item.bp-gaveta__trava, .bp-gaveta__trava { position: sticky; z-index: 3; background: var(--card); }
@media (hover: hover) and (pointer: fine) { .bp-gaveta__item.bp-gaveta__trava:hover { background: var(--muted); } }
.bp-gaveta__fixado.bp-gaveta__trava {
  background: color-mix(in srgb, var(--fg-forte) 5%, var(--card));
  box-shadow: 0 6px 8px -6px rgb(0 0 0 / .14);
}
.bp-gaveta__voltar {
  display: grid; place-items: center; flex-shrink: 0; width: 30px; height: 30px;
  border: 0; border-radius: 8px; background: transparent; color: var(--fg); cursor: pointer;
}
@media (hover: hover) and (pointer: fine) { .bp-gaveta__voltar:hover { background: var(--muted); } }
.bp-gaveta__voltar svg { width: 18px; height: 18px; }
.bp-gaveta__fixado-texto { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.bp-gaveta__fixado-texto b {
  font-size: .8125rem; font-weight: 700; color: var(--primary-texto); line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bp-gaveta__fixado-texto small { font-size: .625rem; color: var(--muted-fg); line-height: 1.3; }
.bp-gaveta__itens-evento { display: flex; flex-direction: column; padding-top: 2px; }
/* O nome do evento é o link da visão geral. */
a.bp-gaveta__fixado-texto { color: inherit; text-decoration: none; }
/* Item do evento aberto na tela (dono, 01/10/2026): sem o fundo cinza dos
   outros itens — o ícone fica verde e o texto em negrito. Por isso o texto
   dos itens do evento é mais leve que o resto da gaveta: senão o negrito
   não teria do que se diferenciar. */
.bp-gaveta__itens-evento > .bp-gaveta__item b { font-weight: 500; }
.bp-gaveta__itens-evento > .bp-gaveta__item[aria-current="page"] { background: transparent; }
.bp-gaveta__itens-evento > .bp-gaveta__item[aria-current="page"] svg { color: var(--primary-texto); }
.bp-gaveta__itens-evento > .bp-gaveta__item[aria-current="page"] b { font-weight: 800; }
.bp-gaveta__itens-evento > .bp-gaveta__item { animation: bp-evento-entra .25s ease both; animation-delay: calc(var(--k, 0) * 30ms); }
@keyframes bp-evento-entra { from { opacity: 0; translate: 0 -4px; } }
@media (prefers-reduced-motion: reduce) {
  .bp-gaveta__itens-evento > .bp-gaveta__item { animation: none; }
}
/* "Sair" à esquerda, a versão à direita, na mesma linha. */
.bp-gaveta__rodape {
  margin-top: auto; padding: 6px 12px 6px 6px; border-top: 1px solid var(--border);
  display: flex; align-items: center; gap: 8px;
}
.bp-gaveta__rodape .bp-gaveta__item { flex: 1; min-width: 0; }
.bp-gaveta__rodape [data-versao] { flex-shrink: 0; }
/* Gaveta mais estreita pede tipografia menor, senão o nome do item quebra
   em duas linhas — e quatro itens de duas linhas cada voltam a ocupar a tela
   inteira, que é o que se queria evitar ao encolher.
   O QUE NÃO ENCOLHE É O ALVO DE TOQUE: o `min-height: 44px` é o mesmo número
   de plataforma usado no painel. Sai espaço em branco e corpo de letra,
   nunca a área que a mão precisa acertar — antes a altura vinha só do
   padding, agora vem declarada e o padding fica livre para diminuir. */
.bp-gaveta__item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 44px; padding: 8px 10px; border: 0; border-radius: 10px;
  background: transparent; color: var(--fg-forte); text-decoration: none;
  font: inherit; text-align: left; cursor: pointer;
}
.bp-gaveta__item svg { width: 18px; height: 18px; flex-shrink: 0; }
/* O segundo nível: dois seletores de classe, para vencer o `padding` do
   `.bp-gaveta__item` logo acima — com um só, o recuo perdia e os itens dos
   grupos ficavam alinhados com o título. */
.bp-gaveta__item.bp-gaveta__subitem { padding-left: 26px; }
/* O cinza de passar o mouse é SÓ do mouse — pedido do dono, 01/10/2026:
   no celular, rolar a lista acendia o item onde o dedo encostava. O toque
   não tem "passar por cima": o `:hover` grudava no item tocado, e o realce
   azul de toque do Android piscava a cada rolagem. No celular a lista só
   rola; o que fica cinza é a tela atual (`aria-current`, abaixo). */
@media (hover: hover) and (pointer: fine) { .bp-gaveta__item:hover { background: var(--muted); } }
.bp-gaveta { -webkit-tap-highlight-color: transparent; }
/* A gaveta recebe o foco ao abrir (menu-topo.js) só para o teclado e o
   leitor de tela saberem onde estão — ela mesma não ganha anel. */
.bp-gaveta:focus { outline: none; }
@media (hover: none) {
  /* Segurar o dedo num item também não seleciona o texto nem abre o menu de
     "copiar" do sistema: na lista não há o que copiar. */
  .bp-gaveta { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
  /* No celular, nenhum anel de foco dentro da gaveta: o toque não é
     teclado, e o anel verde parecia um item já escolhido. */
  .bp-gaveta :focus, .bp-gaveta :focus-visible { outline: none; }
}
.bp-gaveta__item:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.bp-gaveta__texto { min-width: 0; }
.bp-gaveta__texto b { display: block; font-size: .8125rem; font-weight: 600; }
.bp-gaveta__texto small { display: block; font-size: .6875rem; color: inherit; margin-top: 1px; }
.bp-gaveta__item--perigo { color: #e5484d; }

/* Item que pede conta, visto por quem não entrou: continua um destino (o
   toque leva ao login), então apaga sem sumir — cinza demais lê-se como
   quebrado. (O menu inferior deixou de apagar a aba trancada em 01/10/2026;
   aqui o caso só aparece se a sessão cair com a gaveta aberta.) */
.bp-gaveta__item--trancada { opacity: .55; }
/* O item da tela atual: o texto continua preto, e só o FUNDO fica levemente
   cinza. Pedido do dono, 01/10/2026, com print: o verde sobre verde-claro
   que estava aqui "está muito ruim de leitura" — "deixe tudo preto" (por
   isso o texto da gaveta inteira, descrição incluída, é `--fg-forte`), e
   depois: "o escrito pode manter preto, apenas deixe o cinza de seleção no
   fundo". Misturado ao `--card`, e não um cinza fixo: no tema escuro o
   mesmo cálculo dá um fundo um pouco mais claro que o da gaveta. */
.bp-gaveta__item[aria-current="page"] {
  background: color-mix(in srgb, var(--fg-forte) 7%, var(--card));
}

/* ── O menu do painel dentro da mesma gaveta ───────────────────────────────
   Pedido do dono, 30/09/2026: no painel "ficou com dois menus" — o cabeçalho
   e uma coluna lateral com a marca repetida. A coluna saiu e o menu do painel
   entrou nesta gaveta (ver painel.js, `montarCasca`). O que só o painel tem:
   a volta para "Meus eventos", o nome do evento aberto, os grupos que abrem
   e quem está conectado. */
.bp-gaveta__item--voltar { color: var(--muted-fg); }
.bp-gaveta__secao {
  padding: 8px 10px 4px; font-size: .6875rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted-fg); overflow-wrap: anywhere;
}
.bp-gaveta__divisa { height: 1px; margin: 6px 4px; background: var(--border); }
.bp-gaveta__cabeca .bp-gaveta__texto { flex: 1; }
.bp-gaveta__chevron { transition: transform .18s; }
.bp-gaveta__grupo[data-aberto="true"] .bp-gaveta__chevron { transform: rotate(180deg); }
.bp-gaveta__filhos { display: none; flex-direction: column; }
.bp-gaveta__grupo[data-aberto="true"] .bp-gaveta__filhos { display: flex; }
/* O recuo diz a que grupo o filho pertence: alinha o texto com o do pai. */
.bp-gaveta__filho { padding-left: 38px; }
.bp-gaveta__item .bp-avatar { width: 28px; height: 28px; font-size: 12px; }
.bp-gaveta__texto small, .bp-gaveta__texto b { overflow: hidden; text-overflow: ellipsis; }

@media (prefers-reduced-motion: reduce) {
  .bp-gaveta__chevron { transition: none; }
  .bp-gaveta-veu { backdrop-filter: none; }
  .bp-gaveta, .bp-gaveta-veu { transition: none; }
}

/* ── A coluna do ☰ no computador ───────────────────────────────────────────
   Pedido do dono, 10/10/2026: no computador o menu da direita fica ABERTO, e
   o ☰ do alto dele o recolhe numa faixa de ícones (e o abre de novo); no
   celular, nada muda. Quem liga é menu-topo.js (`aplicarModo`), com as
   classes `bp-menu-fixo` e `bp-menu-recolhido` no body — e não uma media
   query aqui, porque a coluna só existe com sessão: sem ela, o ☰ continua
   abrindo o login (01/10/2026).

   A coluna vai do alto ao pé da janela, e o resto da página — cabeçalho
   incluído — anda para a esquerda (`padding-right` no body). É isso que
   mantém o cabeçalho alinhado com a coluna do conteúdo: a conta de 1240px lá
   em cima mede a largura que SOBROU, e a logo continua na mesma vertical do
   conteúdo (o dono já reclamou de 13px de diferença). Quem flutua preso à
   borda direita da janela — a barra de compra do evento, os avisos — soma
   `--recuo-menu` para não nascer embaixo da coluna. */
:root { --recuo-menu: 0px; }
/* Aberta, a largura da gaveta do celular (14.5rem). Recolhida, em px, e não
   em rem: a fonte-base do site é 18px, e a conta que centraliza os ícones e o
   ☰ (abaixo) é feita em px — 6 da lista + 17 do item + 18 do ícone + 17 + 6 =
   64 de miolo, mais 1 da borda esquerda da coluna. Sem esse 1, o miolo fica
   com 63 e o ☰ (12 + 40 + 12) transborda e sai do lugar. */
body.bp-menu-fixo { --recuo-menu: 14.5rem; padding-right: var(--recuo-menu); }
body.bp-menu-fixo.bp-menu-recolhido { --recuo-menu: 65px; }
body.bp-menu-fixo .bp-gaveta {
  /* Abaixo do cabeçalho (90) e de tudo o que cobre a tela de propósito — a
     portaria em tela cheia (94 e 96) —, que continua por cima dela. */
  z-index: 89; width: var(--recuo-menu);
  transform: none; visibility: visible; box-shadow: none;
  overflow-x: hidden; transition: none;
}
/* O X não tem o que fechar, e o ☰ do cabeçalho daria dois menus na mesma
   tela: o ☰ do alto da coluna faz o papel dos dois. */
body.bp-menu-fixo :is(.bp-gaveta-veu, #bpMenuTopo, .bp-gaveta__fechar) { display: none; }
/* O topo da coluna tem a altura do cabeçalho, e as duas linhas de baixo se
   encontram. 12px à direita do ☰ de 40px: na faixa de 64px é o que o
   centraliza. */
body.bp-menu-fixo .bp-gaveta__topo { height: var(--altura-topo); padding: 0 12px 0 13px; }
.bp-gaveta__recolher { display: none; }
body.bp-menu-fixo .bp-gaveta__recolher {
  display: grid; place-items: center; flex-shrink: 0; width: 40px; height: 40px; margin-left: auto;
  border: 0; border-radius: 12px; background: transparent; color: var(--fg-forte); cursor: pointer;
}
.bp-gaveta__recolher svg { width: 22px; height: 22px; }
body.bp-menu-fixo .bp-gaveta__recolher:hover { background: var(--muted); }
.bp-gaveta__recolher:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }

/* A FAIXA DE ÍCONES. Os ícones ficam a 17px da beirada esquerda do item: na
   faixa de 64px, é o centro. Alinhados à esquerda, e não `center`, para não
   saltarem para o meio no primeiro quadro do recolher — encostados na beira,
   eles acompanham a coluna enquanto ela estreita. */
body.bp-menu-recolhido :is(.bp-gaveta__topo strong, .bp-gaveta__seta, .bp-gaveta__fixado,
  .bp-gaveta__rodape [data-versao]) { display: none; }
body.bp-menu-recolhido .bp-gaveta__topo { padding-left: 12px; }
/* O nome sai da VISTA, não do item: o leitor de tela continua lendo "Meus
   ingressos", e é dele que a dica (menu-topo.js) tira o texto. */
body.bp-menu-recolhido .bp-gaveta__texto {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
body.bp-menu-recolhido :is(.bp-gaveta__item, .bp-gaveta__item.bp-gaveta__subitem) { gap: 0; padding-inline: 17px; }
body.bp-menu-recolhido .bp-gaveta__eventos { margin-left: 0; }
body.bp-menu-recolhido .bp-gaveta__rodape { padding-inline: 6px; }
/* Sem recuo, nada diz de quem é cada ícone: os itens do grupo aberto ganham
   um fundo em comum, logo abaixo do ícone do grupo. */
body.bp-menu-recolhido .bp-gaveta__bloco[data-ativo="true"] .bp-gaveta__sub > div {
  background: color-mix(in srgb, var(--fg-forte) 4%, var(--card)); border-radius: 10px;
}
/* A tela atual, sobre esse fundo: cinza mais forte e o ícone verde — só o
   cinza de 7% da coluna aberta sumiria contra os 4% do grupo. */
body.bp-menu-recolhido .bp-gaveta__item[aria-current="page"] {
  background: color-mix(in srgb, var(--fg-forte) 11%, var(--card));
}
body.bp-menu-recolhido .bp-gaveta__item[aria-current="page"] svg { color: var(--primary-texto); }
/* As travas da lista (`medirGrupo`) existem para segurar NOMES no alto
   enquanto a lista rola. Na faixa não há nome, e a trava só pintaria o fundo
   da coluna por cima do fundo do grupo. */
body.bp-menu-recolhido :is(.bp-gaveta__cliente, .bp-gaveta__trava,
  .bp-gaveta__subiu > .bp-gaveta__bloco > .bp-gaveta__abre) { position: static; }
/* E o fundo opaco da trava, que existia para esconder o que rola por baixo,
   viraria um bloco branco no meio do cinza do grupo. O cinza de passar o
   mouse e o da tela atual continuam valendo. */
body.bp-menu-recolhido .bp-gaveta__trava:not(:hover, [aria-current="page"]) { background: transparent; }

/* A animação de recolher e abrir. Só durante o clique (`bp-menu-anima`, posta
   e tirada por menu-topo.js): presa à coluna, ela animaria também a chegada,
   e a cada recarga a coluna deslizaria para dentro e o conteúdo andaria. */
body.bp-menu-anima { transition: padding-right .28s cubic-bezier(.2, .8, .2, 1); }
body.bp-menu-anima .bp-gaveta { transition: width .28s cubic-bezier(.2, .8, .2, 1); }
/* Enquanto a coluna alarga, o nome não quebra em duas linhas: quebrado, a
   lista mudaria de altura a cada quadro. */
body.bp-menu-anima .bp-gaveta__texto :is(b, small) { white-space: nowrap; }
@media (prefers-reduced-motion: reduce) {
  body.bp-menu-anima, body.bp-menu-anima .bp-gaveta { transition: none; }
}

/* A dica da faixa: o nome do item, à esquerda dele (a coluna encosta na
   borda direita). Fora da gaveta, para o `overflow` dela não a cortar. */
.bp-gaveta__dica {
  position: fixed; z-index: 120; translate: 0 -50%;
  max-width: 16rem; padding: 6px 10px; border-radius: 8px;
  background: var(--fg-forte); color: var(--card);
  font-size: .75rem; font-weight: 600; line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  pointer-events: none;
  box-shadow: 0 8px 20px -8px rgb(0 0 0 / .4);
}

/* No papel, só o conteúdo: relatório impresso com a coluna do menu ao lado
   perderia um quinto da folha. */
@media print {
  .bp-gaveta, .bp-gaveta__dica { display: none !important; }
  body.bp-menu-fixo { padding-right: 0; }
}

/* ── O selo de versão, agora dentro do menu ────────────────────────────────
   Era uma pílula fixa no canto inferior direito. Saiu de lá porque cobria a
   aba "Perfil" desde que a barra do rodapé nasceu, e porque um número que só
   a equipe lê não precisa ficar por cima do que o comprador veio fazer.

   Quem preenche é assets/version-check.js, que procura por `[data-versao]`.
   Vazio (antes de a busca responder, ou se ela falhar) o elemento não ocupa
   espaço nenhum — nada de um espaço em branco com cara de defeito. */
[data-versao] {
  font: 600 11px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: .3px; color: var(--muted-fg); user-select: none;
}
[data-versao]:empty { display: none; }

/* ── O login num modal ─────────────────────────────────────────────────────
   Pedido do dono, 01/10/2026: "a tela de login reduzida a um modal
   centralizado no meio da tela" — aberto pelo ☰ e pelas abas "Meus
   ingressos" e "Perfil" quando não há sessão (entrar-modal.js). O <dialog>
   já nasce centralizado pelo navegador; daqui sai só o tamanho e o miolo, no
   mesmo vocabulário da tela inteira (/vistas/publico/entrar.html). */
dialog.bp-entrar-modal { max-width: 24rem; max-height: calc(100dvh - 2rem); overflow-y: auto; }
.bp-entrar-modal__topo {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 12px 0 1.5rem;
}
.bp-entrar-modal__topo img { display: block; height: 32px; width: auto; }
.bp-entrar-modal__fechar {
  display: grid; place-items: center; width: 40px; height: 40px;
  border: 0; border-radius: 10px; background: transparent; color: var(--muted-fg); cursor: pointer;
}
.bp-entrar-modal__fechar svg { width: 20px; height: 20px; }
.bp-entrar-modal__fechar:hover { background: var(--muted); color: var(--fg); }
dialog.bp-entrar-modal form { padding-top: .75rem; padding-bottom: 0; gap: .875rem; }
.bp-entrar-modal h2 { font-size: 1.375rem; margin: 0; }
.bp-entrar-modal__sub { margin: .25rem 0 0; color: var(--muted-fg); font-size: .8125rem; line-height: 1.5; }
.bp-entrar-modal__lembrar { display: flex; align-items: center; gap: .5rem; font-size: .8125rem; color: var(--muted-fg); }
.bp-entrar-modal__lembrar input { accent-color: var(--primary); width: 1rem; height: 1rem; }
.bp-entrar-modal .bp-link { align-self: center; }
.bp-entrar-modal__troca {
  text-align: center; font-size: .8125rem; color: var(--muted-fg);
  margin: 0; padding: 1rem 1.5rem 1.5rem;
}
.bp-entrar-modal__troca .bp-link { display: inline; margin: 0; }
