*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
:root{
  --bg:#050b18;--bg2:#0a1628;--card:rgba(255,255,255,.06);
  --border:rgba(99,179,255,.15);--indigo:#6366f1;--emerald:#10b981;
  --rose:#f43f5e;--amber:#f59e0b;--cyan:#06b6d4;--gold:#fbbf24;
  --text:#f0f7ff;--muted:#7b9bbf;
  /* Cores de marca PARA TEXTO. Existem separadas das de marca porque a mesma cor faz dois
     trabalhos diferentes: dourado como fundo de selo funciona nos dois temas, dourado como
     TEXTO some sobre fundo claro. Medido: "+20 XP" na lista de musicas dava 1,54 de contraste
     no modo claro, e sao 52 rotulos assim so naquela tela; "Ranking Global" dava 1,54.
     A tentativa anterior (secao 17 do PENDENCIAS) redefiniu --gold direto e quebrou o selo
     "Nivel 2", que usa dourado de FUNDO - 16 falhas viraram 12 e nasceu uma nova. Separar em
     dois tokens e o que faz a correcao nao ter esse efeito colateral.
     No escuro, cada -txt E a propria cor de marca: o modo escuro fica byte a byte igual, e por
     construcao, nao por sorte. So o bloco do modo claro, abaixo, muda alguma coisa. */
  /* Indigo um tom mais fundo, para quando ele e PREENCHIMENTO com texto branco em cima.
     Medido: branco sobre --indigo (#6366f1) da 4,47 - reprova por 0,03 no minimo de 4,5, e
     reprova nos DOIS temas, porque o preenchimento e escuro em ambos. Nao e problema de modo
     claro, e por isso nao mora no bloco do tema. Sobre #4f46e5 o branco da 6,29.
     Separado de --indigo porque indigo tambem e usado como fundo SEM texto (os pontinhos de
     "digitando" do VOX, por exemplo), e ali nao ha contraste nenhum a corrigir. */
  --indigo-fill:#4f46e5;
  --gold-txt:var(--gold);--amber-txt:var(--amber);--emerald-txt:var(--emerald);
  --cyan-txt:var(--cyan);--indigo-txt:var(--indigo);--rose-txt:var(--rose);
  /* Sobreposicoes e superficies. Existem porque o app criava superficies sutis com
     var(--overlay) e cartoes com rgba(var(--surface-rgb), .7) escritos direto - o que so funciona
     sobre fundo escuro. No claro, branco sobre branco some e o cartao preto continua preto.
     Passando por variavel, o mesmo componente serve aos dois temas sem saber disso.
     --surface-rgb vai em componentes para cada uso manter a propria opacidade. */
  --overlay:rgba(255,255,255,.05);
  --overlay-2:rgba(255,255,255,.08);
  --overlay-3:rgba(255,255,255,.12);
  --surface-rgb:15,20,35;
  --scrim:rgba(5,11,24,.9);
  --shadow:rgba(0,0,0,.5);

  /* Texto e borda para superficies que sao ESCURAS DE PROPOSITO nos dois temas - o painel de
     acerto/erro da licao e o caso atual. Elas nao podem usar var(--text): no modo claro isso
     vira quase-preto sobre quase-preto, que foi exatamente o que o dono viu ao errar uma
     questao ("nao consegui ler as alternativas... a cor nao estava legivel", e depois o print
     do Teacher Tip ilegivel). Definido so no :root e NAO redefinido no bloco claro: o ponto e
     justamente nao acompanhar o tema. */
  --text-on-dark:#f0f7ff;
  --border-on-dark:rgba(255,255,255,.14);
  /* Quanto do fundo da tela esta coberto pela barra do navegador.
     O app usa html,body{overflow:hidden}, e nesse caso o Safari do iPhone mantem a barra de
     ferramentas SEMPRE visivel - entao 100vh fica maior que a area de fato visivel, e um
     elemento em position:fixed;bottom:0 vai parar ATRAS da barra do navegador. Foi o que o
     dono viu: os icones das abas apareciam e os NOMES sumiam, cortados na borda de baixo.
     100dvh e a altura dinamica, que ja desconta a barra. A diferenca entre as duas E a altura
     da barra - zero quando nao ha barra (app instalado na tela inicial, desktop), e o tanto
     certo quando ha. Nao precisa detectar navegador nem sistema: a propria conta se ajusta.
     Onde dvh nao existir, o calc e invalido e ignorado, voltando ao comportamento de hoje. */
  --chrome-bottom:calc(100vh - 100dvh);

  /* ===== VIDRO (glassmorphism) =====
     Pedido do dono para o modo claro, e a queixa de contraste da auditoria e o MESMO problema:
     os paineis ja tinham backdrop-filter, mas o fundo deles era cor escura escrita a mao
     (rgba(2,6,23,.85) e parentes). Blur sobre fundo fixo escuro nao vira vidro no tema claro -
     vira uma mancha escura com texto escuro em cima.
     Passando por --surface-rgb, o mesmo painel serve aos dois temas: escuro fica fumê, claro
     fica leitoso. A borda e o detalhe que faz parecer vidro de verdade - um fio mais claro que
     a superficie, imitando a quina iluminada de uma placa. */
  --glass:rgba(var(--surface-rgb),.82);
  --glass-soft:rgba(var(--surface-rgb),.62);
  --glass-edge:rgba(255,255,255,.10);
  --glass-blur:blur(14px) saturate(140%);

  /* ===== CAMADAS DE EMPILHAMENTO (z-index) =====
     Isto existe porque nao ter uma fonte unica da verdade aqui ja custou dois defeitos.

     O portao de visto ficou INVISIVEL em producao: era um modal em z-index 400, e o globo
     que ele precisava cobrir esta em 9999. Ninguem errou por descuido - errou porque nao
     havia onde consultar. E o cartao de avaliacao pos-licao (900) so nao aparece atras da
     tela de fim de licao (999999) porque resultScreen.js esconde uma antes de mostrar o
     outro; a ordem correta na tela depende hoje da ordem das chamadas, o que quebra assim
     que alguem reorganizar aquela funcao.

     A regra, entao: NUNCA escreva um numero de nivel de pagina. Escolha um nome desta lista.
     Se nenhum servir, acrescente um nome aqui - onde da para ver a ordem inteira de uma vez -
     em vez de inventar um numero no lugar de uso. Empilhamento LOCAL dentro de um componente
     (0 a 20, tipo texto sobre a propria imagem) continua numero mesmo: aquilo nao e ordem
     global e nomear so faria ruido.

     Quase tudo aqui manteve o valor que ja tinha - a migracao foi renomear, nao reordenar.
     As quatro excecoes sao correcoes deliberadas, todas do mesmo defeito: overlay de tela
     cheia parado numa faixa baixa demais para o que precisa cobrir.
       #modal-tinder-feedback  900 -> --z-modal    (dependia da ordem das chamadas)
       #modal-cast             400 -> --z-modal    (o 400 do portao de visto, de novo)
       #modal-feedback         400 -> --z-modal    (idem)
       #toast                  300 -> --z-toast    (invisivel atras do modal de pagamento)
     E #achievement-toast subiu de 10000 para --z-toast pelo mesmo motivo. Os dois avisos tem
     pointer-events:none, entao estarem no topo nao bloqueia clique de ninguem. */

  --z-screen-under:50;   /* ranking e historico, atras das telas principais */
  --z-widget:99;         /* botao flutuante do VOX */
  --z-screen:100;        /* as telas do app (.screen) */
  --z-hud-menu:120;      /* menu "mais" do HUD, sobre as telas */
  --z-panel:200;         /* confete e o painel do VOX, sobre o mapa */
  --z-minigame:250;      /* overlay do minijogo */
  --z-card:300;          /* prox-card do NPC, feedback do minijogo */
  --z-loading:400;       /* "preparando sua missao", sobre o cartao que o disparou */
  --z-landmark:450;      /* modal de ponto turistico */
  --z-highlight:500;     /* faixa de combo, escolha de voz */
  --z-modal:9000;        /* passaporte, conquistas, avaliacao pos-licao, e padrao de .ov-modal */
  --z-banner:9500;       /* faixa da ofensiva, sobre os modais comuns */
  --z-fullscreen:9600;   /* foto de ponto turistico em tela cheia */
  --z-takeover:9999;     /* toma a tela toda: globo, camera, chat de IA, gerador de cidade */
  --z-gate:10050;        /* portoes que bloqueiam: visto / oferta Pro */
  --z-ad:10450;          /* video patrocinado - acima do portao que o abriu */
  --z-ad-skip:10451;     /* o botao de fechar, um acima do proprio video */
  --z-payment:10460;     /* PIX: acima do anuncio, senao o anuncio cobre o pagamento */
  --z-admin:10500;       /* central de comando do dono */
  --z-broadcast:10600;   /* recado global do dono, acima ate da central */
  --z-toast:10700;       /* AVISOS EFEMEROS ACIMA DE TUDO QUE E CLICAVEL. Estavam em 300 (#toast)
                            e 10000 (#achievement-toast), os dois ABAIXO do modal de pagamento
                            (10460): quem tocava em "copiar codigo Pix" recebia a confirmacao
                            atras do proprio modal e nao via nada. Os dois tem pointer-events:none,
                            entao no topo nao bloqueiam clique de ninguem. */
  --z-debug:99999;       /* overlay de depuracao e xp flutuante */
  --z-result:999999;     /* tela de fim de licao, acima de tudo */
}

/* MODO CLARO - pedido por uma testadora ("algumas pessoas nao gostam do modo escuro, mas
   mantenha o escuro como padrao"). As duas metades importam: sem o atributo data-theme nada
   aqui se aplica, entao quem nao tocar no botao ve exatamente o app de antes.
   Os acentos de marca (indigo, esmeralda, ciano, ambar) NAO mudam de proposito - sao cores
   saturadas que funcionam sobre os dois fundos, e troca-las descaracterizaria o app. */
html[data-theme="light"]{
  --bg:#f4f6fb;--bg2:#e9eef7;--card:rgba(15,23,42,.04);
  --border:rgba(15,23,42,.14);
  --text:#0f172a;--muted:#5a6b85;
  /* As variantes escuras da MESMA familia de cor. Escolhidas por medicao sobre o fundo claro
     (#f4f6fb), com folga em vez de raspando no minimo: os -700 de ambar e dourado passavam por
     0,05, e margem apertada volta a falhar assim que um cartao muda de tom. */
  --gold-txt:#854d0e;      /* 6,34 */
  --amber-txt:#92400e;     /* 6,56 */
  --emerald-txt:#047857;   /* 5,07 */
  --cyan-txt:#0e7490;      /* 4,96 */
  --indigo-txt:#4338ca;    /* 7,31 */
  --rose-txt:#be123c;      /* 5,81 */
  --overlay:rgba(15,23,42,.05);
  --overlay-2:rgba(15,23,42,.08);
  --overlay-3:rgba(15,23,42,.12);
  --surface-rgb:255,255,255;
  --scrim:rgba(15,23,42,.55);
  --shadow:rgba(15,23,42,.18);
  /* No claro o vidro pede MAIS transparencia, nao menos: a graca e ver o que passa por tras.
     E a quina iluminada vira quase branca, que e o que da o brilho de borda. */
  --glass:rgba(var(--surface-rgb),.70);
  --glass-soft:rgba(var(--surface-rgb),.52);
  --glass-edge:rgba(255,255,255,.85);
  color-scheme:light;
}
html,body{width:100%;height:100%;overflow:hidden}
body{font-family:'Outfit',sans-serif;background:var(--bg);color:var(--text)}
button{font-family:'Outfit',sans-serif;cursor:pointer;border:none;outline:none;transition:all .18s ease}
button:active{transform:scale(.96)}
.screen{display:none;position:fixed;inset:0;flex-direction:column;overflow-y:auto;overflow-x:hidden;z-index:var(--z-screen)}
.screen.show{display:flex}
.screen::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url('../img/logo.jpg');
  background-repeat: no-repeat;
  background-position: center center;
  background-size: min(80vw, 400px);
  opacity: 0.04;
  pointer-events: none;
  z-index: -1;
}
/* === SETUP === */
#screen-setup{align-items:center;justify-content:center;padding:40px 24px;gap:18px;text-align:center;background:radial-gradient(ellipse at 50% 20%,rgba(99,102,241,.3) 0%,var(--bg) 70%)}
.upload-zone{width:180px;height:180px;border:3px dashed var(--indigo);border-radius:50%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;cursor:pointer;position:relative;overflow:hidden;transition:all .25s;background:rgba(99,102,241,.08)}
.upload-zone:hover{border-color:var(--cyan-txt);background:rgba(6,182,212,.1);transform:scale(1.03)}
.upload-zone canvas{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:50%}
/* === A APRESENTACAO DA TELA INICIAL ===
   Texto de verdade na pagina que o Google indexa, e a unica coisa que um estranho tem para
   decidir se comeca. Ate a v167 esta tela dizia so "Ah, ola. Outro humano que quer aprender
   ingles" e mostrava um botao - nada sobre o que e o produto, o que tem dentro ou quanto custa.
   Etiqueta de busca faz o site poder aparecer; TEXTO e o que faz ele aparecer para alguem.

   Mora DEPOIS do botao de proposito. A primeira tela continua sendo exatamente o que era -
   logo, mascote, botao - e isto so existe para quem rolar. Quem ja decidiu comecar nao precisa
   ler nada disto, e o funil de entrada, que ja foi encurtado uma vez, nao ganha um passo novo. */
.ini-rolar{display:flex;flex-direction:column;align-items:center;gap:2px;margin-top:22px;
  font-size:.72rem;color:var(--muted);opacity:.75;letter-spacing:.5px}
.ini-rolar span:last-child{font-size:1rem;line-height:1;animation:iniDesce 1.8s ease-in-out infinite}
@keyframes iniDesce{0%,100%{transform:translateY(0)}50%{transform:translateY(4px)}}
@media (prefers-reduced-motion: reduce){.ini-rolar span:last-child{animation:none}}

.ini{position:relative;z-index:3;width:100%;max-width:680px;margin:0 auto;
  padding:26px 22px 64px;box-sizing:border-box;text-align:center}
/* Titulos centralizados, texto corrido justificado - foi o pedido, e as duas palavras juntas
   so fazem sentido assim: centralizar paragrafo longo deixa as duas margens serrilhadas e
   cansa de ler. `hyphens:auto` nao e detalhe: justificar sem hifenizacao abre rios brancos no
   meio da linha, e no celular, onde a coluna e estreita, fica pior que nao justificar. O
   `lang="pt-BR"` no <html> e o que ensina o navegador a hifenizar em portugues. */
.ini h2{font-size:1.25rem;font-weight:800;color:var(--text);margin:34px 0 10px;line-height:1.25;
  text-wrap:balance;text-align:center}
.ini h2:first-of-type{margin-top:0}
.ini p{font-size:.95rem;line-height:1.65;color:var(--muted);margin:0 0 12px;
  text-align:justify;hyphens:auto;-webkit-hyphens:auto}
/* O fundo estrelado agora atravessa esta secao (o canvas virou position:fixed), entao os
   cartoes precisam de fundo proprio opaco - senao uma estrela aparece no meio do texto. Os
   cartoes ja tinham; os blocos soltos e que nao. */
.ini-passos li{text-align:left}
.ini-passos span{text-align:justify;hyphens:auto;-webkit-hyphens:auto}
.ini-perguntas summary{text-align:left}
.ini-perguntas p{text-align:justify;hyphens:auto;-webkit-hyphens:auto}
.ini-plano p{text-align:justify;hyphens:auto;-webkit-hyphens:auto}

.ini strong{color:var(--text)}
/* Duas camadas pelo mesmo motivo do cartao do nivelamento: --card e um branco a 6%, e sozinho
   deixa a marca d'agua de .screen::before aparecer por dentro. */
.ini-cartao{background-color:var(--bg);background-image:linear-gradient(var(--card),var(--card));
  border:1px solid var(--border);border-radius:16px;padding:16px 18px}
.ini-passos{display:flex;flex-direction:column;gap:12px;margin:0;padding:0;list-style:none;counter-reset:ini}
/* O numero ocupa a coluna estreita e as DUAS linhas; o titulo e o texto ficam empilhados na
   coluna larga. Sem o grid-column explicito, `b` e `span` entram como itens separados e o
   texto cai na coluna de 32px - uma palavra por linha, que foi como saiu na primeira medicao. */
.ini-passos li{counter-increment:ini;display:grid;grid-template-columns:32px 1fr;
  column-gap:12px;row-gap:2px;align-items:start}
.ini-passos li::before{content:counter(ini);grid-column:1;grid-row:1 / span 2;
  display:flex;align-items:center;justify-content:center;
  width:32px;height:32px;border-radius:50%;background:var(--indigo-fill);color:#fff;
  font-weight:800;font-size:.92rem}
.ini-passos b{grid-column:2;grid-row:1;color:var(--text);font-size:.98rem;line-height:1.35}
.ini-passos span{grid-column:2;grid-row:2;font-size:.9rem;line-height:1.55;color:var(--muted)}
.ini-numeros{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-bottom:14px}
.ini-numeros div:last-child{grid-column:1 / -1}
.ini-numeros div{background-color:var(--bg);background-image:linear-gradient(var(--card),var(--card));
  border:1px solid var(--border);border-radius:14px;padding:14px 12px;text-align:center}
.ini-numeros b{display:block;font-size:1.5rem;font-weight:900;color:var(--cyan-txt);
  font-variant-numeric:tabular-nums;line-height:1.1}
.ini-numeros span{display:block;font-size:.76rem;color:var(--muted);margin-top:3px;line-height:1.35}
.ini-planos{display:flex;flex-direction:column;gap:12px}
.ini-plano{background-color:var(--bg);background-image:linear-gradient(var(--card),var(--card));
  border:1px solid var(--border);border-radius:16px;padding:16px 18px}
.ini-plano.destaque{border-color:var(--indigo-fill)}
.ini-plano h3{margin:0 0 2px;font-size:1rem;font-weight:800;color:var(--text)}
.ini-plano .ini-preco{font-size:1.35rem;font-weight:900;color:var(--emerald-txt);margin-bottom:8px;
  font-variant-numeric:tabular-nums}
.ini-plano.destaque .ini-preco{color:var(--indigo-txt)}
.ini-plano p{margin:0;font-size:.9rem}
.ini-nota{font-size:.82rem;line-height:1.55;color:var(--muted);margin-top:12px;text-align:center}
.ini-perguntas{display:flex;flex-direction:column;gap:10px}
.ini-perguntas details{background-color:var(--bg);background-image:linear-gradient(var(--card),var(--card));
  border:1px solid var(--border);border-radius:14px;padding:12px 16px}
.ini-perguntas summary{cursor:pointer;font-weight:700;color:var(--text);font-size:.94rem;
  list-style:none;display:flex;justify-content:space-between;align-items:center;gap:12px}
.ini-perguntas summary::-webkit-details-marker{display:none}
.ini-perguntas summary::after{content:'+';color:var(--cyan-txt);font-weight:800;font-size:1.15rem;
  line-height:1;flex-shrink:0}
.ini-perguntas details[open] summary::after{content:'\2212'}
.ini-perguntas p{margin:10px 0 0;font-size:.9rem}
.ini-fim{margin-top:34px;text-align:center}
/* O rodape fecha a pagina. Discreto de proposito: ele existe para estar la, nao para ser lido.
   A linha em cima separa sem pesar, e o `text-align:center` precisa ser explicito porque os
   paragrafos desta secao sao justificados. */
.ini-rodape{margin-top:40px;padding-top:18px;border-top:1px solid var(--border);
  text-align:center;font-size:.75rem;color:var(--muted);opacity:.8;letter-spacing:.3px}
.ini-rodape a{color:inherit;text-decoration:underline;text-underline-offset:3px}
.ini-fim .btn-glow{width:100%;font-size:1.05rem;padding:16px}
/* No computador a coluna abre e os numeros deitam numa linha so. O celular fica como esta. */
@media (min-width: 700px){
  .ini{padding:34px 28px 80px}
  .ini h2{font-size:1.5rem;margin-top:44px}
  .ini p{font-size:1rem}
  .ini-numeros{grid-template-columns:repeat(5,1fr)}
  .ini-numeros div:last-child{grid-column:auto}
  .ini-planos{flex-direction:row}
  .ini-plano{flex:1}
  .ini-fim .btn-glow{max-width:340px}
}

/* === TESTE DE NIVELAMENTO ===
   A tela ficava numa coluna de 270px encostada no alto de uma janela de 1600x900, com o resto
   vazio. Duas causas somadas, e nenhuma delas era falta de max-width:

   1. `margin:0 auto` num filho de flex-column DESLIGA o esticamento: o item passa a ter a
      largura do proprio conteudo, e o max-width:480px que estava la nunca chegava a valer
      porque o conteudo nunca chegava aos 480. width:100% e o que devolve a largura.
   2. A caixa nascia colada no topo. `margin:auto` centraliza nos dois eixos - e centraliza de
      um jeito que nao corta: quando o conteudo e mais alto que a janela as margens viram zero
      sozinhas e a rolagem continua alcancando o inicio, que e o que justify-content:center
      estragaria.

   O tamanho do texto vem de `em` daqui, e nao de `rem` do documento, para que uma unica
   mudanca de font-size no desktop leve a tela inteira junto - fonte, respiro e botoes.
   Primeiro contato de quem chega pelo computador: "MUITO PEQUENA ESSA TELA. PODEMOS PERDER
   CLIENTES AQUI". */
#screen-diagnostic .diag-caixa{width:100%;max-width:480px;margin:auto;padding:20px;box-sizing:border-box;font-size:16px}
#screen-diagnostic .diag-topo{text-align:center;margin-bottom:1.25em}
#screen-diagnostic .diag-logo{height:2.25em;width:auto}
#screen-diagnostic .diag-titulo{font-size:1.1em;font-weight:800;color:var(--cyan-txt);margin-top:.5em}
#screen-diagnostic .diag-sub{font-size:.82em;color:var(--muted)}
/* 760px pega tablet deitado e computador, e deixa o celular exatamente como estava - inclusive
   o celular grande em pe, que continua com a tela desenhada para ele. */
@media (min-width: 760px){
  /* Duas camadas de proposito: --card e quase transparente (rgba branco a 6%), e sozinho
     deixava a marca d'agua que .screen::before desenha atras aparecer POR DENTRO do cartao.
     A cor de fundo opaca corta a marca d'agua, e o degrade de uma cor so por cima devolve o
     tom do cartao. Os dois valores viram do tema, entao o claro continua certo tambem. */
  #screen-diagnostic .diag-caixa{max-width:640px;padding:32px 36px;font-size:19px;
    background-color:var(--bg);background-image:linear-gradient(var(--card),var(--card));
    border:1px solid var(--border);border-radius:20px;
    box-shadow:0 24px 60px rgba(0,0,0,.35)}
  /* No tema claro o cartao e a pagina tem quase a mesma cor, entao o que separa os dois e a
     borda e a sombra - uma sombra preta a 35% viraria uma mancha suja sobre fundo claro. */
  html[data-theme="light"] #screen-diagnostic .diag-caixa{box-shadow:0 18px 44px rgba(15,23,42,.12)}
  #screen-diagnostic .diag-logo{height:3em}
  #screen-diagnostic .diag-titulo{font-size:1.5em}
  #screen-diagnostic .diag-sub{font-size:.95em}
}
/* === SPLASH === */
#screen-splash{align-items:stretch;justify-content:flex-start;overflow-y:auto;overflow-x:hidden}
#splash-canvas{position:absolute;inset:0;z-index:0}
.splash-content{position:relative;z-index:2;width:100%;display:flex;flex-direction:column;align-items:center;gap:12px;padding:0 24px 40px}
.splash-bubble{background:#fff;border:3px solid #1a1a2e;border-radius:16px 16px 16px 4px;padding:12px 16px;font-family:'Bangers',cursive;font-size:1.05rem;color:#111;letter-spacing:.8px;max-width:240px;box-shadow:4px 4px 0 #1a1a2e;margin-bottom:8px;line-height:1.35;animation:bubblePop .4s ease}
@keyframes bubblePop{from{transform:scale(.8);opacity:0}to{transform:scale(1);opacity:1}}
@keyframes titleGlow{from{filter:drop-shadow(0 0 8px rgba(99,102,241,.5))}to{filter:drop-shadow(0 0 20px rgba(6,182,212,.7))}}
.btn-primary{width:100%;padding:16px 24px;border-radius:16px;background:linear-gradient(135deg,#6366f1,#a855f7);color:#ffffff;font-family:Outfit,sans-serif;font-weight:800;font-size:1.1rem;border:none;cursor:pointer;box-shadow:0 4px 20px rgba(99,102,241,0.4);transition:transform 0.2s,box-shadow 0.2s;position:relative;z-index:10;}
.btn-primary:active{transform:scale(0.97);}
.btn-glow{background:linear-gradient(135deg,#6366f1,#7c3aed);color:#fff;font-size:1.1rem;font-weight:800;padding:16px 28px;border-radius:18px;box-shadow:0 0 28px rgba(99,102,241,.5),0 4px 20px rgba(0,0,0,.3);width:100%;display:block;letter-spacing:.5px}
.btn-glow:hover{box-shadow:0 0 40px rgba(99,102,241,.7),0 4px 20px rgba(0,0,0,.3);transform:translateY(-2px)}
/* Secondary action (skip/retry) - was background:rgba(255,255,255,.1) inline at every call
   site, which is nearly invisible against this app's near-black background (--bg:#050b18) -
   reported live as "not eye catching" for the audio-skip button, and the exact same style was
   copy-pasted onto the lesson-retry button too. Real border + a visible tinted fill instead of
   a near-transparent one, still clearly quieter than the primary gradient/glow so it doesn't
   compete with the main action next to it. */
.btn-glow.btn-secondary{background:rgba(123,155,191,.16);box-shadow:0 2px 12px rgba(0,0,0,.3);border:2px solid rgba(123,155,191,.55)}
.btn-glow.btn-secondary:hover{background:rgba(123,155,191,.28);border-color:var(--muted);box-shadow:0 2px 12px rgba(0,0,0,.3);transform:translateY(-2px)}
/* .btn-glow define color:#fff porque o fundo dele e um gradiente indigo escuro. O .btn-secondary
   TROCA esse fundo por um cinza translucido e mantem o texto branco - no escuro aquele cinza
   pousa sobre fundo escuro e funciona; no claro pousa sobre fundo claro e vira branco sobre
   branco. Medido no Perfil: 1,18. Branco sobre claro nunca e escolha de estilo, e defeito.
   Aqui o texto passa a acompanhar o tema, como o resto do app. */
html[data-theme="light"] .btn-glow.btn-secondary{color:var(--text)}
.btn-soft{background:var(--overlay-2);border:1px solid var(--border);color:var(--text);font-size:1rem;font-weight:600;padding:13px 22px;border-radius:16px;width:100%;backdrop-filter:blur(8px)}
.btn-soft:hover{background:rgba(255,255,255,.14);border-color:rgba(99,179,255,.35)}
.btn-ghost{background:transparent;color:var(--muted);font-size:.92rem;padding:10px;width:100%}
.btn-icon{background:var(--overlay-2);border:1px solid var(--border);color:var(--text);border-radius:12px;padding:10px 16px;font-size:1.05rem;backdrop-filter:blur(8px)}
/* === INTERVIEW === */
#screen-interview{background:linear-gradient(180deg,#0a0f20 0%,#050b18 100%)}
/* Was missing entirely - every other screen sets its own background since .screen
   itself doesn't, so without this the game canvas/HUD (never actually hidden,
   just relied upon being covered) showed through behind the taste-demo content. */
#screen-taste-demo{background:linear-gradient(180deg,#0a0f20 0%,#050b18 100%)}
#screen-reveal{background:linear-gradient(180deg,#0a0f20 0%,#050b18 100%)}

/* PASSPORT */
.passport-seal-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(100px,1fr));gap:10px}
.passport-seal{background:rgba(245,158,11,0.08);border:1px solid rgba(245,158,11,0.35);border-radius:16px;padding:14px 8px;display:flex;flex-direction:column;align-items:center;gap:4px;text-align:center}
.passport-seal-icon{font-size:2rem}
.passport-seal-name{font-weight:800;font-size:.8rem;color:var(--gold-txt)}
.passport-seal-label{font-size:.65rem;color:var(--muted)}
.passport-empty{font-size:.85rem;color:var(--muted);text-align:center;padding:16px;background:rgba(255,255,255,0.03);border-radius:14px}
.passport-page{margin-bottom:16px;background:rgba(255,255,255,0.03);border:1px solid var(--border);border-radius:16px;padding:12px}
.passport-page-title{font-weight:800;font-size:.88rem;margin-bottom:10px;display:flex;align-items:center;gap:6px}
.passport-page-count{margin-left:auto;font-size:.72rem;color:var(--muted);font-weight:700}
.passport-stamp-row{display:grid;grid-template-columns:repeat(auto-fill,minmax(76px,1fr));gap:8px}
.passport-stamp{display:flex;flex-direction:column;align-items:center;gap:3px;text-align:center;opacity:0.4;filter:grayscale(1)}
.passport-stamp.stamped{opacity:1;filter:none}
.passport-stamp-icon{font-size:1.3rem}
.passport-stamp-name{font-size:.62rem;color:var(--muted);line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:76px}

/* GAME JUICE */
.combo-banner{position:absolute;top:18%;left:50%;transform:translateX(-50%);z-index:var(--z-highlight);background:linear-gradient(135deg,#f59e0b,#ef4444);color:#fff;font-family:Bangers,cursive;font-size:1.6rem;letter-spacing:1px;padding:10px 22px;border-radius:16px;box-shadow:0 8px 24px rgba(245,158,11,0.5);display:flex;align-items:center;gap:8px;animation:comboPop .35s ease, comboFade .3s ease 1.3s forwards;pointer-events:none}
.combo-emoji{font-size:1.4rem}
@keyframes comboPop{0%{transform:translateX(-50%) scale(0.4);opacity:0}60%{transform:translateX(-50%) scale(1.08);opacity:1}100%{transform:translateX(-50%) scale(1)}}
@keyframes comboFade{to{opacity:0;transform:translateX(-50%) translateY(-10px)}}
@keyframes gjShake{0%,100%{transform:translateX(0)}20%{transform:translateX(-6px)}40%{transform:translateX(6px)}60%{transform:translateX(-4px)}80%{transform:translateX(4px)}}
.gj-shake{animation:gjShake .45s ease}
@keyframes gjBounce{0%,100%{transform:scale(1)}30%{transform:scale(1.25) rotate(-4deg)}60%{transform:scale(1.1) rotate(3deg)}}
.gj-bounce{animation:gjBounce .5s ease}
@keyframes gjShakeSm{0%,100%{transform:translateX(0) rotate(0)}25%{transform:translateX(-3px) rotate(-6deg)}75%{transform:translateX(3px) rotate(6deg)}}
.gj-shake-sm{animation:gjShakeSm .5s ease}

/* STREAK ENGINE */
.streak-reminder-banner{position:fixed;bottom:16px;left:50%;transform:translateX(-50%);z-index:var(--z-banner);background:linear-gradient(135deg,#1e293b,#0f172a);border:1px solid rgba(249,115,22,0.4);color:#fff;padding:12px 14px;border-radius:14px;box-shadow:0 8px 24px rgba(0,0,0,0.4);display:flex;align-items:center;gap:10px;font-size:.85rem;max-width:92vw;animation:comboPop .3s ease}
.streak-reminder-banner button{background:rgba(255,255,255,0.1);border:none;color:#fff;width:26px;height:26px;border-radius:50%;cursor:pointer;flex-shrink:0;font-size:.75rem}

/* KARAOKE / MUSIC */
.kar-player-card{display:block;width:100%;min-height:220px;margin-top:14px;border-radius:16px;overflow:hidden;background:#000;box-shadow:0 4px 20px rgba(0,0,0,0.35)}
.kar-player-card iframe{display:block;border-radius:16px}
.kar-mode-toggle{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}
.kar-mode-btn{flex:1 1 130px;background:var(--overlay);border:1px solid var(--border);color:var(--muted);padding:10px 12px;border-radius:12px;font-weight:700;font-size:.85rem;cursor:pointer;transition:all .2s}
.kar-mode-btn.active{background:linear-gradient(135deg,#06b6d4,#6366f1);border-color:transparent;color:#fff;box-shadow:0 0 14px rgba(99,102,241,.4)}
.kar-progress-summary{margin-top:8px;font-size:.75rem;color:var(--muted);font-weight:700}
.kar-progress-summary .mastered-chip{background:rgba(245,158,11,.18);color:var(--gold-txt);border:1px solid rgba(245,158,11,.4);border-radius:99px;padding:3px 10px;font-weight:800}
.kar-line{background:rgba(255,255,255,.04);border:2px solid transparent;border-radius:14px;padding:14px;margin-bottom:8px}
.kar-line-done{border-color:rgba(16,185,129,.35) !important;background:rgba(16,185,129,.06) !important}
.kar-line-num{font-size:.7rem;color:rgba(99,102,241,.6);font-weight:700;margin-right:8px}
.kar-line-num.kar-line-check{color:#10b981}
.kar-line-en{font-size:1.1rem;font-weight:700;color:var(--text);line-height:1.5;margin-bottom:4px;display:inline}
.kar-line-pt{color:var(--muted);font-size:.82rem;font-style:italic;margin-top:4px}
.kar-word-tok{display:inline-block}
.kar-word-hit{color:#6ee7b7;font-weight:700}
.kar-word-miss{color:var(--muted)}
.cloze-blank{display:inline-block;background:rgba(245,158,11,.18);border:1px dashed rgba(245,158,11,.6);color:var(--gold-txt);border-radius:8px;padding:0 10px;font-weight:800;margin:0 2px}
.cloze-opts{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.cloze-opt-btn,.match-opt-btn{background:rgba(99,102,241,.15);border:1px solid rgba(99,102,241,.35);color:var(--text);padding:8px 16px;border-radius:10px;font-size:.88rem;font-weight:700;cursor:pointer;transition:all .15s;min-height:40px}
.cloze-opt-btn:disabled,.match-opt-btn:disabled{cursor:default;opacity:.6}
.cloze-opt-btn.cloze-correct,.match-opt-btn.cloze-correct{background:rgba(16,185,129,.25);border-color:#10b981;color:#6ee7b7;opacity:1}
.cloze-opt-btn.cloze-wrong,.match-opt-btn.cloze-wrong{background:rgba(244,63,94,.2);border-color:var(--rose-txt);color:#fda4af;opacity:1}
.kar-reorder-run{background:rgba(255,255,255,.04);border:2px solid transparent;border-radius:14px;padding:14px;margin-bottom:10px}
.kar-reorder-bank,.kar-reorder-placed{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px;min-height:44px}
.kar-reorder-placed{padding:8px;border:1px dashed var(--border);border-radius:10px}
.kar-reorder-card{background:rgba(99,102,241,.15);border:1px solid rgba(99,102,241,.35);color:var(--text);padding:8px 12px;border-radius:10px;font-size:.85rem;cursor:pointer;transition:all .15s;max-width:100%}
.kar-reorder-card.placed{background:rgba(16,185,129,.15);border-color:rgba(16,185,129,.4);cursor:pointer}
.kar-shake{animation:karShake .4s}
@keyframes karShake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}

/* SONG LIBRARY FILTERS */
.song-filter-row{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.song-filter-chip{background:var(--overlay);border:1px solid var(--border);color:var(--muted);padding:8px 14px;border-radius:99px;font-size:.82rem;font-weight:700;cursor:pointer;transition:all .15s}
.song-filter-chip.active{background:linear-gradient(135deg,#06b6d4,#6366f1);border-color:transparent;color:#fff}
.song-badge{background:rgba(255,255,255,.06);border:1px solid var(--border);color:var(--muted);font-size:.68rem;font-weight:700;padding:2px 9px;border-radius:99px}
.int-topbar{display:flex;align-items:center;gap:12px;padding:16px 20px;border-bottom:1px solid var(--border);flex-shrink:0}
.int-prog-bg{flex:1;height:8px;background:var(--card);border-radius:99px;overflow:hidden}
.int-prog-fill{height:100%;background:linear-gradient(90deg,var(--indigo),var(--cyan));border-radius:99px;transition:width .45s cubic-bezier(.4,0,.2,1)}
.int-prof-bar{flex-shrink:0;padding:18px 20px 0;display:flex;gap:12px;align-items:flex-end}
.int-av{width:64px;height:64px;border-radius:50%;overflow:hidden;flex-shrink:0;border:3px solid var(--indigo);background:var(--bg2)}
.int-av img{width:100%;height:100%;object-fit:cover}
.int-bubble{background:#fff;border:2px solid #333;border-radius:14px 14px 14px 4px;padding:11px 15px;font-family:'Bangers',cursive;font-size:.95rem;color:#222;max-width:260px;box-shadow:2px 2px 0 #333;line-height:1.35}
.int-content{flex:1;padding:20px;display:flex;flex-direction:column;gap:14px;overflow-y:auto}
.int-q{font-size:1.6rem;font-weight:800;line-height:1.2}
.int-sub{color:var(--muted);font-size:.92rem}
.int-input{width:100%;background:rgba(255,255,255,.06);border:2px solid var(--border);border-radius:14px;padding:16px 18px;font-family:'Outfit',sans-serif;font-size:1.1rem;color:var(--text);outline:none;transition:border-color .2s}
.int-input:focus{border-color:var(--indigo-txt);box-shadow:0 0 0 3px rgba(99,102,241,.15)}
.int-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
.int-grid3{grid-template-columns:repeat(3,1fr)}
.int-card{background:var(--overlay);border:2px solid var(--border);border-radius:16px;padding:14px 10px;display:flex;flex-direction:column;align-items:center;gap:6px;cursor:pointer;transition:all .18s}
.int-card:hover,.int-card.sel{background:rgba(99,102,241,.18);border-color:var(--indigo-txt);transform:scale(1.03)}
.int-card.sel{box-shadow:0 0 18px rgba(99,102,241,.4)}
.int-card-icon{font-size:1.8rem}
.int-card-lbl{font-size:.82rem;font-weight:700;color:var(--muted);text-align:center}
.int-footer{padding:16px 20px 30px;flex-shrink:0}
/* === WORLD LOAD === */
#screen-world-load{align-items:center;justify-content:center;background:radial-gradient(ellipse at 50% 30%,rgba(99,102,241,.3) 0%,var(--bg) 70%);gap:20px;text-align:center;padding:40px 24px}
.wl-prof{width:100px;height:100px;border-radius:50%;overflow:hidden;border:3px solid var(--indigo);margin:0 auto;display:none;box-shadow:0 0 24px rgba(99,102,241,.4)}
.wl-prof img{width:100%;height:100%;object-fit:cover}
.wl-bar-bg{width:100%;max-width:320px;height:10px;background:rgba(255,255,255,.1);border-radius:99px;overflow:hidden}
.wl-bar-fill{height:100%;width:0%;background:linear-gradient(90deg,var(--indigo),var(--cyan),var(--emerald));border-radius:99px;transition:width .55s cubic-bezier(.4,0,.2,1)}
/* === GAME === */
#game-canvas{display:none;position:fixed;inset:0;z-index:1;background:#1a1a2e}
#game-canvas.show{display:block}
#game-hud{display:none;position:fixed;inset:0;z-index:10;pointer-events:none}
#game-hud.show{display:block}
/* === HUD BAR - Mobile First Responsive === */
.hud-bar{
  display:flex;
  align-items:center;
  flex-wrap:nowrap;
  gap:6px;
  padding:calc(env(safe-area-inset-top,8px) + 6px) 10px 6px 10px;
  background:rgba(var(--surface-rgb), .96);
  backdrop-filter:blur(16px);
  border-bottom:1px solid var(--border);
  box-sizing:border-box;
  width:100%;
}
/* Double XP master switch (PROPRIUS Command Center) - golden aura so the effect stays
   visible on the real HUD long after the admin dashboard itself is closed. */
.hud-bar.double-xp-active{
  border-bottom:1px solid rgba(245,158,11,.6);
  box-shadow:0 2px 22px rgba(245,158,11,.45), inset 0 -2px 12px rgba(245,158,11,.12);
  animation:hudDoubleXpPulse 2.2s ease-in-out infinite;
}
@keyframes hudDoubleXpPulse{
  0%,100%{ box-shadow:0 2px 22px rgba(245,158,11,.35), inset 0 -2px 12px rgba(245,158,11,.1); }
  50%     { box-shadow:0 2px 30px rgba(245,158,11,.6), inset 0 -2px 16px rgba(245,158,11,.2); }
}
/* Everything except the Viajar button (pinned, see .hud-travel-btn) scrolls in here.
   The mask-image fades the right edge to transparent as a "there's more" cue, since
   the scrollbar itself is hidden (scrollbar-width:none / ::-webkit-scrollbar below). */
.hud-scroll{
  display:flex;
  align-items:center;
  flex-wrap:nowrap;
  gap:6px;
  overflow-x:auto;
  scrollbar-width:none;
  flex:1;
  min-width:0;
  -webkit-mask-image:linear-gradient(to right, black calc(100% - 20px), transparent 100%);
  mask-image:linear-gradient(to right, black calc(100% - 20px), transparent 100%);
}
.hud-scroll::-webkit-scrollbar{display:none;}
.hud-travel-btn{flex-shrink:0;}
.hud-profile-group{
  display:flex;
  align-items:center;
  gap:8px;
  flex-shrink:0;
  cursor:pointer;
  pointer-events:auto;
}
.hud-av{
  width:40px;
  height:40px;
  min-width:40px;
  border-radius:50%;
  overflow:hidden;
  border:2px solid var(--indigo);
  flex-shrink:0;
  background:linear-gradient(135deg,var(--indigo),var(--cyan));
  pointer-events:all;
  cursor:pointer;
  transition:transform .2s;
  box-shadow:0 0 10px rgba(99,102,241,.4);
  position:relative;
  display:flex;
  align-items:center;
  justify-content:center;
}
.hud-av:hover{transform:scale(1.08)}
.hud-av img{width:100%;height:100%;object-fit:cover;position:absolute;top:0;left:0}
/* "Farmar Aura" passive-XP halo (js/systems/auraEngine.js) - a progressive ring driven by
   the --aura-pct custom property (0..1, updated every tick) so it visibly builds up rather
   than popping in all at once. Violet/pink on purpose, distinct from the amber Double-XP
   aura on .hud-bar (a different element entirely) so the two read as separate systems. */
.hud-av.aura-charging::after{
  content:'';
  position:absolute;
  inset:-5px;
  border-radius:50%;
  border:2px solid rgba(168,85,247,.9);
  box-shadow:0 0 12px rgba(168,85,247,.7);
  opacity:var(--aura-pct,0);
  pointer-events:none;
}
/* Temporary celebration when the meter fills - JS removes this class again after ~10s, it
   is not a persistent state like .aura-charging or the Double-XP aura. */
.hud-av.aura-burst{ animation:auraBurstBounce 1.2s ease infinite, auraBurstPulse 1.2s ease infinite; }
@keyframes auraBurstBounce{ 0%,100%{transform:scale(1)} 50%{transform:scale(1.12)} }
@keyframes auraBurstPulse{
  0%{box-shadow:0 0 10px rgba(99,102,241,.4)}
  30%{box-shadow:0 0 32px 10px rgba(244,114,182,.9)}
  100%{box-shadow:0 0 10px rgba(99,102,241,.4)}
}
#hud-name{
  font-weight:800;
  font-size:.88rem;
  color:var(--text);
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
  max-width:95px;
}
#hud-city{
  font-size:.70rem;
  color:var(--muted);
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
  max-width:95px;
}
.hud-stat{
  display:flex;
  align-items:center;
  gap:3px;
  font-size:.75rem;
  font-weight:800;
  background:rgba(255,255,255,.07);
  padding:5px 8px;
  border-radius:10px;
  border:1px solid var(--border);
  letter-spacing:.1px;
  white-space:nowrap;
  flex-shrink:0;
}
.hud-btn{
  pointer-events:all;
  background:rgba(99,102,241,.25);
  border:1px solid rgba(99,102,241,.4);
  color:var(--text);
  border-radius:10px;
  padding:6px 10px;
  font-size:.75rem;
  font-weight:700;
  cursor:pointer;
  transition:all .15s;
  white-space:nowrap;
  flex-shrink:0;
  min-height:32px;
}
.hud-btn:hover{background:rgba(99,102,241,.45);transform:translateY(-1px)}

/* ===== HUD DO CELULAR: BARRA DE ABAS =====
   Reclamacao do dono: "o hud no celular ainda esta dificil de entender".
   Medi antes de desenhar: a fileira de status e acoes precisava de 994px num trilho de 445.
   Sete itens ficavam fora da tela, alcancaveis so por rolagem horizontal dentro de uma barra
   fixa - que no toque e praticamente indescobrivel. E o problema nao era falta de rotulo:
   acrescentar palavras aos botoes existentes pioraria, porque falta espaco, nao texto.

   Havia tambem tres confusoes que espaco nenhum resolve:
     - a ofensiva aparecia DUAS vezes na mesma barra ("N dias seguidos" e a pilha 🔥 N)
     - 🏆 significava "nivel" numa pilha e "conquistas" num botao, lado a lado
     - ⭐ 0 e ❤ 3 eram numeros sem substantivo: nao da para descobrir o que sao olhando

   A divisao aqui e por PERGUNTA, nao por tipo de widget. "Como estou indo?" fica em cima
   (identidade + as duas vitalidades que mudam comportamento: vidas e ofensiva) e vira uma
   linha de progresso com as palavras escritas. "O que posso fazer?" desce para abas com nome,
   ao alcance do polegar, no padrao que a pessoa ja sabe usar de qualquer outro app do celular.

   Cinco abas de 20% = exatamente a largura da tela. Nada rola, nada some, e o menu "⋯" deixa
   de existir no celular. Desktop e tablet ficam como estavam - la havia espaco de sobra e a
   mudanca so traria risco sem ganho. */

/* Vitalidades no alto: so o que muda o comportamento de quem joga. */
.hud-vitais{display:none;align-items:center;gap:8px;margin-left:auto;flex-shrink:0}
.hud-vital{display:flex;align-items:center;gap:4px;font-weight:800;font-size:.9rem;white-space:nowrap}
.hud-vital.vidas{color:var(--rose-txt)}
.hud-vital.ofensiva{padding:4px 10px;border-radius:12px;background:rgba(245,158,11,.16);
  border:1px solid rgba(245,158,11,.42);color:var(--gold-txt)}

/* A barra de XP ja existia sem legenda nenhuma. Escrever o nivel e o XP AQUI e o que permite
   remover duas pilhas la de cima - e responde "⭐ 0 e o que?" pelo caminho mais simples que
   existe, que e escrever o substantivo. */
.hud-progresso{display:none;padding:5px 12px 7px;background:rgba(var(--surface-rgb),.96);
  border-bottom:1px solid var(--border)}
.hud-progresso-linha{display:flex;justify-content:space-between;gap:10px;font-size:.68rem;
  color:var(--muted);font-weight:600;margin-bottom:4px}
.hud-progresso-linha b{color:var(--text);font-weight:800}


/* Fileira de atalhos: chips com NOME, nunca icone solto. Toda a reclamacao que originou a
   barra de abas era nao dar para entender os botoes; devolver emoji sem palavra seria desfazer
   o conserto para ganhar alguns pixels. Rola na horizontal como ultima defesa, mas quatro
   chips cabem sem rolagem num aparelho de 375px, que e o caso medido. */
.hud-atalhos{display:none;gap:6px;padding:7px 10px 8px;overflow-x:auto;
  /* #game-hud e pointer-events:none de proposito (o canvas embaixo precisa receber o toque
     e o arrasto), e cada filho religa por conta propria. Eu religuei nas abas e esqueci
     aqui - os chips apareciam e nao clicavam. pointer-events e HERDADO, entao uma linha no
     container ja cobre todos eles. Mesma armadilha que o menu "mais" ja tinha caido antes,
     documentada no comentario de .hud-more-menu. */
  pointer-events:auto;
  background:rgba(var(--surface-rgb),.99);border-bottom:1px solid var(--border);
  scrollbar-width:none;-webkit-overflow-scrolling:touch}
.hud-atalhos::-webkit-scrollbar{display:none}
.hud-atalho{display:flex;align-items:center;gap:5px;flex-shrink:0;
  padding:6px 11px;border-radius:12px;border:1px solid var(--border);
  background:var(--overlay);color:var(--text);
  font-family:'Outfit',sans-serif;font-size:.72rem;font-weight:700;cursor:pointer;white-space:nowrap}
.hud-atalho:active{transform:scale(.95)}
@media(max-width:480px){ .hud-atalhos{display:flex} }
.hud-tabs{display:none;position:fixed;left:0;right:0;bottom:0;z-index:var(--z-screen);
  background:rgba(var(--surface-rgb),.97);backdrop-filter:blur(14px);
  border-top:1px solid var(--border);
  /* PADDING, nao margin. Com margin-bottom a barra INTEIRA subia e sobrava uma faixa de mapa
     embaixo dela - o dono viu isso como "poderiam estar melhor alinhados... sem comer parte
     do mapa". Com padding, o fundo da barra encosta na borda da tela e so o CONTEUDO sobe o
     tanto que a barra do navegador ocupa. Nada de faixa sobrando, e os nomes continuam acima
     da barra do Safari. */
  padding:7px 0 calc(max(10px,env(safe-area-inset-bottom)) + var(--chrome-bottom));
  pointer-events:auto}
.hud-tab{flex:1 1 20%;display:flex;flex-direction:column;align-items:center;gap:2px;
  background:none;border:none;padding:2px 0;color:var(--muted);font-family:'Outfit',sans-serif;
  font-size:.66rem;font-weight:700;cursor:pointer;min-width:0}
.hud-tab .ico{font-size:1.2rem;line-height:1.1}
.hud-tab.ativa{color:var(--cyan-txt)}
.hud-tab:active{transform:scale(.94)}
/* Viajar e o ciclo central do jogo - viajar para outra cidade e o que abre conteudo novo.
   Ganha peso visual de proposito, para nao virar mais um icone igual aos outros. */
.hud-tab.destaque .ico{background:linear-gradient(135deg,var(--cyan),var(--indigo));
  color:#fff;border-radius:14px;padding:4px 14px}
.hud-tab-selo{position:absolute;top:-2px;right:-6px;background:var(--rose);color:#fff;
  font-size:.55rem;font-weight:800;border-radius:8px;padding:1px 5px;line-height:1.3}

@media(max-width:480px){
  .hud-tabs{display:flex}
  .hud-vitais{display:flex}
  .hud-progresso{display:block}
  /* O que subiu para o alto ou desceu para as abas nao precisa mais existir na fileira. */
  .hud-scroll{display:none !important}
  .hud-more-btn{display:none !important}
  .hud-travel-btn{display:none !important}
  #hud-streak-text{display:none}
  .hud-profile-text{min-width:0 !important;flex:1}
  /* Os limites de 75px e 56px la embaixo sao de quando o nome disputava a barra com quatro
     pilhas e nove botoes - naquele aperto, truncar "Marcelo" em "Marc..." era o mal menor.
     As pilhas subiram e os botoes desceram para as abas, entao o aperto acabou e o nome pode
     voltar a ser o nome. !important porque aquelas regras vem depois desta no arquivo; mexer
     na ordem seria mais arriscado que declarar a intencao aqui. */
  #hud-name{font-size:.95rem !important;max-width:none !important}
  #hud-city{font-size:.72rem;max-width:none !important;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* A barra de abas ocupa o rodape, onde estas tres coisas moravam. Todas sobem, em vez de
     sumirem: minimapa e orientacao no mapa, os controles de zoom sao uso constante, e o VOX e
     o atalho de ajuda.
     O VOX em especial eu nao tinha previsto - achei varrendo TODOS os elementos de posicao
     fixa que invadiam a faixa da barra, em vez de so olhar a tela. Ele fica em --z-widget (99)
     contra --z-screen (100) da barra, entao 37px dele desapareciam por tras. Empurrar o
     z-index dele para cima seria pior: um botao boiando sobre a navegacao. */
  #minimap-container{bottom:calc(74px + env(safe-area-inset-bottom) + var(--chrome-bottom)) !important}
  #vox-widget{bottom:calc(74px + env(safe-area-inset-bottom) + var(--chrome-bottom)) !important}
  /* Empilhado ACIMA do VOX, nao ao lado: os dois moram no canto inferior direito, e quando
     subi os dois juntos eles se sobrepuseram - "Centralizar camera" e "Tela cheia" ficaram
     inalcancaveis ao toque. Descobri perguntando ao navegador quem responde no centro de cada
     botao (elementFromPoint), nao olhando o print: a pilha PARECIA certa na imagem.
     74px da barra + 81px do VOX + 10px de folga. */
  .map-controls{bottom:calc(165px + env(safe-area-inset-bottom) + var(--chrome-bottom)) !important}
}

/* Rotulo escrito ao lado do icone, em tela larga. O dono relatou que "fica dificil entender
   para que serve cada botao do hud" - e tem razao: 🎵 🎙 🏆 📘 🏅 sao seis emojis lado a lado
   sem uma palavra, e title= so aparece no hover, que no celular nao existe. (Dois deles eram
   ate o MESMO 📖: Caderno de Erros e Passaporte. O passaporte virou 📘.)
   Sai do mesmo data-rotulo que alimenta o menu "mais", entao continua havendo um lugar so
   onde o nome de cada botao e escrito. So a partir de 900px, onde sobra espaco de verdade -
   no celular a resposta e o menu, que agora lista tudo com nome. */
@media(min-width:900px){
  .hud-btn[data-rotulo]::after{
    content:attr(data-rotulo);
    margin-left:6px;
    font-size:.78rem;
    font-weight:700;
    letter-spacing:.01em;
  }
  /* Estes dois ja escrevem o proprio nome no botao - repetir sairia "Aulas Aulas". */
  .hud-btn[data-rotulo="Aulas"]::after,
  .hud-btn[data-rotulo="Para Mim"]::after,
  .hud-btn[data-rotulo="Caderno de Erros"]::after,
  .hud-btn[data-rotulo="PROPRIUS Pro"]::after{content:none}
}
@media(min-width:600px){
  .hud-bar{gap:10px;padding:12px 18px}
  .hud-av{width:46px;height:46px;min-width:46px}
  #hud-name{font-size:1rem;max-width:140px}
  /* 140px truncated a real geocoded "City, State (checkmark done/total)" string mid-word
     on desktop, where there's no actual space pressure - confirmed live on the deployed
     site. Mobile's tighter 95px/75px breakpoints below are untouched, that space really is
     scarce there. */
  #hud-city{font-size:.78rem;max-width:230px}
  .hud-stat{font-size:.88rem;padding:7px 12px}
  .hud-btn{padding:8px 14px;font-size:.82rem}
}
@media(max-width:480px){
  .hud-btn-hide{display:none !important;}
  .hud-stat-hide{display:none !important;}
  #hud-name{max-width:75px;font-size:.80rem;}
  #hud-city{max-width:75px;font-size:.65rem;}
  /* Duplicates the streak .hud-stat pill right after it in the scroll row - on the
     smallest screens that redundancy is real width the buttons need more. */
  .hud-streak-line{display:none;}
}
/* Reported live from a real phone (this time a completely ordinary 375px iPhone SE/12/13
   mini, not an edge-case narrow device) as "the HUD isn't entirely visible / doesn't show
   all the features". Measured live: at 375px, .hud-scroll needed 358px of content in only
   133px of actual visible space - name/city, every hud-btns-grp button (including one that
   was tucked behind the fade mask along with everything else), and most of the stat pills
   were scrolled off past the right edge with nothing but a subtle fade as a "there's more"
   cue. This tier used to only kick in below 360px, tuned against a 320px test device years
   ago - but 375-428px covers the large majority of phones actually in use (iPhone SE through
   Pro Max, most Android), and ALL of that range was silently falling through to the roomier
   480px tier above, which isn't tight enough on its own. Widened the threshold so this whole
   realistic phone range gets the same treatment the 320px device already had.
   Reclaims width everywhere it's safe to (avatar, name/city, stat-pill padding, Viajar's
   padding) and finally hides Aulas - the single least time-critical item left, since
   booking a lesson can wait a tap longer than seeing your hearts - so the three genuinely
   gameplay-critical pills (XP/streak/hearts) actually fit without needing a scroll at all. */
@media(max-width:430px){
  /* padding-left/right only, NOT the shorthand - the base rule's top padding uses
     env(safe-area-inset-top,8px) for notched phones and must survive this override. */
  .hud-bar{padding-left:6px;padding-right:6px;gap:3px}
  .hud-av{width:32px;height:32px;min-width:32px}
  .hud-profile-group{gap:5px}
  .hud-profile-text{min-width:44px !important}
  #hud-name{max-width:56px;font-size:.72rem}
  #hud-city{max-width:56px;font-size:.6rem}
  .hud-scroll{gap:3px}
  /* Live-measured at 375px (the WhatsApp-reported device) with a fresh, low-numbers save:
     the 4 gameplay-critical pills alone (Nivel/XP/Streak/Vidas) still ran 12px past
     .hud-scroll's own visible width even after the previous pass hid every hud-btns-grp
     button - the comment above promising "fit without needing a scroll at all" wasn't quite
     true yet. Shaved padding here + the gap trims above close that 12px exactly for a
     typical early-game save. A veteran player's wider numbers (5-digit XP, 2-digit streak)
     can still overflow a few px past this - .hud-scroll's overflow-x:auto + fade-mask stays
     as the safety net for that case, this isn't relying on removing scroll capability, only
     on the common case not needing it. */
  .hud-stat{padding:3px 5px;gap:2px;font-size:.7rem}
  .hud-travel-btn{padding:6px 9px !important;font-size:.7rem}
  .hud-btns-grp > .hud-btn:not(.hud-btn-hide){display:none !important;}
  /* O "⋯" nao aparece mais no celular. Ele existia para caber nove itens sem rotulo num
     espaco que nao tinha; com a barra de abas eles ganharam nome e casa (Missoes e Perfil),
     e um menu de tres pontinhos ao lado de cinco abas nomeadas so recriaria a duvida que a
     barra veio resolver. Continua existindo em tablet, onde nao ha abas. */
}
/* "⋯ mais" trigger + dropdown - see the HTML comment above #hud-more-btn for the bug this
   fixes. display:none by default (desktop/tablet show every .hud-btns-grp button individually
   already, this stays out of the way entirely there); the media query above is the ONLY place
   that reveals it, at the exact width .hud-btns-grp's own buttons disappear. */
.hud-more-btn{
  display:none;
  position:relative;
  pointer-events:all;
  background:var(--overlay-2);
  border:1px solid var(--border);
  color:var(--text);
  border-radius:10px;
  width:32px;height:32px;
  min-height:32px;
  align-items:center;justify-content:center;
  font-size:1.1rem;
  font-weight:900;
  cursor:pointer;
  flex-shrink:0;
}
.hud-more-btn:hover{background:rgba(255,255,255,.14)}
#hud-more-dot{
  position:absolute;top:2px;right:2px;
  width:8px;height:8px;border-radius:50%;
  background:var(--rose);
  box-shadow:0 0 4px rgba(0,0,0,.5);
}
.hud-more-menu{
  display:none;
  /* Live bug, phone-tested: opened fine (App.toggleHudMore() correctly toggled .open) but
     NOTHING inside it responded to taps. Root cause confirmed via getComputedStyle, not
     just reading the cascade: #game-hud sets pointer-events:none on itself (deliberately -
     it's a full-viewport overlay and the game canvas underneath still needs to receive
     touch/drag), and .hud-more-btn/.hud-btn/.hud-profile-group/.hud-av all re-enable it on
     themselves individually - but this menu (added later, in a separate pass, for the same
     ≤430px overflow case) never got the same treatment, and pointer-events is an INHERITED
     CSS property, so every .hud-more-item inside it silently inherited :none too. One
     pointer-events:auto here is enough - inheritance then gives every child the same value
     from this element rather than skipping past it to #game-hud, no per-item fix needed. */
  pointer-events:auto;
  position:fixed;
  top:calc(env(safe-area-inset-top,8px) + 52px);
  right:8px;
  z-index:var(--z-hud-menu);
  flex-direction:column;
  gap:2px;
  background:var(--glass);
  backdrop-filter:var(--glass-blur);
  border:1px solid var(--border);
  border-radius:14px;
  padding:6px;
  min-width:200px;
  max-width:calc(100vw - 16px);
  box-shadow:0 12px 32px rgba(0,0,0,.5);
}
.hud-more-menu.open{display:flex}
.hud-more-item{
  position:relative;
  background:none;border:none;
  color:var(--text);
  text-align:left;
  padding:11px 12px;
  border-radius:9px;
  font-size:.88rem;
  font-weight:600;
  cursor:pointer;
  min-height:40px;
}
.hud-more-item:hover,.hud-more-item:active{background:rgba(99,102,241,.18)}
#hud-more-mistake-badge{
  display:inline-block;margin-left:6px;
  background:var(--rose);color:#fff;
  font-size:.68rem;font-weight:800;
  padding:1px 6px;border-radius:99px;
}
.hud-xp-strip{height:4px;background:var(--overlay);pointer-events:none}
.hud-xp-fill{height:100%;background:linear-gradient(90deg,var(--indigo),var(--cyan));border-radius:0 3px 3px 0;transition:width .5s cubic-bezier(.4,0,.2,1)}
.hud-hint{position:fixed;bottom:80px;left:50%;transform:translateX(-50%);background:rgba(0,0,0,.85);backdrop-filter:blur(10px);color:var(--text);padding:10px 20px;border-radius:14px;font-size:.88rem;font-weight:600;pointer-events:none;z-index:20;display:none;border:1px solid var(--border)}
.hud-hint.show{display:block}
/* === MINIGAME === */
#minigame-overlay{display:none;position:fixed;inset:0;z-index:var(--z-minigame);flex-direction:column;background:var(--bg)}
#minigame-overlay.open{display:flex}
.mg-topbar{display:flex;align-items:center;gap:10px;padding:14px 18px;border-bottom:1px solid var(--border);flex-shrink:0;background:rgba(var(--surface-rgb), .95)}
/* flex-shrink:0 e nowrap nao sao zelo: os cinco coracoes sao UM texto dentro de um item
   flexivel, entao quando a linha aperta ele encolhe e o texto QUEBRA. Medido num iPhone de
   375px: .mg-hearts virava 63x164 - cinco coracoes empilhados em coluna - e sozinho jogava a
   barra do topo para 193px de altura, um quarto da tela da licao. */
.mg-hearts{display:flex;gap:4px;font-size:1.55rem;flex-shrink:0;white-space:nowrap}
.mg-xp-pill{background:rgba(251,191,36,.15);border:1px solid rgba(251,191,36,.35);color:var(--gold-txt);padding:5px 12px;border-radius:99px;font-size:.88rem;font-weight:700}
.mg-streak{background:rgba(249,115,22,.15);border:1px solid rgba(249,115,22,.35);color:#fb923c;padding:5px 12px;border-radius:99px;font-size:.88rem;font-weight:700}
/* This row had no narrow-width handling at all before the repeat button (below) - unlike
   .hud-bar, nothing here was ever tuned against a real narrow device. Adding one more
   flex-shrink:0 element was enough to overflow by ~6px at 320px (confirmed live) - .mg-prog-bg
   (flex:1) absorbs most width changes fine, but the two pill badges and the new icon button
   don't shrink at all on their own. Small, targeted tightening rather than leaving this row
   as the next surprise report - same discipline as the .hud-bar fix above. */
/* E A CONTA NAO FECHA EM UMA LINHA SO NO CELULAR, entao ela passa a ser duas. Medido num
   aparelho de 375px: fechar 39 + VOX 34 + repetir 41 + XP 58 + ofensiva 45 = 217px fixos, mais
   5 espacos e o respiro lateral. Sobravam 62px para os coracoes E a barra de progresso
   dividirem - e o resultado foi o pior possivel: os coracoes quebraram em cinco linhas e a
   BARRA DE PROGRESSO FICOU COM ZERO PIXEL DE LARGURA. O aluno perdia a unica indicacao de
   quanto falta para acabar a licao, e nem sabia que ela existia.
   A barra ganha linha propria porque, das duas, ela e a que nao pode sumir - coracao pequeno
   ainda e coracao, barra invisivel nao e barra. */
@media(max-width:430px){
  .mg-topbar{flex-wrap:wrap;row-gap:8px;gap:6px;padding:10px 12px}
  .mg-hearts{font-size:1.1rem;gap:3px}
  .mg-prog-bg{flex:1 0 100%;order:9}   /* linha de baixo, largura inteira */
  .mg-xp-pill,.mg-streak{padding:4px 9px;font-size:.8rem}
}
@media(max-width:360px){
  .mg-topbar{gap:5px;padding:9px 9px}
  .mg-hearts{font-size:1rem}
  .mg-xp-pill,.mg-streak{padding:4px 8px;font-size:.74rem}
}
.mg-prog-bg{flex:1;height:8px;background:rgba(255,255,255,.1);border-radius:99px;overflow:hidden}
.mg-prog-fill{height:100%;background:linear-gradient(90deg,var(--indigo),var(--cyan));border-radius:99px;transition:width .35s}
.mg-comic-panel{width:100%;position:relative;overflow:hidden;flex-shrink:0;min-height:200px}
/* A TIRINHA DENTRO DA MISSAO. O tamanho estava preso em `max-height:clamp(140px,26vh,300px)`,
   escrito quando a tirinha era so uma ilustracao - e reclamado pelo dono em 15/09, com print:
   "sem contar que a tirinha esta muito pequena". No computador dele, 26vh davam 211 pixels no meio
   de uma tela de 1900: um selo. Agora a altura manda no celular (onde a largura e pouca e a pergunta
   precisa aparecer junto) e a largura manda no computador, ate 480px. Continua abrindo inteira ao
   toque, que e onde se leem os baloes. */
.mg-tirinha{max-width:100%;max-height:36vh;object-fit:contain;border-radius:12px;border:2px solid var(--border);box-shadow:0 4px 12px rgba(0,0,0,.4);cursor:zoom-in}
@media (min-width:700px){.mg-tirinha{max-width:min(100%,480px);max-height:min(50vh,480px)}}
/* NO CELULAR, A PRIMEIRA RESPOSTA TEM QUE APARECER SEM ROLAR. Medido em 20/09, com o dado da
   planilha na mao: das 10 desistencias de licao em 7 dias, SETE foram no exercicio 0 - a pessoa
   abria a licao e saia na primeira pergunta. Medido num iPhone SE (375x667), a tela dela era:
   barra 94px + este painel 200px + pergunta + tirinha de 240px = a primeira alternativa comecava
   em 715, quarenta e oito pixels ABAIXO da dobra. Nao havia nada para tocar, e rolar so se
   adivinhasse. Antes da v198 a tirinha era menor e uma alternativa aparecia de raspao; aumentar a
   tirinha (pedido certo do dono) empurrou a ultima que sobrava para fora.
   O painel do topo e cenario: foto da cidade, o professor e a fala. No celular ele encolhe, a
   tirinha encolhe um pouco, e a resposta sobe para dentro da tela. */
.mg-cena{width:100%;height:180px;position:relative;overflow:hidden}
.mg-cena-fala{position:absolute;bottom:20px;left:140px;right:20px;background:rgba(255,255,255,.95);color:#000;padding:12px;border-radius:12px;font-family:'Bangers',cursive;letter-spacing:1px;box-shadow:0 6px 16px rgba(0,0,0,.3);z-index:3;font-size:1.1rem}
.mg-cena-prof{position:absolute;bottom:10px;left:20px;width:100px;height:100px;object-fit:cover;border-radius:50%;border:4px solid #6366f1;box-shadow:0 0 15px rgba(0,0,0,.5);z-index:2}
.mg-cena-lugar{position:absolute;top:10px;left:10px;background:rgba(251,191,36,.95);color:#111;font-family:Bangers,cursive;font-size:.75rem;padding:4px 10px;border-radius:6px;letter-spacing:1px}
@media (max-width:699px){
  .mg-comic-panel{min-height:120px}
  .mg-cena{height:120px}
  .mg-cena-fala{bottom:12px;left:104px;right:12px;padding:8px 10px;font-size:.92rem}
  .mg-cena-prof{bottom:10px;left:12px;width:78px;height:78px;border-width:3px}
  .mg-tirinha{max-height:30vh}
}
.mg-comic-speech{position:absolute;top:10px;right:10px;background:#fff;border:2px solid #222;border-radius:12px 12px 4px 12px;padding:10px 14px;font-family:'Bangers',cursive;font-size:1rem;color:#222;max-width:55%;box-shadow:2px 2px 0 #222;line-height:1.4;z-index:5}
.mg-scroll{flex:1;overflow-y:auto;padding:20px 18px;display:flex;flex-direction:column;gap:0;background:rgba(var(--surface-rgb), .72);backdrop-filter:blur(6px)}
.mg-badge{background:rgba(99,102,241,.2);border:1px solid rgba(99,102,241,.4);color:#a5b4fc;font-size:.82rem;font-weight:700;padding:4px 12px;border-radius:99px;display:inline-block}
.mg-q{font-size:1.45rem;font-weight:800;margin:12px 0 18px;line-height:1.35;text-shadow:0 2px 4px rgba(0,0,0,0.8), 0 0 15px rgba(0,0,0,1)}
.mg-opts{display:flex;flex-direction:column;gap:12px}
.mg-opt{background:rgba(var(--surface-rgb), 0.65);backdrop-filter:blur(8px);border:2px solid var(--border);color:var(--text);padding:17px 20px;border-radius:16px;font-size:1.1rem;font-weight:600;text-align:left;width:100%;transition:all .15s;min-height:58px;line-height:1.3}
.mg-opt:hover{background:rgba(99,102,241,.3);border-color:var(--indigo-txt);transform:translateX(4px)}
.mg-opt.selected{background:rgba(99,102,241,0.28);border-color:#00f2ff;color:var(--text);box-shadow:0 0 16px rgba(0,242,255,0.4);transform:scale(1.01)}
.mg-opt.correct{background:rgba(16,185,129,.4);border-color:var(--emerald-txt);color:#6ee7b7}
.mg-opt.wrong{background:rgba(244,63,94,.12);border-color:var(--rose-txt);color:#fda4af}
.mg-opt:disabled{cursor:not-allowed;transform:none}

/* ===== MODO CLARO: as tres cores que so funcionavam no escuro =====
   Achado varrendo o contraste de todas as telas em 08/09. Estas tres regras usam tom CLARO de
   propósito - foram escritas para fundo escuro, e la funcionam bem. No modo claro o fundo delas
   tambem e claro, e o texto some.

   MEDIDO, com o fundo real de cada uma composto camada a camada:

                        escuro        claro (antes)   claro (agora)
     .mg-opt.correct     5,76           1,03            6,54
     .mg-opt.wrong       8,94           1,58            6,71
     .mg-badge           7,60           1,52            7,55

   1,03 e verde-claro sobre verde-claro: praticamente invisivel. E a pior das tres porque e a cor
   que diz ao cliente QUAL ERA A RESPOSTA CERTA - no modo claro ele respondia e nao conseguia ler
   o resultado. O dono ja tinha relatado nao conseguir ler alternativas no modo claro; aquilo foi
   corrigido para a alternativa NAO respondida (hoje 17,72), e este estado, o de depois de
   responder, ficou para tras.

   As cores novas mantem o matiz de cada estado (verde continua verde, rosa continua rosa) - so
   escurecem o suficiente. Nenhuma delas encosta no modo escuro, que ja passava. */
html[data-theme="light"] .mg-opt.correct{color:#064e3b}
html[data-theme="light"] .mg-opt.wrong{color:#9f1239}
html[data-theme="light"] .mg-badge{color:#3730a3}
.mg-translate-input{width:100%;background:rgba(var(--surface-rgb), 0.65);backdrop-filter:blur(8px);border:2px solid var(--border);border-radius:16px;padding:17px 20px;font-family:'Outfit',sans-serif;font-size:1.15rem;color:var(--text);outline:none;transition:border-color .2s}
.mg-translate-input:focus{border-color:var(--indigo-txt);box-shadow:0 0 0 3px rgba(99,102,241,.15)}
.mg-words{display:flex;flex-wrap:wrap;gap:10px;min-height:56px;padding:12px;background:rgba(99,102,241,.08);border:1px dashed rgba(99,102,241,.3);border-radius:14px;margin:10px 0}
.mg-word-bank{display:flex;flex-wrap:wrap;gap:10px;padding:14px;background:rgba(255,255,255,.03);border-radius:14px}
.mg-word{background:rgba(99,102,241,.2);border:1px solid rgba(99,102,241,.45);color:var(--text);padding:10px 18px;border-radius:12px;font-size:1.05rem;font-weight:600;cursor:pointer;transition:all .15s;min-height:46px}
.mg-word:hover{background:rgba(99,102,241,.35);transform:scale(1.05)}
.mg-word.placed{opacity:.3;cursor:not-allowed;transform:none}
.mg-feedback{border-radius:22px;padding:28px;display:none;animation:popIn .35s cubic-bezier(0.175, 0.885, 0.32, 1.275);position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:var(--z-card);width:calc(100vw - 28px);max-width:480px;max-height:calc(100vh - 40px);max-height:calc(100dvh - 40px);overflow-y:auto;box-shadow:0 20px 60px rgba(0,0,0,0.8), 0 0 0 100vmax rgba(0,0,0,0.75);backdrop-filter:blur(16px)}
@media(min-width:500px){.mg-feedback{padding:38px;border-radius:26px}}
.mg-feedback.show{display:block}
.mg-feedback.ok{background:rgba(6,25,20,.95);border:2px solid rgba(16,185,129,.6)}
.mg-feedback.fail{background:rgba(25,5,10,.95);border:2px solid rgba(244,63,94,.6)}

/* O painel de resultado da questao e escuro nos dois temas de proposito: e um alerta momentaneo,
   e sua paleta (rosa no erro, verde no acerto, dourado do Teacher Tip, ciano do link) foi feita
   para fundo escuro. O que estava errado nao era o fundo - era o texto herdar var(--text), que
   no modo claro e quase-preto. Resultado: painel preto com letra preta. Aqui o texto passa a ter
   cor propria, e tudo que herda dentro dele fica legivel de uma vez. */
.mg-feedback{color:var(--text-on-dark)}
.mg-feedback .mg-tip-text{color:inherit}
.mg-feedback .mg-tip-row{border-top-color:var(--border-on-dark)}
/* .btn-soft usa var(--overlay) e var(--text), ambos do tema - dentro deste painel os dois somem
   no claro. O botao "Por que errei?" aparecia apagado no print do dono por isso. */
.mg-feedback .btn-soft{color:var(--text-on-dark);background:rgba(255,255,255,.10);
  border-color:rgba(255,255,255,.20)}
@keyframes popIn{from{opacity:0;transform:translate(-50%,-45%) scale(0.95)}to{opacity:1;transform:translate(-50%,-50%) scale(1)}}
.mg-tip-row{display:flex;gap:16px;align-items:center;margin-top:18px;padding-top:18px;border-top:1px solid var(--overlay-2)}
.mg-tip-av{width:72px;height:72px;border-radius:50%;overflow:hidden;border:3px solid var(--gold);flex-shrink:0;box-shadow:0 4px 12px rgba(251,191,36,.25)}
.mg-tip-av img{width:100%;height:100%;object-fit:cover}
.mg-tip-label{font-family:'Bangers',cursive;font-size:1.6rem;color:var(--gold-txt);margin-bottom:8px;letter-spacing:.5px}
.mg-tip-text{font-size:1.45rem;color:var(--text);line-height:1.6}
/* Column, not one wide row: the label ("Curtiu este topico?") and the 3 reaction buttons
   used to compete for the same horizontal line, so the 3rd button (indiferente) wrapped to
   its own row alone on narrow phone screens - reported live. Label now always gets its own
   full-width line; .mg-rating-btns is a separate row underneath that only ever holds 3 small
   buttons, which fits even a 320px-wide screen with room to spare. */
.mg-rating{display:flex;flex-direction:column;gap:10px;margin-top:16px;padding-top:14px;border-top:1px solid var(--overlay-2)}
/* O cartao de feedback e ESCURO nos dois temas (.mg-feedback usa --text-on-dark logo acima),
   mas este rotulo usava var(--muted), que INVERTE com o tema. No escuro dava 6,30; no claro o
   cinza escurece e cai para 3,35 sobre um fundo que continuou escuro - cinza escuro sobre verde
   escuro. E a armadilha de usar token dependente de tema numa superficie que nao depende dele.
   A opacidade de .65 mantem o rotulo secundario de proposito: o texto principal do cartao esta
   em 16,8, este fica em 7,6 - hierarquia preservada, e os dois legiveis. */
.mg-rating-lbl{font-size:.82rem;color:rgba(240,247,255,.65);font-weight:600}
.mg-rating-btns{display:flex;gap:8px}
.mg-rating-btn{background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:10px;padding:8px 16px;font-size:1.1rem;cursor:pointer;transition:all .2s}
.mg-rating-btn:hover{transform:scale(1.18)}
.mg-rating-btn.active{background:rgba(99,102,241,.25);border-color:var(--indigo-txt);transform:scale(1.18)}
.mg-bottom{padding:16px 18px;padding-bottom:calc(18px + env(safe-area-inset-bottom));border-top:1px solid var(--border);flex-shrink:0}
.mg-check-btn{width:100%;background:linear-gradient(135deg,var(--indigo),#7c3aed);color:#fff;font-size:1.15rem;font-weight:800;padding:18px;border-radius:18px;box-shadow:0 0 24px rgba(99,102,241,.4);letter-spacing:.5px;min-height:58px}
.mg-check-btn:hover{box-shadow:0 0 36px rgba(99,102,241,.6)}
.mg-check-btn:disabled{opacity:.5;transform:none;box-shadow:none}
/* === XP FLOAT ANIMATION === */
.xp-float {
  position: fixed;
  pointer-events: none;
  font-size: 1.4rem;
  font-weight: 900;
  color: #f59e0b;
  text-shadow: 0 0 12px rgba(245,158,11,0.7);
  z-index:var(--z-debug);
  animation: xpFloatUp 1.2s cubic-bezier(0.22,1,0.36,1) forwards;
}
@keyframes xpFloatUp {
  0%   { opacity:1; transform:translateY(0) scale(1); }
  60%  { opacity:1; transform:translateY(-60px) scale(1.2); }
  100% { opacity:0; transform:translateY(-110px) scale(0.8); }
}
/* === COMPLETE SCREEN UPGRADE === */
#screen-complete {
  background: radial-gradient(ellipse at 50% 30%, rgba(99,102,241,.35) 0%, rgba(var(--surface-rgb), 0.98) 70%);
  overflow-y: auto;
}
.complete-xp-counter {
  font-family: 'Bangers', cursive;
  font-size: 3.5rem;
  color: var(--gold-txt);
  letter-spacing: 3px;
  text-shadow: 0 0 30px rgba(245,158,11,0.6);
  animation: xpPop 0.5s cubic-bezier(0.34,1.56,0.64,1) both;
}
@keyframes xpPop {
  0%   { transform: scale(0); opacity:0; }
  100% { transform: scale(1); opacity:1; }
}
.complete-stat-bar {
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
  margin: 8px 0;
}
.complete-stat {
  background: var(--overlay);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 14px;
  padding: 10px 18px;
  text-align: center;
  min-width: 80px;
}
.complete-next-btn {
  background: linear-gradient(135deg, #6366f1, #8b5cf6);
  color: white;
  border: none;
  border-radius: 16px;
  padding: 16px 32px;
  font-weight: 900;
  font-size: 1.1rem;
  cursor: pointer;
  width: 100%;
  max-width: 320px;
  box-shadow: 0 8px 24px rgba(99,102,241,0.4);
  transition: transform 0.2s cubic-bezier(0.34,1.56,0.64,1), box-shadow 0.2s;
  letter-spacing: 0.5px;
}
.complete-next-btn:hover { transform: translateY(-3px) scale(1.02); box-shadow: 0 12px 32px rgba(99,102,241,0.5); }
.complete-next-btn:active { transform: scale(0.97); }

/* === RANKING & LOG SCREENS === */
#screen-ranking,#screen-history{display:none;position:fixed;inset:0;z-index:var(--z-screen-under);background:var(--bg);flex-direction:column;overflow:hidden;}
#screen-ranking.show,#screen-history.show{display:flex;}
.rank-header{padding:calc(env(safe-area-inset-top,10px) + 12px) 16px 12px;background:rgba(var(--surface-rgb), .97);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;flex-shrink:0;}
.rank-title{font-family:"Bangers",cursive;font-size:1.8rem;color:var(--gold-txt);letter-spacing:2px;flex:1;}
.rank-back-btn{background:var(--overlay-2);border:1px solid var(--border);color:var(--text);border-radius:10px;padding:8px 14px;font-size:.85rem;font-weight:700;cursor:pointer;}
.rank-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:10px;}
.rank-card{display:flex;align-items:center;gap:12px;background:rgba(255,255,255,.04);border:1px solid var(--border);border-radius:16px;padding:12px 16px;transition:transform .15s,background .15s;position:relative;overflow:hidden;}
.rank-card:hover{transform:translateX(4px);background:rgba(255,255,255,.07);}
.rank-card.rank-1{background:linear-gradient(135deg,rgba(245,158,11,.15),rgba(245,158,11,.03));border-color:rgba(245,158,11,.4);}
.rank-card.rank-2{background:linear-gradient(135deg,rgba(148,163,184,.12),rgba(148,163,184,.02));border-color:rgba(148,163,184,.3);}
.rank-card.rank-3{background:linear-gradient(135deg,rgba(180,83,9,.12),rgba(180,83,9,.02));border-color:rgba(180,83,9,.3);}
.rank-pos{font-family:"Bangers",cursive;font-size:1.6rem;min-width:38px;text-align:center;}
.rank-1 .rank-pos{color:#f59e0b;}.rank-2 .rank-pos{color:#94a3b8;}.rank-3 .rank-pos{color:#b45309;}
.rank-avatar{width:44px;height:44px;border-radius:50%;background:linear-gradient(135deg,var(--indigo),var(--cyan));display:flex;align-items:center;justify-content:center;font-size:1.2rem;font-weight:900;flex-shrink:0;color:white;}
.rank-info{flex:1;min-width:0;}
.rank-name{font-weight:800;font-size:.95rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.rank-meta{font-size:.75rem;color:var(--muted);margin-top:2px;}
.rank-xp{font-family:"Bangers",cursive;font-size:1.3rem;color:var(--gold-txt);letter-spacing:1px;text-align:right;flex-shrink:0;}
.rank-xp-label{font-size:.65rem;color:var(--muted);font-weight:700;display:block;}
.rank-me-badge{position:absolute;top:6px;right:8px;background:var(--indigo-fill);color:white;font-size:.6rem;font-weight:800;padding:2px 7px;border-radius:99px;letter-spacing:.5px;}
.rank-empty{text-align:center;color:var(--muted);padding:48px 24px;font-size:.95rem;line-height:1.7;}
/* Phase B 2.3: weekly league banner + promotion/relegation zone treatment. */
.league-banner{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 16px;border-bottom:1px solid;flex-shrink:0;flex-wrap:wrap;}
.league-banner-title{font-family:"Bangers",cursive;font-size:1.3rem;letter-spacing:1px;}
.league-banner-countdown{font-size:.75rem;color:var(--muted);font-weight:700;white-space:nowrap;}
.rank-card.rank-zone-promo{border-color:rgba(16,185,129,.5);box-shadow:inset 3px 0 0 var(--emerald);}
.rank-card.rank-zone-demo{border-color:rgba(244,63,94,.5);box-shadow:inset 3px 0 0 var(--rose);}
.rank-zone-tag{position:absolute;top:6px;right:8px;font-size:.6rem;font-weight:800;padding:2px 7px;border-radius:99px;letter-spacing:.3px;}
.rank-zone-tag-promo{background:rgba(16,185,129,.18);color:var(--emerald-txt);border:1px solid rgba(16,185,129,.4);}
.rank-zone-tag-demo{background:rgba(244,63,94,.18);color:var(--rose-txt);border:1px solid rgba(244,63,94,.4);}
/* .rank-me-badge already claims the top-right corner - when a card is BOTH "me" and in a
   zone, push the zone tag down so the two labels stack instead of overlapping illegibly. */
.rank-card.rank-zone-promo .rank-me-badge,.rank-card.rank-zone-demo .rank-me-badge{top:24px;}
.rank-setup-box{background:rgba(99,102,241,.08);border:1px dashed rgba(99,102,241,.4);border-radius:16px;padding:20px;text-align:center;margin:8px 0;}
.rank-setup-input{width:100%;box-sizing:border-box;background:rgba(0,0,0,.3);border:1px solid var(--border);border-radius:10px;color:var(--text);padding:10px 14px;font-size:.82rem;margin-top:10px;font-family:monospace;}
.log-event-card{display:flex;align-items:flex-start;gap:12px;padding:12px;background:rgba(255,255,255,.03);border:1px solid var(--border);border-radius:12px;}
.log-event-icon{width:36px;height:36px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:1.1rem;flex-shrink:0;}
.log-event-body{flex:1;min-width:0;}
.log-event-title{font-weight:700;font-size:.88rem;}
.log-event-meta{font-size:.72rem;color:var(--muted);margin-top:3px;}

/* === COMPLETE === */
/* === COMPLETE === */
#screen-complete{display:none;position:fixed;inset:0;z-index:var(--z-result);align-items:center;justify-content:flex-start;overflow-y:auto;-webkit-overflow-scrolling:touch;box-sizing:border-box;background:radial-gradient(ellipse at 50% 30%,rgba(99,102,241,.45) 0%,var(--bg) 75%);background-color:var(--bg);padding:24px 20px 60px;flex-direction:column;gap:16px;text-align:center}
#screen-complete.open{display:flex}
.complete-icon{font-size:5rem;animation:bounce .6s ease infinite alternate}
@keyframes bounce{from{transform:translateY(0)}to{transform:translateY(-12px)}}
/* === GENERIC SCREENS === */
.topbar-std{display:flex;align-items:center;gap:12px;padding:14px 18px;border-bottom:1px solid var(--border);flex-shrink:0;background:rgba(var(--surface-rgb), .9);backdrop-filter:blur(12px)}
.scroll-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:14px}
#screen-cast,#screen-recommended,#screen-karaoke,#screen-songs,#screen-profile,#screen-booking,#screen-chat{background:var(--bg)}
.song-card{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:14px 16px;display:flex;align-items:center;gap:12px;cursor:pointer;transition:all .18s}
.song-card:hover{border-color:var(--indigo-txt);background:rgba(99,102,241,.08);transform:translateX(4px)}
.rec-card{background:var(--card);border:1px solid var(--border);border-radius:16px;padding:14px;display:flex;gap:12px;align-items:center;cursor:pointer;transition:all .18s}
.rec-card:hover{border-color:var(--indigo-txt);background:rgba(99,102,241,.06)}
.pref-tag{font-size:.7rem;font-weight:700;padding:3px 9px;border-radius:99px;border:1px solid var(--border);color:var(--muted)}
.pref-tag.hot{background:rgba(99,102,241,.2);border-color:var(--indigo-txt);color:#a5b4fc}
.cast-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px;padding:20px}
.cast-card{background:var(--card);border:1px solid var(--border);border-radius:16px;padding:16px;display:flex;flex-direction:column;align-items:center;gap:10px;cursor:pointer;transition:all .2s}
.cast-photo{width:72px;height:72px;border-radius:50%;object-fit:cover;border:2px solid var(--indigo)}
.stat-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
.stat-card{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:16px;text-align:center}
.stat-val{font-size:2rem;font-weight:900;background:linear-gradient(135deg,var(--cyan),var(--indigo));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
.stat-lbl{font-size:.78rem;color:var(--muted);margin-top:2px}
.time-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.time-btn{background:var(--card);border:1px solid var(--border);color:var(--text);padding:12px 8px;border-radius:12px;font-size:.88rem;font-weight:600;cursor:pointer}
.time-btn:hover,.time-btn.sel{background:rgba(99,102,241,.2);border-color:var(--indigo-txt)}
#confetti-canvas{position:fixed;inset:0;pointer-events:none;z-index:var(--z-panel);display:none}
#toast{position:fixed;bottom:100px;left:50%;transform:translateX(-50%) translateY(12px);background:var(--glass);backdrop-filter:var(--glass-blur);border:1px solid var(--border);color:var(--text);padding:10px 22px;border-radius:14px;font-size:.9rem;font-weight:600;z-index:var(--z-toast);opacity:0;transition:all .3s;pointer-events:none;white-space:nowrap;max-width:90vw}
#toast.show{opacity:1;transform:translateX(-50%) translateY(0)}

/* ===== SEM backdrop-filter POR CIMA DO CANVAS DO JOGO =====
   O dono mandou prints do iPhone com um retangulo translucido no meio do mapa contendo uma
   copia MENOR do mapa dentro, e outra menor dentro dessa - efeito de imagem-dentro-de-imagem.
   Aparece nos DOIS temas (entao nao e cor) e NAO reproduz no Chromium, nem zoomado para dentro
   nem para fora (entao nao e o desenho do canvas, que limpa o quadro inteiro a cada frame).

   Sobrou a combinacao conhecida por fazer isso: backdrop-filter sobre <canvas> no Safari do
   iOS. Seis elementos ficavam nessa condicao, e o #toast era o pior caso possivel - sempre
   presente no DOM, opacidade 0, com transform, e blur, direto sobre o mapa. Um elemento assim
   continua sendo uma camada de composicao que amostra o fundo mesmo invisivel.

   HONESTIDADE: isto e a hipotese de maior probabilidade, nao um diagnostico provado - nao
   tenho um iPhone aqui para confirmar. Mas custa quase nada: o blur sai so de quem fica sobre
   o canvas, compensado com fundo um pouco mais opaco, e o vidro continua onde e seguro (menus,
   folhas e paineis sobre DOM comum). Se nao resolver, perdemos um desfoque que ninguem via.

   O #toast ganhou visibility alem da opacidade: com visibility:hidden ele sai da composicao
   quando escondido, em vez de ficar como camada invisivel eternamente sobre o mapa. */
.hud-bar{backdrop-filter:none !important;-webkit-backdrop-filter:none !important;
  background:rgba(var(--surface-rgb),.99) !important}
.hud-tabs{backdrop-filter:none !important;-webkit-backdrop-filter:none !important;
  background:rgba(var(--surface-rgb),1) !important}
.hud-progresso{background:rgba(var(--surface-rgb),.99)}
.map-ctrl-btn{backdrop-filter:none !important;-webkit-backdrop-filter:none !important}
#minimap-container{backdrop-filter:none !important;-webkit-backdrop-filter:none !important}
#hud-hint{backdrop-filter:none !important;-webkit-backdrop-filter:none !important}
#toast{backdrop-filter:none !important;-webkit-backdrop-filter:none !important;
  background:rgba(var(--surface-rgb),.98) !important;
  visibility:hidden}
#toast.show{visibility:visible}
@keyframes voxFloat {
  0% { transform: translateY(0px) rotate(0deg); }
  50% { transform: translateY(-8px) rotate(1deg); }
  100% { transform: translateY(0px) rotate(0deg); }
}
@keyframes micPulse {
  0%   { box-shadow: 0 0 0 0 rgba(239,68,68,0.7); }
  70%  { box-shadow: 0 0 0 18px rgba(239,68,68,0); }
  100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); }
}
.mic-recording {
  animation: micPulse 1.2s ease-out infinite !important;
  background: var(--rose) !important;
}
#vox-widget {
  pointer-events: auto;
  position: fixed;
  bottom: 18px;
  right: 18px;
  width: 80px;
  height: 80px;
  border-radius: 50%;
  border: 3.5px solid #7c3aed;
  background: rgba(10,15,30,0.85);
  box-shadow: 0 0 28px rgba(124, 58, 237, 0.7), inset 0 0 10px rgba(124, 58, 237, 0.4);
  cursor: pointer;
  overflow: visible; /* Allow tooltip to show outside bounds */
  animation: voxFloat 3s ease-in-out infinite, voxGlow 2.5s ease-in-out infinite alternate;
  transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  z-index: var(--z-widget);
  display: flex;
  align-items: center;
  justify-content: center;
}
@media (min-width: 600px) {
  #vox-widget { width: 110px; height: 110px; bottom: 22px; right: 22px; }
}
#vox-widget:hover {
  transform: scale(1.1);
}
#vox-widget img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  pointer-events: none;
}
/* Was right:50%/transform:translateX(50%) - centers on #vox-widget's own midpoint, but
   that widget sits fixed 18px from the real screen edge (position:fixed;right:18px), so a
   nowrap bubble this wide centered on it always extended past the actual viewport's right
   edge - on EVERY screen width, not just narrow ones, since the overflow amount depends on
   the widget's fixed distance from the edge, not on viewport width. html,body{overflow:
   hidden} then silently clipped that overflow rather than showing a scrollbar, so the
   tooltip's text was quietly cut off for every visitor. Anchoring to the widget's own right
   edge instead (which already sits safely inside the viewport) means the bubble only ever
   grows leftward, into the page, never off it. */
.vox-tooltip {
  position: absolute;
  top: -45px;
  right: 0;
  background: linear-gradient(135deg, #7c3aed, #06b6d4);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 800;
  padding: 6px 12px;
  border-radius: 12px;
  white-space: nowrap;
  box-shadow: 0 4px 14px rgba(124,58,237,0.5);
  animation: tooltipFloat 2s ease-in-out infinite alternate;
  pointer-events: none;
}
.vox-tooltip::after {
  content: '';
  position: absolute;
  bottom: -5px;
  right: 35px; /* roughly under #vox-widget's own horizontal center (it's 80px wide, tooltip's
                  right edge already lines up with the widget's right edge above) */
  border-width: 5px 5px 0;
  border-style: solid;
  border-color: #06b6d4 transparent;
  display: block;
  width: 0;
}

/* O balao do VOX e rotulo, nao controle: ele fica sobre o canto onde moram os botoes de zoom
   e o de tela cheia, e no celular estava roubando o toque deles - o dono relatou que "o balao
   de fala do vox esta acima do botao de deixar tela cheia, o que nao funciona no celular".
   pointer-events:none faz o toque atravessar direto para o botao embaixo. Quem quer falar com
   o VOX toca no proprio VOX, que continua clicavel. */
.vox-tooltip{pointer-events:none}
@keyframes voxGlow {
  0% {
    box-shadow: 0 0 25px rgba(124, 58, 237, 0.65), inset 0 0 10px rgba(124, 58, 237, 0.4);
    border-color: #6366f1;
  }
  100% {
    box-shadow: 0 0 42px rgba(6, 182, 212, 0.95), inset 0 0 18px rgba(6, 182, 212, 0.6);
    border-color: #06b6d4;
  }
}
@keyframes tooltipFloat {
  /* The 50% horizontal component here was a leftover from when .vox-tooltip was
     positioned with right:50%/transform:translateX(50%) (the old centering trick this
     animation was written to match) - now that the base rule anchors via right:0
     instead, this stale 50% kept shifting the tooltip right by half its own width on
     every frame regardless, undoing the overflow fix above. Vertical float only now. */
  0% { transform: translateY(0); }
  100% { transform: translateY(-5px); }
}


.vox-badge {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(99,102,241,0.9);
  color: white;
  font-size: 0.82rem;
  text-align: center;
  font-weight: 800;
  padding: 4px 0;
  letter-spacing: 1px;
}
/* ===== VOX ASSISTANT PANEL ===== */
#vox-panel {
  position: fixed;
  /* sits just above the widget: widget bottom(18px) + widget height(80px) + gap(10px) = 108px */
  bottom: 108px;
  right: 12px;
  width: min(360px, calc(100vw - 24px));
  /* never taller than viewport minus widget area minus safe top margin */
  max-height: calc(100dvh - 130px);
  background: rgba(var(--surface-rgb), 0.97);
  border: 1px solid var(--indigo);
  border-radius: 20px;
  box-shadow: 0 0 40px rgba(99,102,241,0.5), 0 20px 60px rgba(0,0,0,0.6);
  z-index: var(--z-panel);
  display: none;
  flex-direction: column;
  overflow: hidden;
  backdrop-filter: blur(16px);
  animation: voxPanelIn 0.25s cubic-bezier(0.34,1.56,0.64,1);
  pointer-events: auto; /* re-enable mouse/touch events within game-hud child */
}
@media (min-width: 600px) {
  #vox-panel { bottom: 155px; right: 16px; max-height: calc(100dvh - 180px); }
}
/* On very small screens: pin panel to safe inset instead of floating */
@media (max-width: 400px) {
  #vox-panel {
    left: 8px;
    right: 8px;
    bottom: 108px;
    width: auto;
    border-radius: 16px;
  }
}
#vox-panel.open { display: flex; }
@keyframes voxPanelIn {
  from { opacity:0; transform: scale(0.85) translateY(20px); }
  to   { opacity:1; transform: scale(1)   translateY(0); }
}
#vox-panel-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  background: linear-gradient(135deg, rgba(99,102,241,0.25), rgba(6,182,212,0.15));
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
#vox-panel-header .vph-avatar {
  width: 44px; height: 44px;
  border-radius: 50%;
  border: 2px solid var(--indigo);
  overflow: hidden; flex-shrink: 0;
  box-shadow: 0 0 12px rgba(99,102,241,0.5);
}
#vox-panel-header .vph-avatar img { width:100%; height:100%; object-fit:cover; }
#vox-panel-header .vph-info { flex:1; }
#vox-panel-header .vph-name { font-weight:800; font-size:.95rem; color:var(--cyan-txt); }
#vox-panel-header .vph-sub  { font-size:.72rem; color:var(--muted); }
#vox-panel-close { background:none; border:none; color:var(--muted); font-size:1.3rem; cursor:pointer; padding:4px; border-radius:8px; }
#vox-panel-close:hover { color:var(--text); background:var(--overlay-2); }
#vox-roast-btn { background:none; border:none; color:#f97316; font-size:1.1rem; cursor:pointer; padding:4px 6px; border-radius:8px; margin-right:2px; }
#vox-roast-btn:hover { background:rgba(249,115,22,.12); }
#vox-conv-btn { background:none; border:none; color:var(--cyan-txt); font-size:1.1rem; cursor:pointer; padding:4px 6px; border-radius:8px; margin-right:2px; }
#vox-conv-btn:hover { background:rgba(6,182,212,.12); }
#vox-chat-history {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  /* no fixed max-height — panel max-height controls this via flex */
  min-height: 80px;
}
.vox-msg { display:flex; gap:8px; align-items:flex-end; }
.vox-msg.vox   { flex-direction:row; }
.vox-msg.user  { flex-direction:row-reverse; }
.vox-bubble {
  padding: 10px 14px;
  border-radius: 16px;
  font-size: .85rem;
  line-height: 1.45;
  max-width: 82%;
}
.vox-msg.vox  .vox-bubble { background:rgba(99,102,241,0.18); border:1px solid rgba(99,102,241,0.3); color:var(--text); border-bottom-left-radius:4px; }
.vox-msg.user .vox-bubble { background:linear-gradient(135deg,var(--indigo),var(--cyan)); color:#fff; border-bottom-right-radius:4px; }
.vox-typing { display:flex; gap:4px; align-items:center; padding:10px 14px; }
.vox-typing span { width:7px; height:7px; border-radius:50%; background:var(--indigo); animation:typingDot 1.2s infinite; }
.vox-typing span:nth-child(2){ animation-delay:.2s; }
.vox-typing span:nth-child(3){ animation-delay:.4s; }
@keyframes typingDot { 0%,80%,100%{transform:scale(0.6);opacity:.4} 40%{transform:scale(1);opacity:1} }
#vox-input-area {
  padding: 12px 14px;
  border-top: 1px solid var(--border);
  display: flex;
  gap: 8px;
  flex-shrink: 0;
  background: rgba(0,0,0,0.2);
}
#vox-text-inp {
  flex: 1;
  background: rgba(255,255,255,.06);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 10px 14px;
  border-radius: 12px;
  outline: none;
  font-family: 'Outfit', sans-serif;
  font-size: 1rem;   /* must be >= 16px to prevent iOS auto-zoom */
  resize: none;
  min-height: 44px;
  -webkit-appearance: none;
}
#vox-text-inp:focus { border-color:var(--indigo-txt); }
#vox-send-btn {
  background:var(--indigo-fill); color:#fff; border:none;
  border-radius:12px; padding:10px 14px; cursor:pointer;
  font-size:1.1rem; flex-shrink:0;
  transition: background .2s;
}
#vox-send-btn:hover { background:#4f46e5; }
#vox-mic-btn {
  background:var(--overlay-2); color:var(--text); border:1px solid var(--border);
  border-radius:12px; padding:10px 12px; cursor:pointer;
  font-size:1.0rem; flex-shrink:0;
  transition: all .2s;
}
#vox-mic-btn.vox-mic-active { background:var(--rose); border-color:var(--rose-txt); animation:micPulse 1.2s ease-out infinite; }
/* ===== GRAMMAR FEEDBACK CARD ===== */
.grammar-card {
  background: rgba(10,15,30,0.95);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 14px;
  margin-top: 12px;
  font-size: .83rem;
  animation: bubblePop .3s ease;
}
.grammar-card-title { font-weight:800; font-size:.88rem; margin-bottom:10px; display:flex; align-items:center; gap:6px; }
.pronunciation-meter {
  height: 8px; border-radius: 99px;
  background: var(--overlay-2);
  overflow: hidden; margin: 6px 0 12px;
}
.pronunciation-fill {
  height: 100%; border-radius:99px;
  transition: width 0.6s cubic-bezier(.4,0,.2,1);
}
.grammar-error-row {
  display:flex; gap:8px; align-items:flex-start;
  padding: 7px 10px;
  background: rgba(244,63,94,0.07);
  border: 1px solid rgba(244,63,94,0.2);
  border-radius: 10px;
  margin-bottom: 6px;
}
.grammar-ok-row {
  display:flex; gap:8px; align-items:center;
  padding: 7px 10px;
  background: rgba(16,185,129,0.07);
  border: 1px solid rgba(16,185,129,0.2);
  border-radius: 10px;
  margin-bottom: 6px;
  font-size:.82rem; color:var(--emerald-txt);
}
.grammar-speak-btn {
  width:100%; margin-top:10px;
  background:rgba(6,182,212,.15); border:1px solid var(--cyan);
  color:var(--cyan-txt); padding:9px; border-radius:10px;
  cursor:pointer; font-weight:700; font-size:.83rem;
  transition: background .2s;
}
.grammar-speak-btn:hover { background:rgba(6,182,212,.28); }
/* chat grammar hint */
.chat-grammar-hint {
  font-size:.74rem; padding:5px 12px;
  border-radius:10px; margin-top:3px;
  align-self: flex-end;
  max-width:82%;
}
.chat-grammar-hint.ok   { background:rgba(16,185,129,.12); color:var(--emerald-txt); }
.chat-grammar-hint.warn { background:rgba(244,63,94,.12);  color:#fda4af; }
/* vox-widget notification dot */
#vox-notif {
  position:absolute; top:2px; right:2px;
  width:14px; height:14px; border-radius:50%;
  background:var(--rose); border:2px solid var(--bg);
  display:none;
  animation:micPulse 1.5s ease-out infinite;
}
/* =====================================================
   GLOBAL MOBILE RESPONSIVE
   ===================================================== */

/* Prevent iOS input zoom on ALL inputs and selects */
input, select, textarea {
  font-size: 1rem !important;
  -webkit-appearance: none;
}

/* Bug fix: every <select> in this app sets a light `color` (var(--text)/#fff, for the closed
   box against the dark theme) but never a matching background on its <option> children - most
   browsers render the OPEN dropdown list's option rows on their own native (usually opaque
   white) popup background regardless of the select's own background, since <option> only
   inherits `color`, not `background`, from its parent by default. Result: light text on a
   white popup = unreadable/invisible options (confirmed live - the cast-creation "Personalidade"
   select and the Command Center's .ac-select mission-dispatch dropdown both hit this). One
   global rule instead of patching every select individually, so this can't recur on a select
   added later either. */
select option {
  background: var(--bg2);
  color: var(--text);
}

/* Chat screen — make history scrollable with momentum on iOS */
#chat-history {
  -webkit-overflow-scrolling: touch;
}

/* Falar Agora button — adequate touch target */
#chat-mic-btn, .btn-glow {
  min-height: 52px;
  touch-action: manipulation;
}

/* All interactive buttons — minimum touch target */
button, .mg-opt, .mg-word, .hud-btn, .time-btn, .rec-card, .cast-card {
  touch-action: manipulation;
}

/* hud-hint — move up so it clears the VOX widget on mobile */
.hud-hint {
  bottom: calc(108px + env(safe-area-inset-bottom, 0px));
}
@media(min-width: 600px) {
  .hud-hint { bottom: 80px; }
}

/* Cast grid — single column on very small phones */
@media(max-width: 380px) {
  .cast-grid { grid-template-columns: 1fr; }
  .stat-grid  { grid-template-columns: 1fr; }
  .time-grid  { grid-template-columns: repeat(2, 1fr); }
  .int-q      { font-size: 1.3rem; }
}

/* Scroll area extra bottom padding so content isn't cut by fixed bottom bars */
.mg-scroll { padding-bottom: 8px; }

/* Screen-level scroll — prevent body scroll behind modals */
.screen { -webkit-overflow-scrolling: touch; }

/* Complete screen — tighter on small phones */
@media(max-width: 420px) {
  #screen-complete { padding: 20px 16px; gap: 12px; }
  .complete-icon   { font-size: 3.5rem; }
}

/* Topbar back button — better tap area */
.topbar-std .btn-icon {
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* onboarding interview — narrower padding on tiny screens */
@media(max-width: 420px) {
  .int-q   { font-size: 1.25rem; }
  .int-sub { font-size: .82rem; }
}

/* ===== VOICE PICKER MODAL ===== */
#modal-voice {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(var(--surface-rgb), 0.92);
  z-index: var(--z-highlight);
  align-items: flex-end;
  justify-content: center;
  backdrop-filter: blur(10px);
  padding: 0;
}
#modal-voice.open { display: flex; }
.vp-sheet {
  background: linear-gradient(180deg, #0d1b35 0%, #080f22 100%);
  border: 1px solid rgba(99,102,241,0.3);
  border-radius: 28px 28px 0 0;
  width: 100%;
  max-width: 560px;
  max-height: 90dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: vpSlideUp .35s cubic-bezier(.34,1.56,.64,1);
  box-shadow: 0 -10px 60px rgba(99,102,241,0.25);
}
@keyframes vpSlideUp {
  from { transform: translateY(100%); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}
.vp-handle {
  width: 40px; height: 5px;
  background: rgba(255,255,255,.2);
  border-radius: 99px;
  margin: 12px auto 0;
  flex-shrink: 0;
}
.vp-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 20px 10px;
  border-bottom: 1px solid rgba(255,255,255,.07);
  flex-shrink: 0;
}
.vp-title {
  font-family: 'Outfit', sans-serif;
  font-size: 1.1rem;
  font-weight: 800;
  flex: 1;
  background: linear-gradient(135deg, #6366f1, #06b6d4);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.vp-close {
  background: var(--overlay-2);
  border: 1px solid var(--overlay-3);
  color: var(--muted);
  border-radius: 10px;
  padding: 7px 11px;
  cursor: pointer;
  font-size: 1rem;
  transition: all .15s;
}
.vp-close:hover { background: rgba(255,255,255,.15); color: var(--text); }
.vp-filters {
  display: flex;
  gap: 8px;
  padding: 12px 20px 10px;
  flex-shrink: 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.vp-filter-btn {
  background: rgba(255,255,255,.06);
  border: 1px solid var(--overlay-3);
  color: var(--muted);
  border-radius: 99px;
  padding: 6px 14px;
  font-size: .82rem;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  transition: all .15s;
  flex-shrink: 0;
}
.vp-filter-btn.active {
  background: rgba(99,102,241,.25);
  border-color: var(--indigo-txt);
  color: #a5b4fc;
}
.vp-list {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 8px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.vp-voice-card {
  background: rgba(255,255,255,.04);
  border: 2px solid var(--overlay-2);
  border-radius: 16px;
  padding: 13px 16px;
  display: flex;
  align-items: center;
  gap: 12px;
  cursor: pointer;
  transition: all .18s;
  touch-action: manipulation;
}
.vp-voice-card:hover { background: rgba(99,102,241,.12); border-color: rgba(99,102,241,.3); }
.vp-voice-card.selected {
  background: rgba(99,102,241,.18);
  border-color: var(--indigo-txt);
  box-shadow: 0 0 18px rgba(99,102,241,.25);
}
.vp-voice-flag { font-size: 1.5rem; flex-shrink: 0; }
.vp-voice-info { flex: 1; min-width: 0; }
.vp-voice-name {
  font-weight: 700;
  font-size: .9rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.vp-voice-accent { font-size: .75rem; color: var(--muted); margin-top: 2px; }
.vp-voice-badge {
  font-size: .65rem;
  font-weight: 800;
  background: rgba(99,102,241,.3);
  color: #a5b4fc;
  border-radius: 6px;
  padding: 2px 7px;
  letter-spacing: .5px;
  flex-shrink: 0;
}
.vp-preview-btn {
  background: rgba(6,182,212,.15);
  border: 1px solid rgba(6,182,212,.35);
  color: var(--cyan-txt);
  border-radius: 10px;
  padding: 8px 12px;
  font-size: .85rem;
  font-weight: 700;
  cursor: pointer;
  flex-shrink: 0;
  min-width: 44px;
  min-height: 44px;
  transition: background .15s;
}
.vp-preview-btn:hover { background: rgba(6,182,212,.28); }
.vp-check { color: var(--emerald-txt); font-size: 1.1rem; flex-shrink: 0; }
.vp-controls {
  padding: 14px 20px;
  border-top: 1px solid rgba(255,255,255,.07);
  display: flex;
  flex-direction: column;
  gap: 14px;
  flex-shrink: 0;
  background: rgba(0,0,0,.2);
}
.vp-slider-row {
  display: flex;
  align-items: center;
  gap: 12px;
}
.vp-slider-lbl {
  font-size: .8rem;
  font-weight: 700;
  color: var(--muted);
  width: 80px;
  flex-shrink: 0;
}
.vp-slider {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  height: 6px;
  border-radius: 99px;
  background: var(--overlay-3);
  outline: none;
  cursor: pointer;
}
.vp-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--indigo), var(--cyan));
  cursor: pointer;
  box-shadow: 0 0 8px rgba(99,102,241,.6);
  transition: transform .15s;
}
.vp-slider::-webkit-slider-thumb:active { transform: scale(1.25); }
.vp-slider-val {
  font-size: .78rem;
  font-weight: 700;
  color: var(--cyan-txt);
  width: 48px;
  text-align: right;
  flex-shrink: 0;
}
.vp-footer {
  display: flex;
  gap: 10px;
  padding: 12px 20px calc(12px + env(safe-area-inset-bottom, 0px));
  flex-shrink: 0;
}
.vp-test-btn {
  background: rgba(255,255,255,.07);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 14px;
  padding: 13px 16px;
  font-size: .9rem;
  font-weight: 700;
  cursor: pointer;
  flex: 1;
  transition: background .15s;
  min-height: 52px;
}
.vp-test-btn:hover { background: rgba(255,255,255,.13); }
.vp-save-btn {
  background: linear-gradient(135deg, var(--indigo), #7c3aed);
  border: none;
  color: #fff;
  border-radius: 14px;
  padding: 13px 20px;
  font-size: .95rem;
  font-weight: 800;
  cursor: pointer;
  flex: 2;
  box-shadow: 0 0 20px rgba(99,102,241,.4);
  min-height: 52px;
  transition: box-shadow .2s;
}
.vp-save-btn:hover { box-shadow: 0 0 30px rgba(99,102,241,.65); }
.vp-empty {
  text-align: center;
  padding: 30px 20px;
  color: var(--muted);
  font-size: .9rem;
}

/* ===== PROXIMITY POPUP CARD ===== */
/* ESCONDIDO PELA PRÓPRIA ALTURA, e não por um número fixo.
   Até 21/09/2026 este cartão se escondia com `bottom: -220px` - um número medido uma vez,
   quando o cartão mais alto tinha 220px. O da Sophia em Palmas cresceu para 265px (tem botão de
   revisão e de roleplay além do principal), e 265 - 220 deixava 45px dele DENTRO da tela. Como
   ele tem z-index 300 e a lição tem 250, esses 45px ficavam por cima do botão "Verificar",
   cortando-o pela metade. O dono mandou a foto: a lição aberta, o botão cortado, o cartão da
   Sophia por cima.
   Não dava erro e nem bloqueava o toque (pointer-events: none quando fechado), então o botão
   continuava funcionando - só parecia quebrado. É o pior tipo de defeito para achar sozinho.
   `translateY(100%)` desce exatamente a altura do elemento, seja ela qual for: um cartão que
   cresça amanhã continua escondido sem ninguém ter que remedir nada.
   A transição passou de `bottom` para `transform` de propósito - é a mesma animação, feita pela
   GPU em vez de forçar recálculo de layout a cada quadro. */
#prox-card {
  position: fixed;
  bottom: 0;
  left: 50%;
  transform: translate(-50%, 100%);
  width: min(96vw, 480px);
  background: linear-gradient(160deg, #0d1b35 0%, #080f22 100%);
  border: 1px solid rgba(99,102,241,0.4);
  border-radius: 24px 24px 0 0;
  z-index: var(--z-card);
  padding: 18px 18px 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  box-shadow: 0 -8px 40px rgba(99,102,241,0.3), 0 -2px 0 rgba(99,102,241,0.5);
  transition: transform 0.38s cubic-bezier(0.34,1.2,0.64,1);
  pointer-events: none;
  will-change: transform;
}
#prox-card.open {
  transform: translate(-50%, 0);
  pointer-events: all;
}
.prox-handle {
  width: 36px; height: 4px;
  background: rgba(255,255,255,.2);
  border-radius: 99px;
  margin: 0 auto -4px;
}
.prox-top {
  display: flex;
  align-items: center;
  gap: 14px;
}
.prox-avatar {
  width: 56px; height: 56px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.4rem;
  font-weight: 900;
  color: #fff;
  border: 2px solid rgba(255,255,255,.25);
  overflow: hidden;
  background: var(--indigo);
}
.prox-avatar img { width: 100%; height: 100%; object-fit: cover; }
.prox-info { flex: 1; min-width: 0; }
.prox-name {
  font-size: 1.05rem;
  font-weight: 800;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.prox-role {
  font-size: .78rem;
  color: var(--muted);
  margin-top: 2px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* O nivel da missao em relacao ao aluno (Game.nivelDaMissao). Texto e nao pilula cheia: o
   cartao ja tem o selo de Quest/Completo ao lado, e dois selos coloridos disputariam o olho. */
.prox-nivel { font-size: .7rem; font-weight: 700; margin-top: 3px; letter-spacing: .2px; }
.prox-nivel.revisao { color: var(--muted); }
.prox-nivel.nivel { color: var(--emerald-txt); }
.prox-nivel.desafio { color: var(--gold-txt); }
.prox-badge {
  font-size: .65rem;
  font-weight: 800;
  padding: 3px 9px;
  border-radius: 99px;
  letter-spacing: .5px;
  flex-shrink: 0;
}
.prox-badge.quest {
  background: rgba(245,158,11,.2);
  color: #f59e0b;
  border: 1px solid rgba(245,158,11,.4);
}
.prox-badge.done {
  background: rgba(16,185,129,.15);
  color: var(--emerald-txt);
  border: 1px solid rgba(16,185,129,.3);
}
.prox-badge.landmark {
  background: rgba(6,182,212,.15);
  color: var(--cyan-txt);
  border: 1px solid rgba(6,182,212,.3);
}
.prox-bubble {
  font-size: .88rem;
  line-height: 1.5;
  color: rgba(255,255,255,.85);
  background: var(--overlay);
  border-left: 3px solid var(--indigo);
  border-radius: 0 10px 10px 0;
  padding: 8px 12px;
  min-height: 36px;
  font-style: italic;
}
.prox-actions {
  display: flex;
  gap: 10px;
}
.prox-btn-primary {
  flex: 2;
  background: linear-gradient(135deg, var(--indigo), #7c3aed);
  border: none;
  color: #fff;
  border-radius: 14px;
  padding: 13px;
  font-size: .92rem;
  font-weight: 800;
  cursor: pointer;
  min-height: 50px;
  box-shadow: 0 0 18px rgba(99,102,241,.4);
  transition: box-shadow .2s;
  touch-action: manipulation;
}
.prox-btn-primary:active { box-shadow: 0 0 30px rgba(99,102,241,.7); }
.prox-btn-secondary {
  flex: 1;
  background: rgba(255,255,255,.07);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 14px;
  padding: 13px;
  font-size: .88rem;
  font-weight: 700;
  cursor: pointer;
  min-height: 50px;
  transition: background .15s;
  touch-action: manipulation;
}
.prox-btn-secondary:active { background: rgba(255,255,255,.15); }
/* Phase C 3.3: repeatable roleplay bonus, offered only on an already-completed NPC. */
.prox-btn-roleplay {
  width: 100%;
  background: linear-gradient(135deg, #f59e0b, #d97706);
  border: none;
  color: #fff;
  border-radius: 14px;
  padding: 12px;
  font-size: .9rem;
  font-weight: 800;
  cursor: pointer;
  min-height: 46px;
  margin-bottom: 10px;
  box-shadow: 0 0 14px rgba(245,158,11,.35);
  transition: box-shadow .2s;
  touch-action: manipulation;
}
.prox-btn-roleplay:active { box-shadow: 0 0 24px rgba(245,158,11,.6); }
.prox-btn-revisao {
  display: block; width: 100%; margin-top: 8px; padding: 10px 14px; border-radius: 12px;
  background: transparent; border: 1px solid var(--border); color: var(--muted);
  font: inherit; font-size: .82rem; font-weight: 700; cursor: pointer;
}
.prox-btn-revisao:hover, .prox-btn-revisao:focus-visible { color: var(--text); border-color: var(--muted); }

/* ===== LANDMARK MODAL ===== */
#modal-landmark {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(var(--surface-rgb), 0.88);
  z-index: var(--z-landmark);
  align-items: flex-end;
  justify-content: center;
  backdrop-filter: blur(8px);
}
#modal-landmark.open { display: flex; }
.lm-sheet {
  background: linear-gradient(180deg, rgba(var(--surface-rgb),.94) 0%, rgba(var(--surface-rgb),.86) 100%); backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(6,182,212,0.35);
  border-radius: 28px 28px 0 0;
  width: 100%;
  max-width: 520px;
  /* 90dvh, e nao 88: os 15px de diferenca sao o que faltava para o quiz caber inteiro na
     tela baixa medida acima, e continuam deixando a faixa do mapa aparecendo atras, que e o
     que faz isto se ler como uma folha sobre o mapa e nao como uma tela nova. */
  max-height: 90dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: vpSlideUp .32s cubic-bezier(.34,1.4,.64,1);
  box-shadow: 0 -10px 50px rgba(6,182,212,0.2);
}
/* A foto acompanha a ALTURA da janela, em vez de ocupar 260px fixos sempre.
   O dono mostrou o quiz do Mercado Adolpho Lisboa com barra de rolagem e a 4a alternativa
   cortada: "temos que pensar em uma maneira de nao precisar dessa rolagem para ver as
   opcoes". Medido na tela dele (janela de 748px de altura, que e o que sobra num monitor de
   1080 com o Windows em 125%): folha 658, foto 260, cabecalho 67, restando 313 para um corpo
   que precisava de 405. Faltavam 92px, e a foto sozinha comia 40% do modal.
   Rolar para achar alternativa e ruim de um jeito especifico: quem nao percebe a barra
   responde entre as tres que ve, achando que sao todas - o quiz vira outra pergunta.
   24vh no lugar de 260px devolve exatamente o que faltava nas telas baixas e nao muda nada
   nas altas, onde o clamp trava de volta nos mesmos 260px de antes. O piso de 130px existe
   para a foto nao virar uma tarja em janela muito curta - abaixo disso rolar e melhor que
   uma imagem irreconhecivel. */
.lm-photo {
  display: none;
  width: 100%;
  height: clamp(130px, 24vh, 260px);
  /* A foto CEDE espaco, e cede exatamente o que faltar - nem um pixel a mais.
     O clamp acima ja resolvia a maioria, mas medindo os 175 quizzes um por um a 748px de
     altura sobravam 6 com a ultima alternativa cortada; o pior deles (Capim Dourado
     Shopping) precisava de 38px. Numero magico escolhido a dedo resolveria esses 6 e
     quebraria no proximo ponto turistico com curiosidade comprida.
     O fator de encolhimento alto faz a foto absorver praticamente todo o deficit antes do
     corpo comecar a encolher - entao o quiz fica inteiro e a foto so perde o quanto for
     preciso, ficando grande onde ha espaco. O piso de 120px e onde ela para de ceder: dali
     em diante rolar e melhor que uma imagem irreconhecivel. */
  flex: 0 100 auto;
  min-height: 120px;
  position: relative;
  overflow: hidden;
  background: linear-gradient(135deg, rgba(6,182,212,.15), rgba(var(--surface-rgb), .4));
}
/* Janela baixa demais para caber foto E quiz: a foto sai.
   Medido em janela de 600px de altura (o que sobra num laptop de 1366x768 com o Windows em
   125%): mesmo com a foto ja no piso de 120px, 170 dos 175 quizzes ficavam com alternativa
   cortada. Nao ha rearranjo que faca os dois caberem ali - e entre ver a foto e ver a
   resposta certa, quem abriu o quiz veio pela resposta. Acima de 720px a foto fica: ela
   encolhe o quanto precisar e o quiz cabe inteiro, entao a regra nao dispara.
   O !important existe porque LandmarkModal.open() liga a foto por style inline (e o onerror
   da <img> tambem mexe ali) - sem ele, o inline ganharia desta regra. */
@media (max-height: 720px) {
  .lm-com-quiz .lm-photo { display: none !important; }
}
.lm-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lm-photo::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(var(--surface-rgb), 0) 55%, rgba(var(--surface-rgb), .95) 100%);
  pointer-events: none;
}
.lm-photo-expand {
  position: absolute; right: 12px; bottom: 12px;
  width: 38px; height: 38px;
  border-radius: 12px;
  background: rgba(var(--surface-rgb), .55);
  backdrop-filter: blur(6px);
  border: 1px solid rgba(255,255,255,.25);
  color: #fff;
  font-size: 1.05rem;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background .2s, transform .2s;
}
.lm-photo-expand:hover { background: rgba(6,182,212,.35); transform: scale(1.06); }
/* No celular a mesma regra vale: o clamp acima ja encolhe pela altura da janela, que e o
   que importa aqui. A altura fixa de 220px que morava neste ponto brigava com ele. */

/* ===== LANDMARK PHOTO FULLSCREEN LIGHTBOX ===== */
#lm-photo-fullscreen {
  display: none;
  position: fixed; inset: 0;
  z-index:var(--z-fullscreen);
  background: rgba(3,7,16,.94);
  backdrop-filter: blur(10px);
  align-items: center;
  justify-content: center;
  padding: 24px;
}
#lm-photo-fullscreen.open { display: flex; }
#lm-photo-fullscreen-img {
  max-width: 96vw;
  max-height: 90vh;
  object-fit: contain;
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0,0,0,.6);
  animation: lmFsIn .25s cubic-bezier(.34,1.2,.64,1);
}
@keyframes lmFsIn { from { opacity:0; transform:scale(.94); } to { opacity:1; transform:scale(1); } }
.lm-fs-close {
  position: fixed; top: 18px; right: 18px;
  width: 44px; height: 44px;
  border-radius: 50%;
  background: rgba(255,255,255,.1);
  backdrop-filter: blur(6px);
  border: 1px solid rgba(255,255,255,.25);
  color: #fff;
  font-size: 1.15rem;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.lm-fs-close:hover { background: rgba(255,255,255,.2); }
.lm-handle {
  width: 36px; height: 4px;
  background: rgba(255,255,255,.2);
  border-radius: 99px;
  margin: 12px auto 0;
  flex-shrink: 0;
}
.lm-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 20px 10px;
  border-bottom: 1px solid rgba(255,255,255,.07);
  flex-shrink: 0;
}
.lm-icon { font-size: 2rem; flex-shrink: 0; }
.lm-title-wrap { flex: 1; min-width: 0; }
.lm-title {
  font-family: 'Bangers', cursive;
  font-size: 1.3rem;
  letter-spacing: 1px;
  background: linear-gradient(135deg, var(--cyan), #06d6a0);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lm-subtitle { font-size: .78rem; color: var(--muted); }
.lm-close {
  background: var(--overlay-2);
  border: 1px solid var(--overlay-3);
  color: var(--muted);
  border-radius: 10px;
  padding: 7px 11px;
  cursor: pointer;
  font-size: 1rem;
  flex-shrink: 0;
}
.lm-body {
  flex: 1;
  overflow-y: auto;
  padding: 16px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.lm-fact {
  background: rgba(6,182,212,.07);
  border: 1px solid rgba(6,182,212,.2);
  border-radius: 14px;
  padding: 14px;
  font-size: .92rem;
  line-height: 1.6;
  color: rgba(255,255,255,.9);
}
.lm-quiz-label {
  font-weight: 800;
  color: var(--cyan-txt);
  font-size: .85rem;
  margin-bottom: 10px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.lm-quiz-opt {
  display: block;
  width: 100%;
  text-align: left;
  background: var(--overlay);
  border: 1.5px solid rgba(255,255,255,.1);
  color: var(--text);
  padding: 11px 14px;
  border-radius: 12px;
  margin-bottom: 8px;
  cursor: pointer;
  font-size: .9rem;
  transition: all .15s;
  touch-action: manipulation;
  min-height: 48px;
}
.lm-quiz-opt:hover { background: rgba(6,182,212,.12); border-color: rgba(6,182,212,.35); }
.lm-quiz-opt.correct { background: rgba(16,185,129,.2); border-color: var(--emerald-txt); color: var(--emerald-txt); }
.lm-quiz-opt.wrong   { background: rgba(244,63,94,.15); border-color: var(--rose-txt); color: var(--rose-txt); }
.lm-quiz-opt:disabled { cursor: default; }
.lm-done-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  background: rgba(16,185,129,.12);
  border: 1px solid rgba(16,185,129,.3);
  border-radius: 14px;
  padding: 14px;
  font-size: .9rem;
  color: var(--emerald-txt);
  font-weight: 700;
}


/* ===== MAP ZOOM & NAVIGATION CONTROLS ===== */
.map-controls {
  position: absolute;
  right: 18px;
  bottom: 250px; /* Moved higher to avoid Vox Mascot */
  display: flex;
  flex-direction: column;
  gap: 10px;
  z-index: 15;
  pointer-events: auto;
}
@media (min-width: 600px) {
  .map-controls {
    right: 24px;
    bottom: 260px;
  }
}
.map-ctrl-btn {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(10, 22, 40, 0.88);
  border: 1.5px solid rgba(99, 102, 241, 0.4);
  color: #fff;
  font-size: 1.2rem;
  font-weight: bold;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(0,0,0,0.5);
  backdrop-filter: blur(8px);
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  pointer-events: auto;
}
.map-ctrl-btn:hover {
  background: var(--indigo);
  border-color: #a5b4fc;
  transform: scale(1.08);
}
.map-ctrl-btn:active {
  transform: scale(0.95);
}
#focus-btn {
  display: none;
  background: rgba(245, 158, 11, 0.15);
  border-color: var(--amber-txt);
  color: var(--gold-txt);
}
#focus-btn.visible {
  display: flex;
  animation: voxFloat 2s ease-in-out infinite;
}

/* ===== CIRCULAR MINIMAP RADAR ===== */
#minimap-container {
  position: absolute;
  left: 18px;
  bottom: 18px;
  width: 110px;
  height: 110px;
  border-radius: 50%;
  background: rgba(var(--surface-rgb), 0.88);
  border: 2px solid rgba(99, 102, 241, 0.5);
  box-shadow: 0 4px 16px rgba(0,0,0,0.6), 0 0 12px rgba(99, 102, 241, 0.2);
  z-index: 15;
  overflow: hidden;
  backdrop-filter: blur(8px);
  pointer-events: auto;
}
@media (min-width: 600px) {
  #minimap-container {
    left: 24px;
    bottom: 24px;
  }
}
#minimap-canvas {
  width: 100%;
  height: 100%;
  display: block;
}

/* ===== HOLOGRAPHIC SCANNER ANIMATION ===== */
@keyframes scan {
  0% { left: -50%; }
  100% { left: 100%; }
}

/* ===== TINDER FEEDBACK CARD ===== */
.tinder-card {
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.tinder-btn.skip:hover {
  box-shadow: 0 0 15px rgba(239, 68, 68, 0.4);
}
.tinder-btn.like:hover {
  box-shadow: 0 0 12px rgba(255, 255, 255, 0.2);
}
.tinder-btn.love:hover {
  box-shadow: 0 0 15px rgba(16, 185, 129, 0.4);
}

/* 200px (was 140px): the 9-tile action grid gained a 46px icon chip + 14px margin (60px)
   on top of its text - at 140px that left ~80px for text, guaranteeing "Meu Historico"/
   "Agendar Aula"/"Meu Elenco"/"Voz do Ingles" wrap to 2 lines while shorter neighbors like
   "Conquistas" stay 1 line, so icons ended up at visibly different vertical positions card
   to card ("still misaligned", direct chat feedback with a screenshot). 200px gives every
   title in this grid room for its full text on one line at this font-size/weight. */
.bento-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(225px, 1fr)); gap: 14px; margin-top: 20px; }
.bento-row { display: flex; gap: 14px; margin-top: 14px; flex-wrap: wrap; }
.bento-card { background: rgba(var(--surface-rgb), 0.7); backdrop-filter: blur(12px); border: 1px solid var(--overlay); border-radius: 20px; padding: 18px; box-shadow: 0 8px 32px rgba(0,0,0,0.2); transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), background 0.2s; display: flex; flex-direction: column; min-width: 0; }
/* Grid/flex items default to min-width:auto, which lets their content's natural width
   override the grid track size - the exact bug that let a card's title/subtitle text push
   past its own column and visually overlap the next card. min-width:0 here (and on every
   direct child, since several cards override flex-direction to row via inline style) forces
   the text to actually wrap within the space the grid gave it instead. */
.bento-card > * { min-width: 0; }
.bento-card:hover { transform: translateY(-4px) scale(1.02); background: rgba(25, 30, 50, 0.85); border: 1px solid rgba(99, 102, 241, 0.3); }
.bento-title { font-weight: 800; font-size: 1.05rem; color: var(--text); margin-bottom: 4px; }
.bento-subtitle { color: var(--muted); font-size: 0.8rem; line-height: 1.4; }
/* Action-grid icon chip - the 9-tile "bento" grid on the Profile screen used to be a wall of
   near-identical dark boxes (bare emoji + text, no color variety), the one visual outlier
   being a single hand-rolled gradient background on the Ranking card. Giving every tile's
   icon its own soft-glow color chip (background/box-shadow come from each tile's own inline
   style, same rgba-per-instance convention already used throughout this file, rather than a
   CSS color-mix() dependency) turns 9 identical rectangles into a scannable, color-coded grid
   - and folds the old one-off Ranking gradient into the same system everyone else now uses.
   Sizing/shape lives here once; only the color varies per card. */
.bento-icon{
  width:46px;height:46px;border-radius:14px;flex-shrink:0;margin-right:14px;
  display:flex;align-items:center;justify-content:center;font-size:1.35rem;
  transition:transform .2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.bento-card:hover .bento-icon{ transform:scale(1.08) rotate(-4deg); }
.glass-panel { background: var(--glass-soft); backdrop-filter: var(--glass-blur); border-radius: 24px; border: 1px solid var(--overlay); padding: 20px; }
#achievement-toast { position: fixed; top: -100px; left: 50%; transform: translateX(-50%); background: rgba(var(--surface-rgb), 0.95); backdrop-filter: blur(16px); border: 2px solid rgba(245, 158, 11, 0.5); border-radius: 24px; padding: 16px 24px; box-shadow: 0 15px 40px rgba(245, 158, 11, 0.25), inset 0 0 20px rgba(245, 158, 11, 0.15); z-index:var(--z-toast); transition: top 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); pointer-events: none; min-width: 320px; display: flex; align-items: center; gap: 16px; }
#achievement-toast.show { top: max(30px, env(safe-area-inset-top, 30px)); }

/* ===== FEEDBACK MODAL ===== */
.fb-cat-chip {
  background: var(--overlay);
  border: 1px solid var(--border);
  color: var(--muted);
  padding: 8px 14px;
  border-radius: 20px;
  font-size: .82rem;
  font-weight: 700;
  cursor: pointer;
  transition: all .15s;
}
.fb-cat-chip:hover { background: rgba(255,255,255,.09); }
.fb-cat-chip.active { background: rgba(99,102,241,.2); border-color: var(--indigo-txt); color: var(--text); }

/* ===== COSMETIC AVATAR FRAMES (merit-unlocked, no currency) ===== */
/* Override whichever inline border-color/box-shadow the avatar already has (.hud-av's
   var(--indigo) ring, profile's var(--primary) ring) - !important is warranted here since
   the whole point is overriding a per-element inline style, not fighting another stylesheet rule. */
.cosmetic-frame-artist { border-color: #f43f5e !important; box-shadow: 0 0 4px 2px #f59e0b, 0 0 16px rgba(244,63,94,.6) !important; }
.cosmetic-frame-radiant { border-color: #06b6d4 !important; box-shadow: 0 0 18px rgba(6,182,212,.75) !important; }
.cosmetic-frame-night { border-color: #4338ca !important; box-shadow: 0 0 16px rgba(67,56,202,.6), 0 0 32px rgba(15,10,50,.7) !important; }

/* ===== PROPRIUS COMMAND CENTER (hidden admin dashboard) =====
   Deliberately its own palette, scoped locally rather than added to :root - this is a
   single hidden surface, not a reusable part of the app's regular design language, so
   giving it dedicated tokens keeps it from ever leaking into (or fighting) the real
   --cyan/--rose/etc already used everywhere else. Note this PIN is a UI gate, not real
   security - there's no backend/auth anywhere in this app, so anyone could bypass it via
   devtools exactly as easily as any other client-only check; it exists to keep the panel
   out of a curious student's way, not to protect anything sensitive (every value it can
   read/change is already this device's own local App.S state, same as the rest of the app). */
#modal-admin-pin, #modal-admin-dashboard {
  --ac-cyan: #00f2ff; --ac-violet: #7c3aed; --ac-gold: #f59e0b;
  --ac-emerald: #10b981; --ac-red: #ef4444;
  --ac-void: #030712; --ac-panel: rgba(15,23,42,.85);
  font-family: Outfit, sans-serif;
}

@keyframes radarSweep { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes neonPulse {
  0%, 100% { box-shadow: 0 0 8px var(--ac-emerald); }
  50%      { box-shadow: 0 0 20px var(--ac-emerald); }
}
@keyframes scanline {
  0%   { background-position: 0 0; }
  100% { background-position: 0 100%; }
}
@keyframes pinShake {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(4px); }
  30%, 50%, 70% { transform: translateX(-8px); }
  40%, 60% { transform: translateX(8px); }
}
@keyframes acFadeIn { from { opacity: 0; transform: scale(.96); } to { opacity: 1; transform: scale(1); } }

/* ---- shared: scanline overlay + glass panel ---- */
.ac-scanline-overlay {
  position: absolute; inset: 0; pointer-events: none; z-index: 2;
  background: linear-gradient(to bottom, rgba(255,255,255,0) 0%, rgba(255,255,255,0) 50%, rgba(0,0,0,.3) 50%, rgba(0,0,0,.3) 100%);
  background-size: 100% 4px;
  animation: scanline 8s linear infinite;
  opacity: .25;
}
.ac-panel {
  background: var(--ac-panel);
  backdrop-filter: blur(20px);
  border: 1px solid rgba(0,242,255,.3);
  box-shadow: 0 0 30px rgba(0,242,255,.12), inset 0 0 15px rgba(124,58,237,.1);
  border-radius: 18px;
  position: relative;
  overflow: hidden;
}

/* ---- PIN modal ---- */
/* O unico sobreposto do app que ainda centralizava sem poder rolar - encontrado varrendo os
   dezessete. Centralizar conteudo mais alto que a tela empurra o comeco para ANTES do ponto
   zero da rolagem, e ele vira inalcancavel: foi assim na tela de nivelamento, no quiz de ponto
   turistico e no paywall. Aqui o cartao e pequeno e provavelmente nunca estouraria, mas a
   correcao custa duas linhas e nao muda nada quando cabe. */
#modal-admin-pin {
  display: none; position: fixed; inset: 0; z-index:var(--z-admin);
  background: radial-gradient(ellipse at 50% 30%, rgba(124,58,237,.18), var(--ac-void) 70%);
  align-items: flex-start; justify-content: flex-start; overflow-y: auto; padding: 20px;
}
#modal-admin-pin.open { display: flex; }
.ac-pin-card {
  width: 100%; max-width: 340px; margin: auto;   /* centraliza sem cortar o topo quando nao cabe */ padding: 32px 28px; text-align: center;
  animation: acFadeIn .25s cubic-bezier(.34,1.3,.64,1);
}
.ac-pin-card.shake { animation: pinShake .4s ease; }
.ac-pin-title { font-family: 'Bangers', cursive; letter-spacing: 2px; font-size: 1.3rem; color: var(--ac-cyan); text-shadow: 0 0 12px rgba(0,242,255,.6); margin-bottom: 4px; }
.ac-pin-sub { font-size: .75rem; color: #64748b; margin-bottom: 22px; letter-spacing: 1px; text-transform: uppercase; }
.ac-pin-dots { display: flex; justify-content: center; gap: 14px; margin-bottom: 26px; }
.ac-pin-dot { width: 14px; height: 14px; border-radius: 50%; border: 1px solid rgba(0,242,255,.4); background: transparent; transition: all .15s; }
.ac-pin-dot.filled { background: var(--ac-cyan); box-shadow: 0 0 10px var(--ac-cyan); }
.ac-pin-dot.err { background: var(--ac-red); border-color: var(--ac-red); box-shadow: 0 0 10px var(--ac-red); }
.ac-pin-pad { display: grid; grid-template-columns: repeat(3,1fr); gap: 10px; }
.ac-pin-key {
  aspect-ratio: 1; border-radius: 14px; border: 1px solid rgba(0,242,255,.25);
  background: rgba(0,242,255,.05); color: #e2e8f0; font-size: 1.2rem; font-weight: 700;
  cursor: pointer; transition: all .15s; touch-action: manipulation;
}
.ac-pin-key:hover, .ac-pin-key:active { background: rgba(0,242,255,.18); border-color: var(--ac-cyan); transform: scale(1.04); }
.ac-pin-key.ac-pin-clear { color: var(--ac-red); border-color: rgba(239,68,68,.3); font-size: .78rem; }
.ac-pin-key.ac-pin-enter { color: var(--ac-emerald); border-color: rgba(16,185,129,.3); font-size: .78rem; }
.ac-pin-close { margin-top: 20px; background: none; border: none; color: #475569; font-size: .8rem; cursor: pointer; }

/* ---- Dashboard ---- */
#modal-admin-dashboard {
  display: none; position: fixed; inset: 0; z-index:var(--z-admin);
  background: var(--ac-void); color: #e2e8f0;
  flex-direction: column; overflow: hidden;
}
#modal-admin-dashboard.open { display: flex; }
.ac-dash-bg {
  position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(ellipse 700px 400px at 15% 0%, rgba(124,58,237,.16), transparent 60%),
    radial-gradient(ellipse 600px 400px at 100% 100%, rgba(0,242,255,.1), transparent 60%),
    var(--ac-void);
}
.ac-dash-header {
  position: relative; z-index: 1; flex-shrink: 0;
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 20px; border-bottom: 1px solid rgba(0,242,255,.2);
  background: rgba(3,7,18,.7); backdrop-filter: blur(10px);
}
.ac-dash-status { display: flex; align-items: center; gap: 10px; font-size: .82rem; font-weight: 700; letter-spacing: .5px; }
.ac-dash-status .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--ac-emerald); animation: neonPulse 1.6s ease-in-out infinite; }
.ac-dash-clock { font-family: 'JetBrains Mono', monospace; color: var(--ac-cyan); font-size: .8rem; margin-left: 4px; opacity: .8; }
.ac-dash-lock { background: rgba(239,68,68,.12); border: 1px solid rgba(239,68,68,.35); color: #fca5a5; border-radius: 10px; padding: 8px 14px; font-size: .8rem; font-weight: 700; cursor: pointer; }
.ac-dash-lock:hover { background: rgba(239,68,68,.22); }

.ac-dash-body { position: relative; z-index: 1; flex: 1; overflow-y: auto; padding: 18px; display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 860px) { .ac-dash-body { grid-template-columns: 1fr; } }
.ac-col { display: flex; flex-direction: column; gap: 18px; min-width: 0; }

.ac-section-title { font-size: .72rem; font-weight: 800; letter-spacing: 1.5px; text-transform: uppercase; color: var(--ac-cyan); display: flex; align-items: center; gap: 8px; margin-bottom: 14px; }
.ac-section-title::before { content: ''; width: 16px; height: 2px; background: var(--ac-cyan); box-shadow: 0 0 6px var(--ac-cyan); }

/* Radar */
.ac-radar-wrap { padding: 18px; display: flex; flex-direction: column; align-items: center; }
.ac-radar-svg { width: 100%; max-width: 280px; height: auto; }
.ac-radar-beam-group { transform-origin: 140px 140px; animation: radarSweep 4s linear infinite; }
.ac-radar-legend { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 14px; }
.ac-radar-chip { font-size: .68rem; padding: 4px 10px; border-radius: 99px; background: rgba(0,242,255,.08); border: 1px solid rgba(0,242,255,.25); color: #94a3b8; }
.ac-radar-chip.hot { color: var(--ac-cyan); border-color: var(--ac-cyan); background: rgba(0,242,255,.14); }

/* Terminal */
.ac-terminal { padding: 16px; height: 240px; display: flex; flex-direction: column; }
.ac-terminal-log { flex: 1; overflow-y: auto; font-family: 'JetBrains Mono', monospace; font-size: .74rem; line-height: 1.7; color: var(--ac-cyan); text-shadow: 0 0 4px rgba(0,242,255,.35); }
.ac-terminal-log .ac-t-line { opacity: 0; animation: acFadeIn .3s ease forwards; white-space: pre-wrap; word-break: break-word; }
.ac-terminal-log .ac-t-tag { color: var(--ac-violet); font-weight: 700; }
.ac-terminal-empty { color: #475569; font-style: italic; }

/* VOX persona cards */
.ac-persona-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; padding: 16px; }
.ac-persona-card {
  background: rgba(255,255,255,.03); border: 1px solid rgba(0,242,255,.18); border-radius: 14px;
  padding: 14px 10px; text-align: center; cursor: pointer; transition: all .18s;
}
.ac-persona-card:hover { border-color: var(--ac-cyan); background: rgba(0,242,255,.06); }
.ac-persona-card.active { border-color: var(--ac-cyan); background: rgba(0,242,255,.12); box-shadow: 0 0 16px rgba(0,242,255,.25), inset 0 0 10px rgba(0,242,255,.1); }
.ac-persona-icon { font-size: 1.6rem; display: block; margin-bottom: 6px; }
.ac-persona-name { font-size: .74rem; font-weight: 700; color: #e2e8f0; }
.ac-persona-card.active .ac-persona-name { color: var(--ac-cyan); }

/* Broadcast */
.ac-broadcast { padding: 16px; display: flex; flex-direction: column; gap: 10px; }
.ac-broadcast input {
  background: var(--overlay); border: 1px solid rgba(0,242,255,.2); border-radius: 10px;
  padding: 10px 12px; color: #fff; font-family: Outfit, sans-serif; font-size: .85rem; outline: none;
}
.ac-broadcast input:focus { border-color: var(--ac-cyan); }
.ac-btn-neon {
  border: none; border-radius: 12px; padding: 12px; font-weight: 800; font-size: .85rem; cursor: pointer;
  color: #04121a; background: linear-gradient(135deg, var(--ac-cyan), #0ea5e9);
  box-shadow: 0 0 16px rgba(0,242,255,.35); transition: transform .15s;
}
.ac-btn-neon:hover { transform: translateY(-1px); }

/* Reward / CEFR buttons */
.ac-reward-grid { padding: 16px; display: flex; flex-direction: column; gap: 10px; }
.ac-btn-reward {
  border: 1px solid rgba(16,185,129,.35); background: rgba(16,185,129,.08); color: #6ee7b7;
  border-radius: 12px; padding: 11px; font-weight: 700; font-size: .82rem; cursor: pointer; transition: all .15s;
}
.ac-btn-reward:hover { background: rgba(16,185,129,.18); }
.ac-btn-reward.gold { border-color: rgba(245,158,11,.35); background: rgba(245,158,11,.08); color: #fcd34d; }
.ac-btn-reward.gold:hover { background: rgba(245,158,11,.18); }
.ac-cefr-row { display: flex; gap: 8px; }
.ac-btn-cefr {
  flex: 1; border: 1px solid rgba(124,58,237,.35); background: rgba(124,58,237,.08); color: #c4b5fd;
  border-radius: 10px; padding: 9px 4px; font-size: .72rem; font-weight: 700; cursor: pointer; transition: all .15s;
}
.ac-btn-cefr:hover, .ac-btn-cefr.active { background: rgba(124,58,237,.22); border-color: var(--ac-violet); color: var(--text); }

/* Double-XP reward toggle */
.ac-btn-doublexp { border-color: rgba(245,158,11,.35); background: rgba(245,158,11,.08); color: #fcd34d; }
.ac-btn-doublexp:hover { background: rgba(245,158,11,.18); }
.ac-btn-doublexp.active { background: rgba(245,158,11,.28); border-color: var(--ac-gold); box-shadow: 0 0 14px rgba(245,158,11,.35); color: var(--text); }
.ac-btn-adfree { border-color: rgba(0,242,255,.35); background: rgba(0,242,255,.08); color: #67e8f9; }
.ac-btn-adfree:hover { background: rgba(0,242,255,.18); }
.ac-btn-adfree.active { background: rgba(0,242,255,.28); border-color: var(--ac-cyan); box-shadow: 0 0 14px rgba(0,242,255,.35); color: var(--text); }

/* ---- generic compact panel (HUD-1..4 widgets share this) ---- */
.ac-panel.ac-compact { padding: 16px; }
.ac-pill {
  display: inline-flex; align-items: center; font-size: .66rem; font-weight: 700; letter-spacing: .3px;
  padding: 3px 9px; border-radius: 99px; background: rgba(0,242,255,.08); border: 1px solid rgba(0,242,255,.25); color: #94a3b8;
}

/* HUD-1: competency mini-radar + weakness alert */
.ac-mini-radar-row { display: flex; align-items: center; gap: 14px; }
.ac-mini-radar-svg { width: 108px; height: 108px; flex-shrink: 0; }
.ac-mini-radar-legend { display: flex; flex-direction: column; gap: 5px; flex: 1; min-width: 0; }
.ac-mini-radar-item { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: .68rem; color: #94a3b8; }
.ac-mini-radar-item .val { font-family: 'JetBrains Mono', monospace; color: var(--ac-cyan); font-weight: 700; }
.ac-mini-radar-item.weak .val { color: var(--ac-red); }
.ac-weakness-alert {
  display: none; margin-top: 12px; padding: 9px 12px; border-radius: 10px; font-size: .72rem; font-weight: 800;
  color: #fca5a5; background: rgba(239,68,68,.12); border: 1px solid rgba(239,68,68,.4);
  box-shadow: 0 0 14px rgba(239,68,68,.25); animation: neonPulseRed 1.6s ease-in-out infinite;
}
.ac-weakness-alert.show { display: block; }
@keyframes neonPulseRed {
  0%, 100% { box-shadow: 0 0 8px rgba(239,68,68,.3); }
  50%      { box-shadow: 0 0 18px rgba(239,68,68,.55); }
}

/* HUD-2: karaoke song inspector */
.ac-song-card { display: flex; flex-direction: column; gap: 10px; }
.ac-song-head { display: flex; align-items: center; gap: 10px; }
.ac-song-cover {
  width: 42px; height: 42px; border-radius: 10px; flex-shrink: 0; display: flex; align-items: center;
  justify-content: center; font-size: 1.3rem; background: linear-gradient(135deg, rgba(124,58,237,.35), rgba(0,242,255,.25));
  border: 1px solid rgba(0,242,255,.25);
}
.ac-song-titlewrap { min-width: 0; }
.ac-song-title { font-size: .84rem; font-weight: 800; color: #e2e8f0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ac-song-artist { font-size: .68rem; color: #64748b; }
.ac-song-badges { display: flex; gap: 6px; flex-wrap: wrap; }
.ac-song-modes { display: grid; grid-template-columns: repeat(4,1fr); gap: 6px; }
.ac-song-mode {
  display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 7px 4px; border-radius: 10px;
  background: rgba(255,255,255,.03); border: 1px solid rgba(148,163,184,.2); font-size: .62rem; color: #64748b; font-weight: 700;
}
.ac-song-mode .pct { font-family: 'JetBrains Mono', monospace; font-size: .7rem; }
.ac-song-mode.done { border-color: var(--ac-emerald); background: rgba(16,185,129,.1); color: #6ee7b7; }
.ac-song-mode.partial { border-color: var(--ac-gold); background: rgba(245,158,11,.08); color: #fcd34d; }
.ac-song-mastered { text-align: center; font-size: .7rem; font-weight: 800; color: var(--ac-gold); text-shadow: 0 0 8px rgba(245,158,11,.5); }

/* HUD-3: global exploration matrix */
.ac-explore-total { display: flex; align-items: baseline; gap: 8px; margin-bottom: 10px; }
.ac-explore-total .num { font-family: 'JetBrains Mono', monospace; font-size: 1.6rem; font-weight: 800; color: var(--ac-cyan); text-shadow: 0 0 10px rgba(0,242,255,.4); }
.ac-explore-total .lbl { font-size: .68rem; color: #64748b; text-transform: uppercase; letter-spacing: .5px; }
.ac-explore-grid { display: grid; grid-template-columns: repeat(auto-fill,minmax(84px,1fr)); gap: 6px; max-height: 150px; overflow-y: auto; }
.ac-explore-item {
  display: flex; flex-direction: column; gap: 2px; padding: 6px 8px; border-radius: 8px;
  background: rgba(255,255,255,.03); border: 1px solid rgba(148,163,184,.15);
}
.ac-explore-item .city { font-size: .64rem; color: #94a3b8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ac-explore-item .cnt { font-family: 'JetBrains Mono', monospace; font-size: .72rem; font-weight: 700; color: var(--ac-cyan); }
.ac-explore-item.full { border-color: var(--ac-emerald); }
.ac-explore-item.full .cnt { color: var(--ac-emerald); }

/* HUD-4: daily quests telemetry */
.ac-quest-row { display: flex; flex-direction: column; gap: 5px; margin-bottom: 12px; }
.ac-quest-row:last-child { margin-bottom: 0; }
.ac-quest-text { font-size: .72rem; color: #cbd5e1; display: flex; justify-content: space-between; gap: 8px; }
.ac-quest-text .qv { font-family: 'JetBrains Mono', monospace; color: var(--ac-cyan); font-size: .68rem; flex-shrink: 0; }
.ac-quest-bar-track { height: 6px; border-radius: 99px; background: rgba(255,255,255,.06); overflow: hidden; }
.ac-quest-bar-fill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, var(--ac-cyan), var(--ac-violet)); transition: width .4s ease; }
.ac-quest-row.done .ac-quest-text { color: var(--ac-emerald); }
.ac-quest-row.done .ac-quest-bar-fill { background: var(--ac-emerald); }

/* HUD-5: sky palette overrider */
.ac-sky-row { display: flex; gap: 8px; padding: 16px; }
.ac-btn-sky {
  flex: 1; border: 1px solid rgba(0,242,255,.25); background: rgba(255,255,255,.03); color: #94a3b8;
  border-radius: 10px; padding: 10px 4px; font-size: .72rem; font-weight: 700; cursor: pointer; transition: all .15s;
}
.ac-btn-sky:hover { background: rgba(0,242,255,.08); }
.ac-btn-sky.active { background: rgba(0,242,255,.16); border-color: var(--ac-cyan); color: var(--text); box-shadow: 0 0 12px rgba(0,242,255,.25); }

/* HUD-6: instant mission dispatcher */
.ac-dispatch-row { display: flex; flex-direction: column; gap: 10px; padding: 16px; }
.ac-select {
  background: var(--overlay); border: 1px solid rgba(0,242,255,.2); border-radius: 10px;
  padding: 10px 12px; color: #fff; font-family: Outfit, sans-serif; font-size: .85rem; outline: none; width: 100%;
}
.ac-select:focus { border-color: var(--ac-cyan); }

/* HUD-7: VOX pitch/rate sliders */
.ac-vox-audio-row { padding: 0 16px 16px; display: flex; flex-direction: column; gap: 10px; border-top: 1px solid rgba(0,242,255,.12); margin-top: 4px; padding-top: 14px; }
.ac-slider-label { display: flex; justify-content: space-between; font-size: .68rem; color: #94a3b8; text-transform: uppercase; letter-spacing: .4px; }
.ac-slider-label span { font-family: 'JetBrains Mono', monospace; color: var(--ac-cyan); text-transform: none; }
.ac-slider { -webkit-appearance: none; appearance: none; width: 100%; height: 4px; border-radius: 99px; background: rgba(0,242,255,.15); outline: none; margin: -4px 0 0; }
.ac-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 16px; height: 16px; border-radius: 50%; background: var(--ac-cyan); box-shadow: 0 0 8px var(--ac-cyan); cursor: pointer; }
.ac-slider::-moz-range-thumb { width: 16px; height: 16px; border: none; border-radius: 50%; background: var(--ac-cyan); box-shadow: 0 0 8px var(--ac-cyan); cursor: pointer; }

/* HUD-9: animated particle canvas - sits behind .ac-dash-body's glass panels */
#ac-particle-canvas { position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: .55; }

/* HUD-10: hologram glitch, triggered on VOX persona switch */
@keyframes hologramGlitch {
  0%   { transform: translate(0,0); filter: none; opacity: 1; }
  10%  { transform: translate(-2px,1px); filter: drop-shadow(2px 0 0 rgba(255,0,90,.6)) drop-shadow(-2px 0 0 rgba(0,242,255,.6)); }
  20%  { transform: translate(2px,-1px); opacity: .85; }
  30%  { transform: translate(-1px,0); filter: drop-shadow(-2px 0 0 rgba(255,0,90,.5)) drop-shadow(2px 0 0 rgba(0,242,255,.5)); }
  45%  { transform: translate(1px,1px); opacity: .9; }
  60%  { transform: translate(-1px,-1px); filter: drop-shadow(1px 0 0 rgba(255,0,90,.3)) drop-shadow(-1px 0 0 rgba(0,242,255,.3)); }
  100% { transform: translate(0,0); filter: none; opacity: 1; }
}
.ac-hologram-glitch { animation: hologramGlitch .4s linear; }

/* Global broadcast banner (not scoped to the admin token block - it's shown app-wide) */
#global-broadcast-banner {
  display: none; position: fixed; top: 0; left: 0; right: 0; z-index:var(--z-broadcast);
  background: linear-gradient(90deg, rgba(3,7,18,.97), rgba(15,23,42,.97));
  border-bottom: 1px solid rgba(0,242,255,.4);
  box-shadow: 0 4px 24px rgba(0,242,255,.15);
  padding: 10px 16px; align-items: center; gap: 12px;
  font-family: Outfit, sans-serif; font-size: .85rem; font-weight: 700; color: #e0f7ff;
  animation: acFadeIn .3s ease;
}
#global-broadcast-banner.open { display: flex; }
#global-broadcast-banner .gbb-icon { flex-shrink: 0; filter: drop-shadow(0 0 6px #00f2ff); }
#global-broadcast-banner .gbb-text { flex: 1; min-width: 0; }
#global-broadcast-banner .gbb-close { flex-shrink: 0; background: none; border: none; color: #64748b; font-size: 1.1rem; cursor: pointer; }

/* ===== UNIFIED MODAL/OVERLAY CONVENTION (.ov-modal) =====
   Every dismissable modal/popup in the app (NOT the .screen+.show full-screen navigation
   views App.navigate() already handles consistently, and NOT toast/banner notifications,
   which intentionally self-dismiss rather than being closeAllModals() candidates) used to
   split across 4 different ad-hoc conventions: a bare .open class (also reused elsewhere
   for unrelated sub-panel toggles, so it couldn't be swept generically on its own), raw
   inline style.display set directly wherever a modal happened to be opened (including
   plain onclick="" attributes in the HTML, easy to miss), and one dynamically-created
   modal using opacity+pointerEvents instead of either. That's the direct root cause of
   the whole "modal left open after navigating away" bug family fixed piecemeal earlier
   this session - closeAllModals() had to hand-enumerate every overlay by its own idiom,
   so a newly-added one that wasn't (or wasn't correctly) added to that list just stayed
   open. Every modal now uses this one shared marker class + .open state instead, which
   lets closeAllModals() sweep all of them generically as a safety net (see app.js) -
   any future overlay "just works" here as long as it carries this class, no hand-
   enumeration required for the visibility part specifically (individual .close() methods
   are still called first, for whatever non-visibility state cleanup they still do). */
.ov-modal { display: none; }
.ov-modal.open { display: flex; }

/* Camada padrao de modal. Sem isto, um modal construido em JS nasce em z-index:auto e fica
   atras de qualquer coisa posicionada com numero positivo - foi literalmente assim que o
   portao de visto ficou invisivel sobre o globo. Nao muda nada de quem ja declarou a sua:
   regra por id (#prox-card 300, #modal-landmark 450, #modal-voice 500, #minigame-overlay 250)
   e estilo inline vencem esta por especificidade, e em elemento nao posicionado z-index nao
   tem efeito. O ganho e para o proximo: ele nasce no lugar certo sem ninguem precisar lembrar. */
.ov-modal.open { z-index: var(--z-modal); }

/* 4.3 fix (accessibility): 31 @keyframes and 30+ animation: rules exist across this file
   (combo banners, confetti-adjacent pops, panel slides, the HUD's ambient particle canvas,
   etc.) - none of them respected prefers-reduced-motion, a real problem for players with
   vestibular disorders who get real physical symptoms (dizziness, nausea) from motion they
   didn't choose. A blanket override at the end of the cascade instead of hand-editing every
   individual rule: shrinks every animation/transition to effectively instant rather than
   deleting them outright, so anything JS still expects to visually "complete" (a class
   toggle, a fade) still resolves correctly, it just no longer moves. Kept intentionally
   last in the file so nothing after it can accidentally out-specificity it back on. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ===== ANUNCIOS =====
   Bloco vazio nao ocupa espaco: enquanto Anuncios.podeExibir() disser nao - que e hoje, e
   sempre para quem paga - os <div class="anuncio-slot"> ficam sem conteudo e sem altura, como
   se nao existissem. Sem :empty sobraria uma faixa vazia no rodape do ranking.

   Faixa de rodape, com borda em cima e fundo proprio, e nao um cartao no meio da lista: o
   anuncio precisa se ler como parte da moldura do app, nao como mais um item para tocar. Essa
   e a diferenca entre uma impressao e um clique acidental - e clique acidental derruba a conta
   no AdSense. flex-shrink:0 porque as duas telas sao flex em coluna: sem isso a faixa seria
   espremida ate sumir quando a lista fosse longa. */
.anuncio-slot:empty{display:none}
.anuncio-slot{flex-shrink:0;border-top:1px solid var(--border);background:var(--bg);
  box-shadow:0 -6px 14px var(--shadow)}
.anuncio-bloco{margin:0 auto;padding:10px 16px 12px;max-width:360px;text-align:center}
.anuncio-bloco .adsbygoogle{display:block;min-height:90px}
/* A saida para o Pro anda junto com TODO anuncio - e ela que transforma o incomodo em venda.
   Discreta de proposito: quem quiser ignorar ignora, quem se incomodou tem para onde ir. */
.anuncio-saida{display:inline-block;margin-top:8px;background:none;border:none;
  color:var(--muted);font-size:.76rem;font-weight:700;text-decoration:underline;cursor:pointer}
.anuncio-saida:hover{color:var(--indigo-txt)}

/* ===== BARRA DE CONSENTIMENTO (LGPD) =====
   Presa no rodape e NAO cobrindo a tela: barra que trava o app ate a pessoa clicar transforma
   consentimento em pedagio, e pedagio nao e escolha livre. Ela empurra o proprio espaco no fim
   do documento e o resto do app continua utilizavel atras dela.
   padding-bottom com env(safe-area-inset-bottom) para nao ficar atras da barra do iPhone. */
.consent-barra{
  position:fixed;left:0;right:0;bottom:0;z-index:2147483000;
  background:var(--bg2);border-top:1px solid var(--border);
  box-shadow:0 -8px 24px var(--shadow);
  padding:14px 16px calc(14px + env(safe-area-inset-bottom,0px));
  display:flex;flex-direction:column;gap:12px;
  max-width:640px;margin:0 auto;border-radius:16px 16px 0 0;
  animation:consentSobe .28s ease}
@keyframes consentSobe{from{transform:translateY(100%)}to{transform:translateY(0)}}
@media (prefers-reduced-motion:reduce){.consent-barra{animation:none}}
.consent-texto{font-size:.8rem;line-height:1.5;color:var(--text)}
.consent-texto a{color:var(--cyan-txt)}
/* Os dois botoes sao IGUAIS de proposito, e isso e a parte que importa desta folha inteira.
   "Aceitar" grande e colorido ao lado de um "recusar" cinza e minusculo nao e consentimento
   livre - e o padrao escuro que a LGPD existe para impedir. Mesmo tamanho, mesmo peso, mesma
   area de toque: a pessoa escolhe pelo que quer, e nao pelo que e mais facil de acertar. */
.consent-botoes{display:flex;gap:10px}
.consent-btn{
  flex:1;min-height:44px;padding:11px 14px;
  background:var(--overlay-2);border:1px solid var(--overlay-3);color:var(--text);
  border-radius:12px;font:700 .85rem system-ui,sans-serif;cursor:pointer}
.consent-btn:hover{background:var(--overlay-3);border-color:var(--indigo-txt)}

/* Texto que existe para o buscador e para o leitor de tela, e some para quem enxerga.
   Criado em 24/09 para o <h1> da tela inicial, que embrulhava a logo com font-size:0 e deixava
   as palavras so no alt da imagem.

   NAO usa display:none nem visibility:hidden: as duas escondem o texto de TODO MUNDO, inclusive
   do leitor de tela, que e justamente quem precisa dele. O jeito certo e tirar do fluxo e
   recortar ate 1px - o texto continua existindo, sendo lido e sendo indexado.

   clip e clip-path juntos de proposito: clip esta obsoleto e clip-path e o substituto, mas
   navegador antigo so entende o primeiro. Custa uma linha manter os dois. */
.so-leitor {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
