/* ══════════════════════════════════════════════════════════════════════════
   YGO Classic Duels — estilos do jogo.
   As telas (login/lobby/loja/decks) usam Tailwind (tailwind.css); este arquivo
   cuida do BOARD DE DUELO, efeitos/animações e componentes compartilhados.
   ══════════════════════════════════════════════════════════════════════════ */

:root {
  /* Dourado fica reservado para ALERTAS (aguardando, turno, vitória, toasts). */
  --gold: #e8c064;
  --gold-bright: #ffd75e;
  /* Acento da interface: azul sobre azul-escuro/quase-preto. */
  --accent: #59a7f0;
  --accent-bright: #8ec7ff;
  --abyss: #0a0e14;
  --panel: #141b26;
  --line: #2c3a4a;
  /* ── Painel chanfrado: os MESMOS valores da home e das configurações ───────
     A assinatura da casa é "elemento com clip-path pinta a BORDA · ::before
     inset:1px pinta o FUNDO". Estes três tokens são o par de cores desse
     truque; o duelo os usa para não ter uma paleta própria (era azul saturado)
     enquanto o resto da plataforma usa aço sobre carvão. */
  --edge: rgba(140, 158, 182, 0.22);   /* fio do chanfro, neutro */
  --edge-lit: rgba(120, 180, 255, 0.40); /* fio ACESO: diálogo/painel em foco */
  --fill-panel: linear-gradient(168deg, rgba(20, 25, 33, 0.94), rgba(10, 13, 19, 0.93));
  /* Caixa DENTRO de um painel (texto de efeito, registro): mais funda que ele. */
  --fill-inset: rgba(5, 9, 16, 0.66);
  /* Divisória de cabeçalho — a mesma linha fina do .set-card-head. */
  --hair: rgba(140, 165, 200, 0.14);
  /* Costura da coluna do duelista (moldura lateral do avatar, diagonal da base
     e separador da barra de vida). PRETA: qualquer cinza-azulado ali vira um
     contorno claro em volta do retrato e é a primeira coisa que o olho pega —
     e o assunto daquela área é o personagem, não a moldura. A 25% ela
     separa sem virar contorno: é sombra, não traço. */
  --seam: rgba(0, 0, 0, 0.25);
  /* Queda da diagonal do perfil: a MESMA medida corta a base do avatar
     (partículas) e inclina o topo da barra de vida — assim os dois casam
     exatamente. Subir = diagonal mais acentuada. */
  --avatar-cut: 36px;
  --steel: #9fb4c8;
  /* Enquadramento dos retratos de perfil nos espaços REDONDOS/pequenos. Eles
     são bustos altos e de proporções variadas na zona (894×894, 768×1080…):
     recortar pelo centro pega o peito e decapita o personagem. Puxando o corte
     para perto do topo, o que sobrevive é sempre o ROSTO. */
  --face-crop: 50% 14%;
  --danger: #ff5c49;
  --heal: #5eff9c;
  /* Carta na MÃO: a largura é o token, a altura sai dela pela proporção da
     carta (59×86). Existem para as fileiras da mão poderem RESERVAR a altura
     de uma carta mesmo com a mão vazia — antes a fileira colapsava e o board
     (que é `flex: 1` entre as duas) subia ou descia sozinho. Mão vazia é
     estado comum (setou tudo, descartou por Dark World); o tabuleiro andar
     junto era a peça saindo debaixo do dedo. */
  --hand-card-w: clamp(64px, 6.2vw, 92px);
  --hand-card-h: calc(var(--hand-card-w) * 86 / 59);
  --ohand-card-w: clamp(40px, 3.6vw, 58px);
  --ohand-card-h: calc(var(--ohand-card-w) * 86 / 59);
  /* Respiro lateral do #field. Era uma zona inteira + 46px, para caber os
     slots satélite de BANIDAS; hoje é só a folga das colunas externas, que já
     se afastam 24px pelo `edge-l/edge-r`. Vira token porque a linha da
     divisória precisa dele para alcançar as duas bordas. */
  --field-pad-x: 42px;
  /* Trilho de fases colado por fora da borda direita, e a altura de cada
     degrau dele (o cursor deslizante herda a mesma). */
  --rail-w: 44px;
  --seg-h: 30px;

  /* Largura de zona: o MENOR entre o que a largura permite e o que a altura
     permite. Só a conta de largura existia, e o teto de 96px era ela disfarçada
     de gosto — numa tela 1366×768 o board já transbordava e o `overflow:hidden`
     escondia o corte.

     LARGURA: (100vw − 726) ÷ 7 colunas. As colunas laterais têm 224px de piso e
     comem a calha que sobra; 726 = 2×224 + 2×20 de calha + 24 de padding do
     root + 122 do campo fora do grid (gaps, padding, borda) + 2×44 do trilho e
     do espelho dele que mantém o board centrado.

     ALTURA: o que sobra do #board3d dividido pelas 4 fileiras. 102 = padding e
     borda do #duel-root e do #field + os gaps + a divisória; as duas mãos
     entram pelos próprios tokens, que já dependem da largura da janela.

     O teto subiu de 96 para 120: com as fases fora do meio do board e as
     banidas fora da lateral, em tela cheia sobrava calha para dar de sobra.

     As três peças ficam separadas para os @media trocarem só a que muda: o
     orçamento de LARGURA muda com as colunas laterais, o de ALTURA não muda
     nunca (é a mesma pilha vertical em qualquer janela). */
  --zone-fit-w: calc((100vw - 726px) / 7);
  --zone-fit-h: calc((100vh - 102px - var(--hand-card-h) - var(--ohand-card-h)) / 4 / 1.375);
  --zone-cap: 120px;
  --zone-w: clamp(50px, min(var(--zone-fit-w), var(--zone-fit-h)), var(--zone-cap));
  --zone-h: calc(var(--zone-w) * 1.375);
  /* Cantos "quebrados" (chanfro no canto sup-esq e inf-dir): a assinatura
     visual tecnológica do board — usada em painéis, botões e diálogos. */
  /* --cut-xs: mesma assinatura em peças MIÚDAS (chip, selo, interruptor), onde o
     corte de 8px comeria metade do elemento. */
  --cut-xs: polygon(5px 0, 100% 0, 100% calc(100% - 5px), calc(100% - 5px) 100%, 0 100%, 0 5px);
  --cut-sm: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
  --cut-md: polygon(14px 0, 100% 0, 100% calc(100% - 14px), calc(100% - 14px) 100%, 0 100%, 0 14px);
  /* Espelho horizontal do cut-md: chanfra SUP-DIR + INF-ESQ. Vai na lateral
     esquerda p/ os dois painéis "se encararem" (cantos internos espelhados). */
  --cut-md-mirror: polygon(0 0, calc(100% - 14px) 0, 100% 14px, 100% 100%, 14px 100%, 0 calc(100% - 14px));
  /* O mesmo corte do --cut-md-mirror (SUP-DIR + INF-ESQ), mas GRANDE: é a
     assinatura do BOARD. O tamanho é responsivo porque o corte come o padding
     lateral do #field, e esse padding encolhe junto com a tela — passar do
     padding significaria decepar a primeira/última zona (ver os @media). */
  /* Paralelogramo dos segmentos de fase (bordas laterais inclinadas). */
  --slant: polygon(7px 0, 100% 0, calc(100% - 7px) 100%, 0 100%);
  /* Cursor "navigation-arrow": seta dourada SÓLIDA com leve degradê (dourado
     claro → um pouco mais escuro), sem borda. Hotspot na ponta (6 6). */
  --cursor-nav: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'><defs><linearGradient id='cg' x1='0' y1='0' x2='0.8' y2='1'><stop offset='0' stop-color='%23ffe08c'/><stop offset='1' stop-color='%23e6b84f'/></linearGradient></defs><path d='M6 6 L25 13 L15 15 L13 25 Z' fill='url(%23cg)'/></svg>") 6 6;
  /* Mesma seta, dourado mais ESCURO — usada enquanto o botão está pressionado. */
  --cursor-nav-down: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'><defs><linearGradient id='cg' x1='0' y1='0' x2='0.8' y2='1'><stop offset='0' stop-color='%23dca747'/><stop offset='1' stop-color='%23a87c28'/></linearGradient></defs><path d='M6 6 L25 13 L15 15 L13 25 Z' fill='url(%23cg)'/></svg>") 6 6;

  /* ── Marcas das ZONAS do board (glifos Phosphor, peso LIGHT) ──────────────
     Vão como MÁSCARA e não como fonte de ícone: o bundle de ícones da
     plataforma (`fonts/phosphor/style.css` no CDN) só traz o peso duotone, e
     subir a fonte Light inteira — 155 kB — por causa de cinco marcas não se
     paga. Máscara ainda tem a vantagem de herdar a cor: a mesma marca acende
     no hover e na zona elegível sem precisar de um segundo arquivo.
     Extraídos de @phosphor-icons/web/src/light/selection.json (grade 1024). */
  --ic-circle: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'><path d='M512 104c-225.332 0-408 182.668-408 408s182.668 408 408 408c225.332 0 408-182.668 408-408v0c-0.273-225.222-182.778-407.727-407.974-408l-0.026-0zM512 872c-198.823 0-360-161.177-360-360s161.177-360 360-360c198.823 0 360 161.177 360 360v0c-0.228 198.731-161.269 359.773-359.979 360l-0.021 0z'/></svg>");
  --ic-circle-dashed: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'><path d='M392.76 146.16c-0.486-1.804-0.765-3.875-0.765-6.011 0-11.11 7.549-20.457 17.797-23.191l0.168-0.038c30.61-8.219 65.754-12.94 102-12.94s71.39 4.721 104.85 13.582l-2.85-0.642c10.435 2.76 18.002 12.116 18.002 23.24 0 13.256-10.746 24.002-24.002 24.002-2.132 0-4.199-0.278-6.167-0.8l0.167 0.038c-27.008-7.261-58.017-11.431-90-11.431s-62.992 4.171-92.512 11.998l2.512-0.566c-1.79 0.478-3.845 0.753-5.964 0.753-11.12 0-20.474-7.563-23.198-17.825l-0.038-0.168zM220.76 226.16c-46.998 47.869-82.321 107.36-101.258 173.76l-0.702 2.88c-0.549 1.913-0.864 4.111-0.864 6.382 0 10.986 7.381 20.248 17.455 23.097l0.169 0.041c1.91 0.559 4.104 0.88 6.373 0.88 0.009 0 0.019-0 0.028-0l-0.001 0c10.973-0.005 20.223-7.373 23.079-17.431l0.041-0.169c17.381-61.039 48.568-113.441 90.088-155.649l-0.048 0.049c4.254-4.328 6.88-10.267 6.88-16.82 0-13.255-10.745-24-24-24-6.702 0-12.762 2.747-17.117 7.177l-0.003 0.003zM165.12 608.36c-2.658-10.578-12.084-18.285-23.31-18.285-13.255 0-24 10.745-24 24 0 2.529 0.391 4.966 1.116 7.255l-0.046-0.17c19.614 69.314 54.941 128.836 102.020 176.781l-0.060-0.061c4.294 4.082 10.115 6.593 16.523 6.593 13.255 0 24-10.745 24-24 0-6.268-2.403-11.975-6.338-16.25l0.015 0.017c-41.448-42.25-72.6-94.749-89.3-153.338l-0.62-2.542zM601.96 860.6c-27.008 7.261-58.017 11.431-90 11.431s-62.992-4.171-92.512-11.998l2.512 0.566c-1.801-0.484-3.868-0.762-6-0.762-13.256 0-24.002 10.746-24.002 24.002 0 11.124 7.567 20.48 17.835 23.202l0.167 0.038c30.61 8.216 65.754 12.935 102 12.935s71.39-4.719 104.851-13.576l-2.851 0.642c10.435-2.76 18.002-12.116 18.002-23.24 0-13.256-10.746-24.002-24.002-24.002-2.132 0-4.199 0.278-6.167 0.8l0.167-0.038zM888.44 591.68c-1.916-0.55-4.118-0.867-6.393-0.867-10.972 0-20.225 7.363-23.086 17.418l-0.041 0.169c-17.317 61.191-48.515 113.737-90.091 156.052l0.051-0.052c-4.254 4.328-6.88 10.267-6.88 16.82 0 13.255 10.745 24 24 24 6.702 0 12.762-2.747 17.117-7.177l0.003-0.003c47.062-47.917 82.43-107.478 101.378-173.96l0.702-2.88c0.549-1.913 0.864-4.111 0.864-6.382 0-10.986-7.381-20.248-17.455-23.097l-0.169-0.041zM858.88 415.68c2.897 10.227 12.147 17.595 23.119 17.6l0.001 0c0.008 0 0.017 0 0.027 0 2.269 0 4.463-0.321 6.54-0.921l-0.166 0.041c10.224-2.902 17.587-12.155 17.587-23.127 0-2.275-0.317-4.476-0.908-6.562l0.041 0.169c-19.614-69.314-54.941-128.836-102.020-176.781l0.060 0.061c-4.294-4.082-10.115-6.593-16.523-6.593-13.255 0-24 10.745-24 24 0 6.268 2.403 11.975 6.338 16.25l-0.015-0.017c41.451 42.234 72.604 94.721 89.301 153.3l0.619 2.54z'/></svg>");
  --ic-ghost: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'><path d='M440 464c0 22.091-17.909 40-40 40s-40-17.909-40-40c0-22.091 17.909-40 40-40v0c22.091 0 40 17.909 40 40v0zM624 424c-22.091 0-40 17.909-40 40s17.909 40 40 40c22.091 0 40-17.909 40-40v0c0-22.091-17.909-40-40-40v0zM888 480v384c-0.007 13.249-10.75 23.987-24 23.987-5.787 0-11.096-2.048-15.241-5.46l0.041 0.033-102.12-83.56-102.16 83.56c-4.104 3.378-9.413 5.427-15.2 5.427s-11.096-2.048-15.241-5.46l0.041 0.033-102.12-83.56-102.12 83.56c-4.104 3.378-9.413 5.427-15.2 5.427s-11.096-2.048-15.241-5.46l0.041 0.033-102.16-83.56-102.12 83.56c-4.104 3.378-9.413 5.427-15.2 5.427-13.25 0-23.993-10.738-24-23.986l-0-0.001v-384c0-207.659 168.341-376 376-376s376 168.341 376 376v0zM840 480c0-181.149-146.851-328-328-328s-328 146.851-328 328v0 333.36l78.12-64c4.104-3.378 9.413-5.427 15.2-5.427s11.096 2.048 15.241 5.46l-0.041-0.033 102.16 83.56 102.12-83.56c4.104-3.378 9.413-5.427 15.2-5.427s11.096 2.048 15.241 5.46l-0.041-0.033 102.12 83.56 102.16-83.56c4.104-3.378 9.413-5.427 15.2-5.427s11.096 2.048 15.241 5.46l-0.041-0.033 78.12 64z'/></svg>");
  --ic-hexagon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'><path d='M890.88 271.64l-352-192.72c-7.752-4.361-17.016-6.929-26.88-6.929s-19.128 2.569-27.16 7.074l0.28-0.144-352 192.72c-17.47 9.697-29.102 28.028-29.12 49.077l-0 0.003v382.56c0.018 21.052 11.65 39.383 28.834 48.934l0.286 0.146 352 192.72c7.753 4.354 17.017 6.918 26.88 6.918s19.127-2.564 27.161-7.063l-0.281 0.145 352-192.72c17.47-9.697 29.102-28.028 29.12-49.077l0-0.003v-382.56c-0.018-21.052-11.65-39.383-28.834-48.934l-0.286-0.146zM872 703.28c0 0.021 0 0.046 0 0.072 0 2.946-1.592 5.519-3.963 6.908l-0.038 0.020-352 192.72c-1.109 0.618-2.432 0.982-3.84 0.982s-2.731-0.364-3.881-1.003l0.041 0.021-352.32-192.72c-2.408-1.409-4-3.983-4-6.928 0-0.025 0-0.050 0-0.075l-0 0.004v-382.56c-0-0.021-0-0.046-0-0.072 0-2.946 1.592-5.519 3.963-6.908l0.038-0.020 352-192.72c1.109-0.618 2.432-0.982 3.84-0.982s2.731 0.364 3.881 1.003l-0.041-0.021 352 192.72c2.408 1.409 4 3.983 4 6.928 0 0.025-0 0.050-0 0.075l0-0.004z'/></svg>");
  --ic-octagon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'><path d='M903.6 326.6l-206.2-206.2c-10.085-10.131-24.042-16.4-39.463-16.4-0.048 0-0.096 0-0.144 0l0.007-0h-291.6c-0.041-0-0.089-0-0.137-0-15.421 0-29.378 6.269-39.461 16.398l-0.002 0.002-206.2 206.2c-10.131 10.085-16.4 24.042-16.4 39.463 0 0.048 0 0.096 0 0.144l-0-0.007v291.6c-0 0.041-0 0.089-0 0.137 0 15.421 6.269 29.378 16.398 39.461l0.002 0.002 206.2 206.2c10.085 10.131 24.042 16.4 39.463 16.4 0.048 0 0.096-0 0.144-0l-0.007 0h291.6c0.041 0 0.089 0 0.137 0 15.421 0 29.378-6.269 39.461-16.398l0.002-0.002 206.2-206.2c10.131-10.085 16.4-24.042 16.4-39.463 0-0.048-0-0.096-0-0.144l0 0.007v-291.6c0-0.041 0-0.089 0-0.137 0-15.421-6.269-29.378-16.398-39.461l-0.002-0.002zM872 657.8c0 0.002 0 0.004 0 0.006 0 2.218-0.902 4.224-2.36 5.673l-0 0-206.2 206.16c-1.442 1.45-3.435 2.35-5.638 2.36l-0.002 0h-291.6c-0.002 0-0.004 0-0.006 0-2.218 0-4.224-0.902-5.673-2.36l-0-0-206.16-206.16c-1.458-1.449-2.36-3.456-2.36-5.674 0-0.002 0-0.004 0-0.007l-0 0v-291.6c-0-0.002-0-0.004-0-0.006 0-2.218 0.902-4.224 2.36-5.673l0-0 206.2-206.16c1.442-1.45 3.435-2.35 5.638-2.36l0.002-0h291.6c0.002-0 0.004-0 0.006-0 2.218 0 4.224 0.902 5.673 2.36l0 0 206.16 206.2c1.45 1.442 2.35 3.435 2.36 5.638l0 0.002z'/></svg>");
  --ic-prohibit: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'><path d='M512 104c-225.332 0-408 182.668-408 408s182.668 408 408 408c225.332 0 408-182.668 408-408v0c-0.273-225.222-182.778-407.727-407.974-408l-0.026-0zM872 512c0 0.095 0 0.208 0 0.32 0 90.839-33.795 173.785-89.498 236.95l0.338-0.391-507.72-507.72c62.961-55.368 146.075-89.154 237.080-89.154 198.712 0 359.8 161.088 359.8 359.8 0 0.068-0 0.136-0 0.205l0-0.010zM152 512c-0-0.095-0-0.208-0-0.32 0-90.839 33.795-173.785 89.498-236.95l-0.338 0.391 507.72 507.72c-62.961 55.368-146.075 89.154-237.080 89.154-198.712 0-359.8-161.088-359.8-359.8 0-0.068 0-0.136 0-0.205l-0 0.010z'/></svg>");
  --ic-spiral: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'><path d='M984 576c0 13.255-10.745 24-24 24s-24-10.745-24-24v0c-0.25-216.395-175.605-391.75-391.976-392l-0.024-0c-198.731 0.228-359.773 161.269-360 359.979l-0 0.021c0.227 181.058 146.942 327.772 327.978 328l0.022 0c163.394-0.205 295.795-132.606 296-295.981l0-0.019c-0.182-145.73-118.27-263.818-263.983-264l-0.017-0c-128.066 0.159-231.841 103.934-232 231.984l-0 0.016c0.136 110.402 89.598 199.863 199.987 200l0.013 0c92.784 0 168-75.216 168-168v0c0-75.111-60.889-136-136-136v0c-57.438 0-104 46.562-104 104v0c0 39.765 32.235 72 72 72v0c22.091 0 40-17.909 40-40v0c0-4.418-3.582-8-8-8v0c-13.255 0-24-10.745-24-24s10.745-24 24-24v0c30.928 0 56 25.072 56 56v0c0 48.601-39.399 88-88 88v0c-66.274 0-120-53.726-120-120v0c0-83.947 68.053-152 152-152v0c101.565 0.136 183.864 82.435 184 183.987l0 0.013c-0.137 119.239-96.762 215.864-215.987 216l-0.013 0c-136.903-0.159-247.841-111.097-248-247.985l-0-0.015c0.182-154.567 125.434-279.818 279.983-280l0.017-0c172.23 0.205 311.795 139.77 312 311.98l0 0.020c-0.227 189.894-154.106 343.773-343.978 344l-0.022 0c-207.558-0.25-375.749-168.441-376-375.975l-0-0.025c0.273-225.222 182.778-407.727 407.974-408l0.026-0c242.886 0.296 439.704 197.114 440 439.972l0 0.028z'/></svg>");
}

.hidden { display: none !important; }

/* Sem seleção/arraste acidental ao clicar-e-arrastar (feel de app/jogo). Campos
   de texto seguem selecionáveis para o usuário digitar/editar normalmente. */
body { -webkit-user-select: none; -moz-user-select: none; user-select: none; }
input, textarea, [contenteditable] { -webkit-user-select: text; -moz-user-select: text; user-select: text; }
img { -webkit-user-drag: none; user-drag: none; }

/* ── Barra de rolagem (TODA a plataforma) ──────────────────────────────────
   Um só desenho para qualquer área rolável — modais, listas, log do duelo,
   inspetor. Traço da casa: nada de pílula cinza do sistema; a barra é um FIO
   RETO (cantos vivos, como os chanfros dos painéis), quase invisível parada, e
   que acende no AZUL do acento quando o ponteiro entra na área rolável — o que
   dá o retorno sem competir com o conteúdo.
   O `border` transparente + `background-clip: padding-box` é o truque que
   afina o fio dentro de uma calha larga: a área de arraste continua confortável
   (10px), mas o que se vê são 4px. Regra global de propósito — área rolável
   nova já nasce no padrão, sem CSS próprio. */
* { scrollbar-width: thin; scrollbar-color: rgba(159, 180, 200, 0.16) transparent; }
*:hover { scrollbar-color: rgba(142, 199, 255, 0.38) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-corner { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(159, 180, 200, 0.16); border: 3px solid transparent;
  background-clip: padding-box; /* deixa o fio com 4px dentro da calha de 10px */
  transition: background 0.16s;
}
:hover::-webkit-scrollbar-thumb { background: rgba(142, 199, 255, 0.34); }
::-webkit-scrollbar-thumb:hover { background: rgba(142, 199, 255, 0.6); }
::-webkit-scrollbar-thumb:active { background: var(--accent-bright); }

/* Fundo com auras (todas as telas) */
#bg-aura {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(600px 400px at 15% -5%, rgba(90, 150, 230, 0.09), transparent 70%),
    radial-gradient(700px 500px at 110% 15%, rgba(56, 120, 198, 0.12), transparent 70%),
    radial-gradient(900px 700px at 50% 120%, rgba(30, 70, 140, 0.14), transparent 70%);
}

/* ── Componentes compartilhados (criados via JS) ───────────────────────── */

.room-entry {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  padding: 12px 16px; clip-path: var(--cut-sm);
  background: rgba(255, 255, 255, 0.04); transition: background 0.16s;
}
.room-entry:hover { background: rgba(255, 255, 255, 0.08); }
.room-entry .re-info { min-width: 0; }
.room-entry .re-name { font-size: 14px; font-weight: 800; color: #e7ebf1; }
.room-entry .re-meta {
  margin-top: 3px; font-size: 11.5px; color: #8b93a0;
  display: flex; align-items: center; gap: 3px; flex-wrap: wrap;
}
.room-entry .re-meta i { font-size: 13px; opacity: 0.8; }
.room-entry .re-right { display: flex; align-items: center; gap: 10px; flex: none; }
.re-status {
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 4px 9px; border-radius: 999px;
}
.re-status--waiting { color: #6ee7a5; background: rgba(52, 214, 126, 0.14); }
.re-status--rps { color: var(--gold-bright); background: rgba(232, 192, 100, 0.14); }
.re-status--duel, .re-status--done { color: #9fb4c8; background: rgba(160, 180, 210, 0.12); }
.re-join {
  border: none; cursor: pointer; font-family: inherit; clip-path: var(--cut-sm);
  padding: 8px 16px; font-weight: 800; font-size: 12.5px; color: #fff;
  background: linear-gradient(180deg, #34d67e, #12a355);
  display: inline-flex; align-items: center; gap: 6px; transition: filter 0.15s, transform 0.1s;
}
.re-join:hover { filter: brightness(1.1); }
.re-join:active { transform: scale(0.95); }

/* (A loja de boosters — prateleira, boosters e carrinho — vive na seção
    "LOJA DE BOOSTERS" mais abaixo, junto do parallax da cena.) */

.deck-entry {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: 12px;
  background: rgba(255, 255, 255, 0.03); transition: border-color 0.15s;
}
.deck-entry:hover { border-color: rgba(56, 189, 248, 0.5); }
.deck-entry .deck-meta { color: var(--steel); font-size: 12.5px; }
.deck-entry button {
  border: 1px solid var(--line); border-radius: 8px; padding: 7px 12px; font-size: 13px;
  font-weight: 600; color: #e2e8f0; background: rgba(255, 255, 255, 0.05); cursor: pointer;
  transition: background 0.15s, transform 0.1s;
}
.deck-entry button:hover { background: rgba(255, 255, 255, 0.1); }
.deck-entry button.danger { color: #fca5a5; border-color: rgba(153, 27, 27, 0.6); background: rgba(69, 10, 10, 0.4); }
.deck-entry button:active { transform: scale(0.95); }

.filter-btn {
  border: 1px solid var(--line); border-radius: 999px; padding: 5px 11px; font-size: 12px;
  font-weight: 600; color: var(--steel); background: transparent; cursor: pointer; transition: all 0.15s;
}
.filter-btn:hover { color: #e2e8f0; border-color: var(--steel); }
.filter-btn.selected-filter { color: var(--abyss); background: var(--accent); border-color: var(--accent); font-weight: 800; }

.scroll-list {
  height: 420px; overflow-y: auto; background: rgba(6, 10, 15, 0.7);
  border: 1px solid var(--line); border-radius: 10px; padding: 4px;
}
.scroll-list.small { height: 150px; }
.card-row {
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  padding: 6px 9px; border-radius: 7px; font-size: 13px; cursor: pointer; transition: background 0.12s;
}
.card-row:hover { background: rgba(56, 120, 198, 0.15); }
.card-row .qty { color: var(--steel); font-size: 11.5px; white-space: nowrap; }
.card-row.depleted { opacity: 0.35; }

.rps-btn {
  font-size: 32px; width: 68px; height: 68px; clip-path: var(--cut-sm); cursor: pointer;
  border: none; color: #dbe9fa; background: rgba(120, 180, 255, 0.28);
  display: inline-flex; align-items: center; justify-content: center;
  transition: transform 0.15s, background 0.15s, box-shadow 0.15s;
}
.rps-btn:hover {
  transform: translateY(-4px) scale(1.06); background: rgba(120, 180, 255, 0.5);
  box-shadow: 0 12px 30px -10px rgba(90, 160, 240, 0.5);
}

.rarity-COMMON { color: #c8d4e0; }
.rarity-RARE { color: #6bb2ff; }
.rarity-SUPER { color: #c9a2ff; }
.rarity-ULTRA { color: var(--gold-bright); }
@keyframes pull-reveal {
  from { opacity: 0; transform: translateX(-18px) scale(0.9); }
  to { opacity: 1; transform: none; }
}

/* ── Modal / menu de contexto / toast / preview ────────────────────────── */

#modal-backdrop {
  position: fixed; inset: 0; background: rgba(2, 4, 8, 0.72); z-index: 40;
  display: flex; align-items: center; justify-content: center; backdrop-filter: blur(3px);
  animation: fade-in 0.15s ease-out;
}
#modal {
  position: relative; background: rgba(120, 180, 255, 0.4); border: none;
  clip-path: var(--cut-md);
  padding: 20px; width: 620px; max-width: 94vw; max-height: 82vh;
  display: flex; flex-direction: column; gap: 12px;
  filter: drop-shadow(0 30px 70px rgba(0, 0, 0, 0.85));
  animation: modal-pop 0.22s cubic-bezier(0.2, 1.3, 0.4, 1);
}
#modal::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-md);
  background: rgba(15, 21, 33, 0.97); pointer-events: none;
}
@keyframes modal-pop { from { opacity: 0; transform: scale(0.92) translateY(10px); } }
@keyframes fade-in { from { opacity: 0; } }
#modal h3 { color: var(--accent-bright); font-size: 15px; font-weight: 800; letter-spacing: 0.02em; }
#modal-list { overflow-y: auto; display: flex; flex-direction: column; gap: 4px; }

/* ── Picker de cartas: lista agrupada + toggle à esquerda, preview à direita;
   divider e painel de efeito (abas + scroll) embaixo. Alturas FIXAS: o modal
   não muda de tamanho conforme o mouse passa por textos maiores/menores. */
.picker { display: flex; flex-direction: column; gap: 10px; height: min(540px, 68vh); }
.picker.compact { height: min(440px, 60vh); }
.picker-top { display: flex; gap: 14px; flex: 1; min-height: 0; }
/* Declarar 1 nome de carta (D.D. Designator, Mind Crush): a coluna da esquerda
   ganha a busca em cima da lista. O `.picker-list` de dentro herda o scroll. */
/* `min-height: 0` nos DOIS: sem isso o item flex adota a altura do conteúdo
   e a lista transborda o modal em vez de rolar dentro dele — a pegadinha
   clássica de scroll aninhado em flexbox. */
.picker-search-col {
  flex: 1.15; min-width: 0; min-height: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.picker-search-col .picker-list { flex: 1; min-height: 0; }
.picker-search {
  width: 100%; padding: 7px 10px; font: inherit; font-size: 12px;
  color: #e8eef6; background: rgba(9, 13, 21, 0.9);
  border: 1px solid rgba(159, 180, 200, 0.22); border-radius: 6px; outline: none;
}
.picker-search::placeholder { color: rgba(159, 180, 200, 0.5); }
.picker-search:focus { border-color: rgba(120, 200, 255, 0.55); }
/* O X nativo do type=search fica cinza demais no fundo escuro. */
.picker-search::-webkit-search-cancel-button { filter: invert(0.7); cursor: pointer; }
.picker-list {
  flex: 1.15; min-width: 0; overflow-y: auto; padding-right: 4px;
}
.picker-group {
  position: sticky; top: 0; z-index: 1; padding: 6px 8px 4px;
  font-size: 10px; font-weight: 900; letter-spacing: 0.14em; text-transform: uppercase;
  background: rgba(15, 21, 33, 0.97);
}
.picker-group.g-monster { color: #ffd9a8; }
.picker-group.g-spell { color: #a8f0d8; }
.picker-group.g-trap { color: #f3c2e4; }
.picker-row {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 7px 9px; border-radius: 5px; font-size: 13px; color: #dbe7f5;
  transition: background 0.12s;
}
.picker-row:hover { background: rgba(56, 120, 198, 0.16); }
.picker-row .picker-name {
  flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
/* Badge "de onde vem" a carta (campo/mão/cemitério/banido) no picker. */
.picker-where {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 3px;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.02em;
  color: rgba(190, 208, 230, 0.7); padding: 2px 7px; border-radius: 999px;
  background: rgba(120, 160, 210, 0.14); border: 1px solid rgba(120, 160, 210, 0.22);
}
.picker-where i { font-size: 13px; }
/* o toggle: bolinha que fica verdinha quando marcada */
.picker-toggle {
  flex-shrink: 0; width: 20px; height: 20px; border-radius: 50%;
  border: 2px solid rgba(150, 175, 205, 0.4); background: transparent;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; color: transparent; transition: all 0.15s;
}
.picker-row.sel { background: rgba(16, 122, 60, 0.22); }
.picker-row.sel .picker-toggle {
  border-color: #2fbf6b; background: #2fbf6b; color: #06131c;
}
/* Candidata travada pela restrição de combinação (fusão): não completa nenhuma
   receita válida junto com o que já está marcado. */
.picker-row.picker-dis { opacity: 0.38; pointer-events: none; }
.picker-preview {
  flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column;
  gap: 6px; align-items: center;
}
.picker-preview img {
  flex: 1; min-height: 0; width: 100%; object-fit: contain;
  filter: drop-shadow(0 14px 30px rgba(0, 0, 0, 0.7));
}
.picker-pname { font-weight: 800; font-size: 13px; color: var(--accent-bright); text-align: center; }
.picker-pstats { font-size: 11px; color: var(--steel); text-align: center; }
.picker-divider {
  flex-shrink: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(120, 165, 215, 0.45), transparent);
}
/* painel de efeito: altura fixa, abas quando a carta tem mais de 1 efeito */
.picker-effect {
  flex-shrink: 0; height: 112px; display: flex; flex-direction: column; gap: 7px;
}
.picker-tabs { display: flex; gap: 6px; flex-shrink: 0; flex-wrap: wrap; }
.picker-tab {
  padding: 3px 11px; border-radius: 4px; cursor: pointer; user-select: none;
  border: 1px solid rgba(120, 160, 210, 0.28); background: rgba(255, 255, 255, 0.04);
  font-size: 10px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--steel); transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.picker-tab:hover { background: rgba(56, 120, 198, 0.16); color: #dbe7f5; }
.picker-tab.on {
  background: rgba(56, 120, 198, 0.28); border-color: rgba(100, 160, 230, 0.6);
  color: var(--accent-bright);
}
.picker-tab.static { cursor: default; }
.picker-tab.static:hover { background: rgba(56, 120, 198, 0.28); }
.picker-ptext {
  flex: 1; min-height: 0; font-size: 11.5px; line-height: 1.55; color: #cdd9e6;
  white-space: pre-wrap; overflow-y: auto; padding-right: 4px;
}
#modal-list button {
  background: rgba(255, 255, 255, 0.04); text-align: left; font-weight: 500; font-size: 13px;
  color: #e2e8f0; border: 1px solid transparent; border-radius: 8px; padding: 8px 11px;
  cursor: pointer; transition: background 0.12s, border-color 0.12s;
}
#modal-list button:hover { background: rgba(56, 120, 198, 0.18); }
#modal-list button.selected { background: rgba(16, 122, 60, 0.35); border-color: #2fbf6b; }
.modal-actions { display: flex; gap: 8px; }
.modal-actions button {
  flex: 1; border: none; clip-path: var(--cut-sm); padding: 10px; font-weight: 800; font-size: 13px;
  cursor: pointer; color: var(--abyss); background: linear-gradient(180deg, #6cbcff, #2a7fd8);
  transition: filter 0.15s, transform 0.1s;
}
.modal-actions button.secondary { color: #e2e8f0; background: rgba(255, 255, 255, 0.08); }
.modal-actions button:hover { filter: brightness(1.1); }
.modal-actions button:active { transform: scale(0.97); }
.modal-actions button:disabled { filter: grayscale(0.8) brightness(0.75); opacity: 0.6; }

/* Escolha VISUAL (posição/modo): duas cartas grandes lado a lado.
   O frame é QUADRADO (lado = altura da carta) para caber tanto a carta em pé
   quanto a mesma girada 90° na MESMA escala — sem espremer a de defesa. */
.vpick { display: flex; gap: 16px; justify-content: center; padding: 6px 2px 2px; }
.vpick-opt {
  cursor: pointer; flex: 0 0 auto; box-sizing: border-box;
  display: flex; flex-direction: column; align-items: center; gap: 9px;
  width: 210px; padding: 12px; border-radius: 10px;
  border: 2px solid rgba(120, 160, 210, 0.22); background: rgba(255, 255, 255, 0.03);
  transition: border-color 0.15s, background 0.15s, transform 0.12s;
}
.vpick-opt:hover { background: rgba(120, 160, 210, 0.12); transform: translateY(-2px); }
.vpick-opt.sel { border-color: #2fbf6b; background: rgba(16, 122, 60, 0.18); }
.vpick-frame {
  flex: 0 0 auto; width: 182px; height: 182px;
  display: flex; align-items: center; justify-content: center;
}
.vpick-frame img {
  max-width: 178px; max-height: 178px; border-radius: 6px;
  box-shadow: 0 8px 20px -5px rgba(0, 0, 0, 0.75);
}
/* Girada 90°: mesma escala da carta em pé (a rotação é só transform visual). */
.vpick-frame img.rot { transform: rotate(90deg); }
.vpick-cap {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 13px; font-weight: 800; color: #dbe7f5;
}
.vpick-cap i { font-size: 16px; }
.vpick-opt.sel .vpick-cap { color: #6fe6a3; }

/* [Reasoning] Declaração de NÚMERO: fichas quadradas (não há carta para
   ilustrar, então o .vpick não serve). Mesma linguagem de seleção do .vpick. */
.numpick {
  display: grid; grid-template-columns: repeat(6, 1fr); gap: 10px;
  padding: 10px 4px 4px; justify-items: stretch;
}
.numpick-opt {
  cursor: pointer; box-sizing: border-box; padding: 14px 0;
  font-size: 20px; font-weight: 800; color: #dbe7f5;
  border-radius: 10px; font-variant-numeric: tabular-nums;
  border: 2px solid rgba(120, 160, 210, 0.22); background: rgba(255, 255, 255, 0.03);
  transition: border-color 0.15s, background 0.15s, transform 0.12s;
}
.numpick-opt:hover { background: rgba(120, 160, 210, 0.12); transform: translateY(-2px); }
.numpick-opt.sel { border-color: #2fbf6b; background: rgba(16, 122, 60, 0.18); color: #6fe6a3; }
@media (max-width: 560px) { .numpick { grid-template-columns: repeat(4, 1fr); } }

/* Menu de contexto: UM único shape (corpo + cauda/setinha) desenhado por
   clip-path — a cauda segue o MESMO contorno/borda do menu, integrada (sem
   emenda). --tail é o polígono; --tail-pad afasta os botões da cauda. */
#context-menu {
  position: fixed; z-index: 30;
  filter: drop-shadow(0 18px 40px rgba(0, 0, 0, 0.75));
  transform-origin: left center;
  animation: menu-pop 0.16s cubic-bezier(0.2, 1.25, 0.4, 1);
  /* cauda à ESQUERDA (menu abre à direita da carta) — 4 cantos chanfrados */
  --tail: polygon(16px 0, calc(100% - 7px) 0, 100% 7px, 100% calc(100% - 7px), calc(100% - 7px) 100%, 16px 100%, 9px calc(100% - 7px), 9px calc(50% + 8px), 0 50%, 9px calc(50% - 8px), 9px 7px);
  --tail-pad: 0 0 0 9px;
}
#context-menu.menu-left {
  transform-origin: right center;
  /* cauda à DIREITA (menu abre à esquerda da carta) — 4 cantos chanfrados */
  --tail: polygon(7px 0, calc(100% - 16px) 0, calc(100% - 9px) 7px, calc(100% - 9px) calc(50% - 8px), 100% 50%, calc(100% - 9px) calc(50% + 8px), calc(100% - 9px) calc(100% - 7px), calc(100% - 16px) 100%, 7px 100%, 0 calc(100% - 7px), 0 7px);
  --tail-pad: 0 9px 0 0;
}
.menu-body {
  position: relative; background: rgba(120, 180, 255, 0.45);
  display: flex; flex-direction: column; min-width: 180px;
  padding: var(--tail-pad); clip-path: var(--tail); backdrop-filter: blur(6px);
}
.menu-body::before {
  content: ''; position: absolute; inset: 1px; z-index: -1;
  clip-path: var(--tail); background: rgba(14, 20, 32, 0.97); pointer-events: none;
}
@keyframes menu-pop { from { opacity: 0; transform: scale(0.82); } to { opacity: 1; transform: scale(1); } }
#context-menu.menu-closing { animation: menu-close 0.14s ease-in forwards; }
@keyframes menu-close { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.85); } }
#context-menu button {
  background: none; border: none; text-align: left; padding: 10px 14px; font-size: 13px;
  font-weight: 600; color: #e2e8f0; cursor: pointer;
}
#context-menu button:hover { background: rgba(90, 160, 240, 0.2); color: var(--accent-bright); }

#toast {
  position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%);
  background: rgba(20, 27, 38, 0.95); border: 1px solid rgba(232, 192, 100, 0.5);
  color: #f1f5f9; padding: 11px 20px; border-radius: 12px; z-index: 50; font-size: 14px;
  font-weight: 600; box-shadow: 0 14px 40px -10px rgba(0, 0, 0, 0.8);
  animation: toast-in 0.25s cubic-bezier(0.2, 1.3, 0.4, 1);
}
@keyframes toast-in { from { opacity: 0; transform: translate(-50%, 14px); } }

#card-preview {
  /* acima do modal (40): o preview serve justamente os pickers de alvo/fusão. */
  position: fixed; left: 14px; bottom: 14px; width: 236px; z-index: 45;
  background: rgba(14, 19, 28, 0.94); border: 1px solid rgba(120, 180, 255, 0.45);
  border-radius: 14px; padding: 12px; pointer-events: none;
  display: flex; flex-direction: column; gap: 7px; backdrop-filter: blur(6px);
  box-shadow: 0 24px 70px -20px rgba(0, 0, 0, 0.9);
  animation: fade-in 0.15s;
}
/* A moldura leva a medida e a sombra; a <img> só preenche. Ela é quem hospeda
   as camadas do acabamento (ver "ACABAMENTOS DE CARTA"). */
#preview-card-art {
  position: relative; display: block; width: 172px; align-self: center;
  border-radius: 8px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
}
#preview-img { display: block; width: 100%; border-radius: 8px; }
#preview-name { font-weight: 800; color: var(--accent-bright); font-size: 14px; }
#preview-stats { font-size: 11.5px; color: var(--steel); }
#preview-text {
  font-size: 11px; line-height: 1.5; color: #d5dde5;
  max-height: 128px; overflow-y: auto; white-space: pre-wrap;
}

/* ══════════════════════════════════════════════════════════════════════════
   O BOARD DE DUELO
   ══════════════════════════════════════════════════════════════════════════ */

/* Cursor do jogo em TODAS as telas (nativo, imagem). */
* { cursor: var(--cursor-nav), auto !important; }
input, textarea, [contenteditable="true"] { cursor: text !important; }
/* Sliders (ex.: volume) NÃO são campo de texto — mantêm o cursor do jogo. */
input[type="range"] { cursor: var(--cursor-nav), pointer !important; }
:disabled { cursor: not-allowed !important; }
/* Clicar/segurar (qualquer botão) troca a seta pro dourado mais escuro. Nativo
   não faz fade, então é troca instantânea — mas sem bug de seta dupla. */
body.pressing, body.pressing * { cursor: var(--cursor-nav-down), pointer !important; }

/* ── Céu do duelo: NEBULOSA animada (src/duel/nebula.ts) ───────────────────
   Mesmo lugar dos outros fundos de cena (#parallax, #academy-bg, #lobby-bg):
   fixo atrás do <main class="z-10">, ligado por body.scene-duel. Duas
   profundidades com velocidades diferentes dão a sensação de espaço; o
   `isolation: isolate` prende o mix-blend-mode dos canvas e do grão AQUI —
   sem ele o "screen" das nuvens vazaria por cima do board. */
#duel-sky {
  position: fixed; inset: 0; z-index: 0; display: none; pointer-events: none;
  isolation: isolate;
  background:
    radial-gradient(ellipse 95% 75% at 20% 82%, rgba(16, 58, 74, 0.55), transparent 62%),
    radial-gradient(ellipse 85% 80% at 82% 16%, rgba(38, 26, 84, 0.50), transparent 64%),
    radial-gradient(ellipse 55% 45% at 74% 76%, rgba(70, 20, 48, 0.26), transparent 68%),
    radial-gradient(ellipse 70% 60% at 60% 55%, rgba(14, 44, 60, 0.30), transparent 70%),
    #02030c;
}
body.scene-duel #duel-sky { display: block; animation: neb-wake 2.4s ease-out both; }
body.scene-duel #bg-aura { display: none; }
@keyframes neb-wake { from { opacity: 0; } to { opacity: 1; } }

/* Cada profundidade se move numa velocidade diferente (o JS escreve o
   translate; a escala > 1 existe p/ o deslocamento nunca revelar a borda). */
.neb-depth { position: absolute; inset: 0; will-change: transform; }
#neb-depth-clouds { transform: scale(1.10); }
#neb-depth-stars { transform: scale(1.06); }
#duel-sky canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* `screen`: nuvem e estrela são LUZ somada ao céu, não tinta por cima dele. */
#neb-clouds, #neb-stars { mix-blend-mode: screen; }

/* Vinheta MAIS ABERTA que a do protótipo. Lá o fundo é o espetáculo e a
   vinheta fecha as bordas para o olho ir ao centro; aqui o centro é o BOARD, e
   a nebulosa só aparece justamente na moldura — fechar as bordas apagaria a
   única parte dela que se vê. Fica o suficiente para os cantos não brigarem
   com os painéis. */
.neb-vignette {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse 78% 78% at 50% 50%,
    transparent 0%, transparent 40%, rgba(0, 0, 0, 0.16) 70%, rgba(0, 0, 0, 0.38) 92%, rgba(0, 0, 0, 0.48) 100%);
}
/* Em tela alta e estreita a vinheta precisa ser mais suave nas laterais. */
@media (max-aspect-ratio: 3/4) {
  .neb-vignette {
    background: radial-gradient(ellipse 98% 66% at 50% 50%,
      transparent 0%, transparent 42%, rgba(0, 0, 0, 0.14) 72%, rgba(0, 0, 0, 0.32) 94%, rgba(0, 0, 0, 0.42) 100%);
  }
}

/* Grão de filme — também disfarça o banding dos degradês do céu. */
.neb-grain {
  position: absolute; inset: -8%; pointer-events: none; opacity: 0.055; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='220' height='220' filter='url(%23n)'/></svg>");
  animation: neb-grain 1.05s steps(1) infinite;
}
@keyframes neb-grain {
  0% { transform: translate(0, 0); }        20% { transform: translate(-1.5%, 1%); }
  40% { transform: translate(1%, -1.5%); }  60% { transform: translate(-1%, -1%); }
  80% { transform: translate(1.5%, 1.5%); } 100% { transform: translate(0, 0); }
}
@media (prefers-reduced-motion: reduce) { .neb-grain { animation: none; } }

/* Em duelo o navbar some e o board ocupa a tela inteira. */
body.in-duel > header { display: none; }
body.in-duel #duel-root { height: 100vh; }

/* O #duel-root não pinta mais fundo próprio — quem pinta é o céu, atrás dele.
   Fica só um VÉU LEVE: o board já é translúcido e os painéis já são opacos, o
   que precisa de ajuda é o contraste das cartas na mão, que ficam soltas sobre
   o céu no topo e na base. Véu pesado aqui apaga a nebulosa inteira — foi
   exatamente o que aconteceu na primeira tentativa. */
#duel-root {
  display: flex; gap: 20px; height: calc(100vh - 58px); padding: 10px 12px;
  background:
    radial-gradient(1200px 620px at 50% 50%, rgba(2, 5, 12, 0.20), transparent 76%),
    linear-gradient(180deg, rgba(3, 6, 13, 0.32), rgba(2, 4, 10, 0.08) 46%, rgba(3, 6, 13, 0.36));
  overflow: hidden;
}

/* ── Coluna esquerda: inspetor de carta + registro ─────────────────────── */

/* Chanfro com borda que ACOMPANHA o corte: clip-path decapita a border nativa
   na diagonal, então o fundo do elemento vira a COR DA LINHA e um ::before
   interno (inset 1px, mesmo polígono) pinta o fundo real — o anel de 1px que
   sobra é a borda, inclusive nos cantos quebrados. */
/* Colunas laterais SIMÉTRICAS: jogador+inspetor à esquerda, inimigo+registro
   à direita — mesma largura e mesmo tratamento. */
#duel-left {
  position: relative;
  /* "Engorda" as laterais comendo a calha vazia que sobra ao redor do board
     em telas largas — o board NUNCA encolhe (--zone-w intacto). Enxugadas de
     248/400 para 224/336: o board é o assunto, a coluna é apoio. O que sobra
     vira a calha entre a coluna e o board (o `gap` do #duel-root). */
  width: clamp(224px, calc((100vw - 1120px) / 2), 336px); flex-shrink: 0;
  display: flex; flex-direction: column; gap: 0;
  border: none; clip-path: var(--cut-md-mirror); overflow: hidden;
  /* Sem backdrop-filter: o céu ATRÁS agora é animado, e desfocar um fundo que
     muda a cada frame custa uma recomposição por frame só p/ o que o painel
     quase esconde. O `--fill-panel` já dá o contraste sozinho. */
  background: var(--edge); min-height: 0;
  filter: drop-shadow(0 18px 40px rgba(0, 0, 0, 0.55));
}
#duel-left::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-md-mirror);
  background: var(--fill-panel); pointer-events: none;
}
#inspector {
  flex: 1; display: flex; flex-direction: column; gap: 9px;
  padding: calc(12px + var(--avatar-cut)) 12px 12px; margin-top: calc(-1 * var(--avatar-cut));
  min-height: 0;
  /* Mesma costura do avatar e da barra de vida: a coluna lateral é UMA peça
     só, e a moldura dela não pode trocar de cor no meio do caminho. */
  border-left: 1px solid var(--seam);
  border-right: 1px solid var(--seam);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), transparent 40%);
  /* Topo recortado na MESMA diagonal do rodapé da barra → a área da carta
     "acompanha" o corte em vez de começar reto. Puxado p/ cima (margin) p/
     encostar na barra; padding-top compensa o conteúdo. */
  clip-path: polygon(0 0, 100% var(--avatar-cut), 100% 100%, 0 100%);
}
#insp-empty {
  flex: 1; display: flex; align-items: center; justify-content: center; text-align: center;
  color: rgba(150, 175, 205, 0.4); font-size: 12.5px; line-height: 1.7; font-weight: 600;
}

/* Carta em destaque: flutuação sutil contínua + "pop" de entrada em carta nova. */
/* Topo do inspetor: carta à ESQUERDA + stats empilhados à DIREITA. */
#insp-top { display: flex; align-items: flex-start; gap: 11px; }
#insp-top.solo { justify-content: center; }   /* magia/armadilha (sem stats): carta centralizada */
#insp-card {
  position: relative; flex: 0 0 auto; width: min(50%, 148px); perspective: 750px;
  animation: insp-float 4.5s ease-in-out infinite;
}
#insp-card img {
  width: 100%; display: block; border-radius: 8px;
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.72), 0 0 0 1px rgba(120, 160, 210, 0.14);
  transition: transform 0.16s ease-out;   /* segue o cursor (leve 3D) suavemente */
}
#insp-card.pop img { animation: insp-pop 0.46s cubic-bezier(0.2, 1.25, 0.35, 1); }
/* Badge de raridade no inspetor do duelo (mesmo estilo das outras telas). */
#insp-card::after {
  content: ''; position: absolute; bottom: 100%; right: 2px; margin-bottom: 1px; z-index: 3; pointer-events: none;
  box-sizing: border-box; width: 33px; height: 17px;
  display: flex; align-items: center; justify-content: center; padding-left: 5px;
  font-family: "Cabin", "Segoe UI", system-ui, sans-serif; font-size: 10.5px; font-weight: 900; letter-spacing: 0.03em;
  line-height: 1; color: #fff; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.55);
  clip-path: polygon(30% 0, 100% 0, 100% 100%, 0 100%);
  box-shadow: -1px 1px 4px rgba(0, 0, 0, 0.5);
}
#insp-card.r-COMMON::after { content: 'N';  background: linear-gradient(135deg, #9aa7b5, #566470); }
#insp-card.r-RARE::after   { content: 'R';  background: linear-gradient(135deg, #63b2f8, #2464c8); }
#insp-card.r-SUPER::after  { content: 'SR'; background: linear-gradient(135deg, #ff9a4d, #e0431f); }
#insp-card.r-ULTRA::after  { content: 'UR'; background: linear-gradient(125deg, #c07bff 0%, #7b8cff 38%, #5aa8ff 62%, #ff85cc 100%); }
@keyframes insp-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
@keyframes insp-pop {
  0% { opacity: 0; transform: scale(0.86) rotateX(16deg); }
  100% { opacity: 1; transform: none; }
}

/* Stats (só monstros): ATK/DEF em destaque + estrelas de nível / atributo. */
/* Stats EMPILHADOS à direita da carta: [ícone/rótulo] … [valor à direita]. */
#insp-stats { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
/* Chanfrada como o resto da interface (borda = fundo, ::before = preenchimento);
   a mesma linha serve ao inspetor do duelo, à loja e ao montador. */
.insp-stat {
  position: relative; isolation: isolate;
  display: flex; align-items: center; gap: 7px; min-width: 0;
  clip-path: var(--cut-xs); background: rgba(150, 160, 175, 0.22); padding: 5px 9px;
}
.insp-stat::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-xs);
  background: rgba(8, 13, 22, 0.72);
}
.insp-stat-ic { width: 18px; height: 18px; object-fit: contain; flex: 0 0 auto; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5)); }
.insp-stat-k { font-size: 8.5px; font-weight: 800; letter-spacing: 0.14em; color: var(--steel); flex: 0 0 auto; }
.insp-stat-v {
  margin-left: auto; min-width: 0; font-size: 14px; font-weight: 800; color: #eaf3ff;
  font-variant-numeric: tabular-nums; text-transform: uppercase; letter-spacing: 0.02em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Nome + tipo (tipo colorido pela natureza da carta). */
#insp-head { display: flex; flex-direction: column; gap: 1px; }
#insp-name { font-weight: 800; color: var(--accent-bright); font-size: 15px; line-height: 1.22; }
#insp-type { font-size: 10.5px; font-weight: 800; letter-spacing: 0.05em; text-transform: uppercase; color: var(--steel); }
#insp-head.kind-monster #insp-type { color: #ffd9a8; }
#insp-head.kind-spell #insp-type { color: #a8f0d8; }
#insp-head.kind-trap #insp-type { color: #f3c2e4; }

/* Abas quando a carta tem mais de um efeito (segmentos ●) */
#insp-tabs { display: flex; gap: 4px; }
#insp-tabs button {
  position: relative; flex: 1; font-size: 10px; font-weight: 800; padding: 4px 8px;
  color: var(--steel); background: rgba(110, 140, 180, 0.4);
  border: none; clip-path: var(--slant); transition: color 0.15s; cursor: pointer;
}
#insp-tabs button::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--slant);
  background: rgba(20, 27, 40, 0.95); transition: background 0.15s;
}
#insp-tabs button.on { color: var(--abyss); background: var(--accent); }
#insp-tabs button.on::before { background: var(--accent); }

/* Descrição do efeito: fundo mais ESCURO, scrollável (efeitos podem ser longos). */
#insp-text {
  flex: 1; min-height: 46px; overflow-y: auto; font-size: 11px; line-height: 1.6;
  color: #d5dde5; white-space: pre-wrap;
  background: var(--fill-inset); border: 1px solid var(--hair); border-radius: 7px; padding: 9px 11px;
}
#insp-text:empty { display: none; }
#log-panel {
  flex: 1; display: flex; flex-direction: column; gap: 8px; min-height: 0;
  padding: calc(12px + var(--avatar-cut)) 12px 12px; margin-top: calc(-1 * var(--avatar-cut));
  border-left: 1px solid var(--seam);
  border-right: 1px solid var(--seam);
  /* Oponente: topo recortado na diagonal ESPELHADA ("/") p/ casar com a barra dele. */
  clip-path: polygon(0 var(--avatar-cut), 100% 0, 100% 100%, 0 100%);
}
.side-label {
  display: flex; align-items: center; gap: 7px;
  font-size: 10.5px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.16em;
  color: var(--steel);
}
.side-label i { font-size: 15px; color: var(--accent-bright); }

/* ── REGISTRO DO DUELO: linha do tempo ─────────────────────────────────────
   Uma trilha vertical (fio + ponto por lance) com capítulos por TURNO, um
   marcador fino por fase e, em cada lance, quem fez · o que fez · a miniatura
   das cartas envolvidas. A miniatura é a peça-chave: "Destruído por efeito"
   não diz nada, "Mirror Force destruiu estes três monstros" diz tudo — e ela
   ainda serve de atalho (hover = prévia, clique = inspetor).
   As cores do ícone contam a FAMÍLIA do lance (invocação, ataque, destruição,
   magia…); o anel dele conta de QUEM foi (azul você, vermelho o inimigo). */
#duel-log {
  flex: 1; min-height: 60px; overflow-y: auto;
  background: var(--fill-inset); border: 1px solid var(--hair); border-radius: 4px;
  padding: 6px 6px 10px; color: #b9c7d6;
  display: flex; flex-direction: column;
  scrollbar-gutter: stable;
}
#duel-log:empty::before {
  content: attr(data-empty); display: block; margin: auto; padding: 20px 12px; text-align: center;
  font-size: 11.5px; font-weight: 600; line-height: 1.7; color: rgba(150, 175, 205, 0.4);
}

/* Capítulo: começa um turno. Quebra a trilha de propósito — é o respiro que
   deixa o registro navegável em vez de virar uma fita sem fim. */
.tl-turn {
  display: flex; align-items: center; gap: 8px; flex: none;
  margin: 12px 2px 7px; padding: 6px 10px; clip-path: var(--cut-xs);
  background: linear-gradient(90deg, rgba(120, 175, 255, 0.22), rgba(120, 175, 255, 0.03) 78%, transparent);
}
.tl-turn:first-child { margin-top: 2px; }
.tl-turn[data-side="opp"] {
  background: linear-gradient(90deg, rgba(255, 120, 105, 0.22), rgba(255, 120, 105, 0.03) 78%, transparent);
}
.tl-turn-n {
  font-size: 9.5px; font-weight: 900; letter-spacing: 0.14em; text-transform: uppercase; color: #dbe9fa;
}
.tl-turn-who {
  margin-left: auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 11px; font-weight: 800; color: var(--accent-bright);
}
.tl-turn[data-side="opp"] .tl-turn-who { color: #ffb0a2; }

/* Marcador de fase: fino, sem peso — está ali para situar, não para ser lido. */
.tl-phase {
  position: relative; flex: none;
  display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 0 6px; align-items: center;
  padding: 3px 8px 3px 4px;
}
.tl-phase span {
  grid-column: 2;
  font-size: 9px; font-weight: 900; letter-spacing: 0.14em; text-transform: uppercase;
  color: rgba(159, 180, 200, 0.5);
}

/* Lance. Grade [trilha/ícone · corpo · selo] — o selo (delta de LP, nº do elo)
   fica ancorado à direita e não empurra o texto. */
.tl-row {
  position: relative; flex: none;
  display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; gap: 0 6px;
  align-items: start; padding: 4px 8px 4px 4px;
  transition: background 0.12s;
}
.tl-row:hover { background: rgba(255, 255, 255, 0.035); }

/* O fio da trilha: um pedaço por linha, colados formam a vertical contínua. */
.tl-row::before, .tl-phase::before {
  content: ''; position: absolute; left: 15px; top: 0; bottom: 0; width: 1px;
  background: rgba(140, 165, 200, 0.20);
}
/* Traço curto ligando a fase à trilha. */
.tl-phase::after {
  content: ''; position: absolute; left: 12px; top: 50%; width: 8px; height: 1px;
  background: rgba(140, 165, 200, 0.3);
}

.tl-ico {
  --ring: rgba(140, 165, 200, 0.16);
  position: relative; z-index: 1; justify-self: center; margin-top: 1px;
  width: 19px; height: 19px; display: grid; place-items: center; border-radius: 50%;
  font-size: 12px; line-height: 1; color: var(--steel);
  background: #0a0f18;                 /* tapa o fio da trilha atrás do ponto */
  box-shadow: 0 0 0 1px var(--ring);
}
/* De QUEM foi o lance: o anel do ponto (azul você, vermelho o inimigo). */
.tl-row[data-side="me"] .tl-ico { --ring: rgba(110, 170, 255, 0.40); }
.tl-row[data-side="opp"] .tl-ico { --ring: rgba(255, 120, 105, 0.40); }
/* FAMÍLIA do lance: a cor do ícone. */
.tl-row.t-summon  .tl-ico { color: #93e3b3; }
.tl-row.t-attack  .tl-ico { color: #ffb689; }
.tl-row.t-destroy .tl-ico { color: #ff8f7d; }
.tl-row.t-spell   .tl-ico { color: #8ecdff; }
.tl-row.t-draw    .tl-ico { color: #c4b2ff; }
.tl-row.t-grave   .tl-ico { color: #9aa8bc; }
.tl-row.t-banish  .tl-ico { color: #d9a6ff; }
.tl-row.t-life    .tl-ico { color: #ffd28a; }
.tl-row.t-system  .tl-ico { color: var(--gold); }

.tl-body { grid-column: 2; min-width: 0; }
.tl-text { font-size: 11.5px; line-height: 1.45; color: #c6d3e1; overflow-wrap: anywhere; }
.tl-row.t-system .tl-text { color: #d9caa4; }
.tl-cards { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-top: 5px; }
.tl-mini {
  position: relative; display: block; flex: none; width: 27px; aspect-ratio: 59 / 86;
  border-radius: 3px; overflow: hidden;
  box-shadow: 0 0 0 1px rgba(150, 180, 215, 0.22), 0 3px 8px -3px rgba(0, 0, 0, 0.8);
  transition: transform 0.14s ease-out, box-shadow 0.14s;
}
.tl-mini img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tl-mini:hover {
  transform: scale(1.16) translateY(-1px); z-index: 2;
  box-shadow: 0 0 0 1px rgba(142, 199, 255, 0.75), 0 7px 16px -4px rgba(0, 0, 0, 0.9);
}
.tl-more { font-size: 10px; font-weight: 800; color: var(--steel); padding-left: 1px; }

.tl-badge {
  grid-column: 3; align-self: start; margin-top: 2px; white-space: nowrap;
  font-size: 10px; font-weight: 900; padding: 2px 6px; clip-path: var(--cut-xs);
  font-variant-numeric: tabular-nums;
}
.tl-badge.b-up { color: #bdf5d4; background: rgba(94, 255, 156, 0.16); }
.tl-badge.b-down { color: #ffc9c0; background: rgba(255, 92, 73, 0.22); }
.tl-badge.b-flat { color: var(--steel); background: rgba(150, 175, 210, 0.14); }

/* Entrada suave só do que ACABOU de chegar (o registro é acrescido, nunca
   repintado — por isso as linhas antigas não reanimam a cada lance). */
.tl-row, .tl-turn, .tl-phase { animation: tl-in 0.26s ease-out; }
@keyframes tl-in { from { opacity: 0; transform: translateY(6px); } }
@media (prefers-reduced-motion: reduce) {
  .tl-row, .tl-turn, .tl-phase { animation: none; }
}
/* (scrollbar: o desenho global no topo do arquivo cobre o log e o inspetor) */
#btn-surrender {
  position: relative; border: none; clip-path: var(--cut-sm);
  background: rgba(153, 27, 27, 0.65);
  color: #fca5a5; font-size: 12.5px; font-weight: 700; padding: 9px;
}
#btn-surrender::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm);
  background-color: rgba(40, 7, 7, 0.9); transition: background 0.15s;
}
#btn-surrender:hover::before {
  background-image: linear-gradient(rgba(180, 40, 40, 0.35), rgba(180, 40, 40, 0.35));
}

/* ── Coluna direita: duelistas (oponente em cima, jogador embaixo) ─────── */

#duel-right {
  position: relative;
  width: clamp(224px, calc((100vw - 1120px) / 2), 336px); flex-shrink: 0;
  display: flex; flex-direction: column; min-height: 0;
  border: none; clip-path: var(--cut-md); overflow: hidden;
  background: var(--edge);
  filter: drop-shadow(0 18px 40px rgba(0, 0, 0, 0.55));
}
#duel-right::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-md);
  background: var(--fill-panel); pointer-events: none;
}
/* Área do AVATAR: base cortada na DIAGONAL ("\") — as partículas/fundo terminam
   nesse corte. A barra de vida (.lp-zone, logo abaixo) encaixa a inclinação do
   topo dela nessa MESMA linha (via --avatar-cut). Mantém fundo tingido + aura +
   bordas laterais. Padding-bottom folgado p/ o nome caber ACIMA do corte. */
.duelist {
  flex: 0 0 auto; position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  gap: 5px; padding: 8px 12px calc(var(--avatar-cut) + 6px);
  border-left: 1px solid var(--seam);
  border-right: 1px solid var(--seam);
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 calc(100% - var(--avatar-cut)));
}
/* Linha-costura NA diagonal da base do avatar: define o corte e casa com o topo
   da barra logo abaixo (mesma inclinação, --avatar-cut). O clip do próprio
   .duelist deixa aparecer só o ~1px em cima da linha. */
.duelist::after {
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: var(--seam);
  clip-path: polygon(
    0 calc(100% - var(--avatar-cut) - 1.2px),
    100% calc(100% - 1.2px),
    100% 100%,
    0 calc(100% - var(--avatar-cut))
  );
}
/* Oponente: avatar espelhado ("/", corte alto na DIREITA) + linha-costura idem. */
.duelist.opp {
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--avatar-cut)), 0 100%);
}
.duelist.opp::after {
  clip-path: polygon(
    0 calc(100% - 1.2px),
    100% calc(100% - var(--avatar-cut) - 1.2px),
    100% calc(100% - var(--avatar-cut)),
    0 100%
  );
}
/* Nome + #action: sentam ACIMA da diagonal, no lado INICIAL/alto da barra (esq no
   jogador), INCLINADOS acompanhando o caimento da LP bar (--lp-rot herdado do
   painel). #action pequeno em cima, nome (CAPS) embaixo. */
.lp-names {
  position: absolute; z-index: 1; pointer-events: none;
  display: flex; flex-direction: column; gap: 0;
  left: 15px; bottom: calc(var(--avatar-cut) + 7px);
  align-items: flex-start;
  transform: rotate(var(--lp-rot, 0deg)); transform-origin: left bottom;
}
/* Oponente espelhado: o lado alto é a DIREITA. */
.duelist.opp .lp-names {
  left: auto; right: 15px;
  align-items: flex-end;
  transform-origin: right bottom;
}
/* Área do duelista: PRETO translúcido, o mesmo dos painéis — sem tingimento
   por lado. Você azul / inimigo vermelho competia com a nebulosa e com as
   cores das cartas, e a informação que ele dava (de quem é este lado) já vem
   do nome, da barra de vida e do lado da tela em que a placa está. O vermelho
   volta, e aí sim significando algo, quando o duelista TOMA DANO. */
.duelist.me, .duelist.opp {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.045), transparent 70%),
    rgba(6, 9, 15, 0.72);
}
/* Jogador (coluna esquerda) espelhado: os dois se encaram através do board.
   `scale` individual compõe com o transform do frame-pop sem conflito. */
#plate-me .avatar-slot video { scale: -1 1; }
/* Aura SEMPRE ligada e NEUTRA nos dois lados (a aura é o radial do ::before
   do slot, que desvanece antes das bordas). */
.duelist.me, .duelist.opp { box-shadow: inset 0 0 46px -16px rgba(220, 232, 248, 0.16); }
.duelist.me .avatar-slot::before,
.duelist.opp .avatar-slot::before { --aura: rgba(220, 232, 248, 0.1); }

/* Carta SELECIONADA (última clicada): borda branca para não se perder. */
/* ── Contorno de ESTADO na carta do board ──────────────────────────────────
   A MESMA peça da mão: um retângulo de 2px colado na carta, cantos retos, com
   um fio de brilho e mais nada. Antes cada estado tingia a borda da arte e
   somava um halo de 12–22px — três ou quatro cartas acesas ao mesmo tempo e o
   board virava uma sopa de luz, sem dizer qual estado era qual.
   Uma regra só desenha o contorno; cada estado só escolhe a COR (`--edge-on`).
   A ordem abaixo é a de prioridade: quem vem depois ganha quando dois estados
   caem na mesma carta. */
.bcard.pickable     { --edge-on: rgba(142, 199, 255, 0.95); }
.bcard.activatable  { --edge-on: rgba(255, 215, 94, 0.95); }
.bcard.selected     { --edge-on: rgba(255, 255, 255, 0.95); }
.bcard.attacker-sel { --edge-on: rgba(142, 199, 255, 0.95); }
.bcard.attacking,
.bcard.targetable,
.bcard.battle-target { --edge-on: rgba(255, 92, 73, 0.95); }
.bcard.pick-sel     { --edge-on: #37d17f; }
.bcard.pickable::after, .bcard.activatable::after, .bcard.selected::after,
.bcard.attacker-sel::after, .bcard.attacking::after,
.bcard.targetable::after, .bcard.battle-target::after, .bcard.pick-sel::after {
  content: ''; position: absolute; inset: -1px; border-radius: 0; z-index: 6;
  pointer-events: none;
  border: 2px solid var(--edge-on, transparent);
  box-shadow: 0 0 3px var(--edge-on, transparent);
}
/* Só o ALVO de ataque pulsa: ali o contorno não está informando, está
   convidando o clique. */
.bcard.targetable::after, .bcard.battle-target::after { animation: target-pulse 0.9s infinite; }
.hcard.selected img {
  border: 2px solid #fff;
  box-shadow: 0 0 14px rgba(255, 255, 255, 0.5), 0 8px 22px -6px rgba(0, 0, 0, 0.85);
}

/* ── Seleção de alvo DIRETO no board (pickers de cartas do campo) ────────
   Candidatas acendem em azul, selecionadas ficam verdes, o resto apaga. */
/* Selecionada (alvo de efeito / sacrifício): borda verde NÍTIDA (como a da mão)
   + uma setinha que sobe e desce apontando pra carta. */
.bcard.pick-sel::before {
  content: ''; position: absolute; left: 50%; top: -20px; width: 18px; height: 18px; z-index: 7;
  transform: translateX(-50%); pointer-events: none;
  background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path d='M5 8 L12 15 L19 8' fill='none' stroke='%2337d17f' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.75));
  animation: pick-bob 0.9s ease-in-out infinite;
}
.bcard.def.pick-sel::before { display: none; } /* carta em defesa gira 90° — sem a seta */
@keyframes pick-bob { 0%, 100% { top: -20px; } 50% { top: -13px; } }
.bcard.pick-dim { opacity: 0.4; pointer-events: none; }

/* Barra flutuante do picker de board: título + confirmar/cancelar. */
#pick-bar {
  position: absolute; left: 50%; bottom: 8px; transform: translateX(-50%); z-index: 14;
  display: flex; align-items: center; gap: 10px;
  background: rgba(120, 180, 255, 0.5); clip-path: var(--cut-sm);
  padding: 1px; /* anel */
}
#pick-bar .pick-inner {
  display: flex; align-items: center; gap: 10px;
  background: rgba(8, 13, 22, 0.96); clip-path: var(--cut-sm); padding: 8px 14px;
}
#pick-info { font-size: 12.5px; font-weight: 700; color: #dbe9fa; white-space: nowrap; }
#pick-bar button {
  border: none; clip-path: var(--cut-sm); font-size: 11.5px; font-weight: 800;
  padding: 7px 14px; white-space: nowrap;
}
#pick-confirm { color: #06131c; background: linear-gradient(180deg, #57d68d, #23a45c); }
#pick-confirm:hover { filter: brightness(1.1); }
#pick-confirm:disabled { filter: grayscale(0.8) brightness(0.75); opacity: 0.6; }
#pick-cancel { color: #cbd5e1; background: rgba(255, 255, 255, 0.1); }
#pick-cancel:hover { background: rgba(255, 255, 255, 0.18); }

/* Retrato do duelista: só o PNG, sem moldura — os frames trocam com as ações
   do duelo (idle/draw_01/draw_02/damage/set). */
.avatar-slot {
  /* Referência de posição/tamanho do avatar. O modelo Live2D é renderizado no
     overlay #avatar-stage e recortado sobre ESTE rect (com fade-out na base
     feito pela máscara do Pixi). Aqui só vive a aura (::before). */
  width: 100%; height: clamp(168px, 24vh, 226px);
  position: relative; overflow: hidden;
}
/* Fundo animado da placa (canvas 2D): cobre a placa INTEIRA — borda a borda,
   incluindo o padding — ATRÁS do conteúdo. O conteúdo (avatar-slot, nome,
   action) fica por cima (z-index 1); o personagem Live2D vem no overlay Pixi. */
/* width/height 100% OBRIGATÓRIOS: <canvas> é replaced element — só com inset:0 ele
   usa o tamanho intrínseco (buffer), então em zoom ≠ 100% (DPR ≠ 1) o display não
   batia com a placa e o fundo ficava CORTADO. Forçando 100% o display sempre
   preenche a placa (o buffer segue o DPR à parte, no JS). */
.avatar-bg { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }
/* Conteúdo acima do canvas de fundo (z-0). Exclui .lp-names — ele é posicionado
   ABSOLUTO (inclinado no lado da barra) e traz o próprio z-index. */
.duelist > :not(.avatar-bg):not(.lp-names) { position: relative; z-index: 1; }
/* Avatar em VÍDEO (corpo inteiro, VP9 com alpha): o elemento é MAIOR que o
   slot e ancorado no topo — zoom em cabeça+tronco; o resto do corpo fica
   fora do recorte (overflow hidden). */
.avatar-slot video {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%;
  /* cover enche a LARGURA (lados NUNCA cortam) e corta só embaixo (pernas) →
     foco no tronco pra cima. Menos zoom = área do avatar mais alta (.avatar-slot). */
  object-fit: cover; object-position: top center;
  filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.55));
  pointer-events: none;
}
/* pulso curto quando o frame troca (reaplicado via classe pelo JS) */
.avatar-slot video.frame-pop { animation: frame-pop 0.28s ease-out; }
@keyframes frame-pop {
  0% { transform: scale(0.96); }
  55% { transform: scale(1.03); }
  100% { transform: scale(1); }
}
/* Avatar em CANVAS Live2D: UM canvas/contexto WebGL (overlay full-viewport,
   #avatar-stage) renderiza os DOIS modelos — recursos de GPU não cruzam
   contextos, então dois canvases separados quebram. Cada modelo é posicionado
   + recortado (máscara Pixi) sobre o rect do seu .avatar-slot. Fica abaixo do
   #fx-layer (z 20) e dos modais, e acima do conteúdo dos painéis. */
#avatar-stage { position: fixed; inset: 0; z-index: 15; pointer-events: none; }
/* Fallback estático se WebGL/modelo falhar: PNG no próprio slot. */
.avatar-slot.avatar-fallback { background: center top / cover no-repeat url("https://yugiohonline.b-cdn.net/avatars/sprites/idle.png"); }
/* Texto de debug/mapeamento da ação atual do avatar (#action: idle...). */
.plate-action {
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 9px; letter-spacing: 0.06em; color: var(--steel);
  opacity: 0.55; margin: 0; user-select: none;
}
.plate-name {
  max-width: 168px; margin: 0; font-size: 15px; font-weight: 800;
  letter-spacing: 0.06em; color: #fff; text-transform: uppercase;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  text-shadow: 0 2px 9px rgba(0, 0, 0, 0.8);
}
/* ── Faixa de VIDA: encaixada na diagonal do avatar, de ponta a ponta ───────
   Puxada PARA CIMA (margin-top = -corte) p/ sobrepor o triângulo recortado do
   avatar; a barra é um PARALELOGRAMO (clip-path) cujo TOPO desce na MESMA linha
   do corte (--avatar-cut). Número/rótulo ficam FORA do recorte (soltos em
   .lp-area) p/ nunca serem cortados. Borda inferior reta separa da carta. */
.lp-zone {
  position: relative;
  margin-top: calc(-1 * var(--avatar-cut));
  /* Bordas laterais continuam a moldura do avatar (continuidade da borda). */
  border-left: 1px solid var(--seam);
  border-right: 1px solid var(--seam);
}
/* "Borda" INFERIOR da barra, inclinada no MESMO corte — separa da área da carta
   (que também é recortada em diagonal p/ casar). */
.lp-zone::after {
  content: ''; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background: var(--seam);
  clip-path: polygon(
    0 calc(100% - var(--avatar-cut) - 1.2px),
    100% calc(100% - 1.2px),
    100% 100%,
    0 calc(100% - var(--avatar-cut))
  );
}
/* Oponente: separador inferior espelhado ("/"). */
.lp-zone.opp::after {
  clip-path: polygon(
    0 calc(100% - 1.2px),
    100% calc(100% - var(--avatar-cut) - 1.2px),
    100% calc(100% - var(--avatar-cut)),
    0 100%
  );
}
.lp-area { position: relative; width: 100%; }
/* faixa NEUTRA (sem tom azul/vermelho) — quem dá o visual é a barra preta 50% */
/* "LP" + número JUNTOS dentro da barra (LP antes do número). */
/* Número GRANDE (quase a altura da barra), SEM sombra, alinhado ao INÍCIO
   (lado externo) da barra, na cor translúcida que o "LP" tinha. */
.lp-num {
  position: absolute; transform: translateY(-50%) rotate(var(--lp-rot, 0deg)); z-index: 2;
  font-size: 32px; line-height: 1; font-weight: 900;
  color: #fff; font-variant-numeric: tabular-nums;
  pointer-events: none; white-space: nowrap;
}
/* Número no lado ALTO da diagonal (jogador = esq, oponente = dir), inclinado
   junto com a barra (--lp-rot herdado do PAINEL, setado por JS em updateAvatarCut
   — assim o número E o nome inclinam com o mesmo valor). Só branco, sem sombra. */
.lp-area.me  .lp-num { left: 12px;  top: calc((100% - var(--avatar-cut)) / 2 + 3px); }
.lp-area.opp .lp-num { right: 12px; top: calc((100% - var(--avatar-cut)) / 2 + 3px); }
/* "LIFE POINTS": aparece SÓ na animação de início (varre a barra via JS), no
   tamanho da fonte do número. Sem hover. */
.lp-hint {
  /* SEM o +3px do número: como a varredura acompanha a diagonal via yAt (JS),
     a base precisa ficar no centro EXATO da faixa (Vh/2). */
  position: absolute; left: 12px; top: calc((100% - var(--avatar-cut)) / 2);
  transform: translateY(-50%) rotate(var(--lp-rot, 0deg)); z-index: 3;
  font-size: 32px; line-height: 1; font-weight: 900; letter-spacing: 0.06em;
  text-transform: uppercase; color: #fff;
  white-space: nowrap; pointer-events: none; opacity: 0;
}
/* O letreiro (hint) fica SEMPRE ancorado à esquerda (left:12) nos dois lados: a
   varredura é feita por translateX a partir da esquerda, então ancorar o opp à
   direita quebrava o cálculo (saía torto/baixo). Só o NÚMERO estático fica à
   direita no opp; a direção espelhada da varredura já é tratada no JS. */
/* Barra: RETA, preta com 50% de opacidade e borda um pouco maior. UM ÚNICO corte
   no canto superior do lado do board (você = dir, oponente = esq). A vida (fill)
   colorida fica por cima; o trecho vazio mostra o preto 50%. */
.lp-bar {
  position: relative; width: 100%; height: calc(44px + var(--avatar-cut)); overflow: hidden;
  /* Trilho: o MESMO `--fill-inset` do registro e do texto de efeito — é a
     "caixa dentro do painel" da casa. Antes era um preto próprio (0.92) que
     não conversava com nada; agora o trecho vazio da barra tem a profundidade
     das outras caixas e deixa passar um resto do painel. */
  background: var(--fill-inset);
  /* Paralelogramo: topo e base descem da esquerda p/ a direita na MESMA
     inclinação do corte do avatar (--avatar-cut) → encaixa de ponta a ponta. */
  clip-path: polygon(0 0, 100% var(--avatar-cut), 100% 100%, 0 calc(100% - var(--avatar-cut)));
}
/* Oponente ESPELHADO ("/"): topo/base sobem da esquerda p/ a direita. */
.lp-area.opp .lp-bar {
  clip-path: polygon(0 var(--avatar-cut), 100% 0, 100% calc(100% - var(--avatar-cut)), 0 100%);
}
.lp-area.opp .lp-bar { display: flex; justify-content: flex-end; /* esvazia pelo lado do board */ }
.lp-fill {
  position: relative; height: 100%; width: 0;
  background: linear-gradient(90deg, #2ecf6e, #7ff5a1);
  transition: width 0.7s cubic-bezier(0.3, 0.9, 0.3, 1), background 0.4s, filter 0.45s ease;
}
/* Pulso de cor durante a contagem (início/dano): fica mais forte e volta suave. */
.lp-fill.lp-pulse { filter: brightness(1.4) saturate(1.35); }
/* Oponente é espelhado: inverte o degradê p/ o "cheio" ficar no lado de fora, igual ao seu. */
.lp-area.opp .lp-fill { transform: scaleX(-1); }
.lp-fill.green { background: linear-gradient(90deg, #2ecf6e, #7ff5a1); }
.lp-fill.blue { background: linear-gradient(90deg, #2f8fd8, #7dd3fc); }
.lp-fill.yellow { background: linear-gradient(90deg, #e0a63c, #ffd75e); }
.lp-fill.red { background: linear-gradient(90deg, #d8452f, #ff8a6b); }
@keyframes wait-pulse {
  0%, 100% { opacity: 0.65; }
  50% { opacity: 1; box-shadow: 0 0 14px -2px rgba(232, 192, 100, 0.45); }
}

/* ── Área central ──────────────────────────────────────────────────────── */

#board-wrap { position: relative; flex: 1; display: flex; flex-direction: column; min-width: 0; }

/* Board 2D flat: limpo, azul-escuro, sem perspectiva nem neon pesado. */
#board3d { flex: 1; display: flex; align-items: center; justify-content: center; min-height: 0; }
/* Board TODO QUADRADO: borda reta simples, sem chanfro.
   A margem esquerda é o ESPELHO do trilho de fases, que fica colado do outro
   lado: sem ela o par [board | trilho] é que ficaria centrado no #board3d, e o
   board sairia do eixo das mãos por meia largura de trilho. */
#field {
  position: relative; overflow: hidden;
  /* nunca encolher abaixo do conteúdo (overflow:hidden zera o min-size do flex) */
  min-width: max-content;
  display: flex; flex-direction: column; gap: 6px;
  padding: 14px var(--field-pad-x); margin-left: var(--rail-w);
  /* Board QUADRADO: borda reta simples, sem chanfro. Com o retângulo de volta
     a `border` nativa serve (era o clip-path que a decepava nas diagonais). */
  border: 1px solid var(--edge); border-radius: 0;
  /* Sem os radiais de glow topo/base: o brilho por turno agora vem do canvas
     #board-bg (senão dobrava embaixo e brigava de cor no turno do inimigo).
     TAMPO A 25%: o board é praticamente uma vidraça sobre a nebulosa. A 86%
     (como estava) o céu simplesmente não aparecia — e o fundo animado existe
     para ser visto. Os mesmos tons do `--fill-panel` das laterais, só que
     diluídos, para o board e os painéis serem a mesma matéria. */
  background: linear-gradient(168deg, rgba(20, 25, 33, 0.25), rgba(10, 13, 19, 0.25));
}
/* Fundo de partículas do board: ATRÁS dos slots (o conteúdo do #field é
   z-index 1), recortado pelo overflow:hidden do #field. */
/* width/height 100% pelo mesmo motivo do .avatar-bg (canvas replaced + zoom/DPR). */
#board-bg { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }
.field-side, #field-divider { position: relative; z-index: 1; }
/* (Sem cantoneiras nos quatro cantos: a borda reta do #field já fecha o
   desenho, e os "L" sobrepostos só somavam traço.) */
#board-wrap.shake #field { animation: shake 0.45s; }
@keyframes shake {
  0%, 100% { transform: translate(0, 0); }
  20% { transform: translate(-8px, 2px); }
  40% { transform: translate(7px, -2px); }
  60% { transform: translate(-5px, 1px); }
  80% { transform: translate(4px, -1px); }
}

.field-side {
  display: grid; grid-template-columns: repeat(7, var(--zone-w)); grid-auto-rows: var(--zone-h);
  gap: 6px;
}
/* (O meu lado NÃO repinta a borda das zonas no meu turno: o slot tem a mesma
   cor dos dois lados do board. Quem conta de quem é o turno é o fluxo das
   partículas do #board-bg e o console de fases.) */

/* Pilhas (deck/cemitério/extra/field) só ganham um respiro lateral do board
   principal — mesma visibilidade das outras zonas. */
.zone.edge-l { transform: translateX(-24px); }
.zone.edge-r { transform: translateX(24px); }

/* Divisória do board: UMA linha, de borda a borda. Era uma faixa de 36px com o
   console de fases no meio — o assunto mais alto do tabuleiro morava bem no
   ponto onde ele devia estar mais quieto, e comia altura que agora vira slot
   maior. As fases mudaram-se para o trilho da direita; aqui sobrou o traço que
   separa os dois campos, mais as fichas de contagem ancoradas à esquerda.
   A altura existe para as fichas (elas montam a cavalo na linha); a LINHA em si
   é o ::before, esticado até o padding do #field para encostar nas duas bordas. */
#field-divider {
  position: relative; height: 16px; flex: none;
  display: flex; align-items: center; gap: 13px;
  /* As margens negativas desfazem o padding do #field: a divisória é a única
     peça que atravessa o campo de borda a borda. */
  margin-inline: calc(-1 * var(--field-pad-x));
}
/* Os dois traços. Mesmo fio das casas e da moldura (`--edge`) — a divisória
   não é um elemento novo em cima do board, é o board continuando. */
#field-divider::before, #field-divider::after {
  content: ''; flex: 1; height: 1px; background: var(--edge);
}
/* O "VS" mora na abertura entre os dois traços: a linha não fecha no meio. */
#field-vs {
  font-size: 9px; font-weight: 900; letter-spacing: 0.16em; line-height: 1;
  color: rgba(150, 175, 205, 0.34); user-select: none; flex: none;
}

/* ── Trilho de fases: vertical, colado por FORA da borda direita do board ───
   O tempo do duelo desce: DP, SP, MP1, o número do TURNO na altura da
   divisória, e então BP, MP2, EP. Sem borda à esquerda porque ali já está a
   borda do board — as duas seriam um fio dobrado.
   Ele é IRMÃO do #field dentro do #board3d, não um flutuante por cima: assim a
   largura dele entra na conta do layout e nunca invade a coluna lateral. Para
   o board continuar CENTRADO apesar do trilho, o #field ganha uma margem
   esquerda do mesmo tamanho (ver `#field`). */
#phase-rail {
  position: relative; align-self: center; flex: none; z-index: 2;
  width: var(--rail-w); overflow: hidden;
  display: flex; flex-direction: column;
  border: 1px solid var(--edge); border-left: none; border-radius: 0;
  background: linear-gradient(168deg, rgba(20, 25, 33, 0.72), rgba(10, 13, 19, 0.72));
}
#phase-rail span {
  position: relative; z-index: 1;
  height: var(--seg-h); display: flex; align-items: center; justify-content: center;
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.07em; color: #566c86;
  transition: color 0.25s, background 0.2s; white-space: nowrap; user-select: none;
}
#phase-rail span + span { border-top: 1px solid var(--hair); }

/* ── O bloco do TURNO, no meio do trilho ───────────────────────────────────
   Não é uma fase: é o relógio da partida, e por isso se anuncia diferente —
   poço mais escuro, a palavra deitada na vertical e o número VAZADO, só
   contorno. Ele fica na altura exata da divisória, então a metade de cima do
   trilho é a metade de cima do tabuleiro. */
/* `#phase-rail span` tem id+tipo e ganharia de um `#turn-chip` sozinho — daí
   os dois ids no seletor. */
#phase-rail #turn-chip {
  flex-direction: row; align-items: center; justify-content: center; gap: 4px;
  height: auto; padding: 9px 0;
  background: rgba(4, 7, 13, 0.55);
  box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.5), inset 0 -1px 0 rgba(255, 255, 255, 0.04);
}
#turn-word {
  /* `vertical-rl` deita a palavra inteira no eixo do trilho; `upright` a
     empilharia letra a letra e comeria o dobro da altura. */
  writing-mode: vertical-rl; text-orientation: mixed;
  font-size: 8px; font-weight: 800; letter-spacing: 0.2em;
  color: rgba(146, 176, 212, 0.5); text-transform: uppercase;
}
#turn-num {
  font-style: normal; font-size: 23px; font-weight: 900; line-height: 1;
  font-variant-numeric: tabular-nums;
  /* Contorno sem miolo. A cor plena fica declarada ANTES como piso: se o
     navegador não conhece `text-stroke`, o número aparece sólido em vez de
     sumir num `color: transparent` sem traço nenhum. */
  color: rgba(198, 220, 248, 0.9);
}
@supports (-webkit-text-stroke: 1px red) {
  #turn-num {
    color: transparent;
    -webkit-text-stroke: 1.1px rgba(198, 220, 248, 0.88);
  }
}
/* Virada de turno: o número INCHA e o contorno acende, depois assenta. */
#turn-num.bump { animation: turn-bump 0.66s cubic-bezier(0.25, 1.4, 0.4, 1); }
@keyframes turn-bump {
  0% { transform: scale(1.75); opacity: 0; filter: drop-shadow(0 0 10px rgba(142, 199, 255, 0.9)); }
  35% { opacity: 1; filter: drop-shadow(0 0 9px rgba(142, 199, 255, 0.75)); }
  100% { transform: scale(1); opacity: 1; filter: none; }
}
@media (prefers-reduced-motion: reduce) {
  #turn-num.bump { animation: none; }
}

/* ── Fase ATIVA e fase alcançável ──────────────────────────────────────────
   As duas falam a mesma língua: uma barra no flanco INTERNO do trilho, do lado
   em que o board encosta. A ativa é grossa e acesa com o degrau inteiro banhado
   de luz que se dissolve para fora; a alcançável é um toco fino que pulsa. Era
   um retângulo azul chapado com o texto preto por cima — legível, mas o mesmo
   peso visual de um botão, no elemento que só precisa dizer "está aqui". */
#phase-rail span[data-ph].on {
  color: #eaf4ff; text-shadow: 0 0 10px rgba(120, 190, 255, 0.7);
}
#phase-rail span[data-ph].can {
  color: var(--accent-bright); cursor: pointer;
  animation: phase-invite 1.8s infinite;
}
#phase-rail span[data-ph].can:hover {
  background: rgba(120, 180, 255, 0.16);
  box-shadow: inset 3px 0 0 var(--accent-bright); animation: none;
}
@keyframes phase-invite {
  0%, 100% { box-shadow: inset 2px 0 0 rgba(120, 180, 255, 0.22); }
  50% { box-shadow: inset 2px 0 0 rgba(142, 199, 255, 0.85); }
}
/* O CURSOR é um bloco só, atrás dos rótulos, que DESLIZA de um degrau para o
   outro — a fase não pisca de lugar, ela anda até lá. Por isso ele é um
   elemento e não um `background` no segmento aceso: fundo não tem como
   percorrer o caminho entre dois elementos.
   Todos os degraus têm a mesma altura, então basta transladar. */
#phase-cursor {
  position: absolute; left: 0; right: 0; top: 0; z-index: 0;
  height: var(--seg-h);
  background: linear-gradient(270deg,
    rgba(90, 160, 240, 0.02) 0%,
    rgba(96, 170, 255, 0.20) 55%,
    rgba(120, 190, 255, 0.42) 100%);
  box-shadow:
    inset 3px 0 0 var(--accent-bright),
    inset 0 1px 0 rgba(142, 199, 255, 0.34),
    inset 0 -1px 0 rgba(142, 199, 255, 0.34);
  transform: translateY(var(--cursor-y, 0px));
  transition: transform 0.42s cubic-bezier(0.35, 0.9, 0.2, 1), opacity 0.25s;
}
/* Primeiro posicionamento (ou volta do replay): assume o lugar sem viajar. */
#phase-cursor.no-anim { transition: none; }
/* Fase que o trilho não lista (DAMAGE, PRE_DRAW…): o cursor se apaga no lugar
   em vez de escorregar para um degrau que não é o certo. */
#phase-cursor.off { opacity: 0; }

/* ── Contadores de turno: fichinhas na faixa central (§6.6) ────────────────
   Cada efeito de contagem multi-turno (Final Countdown, Swords of Revealing
   Light, Gold Sarcophagus...) vira uma ficha: carta + relógio + turnos que
   faltam. Ancoradas à ESQUERDA do divisor (absolutas, fora do fluxo → não
   empurram o console de fases centralizado). Pulsam quando a contagem muda. */
#timer-track {
  /* Ancorado em relação ao GRID, não à divisória: ela atravessa o padding do
     campo (margem negativa), então o zero dela fica antes da primeira casa. */
  position: absolute; left: calc(var(--field-pad-x) + 10px); top: 50%; transform: translateY(-50%);
  display: flex; align-items: center; gap: 6px; z-index: 3;
  pointer-events: none; /* só as fichas capturam clique */
}
#timer-track.hidden { display: none; }
.timer-chip {
  position: relative; overflow: hidden; pointer-events: auto;
  display: flex; align-items: center; gap: 5px; padding: 3px 9px 3px 3px;
  border-radius: 999px; border: 1px solid var(--tc-accent); cursor: pointer;
  background: linear-gradient(180deg, rgba(14, 22, 38, 0.96), rgba(7, 12, 22, 0.96));
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.45), inset 0 0 0 1px rgba(255, 255, 255, 0.04);
}
.timer-chip.mine { --tc-accent: rgba(96, 165, 255, 0.9);  --tc-glow: rgba(96, 165, 255, 0.55); }
.timer-chip.foe  { --tc-accent: rgba(240, 140, 70, 0.92); --tc-glow: rgba(240, 140, 70, 0.6); }
.timer-chip:hover { filter: brightness(1.15); }
.tc-art {
  width: 24px; height: 24px; border-radius: 50%; flex: none;
  background-size: 150%; background-position: 50% 26%; /* enquadra a arte da carta */
  box-shadow: inset 0 0 0 1px var(--tc-accent);
}
.tc-clock { display: flex; align-items: center; gap: 3px; color: var(--tc-accent); }
.tc-clock i { font-size: 15px; line-height: 1; }
.tc-clock b { font-size: 14px; font-weight: 900; color: #eaf2ff; min-width: 10px; text-align: center; }
/* Barra do progresso decorrido, no rodapé da ficha. */
.timer-chip::after {
  content: ''; position: absolute; left: 0; bottom: 0; height: 2px;
  width: calc(var(--passed, 0) * 100%); background: var(--tc-accent); opacity: 0.9;
}
/* Pulso ao surgir ou quando a contagem muda (o JS aplica .tick nesse render). */
.timer-chip.tick { animation: tc-tick 0.6s ease; }
@keyframes tc-tick {
  0% { transform: scale(1); box-shadow: 0 0 0 0 var(--tc-glow); }
  35% { transform: scale(1.2); box-shadow: 0 0 15px 3px var(--tc-glow); }
  100% { transform: scale(1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.45); }
}
/* Controles de turno: cluster vertical no canto inferior DIREITO do board,
   ao lado da mão (estilo Duel Links). Fora do divisor de propósito: em
   resoluções compactas não cabem console central + botões na mesma linha, e
   qualquer âncora no meio do campo acaba sobre uma pilha (GY/DECK). */
#turn-controls {
  position: absolute; right: 10px; bottom: 12px; z-index: 12;
  display: flex; flex-direction: column; align-items: flex-end; gap: 8px;
  pointer-events: none;
}
#turn-controls button { pointer-events: auto; }
/* Cantinho de utilidades: fileira de botões-ícone redondos no canto inferior
   ESQUERDO do board (oposto aos controles): música, auto-recusa, velocidade
   da CPU (só PVE) e idioma. */
#corner-tools {
  position: absolute; left: 10px; bottom: 12px; z-index: 12;
  display: flex; gap: 8px;
}
#corner-tools > button {
  width: 36px; height: 36px; display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(232, 192, 100, 0.45); border-radius: 99px;
  background: rgba(20, 16, 6, 0.82); color: #ffe9b8; font-size: 17px; cursor: pointer;
}
#corner-tools > button:hover { background: rgba(44, 36, 14, 0.92); }
#btn-music-mute.muted { color: #8a8f98; border-color: rgba(255, 255, 255, 0.16); }
/* Auto-recusa (AUTO_PASS): apagado = desligado; aceso (âmbar + pulso) = ativa. */
#btn-auto-pass { color: #8a8f98; border-color: rgba(255, 255, 255, 0.16); }
#btn-auto-pass.on {
  color: #ffe9b8; border-color: rgba(232, 192, 100, 0.65);
  background: rgba(44, 36, 14, 0.92); animation: wait-pulse 1.6s infinite;
}
/* Velocidade da CPU e idioma mostram texto curto (1×/PT) no mesmo círculo —
   fino e discreto, para casar com o peso visual dos ícones duotone.
   (O seletor precisa do container: `#corner-tools > button` tem especificidade
   maior e senão o font-size de 17px dos ícones vence.) */
#corner-tools > #btn-bot-speed, #corner-tools > #btn-lang {
  font-size: 11px; font-weight: 300; letter-spacing: 0.02em;
}
/* HUD mobile remonta o layout em grid — sem canto livre p/ os botões. */
@media (max-width: 600px) { #corner-tools { display: none; } }
/* Status do turno mora aqui também: "Aguardando oponente…" / "Sua vez de agir!" */
#turn-status {
  display: flex; align-items: center; gap: 6px;
  font-size: 10.5px; font-weight: 800; white-space: nowrap; color: #ffe9b8;
  background: rgba(20, 16, 6, 0.88); border: 1px solid rgba(232, 192, 100, 0.5);
  border-radius: 99px; padding: 5px 13px; animation: wait-pulse 1.6s infinite;
}
#turn-status .ph-duotone { font-size: 13px; }
#turn-status.action {
  color: #d8ffe8; border-color: rgba(110, 231, 183, 0.55); background: rgba(6, 20, 14, 0.88);
}
#btn-next-phase {
  position: relative; border: none; clip-path: var(--cut-sm);
  background: rgba(120, 180, 255, 0.55);
  color: var(--accent-bright); font-size: 10.5px; font-weight: 800; letter-spacing: 0.07em;
  text-transform: uppercase; padding: 8px 14px; white-space: nowrap;
}
#btn-next-phase::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm);
  background-color: rgba(9, 16, 28, 0.94); transition: background 0.15s;
}
#btn-next-phase:hover::before {
  background-image: linear-gradient(rgba(90, 160, 240, 0.3), rgba(90, 160, 240, 0.3));
}
/* Encerrar turno: o botão "gordinho" e definitivo, sempre no canto direito */
#btn-end-turn {
  border: none; clip-path: var(--cut-sm);
  background: linear-gradient(180deg, #7fc0ff, #2f7fd6);
  color: #06101c; font-size: 11.5px; font-weight: 900; letter-spacing: 0.07em;
  text-transform: uppercase; padding: 10px 20px;
  white-space: nowrap; transition: filter 0.15s, transform 0.1s;
}
#btn-end-turn:hover { filter: brightness(1.12); }
#btn-end-turn:active { transform: scale(0.96); }

/* Velocidade da CPU (só PVE): agora um dos botões-ícone do #corner-tools. */

/* Botão "Detalhes": só existe no CELULAR (no desktop o inspetor lateral já mostra
   a carta). O @media (max-width:600px) o exibe quando há carta selecionada. */
#btn-details { display: none; }

/* Zonas: QUADRADAS (sem raio) e translúcidas — a nebulosa aparece por baixo.
   Borda e preenchimento saem dos mesmos tokens dos painéis laterais (`--edge`
   / `--fill-panel`), para o board não ter paleta própria. */
.zone {
  position: relative; border: 1px solid var(--edge); border-radius: 0;
  background:
    linear-gradient(160deg, rgba(255, 255, 255, 0.025), transparent 60%),
    rgba(10, 13, 19, 0.30);
  display: flex; align-items: center; justify-content: center;
  transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;
}
.zone .zlabel {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 800; letter-spacing: 0.14em; color: rgba(150, 175, 205, 0.35);
  pointer-events: none; user-select: none;
}
/* Zona com MARCA (monstro, magia/armadilha, campo, cemitério, banidas): a
   máscara do glifo substitui o texto. `font-size: 0` some com o rótulo antigo
   sem precisar mexer no DOM de quem monta a zona. */
.zone[data-ic] .zlabel { font-size: 0; }
.zone[data-ic] .zlabel::before {
  content: ''; display: block; width: 44%; max-width: 32px; aspect-ratio: 1;
  background-color: currentColor;
  -webkit-mask: var(--zic) center / contain no-repeat;
  mask: var(--zic) center / contain no-repeat;
}
.zone[data-ic="hexagon"]       { --zic: var(--ic-hexagon); }
.zone[data-ic="octagon"]       { --zic: var(--ic-octagon); }
.zone[data-ic="spiral"]        { --zic: var(--ic-spiral); }
.zone[data-ic="ghost"]         { --zic: var(--ic-ghost); }
.zone[data-ic="prohibit"]      { --zic: var(--ic-prohibit); }
.zone[data-ic="circle"]        { --zic: var(--ic-circle); }
.zone[data-ic="circle-dashed"] { --zic: var(--ic-circle-dashed); }
.zone.pile { background: rgba(8, 11, 18, 0.42); }
.zone.clickable:hover { border-color: var(--accent); box-shadow: 0 0 16px -4px rgba(90, 160, 240, 0.5); }
/* O slot conta o que aconteceu nele: AZUL quando uma carta entra, VERMELHO
   quando a carta que estava ali queimou. A MARCA da zona (hexágono, octógono,
   fantasma…) acende junto e na mesma cor — na destruição o slot fica vazio, e
   aí é a marca que sobra para carregar o recado. */
/* `--glow-ms` vem do JS: o brilho tem de durar o que dura o efeito em cima do
   slot, senão apaga no meio da animação e parece que nunca aconteceu. */
.zone.slot-flash { animation: slot-flash var(--glow-ms, 0.8s) ease-out; }
@keyframes slot-flash {
  0% {
    border-color: #cfe6ff;
    box-shadow: 0 0 24px -1px rgba(150, 200, 255, 0.95), inset 0 0 18px rgba(150, 200, 255, 0.55);
  }
  /* platô: fica ACESO enquanto o efeito roda, e só então esfria */
  60% {
    border-color: rgba(170, 215, 255, 0.85);
    box-shadow: 0 0 18px -2px rgba(150, 200, 255, 0.7), inset 0 0 14px rgba(150, 200, 255, 0.4);
  }
  100% { border-color: var(--edge); box-shadow: none; }
}
.zone.slot-fail { animation: slot-fail var(--glow-ms, 0.8s) ease-out; }
@keyframes slot-fail {
  0% {
    border-color: #ffb3a2;
    box-shadow: 0 0 24px -1px rgba(255, 110, 90, 0.9), inset 0 0 18px rgba(255, 90, 70, 0.5);
  }
  /* platô até os cacos pousarem na pilha */
  70% {
    border-color: rgba(255, 140, 120, 0.85);
    box-shadow: 0 0 18px -2px rgba(255, 100, 80, 0.66), inset 0 0 14px rgba(255, 90, 70, 0.36);
  }
  100% { border-color: var(--edge); box-shadow: none; }
}
.zone.slot-flash .zlabel::before { animation: mark-flash var(--glow-ms, 0.8s) ease-out; }
.zone.slot-fail .zlabel::before { animation: mark-fail var(--glow-ms, 0.8s) ease-out; }
@keyframes mark-flash {
  0% { background-color: rgba(206, 232, 255, 0.98); filter: drop-shadow(0 0 9px rgba(140, 200, 255, 0.95)); }
  60% { background-color: rgba(190, 224, 255, 0.92); filter: drop-shadow(0 0 7px rgba(140, 200, 255, 0.75)); }
  100% { background-color: currentColor; filter: none; }
}
@keyframes mark-fail {
  0% { background-color: rgba(255, 176, 158, 0.98); filter: drop-shadow(0 0 9px rgba(255, 90, 70, 0.95)); }
  70% { background-color: rgba(255, 160, 140, 0.92); filter: drop-shadow(0 0 7px rgba(255, 90, 70, 0.75)); }
  100% { background-color: currentColor; filter: none; }
}

/* Zona elegível para posicionar a carta (invocar/setar/drop) */
.zone.placeable {
  border-color: var(--accent-bright); background: rgba(90, 160, 240, 0.12);
  animation: zone-invite 1s infinite;
}
.zone.placeable:hover, .zone.placeable.drag-over {
  background: rgba(120, 190, 255, 0.26);
  box-shadow: 0 0 24px -2px rgba(140, 190, 255, 0.7);
}
.zone.placeable .zlabel { color: rgba(140, 190, 255, 0.8); }
/* o clique deve cair na zona, mesmo sobre um monstro que será tributado */
.zone.placeable .bcard { pointer-events: none; }
@keyframes zone-invite {
  0%, 100% { box-shadow: 0 0 0 0 rgba(140, 190, 255, 0.0); }
  50% { box-shadow: 0 0 18px -2px rgba(140, 190, 255, 0.55); }
}
/* Contagem das pilhas: número branco bold no centro da carta, sobre um véu
   preto de ~40% cobrindo o topo da pilha. */
.zone .count-badge {
  position: absolute; inset: 4px; z-index: 3; pointer-events: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: 0; font-size: 17px; font-weight: 800; color: #fff;
  background: rgba(0, 0, 0, 0.4); text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
  font-variant-numeric: tabular-nums;
}
/* ── CEMITÉRIO + BANIDAS: uma casa só ──────────────────────────────────────
   As duas pilhas de ARQUIVO dividem o mesmo slot: ninguém joga a partir dele
   (o clique só abre a lista), as banidas passam duelos inteiros vazias, e duas
   casas separadas cobravam largura de tabuleiro o ano inteiro para servir uma
   consulta ocasional. A distinção vive onde ela é usada: no modal com abas.
   O tom é neutro com um fio de brasa — a casa não pode disputar atenção com os
   monstros, mas também não é uma zona de jogo comum. */
.zone.piles-merged {
  border-color: rgba(178, 132, 126, 0.30);
  background:
    repeating-linear-gradient(45deg, rgba(226, 168, 160, 0.035) 0 4px, transparent 4px 9px),
    linear-gradient(160deg, rgba(255, 255, 255, 0.02), transparent 60%),
    rgba(24, 18, 20, 0.34);
}
.zone.piles-merged .zlabel { color: rgba(196, 160, 156, 0.36); }
.zone.piles-merged.clickable:hover {
  border-color: rgba(232, 150, 132, 0.62);
  background:
    repeating-linear-gradient(45deg, rgba(226, 168, 160, 0.05) 0 4px, transparent 4px 9px),
    rgba(48, 26, 26, 0.44);
}
/* Casa VAZIA: a marca RESPIRA entre as duas pilhas que moram aqui — o
   fantasma do cemitério e o proibido das banidas, uma sumindo enquanto a outra
   aparece. É o único jeito de um slot só continuar dizendo que é dois.
   Os dois glifos ficam SOBREPOSTOS (a marca padrão é um `::before` em fluxo,
   e dois em fluxo ficariam lado a lado), com o mesmo ciclo defasado em meia
   volta: onde um chega a zero o outro chega a um, e a troca é a travessia. */
.zone.piles-merged.empty .zlabel::before,
.zone.piles-merged.empty .zlabel::after {
  content: ''; position: absolute; top: 50%; left: 50%;
  width: 44%; max-width: 32px; aspect-ratio: 1;
  transform: translate(-50%, -50%);
  background-color: currentColor;
  -webkit-mask: center / contain no-repeat;
  mask: center / contain no-repeat;
  animation: pile-mark-breathe 7s ease-in-out infinite;
}
.zone.piles-merged.empty .zlabel::before {
  -webkit-mask-image: var(--ic-ghost); mask-image: var(--ic-ghost);
}
.zone.piles-merged.empty .zlabel::after {
  -webkit-mask-image: var(--ic-prohibit); mask-image: var(--ic-prohibit);
  animation-delay: -3.5s;   /* meia volta: um entra exatamente quando o outro sai */
}
@keyframes pile-mark-breathe {
  0%, 40% { opacity: 1; }
  50%, 90% { opacity: 0; }
  100% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  /* Sem alternância: fica só o cemitério, que é a pilha do dia a dia. */
  .zone.piles-merged.empty .zlabel::before { animation: none; opacity: 1; }
  .zone.piles-merged.empty .zlabel::after { display: none; }
}

/* Cartas no board */
.bcard {
  position: absolute; inset: 4px; border-radius: 0; overflow: visible;
  transition: transform 0.35s cubic-bezier(0.3, 1.2, 0.4, 1), box-shadow 0.2s;
}
.bcard .bface {
  position: absolute; inset: 0; border-radius: 0; overflow: hidden;
  background-size: cover; background-position: center;
  border: 1px solid rgba(255, 255, 255, 0.25);
  box-shadow: 0 6px 16px -4px rgba(0, 0, 0, 0.7);
}
/* scan completo da carta: cobre o slot com corte mínimo nas bordas */
.bface img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center;
}
.bface.bfallback {
  display: flex; align-items: center; justify-content: center; text-align: center;
  font-size: 9px; font-weight: 700; color: var(--steel); padding: 4px;
  background: linear-gradient(160deg, #22304a, #131b29);
}
.bcard.monster .bface { border-color: rgba(214, 160, 74, 0.65); }
.bcard.spell .bface { border-color: rgba(45, 165, 130, 0.65); }
.bcard.trap .bface { border-color: rgba(190, 90, 160, 0.65); }
/* hover sem deslocamento: a carta não pode "fugir" de baixo do cursor */
.bcard:hover { transform: scale(1.05); z-index: 5; }
.bcard:hover .bface { box-shadow: 0 14px 30px -6px rgba(0, 0, 0, 0.8), 0 0 18px -2px rgba(120, 180, 255, 0.55); }

/* DEFESA: a carta deita girando no ANTI-horário. O sentido não é indiferente
   — ele decide para onde aponta a aresta de baixo da carta, a que traz ATK/DEF.
   Com -90° ela aponta para a DIREITA (com +90° apontava para a esquerda). */
.bcard.def { transform: rotate(-90deg) scale(0.82); }
.bcard.def:hover { transform: rotate(-90deg) scale(0.86); }

/* Cartas do oponente viradas para o lado dele; stats/labels ficam legíveis
   (só a arte gira, as placas de ATK/DEF ficam fora do flip). */
#field-opp .bface img { transform: rotate(180deg); }
#field-opp .pile-card.top { transform: rotate(180deg); }

/* Placa de ATK/DEF: UMA só, no formato "1200/800" — duas plaquinhas soltas
   competiam entre si e o olho tinha de decidir qual valia. Aqui os dois
   números vivem juntos e quem manda é o TAMANHO: em posição de Ataque o ATK é
   grande e o DEF fica pequeno e apagado; em Defesa, o inverso. A informação
   completa continua na tela, mas a leitura de relance dá o número que importa
   agora. Quadrada como o resto do board. */
.bcard .bstats {
  position: absolute; left: 50%; bottom: -9px; transform: translateX(-50%); z-index: 4;
  display: flex; align-items: baseline; gap: 1px;
  padding: 1px 5px; border-radius: 0;
  background: rgba(8, 12, 18, 0.92); border: 1px solid rgba(255, 255, 255, 0.2);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.6);
  font-weight: 900; line-height: 1.25; white-space: nowrap;
  font-variant-numeric: tabular-nums; pointer-events: none;
}
.bcard .bstats i { font-style: normal; transition: font-size 0.2s, opacity 0.2s; }
.bcard .bstats i.a { color: #ffd0a0; }
.bcard .bstats i.d { color: #9fd0ff; }
.bcard .bstats b { font-weight: 700; font-size: 8px; color: rgba(159, 180, 200, 0.55); }
/* Em ATAQUE manda o ATK; em DEFESA, o DEF. */
.bcard:not(.def) .bstats i.a, .bcard.def .bstats i.d { font-size: 10.5px; }
.bcard:not(.def) .bstats i.d, .bcard.def .bstats i.a { font-size: 8px; opacity: 0.55; }
/* A placa segue no MESMO ponto da tela de antes (acima da carta deitada):
   com o pai a -90°, isso é o lado DIREITO no referencial local, e o
   contra-giro que a deixa legível passa a ser +90°. */
.bcard.def .bstats { transform: translateX(50%) rotate(90deg); bottom: auto; top: 50%; left: auto; right: -6px; margin-top: -8px; }
/* Nas cartas do OPONENTE as placas ficam viradas para o lado DELE: no topo da
   carta (que é a "base" na visão dele); em defesa, no outro flanco. O texto
   continua legível — só o posicionamento muda. */
#field-opp .bcard .bstats { bottom: auto; top: -9px; }
#field-opp .bcard.def .bstats {
  right: auto; left: -6px; top: 50%; transform: translateX(-50%) rotate(90deg);
}
.bcard.buffed .bstats i.a { color: var(--heal); }
.bcard.nerfed .bstats i.a { color: var(--danger); }
/* Bônus só-de-batalha (Skyscraper): a placa pisca em dourado no cálculo. */
.bcard .bstats.fx-boost i.a, .bcard .bstats.fx-boost i.d {
  color: #ffd54a; border-color: rgba(255, 213, 74, 0.85);
  box-shadow: 0 0 12px rgba(255, 213, 74, 0.9); animation: stat-boost 0.5s ease-in-out 2;
}
@keyframes stat-boost { 50% { filter: brightness(1.7); } }

/* Spell Counters: bolinha roxa no canto superior esquerdo da carta. */
.bcard .bcounters {
  position: absolute; top: -6px; left: -6px; z-index: 5;
  width: 17px; height: 17px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 900; color: #f3ebff;
  background: radial-gradient(circle at 35% 30%, #9a6ae8, #5b2ea6 70%);
  border: 1px solid rgba(220, 190, 255, 0.65);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.6), 0 0 8px rgba(150, 90, 230, 0.5);
  pointer-events: none;
}

/* Verso de carta (facedown / pilhas / mão do oponente) — arte oficial;
   o gradiente fica de fallback caso a imagem não carregue. */
.cardback {
  background:
    url("https://yugiohonline.b-cdn.net/ui/card-back.webp") center / cover no-repeat,
    radial-gradient(60% 60% at 50% 42%, rgba(120, 80, 190, 0.75), transparent 70%),
    linear-gradient(160deg, #3a2a10, #191108);
  position: relative;
}
.bcard.facedown .bface { border-color: rgba(150, 120, 210, 0.5); }

/* Minha carta baixa: em repouso o verso "pisca" translúcido revelando de
   leve a carta (escurecida) por baixo; no hover um FLIP 3D LATERAL de
   verdade — o verso vira e do outro lado está a carta (dois lados com
   backface-visibility; a carta só aparece depois dos 90°). */
.bcard.facedown.peek .bface { perspective: 520px; }
.bcard.facedown.peek .bface > img { filter: brightness(0.5) saturate(0.85); }
.bcard .flipper {
  position: absolute; inset: 0; pointer-events: none;
  transform-style: preserve-3d;
  transition: transform 0.55s cubic-bezier(0.35, 0.85, 0.3, 1);
}
.bcard .fd-front, .bcard .fd-back {
  position: absolute; inset: 0; border-radius: 0;
  background-size: cover; background-position: center;
  backface-visibility: hidden;
}
/* Carta recriada sob o cursor: assume o hover sem reanimar (duel/board.ts).
   Sem isto, clicar numa carta baixada — que re-renderiza o board — refazia o
   flip inteiro, embora ela já estivesse espiada. */
.bcard.hover-carry, .bcard.hover-carry .flipper,
.bcard.hover-carry .bface, .bcard.hover-carry .bface > img { transition: none !important; }
.bcard.hover-carry .fd-front { animation: none !important; }
.bcard .fd-front { background-image: url("https://yugiohonline.b-cdn.net/ui/card-back.webp"); }
.bcard.facedown.peek .fd-front { animation: fd-peek 3.4s ease-in-out infinite; }
/* verso do flipper: a carta em si, pré-girada para o lado oposto */
.bcard .fd-back { transform: rotateY(180deg); }
/* `.peek-hold` = carta ACABOU de ser baixada com o cursor em cima dela. O
   hover já está valendo no instante em que ela nasce, e sem esta trava ela
   viraria sozinha — espiar é um gesto de quem passa o mouse, não de quem
   acabou de jogar. Sai no primeiro movimento do ponteiro para fora dela
   (duel/board.ts). */
.bcard.facedown.peek:not(.peek-hold):hover .flipper { transform: rotateY(180deg); }
.bcard.facedown.peek:not(.peek-hold):hover .fd-front { animation: none; opacity: 1; }
/* durante o giro, a carta-espiada de trás some (senão "já aparece" antes) */
.bcard.facedown.peek:not(.peek-hold):hover .bface > img { opacity: 0; }
/* Carta em DEFESA gira 90°, e o flip NÃO muda de eixo por causa disso: a carta
   sempre vira em torno da lombada dela (o eixo maior), que no referencial dela
   é o Y — quem cuida de como isso aparece na tela é o `rotate(-90deg)` do
   próprio slot. Deitada, o mesmo rotateY sai como um giro de cima para baixo,
   que é como se vira uma carta que está de lado. Antes havia um override em
   rotateX aqui para "manter o giro lateral", e era justamente o errado: a
   carta deitada girava de lado, como se ainda estivesse em pé. */
@keyframes fd-peek {
  0%, 100% { opacity: 0.95; }
  50% { opacity: 0.45; }
}


/* Pilhas (deck/extra/cemitério): cartas de verdade levemente desalinhadas.
   O número de camadas acompanha a contagem — pilha rala = menos cartas. */
/* Quem ocupa a casa é a carta do FUNDO: é ela que está pousada no slot, com o
   mesmo recuo de qualquer carta em campo, e o monte se levanta a partir dela
   (o recuo do bloco fica no JS, junto do passo — ver `STACK_STEP`).
   O monte cresce para DENTRO do tabuleiro — o contrário do lado para onde a
   coluna se afasta pelo `edge-l`/`edge-r`. Assim o meu deck (borda direita)
   engorda para a esquerda e o meu extra (borda esquerda) para a direita; no
   lado do oponente, que é espelhado, a regra se inverte sozinha porque as
   classes já estão trocadas. O que sobra do monte (~3px com o deck cheio) cai
   na calha entre as colunas, que ali tem 30px: nunca encosta na casa vizinha. */
.pile-stack { position: absolute; inset: 4px; border-radius: 0; z-index: 0; }
.zone.edge-l .pile-stack { --mound: 1; }
.zone.edge-r .pile-stack { --mound: -1; }
.pile-card {
  position: absolute; inset: 0; border-radius: 0;
  background-size: cover; background-position: center;
  border: 1px solid rgba(12, 18, 28, 0.95);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
}
/* camada "cega" para pilhas de cartas viradas para cima (cemitério) */
.pile-card.plain { background: linear-gradient(160deg, #26303f, #151d29); }
/* o cemitério mostra a carta REAL (scan completo) do topo */
.pile-card.top.face { background-position: center top; }
/* A carta recém-destruída só APARECE na pilha quando os cacos chegam (ver
   holdPileTop em duel/fx.ts). Some só o TOPO: as camadas de baixo ficam, então
   uma pilha que já tinha cartas não pisca — e o contador também fica, porque o
   número novo é informação, não animação. */
.zone.pile-hold .pile-card.top { opacity: 0; }
.zone.pile-land .pile-card.top { animation: pile-land 0.42s cubic-bezier(0.2, 1.3, 0.4, 1); }
/* `scale` avulso, não `transform`: o topo da pilha do OPONENTE já carrega um
   `transform: rotate(180deg)`, e animar `transform` aqui o desgiraria por meio
   segundo. As propriedades independentes compõem com ele. */
@keyframes pile-land {
  0% { opacity: 0; scale: 1.16; filter: brightness(2.2) saturate(0.4); }
  40% { opacity: 1; }
  100% { opacity: 1; scale: 1; filter: none; }
}
@media (prefers-reduced-motion: reduce) {
  .zone.pile-hold .pile-card.top { opacity: 1; }
  .zone.pile-land .pile-card.top { animation: none; }
}

/* Batalha em andamento (visível para os DOIS jogadores): espada no atacante,
   pulso vermelho no alvo. A espada é um <i> de ícone criado pelo boardCard —
   a fonte duotone precisa dos DOIS pseudos do próprio elemento. */
.bcard .atk-marker {
  position: absolute; top: -19px; left: 50%; transform: translateX(-50%);
  z-index: 7; font-size: 16px; color: var(--danger); pointer-events: none;
  filter: drop-shadow(0 0 6px rgba(255, 70, 50, 0.85)) drop-shadow(0 2px 3px rgba(0, 0, 0, 0.8));
  animation: sword-bob 0.8s ease-in-out infinite;
}
/* Espadinha "idle": este monstro AINDA pode atacar (sem bob, mais discreta). */
.bcard .atk-marker.idle {
  animation: none; font-size: 13px; top: -15px; opacity: 0.9;
  filter: drop-shadow(0 0 4px rgba(255, 70, 50, 0.6)) drop-shadow(0 1px 2px rgba(0, 0, 0, 0.8));
}


@keyframes target-pulse {
  0%, 100% { box-shadow: 0 0 3px var(--edge-on); }
  50% { box-shadow: 0 0 9px 1px var(--edge-on); }
}

/* ── Mãos ──────────────────────────────────────────────────────────────── */

/* Altura RESERVADA (não `min-height`): a fileira ocupa exatamente uma carta,
   com mão cheia ou vazia. Ela é responsiva porque a medida vem do mesmo token
   da carta (--hand-card-w em vw) — fixa no lugar, elástica no tamanho. Sem
   isso, ficar sem cartas na mão fazia o board inteiro escorregar para o lado
   de quem esvaziou.
   As cartas ficam SEPARADAS (não mais em leque sobreposto): cada uma se lê
   inteira sem precisar passar o mouse. A folga acompanha a largura da tela
   pelo mesmo motivo da carta — numa mão muito grande ela encolhe em vez de
   estourar a fileira. */
.hand-row {
  display: flex; justify-content: center; align-items: flex-end;
  gap: clamp(3px, 0.4vw, 7px);
  position: relative; z-index: 6; flex: none;
}
.hand-row.me { height: calc(var(--hand-card-h) + 10px); padding: 6px 0 4px; }
.hand-row.opp { height: calc(var(--ohand-card-h) + 2px); padding: 2px 0 0; align-items: flex-start; }

.hcard {
  width: var(--hand-card-w); aspect-ratio: 59 / 86;
  position: relative;
  transition:
    width 0.22s cubic-bezier(0.3, 1.3, 0.4, 1),
    margin 0.22s cubic-bezier(0.3, 1.3, 0.4, 1),
    transform 0.22s cubic-bezier(0.3, 1.3, 0.4, 1),
    z-index 0s;
}
.hcard img, .hcard .hback {
  position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 0;
  object-fit: cover; border: 1px solid rgba(255, 255, 255, 0.25);
  box-shadow: 0 8px 22px -6px rgba(0, 0, 0, 0.85);
}
/* A carta destacada cresce por LAYOUT, não por `transform: scale()`.
 *
 * Um `scale` num elemento que o Chrome pôs em camada própria (e a transição de
 * transform põe) NÃO redesenha a arte: ele estica a textura que já havia sido
 * rasterizada no tamanho pequeno. O resultado é a carta borrada justamente
 * quando ela está grande e você quer LER o texto dela.
 *
 * Crescendo a largura, a arte é diagramada e rasterizada já nos ~118px finais
 * — nítida por construção, sem depender de o navegador resolver reraster.
 *
 * As duas contas que mantêm o resultado idêntico ao do `scale(1.28)`:
 *  · `margin` lateral negativa de metade do que ela cresceu (0,28 ÷ 2 = 0,14)
 *    devolve à linha o espaço tomado — a carta invade as vizinhas como antes,
 *    e nenhuma delas se desloca;
 *  · a fileira alinha por BAIXO, então crescer empurra a carta para cima
 *    sozinha. O `scale` crescia a partir do CENTRO (metade para cada lado),
 *    então o levantamento devolve 14% da altura para a carta parar na mesma
 *    linha de antes.
 */
.hand-row.me .hcard:hover {
  width: calc(var(--hand-card-w) * 1.28);
  margin-inline: calc(var(--hand-card-w) * -0.14);
  transform: translateY(calc(var(--hand-card-h) * 0.14 - 26px)) !important;
  z-index: 60 !important;
}
.hand-row.me .hcard:hover img { box-shadow: 0 20px 40px -8px rgba(0, 0, 0, 0.9), 0 0 22px -4px rgba(120, 180, 255, 0.6); }
.hand-row.me .hcard { touch-action: none; }
.hand-row.opp .hcard { width: var(--ohand-card-w); }

/* [Ceremonial Bell] Mao ABERTA: o servidor manda os codigos e as cartas
   aparecem de frente. O halo ambar existe para ninguem jogar achando que a
   mao ainda e secreta — e vale para os DOIS lados (o print costuma abrir a
   sua tambem). */
.hand-row.revealed .hcard img,
.hand-row.revealed .hcard .hback {
  box-shadow: 0 0 0 1px rgba(240, 196, 92, 0.85), 0 0 14px -2px rgba(240, 196, 92, 0.55);
}
.hand-row.revealed::after {
  content: ''; position: absolute; left: 50%; transform: translateX(-50%);
  width: min(340px, 60%); height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, transparent, rgba(240, 196, 92, 0.85), transparent);
}
.hand-row.revealed.me::after { top: 0; }
.hand-row.revealed.opp::after { bottom: 0; }

/* ── Drag & drop da mão para o board ───────────────────────────────────── */

/* cartas são cartas, não imagens: nada de arrasto/seleção nativos */
#screen-duel { user-select: none; }
#screen-duel img { -webkit-user-drag: none; user-select: none; }

body.dragging, body.dragging #screen-duel, body.dragging #screen-duel * { cursor: grabbing !important; }
/* Arrastando: a carta sob o cursor não se destaca. Precisa desfazer as TRÊS
   coisas do destaque — o crescimento também, não só o transform. */
body.dragging .hand-row.me .hcard:hover {
  width: var(--hand-card-w); margin-inline: 0;
  transform: none !important;
}

.hcard.drag-src { opacity: 0.35; }
.bcard.drag-src { opacity: 0.35; }
.drag-ghost {
  position: fixed; z-index: 70; pointer-events: none; width: 94px;
  transform: translate(-50%, -60%) rotate(3deg);
  filter: drop-shadow(0 18px 30px rgba(0, 0, 0, 0.75));
}
.drag-ghost img { width: 100%; border-radius: 0; border: 1px solid rgba(150, 195, 255, 0.7); }

/* Carta da mão com efeito ativável: mesmo glow amarelo do board — constante. */
.hcard.playable::after {
  content: ''; position: absolute; inset: -1px; border-radius: 0; pointer-events: none;
  border: 2px solid rgba(255, 215, 94, 0.95); /* borda nítida, glow bem discreto */
  box-shadow: 0 0 3px rgba(255, 215, 94, 0.3);
}
/* Jogável mas sem efeito ativável (invocar/setar): glow BRANCO, mais sutil. */
.hcard.playable-soft::after {
  content: ''; position: absolute; inset: -1px; border-radius: 0; pointer-events: none;
  border: 2px solid rgba(255, 255, 255, 0.8); /* borda nítida, glow bem discreto */
  box-shadow: 0 0 3px rgba(255, 255, 255, 0.2);
}

/* ── Mira de ataque: espadinha no atacante + traço até o alvo ──────────── */

@keyframes sword-bob {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50% { transform: translateX(-50%) translateY(-4px); }
}
/* Seta do ataque: grossa e reta (quadrada, como o resto do board). Ela é a
   leitura mais importante do turno — quem bate em quem — então tem peso. */
.attack-line {
  position: absolute; height: 6px; transform-origin: 0 50%; z-index: 19; pointer-events: none;
  background: linear-gradient(90deg, rgba(255, 92, 73, 0.08), rgba(255, 92, 73, 0.95));
  border-radius: 0; box-shadow: 0 0 16px rgba(255, 60, 40, 0.6);
  animation: fade-in 0.15s ease-out;
}
.attack-line::after {
  content: ''; position: absolute; right: 0; top: 50%; width: 17px; height: 17px;
  transform: translate(6px, -50%) rotate(45deg);
  border-top: 6px solid rgba(255, 92, 73, 0.98); border-right: 6px solid rgba(255, 92, 73, 0.98);
  filter: drop-shadow(0 0 8px rgba(255, 60, 40, 0.55));
}

/* Aviso de ATAQUE DIRETO: vermelho translúcido piscando sobre o board — o
   golpe que passa por cima de tudo merece ser dito com todas as letras. */
.fx-direct {
  position: fixed; left: 0; right: 0; z-index: 22; pointer-events: none; text-align: center;
  font-size: clamp(28px, 3.6vw, 52px); font-weight: 900;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: rgba(255, 92, 73, 0.72);
  text-shadow: 0 0 24px rgba(255, 40, 24, 0.55), 0 4px 18px rgba(0, 0, 0, 0.85);
  animation: direct-blink 0.42s steps(1, end) infinite;
}
@keyframes direct-blink {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0.22; }
}
@media (prefers-reduced-motion: reduce) { .fx-direct { animation: none; } }

/* ── Faixa da chain sobre o board ──────────────────────────────────────── */

#chain-strip {
  position: absolute; top: 6px; left: 50%; transform: translateX(-50%); z-index: 18;
  display: flex; gap: 6px; pointer-events: none; max-width: 80%; flex-wrap: wrap; justify-content: center;
}
.chain-pill {
  display: flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 700;
  color: #e9d8ff; background: rgba(30, 18, 52, 0.92); border: 1px solid rgba(160, 110, 230, 0.5);
  border-radius: 99px; padding: 5px 12px; box-shadow: 0 8px 24px -8px rgba(0, 0, 0, 0.8);
  animation: modal-pop 0.2s ease-out;
}
.chain-pill .n {
  background: #7c4dcc; color: white; border-radius: 99px; min-width: 18px; height: 18px;
  display: flex; align-items: center; justify-content: center; font-size: 10.5px;
}
.chain-pill.negated { opacity: 0.45; text-decoration: line-through; }

/* Efeitos ativáveis sem carta visível (ex.: efeitos do cemitério) */
#quick-options {
  /* acima do cluster de turno inteiro (status + 2 botões ≈ 125px) */
  position: absolute; right: 10px; bottom: 140px; z-index: 12;
  display: flex; flex-direction: column; gap: 6px; max-width: 240px;
}
#quick-options button {
  position: relative; border: none; clip-path: var(--cut-sm); text-align: left;
  background: rgba(56, 189, 248, 0.45); color: #cfe8ff; font-size: 12px; font-weight: 700;
  padding: 8px 14px;
}
#quick-options button::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm);
  background-color: rgba(9, 20, 36, 0.94); transition: background 0.15s;
}
#quick-options button:hover::before {
  background-image: linear-gradient(rgba(56, 120, 198, 0.4), rgba(56, 120, 198, 0.4));
}

/* ── Prompt central do duelo: respostas, triggers e escolhas ───────────── */

#prompt-modal {
  position: fixed; inset: 0; z-index: 32; display: flex; align-items: center; justify-content: center;
  pointer-events: none;
}
#prompt-card {
  position: relative; pointer-events: auto; width: 440px; max-width: 94vw; max-height: 70vh;
  display: flex; flex-direction: column; gap: 10px; text-align: center;
  background: rgba(120, 180, 255, 0.55); border: none;
  clip-path: var(--cut-md); padding: 20px 22px; backdrop-filter: blur(8px);
  /* clip-path corta box-shadow externo: a sombra vem por drop-shadow (segue o chanfro) */
  filter: drop-shadow(0 30px 60px rgba(0, 0, 0, 0.85)) drop-shadow(0 0 26px rgba(90, 160, 240, 0.22));
  animation: modal-pop 0.22s cubic-bezier(0.2, 1.3, 0.4, 1), prompt-glow 1.8s 0.3s infinite;
}
#prompt-card::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-md);
  background: rgba(10, 15, 26, 0.94); pointer-events: none;
}
/* o pulso da moldura anima o ANEL (fundo do card), não a border nativa */
@keyframes prompt-glow {
  0%, 100% { background-color: rgba(120, 180, 255, 0.4); }
  50% { background-color: rgba(160, 205, 255, 0.85); }
}
#prompt-icon { font-size: 32px; line-height: 1; filter: drop-shadow(0 0 14px rgba(120, 180, 255, 0.55)); }
#prompt-title { font-size: 14.5px; font-weight: 800; color: #e3efff; line-height: 1.5; }
/* A carta em questão + o que o efeito faz (newbie friendly) */
/* Altura FIXA: passar o mouse entre as opções não muda mais o tamanho do modal
   (a imagem reserva o espaço via aspect-ratio; o texto rola dentro da altura). */
#prompt-preview {
  display: flex; gap: 12px; align-items: stretch; text-align: left;
  height: 176px; box-sizing: border-box;
  background: rgba(6, 10, 18, 0.55); border-radius: 8px; padding: 10px;
}
#prompt-preview img {
  height: 100%; aspect-ratio: 59 / 86; flex-shrink: 0; border-radius: 6px;
  object-fit: cover; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.7);
}
#prompt-preview-text {
  flex: 1; height: 100%; overflow-y: auto; min-width: 0;
  font-size: 11px; line-height: 1.55; color: #cdd9e6; white-space: pre-wrap;
}
#prompt-chain { display: flex; flex-wrap: wrap; gap: 5px; justify-content: center; }
#prompt-chain:empty { display: none; }
/* a rolagem mora na lista (o card não pode rolar: o ::before da moldura
   rolaria junto e o anel sumiria) */
#prompt-actions { display: flex; flex-direction: column; gap: 6px; overflow-y: auto; min-height: 0; }
#prompt-actions button {
  position: relative; border: none; clip-path: var(--cut-sm); text-align: left;
  background: rgba(56, 189, 248, 0.4); color: #cfe8ff; font-size: 13px; font-weight: 700;
  padding: 10px 13px; transition: transform 0.1s; flex-shrink: 0;
}
#prompt-actions button::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm);
  background-color: rgba(16, 30, 50, 0.95); transition: background 0.15s;
}
#prompt-actions button:hover::before {
  background-image: linear-gradient(rgba(56, 120, 198, 0.35), rgba(56, 120, 198, 0.35));
}
#prompt-actions button:active { transform: scale(0.98); }
#prompt-actions button.pass {
  background: rgba(150, 165, 185, 0.4); color: #cbd5e1; text-align: center;
}
#prompt-actions button.pass::before { background-color: rgba(26, 31, 40, 0.95); }
#prompt-actions button.pass:hover::before {
  background-image: linear-gradient(rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.08));
}

/* ── Camada de efeitos (FX) ────────────────────────────────────────────── */

/* fixed: nunca é cortado pelo overflow de #duel-root (FX nos placares laterais). */
#fx-layer { position: fixed; inset: 0; pointer-events: none; z-index: 20; overflow: visible; }

/* ── EMBARALHAR A ABERTURA: o baralho no meio da tela, em 3D ───────────────
   O monte é tridimensional de verdade: cada carta é um plano com o seu próprio
   `translateZ`, e a espessura aparece porque a rotação da cena desloca as de
   baixo na tela. Nada de espessura desenhada à mão — o desalinho tem de
   sobreviver ao pacote sendo tirado e recolocado, e só a geometria faz isso.

   A DIVISÃO DE TRABALHO entre as três camadas não é organização, é a armadilha
   do `preserve-3d`: propriedade de AGRUPAMENTO (opacity, filter) no mesmo
   elemento que carrega a cena 3D a achata para `flat`, e o monte vira um
   retângulo só. Por isso o véu que aparece/some é o PALCO, a perspectiva é a
   CENA e o 3D é o MONTE — cada um no seu elemento. */
.shuffle-fx {
  position: fixed; inset: 0; z-index: 30; pointer-events: none;
  display: flex; align-items: center; justify-content: center;
  /* Sombra atrás do baralho para ele descolar da nebulosa, que é colorida e
     competiria com o verso da carta. */
  background: radial-gradient(42% 42% at 50% 50%,
    rgba(2, 5, 11, 0.68), rgba(2, 5, 11, 0.32) 64%, transparent 100%);
  animation: reveal-veil 0.4s ease-out both;
}
.shuffle-fx.out { animation: shuffle-veil-out 0.34s ease-in both; }
@keyframes shuffle-veil-out { to { opacity: 0; } }

.shuffle-scene { perspective: 1500px; perspective-origin: 50% 42%; }
.shuffle-deck {
  --sh-w: min(21vh, 158px);
  position: relative;
  width: var(--sh-w); height: calc(var(--sh-w) * 86 / 59);
  transform-style: preserve-3d;
  /* Vista isométrica: tombado para trás e girado na diagonal. */
  transform: rotateX(54deg) rotateZ(-34deg);
  animation: shuffle-in 0.38s cubic-bezier(0.2, 0.9, 0.3, 1) both;
}
/* Entra deitando: chega quase de topo e assenta no ângulo de trabalho. */
@keyframes shuffle-in { from { transform: rotateX(78deg) rotateZ(-34deg) scale(0.76); } }
.shuffle-deck.out { animation: shuffle-out 0.34s ease-in both; }
@keyframes shuffle-out { to { transform: rotateX(66deg) rotateZ(-34deg) scale(0.86); } }
/* A sombra PROJETADA na mesa: um borrão no plano do tampo, abaixo do monte.
   Mora dentro do 3D para acompanhar o giro em vez de ficar colada na tela. */
.shuffle-deck::after {
  content: ''; position: absolute; inset: -18% -26%;
  transform: translateZ(-26px);
  background: radial-gradient(50% 50% at 50% 50%, rgba(0, 0, 0, 0.66), transparent 70%);
}
.shuffle-card {
  position: absolute; inset: 0; display: block;
  background-size: cover; background-position: center;
  /* O fio escuro é o CORTE da carta: sem ele as fatias se fundem numa mancha e
     a espessura deixa de contar quantas cartas são. */
  border: 1px solid rgba(6, 10, 18, 0.92);
  box-shadow: inset 0 0 0 1px rgba(150, 185, 230, 0.10);
}
@media (prefers-reduced-motion: reduce) {
  .shuffle-deck, .shuffle-deck.out { animation: none; }
  .shuffle-card { animation: none !important; }
}

/* Revelação de carta buscada (mostrada aos dois jogadores). */
/* ── REVELAÇÃO: a carta buscada, GRANDE, no meio da tela ───────────────────
   Sem moldura e sem caixa: a carta é o efeito. Ela chega desfocada e clareada
   e RESOLVE para nítida — o gesto de algo escondido vindo à tona — segura um
   instante e sai subindo. O véu atrás escurece o board só o bastante para a
   carta descolar do fundo (a nebulosa é colorida e competiria com a arte). */
.reveal-fx {
  position: fixed; inset: 0; z-index: 30; pointer-events: none;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: clamp(14px, 2.2vh, 26px);
  background: radial-gradient(60% 60% at 50% 46%, rgba(2, 5, 11, 0.62), rgba(2, 5, 11, 0.34) 70%, transparent 100%);
  animation: reveal-veil 0.4s ease-out both;
}
@keyframes reveal-veil { from { opacity: 0; } }

.reveal-row { display: flex; align-items: center; justify-content: center; gap: clamp(10px, 1.6vw, 26px); }
/* A carta domina a tela sem tomá-la: com várias, cada uma encolhe para o
   conjunto continuar cabendo (o `--n` vem do JS). */
.reveal-row { --reveal-h: 44vh; }
/* A carta vive dentro de uma célula para os raios da negação poderem cobri-la
   sem herdar o filtro que roda na imagem. */
.reveal-cell { position: relative; display: block; line-height: 0; }
.reveal-row img {
  height: min(calc(var(--reveal-h) / max(1, var(--n, 1) * 0.55)), var(--reveal-h));
  max-width: calc(84vw / max(1, var(--n, 1)));
  width: auto; border-radius: 0; display: block;
  box-shadow: 0 26px 60px -10px rgba(0, 0, 0, 0.9), 0 0 42px -6px rgba(130, 190, 255, 0.45);
  animation: reveal-card 0.72s cubic-bezier(0.2, 0.8, 0.3, 1) both;
}
/* Chega borrada e clareada → resolve para nítida. */
@keyframes reveal-card {
  0% { opacity: 0; transform: scale(1.14) translateY(10px); filter: blur(14px) brightness(2.6) saturate(0.5); }
  45% { opacity: 1; filter: blur(5px) brightness(1.7) saturate(0.8); }
  100% { opacity: 1; transform: scale(1) translateY(0); filter: blur(0) brightness(1) saturate(1); }
}

/* ── Modo ATIVAÇÃO ────────────────────────────────────────────────────────
   Mesma apresentação da revelação, em voz baixa: a carta é bem menor e o véu
   quase não escurece o tabuleiro. Ativar efeito acontece o tempo todo — se
   isto tomasse a tela como a revelação toma, o duelo viraria uma sucessão de
   telas cheias. É um aceno para a carta, não uma parada. */
.reveal-fx.mode-activate {
  gap: clamp(8px, 1.2vh, 14px);
  background: radial-gradient(44% 44% at 50% 46%, rgba(2, 5, 11, 0.44), rgba(2, 5, 11, 0.16) 70%, transparent 100%);
}
.reveal-fx.mode-activate .reveal-row { --reveal-h: 26vh; }
.reveal-fx.mode-activate .reveal-row img {
  box-shadow: 0 18px 40px -10px rgba(0, 0, 0, 0.85), 0 0 34px -6px rgba(255, 215, 94, 0.5);
  animation-duration: 0.5s;
}
.reveal-fx.mode-activate .reveal-cap { font-size: clamp(12px, 1.1vw, 16px); }

/* ── Modo NEGAÇÃO ─────────────────────────────────────────────────────────
   A cor é ARRANCADA da carta: ela chega já dessaturada, pisca entre preto e
   branco e a cor colorida, e termina cinza e apagada — "isto não vai
   acontecer". O pisca é em `step-end` de propósito: negação é um corte, e uma
   transição suave entre os estados leria como transformação, não como corte. */
.reveal-fx.mode-negate {
  background: radial-gradient(58% 58% at 50% 46%, rgba(4, 4, 6, 0.74), rgba(3, 3, 5, 0.4) 70%, transparent 100%);
}
.reveal-fx.mode-negate .reveal-row { --reveal-h: 34vh; }
.reveal-fx.mode-negate .reveal-row img {
  box-shadow: 0 22px 50px -10px rgba(0, 0, 0, 0.95), 0 0 40px -4px rgba(190, 215, 255, 0.42);
  animation: negate-in 1.45s linear both;
}
/* O estado DOMINANTE é o preto e branco; a cor só volta em lampejos curtos, e
   cada vez mais raros. Com beats de cor longos a leitura se inverte — parece
   uma carta colorida piscando, não uma carta perdendo a cor. */
@keyframes negate-in {
  0%   { opacity: 0; transform: scale(1.12) translateY(8px); filter: blur(11px) grayscale(1) brightness(2.2); }
  14%  { opacity: 1; transform: scale(1) translateY(0); filter: blur(0) grayscale(1) contrast(1.85) brightness(1.45); animation-timing-function: step-end; }
  22%  { filter: blur(0) grayscale(0) contrast(1) brightness(1.05); animation-timing-function: step-end; }
  28%  { filter: blur(0) grayscale(1) contrast(1.85) brightness(1.45); animation-timing-function: step-end; }
  38%  { filter: blur(0) grayscale(0) contrast(1) brightness(1.05); animation-timing-function: step-end; }
  44%  { filter: blur(0) grayscale(1) contrast(1.9) brightness(1.55); animation-timing-function: step-end; }
  56%  { filter: blur(0) grayscale(0) contrast(1) brightness(1); animation-timing-function: step-end; }
  62%  { filter: blur(0) grayscale(1) contrast(1.9) brightness(1.5); animation-timing-function: step-end; }
  84%  { filter: blur(0) grayscale(1) contrast(1.5) brightness(1.05); }
  100% { transform: scale(0.99); filter: blur(0) grayscale(1) contrast(1.35) brightness(0.82); }
}
.reveal-fx.mode-negate .reveal-cap { color: rgba(226, 236, 248, 0.86); text-shadow: 0 0 22px rgba(150, 195, 255, 0.4), 0 3px 14px rgba(0, 0, 0, 0.9); }

/* Raios em DUAS camadas. A ordem no DOM decide a profundidade: a camada `back`
   é irmã anterior da arte e passa por baixo dela (só as pontas escapam pelos
   lados — é o que dá volume), a `front` cruza a carta por cima. A de trás
   ocupa uma caixa bem maior, senão não sobraria ponta para aparecer.
   `preserveAspectRatio="none"` deixa o traçado acompanhar qualquer tamanho de
   carta, e `non-scaling-stroke` impede que a espessura estique junto e vire um
   borrão achatado. */
/* A caixa do SVG é a MESMA nas duas camadas (o viewBox 220×236 do JS assume
   isso), e bem maior que a carta: os raios precisam de espaço para entrar e
   sair, e os filamentos que a contornam, de folga para se afastar da borda. */
.spot-bolts { position: absolute; inset: -31% -60%; overflow: visible; pointer-events: none; }
/* Mistura ADITIVA: onde dois raios se cruzam a luz SOMA, como luz de verdade.
   Sem isto o cruzamento fica opaco e entrega que são dois traços empilhados. */
.spot-bolts { mix-blend-mode: screen; }
.spot-bolts .bolt {
  fill: none; stroke-linecap: round; stroke-linejoin: round;
  vector-effect: non-scaling-stroke; opacity: 0;
  animation: bolt-strike 0.44s steps(1, end) infinite;
}
/* Quatro traços no mesmo caminho, do mais largo ao mais fino. A ordem das
   cores é a de um arco elétrico: ROXO difuso na periferia (onde o ar ainda
   está ionizado), AZUL no halo, quase branco no corpo e BRANCO puro no núcleo.
   É a pilha inteira que faz parecer incandescente. */
.spot-bolts .bolt.aura { stroke: rgba(150, 92, 255, 0.5);  stroke-width: 17; filter: blur(8px); }
.spot-bolts .bolt.halo { stroke: rgba(86, 150, 255, 0.65); stroke-width: 9;  filter: blur(3.5px); }
.spot-bolts .bolt.body { stroke: rgba(206, 231, 255, 0.95); stroke-width: 3.2; filter: blur(1px); }
.spot-bolts .bolt.core { stroke: #fff; stroke-width: 1.3; }
/* Ramificações são mais finas — elas se apagam antes do tronco. */
.spot-bolts .bolt.thin.aura { stroke-width: 10; }
.spot-bolts .bolt.thin.halo { stroke-width: 5; }
.spot-bolts .bolt.thin.body { stroke-width: 1.9; }
.spot-bolts .bolt.thin.core { stroke-width: 0.8; }
/* A camada de trás é mais fria, mais fraca e mais roxa: está atrás da carta e
   no fundo da cena, e é a distância que separa as duas. */
.spot-bolts.back .bolt.aura { stroke: rgba(126, 72, 232, 0.42); stroke-width: 20; }
.spot-bolts.back .bolt.halo { stroke: rgba(72, 128, 232, 0.5); }
.spot-bolts.back .bolt.body { stroke: rgba(176, 212, 255, 0.75); }
.spot-bolts.back .bolt.core { stroke: rgba(238, 246, 255, 0.9); stroke-width: 1; }
/* Descarga DUPLA (o estalo curto e o golpe), e os quatro raios entram
   defasados de 1/4 de ciclo (o JS escalona em 110ms sobre 440ms) — assim há
   sempre um ou dois no ar, correndo em volta da carta, em vez de piscadas
   isoladas com buracos entre elas. */
@keyframes bolt-strike {
  0%, 22%   { opacity: 1; }
  23%, 30%  { opacity: 0; }
  31%, 56%  { opacity: 1; }
  57%, 100% { opacity: 0; }
}

/* A TREMIDINHA. Vive na célula, não na arte: a arte já tem a sua animação de
   `filter` (o pisca preto-e-branco), e as duas brigariam pela mesma
   propriedade. Usa `translate`/`rotate` independentes em vez de `transform`
   pelo mesmo motivo — compõem sem se sobrescrever.
   A amplitude DECAI: sacudir sempre igual parece defeito de renderização;
   sacudir forte e ir cedendo parece a carta encaixando o golpe. */
.reveal-fx.mode-negate .reveal-cell { animation: negate-shake 1.15s steps(1, end) both; }
@keyframes negate-shake {
  0%   { translate: 0 0;        rotate: 0deg; }
  5%   { translate: -4px 2px;   rotate: -0.9deg; }
  11%  { translate: 4px -2px;   rotate: 0.9deg; }
  17%  { translate: -3px -2px;  rotate: -0.7deg; }
  23%  { translate: 3px 2px;    rotate: 0.7deg; }
  30%  { translate: -3px 1px;   rotate: -0.6deg; }
  37%  { translate: 2px -2px;   rotate: 0.5deg; }
  45%  { translate: -2px -1px;  rotate: -0.4deg; }
  53%  { translate: 2px 1px;    rotate: 0.4deg; }
  62%  { translate: -1px 1px;   rotate: -0.25deg; }
  71%  { translate: 1px -1px;   rotate: 0.25deg; }
  81%  { translate: -1px 0;     rotate: -0.15deg; }
  90%  { translate: 1px 0;      rotate: 0.1deg; }
  100% { translate: 0 0;        rotate: 0deg; }
}

/* Só o texto, sem ícone: amarelo translúcido, piscando. O `--d` vem do JS —
   a entrada espera as cartas assentarem, e o pisca começa logo depois dela
   (por isso os dois atrasos saem do mesmo valor). */
.reveal-cap {
  display: inline-flex; align-items: center;
  font-size: clamp(15px, 1.5vw, 21px); font-weight: 900;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: rgba(255, 215, 94, 0.8);
  text-shadow: 0 0 24px rgba(232, 192, 100, 0.45), 0 3px 14px rgba(0, 0, 0, 0.9);
  animation:
    reveal-cap 0.5s ease-out var(--d, 0ms) both,
    reveal-blink 0.9s ease-in-out calc(var(--d, 0ms) + 0.5s) infinite;
}
@keyframes reveal-cap {
  from { opacity: 0; transform: translateY(10px); letter-spacing: 0.3em; }
}
@keyframes reveal-blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.42; }
}
@media (prefers-reduced-motion: reduce) {
  .reveal-row img, .reveal-fx { animation-duration: 0.01s; }
  .reveal-cap { animation: none; }
  /* Estroboscópio é justamente o que esta preferência existe para evitar: o
     pisca e os raios saem, mas o cinza FICA — ele é a informação. */
  .reveal-fx.mode-negate .reveal-row img { animation: none; filter: grayscale(1) contrast(1.35); }
  .reveal-fx.mode-negate .reveal-cell { animation: none; }
  .spot-bolts, .fx-negate { animation: none; opacity: 0.9; }
  .spot-bolts .bolt { animation: none; opacity: 1; }
}

/* Dado d6 (Dark Master Zorc e futuras cartas de dado). No BODY, acima do
   #prompt-modal (z:32) e não-clicável — o JS (fxDieRoll) anima o .die-cube. */
.die-fx {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 112px; height: 112px; perspective: 720px;
  z-index: 48; pointer-events: none;
}
.die-cube {
  width: 100%; height: 100%; border-radius: 20px;
  background: radial-gradient(120% 120% at 30% 22%, #fffdf6 0%, #f4ecd8 46%, #e3d5b6 100%);
  box-shadow:
    inset 0 3px 6px rgba(255, 255, 255, 0.85),
    inset 0 -8px 14px rgba(120, 96, 54, 0.42),
    0 12px 26px rgba(0, 0, 0, 0.55),
    0 0 0 2px rgba(214, 183, 110, 0.55),
    0 0 30px 6px rgba(240, 196, 92, 0.45);
  display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 1fr);
  padding: 13px; box-sizing: border-box;
  transform-style: preserve-3d; will-change: transform, opacity;
}
.die-cell { display: flex; align-items: center; justify-content: center; }
.die-pip {
  width: 66%; height: 66%; border-radius: 50%;
  background: radial-gradient(120% 120% at 35% 30%, #4a4658 0%, #241f30 60%, #14101c 100%);
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.25), inset 0 -2px 3px rgba(0, 0, 0, 0.5);
}

/* Moeda — irmã do dado: mesmo lugar, mesma altura de empilhamento, mesma
   gramática. Gira de CANTO (rotateX): `backface-visibility: hidden` faz ela
   sumir ao passar pelo perfil, que é o que uma moeda fina faz de verdade. */
.coin-fx {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 118px; height: 118px; perspective: 760px;
  z-index: 48; pointer-events: none;
}
/* `will-change` aqui lista SÓ transform. Pôr `opacity` junto — mesmo sem
   opacidade aplicada — faz o Chrome tratar o disco como grupo e achatar o
   `transform-style` para `flat`; aí o `backface-visibility` das faces deixa de
   valer e a coroa sai como a cara espelhada. O fade mora no invólucro. */
.coin-disc { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; will-change: transform; }
.coin-face {
  position: absolute; inset: 0; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  backface-visibility: hidden;
  font-size: 15px; font-weight: 900; letter-spacing: 0.12em; text-transform: uppercase;
  color: #5d4515; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
  background: radial-gradient(120% 120% at 32% 24%, #fff8dd 0%, #f2d989 44%, #c9a24a 100%);
  box-shadow:
    inset 0 3px 6px rgba(255, 255, 255, 0.8),
    inset 0 -8px 14px rgba(120, 90, 30, 0.45),
    0 0 0 3px rgba(196, 158, 70, 0.65),
    0 12px 26px rgba(0, 0, 0, 0.55),
    0 0 30px 6px rgba(240, 196, 92, 0.42);
}
.coin-face.tails {
  transform: rotateX(180deg);
  background: radial-gradient(120% 120% at 32% 24%, #f6f9ff 0%, #cfd8e6 44%, #93a1b6 100%);
  color: #33404f;
  box-shadow:
    inset 0 3px 6px rgba(255, 255, 255, 0.85),
    inset 0 -8px 14px rgba(60, 74, 92, 0.4),
    0 0 0 3px rgba(154, 170, 192, 0.65),
    0 12px 26px rgba(0, 0, 0, 0.55),
    0 0 30px 6px rgba(180, 205, 240, 0.4);
}

/* Carta NEGADA no tabuleiro: um véu que DESSATURA o que está embaixo em vez de
   repintar a carta. Assim ele serve monstro em defesa, carta do oponente e
   verso sem precisar clonar a arte nem refazer a rotação do palco. */
.fx-negate {
  position: absolute; pointer-events: none;
  backdrop-filter: grayscale(1) contrast(1.5) brightness(1.22);
  -webkit-backdrop-filter: grayscale(1) contrast(1.5) brightness(1.22);
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.85), 0 0 18px rgba(190, 220, 255, 0.5);
  animation: negate-blink 0.3s steps(1, end) 3 both;
}
@keyframes negate-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
/* Com aceleração de hardware desligada não existe backdrop-filter, e o véu
   ficaria só numa moldura piscando. Aí o pisca vira um lampejo claro por cima
   da carta: perde a graça de dessaturar, mas continua dizendo o que houve. */
@supports not ((backdrop-filter: grayscale(1)) or (-webkit-backdrop-filter: grayscale(1))) {
  .fx-negate { background: rgba(232, 240, 252, 0.5); }
}

.fx-ghost {
  position: absolute; border-radius: 7px; background-size: cover; background-position: center 20%;
  border: 1px solid rgba(255, 255, 255, 0.4); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.8);
  will-change: transform, opacity;
}
.fx-ring {
  position: absolute; border-radius: 50%; border: 3px solid #bfe0ff;
  box-shadow: 0 0 30px rgba(150, 200, 255, 0.8), inset 0 0 20px rgba(150, 200, 255, 0.5);
  animation: fx-ring 0.6s ease-out forwards;
}
@keyframes fx-ring {
  from { opacity: 1; transform: scale(0.4); }
  to { opacity: 0; transform: scale(1.6); }
}
/* Onda de invocação/set: expande do ponto de entrada e cruza o board (recortada
   pelo overflow:hidden do #field). Um par escalonado dá o efeito de ripple. */
.fx-ripple {
  position: absolute; z-index: 2; pointer-events: none; border-radius: 50%;
  border: 2px solid rgba(150, 200, 255, 0.75);
  box-shadow: 0 0 26px rgba(120, 180, 255, 0.45), inset 0 0 40px rgba(120, 180, 255, 0.18);
  transform: translate(-50%, -50%) scale(0.03); will-change: transform, opacity;
  animation: fx-ripple 0.85s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
}
.fx-ripple.soft {
  border-color: rgba(150, 200, 255, 0.4);
  box-shadow: 0 0 18px rgba(120, 180, 255, 0.3);
}
/* ── CIRCUITO DA JOGADA: as trilhas que acendem em volta da carta ──────────
   Nasce com a onda (duel/fx.ts → fxRipple) e some junto. Cada trilha se
   DESENHA de dentro para fora — `stroke-dashoffset` indo a zero é o que dá a
   leitura de corrente correndo pelo fio, e não de uma linha que só apareceu.
   O `pathLength="1"` do SVG normaliza o comprimento de todas, então uma regra
   só serve para trilha curta e longa. `--d` é o atraso de cada uma (o JS
   calcula a partir da duração da onda). */
/* DEBAIXO do slot (z-index 0): acima do canvas de partículas (que é z-index 0 e
   vem antes no DOM) e abaixo das zonas e das cartas, que são z-index 1. É o que
   impede o circuito de passar por cima da carta vizinha — e o que o faz parecer
   estar EMBUTIDO no tabuleiro, correndo por baixo dos slots, em vez de flutuar
   sobre eles. O `overflow: hidden` do #field cuida do resto: nada escapa da
   moldura do board. */
.fx-circuit { position: absolute; z-index: 0; pointer-events: none; }
.fx-circuit svg { display: block; width: 100%; height: 100%; }
.fx-circuit .tr, .fx-circuit .fr {
  fill: none; stroke: rgba(158, 208, 255, 0.92); stroke-width: 2.2;
  stroke-linecap: square; stroke-linejoin: miter;
  stroke-dasharray: 1; stroke-dashoffset: 1;
  filter: drop-shadow(0 0 4px rgba(110, 180, 255, 0.7));
  animation: circuit-draw 0.62s cubic-bezier(0.25, 0.85, 0.35, 1) var(--d, 0ms) both;
}
/* As cantoneiras coladas na carta são a origem: acendem no instante zero. */
.fx-circuit .fr { stroke-width: 2.8; animation-duration: 0.34s; animation-delay: 0ms; }
@keyframes circuit-draw {
  0% { stroke-dashoffset: 1; opacity: 0; }
  12% { opacity: 1; }
  62% { stroke-dashoffset: 0; opacity: 1; }
  100% { stroke-dashoffset: 0; opacity: 0; }
}
/* A via acende quando a corrente CHEGA nela (o JS soma o atraso da trilha). */
.fx-circuit .via {
  fill: rgba(198, 232, 255, 0.98); transform-box: fill-box; transform-origin: center;
  filter: drop-shadow(0 0 5px rgba(120, 190, 255, 0.9));
  animation: circuit-via 0.5s ease-out var(--d, 0ms) both;
}
@keyframes circuit-via {
  0% { opacity: 0; transform: scale(0.2); }
  30% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1); }
}

/* ── Humor FALHA: a carta queimou ──────────────────────────────────────────
   O mesmo circuito, mas com defeito. Três coisas mudam, e as três importam:
   VERMELHO (é perda, não jogada), `steps(1, end)` — a corrente não corre mais,
   ela SALTA de um pedaço para o outro com apagões no meio — e `--cut`, que é
   o quanto de cada trilha fica por desenhar: quase nenhuma chega ao fim.
   O resultado é irregular de propósito; o desenho bonito é o da invocação. */
.fx-circuit.fail .tr, .fx-circuit.fail .fr {
  stroke: rgba(255, 96, 74, 0.92);
  filter: drop-shadow(0 0 4px rgba(255, 60, 40, 0.65));
  animation-name: circuit-fail;
  animation-timing-function: steps(1, end);
  animation-duration: 0.72s;
}
.fx-circuit.fail .fr { animation-duration: 0.46s; }
.fx-circuit.fail .via {
  fill: rgba(255, 150, 130, 0.95);
  filter: drop-shadow(0 0 5px rgba(255, 70, 50, 0.85));
  animation-name: circuit-via-fail;
  animation-timing-function: steps(1, end);
}
@keyframes circuit-fail {
  0% { stroke-dashoffset: 1; opacity: 0; }
  8% { stroke-dashoffset: 0.74; opacity: 1; }
  15% { stroke-dashoffset: 0.74; opacity: 0.1; }
  22% { stroke-dashoffset: 0.52; opacity: 1; }
  30% { stroke-dashoffset: 0.52; opacity: 0.14; }
  38% { stroke-dashoffset: var(--cut, 0.3); opacity: 0.95; }
  52% { opacity: 0.12; }
  61% { opacity: 0.8; }
  74% { opacity: 0.1; }
  86% { opacity: 0.45; }
  100% { stroke-dashoffset: var(--cut, 0.3); opacity: 0; }
}
@keyframes circuit-via-fail {
  0% { opacity: 0; transform: scale(0.2); }
  25% { opacity: 1; transform: scale(1); }
  40% { opacity: 0.1; }
  55% { opacity: 0.9; }
  72% { opacity: 0.1; }
  100% { opacity: 0; }
}
/* O quadro inteiro treme de leve, como sinal falhando. */
.fx-circuit.fail svg { animation: circuit-glitch 0.36s steps(1, end) 2; }
@keyframes circuit-glitch {
  0%, 100% { transform: translate(0, 0); }
  16% { transform: translate(1.6px, -1px); }
  22% { transform: translate(-1.2px, 0); }
  58% { transform: translate(0.9px, 1px); }
  66% { transform: translate(0, 0); }
}
/* A onda do impacto acompanha: vermelha, não azul. */
.fx-ripple.fail {
  border-color: rgba(255, 96, 74, 0.75);
  box-shadow: 0 0 26px rgba(255, 60, 40, 0.4), inset 0 0 40px rgba(255, 60, 40, 0.14);
}
.fx-ripple.fail.soft { border-color: rgba(255, 96, 74, 0.4); box-shadow: 0 0 18px rgba(255, 60, 40, 0.3); }

@media (prefers-reduced-motion: reduce) { .fx-circuit { display: none; } }

/* Toque no tabuleiro: um anelzinho no ponto do clique. É retorno de INPUT, não
   de jogada — fica bem mais discreto e mais rápido que a onda de invocação
   (sem glow, um fio só, meio segundo), senão cada clique parecia um efeito. */
.fx-tap {
  position: absolute; z-index: 2; pointer-events: none; border-radius: 50%;
  width: 92px; height: 92px; border: 1px solid rgba(170, 205, 255, 0.42);
  transform: translate(-50%, -50%) scale(0.12); will-change: transform, opacity;
  animation: fx-tap 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
}
@keyframes fx-tap {
  from { opacity: 0.55; transform: translate(-50%, -50%) scale(0.12); }
  to { opacity: 0; transform: translate(-50%, -50%) scale(1); }
}
@media (prefers-reduced-motion: reduce) { .fx-tap { display: none; } }
@keyframes fx-ripple {
  from { opacity: 0.85; transform: translate(-50%, -50%) scale(0.03); }
  to { opacity: 0; transform: translate(-50%, -50%) scale(1); }
}
.fx-flash {
  position: absolute; border-radius: 9px; background: white;
  animation: fx-flash 0.35s ease-out forwards;
}
@keyframes fx-flash { from { opacity: 0.95; } to { opacity: 0; transform: scale(1.25); } }
/* Caco de "vidro" da destruição: pedaço da arte da carta, embranquecido,
   voando para fora (transform/opacity via WAAPI — leve p/ GPU). */
.fx-piece {
  position: absolute; will-change: transform, opacity;
  background-repeat: no-repeat;
  /* O halo do caco — é o que faz o pedaço parecer VIDRO pegando luz, e não um
     recorte da imagem. Anda junto com o `brightness` da animação. */
  box-shadow: 0 0 9px rgba(255, 255, 255, 0.42);
}
/* Palco da destruição: mantém a carta na orientação do board (lado/posição)
   e hospeda tremida, flash e cacos em coordenadas locais. */
.fx-cardwrap {
  position: absolute; pointer-events: none; z-index: 6; will-change: transform;
}
.fx-cardwrap .fx-cardface {
  position: absolute; inset: 0; border-radius: 7px;
  background-size: cover; background-position: center;
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.7);
}
/* Magia/armadilha one-shot ATIVADA, mantida em campo durante a resolução:
   brilho azul de "ativação" (os dois jogadores veem a carta chegar em campo). */
.fx-activate-card { z-index: 22; }
.fx-activate-card .fx-cardface {
  border-color: rgba(140, 195, 255, 0.9);
  box-shadow:
    0 0 0 2px rgba(120, 180, 255, 0.6),
    0 0 26px 7px rgba(80, 150, 240, 0.55),
    0 8px 22px rgba(0, 0, 0, 0.7);
}

/* Ativação comprometida (§6.7): a carta já está em campo → a seleção é
   OBRIGATÓRIA. Sem botão de cancelar; o jogador tem de completar. */
body.must-complete #modal-cancel,
body.must-complete #pick-cancel { display: none !important; }
.fx-num {
  position: absolute; font-size: 30px; font-weight: 900; z-index: 22;
  text-shadow: 0 3px 12px rgba(0, 0, 0, 0.9); font-variant-numeric: tabular-nums;
  animation: fx-num 1.15s cubic-bezier(0.2, 0.8, 0.4, 1) forwards;
}
.fx-num.dmg { color: var(--danger); }
.fx-num.heal { color: var(--heal); }
@keyframes fx-num {
  0% { opacity: 0; transform: translateY(8px) scale(0.6); }
  18% { opacity: 1; transform: translateY(0) scale(1.15); }
  75% { opacity: 1; transform: translateY(-22px) scale(1); }
  100% { opacity: 0; transform: translateY(-40px) scale(0.95); }
}
.fx-vignette {
  position: fixed; inset: 0; pointer-events: none; z-index: 21;
  animation: fx-vignette 0.55s ease-out forwards;
}
.fx-vignette.dmg { box-shadow: inset 0 0 140px 40px rgba(255, 40, 20, 0.5); }
.fx-vignette.heal { box-shadow: inset 0 0 140px 40px rgba(60, 255, 140, 0.35); }
@keyframes fx-vignette { from { opacity: 1; } to { opacity: 0; } }
.fx-shield {
  position: absolute; display: flex; align-items: center; justify-content: center;
  font-size: 34px; animation: fx-shield 0.8s ease-out forwards;
  text-shadow: 0 0 20px rgba(120, 190, 255, 0.9);
}
@keyframes fx-shield {
  0% { opacity: 0; transform: scale(0.4); }
  30% { opacity: 1; transform: scale(1.25); }
  100% { opacity: 0; transform: scale(1); }
}
.fx-swirl {
  position: absolute; border-radius: 50%; z-index: 21;
  background: conic-gradient(from 0deg, rgba(160, 90, 255, 0), rgba(160, 90, 255, 0.85), rgba(255, 150, 60, 0.85), rgba(160, 90, 255, 0));
  filter: blur(2px); animation: fx-swirl 0.95s cubic-bezier(0.4, 0, 0.4, 1) forwards;
}
@keyframes fx-swirl {
  0% { opacity: 0; transform: rotate(0deg) scale(0.3); }
  25% { opacity: 1; }
  100% { opacity: 0; transform: rotate(540deg) scale(1.5); }
}
/* Pilar de luz do Ritual Summon */
.fx-pillar {
  position: absolute; z-index: 21; pointer-events: none; border-radius: 8px;
  background: linear-gradient(180deg,
    transparent, rgba(160, 200, 255, 0.75) 30%, rgba(255, 255, 255, 0.95) 50%,
    rgba(160, 200, 255, 0.75) 70%, transparent);
  filter: blur(2px);
  animation: fx-pillar 0.9s ease-out forwards;
}
@keyframes fx-pillar {
  0% { opacity: 0; transform: scaleY(0.15); }
  30% { opacity: 1; transform: scaleY(1.04); }
  100% { opacity: 0; transform: scaleY(1); }
}
/* Orbe de energia dos tributos (voa até o monstro invocado) */
.fx-orb {
  position: absolute; z-index: 22; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle at 40% 35%, #fff, #ffd75e 45%, rgba(255, 180, 60, 0) 75%);
  will-change: transform, opacity;
}

/* ══════════════════════════════════════════════════════════════════════════
   FUSÃO — "Olho do Vórtice": cerimônia SEMPRE no centro do board. O fusion.png
   gira no próprio eixo (spin no FILHO; o wrapper anima scale/opacity/filter via
   WAAPI sem brigar com o spin); materiais são sugados como por um buraco negro
   e partículas verde/roxo orbitam no mesmo sentido. GPU-only. ═══════════════ */
.fx-fusion-png {
  position: absolute; z-index: 21; pointer-events: none;
  will-change: transform, opacity, filter;
}
.fx-fusion-spin {
  position: absolute; inset: 0;
  background: url("https://yugiohonline.b-cdn.net/ui/fusion.png") center / contain no-repeat;
  filter: drop-shadow(0 0 26px rgba(176, 107, 255, 0.55));
  animation: fx-fusion-spin 1.05s linear infinite;
  will-change: transform;
}
@keyframes fx-fusion-spin { to { transform: rotate(360deg); } }
.fx-ghost.fusing {
  z-index: 22; border-color: rgba(216, 160, 255, 0.85);
  box-shadow: 0 0 16px rgba(186, 120, 255, 0.75), 0 0 34px rgba(110, 255, 170, 0.35);
}
.fx-fusion-particle {
  position: absolute; z-index: 22; pointer-events: none; border-radius: 50%;
  mix-blend-mode: screen; will-change: transform, opacity;
}
.fx-fusion-particle.green {
  background: radial-gradient(circle at 40% 35%, #eafff2, #52ff9a 45%, rgba(82, 255, 154, 0) 75%);
  box-shadow: 0 0 8px rgba(110, 255, 170, 0.85);
}
.fx-fusion-particle.purple {
  background: radial-gradient(circle at 40% 35%, #f6eaff, #b06bff 45%, rgba(176, 107, 255, 0) 75%);
  box-shadow: 0 0 8px rgba(190, 130, 255, 0.85);
}
.fx-burst {
  position: absolute; z-index: 23; pointer-events: none; border-radius: 50%;
  background: radial-gradient(circle, #ffffff 0%, #e9d6ff 26%, rgba(176, 107, 255, 0.6) 48%, transparent 70%);
  mix-blend-mode: screen; will-change: transform, opacity;
}
.fx-fusion-reveal {
  position: absolute; z-index: 23; pointer-events: none; border-radius: 7px;
  background-size: cover; background-position: center;
  border: 1px solid rgba(224, 190, 255, 0.85);
  box-shadow: 0 0 30px rgba(186, 120, 255, 0.75), 0 12px 34px rgba(0, 0, 0, 0.75);
  will-change: transform, opacity, filter;
}

/* ══════════════════════════════════════════════════════════════════════════
   RITUAL — "Hexagram of Six Flames · Ascendant": círculo de invocação desenhado,
   6 chamas magenta/violeta acendendo em sentido horário, hexagrama traçado,
   convergência e a carta ERGUENDO-SE da luz. Duotom magenta→violeta (sem azul/
   laranja) p/ contrastar com a fusão. GPU-only. ═══════════════════════════ */
.fx-ritual-veil {
  position: absolute; z-index: 19; pointer-events: none; border-radius: 12px;
  background: radial-gradient(ellipse at center,
    rgba(60, 8, 60, 0) 26%, rgba(30, 4, 46, 0.60) 100%);
  mix-blend-mode: multiply; will-change: opacity;
  animation: fx-ritual-veil 1900ms ease-in-out forwards;
}
@keyframes fx-ritual-veil {
  0% { opacity: 0; } 18% { opacity: 1; } 80% { opacity: 1; } 100% { opacity: 0; }
}
.fx-ritual-circle {
  position: absolute; z-index: 20; pointer-events: none; border-radius: 50%;
  border: 2px solid rgba(199, 123, 255, 0.55);
  box-shadow: 0 0 46px rgba(176, 107, 255, 0.40), inset 0 0 70px rgba(255, 92, 224, 0.16);
  background: radial-gradient(circle, transparent 56%, rgba(138, 63, 251, 0.14) 70%, transparent 74%);
  will-change: transform, opacity;
  animation: fx-ritual-circle 1900ms cubic-bezier(0.3, 0, 0.3, 1) forwards;
}
.fx-ritual-circle::before {
  content: ''; position: absolute; inset: 13%; border-radius: 50%;
  border: 1.5px dashed rgba(255, 139, 232, 0.5);
  box-shadow: inset 0 0 22px rgba(255, 92, 224, 0.18);
  animation: fx-ritual-spin 6s linear infinite;
}
.fx-ritual-circle::after {
  content: ''; position: absolute; inset: 31%; border-radius: 50%;
  border: 1px solid rgba(199, 123, 255, 0.4);
  box-shadow: inset 0 0 26px rgba(255, 92, 224, 0.28);
}
@keyframes fx-ritual-circle {
  0%   { opacity: 0; transform: rotate(0deg) scale(0.35); }
  15%  { opacity: 1; transform: rotate(28deg) scale(1); }
  80%  { opacity: 1; transform: rotate(150deg) scale(1); }
  100% { opacity: 0; transform: rotate(196deg) scale(1.08); }
}
@keyframes fx-ritual-spin { to { transform: rotate(-360deg); } }
.fx-ritual-sweep {
  position: absolute; z-index: 21; pointer-events: none; border-radius: 50%;
  background: conic-gradient(from -95deg,
    rgba(255, 140, 230, 0)   0deg,
    rgba(255, 140, 230, 0)   300deg,
    rgba(255, 150, 235, 0.7) 344deg,
    rgba(255, 255, 255, 1)   358deg,
    rgba(255, 255, 255, 0)   360deg);
  -webkit-mask: radial-gradient(circle closest-side, transparent 84%, #000 88%, #000 98%, transparent 100%);
          mask: radial-gradient(circle closest-side, transparent 84%, #000 88%, #000 98%, transparent 100%);
  filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.9));
  animation: fx-ritual-sweep 850ms cubic-bezier(0.35, 0.1, 0.25, 1) forwards;
  will-change: transform, opacity;
}
@keyframes fx-ritual-sweep {
  0%   { transform: rotate(0deg);   opacity: 0; }
  14%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { transform: rotate(360deg); opacity: 0; }
}
.fx-ritual-flame {
  position: absolute; z-index: 22; pointer-events: none;
  border-radius: 50% 50% 48% 48% / 62% 62% 40% 40%;
  background: radial-gradient(ellipse at 50% 72%,
    #ffffff 0%, #ffb3f0 18%, #ff4fd8 42%, #b06bff 72%, rgba(138, 63, 251, 0) 100%);
  filter: drop-shadow(0 0 14px rgba(255, 79, 216, 0.85));
  transform-origin: 50% 88%; will-change: transform, opacity, filter;
}
.fx-ritual-flame::before {
  content: ''; position: absolute; inset: 22% 30% 14% 30%; border-radius: 50%;
  background: radial-gradient(circle, #fff, rgba(255, 179, 240, 0) 70%);
  animation: fx-flame-flicker 0.8s ease-in-out infinite;
}
@keyframes fx-flame-flicker {
  0%, 100% { opacity: 0.65; transform: scaleY(1); }
  50%      { opacity: 1;    transform: scaleY(1.2); }
}
.fx-ritual-line {
  position: absolute; z-index: 22; pointer-events: none; border-radius: 2px;
  background: linear-gradient(90deg,
    rgba(255, 79, 216, 0.1), #ff8be8 20%, #c77bff 80%, rgba(199, 123, 255, 0.1));
  box-shadow: 0 0 10px rgba(255, 79, 216, 0.8), 0 0 22px rgba(176, 107, 255, 0.5);
  will-change: transform, opacity;
}
.fx-ritual-mote {
  position: absolute; z-index: 23; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle at 40% 35%, #fff, #ff8be8 45%, rgba(199, 123, 255, 0) 75%);
  box-shadow: 0 0 12px rgba(255, 139, 232, 0.9); will-change: transform, opacity;
}
.fx-ritual-spark {
  position: absolute; z-index: 23; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.95), rgba(255, 139, 232, 0.7) 34%, rgba(199, 123, 255, 0) 72%);
  will-change: transform, opacity;
  animation: fx-ritual-spark 0.48s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
}
@keyframes fx-ritual-spark {
  0%   { opacity: 0;    transform: scale(0.2); }
  25%  { opacity: 0.95; }
  100% { opacity: 0;    transform: scale(1.6); }
}
.fx-ritual-core {
  position: absolute; z-index: 23; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, #fff 0%, #ffb3f0 30%, #c77bff 55%, rgba(138, 63, 251, 0) 76%);
  filter: blur(1px); will-change: transform, opacity;
  animation: fx-ritual-core 0.56s ease-out forwards;
}
@keyframes fx-ritual-core {
  0%   { opacity: 0; transform: scale(0.2); }
  40%  { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.95); }
}
.fx-ritual-burst {
  position: absolute; z-index: 22; pointer-events: none; border-radius: 50%;
  border: 3px solid rgba(255, 150, 235, 0.9);
  box-shadow: 0 0 26px rgba(255, 110, 200, 0.7), inset 0 0 24px rgba(199, 123, 255, 0.5);
  will-change: transform, opacity;
  animation: fx-ritual-burst 0.56s cubic-bezier(0.2, 0.75, 0.3, 1) forwards;
}
@keyframes fx-ritual-burst {
  0%   { opacity: 0.95; transform: scale(0.2); }
  100% { opacity: 0;    transform: scale(1.6); }
}
.fx-ritual-flash {
  position: absolute; z-index: 24; pointer-events: none; border-radius: 10px;
  background: radial-gradient(circle at 50% 55%, #fff 0%, #ffb3f0 38%, rgba(255, 79, 216, 0) 74%);
  animation: fx-flash 0.42s ease-out forwards;
}
.fx-ritual-card {
  position: absolute; z-index: 24; border-radius: 8px; pointer-events: none;
  background-size: cover; background-position: center;
  border: 1px solid rgba(255, 179, 240, 0.6);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.85), 0 0 36px rgba(255, 79, 216, 0.55);
  will-change: transform, opacity, filter;
}

.fx-chain-badge {
  position: absolute; z-index: 22; font-size: 11px; font-weight: 900; letter-spacing: 0.1em;
  color: #f3e8ff; background: rgba(124, 77, 204, 0.92); padding: 3px 10px; border-radius: 99px;
  border: 1px solid rgba(200, 160, 255, 0.7); box-shadow: 0 0 18px rgba(140, 90, 220, 0.7);
  animation: fx-num 1.1s ease-out forwards;
}
/* 1º elo = só ATIVAÇÃO (azul); vira corrente roxa quando alguém responde. */
.fx-chain-badge.activation {
  color: #eaf4ff; background: rgba(48, 118, 200, 0.92);
  border-color: rgba(150, 200, 255, 0.75); box-shadow: 0 0 18px rgba(90, 160, 240, 0.7);
}

/* Entrada de cartas recém-colocadas no board */
.bcard.anim-enter { animation: card-enter 0.45s cubic-bezier(0.2, 1.3, 0.4, 1); }
@keyframes card-enter {
  0% { opacity: 0; transform: translateY(-26px) scale(1.35); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
.bcard.def.anim-enter { animation: card-enter-def 0.45s cubic-bezier(0.2, 1.3, 0.4, 1); }
@keyframes card-enter-def {
  0% { opacity: 0; transform: rotate(-90deg) translateY(-26px) scale(1.1); }
  100% { opacity: 1; transform: rotate(-90deg) scale(0.82); }
}
.bcard.anim-flip .bface { animation: card-flip 0.5s ease-in-out; }
@keyframes card-flip {
  0% { transform: rotateY(180deg); filter: brightness(0.4); }
  100% { transform: rotateY(0deg); filter: none; }
}
.hcard.anim-draw { animation: hand-draw 0.5s cubic-bezier(0.2, 1.1, 0.4, 1) backwards; }
@keyframes hand-draw {
  0% { opacity: 0; transform: translate(60px, -40px) rotate(12deg) scale(0.7); }
  100% { opacity: 1; }
}

/* Banner de turno */
#turn-banner {
  position: absolute; left: 0; right: 0; top: 42%; z-index: 24; pointer-events: none;
  text-align: center; font-size: clamp(26px, 3.4vw, 44px); font-weight: 900;
  letter-spacing: 0.3em; color: var(--gold-bright);
  text-shadow: 0 0 30px rgba(232, 192, 100, 0.8), 0 4px 20px rgba(0, 0, 0, 0.9);
  animation: banner-sweep 1.5s cubic-bezier(0.2, 0.8, 0.3, 1) forwards;
}
/* variação para trocas de fase: menor e azul, mesma varredura */
#turn-banner.small {
  font-size: clamp(19px, 2.4vw, 30px); color: var(--accent-bright);
  text-shadow: 0 0 26px rgba(140, 190, 255, 0.8), 0 4px 18px rgba(0, 0, 0, 0.9);
  animation-duration: 1.1s;
}
@keyframes banner-sweep {
  0% { opacity: 0; transform: translateX(-60px) skewX(-8deg); }
  20% { opacity: 1; transform: translateX(0) skewX(0); }
  80% { opacity: 1; }
  100% { opacity: 0; transform: translateX(60px); }
}

/* Overlay de resultado */
#result-overlay {
  position: absolute; inset: 0; z-index: 26; display: flex; align-items: center; justify-content: center;
  background: rgba(4, 6, 10, 0.78); backdrop-filter: blur(4px); animation: fade-in 0.5s;
}
#result-card { text-align: center; animation: modal-pop 0.5s cubic-bezier(0.2, 1.3, 0.4, 1); }
#result-title {
  font-size: clamp(44px, 6vw, 76px); font-weight: 900; letter-spacing: 0.18em;
}
#result-title.win { color: var(--gold-bright); text-shadow: 0 0 50px rgba(255, 215, 94, 0.8); }
#result-title.lose { color: #7d8ea1; text-shadow: 0 0 40px rgba(60, 80, 110, 0.8); }
#result-reason { margin-top: 6px; color: var(--steel); font-size: 14px; letter-spacing: 0.1em; }
.result-actions {
  margin-top: 26px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap;
}
#btn-result-lobby, #btn-result-replay {
  border: none; clip-path: var(--cut-md); padding: 13px 34px; cursor: pointer;
  font-family: inherit;
  font-size: 15px; font-weight: 900; color: var(--abyss); text-transform: uppercase;
  letter-spacing: 0.06em;
  background: linear-gradient(180deg, #6cbcff, #2a7fd8);
  transition: transform 0.15s, filter 0.15s;
}
/* "Ver replay" é a ação secundária: mesmo peso, cor do ouro do board. */
#btn-result-replay { background: linear-gradient(180deg, var(--gold-bright), var(--gold)); }
#btn-result-lobby:hover, #btn-result-replay:hover { filter: brightness(1.1); transform: translateY(-2px); }
#btn-result-replay.hidden { display: none; }

/* Responsividade do duelo */
@media (max-width: 1280px) {
  #duel-left, #duel-right { width: 190px; }
  /* 642 = 2×190 de coluna + 2×20 de calha + 24 do root + 110 do campo fora do
     grid + 2×44 do trilho e do espelho dele. */
  :root { --zone-fit-w: calc((100vw - 642px) / 7); --zone-cap: 100px; --field-pad-x: 36px; }
  #field { padding: 12px var(--field-pad-x); }
  .zone.edge-l { transform: translateX(-18px); }
  .zone.edge-r { transform: translateX(18px); }
}
/* Em janelas estreitas a mão centralizada alcançaria o cluster de turno no
   canto — reserva uma pista à direita para os botões (a mão desloca um pouco). */
@media (max-width: 1100px) and (min-width: 821px) {
  .hand-row.me { margin-right: 190px; }
}
@media (max-width: 1024px) {
  /* Telas apertadas: ficam só os perfis (LP/avatar); inspetor e registro somem. */
  #duel-left, #duel-right { width: 154px; }
  #inspector, #log-panel { display: none; }
  /* 572 = 2 colunas (308) + padding do root (24) + 2 calhas (40) + o campo
     fora do grid (110: gaps + padding lateral + borda) + 2×44 do trilho. */
  :root { --zone-fit-w: calc((100vw - 572px) / 7); }
  #card-preview { display: none !important; }
}
@media (max-width: 820px) {
  /* Empilhado: a calha de 20px do desktop (que separa coluna e board na
     HORIZONTAL) vira altura desperdiçada aqui. */
  #duel-root { flex-direction: column; gap: 8px; height: auto; min-height: calc(100vh - 58px); overflow-y: auto; }
  body.in-duel #duel-root { height: auto; min-height: 100vh; }
  /* em telas estreitas o padding lateral encolhe ao mínimo do afastamento */
  :root { --field-pad-x: 24px; }
  #field { padding: 10px var(--field-pad-x); }
  /* Coluna única: inimigo em cima do board, jogador embaixo. */
  #duel-left, #duel-right { width: auto; flex-direction: row; align-items: stretch; }
  #duel-right { order: -1; }
  #duel-left { order: 1; }
  .duelist { flex: 0 0 auto; flex-direction: row; align-items: center; gap: 10px; padding: 8px 10px; border: none; clip-path: none; }
  .duelist > .avatar-slot { width: 46px; height: 58px; }
  .lp-names { position: static; flex-direction: row; gap: 6px; transform: none; }
  /* LP compacta ao lado do avatar: SEM diagonal nesse modo estreito */
  .lp-zone { flex: 1; margin-top: 0; padding: 6px 10px; border: none; }
  .lp-bar { min-width: 110px; height: 34px; clip-path: none; }
  .lp-area.me .lp-num, .lp-area.opp .lp-num, .lp-hint { top: 50%; }
}
/* ── Celular (≤600px): HUD ENXUTA, refeita só para telas pequenas ───────────
   Interface compacta e própria do celular — TUDO dentro deste @media, o layout
   desktop fica intacto. Sem área de avatar nem animações (também desligadas no
   JS via isMobile()): cada perfil é uma FAIXA fina só com NOME + BARRA DE VIDA.
   Cemitério e banidas se fundem numa zona (toque → modal com abas). Board mais
   enxuto: sem satélites de banidas, colunas coladas, zonas maiores. */
@media (max-width: 600px) {
  /* Avatar e painéis de perfil FORA: some tudo (avatar, #action, inspetor,
     registro). O overlay Live2D fica oculto (e nem sobe, via isMobile no JS). */
  #avatar-stage { display: none !important; }
  .duelist { display: none !important; }
  #inspector, #log-panel { display: none !important; }
  .lp-hint, .lp-zone::after { display: none; }   /* sem varredura nem costura */

  /* Cada lado vira um BLOCO do jogador: grade [ mão | botões ] em cima e a
     BARRA DE VIDA embaixo (largura toda). As mãos/controles/nome são movidos
     p/ cá pelo syncMobileLayout(); aqui só posiciono por grid-area. */
  #duel-left, #duel-right {
    display: grid; clip-path: none; overflow: visible; width: auto;
    align-content: center; gap: 9px 6px; padding: 7px;
    /* Painel LIMPO e sólido: cobre os glows/gradientes do fundo do #duel-root
       (era o "fundo estranho" atrás do jogador). */
    background: rgba(9, 13, 21, 0.82); border-radius: 14px;
  }
  #duel-left::before, #duel-right::before { display: none; }
  #duel-left {
    grid-template-columns: 1fr auto;
    grid-template-areas: "hand controls" "bar bar";
    border-top: 1px solid rgba(90, 140, 220, 0.28);   /* separa do board (você = azul) */
  }
  #duel-right {
    grid-template-columns: 1fr;
    /* ESPELHADO: vida EM CIMA (borda externa), cartas embaixo (perto do board) —
       o inverso do jogador, que tem a vida na borda de baixo. */
    grid-template-areas: "bar" "hand";
    border-bottom: 1px solid rgba(210, 90, 80, 0.28);  /* separa do board (inimigo = vermelho) */
  }

  /* Mãos (movidas p/ os blocos): cartas coladas à ESQUERDA. A altura continua
     RESERVADA (mesma regra do desktop), só que na medida do celular. */
  #my-hand-row, #opp-hand-row { grid-area: hand; min-width: 0; }
  .hand-row { justify-content: flex-start; padding: 0; }
  .hand-row.me { padding: 0; height: var(--hand-card-h); }
  .hand-row.opp { padding: 0; height: var(--ohand-card-h); }

  /* Botões de interação à DIREITA, empilhados (movidos p/ dentro do bloco). */
  #turn-controls {
    grid-area: controls; position: static; right: auto; bottom: auto;
    flex-direction: column; align-items: flex-end; justify-content: center; gap: 5px;
  }

  /* ── BARRA DE VIDA simples: número numa ponta, NOME na ponta oposta, sobre o
     fill colorido. Reaproveita todo o fill/número/cor já animados. */
  .lp-zone { grid-area: bar; margin-top: 0; padding: 0; border: none; }
  .lp-area { position: relative; display: block; width: 100%; }
  .lp-bar {
    width: 100%; height: 30px; clip-path: none; border-radius: 6px;
    border: 1px solid rgba(120, 160, 210, 0.3);
  }
  .lp-num {
    font-size: 18px; top: 50%; transform: translateY(-50%);
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
  }
  .lp-area.me  .lp-num { left: 10px;  right: auto; }
  .lp-area.opp .lp-num { right: 10px; left: auto; }
  /* NOME dentro da barra, no canto OPOSTO ao número. */
  .lp-area .plate-name {
    position: absolute; top: 50%; transform: translateY(-50%); margin: 0;
    max-width: 46%; font-size: 11px; font-weight: 800; letter-spacing: 0.04em;
    color: rgba(255, 255, 255, 0.82); text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; pointer-events: none;
  }
  .lp-area.me  .plate-name { right: 10px; left: auto; text-align: right; }
  .lp-area.opp .plate-name { left: 10px;  right: auto; text-align: left; }
  /* Barra do OPONENTE = a MESMA do jogador, só que ESPELHADA. O desktop enchia
     pelo lado de fora via flex-end + scaleX no fill (feito p/ a barra diagonal);
     no celular isso não casa. Aqui volto a barra ao mesmo mecanismo do jogador
     (fill preenchendo da esquerda, em bloco) e espelho a BARRA INTEIRA — o
     número e o nome ficam fora da barra, então não invertem. */
  .lp-area.opp .lp-bar { display: block; transform: scaleX(-1); clip-path: none; }
  .lp-area.opp .lp-fill { transform: none; }

  /* ── BOARD ENXUTO: sem folga lateral, colunas coladas (sem espalhamento),
     zonas um pouco maiores. Aqui a largura da zona é ditada só pela tela — a
     conta de encaixe do desktop não vale, o board é a tela inteira. */
  :root {
    --zone-w: clamp(26px, calc((100vw - 40px) / 7), 52px);
    --zone-h: clamp(46px, calc(var(--zone-w) * 1.42), 86px);
    --field-pad-x: 6px;
    --rail-w: 0px;          /* o trilho deita: não ocupa lateral nenhuma */
    /* Cartas da mão menores: a altura reservada da fileira acompanha sozinha
       (ela é derivada destes tokens). */
    --hand-card-w: clamp(44px, 13vw, 64px);
    --ohand-card-w: clamp(30px, 9vw, 46px);
  }
  #field { padding: 8px var(--field-pad-x); gap: 4px; min-width: 0; }
  .field-side { gap: 4px; }
  /* coladas — sem "spread" 3D */
  .zone.edge-l, .zone.edge-r { transform: none; }
  .zone .zlabel { font-size: 7.5px; letter-spacing: 0.04em; }
  .zone .count-badge { font-size: 12px; inset: 3px; }

  /* Placa da carta = UM valor só, conforme a posição: em ATAQUE mostra o ATK,
     em DEFESA (.def) mostra o DEF. Os dois <i> continuam no DOM (o JS de batalha
     atualiza ambos) — só escondo o irrelevante, e junto com ele a barra: numa
     zona de 26px não cabe "1200/800". */
  .bcard:not(.def) .bstats i.d, .bcard.def .bstats i.a, .bcard .bstats b { display: none; }

  #field-divider { height: 20px; }
  /* O trilho de fases DEITA: no celular uma coluna de 44px comeria um oitavo da
     tela. Ele desce para baixo do board e vira faixa, colado na borda de baixo
     (por isso some a borda de cima, e não a da esquerda).
     O cursor deslizante fica de fora — ele anda no eixo Y, e virar isso pediria
     um segundo caminho no JS para um gesto que num toque ninguém acompanha. Na
     faixa, quem acende é o próprio degrau. */
  #board3d { flex-direction: column; }
  #phase-rail {
    flex-direction: row; width: auto; align-self: stretch;
    border: 1px solid var(--edge); border-top: none;
  }
  #phase-rail span { flex: 1; height: 20px; font-size: 8.5px; letter-spacing: 0.04em; }
  #phase-rail span + span { border-top: none; border-left: 1px solid var(--hair); }
  /* Na faixa deitada o bloco do turno vira mais um degrau: só o número, sem a
     palavra na vertical (que aqui ficaria atravessada). */
  #phase-rail #turn-chip { height: 20px; padding: 0; }
  #turn-word { display: none; }
  #turn-num { font-size: 12px; }
  #phase-cursor { display: none; }
  #phase-rail span[data-ph].on {
    background: linear-gradient(180deg, var(--accent-bright), #3f87d8);
  }
  /* Contadores compactos no celular (divisor fino). */
  #timer-track { left: 4px; gap: 4px; }
  .timer-chip { padding: 2px 6px 2px 2px; gap: 3px; }
  .tc-art { width: 18px; height: 18px; }
  .tc-clock i { font-size: 12px; }
  .tc-clock b { font-size: 11px; }

  /* Mão: cartas menores; a folga entre elas encolhe junto. */
  .hand-row { gap: 2px; }
  /* Mesma conta da regra grande, com o destaque menor (1,18 → metade = 0,09). */
  .hand-row.me .hcard:hover {
    width: calc(var(--hand-card-w) * 1.18);
    margin-inline: calc(var(--hand-card-w) * -0.09);
    transform: translateY(calc(var(--hand-card-h) * 0.09 - 14px)) !important;
  }

  /* Botões de interação compactos (o posicionamento à direita da mão está na
     seção de perfil, via grid-area). */
  #btn-end-turn { padding: 7px 12px; font-size: 10px; }
  #btn-next-phase { padding: 6px 10px; font-size: 9.5px; }
  #turn-status { padding: 4px 9px; font-size: 9px; }
  /* "Detalhes" aparece quando há carta selecionada (JS tira o .hidden). */
  #btn-details:not(.hidden) {
    display: inline-flex; align-items: center; gap: 5px;
    border: 1px solid rgba(120, 180, 255, 0.5); border-radius: 6px;
    background: rgba(16, 30, 50, 0.94); color: var(--accent-bright);
    font-size: 10px; font-weight: 800; padding: 6px 11px; white-space: nowrap;
  }
  #btn-details:not(.hidden):active { transform: scale(0.96); }

  /* Telas/overlays que moravam no #board-wrap cobririam só o board agora (as
     mãos saíram): fixam na viewport p/ cobrir tudo. */
  #result-overlay, #turn-banner { position: fixed; }

  /* Modais/pickers com folga vertical (o conteúdo rola se precisar). */
  #modal, #prompt-card { max-height: 90vh; }
  #pick-bar { max-width: 96vw; }
}

/* ── Modal de PILHAS (celular): abas Cemitério / Banidas + grade de cartas ────
   As duas pilhas ocupam a mesma zona no board; aqui o jogador alterna entre
   elas. Fica oculto (.hidden) fora do celular. */
#piles-modal {
  position: fixed; inset: 0; z-index: 42; padding: 16px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(2, 4, 8, 0.72); backdrop-filter: blur(3px);
  animation: fade-in 0.15s ease-out;
}
#piles-card {
  position: relative; width: 460px; max-width: 94vw; max-height: 86vh;
  display: flex; flex-direction: column; gap: 10px; padding: 16px;
  background: rgba(120, 180, 255, 0.4); clip-path: var(--cut-md);
  filter: drop-shadow(0 30px 70px rgba(0, 0, 0, 0.85));
  animation: modal-pop 0.22s cubic-bezier(0.2, 1.3, 0.4, 1);
}
#piles-card::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-md);
  background: rgba(15, 21, 33, 0.97); pointer-events: none;
}
#piles-title { color: var(--accent-bright); font-size: 15px; font-weight: 800; letter-spacing: 0.02em; }
#piles-tabs { display: flex; gap: 8px; }
#piles-tabs button {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  border: 1px solid rgba(120, 160, 210, 0.28); background: rgba(255, 255, 255, 0.04);
  color: var(--steel); font-size: 12px; font-weight: 800; letter-spacing: 0.03em;
  padding: 8px 10px; border-radius: 7px; cursor: pointer; transition: background 0.14s, color 0.14s, border-color 0.14s;
}
#piles-tabs button i { font-size: 15px; }
#piles-tabs button b { color: #eaf3ff; font-variant-numeric: tabular-nums; }
#piles-tabs button:hover { background: rgba(56, 120, 198, 0.16); color: #dbe7f5; }
#piles-tab-grave.on {
  background: rgba(56, 120, 198, 0.28); border-color: rgba(100, 160, 230, 0.6); color: var(--accent-bright);
}
#piles-tab-banish.on {
  background: rgba(150, 60, 50, 0.28); border-color: rgba(230, 120, 105, 0.6); color: #ffb3a3;
}
#piles-grid {
  flex: 1; min-height: 0; overflow-y: auto; padding: 4px 2px;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(62px, 1fr)); gap: 8px;
  align-content: start;
}
.piles-cell { position: relative; aspect-ratio: 59 / 86; }
.piles-cell img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  border-radius: 6px; border: 1px solid rgba(255, 255, 255, 0.18);
  box-shadow: 0 4px 12px -3px rgba(0, 0, 0, 0.7);
}
.piles-empty {
  grid-column: 1 / -1; text-align: center; color: rgba(150, 175, 205, 0.5);
  font-size: 13px; font-weight: 600; padding: 34px 0;
}
#piles-close {
  border: none; clip-path: var(--cut-sm); padding: 10px; font-weight: 800; font-size: 13px;
  cursor: pointer; color: #e2e8f0; background: rgba(255, 255, 255, 0.08);
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
}
#piles-close:hover { background: rgba(255, 255, 255, 0.14); }

/* ── Modal de DETALHES da carta (celular): imagem + nome/tipo/stats + efeito ──
   Aberto pelo botão "Detalhes" (o inspetor lateral fica oculto no mobile). */
#card-modal {
  position: fixed; inset: 0; z-index: 43; padding: 16px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(2, 4, 8, 0.72); backdrop-filter: blur(3px);
  animation: fade-in 0.15s ease-out;
}
#cm-card {
  position: relative; width: 440px; max-width: 94vw; max-height: 88vh;
  display: flex; flex-direction: column; gap: 11px; padding: 16px;
  background: rgba(120, 180, 255, 0.4); clip-path: var(--cut-md);
  filter: drop-shadow(0 30px 70px rgba(0, 0, 0, 0.85));
  animation: modal-pop 0.22s cubic-bezier(0.2, 1.3, 0.4, 1);
}
#cm-card::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-md);
  background: rgba(15, 21, 33, 0.98); pointer-events: none;
}
#cm-top { display: flex; gap: 12px; align-items: flex-start; }
#cm-art {
  position: relative; display: block; flex: 0 0 auto; width: 40%; max-width: 148px;
  border-radius: 8px; box-shadow: 0 12px 30px rgba(0, 0, 0, 0.7);
}
#cm-img { display: block; width: 100%; border-radius: 8px; }
#cm-head { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
#cm-name { font-weight: 800; font-size: 15px; line-height: 1.22; color: var(--accent-bright); }
#cm-type { font-size: 10.5px; font-weight: 800; letter-spacing: 0.05em; text-transform: uppercase; color: var(--steel); }
#cm-head.kind-monster #cm-type { color: #ffd9a8; }
#cm-head.kind-spell #cm-type { color: #a8f0d8; }
#cm-head.kind-trap #cm-type { color: #f3c2e4; }
#cm-stats { display: flex; flex-direction: column; gap: 5px; margin-top: 3px; }
#cm-text {
  overflow-y: auto; font-size: 12px; line-height: 1.6; color: #d5dde5; white-space: pre-wrap;
  background: rgba(3, 6, 12, 0.72); border: 1px solid var(--line); border-radius: 7px; padding: 10px 12px;
}
#cm-text:empty { display: none; }
#cm-close {
  border: none; clip-path: var(--cut-sm); padding: 10px; font-weight: 800; font-size: 13px;
  cursor: pointer; color: #e2e8f0; background: rgba(255, 255, 255, 0.08);
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
}
#cm-close:hover { background: rgba(255, 255, 255, 0.14); }

/* ══════════════════════════════════════════════════════════════════════════
   DUEL ACADEMY — telas fora do duelo (login + home): parallax, navbar, UI kit
   chanfrado e loading. Reusa os MESMOS tokens do board (--cut-sm/-md/--slant +
   truque de borda `elemento clip-path` + `::before inset:1px`) p/ consistência.
   ══════════════════════════════════════════════════════════════════════════ */
:root {
  /* Céu do parallax: azul claro no topo com leve degradê descendo. */
  --sky-top: #cfecff;
  --sky-mid: #a9d6f5;
  --sky-bottom: #7cb4e6;
}

/* ── Parallax (fundo de login + home) ──────────────────────────────────────
   Fixo atrás de tudo; só aparece em body.scene-parallax. As 5 PNGs (cena da
   Academia) empilham sobre um degradê azul-claro; o centro aberto das camadas
   deixa o céu aparecer. Camadas ligeiramente maiores que a viewport p/ o
   mouse-parallax nunca revelar as bordas. */
#parallax {
  position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none;
  display: none;
  /* Céu: #2c8df7 no topo, clareando até a metade, depois preto. */
  background: linear-gradient(180deg,
    #2c8df7 0%, #66b0fa 26%, #bfe2ff 46%, #060810 55%, #000 100%);
}
body.scene-parallax #parallax { display: block; }
body.scene-parallax #bg-aura { display: none; }
/* No login a cena ganha um véu escuro (vignette) p/ casar com a UI preta;
   na home (lobby) o parallax segue claro. */
#parallax::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: 0;
  transition: opacity 0.4s ease;
  background: radial-gradient(120% 85% at 50% 22%, transparent 55%, rgba(3, 5, 9, 0.30) 100%),
    linear-gradient(180deg, rgba(4, 6, 10, 0.06), rgba(2, 3, 6, 0.20));
}
body.on-auth #parallax::after { opacity: 1; }
.plx-layer {
  position: absolute; inset: -7%;
  background-repeat: no-repeat; background-position: center bottom; background-size: cover;
  will-change: transform;
  transform: translate3d(0, 0, 0);
  transition: transform 0.5s cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* Camadas do menu (fundo → frente): recebem o parallax do mouse (via JS). */
.plx-back      { background-image: url("https://yugiohonline.b-cdn.net/backgrounds/parallax/menu/back.png"); }
.plx-buildings { background-image: url("https://yugiohonline.b-cdn.net/backgrounds/parallax/menu/buildings.png"); }
.plx-front     { background-image: url("https://yugiohonline.b-cdn.net/backgrounds/parallax/menu/front.png"); }

/* Nuvens (transparente): camada PRÓPRIA, isolada do parallax — NÃO é .plx-layer,
   então não pega o transform do mouse nem a transition dele (por isso a animação
   nunca "trava" ao mexer o mouse). Composição na GPU (will-change + translateZ).
   Deslizam p/ esquerda e depois direita, em loop suave; o degradê aparece atrás. */
.plx-clouds {
  position: absolute; inset: -7%; z-index: 0; pointer-events: none;
  background: url("https://yugiohonline.b-cdn.net/backgrounds/parallax/menu/clouds.png") center bottom / cover no-repeat;
  will-change: transform; transform: translateZ(0);
  animation: sky-drift 26s ease-in-out infinite alternate;
}
@keyframes sky-drift {
  from { transform: translate3d(-4%, 0, 0); }
  to   { transform: translate3d(4%, 0, 0); }
}
@media (prefers-reduced-motion: reduce) { .plx-clouds { animation: none !important; } }
/* Toque (sem mouse): deriva lateral lenta nas 3 camadas (nuvens seguem o sky-drift). */
@media (hover: none) {
  .plx-back, .plx-buildings, .plx-front { animation: plx-drift 26s ease-in-out infinite alternate; }
  .plx-buildings { animation-duration: 22s; }
  .plx-front { animation-duration: 18s; }
}
@keyframes plx-drift {
  from { transform: translate3d(-1.1%, 0, 0); }
  to   { transform: translate3d(1.1%, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .plx-layer { animation: none !important; transition: none !important; transform: none !important; }
}

/* ── Fundo fixo do login (academy_map) ──────────────────────────────────────
   Substitui o parallax na tela de entrada: arte fixa da Academia sob o form.
   Só aparece em body.scene-academy. O ::after é um véu escuro (vignette) p/ dar
   contraste ao form preto sobre a arte clara — centro-topo mais limpo, bordas
   mais escuras. */
#academy-bg {
  position: fixed; inset: 0; z-index: 0; display: none; pointer-events: none;
  background: #0a0e14 url("https://yugiohonline.b-cdn.net/backgrounds/academy/academy_map.png") center / cover no-repeat;
}
#academy-bg::after {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(120% 92% at 50% 30%, transparent 42%, rgba(3, 5, 9, 0.58) 100%),
    linear-gradient(180deg, rgba(4, 6, 11, 0.30), rgba(2, 3, 7, 0.55));
}
body.scene-academy #academy-bg { display: block; }
body.scene-academy #bg-aura { display: none; }

/* ── Fundo fixo da home (front_academy por período do dia) ──────────────────
   Substitui o parallax na home: a fachada da Academia troca por horário do jogo
   (manhã/tarde/noite) via classe .phase-* — definida pelo relógio do jogo (JS).
   Só aparece em body.scene-lobby; o ::after é um véu escuro p/ os painéis. */
#lobby-bg {
  position: fixed; inset: 0; z-index: 0; display: none; pointer-events: none;
  background: #0a0e14; /* fallback atrás das duas camadas */
}
/* Duas camadas empilhadas: a visível fica em opacity 1, a oculta em 0. Na troca
   de período o JS pinta a fachada nova na oculta e cruza as opacidades — um
   dissolve suave (crossfade) no lugar do corte seco. */
#lobby-bg .lb-layer {
  position: absolute; inset: 0; opacity: 0;
  background: center / cover no-repeat;
  transition: opacity 1.5s ease;
  will-change: opacity;
}
#lobby-bg::after { /* véu por cima das duas camadas, p/ contraste dos painéis */
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(4, 6, 11, 0.32), rgba(2, 3, 7, 0.58));
}
body.scene-lobby #lobby-bg { display: block; }
body.scene-lobby #bg-aura { display: none; }
@media (prefers-reduced-motion: reduce) { #lobby-bg .lb-layer { transition: none; } }

/* ══════════════════════════════════════════════════════════════════════════
   LOJA DE BOOSTERS — sobre o parallax da Academia (mesmo padrão do login/home),
   com painéis chanfrados pretos translúcidos. 3 colunas: lista de cartas do
   pacote (esq.) · carta grande + specs + barra de compra (centro) · pacotes 5/
   linha (dir.).  Painéis reusam .ui-panel (clip-path chanfrado + ::before fill).
   ══════════════════════════════════════════════════════════════════════════ */
/* Fundo fixo da loja (shop.jpg) sob os painéis; só aparece em body.scene-shop.
   O ::after é um véu escuro p/ dar contraste aos painéis sobre a arte clara. */
#shop-bg {
  position: fixed; inset: 0; z-index: 0; display: none; pointer-events: none;
  background: #0a0e14 url("https://yugiohonline.b-cdn.net/backgrounds/shop/shop.jpg") center / cover no-repeat;
}
#shop-bg::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(4, 6, 11, 0.42), rgba(2, 3, 7, 0.62));
}
body.scene-shop #shop-bg { display: block; }
body.scene-shop #bg-aura { display: none; }
/* Painéis PRETOS translúcidos (mesmo padrão do login/home) — borda cinza (sem
   azul) + preenchimento quase preto. */
#screen-shop .ui-panel { background: rgba(150, 160, 175, 0.18); filter: drop-shadow(0 14px 30px rgba(0, 0, 0, 0.4)); }
#screen-shop .ui-panel::before { background: linear-gradient(165deg, rgba(16, 18, 23, 0.92), rgba(7, 9, 13, 0.9)); backdrop-filter: blur(9px); }

/* A loja ocupa exatamente a altura da viewport (sem rolagem de página); o que
   rola é o INTERIOR de cada painel. */
.shop-stage {
  position: relative; z-index: 2;
  height: calc(100vh - 66px); overflow: hidden;
  display: flex; flex-direction: column;
  padding: 16px clamp(16px, 3vw, 40px) clamp(14px, 3vh, 30px);
}
.shop-bar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.shop-bar h2 {
  display: flex; align-items: center; gap: 9px;
  font-size: 21px; font-weight: 800; letter-spacing: 0.04em; color: #eef4fc;
  text-shadow: 0 2px 16px rgba(0, 0, 0, 0.85);
}
.shop-bar h2 .accent { color: var(--accent-bright); }
.shop-back {
  position: relative; border: none; clip-path: var(--cut-sm); cursor: pointer;
  padding: 9px 16px; font-family: inherit; font-size: 13px; font-weight: 800; color: #dbe7f5;
  background: rgba(120, 180, 255, 0.4); isolation: isolate;
  display: inline-flex; align-items: center; gap: 6px; transition: filter 0.15s, transform 0.1s;
}
.shop-back::before { content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm); background: rgba(20, 27, 38, 0.9); }
.shop-back:hover { filter: brightness(1.2); }
.shop-back:active { transform: scale(0.95); }

.shop-body {
  flex: 1; display: flex; gap: 18px; align-items: stretch; min-height: 0;
  width: min(100%, 1600px); margin: clamp(8px, 3vh, 34px) auto 0;
}
/* Os painéis usam a classe .ui-panel (mesmo chanfro/preenchimento do login/home).
   Aqui vão só o layout de cada coluna; garanto que o conteúdo fique acima do
   ::before (que é z-index:-1 no .ui-panel). */
.shop-cardlist > *, .shop-detail > *, .shop-buybar > *, .shop-packs > * { position: relative; }

/* Esquerda+meio empilham a barra de compra embaixo; à direita, os boosters. */
.shop-main { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: 14px; }
.shop-main-top { flex: 1; min-height: 0; display: flex; gap: 18px; align-items: stretch; }

/* ── Meio: lista de cartas do pacote (rola por dentro) ─────────────────────── */
.shop-cardlist {
  flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; padding: 14px 12px;
}
.cl-head {
  display: flex; align-items: center; gap: 6px; margin-bottom: 10px;
  font-size: 11px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--steel);
}
.cl-head span { color: #cdd7e3; }
/* Barra de progresso de depleção — CHANFRADA (estilo HUD, canto sup-esq/inf-dir),
   sutil, preenche da esquerda p/ a direita. Fica embaixo de toda a barra de compra. */
.bb-progress {
  position: relative; height: 10px; width: 100%;
  clip-path: polygon(5px 0, 100% 0, 100% calc(100% - 5px), calc(100% - 5px) 100%, 0 100%, 0 5px);
  background: rgba(159, 180, 200, 0.12);
}
.bb-progress.hidden { display: none; }
.bb-progress-fill {
  height: 100%; width: 0;
  background: linear-gradient(90deg, #2e93d8, #38bdf8 55%, #7fe3ff);
  box-shadow: 0 0 10px -2px rgba(56, 189, 248, 0.5);
  transition: width 0.4s cubic-bezier(0.4, 0.9, 0.3, 1);
}
.bb-progress.is-done .bb-progress-fill {
  background: linear-gradient(90deg, #22b57a, #34d399 55%, #7bf0c0);
  box-shadow: 0 0 10px -2px rgba(52, 211, 153, 0.5);
}
.cl-cards {
  flex: 1; min-height: 0; overflow-y: auto; padding: 18px 2px 2px;   /* headroom p/ o badge acima */
  display: grid; grid-template-columns: repeat(auto-fill, minmax(86px, 1fr)); gap: 20px 8px; align-content: start;
}
.cl-thumb {
  position: relative; padding: 0; border: 2px solid transparent; border-radius: 4px; background: none; cursor: pointer;
  line-height: 0; transition: transform 0.12s, border-color 0.12s;
}
.cl-thumb img { width: 100%; display: block; border-radius: 3px; }
.cl-thumb:hover { transform: translateY(-2px); border-color: rgba(120, 180, 255, 0.5); }
.cl-thumb.sel { border-color: var(--accent-bright); }
/* O brilho da seleção vai num ::before ACIMA do badge (z-index 7 > 6) — assim o
   badge fica "atrás" do brilho e não o corta no canto de cima. */
.cl-thumb.sel::before {
  content: ''; position: absolute; inset: -2px; z-index: 7; border-radius: 4px; pointer-events: none;
  box-shadow: 0 0 10px -2px rgba(89, 167, 240, 0.7);
}

/* ══════════ Badge de RARIDADE no topo-direito de cada carta ══════════
   Compartilhado pela loja (.cl-thumb) e pelo montador (.de-card). Chip chanfrado
   (cortado na diagonal, esq→dir via clip-path); a raridade vem da classe r-* que
   as duas telas já aplicam — 100% CSS, sem tocar em JS. */
.cl-thumb::after, .de-card::after, .olog-card::after {
  content: '';
  /* FORA da imagem, encostado no topo: bottom:100% + margin-bottom = largura da
     BORDA (2px) deixa o rodapé do badge na borda EXTERNA de cima, sem cobrir a
     borda da carta (o container é relativo à caixa de padding, dentro da borda). */
  position: absolute; bottom: 100%; right: 3px; margin-bottom: 2px; z-index: 6; pointer-events: none;
  box-sizing: border-box; width: 28px; height: 15px;   /* TAMANHO FIXO nas 4 raridades */
  /* padding-left compensa o recorte diagonal (centro visual ~57%) → texto no centro. */
  display: flex; align-items: center; justify-content: center; padding-left: 4px;
  font-family: "Cabin", "Segoe UI", system-ui, sans-serif; font-size: 9px; font-weight: 900; letter-spacing: 0.02em;
  line-height: 1; color: #fff; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.55);
  clip-path: polygon(30% 0, 100% 0, 100% 100%, 0 100%);
  box-shadow: -1px 1px 3px rgba(0, 0, 0, 0.45);
}
/* Deck (coluna do MEIO): muitas cartas por linha → badge um pouco menor, na
   proporção. (O histórico Open Boosters usa o badge FLUTUANTE igual aos outros.) */
.de-card--deck::after { width: 24px; height: 13px; font-size: 8px; padding-left: 3px; }
.olog-card::after { margin-bottom: 1px; }   /* borda do olog é 1px */
.cl-thumb.r-COMMON::after, .de-card.r-COMMON::after, .olog-card.r-COMMON::after { content: 'N';  background: linear-gradient(135deg, #9aa7b5, #566470); }
.cl-thumb.r-RARE::after,   .de-card.r-RARE::after,   .olog-card.r-RARE::after   { content: 'R';  background: linear-gradient(135deg, #63b2f8, #2464c8); }
.cl-thumb.r-SUPER::after,  .de-card.r-SUPER::after,  .olog-card.r-SUPER::after  { content: 'SR'; background: linear-gradient(135deg, #ff9a4d, #e0431f); }
.cl-thumb.r-ULTRA::after,  .de-card.r-ULTRA::after,  .olog-card.r-ULTRA::after  {
  content: 'UR';
  background: linear-gradient(125deg, #c07bff 0%, #7b8cff 38%, #5aa8ff 62%, #ff85cc 100%);
}

/* Mesmo badge, MAIOR, na carta em DESTAQUE (painel de detalhe da loja e do
   montador). O container abraça a arte p/ o badge cair no topo-direito dela; a
   raridade vem da classe r-* do corpo do detalhe (sd-body / de-detail-body). */
.sd-art { position: relative; flex: none; width: fit-content; max-width: 100%; margin: 0 auto; }
.de-art { position: relative; width: 60%; margin: 0 auto; }
.sd-art::after, .de-art::after {
  content: ''; position: absolute; bottom: 100%; right: 4px; margin-bottom: 1px; z-index: 6; pointer-events: none;
  box-sizing: border-box; width: 40px; height: 20px;   /* TAMANHO FIXO nas 4 raridades */
  display: flex; align-items: center; justify-content: center; padding-left: 6px;   /* compensa o recorte diagonal */
  font-family: "Cabin", "Segoe UI", system-ui, sans-serif; font-size: 12px; font-weight: 900; letter-spacing: 0.03em;
  line-height: 1; color: #fff; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.55);
  clip-path: polygon(30% 0, 100% 0, 100% 100%, 0 100%);
  box-shadow: -1px 1px 4px rgba(0, 0, 0, 0.5);
}
.sd-body.r-COMMON .sd-art::after, .de-detail-body.r-COMMON .de-art::after { content: 'N';  background: linear-gradient(135deg, #9aa7b5, #566470); }
.sd-body.r-RARE .sd-art::after,   .de-detail-body.r-RARE .de-art::after   { content: 'R';  background: linear-gradient(135deg, #63b2f8, #2464c8); }
.sd-body.r-SUPER .sd-art::after,  .de-detail-body.r-SUPER .de-art::after  { content: 'SR'; background: linear-gradient(135deg, #ff9a4d, #e0431f); }
.sd-body.r-ULTRA .sd-art::after,  .de-detail-body.r-ULTRA .de-art::after  { content: 'UR'; background: linear-gradient(125deg, #c07bff 0%, #7b8cff 38%, #5aa8ff 62%, #ff85cc 100%); }

/* ── Esquerda: informações da carta selecionada (largura fixa) ───────────── */
.shop-detail { flex: none; width: 320px; min-height: 0; padding: 24px 16px 16px; display: flex; }
.sd-empty {
  margin: auto; display: flex; flex-direction: column; align-items: center; gap: 12px;
  text-align: center; color: var(--steel); font-size: 14px; line-height: 1.5;
}
.sd-empty i { font-size: 42px; opacity: 0.55; }
.sd-body { flex: 1; min-height: 0; width: 100%; display: flex; flex-direction: column; gap: 12px; align-items: center; animation: fade-in 0.25s ease-out; }
#sd-img {
  display: block; width: auto; max-width: 100%; max-height: 33vh; height: auto; border-radius: 6px;
  filter: drop-shadow(0 14px 26px rgba(0, 0, 0, 0.6));
}
.sd-info {
  flex: 1; min-height: 0; width: 100%; overflow-y: auto; padding-right: 4px;
  display: flex; flex-direction: column; gap: 10px;
}
.sd-head { border-left: 3px solid var(--accent); padding-left: 11px; }
.sd-head.kind-monster { border-color: #f0b060; }
.sd-head.kind-spell { border-color: #3fc79a; }
.sd-head.kind-trap { border-color: #d06fbf; }
.sd-name { font-size: 18px; font-weight: 800; color: #eef4fc; line-height: 1.22; }
.sd-type { margin-top: 3px; font-size: 12.5px; font-weight: 700; color: var(--steel); }
.sd-stats { display: flex; flex-wrap: wrap; gap: 6px; }
/* Só tamanho/tipografia: a moldura chanfrada vem da regra base de .insp-stat. */
.sd-stats .insp-stat {
  display: inline-flex; align-items: center; gap: 5px; padding: 4px 9px;
  font-size: 12.5px; font-weight: 700; color: #dbe7f5;
}
.sd-stats .insp-stat-ic { width: 15px; height: 15px; object-fit: contain; }
.sd-stats .insp-stat-k { color: var(--steel); font-size: 10.5px; letter-spacing: 0.04em; }
.sd-text {
  font-size: 12.5px; line-height: 1.55; color: #cbd6e2; white-space: pre-wrap;
  border-top: 1px solid var(--line); padding-top: 10px;
}

/* Barra de compra HORIZONTAL (cobre esquerda+meio): preço · progresso · qtd · botão. */
/* Barra de compra: linha 1 (nome · cartas · qtd · comprar) + barra de progresso embaixo. */
.shop-buybar { flex: none; display: flex; flex-direction: column; gap: 12px; padding: 13px 20px 15px; }
.bb-top { display: flex; align-items: center; gap: 18px; }
.bb-pack { flex: none; min-width: 0; max-width: 260px; display: flex; flex-direction: column; gap: 2px; }
.bb-name { font-size: 18px; font-weight: 800; color: #eef4fc; letter-spacing: 0.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Descrição do booster: 2ª linha pequena e discreta sob o nome; some se vazia. */
.bb-desc { font-size: 11px; font-weight: 500; color: var(--steel); opacity: 0.7; letter-spacing: 0.01em; line-height: 1.25; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.bb-desc:empty { display: none; }
.bb-unit { flex: none; font-size: 12px; font-weight: 700; color: var(--gold-bright); display: inline-flex; align-items: center; gap: 4px; }
/* Cartas obtidas / total pra zerar (ex.: 117/298). */
.bb-cards { flex: none; display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 700; color: var(--steel); }
.bb-cards.hidden { display: none; }
.bb-cards i { color: var(--accent-bright); font-size: 15px; }
.bb-cards b { color: #dbe7f5; font-variant-numeric: tabular-nums; font-size: 14px; }
/* Grupo à DIREITA: custo total · quantidade (−/+) · comprar. */
.bb-controls { margin-left: auto; display: flex; align-items: center; gap: 14px; }
.bb-total { display: inline-flex; align-items: center; gap: 5px; font-size: 16px; font-weight: 800; color: var(--gold-bright); }
.bb-total.hidden { display: none; }
.bb-total b { font-variant-numeric: tabular-nums; }
.qty-stepper { display: inline-flex; align-items: center; justify-content: center; gap: 8px; }
.qty-btn {
  width: 34px; height: 34px; padding: 0; border: 1px solid var(--line); border-radius: 9px;
  font-size: 20px; line-height: 1; color: #e2e8f0; background: rgba(255, 255, 255, 0.06); cursor: pointer;
  transition: background 0.12s, transform 0.1s;
}
.qty-btn:hover:not(:disabled) { background: rgba(255, 255, 255, 0.12); }
.qty-btn:active:not(:disabled) { transform: scale(0.9); }
.qty-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.qty-val { min-width: 30px; text-align: center; font-size: 18px; font-weight: 800; color: var(--accent-bright); font-variant-numeric: tabular-nums; }
.qty-stepper.hidden { display: none; }
.bb-buy {
  flex: none; width: auto; min-width: 200px; position: relative; border: none; clip-path: var(--cut-sm); cursor: pointer; isolation: isolate;
  padding: 13px 22px; font-family: inherit; font-weight: 800; font-size: 14px; color: #06231a;
  background: linear-gradient(180deg, #4fe08b, #16a35a);
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; transition: filter 0.15s, transform 0.1s;
}
.bb-buy b { min-width: 1.4em; text-align: left; font-variant-numeric: tabular-nums; }
.bb-buy b.hidden { display: none; }
.bb-buy:hover:not(:disabled) { filter: brightness(1.1); }
.bb-buy:active:not(:disabled) { transform: scale(0.97); }
.bb-buy:disabled { filter: grayscale(0.5) brightness(0.7); cursor: not-allowed; }
.bb-buy.processing { opacity: 0.75; cursor: progress; }
/* Estado RESETAR (pacote zerado): âmbar em vez de verde. */
.bb-buy.is-reset { background: linear-gradient(180deg, #fbbf24, #f59e0b); color: #041016; }

/* ── Direita: grade de pacotes (menor que antes) ──────────────────────────── */
.shop-packs {
  flex: none; width: clamp(360px, 32vw, 480px); min-width: 0; min-height: 0;
  display: flex; flex-direction: column; padding: 16px;
}
/* Abas + busca SEMPRE acima da grade — evita que um booster (hover/transform)
   roube o clique destinado à busca ou às abas quando a lista está rolável. */
.packs-tabs, .pack-search { position: relative; z-index: 3; }
.pack-grid { z-index: 1; }
/* Abas Boosters / Open Boosters. */
.packs-tabs { display: flex; gap: 6px; margin-bottom: 12px; }
.packs-tab {
  flex: 1; border: 1px solid var(--line); border-radius: 9px; padding: 8px 10px; cursor: pointer;
  font-family: inherit; font-size: 12px; font-weight: 800; letter-spacing: 0.03em; color: var(--steel);
  background: rgba(255, 255, 255, 0.04); display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  transition: color 0.14s, background 0.14s, border-color 0.14s;
}
.packs-tab:hover { color: #e2e8f0; }
.packs-tab.is-on { color: var(--abyss); background: var(--accent); border-color: var(--accent); }
/* Busca: por nome do booster OU carta que ele contém. */
.pack-search {
  position: relative; display: flex; align-items: center; margin-bottom: 12px;
}
.pack-search-ico {
  position: absolute; left: 11px; color: var(--steel); font-size: 15px; pointer-events: none;
}
.pack-search-input {
  flex: 1; min-width: 0; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: 9px; background: rgba(255, 255, 255, 0.04);
  padding: 9px 32px 9px 32px; color: #e2e8f0; font-family: inherit; font-size: 13px; font-weight: 600;
  transition: border-color 0.14s, background 0.14s, box-shadow 0.14s;
}
.pack-search-input::placeholder { color: var(--steel); font-weight: 500; }
.pack-search-input:focus {
  outline: none; border-color: var(--accent);
  background: rgba(255, 255, 255, 0.06); box-shadow: 0 0 0 3px rgba(89, 167, 240, 0.15);
}
.pack-search-clear {
  position: absolute; right: 6px; display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border: none; border-radius: 6px; cursor: pointer;
  background: rgba(255, 255, 255, 0.06); color: var(--steel); font-size: 13px;
  transition: color 0.12s, background 0.12s;
}
.pack-search-clear:hover { color: #e2e8f0; background: rgba(255, 255, 255, 0.12); }
/* Pacote escondido pelo filtro da busca (sai do fluxo da grade). */
.pack-grid .booster.filtered-out { display: none; }
/* Aviso quando a busca não casa nenhum booster nem carta. */
.pack-empty {
  flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center;
  text-align: center; padding: 24px; color: var(--steel); font-size: 13px; font-weight: 600;
}
/* Carta que casou a busca dentro do pacote: destacada em âmbar (antes da seleção). */
.cl-thumb.match { border-color: #f0b95a; box-shadow: 0 0 9px -2px rgba(240, 185, 90, 0.7); }
/* ── Open Boosters: listagem das últimas aberturas ──────────────────────── */
.open-log {
  flex: 1; min-height: 0; overflow-y: auto; padding: 2px 4px 8px; display: flex; flex-direction: column; gap: 10px;
}
.open-empty { margin: auto; text-align: center; color: var(--steel); font-size: 13px; line-height: 1.5; padding: 40px 12px; }
.open-empty i { display: block; font-size: 34px; opacity: 0.55; margin-bottom: 10px; }
.olog-row {
  border: 1px solid var(--line); border-radius: 11px; padding: 10px; background: rgba(255, 255, 255, 0.03);
  animation: pull-reveal 0.3s cubic-bezier(0.2, 1.3, 0.4, 1);
}
.olog-top { display: flex; align-items: center; gap: 9px; margin-bottom: 8px; }
.olog-cover { width: 26px; height: 45px; object-fit: cover; border-radius: 3px; flex: none; box-shadow: 0 3px 8px rgba(0, 0, 0, 0.5); }
.olog-meta { flex: 1; min-width: 0; }
.olog-name { font-size: 12.5px; font-weight: 800; color: #eef4fc; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.olog-when { font-size: 10.5px; color: var(--steel); margin-top: 1px; }
.olog-cards { display: grid; grid-template-columns: repeat(5, 1fr); gap: 18px 5px; padding-top: 16px; }
.olog-card { position: relative; padding: 0; border: 1px solid transparent; border-radius: 4px; background: none; cursor: pointer; line-height: 0; transition: transform 0.12s, border-color 0.12s; }
.olog-card img { width: 100%; display: block; border-radius: 3px; }
.olog-card:hover { transform: translateY(-2px); border-color: rgba(120, 180, 255, 0.6); }
.pack-grid {
  position: relative; flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 6px 6px 10px;
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 30px 18px; align-content: start; justify-items: center;
}
/* Indicador de seleção (cantos) que DESLIZA até o pacote escolhido. */
.pack-sel {
  position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none; opacity: 0;
  --c: var(--accent-bright); --len: 16px; --th: 2px;
  background:
    linear-gradient(var(--c), var(--c)) left 0 top 0 / var(--len) var(--th),
    linear-gradient(var(--c), var(--c)) left 0 top 0 / var(--th) var(--len),
    linear-gradient(var(--c), var(--c)) right 0 top 0 / var(--len) var(--th),
    linear-gradient(var(--c), var(--c)) right 0 top 0 / var(--th) var(--len),
    linear-gradient(var(--c), var(--c)) left 0 bottom 0 / var(--len) var(--th),
    linear-gradient(var(--c), var(--c)) left 0 bottom 0 / var(--th) var(--len),
    linear-gradient(var(--c), var(--c)) right 0 bottom 0 / var(--len) var(--th),
    linear-gradient(var(--c), var(--c)) right 0 bottom 0 / var(--th) var(--len);
  background-repeat: no-repeat;
  filter: drop-shadow(0 0 5px rgba(89, 167, 240, 0.75));
  transition: transform 0.34s cubic-bezier(0.34, 0.9, 0.3, 1),
    width 0.34s cubic-bezier(0.34, 0.9, 0.3, 1), height 0.34s cubic-bezier(0.34, 0.9, 0.3, 1),
    opacity 0.2s ease;
}
.pack-sel.on { opacity: 1; }

/* ── Pacotinho = a ARTE do booster (imagem), SEM moldura/card visível. Pendurada
   no gancho: ao entrar o mouse recebe um "empurrão" e balança amortecido. Os
   efeitos (balanço, sombra, faixa de luz, seleção) vão sobre a própria imagem. ─ */
.booster {
  position: relative; display: block; width: 100%; max-width: 110px; padding: 0; border: none;
  background: none; font-family: inherit; cursor: pointer; aspect-ratio: 209 / 360;
}
.booster.swinging { z-index: 3; }
/* Container transparente: recorta a faixa de luz à imagem e gira no balanço. */
.bp-img-wrap {
  position: absolute; inset: 0; overflow: hidden; transform-origin: top center;
  filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.45));
  transition: transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1), filter 0.2s;
}
.booster:hover .bp-img-wrap { filter: drop-shadow(0 12px 22px rgba(0, 0, 0, 0.6)); }
.bp-img { display: block; width: 100%; height: 100%; object-fit: contain; }
/* Faixa de luz que varre a imagem da ESQUERDA p/ a DIREITA no hover. */
.bp-img-wrap::after {
  content: ''; position: absolute; top: -20%; bottom: -20%; left: 0; width: 45%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.42) 50%, transparent);
  transform: translateX(-160%) skewX(-8deg); pointer-events: none; z-index: 1;
}
.booster:hover .bp-img-wrap::after { transform: translateX(320%) skewX(-8deg); transition: transform 0.6s ease; }
/* O balanço é disparado por JS (classe .swinging) ao ENTRAR o mouse — não fica
   preso ao :hover. Assim, ao tirar o mouse, ele continua balançando e vai
   amortecendo até parar (pêndulo), em vez de cortar seco. `linear` porque as
   próprias keyframes (seno amortecido) já definem a velocidade. */
.booster.swinging .bp-img-wrap { animation: bp-swing 2.2s linear 1; }
/* --dir (1 ou -1, definido no JS) espelha o balanço conforme a direção em que o
   mouse entrou: →  começa p/ um lado; ←  começa p/ o outro. */
@keyframes bp-swing {
  0%   { transform: rotate(0deg); }
  5%   { transform: rotate(calc(var(--dir, 1) * 7.6deg)); }
  10%  { transform: rotate(calc(var(--dir, 1) * 6.8deg)); }
  15%  { transform: rotate(calc(var(--dir, 1) * 0.2deg)); }
  20%  { transform: rotate(calc(var(--dir, 1) * -5deg)); }
  25%  { transform: rotate(calc(var(--dir, 1) * -4.7deg)); }
  30%  { transform: rotate(calc(var(--dir, 1) * -0.3deg)); }
  35%  { transform: rotate(calc(var(--dir, 1) * 3.3deg)); }
  40%  { transform: rotate(calc(var(--dir, 1) * 3.2deg)); }
  45%  { transform: rotate(calc(var(--dir, 1) * 0.3deg)); }
  50%  { transform: rotate(calc(var(--dir, 1) * -2.2deg)); }
  55%  { transform: rotate(calc(var(--dir, 1) * -2.2deg)); }
  60%  { transform: rotate(calc(var(--dir, 1) * -0.3deg)); }
  65%  { transform: rotate(calc(var(--dir, 1) * 1.5deg)); }
  70%  { transform: rotate(calc(var(--dir, 1) * 1.5deg)); }
  75%  { transform: rotate(calc(var(--dir, 1) * 0.2deg)); }
  80%  { transform: rotate(calc(var(--dir, 1) * -1deg)); }
  85%  { transform: rotate(calc(var(--dir, 1) * -1deg)); }
  90%  { transform: rotate(calc(var(--dir, 1) * -0.2deg)); }
  95%  { transform: rotate(calc(var(--dir, 1) * 0.6deg)); }
  100% { transform: rotate(0deg); }
}
@media (prefers-reduced-motion: reduce) {
  .booster.swinging { animation: none; }
  .pack-sel { transition: opacity 0.2s ease; }
}

@keyframes spin { to { transform: rotate(360deg); } }

/* Telas menores: encolhe as colunas mantendo as 3 lado a lado (sem rolagem de
   página); cada painel segue rolando por dentro. */
@media (max-width: 1280px) {
  .shop-body { gap: 14px; }
  .shop-detail { width: 280px; }
  .shop-packs { width: clamp(320px, 34vw, 420px); }
  .pack-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px 14px; }
}
@media (max-width: 940px) {
  .shop-detail { width: 230px; }
  .pack-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .sd-name { font-size: 16px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   ABERTURA DE BOOSTERS — overlay preto + blur (não interfere na loja). Pacote(s)
   → botão Abrir → corte diagonal (as metades caem) → cartas de VERSO → flip.
   ══════════════════════════════════════════════════════════════════════════ */
#open-overlay {
  position: fixed; inset: 0; z-index: 70;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 24px;
  background: rgba(0, 0, 0, 0.84); backdrop-filter: blur(10px);
  animation: fade-in 0.2s ease-out;
}
.oo-title { font-size: 16px; font-weight: 800; letter-spacing: 0.05em; color: #eef4fc; text-align: center; text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6); }
.oo-stage { display: flex; align-items: center; justify-content: center; min-height: 0; max-width: 94vw; }

/* Fase 1 — pacotes fatiados em tiras diagonais (mais tiras = melhor raridade),
   com brilho conforme a raridade (R azul · SR laranja · UR arco-íris). */
.oo-packs { display: flex; gap: 26px; flex-wrap: wrap; align-items: center; justify-content: center; }
.oo-pack {
  position: relative; width: clamp(150px, 17vw, 216px); aspect-ratio: 209 / 360;
  filter: drop-shadow(0 18px 34px rgba(0, 0, 0, 0.7));
  animation: oo-pack-in 0.4s cubic-bezier(0.2, 1.4, 0.4, 1) backwards;
  transition: transform 0.12s ease;
}
/* Glow por raridade (acompanha as partículas). */
.oo-pack.r-SUPER { filter: drop-shadow(0 18px 34px rgba(0, 0, 0, 0.7)) drop-shadow(0 0 18px rgba(255, 175, 70, 0.75)); }
.oo-pack.r-ULTRA { filter: drop-shadow(0 18px 34px rgba(0, 0, 0, 0.7)) drop-shadow(0 0 19px rgba(200, 110, 255, 0.78)); }
@keyframes oo-pack-in { from { opacity: 0; transform: translateY(24px) scale(0.9); } }
/* Partículas por cima da arte do booster (só SR/UR). SR douradas · UR multicolor
   (cada partícula com sua matiz). Sobem, driftam e piscam em fluxo contínuo. */
.oo-particles { position: absolute; inset: 0; z-index: 2; overflow: visible; pointer-events: none; opacity: 0.6; }
.oo-pcl {
  position: absolute; bottom: -4%; width: var(--sz, 5px); height: var(--sz, 5px); border-radius: 50%;
  opacity: 0; will-change: transform, opacity; animation: pcl-float var(--dur, 3s) linear infinite;
}
.oo-particles.r-SUPER .oo-pcl { background: radial-gradient(circle, #fff 12%, #ffc14d 52%, transparent 72%); box-shadow: 0 0 6px rgba(255, 185, 70, 0.85); }
.oo-particles.r-ULTRA .oo-pcl {
  background: radial-gradient(circle, #fff 12%, hsl(var(--h, 300) 92% 62%) 52%, transparent 72%);
  box-shadow: 0 0 6px hsl(var(--h, 300) 92% 62% / 0.85);
}
@keyframes pcl-float {
  0% { transform: translate(0, 0) scale(0); opacity: 0; }
  14% { transform: translate(calc(var(--drift, 0px) * 0.22), calc(var(--rise, 240px) * -0.15)) scale(1); opacity: 1; }
  80% { opacity: 0.85; }
  100% { transform: translate(var(--drift, 0px), calc(var(--rise, 240px) * -1)) scale(0.3); opacity: 0; }
}
/* Tiras do pacote (cada uma mostra sua fatia da arte via clip-path). */
.oo-piece { position: absolute; inset: 0; background-size: cover; background-position: center; will-change: transform, opacity; }
.oo-slash {
  position: absolute; inset: -6%; z-index: 3; pointer-events: none; opacity: 0;
  background: linear-gradient(45deg, transparent 47.5%, rgba(255, 255, 255, 0.95) 49.5%, rgba(255, 255, 255, 0.95) 50.5%, transparent 52.5%);
  filter: drop-shadow(0 0 6px rgba(180, 220, 255, 0.9));
}
.oo-pack.cut .oo-slash { animation: oo-slash 0.45s ease-out forwards; }
@keyframes oo-slash { 0% { opacity: 0; } 25% { opacity: 1; } 100% { opacity: 0; } }
.oo-pack.cut .oo-particles { opacity: 0; transition: opacity 0.25s; }
.oo-pack.cut .oo-piece { animation: oo-piece-fall 0.8s ease-in forwards; animation-delay: var(--d, 0s); }
@keyframes oo-piece-fall {
  0% { transform: translate(0, 0) rotate(0); opacity: 1; }
  12% { transform: translate(calc(var(--dx, 0px) * 0.18), -4px) rotate(calc(var(--rot, 0deg) * 0.18)); opacity: 1; }
  100% { transform: translate(var(--dx, 0px), 132%) rotate(var(--rot, 0deg)); opacity: 0; }
}

/* Fase 2 — cartas de VERSO; clicar faz o flip revelando a carta. Horizontal e
   responsivo: largura definida p/ o auto-fit criar várias colunas (não empilhar). */
.oo-cards {
  position: relative; width: min(94vw, 1060px); margin: 0 auto;
  display: grid; gap: 14px; padding: 10px 6px; overflow-y: auto; max-height: 78vh; justify-content: center;
  grid-template-columns: repeat(auto-fit, clamp(82px, 8.5vw, 118px));
}
.oc-card {
  padding: 0; border: none; background: none; cursor: pointer; perspective: 850px;
  width: 100%; aspect-ratio: 59 / 86; transition: transform 0.15s;
  animation: oo-card-in 0.4s cubic-bezier(0.2, 1.3, 0.4, 1) backwards;
}
@keyframes oo-card-in { from { opacity: 0; transform: translateY(18px); } }
/* Glow leve por raridade (acompanha as partículas; vale de costas e virada). */
.oc-card.r-SUPER, .oc-card.r-ULTRA { border-radius: 6px; }
.oc-card.r-SUPER { box-shadow: 0 0 22px -1px rgba(255, 175, 70, 0.72); }
.oc-card.r-ULTRA { box-shadow: 0 0 24px 0 rgba(200, 110, 255, 0.75); }
.oc-card:not(.flipped):hover { transform: translateY(-5px); }
.oc-inner { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; transition: transform 0.55s cubic-bezier(0.3, 0.8, 0.3, 1); }
.oc-card.flipped .oc-inner { transform: rotateY(180deg); }
.oc-face { position: absolute; inset: 0; backface-visibility: hidden; border-radius: 6px; overflow: hidden; box-shadow: 0 8px 18px rgba(0, 0, 0, 0.55); }
.oc-back { background: url("https://yugiohonline.b-cdn.net/ui/card-back.webp") center / cover no-repeat; }
.oc-front { transform: rotateY(180deg); background: #0a0e14; }
.oc-front img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Célula: a carta (flip) + o rótulo embaixo. O rótulo só aparece DEPOIS de virar
   (sibling .flipped) e reserva espaço fixo pra grade não pular ao surgir. */
.oc-cell { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.oc-label {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 16px; opacity: 0; transition: opacity 0.35s ease 0.15s; line-height: 1;
}
.oc-card.flipped + .oc-label { opacity: 1; }
.oc-new {
  color: #ffe27a; font-size: 10.5px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase;
  text-shadow: 0 0 8px rgba(255, 210, 70, 0.9), 0 0 2px rgba(255, 190, 40, 0.85);
  animation: oc-new-glow 1.5s ease-in-out infinite;
}
@keyframes oc-new-glow {
  0%, 100% { text-shadow: 0 0 7px rgba(255, 210, 70, 0.8), 0 0 2px rgba(255, 190, 40, 0.8); }
  50% { text-shadow: 0 0 14px rgba(255, 224, 120, 1), 0 0 5px rgba(255, 195, 50, 0.95); }
}
.oc-copies {
  color: #eaf2fb; background: rgba(120, 150, 190, 0.22); border: 1px solid rgba(160, 190, 225, 0.28);
  border-radius: 5px; padding: 1px 6px; font-size: 10.5px; font-weight: 800; letter-spacing: 0.02em;
}
/* (As cartas reveladas não ganham brilho na moldura; só o selo "Nova" pulsa e os
   pacotes na hora de abrir ganham partículas por raridade.) */

.oo-actions { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }
.oo-btn {
  position: relative; border: none; clip-path: var(--cut-sm); cursor: pointer; isolation: isolate;
  padding: 12px 24px; font-family: inherit; font-weight: 800; font-size: 14px; color: #dbe9fa;
  background: rgba(120, 180, 255, 0.45); display: inline-flex; align-items: center; gap: 8px;
  transition: filter 0.15s, transform 0.1s;
}
.oo-btn::before { content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm); background: rgba(20, 27, 38, 0.9); }
.oo-btn:hover { filter: brightness(1.2); }
.oo-btn:active { transform: scale(0.96); }
.oo-btn--primary { color: #06231a; background: linear-gradient(180deg, #4fe08b, #16a35a); }
.oo-btn--primary::before { display: none; }
@media (prefers-reduced-motion: reduce) {
  .oo-pack.cut .oo-piece { animation-duration: 0.01s; }
  .oo-pcl { animation: none !important; opacity: 0; }
}

/* ── Modal de abertura: grade de CARTAS reveladas (imagem + contador) ────── */
#modal.pulls-modal { width: 880px; }
.pulls-grid {
  overflow-y: auto; display: grid; gap: 12px; padding: 2px;
  grid-template-columns: repeat(auto-fill, minmax(94px, 1fr));
}
.pull-card {
  position: relative; border-radius: 8px; border: 2px solid transparent;
  animation: pull-reveal 0.42s cubic-bezier(0.2, 1.4, 0.4, 1) backwards;
}
.pull-card img { width: 100%; display: block; border-radius: 6px; }
.pull-card .pc-name {
  margin-top: 4px; font-size: 10.5px; font-weight: 700; line-height: 1.2; text-align: center;
  color: #cdd7e3; overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.pull-card .pc-count {
  position: absolute; top: 5px; right: 5px; min-width: 22px; height: 22px; padding: 0 6px;
  border-radius: 999px; display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 800; color: #06131c;
  background: linear-gradient(180deg, #ffe27a, #e8b23c); box-shadow: 0 2px 9px rgba(0, 0, 0, 0.55);
}
.pull-card.r-COMMON { border-color: rgba(200, 212, 224, 0.32); }
.pull-card.r-RARE { border-color: #6bb2ff; box-shadow: 0 0 15px -3px rgba(107, 178, 255, 0.65); }
.pull-card.r-SUPER { border-color: #c9a2ff; box-shadow: 0 0 17px -3px rgba(201, 162, 255, 0.72); }
.pull-card.r-ULTRA { border-color: var(--gold-bright); box-shadow: 0 0 20px -2px rgba(255, 215, 94, 0.78); }

/* ── UI kit chanfrado (login, home, navbar) ────────────────────────────────
   Mesmo padrão do #modal: fundo = "borda" translúcida de acento, ::before
   (inset 1px) = preenchimento. */
/* O duotone do `check` desenha um QUADRADO esmaecido (camada :before) atrás do
   tique. Some com o quadrado deixando SÓ o tique (fica mais limpo em botões,
   modais e status) — mantém `opacity:0` em vez de `display:none` pra preservar
   o box de 1em e não desalinhar o :after (que tem margin-left:-1em). */
.ph-duotone.ph-check::before { opacity: 0; }
.ph-duotone.ph-plus::before { opacity: 0; }   /* mesmo quadrado esmaecido atrás do "+" */

.ui-panel {
  position: relative; border: none; clip-path: var(--cut-md);
  background: rgba(120, 180, 255, 0.40);
  filter: drop-shadow(0 26px 60px rgba(0, 0, 0, 0.68));
}
.ui-panel::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-md);
  background: linear-gradient(165deg, rgba(17, 24, 37, 0.93), rgba(9, 13, 21, 0.9));
  backdrop-filter: blur(7px); pointer-events: none;
}

.ui-btn {
  position: relative; border: none; clip-path: var(--cut-sm); cursor: pointer;
  padding: 12px 20px; font-size: 13.5px; font-weight: 800; letter-spacing: 0.02em;
  color: #dbe9fa; background: rgba(120, 180, 255, 0.5); font-family: inherit;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  isolation: isolate; /* stacking context p/ o ::before (z-index:-1) da borda */
  transition: filter 0.15s, transform 0.08s;
}
.ui-btn::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm);
  background: rgba(255, 255, 255, 0.06);
}
.ui-btn:hover { filter: brightness(1.16); }
.ui-btn:active { transform: scale(0.96); }
.ui-btn--primary { color: #06131c; background: linear-gradient(180deg, #86c6ff, #3f86e0); }
.ui-btn--primary::before { display: none; }
.ui-btn--ghost::before { background: rgba(20, 27, 38, 0.82); }
.ui-btn--danger { color: #ffd7d1; background: rgba(255, 92, 73, 0.55); }
.ui-btn--danger::before { background: rgba(40, 12, 12, 0.55); }
.ui-btn--danger:hover { color: #fff; }

/* Input chanfrado via wrapper (input não aceita ::before): a moldura acende no
   foco. */
.ui-field {
  position: relative; clip-path: var(--cut-sm);
  background: rgba(120, 160, 220, 0.34); transition: background 0.18s;
}
.ui-field::before {
  content: ''; position: absolute; inset: 1px; clip-path: var(--cut-sm);
  background: rgba(8, 13, 22, 0.86); pointer-events: none;
}
.ui-field:focus-within { background: var(--accent); }
.ui-field input {
  position: relative; width: 100%; border: none; background: transparent;
  padding: 11px 13px; font-size: 13.5px; color: #eaf2fb; outline: none; font-family: inherit;
}
.ui-field input::placeholder { color: #7f93a8; }

/* Caixa de marcação chanfrada. O `input` real fica invisível ANTES da caixa
   (irmão anterior) — quem pinta o estado é o `+`. `.ar-box` é a do login;
   `.ui-check` é a mesma peça para qualquer lista de marcação (filtros do
   montador). */
.ar-box, .ui-check {
  flex: none; width: 20px; height: 20px; clip-path: var(--cut-sm);
  background: rgba(150, 160, 175, 0.28); position: relative; isolation: isolate;
  display: inline-flex; align-items: center; justify-content: center; transition: background 0.14s;
}
.ar-box::before, .ui-check::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm);
  background: rgba(8, 13, 22, 0.86); transition: background 0.14s;
}
.ar-box i, .ui-check i {
  font-size: 14px; color: #06131c; opacity: 0; transform: scale(0.5);
  transition: opacity 0.14s, transform 0.14s;
}
input:checked + .ar-box, input:checked + .ui-check { background: var(--accent-bright); }
input:checked + .ar-box::before, input:checked + .ui-check::before { background: var(--accent-bright); }
input:checked + .ar-box i, input:checked + .ui-check i { opacity: 1; transform: scale(1); }
input:focus-visible + .ar-box, input:focus-visible + .ui-check { box-shadow: 0 0 0 2px rgba(142, 199, 255, 0.5); }

/* Interruptor (liga/desliga) chanfrado: trilho = "borda" recolorível, ::before
   (inset 1px) = preenchimento, e o botão desliza dentro do recorte. O rótulo
   acende junto para o estado ligado ser legível sem depender só da cor. */
.ui-switch {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none;
  font-size: 11.5px; font-weight: 800; letter-spacing: 0.04em; color: #8b99ab;
  transition: color 0.15s;
}
.ui-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.us-track {
  position: relative; isolation: isolate; flex: none; width: 38px; height: 20px; padding: 3px;
  clip-path: var(--cut-xs); background: rgba(150, 160, 175, 0.3); transition: background 0.16s;
}
.us-track::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-xs);
  background: rgba(8, 13, 22, 0.9); transition: background 0.16s;
}
.us-knob {
  display: block; width: 14px; height: 14px; clip-path: var(--cut-xs); background: #8b99ab;
  transition: transform 0.18s cubic-bezier(0.2, 0.9, 0.3, 1.15), background 0.16s;
}
.ui-switch:hover { color: #c3d2e4; }
.ui-switch:hover .us-track { background: rgba(180, 195, 215, 0.45); }
.ui-switch:hover .us-knob { background: #c3d2e4; }
.ui-switch input:checked + .us-track { background: var(--accent-bright); }
.ui-switch input:checked + .us-track::before { background: rgba(24, 58, 98, 0.92); }
.ui-switch input:checked + .us-track .us-knob { transform: translateX(18px); background: var(--accent-bright); }
.ui-switch input:checked ~ .us-txt { color: #dbeafc; }
.ui-switch input:focus-visible + .us-track { box-shadow: 0 0 0 2px rgba(142, 199, 255, 0.5); }
@media (prefers-reduced-motion: reduce) { .us-knob { transition: background 0.16s; } }

/* ── Navbar (topo, preto translúcido — só aparece DEPOIS do login) ──────────*/
/* No login não há navbar: a tela de entrada é limpa, só o card sobre o parallax. */
body.on-auth .navbar { display: none; }

.navbar {
  position: relative; z-index: 20;
  display: flex; align-items: stretch;
  height: 66px; padding: 0 0 0 18px;
  /* Preto puro, só com leve opacidade + blur atrás (sem borda embaixo). */
  background: rgba(0, 0, 0, 0.82);
  backdrop-filter: blur(14px);
}
.nav-brand {
  display: flex; align-items: center; gap: 11px; user-select: none;
  font-weight: 800; letter-spacing: 0.15em; font-size: 14px; color: #eaf2fb;
}
.nav-logo {
  width: 52px; height: 52px; object-fit: contain;
  filter: drop-shadow(0 0 10px rgba(120, 170, 240, 0.35));
}

/* Divisor DIAGONAL (o "/" técnico) entre a brand e o menu. */
.nav-div {
  align-self: stretch; width: 1px; margin: 0 18px 0 22px; transform: skewX(-16deg);
  background: linear-gradient(180deg, transparent, rgba(150, 180, 220, 0.30) 24%,
    rgba(150, 180, 220, 0.30) 76%, transparent);
}

/* Menu = abas (Loja/Decks) com SELEÇÃO DESLIZANTE. O hover antigo foi removido:
   agora só a aba ativa (página aberta) acende, e a seleção "escorrega" entre elas. */
.nav-menu { position: relative; display: flex; align-items: stretch; }
.nav-cell {
  position: relative; z-index: 1; display: inline-flex; align-items: center; gap: 8px; padding: 0 22px;
  border: none; background: transparent; cursor: pointer; font-family: inherit;
  font-size: 13px; font-weight: 700; letter-spacing: 0.02em; color: var(--steel);
  transition: color 0.18s;
}
.nav-cell i { font-size: 18px; transition: color 0.18s; }
.nav-cell:hover { color: #cdd8e6; }
.nav-cell:hover i { color: var(--accent-bright); }
.nav-cell.is-active { color: #f2f6fc; }
.nav-cell.is-active i { color: var(--accent-bright); }

/* A seleção: fundo PRETO mais escuro no ângulo diagonal, ocupando a largura toda
   da aba, com um "inline" (risco) de acento animado na base. JS ajusta left/width
   e a transição faz a peça deslizar até a nova aba selecionada. */
.nav-sel {
  position: absolute; top: 0; bottom: 0; left: 0; width: 0; z-index: 0; opacity: 0;
  clip-path: polygon(16px 0, 100% 0, calc(100% - 16px) 100%, 0 100%);
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0.60));
  transition: left 0.34s cubic-bezier(0.34, 1.1, 0.36, 1),
    width 0.34s cubic-bezier(0.34, 1.1, 0.36, 1), opacity 0.2s;
}
.nav-sel.on { opacity: 1; }
.nav-sel::after {
  content: ''; position: absolute; left: 16px; right: 16px; bottom: 6px; height: 2px;
  clip-path: var(--slant);
  background: linear-gradient(90deg, transparent, var(--accent-bright), transparent);
}

/* DUELO: paralelogramo verde, botão GRANDE (bem comprido na horizontal). */
.nav-cta--duel {
  clip-path: polygon(18px 0, 100% 0, calc(100% - 18px) 100%, 0 100%); padding: 0 66px; color: #fff;
  background: linear-gradient(165deg, #34d67e, #12a355 70%, #0c8f49);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
}
/* Partículas contínuas (spawn via JS ao passar o mouse): sobem de forma
   não-linear e aleatória. Cada dot recebe --dx/--dy/--dur próprios. */
.duel-particle {
  position: absolute; bottom: 4px; z-index: 1; border-radius: 50%;
  background: #eafff3; box-shadow: 0 0 6px 1px #8dffc0; pointer-events: none;
  animation: duel-rise var(--dur, 1s) cubic-bezier(0.35, 0, 0.5, 1) forwards;
}
@keyframes duel-rise {
  0% { opacity: 0; transform: translate(0, 0) scale(0.3); }
  18% { opacity: 1; }
  70% { opacity: 0.9; }
  100% { opacity: 0; transform: translate(var(--dx, 0), var(--dy, -30px)) scale(1); }
}
.nav-cta--duel .cta-in i { filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.35)); }
/* Ícone do duel disk (svg de linhas brancas) no lugar da espada. */
.nav-cta--duel .duel-disk {
  height: 34px; width: auto; display: block; margin-right: 2px;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4));
}
.nav-cta--duel:hover {
  filter: brightness(1.08);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0 0 26px -2px rgba(46, 214, 126, 0.65);
}
.nav-cta--duel:active { filter: brightness(0.96); }

/* Grupo da conta (empurrado p/ direita): DUELO → usuário (diagonais) → avatar →
   Config → Sair. Só o nav-id encaixa na diagonal do DUELO (-18); o avatar e os
   dois botões são QUADRADOS e ficam retos, um do lado do outro. */
.nav-account { display: flex; align-items: stretch; margin-left: auto; }
.nav-account > * { align-self: stretch; }
.nav-account > .nav-id { margin-left: -18px; } /* encaixe diagonal só entre DUELO e usuário */

/* Área da conta (só exibição): carteira → divisor → nome (à DIREITA), avatar depois.
   Diagonal só à ESQUERDA (encaixe com o DUELO); direita RETA (encosta no avatar quadrado). */
.nav-id {
  isolation: isolate; display: flex; align-items: stretch;
  clip-path: polygon(18px 0, 100% 0, 100% 100%, 0 100%);
  padding-left: 12px; white-space: nowrap; background: #000;
}
.id-div {
  align-self: stretch; width: 1px; margin: 0 14px 0 4px; transform: skewX(-16deg);
  background: linear-gradient(180deg, transparent, rgba(160, 185, 220, 0.32) 22%,
    rgba(160, 185, 220, 0.32) 78%, transparent);
}
.id-who {
  display: flex; flex-direction: column; justify-content: center; align-items: flex-end; gap: 4px;
  padding-right: 26px; text-align: right; /* leve respiro até o avatar */
}
.id-name { color: #f2f6fc; font-size: 14px; font-weight: 800; letter-spacing: 0.02em; line-height: 1; }
.id-title { color: #868f9c; font-size: 11px; font-weight: 500; letter-spacing: 0.02em; line-height: 1; }

/* Carteira: moeda à FRENTE (direita), DP mais ATRÁS (esquerda), escalonadas
   seguindo o corte; número em cor SÓLIDA (sem contorno, sem fundo próprio). */
.id-wallet {
  display: flex; flex-direction: column; justify-content: center; gap: 5px; padding: 0 8px;
}
.id-cur { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 900; }
.id-cur--gold { align-self: flex-start; margin-left: 12px; color: var(--gold-bright); } /* à frente */
.id-cur--gold i { color: var(--gold); font-size: 14px; }
.id-cur--dp { align-self: flex-start; color: #6cb5ff; } /* atrás */
.id-cur--dp i { color: #4aa8ff; font-size: 13px; }

/* Avatar (no meio da conta) — imagem simples QUADRADA, sem efeito de hover. */
.nav-avatar {
  isolation: isolate; align-self: stretch; width: 62px; overflow: hidden;
  background: #000;
}
.nav-avatar img { width: 100%; height: 100%; object-fit: cover; object-position: var(--face-crop); display: block; }

/* CTAs de altura cheia (Config + Sair): mesma pegada técnica, com partículas. */
.nav-cta {
  isolation: isolate; position: relative; align-self: stretch; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: none; cursor: pointer; font-family: inherit;
  font-size: 13px; font-weight: 900; letter-spacing: 0.08em; text-transform: uppercase;
  transition: filter 0.18s, box-shadow 0.2s, background 0.2s, color 0.18s;
}
.nav-cta .cta-in { position: relative; z-index: 2; display: inline-flex; align-items: center; gap: 8px; }
.nav-cta .cta-in i { font-size: 18px; }
/* varredura de luz (glint) que cruza no hover */
.nav-cta::after {
  content: ''; position: absolute; top: 0; bottom: 0; left: -60%; width: 45%; z-index: 1;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.30), transparent);
  transform: skewX(-18deg); opacity: 0; transition: opacity 0.2s;
}
.nav-cta:hover::after { opacity: 1; animation: cta-glint 0.9s ease-in-out; }
@keyframes cta-glint { from { left: -60%; } to { left: 130%; } }

/* Botões "power" (Config + Sair): só ícone, PRETO/azul-escuro por padrão (chamam
   pouca atenção). No hover ganham BORDA na cor do botão (seguindo a diagonal),
   miolo mais escuro e ícone aceso. Cores SÓLIDAS → transição limpa de ida e volta. */
.nav-cta--pwr {
  padding: 0 24px; color: #56617a; /* simétrico → ícone centralizado */
  background-color: #0e141d; transition: background-color 0.2s ease, color 0.2s ease;
}
.nav-cta--pwr .cta-in i { font-size: 19px; }
.nav-cta--pwr::before {
  content: ''; position: absolute; inset: 2px; z-index: 0; clip-path: inherit;
  background-color: #0e141d; transition: background-color 0.2s ease;
}
.nav-cta--pwr:hover { background-color: var(--pwr); color: var(--pwr); }
.nav-cta--pwr:hover::before { background-color: var(--pwr-inner); }
.nav-cta--pwr:active { filter: brightness(0.94); }

/* Config: azul (mesmo tom de antes), QUADRADO. */
.nav-cta--settings { --pwr: #3d8bff; --pwr-inner: #0c1a34; }
/* Sair: vermelho, QUADRADO, flush no canto direito. */
.nav-cta--logout { --pwr: #ff3b30; --pwr-inner: #2a0d0c; }

/* Partículas / brilhinhos — dots que sobem e cintilam ao passar o mouse. */
.sparks { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.sparks i {
  position: absolute; width: 3px; height: 3px; border-radius: 50%;
  background: #fff; opacity: 0; box-shadow: 0 0 6px 1px currentColor;
}
.nav-cta:hover .sparks i { animation: spark 1.05s ease-in-out infinite; }
.sparks i:nth-child(1) { left: 14%; bottom: 12%; animation-delay: 0s; }
.sparks i:nth-child(2) { left: 30%; bottom: 22%; width: 2px; height: 2px; animation-delay: 0.16s; }
.sparks i:nth-child(3) { left: 46%; bottom: 8%; animation-delay: 0.33s; }
.sparks i:nth-child(4) { left: 62%; bottom: 26%; width: 2px; height: 2px; animation-delay: 0.48s; }
.sparks i:nth-child(5) { left: 78%; bottom: 14%; animation-delay: 0.62s; }
.sparks i:nth-child(6) { left: 88%; bottom: 30%; width: 2px; height: 2px; animation-delay: 0.78s; }
.sparks i:nth-child(7) { left: 22%; bottom: 34%; animation-delay: 0.9s; }
@keyframes spark {
  0% { opacity: 0; transform: translateY(5px) scale(0.3); }
  35% { opacity: 1; transform: translateY(-3px) scale(1); }
  100% { opacity: 0; transform: translateY(-16px) scale(0.4); }
}
@media (prefers-reduced-motion: reduce) {
  .nav-cta:hover .sparks i { animation: none; }
  .nav-cta:hover::after { animation: none; }
  .duel-particle { animation: none !important; display: none; }
}

/* ── Overlay de loading (global) — card chanfrado + orbe de anéis + shimmer ──*/
#loading {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: rgba(4, 7, 12, 0.66); backdrop-filter: blur(5px);
  animation: fade-in 0.15s ease-out;
}
.load-card {
  display: flex; flex-direction: column; align-items: center; gap: 18px;
  padding: 30px 48px; position: relative; isolation: isolate; clip-path: var(--cut-md);
  background: rgba(140, 158, 182, 0.18); filter: drop-shadow(0 20px 46px rgba(0, 0, 0, 0.55));
}
.load-card::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-md);
  background: linear-gradient(168deg, rgba(18, 24, 34, 0.96), rgba(9, 12, 19, 0.95)); backdrop-filter: blur(10px);
}
.load-orb { position: relative; width: 76px; height: 76px; display: flex; align-items: center; justify-content: center; }
.load-ring {
  position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(from 90deg, transparent 0 25%, var(--accent-bright));
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 4px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 4px));
  animation: ldspin 0.85s linear infinite;
}
.load-ring--2 {
  inset: 10px; opacity: 0.85;
  background: conic-gradient(from 270deg, transparent 0 45%, var(--gold-bright));
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
  animation: ldspin 1.3s linear infinite reverse;
}
.load-core { font-size: 26px; color: #cfe6ff; filter: drop-shadow(0 0 10px rgba(142, 199, 255, 0.6)); animation: ldspin 1.4s linear infinite; }
.load-text { font-size: 12px; font-weight: 800; letter-spacing: 0.16em; text-transform: uppercase; color: var(--steel); }
.load-bar { width: 150px; height: 3px; overflow: hidden; clip-path: var(--cut-sm); background: rgba(255, 255, 255, 0.06); }
.load-bar span { display: block; width: 40%; height: 100%; background: linear-gradient(90deg, transparent, var(--accent-bright), transparent); animation: load-slide 1.15s ease-in-out infinite; }
@keyframes load-slide { 0% { transform: translateX(-130%); } 100% { transform: translateX(330%); } }
@keyframes ldspin { to { transform: rotate(360deg); } }

/* ── Login (screen-auth sobre o fundo fixo academy_map) — paleta PRETA ──────
   Logo grande FORA do card; dentro: cabeçalho + campos com ícone + lembrar. */
.auth-wrap {
  display: flex; flex-direction: column; align-items: center; gap: 22px;
  width: 100%; max-width: 384px;
}
#screen-auth .auth-card { width: 100%; max-width: 384px; padding: 28px 26px 24px; }
.auth-logo {
  display: block; width: min(320px, 82vw); height: auto; object-fit: contain;
  filter: drop-shadow(0 10px 26px rgba(0, 0, 0, 0.55)) drop-shadow(0 0 22px rgba(200, 210, 225, 0.16));
}
.auth-head { text-align: center; margin-bottom: 20px; }
.auth-title { font-size: 19px; font-weight: 800; letter-spacing: 0.02em; color: #eef4fc; }
.auth-sub { margin-top: 5px; font-size: 12.5px; color: #93a3b6; }
.auth-fields { display: flex; flex-direction: column; gap: 12px; }
.auth-field { display: flex; align-items: center; }
.auth-field input { flex: 1; min-width: 0; width: auto; }
.af-eye { position: relative; z-index: 1; flex: none; border: none; background: none; cursor: pointer; color: #8aa0b8; padding: 0 12px; font-size: 17px; display: inline-flex; align-items: center; transition: color 0.14s; }
.af-eye:hover { color: var(--accent-bright); }
.auth-remember { display: flex; align-items: center; gap: 9px; cursor: pointer; user-select: none; margin: 3px 2px 5px; font-size: 12.5px; color: #a9b6c6; }
.auth-remember input { position: absolute; opacity: 0; width: 0; height: 0; }
/* A caixa (.ar-box) é a peça compartilhada do UI kit; aqui só o hover da linha. */
.auth-remember:hover .ar-box { background: rgba(180, 195, 215, 0.45); }
.auth-primary, .auth-ghost { width: 100%; padding: 13px; }
.auth-divider { display: flex; align-items: center; gap: 12px; margin: 3px 0; color: #5f6f80; font-size: 11px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; }
.auth-divider::before, .auth-divider::after { content: ''; flex: 1; height: 1px; background: linear-gradient(90deg, transparent, rgba(150, 165, 190, 0.28), transparent); }
#auth-error { margin-top: 14px; min-height: 18px; font-size: 12.5px; color: #ff8a7a; text-align: center; }

/* Mesma fidelidade da tela de Config: card chanfrado, campo com FOCO acento e
   botão primário azul. Um véu levemente translúcido deixa a Academia respirar. */
#screen-auth .auth-card {
  background: rgba(140, 158, 182, 0.20);
  filter: drop-shadow(0 16px 34px rgba(0, 0, 0, 0.42));
}
#screen-auth .auth-card::before {
  background: linear-gradient(168deg, rgba(20, 25, 33, 0.94), rgba(10, 13, 19, 0.92));
  backdrop-filter: blur(9px);
}
#screen-auth .ui-field { background: rgba(150, 160, 175, 0.22); }
#screen-auth .ui-field:focus-within { background: var(--accent); }
#screen-auth .ui-btn--ghost::before { background: rgba(20, 27, 38, 0.85); }
#screen-auth .ui-btn--primary {
  color: #06131c; background: linear-gradient(180deg, #86c6ff, #3f86e0);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
#screen-auth .ui-btn--primary::before { display: none; }
#screen-auth .ui-btn--primary:hover { filter: brightness(1.12); }

/* ── Home / lobby (screen-lobby) — paleta PRETA, redesenhada ────────────────*/
/* Painéis pretos translúcidos (como o login); as outras telas seguem azuis. */
#screen-lobby .ui-panel { background: rgba(150, 160, 175, 0.18); filter: drop-shadow(0 14px 30px rgba(0, 0, 0, 0.34)); }
#screen-lobby .ui-panel::before { background: linear-gradient(165deg, rgba(16, 18, 23, 0.90), rgba(7, 9, 13, 0.88)); backdrop-filter: blur(9px); }
#screen-lobby .ui-field { background: rgba(150, 160, 175, 0.20); }
#screen-lobby .ui-field:focus-within { background: rgba(220, 226, 236, 0.5); }
#screen-lobby .ui-btn { background: rgba(150, 160, 175, 0.26); }
#screen-lobby .ui-btn--ghost::before { background: rgba(14, 16, 21, 0.9); }

/* Indicadores do canto direito da barra da home, todos na mesma pílula preta
   chanfrada: calendário + hora do jogo (1 dia = 1 hora real, a semana gira de
   segunda a domingo), duelistas online agora e total de duelos já disputados.
   Somem junto com a home (filhos de #screen-lobby.hidden). */
.home-meta { display: flex; align-items: center; gap: 8px; flex: none; flex-wrap: wrap; }

/* Relógio do jogo: dia da semana · hora, separados por um fio vertical. */
.game-clock,
.home-stat {
  display: inline-flex; align-items: center; gap: 8px; flex: none;
  padding: 8px 15px; clip-path: var(--cut-sm);
  color: #eaf2fb; font-weight: 800; letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums; user-select: none;
  background: rgba(8, 10, 15, 0.55);
}
.game-clock i, .home-stat i { font-size: 18px; line-height: 1; color: var(--accent-bright); }
.game-clock .gc-time { font-size: 15px; }
.game-clock .gc-day { font-size: 13px; text-transform: uppercase; color: #dbe8f7; }
.game-clock .gc-sep { width: 1px; height: 15px; background: rgba(160, 190, 225, 0.28); }
/* A virada do dia (topo de cada hora real) dá um flash dourado no rótulo. */
.game-clock.gc-turn .gc-day { animation: gc-day-turn 1.1s ease-out; }
@keyframes gc-day-turn {
  0% { color: var(--gold-bright); text-shadow: 0 0 14px rgba(255, 215, 94, 0.75); }
  100% { color: #dbe8f7; text-shadow: none; }
}

/* Placar: número em destaque + rótulo miúdo. Online em verde (com pinguinho
   pulsando = "ao vivo"); duelos em dourado (conquista acumulada). */
.home-stat { gap: 7px; padding: 8px 14px; }
.home-stat .hs-n { font-size: 15px; font-weight: 900; }
.home-stat .hs-l { font-size: 11px; font-weight: 800; text-transform: uppercase; color: #90a7c3; }
.home-stat--online i { color: #7ee2a8; }
.home-stat--online .hs-live {
  width: 7px; height: 7px; border-radius: 50%; flex: none; background: #55e08b;
  animation: hs-live-pulse 2.2s ease-out infinite;
}
@keyframes hs-live-pulse {
  0% { box-shadow: 0 0 0 0 rgba(85, 224, 139, 0.55); }
  70% { box-shadow: 0 0 0 7px rgba(85, 224, 139, 0); }
  100% { box-shadow: 0 0 0 0 rgba(85, 224, 139, 0); }
}
.home-stat--duels i { color: var(--gold-bright); }
@media (prefers-reduced-motion: reduce) {
  .home-stat--online .hs-live { animation: none; }
  .game-clock.gc-turn .gc-day { animation: none; }
}

/* Home: stage + barra + CTA + card de salas (linguagem de Config/sala). */
.home-stage { width: min(94vw, 900px); margin: 0 auto; padding: 26px 6px 44px; }
.home-bar { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 20px; flex-wrap: wrap; }
.home-bar-title { display: flex; align-items: center; gap: 11px; min-width: 0; font-size: 22px; font-weight: 800; letter-spacing: 0.02em; color: #eef4fc; text-shadow: 0 2px 14px rgba(0, 0, 0, 0.7); }
.home-bar-title i { color: var(--accent-bright); font-size: 25px; }
.home-bar-title b { color: var(--gold-bright); font-weight: 900; }

/* CTA grande "Criar Sala" (chanfrado, acento azul, com glint no hover). */
.home-create {
  width: 100%; margin-bottom: 20px; display: flex; align-items: center; gap: 16px;
  padding: 18px 22px; clip-path: var(--cut-md); border: none; cursor: pointer;
  position: relative; isolation: isolate; overflow: hidden; font-family: inherit; text-align: left;
  background: linear-gradient(120deg, rgba(89, 167, 240, 0.85), rgba(52, 120, 210, 0.85));
  filter: drop-shadow(0 16px 34px rgba(40, 100, 200, 0.4));
  transition: filter 0.16s, transform 0.08s;
}
.home-create::before { content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-md); background: linear-gradient(120deg, rgba(30, 70, 130, 0.96), rgba(16, 34, 64, 0.96)); }
.home-create .hc-ic { flex: none; width: 54px; height: 54px; display: flex; align-items: center; justify-content: center; clip-path: var(--cut-sm); background: rgba(142, 199, 255, 0.16); }
.home-create .hc-ic i { font-size: 32px; color: var(--accent-bright); }
.home-create .hc-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.home-create .hc-t { font-size: 19px; font-weight: 900; letter-spacing: 0.05em; text-transform: uppercase; color: #eef6ff; }
.home-create .hc-s { font-size: 12.5px; font-weight: 600; color: #a9c4e6; }
.home-create .hc-go { flex: none; font-size: 24px; color: var(--accent-bright); transition: transform 0.16s; }
.home-create::after { content: ''; position: absolute; top: 0; bottom: 0; left: -60%; width: 45%; background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.22), transparent); transform: skewX(-18deg); opacity: 0; transition: opacity 0.2s; }
.home-create:hover { filter: brightness(1.06) drop-shadow(0 18px 38px rgba(40, 100, 200, 0.5)); }
.home-create:hover .hc-go { transform: translateX(4px); }
.home-create:hover::after { opacity: 1; animation: cta-glint 0.9s ease-in-out; }
.home-create:active { transform: scale(0.99); }

/* Card "Salas abertas": cabeçalho com título + entrar-por-código. */
.home-rooms-head { justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.code-join { display: flex; align-items: center; gap: 10px; }
.code-join .ui-field { width: 180px; }
.home-rooms .room-list { margin-top: 0; }
.room-list { display: flex; flex-direction: column; gap: 8px; }
.room-empty { padding: 24px; text-align: center; color: #8b93a0; font-size: 13px; display: flex; align-items: center; justify-content: center; gap: 8px; }

@media (max-width: 640px) {
  .home-rooms-head { flex-direction: column; align-items: stretch; padding-left: 0; }
  .code-join { width: 100%; padding: 0 20px 2px; flex-wrap: wrap; }
  .code-join .ui-field { flex: 1; width: auto; }
  /* Empilhado, as abas viram a primeira faixa: sem margem negativa embaixo (o
     traço da ativa passa a separar as abas dos controles, não do corpo). */
  .home-tabs { margin-bottom: 0; border-bottom: 1px solid rgba(140, 165, 200, 0.14); }
  .home-tab { flex: 1; justify-content: center; padding: 14px 10px 13px; }
  .rl-scope { flex: 1 1 100%; min-width: 0; }
  /* Tela curta: a moldura fixa encolhe (a rolagem interna continua). */
  .home-lists { height: 60vh; }
  /* O leque de capas rouba largura de mais numa linha estreita. */
  .rl-covers { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   SALA (rebuild no traço da interface): barra + cards Jogadores/Deck, seleção
   de deck como CARDS com mini-leque de capa. */
.room-stage { width: min(94vw, 860px); margin: 0 auto; padding: 26px 6px 44px; }
.room-bar { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 20px; flex-wrap: wrap; }
.room-bar-title { display: flex; align-items: center; gap: 11px; min-width: 0; font-size: 22px; font-weight: 800; letter-spacing: 0.02em; color: #eef4fc; text-shadow: 0 2px 14px rgba(0, 0, 0, 0.7); }
.room-bar-title i { color: var(--accent-bright); font-size: 25px; }
.room-bar-title span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.room-code { flex: none; display: inline-flex; align-items: center; gap: 6px; clip-path: var(--cut-sm); padding: 7px 13px; background: rgba(255, 255, 255, 0.05); color: var(--steel); font-size: 13px; font-weight: 700; }
.room-code i { color: var(--accent-bright); font-size: 15px; }
.room-code b { color: #eef4fc; font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace; letter-spacing: 0.12em; }
/* Editar o nome da sala (lápis ao lado do título → vira input inline). */
.room-edit { flex: none; border: none; background: rgba(255, 255, 255, 0.06); color: var(--steel); width: 30px; height: 30px; clip-path: var(--cut-sm); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; font-size: 15px; transition: background 0.12s, color 0.12s; }
.room-edit:hover { background: rgba(142, 199, 255, 0.2); color: var(--accent-bright); }
.room-title-input { min-width: 0; max-width: 360px; flex: 1; font-family: inherit; font-size: 20px; font-weight: 800; color: #eef4fc; background: rgba(8, 12, 18, 0.72); border: none; outline: none; clip-path: var(--cut-sm); padding: 4px 12px; }

.room-grid { display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); gap: 20px; align-items: start; }
@media (max-width: 720px) { .room-grid { grid-template-columns: 1fr; } }

/* Lista de jogadores. */
.room-players { display: flex; flex-direction: column; gap: 10px; }
.rp-row { display: flex; align-items: center; gap: 12px; padding: 10px 12px; clip-path: var(--cut-sm); background: rgba(255, 255, 255, 0.04); }
.rp-av { flex: none; width: 38px; height: 38px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 20px; color: var(--accent-bright); background: radial-gradient(circle at 50% 35%, rgba(89, 167, 240, 0.28), rgba(89, 167, 240, 0.05)); }
.rp-info { flex: 1; min-width: 0; }
.rp-name { font-size: 14px; font-weight: 800; color: #eef4fc; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rp-deck { display: flex; align-items: center; gap: 5px; margin-top: 2px; font-size: 11.5px; color: var(--steel); }
.rp-deck i { flex: none; font-size: 13px; color: var(--accent-bright); }
.rp-status { flex: none; display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 800; letter-spacing: 0.03em; text-transform: uppercase; color: var(--steel); }
.rp-status i { font-size: 13px; }
.rp-status.is-on { color: var(--heal); }
/* Assento vazio (só WAITING): convite + habilitar CPU · avatar/remover da CPU. */
.rp-row.rp-empty { border: 1px dashed rgba(142, 165, 200, 0.28); background: rgba(255, 255, 255, 0.015); }
.rp-av.is-empty { color: var(--steel); background: rgba(150, 165, 190, 0.1); }
.rp-av.is-bot { color: #ffcf6b; background: radial-gradient(circle at 50% 35%, rgba(255, 199, 100, 0.28), rgba(255, 199, 100, 0.05)); }
.rp-hint { flex: 1; min-width: 0; font-size: 12.5px; font-weight: 700; color: var(--steel); }
.rp-addbot { flex: none; border: none; cursor: pointer; font-family: inherit; clip-path: var(--cut-sm); padding: 8px 13px; font-size: 12px; font-weight: 800; color: #201a08; background: linear-gradient(180deg, #ffd75e, #e6a72f); display: inline-flex; align-items: center; gap: 6px; transition: filter 0.14s, transform 0.1s; }
.rp-addbot:hover { filter: brightness(1.08); }
.rp-addbot:active { transform: scale(0.96); }
.rp-addbot i { font-size: 15px; }
.rp-remove { flex: none; border: none; cursor: pointer; width: 26px; height: 26px; clip-path: var(--cut-sm); background: rgba(255, 255, 255, 0.06); color: var(--steel); display: inline-flex; align-items: center; justify-content: center; font-size: 14px; transition: background 0.12s, color 0.12s; }
.rp-remove:hover { background: rgba(255, 92, 73, 0.22); color: #fff; }

/* Mini-leque de capa (3 cartas em leque) — reusado no deck escolhido e no modal. */
.rd-fan { position: relative; width: 100%; height: 70px; }
.rd-fan-card { position: absolute; left: 50%; top: 4px; width: 40px; aspect-ratio: 59 / 86; margin-left: -20px; border-radius: 4px; overflow: hidden; background: #0a0e14; box-shadow: 0 4px 9px -3px rgba(0, 0, 0, 0.7); transition: transform 0.16s; }
.rd-fan-card img { width: 100%; height: 100%; object-fit: cover; display: block; }
.rd-fan-card--left { transform: rotate(-14deg) translateX(-13px); z-index: 1; }
.rd-fan-card--right { transform: rotate(14deg) translateX(13px); z-index: 2; }
.rd-fan-card--mid { transform: translateY(-4px); z-index: 3; }

/* Deck ESCOLHIDO na sala (leque + nome/contagem) + botão que abre o modal. */
.room-deck-sel { display: flex; align-items: center; gap: 14px; padding: 11px 14px; position: relative; isolation: isolate; clip-path: var(--cut-sm); background: rgba(140, 158, 182, 0.2); }
.room-deck-sel::before { content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm); background: linear-gradient(168deg, rgba(20, 25, 33, 0.96), rgba(10, 13, 19, 0.95)); }
.room-deck-sel .rd-fan { width: 66px; height: 60px; flex: none; }
.room-deck-sel .rd-fan-card { width: 34px; margin-left: -17px; top: 2px; }
.room-deck-sel .rd-fan-card--left { transform: rotate(-12deg) translateX(-11px); }
.room-deck-sel .rd-fan-card--right { transform: rotate(12deg) translateX(11px); }
.rds-info { min-width: 0; flex: 1; }
.rds-name { font-size: 15px; font-weight: 800; color: #eef4fc; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rds-meta { margin-top: 3px; font-size: 12px; font-weight: 700; color: var(--steel); display: inline-flex; align-items: center; gap: 6px; }
.rds-meta i { color: var(--accent-bright); font-size: 14px; }
.rds-empty { padding: 22px 8px; text-align: center; color: var(--steel); font-size: 13px; }
.rd-pick-btn { width: 100%; margin-top: 12px; border: none; clip-path: var(--cut-sm); cursor: pointer; padding: 11px; position: relative; isolation: isolate; font-family: inherit; font-size: 13.5px; font-weight: 800; letter-spacing: 0.02em; color: #dbe9fa; background: rgba(120, 180, 255, 0.3); display: inline-flex; align-items: center; justify-content: center; gap: 8px; transition: background 0.14s, transform 0.1s; }
.rd-pick-btn:hover { background: rgba(120, 180, 255, 0.46); }
.rd-pick-btn:active { transform: scale(0.98); }
.rd-pick-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.rd-pick-btn i { font-size: 16px; }

/* Modal "Selecionar deck": busca + lista de decks completos. */
.rdm-modal { position: fixed; inset: 0; z-index: 70; display: flex; align-items: center; justify-content: center; padding: 20px; background: rgba(4, 7, 12, 0.72); backdrop-filter: blur(3px); }
.rdm-box { width: min(92vw, 440px); max-height: 82vh; display: flex; flex-direction: column; position: relative; isolation: isolate; clip-path: var(--cut-md); background: rgba(150, 170, 200, 0.28); animation: rdm-in 0.16s ease; }
.rdm-box::before { content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-md); background: linear-gradient(165deg, rgba(20, 26, 36, 0.98), rgba(10, 13, 20, 0.98)); }
@keyframes rdm-in { from { transform: translateY(10px) scale(0.98); opacity: 0; } to { transform: none; opacity: 1; } }
.rdm-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 16px 18px 12px; }
.rdm-head h3 { font-size: 16px; font-weight: 800; color: #eef4fc; display: flex; align-items: center; gap: 9px; }
.rdm-head h3 i { color: var(--accent-bright); }
.rdm-x { border: none; background: rgba(255, 255, 255, 0.06); color: var(--steel); width: 30px; height: 30px; clip-path: var(--cut-sm); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; font-size: 16px; transition: background 0.12s, color 0.12s; }
.rdm-x:hover { background: rgba(255, 92, 73, 0.22); color: #fff; }
.rdm-search { display: flex; align-items: center; gap: 8px; margin: 0 18px 12px; padding: 9px 12px; clip-path: var(--cut-sm); background: rgba(255, 255, 255, 0.06); }
.rdm-search i { color: var(--steel); font-size: 16px; }
.rdm-search input { flex: 1; min-width: 0; background: none; border: none; outline: none; color: #eef4fc; font-family: inherit; font-size: 13.5px; }
.rdm-list { overflow-y: auto; padding: 0 14px 16px; display: flex; flex-direction: column; gap: 8px; }
.rdm-row { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; border: none; cursor: pointer; padding: 9px 11px; clip-path: var(--cut-sm); background: rgba(255, 255, 255, 0.04); transition: background 0.12s; }
.rdm-row:hover { background: rgba(120, 180, 255, 0.16); }
.rdm-row.sel { background: rgba(120, 180, 255, 0.26); }
.rdm-row .rd-fan { width: 56px; height: 52px; flex: none; }
.rdm-row .rd-fan-card { width: 30px; margin-left: -15px; top: 2px; }
.rdm-row .rd-fan-card--left { transform: rotate(-12deg) translateX(-10px); }
.rdm-row .rd-fan-card--right { transform: rotate(12deg) translateX(10px); }
.rdm-info { min-width: 0; flex: 1; }
.rdm-name { font-size: 13.5px; font-weight: 800; color: #eef4fc; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rdm-meta { margin-top: 2px; font-size: 11px; font-weight: 700; color: var(--steel); font-variant-numeric: tabular-nums; }
.rdm-row .rdm-check { flex: none; color: var(--accent-bright); font-size: 18px; opacity: 0; }
.rdm-row.sel .rdm-check { opacity: 1; }
.rdm-empty { padding: 26px 8px; text-align: center; color: var(--steel); font-size: 13px; }

/* Modal "Duelar contra a CPU": dificuldade (3 cards chanfrados) + roster.
   Mesmo traço da tela de Config: card com clip-path + ::before de 1px que
   recolore no hover/seleção — aqui a cor identifica o NÍVEL. */
.cpu-box { width: min(94vw, 560px); }
.cpu-section-label { margin: 2px 18px 8px; font-size: 10.5px; font-weight: 900; letter-spacing: 0.14em; text-transform: uppercase; color: var(--steel); }
.cpu-levels { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin: 0 18px 14px; }
.cpu-lv { position: relative; isolation: isolate; border: none; cursor: pointer; font-family: inherit; text-align: left; padding: 11px 12px; clip-path: var(--cut-sm); background: rgba(142, 165, 200, 0.3); transition: background 0.14s, transform 0.1s; }
.cpu-lv::before { content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm); background: rgba(16, 21, 29, 0.96); transition: background 0.14s; }
.cpu-lv:hover { transform: translateY(-1px); }
.cpu-lv-icon { font-size: 19px; color: var(--steel); transition: color 0.14s; }
.cpu-lv-name { margin-top: 5px; font-size: 13px; font-weight: 900; color: #eef4fc; }
.cpu-lv-desc { margin-top: 3px; font-size: 10.5px; line-height: 1.35; color: var(--steel); }
.cpu-lv.lv-easy:hover, .cpu-lv.lv-easy.sel { background: rgba(52, 214, 126, 0.75); }
.cpu-lv.lv-normal:hover, .cpu-lv.lv-normal.sel { background: rgba(120, 180, 255, 0.8); }
.cpu-lv.lv-hard:hover, .cpu-lv.lv-hard.sel { background: rgba(255, 199, 100, 0.8); }
.cpu-lv.lv-easy.sel .cpu-lv-icon { color: #34d67e; }
.cpu-lv.lv-normal.sel .cpu-lv-icon { color: var(--accent-bright); }
.cpu-lv.lv-hard.sel .cpu-lv-icon { color: #ffcf6b; }
.cpu-lv.sel::before { background: rgba(22, 29, 40, 0.96); }
.cpu-lv.sel .cpu-lv-desc { color: #b9c8dc; }

.cpu-list { max-height: 34vh; }
.cpu-av { flex: none; width: 34px; height: 34px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 17px; color: var(--accent-bright); background: radial-gradient(circle at 50% 35%, rgba(89, 167, 240, 0.26), rgba(89, 167, 240, 0.05)); }
.cpu-row.sel .cpu-av { color: #ffcf6b; background: radial-gradient(circle at 50% 35%, rgba(255, 199, 100, 0.28), rgba(255, 199, 100, 0.05)); }
.cpu-tier { flex: none; padding: 3px 8px; clip-path: var(--cut-sm); font-size: 10px; font-weight: 900; letter-spacing: 0.05em; text-transform: uppercase; }
.cpu-tier.tier-starter { color: #a9e8c6; background: rgba(52, 214, 126, 0.18); }
.cpu-tier.tier-standard { color: #b6d6ff; background: rgba(120, 180, 255, 0.18); }
.cpu-tier.tier-elite { color: #ffd79a; background: rgba(255, 199, 100, 0.2); }

.cpu-confirm { margin: 4px 18px 18px; border: none; clip-path: var(--cut-sm); cursor: pointer; padding: 12px; font-family: inherit; font-size: 14px; font-weight: 900; letter-spacing: 0.06em; text-transform: uppercase; color: #201a08; background: linear-gradient(180deg, #ffd75e, #e6a72f); display: inline-flex; align-items: center; justify-content: center; gap: 8px; transition: filter 0.14s, transform 0.1s; }
.cpu-confirm:hover { filter: brightness(1.08); }
.cpu-confirm:active { transform: scale(0.98); }
.cpu-confirm i { font-size: 17px; }

/* Assento da CPU: nome + selo de dificuldade em cima, arquétipo embaixo. O selo
   nunca encolhe; quem trunca é o texto (a fileira do assento é estreita). */
.rp-row .rp-name { display: flex; align-items: center; gap: 7px; min-width: 0; }
.rp-nametext { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rp-row .rp-deck { min-width: 0; }
.rp-theme { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rp-level { flex: none; display: inline-flex; align-items: center; gap: 4px; padding: 2px 7px; clip-path: var(--cut-sm); font-size: 10px; font-weight: 900; letter-spacing: 0.04em; text-transform: uppercase; }
.rp-level i { font-size: 12px; }
.rp-level.lv-easy { color: #a9e8c6; background: rgba(52, 214, 126, 0.18); }
.rp-level.lv-normal { color: #b6d6ff; background: rgba(120, 180, 255, 0.18); }
.rp-level.lv-hard { color: #ffd79a; background: rgba(255, 199, 100, 0.2); }

/* PRONTO (verde) / Cancelar (neutro) · contagem · RPS · escolha · Sair. */
.room-ready { width: 100%; margin-top: 16px; border: none; clip-path: var(--cut-sm); cursor: pointer; padding: 13px; font-family: inherit; font-size: 15px; font-weight: 900; letter-spacing: 0.06em; text-transform: uppercase; color: #06231a; background: linear-gradient(180deg, #34d67e, #12a355); display: inline-flex; align-items: center; justify-content: center; gap: 8px; transition: filter 0.14s, transform 0.1s; }
.room-ready:hover { filter: brightness(1.1); }
.room-ready:active { transform: scale(0.98); }
.room-ready.is-cancel { color: #1a1f27; background: linear-gradient(180deg, #d3dbe6, #97a4b5); }

.room-countdown { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px; padding: 30px 0 26px; }
.rc-ring { width: 108px; height: 108px; border-radius: 50%; display: flex; align-items: center; justify-content: center; position: relative; background: radial-gradient(circle at 50% 40%, rgba(89, 167, 240, 0.22), rgba(89, 167, 240, 0.04)); box-shadow: inset 0 0 0 2px rgba(142, 199, 255, 0.35), 0 0 34px -6px rgba(89, 167, 240, 0.5); }
.rc-ring::before { content: ''; position: absolute; inset: -4px; border-radius: 50%; border: 3px solid transparent; border-top-color: var(--accent-bright); animation: rc-spin 1s linear infinite; }
@keyframes rc-spin { to { transform: rotate(360deg); } }
#rc-num { font-size: 50px; font-weight: 900; color: #eef4fc; font-variant-numeric: tabular-nums; text-shadow: 0 2px 14px rgba(89, 167, 240, 0.6); }
@keyframes rc-pop { 0% { transform: scale(0.5); opacity: 0.2; } 60% { transform: scale(1.14); } 100% { transform: scale(1); opacity: 1; } }
.rc-label { font-size: 12px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--gold-bright); }

.rps-choices { display: flex; justify-content: center; gap: 12px; margin: 8px 0 4px; }
.rps-pick { flex: 1; max-width: 128px; display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 18px 8px; border: none; cursor: pointer; position: relative; isolation: isolate; clip-path: var(--cut-sm); font-family: inherit; color: #dbe9fa; background: rgba(120, 180, 255, 0.28); transition: transform 0.14s, background 0.14s, box-shadow 0.14s; }
.rps-pick::before { content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm); background: linear-gradient(168deg, rgba(22, 30, 42, 0.92), rgba(12, 17, 26, 0.92)); transition: background 0.14s; }
.rps-pick i { font-size: 36px; color: var(--accent-bright); }
.rps-pick span { font-size: 12px; font-weight: 800; letter-spacing: 0.03em; }
.rps-pick:hover { transform: translateY(-4px); box-shadow: 0 12px 26px -12px rgba(90, 160, 240, 0.6); }
.rps-pick:hover::before { background: linear-gradient(168deg, rgba(30, 46, 66, 0.95), rgba(16, 24, 38, 0.95)); }
.rps-pick.chosen { background: var(--accent-bright); }
.rps-pick.chosen::before { background: linear-gradient(168deg, rgba(28, 44, 64, 0.6), rgba(16, 26, 40, 0.6)); }
.rps-pick.chosen i, .rps-pick.chosen span { color: #cfe6ff; }
.rps-pick.dim { opacity: 0.35; }
.rps-pick:disabled { cursor: default; }
.rps-pick.dim:hover { transform: none; box-shadow: none; }
.rps-pick.dim:hover::before { background: linear-gradient(168deg, rgba(22, 30, 42, 0.92), rgba(12, 17, 26, 0.92)); }
.rps-status { min-height: 18px; margin-top: 16px; text-align: center; font-size: 13px; font-weight: 700; color: var(--gold-bright); }

.rps-choice { display: flex; flex-direction: column; align-items: center; gap: 18px; padding: 14px 0 8px; }
.rps-choice-msg { text-align: center; font-size: 14.5px; font-weight: 700; color: #eef4fc; line-height: 1.55; }
.rps-choice-msg b { color: var(--gold-bright); }
.rps-choice-actions { display: flex; gap: 12px; width: 100%; }
.choice-btn { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 17px 10px; border: none; cursor: pointer; position: relative; isolation: isolate; clip-path: var(--cut-sm); font-family: inherit; color: #eaf2fd; background: rgba(120, 180, 255, 0.28); transition: transform 0.14s, background 0.14s; }
.choice-btn::before { content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm); background: linear-gradient(168deg, rgba(22, 30, 42, 0.92), rgba(12, 17, 26, 0.92)); }
.choice-btn i { font-size: 28px; color: var(--accent-bright); }
.choice-btn span { font-size: 12.5px; font-weight: 800; letter-spacing: 0.02em; }
.choice-btn:hover { transform: translateY(-3px); }
#btn-go-first { background: rgba(52, 214, 126, 0.32); }
#btn-go-first i { color: var(--heal); }

/* Overlay de VERSUS: sobe por cima de tudo quando o duelo arranca (fixed). */
.versus-overlay { position: fixed; inset: 0; z-index: 120; display: flex; align-items: center; justify-content: center; overflow: hidden; background: radial-gradient(circle at 50% 50%, rgba(10, 16, 26, 0.93), rgba(4, 6, 11, 0.985)); }
.versus-overlay .vs-side { display: flex; flex-direction: column; align-items: center; gap: 12px; width: min(38vw, 360px); padding: 24px; }
.vs-left { animation: vs-in-l 0.6s cubic-bezier(0.2, 0.9, 0.25, 1) both; }
.vs-right { animation: vs-in-r 0.6s cubic-bezier(0.2, 0.9, 0.25, 1) both; }
@keyframes vs-in-l { from { transform: translateX(-70vw); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes vs-in-r { from { transform: translateX(70vw); opacity: 0; } to { transform: none; opacity: 1; } }
.vs-av { width: 96px; height: 96px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 52px; color: var(--accent-bright); background: radial-gradient(circle at 50% 35%, rgba(89, 167, 240, 0.32), rgba(89, 167, 240, 0.05)); box-shadow: 0 0 42px -8px rgba(89, 167, 240, 0.6); }
.vs-right .vs-av { color: var(--danger); background: radial-gradient(circle at 50% 35%, rgba(255, 92, 73, 0.3), rgba(255, 92, 73, 0.05)); box-shadow: 0 0 42px -8px rgba(255, 92, 73, 0.55); }
.vs-name { font-size: 22px; font-weight: 900; color: #eef4fc; text-align: center; text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6); }
.vs-deck { font-size: 13px; font-weight: 700; color: var(--steel); text-align: center; display: inline-flex; align-items: center; gap: 6px; }
.vs-deck i { color: var(--accent-bright); }
.vs-center { flex: none; z-index: 2; }
.vs-word { display: inline-block; font-size: clamp(64px, 12vw, 152px); font-weight: 900; font-style: italic; letter-spacing: 0.02em; color: #fff; text-shadow: 0 0 34px rgba(255, 215, 94, 0.6), 0 6px 0 rgba(0, 0, 0, 0.4); animation: vs-pop 0.5s 0.22s both; }
@keyframes vs-pop { 0% { transform: scale(0); } 70% { transform: scale(1.25); } 100% { transform: scale(1); } }
.versus-overlay.out { animation: vs-fade 0.5s ease forwards; }
@keyframes vs-fade { to { opacity: 0; } }
@media (max-width: 640px) {
  .versus-overlay { flex-direction: column; gap: 6px; }
  .versus-overlay .vs-side { width: min(80vw, 320px); padding: 12px; gap: 8px; }
  .vs-av { width: 68px; height: 68px; font-size: 36px; }
  .vs-name { font-size: 17px; }
}

.room-leave { display: flex; width: fit-content; margin: 22px auto 0; }

/* ── Configurações (screen-settings) — paleta preta ────────────────────────*/
/* ══════════════════════════════════════════════════════════════════════════
   CONFIGURAÇÕES — barra (título + Voltar) + grade de cards que USA a largura
   (Conta | Áudio+Idioma), em vez de uma coluna estreita e comprida. Tema
   neutro; sliders de volume custom com preenchimento (--fill) e % ao vivo. */
#screen-settings .ui-field { background: rgba(150, 160, 175, 0.22); }
#screen-settings .ui-field:focus-within { background: var(--accent); }
#screen-settings .ui-btn--ghost::before { background: rgba(20, 27, 38, 0.85); }
#screen-settings .ui-btn--primary { color: #06131c; background: linear-gradient(180deg, #86c6ff, #3f86e0); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14); }
#screen-settings .ui-btn--primary::before { display: none; }
#screen-settings .ui-btn--primary:hover { filter: brightness(1.12); }

.settings-stage { width: min(96vw, 1040px); margin: 0 auto; padding: 26px 6px 48px; }
.settings-bar { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 22px; }
.settings-title {
  display: flex; align-items: center; gap: 11px;
  font-size: 23px; font-weight: 800; letter-spacing: 0.03em; color: #eef4fc;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.7);
}
.settings-title i { color: var(--accent-bright); font-size: 26px; }

.settings-grid { display: grid; grid-template-columns: minmax(0, 1.02fr) minmax(0, 0.98fr); gap: 20px; align-items: start; }
.settings-col { display: flex; flex-direction: column; gap: 20px; }
@media (max-width: 780px) { .settings-grid { grid-template-columns: 1fr; } }

/* Card chanfrado (borda clara via ::before inset 1px) com cabeçalho e corpo. */
.set-card {
  position: relative; clip-path: var(--cut-md); isolation: isolate;
  background: rgba(140, 158, 182, 0.20);
  filter: drop-shadow(0 16px 34px rgba(0, 0, 0, 0.42));
}
.set-card::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-md);
  background: linear-gradient(168deg, rgba(20, 25, 33, 0.96), rgba(10, 13, 19, 0.95));
  backdrop-filter: blur(9px);
}
.set-card-head {
  display: flex; align-items: center; gap: 10px; padding: 14px 20px;
  border-bottom: 1px solid rgba(140, 165, 200, 0.14);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), transparent);
}
.set-card-head i { color: var(--accent-bright); font-size: 20px; }
.set-card-head h3 { font-size: 14px; font-weight: 800; letter-spacing: 0.07em; text-transform: uppercase; color: #e6eef8; }
.set-card-body { padding: 20px; display: flex; flex-direction: column; gap: 14px; }

/* Grupos do card de Conta (nome / senha), separados por um divisor. */
.set-group { display: flex; flex-direction: column; gap: 10px; }
.set-group-label {
  display: flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 700; letter-spacing: 0.03em; color: var(--steel);
}
.set-group-label i { color: var(--accent-bright); font-size: 15px; }
.set-group .ui-btn { width: 100%; margin-top: 2px; }
.set-divider { height: 1px; background: linear-gradient(90deg, transparent, rgba(150, 175, 210, 0.22), transparent); }

/* ── Sliders de volume (custom): ícone · rótulo · trilha c/ fill · % ──────── */
.vol-row { display: flex; align-items: center; gap: 13px; }
.vol-row + .vol-row { margin-top: 15px; }
.vol-ico { flex: none; width: 20px; text-align: center; font-size: 17px; color: var(--accent-bright); transition: color 0.2s; }
.vol-label { flex: none; width: 60px; font-size: 12.5px; font-weight: 700; letter-spacing: 0.03em; color: #cbd6e4; }
.vol-slider { flex: 1; min-width: 0; height: 20px; background: transparent; cursor: pointer; -webkit-appearance: none; appearance: none; }
.vol-slider::-webkit-slider-runnable-track {
  height: 6px; border-radius: 999px;
  background: linear-gradient(90deg, var(--accent) var(--fill, 50%), rgba(255, 255, 255, 0.13) var(--fill, 50%));
}
.vol-slider::-moz-range-track { height: 6px; border-radius: 999px; background: rgba(255, 255, 255, 0.13); }
.vol-slider::-moz-range-progress { height: 6px; border-radius: 999px; background: var(--accent); }
.vol-slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; margin-top: -5px;
  width: 16px; height: 16px; border-radius: 50%;
  background: #eaf3ff; border: 2px solid var(--accent-bright);
  box-shadow: 0 0 9px rgba(89, 167, 240, 0.65); transition: transform 0.1s;
}
.vol-slider::-moz-range-thumb {
  width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--accent-bright);
  background: #eaf3ff; box-shadow: 0 0 9px rgba(89, 167, 240, 0.65);
}
.vol-slider:hover::-webkit-slider-thumb { transform: scale(1.12); }
.vol-slider:active::-webkit-slider-thumb { transform: scale(1.2); }
.vol-slider:hover::-moz-range-thumb { transform: scale(1.12); }
.vol-val { flex: none; width: 42px; text-align: right; font-size: 12px; font-weight: 800; color: #dbe7f5; font-variant-numeric: tabular-nums; }
.vol-row.is-muted .vol-ico, .vol-row.is-muted .vol-val { color: #6b7789; }
.vol-row.is-muted .vol-slider::-webkit-slider-thumb { border-color: #6b7789; box-shadow: none; }
.vol-row.is-muted .vol-slider::-moz-range-thumb { border-color: #6b7789; box-shadow: none; }

/* Seletor de idioma. */
.set-select-row { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.set-select-row span { font-size: 13px; font-weight: 600; color: #cbd6e4; }
.set-select {
  appearance: none; -webkit-appearance: none;   /* remove a seta nativa (torta no chanfro) */
  flex: none; min-width: 172px; padding: 9px 34px 9px 13px; cursor: pointer;
  clip-path: var(--cut-sm); border: none; outline: none;
  color: #eaf2fb; font-family: inherit; font-size: 13px; font-weight: 600;
  /* Seta própria (chevron): posicionada com precisão, centralizada na vertical. */
  background-color: rgba(150, 160, 175, 0.24);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 16 16' fill='none' stroke='%239fb4c8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
}
.set-select:hover { background-color: rgba(150, 160, 175, 0.30); }
.set-select:focus { background-color: rgba(150, 160, 175, 0.36); }
.set-select option { background: #12151b; color: #eaf2fb; }

.settings-msg { margin: 2px 2px 0; min-height: 17px; font-size: 12.5px; font-weight: 600; text-align: center; }
.settings-msg.is-ok { color: var(--heal); }
.settings-msg.is-err { color: #ff8a7a; }

/* ══════════════════════════════════════════════════════════════════════════
   MONTADOR DE DECKS — editor em 3 colunas (detalhe · deck+extra · pool).
   Cartas exibidas como IMAGENS (grade); painéis reusam .ui-panel (chanfro).
   ══════════════════════════════════════════════════════════════════════════ */
/* Lista "Meus Decks" — mesmo traço da tela de Configurações: stage largo, barra
   (título + ações) e cards CHANFRADOS (clip-path + borda clara via ::before, que
   dá pra recolorir no hover trocando o `background` do card). */
.decks-stage { width: min(96vw, 1040px); margin: 0 auto; padding: 26px 6px 48px; }
.decks-bar { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 22px; flex-wrap: wrap; }
.decks-title { display: flex; align-items: center; gap: 11px; font-size: 23px; font-weight: 800; letter-spacing: 0.03em; color: #eef4fc; text-shadow: 0 2px 14px rgba(0, 0, 0, 0.7); }
.decks-title i { color: var(--accent-bright); font-size: 26px; }
.decks-bar-tools { display: flex; gap: 10px; }
#screen-decks .ui-btn--ghost::before { background: rgba(20, 27, 38, 0.85); }
#screen-decks .ui-btn--primary { color: #06131c; background: linear-gradient(180deg, #86c6ff, #3f86e0); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14); }
#screen-decks .ui-btn--primary::before { display: none; }
#screen-decks .ui-btn--primary:hover { filter: brightness(1.12); }

.deck-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 18px; }
.deck-empty { grid-column: 1 / -1; color: var(--steel); font-size: 14px; padding: 40px; text-align: center; }
.deck-card {
  position: relative; clip-path: var(--cut-md); isolation: isolate;
  display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 20px 16px 16px;
  background: rgba(140, 158, 182, 0.22);
  filter: drop-shadow(0 14px 30px rgba(0, 0, 0, 0.42));
  transition: transform 0.14s, background 0.14s, filter 0.14s;
}
.deck-card::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-md);
  background: linear-gradient(168deg, rgba(20, 25, 33, 0.96), rgba(10, 13, 19, 0.95));
  backdrop-filter: blur(9px);
}
.deck-card:hover { transform: translateY(-4px); background: rgba(89, 167, 240, 0.6); filter: drop-shadow(0 20px 40px rgba(0, 0, 0, 0.5)); }
.deck-card.is-draft { background: rgba(232, 192, 100, 0.45); }
.deck-card.is-draft:hover { background: rgba(232, 192, 100, 0.72); }
.deck-card-title {
  width: 100%; text-align: center; font-size: 15px; font-weight: 800; color: #eef4fc;
  letter-spacing: 0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Leque de 3 cartas (capa escolhida ou verso), sobrepostas como uma "mão". */
.deck-fan { position: relative; width: 100%; height: 106px; margin: 4px 0 2px; }
.fan-card {
  position: absolute; left: 50%; top: 6px; width: 58px; aspect-ratio: 59 / 86; margin-left: -29px;
  border-radius: 5px; overflow: hidden; background: #0a0e14; transform-origin: 50% 90%;
  box-shadow: 0 6px 14px -4px rgba(0, 0, 0, 0.7); transition: transform 0.18s ease;
}
.fan-card img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fan-card--left { transform: rotate(-15deg) translateX(-23px); z-index: 1; }
.fan-card--right { transform: rotate(15deg) translateX(23px); z-index: 2; }
.fan-card--mid { transform: translateY(-6px); z-index: 3; box-shadow: 0 9px 18px -4px rgba(0, 0, 0, 0.78); }
.deck-card:hover .fan-card--left { transform: rotate(-20deg) translateX(-30px); }
.deck-card:hover .fan-card--right { transform: rotate(20deg) translateX(30px); }
.deck-card:hover .fan-card--mid { transform: translateY(-11px); }

/* Infos em lista (principal · extra · status), uma abaixo da outra. */
.deck-card-info { width: 100%; display: flex; flex-direction: column; gap: 5px; margin-top: 2px; }
.di-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: 12px; }
.di-label { display: inline-flex; align-items: center; gap: 6px; color: var(--steel); font-weight: 600; }
.di-label i { color: var(--accent-bright); font-size: 14px; }
.di-val { color: #eef4fc; font-weight: 800; font-variant-numeric: tabular-nums; }
.di-status { justify-content: flex-start; margin-top: 2px; }
.di-status .di-label { font-weight: 700; }
.di-status.is-ready .di-label, .di-status.is-ready .di-label i { color: var(--heal); }
.di-status.is-draft .di-label, .di-status.is-draft .di-label i { color: var(--gold-bright); }
.deck-card-actions { display: flex; gap: 8px; width: 100%; margin-top: 8px; }
.deck-card-edit {
  flex: 1; border: none; clip-path: var(--cut-sm); padding: 9px; cursor: pointer;
  font-family: inherit; font-size: 13px; font-weight: 800; color: #06131c;
  background: linear-gradient(180deg, #86c6ff, #3f86e0); display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  transition: filter 0.14s, transform 0.1s;
}
.deck-card-edit:hover { filter: brightness(1.1); }
.deck-card-edit:active, .deck-card-del:active { transform: scale(0.95); }
.deck-card-del {
  border: none; clip-path: var(--cut-sm); padding: 9px 12px; cursor: pointer;
  color: #fca5a5; background: rgba(120, 30, 30, 0.5); font-size: 15px; transition: background 0.14s, color 0.14s;
}
.deck-card-del:hover { background: rgba(150, 35, 35, 0.72); color: #ffd7d1; }

/* MESMO tom dos cards da tela de Config e da home (e dos cards de "Meus decks",
   logo abaixo): a borda levemente azulada e o miolo quase preto com blur. As
   colunas do editor eram mais cinzas/escuras e destoavam do resto. */
#screen-decks .ui-panel { background: rgba(140, 158, 182, 0.20); filter: drop-shadow(0 16px 34px rgba(0, 0, 0, 0.42)); }
#screen-decks .ui-panel::before { background: linear-gradient(168deg, rgba(20, 25, 33, 0.96), rgba(10, 13, 19, 0.95)); backdrop-filter: blur(9px); }

.de-stage {
  height: calc(100vh - 66px); overflow: hidden;
  display: flex; flex-direction: column;
  padding: 14px clamp(14px, 2.5vw, 34px) clamp(12px, 2.5vh, 26px);
}
.de-stage.hidden { display: none; }

/* Barra superior: título + nome + status + salvar/voltar. */
.de-bar { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 12px; flex-wrap: wrap; }
.de-bar h2 { display: flex; align-items: center; gap: 9px; font-size: 19px; font-weight: 800; letter-spacing: 0.03em; color: #eef4fc; }
.de-bar h2 span { color: var(--accent-bright); }
.de-bar-tools { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* Linha do nome do deck (coluna CENTRAL): campo do kit (lápis à esquerda) +
   botão de "cartas de capa" à direita — o MESMO par da busca do pool. */
.de-name-row { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
.de-name-field { flex: 1; min-width: 0; display: flex; align-items: center; }
.de-name-ico { position: absolute; left: 13px; z-index: 1; color: var(--accent-bright); font-size: 16px; pointer-events: none; }
/* Seletor com DOIS níveis de propósito: `.ui-field input` (0,1,1) vence uma
   classe sozinha, e era ele quem devolvia o padding de 13px — o nome do deck
   subia por cima do lápis. 13 (folga) + 16 (lápis) + 11 (respiro) = 40. */
.de-name-field .de-name {
  position: relative; flex: 1; min-width: 0; border: none; background: transparent; outline: none;
  padding: 11px 13px 11px 40px; color: #eaf2fb; font-family: inherit; font-size: 15px; font-weight: 700;
  text-align: left;
}
.de-name::placeholder { color: #7f93a8; font-weight: 600; }
.de-cover-btn {
  flex: none; position: relative; border: none; clip-path: var(--cut-sm); isolation: isolate; cursor: pointer;
  width: 42px; height: 40px; display: inline-flex; align-items: center; justify-content: center;
  color: #dbe9fa; background: rgba(120, 180, 255, 0.5); font-size: 18px; transition: filter 0.14s, transform 0.1s;
}
.de-cover-btn::before { content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm); background: rgba(20, 27, 38, 0.85); }
.de-cover-btn:hover { filter: brightness(1.18); }
.de-cover-btn:active { transform: scale(0.94); }
.de-cover-btn.has-cover { color: var(--gold-bright); background: rgba(232, 192, 100, 0.6); }
.de-cover-btn.has-cover::before { background: rgba(32, 27, 12, 0.85); }

/* Lupa da área de informações: mora no canto superior direito do painel, sobre a
   folga que o `padding-top` do corpo já deixava. É só o ÍCONE — sem caixa, sem
   borda: num painel que já é todo moldura, mais um botão desenhado competiria
   com a carta. O hover clareia, e é isso que diz que ele é clicável. Some junto
   com a carta — sem carta em foco ela não teria o que abrir. */
.de-detail > .card-zoom {
  position: absolute; top: 12px; right: 12px; z-index: 9;
  padding: 4px; border: none; background: none; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  color: #7c8b9d; font-size: 19px; line-height: 1;
  transition: color 0.14s, transform 0.1s;
}
.de-detail > .card-zoom:hover { color: #dceaf9; }
.de-detail > .card-zoom:active { transform: scale(0.9); }
.de-detail > .card-zoom.hidden { display: none; }

/* Modal do picker de cartas de capa (grade das cartas do deck; escolhe até 3). */
.cover-modal { position: fixed; inset: 0; z-index: 80; display: flex; align-items: center; justify-content: center; padding: 20px; background: rgba(4, 6, 10, 0.72); backdrop-filter: blur(4px); }
.cover-modal.hidden { display: none; }
.cover-box { position: relative; clip-path: var(--cut-md); isolation: isolate; width: min(92vw, 720px); max-height: 84vh; display: flex; flex-direction: column; background: rgba(140, 158, 182, 0.24); filter: drop-shadow(0 24px 50px rgba(0, 0, 0, 0.6)); }
.cover-box::before { content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-md); background: linear-gradient(168deg, rgba(20, 25, 33, 0.98), rgba(10, 13, 19, 0.97)); }
.cover-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 20px; border-bottom: 1px solid rgba(140, 165, 200, 0.14); }
.cover-head h3 { display: flex; align-items: center; gap: 9px; font-size: 15px; font-weight: 800; letter-spacing: 0.04em; color: #e6eef8; }
.cover-head h3 i { color: var(--accent-bright); font-size: 19px; }
.cover-hint { font-size: 11px; font-weight: 700; color: var(--steel); background: rgba(255, 255, 255, 0.06); border-radius: 999px; padding: 2px 9px; }
.cover-close { border: none; background: transparent; cursor: pointer; color: var(--steel); font-size: 20px; padding: 4px; display: inline-flex; transition: color 0.14s; }
.cover-close:hover { color: #fff; }
.cover-grid { flex: 1; overflow-y: auto; display: grid; grid-template-columns: repeat(auto-fill, minmax(74px, 1fr)); gap: 10px; padding: 18px 20px; }
.cover-empty { grid-column: 1 / -1; text-align: center; color: var(--steel); font-size: 13px; padding: 34px; }
.cover-cell { position: relative; padding: 0; border: 2px solid transparent; border-radius: 6px; background: none; cursor: pointer; aspect-ratio: 59 / 86; overflow: hidden; transition: transform 0.1s, border-color 0.12s; }
.cover-cell img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 4px; transition: filter 0.12s; }
.cover-cell:hover { transform: translateY(-2px); }
.cover-cell:not(.sel) img { filter: brightness(0.82); }
.cover-cell.sel { border-color: var(--accent-bright); box-shadow: 0 0 12px -2px rgba(89, 167, 240, 0.7); }
.cover-badge { position: absolute; top: 4px; left: 4px; width: 20px; height: 20px; border-radius: 50%; background: var(--accent-bright); color: var(--abyss); font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.5); }
.cover-foot { display: flex; justify-content: flex-end; gap: 10px; padding: 14px 20px; border-top: 1px solid rgba(140, 165, 200, 0.14); }

/* ── Seletor de VISUAL da carta (acabamento · arte) ──────────────────────
   Mesma caixa do picker de capa; o que muda é que cada opção é a PRÓPRIA carta
   já com o visual aplicado — mostrar o efeito num quadrado abstrato não diria
   nada ao jogador. */
.skin-box { width: min(92vw, 660px); }
.skin-switch { margin: 0 20px; }
.skin-grid {
  flex: 1; overflow-y: auto; display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 14px; padding: 18px 20px;
}
.skin-cell {
  display: flex; flex-direction: column; gap: 7px; padding: 0; border: none;
  background: none; cursor: pointer; font-family: inherit; transition: transform 0.12s;
}
.skin-cell:hover { transform: translateY(-3px); }
.skin-frame {
  position: relative; display: block; aspect-ratio: 59 / 86; border-radius: 6px; overflow: hidden;
  box-shadow: 0 0 0 2px transparent, 0 10px 24px -8px rgba(0, 0, 0, 0.8); transition: box-shadow 0.14s;
}
.skin-frame img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* A opção não escolhida recua com OPACIDADE, não com `filter`: cada acabamento
   filtra a arte do seu jeito (o Reverse Holo não filtra nada, a Vibrance satura)
   e um brightness por cima apagaria justamente a diferença que se está julgando. */
.skin-cell:not(.sel) .skin-frame { opacity: 0.82; }
.skin-cell.sel .skin-frame { box-shadow: 0 0 0 2px var(--accent-bright), 0 0 16px -2px rgba(89, 167, 240, 0.75); }
.skin-cap {
  font-size: 11px; font-weight: 700; line-height: 1.25; color: #9dabbb; text-align: center;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.skin-cell.sel .skin-cap { color: var(--accent-bright); }
.skin-frame[data-fx] .fx-lay { border-radius: 6px; }

/* ── LUPA: a carta grande, girável nas duas mãos ─────────────────────────
   Ocupa a tela inteira e escurece o resto — aqui só existe a carta. Ela tem
   DUAS faces num `preserve-3d`, então passar dos 90° mostra o verso de verdade
   em vez de espelhar a arte. O rodapé é prova de roupa: troca acabamento e arte
   sem gravar nada. */
.viewer-modal {
  position: fixed; inset: 0; z-index: 95; display: flex; flex-direction: column;
  background: rgba(3, 5, 9, 0.88); backdrop-filter: blur(7px);
}
.viewer-modal.hidden { display: none; }
.viewer-bar { flex: none; display: flex; align-items: center; gap: 14px; padding: 16px 22px; }
.viewer-name {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 15px; font-weight: 800; letter-spacing: 0.04em; color: #e6eef8;
}
.viewer-name i { color: var(--accent-bright); font-size: 20px; }
.viewer-hint {
  margin-left: auto; display: inline-flex; align-items: center; gap: 7px;
  font-size: 11.5px; font-weight: 600; color: #6f7f92;
}
.viewer-hint i { font-size: 15px; }

.viewer-stage {
  flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center;
  perspective: 1700px; cursor: grab; touch-action: none; user-select: none;
}
.viewer-stage.is-turning { cursor: grabbing; }
/* O bamboleio de repouso mora num elemento SEPARADO do que o arraste escreve:
   animação e estilo inline brigam na cascata, e a animação sempre ganha. */
.viewer-sway { transform-style: preserve-3d; animation: viewer-sway 11s ease-in-out infinite; }
@keyframes viewer-sway {
  0%, 100% { transform: rotateY(-5deg) rotateX(1.6deg); }
  50% { transform: rotateY(5deg) rotateX(-1.6deg); }
}
.viewer-card {
  position: relative; height: min(60vh, 640px); aspect-ratio: 59 / 86;
  transform-style: preserve-3d;
  transform: rotateX(var(--vx, 0deg)) rotateY(var(--vy, 0deg));
}
.viewer-face {
  position: absolute; inset: 0; border-radius: 12px; overflow: hidden;
  backface-visibility: hidden;
  box-shadow: 0 34px 70px -22px rgba(0, 0, 0, 0.9), 0 0 0 1px rgba(255, 255, 255, 0.06);
}
.viewer-face img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.viewer-face--back { transform: rotateY(180deg); }

/* A prova de roupa: duas fileiras CENTRADAS sob a carta. Nada de nomes soltos —
   o acabamento é um quadradinho da própria arte com o efeito rodando, e a arte é
   uma miniatura da carta; o nome fica na legenda do que está escolhido. */
.viewer-foot {
  flex: none; display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 10px 22px 18px;
}
.viewer-swatches, .viewer-thumbs {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; max-width: min(94vw, 900px);
}
.viewer-thumbs.hidden { display: none; }
/* Traço entre as duas fileiras: elas respondem a perguntas diferentes (como a
   carta BRILHA × qual arte ela usa) e sem a separação viravam uma coisa só. */
.viewer-div {
  width: min(46vw, 340px); height: 1px; margin: 3px 0;
  background: linear-gradient(90deg, transparent, rgba(140, 165, 200, 0.32), transparent);
}
.viewer-div.hidden { display: none; }
.viewer-sw, .viewer-th {
  position: relative; padding: 0; border: none; background: none; cursor: pointer; line-height: 0;
  border-radius: 7px; box-shadow: 0 0 0 2px transparent, 0 6px 16px -8px rgba(0, 0, 0, 0.9);
  transition: box-shadow 0.14s, transform 0.12s, opacity 0.14s;
}
/* Quadradinho: um RECORTE da arte, não a carta inteira — a 46px a carta toda
   vira borrão, e o que se está julgando é o brilho, não a moldura. */
.viewer-sw { width: 46px; height: 46px; }
.viewer-th { width: 46px; aspect-ratio: 59 / 86; }
.viewer-face-sm {
  position: absolute; inset: 0; display: block; border-radius: 7px; overflow: hidden;
}
.viewer-face-sm img { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* O recorte pega a ARTE (terço de cima da carta), não o texto. */
.viewer-sw .viewer-face-sm img { object-fit: cover; object-position: 50% 26%; }
.viewer-th .viewer-face-sm img { object-fit: cover; object-position: 50% 50%; }
.viewer-face-sm[data-fx] .fx-lay { border-radius: 7px; }
.viewer-sw:not(.is-on), .viewer-th:not(.is-on) { opacity: 0.78; }
.viewer-sw:hover, .viewer-th:hover { transform: translateY(-3px); opacity: 1; }
.viewer-sw.is-on, .viewer-th.is-on {
  box-shadow: 0 0 0 2px var(--accent-bright), 0 0 14px -2px rgba(89, 167, 240, 0.8);
}
/* Bloqueado ainda é clicável: aqui nada é vestido, então provar o que não se tem
   é justamente a graça. O cadeado diz que ainda falta destravar — e escolhido,
   a borda vira ouro para casar com o aviso lá embaixo. */
.viewer-sw.is-locked.is-on, .viewer-th.is-locked.is-on {
  box-shadow: 0 0 0 2px var(--gold-bright), 0 0 14px -2px rgba(232, 192, 100, 0.7);
}
/* O selo do quadradinho: diz que ali se escolhe um ACABAMENTO. Branco e
   translúcido, sem fundo — o efeito continua correndo por baixo, que é o que se
   está julgando. `pointer-events: none` para o clique ser sempre do botão. */
.viewer-mark {
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  display: flex; align-items: center; justify-content: center;
  color: rgba(255, 255, 255, 0.62); font-size: 19px; line-height: 1;
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.7));
  transition: color 0.14s;
}
.viewer-sw:hover .viewer-mark { color: rgba(255, 255, 255, 0.85); }
.viewer-sw.is-on .viewer-mark { color: rgba(255, 255, 255, 0.9); }
.viewer-lock {
  position: absolute; right: -3px; bottom: -3px; width: 17px; height: 17px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; z-index: 3;
  background: rgba(8, 11, 16, 0.92); color: #b9c6d6; font-size: 10px; line-height: 1;
  box-shadow: 0 0 0 1px rgba(140, 165, 200, 0.25);
}
.viewer-sw.is-locked.is-on .viewer-lock, .viewer-th.is-locked.is-on .viewer-lock { color: var(--gold-bright); }
.viewer-cap {
  font-size: 11.5px; font-weight: 700; color: #9dabbb; letter-spacing: 0.02em; text-align: center;
}
.viewer-note {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  font-size: 11.5px; font-weight: 600; color: var(--gold-bright); text-align: center;
}
.viewer-note.hidden { display: none; }
.viewer-note i { font-size: 15px; }
@media (max-width: 760px) {
  .viewer-card { height: min(44vh, 400px); }
  .viewer-hint { display: none; }
  .viewer-sw, .viewer-th { width: 38px; }
  .viewer-sw { height: 38px; }
}
@media (prefers-reduced-motion: reduce) {
  .viewer-sway { animation: none; }
}
.de-status { font-size: 12px; font-weight: 800; padding: 4px 11px; border-radius: 999px; }
.de-status.is-ready { color: #0a0e14; background: var(--heal); }
.de-status.is-draft { color: var(--gold-bright); background: rgba(232, 192, 100, 0.16); }
/* Botões do editor no traço da interface: chanfrados (clip-path), com a borda
   clara via ::before. Voltar = ghost; Salvar = primário VERDE (commit). */
.de-btn {
  position: relative; border: none; clip-path: var(--cut-sm); cursor: pointer; isolation: isolate;
  padding: 9px 16px; font-family: inherit; font-size: 13px; font-weight: 800; letter-spacing: 0.02em; color: #dbe9fa;
  background: rgba(120, 180, 255, 0.5); display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  transition: filter 0.14s, transform 0.1s;
}
.de-btn::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm);
  background: rgba(20, 27, 38, 0.85);
}
.de-btn:hover { filter: brightness(1.16); }
.de-btn:active { transform: scale(0.96); }
.de-btn--save { color: #06231a; background: linear-gradient(180deg, #34d67e, #12a355); }
.de-btn--save::before { display: none; }
.de-btn--save:hover { filter: brightness(1.1); }

/* Corpo: 3 colunas que rolam por dentro. */
.de-body { flex: 1; display: flex; gap: 16px; min-height: 0; width: min(100%, 1700px); margin: 0 auto; }
.de-detail, .de-build, .de-pool { display: flex; flex-direction: column; min-height: 0; padding: 14px; }
.de-detail > *, .de-build > *, .de-pool > * { position: relative; }
.de-detail { width: 296px; flex: none; }
.de-build { flex: 1.35; min-width: 0; }
/* `container-type` p/ os filtros reagirem à LARGURA DA COLUNA (que muda com a
   janela E com o layout), não à da janela. Seguro aqui: a largura vem do flex
   (flex-basis 0 + min-width 0), nunca do conteúdo. */
.de-pool { flex: 1.2; min-width: 0; container-type: inline-size; }

/* ── Coluna esquerda: detalhe da carta ─────────────────────────────────── */
.de-empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: var(--steel); text-align: center; font-size: 13px; line-height: 1.5; }
.de-empty i { font-size: 34px; opacity: 0.5; }
/* Quem rola é a caixa do EFEITO: a arte, a posse e as ações ficam sempre à
   vista. O `overflow-y` da coluna é só válvula de escape para janelas muito
   baixas (quando nem o mínimo da caixa de efeito cabe). */
.de-detail-body { display: flex; flex-direction: column; gap: 11px; flex: 1; min-height: 0; overflow-y: auto; padding-top: 24px; }
.de-art { flex: none; }
.de-art img { width: 100%; display: block; border-radius: 6px; box-shadow: 0 8px 20px -6px rgba(0, 0, 0, 0.7); }
.de-info { display: flex; flex-direction: column; gap: 9px; flex: 1 1 auto; min-height: 0; }
.de-name-h { font-size: 16px; font-weight: 800; color: #eef4fc; line-height: 1.2; }
.de-head.kind-monster .de-name-h { color: #f6c667; }
.de-head.kind-spell .de-name-h { color: #6fe0c0; }
.de-head.kind-trap .de-name-h { color: #e59ad0; }
.de-type { font-size: 12px; color: var(--steel); margin-top: 3px; }
.de-stats { flex: none; display: flex; flex-direction: column; gap: 4px; }
/* Duas linhas em vez de cinco. [ATK · nível · DEF]: o nível fica no MEIO e
   ocupa só o que precisa (`auto`), sobrando largura para os números.
   [Atributo · raça]: partes iguais, e `auto-flow` cobre o caso de vir só um. */
.de-stats-trio { display: grid; grid-template-columns: 1fr auto 1fr; gap: 4px; }
.de-stats-duo { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 4px; }
.de-stats-trio .insp-stat, .de-stats-duo .insp-stat { gap: 5px; padding: 5px 8px; }
.de-stats .insp-stat-k { font-size: 10px; letter-spacing: 0.06em; }
.de-stats .insp-stat-v { font-size: 13.5px; }
/* Raça/atributo são palavras (não números): fonte um pouco menor para caber
   inteira em meia coluna — "WINGED BEAST" é o pior caso. */
.de-stats-duo .insp-stat-v { font-size: 12px; letter-spacing: 0; }

/* Caixa do efeito: cabeçalho fixo + texto rolável (a única rolagem da coluna). */
.de-textbox {
  position: relative; isolation: isolate; flex: 1 1 auto; min-height: 66px;
  display: flex; flex-direction: column; clip-path: var(--cut-sm);
  background: rgba(120, 160, 220, 0.26);
}
.de-textbox::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm);
  background: rgba(8, 13, 22, 0.72);
}
.de-textbox-head {
  flex: none; display: flex; align-items: center; gap: 6px; padding: 7px 11px 5px;
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: #7f93a8;
}
.de-textbox-head i { font-size: 13px; color: var(--accent-bright); }
.de-text {
  flex: 1; min-height: 0; overflow-y: auto; padding: 0 11px 9px;
  font-size: 12.5px; line-height: 1.5; color: #c8d4e0; white-space: pre-wrap;
}
/* Barra de rolagem discreta, para a caixa não parecer um campo de formulário. */
.de-text::-webkit-scrollbar { width: 8px; }
.de-text::-webkit-scrollbar-thumb { background: rgba(140, 170, 210, 0.28); }
.de-text::-webkit-scrollbar-track { background: transparent; }

/* Posse: no deck × na coleção, lado a lado. */
.de-own { flex: none; display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
.de-own-cell {
  position: relative; isolation: isolate; display: flex; flex-direction: column; gap: 2px;
  padding: 7px 10px; clip-path: var(--cut-xs); background: rgba(150, 160, 175, 0.22);
}
.de-own-cell::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-xs);
  background: rgba(12, 17, 26, 0.9);
}
.do-l { display: flex; align-items: center; gap: 5px; font-size: 10px; font-weight: 800; letter-spacing: 0.05em; text-transform: uppercase; color: #7f93a8; }
.do-l i { font-size: 12px; }
.do-v { font-size: 15px; font-weight: 900; color: #eaf2fb; font-variant-numeric: tabular-nums; }
.de-own-cell.is-none .do-v { color: #ff8a7a; }
.de-own-cell.is-full .do-v { color: var(--gold-bright); }

/* Ações: adicionar · favoritar · remover (mesma família chanfrada do kit). */
.de-actions { flex: none; display: grid; grid-template-columns: 1fr auto 1fr; gap: 7px; }
.de-act {
  position: relative; isolation: isolate; border: none; cursor: pointer; font-family: inherit;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 9px 8px; clip-path: var(--cut-sm); white-space: nowrap;
  font-size: 11.5px; font-weight: 800; letter-spacing: 0.03em;
  color: #b9c7d8; background: rgba(150, 160, 175, 0.26);
  transition: color 0.14s, background 0.14s, filter 0.14s, transform 0.08s;
}
.de-act::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm);
  background: rgba(14, 19, 28, 0.92); transition: background 0.14s;
}
.de-act i { font-size: 14px; }
.de-act:not(:disabled):hover { color: #eaf2fb; background: rgba(180, 195, 215, 0.45); }
.de-act:not(:disabled):active { transform: scale(0.96); }
.de-act:disabled { cursor: not-allowed; opacity: 0.38; }
.de-act--add:not(:disabled) { color: #bfe2ff; background: var(--accent); }
.de-act--add:not(:disabled)::before { background: rgba(16, 40, 72, 0.92); }
.de-act--add:not(:disabled):hover { color: #06131c; background: var(--accent-bright); }
.de-act--add:not(:disabled):hover::before { background: var(--accent-bright); }
.de-act--rm:not(:disabled):hover { color: #ffd7d1; background: rgba(255, 92, 73, 0.55); }
.de-act--rm:not(:disabled):hover::before { background: rgba(40, 12, 12, 0.72); }
/* Favoritar é só o ícone (a estrela já diz tudo) e acende em dourado. */
.de-act--fav { padding: 9px 12px; font-size: 15px; }
.de-act--fav .da-txt { display: none; }
.de-act--fav:not(:disabled):hover { color: var(--gold-bright); }
.de-act--fav.is-on { color: #1b1405; background: var(--gold-bright); }
.de-act--fav.is-on::before { background: var(--gold-bright); }

/* ── Coluna central: deck principal + extra ────────────────────────────── */
.de-build-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.de-build-head--extra { margin-top: 12px; }
.de-build-title { font-size: 12.5px; font-weight: 800; letter-spacing: 0.05em; color: var(--steel); text-transform: uppercase; display: flex; align-items: center; gap: 6px; }
.de-build-count { font-size: 13px; font-weight: 800; color: var(--accent-bright); font-variant-numeric: tabular-nums; }
.de-build-count.is-bad { color: #ff8a7a; }
/* Ícone de status ao lado do 40–60 (rascunho vs pronto), com tooltip nativo. */
.de-build-right { display: inline-flex; align-items: center; gap: 7px; }
.de-status-icon { display: inline-flex; align-items: center; font-size: 17px; cursor: help; }
.de-status-icon.is-ready { color: var(--heal); }
.de-status-icon.is-draft { color: var(--gold-bright); }

/* Grade de cartas. Cada célula tem ASPECT-RATIO próprio e a imagem é ABSOLUTA
   dentro dela (inset:0) — a altura da célula vem do aspect-ratio, nunca do
   conteúdo, então as linhas jamais se sobrepõem. Deck/Extra = até 10 por linha. */
.de-grid {
  /* row-gap 20px + padding-top 18px = espaço p/ o badge (FORA da carta, acima)
     não encostar na linha de cima nem ser cortado no topo da área rolável. */
  display: grid; gap: 20px 8px; align-content: start; align-items: start; padding: 18px 2px 2px;
  overflow-y: auto;
}
/* Controles (busca/abas/subfiltros) SEMPRE acima da grade — evita que uma carta
   com hover (z-index) receba o clique destinado a uma aba. */
.de-pool-search, .de-tabs, .de-pool-row { position: relative; z-index: 3; }
/* Os subfiltros ficam acima dos IRMÃOS SEGUINTES: com o mesmo z-index, a linha
   da contagem (que vem depois no DOM) ganhava do menu suspenso aberto e o
   "N cartas" aparecia POR CIMA da lista. */
.de-subfilters { position: relative; z-index: 6; }
.de-grid--pool { position: relative; z-index: 1; }
.de-grid--deck { grid-template-columns: repeat(10, minmax(0, 1fr)); }
.de-build .de-grid { flex: 1; min-height: 0; }
/* min-height: com o Extra VAZIO a grade teria altura 0 e não daria para soltar
   uma Fusão nela. */
.de-grid--extra { flex: none; max-height: 30%; min-height: 78px; }
.de-grid--pool { flex: 1; min-height: 0; grid-template-columns: repeat(auto-fill, minmax(66px, 1fr)); }

/* Carta (imagem) — reutilizada no deck e no pool.
   ALTURA via padding-bottom % (proporção 59:86 → 86/59 = 145.76%): a caixa NÃO
   depende de aspect-ratio (que o `align-items:stretch` do grid quebrava, colapsando
   as cartas em tiras sobrepostas). Com height:0 + padding, a altura vem SEMPRE da
   largura da coluna — determinística, sem sobreposição em nenhum navegador. */
.de-card {
  position: relative; box-sizing: border-box; height: 0; padding: 0 0 145.76%;
  border: 2px solid transparent; border-radius: 5px; background: rgba(0, 0, 0, 0.25);
  cursor: pointer; line-height: 0; overflow: visible;  /* deixa o badge de raridade FLUTUAR acima */
  transition: transform 0.1s, border-color 0.12s, box-shadow 0.12s;
}
/* A imagem se auto-recorta (a caixa não clipa mais, p/ o badge poder sair pra fora). */
.de-card-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 3px; }
/* Sentinela invisível de carregamento em lotes (ocupa a linha toda). */
.de-pool-sentinel { grid-column: 1 / -1; height: 1px; }
.de-card:hover { transform: translateY(-2px); border-color: rgba(120, 180, 255, 0.65); z-index: 2; }
/* Carta FIXADA pelo clique: é o alvo dos botões do detalhe. */
.de-card.is-pinned { border-color: var(--gold-bright); box-shadow: 0 0 12px -2px rgba(255, 215, 94, 0.55); }
/* Arraste: a carta some pela metade e o DESTINO válido se acende. */
.de-card[draggable="true"] { cursor: grab; }
.de-card.is-dragging { opacity: 0.4; cursor: grabbing; }
.de-grid.is-drop-ok { outline: 1px dashed rgba(142, 199, 255, 0.45); outline-offset: -3px; }
.de-grid.is-drop-over {
  outline: 2px dashed var(--accent-bright); outline-offset: -3px;
  background: rgba(89, 167, 240, 0.09);
}
.de-card.r-RARE { box-shadow: inset 0 0 0 1px rgba(107, 178, 255, 0.4); }
.de-card.r-SUPER { box-shadow: inset 0 0 0 1px rgba(201, 162, 255, 0.5); }
.de-card.r-ULTRA { box-shadow: inset 0 0 0 1px rgba(255, 215, 94, 0.55); }
/* Selo usado/possuído (canto inferior direito). */
.de-card-badge {
  position: absolute; right: 2px; bottom: 2px; font-size: 10px; font-weight: 800; color: #fff;
  background: rgba(6, 10, 16, 0.85); border-radius: 4px; padding: 1px 4px; line-height: 1.3; pointer-events: none;
}
.de-card-badge.hidden { display: none; }
/* Não-possuída: cinza; esgotada no deck: esmaecida. */
.de-card.is-unowned { filter: grayscale(1) brightness(0.5); }
.de-card.is-unowned:hover { filter: grayscale(1) brightness(0.68); }
.de-card.is-maxed .de-card-img { opacity: 0.5; }
/* Estrela de favorito (canto superior esquerdo). */
.de-star {
  position: absolute; left: 2px; top: 2px; font-size: 12px; line-height: 1; color: rgba(255, 255, 255, 0.45);
  background: rgba(6, 10, 16, 0.72); border-radius: 4px; padding: 2px 3px; opacity: 0;
  transition: opacity 0.12s, color 0.12s;
}
.de-card:hover .de-star { opacity: 1; }
.de-star.is-on { opacity: 1; color: var(--gold-bright); }
.de-star:hover { color: var(--gold-bright); }

/* ── Coluna direita: busca + naturezas + subfiltros + pool ───────────────
   Tudo no vocabulário do UI kit: recorte chanfrado (--cut-*) e o ::before de
   inset 1px fazendo a "borda" recolorível. Nada de cantos arredondados aqui —
   eram a única ilha de outra linguagem na interface. */

/* Busca: o próprio .ui-field do kit, com folga para o ícone e o limpar. */
.de-pool-search { display: flex; align-items: center; margin-bottom: 10px; }
.de-search-ico {
  position: absolute; left: 12px; z-index: 1; color: #7f93a8; font-size: 16px; pointer-events: none;
  transition: color 0.16s;
}
.de-pool-search:focus-within .de-search-ico { color: var(--accent-bright); }
.de-pool-search .de-search-input {
  position: relative; flex: 1; min-width: 0; border: none; background: transparent; outline: none;
  padding: 11px 34px; font-family: inherit; font-size: 13px; font-weight: 600; color: #eaf2fb;
}
.de-search-input::placeholder { color: #7f93a8; font-weight: 500; }
.de-search-clear {
  position: absolute; right: 7px; z-index: 1; width: 21px; height: 21px; border: none; cursor: pointer;
  clip-path: var(--cut-xs); background: rgba(150, 160, 175, 0.3); color: #cbd8e8;
  display: inline-flex; align-items: center; justify-content: center; font-size: 12px;
  transition: background 0.14s, color 0.14s;
}
.de-search-clear:hover { color: #06131c; background: var(--accent-bright); }
.de-search-clear.hidden { display: none; }

/* Abas de natureza (Todas · Monstros · Magias · Armadilhas · ★): mesma peça das
   abas da home — chanfro nos cantos DE CIMA, base reta sobre o fio, traço
   dourado deslizando na ativa. */
.de-tabs {
  display: flex; align-items: stretch; gap: 3px; margin-bottom: 10px;
  border-bottom: 1px solid rgba(150, 170, 200, 0.16);
}
.de-tab {
  --cut-tab: polygon(8px 0, calc(100% - 8px) 0, 100% 8px, 100% 100%, 0 100%, 0 8px);
  position: relative; flex: 1; min-width: 0; border: none; cursor: pointer; font-family: inherit;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 9px 4px; clip-path: var(--cut-tab); white-space: nowrap;
  font-size: 11px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase;
  color: #8b93a0; background: transparent; transition: color 0.16s, background 0.16s;
}
.de-tab i { font-size: 15px; color: inherit; }
.de-tab::after {
  content: ''; position: absolute; left: 8px; right: 8px; bottom: 0; height: 2px;
  background: var(--gold); transform: scaleX(0); transform-origin: 50% 100%;
  transition: transform 0.18s ease;
}
.de-tab:hover { color: #c9d3e0; background: rgba(255, 255, 255, 0.04); }
.de-tab.is-on { color: var(--gold-bright); background: rgba(232, 192, 100, 0.08); }
.de-tab.is-on::after { transform: scaleX(1); }
.de-tab--icon { flex: none; width: 42px; }
.dt-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* Coluna estreita: as abas viram só ÍCONE (o `title` segura o nome) em vez de
   deixar "ARMADILHAS" vazar do próprio recorte. */
@container (max-width: 430px) {
  .de-tab .dt-txt { display: none; }
  .de-tab { padding: 9px 2px; }
}

/* Sub-filtros da aba ativa: chips multi-seleção + limpar. */
.de-subfilters { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 9px; }
.de-subfilters.hidden { display: none; }
.de-dd { position: relative; }
.de-dd-btn, .de-clear-filters {
  position: relative; isolation: isolate; border: none; cursor: pointer; font-family: inherit;
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 11px; clip-path: var(--cut-sm);
  font-size: 11.5px; font-weight: 800; letter-spacing: 0.03em; white-space: nowrap;
  color: #b9c7d8; background: rgba(150, 160, 175, 0.26);
  transition: color 0.15s, background 0.15s;
}
.de-dd-btn::before, .de-clear-filters::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm);
  background: rgba(14, 19, 28, 0.92); transition: background 0.15s;
}
.de-dd-btn i { font-size: 12px; transition: transform 0.16s; }
.de-dd-btn:hover, .de-clear-filters:hover { color: #eaf2fb; background: rgba(180, 195, 215, 0.45); }
.de-dd.open .de-dd-btn i { transform: rotate(180deg); }
/* Aberto ou com seleção: a "borda" acende no acento e o miolo escurece em azul. */
.de-dd.open .de-dd-btn, .de-dd.has-sel .de-dd-btn { color: #eaf2fb; background: var(--accent); }
.de-dd.has-sel .de-dd-btn::before { background: rgba(18, 42, 74, 0.92); }
.de-dd-badge {
  min-width: 16px; padding: 1px 4px; clip-path: var(--cut-xs); font-size: 10px; font-weight: 900;
  line-height: 14px; text-align: center; color: #1b1405; background: var(--gold-bright);
}
.de-dd-badge.hidden { display: none; }
/* Menu suspenso. Duas camadas em vez de ::before: a rolagem interna (raças) faria
   um ::before absoluto rolar junto e a "borda" sumiria — a externa é a borda, a
   interna é o preenchimento que rola. */
.de-dd-menu {
  position: absolute; z-index: 30; top: calc(100% + 6px); left: 0; display: none; padding: 1px;
  clip-path: var(--cut-md); background: rgba(120, 180, 255, 0.42);
  filter: drop-shadow(0 18px 34px rgba(0, 0, 0, 0.62));
}
.de-dd.open .de-dd-menu { display: block; }
.de-dd-list {
  display: flex; flex-direction: column; gap: 2px; padding: 7px;
  min-width: 176px; max-height: 286px; overflow-y: auto;
  clip-path: var(--cut-md); background: rgba(11, 15, 23, 0.97);
}
.de-dd-item {
  position: relative; display: flex; align-items: center; gap: 9px; padding: 6px 9px;
  clip-path: var(--cut-xs); cursor: pointer; font-size: 12.5px; font-weight: 700; color: #c2cfdf;
  white-space: nowrap; transition: background 0.12s, color 0.12s;
}
.de-dd-item:hover { background: rgba(90, 160, 240, 0.16); color: #eef4fc; }
.de-dd-item:hover .ui-check { background: rgba(180, 195, 215, 0.45); }
.de-dd-item:has(input:checked) { color: #fff; background: rgba(89, 167, 240, 0.14); }
.de-dd-item input { position: absolute; opacity: 0; width: 0; height: 0; }
/* Caixa miúda: mesma peça do kit, menor e com o chanfro na medida (o corte de
   8px num quadrado de 17px comeria metade da forma). */
.de-dd-item .ui-check { width: 17px; height: 17px; clip-path: var(--cut-xs); }
.de-dd-item .ui-check::before { clip-path: var(--cut-xs); }
.de-dd-item .ui-check i { font-size: 12px; }
.de-dd-ic { width: 18px; height: 18px; object-fit: contain; }
.de-clear-filters { margin-left: auto; }
.de-clear-filters:hover { color: #ffd7d1; background: rgba(255, 92, 73, 0.5); }
.de-clear-filters:hover::before { background: rgba(40, 12, 12, 0.72); }

/* Linha do rodapé dos filtros: contagem à esquerda, interruptor à direita. */
.de-pool-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 7px; }
.de-pool-count { font-size: 11.5px; font-weight: 700; color: var(--steel); }
.de-owned-switch { flex: none; }
.de-pool-empty { flex: 1; display: flex; align-items: center; justify-content: center; color: var(--steel); font-size: 13px; }
.de-pool-empty.hidden { display: none; }

/* Responsivo: telas menores encolhem o detalhe e permitem rolagem geral. */
@media (max-width: 1180px) {
  .de-detail { width: 240px; }
  .de-grid--deck { grid-template-columns: repeat(8, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .de-stage { height: auto; overflow: visible; }
  .de-body { flex-direction: column; width: 100%; }
  .de-detail, .de-build, .de-pool { width: auto; flex: none; }
  .de-build .de-grid, .de-grid--pool { max-height: 60vh; }
}

/* ══════════════════════════════════════════════════════════════════════════
   REPLAYS — abas do lobby, lista de duelos gravados e o player de duelo.
   Reusa os MESMOS tokens do board (--cut-sm/-md, --gold/--panel/--line) e o
   componente .room-entry das salas: um replay é "uma sala que já aconteceu".
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Abas [ Salas | Replays ] DENTRO do cabeçalho do card, à esquerda ─────
   Tomam o lugar do antigo título: a aba ativa É o título da seção. Chanfradas
   (--cut-sm) para casar com o card, e a ativa "encosta" no corpo por um traço
   dourado alinhado à borda inferior do cabeçalho — leitura de aba de verdade. */
/* A faixa desce até a BORDA DE BAIXO do cabeçalho (a aba ativa "encosta" no
   corpo pelo traço dourado), mas RESPEITA o padding de cima — encostada no
   limite do card a aba brigava com o chanfro dele. Daí o -15px só embaixo
   (14px de padding + 1px de borda) e nada em cima.
   `align-self: stretch` é necessário porque o cabeçalho é `align-items: center`:
   sem ele a faixa ficava centralizada e o traço flutuava acima do corpo. */
.home-tabs {
  display: flex; align-items: stretch; align-self: stretch; gap: 4px;
  margin: 0 0 -15px;
}
.home-tab {
  /* Pontinhas chanfradas nos cantos DE CIMA: a base fica reta e encostada na
     borda do cabeçalho (leitura de aba), e o corte diagonal repete o
     vocabulário de --cut-sm/--cut-md do resto da interface. */
  --cut-tab: polygon(9px 0, calc(100% - 9px) 0, 100% 9px, 100% 100%, 0 100%, 0 9px);
  position: relative; display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  font-family: inherit; font-size: 13px; font-weight: 800; letter-spacing: 0.06em;
  /* SEM padding vertical: a altura vem do `stretch` da faixa (o texto é
     centralizado pelo próprio inline-flex). Com padding, o conteúdo ficava mais
     alto que o espaço disponível e a aba transbordava por baixo da borda. */
  text-transform: uppercase; padding: 0 20px; border: none;
  clip-path: var(--cut-tab);
  color: #8b93a0; background: transparent;
  transition: color 0.16s, background 0.16s;
}
.home-tab i { font-size: 17px; color: inherit; transition: color 0.16s; }
.home-tab::after {
  content: ''; position: absolute; left: 10px; right: 10px; bottom: 0; height: 2px;
  background: var(--gold); transform: scaleX(0); transform-origin: 50% 100%;
  transition: transform 0.18s ease;
}
.home-tab:hover { color: #c9d3e0; background: rgba(255, 255, 255, 0.04); }
.home-tab:hover i { color: #c9d3e0; }
.home-tab.on { color: var(--gold-bright); background: rgba(232, 192, 100, 0.08); }
.home-tab.on i { color: var(--gold-bright); }
.home-tab.on::after { transform: scaleX(1); }
/* Folga à esquerda: a primeira aba não pode encostar no chanfro do próprio card
   (--cut-md corta 14px na diagonal, então 18px deixa a aba livre dele). */
.home-rooms-head { padding-left: 18px; }

/* Seletor de escopo (todos os replays / meus): dentro de um .ui-field, o MESMO
   componente do campo de código ao lado — o `.set-select` das Configurações é
   um bloco cinza sólido e destoava lado a lado com o campo escuro. */
.rl-scope { flex: none; min-width: 178px; }
.rl-scope select {
  position: relative; width: 100%; cursor: pointer;
  appearance: none; -webkit-appearance: none;   /* a seta nativa fica torta no chanfro */
  border: none; background-color: transparent; outline: none;
  padding: 11px 34px 11px 13px;
  font-family: inherit; font-size: 13.5px; font-weight: 600; color: #eaf2fb;
  /* Chevron próprio, alinhado com a borda direita do campo. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 16 16' fill='none' stroke='%239fb4c8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
}
.rl-scope select option { background: #12151b; color: #eaf2fb; }

/* Altura FIXA do corpo: trocar de aba não pode mexer no tamanho do card — nem
   crescer (30 replays) nem encolher (1 sala). A lista rola por dentro; só a
   MOLDURA fica parada. Mesma barra de rolagem discreta do resto do app. */
.home-lists {
  height: 440px; overflow-y: auto; overflow-x: hidden;
}
/* (scrollbar: desenho global no topo do arquivo) */
/* A lista precisa poder passar da altura do container (senão o flex a comprime
   e a rolagem nunca aparece). */
.home-lists > .room-list { flex: none; }


/* ── Linha de um replay na lista ────────────────────────────────────────── */
/* Capas: o MESMO leque de 3 cartas da aba "Meus Decks" (.deck-fan/.fan-card),
   um por duelista, na variante MINI — e o verso tradicional do YGO nos espaços
   sem carta escolhida. Reusa o componente em vez de duplicá-lo. */
.rl-covers { display: flex; align-items: center; gap: 2px; flex: none; }
.deck-fan--mini { width: 84px; height: 58px; margin: 0; }
.deck-fan--mini .fan-card {
  width: 32px; margin-left: -16px; top: 3px; border-radius: 3px;
  box-shadow: 0 3px 8px -3px rgba(0, 0, 0, 0.7);
}
.deck-fan--mini .fan-card--left { transform: rotate(-15deg) translateX(-13px); }
.deck-fan--mini .fan-card--right { transform: rotate(15deg) translateX(13px); }
.deck-fan--mini .fan-card--mid { transform: translateY(-3px); }
/* O leque "abre" no hover da LINHA (no card de deck é no hover do card). */
.room-entry:hover .deck-fan--mini .fan-card--left { transform: rotate(-21deg) translateX(-18px); }
.room-entry:hover .deck-fan--mini .fan-card--right { transform: rotate(21deg) translateX(18px); }
.room-entry:hover .deck-fan--mini .fan-card--mid { transform: translateY(-6px); }
.rl-vs {
  font-size: 10px; font-weight: 900; color: var(--gold); letter-spacing: 0.06em;
  padding: 0 3px; flex: none;
}
/* O bloco de info absorve a folga: assim os nomes de TODAS as linhas começam na
   mesma coluna (sem isto, pílulas de largura diferente deslocavam o texto). */
.rl-row { gap: 14px; }
.rl-row .re-info { flex: 1; min-width: 0; }
.rl-row .re-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Metadados em segmentos: o ícone NUNCA se separa do rótulo ao quebrar linha
   (antes a ampulheta ficava órfã no fim de uma linha e "9 turnos" na seguinte). */
.room-entry .re-meta { gap: 0 4px; }
.re-meta .rl-bit { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.re-meta .rl-bit:not(:last-child)::after { content: '·'; margin-left: 5px; opacity: 0.55; }
/* Pílula de status com ícone (troféu de um duelo alheio). */
.re-status { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.re-status i { font-size: 13px; }
/* Código da partida: monoespaçado, para ler e ditar sem erro. */
.rl-code {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 11px; font-weight: 700; letter-spacing: 0.14em;
  color: var(--gold); background: rgba(232, 192, 100, 0.12);
  padding: 3px 8px; border-radius: 999px; cursor: pointer;
}
.rl-code:hover { background: rgba(232, 192, 100, 0.22); }
.re-status--win { color: #6ee7a5; background: rgba(52, 214, 126, 0.14); }
.re-status--loss { color: var(--danger); background: rgba(255, 92, 73, 0.14); }
.re-status--draw { color: #9fb4c8; background: rgba(160, 180, 210, 0.12); }
.re-status--pve { color: #8ec7ff; background: rgba(89, 167, 240, 0.14); }
.rl-del {
  border: none; cursor: pointer; font-family: inherit; clip-path: var(--cut-sm);
  padding: 8px 11px; font-size: 13px; color: #c9d3e0;
  background: rgba(255, 255, 255, 0.06); transition: background 0.15s, color 0.15s;
}
.rl-del:hover { background: rgba(255, 92, 73, 0.2); color: var(--danger); }
.rl-empty { padding: 26px 16px; text-align: center; color: #8b93a0; font-size: 13px; }

/* ── Modo replay: o board inteiro vira somente-leitura ──────────────────── */
/* Cinto e suspensório sobre os gates de `replayMode` no board.ts: mesmo que um
   handler escape, nada no campo aceita ponteiro. As pilhas (DECK/EX/GY) são a
   exceção — clicá-las abre a lista de cartas, que é justamente a graça. */
body.in-replay #field-me .zone,
body.in-replay #field-opp .zone,
body.in-replay .hand-row .hcard { pointer-events: none; }
body.in-replay #field-me .zone.pile,
body.in-replay #field-opp .zone.pile { pointer-events: auto; cursor: pointer; }
body.in-replay #turn-controls,
body.in-replay #quick-options,
body.in-replay #pick-bar { display: none; }
/* A mão do oponente fica visível no replay — sem o leque "escondido". */
body.in-replay #opp-hand-row .hcard img { opacity: 1; }

/* ── Barra do player ─────────────────────────────────────────────────────
   NO FLUXO (não absoluta): o #board-wrap é uma coluna flex e a barra já vem
   depois da mão no DOM, então ela se acomoda ABAIXO das cartas. Absoluta em
   `bottom` ela cobria a mão do jogador. */
#replay-bar {
  position: relative; z-index: 30; align-self: center; flex: none;
  margin: 4px 0 10px;
  display: flex; align-items: center; gap: 16px; padding: 10px 18px;
  width: min(880px, calc(100% - 32px));
  clip-path: var(--cut-md);
  background: linear-gradient(180deg, rgba(232, 192, 100, 0.5), rgba(232, 192, 100, 0.22));
}
/* Borda chanfrada de 1px: o ::before recuado 1px pinta o interior escuro. */
#replay-bar::before {
  content: ''; position: absolute; inset: 1px; z-index: -1;
  clip-path: var(--cut-md); background: rgba(10, 14, 20, 0.94);
}
#replay-bar.hidden { display: none; }
.rp-transport { display: flex; align-items: center; gap: 4px; flex: none; }
#replay-bar button {
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  width: 32px; height: 32px; font-size: 15px; font-family: inherit;
  border: 1px solid rgba(232, 192, 100, 0.28); border-radius: 99px;
  background: rgba(20, 16, 6, 0.7); color: #ffe9b8;
  transition: background 0.15s, border-color 0.15s, transform 0.1s;
}
#replay-bar button:hover { background: rgba(58, 47, 18, 0.95); border-color: rgba(232, 192, 100, 0.6); }
#replay-bar button:active { transform: scale(0.92); }
#replay-bar button:disabled { opacity: 0.32; cursor: default; transform: none; }
#replay-bar button.rp-main {
  width: 40px; height: 40px; font-size: 19px;
  background: linear-gradient(180deg, var(--gold-bright), var(--gold)); color: var(--abyss);
  border-color: transparent;
}
/* Trilha: o range ocupa a largura e as marcas de turno ficam por baixo. */
.rp-track { flex: 1; min-width: 0; position: relative; display: flex; flex-direction: column; gap: 3px; }
#rp-scrub {
  -webkit-appearance: none; appearance: none; width: 100%; height: 5px; cursor: pointer;
  background: rgba(255, 255, 255, 0.14); border-radius: 99px; outline: none;
}
#rp-scrub::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 14px; height: 14px; border-radius: 99px;
  background: var(--gold-bright); border: 2px solid var(--abyss); cursor: pointer;
}
#rp-scrub::-moz-range-thumb {
  width: 14px; height: 14px; border-radius: 99px;
  background: var(--gold-bright); border: 2px solid var(--abyss); cursor: pointer;
}
/* Marcas de turno: riscos posicionados em % sobre a trilha (clicáveis).
   Seletor com o #replay-bar de propósito: `#replay-bar button` (id+tipo) vence
   uma classe sozinha e transformava cada risco num botão redondo de 32px. */
.rp-turns { position: relative; height: 7px; }
#replay-bar .rp-turn-mark {
  position: absolute; top: 0; left: 0; width: 3px; height: 7px; min-width: 0;
  padding: 0; border: none; border-radius: 1px;
  background: rgba(232, 192, 100, 0.5); cursor: pointer; transform: translateX(-1px);
  transition: background 0.14s, height 0.14s;
}
#replay-bar .rp-turn-mark:hover {
  background: var(--gold-bright); height: 10px; transform: translateX(-1px);
}
.rp-meta {
  flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 1px;
  min-width: 82px;
}
.rp-pos {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 11.5px; font-weight: 700; color: #ffe9b8;
}
.rp-phase { font-size: 10px; color: #8b93a0; letter-spacing: 0.04em; white-space: nowrap; }
.rp-tools { display: flex; align-items: center; gap: 5px; flex: none; }
/* Mesma armadilha de especificidade: precisa do #replay-bar para vencer o
   `width: 32px` do botão-ícone e deixar o "1×"/"1.5×" respirar. */
#replay-bar #rp-speed {
  width: auto; min-width: 38px; padding: 0 11px; border-radius: 99px;
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.02em;
}
#rp-exit:hover { background: rgba(255, 92, 73, 0.24); border-color: rgba(255, 92, 73, 0.5); color: #ffb4aa; }

/* Telas estreitas: a barra vira duas linhas e some o que é acessório. */
@media (max-width: 760px) {
  #replay-bar { flex-wrap: wrap; gap: 8px 12px; padding: 8px 12px; margin-bottom: 6px; }
  .rp-track { order: 3; flex-basis: 100%; }
  .rp-phase { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   PERFIL DO DUELISTA — retrato + título
   O retrato é o mesmo <img> em toda parte (navbar, sala, VERSUS, pickers): a
   regra é sempre "foto quando existe, sprite genérico quando não". O TÍTULO é
   ícone + texto colorido pela RARIDADE, e a cor é o único sinal de prestígio —
   por isso as três classes `tt-*` vivem soltas aqui e são reusadas por toda
   variação de chip (navbar, sala, VERSUS, modal).
   ══════════════════════════════════════════════════════════════════════════ */

/* Raridade: branco (comum) · azul (raro) · dourado (lendário). Vem DEPOIS de
   .id-title & cia. de propósito — mesma especificidade, então a cor da raridade
   é que vale. */
.tt-common { color: #d8e2ef; }
.tt-common i { color: #f3f7fc; }
.tt-rare { color: #79bcff; }
.tt-rare i { color: #4aa8ff; }
.tt-legendary { color: var(--gold-bright); }
.tt-legendary i { color: var(--gold); }

/* Chip base do título (ícone + texto numa linha só). */
.duel-title, .id-title, .rp-title, .vs-title-chip, .profile-title-chip, .title-row-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-weight: 700; letter-spacing: 0.02em; line-height: 1; white-space: nowrap;
}
/* Sem título: o chip some por inteiro em vez de deixar um buraco no layout.
   Vem DEPOIS da regra base — mesma especificidade, e o `none` é que vale. */
.tt-none { display: none; }

/* ── Navbar ──────────────────────────────────────────────────────────────*/
.id-title-slot { display: inline-flex; align-items: center; justify-content: flex-end; }
.id-title { font-size: 11px; }
.id-title i { font-size: 12px; }
/* O retrato virou BOTÃO (atalho para a troca): zera a pinta de botão e ganha um
   leve realce no hover — o resto do navbar continua sem efeito. */
.nav-avatar { border: none; padding: 0; cursor: pointer; position: relative; }
.nav-avatar::after {
  content: ''; position: absolute; inset: 0; background: rgba(120, 180, 255, 0);
  transition: background 0.16s;
}
.nav-avatar:hover::after { background: rgba(120, 180, 255, 0.18); }

/* ── Card de Perfil (Configurações) ──────────────────────────────────────*/
/* Vive na coluna da direita (o `gap` da .settings-col já dá o respiro) e é
   deliberadamente BAIXO: a tela de Config precisa caber sem rolagem. */
.profile-body { flex-direction: row; align-items: center; gap: 18px; padding: 16px 20px; }
.profile-av {
  flex: none; position: relative; width: 84px; height: 84px; padding: 0; border: none;
  cursor: pointer; overflow: hidden; clip-path: var(--cut-md);
  background: rgba(120, 180, 255, 0.22);
}
.profile-av img { width: 100%; height: 100%; object-fit: cover; object-position: var(--face-crop); display: block; }
/* Selo da câmera: só aparece no hover, cobrindo a base da foto. */
.profile-av-edit {
  position: absolute; left: 0; right: 0; bottom: 0; height: 26px;
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 17px; background: rgba(8, 12, 20, 0.82);
  transform: translateY(100%); transition: transform 0.16s;
}
.profile-av:hover .profile-av-edit, .profile-av:focus-visible .profile-av-edit { transform: none; }
.profile-info { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 7px; }
.profile-name { font-size: 18px; font-weight: 900; color: #f2f6fc; letter-spacing: 0.02em; }
.profile-title {
  display: inline-flex; align-items: center; gap: 9px; border: none; cursor: pointer;
  padding: 7px 12px; clip-path: var(--cut-sm); font-family: inherit; font-size: 13px;
  background: rgba(255, 255, 255, 0.06); transition: background 0.12s;
}
.profile-title:hover { background: rgba(120, 180, 255, 0.18); }
.profile-title { color: var(--steel); } /* cor do rótulo de reserva (sem título) */
.profile-title > i { color: var(--steel); font-size: 14px; }
.profile-title-chip { font-size: 13.5px; font-weight: 800; }
.profile-title-chip i { font-size: 16px; }
.profile-hint { font-size: 11.5px; color: var(--steel); }

/* ── Modal: escolher AVATAR (grade com busca) ────────────────────────────*/
.avatar-box { width: min(94vw, 660px); }
.avatar-grid {
  overflow-y: auto; min-height: 0; padding: 0 16px 18px;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(102px, 1fr)); gap: 10px;
  /* A grade é item de um flex em coluna com `max-height`. Sem estas duas, as
     linhas viravam refém da altura sobrada (achatando as células em vez de
     rolar): `max-content` fixa a linha no tamanho da célula e `start` impede
     que sobra de espaço estique a última fileira. */
  grid-auto-rows: max-content; align-content: start;
}
.av-cell {
  position: relative; border: none; padding: 0; cursor: pointer; overflow: hidden;
  clip-path: var(--cut-sm); background: rgba(255, 255, 255, 0.05);
  transition: background 0.12s, filter 0.12s;
}
/* Os retratos NÃO têm proporção única na zona (894×894, 1020×784, 768×1080…),
   então `cover` num quadrado decapitava uns e sobrava fundo em outros. Aqui a
   célula é RETRATO com altura fixa e o render entra por `contain`: nada é
   cortado, e o personagem se identifica de relance — que é o serviço do picker.
   Altura em px (não `aspect-ratio`) porque a grade vive num flex com
   `overflow-y: auto`, onde a altura da linha não pode depender do conteúdo. */
.av-cell img {
  width: 100%; height: 108px; object-fit: contain; object-position: center bottom;
  display: block; padding: 6px 6px 0;
}
.av-cell:hover { background: rgba(120, 180, 255, 0.2); filter: brightness(1.08); }
.av-cell.sel { background: rgba(120, 180, 255, 0.34); }
.av-cell-name {
  display: block; padding: 5px 6px; font-size: 10.5px; font-weight: 700; color: #cfdae8;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.av-cell-check {
  position: absolute; top: 5px; right: 5px; font-size: 19px; color: var(--accent-bright);
  opacity: 0; text-shadow: 0 2px 8px rgba(0, 0, 0, 0.8);
}
.av-cell.sel .av-cell-check { opacity: 1; }

/* ── Modal: escolher TÍTULO (lista por raridade) ─────────────────────────*/
.title-box { width: min(94vw, 480px); }
.title-list { overflow-y: auto; padding: 0 16px 18px; display: flex; flex-direction: column; gap: 6px; }
.title-group {
  display: flex; align-items: center; gap: 6px; margin: 12px 0 3px;
  font-size: 10px; font-weight: 900; letter-spacing: 0.14em; text-transform: uppercase;
}
.title-group:first-child { margin-top: 2px; }
.title-group i { font-size: 12px; }
.title-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; text-align: left; border: none; cursor: pointer; padding: 10px 12px;
  clip-path: var(--cut-sm); background: rgba(255, 255, 255, 0.04);
  font-family: inherit; transition: background 0.12s;
}
.title-row:hover { background: rgba(120, 180, 255, 0.15); }
.title-row.sel { background: rgba(120, 180, 255, 0.25); }
.title-row-chip { font-size: 13.5px; font-weight: 800; }
.title-row-chip i { font-size: 16px; }
/* O lendário ganha um fio dourado à esquerda — a lista inteira se lê num relance. */
.title-row.tt-legendary { box-shadow: inset 3px 0 0 var(--gold); }
.title-row.tt-rare { box-shadow: inset 3px 0 0 #4aa8ff; }
.title-row .rdm-check { flex: none; color: var(--accent-bright); font-size: 18px; opacity: 0; }
.title-row.sel .rdm-check { opacity: 1; }

/* ── Retratos nas listas do PVE e na sala ────────────────────────────────*/
/* .rp-av/.cpu-av já são círculos com um ícone dentro; com foto, a imagem ocupa
   o círculo inteiro e o gradiente de fundo deixa de aparecer. */
.rp-av img, .cpu-av img {
  width: 100%; height: 100%; object-fit: cover; object-position: var(--face-crop);
  border-radius: 50%; display: block;
}
.cpu-av.has-photo { background: none; }
.rp-title { font-size: 10.5px; }
.rp-title i { font-size: 12px; }

/* ── Tela de VERSUS ──────────────────────────────────────────────────────*/
.vs-av { overflow: hidden; padding: 0; }
.vs-av img {
  width: 100%; height: 100%; object-fit: cover; object-position: var(--face-crop);
  border-radius: 50%; display: block;
}
.vs-title { min-height: 16px; display: flex; align-items: center; justify-content: center; color: var(--steel); }
.vs-title, .vs-title-chip { font-size: 13px; font-weight: 800; text-align: center; }
.vs-title i { font-size: 15px; }
/* Contra a CPU o lugar do título mostra o ARQUÉTIPO — sem cor de raridade. */
.vs-right .vs-title > i:first-child { color: var(--danger); }
@media (max-width: 640px) { .vs-title { font-size: 11px; } }

/* ══════════════════════════════════════════════════════════════════════════
   LABORATÓRIO — cópias acima de 3 viram Duel Points, e o pó vira carta nova.
   A tela é o MONTADOR DE DECKS por dentro: reusa `.de-bar`, `.de-body`,
   `.de-detail`, `.de-pool`, `.de-grid`, `.de-card`, `.de-tab`, `.de-dd`…  — nada
   de paleta própria. Só o que não existe no montador ganha classe `.lab-*`:
   a coluna do meio (as duas abas de ambiente, a carta em síntese e o contador).
   ══════════════════════════════════════════════════════════════════════════ */
/* Fundo do laboratório, no mesmo molde da loja (imagem fixa + véu escuro). */
#lab-bg {
  position: fixed; inset: 0; z-index: 0; display: none; pointer-events: none;
  background: #0a0e14 url("https://yugiohonline.b-cdn.net/backgrounds/lab/lab.png") center / cover no-repeat;
}
#lab-bg::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(4, 6, 11, 0.5), rgba(2, 3, 7, 0.7));
}
body.scene-lab #lab-bg { display: block; }
body.scene-lab #bg-aura { display: none; }

/* Painéis: o MESMO tom do montador e da tela de Config (borda azulada de 1px,
   miolo quase preto com blur). Nada de verde. */
#screen-lab .ui-panel { background: rgba(140, 158, 182, 0.20); filter: drop-shadow(0 16px 34px rgba(0, 0, 0, 0.42)); }
#screen-lab .ui-panel::before { background: linear-gradient(168deg, rgba(20, 25, 33, 0.96), rgba(10, 13, 19, 0.95)); backdrop-filter: blur(9px); }
#screen-lab .ui-field { background: rgba(150, 160, 175, 0.22); }
#screen-lab .ui-field:focus-within { background: var(--accent); }

/* `position/z-index` NÃO são decorativos aqui: o #lab-bg é `fixed` e mora DENTRO
   da própria <section> (como o da loja). No mesmo contexto de empilhamento, um
   elemento POSICIONADO (o fundo, z-index 0) pinta por cima de tudo que é
   ESTÁTICO — foi assim que o fundo engoliu o título da barra, que é um <h2> sem
   position. Subir o stage resolve de uma vez, como `.shop-stage` já fazia. */
.lab-stage {
  position: relative; z-index: 2;
  height: calc(100vh - 66px); overflow: hidden;
  display: flex; flex-direction: column;
  padding: 14px clamp(14px, 2.5vw, 34px) clamp(12px, 2.5vh, 26px);
}
.lab-stage .de-body { flex: 1; }
.lab-title { display: flex; align-items: center; gap: 9px; font-size: 19px; font-weight: 800; letter-spacing: 0.03em; color: #eef4fc; }
.lab-title i { color: var(--accent-bright); font-size: 22px; }
.lab-title .accent { color: var(--accent-bright); }

/* Pulso do número no navbar quando o saldo muda (ganho ou gasto) — é lá que o
   saldo de DP vive; a barra do laboratório não o repete. */
@keyframes dp-bump {
  0% { transform: none; }
  35% { transform: scale(1.42); color: #cdf0ff; text-shadow: 0 0 16px var(--accent-bright); }
  100% { transform: none; }
}
#dp.dp-bump { display: inline-block; animation: dp-bump 0.6s cubic-bezier(0.3, 1.4, 0.4, 1); }

/* ── Coluna do meio: a bancada ─────────────────────────────────────────── */
.lab-bench { flex: 1.35; min-width: 0; min-height: 0; display: flex; flex-direction: column; padding: 14px; }
.lab-bench > * { position: relative; }

/* Abas de AMBIENTE no topo do próprio card, com a peça de seleção deslizando
   entre elas (o mesmo gesto do menu do navbar). */
.lab-switch {
  position: relative; display: flex; align-items: stretch; gap: 3px; margin-bottom: 14px;
  border-bottom: 1px solid rgba(150, 170, 200, 0.16);
}
.lab-swtab {
  flex: 1; position: relative; z-index: 1; border: none; background: none; cursor: pointer;
  font-family: inherit; padding: 11px 8px; font-size: 12.5px; font-weight: 800; letter-spacing: 0.03em;
  color: #8896a6; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  transition: color 0.18s;
}
.lab-swtab i { font-size: 17px; transition: color 0.18s; }
.lab-swtab:hover { color: #c9d3e0; }
.lab-swtab.is-on { color: #eef4fc; }
.lab-swtab.is-on i { color: var(--accent-bright); }
/* O traço que escorrega: JS posiciona left/width, o CSS anima. */
.lab-switch-sel {
  position: absolute; bottom: -1px; height: 2px; left: 0; width: 0;
  background: var(--accent-bright); box-shadow: 0 0 10px -1px rgba(142, 199, 255, 0.8);
  transition: left 0.28s cubic-bezier(0.4, 0.9, 0.3, 1), width 0.28s cubic-bezier(0.4, 0.9, 0.3, 1);
  pointer-events: none;
}

/* Troca de ambiente: fade curto (o conteúdo é bem diferente entre as abas, e
   um slide levaria a lista do descarte "passando por cima" da carta). */
.lab-view { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 14px; animation: lab-fade 0.22s ease-out; }
.lab-view.hidden { display: none; }
@keyframes lab-fade { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* ── A carta em síntese ────────────────────────────────────────────────────
   Fica PARADA e centralizada; o mouse só a inclina de leve. Ela vive em
   preto-e-branco e só ganha cor durante a criação — do centro para fora. */
.lab-specimen {
  flex: 1; min-height: 0; position: relative;
  display: flex; align-items: center; justify-content: center;
  perspective: 1100px;
  --tilt-x: 0deg; --tilt-y: 0deg; --reveal: 0%;
}
.lab-card-3d {
  position: relative; height: min(100%, 46vh); aspect-ratio: 59 / 86; border-radius: 8px;
  transform: rotateX(var(--tilt-x)) rotateY(var(--tilt-y));
  transition: transform 0.22s ease-out, filter 0.25s;
  box-shadow: 0 18px 40px -12px rgba(0, 0, 0, 0.85);
}
.lab-spec {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  display: block; border-radius: 8px;
}
.lab-spec.hidden { display: none; }
/* A cópia preto-e-branco é o estado normal da carta na câmara. */
.lab-spec--gray { filter: grayscale(1) brightness(0.62) contrast(1.06); }
/* A colorida é revelada por um círculo que cresce DO CENTRO em todas as direções.
   75% já cobre o canto de um retângulo 59:86 (a % de `circle()` resolve contra a
   diagonal normalizada); 80% dá folga. */
.lab-spec--color { clip-path: circle(var(--reveal) at 50% 50%); }
/* Slot vazio (nenhuma carta escolhida). */
.lab-slot {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 12px; padding: 20px; text-align: center;
  color: #6c7c8e; font-size: 12.5px; line-height: 1.5; font-weight: 600;
  border: 2px dashed rgba(140, 165, 200, 0.28); border-radius: 8px;
}
.lab-slot i { font-size: 38px; color: var(--accent-bright); opacity: 0.55; }
.lab-slot.hidden { display: none; }
/* Encaixe de uma carta nova. */
.lab-specimen.is-loading .lab-card-3d { animation: lab-drop 0.42s cubic-bezier(0.25, 1.3, 0.4, 1); }
@keyframes lab-drop {
  from { opacity: 0; transform: translateY(-22px) scale(0.9); }
  to { opacity: 1; }
}
/* Alvo do arraste. */
.lab-specimen.is-drop-over .lab-card-3d { transform: scale(1.05) rotateX(var(--tilt-x)) rotateY(var(--tilt-y)); }
.lab-specimen.is-drop-ok .lab-slot { border-color: rgba(142, 199, 255, 0.55); }

/* Enquanto a síntese roda, a carta respira; ao terminar, um zoom leve + brilho. */
.lab-specimen.is-working .lab-card-3d { animation: lab-working 1.1s ease-in-out infinite; }
@keyframes lab-working {
  0%, 100% { filter: none; }
  50% { filter: brightness(1.12) drop-shadow(0 0 18px rgba(142, 199, 255, 0.45)); }
}
.lab-specimen.is-done .lab-card-3d { animation: lab-done 0.85s cubic-bezier(0.2, 1, 0.3, 1); }
@keyframes lab-done {
  0% { transform: scale(1); filter: none; }
  35% { transform: scale(1.09); filter: brightness(1.5) drop-shadow(0 0 34px rgba(120, 220, 170, 0.75)); }
  100% { transform: scale(1); filter: none; }
}

/* ── O contador: o ÚNICO indicador da bancada ──────────────────────────── */
.lab-meter {
  flex: none; display: flex; align-items: baseline; justify-content: center; gap: 8px;
  font-variant-numeric: tabular-nums;
}
.lm-now { font-size: 30px; font-weight: 900; color: #eef4fc; letter-spacing: -0.01em; transition: color 0.2s; }
.lm-sep { font-size: 22px; font-weight: 700; color: #4c5866; }
.lm-cost { font-size: 22px; font-weight: 800; color: var(--steel); }
.lm-unit { font-size: 12px; font-weight: 800; letter-spacing: 0.09em; color: #6d7d8e; margin-left: 2px; }
.lm-note { font-size: 12px; font-weight: 600; color: var(--steel); margin-left: 10px; align-self: center; }
/* Contando: o número acende enquanto sobe. Completo: verde de "pronto" (o mesmo
   --heal do resto da interface, não uma cor nova). */
.lab-meter.is-counting .lm-now { color: var(--accent-bright); }
.lab-meter.is-full .lm-now { color: var(--heal); text-shadow: 0 0 18px rgba(94, 255, 156, 0.35); }

/* Botões da bancada: os MESMOS `.de-btn` do montador. O "Salvar" do montador
   nunca fica indisponível, então o estado `:disabled` não existia lá — aqui
   existe (sem DP, sem alvo, tanque vazio) e precisa PARECER indisponível. */
.lab-do { flex: none; padding: 12px 18px; font-size: 13.5px; }
.de-btn:disabled, .lab-do:disabled { cursor: not-allowed; filter: grayscale(0.85) brightness(0.7); opacity: 0.55; }
.de-btn:disabled:hover, .lab-do:disabled:hover { filter: grayscale(0.85) brightness(0.7); }
.de-btn:disabled:active, .lab-do:disabled:active { transform: none; }
.lab-do-row { flex: none; display: flex; gap: 10px; }
.lab-do-row .de-btn { flex: 1; }
.lab-do-row .lab-do { flex: 2; }

/* ── A ação da bancada: três MODOS, um botão ─────────────────────────────
   Criar do zero (DP), destravar um acabamento ou destravar um print alternativo
   (3 cópias). Os ícones à esquerda escolhem; o botão diz o que vai acontecer, e
   a linha de baixo diz o que vai custar. */
.lab-act { flex: none; display: flex; align-items: stretch; gap: 10px; }
/* A borda é a MESMA receita dos outros chanfrados da interface: o fundo do
   elemento é a linha e um `::before` recuado 1px é o preenchimento — os dois com
   o mesmo `clip-path`. Um `box-shadow: inset` não serve aqui: ele desenha um
   retângulo e o chanfro o corta, deixando as pontas sem borda. */
.lab-modes {
  position: relative; isolation: isolate;
  flex: none; display: flex; gap: 4px; padding: 3px; clip-path: var(--cut-sm);
  background: rgba(140, 165, 200, 0.22);
}
.lab-modes::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; clip-path: var(--cut-sm);
  background: rgba(20, 27, 38, 0.85);
}
.lab-mode {
  width: 38px; border: none; background: transparent; border-radius: 0; cursor: pointer;
  color: #7d8b9c; font-size: 17px; display: inline-flex; align-items: center; justify-content: center;
  transition: color 0.14s, background 0.14s, transform 0.1s;
}
/* O realce dos das PONTAS acompanha o chanfro da caixa: o primeiro corta o canto
   superior esquerdo, o último o inferior direito — os mesmos dois cantos do
   `--cut-sm`. O do meio é um retângulo.
   O TAMANHO do corte é o que dá a folga: as duas diagonais são paralelas e a
   distância entre elas é (3 + 3 + c − 8)/√2, com c = corte do botão e 3px de
   padding da caixa. Com c=5 dava 2,1px — praticamente colado à borda. Com c=10
   dá 5,7px, a mesma respiração das bordas retas.
   O recorte vale sempre (não só selecionado) para o realce do hover ter a mesma
   silhueta e nada saltar ao clicar. */
.lab-mode:first-child { clip-path: polygon(10px 0, 100% 0, 100% 100%, 0 100%, 0 10px); }
.lab-mode:last-child {
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%);
}
.lab-mode:hover { color: #cfe0f2; background: rgba(255, 255, 255, 0.06); }
.lab-mode:active { transform: scale(0.94); }
.lab-mode.is-on { color: var(--accent-bright); background: rgba(89, 167, 240, 0.16); }
.lab-act .lab-do { flex: 1; }
/* O aviso do custo. Discreto por definição: quem já sabe o que está fazendo não
   deve tropeçar nele, e quem não sabe encontra a regra sem sair da tela. */
.lab-do-note {
  flex: none; min-height: 15px; text-align: center; font-size: 11px; font-weight: 600;
  color: #78879a; font-variant-numeric: tabular-nums; transition: color 0.16s;
}
.lab-do-note.is-ready { color: var(--heal); }

/* ── Tanque de descarte ────────────────────────────────────────────────── */
.lab-vat {
  flex: 1; min-height: 0; overflow-y: auto; padding: 10px; clip-path: var(--cut-sm);
  background: rgba(255, 255, 255, 0.03); box-shadow: inset 0 0 0 1px rgba(140, 165, 200, 0.14);
  transition: box-shadow 0.16s, background 0.16s;
}
.lab-vat.is-drop-ok { box-shadow: inset 0 0 0 1px rgba(142, 199, 255, 0.4); }
.lab-vat.is-drop-over { background: rgba(89, 167, 240, 0.09); box-shadow: inset 0 0 0 2px var(--accent-bright); }
.lab-vat-empty {
  height: 100%; min-height: 130px; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 12px; text-align: center;
  color: var(--steel); font-size: 13px; line-height: 1.6;
}
.lab-vat-empty i { font-size: 36px; opacity: 0.5; color: var(--accent-bright); }
.lab-vat-empty small { color: #6f7f8c; font-size: 11.5px; }
.lab-vat-empty.hidden { display: none; }
.lab-vat-list { display: flex; flex-direction: column; gap: 6px; }
.lab-vat-row {
  display: flex; align-items: center; gap: 11px; padding: 7px 10px; clip-path: var(--cut-xs);
  background: rgba(255, 255, 255, 0.045); animation: fade-in 0.2s ease-out; transition: background 0.14s;
}
.lab-vat-row:hover { background: rgba(89, 167, 240, 0.12); }
.lvr-img { width: 30px; aspect-ratio: 59 / 86; object-fit: cover; border-radius: 3px; flex: none; display: block; }
.lab-vat-row.r-RARE .lvr-img { box-shadow: 0 0 0 1px rgba(107, 178, 255, 0.5); }
.lab-vat-row.r-SUPER .lvr-img { box-shadow: 0 0 0 1px rgba(255, 154, 77, 0.55); }
.lab-vat-row.r-ULTRA .lvr-img { box-shadow: 0 0 0 1px rgba(192, 123, 255, 0.6); }
.lvr-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.lvr-name { font-size: 12.5px; font-weight: 800; color: #e7eef7; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lvr-meta { font-size: 10.5px; font-weight: 600; color: #7f909e; }
.lvr-qty { flex: none; display: inline-flex; align-items: center; gap: 2px; }
.lvr-btn {
  width: 22px; height: 22px; border: none; cursor: pointer; clip-path: var(--cut-xs);
  background: rgba(150, 160, 175, 0.28); color: #d3dfe9; font-size: 14px; font-weight: 900; font-family: inherit;
  display: inline-flex; align-items: center; justify-content: center; transition: background 0.14s, color 0.14s;
}
.lvr-btn:not(:disabled):hover { background: var(--accent-bright); color: #06131c; }
.lvr-btn:disabled { opacity: 0.3; cursor: not-allowed; }
.lvr-val { min-width: 34px; text-align: center; font-size: 11.5px; font-weight: 800; color: #cfdae6; font-variant-numeric: tabular-nums; }
.lvr-gain { flex: none; min-width: 46px; text-align: right; font-size: 12.5px; font-weight: 900; color: #9ed2ff; font-variant-numeric: tabular-nums; }
.lvr-x {
  flex: none; width: 22px; height: 22px; border: none; background: transparent; cursor: pointer;
  color: #7f909e; font-size: 14px; display: inline-flex; align-items: center; justify-content: center;
  transition: color 0.14s;
}
.lvr-x:hover { color: var(--danger); }

/* ── Ficha do laboratório na coluna da esquerda ────────────────────────── */
/* A `.de-own` do montador põe 2 células lado a lado; aqui são TRÊS números
   diferentes (posse · custo · pó), e em coluna eles se confundiam — cada um
   ganha a própria LINHA, com rótulo à esquerda e valor à direita. */
.lab-own { flex: none; display: flex; flex-direction: column; gap: 6px; }
.lab-own .de-own-cell { flex-direction: row; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 12px; }
.lab-own .do-l { flex: none; }
.lab-own .do-v { font-size: 14px; font-variant-numeric: tabular-nums; }
.lab-own .de-own-cell:nth-child(2) .do-l i { color: var(--accent-bright); }
.lab-own .de-own-cell:nth-child(3) .do-l i { color: var(--heal); }
.lab-warn {
  display: flex; align-items: flex-start; gap: 7px; padding: 8px 11px; clip-path: var(--cut-xs);
  background: rgba(232, 192, 100, 0.13); color: var(--gold-bright);
  font-size: 11.5px; line-height: 1.45; font-weight: 600;
}
.lab-warn i { font-size: 15px; flex: none; }
.lab-warn.hidden { display: none; }

/* ── Células do catálogo: as `.de-card` do montador + as marcas do lab ──── */
/* Selo de custo/pó acima da carta (o montador usa o espaço para o badge de
   raridade, que aqui continua igual — este entra ABAIXO, no rodapé da célula). */
.de-card--lab .lab-tag {
  position: absolute; left: 0; right: 0; bottom: -15px; z-index: 4; pointer-events: none;
  display: flex; align-items: center; justify-content: center; gap: 3px;
  font-size: 9.5px; font-weight: 900; line-height: 1; letter-spacing: 0.02em; color: #9ed2ff;
}
.de-card--lab .lab-tag i { font-size: 11px; }
.de-card--lab.is-dust .lab-tag { color: var(--heal); }
.de-card--lab.is-forbidden .lab-tag { color: #ff8a7a; }
/* Na câmara / no tanque: o mesmo destaque dourado que o montador usa p/ a carta
   fixada, para não inventar um segundo vocabulário de seleção. */
.de-card--lab.is-target, .de-card--lab.in-vat { border-color: var(--gold-bright); box-shadow: 0 0 12px -2px rgba(255, 215, 94, 0.55); }
.de-card--lab.is-forbidden::after {
  content: ''; position: absolute; inset: -2px; border-radius: 5px; pointer-events: none; z-index: 3;
  box-shadow: inset 0 0 0 2px rgba(255, 92, 73, 0.6);
}
/* A grade precisa de folga embaixo p/ o selo de custo (que fica FORA da carta). */
.lab-stage .de-grid--pool { gap: 30px 8px; }

/* ── Telas menores: mesmo comportamento do montador ─────────────────────── */
@media (max-width: 1180px) {
  .lab-stage .de-detail { display: none; }
}
@media (max-width: 900px) {
  .lab-stage { height: auto; overflow: visible; }
  .lab-stage .de-body { flex-direction: column; }
  .lab-bench { min-height: 66vh; }
  .lab-card-3d { height: 34vh; }
}
@media (prefers-reduced-motion: reduce) {
  .lab-specimen.is-working .lab-card-3d, .lab-view { animation: none !important; }
}

/* ══════════════════════════════════════════════════════════════════════════
   ACABAMENTOS DE CARTA (foil)
   ──────────────────────────────────────────────────────────────────────────
   Um foil não é uma textura desenhada por cima: é um padrão que se desloca em
   relação ao olho. O `background-position` de cada camada anda sozinho, cada
   uma em velocidade e sentido diferentes — o PARALAXE entre elas é o efeito.

   Os onze são portados do protótipo (`Assets YGO/level_cards`), que já foi
   calibrado nestas mesmas cartas. O que mudou em relação a ele, e por quê:

   1. **O ponteiro não participa do ACABAMENTO.** No protótipo o foil é uma
      DEMO: você passa o mouse e ele acende. Num jogo a carta fica parada no
      campo, na mão, na grade, e ninguém aponta para ela — foil que só existe
      sob o cursor é hover effect, não foil. Aqui TUDO vem de uma animação
      própria (`fx-alive`): `--fx-life` é o quanto a carta está acesa neste
      instante, `--fx-sweep-*` é por onde o realce está passando, e `--dx`/`--dy`
      é a deriva do padrão. (A INCLINAÇÃO é outra coisa e continua no ponteiro —
      ver a regra `.de-art, .sd-art, .skin-frame` mais abaixo.)
   2. **Nenhum período pode ser absoluto.** Todos os valores do protótipo estavam
      em pixel, calibrados numa carta de ~340px; aqui a MESMA carta aparece de
      40px (mão do oponente) a 500px (câmara do laboratório). Viraram % da LINHA
      do gradiente, que é proporcional à caixa: valor do protótipo ÷ comprimento
      da linha na carta dele (o mosaico do Cristal a 60° corre numa linha de
      759px, então 39px = 5,14%).
   3. **Paletas separadas.** No protótipo quase todo efeito puxava do mesmo
      arco-íris e, lado a lado, eles viravam o mesmo efeito com nomes
      diferentes. Aqui cada um tem a sua: arco-íris só no Holográfico e nos dois
      Reverse; o Cristal é GELO, o Starfoil é PRATA, o Starlight é prisma
      rosa/ouro, a Aurora é PÚRPURA, o Shiny fica com a "sunpillar" e o
      Terminal com ciano/magenta.
   4. Metade das cartas do jogo é pintada em `background-image` e não tem `<img>`
      para filtrar: quem tem imagem recebe o mesmo `filter` do protótipo
      (`.fx-on-img`), quem não tem ganha a camada `.fx-dim`, que faz o mesmo
      papel por blend (`#000` em multiply a 0.3 é exatamente `brightness(.7)`).

   O hospedeiro é o elemento que CONTÉM a arte (`.bface` no board, `.hcard` na
   mão, `.de-card` nas grades…): ele recebe `data-fx` e as camadas. Quem as
   pendura é `client/src/cosmetics.ts`.

   Holográfico, Aurora e Shiny vêm do pokemon-cards-css de simeydotme
   (github.com/simeydotme/pokemon-cards-css), inclusive a paleta "sunpillar".
   ══════════════════════════════════════════════════════════════════════════ */
:root {
  /* Paleta "sunpillar" — a assinatura do Shiny. */
  --sun-1: hsl(2, 100%, 73%);
  --sun-2: hsl(53, 100%, 69%);
  --sun-3: hsl(93, 100%, 69%);
  --sun-4: hsl(176, 100%, 76%);
  --sun-5: hsl(228, 100%, 74%);
  --sun-6: hsl(283, 100%, 73%);

  /* Texturas em SVG embutido. O ruído do feTurbulence se concentra perto de
     0,5 — cortar o alfa direto zeraria tudo; é preciso amplificar antes
     (alfa = k·R − c), que é o que a feColorMatrix de cada filtro faz. */
  --fx-tex-glitter: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='420' height='420'%3E%3Cfilter id='g' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.7' numOctaves='1' seed='11' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 5 0 0 0 -3.4'/%3E%3C/filter%3E%3Crect width='420' height='420' filter='url(%23g)'/%3E%3C/svg%3E");
  --fx-tex-stars: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='420' height='420'%3E%3Cfilter id='s' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='turbulence' baseFrequency='.9' numOctaves='1' seed='5' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 6 0 0 0 -4'/%3E%3C/filter%3E%3Crect width='420' height='420' filter='url(%23s)'/%3E%3C/svg%3E");
  --fx-tex-dust: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='d' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.4' numOctaves='2' seed='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 3 0 0 0 -1.7'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23d)'/%3E%3C/svg%3E");
}

/* Registrar com @property é o que faz INTERPOLAR: custom property não
   registrada SALTA de um keyframe para o outro. `inherits: true` porque o
   Cristal precisa que as duas camadas leiam o MESMO valor — se as arestas
   derivassem separadas das facetas, o mosaico rasgava. */
@property --fx-drift-x { syntax: '<percentage>'; inherits: true; initial-value: 0%; }
@property --fx-drift-y { syntax: '<percentage>'; inherits: true; initial-value: 0%; }
@property --fx-life { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --fx-sweep-x { syntax: '<percentage>'; inherits: true; initial-value: 0%; }
@property --fx-sweep-y { syntax: '<percentage>'; inherits: true; initial-value: 0%; }

/* Trajetória elíptica: nunca passa duas vezes pelo mesmo ponto no mesmo
   sentido, o que evita a leitura de vaivém mecânico. A "vida" e o passeio do
   realce correm no MESMO ciclo, então o brilho acende onde o padrão está
   andando — luz varrendo a superfície, não duas animações independentes.

   O teto da vida é 0,74 e não 1 de propósito: levar a carta ao máximo a cada
   volta lava a arte e vira estroboscópio. O que se quer é cintilação. */
@keyframes fx-alive {
  0%, 100% { --fx-drift-x: 0%; --fx-drift-y: 0%; --fx-life: 0.2; --fx-sweep-x: -26%; --fx-sweep-y: -16%; }
  25% { --fx-drift-x: 6%; --fx-drift-y: -4%; --fx-life: 0.52; --fx-sweep-x: 12%; --fx-sweep-y: 18%; }
  50% { --fx-drift-x: 0%; --fx-drift-y: -8%; --fx-life: 0.74; --fx-sweep-x: 28%; --fx-sweep-y: -8%; }
  75% { --fx-drift-x: -6%; --fx-drift-y: -4%; --fx-life: 0.44; --fx-sweep-x: -10%; --fx-sweep-y: 16%; }
}

/* Hospedeiro. `isolation` PRECISA existir: sem ela o color-dodge das camadas
   sangraria para o fundo da tela em vez de parar na carta. */
[data-fx] {
  isolation: isolate;
  --fx: 1;            /* intensidade; contextos apertados podem baixar */
  --o: 0.5;           /* opacidade base do foil, por efeito */
  --fx-amp: 1;        /* multiplicador de DERIVA, por efeito */
  /* Deriva já com a amplitude do efeito: é o que todo `background-position` usa. */
  --dx: calc(var(--fx-drift-x) * var(--fx-amp));
  --dy: calc(var(--fx-drift-y) * var(--fx-amp));
  /* O quanto o efeito está aceso e por onde o realce passa — tudo da animação. */
  --fx-hot: var(--fx-life);
  --fx-lit: calc(var(--fx-life) * 0.62);
  --fx-at-x: calc(50% + var(--fx-sweep-x));
  --fx-at-y: calc(50% + var(--fx-sweep-y));
  animation: fx-alive var(--fx-drift-time, 12s) ease-in-out infinite;
}
/* Períodos primos entre si: cartas vizinhas nunca sincronizam na tela. */
[data-fx="holo"] { --fx-drift-time: 11s; --o: 0.42; }
/* O Cristal anda MAIS que os outros: o mosaico é o efeito, e um mosaico parado
   parece textura colada. Deriva 2,4× num ciclo mais curto. */
[data-fx="crystal"] { --fx-drift-time: 7s; --o: 0.52; --fx-amp: 2.4; }
[data-fx="star"] { --fx-drift-time: 12s; --o: 0.5; }
[data-fx="starlight"] { --fx-drift-time: 14s; --o: 0.58; }
[data-fx="reverse"] { --fx-drift-time: 15s; --o: 0.75; }
/* Mesma intensidade do Reverse (é o mesmo efeito); só o PERÍODO difere, e é de
   propósito — dois efeitos com o mesmo ciclo sincronizariam lado a lado. */
[data-fx="reverse-full"] { --fx-drift-time: 13s; --o: 0.75; }
[data-fx="vibrance"] { --fx-drift-time: 10s; --o: 0.55; }
[data-fx="matte"] { --fx-drift-time: 17s; --o: 0.5; }
[data-fx="curtain"] { --fx-drift-time: 9s; --o: 0.8; }
[data-fx="shiny"] { --fx-drift-time: 12.5s; --o: 0.72; }
[data-fx="terminal"] { --fx-drift-time: 8s; --o: 0.72; }

/* ── Inclinação: a carta EM FOCO vira na mão ───────────────────────────────
   O ACABAMENTO não reage ao mouse (item 1 do cabeçalho), mas a carta grande
   sim: nas apresentações onde existe UMA carta em foco — o detalhe do montador
   e do laboratório, o da loja, o seletor de visual — ela acompanha o ponteiro
   como se estivesse na mão. Vale para QUALQUER carta, com acabamento ou sem,
   por isso o seletor não pede `[data-fx]`. Quem escreve os ângulos é o
   `wireCardTilt` de `cosmetics.ts` — a mesma lista de seletores está lá. */
.de-art, .sd-art, .skin-frame {
  --rotate-x: 0deg; --rotate-y: 0deg;
  transform: perspective(760px) rotateX(var(--rotate-y)) rotateY(var(--rotate-x));
  transition: transform 0.25s cubic-bezier(0.16, 0.84, 0.34, 1);
}

.fx-lay {
  position: absolute; inset: 0; display: block; border-radius: inherit;
  pointer-events: none; background-repeat: repeat; z-index: 1;
}
/* O raio não se herda de todo hospedeiro (a `.hcard` não tem raio próprio — quem
   tem é a <img> dentro dela), então cada casa diz o seu. */
.hcard[data-fx] .fx-lay { border-radius: 6px; }
.de-card[data-fx] .fx-lay { border-radius: 3px; }
.lab-card-3d[data-fx] .fx-lay { border-radius: 8px; }
.viewer-face[data-fx] .fx-lay { border-radius: 12px; }
.de-art[data-fx] .fx-lay, .sd-art[data-fx] .fx-lay, .skin-frame[data-fx] .fx-lay { border-radius: 6px; }
#preview-card-art[data-fx] .fx-lay, #cm-art[data-fx] .fx-lay, #insp-card[data-fx] .fx-lay { border-radius: 8px; }
/* Selos e estrela ficam ACIMA do acabamento: são informação, não decoração. Os
   chips de raridade são `::after` do próprio hospedeiro e, sem z-index, valem
   `auto` (0) — o foil passava por cima deles. */
.de-card-badge, .de-star, .de-card--lab .lab-tag { z-index: 8; }
#insp-card::after, .sd-art::after, .de-art::after,
.cl-thumb::after, .de-card::after, .olog-card::after { z-index: 8; }

/* O foil ESCURECE o substrato antes de somar luz: sem essa margem o color-dodge
   satura direto para o branco numa carta clara e a cor não chega a aparecer — é
   o mesmo motivo pelo qual uma carta foil real parece mais escura que a comum
   vista de frente. O `:not(.lab-spec)` protege a câmara do laboratório, onde a
   cópia preto-e-branco tem filtro próprio. */
[data-fx].fx-on-img > img:not(.lab-spec) { filter: brightness(0.7) saturate(1.05); }
#lab-card[data-fx] > .lab-spec--color { filter: brightness(0.7) saturate(1.05); }
/* Hospedeiro sem <img> (pintado em background-image): a camada faz o papel do
   filter — `#000` em multiply a 0.3 é exatamente `brightness(.7)`. */
.fx-dim { background: #000; opacity: 0.3; mix-blend-mode: multiply; }

/* O foil cede sobre a caixa de texto, senão o color-dodge satura a área clara e
   apaga o efeito escrito. A rampa é contínua de propósito: degraus curtos aqui
   aparecem como uma faixa horizontal atravessando a carta. */
.fx-foil, .fx-foil-b {
  -webkit-mask-image: linear-gradient(180deg,
    #000 0 46%, rgba(0, 0, 0, 0.88) 56%, rgba(0, 0, 0, 0.6) 66%,
    rgba(0, 0, 0, 0.34) 76%, rgba(0, 0, 0, 0.3) 100%);
  mask-image: linear-gradient(180deg,
    #000 0 46%, rgba(0, 0, 0, 0.88) 56%, rgba(0, 0, 0, 0.6) 66%,
    rgba(0, 0, 0, 0.34) 76%, rgba(0, 0, 0, 0.3) 100%);
}

/* Realce especular: o BRANCO vem daqui, nunca das camadas de foil. Ele passeia
   com a animação — é o reflexo correndo pela superfície. */
.fx-glare {
  z-index: 3;
  background-image: radial-gradient(farthest-corner circle at var(--fx-at-x) var(--fx-at-y),
    hsla(0, 0%, 100%, 0.5) 5%, hsla(0, 0%, 92%, 0.28) 15%,
    hsla(220, 18%, 38%, 0.18) 38%, hsla(220, 42%, 4%, 0.5) 90%);
  mix-blend-mode: overlay;
  opacity: calc(var(--fx-lit) * 0.8);
}
.fx-rim {
  z-index: 4;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.11),
    inset 0 1px 1px rgba(255, 255, 255, 0.16),
    inset 0 -1px 2px rgba(0, 0, 0, 0.5);
}

/* ── 01 · Holográfico — ARCO-ÍRIS (a paleta canônica; só ele e os Reverse) ── */
[data-fx="holo"] .fx-foil {
  --space: 4.5%;
  background-image:
    repeating-linear-gradient(0deg,
      rgb(255, 119, 115) calc(var(--space) * 1), rgb(255, 237, 95) calc(var(--space) * 2),
      rgb(168, 255, 95) calc(var(--space) * 3), rgb(131, 255, 247) calc(var(--space) * 4),
      rgb(120, 148, 255) calc(var(--space) * 5), rgb(216, 117, 255) calc(var(--space) * 6),
      rgb(255, 119, 115) calc(var(--space) * 7)),
    repeating-linear-gradient(133deg,
      #0e152e 0%, hsl(180, 10%, 60%) 3.8%, hsl(180, 29%, 66%) 4.5%,
      hsl(180, 10%, 60%) 5.2%, #0e152e 10%, #0e152e 12%),
    radial-gradient(farthest-corner circle at var(--fx-at-x) var(--fx-at-y),
      rgba(0, 0, 0, 0.12) 12%, rgba(0, 0, 0, 0.2) 24%, rgba(0, 0, 0, 0.34) 120%);
  background-blend-mode: exclusion, hue, hard-light;
  background-size: 500% 500%, 300% 300%, 200% 200%;
  background-position:
    calc(-50% + var(--dx)) calc(-50% + var(--dy)),
    calc(50% - var(--dx)) calc(50% - var(--dy)),
    center center;
  filter: brightness(calc(0.5 + var(--fx-hot) * 0.26)) contrast(1.85) saturate(1.6);
  mix-blend-mode: color-dodge;
  opacity: calc(var(--o) * var(--fx));
}
[data-fx="holo"] .fx-foil-b {
  background-image: var(--fx-tex-dust);
  background-size: 38% 38%;
  background-position: calc(30% + var(--dx)) calc(30% + var(--dy));
  mix-blend-mode: color-dodge;
  opacity: calc((0.06 + var(--fx-lit) * 0.14) * var(--fx));
}

/* ── 02 · Cristal — GELO ───────────────────────────────────────────────────
   Três famílias de faixas a 60° uma da outra, com períodos diferentes: ao se
   cruzarem recortam a superfície num mosaico irregular, e cada célula cai numa
   luminância distinta. É isso que lê como pedra lapidada. A rampa de cor é de
   GELO (ciano/branco/lilás claro) — no protótipo ela puxava para o arco-íris e
   o Cristal virava mais um holográfico.
   Os períodos estão em % DA LINHA do gradiente (item 2 do cabeçalho): 5,14% e
   2,5% são os 39px e 19px do protótipo divididos pelos 759px que a linha a 60°
   mede na carta dele. */
[data-fx="crystal"] .fx-foil {
  background-image:
    repeating-linear-gradient(60deg,
      rgba(255, 255, 255, 0.32) 0 2.5%, rgba(0, 0, 0, 0.32) 2.5% 5.14%),
    repeating-linear-gradient(-60deg,
      rgba(255, 255, 255, 0.32) 0 1.84%, rgba(0, 0, 0, 0.32) 1.84% 3.56%),
    repeating-linear-gradient(0deg,
      rgba(255, 255, 255, 0.3) 0 3.46%, rgba(0, 0, 0, 0.3) 3.46% 7.06%),
    linear-gradient(112deg,
      #d8f6ff 0%, #7fc4ff 16%, #ffffff 32%, #a9e4ff 48%,
      #6f9dff 64%, #e6f6ff 80%, #8fd4ff 100%),
    radial-gradient(farthest-corner circle at var(--fx-at-x) var(--fx-at-y),
      rgba(0, 0, 0, 0.12) 12%, rgba(0, 0, 0, 0.2) 26%, rgba(0, 0, 0, 0.38) 120%);
  background-blend-mode: overlay, overlay, overlay, hard-light;
  /* 140% e não `auto`: com auto o gradiente ocupa exatamente a caixa, e posição
     em porcentagem vira zero — as facetas ficavam presas. */
  background-size: 140% 140%, 140% 140%, 140% 140%, 240% 240%, 200% 200%;
  background-position:
    calc(70% + var(--dx)) calc(70% + var(--dy)),
    calc(-70% + var(--dx)) calc(70% + var(--dy)),
    center calc(-90% + var(--dy)),
    calc(-80% - var(--dx)) calc(-80% - var(--dy)),
    center center;
  filter: brightness(calc(0.48 + var(--fx-hot) * 0.28)) contrast(1.7) saturate(1.15);
  mix-blend-mode: color-dodge;
  opacity: calc(var(--o) * var(--fx));
}
/* O fio das arestas: mesmos períodos das facetas, com o traço fininho (0,13% da
   linha ≈ 1px na carta do protótipo) — é a quina do mosaico, não outro padrão. */
[data-fx="crystal"] .fx-foil-b {
  background-image:
    repeating-linear-gradient(60deg, rgba(255, 255, 255, 0.6) 0 0.13%, transparent 0.13% 5.14%),
    repeating-linear-gradient(-60deg, rgba(255, 255, 255, 0.6) 0 0.13%, transparent 0.13% 3.56%),
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.5) 0 0.14%, transparent 0.14% 7.06%);
  background-size: 140% 140%, 140% 140%, 140% 140%;
  background-position:
    calc(70% + var(--dx)) calc(70% + var(--dy)),
    calc(-70% + var(--dx)) calc(70% + var(--dy)),
    center calc(-90% + var(--dy));
  mix-blend-mode: color-dodge;
  filter: brightness(calc(0.55 + var(--fx-hot) * 0.7));
  opacity: calc((0.3 + var(--fx-lit) * 0.35) * var(--fx));
}

/* ── 03 · Starfoil — PRATA ─────────────────────────────────────────────────
   Foil de estrelas prateado: as faíscas derivam sozinhas e o fundo é metal, não
   espectro. DUAS animações em paralelo tocando propriedades diferentes — uma o
   background-position, outra o filter — porque duas animações na MESMA
   propriedade se cancelam. */
[data-fx="star"] .fx-foil {
  --space: 5.5%;
  background-image:
    repeating-linear-gradient(115deg,
      #ffffff calc(var(--space) * 1), #b9c9dc calc(var(--space) * 2),
      #eef4fb calc(var(--space) * 3), #8ea3ba calc(var(--space) * 4),
      #dfe9f5 calc(var(--space) * 5), #ffffff calc(var(--space) * 6)),
    radial-gradient(farthest-corner circle at var(--fx-at-x) var(--fx-at-y),
      rgba(0, 0, 0, 0.1) 12%, rgba(0, 0, 0, 0.18) 26%, rgba(0, 0, 0, 0.32) 120%);
  background-blend-mode: overlay;
  background-size: 400% 400%, 200% 200%;
  background-position: calc(-50% + var(--dx)) calc(-50% + var(--dy)), center center;
  filter: brightness(calc(0.52 + var(--fx-hot) * 0.3)) contrast(1.6) saturate(0.7);
  mix-blend-mode: color-dodge;
  opacity: calc(var(--o) * var(--fx));
}
[data-fx="star"] .fx-foil-b {
  /* Malhas menores = mais faíscas por carta. 25% e 12,5% não são arbitrários:
     são os tamanhos que fecham o laço abaixo (P = t/(1−t)) em números exatos —
     um terço e um sétimo. Vieram de 40%/20%: o campo ficou bem mais denso. */
  background-image: var(--fx-tex-stars), var(--fx-tex-glitter);
  background-size: 25% 25%, 12.5% 12.5%;
  mix-blend-mode: color-dodge;
  /* A faísca é o efeito INTEIRO deste foil, então ela vai de ponta a ponta da
     carta: a rampa que alivia a caixa de texto some aqui (a chapa de metal do
     `.fx-foil` continua com ela, que é quem podia apagar o texto escrito). */
  -webkit-mask-image: none; mask-image: none;
  animation: fx-star-drift 17s linear infinite, fx-star-twinkle 2.9s ease-in-out infinite;
}
/* LAÇO EXATO. Porcentagem em background-position não é relativa ao ladrilho e
   sim a (container − imagem): o deslocamento real é (1−t)·P. Para andar um
   ladrilho inteiro e o padrão voltar a coincidir consigo mesmo, P = t/(1−t).
   Com t=25% dá 33,3333%; com t=12,5% dá 14,2857%. Sem essa conta o ciclo fecha
   no meio de um ladrilho e SALTA.
   A malha fina anda TRÊS ladrilhos no mesmo tempo em que a grossa anda um: as
   faíscas pequenas correm, as grandes passeiam, e é o descompasso entre as duas
   que dá profundidade em vez de um campo escorregando inteiro. */
@keyframes fx-star-drift {
  from { background-position: 0% 0%, 0% 0%; }
  to { background-position: -33.3333% 33.3333%, 42.8571% -42.8571%; }
}
/* O respiro de opacidade nasce e morre no mesmo valor, então também fecha. */
@keyframes fx-star-twinkle {
  0%, 100% { filter: brightness(1.05) contrast(1.8); opacity: calc(0.8 * var(--fx)); }
  50% { filter: brightness(2.05) contrast(1.95); opacity: calc(1 * var(--fx)); }
}

/* ── 04 · Starlight — PRISMA ROSA/OURO ─────────────────────────────────── */
[data-fx="starlight"] .fx-foil {
  --space: 5%;
  background-image:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.32) 0 0.11%, rgba(0, 0, 0, 0.2) 0.11% 0.43%),
    repeating-linear-gradient(-45deg, rgba(255, 255, 255, 0.32) 0 0.11%, rgba(0, 0, 0, 0.2) 0.11% 0.43%),
    repeating-linear-gradient(100deg,
      #ffc2dd calc(var(--space) * 1), #ffe6b0 calc(var(--space) * 2),
      #fff4e2 calc(var(--space) * 3), #ffb8c9 calc(var(--space) * 4),
      #e0c2ff calc(var(--space) * 5), #ffc2dd calc(var(--space) * 6)),
    radial-gradient(farthest-corner circle at var(--fx-at-x) var(--fx-at-y),
      rgba(0, 0, 0, 0.1) 12%, rgba(0, 0, 0, 0.18) 26%, rgba(0, 0, 0, 0.34) 120%);
  background-blend-mode: overlay, overlay, hue;
  /* Mesma correção do Cristal: com `auto` a hachura não se deslocava. */
  background-size: 125% 125%, 125% 125%, 400% 400%, 200% 200%;
  background-position:
    calc(45% + var(--dx)) calc(45% + var(--dy)),
    calc(-45% - var(--dx)) calc(45% + var(--dy)),
    calc(-65% + var(--dx)) calc(-65% + var(--dy)),
    center center;
  filter: brightness(calc(0.56 + var(--fx-hot) * 0.26)) contrast(1.9) saturate(1.5);
  mix-blend-mode: color-dodge;
  opacity: calc(var(--o) * var(--fx));
}
[data-fx="starlight"] .fx-foil-b {
  background-image: var(--fx-tex-glitter);
  background-size: 36% 36%;
  background-position: calc(-22.5% + var(--dx)) calc(-22.5% + var(--dy));
  mix-blend-mode: color-dodge;
  filter: brightness(calc(0.85 + var(--fx-hot) * 1));
  opacity: calc((0.36 + var(--fx-lit) * 0.34) * var(--fx));
}

/* ── 05 · Reverse Holo — ARCO-ÍRIS, só na moldura ──────────────────────────
   O foil cobre a carta inteira MENOS a janela da arte, recortada por clip-path
   com regra par-ímpar. A janela engloba a MOLDURA da arte, não só os pixels
   dentro dela: parar na borda da ilustração deixava uma tira de foil em cima da
   moldura. São os números medidos no protótipo, nesta mesma carta. */
[data-fx="reverse"] .fx-foil,
[data-fx="reverse"] .fx-foil-b {
  clip-path: polygon(evenodd,
    0 0, 100% 0, 100% 100%, 0 100%, 0 0,
    11.4% 18%, 88.7% 18%, 88.7% 70.6%, 11.4% 70.6%, 11.4% 18%);
}
/* A ÚNICA diferença entre os dois é o recorte acima. Todo o resto — máscara
   dispensada, arte sem escurecer, intensidade — vale para os dois, senão o Full
   não seria "o Reverse na carta inteira" e sim outro efeito. */
[data-fx="reverse"] .fx-foil, [data-fx="reverse"] .fx-foil-b,
[data-fx="reverse-full"] .fx-foil, [data-fx="reverse-full"] .fx-foil-b {
  -webkit-mask-image: none; mask-image: none;
}
[data-fx="reverse"].fx-on-img > img:not(.lab-spec),
[data-fx="reverse-full"].fx-on-img > img:not(.lab-spec) { filter: none; }
#lab-card[data-fx="reverse"] > .lab-spec--color,
#lab-card[data-fx="reverse-full"] > .lab-spec--color { filter: none; }
[data-fx="reverse"] .fx-dim, [data-fx="reverse-full"] .fx-dim { opacity: 0; }
[data-fx="reverse"] .fx-foil,
[data-fx="reverse-full"] .fx-foil {
  --space: 4%;
  background-image:
    repeating-linear-gradient(112deg,
      rgb(255, 140, 150) calc(var(--space) * 1), rgb(255, 235, 150) calc(var(--space) * 2),
      rgb(170, 255, 190) calc(var(--space) * 3), rgb(140, 220, 255) calc(var(--space) * 4),
      rgb(200, 160, 255) calc(var(--space) * 5), rgb(255, 140, 150) calc(var(--space) * 6)),
    radial-gradient(farthest-corner circle at var(--fx-at-x) var(--fx-at-y),
      rgba(0, 0, 0, 0.12) 12%, rgba(0, 0, 0, 0.2) 26%, rgba(0, 0, 0, 0.34) 120%);
  background-blend-mode: hue;
  background-size: 340% 340%, 200% 200%;
  background-position: calc(-75% + var(--dx)) calc(-75% + var(--dy)), center center;
  filter: brightness(calc(0.5 + var(--fx-hot) * 0.26)) contrast(1.8) saturate(1.55);
  mix-blend-mode: color-dodge;
  opacity: calc(var(--o) * var(--fx));
}
[data-fx="reverse"] .fx-foil-b,
[data-fx="reverse-full"] .fx-foil-b {
  background-image: var(--fx-tex-glitter);
  background-size: 32% 32%;
  background-position: calc(-25% - var(--dx)) calc(-25% - var(--dy));
  mix-blend-mode: color-dodge;
  filter: brightness(calc(0.7 + var(--fx-hot) * 0.9));
  opacity: calc(0.5 * var(--fx));
}

/* ── 06 · Reverse Holo Full ────────────────────────────────────────────────
   É o Reverse Holo com o recorte fora — nada mais. Todas as regras dele estão
   escritas junto com as do Reverse (acima), e o `clip-path` é a única que o Full
   não recebe: assim os dois não podem divergir sem que se perceba. */

/* ── 07 · Vibrance ─────────────────────────────────────────────────────────
   O oposto de um foil: não acrescenta padrão nenhum. A cor da PRÓPRIA carta é
   empurrada por uma camada em `mix-blend-mode: saturation`, que mexe só na
   saturação e deixa brilho e matiz intactos — a ilustração fica inteira, só
   mais viva. Por cima, um verniz que dá o brilho de papel couché. */
[data-fx="vibrance"].fx-on-img > img:not(.lab-spec) {
  filter: saturate(1.28) contrast(1.06) brightness(1.01);
}
[data-fx="vibrance"] .fx-dim { opacity: 0; }
[data-fx="vibrance"] .fx-foil {
  /* Cinza puro tem saturação zero; totalmente saturado tem 100. Uma camada
     saturada em blend `saturation` puxa a carta para cima sem tocar no resto. */
  background-image: linear-gradient(112deg,
    hsl(350, 100%, 50%), hsl(45, 100%, 50%), hsl(150, 100%, 50%),
    hsl(200, 100%, 50%), hsl(280, 100%, 50%), hsl(350, 100%, 50%));
  background-size: 260% 260%;
  background-position: calc(-60% + var(--dx)) calc(-60% + var(--dy));
  mix-blend-mode: saturation;
  opacity: calc(var(--o) * var(--fx));
}
/* Verniz: brilho amplo e macio, sem cor. É o que separa "carta saturada" de
   "carta com acabamento brilhante". O ângulo acompanha o passeio do realce. */
[data-fx="vibrance"] .fx-foil-b {
  background-image: linear-gradient(calc(120deg + var(--fx-sweep-x) * 0.6),
    transparent 18%, rgba(255, 255, 255, 0.16) 42%, rgba(255, 255, 255, 0.34) 50%,
    rgba(255, 255, 255, 0.16) 58%, transparent 82%);
  background-size: 230% 230%;
  background-position: calc(-100% + var(--dx) * 2) calc(-50% + var(--dy));
  mix-blend-mode: soft-light;
  opacity: calc((0.5 + var(--fx-lit) * 0.5) * var(--fx));
}

/* ── 08 · Fosca ────────────────────────────────────────────────────────────
   O contrário da Vibrance. Superfície fosca não devolve um ponto de luz: ela
   ESPALHA. Por isso o realce aqui é largo e fraco em vez de pequeno e forte, a
   borda perde o fio branco, a cor recua e entra grão de papel. Nenhuma camada
   usa color-dodge. */
[data-fx="matte"].fx-on-img > img:not(.lab-spec) {
  filter: saturate(0.72) contrast(0.93) brightness(0.99);
}
[data-fx="matte"] .fx-dim { background: #808080; mix-blend-mode: saturation; opacity: 0.28; }
/* Grão de papel: a mesma textura de poeira, mas em soft-light, que apenas
   perturba a superfície em vez de acender pontos nela. */
[data-fx="matte"] .fx-foil {
  background-image: var(--fx-tex-dust);
  background-size: 22% 22%;
  background-position: calc(50% + var(--dx) * 0.4) calc(50% + var(--dy) * 0.4);
  mix-blend-mode: soft-light;
  filter: contrast(0.8);
  opacity: calc(var(--o) * var(--fx));
}
/* Sem reflexo especular, o volume tem de vir de sombreamento. */
[data-fx="matte"] .fx-foil-b {
  background-image: radial-gradient(farthest-corner circle at 50% 45%,
    transparent 30%, rgba(20, 20, 26, 0.28) 100%);
  mix-blend-mode: multiply;
  opacity: calc(0.8 * var(--fx));
}
/* O realce vira uma mancha larga e fraca — é a diferença entre fosco e
   brilhante mais do que qualquer textura. */
[data-fx="matte"] .fx-glare {
  background-image: radial-gradient(farthest-corner circle at var(--fx-at-x) var(--fx-at-y),
    hsla(40, 10%, 92%, 0.16) 0%, hsla(40, 8%, 80%, 0.09) 45%, hsla(220, 20%, 10%, 0.28) 100%);
  mix-blend-mode: soft-light;
  opacity: calc(0.35 + var(--fx-lit) * 0.45);
}
/* Papel fosco não tem aresta espelhada. */
[data-fx="matte"] .fx-rim {
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05), inset 0 -1px 3px rgba(0, 0, 0, 0.4);
}

/* ── 09 · Aurora — PÚRPURA ─────────────────────────────────────────────────
   Adaptado do trainer-gallery do pokemon-cards-css. A marca desse foil é o EIXO
   TRAVADO: o fundo só anda em Y, com X fixo em 0%. O feixe sobe e desce mas
   nunca corre de lado — o olho lê como cortina de luz, não como brilho. A paleta é de
   ametista (púrpura → magenta → violeta), não o espectro inteiro. */
[data-fx="curtain"] .fx-foil {
  --space: 5%;
  background-image:
    repeating-linear-gradient(-22deg,
      hsla(283, 62%, 62%, 0.8) calc(var(--space) * 1),
      hsla(312, 66%, 60%, 0.8) calc(var(--space) * 2),
      hsla(268, 55%, 52%, 0.8) calc(var(--space) * 3),
      hsla(330, 60%, 66%, 0.8) calc(var(--space) * 4),
      hsla(292, 70%, 70%, 0.8) calc(var(--space) * 5),
      hsla(255, 60%, 58%, 0.8) calc(var(--space) * 6),
      hsla(283, 62%, 62%, 0.8) calc(var(--space) * 7)),
    radial-gradient(farthest-corner circle at var(--fx-at-x) var(--fx-at-y),
      rgba(0, 0, 0, 0.12) 12%, rgba(0, 0, 0, 0.2) 26%, rgba(0, 0, 0, 0.36) 120%);
  background-blend-mode: color-dodge;
  background-size: 300% 400%, 200% 200%;
  /* A deriva também só anda em Y: mover X aqui destruiria a identidade. */
  background-position: 0% calc(50% + var(--dy)), center center;
  filter: brightness(calc(var(--fx-hot) * 0.38 + 0.66)) contrast(2) saturate(1.25);
  mix-blend-mode: color-dodge;
  opacity: calc(var(--o) * var(--fx));
}
[data-fx="curtain"] .fx-foil-b {
  background-image: radial-gradient(farthest-corner circle at var(--fx-at-x) var(--fx-at-y),
    rgba(255, 255, 255, 0.5) 0%, rgba(200, 170, 255, 0.2) 35%, transparent 70%);
  mix-blend-mode: overlay;
  opacity: calc((0.1 + var(--fx-lit) * 0.3) * var(--fx));
}

/* ── 10 · Shiny — SUNPILLAR ────────────────────────────────────────────────
   Adaptado do pokemon-cards-css. O detalhe que faz a diferença é o CISALHAMENTO
   do trilho metálico: a posição X dele recebe uma fração do Y, então ele se
   inclina conforme o padrão sobe e desce — e não apenas desliza. */
[data-fx="shiny"] .fx-foil {
  --space: 5%;
  background-image:
    var(--fx-tex-dust),
    repeating-linear-gradient(0deg,
      var(--sun-1) calc(var(--space) * 1), var(--sun-2) calc(var(--space) * 2),
      var(--sun-3) calc(var(--space) * 3), var(--sun-4) calc(var(--space) * 4),
      var(--sun-5) calc(var(--space) * 5), var(--sun-6) calc(var(--space) * 6),
      var(--sun-1) calc(var(--space) * 7)),
    repeating-linear-gradient(133deg,
      #0e152e 0%, hsl(180, 10%, 60%) 3.8%, hsl(180, 29%, 66%) 4.5%,
      hsl(180, 10%, 60%) 5.2%, #0e152e 10%, #0e152e 12%),
    radial-gradient(farthest-corner circle at var(--fx-at-x) var(--fx-at-y),
      rgba(0, 0, 0, 0.1) 12%, rgba(0, 0, 0, 0.15) 20%, rgba(0, 0, 0, 0.25) 120%);
  background-blend-mode: soft-light, hue, hard-light;
  background-size: 30% 30%, 200% 700%, 300% 100%, 200% 100%;
  background-position:
    center center,
    0% calc(50% + var(--dy)),
    calc(60% + var(--dx)) calc(50% + var(--dy)),
    calc(50% - var(--dx)) calc(50% - var(--dy));
  filter: brightness(calc(var(--fx-hot) * 0.45 + 0.58)) contrast(1.5) saturate(2.25);
  mix-blend-mode: color-dodge;
  opacity: calc(var(--o) * var(--fx));
}
[data-fx="shiny"] .fx-foil-b {
  background-image: var(--fx-tex-glitter);
  background-size: 26% 26%;
  background-position: calc(-30% + var(--dx)) calc(-30% + var(--dy));
  mix-blend-mode: color-dodge;
  filter: brightness(calc(0.75 + var(--fx-hot) * 0.9));
  opacity: calc((0.22 + var(--fx-lit) * 0.3) * var(--fx));
}

/* ── 11 · Duel Terminal — CIANO/MAGENTA ────────────────────────────────── */
[data-fx="terminal"].fx-on-img > img:not(.lab-spec) {
  filter: brightness(0.8) contrast(1.12) saturate(1.18);
}
[data-fx="terminal"] .fx-dim { opacity: 0.2; }
[data-fx="terminal"] .fx-foil {
  background-image:
    /* Banho frio: sem ele o efeito assume a cor quente da carta. */
    linear-gradient(185deg, rgba(0, 175, 215, 0.55) 0%, rgba(0, 85, 165, 0.4) 55%, rgba(35, 0, 95, 0.45) 100%),
    linear-gradient(90deg,
      rgba(255, 0, 90, 1) 0%, rgba(255, 0, 90, 0.35) 16%, transparent 34%,
      transparent 66%, rgba(0, 220, 255, 0.35) 84%, rgba(0, 220, 255, 1) 100%),
    repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.9) 0 0.2%, transparent 0.2% 0.61%);
  background-blend-mode: screen, hard-light;
  background-size: 100% 100%, calc(210% - var(--fx-hot) * 90%) 100%, 100% 100%;
  background-position: center, center, center calc(-20% + var(--dy));
  mix-blend-mode: color-dodge;
  filter: brightness(calc(0.78 + var(--fx-hot) * 0.5)) contrast(1.7) saturate(1.35);
  opacity: calc(var(--o) * var(--fx));
}
[data-fx="terminal"] .fx-foil-b {
  background-image: linear-gradient(180deg,
    transparent 42%, rgba(120, 255, 235, 0.4) 48%, rgba(255, 255, 255, 0.8) 50%,
    rgba(120, 255, 235, 0.4) 52%, transparent 58%);
  background-size: 100% 300%;
  mix-blend-mode: screen;
  opacity: calc(0.6 * var(--fx));
  animation: fx-scan 4.2s linear infinite;
}
/* Com background-size 300%, AUMENTAR a posição move a imagem para CIMA — por
   isso a varredura desce indo de 200% para −100%, e não o contrário. */
@keyframes fx-scan {
  0% { background-position: 0 200%; }
  100% { background-position: 0 -100%; }
}

/* Cartinha pequena (mão do oponente, miniaturas do tanque): o padrão inteiro
   num quadrado de 40px vira ruído — a intensidade cai. */
.hand-row.opp .hcard[data-fx], .lvr-img[data-fx] { --fx: 0.7; }

@media (prefers-reduced-motion: reduce) {
  [data-fx], .fx-foil-b { animation: none !important; }
  .de-art, .sd-art, .skin-frame { transition: none; }
  /* Sem a animação a "vida" cai para o `initial-value` (zero) e a carta ficaria
     congelada no ponto MAIS APAGADO do ciclo — o efeito sumiria. Aqui ela para
     num meio-termo: sem movimento, mas com o foil visível. */
  [data-fx] { --fx-life: 0.45; --fx-sweep-x: 8%; --fx-sweep-y: -6%; }
}
