/* Composição aprovada: Kalima de tempestade, moldura sóbria em preto/ouro e Kundun original. */
.world-boss-frame { background:#07090b; overflow:hidden; }
.world-boss-approved-chrome { position:absolute; z-index:8; inset:0; width:100%; height:100%; pointer-events:none; object-fit:fill; }
.world-boss-frame > *:not(.world-boss-approved-chrome) { z-index:2; }
.world-boss-stage { inset:0; background:#07090b; }
.world-boss-region { width:100%; height:100%; max-height:none; object-fit:cover; filter:none; }
.world-boss-kundun,.world-boss-kundun.is-casting { width:178px; aspect-ratio:1/1.26; transform:translate(-50%,-76%); animation:none; background:transparent!important; filter:drop-shadow(0 3px 4px rgb(0 0 0 / .42)); }
.world-boss-kundun-attack { display:none!important; }
/* O sheet do novo Kundun mantém a mesma silhueta nos oito quadros: quatro
   respirações discretas e quatro passos de conjuração, sem trocar o boss por
   outra arte durante o ataque. */
.world-boss-kundun > img:not(.world-boss-hp-frame) { display:none; }
.world-boss-kundun::before { content:""; position:absolute; z-index:1; inset:0; background:url('../assets/img/world-boss/kundun-dark-lord-sheet-v1.png') 0 0/400% 200% no-repeat; animation:worldBossKundunIdle 1.65s steps(1,end) infinite; pointer-events:none; }
.world-boss-kundun.is-attacking::before { animation:worldBossKundunCast .72s steps(1,end) both; }
.world-boss-kundun b { top:-19%; z-index:6; font:700 14px Georgia,serif; color:#efca58; text-shadow:1px 1px 2px #000,0 0 4px #4c1b0b; }
/* Um único medidor: o PNG tem apenas moldura/crânio, o HTML contém o HP vivo. */
.world-boss-kundun .world-boss-hp-frame { position:absolute; z-index:3; width:200px; height:auto; left:50%; top:-22%; transform:translateX(-50%); object-fit:initial; pointer-events:none; filter:drop-shadow(0 2px 3px #000); }
.world-boss-hp { top:-10%; z-index:5; width:144px; height:11px; border:0; outline:0; border-radius:1px; background:#070707; box-shadow:inset 0 0 3px #000; overflow:hidden; }
.world-boss-hp::before { display:none; }
.world-boss-hp i { position:absolute; z-index:1; left:1px; top:1px; bottom:1px; background:linear-gradient(#d24a36,#8c0a08)!important; box-shadow:inset 0 1px #ff9a76!important; }
.world-boss-hp-text { position:absolute; z-index:2; inset:0; display:grid; place-items:center; color:#f7dda5; font:700 7px Arial,sans-serif; font-style:normal; text-shadow:1px 1px 2px #000; white-space:nowrap; }
/* O ataque pertence somente ao sprite do corpo. Nunca tinge ou amplia a UI. */
.world-boss-kundun.is-attacking,.world-boss-kundun.is-casting { animation:none!important; filter:none!important; }
.world-boss-player { width:38px; height:50px; background-size:calc(var(--wb-cols,4) * 100%) calc(var(--wb-rows,4) * 100%); background-position:0 100%; filter:drop-shadow(0 3px 4px #000); }
.world-boss-projectile { z-index:7; width:118px; height:82px; pointer-events:none; }
.world-boss-impact { z-index:7; width:142px; height:112px; pointer-events:none; }
.world-boss-effect { background-image:none; }
.world-boss-effect.is-void-lance { background-image:url('../assets/img/world-boss/kundun-skill-void-lance-v1.png'); background-size:400% 100%; background-position:0 50%; animation:worldBossVoidLance .62s steps(1,end) both; filter:drop-shadow(0 3px 5px #000); }
.world-boss-effect.is-kalima-rift { width:145px; height:126px; background-image:url('../assets/img/world-boss/kundun-skill-kalima-rift-v1.png'); background-size:400% 100%; background-position:0 50%; animation:worldBossKalimaRift 1.15s steps(1,end) both; filter:drop-shadow(0 3px 5px #000); }
.world-boss-effect.is-dark-decree { width:154px; height:134px; background-image:url('../assets/img/world-boss/kundun-skill-dark-decree-v1.png'); background-size:400% 100%; background-position:0 50%; animation:worldBossDarkDecree 1.15s steps(1,end) both; filter:drop-shadow(0 3px 5px #000); }
.world-boss-effect.is-dark-meteor { z-index:12; width:132px; height:98px; background-image:url('../assets/img/world-boss/kundun-skill-dark-meteor-v1.png'); background-size:400% 100%; background-position:0 50%; animation:worldBossDarkMeteor 1.08s steps(1,end) both; filter:drop-shadow(0 5px 7px rgb(0 0 0 / .48)); }
.world-boss-frame.is-meteor-impact { animation:worldBossMeteorShake .52s linear both; }
.world-boss-player.is-fighting,.world-boss-player.is-attacking { animation:worldBossPlayerFight .62s steps(1,end) infinite; filter:drop-shadow(0 3px 4px #000); }
.world-boss-notice,.world-boss-status { border:1px solid #745d31; background:linear-gradient(145deg,#14120d,#06090a); box-shadow:inset 0 0 18px #000; }
.world-boss-notice { z-index:9!important; top:4.1%; left:2.4%; right:auto; width:460px; min-height:220px; box-sizing:border-box; padding:39px 30px 28px 184px; border:0; background:url('../assets/img/world-boss/world-boss-info-card-v2.png') center/100% 100% no-repeat; box-shadow:none; cursor:pointer; }
.world-boss-notice::after { display:none; }
.world-boss-notice-portrait { display:none; }
.world-boss-notice small,.world-boss-notice strong,.world-boss-notice p { position:relative; z-index:2; display:block; }
.world-boss-notice small { color:#d4ad54; letter-spacing:1.4px; font:700 10px Georgia,serif; }
.world-boss-notice strong { margin:3px 0 8px; color:#d8a8ff; font:700 18px Georgia,serif; white-space:nowrap; }
.world-boss-notice p { margin:2px 0; color:#ded5bd; font:12px/1.2 Georgia,serif; }
.world-boss-notice .world-boss-notice-rewards { max-width:300px; }
.world-boss-region-label { display:none; }
.world-boss-notice [data-world-boss-enter] { display:none; }
.world-boss-timer { color:#dbbd50!important; font:700 13px Georgia,serif!important; margin-top:9px!important; }
.world-boss-status { display:none; }
.world-boss-footer { z-index:9!important; bottom:3.5%; left:29%; right:29%; padding:0; border:0; background:transparent; box-shadow:none; pointer-events:none; }
.world-boss-footer b { color:#e8cf81; text-shadow:0 2px 4px #000,0 0 3px #5c3d0d; }
/* O botão de sair era invisível: sem borda, sem fundo e com `color:transparent`
   engolindo o ×. Ele sempre funcionou — só não dava para vê-lo, e o mapa é um
   overlay de tela cheia, então não havia outra saída. */
/* Sair de um World Boss é recuar da batalha, não fechar uma janela — um "×"
   solto no canto não dizia isso e ainda passava despercebido. */
.world-boss-close {
    z-index:30!important; top:2.4%; right:2.4%;
    width:auto!important; height:auto!important;
    display:grid!important; grid-template-columns:auto auto; align-items:center; gap:0 9px;
    padding:8px 16px 8px 13px!important;
    border:1px solid #a8823a!important; border-radius:2px;
    background:linear-gradient(#2a1a09,#0d0806)!important;
    color:#f2dc97!important;
    box-shadow:0 3px 14px #000c, inset 0 0 0 1px #00000090, inset 0 1px 0 #ffdd9422!important;
    cursor:pointer;
}
.world-boss-close i { grid-row:1/3; font-style:normal; font-size:21px; line-height:1; color:#e7bf62; text-shadow:0 0 8px #a05f1c; }
/* Espadas cruzadas (U+2694). Uma barra só: `\\2694` seria uma barra literal
   seguida do texto "2694", que era o que aparecia no botão. */
.world-boss-close i::before { content:'\2694'; }
.world-boss-close b { color:#f6e2a6; font:700 14px/1.05 Georgia,serif; letter-spacing:1.4px; text-shadow:0 1px 2px #000; }
.world-boss-close small { color:#a89572; font:11px/1.2 Georgia,serif; letter-spacing:.4px; }
.world-boss-close:hover { border-color:#f0d78d!important; background:linear-gradient(#4a3212,#180e07)!important; }
.world-boss-close:hover b { color:#fff6d2; }
.world-boss-close:hover i { color:#ffd98a; text-shadow:0 0 12px #d08b28; }
.world-boss-close:active { transform:translateY(1px); }
@keyframes worldBossPlayerFight { 0%,100% { transform:translate(-50%,-50%) scale(1); background-position:0 100%; } 25% { transform:translate(-50%,-53%) scale(1.03); background-position:33.333% 100%; } 55% { transform:translate(-50%,-50%) scale(1.05); background-position:66.667% 100%; } 75% { transform:translate(-50%,-52%) scale(1.02); background-position:100% 100%; } }
@keyframes worldBossKundunAttack { 0%,100% { transform:translate(-50%,-76%); } }
@keyframes worldBossKundunSheet { 0%,24% { background-position:0 50%; } 25%,49% { background-position:33.333% 50%; } 50%,74% { background-position:66.666% 50%; } 75%,100% { background-position:100% 50%; } }
@keyframes worldBossKundunLunge { 0%,100% { transform:translateY(0); } 35% { transform:translate(2px,-3px) rotate(.5deg); } 65% { transform:translate(-1px,1px) rotate(-.25deg); } }
@keyframes worldBossKundunIdle { 0%,24% { background-position:0 0; } 25%,49% { background-position:33.333% 0; } 50%,74% { background-position:66.667% 0; } 75%,100% { background-position:100% 0; } }
@keyframes worldBossKundunCast { 0%,20% { background-position:0 100%; } 21%,47% { background-position:33.333% 100%; } 48%,74% { background-position:66.667% 100%; } 75%,100% { background-position:100% 100%; } }
@keyframes worldBossVoidLance { 0%,24% { background-position:0 50%; } 25%,49% { background-position:33.333% 50%; } 50%,74% { background-position:66.667% 50%; } 75%,100% { background-position:100% 50%; } }
@keyframes worldBossKalimaRift { 0%,24% { opacity:0; background-position:0 50%; transform:translate(-50%,-50%) scale(.58); } 25%,49% { opacity:1; background-position:33.333% 50%; } 50%,74% { background-position:66.667% 50%; } 75%,100% { opacity:0; background-position:100% 50%; transform:translate(-50%,-50%) scale(1.06); } }
@keyframes worldBossDarkDecree { 0%,24% { opacity:0; background-position:0 50%; transform:translate(-50%,-50%) scale(.52); } 25%,49% { opacity:1; background-position:33.333% 50%; } 50%,74% { background-position:66.667% 50%; } 75%,100% { opacity:0; background-position:100% 50%; transform:translate(-50%,-50%) scale(1.04); } }
@keyframes worldBossDarkMeteor { 0%,21% { background-position:0 50%; } 22%,42% { background-position:33.333% 50%; } 43%,69% { background-position:66.667% 50%; } 70%,100% { background-position:100% 50%; } }
@keyframes worldBossMeteorShake { 0%,100% { transform:translate(0,0); } 10% { transform:translate(-9px,5px); } 25% { transform:translate(10px,-6px); } 40% { transform:translate(-8px,4px); } 60% { transform:translate(6px,-3px); } 80% { transform:translate(-3px,2px); } }
@media(max-width:800px){.world-boss-stage{inset:14% 3% 16%}.world-boss-kundun{width:122px}.world-boss-player{width:26px;height:35px}}

/* ===== Correções de layout e combate ===================================== */

/* Nome do mapa dentro da placa inferior.
   O 9,8% foi CALIBRADO NA TELA, não calculado. Tentei localizar o recesso da
   placa por análise do PNG de três formas — área opaca, cor escura e bordas
   douradas — e nenhuma converge: a moldura se confunde com o losango do topo
   e com as asas das gárgulas, e cada coluna amostrada devolve um valor
   diferente (9,9% a 12,2%). Não vale reabrir essa conta: se a arte da placa
   mudar, é mais rápido recalibrar movendo este número do que medir de novo.

   Prender o CENTRO do bloco (e não a base) é o que mantém o alinhamento em
   qualquer resolução: a fonte usa clamp(...,3vw,...), então o bloco muda de
   altura conforme a largura da janela, e ancorar pela base o empurrava para
   fora da placa em telas largas. */
.world-boss-footer {
    bottom: 9.8%;
    transform: translateY(50%);
    align-content: center;
}

/* Barra de vida: um fundo só.
   A moldura (kundun-hp-frame-v7.png) já desenha o encaixe escuro da barra —
   medido no PNG: 2,7%..98,5% na horizontal e 37,6%..61,9% na vertical. A barra
   pintava um retângulo preto MAIS ESTREITO por cima desse encaixe, e era daí
   que vinha o efeito de "dois fundos". Agora ela é transparente e ocupa
   exatamente o vão da moldura. */
.world-boss-hp {
    top: -11%;
    width: 191px;
    height: 16px;
    background: transparent;
    box-shadow: none;
}
.world-boss-hp i { left: 2px; top: 2px; bottom: 2px; border-radius: 1px; }
.world-boss-hp-text { font-size: 8px; }

/* Aventureiros encaram o Kundun.
   `--wb-face` vale -1 para quem está à direita dele. O nome recebe o mesmo
   scaleX de novo para não sair espelhado junto com o sprite. */
.world-boss-player {
    transform: translate(-50%, -50%) scaleX(var(--wb-face, 1));
    animation: worldBossPlayerFacing 2.2s ease-in-out var(--delay, 0s) infinite;
}
@keyframes worldBossPlayerFacing {
    50% {
        transform: translate(calc(-50% + 5px), calc(-50% - 3px)) scaleX(var(--wb-face, 1));
        background-position: 66.6% 50%;
    }
}

/* Nick acima da cabeça, como no jogo. Antes ficava em top:94%, ou seja,
   embaixo dos pés. */
.world-boss-player b {
    top: auto;
    bottom: 104%;
    transform: translateX(-50%) scaleX(var(--wb-face, 1));
    padding: 0 2px;
    color: #f6e7bb;
    font: 700 9px Arial, sans-serif;
    text-shadow: 1px 1px 2px #000, 0 0 3px #000;
}
.world-boss-player.is-self b { color: #8ce4a0; }

/* A animação de luta é a worldBossPlayerFight (mais abaixo): ela cicla os
   quadros do sprite. Uma animação minha de ataque por cima congelava esse
   ciclo, então o golpe é sinalizado só por brilho — sem trocar a animação. */
.world-boss-player.is-attacking { filter:drop-shadow(0 3px 4px #000); }

/* ===== Barra de vida: encaixe medido na própria arte ====================== */
/*
   O PNG da moldura NÃO tem um encaixe escuro — o miolo dele é transparente.
   São só a caveira à esquerda, uma ponteira à direita e os trilhos de cima e
   de baixo. Medindo o vão livre na imagem (2172x724) e convertendo para os
   200x67 em que ela é renderizada:

       esquerda 30,0px   largura 157,7px   topo 27,3px   altura 11,4px

   A barra usa o MESMO ancoramento vertical da moldura (top:-22%), então as
   duas sobem e descem juntas; os deslocamentos em px são fixos porque a
   moldura também tem largura fixa.

   Como o vão é vazio na arte, a barra precisa do próprio fundo — sem ele,
   sobrava só o preenchimento vermelho flutuando. */
.world-boss-hp {
    left: 50%;
    top: -22%;
    width: 158px;
    height: 11px;
    transform: translate(calc(-50% + 9px), 27px);
    background: linear-gradient(#100405, #2a0a08);
    box-shadow: inset 0 0 3px #000;
    border: 0;
    overflow: hidden;
}
.world-boss-hp i { left: 0; top: 0; bottom: 0; border-radius: 0; }
.world-boss-hp-text { font: 700 8px Arial, sans-serif; }

/* O nome do aventureiro estava saindo espelhado junto com o sprite: a regra
   anterior não vencia o `transform` declarado na folha base. */
.world-boss-player > b {
    transform: translateX(-50%) scaleX(var(--wb-face, 1)) !important;
}

/* worldBossPlayerFight redefinida com o espelhamento.
   Ela é a animação que vale para quem está lutando e vencia a minha, mas não
   carregava scaleX — o resultado era o sprite virado e o nome espelhado por
   cima dele. Os quadros e o balanço são exatamente os originais; a única
   diferença é o scaleX(var(--wb-face)) em cada passo. */
@keyframes worldBossPlayerFight {
    0%, 100% { transform: translate(-50%, -50%) scaleX(var(--wb-face, 1)) scale(1); background-position: 0 100%; }
    25% { transform: translate(-50%, -53%) scaleX(var(--wb-face, 1)) scale(1.03); background-position: 33.333% 100%; }
    55% { transform: translate(-50%, -50%) scaleX(var(--wb-face, 1)) scale(1.05); background-position: 66.667% 100%; }
    75% { transform: translate(-50%, -52%) scaleX(var(--wb-face, 1)) scale(1.02); background-position: 100% 100%; }
}

/* Tamanho do aventureiro conforme a lotação. Dentro do limite de raio pedido,
   trinta sprites em tamanho cheio não cabem sem empilhar — encolher a multidão
   é o que a própria arte de referência faz. */
.world-boss-player {
    width: calc(27px * var(--wb-escala, 1));
    height: calc(35px * var(--wb-escala, 1));
}
.world-boss-player > b { font-size: calc(9px * max(0.8, var(--wb-escala, 1))); }

/* ===== A moldura retangular do sheet do Kundun ============================= */
/*
   O PNG do boss NÃO tem fundo transparente: cada quadro traz um retângulo de
   névoa escura, e os quadros de conjuração (linha de baixo) trazem também um
   clarão roxo que vai até a borda da célula. Desenhado sobre o mapa, esse
   retângulo aparecia como uma caixa preta em volta dele — e, como a barra de
   vida fica logo acima, a borda superior da caixa passava rente a ela.

   A máscara dissolve só a faixa das bordas: o miolo (onde estão o corpo, as
   asas e os chifres) fica intacto, e a névoa que sobra nos cantos se apaga
   antes de chegar à aresta — vira aura em vez de moldura. A faixa é estreita
   (9% nos lados, 6% em cima e embaixo) porque a arte preenche quase toda a
   célula: uma máscara elíptica, mais bonita no papel, comia os chifres. */
.world-boss-kundun::before {
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 9%, #000 91%, transparent 100%), linear-gradient(to bottom, transparent 0, #000 6%, #000 94%, transparent 100%);
    mask-image: linear-gradient(to right, transparent 0, #000 9%, #000 91%, transparent 100%), linear-gradient(to bottom, transparent 0, #000 6%, #000 94%, transparent 100%);
    -webkit-mask-composite: source-in;
    mask-composite: intersect;
}
/* A barra e a moldura de vida ficam FORA do desenho do boss: nem o clarão da
   conjuração nem a máscara podem alcançá-las. */
.world-boss-kundun .world-boss-hp-frame,
.world-boss-kundun .world-boss-hp { -webkit-mask-image: none; mask-image: none; }

/* Alvo da vez. Kundun agora reveza os alvos, então o golpe precisa dizer em
   quem caiu — sem isso a troca some no meio dos efeitos. O sinal é um anel no
   chão, e não um filtro no sprite: mexer no `filter` ou no `animation` do
   aventureiro congelaria o ciclo de quadros dele durante o golpe. */
.world-boss-player.is-targeted::after {
    content: "";
    position: absolute;
    left: 50%; top: 100%;
    width: 165%; aspect-ratio: 2 / 1;
    transform: translate(-50%, -50%);
    border: 1px solid #ff9a63;
    border-radius: 50%;
    box-shadow: 0 0 9px #ff5a2a, inset 0 0 7px #ff5a2a55;
    animation: worldBossAlvo .9s ease-out both;
    pointer-events: none;
}
@keyframes worldBossAlvo {
    0%   { opacity: 0; transform: translate(-50%, -50%) scale(.45); }
    22%  { opacity: 1; }
    100% { opacity: 0; transform: translate(-50%, -50%) scale(1.18); }
}

/* ===== Card do World Boss: encostado no canto e ajustado à placa ==========
   A arte (world-boss-info-card-v2.png, 1793x877) é esticada em 100% 100%, então
   o texto só cai dentro da placa preta se o card mantiver a proporção do PNG e
   se o padding for a medida da placa NA ARTE. Amostrando a imagem, o vão útil
   é x de 42% a 93% e y de 19% a 80,5% — daí os quatro valores abaixo, em px
   sobre a largura/altura escolhidas (520 x 254).

   Antes o card tinha altura livre (min-height:220px) e padding chutado: o texto
   nascia colado no topo da placa, transbordava por baixo e a arte esticava
   junto quando a frase crescia. */
.world-boss-notice {
    top: 1.3%;
    left: 0.7%;
    /* Um único número manda no card. O padding sai dele por calc(), e não em
       %, porque padding percentual no CSS resolve contra a LARGURA DO PAI —
       aqui o pai é a tela inteira, o que estourava o card. */
    --wb-card: 520px;
    width: var(--wb-card);
    min-height: 0;
    aspect-ratio: 1793 / 877;
    padding: calc(var(--wb-card) * .0923) calc(var(--wb-card) * .0885) calc(var(--wb-card) * .0962) calc(var(--wb-card) * .4385);
    display: grid;
    align-content: center;
    gap: 3px;
    overflow: hidden;
}
.world-boss-notice small { font: 700 10px/1 Georgia, serif; letter-spacing: 1.6px; }
.world-boss-notice strong { margin: 0; font-size: 17px; }
.world-boss-notice p { margin: 0; font: 12px/1.32 Georgia, serif; }
/* O limite de 300px vinha de quando o padding não delimitava a coluna; hoje
   ele só criava uma segunda margem, mais estreita que a placa. */
.world-boss-notice .world-boss-notice-rewards { max-width: none; }
.world-boss-timer { margin-top: 6px !important; font: 700 12.5px/1 Georgia, serif !important; }
@media (max-width: 1100px) { .world-boss-notice { --wb-card: 400px; } .world-boss-notice strong { font-size: 14px; } .world-boss-notice p { font-size: 10.5px; } .world-boss-timer { font-size: 11px !important; } }

/* ===== Quadros do aventureiro e ritmo das animações ======================
   O sheet de toda classe é 4x4 (data.js): linha 2 = espera, linha 3 = ataque.
   Em background-size 400% 400%, a linha 3 fica em 100% e a 2 em 66,667%.

   worldBossPlayerFacing pedia `background-position: 66.6% 50%` — 50% na
   vertical não é linha nenhuma, é o vão ENTRE a 1 e a 2. O navegador mostrava
   metade de um quadro e metade do outro, e o personagem parecia sumir no meio
   do golpe. Só acontecia com os OUTROS jogadores porque o local era o único a
   receber `is-fighting`, que usa a animação certa. */
@keyframes worldBossPlayerFacing {
    0%, 100% { transform: translate(-50%, -50%) scaleX(var(--wb-face, 1)); background-position: 0 66.667%; }
    50% { transform: translate(calc(-50% + 4px), calc(-50% - 3px)) scaleX(var(--wb-face, 1)); background-position: 66.667% 66.667%; }
}

/* Ritmo do AVENTUREIRO. Quatro quadros em 0,62s davam ~6,5 trocas por segundo —
   rápido demais para ler o golpe. 1,05s deixa a investida na mesma ordem de
   grandeza da cadência de ataque (900ms), e a defasagem por jogador evita a
   tropa inteira piscando em uníssono. */
.world-boss-player.is-fighting,
.world-boss-player.is-attacking { animation: worldBossPlayerFight 1.05s steps(1, end) var(--delay, 0s) infinite; }
/* O Kundun ficou com a velocidade original de propósito: o pedido de animação
   mais lenta era só para o aventureiro. */

/* ===== A queda do Kundun sacode Kalima ===================================
   O tremor do meteoro (worldBossMeteorShake) é curto e sempre igual — serve
   para um impacto, não para o fim da batalha. Este aqui começa forte e vai
   perdendo força ao longo dos 2,6s, enquanto a arena escurece: é o mapa se
   fechando antes de devolver o jogador à cidade. */
.world-boss-frame.is-boss-death { animation: worldBossQuedaDoKundun 2.6s linear both; }
@keyframes worldBossQuedaDoKundun {
    0%   { transform: translate(0, 0); filter: none; }
    3%   { transform: translate(-16px, 9px) rotate(-.5deg); filter: brightness(1.5) saturate(.6); }
    7%   { transform: translate(15px, -11px) rotate(.45deg); filter: brightness(1.15); }
    12%  { transform: translate(-13px, 8px) rotate(-.35deg); }
    18%  { transform: translate(12px, -7px) rotate(.3deg); }
    25%  { transform: translate(-10px, 6px); }
    33%  { transform: translate(8px, -5px); }
    42%  { transform: translate(-7px, 4px); filter: brightness(.9); }
    52%  { transform: translate(5px, -3px); }
    63%  { transform: translate(-4px, 3px); }
    74%  { transform: translate(3px, -2px); filter: brightness(.7); }
    85%  { transform: translate(-2px, 1px); }
    93%  { transform: translate(1px, -1px); }
    100% { transform: translate(0, 0); filter: brightness(.35); }
}

/* ===== Asa e skin de set em Kalima ========================================
   Os quadros deixaram de ser números fixos de uma grade 4x4: o JS calcula a
   posição de cada um a partir da grade REAL do sheet e manda em variáveis. A
   folha de voo continua 4x4, mas a de set é 12x4 — com as posições cravadas no
   CSS, ela mostrava metade de um quadro e metade do outro.

   `--wb-larg`/`--wb-alt` compensam a célula maior da folha de voo: a asa ocupa
   espaço nela, e sem a compensação o aventureiro encolhia ~20% ao equipar asa.
   A proporção é a mesma já calibrada para a caçada (86x111 a pé, 160x160
   voando), então o corpo fica exatamente do tamanho de antes.

   `--wb-balanco` vale 0 para quem está voando: medindo a folha de voo da Elf
   (célula de 320px), o quadro 0 da linha de golpe nasce 18px mais alto que os
   outros três, que variam só 2px entre si. Ciclar os quatro fazia o corpo
   pular a cada volta. Voando, o ciclo usa os quadros estáveis e o balanço
   extra (o pulinho e o zoom) é desligado: sobra só a batida da asa. */
.world-boss-player {
    width: calc(27px * var(--wb-escala, 1) * var(--wb-larg, 1));
    height: calc(35px * var(--wb-escala, 1) * var(--wb-alt, 1));
    background-position: var(--wb-golpe-0, 0%) var(--wb-golpe-y, 100%);
}
@keyframes worldBossPlayerFacing {
    0%, 100% {
        transform: translate(-50%, -50%) scaleX(var(--wb-face, 1));
        background-position: var(--wb-espera-a, 0%) var(--wb-espera-y, 66.667%);
    }
    50% {
        transform: translate(calc(-50% + 5px * var(--wb-balanco, 1)), calc(-50% - 3px * var(--wb-balanco, 1))) scaleX(var(--wb-face, 1));
        background-position: var(--wb-espera-b, 66.667%) var(--wb-espera-y, 66.667%);
    }
}
@keyframes worldBossPlayerFight {
    0%, 100% { transform: translate(-50%, -50%) scaleX(var(--wb-face, 1)) scale(1); background-position: var(--wb-golpe-0, 0%) var(--wb-golpe-y, 100%); }
    25% { transform: translate(-50%, calc(-50% - 3% * var(--wb-balanco, 1))) scaleX(var(--wb-face, 1)) scale(calc(1 + .03 * var(--wb-balanco, 1))); background-position: var(--wb-golpe-1, 33.333%) var(--wb-golpe-y, 100%); }
    55% { transform: translate(-50%, -50%) scaleX(var(--wb-face, 1)) scale(calc(1 + .05 * var(--wb-balanco, 1))); background-position: var(--wb-golpe-2, 66.667%) var(--wb-golpe-y, 100%); }
    75% { transform: translate(-50%, calc(-50% - 2% * var(--wb-balanco, 1))) scaleX(var(--wb-face, 1)) scale(calc(1 + .02 * var(--wb-balanco, 1))); background-position: var(--wb-golpe-3, 100%) var(--wb-golpe-y, 100%); }
}

/* ---- Chat por cima do mapa do World Boss ----
   O mapa é um overlay fixo de tela cheia em z-index 20020, e o chat vive
   dentro de #view-city num z-index bem menor: dava para ver a luta, mas não
   para falar com ninguém enquanto ela durava. Aqui ele sobe junto e vira
   fixo, senão continuaria preso ao empilhamento da tela da cidade. */
body:has(#world-boss-map:not([hidden])) .city-chat {
    position: fixed !important;
    z-index: 20030 !important;
    left: 10px !important;
    bottom: 10px !important;
}
