@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,400;0,500;0,600;0,700;0,800;0,900&family=DM+Mono:wght@500&family=Jomhuria&display=swap');

/* ---------- Design System · Carteado (docs/design_system_app_jogos_cartas.pdf) ----------
   2ª versão do doc — trocou de "Card Games Mobile" (tema claro) pra um
   tema ESCURO de cassino premium (roxo profundo + lavanda + branco).
   Mesma estratégia da vez passada: remapeia as variáveis já usadas no app
   inteiro (--ink, --muted, --card, --line, --paper, --danger) em vez de
   caçar cada seletor — assim o reskin cobre forms/listas/cards sem tocar
   telas uma a uma. --purple já era #9956DE (Primary do doc, não mudou).
   Cores decorativas que o doc não define (--blue/--green/--orange/--pink/
   --teal/--gold "de moeda e emblema") ficam como estavam — são usadas pra
   variar categorias (tom de recompensa, tile do menu), não fazem parte da
   paleta estrutural de superfície/texto que o doc especifica. */
:root{
  --ink:#E8DDF2;--muted:#B9A9C8;--paper:#5F3887;--card:#4A256A;
  --purple:#9956DE;--purple-dark:#7B3DB8;--purple-light:#B982F0;--purple-soft:#7274ED;--blue:#1FA7E1;--blue-dark:#1483b3;
  --green:#75D06A;--green-dark:#56b04c;--green-ink:#2e3d24;--green-text:#178a4a;--orange:#FFB356;--orange-dark:#e6963a;
  --pink:#FB96BB;--pink-dark:#e06fa0;--yellow:#FFB356;--gold:#FFB356;--gold-dark:#e6963a;--gold-ink:#3a2d00;
  --teal:#6ED1CF;--teal-dark:#4bb3b0;--line:rgba(255,255,255,.14);
  --sky:#7274ED;
  --danger:#EF7185;--danger-dark:#d85a70;
  /* Verso do baralho (pessoal, categoria "deck_back") — padrão roxo (o de
     sempre); as variações trocam essas duas (versos de cor) via
     body[data-deck="x"]. Versos com arte de verdade (ver DECK_BACKS no
     app.js) setam --deck-image ali também — como essa var NÃO tem valor
     aqui no :root (fica indefinida pros versos de cor), os 3 lugares que
     desenham o verso (.mini-back/.card8-back/.flying-card8) usam
     background-image:var(--deck-image, repeating-linear-gradient(...)) e
     caem pro degradê sozinhos quando não tem imagem definida. */
  --deck-dark:var(--purple-dark);--deck-light:var(--purple);
  --success:#3FAE82;--warning:#F3B84B;
  /* escala de espaçamento (4pt/8pt) usada nos blocos estruturais */
  --sp-1:4px;--sp-2:8px;--sp-3:12px;--sp-4:16px;--sp-5:20px;--sp-6:24px;--sp-7:32px;--sp-8:40px;
}
*{box-sizing:border-box}
/* touch-action:manipulation trava pinça/duplo-toque pra dar zoom — reforça
   o maximum-scale/user-scalable do viewport (que o iOS Safari ignora fora
   do modo standalone) sem impedir o scroll/tap normal. */
html,body{overflow-x:hidden;max-width:100%;touch-action:manipulation}

/* Transição entre telas (View Transitions API, disparada em layout() no
   app.js) — crossfade curto e discreto em vez do padrão do navegador (que
   às vezes vem com um leve zoom, mais chamativo do que a gente quer aqui). */
::view-transition-old(root),::view-transition-new(root){animation-duration:.22s;animation-timing-function:ease}
/* Fundo de naipes: era um SVG recriado à mão (não tínhamos o asset
   original) — substituído pelo jpg de verdade em assets/bg-image/, enviado
   pelo time. cover+fixed pra cobrir a tela toda sem repetir/criar emenda. */
/* Véu escuro por cima da foto de cassino, em toda tela que usa esse fundo
   (home, jogos, ranking, login, etc.) — garante leitura do texto claro em
   cima de qualquer trecho da imagem. */
/* Fundo principal do app: só essa imagem (bg-image-telas.webp) + um véu escuro por
   cima pra dar contraste com o texto — sem tingir de roxo (isso saiu de
   .form-page/.games-wrap abaixo, que agora deixam a imagem aparecer
   inteira).
   background-attachment:fixed direto no body é um bug conhecido do
   WebKit/iOS — não repinta direito quando o conteúdo por cima troca
   (innerHTML), deixando resíduos de tela anterior "grudados" por trás dos
   cards agora transparentes (bug relatado: "fica aparecendo imagens de
   outras abas"). Fix padrão: a imagem vai num ::before position:fixed
   próprio (isolado, sempre recalcula do zero) em vez de attachment:fixed
   no body inteiro. */
body{margin:0;background:var(--sky);color:var(--ink);font-family:'Nunito',sans-serif;min-height:100vh;position:relative}
body::before{content:'';position:fixed;inset:0;z-index:-1;background-image:linear-gradient(180deg, rgba(10,4,18,.55) 0%, rgba(10,4,18,.7) 100%), url('/assets/bg-image/bg-image-telas.webp');background-repeat:no-repeat,no-repeat;background-position:center,center;background-size:cover,cover}
/* .auth-bg: mantido como classe neutra hoje, o véu já é padrão em body{} */

/* .table-bg: fundo de mesa personalizado (nível 4+), escolhido ao criar a
   partida. --table-bg-url é setado via JS (layout()). Degradê roxo chapado
   no topo (pra caber o header por cima sem perder legibilidade) esmaecendo
   pra transparência, revelando a foto embaixo. */
/* Sobrescreve o ::before (não o body — ver comentário no body{} acima
   sobre trocar attachment:fixed pelo ::before position:fixed) — mesma
   técnica, sem o bug de repintura do iOS. */
body.table-bg::before{background-image:linear-gradient(180deg, var(--sky) 0, var(--sky) 120px, rgba(99,83,201,.6) 240px, rgba(99,83,201,0) 440px), var(--table-bg-url);background-size:cover,cover;background-position:top center,top center;background-repeat:no-repeat,no-repeat}
body.table-bg header{background:var(--sky)}
h1,h2,.brand,.eyebrow{font-family:'Nunito',cursive}
.app-shell{max-width:640px;margin:auto;min-height:100vh;display:flex;flex-direction:column}
/* Telas sem <header> (login/cadastro/etc., body.auth-bg) não ganham o
   respiro de safe-area que o header já injeta pras demais — soma aqui. */
body.auth-bg .app-shell{padding-top:env(safe-area-inset-top)}
.app-shell>section:last-of-type{flex:1 0 auto}

/* viewport-fit=cover (index.html) deixa a imagem de fundo ir até debaixo da
   barra de status em vez de sobrar uma faixa sólida ali — em troca, o
   próprio conteúdo do header precisa de um respiro extra no topo pra não
   ficar colado/atrás do relógio/ícones do sistema. */
/* sticky (não fixed): continua ocupando espaço no fluxo normal enquanto
   não rola, e gruda no topo assim que a página desce — sem isso o
   conteúdo passava por baixo/por cima dele ao rolar. Sem fundo próprio
   (transparente): deixa aparecer o degradê escuro do body por trás,
   igual ao resto da página. */
/* Altura reduzida (era 72px) — pedido pra "aproveitar mais o espaço nas
   internas": a barra de perfil não precisa ser tão alta quanto a versão
   original, então encolhe aqui e o avatar/pills acompanham (ver
   .header-avatar-wrap .avatar). */
/* position:static (era sticky) — o sticky ficava "grudando" uma camada
   composta antiga do header durante troca de tela no WebKit/iOS, causando
   um "fantasma" sobreposto mesmo depois de várias tentativas de forçar
   reflow. Sem sticky o header rola junto com o conteúdo (não fica fixo no
   topo ao rolar a página) — troca deliberada: prioriza corrigir o bug
   visual persistente sobre manter o header sempre visível. */
header{position:static;z-index:15;height:56px;display:flex;align-items:center;gap:10px;padding:env(safe-area-inset-top) 0 0;box-sizing:content-box;overflow:hidden;
  /* Full-bleed (doc): .app-shell trava a coluna em 640px (pra não esticar
     o conteúdo em telas largas/desktop) — sem isso o fundo do header
     também ficava preso a essa coluna, sobrando o fundo do body dos dois
     lados. Técnica clássica pra "furar" um container centralizado: width
     100vw + margin negativa recentralizando a partir do meio da viewport,
     não do meio do .app-shell. O conteúdo em si (topbar5) continua
     alinhado com o resto do app via max-width/margin:auto nele mesmo (ver
     .topbar5 abaixo), só o FUNDO é que agora vai de ponta a ponta. */
  width:100vw;margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw)}
/* Fundo próprio do header (doc): faixa de "veludo" roxa com naipes
   embutidos (referência enviada: club/heart/spade/diamond em fileira,
   friso quadriculado em relevo, linha dourada embaixo + brilho magenta em
   cima, sumindo pra direita), recriada em CSS puro (sem asset de imagem):
   1) crosshatch diagonal (duas repeating-linear-gradient a 45°/-45°) pro
      relevo quadriculado do veludo;
   2) fileira de naipes (♣♥♠♦ repetindo) via SVG inline em data-URI,
      baixo contraste (fill translúcido) pra ficar "gravado" no tecido, não
      um emoji óbvio;
   3) as linhas de acabamento (magenta em cima, dourada embaixo) via
      box-shadow inset — herdam a mesma máscara de opacidade (mask-image)
      que já fazia o padrão sumir da esquerda pra direita, então as linhas
      desaparecem junto. */
header::before{content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;
  box-shadow:inset 0 2px 0 rgba(216,120,255,.75),inset 0 -3px 0 var(--gold,#ffb356);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='56' viewBox='0 0 240 56'%3E%3Cg fill='rgba(255,255,255,.09)' font-family='Georgia,serif' font-size='22' text-anchor='middle'%3E%3Ctext x='30' y='36'%3E%E2%99%A3%3C/text%3E%3Ctext x='90' y='36'%3E%E2%99%A5%3C/text%3E%3Ctext x='150' y='36'%3E%E2%99%A0%3C/text%3E%3Ctext x='210' y='36'%3E%E2%99%A6%3C/text%3E%3C/g%3E%3C/svg%3E"),
    repeating-linear-gradient(45deg, rgba(255,255,255,.05) 0 1px, transparent 1px 16px),
    repeating-linear-gradient(-45deg, rgba(0,0,0,.14) 0 1px, transparent 1px 16px);
  background-size:240px 56px,16px 16px,16px 16px;
  background-position:0 0,0 0,0 0;
  -webkit-mask-image:linear-gradient(90deg, #000 0%, #000 30%, transparent 78%);
  mask-image:linear-gradient(90deg, #000 0%, #000 30%, transparent 78%)}
/* Termina em transparent (não numa cor sólida) — o fundo da própria tela
   (bg-image, ver body::before) aparece por trás no final do gradiente,
   ao invés de um "bloco" de cor cortando ali. */
header{position:relative;background:linear-gradient(90deg, #7a2fb8 0%, #5c1f96 40%, rgba(46,15,80,.4) 72%, transparent 100%)}
/* Conteúdo do header alinhado com o resto do app (coluna 640px), mesmo com
   o fundo (acima) agora full-bleed. */
header>*{max-width:640px;margin:0 auto;padding-right:var(--sp-7);width:100%;box-sizing:border-box}
/* Navegação principal fixa no rodapé (Placar/Jogos/Ranking/Loja) —
   substituiu os tiles da antiga hub. body.has-bottom-nav dá o respiro
   extra embaixo pro conteúdo não ficar escondido atrás da barra. */
body.has-bottom-nav .app-shell{padding-bottom:calc(74px + env(safe-area-inset-bottom))}
/* padding-bottom (safe-area) mora no ITEM agora, não na barra — assim o
   destaque do item ativo (fundo colorido) preenche até a borda de verdade
   da tela (sem sobrar uma faixa sem destaque embaixo, no iPhone com home
   indicator). */
.bottom-nav{position:fixed;left:0;right:0;bottom:0;display:flex;align-items:stretch;background:#241847;box-shadow:0 -4px 12px rgba(0,0,0,.2);z-index:20}
/* PWA instalado (tela cheia, sem barra do navegador): o safe-area sozinho
   deixa o conteúdo colado demais no relógio/ícones do sistema em cima e
   na barra de gestos embaixo — soma um respiro fixo extra só nesse modo. */
@media (display-mode: standalone){
  header{padding-top:calc(env(safe-area-inset-top) + 10px)}
  .bottom-nav-item{padding-bottom:calc(env(safe-area-inset-bottom) + 10px + 8px)}
  body.has-bottom-nav .app-shell{padding-bottom:calc(84px + env(safe-area-inset-bottom))}
  .account-save-bar{bottom:calc(84px + env(safe-area-inset-bottom))}
}
.bottom-nav-item{position:relative;flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:4px;padding:10px 2px calc(env(safe-area-inset-bottom) + 8px);color:rgba(255,255,255,.6);text-decoration:none;font:700 11px 'Nunito';border-radius:18px 18px 0 0;transition:background .15s}
/* Divisória entre os itens (pedido: "mais dividido") — linha fina, some no
   item ativo dos dois lados (senão cortava o círculo dourado que "flutua"
   por cima da barra). */
.bottom-nav-item:not(:last-child)::after{content:'';position:absolute;right:0;top:14px;bottom:14px;width:1px;background:rgba(255,255,255,.12)}
.bottom-nav-item.active::after,.bottom-nav-item.active + .bottom-nav-item::after{background:transparent}
.bottom-nav-item span:last-child{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bottom-nav-item.active{color:#fff;font-weight:800}
.bottom-nav-icon{font-size:32px;line-height:1;height:32px;width:32px;transition:transform .15s,background .15s,box-shadow .15s;display:inline-flex;align-items:center;justify-content:center;border-radius:50%}
/* Item ativo: ícone "flutua" acima da barra dentro de um círculo dourado
   maior, em vez de tingir o tile inteiro — mesmo efeito de destaque das
   referências (ícone selecionado bem maior que os demais). Escala/anel
   aumentados (era 1.55/4px) pra ficar mais destacado ainda, como pedido. */
.bottom-nav-item.active .bottom-nav-icon{transform:translateY(-16px) scale(1.75);background:var(--gold,#ffb020);box-shadow:0 5px 14px rgba(0,0,0,.4),0 0 0 5px #241847}
.bottom-nav-item.active .bottom-nav-icon{color:var(--gold-ink,#3a2d00)}
/* Ícones do rodapé agora são arte de verdade (webp, assets/ui/icon-*) em
   vez de emoji — mesma altura de linha (36px) pra não desalinhar o texto. */
.bottom-nav-icon img{width:56px;height:56px;object-fit:contain;display:block;transition:width .15s,height .15s}
.bottom-nav-item.active .bottom-nav-icon img{width:39px;height:39px}
/* Ícone da moeda (COIN_ICON em app.js) — sempre em tamanho relativo à
   fonte do texto ao redor (1em), então acompanha qualquer contexto sem
   precisar de regra própria por lugar. */
.coin-icon{width:1em;height:1em;object-fit:contain;vertical-align:-.15em}
.lock-icon-img{width:1em;height:1em;object-fit:contain;vertical-align:-.15em}
.invite-icon{width:1.15em;height:1.15em;object-fit:contain;vertical-align:-.2em}
/* Header: avatar (com moldura, se tiver) + nome/nível/barra de XP/moedas
   numa faixa só, tudo como um link pra Conta — substituiu o antigo chip de
   moedas separado + menu hambúrguer (o menu lateral saiu, ver
   headerProfileHtml em app.js). */
/* Header simplificado: avatar+nome à esquerda, dois pills bem maiores
   (nível e moedas) — a barra de XP saiu daqui de vez (fica só no card de
   perfil da Conta, com mais espaço pra mostrar direito). Tudo centralizado
   verticalmente na faixa do header (align-items:center). */
.header-profile-link{display:flex;align-items:center;gap:12px;flex:1;min-width:0;color:#fff;text-decoration:none}
.header-avatar-wrap{flex-shrink:0}
.header-avatar-wrap .avatar{width:38px;height:38px;font-size:14px}
/* Nome + nível empilhados (era um pill "LVL N" separado ao lado — saiu
   pra dar mais espaço pro nome, que estava truncando cedo demais). */
.header-name-col{display:flex;flex-direction:column;gap:0;min-width:0}
.header-name{font:800 14.5px 'Nunito';white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.header-lvl-sub{font:700 11px 'Nunito';color:rgba(255,255,255,.6)}
.header-lvl-sub .header-lvl-num{color:rgba(255,255,255,.85);font-weight:800}
.header-stat-pill{flex-shrink:0;display:inline-flex;align-items:center;gap:5px;background:linear-gradient(160deg,#3a2f66,#241847);color:#ffd873;font:800 14px 'Nunito';padding:7px 11px;border-radius:12px;white-space:nowrap;box-shadow:0 3px 0 rgba(0,0,0,.25),0 0 0 1px rgba(255,255,255,.08) inset;text-decoration:none;cursor:pointer}
.header-stat-pill .coin-icon{width:1.2em;height:1.2em}
/* Segunda moeda (gemas), só prévia visual — mesmo pill, fundo dourado no
   lugar do roxo padrão, pra distinguir da moeda atual ao lado. */
/* Moeda atual: prateada (era o fundo roxo padrão de .header-stat-pill).
   Gemas (nova moeda, só prévia) seguem douradas — distingue as duas. */
.header-coin-pill{background:linear-gradient(160deg,#e4e8f0,#a8b0c2);color:#2b2251}
.header-coin-pill .header-coin-num{color:#2b2251}
.header-gem-pill{background:linear-gradient(160deg,#ffd873,#e5a730);color:#4a2e00}
.header-gem-pill .header-gem-num{color:#3a2400}

/* Barra "HUD" de teste (headerHudHtml, só link de teste — ver
   SHOP_TEST_FREE) — cartão escuro sem margem nenhuma (encosta nas 3
   bordas: topo e os dois lados — ver header:has(.hud-bar) abaixo, que
   zera o padding do header padrão só nesse caso). O corte diagonal fica
   embaixo, começando logo depois da coluna do avatar: a coluna do avatar
   (~86px) fica com a altura cheia do cartão, o resto (nome/nível/moedas)
   é cortado num ângulo, mais baixo à direita. */
/* Avatar quadrado solto à esquerda + barra reta ao lado (não mais uma
   pílula sobreposta): mesma altura dos dois, 2px de gap entre eles, e só
   a ponta direita da barra arredondada (8px) — resto reto. */
header:has(.hud-row){height:auto;padding:calc(env(safe-area-inset-top) + 16px) 14px 10px;align-items:flex-start}
/* align-items:flex-start (não stretch): a barra tem altura fixa menor que
   o avatar (38px vs 44px) — stretch some browsers acabam centralizando em
   vez de alinhar pelo topo quando um item tem altura fixa, descolando a
   barra do avatar. flex-start garante os dois começando na mesma linha. */
.hud-row{width:100%;display:flex;align-items:flex-start;gap:0}
.hud-avatar-wrap{position:relative;z-index:2;flex-shrink:0}
/* Perfil quadrado (não redondo). Quando a pessoa tem moldura equipada,
   avatarBadge() já devolve um .avatar-frame-wrap com a arte da moldura por
   cima (maior que o avatar, ver FRAME_HOLE_RATIO) — nesse caso o anel
   dourado não entra (senão duplica borda e a arte da moldura fica cortada
   pelo overflow:hidden). Sem moldura, o .avatar puro ganha o anel dourado
   quadrado, igual ao resto do app. */
.hud-avatar{display:block;height:100%}
.hud-avatar .avatar{width:44px;height:44px;font-size:16px;border-radius:12px;border:3px solid var(--gold,#ffb020);background:#1c1533;box-shadow:0 3px 6px rgba(0,0,0,.35)}
.hud-avatar .avatar-frame-wrap{box-shadow:0 3px 6px rgba(0,0,0,.35);border-radius:12px}
.hud-avatar .avatar-frame-wrap .avatar{border-radius:12px}
/* Naipes saíram daqui — ficam só na moldura do subtítulo agora (ver
   .compact .title-wrap h1 abaixo). Reta do lado do perfil (border-radius
   só na ponta direita), mesma altura do avatar. */
/* margin-left negativo: a barra fica alguns pixels atrás do perfil (que
   tem z-index maior acima), em vez de encostada certinho na borda. */
.hud-bar{position:relative;z-index:1;flex:1;min-width:0;height:44px;margin-left:-8px;display:flex;align-items:center;gap:20px;padding:0 14px 0 20px;background:linear-gradient(160deg,#3a2f66,#221739);border-radius:0 8px 8px 0;box-shadow:0 0 0 1.5px rgba(255,216,115,.6),0 0 10px rgba(255,183,32,.45),0 4px 10px rgba(0,0,0,.3),0 0 0 1px rgba(255,255,255,.06) inset}
.hud-info{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;color:#fff;text-decoration:none;gap:1px}
.hud-name{font:800 14px 'Nunito';white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
/* Nível ao lado da barra de progresso, em vez de badge flutuante separado. */
.hud-level-row{display:flex;align-items:center;gap:5px}
.hud-level-num{flex-shrink:0;color:var(--gold,#ffb020);font:800 12px 'Nunito'}
.hud-xp-bar{display:block;flex:1;min-width:0;max-width:100px;height:4px;border-radius:100px;background:rgba(0,0,0,.35);overflow:hidden}
.hud-xp-fill{display:block;height:100%;background:linear-gradient(90deg,#ffd873,#ffb020);border-radius:inherit}
.hud-xp-fill.full{background:#ffe066}
/* Moedas lado a lado (não empilhadas) — barra mais curta/enxuta. */
.hud-pills{flex-shrink:0;display:flex;flex-direction:row;gap:5px}
.hud-coins{flex-shrink:0;display:inline-flex;align-items:center;gap:5px;background:rgba(0,0,0,.28);color:#ffd873;font:800 12.5px 'Nunito';padding:4px 8px;border-radius:100px;text-decoration:none;white-space:nowrap}
.hud-coins .coin-icon{width:1.2em;height:1.2em}
.hud-gems{color:#e3e3e3}

/* Segundo protótipo de header "topo em pílula" (headerTopbar2Html, só link
   de teste — ver SHOP_TEST_FREE). O fundo É o arquivo enviado
   (assets/ui/topbar.webp) — mas em vez de esticar a imagem inteira feito
   uma imagem de fundo comum (o que achata as pontas arredondadas em
   larguras de tela diferentes da original), uso border-image: as pontas
   (15% de cada lado da arte) ficam com largura fixa e não esticam, só o
   meio (miolo roxo/lavanda + corte diagonal) estica pra preencher
   qualquer largura de tela sem distorcer nada.
   */
/* background sólido — sem isso a pílula flutuava por cima da foto de fundo
   do body (aparecia atrás dela e na faixa da status bar), poluindo visual
   já carregado dessa foto atrás de uma pílula que já tem cor própria. */
header:has(.topbar2-row){height:auto;padding:calc(env(safe-area-inset-top) + 14px) 14px 10px;background:#1a0f38}
.topbar2-row{position:relative;width:100%;display:flex;align-items:center;gap:12px;min-height:56px;box-sizing:border-box;border-style:solid;border-width:0 40px;border-image-source:url('/assets/ui/topbar.webp');border-image-slice:0 320 0 320 fill;border-image-repeat:stretch;padding:5px 16px 5px 5px}
.topbar2-avatar-wrap{flex-shrink:0;display:block;margin:-10px 0}
.topbar2-avatar-wrap .avatar{width:60px;height:60px;font-size:20px;border-radius:16px;border:3px solid var(--gold,#ffb020);box-shadow:0 4px 8px rgba(0,0,0,.35)}
.topbar2-info{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;gap:4px;color:#fff;text-decoration:none}
.topbar2-name{font:800 15px 'Nunito';white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;text-shadow:0 1px 2px rgba(0,0,0,.25)}
.topbar2-level-track{display:flex;align-items:center;gap:0;max-width:210px}
.topbar2-level-badge{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background:var(--gold,#ffb020);color:#4a2e00;font:800 12px 'Nunito';border:2px solid #fff;z-index:1}
.topbar2-level-badge-next{background:#e3e1f9;color:#5a4a8a;border-color:#c9bdf0}
.topbar2-level-fill-wrap{flex:1;min-width:24px;height:8px;margin:0 -6px;border-radius:100px;background:rgba(255,255,255,.5);overflow:hidden;box-shadow:0 0 0 1px rgba(0,0,0,.12) inset}
.topbar2-level-fill{display:block;height:100%;background:linear-gradient(90deg,#ffd873,#ffb020);border-radius:inherit}
.topbar2-pills{flex-shrink:0;display:flex;flex-direction:row;gap:6px}
.topbar2-coin{flex-shrink:0;display:inline-flex;align-items:center;gap:5px;background:linear-gradient(160deg,#f4f2fe,#cfc7ec);color:#3a2d6a;font:800 13px 'Nunito';padding:5px 10px;border-radius:100px;text-decoration:none;white-space:nowrap;box-shadow:0 2px 0 rgba(0,0,0,.12)}
.topbar2-coin .coin-icon{width:1.2em;height:1.2em}
.topbar2-gem{background:linear-gradient(160deg,#ffd873,#e5a730);color:#4a2e00}

/* Terceiro protótipo de header (headerTopbar3Html, só link de teste — ver
   SHOP_TEST_FREE) — duas linhas em vez de uma pílula só: nível+XP+moedas
   em cima, avatar+nome+ranking+menu embaixo. */
header:has(.topbar3){height:auto;padding:calc(env(safe-area-inset-top) + 10px) 14px 8px;background:#150b30}
.topbar3{width:100%;display:flex;flex-direction:column;gap:8px}
.topbar3-row-top{display:flex;align-items:center;gap:8px}
.topbar3-level-badge{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:50%;background:linear-gradient(160deg,#5ad2ff,#1c8fd6);color:#04283d;font:800 14px 'Nunito';border:2px solid #fff;box-shadow:0 2px 0 rgba(0,0,0,.25)}
.topbar3-xp-bar{position:relative;flex:1;min-width:0;height:20px;border-radius:100px;background:rgba(0,0,0,.35);overflow:hidden;box-shadow:0 0 0 1px rgba(255,255,255,.08) inset}
.topbar3-xp-fill{display:block;height:100%;background:linear-gradient(90deg,#5ad2ff,#1c8fd6);border-radius:inherit;transition:width .2s ease}
.topbar3-xp-label{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font:800 10px 'Nunito';color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.6)}
.topbar3-coin-pill{flex-shrink:0;display:inline-flex;align-items:center;gap:5px;background:linear-gradient(160deg,#3a2f66,#221739);color:var(--gold,#ffb020);font:800 13px 'Nunito';padding:5px 10px;border-radius:100px;text-decoration:none;box-shadow:0 2px 0 rgba(0,0,0,.25)}
.topbar3-coin-pill .coin-icon{width:16px;height:16px}
.topbar3-gem{color:#a8f0c8}
.topbar3-row-bottom{display:flex;align-items:center;gap:10px}
.topbar3-profile-link{flex:1;min-width:0;display:flex;align-items:center;gap:8px;text-decoration:none}
.topbar3-profile-link .avatar{width:34px;height:34px;font-size:14px;border-radius:10px;border:2px solid var(--gold,#ffb020)}
.topbar3-name-col{min-width:0;display:flex;flex-direction:column;gap:1px}
.topbar3-name{font:800 14px 'Nunito';color:#fff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.topbar3-rank{font:700 11px 'Nunito';color:var(--gold,#ffb020)}
.topbar3-menu-btn{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:10px;background:rgba(255,255,255,.12);color:#fff;font-size:15px;text-decoration:none}

/* Quarto protótipo de header (headerTopbar4Html, só link de teste — ver
   SHOP_TEST_FREE) — nível+XP e barrinhas de "comprar" (com "+" verde) em
   cima; avatar/ranking/configurações em três caixinhas embaixo. */
header:has(.topbar4){height:auto;padding:calc(env(safe-area-inset-top) + 10px) 14px 8px;background:#15264a}
.topbar4{width:100%;display:flex;flex-direction:column;gap:8px}
.topbar4-row-top{display:flex;align-items:center;gap:6px}
.topbar4-level-badge{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;background:linear-gradient(160deg,#5ad2ff,#1c8fd6);color:#04283d;font:800 14px 'Nunito';border:2px solid #fff;box-shadow:0 2px 0 rgba(0,0,0,.25)}
.topbar4-xp-bar{flex:0 0 70px;height:16px;border-radius:100px;background:rgba(0,0,0,.4);overflow:hidden;box-shadow:0 0 0 1px rgba(255,255,255,.08) inset}
.topbar4-xp-fill{display:block;height:100%;background:linear-gradient(90deg,#5ad2ff,#1c8fd6);border-radius:inherit}
.topbar4-buy-bar{position:relative;flex:1;min-width:0;display:flex;align-items:center;justify-content:flex-end;gap:5px;height:26px;border-radius:100px;background:rgba(0,0,0,.4);box-shadow:0 0 0 1px rgba(255,255,255,.08) inset;padding:0 10px 0 15px;text-decoration:none;color:var(--gold,#ffb020);font:800 12px 'Nunito';overflow:visible}
.topbar4-plus{position:absolute;left:-4px;top:50%;transform:translateY(-50%);display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:8px;background:linear-gradient(160deg,#6de37a,#2fae44);color:#fff;font:800 15px 'Nunito';box-shadow:0 2px 0 #1f8a30}
.topbar4-buy-bar .coin-icon{width:16px;height:16px}
.topbar4-buy-gem{color:#a8f0c8}
.topbar4-row-bottom{display:flex;align-items:center;gap:6px}
.topbar4-icon-box{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:10px;background:rgba(0,0,0,.3);box-shadow:0 0 0 1px rgba(255,255,255,.1) inset;font-size:16px;text-decoration:none}
.topbar4-icon-box .avatar{width:26px;height:26px;font-size:11px;border-radius:7px}
.topbar4-rank-bar{flex:1;min-width:0;display:flex;align-items:center;justify-content:center;gap:5px;height:34px;border-radius:10px;background:rgba(0,0,0,.3);box-shadow:0 0 0 1px rgba(255,255,255,.1) inset;color:var(--gold,#ffb020);font:800 12px 'Nunito';text-decoration:none}

/* Quinto protótipo de header (headerTopbar5Html, só link de teste — ver
   SHOP_TEST_FREE) — uma linha só: avatar maior, nome+título embaixo,
   círculo do nível, ranking, moeda prata e moeda dourada. flex-wrap pra
   não vazar em telas bem estreitas (quebra pra 2ª linha se precisar). */
/* padding-bottom reduzido (era 10px igual o top) — no mobile o header
   ficava alto demais, com respiro extra sobrando embaixo do card de
   perfil antes da faixa do título. */
header:has(.topbar5){height:auto;padding:calc(env(safe-area-inset-top) + 10px) 14px 6px}
/* nowrap (era wrap): em telas estreitas as moedas/gemas quebravam pra uma
   segunda linha, embaixo do avatar — força tudo numa linha só. Dois
   blocos agora (.topbar5-profile / .topbar5-stats, ver headerTopbar5Html
   em app.js), com justify-content:space-between entre eles — o perfil
   (avatar+nome+level) fica grudado à esquerda, os pills (ranking/moedas)
   grudados à direita, com o respiro sobrando distribuído entre os dois
   blocos em vez de um margin-left:auto solto num item do meio. */
.topbar5{width:100%;display:flex;flex-wrap:nowrap;align-items:center;justify-content:space-between;gap:8px}
/* Perfil (doc, referência estilo Brawl Stars): um card só (bg próprio)
   com o avatar + nome em cima e, embaixo, o nível na frente da barra de
   XP (era sobreposto no canto do avatar — pedido: mover pra frente da
   barra) — troca o "nível como pill separado" de antes por um card único,
   mais compacto. */
.topbar5-profile{flex-shrink:1;min-width:0;display:flex;align-items:center;gap:8px;background:rgba(0,0,0,.32);border-radius:12px;padding:3px 12px 3px 3px;text-decoration:none;box-shadow:0 2px 0 rgba(0,0,0,.2),inset 0 0 0 1px rgba(255,255,255,.08)}
.topbar5-stats{display:flex;align-items:center;gap:16px;flex-shrink:0}
.topbar5-avatar-wrap{flex-shrink:0;line-height:0}
/* 34px (era 40px) — card de perfil mais baixo, header ocupa menos altura
   no mobile. */
.topbar5-avatar-wrap .avatar{width:34px;height:34px;font-size:14px;border-radius:10px;border:2px solid var(--gold,#ffb020)}
/* min-width:0 — dentro do card, é o nome que cede primeiro (trunca com
   reticências) se a tela for estreita demais, em vez de espremer o resto
   da linha. */
.topbar5-name-col{display:flex;flex-direction:column;justify-content:center;gap:4px;min-width:0}
.topbar5-name{font:800 13px 'Nunito';color:#fff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.topbar5-xp-row{display:flex;align-items:center;gap:5px;min-width:0}
.topbar5-level-badge{flex-shrink:0;display:flex;align-items:center;justify-content:center;min-width:18px;height:16px;padding:0 4px;border-radius:6px;background:linear-gradient(160deg,#5ad2ff,#1c8fd6);color:#04283d;font:800 10px 'Nunito';box-shadow:0 1px 0 rgba(0,0,0,.3)}
.topbar5-xp-bar{flex:1;min-width:48px;height:6px;border-radius:100px;background:rgba(0,0,0,.4);overflow:hidden;box-shadow:inset 0 1px 2px rgba(0,0,0,.4)}
.topbar5-xp-fill{display:block;height:100%;border-radius:inherit;background:linear-gradient(90deg,#5ad2ff,#2f9fe8);transition:width .3s ease}
/* Mesma proporção nos três pills (ranking/prata/dourada) — padding, altura
   de fonte e raio iguais, só a cor de fundo muda. */
.topbar5-rank-pill{flex-shrink:0;display:inline-flex;align-items:center;gap:4px;background:rgba(0,0,0,.3);color:var(--gold,#ffb020);font:800 12px 'Nunito';padding:6px 10px;border-radius:100px;text-decoration:none;box-shadow:0 2px 0 rgba(0,0,0,.25);white-space:nowrap}
.topbar5-coin-pill{flex-shrink:0;display:inline-flex;align-items:center;gap:5px;background:linear-gradient(160deg,#3a2f66,#221739);color:var(--gold,#ffb020);font:800 12px 'Nunito';padding:6px 10px;border-radius:100px;text-decoration:none;box-shadow:0 2px 0 rgba(0,0,0,.25)}
.topbar5-coin-pill .coin-icon{width:24px;height:auto}
/* Moeda dourada (gemas, compra) — mesmo "+" verde do topbar4-plus,
   grudado no canto esquerdo do pill, indicando que é clicável pra
   comprar mais (leva pra Loja → aba Moedas). */
.topbar5-gem{position:relative;color:#a8f0c8;padding-left:22px}
.topbar5-gem-plus{position:absolute;left:-4px;top:50%;transform:translateY(-50%);display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:7px;background:linear-gradient(160deg,#6de37a,#2fae44);color:#fff;font:800 13px 'Nunito';box-shadow:0 2px 0 #1f8a30}

.eyebrow{font:700 11px 'Nunito';letter-spacing:1.4px;color:var(--yellow);margin:0;text-shadow:0 1px 3px rgba(20,10,60,.4)}
.page-head{padding:16px var(--sp-7) 24px}
/* Ranking usa exatamente o mesmo padrão de todas as outras telas (mesmo
   page-head transparente, mesma sobreposição -46px do .page-head.compact
   abaixo) — só com z-index mais baixo nesse caso específico. Como o
   pódio (que vem logo depois no HTML) tem fundo sólido igual ao das
   outras telas, não faz diferença visual quem "pinta por cima" na faixa
   de sobreposição; com z-index mais baixo aqui, é sempre o pódio que
   pinta por cima da faixa, então a coroa do 1º lugar nunca fica escondida
   atrás dela — sem precisar de nenhuma outra regra especial pro Ranking. */
.page-head.compact:has(+ .podium){z-index:0}
.page-head h1,.game-header h1{font:800 34px/1.1 'Nunito';letter-spacing:-.5px;margin:8px 0;color:#fff;text-shadow:0 3px 0 rgba(0,0,0,.12)}
.page-head.on-card h1{color:var(--ink);text-shadow:none}
/* Subtítulo de cada página em formato de faixa/banner (ribbon), com as
   pontas dobradas pra dentro — referência: banners de "evento" de jogos
   mobile. Só nas páginas .compact (título curto e centralizado); telas
   com título de várias linhas ou .on-card mantêm o texto simples de antes.
   A faixa "sobrepõe" o fundo roxo do conteúdo (margin-bottom negativo no
   page-head + z-index maior no title-wrap), diminuindo o respiro entre o
   topo e o conteúdo em vez de deixar aquele vão escuro vazio. */
.page-head.compact{padding-top:8px;padding-bottom:0;margin-bottom:-26px;position:relative;z-index:2}
/* Sem o "eyebrow" (removido acima), a faixa fica mais alta — encosta bem
   no topo da página, sem aquele respiro que era pro texto pequeno. */
.page-head.compact .title-wrap{margin-top:-14px}
/* .form-page tem margin-top próprio (var(--sp-3)) que soma ao
   margin-bottom negativo do page-head.compact acima e reduz a sobreposição
   da faixa — zera aqui pra garantir o mesmo tanto de sobreposição em
   qualquer tipo de conteúdo (form-page, games-wrap, rank-list-page etc). */
.page-head.compact + .form-page{margin-top:0}
.compact .title-wrap{position:relative}
/* Arte de verdade (assets/ui/subtitle-ribbon.webp — pedida ao ChatGPT com
   naipes já embutidos nas pontas) via border-image: as pontas (480px de
   cada lado na fonte, 2086×726 — versão 2, mais alta, com respiro vertical
   de sobra pro texto) não esticam, só o miolo estica horizontal pra caber
   qualquer título, sem distorcer o desenho das pontas. */
/* display:inline-flex (não flex + width:max-content) — o Safari não
   calcula width:max-content de forma confiável num flex item com
   border-image grande, deixando a caixa mais larga que o texto e o texto
   fora do centro. inline-flex já encolhe pro conteúdo sozinho, sem
   depender de nenhuma palavra-chave de sizing. */
/* box-sizing:border-box (não content-box) — a largura já inclui as pontas
   (border-width), senão width:calc(100% - 40px) + 80px de borda em cada
   lado somava e passava do container, cortando a ponta direita. */
/* display:grid + place-items:center pro texto — mais confiável que
   flex+justify-content aqui (a caixa é larga e fixa, então grid centraliza
   o texto sem qualquer folga sobrando de um lado). Sem white-space:nowrap:
   título comprido ("Escolha o jogo", "Configurações"…) quebra linha em vez
   de vazar pra fora da moldura — a altura fixa (120px) já tem folga de
   sobra pras duas linhas. Fonte com clamp() encolhe um pouco em telas
   estreitas, reduzindo a chance de precisar quebrar. */
/* Volta a usar a arte de verdade (subtitle-ribbon.webp via border-image —
   tinha sido trocada por engano por um fundo liso; o pedido era só
   aumentar a altura, não tirar a moldura). Altura 64px -> 84px, caps um
   pouco mais largos (50px -> 60px) pra acompanhar a arte maior sem
   esticar demais.
   "fill" de volta (uma tentativa anterior tinha tirado, pra sumir com a
   faixa dourada de baixo — só que isso alterava a moldura toda, incluindo
   as pontas). Correto foi editar o PRÓPRIO ASSET (subtitle-ribbon.webp):
   a faixa dourada que corria embaixo, no trecho central/fill, foi pintada
   por cima com a cor roxa vizinha (script Python/PIL, mesma técnica de
   sempre pros assets) — moldura e pontas continuam exatamente como
   sempre foram, só sumiu aquela borda específica. */
/* width:100% (era calc(100% - 40px)) + height:100px (era 84px) — moldura
   ocupando a largura toda do title-wrap, mais alta. */
.compact .title-wrap h1{position:relative;display:grid;place-items:center;text-align:center;box-sizing:border-box;height:100px;width:100%;margin:6px auto 0;padding:0 16px 4px;font:800 clamp(13px,3.6vw,18px)/1.15 'Nunito';letter-spacing:0;color:#fff;text-shadow:0 2px 0 rgba(0,0,0,.4);border-style:solid;border-width:0 60px;border-image-source:url('/assets/ui/subtitle-ribbon.webp');border-image-slice:0 480 0 480 fill;border-image-repeat:stretch;overflow-wrap:break-word;word-break:break-word}
/* Botão de voltar embutido no canto esquerdo da própria moldura (ver
   layout() em app.js, que move o .back pra dentro do .title-wrap) — em
   vez do círculo solto de antes, fica por cima da ponta dourada da faixa.
   z-index acima do h1 (que tem position:relative mas z-index:auto) pra
   não ficar escondido atrás do desenho da moldura.
   left:34px (era 8px): posicionado relativo ao .title-wrap, não ao h1 —
   o h1 tem margin:6px auto num width menor (calc(100% - 40px)), então o
   INÍCIO da ponta dourada (border-width:60px do h1) só começa aos 20px daí
   pra frente. Com left:8px o botão ficava ANTES da ponta inteira, solto
   no fundo escuro atrás da moldura, em vez de em cima dela — 34px cai bem
   no meio da ponta (20 a 80px), centralizado nela. */
.back-in-ribbon{position:absolute;top:50%;left:34px;transform:translateY(-50%);z-index:3;width:32px;height:32px;font-size:16px;border-radius:9px}

/* 04. Buttons (doc): Primary #9956DE/#fff, hover #B982F0, pressed #7B3DB8 —
   mantém o "relevo" 3D que o app já usava (sombra embaixo, desce ao
   clicar), só troca a cor de dourado pra roxo. */
.primary{background:var(--purple);border:0;border-radius:14px;color:#fff;padding:15px 20px;font:700 16px 'Nunito';cursor:pointer;width:100%;box-shadow:0 3px 0 var(--purple-dark);transition:background .15s ease}
.primary:hover{background:var(--purple-light)}
.primary:active{transform:translateY(2px);box-shadow:0 1px 0 var(--purple-dark);background:var(--purple-dark)}
.primary b{font-size:18px;margin-left:10px}
/* Secondary (doc): fundo roxo bem sutil + borda roxa + texto lavanda —
   troca o estilo "sólido levantado" (teal) por um botão mais discreto. */
.secondary{background:rgba(153,86,222,.16);border:1px solid var(--purple);border-radius:14px;color:#DCC4FF;padding:11px 16px;font:700 14px 'Nunito';cursor:pointer}
.secondary:active{background:rgba(153,86,222,.28)}
/* Botão branco sólido — usado onde um "secondary" outline ficaria fraco
   demais perto de outro botão de destaque na mesma tela (ex.: "Entrar"
   com código, logo abaixo do "Criar mesa" roxo). */
.white{background:#fff;border:0;border-radius:14px;color:var(--purple-dark);padding:15px 20px;font:700 16px 'Nunito';cursor:pointer;width:100%;box-shadow:0 3px 0 rgba(0,0,0,.15)}
.white:active{transform:translateY(2px);box-shadow:0 1px 0 rgba(0,0,0,.15)}
/* Warning (doc): fundo vermelho sólido + texto branco — ações destrutivas/
   de saída (ex.: "Sair da mesa"). Mesma "receita" do .primary (padding,
   raio, sombra 3D), só troca a cor — usa --danger/--danger-dark (já
   existiam na paleta, sem cor nova solta). */
.warning{background:var(--danger);border:0;border-radius:14px;color:#fff;padding:15px 20px;font:700 16px 'Nunito';cursor:pointer;width:100%;box-shadow:0 3px 0 var(--danger-dark)}
.warning:active{transform:translateY(2px);box-shadow:0 1px 0 var(--danger-dark)}
.back{display:flex;align-items:center;justify-content:center;border:0;background:rgba(255,255,255,.25);border-radius:12px;width:40px;height:40px;color:#fff;font-size:21px;cursor:pointer;text-decoration:none}

/* Botão "glossy" (doc): variante em pílula inspirada em referência de UI de
   jogo (START dourado / MATCH azul, relevo bem metálico) — brilho diagonal
   por cima (::before), dois "rebites" de vidro no canto (::after) e sombra
   de borda grossa embaixo. Fica ao lado de .primary/.white/.warning como
   mais uma opção de CTA, pra telas que pedem um botão mais "premium"
   (ex.: iniciar partida, ações de destaque) sem trocar o sistema todo. */
.btn-glossy{position:relative;overflow:hidden;display:block;border:0;border-radius:100px;padding:16px 22px;font:800 17px 'Nunito';letter-spacing:.3px;color:#fff;text-align:center;text-shadow:0 2px 2px rgba(0,0,0,.4);cursor:pointer;width:100%;box-sizing:border-box;transition:transform .1s ease,box-shadow .1s ease}
.btn-glossy::before{content:'';position:absolute;inset:0;border-radius:inherit;background:linear-gradient(180deg, rgba(255,255,255,.6) 0%, rgba(255,255,255,.05) 42%, rgba(255,255,255,0) 55%);pointer-events:none}
.btn-glossy::after{content:'';position:absolute;left:14%;top:22%;width:7px;height:7px;border-radius:50%;background:rgba(255,255,255,.75);box-shadow:15px 3px 0 rgba(255,255,255,.55),30px 8px 0 rgba(255,255,255,.3);pointer-events:none}
.btn-glossy span{position:relative;z-index:1}
.btn-glossy-gold{background:linear-gradient(160deg,#ffd985,#ff9d2e 55%,#e17a08);box-shadow:0 5px 0 #b85f06,inset 0 0 0 2px rgba(255,255,255,.28),inset 0 -8px 12px rgba(0,0,0,.18)}
.btn-glossy-gold:active{transform:translateY(3px);box-shadow:0 2px 0 #b85f06,inset 0 0 0 2px rgba(255,255,255,.28)}
.btn-glossy-blue{background:linear-gradient(160deg,#9be8ff,#2fb4e6 55%,#1483b3);box-shadow:0 5px 0 #0f6a8f,inset 0 0 0 2px rgba(255,255,255,.32),inset 0 -8px 12px rgba(0,0,0,.16)}
.btn-glossy-blue:active{transform:translateY(3px);box-shadow:0 2px 0 #0f6a8f,inset 0 0 0 2px rgba(255,255,255,.32)}

/* Moldura "glow" (doc): painel escuro com borda neon dupla (linha fina +
   halo desfocado), inspirada em referência de cassino online (cards de
   categoria com brilho ciano). Usa currentColor pra herdar a cor do
   modifier (.glow-blue/.glow-gold/.glow-purple), então dá pra combinar com
   qualquer tile/card que já exista sem duplicar regras por cor. */
.tile-glow{position:relative;border-radius:18px;background:linear-gradient(165deg,#1c2b52,#0d1730);box-shadow:0 0 0 1.5px currentColor,0 0 16px -2px currentColor,inset 0 0 0 1px rgba(255,255,255,.08),inset 0 2px 10px rgba(255,255,255,.06)}
.tile-glow::after{content:'';position:absolute;inset:0;border-radius:inherit;background:linear-gradient(180deg, rgba(255,255,255,.12), rgba(255,255,255,0) 40%);pointer-events:none}
.tile-glow.glow-blue{color:#2fd6ff}
.tile-glow.glow-gold{color:#ffb84d}
.tile-glow.glow-purple{color:#c58bff}

/* ---------- Auth ---------- */
.auth-card{padding:var(--sp-8) var(--sp-7) var(--sp-7);max-width:440px;margin:auto}
.auth-card h1 i{color:var(--yellow);font-style:normal}
.auth-card .muted,.muted{margin:0;color:#fff;opacity:.92;line-height:1.5;text-shadow:0 1px 2px rgba(20,10,60,.35)}
form label{display:grid;gap:7px;font-size:13px;font-weight:700;margin-bottom:16px;color:#fff;text-shadow:0 1px 2px rgba(20,10,60,.35)}
/* Cor de texto fixa (não var(--ink), que agora é clara pro tema escuro) —
   o campo em si continua claro de propósito (contraste forte no formulário
   escuro), então o texto digitado precisa continuar escuro pra não sumir. */
input{width:100%;border:0;background:#fff;color:#2b2251;border-radius:14px;padding:14px 15px;font:600 16px 'Nunito';outline:3px solid transparent;transition:.15s}
input:focus{outline-color:var(--yellow)}
form .primary{margin-top:8px}
.tiny{text-align:center;color:#fff;opacity:.92;font-size:12px;margin-top:22px;line-height:1.7;text-shadow:0 1px 2px rgba(20,10,60,.35)}
.tiny a,form a{color:var(--yellow);font-weight:700;text-decoration:none}
/* .notice já tem fundo lilás claro pensado pra texto ESCURO (var(--purple-dark),
   ver regra base .notice) — essa sobrescrita botava a cor clara do tema
   escuro (var(--ink)) em cima do mesmo fundo claro, quase sumindo o texto
   (baixo contraste, ver bug relatado na tela de "conta criada"). */
.join-choice{display:grid;gap:10px;margin-bottom:8px}
.tiny-sep{text-align:center;color:#fff;opacity:.75;font-size:12px;margin:14px 0;text-shadow:0 1px 2px rgba(20,10,60,.35)}

/* textura de naipes no cartão de autenticação, aproximando o padrão do Figma
   (recriada em SVG — não consegui baixar o PNG original enviado, ver README) */
.display-title{font:400 clamp(44px,13vw,58px)/.82 'Jomhuria';color:#ececfa;text-align:center;
  margin:0 0 6px;text-shadow:0 3px 0 rgba(0,0,0,.15)}
.auth-tagline{text-align:center;color:#fff;font-size:18px;line-height:1.35;margin:0 0 var(--sp-6)}
.auth-tagline b{display:block;color:var(--yellow);font-weight:700}
/* Logo oficial (assets/logotipo/logo-carteado.webp) — substitui o ícone
   redondo + "Carteado" em texto que o AUTH_HERO usava antes. Já traz o
   nome desenhado, por isso aqui é só a imagem, sem título repetido
   embaixo. .display-title continua existindo à parte, usado por
   authHead() em telas sem logo (convite de partida, erro de código etc). */
.brand-logo{width:min(300px,78%);margin:0 auto var(--sp-4);display:block}
.brand-logo img{width:100%;display:block;filter:drop-shadow(0 8px 18px rgba(0,0,0,.35))}
.trophy-mark{font-size:56px;text-align:center;line-height:1;margin:var(--sp-2) 0 var(--sp-3)}

.pill-cta{display:inline-flex;align-items:center;background:var(--teal);border:0;border-radius:100px;
  color:#0a3236;font:700 13px 'Nunito';padding:9px 18px;text-decoration:none;cursor:pointer;box-shadow:0 2px 0 var(--teal-dark)}
.pill-cta:active{transform:translateY(2px);box-shadow:0 1px 0 var(--teal-dark)}
.inline-row{display:flex;align-items:center;justify-content:center;gap:var(--sp-2);flex-wrap:wrap}
.outline-btn{display:block;width:100%;background:transparent;border:2px solid #fff;border-radius:8px;
  color:#fff;font:700 14px 'Nunito';padding:13px;text-align:center;text-decoration:none;cursor:pointer;margin-top:var(--sp-3)}
.danger-btn{display:block;width:calc(100% - 64px);margin:var(--sp-4) 32px 0;background:var(--danger);border:0;border-radius:14px;
  color:#fff;font:700 15px 'Nunito';padding:15px;cursor:pointer;box-shadow:0 3px 0 var(--danger-dark)}
.danger-btn:active{transform:translateY(2px);box-shadow:0 1px 0 var(--danger-dark)}

/* ---------- Home ---------- */
.home-hero{padding:var(--sp-2) var(--sp-7) var(--sp-2)}
.home-hero h1{font:800 34px/1.1 'Nunito';letter-spacing:-.5px;color:#fff;text-shadow:0 3px 0 rgba(0,0,0,.12);margin:var(--sp-1) 0}
/* align-content:start é o que importa aqui: .action-grid costuma ser a
   última <section> da página, que ganha flex:1 0 auto (ver .app-shell)
   pra empurrar o rodapé — sem isso, as linhas do grid esticam pra
   preencher a altura toda em vez de ficarem do tamanho do conteúdo. */
.action-grid{display:grid;grid-template-columns:1fr 1fr;align-content:start;gap:var(--sp-3);padding:var(--sp-2) var(--sp-7) var(--sp-2)}
.action-card{grid-column:span 1;border:0;border-radius:20px;padding:var(--sp-5) var(--sp-4);text-align:left;cursor:pointer;color:#fff;font-family:'Nunito';box-shadow:0 5px 0 rgba(0,0,0,.15);display:flex;flex-direction:column;gap:var(--sp-3);text-decoration:none}
.action-card .icon{font-size:22px;line-height:1;flex-shrink:0;background:rgba(255,255,255,.28);width:44px;height:44px;border-radius:13px;display:grid;place-items:center}
.action-card .icon img{width:26px;height:26px;object-fit:contain}
.action-card strong{font:700 17px 'Nunito';display:block}
.action-card .action-copy{display:flex;flex-direction:column;gap:2px}
.action-card .action-copy span{font-size:12px;color:inherit;opacity:.8}
.action-card.wide{grid-column:span 2;flex-direction:row;align-items:center;padding:var(--sp-4)}
.action-card.gold{background:var(--gold);color:var(--gold-ink);box-shadow:0 4px 0 var(--gold-dark)}
.action-card.gold .icon{background:#fff}
.action-card.white{background:#fff;color:#2b2251;box-shadow:0 3px 0 var(--line)}
.action-card.white .icon{background:var(--gold)}
.action-card.purple{background:var(--purple-soft);color:#fff}
.action-card.purple .icon{background:#fff}
.action-card.teal{background:var(--teal);color:#0a3236;box-shadow:0 4px 0 var(--teal-dark)}
.action-card.teal .icon{background:#fff}
.action-card:active{transform:translateY(2px)}

/* .menu-cta: componente reutilizável de botão de menu (linha compacta,
   ícone + título + descrição) — mesma identidade visual dos CTAs
   principais do app (.primary etc: cor chapada, cantos arredondados),
   só que menor e com "borda" de verdade na base em vez do box-shadow 3D
   usado nos botões grandes. Spec: 20px padding lateral, 16px vertical,
   16px de radius, borda só embaixo. Usar em qualquer lista de opções de
   menu (grid-column:span 2 pro pai ficar de largura total num .action-grid). */
.menu-cta{grid-column:span 2;display:flex;align-items:center;gap:12px;width:100%;box-sizing:border-box;border:0;border-bottom:3px solid transparent;border-radius:16px;padding:16px 20px;text-align:left;text-decoration:none;cursor:pointer;font-family:'Nunito';color:#fff}
.menu-cta .icon{font-size:19px;line-height:1;flex-shrink:0;width:38px;height:38px;border-radius:11px;display:grid;place-items:center;overflow:hidden;background:rgba(255,255,255,.28)}
.menu-cta .icon img{width:100%;height:100%;object-fit:cover;border-radius:11px}
.menu-cta strong{font:700 15px 'Nunito';display:block}
.menu-cta .action-copy{display:flex;flex-direction:column;gap:1px}
.menu-cta .action-copy span{font-size:11px;color:inherit;opacity:.85}
.menu-cta:active{transform:translateY(2px)}
.menu-cta.gold{background:var(--gold);color:var(--gold-ink);border-bottom-color:var(--gold-dark)}
.menu-cta.gold .icon{background:#fff}
.menu-cta.white{background:#fff;color:#2b2251;border-bottom-color:var(--line)}
.menu-cta.white .icon{background:var(--gold)}
.menu-cta.purple{background:var(--purple);color:#fff;border-bottom-color:var(--purple-dark)}
.menu-cta.purple .icon{background:#fff}
.menu-cta.teal{background:var(--teal);color:#0a3236;border-bottom-color:var(--teal-dark)}
.menu-cta.teal .icon{background:#fff}
.menu-cta.pink{background:var(--pink);color:#fff;border-bottom-color:var(--pink-dark)}
.menu-cta.pink .icon{background:rgba(255,255,255,.25)}

/* .menu-cta.tile: ícone quadrado estilo "app icon" (arredondado, com borda
   e sombra próprias) do lado esquerdo do card — modelo da referência
   enviada, substitui a versão anterior com cartas sangrando na lateral. */
.menu-cta.tile{padding:14px 18px;min-height:76px}
.menu-cta.tile .tile-icon{width:56px;height:56px;border-radius:15px;flex-shrink:0;background-size:cover;background-position:center;background-color:rgba(255,255,255,.15);box-shadow:0 3px 0 rgba(0,0,0,.22),0 1px 5px rgba(0,0,0,.28);border:2px solid rgba(0,0,0,.12)}
.menu-cta.tile .tile-icon.tile-icon-emoji{display:grid;place-items:center;font-size:25px}
.menu-cta.tile .tile-icon.icon-invite{background:linear-gradient(160deg,#3fe0d0,#0f8f86)}
.menu-cta.tile .tile-icon.icon-conta{background:linear-gradient(160deg,#8577ff,#4433b0)}
.menu-cta.tile .tile-icon.icon-ranking{background:linear-gradient(160deg,#ffd873,#c9861a)}
.menu-cta.tile .tile-icon.icon-settings{background:linear-gradient(160deg,#93a8ff,#4a5fd6)}
.menu-cta.tile strong{font-size:16.5px}
.menu-cta.tile .action-copy span{font-size:12px}

.section-card{background:transparent;border-radius:22px 22px 0 0;margin-top:var(--sp-3);min-height:40vh;padding:var(--sp-6) var(--sp-7) var(--sp-8)}
.section-title{margin:0 0 var(--sp-4)}
.section-title h2{font:700 21px 'Nunito';margin:0 0 4px;color:var(--ink)}
.section-title p{margin:0;color:var(--muted);font-size:13px}

.mini-game-list{display:grid;gap:10px}
.mini-game{display:flex;align-items:center;gap:12px;border:1px solid var(--line);border-radius:16px;padding:12px 14px;text-decoration:none;color:#2b2251;background:#fbfaff}
.mini-game .dot{width:10px;height:10px;border-radius:50%;background:var(--green)}
.mini-game.done .dot{background:var(--muted)}
.mini-game strong{display:block;font:700 15px 'Nunito'}
.mini-game small{color:var(--muted);font-size:12px}
.mini-game .arrow{margin-left:auto;color:var(--purple)}

.empty{text-align:center;border:2px dashed var(--line);border-radius:20px;padding:var(--sp-8) var(--sp-7);margin-top:var(--sp-2)}
.empty div{font-size:36px}
.empty div img{width:64px;height:64px;object-fit:contain}
.empty h2{font:700 20px 'Nunito';margin:10px 0 4px;color:var(--ink)}
.empty p{color:var(--muted);font-size:14px;margin:0 0 20px}

/* ---------- New game / invite registered users ---------- */
.compact{padding:var(--sp-5) var(--sp-7) var(--sp-2);display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-4)}
.compact{position:relative}
/* O botão de voltar em si é escondido daqui (não fica nem por cima nem do
   lado da faixa) — o JS em layout() já move ele pra dentro do .title-wrap
   (canto esquerdo da moldura, ver .back-in-ribbon), então o .compact só
   precisa reservar 100% da largura pro title-wrap, sem sobrar espaço pro
   back roubar. */
.compact .title-wrap{flex:1 1 100%;display:flex;flex-direction:column;align-items:center;gap:2px;min-width:0;text-align:center}
.compact .eyebrow{display:none}
.compact h1{margin:0;color:#fff;text-shadow:0 2px 0 rgba(0,0,0,.12)}
/* Borda reta (era arredondada) + friso texturizado escuro no topo, via
   ::before em vez de border-image (mais confiável entre navegadores/
   mobile) — pseudo-elemento sozinho, não afeta nada dentro do card. */
/* Fundo com um pouco de transparência (era var(--card) sólido) — deixa o
   novo padrão geométrico do body (ver body acima) aparecer por trás. */
.form-page{position:relative;padding:calc(var(--sp-6) + 5px) var(--sp-7) var(--sp-8);background:transparent;border-radius:0;margin-top:var(--sp-3)}
.form-page label{color:var(--ink);text-shadow:none}
.form-page label{color:var(--ink);text-shadow:none}
.form-page input{background:#f3f0ff;box-shadow:inset 0 0 0 2px var(--line)}
.form-page .muted,.rounds .muted{color:var(--muted);text-shadow:none;opacity:1}
.form-page .muted a,.rounds .muted a{color:var(--purple-light);font-weight:700}
/* CTA fixo no rodapé (fora do fluxo do card) — o card ganha um respiro
   extra embaixo pra nenhum conteúdo ficar escondido atrás do botão */
.form-page.has-sticky-cta{padding-bottom:calc(var(--sp-8) + 76px)}
.sticky-cta{position:fixed;left:0;right:0;bottom:0;z-index:2;background:var(--card);box-shadow:0 -6px 20px rgba(28,18,63,.12);padding:var(--sp-4) var(--sp-7) calc(var(--sp-4) + env(safe-area-inset-bottom))}
.sticky-cta .primary{margin:0}
.form-heading{margin:var(--sp-6) 0 var(--sp-3)}
.form-heading h2{font:700 19px 'Nunito';margin:0 0 3px;color:var(--ink)}
.form-heading p{margin:0;color:var(--muted);font-size:13px}
.search-box input{margin-bottom:14px}
.invite-list{margin-bottom:var(--sp-6);max-height:340px;overflow-y:auto}
.invite-list:has(.person){border-top:1px solid var(--line)}
.person{display:flex;align-items:center;gap:12px;padding:12px 2px;border-bottom:1px solid var(--line);cursor:pointer}
.person input{width:20px;height:20px;order:3;margin-left:auto;accent-color:var(--green)}
.person .avatar{margin:0;width:36px;height:36px}
.person small{color:var(--muted);display:block;font-size:11px}
.notice{padding:var(--sp-4);background:#f1ecff;border-radius:14px;color:var(--purple-dark);font-size:13px;line-height:1.4;margin-bottom:var(--sp-6)}
.confirm-card .muted{margin-bottom:24px}
.confirm-card .notice{margin-bottom:26px}
.secondary.wide{width:100%;margin-bottom:6px}

.avatar{display:inline-grid;place-items:center;width:29px;height:29px;border-radius:14%;background:#3632af;border:2px solid #fff;font:700 12px 'Nunito';color:#fff;box-shadow:0 2px 0 rgba(0,0,0,.1)}
.avatar-bot{background:linear-gradient(135deg,#4b5563,#1f2937);font-size:15px}
/* Moldura de avatar (PNG com miolo transparente) — ver avatarBadge/
   FRAME_HOLE_RATIO em app.js. O wrap fica maior que o avatar (a borda da
   moldura "sobra" pra fora), a imagem cobre o wrap inteiro por cima. */
.avatar-frame-wrap{position:relative;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}
.avatar-frame-img{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:2}
/* Com moldura aplicada, a borda/sombra "padrão" do avatar (branca, ou o
   fundo gradiente do placeholder na Conta) não faz mais sentido — a
   moldura já traz sua própria borda desenhada, e a antiga ficava
   aparecendo entre o avatar e a arte da moldura. */
.avatar-frame-wrap .avatar{border:none;box-shadow:none}
.avatar-frame-wrap .account-avatar{background:none;box-shadow:none}

/* ---------- Game screen ---------- */
.game-header{padding:var(--sp-5) var(--sp-7) var(--sp-4);display:flex;gap:var(--sp-3);align-items:flex-start}
.game-header h1{font-size:29px}
.invite-box{margin:0;display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);background:var(--card);padding:var(--sp-4) var(--sp-7);color:var(--ink);border-top:1px solid var(--line)}
.invite-box>div{flex:1;min-width:0}
.invite-box strong{display:block;font:700 15px 'Nunito';margin-bottom:3px}
.invite-box .muted{margin-top:0;font-size:13px;color:var(--muted);text-shadow:none;opacity:1}
.invite-box b{color:var(--ink)}
.invite-box .secondary{flex-shrink:0;white-space:nowrap}
.score-summary{display:grid;grid-template-columns:repeat(3,1fr);background:var(--card);border-radius:22px 22px 0 0;margin-top:6px}
.score-summary div{padding:var(--sp-5) var(--sp-4) var(--sp-2);text-align:center;border-right:1px solid var(--line)}
.score-summary div:last-child{border:0}
.score-summary span{display:block;color:var(--muted);font:9px 'Nunito';letter-spacing:.5px}
.score-summary strong{font:700 25px 'Nunito';display:block;margin-top:4px;color:var(--ink)}
.round-status{background:var(--card);padding:0 var(--sp-7) var(--sp-4);display:flex;align-items:flex-start;gap:var(--sp-2)}
.round-status .dot{flex-shrink:0;width:9px;height:9px;border-radius:50%;background:var(--orange);margin-top:5px;box-shadow:0 0 0 4px #fff0e2}
.round-status .dot.done{background:var(--green-dark);box-shadow:0 0 0 4px #e3fbf1}
.round-status p{margin:0;font-size:12.5px;color:var(--muted);line-height:1.5}
.round-status p b{color:var(--ink);font-weight:700}
.scored-check{margin-left:7px;width:31px;height:31px;border-radius:50%;display:grid;place-items:center;background:#e3fbf1;color:var(--green-text);font-weight:700;font-size:14px;flex-shrink:0}
.table,.rounds{padding:var(--sp-5) var(--sp-7) 0;background:var(--card)}
/* Histórico e Conta seguem o mesmo fundo transparente das outras telas de
   navegação (ver .form-page/.games-wrap) — .table/.rounds continuam
   sólidos (tela de jogo em si, sempre com o próprio pano de fundo). */
.history-wrap,.account-wrap{padding:var(--sp-5) var(--sp-7) 0;background:transparent}
.rounds{padding-bottom:36px;border-radius:0 0 22px 22px}
.table{padding-top:24px}

/* Modo imersivo (mesa em andamento, 8 Maluco/Pife): fundo escuro/roxo por
   trás da mesa de feltro, sem o header padrão do app — a mesa deve ser o
   único protagonista da tela. Sem fundo custom escolhido, usa um roxo
   texturizado (reaproveita o mesmo padrão de naipes do fundo padrão do
   app, só que numa base mais escura) pra lembrar "pano de cassino" sem
   precisar de asset novo. Com fundo custom escolhido na criação da mesa,
   ele entra por trás igual já funcionava — a personalização fica no que
   envolve a mesa, o feltro em si continua limpo pra não atrapalhar leitura. */
/* Mesmo jpg de assets/bg-image/, só que escurecido com uma vinheta radial
   por cima (multi-layer background) — pro modo imersivo da mesa continuar
   escuro/roxo sem precisar de um segundo asset. */
/* --personal-bg-url: fundo ambiente PESSOAL (escolhido por cada jogador na
   tela de conta, categoria "bg" — nível 4+, 40 🪙 os extras) — setado via
   JS em layout()/renderMesa8()/renderPife(), sempre com um valor definido
   (o padrão é BG_MESA[0] — free/simples-01.webp — quando a pessoa não escolheu
   nada; o fallback aqui só cobre um cenário sem esse JS rodando ainda;
   bg-image-oficial.png virou a cena do cassino usada só no fundo do app
   fora da partida, ver body{} acima). */
body.game-immersive{background-color:#241238;
  /* Trava o scroll da PÁGINA durante a partida — sem isso dava pra
     arrastar o fundo (bounce do iOS, ou um scroll acidental durante o
     jogo). O conteúdo já é pensado pra caber na tela (min-height:100dvh
     abaixo); .table ganha overflow-y:auto como rede de segurança pra
     telas realmente pequenas/muita gente na mesa não cortarem conteúdo. */
  height:100dvh;overflow:hidden;overscroll-behavior:none}
/* Ver comentário no body{} sobre o ::before (attachment:fixed no body
   direto tinha bug de repintura no iOS). */
body.game-immersive::before{background-image:radial-gradient(ellipse at center, rgba(20,8,32,.25) 0%, rgba(10,4,18,.6) 100%), var(--personal-bg-url, url('/assets/background/free/simples-01.webp'));background-repeat:no-repeat,no-repeat;background-position:center,center;background-size:cover,cover}
body.game-immersive .table{overflow-y:auto;-webkit-overflow-scrolling:touch}
/* min-height:100dvh (viewport "dinâmico", já descontando barra do
   navegador no mobile) + flex-column: a mesa (.mesa8-table, flex:1) fica
   com exatamente a altura que sobra depois do resto (barra/timer/mão/sair)
   — cabe na tela sem scroll em qualquer aparelho, sem precisar de JS pra
   medir nada. */
/* ACHADO: `.table` (a section da mesa) é a MESMA classe usada por
   `.table,.rounds,.history-wrap,.account-wrap{background:var(--card)}`
   (regra genérica de "moldura de conteúdo" do resto do app) — isso pintava
   um retângulo sólido (branco antes, roxo-card agora) atrás da mesa esse
   tempo todo. Provavelmente a causa real do fundo branco reportado nas
   conversas anteriores (não só a View Transition, que também contribuía).
   Aqui zera pra deixar o fundo do body/moldura aparecerem. */
body.game-immersive .table{display:flex;flex-direction:column;min-height:100dvh;padding:calc(10px + env(safe-area-inset-top)) 10px 0;background:transparent}
/* Mão + timer + "sair da mesa" (mesa8-hand-dock) saem do fluxo normal e
   flutuam fixos na parte de baixo da tela — antes ocupavam espaço reservado
   na coluna flex, "achatando" a mesa (sobrava pouca altura pro oval no
   mobile). Flutuando por cima, a mesa (flex:1) usa quase 100% da altura
   disponível; o degradê escuro por baixo garante leitura das cartas mesmo
   sobre o pano/moldura. */
/* pointer-events:none no container + auto nos filhos: a caixa do dock é
   retangular, mas o topo dela é transparente (degradê) — sem isso, a área
   "vazia" (visualmente transparente, mas ainda dentro da caixa) engolia os
   toques no monte/descarte que ficam por baixo dela, na mesa. */
body.game-immersive .mesa8-hand-dock{position:fixed;left:0;right:0;bottom:0;z-index:5;max-width:640px;margin:0 auto;padding:26px 10px calc(10px + env(safe-area-inset-bottom));background:linear-gradient(180deg, rgba(24,10,40,0) 0%, rgba(24,10,40,.82) 26%, rgba(24,10,40,.94) 100%);pointer-events:none}
body.game-immersive .mesa8-hand-dock>*{pointer-events:auto}
@media (min-width:860px){ body.game-immersive .mesa8-hand-dock{max-width:min(1040px, 92vw)} }
/* Desktop/landscape (referência: mesa de pôquer com moldura vertical
   centralizada e sobra de espaço nas laterais pro chat/menu/fichas nos
   cantos). A arte da mesa (.mesa8-table) é um PNG único com proporção
   fixa 941/1672 (vertical) — chegamos a girar a moldura toda 90° via
   transform pra "deitar" ela de vez, mas o resultado quebrava o tamanho
   (o rotate soma a caixa ANTES da rotação ao fluxo do flex, então numa
   tela larga o resultado saía gigante/cortado, sobrepondo a mão — ver
   print reportado). Voltamos pro ajuste mais simples e estável: só
   reorganiza o que fica AO REDOR da mesa (menu/placar e "sair da mesa"
   saem do fluxo em coluna e vão pros cantos fixos), liberando a mesa pra
   crescer só pela ALTURA disponível — sobra espaço vazio nas laterais em
   vez de esticar, mas sem o bug de tamanho da rotação. */
@media (min-width:900px) and (min-aspect-ratio:6/5){
  body.game-immersive .table{flex-direction:column;align-items:center;justify-content:center;padding-top:calc(10px + env(safe-area-inset-top))}
  body.game-immersive .mesa8-immersive-bar{position:fixed;top:calc(14px + env(safe-area-inset-top));left:20px;right:20px;z-index:6;margin:0;justify-content:space-between}
  body.game-immersive .mesa8-immersive-label{position:static}
  body.game-immersive .mesa8-score-btn{position:static}
  body.game-immersive .mesa8-table{height:min(calc(100dvh - env(safe-area-inset-top) - 34px), calc((100vw - 340px) * 1.7768));margin:0 auto}
  body.game-immersive .mesa8-leave-link{position:fixed;left:20px;bottom:calc(18px + env(safe-area-inset-bottom));margin:0;z-index:6}
}
.mesa8-immersive-bar{display:flex;align-items:center;justify-content:center;gap:10px;margin:2px 0 0;position:relative}
.mesa8-immersive-label{margin:0;text-align:center;font:700 12px 'Nunito';color:rgba(255,255,255,.55);text-transform:uppercase;letter-spacing:.5px}
.mesa8-score-btn{position:absolute;right:0;background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.2);color:#fff;font:700 11px 'Nunito';padding:6px 12px;border-radius:100px;cursor:pointer}
.mesa8-score-btn:active{background:rgba(255,255,255,.22)}
.mesa8-leave-link{display:block;margin:14px auto 6px;background:none;border:0;color:rgba(255,255,255,.45);font:600 12px 'Nunito';text-decoration:underline;text-underline-offset:2px;cursor:pointer;padding:6px}
/* Textos que ficam soltos no vão entre a mesa e a mão (fora dos cards com
   fundo próprio) precisam virar claros nesse modo — senão some no escuro. */
body.game-immersive #mesa8-timer{color:#fff !important}
body.game-immersive .mesa8-fallback-list + div .mesa8-pile-label{color:rgba(255,255,255,.75) !important}

.players{margin-top:14px;border-top:1px solid var(--line)}
.player{display:flex;align-items:center;gap:12px;padding:13px 3px;border-bottom:1px solid var(--line)}
.player .avatar{margin:0;width:40px;height:40px;font-size:14px}
.player-name{display:grid;gap:3px;flex:1}
.player-name strong{font-size:14px;color:var(--ink)}
.player-name strong small{color:var(--purple);font:9px 'Nunito';margin-left:4px}
.player-name span{font-size:12px;color:#5b52d6;font-weight:600}
.score{text-align:right;display:grid;line-height:1}
.score b{font:700 24px 'Nunito';color:var(--ink)}
.score small{font:9px 'DM Mono';color:var(--muted)}
.add-score{margin-left:7px;border:0;background:var(--gold);color:var(--gold-ink);border-radius:10px;width:34px;height:34px;font-size:20px;font-weight:700;cursor:pointer;box-shadow:0 3px 0 var(--gold-dark)}
.out .score b{color:#e5514a}
.player.me,.player.active-turn{background:#f1ecff}
.player.me .player-name strong,.player.active-turn .player-name strong{color:#2b2251}
.player.me .player-name small,.player.active-turn .player-name small,.player.me .player-name span,.player.active-turn .player-name span{color:#786fa6}
.player.me .score b,.player.active-turn .score b{color:#2b2251}
.player.me .score small,.player.active-turn .score small{color:#786fa6}
.mesa8-fallback-list .player{opacity:.55;transition:opacity .2s ease}
.mesa8-fallback-list .player.active-turn{opacity:1;border-radius:12px;box-shadow:inset 0 0 0 2px var(--gold)}
.player .turn-badge{margin-left:auto;font-size:16px}
.player-name small{color:var(--muted);font-size:12px}
.last-card-badge{margin-left:auto;background:#ffe1a8;color:#8a5a00;font:700 10px 'Nunito';padding:4px 8px;border-radius:20px;white-space:nowrap;animation:pulse-badge 1.1s ease-in-out infinite}
/* Variante compacta pro "Fina!" no assento circular da mesa (coluna estreita
   de 74px, sem o contexto de linha flex do .player que o badge padrão usa). */
.seat-fina-badge{margin:0;background:#ffe1a8;color:#8a5a00;font:800 8px 'Nunito';padding:2px 6px;border-radius:10px}
@keyframes pulse-badge{0%,100%{transform:scale(1)}50%{transform:scale(1.07)}}

/* ---------- Mesa do 8 Maluco: layout circular + cartas de baralho ---------- */
/* Aro ornamentado (verde/dourado/vinho/preto) + feltro: dois PNGs de
   verdade em assets/bg-mesa/ (mesma proporção 526x904, transparentes fora
   da forma), empilhados como duas camadas de background — a moldura por
   cima, o feltro embaixo. Faz o papel que antes era simulado com sombras
   inset em CSS. background-size:100% 100% estica pra acompanhar a altura
   real da mesa (flex, ver abaixo) mesmo quando o box não bate exatamente
   com a proporção nativa do PNG. */
/* --mesa-frame-url/--mesa-felt-url: tipo de mesa (categoria "mesa", nível
   9+, 100 🪙 os extras) — setados via JS por partida (table.bg_key,
   compartilhado, quem escolhe é o host ao criar), com o par clássico como
   valor padrão de fallback. */
.mesa8-table{position:relative;margin:4px auto;
  background-image:var(--mesa-url, url('/assets/bg-mesa/free/mesa-01.webp'));
  background-repeat:no-repeat;
  background-position:center;
  background-size:100% 100%;
  /* A imagem da mesa é um PNG único (pano+moldura já desenhados, proporção
     fixa 941x1672 — vertical, ~1.7768:1 altura/largura). Precisa caber
     INTEIRA sem distorcer nas duas dimensões (não só a altura, ver bug
     anterior com flex:1 puro — numa tela estreita e alta a altura
     disponível sobrava mais que a largura permitia, esticando a mesa
     verticalmente mesmo com aspect-ratio). height agora é o menor entre
     "o que sobra de altura na tela" e "o que a largura disponível permite
     nessa proporção" — o mesmo cálculo de um object-fit:contain, só que
     em CSS puro via min()/calc(), sem JS/medição de viewport. width segue
     a altura via aspect-ratio (auto). Os descontos (90px etc.) são uma
     estimativa da barra imersiva + respiro; não precisam ser exatos. */
  aspect-ratio:941/1672;
  height:min(calc(100dvh - env(safe-area-inset-top) - 90px), calc((100vw - 20px) * 1.7768));
  width:auto;max-width:100%;
  flex:0 0 auto}

/* Anel de contagem regressiva ao redor do avatar de quem está na vez —
   conic-gradient atualizado a cada segundo via JS (scheduleMesa8Countdown/
   schedulePifeCountdown), esvaziando conforme o tempo acaba. */
.turn-ring{display:inline-block;border-radius:26%;line-height:0}
.turn-ring.active{padding:3px;background:conic-gradient(var(--ring-color,#28d17c) calc(var(--turn-pct,100)*1%), rgba(255,255,255,.3) 0);transition:background .3s linear}
.mesa8-seats{position:absolute;inset:0}
.mesa8-seat{position:absolute;transform:translate(-50%,-50%);display:flex;flex-direction:column;align-items:center;gap:3px;width:74px;text-align:center;opacity:.85;transition:opacity .2s ease}
.mesa8-seat.active-turn{opacity:1}
.mesa8-seat.active-turn .avatar{outline:3px solid var(--gold);outline-offset:2px}
.mesa8-seat .avatar{width:38px;height:38px;font-size:13px;box-shadow:0 2px 0 rgba(0,0,0,.25)}
.mesa8-seat.active-turn .avatar{animation:seat-glow 1.1s ease-in-out infinite}
.mesa8-seat-name{font:700 11px 'Nunito';color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.45);max-width:74px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Placar do Pife (várias rodadas — score em pife_table_players) — pontos
   ao lado do nome no assento, no card do fallback list, e um resumo da
   sua própria pontuação em cima da mão. */
.pife-seat-score{color:var(--gold);font-weight:800}
.pife-my-score{text-align:center;margin:0 0 8px;font:700 12px 'Nunito';color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.4)}
.pife-my-score b{color:var(--gold)}
.pife-scoreboard{margin:18px 0;text-align:left}
/* color explícito: --ink é claro (pensado pro fundo escuro do app), mas
   esse card tem fundo claro — sem isso o nome ficava quase invisível
   (texto claro sobre fundo claro). */
.pife-score-row{display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:12px;background:#f8f6ff;color:#2b2251;margin-bottom:6px}
.pife-score-row b{margin-left:auto;color:var(--purple-dark);font-size:13px}
.pife-score-row.eliminated{opacity:.55}
.pife-score-row.eliminated b{color:var(--muted)}
.mesa8-seat-meta{font:600 9px 'DM Mono';color:#e3ffe9;text-shadow:0 1px 2px rgba(0,0,0,.45)}
/* Mesa cheia (8-10 jogadores, mesa8SeatPosition/useCircularSeats sobem o
   limite pra 9 adversários no oval em vez de cair pra lista) — assentos
   mais apertados no arco, então tudo encolhe um pouco pra não sobrepor. */
.mesa8-seats.crowded .mesa8-seat{width:56px;gap:2px}
.mesa8-seats.crowded .mesa8-seat .avatar{width:30px;height:30px;font-size:11px}
.mesa8-seats.crowded .mesa8-seat-name{font-size:9.5px;max-width:56px}
.mesa8-seats.crowded .mesa8-seat-meta{font-size:8px}
.mesa8-seats.crowded .mesa8-seat-cards{width:26px;height:20px}
.mesa8-seats.crowded .mesa8-seat-count{width:15px;height:15px;font-size:9px;right:-4px;bottom:-3px}
.mesa8-seat.is-out{opacity:.4}
@keyframes seat-glow{0%,100%{box-shadow:0 0 0 3px var(--gold),0 2px 0 rgba(0,0,0,.25)}50%{box-shadow:0 0 0 6px var(--gold),0 2px 0 rgba(0,0,0,.25)}}

/* Cartas na mão de cada adversário: leque de cartinhas viradas + selo com
   a quantidade — sobe/desce ao vivo conforme compra/joga, sem revelar o
   conteúdo da mão (só a contagem, que já vem do servidor). */
.mesa8-seat-cards{position:relative;width:34px;height:26px;margin-bottom:2px}
.mesa8-seat-cards .mini-back{position:absolute;top:2px;width:15px;height:21px;border-radius:3px;background-image:var(--deck-image, repeating-linear-gradient(135deg, var(--deck-dark) 0 4px, var(--deck-light) 4px 8px));background-size:cover;background-position:center;border:1px solid rgba(255,255,255,.3);box-shadow:0 1px 3px rgba(0,0,0,.35)}
.mesa8-seat-cards .mini-back:nth-child(1){left:0;top:4px;transform:rotate(-10deg)}
.mesa8-seat-cards .mini-back:nth-child(2){left:9px;top:0;transform:rotate(0deg);z-index:1}
.mesa8-seat-cards .mini-back:nth-child(3){left:18px;top:4px;transform:rotate(10deg)}
.mesa8-seat-count{position:absolute;right:-6px;bottom:-4px;background:var(--gold);color:var(--gold-ink);font:800 10px 'Nunito';width:18px;height:18px;border-radius:50%;display:grid;place-items:center;box-shadow:0 1px 3px rgba(0,0,0,.4);border:2px solid #fff;z-index:2}
.mesa8-seat-count.last{background:#ff5e7a;color:#fff;animation:pulse-badge 1.1s ease-in-out infinite}
/* Distribuição da mão nova: leque de cada adversário "pipoca" na tela em
   sequência (delay escalonado via animation-delay inline), dando o mesmo
   feedback de "começou" que já existe na própria mão. */
/* Mão nova já chegou pronta do servidor junto com o resultado da mão
   anterior — fica invisível (mas ocupando o espaço, sem pular layout)
   enquanto o placar (mesa8BattedToast) ainda tá na tela; vira "dealing"
   só depois que ele some (ver renderMesa8). */
.mesa8-seat.pending-deal,.mesa8-pile-btn.pending-deal,.mesa8-hand.pending-deal{visibility:hidden}
.mesa8-seat.dealing .mesa8-seat-cards{animation:seat-deal-in .4s cubic-bezier(.34,1.56,.64,1) backwards}
@keyframes seat-deal-in{from{transform:translate(var(--dx,0),var(--dy,-16px)) scale(.3);opacity:0}to{transform:translate(0,0) scale(1);opacity:1}}

.mesa8-center{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:flex;align-items:flex-start;gap:20px}
/* Presidente pode ter MUITAS cartas na mão (até 20 com 3 jogadores),
   quebrando em várias linhas no celular — a mão fixa no rodapé
   (.mesa8-hand-dock é position:fixed, ver regra dela) cresce junto e
   cobria a carta central, que fica no meio vertical da mesa igual aos
   outros jogos (bug relatado: "não dá pra ver a carta central"). Só
   nessa mesa, sobe o centro pra ficar sempre acima da mão, não importa
   quantas linhas ela tiver. */
.presidente-table .mesa8-center{top:28%}
.mesa8-pile{position:relative;width:46px;height:64px}
.mesa8-pile .card8-back{position:absolute}
.mesa8-pile .card8-back:nth-child(1){left:0;top:0}
.mesa8-pile .card8-back:nth-child(2){left:3px;top:-3px}
.mesa8-pile .card8-back:nth-child(3){left:6px;top:-6px}
.mesa8-pile-label{margin-top:8px;font:700 10px 'Nunito';color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.45)}
/* "Vira" (a carta virada que define o coringa) — mostrada como uma carta
   de verdade encostada em cima do monte, em vez do texto "Coringa da
   mão: X (vira: Y)" que ficava solto na tela. */
.mesa8-pile-anchor{position:relative;padding-top:26px}
.pife-vira-card{position:absolute;top:0;left:50%;transform:translateX(-50%) rotate(-8deg);z-index:2;pointer-events:none;filter:drop-shadow(0 3px 4px rgba(0,0,0,.4))}
/* Truco (protótipo) — vaza (as 2 cartas na mesa) fica ao lado da carta
   vira, dentro do mesmo .mesa8-center; cada carta jogada entra com o
   mesmo "pop" do .mesa8-hand.dealing (ver deal-in). */
.truco-trick-area{display:flex;align-items:flex-end;gap:16px;min-height:96px;padding-top:26px}
.truco-trick-card{display:flex;flex-direction:column;align-items:center;gap:5px;animation:deal-in .3s ease backwards}
.truco-trick-card.bot{margin-bottom:14px}
.truco-trick-card small{font:700 11px 'Nunito';color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.5)}
/* Banner de fim de mão/partida — sobrepõe o centro da mesa (mesmo lugar da
   vaza) em vez de empurrar o layout; confete (só na vitória da partida)
   cobre a mesa inteira por trás. */
.truco-mao-banner{position:absolute;inset:0;z-index:4;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;padding:0 20px;text-align:center}
.truco-stake-pill{display:inline-block;margin-left:6px;padding:3px 11px;border-radius:100px;background:rgba(255,255,255,.16);color:#fff;font:700 11px 'Nunito';vertical-align:middle}
/* Aviso de quem ganhou a rodada (1ª/2ª/3ª vaza) — pill curta que aparece
   por cima da vaza durante o trucoResolveTrick/trucoSettleTrick (ver
   app.js), some sozinha quando a mesa é recolhida pro próximo lance. */
.truco-trick-toast{position:absolute;left:50%;bottom:14px;transform:translateX(-50%);z-index:5;padding:7px 18px;border-radius:100px;background:rgba(20,10,36,.88);border:1px solid rgba(255,255,255,.25);color:#fff;font:700 12px 'Nunito';white-space:nowrap;box-shadow:0 4px 12px rgba(0,0,0,.4);animation:truco-toast-in .25s cubic-bezier(.34,1.56,.64,1) backwards}
.truco-trick-toast.player{border-color:var(--gold);color:var(--gold)}
@keyframes truco-toast-in{from{transform:translateX(-50%) translateY(8px) scale(.7);opacity:0}to{transform:translateX(-50%) translateY(0) scale(1);opacity:1}}
/* Pedido de truco/6/9/12 — banner grande no centro da mesa, cobre tudo
   por um instante (z-index acima do resto). Cor muda por valor (gold →
   laranja → vermelho conforme escala) e por fase (pedindo/aceitou/correu). */
.truco-call-banner{position:absolute;inset:0;z-index:6;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;background:rgba(10,4,20,.55);animation:truco-call-fade .2s ease}
@keyframes truco-call-fade{from{opacity:0}to{opacity:1}}
.truco-call-label{font:900 40px 'Nunito';color:#fff;letter-spacing:1px;text-shadow:0 4px 10px rgba(0,0,0,.5);animation:truco-call-pop .5s cubic-bezier(.34,1.56,.64,1) backwards}
@keyframes truco-call-pop{from{transform:scale(.4) rotate(-8deg);opacity:0}60%{transform:scale(1.15) rotate(2deg)}to{transform:scale(1) rotate(0);opacity:1}}
.truco-call-sub{font:700 14px 'Nunito';color:#fff;background:rgba(255,255,255,.16);padding:5px 16px;border-radius:100px}
.truco-call-banner.asking .truco-call-label,.truco-call-banner.incoming .truco-call-label{color:var(--gold)}
.truco-call-banner.accepted .truco-call-label,.truco-call-banner.youAccepted .truco-call-label{color:var(--green)}
.truco-call-banner.ran .truco-call-label,.truco-call-banner.youRan .truco-call-label{color:var(--danger)}
/* Pedido de truco DO BOT — precisa de resposta (não é só passivo como o
   próprio pedido do jogador, que resolve sozinho). */
.truco-call-actions{display:flex;gap:10px;margin-top:4px}
/* Linha "Correr" + "Pedir Truco" centralizada (antes só o Pedir Truco
   sozinho, sem alinhamento, ficava colado na esquerda do painel). */
.truco-actions-row{display:flex;justify-content:center;align-items:center;gap:8px;margin-top:6px;flex-wrap:wrap}
/* Botão de correr — outline vermelho pequeno, ao lado do Pedir Truco (não
   reaproveita .warning porque esse é sempre 100% de largura, feito pra
   CTA sozinho tipo "Sair da mesa"). */
.truco-run-btn{background:rgba(239,113,133,.14);border:1px solid var(--danger);border-radius:14px;color:var(--danger);padding:11px 16px;font:700 14px 'Nunito';cursor:pointer}
.truco-run-btn:active{background:rgba(239,113,133,.26)}
.truco-run-btn:disabled{opacity:.45;pointer-events:none}
/* Re-pele visual do Truco (.truco-skin, sempre ligada no protótipo) —
   referência: print de um shop/mesa estilo "battle royale de carteado"
   que o Gean mandou (avatar com anel neon fixo, nome+saldo numa pill
   sólida colorida, fan de cartas na mão já existia antes — ver
   .mesa8-seat-cards/.mini-back). Só troca cor/adorno em cima da mesma
   estrutura (.mesa8-seat/.turn-ring), sem mudar layout. */
.truco-skin .turn-ring{border-radius:50%;box-shadow:0 0 0 2px #1fd6ff,0 0 10px rgba(31,214,255,.6)}
.truco-skin .turn-ring.active{box-shadow:0 0 0 2px #1fd6ff,0 0 14px rgba(31,214,255,.9)}
.truco-skin .avatar{border-radius:50%}
.truco-seat-badge{display:flex;flex-direction:column;align-items:center;gap:2px;background:linear-gradient(160deg,#1fae5a,#0d7a3c);color:#fff;font:800 11px 'Nunito';padding:4px 10px;border-radius:10px;box-shadow:0 2px 0 rgba(0,0,0,.3);max-width:none;white-space:nowrap;margin-top:2px}
.truco-seat-score{display:inline-flex;align-items:center;gap:3px;font:800 11px 'Nunito';color:#ffe066}
.truco-seat-score .coin-icon{width:12px;height:12px}
/* Pife — revelação da mão vencedora antes do modal de vitória (ver
   renderPife/pifeRevealShown em app.js): cada carta "sobe" em sequência
   (animation-delay escalonado por carta), com uma pausa no final antes de
   trocar pro modal de placar. Tudo dentro do .mesa8-table (mesmo pano das
   outras telas), posicionado ABSOLUTO no meio do oval — não mais como
   bloco solto abaixo da mesa (saía da tela, precisava rolar pra ver). */
.pife-reveal-vira{position:absolute;left:50%;top:14%;transform:translate(-50%,-50%);text-align:center;z-index:2}
.pife-reveal-vira .pife-vira-card{position:static;transform:none}
.pife-reveal-dock{position:absolute;left:50%;top:58%;transform:translate(-50%,-50%);z-index:2;width:88%;text-align:center}
.pife-reveal-banner{margin:0 0 12px;font:800 14px 'Nunito';color:#fff;text-shadow:0 2px 4px rgba(0,0,0,.5)}
.pife-reveal-cards{display:flex;flex-wrap:wrap;justify-content:center;gap:6px}
.pife-reveal-card{display:inline-block;animation:pife-reveal-in .4s cubic-bezier(.34,1.56,.64,1) backwards}
@keyframes pife-reveal-in{from{transform:translateY(60px) scale(.5) rotate(-6deg);opacity:0}to{transform:translateY(0) scale(1) rotate(0);opacity:1}}
/* "Vou jogar"/"Não vou jogar" — tela de confirmação antes de cada mão (ver
   pife_confirm_play). Mesma ideia de posicionamento da revelação da mão
   vencedora (absoluto, centralizado no oval da mesa) — pedido explícito
   de ficar centralizado, não um botão perdido no rodapé. */
.pife-confirm-dock{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:2;width:88%;text-align:center}
.pife-confirm-title{margin:0 0 10px;font:800 15px 'Nunito';color:#fff;text-shadow:0 2px 4px rgba(0,0,0,.5)}
.pife-confirm-question{margin:12px 0 6px;font:700 13px 'Nunito';color:#fff;text-shadow:0 1px 3px rgba(0,0,0,.5)}
.pife-confirm-forced{margin:6px 0 0;font:700 12px 'Nunito';color:var(--gold);text-shadow:0 1px 3px rgba(0,0,0,.5)}
.pife-confirm-actions{display:flex;flex-direction:column;gap:10px;margin:16px auto 0;max-width:260px}
/* Selo de histórico no canto do descarte — abre showMoveHistoryModal (app.js)
   com a grade de cartas jogadas na mão atual, em ordem. */
.mesa8-discard-slot,.mesa8-discard-wrap{position:relative;display:inline-block}
.discard-history-btn{position:absolute;top:-8px;right:-8px;width:26px;height:26px;border-radius:50%;border:2px solid #fff;background:rgba(20,14,40,.75);color:#fff;font-size:13px;display:grid;place-items:center;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,.35);z-index:3}
.history-modal{max-width:420px}
.history-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(64px,1fr));gap:10px;margin-top:14px;max-height:60vh;overflow-y:auto}
.history-cell{display:flex;flex-direction:column;align-items:center;gap:4px}
.history-cell-name{font:700 10px 'Nunito';color:var(--muted);text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:64px}

/* Monte vira o próprio botão de comprar — nada de botão separado de
   "Comprar carta" no layout circular, é só tocar no monte. Pisca quando
   a compra é obrigatória (sem jogada válida ou 7 pendente). */
.mesa8-pile-btn{border:0;background:none;padding:6px;margin:-6px;cursor:pointer;border-radius:14px;transition:transform .12s ease}
.mesa8-pile-btn:not(:disabled):active{transform:translateY(2px)}
.mesa8-pile-btn:disabled{cursor:not-allowed;opacity:.75}
.mesa8-pile-btn.needs-draw{animation:pile-pulse 1.1s ease-in-out infinite}
.mesa8-pile-btn.needs-draw .card8-back{box-shadow:0 2px 4px rgba(0,0,0,.35),0 0 0 3px var(--gold)}
@keyframes pile-pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.08)}}
.mesa8-pile-btn.dealing{animation:seat-deal-in .4s cubic-bezier(.34,1.56,.64,1) backwards}

/* Pife: o descarte também é tocável pra comprar (só o topo) — mesmo
   tratamento visual do monte, sem precisar de outro botão separado. */
.pife-discard-btn{border:0;background:none;padding:6px;margin:-6px;cursor:pointer;border-radius:14px;transition:transform .12s ease}
.pife-discard-btn:not(:disabled):active{transform:translateY(2px)}
.pife-discard-btn:disabled{cursor:not-allowed;opacity:.6}

.card8{position:relative;width:46px;height:64px;border-radius:7px;background:#fff;box-shadow:0 2px 4px rgba(0,0,0,.35);display:flex;flex-direction:column;justify-content:space-between;padding:4px;border:1px solid rgba(0,0,0,.08);font-family:'Nunito'}
.card8 .rank{font:700 12px 'Nunito';line-height:1;color:#2b2251}
.card8.red .rank,.card8.red .suit-big{color:#e5514a}
.card8 .suit-big{align-self:center;font-size:20px;line-height:1;color:#2b2251}
.card8-back{width:46px;height:64px;border-radius:7px;background-image:var(--deck-image, repeating-linear-gradient(135deg, var(--deck-dark) 0 6px, var(--deck-light) 6px 12px));background-size:cover;background-position:center;box-shadow:0 2px 4px rgba(0,0,0,.35);border:1px solid rgba(255,255,255,.25);display:flex;align-items:center;justify-content:center;color:#fff;font:800 15px 'Nunito'}
/* Presidente pode chegar a ~20 cartas na mão (3 jogadores) — do tamanho
   padrão (46x64) isso ocupa espaço demais no celular. Só nessa mão
   (.presidente-hand), cartas ~20% menores. */
.presidente-hand .card8{width:37px;height:52px;padding:3px}
.presidente-hand .card8 .rank{font-size:10px}
.presidente-hand .card8 .suit-big{font-size:16px}
/* Verso do baralho — 5 opções grátis de cor a partir do nível 4 (ver
   DECK_BACKS no app.js), aplicadas via data-deck no <body> (setado a cada
   render). Versos com arte de verdade setam --deck-image em vez de
   --deck-dark/--deck-light. */
body[data-deck="verde"]{--deck-dark:var(--green-dark);--deck-light:var(--green)}
body[data-deck="vermelho"]{--deck-dark:var(--danger-dark);--deck-light:var(--danger)}
body[data-deck="azul"]{--deck-dark:var(--blue-dark);--deck-light:var(--blue)}
body[data-deck="dourado"]{--deck-dark:var(--gold-dark);--deck-light:var(--gold)}
/* Verso do baralho com arte real (ver DECK_BACKS no app.js) — os que não
   estão aqui usam o padrão em gradiente definido acima. */
body[data-deck="intermediario-01"]{--deck-image:url('/assets/deck/intermediario/intermediario-01.webp')}
body[data-deck="intermediario-02"]{--deck-image:url('/assets/deck/intermediario/intermediario-02.webp')}
body[data-deck="intermediario-03"]{--deck-image:url('/assets/deck/intermediario/intermediario-03.webp')}
body[data-deck="intermediario-04"]{--deck-image:url('/assets/deck/intermediario/intermediario-04.webp')}
body[data-deck="intermediario-05"]{--deck-image:url('/assets/deck/intermediario/intermediario-05.webp')}
body[data-deck="premium-01"]{--deck-image:url('/assets/deck/premium/premium-01.webp')}
body[data-deck="premium-02"]{--deck-image:url('/assets/deck/premium/premium-02.webp')}
body[data-deck="premium-03"]{--deck-image:url('/assets/deck/premium/premium-03.webp')}
body[data-deck="premium-04"]{--deck-image:url('/assets/deck/premium/premium-04.webp')}
body[data-deck="premium-05"]{--deck-image:url('/assets/deck/premium/premium-05.webp')}
body[data-deck="china-01"]{--deck-image:url('/assets/deck/temas/china/china-01.webp')}
body[data-deck="china-02"]{--deck-image:url('/assets/deck/temas/china/china-02.webp')}
body[data-deck="china-03"]{--deck-image:url('/assets/deck/temas/china/china-03.webp')}
body[data-deck="china-04"]{--deck-image:url('/assets/deck/temas/china/china-04.webp')}
body[data-deck="china-05"]{--deck-image:url('/assets/deck/temas/china/china-05.webp')}
body[data-deck="natureza-01"]{--deck-image:url('/assets/deck/temas/natureza/natureza-01.webp')}
body[data-deck="natureza-02"]{--deck-image:url('/assets/deck/temas/natureza/natureza-02.webp')}
body[data-deck="natureza-03"]{--deck-image:url('/assets/deck/temas/natureza/natureza-03.webp')}
body[data-deck="natureza-04"]{--deck-image:url('/assets/deck/temas/natureza/natureza-04.webp')}
body[data-deck="natureza-05"]{--deck-image:url('/assets/deck/temas/natureza/natureza-05.webp')}

/* 8 curinga ganha um contorno arco-íris pulsante, pra se destacar como
   coringa mesmo à distância. */
.card8.wild{box-shadow:0 2px 4px rgba(0,0,0,.35),0 0 0 2px transparent;animation:wild-glow 1.8s ease-in-out infinite}
@keyframes wild-glow{0%,100%{box-shadow:0 2px 4px rgba(0,0,0,.35),0 0 0 2px #ff5e7a}20%{box-shadow:0 2px 4px rgba(0,0,0,.35),0 0 0 2px #ffb648}40%{box-shadow:0 2px 4px rgba(0,0,0,.35),0 0 0 2px #ffe14d}60%{box-shadow:0 2px 4px rgba(0,0,0,.35),0 0 0 2px #57d68d}80%{box-shadow:0 2px 4px rgba(0,0,0,.35),0 0 0 2px #57a9ff}}

.mesa8-hand{display:flex;justify-content:center;gap:4px;flex-wrap:wrap;margin:14px 0 20px;min-height:64px}
.mesa8-hand .card8-btn{border:0;background:none;padding:0;cursor:pointer;transition:transform .12s ease,opacity .2s ease;outline:none}
.mesa8-hand .card8-btn:not(:disabled):hover{transform:translateY(-6px)}
.mesa8-hand .card8-btn:disabled{cursor:not-allowed;opacity:.45}
.mesa8-hand .card8-btn.not-playable{opacity:.5}
.mesa8-hand .card8-btn.not-playable .card8{filter:grayscale(.6)}
.mesa8-hand .card8-btn.shake-invalid{animation:shake-invalid .4s ease}
.mesa8-hand .card8-btn.shake-invalid .card8{box-shadow:0 2px 4px rgba(0,0,0,.35),0 0 0 3px #e5514a}
@keyframes shake-invalid{0%,100%{transform:translateX(0)}20%{transform:translateX(-6px)}40%{transform:translateX(5px)}60%{transform:translateX(-4px)}80%{transform:translateX(3px)}}
.mesa8-hand.dealing .card8-btn{animation:deal-in .5s ease backwards}
/* Pife — reordenar a mão arrastando (ver enablePifeHandDrag em app.js).
   touch-action:none nas cartas: sem isso, o navegador tenta interpretar o
   toque inicial como scroll da página antes do JS conseguir detectar que é
   um arrasto (comum em touch — o gesto de rolar "ganha" da mão do JS). */
.pife-hand-drag .card8-btn{touch-action:none}
/* A carta original vira só um espaço reservado invisível durante o
   arrasto — quem aparece flutuando na tela é o .card8-ghost (clone em
   position:fixed, ver enablePifeHandDrag/JS), que segue o dedo sem
   nenhuma dependência da posição dela no flex (por isso nunca "pula"). */
.pife-hand-drag .card8-btn.dragging{opacity:0}
.card8-ghost{z-index:30;cursor:grabbing;transform:scale(1.08) rotate(-3deg);box-shadow:0 12px 26px rgba(0,0,0,.45);transition:none}
.card8-ghost .card8{outline:2px solid var(--gold)}

/* Presidente — carta(s) selecionada(s) na mão pra jogar (toque simples,
   sem arrastar — pode escolher mais de uma carta do mesmo valor). */
.card8-btn.selected{transform:translateY(-12px)}
.card8-btn.selected .card8{box-shadow:0 4px 10px rgba(0,0,0,.35),0 0 0 3px var(--gold)}
/* Cartas jogadas no centro da mesa — empilhadas com um respiro pequeno
   entre elas (a de baixo aparece "espiando" atrás), não lado a lado. Só
   de bater o olho já dá pra ver se é 1 carta ou um bloco de várias, sem
   precisar contar/ler o valor de cada uma (pedido: "precisa mostrar que
   tem duas, mesmo que seja empilhada"). O "×N" reforça a contagem com
   texto, ajuda ainda mais quando são 3-4 cartas iguais empilhadas. */
.presidente-pile{position:relative;display:flex;justify-content:center;align-items:center;gap:10px;min-height:78px}
.presidente-pile-stack{position:relative;height:78px}
.presidente-pile-card{position:absolute;top:0}
.presidente-pile-count{background:var(--gold);color:var(--gold-ink);font:800 13px 'Nunito';padding:3px 9px;border-radius:100px;box-shadow:0 2px 0 var(--gold-dark)}
/* Modal de revelação da troca de cartas no início de rodada (Presidente
   ⇄ Vagabundo, Vice-Presidente ⇄ Vice-Vagabundo) — ver
   showPresidenteExchangeReveal em app.js. */
.presidente-exchange-row{display:flex;gap:8px;justify-content:center;flex-wrap:wrap}

/* Reação por emoji (todas as mesas online) — ver emojiReactionBarHtml/
   sendEmojiReaction em app.js. Não é direcionada a ninguém, só aparece
   pra quem está com a mesa aberta no momento (broadcast do Realtime, sem
   gravar nada). */
.emoji-reactions{position:relative;display:flex;justify-content:center;margin:10px 0}
.emoji-toggle-btn{background:rgba(153,86,222,.16);border:1px solid var(--purple);width:40px;height:40px;border-radius:100px;font-size:19px;cursor:pointer;display:grid;place-items:center}
.emoji-picker{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);display:flex;gap:4px;background:var(--card);border-radius:100px;padding:6px 8px;box-shadow:0 8px 20px rgba(0,0,0,.4);z-index:20}
/* [hidden] empata em especificidade com a classe acima (0,1,0 os dois) —
   sem essa regra explícita, quem "ganha" é a última declarada (essa
   folha de estilo carrega depois da folha nativa do navegador), então o
   picker ficava sempre visível mesmo com o atributo hidden ligado. */
.emoji-picker[hidden]{display:none}
.emoji-pick-btn{border:0;background:none;font-size:22px;padding:4px;cursor:pointer;border-radius:50%;transition:transform .1s ease}
.emoji-pick-btn:active{transform:scale(1.25)}
.emoji-bubble{position:fixed;transform:translate(-50%,-100%);font-size:46px;pointer-events:none;z-index:45;animation:emoji-pop 1.8s ease forwards}
@keyframes emoji-pop{
  0%{opacity:0;transform:translate(-50%,-70%) scale(.4)}
  15%{opacity:1;transform:translate(-50%,-115%) scale(1.2)}
  30%{transform:translate(-50%,-110%) scale(1)}
  75%{opacity:1;transform:translate(-50%,-130%) scale(1)}
  100%{opacity:0;transform:translate(-50%,-170%) scale(.85)}
}
.mesa8-hand.dealing .card8-btn:nth-child(1){animation-delay:.04s}
.mesa8-hand.dealing .card8-btn:nth-child(2){animation-delay:.12s}
.mesa8-hand.dealing .card8-btn:nth-child(3){animation-delay:.2s}
.mesa8-hand.dealing .card8-btn:nth-child(4){animation-delay:.28s}
.mesa8-hand.dealing .card8-btn:nth-child(5){animation-delay:.36s}
.mesa8-hand.dealing .card8-btn:nth-child(6){animation-delay:.44s}
.mesa8-hand.dealing .card8-btn:nth-child(7){animation-delay:.52s}
.mesa8-hand.dealing .card8-btn:nth-child(n+8){animation-delay:.6s}
@keyframes deal-in{from{transform:translate(var(--dx,0),var(--dy,-22px)) scale(.55);opacity:0}to{transform:translate(0,0) scale(1);opacity:1}}

/* Carta "voadora": elemento solto (position:fixed) que percorre a tela do
   monte até a mão — criado/animado via JS (flyCardsToHand em app.js) e
   removido no final. Reaproveita o verso de carta já usado no monte. */
.flying-card8{position:fixed;width:48px;height:67px;border-radius:8px;background-image:var(--deck-image, repeating-linear-gradient(135deg, var(--deck-dark) 0 5px, var(--deck-light) 5px 10px));background-size:cover;background-position:center;border:2px solid rgba(255,255,255,.5);box-shadow:0 4px 12px rgba(0,0,0,.45);z-index:999;pointer-events:none;transition:transform .7s cubic-bezier(.3,.65,.35,1),opacity .7s ease .08s}
.mesa8-move-toast{position:fixed;left:50%;top:22%;transform:translate(-50%,-8px) scale(.85);opacity:0;background:rgba(20,8,26,.9);color:#fff;font:800 15px 'Nunito';padding:10px 20px;border-radius:100px;box-shadow:0 8px 20px rgba(0,0,0,.4);z-index:1000;pointer-events:none;transition:opacity .25s ease,transform .25s ease;white-space:nowrap}
.flying-card8-face{position:fixed;z-index:999;pointer-events:none;transition:transform .6s cubic-bezier(.3,.65,.35,1),opacity .6s ease .1s}
.flying-domino-tile{position:fixed;z-index:999;pointer-events:none;transition:transform .6s cubic-bezier(.3,.65,.35,1),opacity .6s ease .1s}
.mesa8-move-toast.show{opacity:1;transform:translate(-50%,0) scale(1)}
.mesa8-move-toast.suit{background:rgba(255,255,255,.96);color:#2b2251}

/* Carta jogada no monte: entra com um "pulo" leve, igual uma carta sendo
   batida na mesa. */
.card8.card-played{animation:card-played .5s ease backwards}
@keyframes card-played{from{transform:translateY(-26px) scale(.7) rotate(-8deg);opacity:.3}60%{transform:translateY(3px) scale(1.06) rotate(1deg)}to{transform:translateY(0) scale(1) rotate(0);opacity:1}}

/* Carta comprada: pisca um contorno dourado ao chegar na mão. */
.mesa8-hand .card8-btn.card-drawn{animation:card-drawn .8s ease}
@keyframes card-drawn{0%{transform:translateY(18px) scale(.75);opacity:.3}45%{transform:translateY(-5px) scale(1.07);box-shadow:0 0 0 3px var(--gold)}100%{transform:translateY(0) scale(1);box-shadow:0 0 0 0 transparent}}

/* "Alguém bateu": explosão de confete caindo + card central com o
   mini-placar da rodada (quem ganhou quanto), antes de cair na mão nova
   que já está por baixo. Bloqueia clique na mesa enquanto mostra. */
.mesa8-batted-overlay{position:fixed;inset:0;z-index:6;background:rgba(20,15,45,.55);display:grid;place-items:center;padding:20px;overflow:hidden;animation:overlay-fade .4s ease 2.4s forwards}
@keyframes overlay-fade{to{opacity:0;pointer-events:none}}
.mesa8-batted-card{position:relative;width:min(100%,340px);background:#fff;border-radius:22px;padding:22px 20px 18px;text-align:center;box-shadow:0 20px 50px rgba(0,0,0,.4);animation:banner-pop .4s cubic-bezier(.34,1.56,.64,1) both}
.mesa8-batted-banner{font:800 19px 'Nunito';color:#2b2251;margin-bottom:14px}
@keyframes banner-pop{from{transform:scale(.6);opacity:0}to{transform:scale(1);opacity:1}}
.hand-result-list{display:flex;flex-direction:column;gap:7px;text-align:left}
.hand-result-row{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:12px;background:var(--paper)}
.hand-result-row.me{box-shadow:0 0 0 2px var(--purple)}
.hand-result-row.winner{background:#fff7dd}
.hand-result-row.winner .hand-result-name{color:#2b2251}
.hand-result-name-wrap{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.hand-result-name{font:700 13px 'Nunito';color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hand-result-note{font:600 10px 'Nunito';color:var(--purple-light);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hand-result-row.winner .hand-result-note{color:var(--purple-dark)}
.hand-result-pts{font:800 12px 'DM Mono';color:var(--muted);flex-shrink:0}
.hand-result-row.winner .hand-result-pts{color:#8a5a00}
.hand-result-next{margin:14px 0 0;font-size:11.5px;color:var(--muted)}

/* Botão de comprar carta: sempre visível/destacado, e acende quando o
   jogador não tem nenhuma jogada válida na mão. */
.mesa8-actions{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;margin-top:4px}
.mesa8-draw-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;text-align:center;border:0;background:var(--purple-soft);color:#fff;font:700 14px 'Nunito';padding:13px 22px;border-radius:100px;cursor:pointer;box-shadow:0 3px 0 var(--purple-dark);transition:transform .12s ease}
.mesa8-draw-btn:active{transform:translateY(2px)}
.mesa8-draw-btn.needs-draw{background:var(--gold);color:var(--gold-ink);box-shadow:0 3px 0 var(--gold-dark);animation:draw-pulse 1.1s ease-in-out infinite}
@keyframes draw-pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.05)}}

/* Peça de confete reaproveitada tanto no "alguém bateu" quanto na tela de
   vitória — cai do topo girando e some antes de chegar embaixo. */
/* Cartas de baralho caindo (ver victoryConfettiHtml) em vez de emoji —
   miniatura de carta de verdade (fundo branco, canto arredondado) pra
   ficar reconhecível mesmo pequena, com rotação aleatória (--rotate)
   somada à volta completa da queda. */
.confetti-piece{position:absolute;top:-50px;display:inline-flex;align-items:center;justify-content:center;min-width:34px;height:44px;padding:0 6px;background:#fff;border-radius:7px;box-shadow:0 3px 6px rgba(0,0,0,.35);font:800 19px 'Nunito';color:#2b2251;animation-name:confetti-fall;animation-timing-function:ease-in;animation-fill-mode:forwards}
.confetti-piece.red{color:#e5514a}
@keyframes confetti-fall{from{transform:translateY(-50px) rotate(var(--rotate,0deg));opacity:1}to{transform:translateY(110vh) rotate(calc(var(--rotate,0deg) + 360deg));opacity:0}}

/* Tela de fim de partida do 8 Maluco: troféu quicando, faixa entrando com
   "pop" e cada linha do ranking surgindo em sequência. */
/* Encolhe um pouco em relação ao .form-page padrão (que vai de ponta a
   ponta, border-radius:0) — a moldura de vitória tem cantos ornamentados
   que ficavam cortados na borda da tela sem essa margem mínima. Padding
   extra (bem maior que o padrão do .form-page) pra nenhum conteúdo real
   (troféu, faixa, placar, botões) colar na borda desenhada da moldura. */
/* aspect-ratio 950/1267 = mesma proporção da arte da moldura (ver
   .buy-preview-victory na Loja) — garante que o card sempre tem a MESMA
   proporção da arte, então o object-fit:contain da moldura preenche o
   card inteiro certinho (sem sobrar tarja em branco nem esticar) não
   importa quantos jogadores tem no placar. max-height trava o tamanho em
   telas baixas/paisagem. Com isso o card não cresce mais junto com o
   conteúdo — quem cresce/rola por dentro é só o .finish8-scroll (ver
   abaixo), até 10 jogadores (máximo do 8 Maluco) sem esticar a moldura. */
.finish8-page{position:relative;overflow:hidden;margin:var(--sp-4) var(--sp-4) 0;border-radius:22px;padding:38px 28px 34px;aspect-ratio:950/1267;max-height:min(640px,82vh);display:flex;flex-direction:column}
.finish8-scroll{flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch}
/* Protótipo em teste (ver winnerFrameHtml em app.js): a moldura passou a
   emoldurar só o avatar do vencedor (.finish8-winner-frame, tamanho fixo),
   não mais o cartão inteiro — então o cartão em si volta a ser um
   .form-page normal, sem altura travada nem scroll interno. */
.finish8-page.winner-mode{aspect-ratio:auto;max-height:none;overflow:visible;display:block}
.finish8-page.winner-mode .finish8-scroll{overflow:visible}
.finish8-confetti{position:absolute;inset:0;pointer-events:none;overflow:hidden}
/* Moldura emoldurando só o avatar de quem venceu — mesma proporção
   950/1267 da arte (garante que a moldura sempre encaixa certinho, sem
   cortar/esticar, como o card inteiro fazia antes). Posição do avatar/nome
   dentro do miolo (top/bottom em %) é a parte mais sensível — ajustar
   junto com o usuário olhando o resultado real de cada arte de moldura. */
.finish8-winner-frame{position:relative;width:180px;max-width:56%;aspect-ratio:950/1267;margin:0 auto 14px}
.finish8-winner-frame-img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;pointer-events:none;z-index:3}
.finish8-winner-avatar{position:absolute;left:50%;top:40%;transform:translate(-50%,-50%);width:54%;aspect-ratio:1;border-radius:50%;background-size:cover;background-position:center;box-shadow:0 4px 14px rgba(0,0,0,.4);z-index:2;display:block}
.finish8-winner-avatar-fallback{display:flex;align-items:center;justify-content:center;background:var(--purple);color:#fff;font:800 26px 'Nunito'}
.finish8-winner-name{position:absolute;left:10%;right:10%;bottom:11%;z-index:2;color:#fff;font:800 13px 'Nunito';text-shadow:0 1px 3px rgba(0,0,0,.6);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Moldura de "Placar de Vitória" (Loja, categoria victory_frame) — cobre o
   cartão inteiro por cima de tudo (troféu, confete, placar); miolo
   transparente deixa o conteúdo aparecer, só a borda decorativa "flutua"
   por cima. */
/* object-fit:contain (não mais cover) — a arte da moldura é retrato fixo
   (proporção própria) e o card tem altura variável (placar com mais ou
   menos jogadores); com cover ela era esticada pra preencher a largura e
   cortava o topo/rodapé ornamentado. Contain sempre mostra a moldura
   inteira, centralizada, sem cortar nenhuma borda.
   z-index NEGATIVO (não mais 3): fica atrás de todo o conteúdo em fluxo
   normal (troféu, faixa, placar, botões — nenhum tem position setado, então
   pintam por cima de qualquer elemento posicionado com z-index negativo).
   Antes, com z-index positivo, a moldura pintava por cima de tudo e
   escondia o ícone do topo e o botão "Voltar" que ficava embaixo dela. */
.finish8-frame-img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;pointer-events:none;z-index:-1;border-radius:22px}
.finish8-trophy{animation:trophy-bounce .6s cubic-bezier(.34,1.56,.64,1) both}
/* Ícone real (mesma coroa do pódio do Ranking, ver .podium-crown) no lugar
   do emoji ♛ — consistência visual entre as duas telas que celebram o
   vencedor. */
.finish8-trophy-img{width:64px;height:auto;margin:0 auto 8px;display:block;filter:drop-shadow(0 3px 4px rgba(0,0,0,.35))}
@keyframes trophy-bounce{0%{transform:scale(.3) translateY(-16px);opacity:0}60%{transform:scale(1.15) translateY(2px);opacity:1}100%{transform:scale(1) translateY(0)}}
.finish8-ribbon{animation:banner-pop .45s cubic-bezier(.34,1.56,.64,1) .15s both}
.finish8-rank-row{animation:rank-row-in .4s ease both}
@keyframes rank-row-in{from{transform:translateX(-14px);opacity:0}to{transform:translateX(0);opacity:1}}

.eliminated-label{padding:14px 3px 4px;font:700 12px 'Nunito';color:var(--muted);text-transform:none}

/* Título "Sua vez!" ganha um leve destaque animado — hierarquia mais
   clara de quando é realmente a hora de agir. */
.my-turn-h1{color:var(--gold) !important;animation:my-turn-pop .5s cubic-bezier(.34,1.56,.64,1)}
@keyframes my-turn-pop{from{transform:scale(.85)}to{transform:scale(1)}}

/* Painel que separa visualmente "sua mão" do resto da tela — mais
   hierarquia, some no fundo em vez de flutuar solto na página. */
.mesa8-hand-panel{background:var(--card);border-radius:20px;padding:16px 14px 18px;margin-top:4px;box-shadow:0 2px 10px rgba(28,18,63,.08);transition:box-shadow .2s ease}
.mesa8-hand-panel .section-title{text-align:center}
.mesa8-hand-panel.my-turn{box-shadow:0 2px 14px rgba(255,200,0,.28),0 0 0 2px var(--gold)}
/* Modo imersivo: a mão gruda direto embaixo da mesa, sem gap/sombra —
   parece uma continuação da mesa, não um card separado flutuando. */
body.game-immersive .mesa8-hand-panel{margin-top:0;box-shadow:none;background:transparent}
body.game-immersive .mesa8-hand-panel.my-turn{box-shadow:0 0 0 2px var(--gold)}
/* Aviso "comprou, descarte" no Pife — precisa de contraste forte contra o
   pano da mesa (fundo escuro, mas nem sempre uniforme), então usa branco
   sólido em vez do --ink/--muted padrão, que ficavam meio apagados ali. */
.pife-hand-hint{text-align:center;margin:0 0 var(--sp-4);color:#fff;font:700 13px 'Nunito';text-shadow:0 1px 3px rgba(0,0,0,.5)}
.rounds>p{display:flex;justify-content:space-between;margin:0;padding:11px 0;border-bottom:1px solid var(--line);font-size:13px;color:var(--ink)}
.rounds>p span{color:var(--muted)}
.rounds>p b{color:var(--orange-dark)}
.winner-banner{margin:var(--sp-4) var(--sp-7) var(--sp-2);background:linear-gradient(160deg,#ffe08a,#ffce54);border:0;padding:var(--sp-4);border-radius:16px;display:flex;gap:var(--sp-3);align-items:center;box-shadow:0 4px 14px #eab30833}
.winner-banner>span,.trophy{flex-shrink:0;font-size:34px;line-height:1;color:#a86b00}
.winner-banner small{color:#8a5a00;font:10px 'Nunito';letter-spacing:1px}
.winner-banner strong{display:block;font:700 20px 'Nunito';margin-top:2px;color:#5c4400}
.winner-banner p{margin:2px 0 0;font-size:12px;color:#7a5300}

/* ---------- Tela de fim de partida (ranking, inspirada em referência
   enviada pelo usuário: faixa "You Win" + lista de colocação) ---------- */
.victory-ribbon{display:inline-block;background:linear-gradient(160deg,#ff6fa5,#e84f88);color:#fff;font:800 21px 'Nunito';padding:12px 30px;border-radius:100px;box-shadow:0 4px 0 #b83766;text-transform:uppercase;letter-spacing:.4px;margin-top:6px}
.rank-list{display:flex;flex-direction:column;gap:9px;text-align:left}
.rank-row{display:flex;align-items:center;gap:10px;padding:12px 16px;border-radius:14px;font:700 14px 'Nunito'}
.rank-row .rank-pos{font:800 13px 'Nunito';width:22px;flex-shrink:0;text-align:center}
.rank-row .avatar{flex-shrink:0}
.rank-row .rank-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rank-row .rank-score{flex-shrink:0;font:700 12px 'DM Mono'}
/* Textura + borda 3D (efeito entalhado): repeating-linear-gradient sutil
   por cima da cor (mesma família de textura usada em .form-page::before)
   e um box-shadow em camadas — luz por cima (inset), sombra por baixo
   (inset) e o "degrau" de baixo (offset), pra dar profundidade real em
   vez de só a cor lisa. Mesmo tratamento no pódio (.podium-gold etc) e
   nas linhas da lista (.rank-row) — top 3 e lista abaixo ficam com o
   mesmo acabamento. */
/* Sem textura aqui (só o pódio/top 3 tem) — mas o mesmo degrau colorido
   de baixo (o "border-bottom" do pódio, na real um box-shadow offset)
   continua, agora do mesmo tamanho do pódio (5px) em vez de 3px — ficava
   sutil demais pra notar por perto do drop-shadow externo. */
.rank-row.rank-gold{background:linear-gradient(160deg,#ffe08a,#ffce54);color:#5c4400;box-shadow:0 5px 0 #e0a800, 0 6px 14px rgba(20,10,40,.22), inset 0 2px 0 rgba(255,255,255,.75), inset 0 -3px 5px rgba(0,0,0,.16)}
.rank-row.rank-silver{background:linear-gradient(160deg,#f2f4f8,#dbe0ea);color:#2b2251;box-shadow:0 5px 0 #b7bfcf, 0 6px 14px rgba(20,10,40,.22), inset 0 2px 0 #fff, inset 0 -3px 5px rgba(0,0,0,.12)}
.rank-row.rank-bronze{background:linear-gradient(160deg,#eec39a,#dba06a);color:#4a2c0f;box-shadow:0 5px 0 #b97b3e, 0 6px 14px rgba(20,10,40,.22), inset 0 2px 0 rgba(255,255,255,.55), inset 0 -3px 5px rgba(0,0,0,.18)}
.rank-row.rank-plain,.rank-row.plain{background:linear-gradient(160deg,#fff,#f4f2fb);color:#2b2251;box-shadow:0 5px 0 #d8d2ea, 0 6px 14px rgba(20,10,40,.22), inset 0 1px 0 #fff, inset 0 -3px 5px rgba(28,18,63,.09)}

/* ---------- Ranking (tela #/ranking): pódio (top 3) + lista por XP ---------- */
.podium{display:grid;grid-template-columns:repeat(3,1fr);align-items:end;gap:10px;padding:28px var(--sp-6) 4px;background:transparent}
.podium-slot{display:flex;flex-direction:column;align-items:center;gap:4px;padding:16px 8px 14px;border-radius:18px;text-align:center;box-shadow:0 3px 0 rgba(0,0,0,.15)}
.podium-slot.empty-slot{box-shadow:none}
.podium-crown{position:absolute;top:-30px;left:50%;transform:translateX(-50%);width:44px;height:auto;filter:drop-shadow(0 3px 4px rgba(0,0,0,.35))}
.podium-slot{position:relative}
.podium-rank-bar{margin-top:8px;width:100%;padding:6px 0;border-radius:100px;font:800 13px 'Nunito';background:rgba(0,0,0,.12)}
.podium-gold .podium-rank-bar{background:#fff7dd;color:#8a5a00}
.podium-name{font:700 13px 'Nunito';max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.podium-level{font:600 10px 'Nunito';opacity:.8}
.podium-xp{font:800 13px 'DM Mono';margin-top:2px}
/* Textura mais discreta que a primeira tentativa: listras mais finas e
   bem menos opacas — só um "grão" de fundo, não compete com o conteúdo. */
.podium-gold{background-image:repeating-linear-gradient(135deg, rgba(255,255,255,.16) 0 3px, rgba(255,255,255,0) 3px 7px), linear-gradient(160deg,#ffe08a,#ffce54);color:#5c4400;box-shadow:0 5px 0 #e0a800, inset 0 2px 0 rgba(255,255,255,.6), inset 0 -3px 6px rgba(0,0,0,.14);padding-top:22px}
.podium-silver{background-image:repeating-linear-gradient(135deg, rgba(255,255,255,.18) 0 3px, rgba(255,255,255,0) 3px 7px), linear-gradient(160deg,#f2f4f8,#dbe0ea);color:#2b2251;box-shadow:0 3px 0 #b7bfcf, inset 0 2px 0 rgba(255,255,255,.75), inset 0 -3px 6px rgba(0,0,0,.1)}
.podium-bronze{background-image:repeating-linear-gradient(135deg, rgba(255,255,255,.13) 0 3px, rgba(255,255,255,0) 3px 7px), linear-gradient(160deg,#eec39a,#dba06a);color:#4a2c0f;box-shadow:0 3px 0 #b97b3e, inset 0 2px 0 rgba(255,255,255,.45), inset 0 -3px 6px rgba(0,0,0,.16)}
.rank-list-page{display:flex;flex-direction:column;gap:9px;padding:16px var(--sp-6) 96px;background:transparent}
.rank-sticky-me{position:fixed;left:0;right:0;bottom:0;z-index:2;display:flex;align-items:center;gap:10px;background:var(--card);box-shadow:0 -6px 20px rgba(28,18,63,.12);padding:12px var(--sp-6) calc(12px + env(safe-area-inset-bottom))}
.rank-sticky-pos{font:800 14px 'Nunito';color:var(--purple);flex-shrink:0}
.rank-sticky-me .rank-name{flex:1;overflow:hidden}
.rank-sticky-me .rank-name strong{display:flex;align-items:center;gap:6px;font-size:13px}
.rank-you-tag{background:var(--purple-soft);color:#fff;font:700 9px 'Nunito';padding:2px 7px;border-radius:100px}
.rank-play-btn{flex-shrink:0;background:var(--gold);color:var(--gold-ink);font:700 13px 'Nunito';padding:9px 16px;border-radius:100px;text-decoration:none;box-shadow:0 3px 0 var(--gold-dark)}

/* ---------- Tela de jogos (#/jogos): cards largos por jogo, com arte
   grande sangrando à direita — inspirado em referência de app de jogos
   casuais, adaptado pro nosso catálogo curto (sem grid 2 colunas). ---------- */
/* flex:none sobrescreve o .app-shell>section:last-of-type{flex:1 0 auto}
   padrão (que estica a última section até preencher a tela inteira,
   pensado pra seções com formulário/lista comprida) — aqui, com poucos
   jogos, isso deixava um vão roxo vazio enorme embaixo do carrossel antes
   do rodapé. Sem o flex-grow a altura vira só o conteúdo (carrossel +
   botão de convidar), e só aparece scroll de verdade quando o conteúdo for
   mais alto que a tela (mais jogos, texto maior etc.). */
.games-wrap{flex:none;padding:22px var(--sp-6) 30px;display:flex;flex-direction:column;gap:14px;background:transparent}
/* Mesmo padrão 3D dos botões do design system (.primary/.secondary — cor
   sólida + sombra de "borda" embaixo que encolhe no :active, como se
   afundasse) — antes esse botão era um estilo à parte, mais chapado, sem
   esse feedback de toque. */
/* Volta ao padrão .primary (roxo sólido + relevo escuro embaixo) — era um
   azul próprio (.btn-glossy-blue), destoando do resto dos CTAs do app.
   .invite-inline não define mais cor/sombra própria, só o espaçamento do
   ícone (o resto vem de .primary, já aplicado junto na classe do botão). */
.invite-inline .invite-icon{margin-right:2px}
.game-card{position:relative;display:block;overflow:hidden;border:0;border-radius:22px;padding:20px;min-height:132px;text-align:left;text-decoration:none;color:#fff;cursor:pointer;box-shadow:0 4px 0 rgba(0,0,0,.18);font-family:'Nunito'}
.game-card:active{transform:translateY(2px)}
.game-card-badge{display:inline-flex;align-items:center;justify-content:center;gap:4px;background:rgba(255,255,255,.25);font:700 11px 'Nunito';line-height:1;padding:7px 12px;border-radius:100px;margin-bottom:12px}
.game-card-badge.soon{background:rgba(255,255,255,.16);color:#fff}
.game-card h3{font:800 22px 'Nunito';margin:0 0 4px;max-width:60%;color:#fff}
.game-card p{font-size:12.5px;opacity:.9;max-width:56%;margin:0;line-height:1.4}
.game-card-art{position:absolute;right:14px;top:50%;transform:translateY(-50%);width:104px;height:104px;object-fit:cover}
.game-card.brand-grad{background:linear-gradient(135deg,#6a4dea,#3a2394)}
/* .45 (era .6) — pedido: deixar mais visivelmente transparente os jogos
   ainda não disponíveis em produção (Domino/Presidente/Truco, gated por
   DOMINO_BLOCKED/PRESIDENTE_BLOCKED/SHOP_TEST_FREE = IS_PRODUCTION, e
   Cacheta, sempre "em breve") — todos já usavam essa mesma classe .soon,
   só a opacidade ficava sutil demais pra ler como "bloqueado" à primeira
   vista. */
.game-card.soon{opacity:.45;cursor:default;box-shadow:none}
.game-card.soon:active{transform:none}
/* Carrossel da tela de Jogos (jogosScreen/initGameCarousel, app.js) — troca
   a lista vertical de cards por uma faixa horizontal com scroll-snap: cada
   card para centralizado, o card do centro fica em tamanho normal e os
   vizinhos encolhem/esmaecem (efeito "coverflow", calculado a cada frame
   de scroll pelo JS — ver initGameCarousel). Setas nos cantos no mesmo
   estilo do botão de voltar padrão do app (.back), só reaproveitado aqui
   como "anterior/próximo" em vez de navegação. */
.game-carousel{position:relative}
/* Largura do card em clamp(dvh) — antes era fixa (210px), sobrando um vão
   vazio embaixo do botão "Convidar" em telas mais altas/desktop. Com dvh no
   meio da conta, o card cresce/encolhe junto com a altura disponível.
   padding lateral usa a mesma expressão (dividida por 2) pra continuar
   centralizando o primeiro/último card certinho no meio da faixa.
   dvh, não vh (era vh): no mobile, a barra de endereço do navegador
   esconde/aparece durante o scroll, mudando a altura "real" da viewport —
   com vh (fixo no valor inicial) a largura calculada do card ficava
   defasada da largura de fato disponível quando isso acontecia, e o
   scroll-snap parava de acertar o centro certinho pra quem rolou depois
   da barra esconder/aparecer ("alguns itens não vão pro centro", exatamente
   esse bug). dvh acompanha a altura real a cada momento, então padding e
   largura do card nunca saem de sincronia. */
.game-carousel-track{display:flex;gap:14px;overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none;padding:34px calc((100% - clamp(170px, 34dvh, 320px)) / 2) 14px}
.game-carousel-track::-webkit-scrollbar{display:none}
.carousel-arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:3;display:flex;align-items:center;justify-content:center;border:0;background:rgba(255,255,255,.25);border-radius:12px;width:40px;height:40px;color:#fff;font-size:21px;cursor:pointer;text-decoration:none}
.carousel-arrow-left{left:6px}
.carousel-arrow-right{right:6px}
/* Card "escudo": a arte (logo com nome já embutido, ver assets/game-logos)
   ocupa o card inteiro — sem o h3/fundo roxo sólido do card antigo, já que
   o nome do jogo já vem desenhado na própria arte. Tamanho fixo (não vw)
   pra initGameCarousel calcular a distância certinho e pro scroll-snap
   sempre acertar o centro. */
.game-carousel-track .game-card.game-card-shield{position:relative;flex:0 0 auto;width:clamp(170px, 34dvh, 320px);min-height:0;padding:0;border-radius:0;box-shadow:none;background:none;overflow:visible;scroll-snap-align:center;transform-origin:center center;transition:transform .1s linear,opacity .1s linear}
.game-card-shield .game-card-art{position:static;transform:none;width:100%;height:auto;aspect-ratio:1058/1487;object-fit:contain;filter:drop-shadow(0 8px 14px rgba(0,0,0,.45))}
.game-card-shield .game-card-badge{position:absolute;top:0;left:50%;transform:translateX(-50%);z-index:2;background:rgba(20,10,36,.8);white-space:nowrap;margin:0}
.game-card-shield .game-card-desc{font:700 11.5px 'Nunito';color:rgba(255,255,255,.8);text-align:center;margin:2px 0 0;line-height:1.3;max-width:100%}
.rank-row.rank-page{padding:10px 14px}
.rank-row.rank-page .rank-pos{width:26px;font-size:15px}
.rank-row.rank-page .rank-name{display:flex;flex-direction:column;gap:0}
.rank-row.rank-page .rank-level{font:600 10px 'Nunito';opacity:.75}
.rank-row.rank-page .rank-xp{flex-shrink:0;font:700 12px 'DM Mono'}

/* ---------- History table ---------- */
.history-wrap{padding-top:var(--sp-6);border-radius:22px 22px 0 0;padding-bottom:var(--sp-8)}
.history-table{width:100%;border-collapse:collapse;margin-top:12px}
.history-table th{text-align:left;font:700 11px 'Nunito';letter-spacing:.4px;color:var(--muted);padding:0 8px 10px;border-bottom:2px solid var(--line)}
.history-table td{padding:12px 8px;border-bottom:1px solid var(--line);font-size:13px;color:var(--ink)}
.history-table td.win{font-weight:700;color:var(--green-text)}
.history-table .badge{font:700 10px 'Nunito';padding:4px 9px;border-radius:20px;background:#f1ecff;color:var(--purple-dark)}
.history-table .badge.done{background:#e3fbf1;color:var(--green-text)}
.history-table-wrap{overflow-x:auto}

/* ---------- Account ---------- */
/* Borda reta (era arredondada, 22px 22px 0 0) + friso texturizado escuro
   no topo, em vez do canto curvo genérico do resto do app — só nessa
   tela mesmo (as outras que compartilham .account-wrap continuam com o
   canto arredondado, ver a regra genérica logo acima). */
.account-wrap{position:relative;padding-top:calc(var(--sp-7) + 5px);border-radius:0;padding-bottom:var(--sp-8);text-align:center}
/* Card do perfil (avatar quadrado + nome + XP), inspirado em telas de
   "Perfil" de jogos mobile: avatar com selo de edição no canto, nível em
   estrela do lado da barra de XP. */
.profile-card{display:flex;align-items:center;gap:16px;text-align:left;margin:0 0 6px}
/* 125px (era 115px) — acompanha o wrap de 152x164 (ver
   accountAvatarWrapWidth/Height em app.js), na mesma proporção de sempre
   (FRAME_HOLE_RATIO .82) tomando a LARGURA como base (o furo da moldura é
   redondo/quadrado, centralizado — a altura extra do wrap é só pras
   flâmulas da arte, não muda o tamanho do furo). */
.account-avatar{position:relative;flex-shrink:0;width:125px;height:125px;border-radius:14%;background:linear-gradient(160deg,var(--pink),var(--purple));display:grid;place-items:center;font:800 46px 'Nunito';color:#fff;box-shadow:0 3px 0 rgba(0,0,0,.15)}
.avatar-edit-badge{position:absolute;bottom:-6px;right:-6px;width:26px;height:26px;border-radius:50%;background:var(--gold);color:var(--gold-ink);display:grid;place-items:center;font-size:12px;box-shadow:0 2px 0 rgba(0,0,0,.2);border:2px solid #fff;text-decoration:none;z-index:3}
.profile-card-info{flex:1;min-width:0}
.profile-card-info h2{font:800 22px 'Nunito';margin:0 0 2px;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Abre o modal de editar nome/senha — texto explícito (não só ícone) pra
   não confundir com o lápis de trocar avatar (avatar-edit-badge, esse sim
   leva pra Loja). */
.profile-edit-link{display:block;width:100%;border:0;background:none;color:var(--purple-light);text-decoration:none;font:700 13px 'Nunito';margin:2px 0 4px;padding:6px;cursor:pointer;text-align:center}
/* Botão de Amigos virou CTA de verdade (.primary) em vez de link discreto
   — ganha destaque igual aos outros botões de ação principal da tela. */
.account-friends-cta{display:block;text-align:center;text-decoration:none;margin:10px 0 22px;box-sizing:border-box}
.account-wrap .muted-dark{color:var(--muted);margin:0 0 22px}
.account-form{margin:0 0 18px;text-align:left}
/* Separa visualmente o bloco de "trocar senha" do de "trocar nome" no
   modal de editar perfil — antes emendava direto sem respiro nem divisor. */
.modal-section{margin-top:22px;padding-top:22px;border-top:1px solid rgba(255,255,255,.1)}
.modal-section .reset-password-status{margin:14px 0 0;font-size:12.5px}
.account-form label{color:var(--ink);text-shadow:none}
.account-form input{background:#f3f0ff;box-shadow:inset 0 0 0 2px var(--line)}
/* Barra fixa de "Salvar alterações" — só existe no DOM quando tem
   pendência (dirty), flutua por cima do bottom-nav (74px + safe-area,
   mesma referência já usada em body.has-bottom-nav .app-shell). Quando
   presente, o conteúdo da Conta ganha um respiro extra embaixo pra não
   ficar escondido atrás dela (.has-save-bar). */
.account-save-bar{position:fixed;left:0;right:0;bottom:calc(74px + env(safe-area-inset-bottom));z-index:19;padding:12px var(--sp-6);background:linear-gradient(0deg, var(--purple-dark) 60%, transparent);}
.account-save-bar .primary{box-shadow:0 4px 14px rgba(0,0,0,.35)}
.account-wrap.has-save-bar{padding-bottom:calc(var(--sp-8) + 66px)}
.account-note{background:#f1ecff;border-radius:14px;padding:14px;text-align:center;color:var(--purple-dark);font-size:13px;margin:10px 0 22px}
.settings-version{margin:18px 0 0;text-align:center;font:700 11px 'Nunito';color:var(--muted);letter-spacing:.5px}
/* ---------- Design system: "linha de configuração" ----------
   Padrão reutilizável pra qualquer tela de opções/ajustes (não só
   Configurações) — ícone + label(+legenda) + controle, cada linha seu
   próprio cartão branco separado por espaço. Duas variantes:
     • interativa: <label class="settings-row"> com <input class="switch">
     • "em breve": <button class="settings-row disabled" disabled> com
       <span class="settings-row-soon">
   Ícone sempre .settings-row-icon (emoji ou <img>), texto sempre
   .settings-row-label (com <small> opcional pra legenda). */
.settings-list{display:flex;flex-direction:column;gap:10px;margin:0 0 26px;width:100%}
.settings-row{display:flex;align-items:center;gap:16px;width:100%;box-sizing:border-box;padding:16px 18px;border:0;border-radius:16px;background:#fff;box-shadow:0 3px 10px rgba(28,18,63,.08);text-align:left;cursor:pointer;font-family:'Nunito'}
.settings-row-icon{font-size:32px;width:38px;flex-shrink:0;text-align:center}
.settings-row-icon img{width:34px;height:34px;object-fit:contain;vertical-align:middle}
.settings-row-label{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;font:800 16px 'Nunito';color:#2b2251}
.settings-row-label small{font:600 13px 'Nunito';color:rgba(43,34,81,.55)}
.settings-row.disabled{cursor:default}
.settings-row.disabled .settings-row-icon{opacity:.45}
.settings-row.disabled .settings-row-label{color:rgba(43,34,81,.45)}
.settings-row-soon{flex-shrink:0;font:800 11.5px 'Nunito';color:rgba(43,34,81,.45);text-transform:uppercase;letter-spacing:.5px;background:rgba(43,34,81,.07);padding:6px 12px;border-radius:100px}
/* Switch estilo iOS no lugar do checkbox quadrado padrão. */
.switch{appearance:none;-webkit-appearance:none;flex-shrink:0;width:46px;height:27px;border-radius:100px;background:var(--line);position:relative;cursor:pointer;transition:background .2s ease;margin:0}
.switch::before{content:'';position:absolute;top:2.5px;left:2.5px;width:22px;height:22px;border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.3);transition:transform .2s ease}
.switch:checked{background:var(--green-dark,#22a06b)}
.switch:checked::before{transform:translateX(19px)}
/* Amigos (amigosScreen) + convite de amigo pra mesa (friendInviteModal) +
   banner de convite recebido na tela de Jogos (jogosScreen) — reaproveita
   .settings-list como container de linhas. */
.friend-code-pill{display:inline-flex;align-items:center;background:linear-gradient(160deg,#3a2f66,#221739);color:var(--gold,#ffb020);font:800 18px 'Nunito';letter-spacing:2px;padding:10px 18px;border-radius:12px}
.friend-row{display:flex;align-items:center;gap:12px;width:100%;box-sizing:border-box;padding:10px 14px;border-radius:14px;background:#fff;box-shadow:0 2px 8px rgba(28,18,63,.08)}
.friend-row-name{flex:1;min-width:0;font:800 14px 'Nunito';color:#2b2251;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.friend-remove-btn{flex-shrink:0;border:0;background:rgba(0,0,0,.06);color:rgba(43,34,81,.6);width:28px;height:28px;border-radius:50%;font-size:13px;cursor:pointer;display:flex;align-items:center;justify-content:center}
.friend-invite-banner{display:flex;align-items:center;gap:10px;background:linear-gradient(160deg,#3a2f66,#221739);border-radius:16px;padding:10px 12px;margin-bottom:14px;box-shadow:0 3px 8px rgba(0,0,0,.25)}
.friend-invite-text{flex:1;min-width:0;font:700 12.5px 'Nunito';color:#fff;line-height:1.3}
.friend-invite-banner .friend-remove-btn{background:rgba(255,255,255,.14);color:#fff}
.level-card{margin:6px 0 0;text-align:left}
.level-row{display:flex;align-items:center;gap:8px;margin-bottom:5px}
.level-star{flex-shrink:0;display:inline-flex;align-items:center;gap:3px;font-size:19px;font:800 13px 'Nunito';color:var(--gold-dark)}
.level-xp{font:700 12px 'DM Mono';color:var(--muted)}
.level-row-bottom{display:flex;align-items:center;justify-content:space-between;margin-bottom:4px}
.coin-badge{background:#fff4d6;color:#8a5a00;font:700 12px 'Nunito';padding:4px 10px;border-radius:100px}
.level-bar{flex:1;height:12px;background:var(--line);border-radius:100px;overflow:hidden;box-shadow:inset 0 1px 3px rgba(0,0,0,.15)}
.level-bar-fill{height:100%;background:linear-gradient(90deg,var(--gold),var(--gold-dark));border-radius:100px}
.level-hint{margin:0;font-size:11.5px;color:var(--muted)}
.level-up-badge{font-size:34px;text-align:center;line-height:1;margin:0 0 6px}

/* ---------- Linha de recompensas (tela #/conta/recompensas): trilha
   vertical que acende conforme o nível sobe, cards em preto-e-branco até
   desbloquear e coloridos depois ---------- */
/* Linha de recompensas (tela "Sua evolução") — card grande colorido por
   categoria, com o ícone numa moldura circular à esquerda, igual a
   referência enviada. Um tom (--reward-*) por categoria; o selo da direita
   é sempre verde quando desbloqueado, e some a cor do card quando bloqueado. */
.reward-track{position:relative;display:flex;flex-direction:column;gap:14px;margin-top:8px}
/* Trilha lateral: bolinha por etapa (dourada quando já passou, com o
   nível do card enquanto bloqueada) sobre UMA barra vertical contínua
   (reward-line-track) que corre atrás de tudo — em vez de um segmento de
   linha por card, que quebrava visivelmente assim que os cards passaram a
   ter espaço entre eles. A barra é um degradê dourado→cinza (calculado em
   rewardTrackHtml pela proporção de itens desbloqueados) e os círculos,
   opacos, ficam por cima "tampando" o meio dela. */
.reward-line-track{position:absolute;top:16px;bottom:16px;left:12.5px;width:3px;z-index:0}
/* reward-step2 é um bloco comum (não flex) — só existe pra ser a
   referência de posicionamento do selo (reward-level-badge, position:
   absolute; left:100%). reward-row é quem organiza a bolinha+card lado a
   lado; sem essa separação, posicionar o selo em % dentro do próprio
   container flex não batia certinho na horizontal em alguns navegadores. */
.reward-step2{position:relative;z-index:1}
.reward-row{display:flex;gap:12px;align-items:stretch}
.reward-line-wrap2{display:flex;flex-direction:column;align-items:center;justify-content:center;width:28px;flex-shrink:0}
.reward-dot2{width:32px;height:32px;border-radius:50%;background:#fff;border:3px solid var(--line);flex-shrink:0;display:grid;place-items:center;font:800 13px 'Nunito';color:rgba(43,34,81,.7);line-height:1}
.reward-dot2.lit{background:var(--gold);border-color:var(--gold-dark);color:var(--gold-ink)}
.reward-dot2 .lock-icon-img{width:15px;height:15px}
/* Furo circular na borda direita (meio da altura) pro selo de nível
   "flutuar" nele em vez de ficar com o quadrado do card cortando o
   círculo por trás — mask-image recorta um buraco ali (mesmo centro do
   selo, um pouco maior), revelando o fundo por trás em vez da cor do
   card. */
.reward-card2{position:relative;display:flex;align-items:center;gap:16px;padding:16px;border-radius:22px;box-shadow:0 3px 10px rgba(28,18,63,.1);transition:opacity .2s ease;flex:1;overflow:visible;text-align:left;-webkit-mask-image:radial-gradient(circle 30px at 100% 50%, transparent 99%, #000 100%);mask-image:radial-gradient(circle 30px at 100% 50%, transparent 99%, #000 100%)}
.reward-icon2{width:78px;height:78px;border-radius:50%;flex-shrink:0;background-size:cover;background-position:center;box-shadow:0 3px 0 rgba(0,0,0,.12),0 2px 8px rgba(0,0,0,.15)}
.reward-card2.locked .reward-icon2{filter:grayscale(1)}
/* padding-right: o selo de nível (reward-level-badge) fica de fora do fluxo
   (position:absolute, metade pra fora do card em right:-24px) — sem essa
   folga o texto (flex:1, cresce livre) ia até a borda e ficava por baixo
   do número. */
.reward-copy2{flex:1;min-width:0;display:flex;flex-direction:column;text-align:left;padding-right:28px}
.reward-copy2 strong{font:800 18px 'Nunito';color:#2b2251}
.reward-copy2 > span{font:600 12.5px 'Nunito';color:rgba(43,34,81,.68);margin-top:2px}
.reward-bottom-row{display:flex;align-items:center;gap:10px;padding-top:9px;margin-top:9px;border-top:1px solid rgba(28,18,63,.1)}
.reward-req{display:flex;align-items:center;gap:5px;font:700 12.5px 'Nunito';color:rgba(43,34,81,.7)}
.reward-card2.unlocked .reward-req{color:var(--green-text)}
/* Nível em destaque: círculo grande sobressaindo na borda direita do
   card, centralizado na ALTURA (não no canto de cima) — mesmo estilo de
   "botão" dos outros selos circulares do app (avatar-edit-badge),
   substituiu o pill pequeno "Nível N". Fica fora do card (irmão dele
   dentro de reward-step2, não filho) pra não ser "engolido" pelo mesmo
   mask-image que fura a borda do card — mask corta a árvore inteira do
   elemento em que é aplicado, incluindo filhos. top:50%+translateY(-50%)
   centraliza na altura; right:-24px (metade dos 48px de largura) põe
   metade pra fora da borda. */
.reward-level-badge{position:absolute;top:50%;right:-24px;transform:translateY(-50%);z-index:2;width:48px;height:48px;border-radius:50%;background:#fff;color:#2b2251;font:800 21px 'Nunito';display:grid;place-items:center;box-shadow:0 3px 0 rgba(0,0,0,.18),0 0 0 3px rgba(255,255,255,.6);border:3px solid rgba(43,34,81,.12)}
.reward-level-badge.unlocked{background:var(--gold);color:var(--gold-ink);border-color:var(--gold-dark)}
.reward-card2.gold{background:linear-gradient(135deg,#fff6d9,#ffe6a8)}
.reward-card2.purple{background:linear-gradient(135deg,#efeaff,#dbceff)}
.reward-card2.blue{background:linear-gradient(135deg,#e3f2ff,#c3e3ff)}
.reward-card2.teal{background:linear-gradient(135deg,#e3faf3,#bdf2dd)}
.reward-card2.amber{background:linear-gradient(135deg,#fff0d9,#ffd89e)}
.reward-card2.pink{background:linear-gradient(135deg,#ffe6f2,#ffbfe0)}
/* Bloqueado: card inteiro em cinza com uma textura sutil (em vez da cor da
   categoria), ícone em P&B e um cadeado grande e translúcido no meio do
   card como marca d'água — o selo do nível some daqui, o card fica
   "apagado" até o jogador subir de nível. */
.reward-card2.locked{background:repeating-linear-gradient(135deg, #e9e5f1 0 10px, #ded9ea 10px 20px)}
.reward-card2.locked::after{content:'🔒';position:absolute;top:50%;right:22px;transform:translateY(-50%);font-size:52px;opacity:.14;pointer-events:none}
.avatar-picker{margin:0 0 30px}
.avatar-picker-title{font:700 13px 'Nunito';color:var(--ink);text-align:left;margin:0 0 10px}
/* Subtítulos de seção da Conta (Configurações/Evolução de recompensas) —
   mesma fonte/peso dos títulos do app (ver profile-card-info h2), maior e
   centralizado, com bastante respiro antes e depois. */
.account-section-title{font:800 20px 'Nunito';color:var(--ink);text-align:center;margin:6px 0 20px}
.avatar-grid{display:grid;grid-template-columns:repeat(3,1fr);column-gap:10px;row-gap:28px}
/* Mesa (pano+moldura, 941×1672 — bem mais alta que larga): thumb padrão
   quadrado cortava boa parte da arte. Menos colunas + aspect-ratio real +
   contain, pra mostrar a mesa inteira. */
.avatar-grid-mesa{grid-template-columns:repeat(3,1fr)}
.avatar-grid-mesa .avatar-option{aspect-ratio:941/1672;background-size:contain;background-repeat:no-repeat;background-color:var(--card)}
/* Baralho (verso, 1024×1536 — mais alto que largo): mesmo problema da mesa,
   thumb quadrado cortava boa parte da arte. */
.avatar-grid-deck{grid-template-columns:repeat(3,1fr)}
.avatar-grid-deck .avatar-option{aspect-ratio:2/3;background-size:contain;background-repeat:no-repeat;background-color:var(--card)}
/* Placar de Vitória (moldura decorativa, 950×1267 — mesmo problema da mesa/
   baralho: quadrado espremia a arte a ponto de só sobrar os frisos das
   laterais visíveis, miolo transparente "sumindo" contra o fundo roxo). */
.avatar-grid-victory{grid-template-columns:repeat(3,1fr)}
.avatar-grid-victory .avatar-option{aspect-ratio:950/1267;background-size:contain;background-repeat:no-repeat;background-color:var(--card)}
/* Fundos: mesmo quadrado de sempre, só menos colunas pra aumentar o thumb
   (a arte em si não tem problema de proporção, cover já mostra inteira). */
.avatar-grid-bg{grid-template-columns:repeat(3,1fr)}
.avatar-grid .loja-item{min-width:0}
/* "Moldura" visível por trás/ao redor do item — anel claro por dentro (lê
   como uma bordinha de cartão, tipo o pedido de referência) + sombra de
   profundidade por fora, em cima do mesmo tile de sempre (sem mudar o
   ajuste da imagem — cover continua preenchendo o quadrado todo). */
.avatar-option{position:relative;aspect-ratio:1;width:100%;border:0;border-radius:14px;background-color:#3632af;background-size:cover;background-position:center;cursor:pointer;box-shadow:0 3px 0 rgba(0,0,0,.15),0 0 0 2px rgba(255,255,255,.14) inset;outline:3px solid transparent;outline-offset:2px}
/* Avatar/moldura (categorias que o próprio avatar usa, com ou sem moldura
   por cima) usam o mesmo radius mais arredondado do avatar (32%) pra
   encaixar direitinho no vão das molduras — mesa/baralho/fundo mantêm o
   radius padrão, mais discreto. */
.avatar-grid-avatar .avatar-option,.avatar-grid-frame .avatar-option{border-radius:14%}
.avatar-option.selected{outline-color:var(--green-dark)}
.avatar-option.locked{filter:grayscale(.85);opacity:.5}
.avatar-option:active{transform:translateY(2px)}
.bg-option.locked{filter:grayscale(1);opacity:.85;position:relative}
/* Preço de compra bem visível mesmo sobre imagem clara ou grayscale: chip
   sólido (não só texto flutuando), cadeado e valor na cor de destaque
   (Texas Rose) do design system — bate o olho em vez de precisar procurar. */
.bg-option .lock-icon{position:absolute;inset:0;display:grid;place-items:center}
.bg-option .lock-icon span{display:inline-flex;align-items:center;gap:4px;background:rgba(20,14,40,.78);color:var(--gold);font:800 13px 'Nunito';padding:6px 11px;border-radius:100px;box-shadow:0 2px 6px rgba(0,0,0,.4);border:1.5px solid rgba(255,255,255,.25)}
.chip-option.locked{filter:grayscale(1);opacity:.6}
.buy-badge{display:inline-flex;align-items:center;gap:3px;margin-left:4px;background:var(--gold);color:var(--gold-ink);font:800 11px 'Nunito';padding:4px 9px;border-radius:100px;box-shadow:0 1px 3px rgba(0,0,0,.25)}
.shop-hint{margin:8px 0 0;font-size:11px;color:var(--muted);text-align:left}
.loja-panel .shop-hint{text-align:center;margin:4px 0 16px}
.shop-hint-level{font-size:14px;font-weight:700;color:var(--ink)}
.lock-hint{background:#f1ecff;border-radius:14px;padding:14px;text-align:center;font-size:13px;color:var(--purple-dark);margin:10px 0}
.level-badge-mini{font-size:10px;font-weight:700;background:var(--gold);color:var(--gold-ink);padding:2px 8px;border-radius:100px;margin-left:6px;vertical-align:middle}
.stats-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin:16px 0 20px}
.stat-tile{background:#f8f6ff;border-radius:14px;padding:16px 6px;text-align:center;box-shadow:0 3px 0 #dcd5f2}
.stat-tile strong{display:block;font:700 20px 'Nunito';color:#2b2251}
.stat-tile span{font-size:10px;color:#786fa6;text-transform:uppercase;letter-spacing:.3px}
.chip-row{display:flex;flex-wrap:wrap;gap:8px}
.chip-option{border:2px solid var(--line);background:#fff;border-radius:100px;padding:8px 14px;font:700 12px 'Nunito';color:#2b2251;cursor:pointer;text-decoration:none;display:inline-block}
.chip-option:disabled{opacity:.4;cursor:not-allowed}
.chip-option.selected{border-color:var(--green-dark);background:#e3fbf1;color:var(--green-text)}

/* ---------- Loja (vitrine de compra — avatar/moldura/fundo/mesa juntos) ---------- */
.menu-cta.tile .tile-icon.icon-loja{background:linear-gradient(160deg,#ffd873,#c9861a)}
.loja-page{padding-bottom:var(--sp-8)}
.loja-intro{text-align:center;margin-bottom:18px}
/* Seletor de categoria (Avatares/Molduras/Fundos/Mesas/Títulos) — paginação
   por setas com o nome da categoria no centro, como em "Peças ‹ ›" de apps
   de loja de jogos. Troca só via classe .active em JS (loja-tab-nav, ver
   app.js), sem re-render/re-fetch — e volta o scroll pro topo a cada troca. */
.loja-tabmenu{display:flex;gap:6px;margin:4px 0 16px;padding:6px;background:linear-gradient(160deg,#3a2f66,#221739);border-radius:14px;box-shadow:0 3px 8px rgba(0,0,0,.25),0 0 0 1px rgba(255,255,255,.06) inset;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.loja-tabmenu::-webkit-scrollbar{display:none}
.loja-tab-btn{flex:0 0 auto;border:0;border-radius:9px;padding:9px 16px;background:transparent;color:rgba(255,255,255,.6);font:800 13px 'Nunito';white-space:nowrap;cursor:pointer;transition:background .15s,color .15s}
.loja-tab-btn.active{background:linear-gradient(160deg,#ffd873,#ffb020);color:#4a2f00;box-shadow:0 2px 4px rgba(0,0,0,.25)}
.loja-panel{display:none}
.loja-panel.active{display:block}
/* Aba "Moedas" — pacotes de compra, só prévia visual (ver COIN_PACKS/
   buy-coins-mock). Cartões simples, sem o selo de bloqueado/desbloqueado
   das outras abas (aqui não tem "possuir", é consumível). */
.coin-packs{display:grid;grid-template-columns:repeat(auto-fit,minmax(96px,1fr));gap:18px}
.coin-pack-card{position:relative;display:flex;flex-direction:column;align-items:center;gap:4px;background:#fff;border-radius:18px;padding:20px 10px 14px;box-shadow:0 3px 10px rgba(28,18,63,.1)}
.coin-pack-card.best{box-shadow:0 3px 10px rgba(28,18,63,.1),0 0 0 2px var(--gold)}
.coin-pack-best{position:absolute;top:-10px;left:50%;transform:translateX(-50%);background:var(--gold);color:var(--gold-ink);font:800 9px 'Nunito';letter-spacing:.3px;padding:3px 10px;border-radius:100px;white-space:nowrap;box-shadow:0 2px 0 var(--gold-dark)}
.coin-pack-card .coin-icon{width:38px;height:38px;margin-bottom:2px}
.coin-pack-amount{font:800 19px 'Nunito';color:#2b2251;line-height:1}
.coin-pack-label{font:700 10px 'Nunito';color:var(--muted);text-transform:uppercase;letter-spacing:.4px;margin-bottom:6px}
.coin-pack-buy{width:100%;padding:9px 6px;font-size:12.5px}
/* Item da vitrine: a arte fica sempre colorida (locked ou não) — só um
   selo pequeno no canto (cadeado ou ✓) e, quando bloqueado, uma tag de
   preço separada embaixo, sem cobrir a imagem. Dá pra ver exatamente o
   que vai comprar antes de decidir (pedido do usuário, referência de
   apps de loja de jogos). */
.loja-item{display:flex;flex-direction:column;gap:2px}
.loja-owned-badge{position:absolute;top:6px;right:6px;width:28px;height:28px;border-radius:50%;display:grid;place-items:center;font-size:12px;font-weight:800;line-height:1;box-shadow:0 1px 3px rgba(0,0,0,.3);background:var(--green-dark);color:#fff}
/* Bloqueado: véu escuro leve sobre a arte inteira — o cadeado não fica
   mais centralizado em cima do item (atrapalhava ler o nome/ver a arte),
   agora mora do lado do preço embaixo (ver .loja-price-tag img). */
.avatar-option.locked::after{content:'';position:absolute;inset:0;border-radius:inherit;background:rgba(20,14,40,.4)}
/* Preço maior/mais destacado (pedido) — fonte quase o dobro, pill mais
   robusta e uma sombra de "borda" embaixo (mesmo relevo 3D dos botões),
   em vez do pill fininho/discreto de antes. */
.loja-price-tag{align-self:center;display:inline-flex;align-items:center;gap:6px;background:var(--gold);color:var(--gold-ink);font:800 20px 'Nunito';padding:6px 16px;border-radius:100px;box-shadow:0 3px 0 var(--gold-dark,#e6963a)}
.loja-price-tag img{width:22px;height:22px}
/* Item já comprado: mantém a tag de preço embaixo (padrão visual único
   pra todos os itens), mas preta-e-branca e translúcida — só referência,
   já que não tem ação nenhuma associada (não compra de novo). */
.loja-price-tag.owned{background:rgba(255,255,255,.16);color:rgba(255,255,255,.55);filter:grayscale(1)}
/* :disabled é usado nos itens "já é seu" (sem ação de compra) — sem isso o
   navegador esmaece o botão por padrão, escondendo a arte real do item. */
.avatar-option:disabled{opacity:1;cursor:default}
/* Categoria "Títulos" não tem imagem própria — mostra o texto do título
   centralizado dentro do tile (showLabel em lojaThumb, app.js). */
.loja-thumb-label{position:absolute;inset:6px;display:flex;align-items:center;justify-content:center;text-align:center;color:#fff;font:800 11px 'Nunito';line-height:1.2;text-shadow:0 1px 2px rgba(0,0,0,.3)}
/* Botão "Padrão" (volta a não usar nenhum item da categoria) — mesmo
   tamanho dos outros tiles, mas sem arte, só o texto. */
.clear-thumb{display:grid;place-items:center;background:var(--card);color:var(--ink);font:800 13px 'Nunito'}

/* Re-pele de teste da Loja (shop-skin-test, ligada por SHOP_TEST_FREE —
   só no link de teste) — paleta escura/roxo-azulada + fitas de destaque,
   referência de print de um shop estilo jogo de tanque/sci-fi que o Gean
   mandou. Só troca cor/textura em cima da mesma estrutura HTML de sempre
   (mesmas classes .loja-*/.avatar-option/.coin-pack-*), nada de layout
   novo — assim é fácil promover pra produção depois ou reverter. */
.loja-page.shop-skin-test{background:radial-gradient(ellipse at 50% 0%, #241457 0%, #0d0526 70%);border-radius:22px;padding-left:var(--sp-7);padding-right:var(--sp-7);margin-left:calc(var(--sp-7) * -1);margin-right:calc(var(--sp-7) * -1);padding-top:var(--sp-6)}
.shop-skin-test .loja-tabmenu{background:linear-gradient(160deg,#241457,#150934);box-shadow:0 3px 8px rgba(0,0,0,.4),0 0 0 1px rgba(120,180,255,.15) inset}
.shop-skin-test .loja-tab-btn.active{background:linear-gradient(160deg,#5ad2ff,#1c8fd6);color:#04283d}
.shop-skin-test .avatar-option{background-color:#3a2472;box-shadow:0 4px 0 rgba(0,0,0,.35),0 0 0 1px rgba(140,110,255,.5) inset;border-radius:16px}
.shop-skin-test .avatar-option::before{content:'';position:absolute;top:0;left:0;right:0;height:34%;border-radius:16px 16px 0 0;background:linear-gradient(180deg,rgba(140,120,255,.55),rgba(140,120,255,0))}
.shop-skin-test .loja-price-tag{background:linear-gradient(160deg,#ff6fd8,#c026e0);color:#fff;box-shadow:0 2px 0 rgba(0,0,0,.25)}
.shop-skin-test .loja-price-tag.owned{background:rgba(255,255,255,.14);color:rgba(255,255,255,.5)}
.shop-skin-test .loja-owned-badge{background:#1fd68a}
/* Aba Moedas nessa re-pele: cartões escuros com miolo roxo (igual aos
   outros tiles) em vez dos cartões brancos padrão, botão de compra verde
   "BUY NOW" do print de referência. */
.shop-skin-test .coin-pack-card{background:linear-gradient(180deg,#4a3299,#241457);box-shadow:0 4px 0 rgba(0,0,0,.35),0 0 0 1px rgba(140,110,255,.5) inset}
.shop-skin-test .coin-pack-amount{color:#fff}
.shop-skin-test .coin-pack-label{color:#c9baf5}
.shop-skin-test .coin-pack-best{background:#2596ff;color:#fff;box-shadow:0 2px 0 #1573c2}
.shop-skin-test .coin-pack-card.best{box-shadow:0 4px 0 rgba(0,0,0,.35),0 0 0 2px #2596ff}
.shop-skin-test .coin-pack-buy{background:linear-gradient(160deg,#5fe86a,#22b143);box-shadow:0 3px 0 #178235;color:#06340f}

/* ---------- Tela de regras (filtro por jogo, ver GAME_RULES em app.js) ---------- */
.rules-link{display:block;text-align:center;margin:18px 0 26px;padding:6px;font:700 13px 'Nunito';color:var(--purple-light);text-decoration:none}
.rules-list{margin:0 0 22px;padding:0 0 0 20px;color:var(--ink)}
.rules-list li{margin-bottom:8px;font-size:13px;line-height:1.5}
.chip-option.frame-chip.selected{background:#fff}
.chip-option.deck-chip{display:inline-flex;align-items:center;gap:6px}
.deck-swatch{width:16px;height:16px;border-radius:4px;display:inline-block;box-shadow:inset 0 0 0 1px rgba(0,0,0,.15)}
.player-title{color:var(--purple);font:9px 'Nunito';display:block;margin-top:1px}
.player-title-big{color:var(--purple);font:700 13px 'Nunito';margin:-2px 0 6px;text-transform:uppercase;letter-spacing:.4px}
.winner-banner .player-title{color:#8a5a00;font-size:10px}
.bg-picker{margin:4px 0 18px}
.bg-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-top:10px}
.bg-option{aspect-ratio:1;border:0;border-radius:14px;background-color:var(--sky);background-size:cover;background-position:center;cursor:pointer;outline:3px solid transparent;outline-offset:2px;font:700 11px 'Nunito';color:#fff;text-shadow:0 1px 3px rgba(0,0,0,.4)}
.bg-option.selected{outline-color:var(--gold)}
.bg-option:active{transform:translateY(2px)}
.danger{display:block;width:100%;background:none;border:0;color:var(--pink-dark);font:700 13px 'Nunito';cursor:pointer;padding:10px;text-align:center}

/* ---------- Modals ---------- */
/* z-index:10 (era 3): precisa ficar por cima do mesa8-hand-dock (z-index:5,
   fixo na parte de baixo da mesa) — senão o placar/qualquer modal abria
   atrás da mão durante uma partida. */
.modal-backdrop{position:fixed;inset:0;background:rgba(10,5,22,.82);z-index:10;display:grid;place-items:center;padding:20px}
.modal-backdrop.victory{background:rgba(6,3,14,.93)}
.modal{position:relative;width:min(100%,430px);background:var(--card);border-radius:22px;padding:var(--sp-7) var(--sp-6);text-align:center;box-shadow:0 20px 70px #1c123f55}
.modal-label{font:600 13px 'Nunito';color:var(--muted);margin:0}
.modal h2{font:700 27px 'Nunito';margin:8px 0;color:var(--ink)}
/* Preview do item no modal de compra — reaproveita o style inline do
   próprio botão clicado (buy-item, ver app.js), então funciona pra
   qualquer categoria (imagem, cor de moldura, gradiente de título). */
.buy-preview{position:relative;width:190px;aspect-ratio:1;margin:4px auto 16px;border-radius:16px;background-color:#3632af;background-size:cover;background-position:center;box-shadow:0 4px 0 rgba(0,0,0,.15)}
.buy-preview-mesa{width:160px;aspect-ratio:941/1672;background-size:contain;background-repeat:no-repeat}
/* Baralho (verso, 2:3) e Placar de Vitória (moldura, 950×1267): mesmo
   motivo do buy-preview-mesa acima — sem isso o quadrado padrão
   espremia/cortava a arte. */
.buy-preview-deck{width:150px;aspect-ratio:2/3;background-size:contain;background-repeat:no-repeat}
.buy-preview-victory{width:170px;aspect-ratio:950/1267;background-size:contain;background-repeat:no-repeat}
.buy-preview-label{position:absolute;inset:6px;display:flex;align-items:center;justify-content:center;text-align:center;color:#fff;font:800 12px 'Nunito';line-height:1.2;text-shadow:0 1px 2px rgba(0,0,0,.3)}
.modal .muted{color:var(--muted);line-height:1.45;margin:0 0 22px}
.modal .points-input{font:700 40px 'Nunito';text-align:center;margin-bottom:10px;background:#dcd7ff;color:var(--purple-dark)}
.score-preview{margin:0 0 20px;font-size:13px;color:var(--muted)}
.score-preview b{color:var(--purple-dark);font-size:15px}
.close{position:absolute;right:12px;top:8px;border:0;background:none;font-size:26px;cursor:pointer;color:var(--muted)}
.victory .modal{animation:pop .45s cubic-bezier(.18,.89,.32,1.28)}
/* Moldura de "Placar de Vitória" no modal do placar presencial — mesmo
   tratamento do finish8-frame-img: cobre o modal inteiro, miolo
   transparente, borda arredondada igual ao card por baixo. */
.victory-frame-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:22px;pointer-events:none;z-index:3}
.confetti{color:var(--orange);letter-spacing:26px;font-size:20px;margin:0 0 5px 18px;animation:float 1.3s ease-in-out infinite alternate}
.trophy{font-size:58px;line-height:1;margin-bottom:8px}
/* Banner de vitória/derrota no topo do modal do Placar presencial: 3
   cartas em leque (ases pra quem venceu, viradas pra quem não) com uma
   faixa colorida por baixo — reaproveita as próprias cartas do jogo
   (.card8/.card8-back), sem precisar de arte nova. */
.victory-banner{position:relative;z-index:2;display:flex;flex-direction:column;align-items:center;margin:-6px 0 16px}
.victory-banner-cards{display:flex;align-items:flex-end;justify-content:center;height:74px}
.victory-banner-card{margin:0 -12px;box-shadow:0 4px 10px rgba(0,0,0,.3)}
.victory-banner-card:nth-child(1){transform:rotate(-16deg) translateY(8px)}
.victory-banner-card:nth-child(2){transform:translateY(-6px);z-index:1}
.victory-banner-card:nth-child(3){transform:rotate(16deg) translateY(8px)}
.victory-banner-ribbon{position:relative;z-index:2;margin-top:-12px;padding:8px 30px;border-radius:100px;font:800 15px 'Nunito';letter-spacing:.5px;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.2)}
.victory-banner-ribbon.win{background:linear-gradient(160deg,var(--gold),var(--gold-dark));box-shadow:0 3px 0 #a06420}
.victory-banner-ribbon.lose{background:linear-gradient(160deg,var(--blue),var(--blue-dark));box-shadow:0 3px 0 #0f6389}
.invite-modal canvas{display:block;margin:0 auto 18px;border-radius:14px}
.invite-modal input{font:16px 'DM Mono';text-align:center;padding:12px;background:#f3f0ff}
@keyframes pop{from{transform:scale(.7);opacity:0}to{transform:scale(1);opacity:1}}
@keyframes float{to{transform:translateY(-8px) rotate(5deg)}}

/* ---------- Instalar PWA ---------- */
/* Modal padrão (.modal-backdrop/.modal, mesmo de todo outro modal do app —
   ver docs/game-ui-guia.md) — era uma faixa fixa colada no rodapé, que
   ficava atrás/cortada pela barra de navegação inferior (z-index menor que
   .bottom-nav) e mostrava só um pedaço do texto. */
.install-modal .install-icon{width:56px;height:56px;border-radius:16px;background:linear-gradient(180deg,var(--orange),var(--orange-dark));display:grid;place-items:center;box-shadow:0 3px 0 #c9590a;margin:0 auto 14px}
.install-modal .install-icon span{font:800 26px 'Nunito';color:#fff}
.install-modal h2{margin:0 0 8px}
.install-modal .ios-share{font-size:14px}

/* ---------- Desktop/telas largas: mesa em modo paisagem ----------
   Só entra em telas realmente largas (tablet paisagem/desktop) — no
   celular, a grande maioria dos acessos, nada muda. A coluna do app
   (limitada a 640px em toda tela pra manter formulários/listas legíveis)
   abre mais LARGA só durante uma partida (body.game-immersive) — como a
   altura da mesa já vem do espaço vertical que sobra (flex:1, ver
   .mesa8-table/.table acima), uma coluna mais larga com a mesma altura já
   faz a mesa virar naturalmente mais "paisagem" sozinha, sem precisar de
   uma proporção separada pro desktop. Os assentos (mesa8SeatPosition, em
   %) se distribuem em elipse acompanhando a proporção real do container. */
@media (min-width: 860px){
  body.game-immersive .app-shell{max-width:min(1040px, 92vw)}
  body.game-immersive .table{padding:26px 26px 0}
}

/* ---------- Tela de carregamento (antes de abrir mesa online) ---------- */
.loading-screen{position:fixed;inset:0;z-index:2000;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:26px;background:#0b6e73 url('/assets/bg-image/loading-bg.webp') center/cover no-repeat}
.loading-cards{position:relative;width:220px;height:150px}
.loading-card{position:absolute;left:50%;bottom:0;width:92px;height:130px;border-radius:12px;background:#fdf8ec;box-shadow:0 10px 22px rgba(0,0,0,.35);padding:10px;font:800 24px 'Nunito';color:#1b2a52;opacity:0;display:flex;flex-direction:column}
.loading-card.red{color:#d23b3b}
.loading-card .loading-suit{margin-top:auto;align-self:flex-end;font-size:36px;line-height:1}
.loading-card.c1{animation:loading-card-1 .55s cubic-bezier(.25,1.5,.4,1) .05s forwards}
.loading-card.c2{animation:loading-card-2 .55s cubic-bezier(.25,1.5,.4,1) .28s forwards}
.loading-card.c3{animation:loading-card-3 .55s cubic-bezier(.25,1.5,.4,1) .5s forwards;box-shadow:0 0 26px rgba(255,225,140,.6),0 10px 24px rgba(0,0,0,.4);z-index:3}
@keyframes loading-card-1{from{opacity:0;transform:translate(-50%,20px) scale(.6) rotate(-4deg)}to{opacity:1;transform:translate(-92%,0) scale(1) rotate(-14deg)}}
@keyframes loading-card-2{from{opacity:0;transform:translate(-50%,20px) scale(.6) rotate(0deg)}to{opacity:1;transform:translate(-58%,0) scale(1) rotate(-4deg)}}
@keyframes loading-card-3{from{opacity:0;transform:translate(-50%,20px) scale(.6) rotate(6deg)}to{opacity:1;transform:translate(-15%,0) scale(1.05) rotate(6deg)}}
.loading-brand{display:flex;align-items:center;gap:8px;margin:0;color:#fff;font:800 15px 'Nunito';text-shadow:0 2px 6px rgba(0,0,0,.25)}
.loading-brand img{width:26px;height:26px;border-radius:8px;display:block}
.loading-text{margin:0;color:rgba(255,255,255,.9);font:700 15px 'Nunito';text-shadow:0 2px 8px rgba(0,0,0,.25);letter-spacing:.3px}

/* Placeholder de carregamento inline (loadingBlockHtml em app.js) — usado
   nas telas normais (Loja/Conta/Jogos/Recompensas) enquanto busca dados,
   diferente da tela cheia de loadingScreen() (só pra abrir mesa online). */
.page-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;min-height:60vh;padding:var(--sp-8) var(--sp-6)}
.page-loading-spinner{width:64px;height:64px;border-radius:20px;overflow:hidden;box-shadow:0 6px 20px rgba(0,0,0,.3);animation:page-loading-pulse 1.2s ease-in-out infinite}
.page-loading-spinner img{width:100%;height:100%;object-fit:contain;display:block}
@keyframes page-loading-pulse{0%,100%{transform:scale(1);opacity:.75}50%{transform:scale(1.08);opacity:1}}
.page-loading-text{margin:0;font:700 13px 'Nunito';letter-spacing:1px;text-transform:uppercase;color:var(--muted)}

/* Arte oficial da abertura (assets/bg-image/) — retrato por padrão
   (celular, a maioria dos acessos), paisagem a partir do mesmo breakpoint
   de desktop já usado na mesa (860px). Ambas já trazem o logo "Carteado" +
   cartas + fichas prontos, então aqui só entra a arte cheia com um fade +
   leve zoom-out de entrada. */
.splash-screen{position:fixed;inset:0;z-index:2000;display:flex;align-items:center;justify-content:center;background:#160a24 url('/assets/bg-image/bg-image-inicial.webp') center/cover no-repeat;animation:splash-in .6s ease}
/* Logo separado do fundo — entra 1.2s depois (ver splashScreen em app.js),
   fade + leve "zoom in" quando ganha .show-logo. */
.splash-logo{width:min(72vw,340px);filter:drop-shadow(0 10px 24px rgba(0,0,0,.5));opacity:0;transform:scale(.85);transition:opacity .5s ease,transform .5s ease}
.splash-logo.show-logo{opacity:1;transform:scale(1)}
@keyframes splash-in{from{opacity:0;transform:scale(1.04)}to{opacity:1;transform:scale(1)}}

/* ---------- Modal de "subiu de nível" (estrela + recompensa em moedas) ---------- */
.level-up-backdrop{background:rgba(10,4,20,.72);z-index:4}
.level-up-card{width:100%;max-width:320px;padding:34px 26px 28px;border-radius:26px;text-align:center;background:radial-gradient(circle at 50% 18%, #3a1550 0%, #1f0a2e 60%, #17081f 100%);box-shadow:0 20px 60px rgba(0,0,0,.5);position:relative;overflow:hidden}
.level-up-eyebrow{margin:0 0 18px;color:#e7b8ff;font:800 12px 'Nunito';letter-spacing:1px;text-transform:uppercase}
.level-up-star-wrap{display:flex;justify-content:center;margin-bottom:6px}
.level-up-star{width:112px;height:112px;display:grid;place-items:center;font:900 44px 'Nunito';color:#a3450a;background:radial-gradient(circle at 35% 30%, #ffe89a 0%, #ffc93d 45%, #ff9d0a 100%);clip-path:polygon(50% 0%,64% 35%,100% 38%,72% 60%,82% 100%,50% 78%,18% 100%,28% 60%,0% 38%,36% 35%);box-shadow:0 0 50px rgba(255,201,61,.65);animation:level-up-star-pop .5s cubic-bezier(.3,1.6,.4,1) backwards .1s}
@keyframes level-up-star-pop{from{transform:scale(.3) rotate(-25deg);opacity:0}to{transform:scale(1) rotate(0deg);opacity:1}}
.level-up-ribbon{display:inline-block;margin:6px 0 4px;padding:7px 22px;border-radius:100px;background:linear-gradient(135deg,#ff8bd6,#c04fd6);color:#fff;font:800 14px 'Nunito';box-shadow:0 4px 0 #8a2ea8}
.level-up-unlock{margin:10px 0 0;color:rgba(255,255,255,.85);font:600 12.5px 'Nunito'}
.level-up-reward-label{margin:18px 0 4px;color:rgba(255,255,255,.55);font:700 11px 'Nunito';text-transform:uppercase;letter-spacing:.8px}
.level-up-coins{margin:0 0 20px;color:#ffd873;font:900 30px 'Nunito';text-shadow:0 2px 10px rgba(255,180,40,.4)}
.level-up-collect{width:100%;border:0;border-radius:100px;padding:15px;background:linear-gradient(135deg,#ff8bd6,#c04fd6);color:#fff;font:800 15px 'Nunito';cursor:pointer;box-shadow:0 4px 0 #8a2ea8}
.level-up-collect:active{transform:translateY(2px);box-shadow:0 2px 0 #8a2ea8}

/* ---------- Dominó ---------- */
/* Peça com pips reais (não números) — grid 3×3, DOMINO_PIP_POS em app.js
   decide quais posições acendem por contagem. */
.pip-face{display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,1fr);width:100%;height:100%;padding:2px;box-sizing:border-box}
.pip-face i{background:#1b1424;border-radius:50%;width:68%;height:68%;justify-self:center;align-self:center}
.domino-tile{display:inline-flex;background:#fdfaf3;border-radius:6px;box-shadow:0 2px 4px rgba(0,0,0,.35);border:1px solid rgba(0,0,0,.1)}
/* Cada metade da peça (um .pip-face) precisa ser um quadrado de verdade —
   senão os pontinhos (grid 3x3 dentro do pip-face) ficam espremidos em
   células retangulares e a peça parece "achatada". width = 1 metade,
   height = 2 metades + a divisória central. */
.domino-tile-v{width:46px;height:94px;flex-direction:column}
.domino-tile-h{width:66px;height:32px;flex-direction:row;flex-shrink:0}
.domino-tile-v .pip-face,.domino-tile-h .pip-face{flex:1}
.domino-tile-divider{background:rgba(0,0,0,.15)}
.domino-tile-v .domino-tile-divider{height:1.5px;margin:0 4px}
.domino-tile-h .domino-tile-divider{width:1.5px;margin:4px 0}
/* Carroça no tabuleiro atravessada (mesmo padrão de peça de mesa
   dominó real) — mesma "metade quadrada" de 32px do tabuleiro, só que
   empilhada em vez de lado a lado. */
.domino-tile-h.double-turn{width:32px;height:66px;flex-direction:column}
.domino-tile-h.double-turn .domino-tile-divider{width:auto;height:1.5px;margin:0 4px}
.domino-tile.double{box-shadow:0 2px 4px rgba(0,0,0,.35),0 0 0 2px var(--gold)}
.domino-hand-btn{border:0;background:none;padding:0;cursor:pointer;transition:transform .12s ease,opacity .2s ease}
.domino-hand-btn:disabled{opacity:.4;cursor:default}
.domino-hand-btn:active:not(:disabled){transform:translateY(2px)}
.mesa8-hand.dealing .domino-hand-btn{animation:deal-in .5s ease backwards}
.domino-tile.tile-played{animation:card-played .5s ease backwards}
/* Corrente jogada sempre centralizada — quando cabe tudo na tela, fica
   parada no meio (era pinada na borda esquerda antes); quando estoura a
   largura, ainda dá pra rolar (o JS centraliza a peça mais nova depois de
   cada jogada, ver dominoScrollBoardToEnd). */
/* flex:1 + align-items:center: cresce pra ocupar o espaço sobrando entre
   a lista de oponentes (topo) e a mão/ações (embaixo) — mesmo "peças no
   centro da tela" da referência, não só centralizado dentro da própria
   caixa. */
.domino-board-wrap{position:relative;overflow-x:auto;overflow-y:hidden;padding:14px 10px;background:rgba(255,255,255,.12);border-radius:16px;margin:0 4px;display:flex;align-items:center;justify-content:center;flex:1;min-height:70px}
.domino-board{display:flex;gap:4px;align-items:center;min-height:40px}
/* Peça selecionada (encaixa nas duas pontas — ver dominoSelectedTile em
   app.js): alvos tocáveis nas pontas do tabuleiro, um pouco maiores que a
   peça em si pra facilitar o toque, com borda pulsante pra chamar
   atenção. position:absolute pra não empurrar o conteúdo do wrap. */
.domino-hand-btn.selected .domino-tile{box-shadow:0 2px 4px rgba(0,0,0,.35),0 0 0 3px var(--gold);transform:translateY(-4px)}
.domino-side-target{position:absolute;top:50%;transform:translateY(-50%);width:48px;height:48px;border-radius:12px;border:3px solid var(--gold);background:rgba(255,203,71,.22);animation:domino-target-pulse 1s ease-in-out infinite;cursor:pointer;z-index:2}
.domino-side-target.left{left:6px}
.domino-side-target.right{right:6px}
@keyframes domino-target-pulse{0%,100%{opacity:.6}50%{opacity:1}}
