/* Caminho: public_html/assets/css/movimento.css
   CAMADA DE MOVIMENTO. Fonte única de durações, curvas e coreografias.

   A gramática do site é o CORTE DO ITAMAE. Nada aqui sobe de baixo para cima
   como em qualquer página: o conteúdo entra no eixo da lâmina, a 68 graus,
   que é o ângulo em que o Mauro corta o maki. Onde o corte é literal, uma
   linha fina de luz passa antes, como o fio da faça pegando a luz do balcão.

   Só existe um momento grande no site inteiro: o carimbo, quando o pedido
   é confirmado. Todo o resto é movimento funcional, curto e a serviço da
   tarefa. Movimento espalhado sem hierarquia cansa e atrapalha a venda.

   Regra técnica: só transform, opacity, clip-path e mask entram em animação.
   Nada que force recálculo de layout. */

/* ==================================================================
   1. TOKENS DE MOVIMENTO
   ================================================================== */
:root {
  /* Durações. A escada é proposital: cada degrau é perceptivelmente maior. */
  --m-instante: 90ms;    /* resposta ao toque, precisa parecer instantânea */
  --m-rapido: 180ms;     /* troca de estado, aparecer e sumir */
  --m-medio: 320ms;      /* entrada de componente */
  --m-lento: 540ms;      /* entrada de bloco na tela */
  --m-corte: 760ms;      /* a revelação assinatura */
  --m-carimbo: 900ms;    /* o único momento grande */

  /* Curvas. Nomeadas pela sensação, não pelos números. */
  --curva-corte: cubic-bezier(0.16, 1, 0.30, 1);    /* parte rápido, assenta devagar */
  --curva-entra: cubic-bezier(0.22, 1, 0.36, 1);
  --curva-sai: cubic-bezier(0.55, 0, 1, 0.45);
  --curva-toque: cubic-bezier(0.34, 1.42, 0.64, 1); /* passa do ponto e volta */
  --curva-peso: cubic-bezier(0.30, 1.60, 0.55, 1);  /* algo que cai e assenta */

  /* Geometria da lâmina */
  --angulo-lamina: 68deg;
  --recuo-lamina-x: -13px;
  --recuo-lamina-y: 17px;

  /* Ritmo da fila. Curto de propósito: fila lenta parece travamento. */
  --passo-fila: 52ms;
  --teto-fila: 8;
}

/* ==================================================================
   2. A ASSINATURA: O CORTE

   Usada em três lugares e só neles: a abertura da página, o título de
   cada categoria e a foto do produto ao abrir. Se aparecer em tudo,
   deixa de ser assinatura e vira ruído.
   ================================================================== */
.com-js .corte {
  --avanco: 0%;
  -webkit-mask-image: linear-gradient(var(--angulo-lamina),
    #000 0 var(--avanco),
    rgba(0, 0, 0, 0.35) calc(var(--avanco) + 5%),
    transparent calc(var(--avanco) + 13%));
  mask-image: linear-gradient(var(--angulo-lamina),
    #000 0 var(--avanco),
    rgba(0, 0, 0, 0.35) calc(var(--avanco) + 5%),
    transparent calc(var(--avanco) + 13%));
  transition: --avanco var(--m-corte) var(--curva-corte);
  position: relative;
}

/* A propriedade precisa ser registrada para poder ser animada.
   Sem isso o navegador trata 0% e 100% como troca seca. */
@property --avanco {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 0%;
}

.com-js .corte.visivel { --avanco: 116%; }

/* O fio da faça: a linha de luz que passa na frente do corte */
.corte::after {
  content: "";
  position: absolute;
  inset: -2px;
  pointer-events: none;
  z-index: 3;
  opacity: 0;
  background: linear-gradient(var(--angulo-lamina),
    transparent 46%,
    color-mix(in srgb, var(--marca-forte) 70%, white) 50%,
    transparent 54%);
  background-size: 260% 260%;
  background-position: 100% 100%;
}

.corte.visivel::after {
  animation: fioDaFaca var(--m-corte) var(--curva-corte) both;
}

@keyframes fioDaFaca {
  0%   { opacity: 0; background-position: 100% 100%; }
  18%  { opacity: 0.9; }
  70%  { opacity: 0.5; }
  100% { opacity: 0; background-position: -30% -30%; }
}

/* ==================================================================
   3. A LÂMINA BARATA

   Mesma gramática, custo de um transform. É o que entra nos cards,
   nas listas e em tudo que aparece em quantidade. O conteúdo chega
   deslizando no eixo da faça, nunca de baixo para cima.
   ================================================================== */
.com-js .revelar,
.com-js .lamina {
  opacity: 0;
  transform: translate3d(var(--recuo-lamina-x), var(--recuo-lamina-y), 0) rotate(-0.7deg);
  transition:
    opacity var(--m-lento) var(--curva-corte),
    transform var(--m-lento) var(--curva-corte);
}

.com-js .revelar.visivel,
.com-js .lamina.visivel {
  opacity: 1;
  transform: none;
}

/* Fila: cada filho entra depois do anterior, com teto para a última
   posição não demorar uma eternidade em listas longas. */
.com-js .fila > * {
  opacity: 0;
  transform: translate3d(var(--recuo-lamina-x), var(--recuo-lamina-y), 0) rotate(-0.7deg);
  transition:
    opacity var(--m-lento) var(--curva-corte),
    transform var(--m-lento) var(--curva-corte);
  transition-delay: calc(min(var(--i, 0), var(--teto-fila)) * var(--passo-fila));
}

.com-js .fila.visivel > * { opacity: 1; transform: none; }

/* ==================================================================
   4. ABERTURA DA PÁGINA

   Sequência encenada, não um fade geral. A ordem conta uma história:
   o selo de aberto, a promessa, o texto, os botões. Roda uma vez só.
   ================================================================== */
.hero .hero-chips > *,
.hero h1,
.hero-texto,
.hero-acoes > * {
  animation: entraLamina var(--m-lento) var(--curva-corte) both;
}

.hero .hero-chips > *:nth-child(1) { animation-delay: 60ms; }
.hero .hero-chips > *:nth-child(2) { animation-delay: 120ms; }
.hero .hero-chips > *:nth-child(3) { animation-delay: 180ms; }
.hero h1 { animation-delay: 150ms; }
.hero-texto { animation-delay: 300ms; }
.hero-acoes > *:nth-child(1) { animation-delay: 400ms; }
.hero-acoes > *:nth-child(2) { animation-delay: 460ms; }

@keyframes entraLamina {
  from {
    opacity: 0;
    transform: translate3d(var(--recuo-lamina-x), var(--recuo-lamina-y), 0) rotate(-0.7deg);
  }
  to { opacity: 1; transform: none; }
}

/* A palavra destacada do título recebe o corte de verdade.
   É o primeiro contato do cliente com a gramática do site. */
.hero h1 .destaque {
  background-size: 200% 100%;
  animation: tintaEspalha 1.6s var(--curva-corte) 260ms both;
}

@keyframes tintaEspalha {
  from { background-position: 100% 0; }
  to { background-position: 0 0; }
}

/* ==================================================================
   5. RESPOSTA AO TOQUE

   O piso de qualidade de um app: nada pode parecer morto ao dedo.
   O afundamento é de 2%, o suficiente para o polegar sentir sem
   parecer que o botão quebrou.
   ================================================================== */
.btn,
.aba,
.produto,
.destaque-card,
.tema-card,
.botao-icone,
.opcao,
.escolha-entrega label,
.contador button {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.btn:active,
.destaque-card:active,
.tema-card:active,
.opcao:active,
.escolha-entrega label:active { transform: scale(0.975); }

.btn { transition: transform var(--m-instante) var(--curva-toque), box-shadow var(--m-rapido) var(--curva-entra), background var(--m-rapido) linear, color var(--m-rapido) linear; }

/* Onda que nasce exatamente onde o dedo tocou.
   As coordenadas chegam do JavaScript em --toque-x e --toque-y. */
.onda-toque {
  position: absolute;
  left: var(--toque-x, 50%);
  top: var(--toque-y, 50%);
  width: 12px;
  height: 12px;
  margin: -6px 0 0 -6px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.22;
  pointer-events: none;
  animation: abreOnda 560ms var(--curva-entra) forwards;
}

@keyframes abreOnda {
  to { transform: scale(26); opacity: 0; }
}

/* O botão principal ganha um brilho que atravessa a superfície,
   como a luz correndo no aço. Discreto e só no hover. */
@media (hover: hover) {
  .btn-marca { position: relative; overflow: hidden; }

  .btn-marca::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(var(--angulo-lamina), transparent 42%, rgba(255, 255, 255, 0.28) 50%, transparent 58%);
    background-size: 240% 240%;
    background-position: 130% 130%;
    opacity: 0;
    pointer-events: none;
  }

  .btn-marca:hover::after { animation: fioDaFaca 720ms var(--curva-corte) both; }
  .btn-marca:hover { transform: translateY(-2px); }
}

/* ==================================================================
   6. CARDS DE PRODUTO

   A foto é o que vende. Ela cresce um pouco no hover e no toque,
   dentro de um recorte que não deixa vazar.
   ================================================================== */
.produto-foto { overflow: hidden; }

.produto-foto img,
.destaque-card img {
  transition: transform var(--m-lento) var(--curva-entra), filter var(--m-medio) linear;
  will-change: transform;
}

@media (hover: hover) {
  .produto:hover .produto-foto img,
  .destaque-card:hover img { transform: scale(1.07); }
}

.produto:active .produto-foto img { transform: scale(1.03); }

/* Enquanto a foto não chegou, o espaço respira em vez de piscar em branco */
.com-js .produto-foto img:not([data-carregada]),
.com-js .destaque-card img:not([data-carregada]) { opacity: 0; }

.com-js .produto-foto img[data-carregada],
.com-js .destaque-card img[data-carregada] { animation: fotoChega var(--m-lento) var(--curva-entra) both; }

@keyframes fotoChega {
  from { opacity: 0; transform: scale(1.06); filter: blur(6px); }
  to { opacity: 1; transform: none; filter: none; }
}

/* O selo de promoção não fica parado: pulsa devagar, como uma lanterna */
.produto-selos .selo-marca { animation: respiraSelo 3.4s var(--easing-suave) infinite; }

@keyframes respiraSelo {
  0%, 100% { transform: none; }
  50% { transform: scale(1.045) rotate(-1.2deg); }
}

/* Item que sai da busca não some seco, encolhe no eixo da lâmina */
.produto.esconder,
.secao-categoria.esconder { animation: saiLamina var(--m-rapido) var(--curva-sai) both; }

@keyframes saiLamina {
  to { opacity: 0; transform: translate3d(6px, -8px, 0) scale(0.97); }
}

/* ==================================================================
   7. BARRA DE CATEGORIAS

   Um indicador desliza da aba antiga para a nova em vez de piscar.
   A posição vem do JavaScript, que mede a aba ativa de verdade.
   ================================================================== */
.abas-categorias { position: relative; }

.indicador-aba {
  position: absolute;
  left: 0;
  top: 0;
  height: var(--ind-altura, 38px);
  width: var(--ind-largura, 0);
  transform: translate3d(var(--ind-x, 0), var(--ind-y, 0), 0);
  border-radius: var(--r-pill);
  background: var(--marca);
  box-shadow: var(--sombra-marca);
  transition: transform var(--m-medio) var(--curva-toque), width var(--m-medio) var(--curva-toque);
  pointer-events: none;
  z-index: 0;
}

.aba { position: relative; z-index: 1; }

/* Com o indicador no ar, a aba ativa não precisa mais de fundo próprio */
.abas-categorias:has(.indicador-aba) .aba[aria-current="true"] {
  background: transparent;
  box-shadow: none;
}

/* Barra fina que mostra o quanto do cardápio já foi percorrido */
.progresso-cardapio {
  position: fixed;
  left: 0;
  top: 0;
  height: 3px;
  width: 100%;
  transform-origin: 0 50%;
  transform: scaleX(var(--progresso, 0));
  background: linear-gradient(90deg, var(--marca), var(--acento));
  z-index: calc(var(--z-cabecalho) + 1);
  pointer-events: none;
}

/* ==================================================================
   8. GAVETA E MODAL

   No celular a gaveta sobe do fundo com peso, como algo que assenta.
   O conteúdo entra logo atrás dela, em fila, para a tela não aparecer
   pronta de uma vez e parecer estática.
   ================================================================== */
.painel { animation: sobeGaveta var(--m-medio) var(--curva-peso) both; }

.painel-corpo > * { animation: entraLamina var(--m-medio) var(--curva-corte) both; }
.painel-corpo > *:nth-child(1) { animation-delay: 70ms; }
.painel-corpo > *:nth-child(2) { animation-delay: 120ms; }
.painel-corpo > *:nth-child(3) { animation-delay: 165ms; }
.painel-corpo > *:nth-child(4) { animation-delay: 205ms; }
.painel-corpo > *:nth-child(n+5) { animation-delay: 240ms; }

.painel-rodape { animation: entraLamina var(--m-medio) var(--curva-corte) 200ms both; }

/* A foto do produto no modal é um dos três lugares do corte de verdade */
.capa-produto { overflow: hidden; }

/* Quantidade que muda: o número salta, o resto fica quieto */
.contador span.mudou { animation: saltaNumero var(--m-medio) var(--curva-toque); }

@keyframes saltaNumero {
  0% { transform: none; }
  40% { transform: translateY(-5px) scale(1.22); color: var(--marca-forte); }
  100% { transform: none; }
}

.contador button:active { transform: scale(0.86); }

/* Opção escolhida: a borda acende e a linha inteira dá um passo à frente */
.opcao { transition: border-color var(--m-rapido) linear, background var(--m-rapido) linear, transform var(--m-instante) var(--curva-toque); }
.opcao:has(input:checked) { animation: acendeOpcao 420ms var(--curva-toque); }

@keyframes acendeOpcao {
  0% { transform: none; }
  35% { transform: translateX(5px); }
  100% { transform: none; }
}

/* ==================================================================
   9. CARRINHO

   Três sinais que o cliente precisa perceber sem ler: o item entrou,
   quantos itens tem, e quanto está custando.
   ================================================================== */

/* O item que voa: um clone da foto, criado e destruído pelo JavaScript */
.voando {
  position: fixed;
  z-index: var(--z-toast);
  border-radius: var(--r-md);
  object-fit: cover;
  pointer-events: none;
  box-shadow: var(--sombra-2);
}

/* A barra do carrinho não aparece, ela sobe */
.barra-inferior {
  transition: transform var(--m-medio) var(--curva-peso), opacity var(--m-rapido) linear;
}

.barra-inferior.pulou { animation: barraRecebe 480ms var(--curva-toque); }

@keyframes barraRecebe {
  0% { transform: none; }
  30% { transform: translateY(-6px) scale(1.015); }
  60% { transform: translateY(1px) scale(0.996); }
  100% { transform: none; }
}

/* O contador de itens fica preso ao canto do ícone por posição, nunca por
   transform: o transform precisa ficar livre para a animação de estouro. */
.selo-quantidade {
  position: absolute;
  top: -7px;
  right: -9px;
  min-width: 20px;
  padding: 0.12rem 0.34rem;
  justify-content: center;
  pointer-events: none;
}

/* O contador de itens estoura quando recebe algo */
.selo-quantidade.pulou { animation: estouraSelo 520ms var(--curva-peso); }

@keyframes estouraSelo {
  0% { transform: scale(1); }
  30% { transform: scale(1.55) rotate(-8deg); }
  55% { transform: scale(0.92) rotate(3deg); }
  100% { transform: scale(1); }
}

/* Valores que mudam rolam para cima como um marcador mecânico */
.valor-anima { display: inline-block; font-variant-numeric: tabular-nums; }
.valor-anima.subindo { animation: rolaValor var(--m-medio) var(--curva-entra); }

@keyframes rolaValor {
  0% { transform: translateY(60%); opacity: 0; }
  100% { transform: none; opacity: 1; }
}

/* Item removido do carrinho desliza para fora antes de sumir */
.item-carrinho.saindo {
  animation: removeItem var(--m-medio) var(--curva-sai) forwards;
  overflow: hidden;
}

@keyframes removeItem {
  to { opacity: 0; transform: translateX(38px); max-height: 0; padding-top: 0; padding-bottom: 0; margin: 0; }
}

/* Carrinho vazio: o ícone flutua devagar, para a tela não parecer travada */
.vazio img.icone-xl { animation: flutua 4.2s var(--easing-suave) infinite; }

@keyframes flutua {
  0%, 100% { transform: translateY(0) rotate(-2deg); }
  50% { transform: translateY(-9px) rotate(2deg); }
}

/* ==================================================================
   10. CHECKOUT

   Aqui o movimento fica de fora do caminho. Quem chegou até esta tela
   já decidiu comprar; animação bonita agora só atrasa a compra.
   O que sobra é o essencial: onde estou, o que faltou, e o que aconteceu.
   ================================================================== */
.passo::after { transition: width var(--m-lento) var(--curva-entra); }

/* Campo com erro treme e a borda acende. Feedback, não decoração. */
.entrada.errado,
.selecao.errado { animation: tremeCampo 420ms var(--curva-entra); border-color: var(--erro); }

@keyframes tremeCampo {
  0%, 100% { transform: none; }
  15% { transform: translateX(-7px); }
  35% { transform: translateX(6px); }
  55% { transform: translateX(-4px); }
  75% { transform: translateX(2px); }
}

/* O botão de enviar tem três estados e a troca entre eles é visível */
.btn.enviando {
  pointer-events: none;
  background-image: linear-gradient(var(--angulo-lamina),
    rgba(255, 255, 255, 0.20) 25%, transparent 25% 50%,
    rgba(255, 255, 255, 0.20) 50% 75%, transparent 75%);
  background-size: 32px 32px;
  animation: esteiraBotao 700ms linear infinite;
}

@keyframes esteiraBotao {
  to { background-position: 32px 0; }
}

.btn.confirmado { animation: confirmaBotao var(--m-medio) var(--curva-peso); }

@keyframes confirmaBotao {
  0% { transform: none; }
  40% { transform: scale(1.04); }
  100% { transform: none; }
}

/* ==================================================================
   11. O CARIMBO

   O único momento grande do site. Quando o pedido é confirmado, o selo
   desce girado, bate no papel e a tinta escapa pelas bordas, do jeito
   que carimbo de verdade faz. Acontece uma vez por pedido e some.
   ================================================================== */
.carimbo-cena {
  position: fixed;
  inset: 0;
  z-index: var(--z-toast);
  display: grid;
  place-items: center;
  background: color-mix(in srgb, var(--fundo) 78%, transparent);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  animation: aparecer var(--m-rapido) linear both;
}

.carimbo-cena.saindo { animation: some var(--m-medio) var(--curva-sai) forwards; }

@keyframes some { to { opacity: 0; } }

.carimbo {
  width: min(46vw, 190px);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 7px solid var(--marca);
  color: var(--marca);
  font-family: var(--fonte-titulo);
  font-weight: var(--peso-black);
  font-size: clamp(1.1rem, 5vw, 1.7rem);
  letter-spacing: 0.06em;
  text-align: center;
  line-height: 1.15;
  white-space: pre-line;
  transform: rotate(-14deg);
  animation: carimbar var(--m-carimbo) var(--curva-peso) both;
}

@keyframes carimbar {
  0%   { opacity: 0; transform: rotate(-32deg) scale(2.6); filter: blur(4px); }
  45%  { opacity: 1; transform: rotate(-11deg) scale(0.94); filter: none; }
  58%  { transform: rotate(-14deg) scale(1.05); }
  70%  { transform: rotate(-13deg) scale(0.99); }
  100% { opacity: 1; transform: rotate(-13deg) scale(1); }
}

/* A tinta que escapa no impacto */
.carimbo-cena::before {
  content: "";
  position: absolute;
  width: min(46vw, 190px);
  aspect-ratio: 1;
  border-radius: 50%;
  border: 3px solid var(--marca);
  opacity: 0;
  animation: tintaEscapa 900ms var(--curva-corte) 380ms both;
}

@keyframes tintaEscapa {
  0% { opacity: 0.55; transform: scale(1); }
  100% { opacity: 0; transform: scale(2.1); }
}

.carimbo-legenda {
  position: absolute;
  bottom: 18vh;
  text-align: center;
  padding: 0 var(--e-5);
  animation: entraLamina var(--m-lento) var(--curva-corte) 620ms both;
}

.carimbo-legenda strong { display: block; font-size: var(--t-lg); font-family: var(--fonte-titulo); }
.carimbo-legenda span { color: var(--texto-3); font-size: var(--t-sm); }

/* ==================================================================
   12. ACOMPANHAMENTO DO PEDIDO

   A linha do tempo se desenha de cima para baixo, e a etapa atual
   respira. Quem está esperando comida olha muito para esta tela.
   ================================================================== */
.trilha-item::before {
  transform-origin: 50% 0;
  animation: desceLinha var(--m-lento) var(--curva-entra) both;
  animation-delay: calc(var(--i, 0) * 110ms);
}

@keyframes desceLinha {
  from { transform: scaleY(0); }
  to { transform: scaleY(1); }
}

.trilha-item {
  animation: entraLamina var(--m-medio) var(--curva-corte) both;
  animation-delay: calc(var(--i, 0) * 110ms);
}

.trilha-item.feito .trilha-bola { animation: assentaBola 420ms var(--curva-peso) both; }

@keyframes assentaBola {
  0% { transform: scale(0.4) rotate(-20deg); }
  60% { transform: scale(1.14) rotate(4deg); }
  100% { transform: none; }
}

/* Onda que sai da etapa atual, como o cheiro subindo da cozinha */
.trilha-item.atual .trilha-bola::after {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  border: 2px solid var(--marca);
  animation: ondaEtapa 2.2s var(--curva-corte) infinite;
}

@keyframes ondaEtapa {
  0% { opacity: 0.7; transform: scale(0.9); }
  100% { opacity: 0; transform: scale(1.9); }
}

/* ==================================================================
   13. COZINHA (KDS)

   Regra diferente do resto do site: aqui movimento é alarme, não charme.
   Comanda nova precisa ser vista do outro lado do balcão, de relance.
   ================================================================== */
/* Só a comanda que acabou de aparecer entra animada. A lista é redesenhada
   a cada seis segundos: animar todas a cada ciclo faria a tela da cozinha
   piscar sem parar, que é o oposto do que o KDS precisa ser. */
.comanda.entrando { animation: chegaComanda var(--m-medio) var(--curva-peso) both; }

@keyframes chegaComanda {
  from { opacity: 0; transform: translate3d(0, 22px, 0) scale(0.97); }
  to { opacity: 1; transform: none; }
}

.comanda.nova { animation: chegaComanda var(--m-medio) var(--curva-peso) both, avisaComanda 1.5s var(--easing-suave) 3; }

/* Sinal permanente enquanto a comanda não foi tocada: uma faixa no ângulo
   da lâmina correndo na borda esquerda, visível do outro lado do balcão. */
.comanda[data-status="novo"]::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 4px;
  background: linear-gradient(180deg, var(--marca), var(--acento), var(--marca));
  background-size: 100% 260%;
  animation: correFaixa 2.6s linear infinite;
}

@keyframes correFaixa {
  to { background-position: 0 -260%; }
}

@keyframes avisaComanda {
  0%, 100% { box-shadow: 0 0 0 0 transparent; }
  50% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--marca) 40%, transparent); }
}

.comanda.saindo { animation: saiComanda var(--m-medio) var(--curva-sai) forwards; }

@keyframes saiComanda {
  to { opacity: 0; transform: translate3d(0, -14px, 0) scale(0.96); }
}

/* Cronômetro que passou do ponto pulsa cada vez mais rápido */
.cronometro.atencao { animation: urgencia 1.6s var(--easing-suave) infinite; }
.cronometro.atrasado { animation: urgencia 1.0s var(--easing-suave) infinite; }
.cronometro.critico { animation: urgencia 0.55s var(--easing-suave) infinite; }

@keyframes urgencia {
  0%, 100% { opacity: 1; transform: none; }
  50% { opacity: 0.55; transform: scale(1.06); }
}

/* Impressão em andamento: a bobina correndo */
.btn.imprimindo::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  background: currentColor;
  transform-origin: 0 50%;
  animation: bobina 1.1s var(--curva-entra) infinite;
}

@keyframes bobina {
  0% { transform: scaleX(0); }
  70% { transform: scaleX(1); }
  100% { transform: scaleX(1); opacity: 0; }
}

/* ==================================================================
   14. HUB ADMINISTRATIVO

   Números aparecem em fila, gráficos se desenham. Faz a leitura do
   dia parecer um relatório sendo entregue, não uma tela recarregando.
   ================================================================== */
.kpi {
  animation: entraLamina var(--m-medio) var(--curva-corte) both;
  animation-delay: calc(var(--i, 0) * 70ms);
}

.kpi .valor { font-variant-numeric: tabular-nums; }

.grafico .linha-dados {
  stroke-dasharray: var(--traco, 2000);
  stroke-dashoffset: var(--traco, 2000);
  animation: desenhaLinha 1.5s var(--curva-entra) 180ms forwards;
}

@keyframes desenhaLinha {
  to { stroke-dashoffset: 0; }
}

.grafico .area-dados { animation: aparecer 900ms linear 900ms both; }

.bloco-admin .barra-valor {
  transform-origin: 0 50%;
  animation: cresceBarra var(--m-lento) var(--curva-corte) both;
  animation-delay: calc(var(--i, 0) * 60ms);
}

@keyframes cresceBarra {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

.tabela tbody tr { transition: background var(--m-rapido) linear, transform var(--m-instante) var(--curva-entra); }
.tabela tbody tr:hover { transform: translateX(3px); }

/* ==================================================================
   15. AVISOS

   Entram no eixo da lâmina, do canto, e saem por onde vieram.
   ================================================================== */
.aviso { animation: entraAviso var(--m-medio) var(--curva-peso) both; }

@keyframes entraAviso {
  from { opacity: 0; transform: translate3d(0, 18px, 0) scale(0.94); }
  to { opacity: 1; transform: none; }
}

/* ==================================================================
   16. ROLAGEM COMO LINHA DO TEMPO

   Onde o navegador suporta, o parallax e a barra de progresso rodam
   sem uma linha de JavaScript, direto no compositor. Onde não suporta,
   simplesmente não acontece, e nada quebra.
   ================================================================== */
@supports (animation-timeline: view()) {
  .produto-foto img {
    animation: deslizaFoto linear both;
    animation-timeline: view();
    animation-range: entry 0% exit 100%;
  }

  @keyframes deslizaFoto {
    from { transform: translateY(-7%) scale(1.12); }
    to { transform: translateY(7%) scale(1.12); }
  }

  .hero-blob {
    animation: gira 40s linear infinite, afundaBlob linear both;
    animation-timeline: auto, view();
    animation-range: normal, entry 0% exit 100%;
  }

  @keyframes afundaBlob {
    from { opacity: 0.55; }
    to { opacity: 0.06; }
  }

  .cabecalho-secao h2 {
    animation: firmaTitulo linear both;
    animation-timeline: view();
    animation-range: entry 10% entry 90%;
  }

  @keyframes firmaTitulo {
    from { opacity: 0.25; letter-spacing: 0.06em; }
    to { opacity: 1; letter-spacing: normal; }
  }
}

@supports (animation-timeline: scroll()) {
  .progresso-cardapio {
    transform: scaleX(0);
    animation: avancaProgresso linear both;
    animation-timeline: scroll(root block);
  }

  @keyframes avancaProgresso {
    to { transform: scaleX(1); }
  }
}

/* ==================================================================
   17. TRANSIÇÃO ENTRE PÁGINAS

   Onde houver suporte, sair do cardápio para o acompanhamento parece
   trocar de tela em um aplicativo, não recarregar um site.
   ================================================================== */
@view-transition { navigation: auto; }

::view-transition-old(root) {
  animation: some var(--m-rapido) var(--curva-sai) both;
}

::view-transition-new(root) {
  animation: entraLamina var(--m-medio) var(--curva-corte) both;
}

/* O logotipo é o mesmo objeto nas duas telas, então ele não pisca:
   viaja de uma posição para a outra. */
.marca-logo { view-transition-name: marca; }

/* ==================================================================
   18. ACESSIBILIDADE DO MOVIMENTO

   Quem pediu menos movimento no sistema recebe a interface inteira,
   com todo o conteúdo visível, e nada se mexendo. Não é uma versão
   pobre: é a mesma tela, parada.
   ================================================================== */
@media (prefers-reduced-motion: reduce) {
  :root {
    --m-instante: 1ms;
    --m-rapido: 1ms;
    --m-medio: 1ms;
    --m-lento: 1ms;
    --m-corte: 1ms;
    --m-carimbo: 1ms;
    --passo-fila: 0ms;
    --recuo-lamina-x: 0px;
    --recuo-lamina-y: 0px;
  }

  .com-js .revelar,
  .com-js .lamina,
  .com-js .fila > *,
  .revelar,
  .lamina,
  .fila > * {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }

  .corte,
  .com-js .corte { --avanco: 116%; -webkit-mask-image: none; mask-image: none; }
  .corte::after,
  .carimbo-cena::before,
  .trilha-item.atual .trilha-bola::after,
  .btn-marca::after { display: none; }

  .hero .hero-chips > *,
  .hero h1,
  .hero-texto,
  .hero-acoes > *,
  .painel-corpo > *,
  .painel-rodape,
  .trilha-item,
  .trilha-item::before,
  .kpi,
  .comanda,
  .aviso {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }

  .produto-selos .selo-marca,
  .vazio img.icone-xl,
  .cronometro.atencao,
  .cronometro.atrasado,
  .cronometro.critico,
  .comanda.entrando,
  .comanda[data-status="novo"]::before,
  .comanda.nova { animation: none !important; }

  .grafico .linha-dados { stroke-dashoffset: 0; animation: none !important; }
  .bloco-admin .barra-valor { transform: none !important; animation: none !important; }

  @view-transition { navigation: none; }
}

/* Quem navega por teclado precisa enxergar onde está, sempre,
   inclusive dentro de elementos que estão animando. */
:focus-visible {
  outline: 3px solid var(--marca-forte);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
