Mudanças entre as edições de "Widget:C.Skins"

De Wiki Gla
Ir para navegação Ir para pesquisar
(Criou página com '<!-- SKINS SYSTEM --> <script> (function initSkinsPodiumUI() { 'use strict'; const podium = document.querySelector('.skins-podium'); if (!podium ||...')
 
m
 
(11 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 1: Linha 1:
<!-- SKINS SYSTEM -->
<!-- SKINS SYSTEM - Layout Isométrico -->
<script>
<script>
    (function initSkinsPodiumUI() {
  (function initSkinsPodiumUI() {
        'use strict';
    const podium = document.querySelector(".skins-podium");
        const podium = document.querySelector('.skins-podium');
    if (!podium || podium.dataset.wired === "1") return;
        if (!podium || podium.dataset.wired === '1') return;
    podium.dataset.wired = "1";
        podium.dataset.wired = '1';


        function applyOffsetX() {
    // ---------- Função para aplicar offset_x individualmente em cada skin ----------
            const allSlots = podium.querySelectorAll('.podium-slot');
    // IMPORTANTE: Usa margin-left em vez de transform para afetar o layout do flexbox
            allSlots.forEach((slot) => {
    function applyOffsetX() {
                const offsetXAttr = slot.getAttribute('data-offset-x');
      const allSlots = podium.querySelectorAll(".podium-slot");
                if (offsetXAttr !== null && offsetXAttr !== '' && offsetXAttr !== 'undefined') {
      allSlots.forEach((slot, index) => {
                    const numOffset = parseFloat(offsetXAttr);
        // Lê o atributo data-offset-x diretamente do elemento
                    if (!isNaN(numOffset) && numOffset !== 0) {
        const offsetXAttr = slot.getAttribute("data-offset-x");
                        const currentStyle = slot.getAttribute('style') || '';
 
                        const cleanedStyle = currentStyle
        if (
                            .replace(/margin-left\s*:[^;]+;?/gi, '')
          offsetXAttr !== null &&
                            .replace(/transform\s*:[^;]+;?/gi, '')
          offsetXAttr !== "" &&
                            .trim();
          offsetXAttr !== "undefined"
                        const newMargin = `margin-left: ${numOffset}px`;
        ) {
                        if (cleanedStyle && cleanedStyle.length > 0) {
          const numOffset = parseFloat(offsetXAttr);
                            slot.setAttribute('style', cleanedStyle + (cleanedStyle.endsWith(';') ? ' ' : '; ') + newMargin + ';');
          if (!isNaN(numOffset) && numOffset !== 0) {
                        } else {
            // Usa margin-left negativo para afetar o layout do flexbox
                            slot.setAttribute('style', newMargin + ';');
            // Isso faz com que o elemento realmente se aproxime dos outros
                        }
            const currentStyle = slot.getAttribute("style") || "";
                    }
            // Remove qualquer margin-left anterior e transform (legado)
                 }
            const cleanedStyle = currentStyle
             });
              .replace(/margin-left\s*:[^;]+;?/gi, "")
              .replace(/transform\s*:[^;]+;?/gi, "")
              .trim();
            // Aplica o margin-left preservando outros estilos (como z-index)
            const newMargin = `margin-left: ${numOffset}px`;
            if (cleanedStyle && cleanedStyle.length > 0) {
              slot.setAttribute(
                "style",
                cleanedStyle +
                (cleanedStyle.endsWith(";") ? " " : "; ") +
                newMargin +
                ";"
              );
            } else {
              slot.setAttribute("style", newMargin + ";");
            }
            // Força a atualização do layout
            slot.offsetHeight;
          } else {
            // Se o offset for 0 ou inválido, remove margin-left e transform
            const currentStyle = slot.getAttribute("style") || "";
            const cleanedStyle = currentStyle
              .replace(/margin-left\s*:[^;]+;?/gi, "")
              .replace(/transform\s*:[^;]+;?/gi, "")
              .trim();
            if (cleanedStyle) {
              slot.setAttribute(
                 "style",
                cleanedStyle + (cleanedStyle.endsWith(";") ? "" : ";")
              );
            } else {
              slot.removeAttribute("style");
            }
          }
        } else {
          // Se não tem offset_x, remove margin-left e transform (preserva outros estilos)
          const currentStyle = slot.getAttribute("style") || "";
          const cleanedStyle = currentStyle
            .replace(/margin-left\s*:[^;]+;?/gi, "")
            .replace(/transform\s*:[^;]+;?/gi, "")
            .trim();
          if (cleanedStyle) {
            slot.setAttribute(
              "style",
              cleanedStyle + (cleanedStyle.endsWith(";") ? "" : ";")
            );
          } else {
            slot.removeAttribute("style");
          }
        }
      });
    }
 
    // Flag para evitar múltiplas execuções simultâneas
    let isApplying = false;
 
    function applyOffsetXOnce() {
      if (isApplying) return;
      isApplying = true;
      applyOffsetX();
      requestAnimationFrame(() => {
        isApplying = false;
      });
    }
 
    // Aplica usando requestAnimationFrame para garantir que o DOM esteja renderizado
    requestAnimationFrame(() => {
      applyOffsetXOnce();
      // Reaplica após pequenos delays para garantir
      setTimeout(applyOffsetXOnce, 50);
      setTimeout(applyOffsetXOnce, 200);
    });
 
    // Também aplica quando o DOM estiver pronto
    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", () => {
        requestAnimationFrame(applyOffsetXOnce);
      });
    }
 
    // Observa mudanças no DOM para reaplicar se necessário (apenas para novos elementos)
    if (window.MutationObserver) {
      const observer = new MutationObserver((mutations) => {
        // Só reaplica se houver mudanças relevantes
        const hasRelevantChanges = mutations.some(
          (m) =>
             m.type === "childList" ||
            (m.type === "attributes" &&
              (m.attributeName === "data-offset-x" ||
                m.attributeName === "style"))
        );
        if (hasRelevantChanges) {
          clearTimeout(observer.timeout);
          observer.timeout = setTimeout(applyOffsetXOnce, 50);
        }
      });
      observer.observe(podium, {
        childList: true,
        subtree: false, // Apenas observa filhos diretos
        attributes: true,
        attributeFilter: ["data-offset-x"],
      });
    }
 
    // ---------- Tooltip único ----------
    function ensureTip() {
      let tip = document.querySelector(".skin-tooltip");
      if (!tip) {
        tip = document.createElement("div");
        tip.className = "skin-tooltip";
        tip.setAttribute("role", "tooltip");
        tip.setAttribute("aria-hidden", "true");
        tip.style.position = "fixed";
        tip.style.transform = "translate(-9999px,-9999px)";
        tip.style.opacity = "0";
        tip.style.transition = "opacity .15s ease";
        document.body.appendChild(tip);
      }
      return tip;
    }
 
    const tip = ensureTip();
    let hoveredSlot = null;
 
    function place(card) {
      if (!card || tip.getAttribute("aria-hidden") === "true") return;
 
      // Calcula nova posição - tooltip centralizada em relação à imagem do piso
      tip.style.transform = "translate(-9999px,-9999px)";
      const tr = tip.getBoundingClientRect();
 
      // Pega a posição da imagem do tile (piso) para centralizar
      const platformImg = card.querySelector(".podium-platform-top img");
      let platformRect = card.getBoundingClientRect(); // Fallback para o card se não encontrar
      if (platformImg) {
        platformRect = platformImg.getBoundingClientRect();
      } else {
        // Se não encontrar a img, tenta o container do tile
        const platform = card.querySelector(".podium-platform");
        if (platform) {
          platformRect = platform.getBoundingClientRect();
        }
      }
 
      // Centraliza horizontalmente baseado na imagem do tile
      let leftPos = Math.round(
        platformRect.left + (platformRect.width - tr.width) / 2
      );
      leftPos = Math.max(
        8,
        Math.min(leftPos, window.innerWidth - tr.width - 8)
      );
 
      // Posiciona logo abaixo da imagem do tile, com pequeno espaçamento
      let top = Math.round(platformRect.bottom + 15);
 
      // Se não couber embaixo, coloca em cima
      if (top + tr.height > window.innerHeight - 8) {
        top = Math.round(platformRect.top - tr.height - 15);
        if (top < 8) top = 8; // Fallback se não couber em cima também
      }
 
      tip.style.transform = `translate(${leftPos}px, ${top}px)`;
    }
 
    function show(card) {
      const tooltipText = card.getAttribute("data-skin-tooltip") || "";
      tip.innerHTML = tooltipText;
      tip.setAttribute("aria-hidden", "false");
      place(card);
      tip.style.opacity = "1";
    }
 
    function hide() {
      tip.setAttribute("aria-hidden", "true");
      tip.style.opacity = "0";
      tip.style.transform = "translate(-9999px,-9999px)";
    }
 
    // Função para restaurar z-index original baseado na posição do slot
    function restoreOriginalZIndex(slot) {
      if (!slot) return;
 
      // Determina a posição do slot (1, 2, 3, 4, etc)
      const allSlots = Array.from(podium.querySelectorAll(".podium-slot"));
      const slotIndex = allSlots.indexOf(slot);
 
      // Z-index: esquerda (0) = menor, direita (último) = maior (direita passa na frente)
      const originalZIndex = slotIndex + 1;
      const originalSpriteZIndex = (slotIndex + 1) * 10;
 
      slot.style.zIndex = originalZIndex.toString();
      const spriteContainer = slot.querySelector(".podium-sprite-container");
      if (spriteContainer)
        spriteContainer.style.zIndex = originalSpriteZIndex.toString();
 
      // CRÍTICO: Garante que TODOS os tiles sempre fiquem atrás de TODAS as sprites
      // Força z-index negativo nos tiles de todos os slots
      const platform = slot.querySelector(".podium-platform");
      const platformTop = slot.querySelector(".podium-platform-top");
      const platformImg = slot.querySelector(".podium-platform-top img");
      if (platform) platform.style.zIndex = "-1";
      if (platformTop) platformTop.style.zIndex = "-2";
      if (platformImg) platformImg.style.zIndex = "-2";
    }
 
    function setHovered(card) {
      if (hoveredSlot === card) {
        // Se já está hovered, não reposiciona - mantém posição fixa
        return;
      }
 
      // Remove hover anterior e restaura z-index original
      if (hoveredSlot) {
        hoveredSlot.classList.remove("hovered");
        restoreOriginalZIndex(hoveredSlot);
        // Garante que tiles continuem atrás após restaurar z-index
        forceTilesBehind();
      }
 
      podium.classList.remove("hovering");
      podium
        .querySelectorAll(".podium-slot.dim")
        .forEach((n) => n.classList.remove("dim"));
 
      if (!card) {
        hoveredSlot = null;
        hide();
        return;
      }
 
      hoveredSlot = card;
      hoveredSlot.classList.add("hovered");
      podium.classList.add("hovering");
      podium.querySelectorAll(".podium-slot").forEach((n) => {
        if (n !== hoveredSlot) n.classList.add("dim");
      });
 
      // Qualquer skin com hover fica acima de tudo
      card.style.zIndex = "9999";
      const spriteContainer = card.querySelector(".podium-sprite-container");
      if (spriteContainer) spriteContainer.style.zIndex = "9999";
 
      // CRÍTICO: Garante que tiles continuem atrás mesmo durante hover
      forceTilesBehind();
 
      show(card);
    }
 
    // Função para verificar se o pixel na posição do mouse é transparente
    function isPixelTransparent(img, x, y) {
      if (!img.complete || img.naturalWidth === 0) return true;
 
      try {
        const canvas = document.createElement("canvas");
        canvas.width = img.naturalWidth;
        canvas.height = img.naturalHeight;
        const ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0);
 
        // Calcula a posição relativa na imagem
        const rect = img.getBoundingClientRect();
        const scaleX = img.naturalWidth / rect.width;
        const scaleY = img.naturalHeight / rect.height;
        const imgX = Math.floor((x - rect.left) * scaleX);
        const imgY = Math.floor((y - rect.top) * scaleY);
 
        // Verifica se está dentro dos limites
        if (
          imgX < 0 ||
          imgX >= img.naturalWidth ||
          imgY < 0 ||
          imgY >= img.naturalHeight
        ) {
          return true;
         }
         }


         requestAnimationFrame(() => {
         // Obtém o pixel
            applyOffsetX();
        const pixelData = ctx.getImageData(imgX, imgY, 1, 1).data;
            setTimeout(applyOffsetX, 50);
        const alpha = pixelData[3]; // Canal alpha
            setTimeout(applyOffsetX, 200);
 
        });
        return alpha < 10; // Considera transparente se alpha < 10
      } catch (e) {
        return false; // Em caso de erro, permite o hover
      }
    }


         if (document.readyState === 'loading') {
    // ---------- Clique YouTube (sem duplicar) ----------
            document.addEventListener('DOMContentLoaded', () => {
    podium.addEventListener(
                requestAnimationFrame(applyOffsetX);
      "click",
            });
      (ev) => {
        const slot = ev.target?.closest(".podium-slot[data-youtube]");
         if (!slot) return;
        const url = (slot.dataset.youtube || "").trim();
        if (!url) return;
        if (slot.dataset._opening === "1") return;
        slot.dataset._opening = "1";
        ev.preventDefault();
        ev.stopPropagation();
        ev.stopImmediatePropagation();
        try {
          window.open(url, "_blank", "noopener,noreferrer");
        } catch (e) {
          location.href = url;
         }
         }
        setTimeout(() => {
          delete slot.dataset._opening;
        }, 500);
      },
      { capture: true }
    );
    podium.addEventListener(
      "keydown",
      (ev) => {
        if (ev.key !== "Enter" && ev.key !== " ") return;
        const slot = ev.target?.closest(".podium-slot[data-youtube]");
        if (!slot) return;
        const url = (slot.dataset.youtube || "").trim();
        if (!url) return;
        if (slot.dataset._opening === "1") return;
        slot.dataset._opening = "1";
        ev.preventDefault();
        ev.stopPropagation();
        ev.stopImmediatePropagation();
        try {
          window.open(url, "_blank", "noopener,noreferrer");
        } catch (e) {
          location.href = url;
        }
        setTimeout(() => {
          delete slot.dataset._opening;
        }, 500);
      },
      { capture: true }
    );
    // ---------- Hitbox pixel-perfect por sprite ----------
    // CRÍTICO: Move tiles para fora do sprite-container para separar contexto de empilhamento
    function moveTilesOutOfSpriteContainer() {
      const allSlots = Array.from(podium.querySelectorAll(".podium-slot"));
      allSlots.forEach((slot) => {
        const spriteContainer = slot.querySelector(".podium-sprite-container");
        const platform = slot.querySelector(".podium-platform");
        // Se o tile ainda está dentro do sprite-container, move para o slot
        if (platform && spriteContainer && spriteContainer.contains(platform)) {
          // Salva os estilos inline atuais antes de mover
          const currentRight = platform.style.right || "";
          const currentBottom = platform.style.bottom || "";
          const computedRight = getComputedStyle(platform).right;
          const computedBottom = getComputedStyle(platform).bottom;


        // YouTube integration
          // Move o tile para fora do sprite-container, mas mantém dentro do slot
        podium.querySelectorAll('.podium-slot[data-youtube]').forEach(slot => {
          slot.appendChild(platform);
            if (slot.dataset.youtubeWired === '1') return;
            slot.dataset.youtubeWired = '1';
            const youtube = slot.getAttribute('data-youtube');
            if (!youtube) return;


            slot.addEventListener('click', () => {
          // Restaura a posição (os valores já estão corretos, apenas precisa manter)
                window.open(youtube, '_blank', 'noopener,noreferrer');
          platform.style.position = "absolute";
             });
          if (currentRight) {
            platform.style.right = currentRight;
          } else if (computedRight && computedRight !== "auto") {
            platform.style.right = computedRight;
          } else {
             // Usa o valor padrão do CSS
            platform.style.right = "-25px";
          }


            slot.addEventListener('keydown', (e) => {
          if (currentBottom) {
                if (e.key === 'Enter' || e.key === ' ') {
            platform.style.bottom = currentBottom;
                    e.preventDefault();
          } else if (computedBottom && computedBottom !== "auto") {
                    window.open(youtube, '_blank', 'noopener,noreferrer');
            platform.style.bottom = computedBottom;
                }
          } else {
            });
            // Usa o valor padrão do CSS
        });
            platform.style.bottom = "-15px";
          }
        }
      });
    }


        // Tooltip i18n
    // CRÍTICO: Força todos os tiles a terem z-index negativo na inicialização
        const tooltipEl = document.createElement('div');
    function forceTilesBehind() {
         tooltipEl.className = 'skin-tooltip';
      const allSlots = Array.from(podium.querySelectorAll(".podium-slot"));
         tooltipEl.style.display = 'none';
      allSlots.forEach((slot) => {
         document.body.appendChild(tooltipEl);
         const platform = slot.querySelector(".podium-platform");
         const platformTop = slot.querySelector(".podium-platform-top");
         const platformImg = slot.querySelector(".podium-platform-top img");


         function getLangKey() {
         if (platform) {
            const raw = (document.documentElement.lang || 'pt').toLowerCase();
          platform.style.zIndex = "0";
            return raw === 'pt-br' ? 'pt' : (raw.split('-')[0] || 'pt');
          platform.style.setProperty("z-index", "0", "important");
        }
        if (platformTop) {
          platformTop.style.zIndex = "0";
          platformTop.style.setProperty("z-index", "0", "important");
        }
        if (platformImg) {
          platformImg.style.zIndex = "0";
          platformImg.style.setProperty("z-index", "0", "important");
         }
         }
      });
    }
    // Move tiles para fora do sprite-container primeiro
    moveTilesOutOfSpriteContainer();
    setTimeout(moveTilesOutOfSpriteContainer, 10);
    setTimeout(moveTilesOutOfSpriteContainer, 100);
    // Depois força z-index negativo
    forceTilesBehind();
    setTimeout(forceTilesBehind, 10);
    setTimeout(forceTilesBehind, 100);
    const slots = Array.from(podium.querySelectorAll(".podium-slot"));
    slots.forEach((slot) => {
      const spriteImg = slot.querySelector(".podium-sprite img");
      // Hitbox apenas na imagem do sprite, verificando transparência
      if (spriteImg) {
        spriteImg.addEventListener(
          "pointermove",
          (ev) => {
            if (!slot.hasAttribute("data-skin-tooltip")) return;
            // Verifica se o pixel é transparente
            if (isPixelTransparent(spriteImg, ev.clientX, ev.clientY)) {
              // Se for transparente e estiver hovered, remove o hover
              if (hoveredSlot === slot) {
                setHovered(null);
              }
              return;
            }
            // Se não for transparente, ativa o hover
            if (hoveredSlot !== slot) {
              setHovered(slot);
            }
          },
          { passive: true }
        );
        spriteImg.addEventListener(
          "pointerenter",
          (ev) => {
            if (!slot.hasAttribute("data-skin-tooltip")) return;
            // Verifica transparência no enter também
            if (!isPixelTransparent(spriteImg, ev.clientX, ev.clientY)) {
              setHovered(slot);
            }
          },
          { passive: true }
        );
        spriteImg.addEventListener(
          "pointerleave",
          (ev) => {
            const toCard =
              ev.relatedTarget &&
              ev.relatedTarget.closest &&
              ev.relatedTarget.closest(".podium-slot");
            if (toCard && podium.contains(toCard)) {
              // Se está indo para outro slot, verifica transparência
              const otherImg = toCard.querySelector(".podium-sprite img");
              if (
                otherImg &&
                ev.relatedTarget &&
                !isPixelTransparent(otherImg, ev.clientX, ev.clientY)
              ) {
                return; // Não remove hover se está indo para pixel não-transparente
              }
            }
            setHovered(null);
          },
          { passive: true }
        );
      }
    });
    podium.addEventListener(
      "pointerleave",
      () => {
        setHovered(null);
      },
      { passive: true }
    );


         podium.querySelectorAll('.podium-slot').forEach(slot => {
    // Só atualiza em scroll/resize, não em mousemove
            if (slot.dataset.tooltipWired === '1') return;
    window.addEventListener(
            slot.dataset.tooltipWired = '1';
      "scroll",
      () => {
         if (hoveredSlot) place(hoveredSlot);
      },
      true
    );
    window.addEventListener("resize", () => {
      if (hoveredSlot) place(hoveredSlot);
    });


            const tooltipRaw = slot.getAttribute('data-skin-tooltip') || '';
    // Função para ajustar sombra ao tamanho exato da imagem do tile
             const tooltipI18n = slot.getAttribute('data-skin-tooltip-i18n');
    function updateShadows() {
      const platformTops = document.querySelectorAll(".podium-platform-top");
      platformTops.forEach((top, index) => {
        const img = top.querySelector("img");
        if (img) {
          const updateShadow = () => {
            // Usa naturalWidth/naturalHeight primeiro (mais rápido)
            let imgWidth = img.naturalWidth || img.offsetWidth || 0;
             let imgHeight = img.naturalHeight || img.offsetHeight || 0;


             function showTooltip(e) {
             // Se ainda não tem dimensões, tenta forçar o carregamento
                const lang = getLangKey();
            if (imgWidth === 0 || imgHeight === 0) {
                 let text = tooltipRaw;
              // Força o recálculo das dimensões
              imgWidth = img.naturalWidth || img.width || img.offsetWidth || 0;
              imgHeight =
                 img.naturalHeight || img.height || img.offsetHeight || 0;
            }


                if (tooltipI18n) {
            if (imgWidth > 0 && imgHeight > 0) {
                    try {
              top.style.setProperty("--img-width", imgWidth + "px");
                        const pack = JSON.parse(tooltipI18n);
              top.style.setProperty("--img-height", imgHeight + "px");
                        text = pack[lang] || pack.pt || pack.en || pack.es || pack.pl || tooltipRaw;
            } else {
                    } catch (e) {
              // Se ainda não tem dimensões, agenda nova tentativa
                        // fallback to raw
              // Especialmente importante para a última skin que pode carregar por último
                    }
              setTimeout(() => {
                const retryWidth =
                  img.naturalWidth || img.offsetWidth || img.width || 0;
                const retryHeight =
                  img.naturalHeight || img.offsetHeight || img.height || 0;
                if (retryWidth > 0 && retryHeight > 0) {
                  top.style.setProperty("--img-width", retryWidth + "px");
                  top.style.setProperty("--img-height", retryHeight + "px");
                 }
                 }
              }, 100 + index * 20); // Delay progressivo para cada tile
            }
          };
          // Tenta atualizar imediatamente
          updateShadow();
          // Se a imagem já carregou, atualiza novamente para garantir
          if (img.complete && img.naturalWidth > 0) {
            requestAnimationFrame(updateShadow);
          } else {
            // Usa 'load' e também verifica periodicamente
            img.addEventListener(
              "load",
              () => {
                requestAnimationFrame(updateShadow);
              },
              { once: true }
            );


                 if (!text) return;
            // Fallback: verifica após um tempo curto (com delay progressivo para última skin)
            setTimeout(() => {
              if (img.complete || img.naturalWidth > 0) {
                 requestAnimationFrame(updateShadow);
              }
            }, 50 + index * 10);


                tooltipEl.innerHTML = text;
            // Fallback adicional para garantir que a última skin seja atualizada
                 tooltipEl.style.display = 'block';
            if (index === platformTops.length - 1) {
                const rect = slot.getBoundingClientRect();
              setTimeout(() => {
                tooltipEl.style.left = rect.left + 'px';
                 updateShadow();
                 tooltipEl.style.top = (rect.top - tooltipEl.offsetHeight - 10) + 'px';
              }, 200);
              setTimeout(() => {
                 updateShadow();
              }, 500);
             }
             }
          }
        }
      });
    }


            function hideTooltip() {
    // Executa imediatamente e também após DOMContentLoaded
                tooltipEl.style.display = 'none';
    updateShadows();
            }
 
    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", updateShadows);
      window.addEventListener("load", updateShadows);
    } else {
      // Se já carregou, executa imediatamente e depois de um frame
      requestAnimationFrame(updateShadows);
    }
 
    // Garante que todas as imagens dos tiles sejam atualizadas após o carregamento completo
    window.addEventListener("load", () => {
      setTimeout(updateShadows, 100);
      setTimeout(updateShadows, 300);
      setTimeout(updateShadows, 500);
    });
 
    // Observa mudanças nas imagens
    if ("MutationObserver" in window) {
      const observer = new MutationObserver(() => {
        updateShadows();
      });
      observer.observe(podium, { childList: true, subtree: true });
    }


            slot.addEventListener('mouseenter', showTooltip);
    // Observa quando imagens dos tiles são carregadas
            slot.addEventListener('mouseleave', hideTooltip);
    const tileImages = document.querySelectorAll(".podium-platform-top img");
         });
    tileImages.forEach((img, index) => {
    })();
      if (img.complete) {
        // Se já carregou, força atualização
        setTimeout(() => updateShadows(), 50 + index * 20);
      } else {
        img.addEventListener(
          "load",
          () => {
            updateShadows();
          },
          { once: true }
         );
      }
    });
  })();
</script>
</script>
<style>
  /* Container escuro para área de skins - igual ao content-card */
  .card-skins {
    width: min(1600px, 96vw);
    max-width: 96vw;
    margin: 10px auto;
    background: rgba(28, 28, 34, 0.95);
    border-radius: 12px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
    padding: 18px;
    z-index: 2;
    box-sizing: border-box;
    overflow-x: hidden;
    overflow-y: visible;
  }
  /* Regras globais para filhos do card-skins - igual ao content-card */
  .card-skins,
  .skins-podium {
    box-sizing: border-box;
    max-width: 100%;
  }
  .card-skins * {
    max-width: 100%;
    box-sizing: border-box;
  }
  /* Exceção: imagens do tile e sprite mantêm tamanho natural (exceto no mobile) */
  .podium-platform-top img,
  .podium-sprite img {
    max-width: none;
  }
  /* Podium de skins - layout isométrico */
  .skins-podium {
    display: flex;
    align-items: flex-end;
    /* Alinha todos os slots pelo bottom */
    justify-content: center;
    gap: 30px;
    padding: 20px 0 50px 0;
    /* Padding extra na parte inferior para os tiles */
    position: relative;
    width: 100%;
    flex-wrap: wrap;
    box-sizing: border-box;
    overflow-x: hidden;
    overflow-y: visible;
  }
  .podium-slot {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    /* Alinha pelo bottom */
    cursor: pointer;
    transition: filter 0.14s ease, box-shadow 0.14s ease;
    flex-shrink: 0;
    max-width: 100%;
    box-sizing: border-box;
    overflow: visible;
    /* Permite que os tiles saiam do slot se necessário */
    /* Permite margin-left negativo para offset_x */
  }
  /* Z-index: sprites da direita passam na frente das da esquerda */
  /* Aplicado dinamicamente via JS, mas CSS base para primeiros slots */
  .podium-slot:nth-child(1) {
    z-index: 1;
    /* Esquerda: mais atrás */
  }
  .podium-slot:nth-child(2) {
    z-index: 2;
  }
  .podium-slot:nth-child(3) {
    z-index: 3;
  }
  .podium-slot:nth-child(4) {
    z-index: 4;
    /* Direita: mais na frente */
  }
  /* Z-index para sprite-containers: direita passa na frente da esquerda */
  /* IMPORTANTE: z-index alto para garantir que sprites sempre fiquem acima dos tiles (z-index negativo) */
  .podium-slot:nth-child(1) .podium-sprite-container {
    z-index: 1000 !important;
    /* Esquerda: mais atrás */
  }
  .podium-slot:nth-child(2) .podium-sprite-container {
    z-index: 2000 !important;
  }
  .podium-slot:nth-child(3) .podium-sprite-container {
    z-index: 3000 !important;
  }
  .podium-slot:nth-child(4) .podium-sprite-container {
    z-index: 4000 !important;
    /* Direita: mais na frente, acima de todos os tiles */
  }
  /* Hitbox baseada na imagem, não no container */
  .podium-slot>* {
    pointer-events: none;
  }
  /* Apenas a imagem do sprite tem hitbox - container não interfere */
  .podium-sprite img {
    pointer-events: auto;
  }
  /* Container e sprite não têm hitbox para não interferir */
  .podium-sprite-container,
  .podium-sprite {
    pointer-events: none;
  }
  /* Piso nunca tem hitbox */
  .podium-platform,
  .podium-platform-top,
  .podium-platform-top img {
    pointer-events: none !important;
  }
  /* Container do sprite - tamanho natural, não afetado pelo tile */
  .podium-sprite-container {
    position: relative;
    z-index: 10;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    /* Alinha pelo bottom (pés) - horizontalmente */
    justify-content: center;
    /* Centraliza horizontalmente */
    filter: drop-shadow(0 6px 20px rgba(0, 0, 0, 0.5));
    transform: none !important;
    flex-shrink: 0;
    max-width: 100%;
    box-sizing: border-box;
    /* REMOVIDO isolation: isolate - estava criando contexto que impedia tiles de ficarem atrás */
  }
  /* Garante que TODAS as sprites fiquem acima de TODOS os tiles */
  /* IMPORTANTE: z-index mínimo de 1 para garantir que sprites sempre fiquem acima dos tiles (z-index negativo) */
  .podium-slot .podium-sprite-container {
    position: relative;
    z-index: 1 !important;
  }
  .podium-sprite {
    display: block;
    position: relative;
    transform: none !important;
    flex-shrink: 0;
  }
  .podium-sprite img {
    width: auto;
    height: auto;
    max-width: none;
    max-height: none;
    image-rendering: pixelated;
    image-rendering: -moz-crisp-edges;
    image-rendering: -webkit-optimize-contrast;
    image-rendering: crisp-edges;
    display: block;
    position: relative;
    z-index: 10 !important;
    /* Imagem sempre acima do piso (z-index maior que tiles) */
    transform: none !important;
    will-change: auto;
    flex-shrink: 0;
  }
  /* Tile isométrico nos pés da sprite - atrás da sprite */
  /* IMPORTANTE: z-index 0 para ficar acima do background do card-skins, mas abaixo das sprites (z-index 10-40) */
  .podium-platform {
    position: absolute;
    width: auto;
    height: auto;
    bottom: -15px;
    right: -25px;
    z-index: 0 !important;
    /* z-index 0 fica acima do background do card-skins, mas abaixo das sprites */
  }
  /* Todos os pisos com z-index 0 - acima do background, mas abaixo das sprites */
  .podium-slot .podium-platform {
    z-index: 0 !important;
  }
  /* CRÍTICO: Garante que tiles fiquem acima do background do card, mas abaixo de TODAS as sprites */
  .podium-slot .podium-platform,
  .podium-slot .podium-platform-top,
  .podium-slot .podium-platform-top img {
    /* z-index 0 garante que fiquem acima do background do card-skins */
    /* mas as sprites têm z-index 10-40, então ficam na frente */
    z-index: 0 !important;
  }
  /* Tile - usando imagem no tamanho natural */
  .podium-platform-top {
    position: absolute;
    width: auto;
    height: auto;
    transform-origin: center bottom;
    transform: rotateX(15deg);
    /* Inclinação fixa em 15 graus */
    z-index: 0 !important;
    /* z-index 0 fica acima do background do card, mas abaixo das sprites */
  }
  .podium-platform-top img {
    display: block;
    width: auto;
    height: auto;
    max-width: none;
    max-height: none;
    image-rendering: pixelated;
    image-rendering: -moz-crisp-edges;
    image-rendering: -webkit-optimize-contrast;
    image-rendering: crisp-edges;
    position: relative;
    z-index: 0 !important;
    /* z-index 0 fica acima do background do card, mas abaixo das sprites (z-index 10-40) */
    border: none !important;
    outline: none;
    box-shadow: none;
    opacity: 1 !important;
    /* Garante que a imagem do tile sempre esteja visível */
  }
  /* Sombra quadrada sólida - perfeitamente alinhada com a imagem */
  .podium-platform-top::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: var(--img-width, 100%);
    height: var(--img-height, 100%);
    background: rgba(0, 0, 0, 0.5);
    z-index: -1 !important;
    /* z-index -1 para ficar atrás da imagem do tile, mas ainda acima do background do card */
    transform: translate(3px, 3px);
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.1s ease;
  }
  /* Mostra a sombra quando as dimensões estão definidas */
  .podium-platform-top[style*="--img-width"]::before {
    opacity: 1;
  }
  /* Sistema de hover - dim outras skins, destaque na hovered */
  .skins-podium.hovering .podium-slot.dim {
    filter: brightness(0.55) saturate(0.85);
    transition: filter 0.14s ease;
  }
  .skins-podium.hovering .podium-slot.hovered {
    filter: none;
  }
  /* CRÍTICO: Remove efeito de hover da imagem do piso (sem "borda fantasma") */
  .skins-podium.hovering .podium-slot.dim .podium-platform-top,
  .skins-podium.hovering .podium-slot.hovered .podium-platform-top,
  .skins-podium.hovering .podium-slot.dim .podium-platform-top img,
  .skins-podium.hovering .podium-slot.hovered .podium-platform-top img {
    filter: none !important;
    box-shadow: none !important;
  }
  /* Borda no tile quando hovered - apenas no container, não na imagem */
  .skins-podium.hovering .podium-slot.hovered .podium-platform-top {
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.12),
      0 10px 28px rgba(0, 0, 0, 0.45);
  }
  /* Remove sombra da imagem do tile no hover */
  .skins-podium.hovering .podium-slot.hovered .podium-platform-top img {
    box-shadow: none !important;
    filter: none !important;
  }
  /* Tooltip */
  .skin-tooltip {
    position: fixed;
    z-index: 9999;
    left: 0;
    top: 0;
    pointer-events: none;
    padding: 10px 12px;
    border-radius: 8px;
    background: rgba(40, 45, 60, 0.98);
    /* Azul escuro para melhor contraste */
    color: #f0f0f0;
    font-size: 13px;
    line-height: 1.4;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6),
      0 0 0 1px rgba(80, 90, 120, 0.4),
      /* Borda azulada para definição */
      inset 0 0 0 1px rgba(255, 255, 255, 0.08);
    transform: translate(-9999px, -9999px);
    opacity: 0;
    transition: opacity 0.15s ease;
    text-align: center;
    white-space: normal;
    max-width: 280px;
    min-width: 200px;
  }
  .skin-tooltip b {
    color: #ffffff;
    font-weight: 600;
  }
  .podium-slot.is-clickable {
    cursor: pointer;
  }
  .podium-slot.is-clickable:focus {
    outline: 2px solid #156bc7;
    outline-offset: 2px;
  }
  /* Responsivo */
  @media (max-width: 1100px) {
    .skins-podium {
      gap: 24px;
    }
  }
  @media (max-width: 768px) {
    .card-skins {
      padding: 14px;
    }
    .skins-podium {
      gap: 20px;
      padding: 15px 0;
    }
  }
  @media (max-width: 600px) {
    .card-skins {
      box-sizing: border-box;
      max-width: calc(100vw - env(safe-area-inset-left) - env(safe-area-inset-right) - 16px);
      width: 100%;
      margin: 10px auto;
      padding: 12px;
      border-radius: 10px;
      overflow-x: hidden;
      overflow-y: visible;
    }
    .skins-podium {
      gap: 16px;
      padding: 10px 8px 50px 8px;
      /* Padding extra na parte inferior para os tiles */
      justify-content: center;
      overflow-y: visible;
    }
    .podium-slot {
      max-width: calc(50% - 8px);
      flex: 0 0 auto;
      min-width: 0;
    }
    .podium-sprite-container {
      max-width: 100%;
      min-width: 0;
    }
    .podium-sprite img {
      max-width: 100%;
      height: auto;
    }
    .podium-platform-top img {
      max-width: 100%;
      height: auto;
    }
  }
  @media (max-width: 400px) {
    .skins-podium {
      gap: 12px;
      padding-left: 4px;
      padding-right: 4px;
    }
    .podium-slot {
      max-width: calc(50% - 6px);
    }
  }
</style>

Edição atual tal como às 14h18min de 22 de janeiro de 2026

<script>

 (function initSkinsPodiumUI() {
   const podium = document.querySelector(".skins-podium");
   if (!podium || podium.dataset.wired === "1") return;
   podium.dataset.wired = "1";
   // ---------- Função para aplicar offset_x individualmente em cada skin ----------
   // IMPORTANTE: Usa margin-left em vez de transform para afetar o layout do flexbox
   function applyOffsetX() {
     const allSlots = podium.querySelectorAll(".podium-slot");
     allSlots.forEach((slot, index) => {
       // Lê o atributo data-offset-x diretamente do elemento
       const offsetXAttr = slot.getAttribute("data-offset-x");
       if (
         offsetXAttr !== null &&
         offsetXAttr !== "" &&
         offsetXAttr !== "undefined"
       ) {
         const numOffset = parseFloat(offsetXAttr);
         if (!isNaN(numOffset) && numOffset !== 0) {
           // Usa margin-left negativo para afetar o layout do flexbox
           // Isso faz com que o elemento realmente se aproxime dos outros
           const currentStyle = slot.getAttribute("style") || "";
           // Remove qualquer margin-left anterior e transform (legado)
           const cleanedStyle = currentStyle
             .replace(/margin-left\s*:[^;]+;?/gi, "")
             .replace(/transform\s*:[^;]+;?/gi, "")
             .trim();
           // Aplica o margin-left preservando outros estilos (como z-index)
           const newMargin = `margin-left: ${numOffset}px`;
           if (cleanedStyle && cleanedStyle.length > 0) {
             slot.setAttribute(
               "style",
               cleanedStyle +
               (cleanedStyle.endsWith(";") ? " " : "; ") +
               newMargin +
               ";"
             );
           } else {
             slot.setAttribute("style", newMargin + ";");
           }
           // Força a atualização do layout
           slot.offsetHeight;
         } else {
           // Se o offset for 0 ou inválido, remove margin-left e transform
           const currentStyle = slot.getAttribute("style") || "";
           const cleanedStyle = currentStyle
             .replace(/margin-left\s*:[^;]+;?/gi, "")
             .replace(/transform\s*:[^;]+;?/gi, "")
             .trim();
           if (cleanedStyle) {
             slot.setAttribute(
               "style",
               cleanedStyle + (cleanedStyle.endsWith(";") ? "" : ";")
             );
           } else {
             slot.removeAttribute("style");
           }
         }
       } else {
         // Se não tem offset_x, remove margin-left e transform (preserva outros estilos)
         const currentStyle = slot.getAttribute("style") || "";
         const cleanedStyle = currentStyle
           .replace(/margin-left\s*:[^;]+;?/gi, "")
           .replace(/transform\s*:[^;]+;?/gi, "")
           .trim();
         if (cleanedStyle) {
           slot.setAttribute(
             "style",
             cleanedStyle + (cleanedStyle.endsWith(";") ? "" : ";")
           );
         } else {
           slot.removeAttribute("style");
         }
       }
     });
   }
   // Flag para evitar múltiplas execuções simultâneas
   let isApplying = false;
   function applyOffsetXOnce() {
     if (isApplying) return;
     isApplying = true;
     applyOffsetX();
     requestAnimationFrame(() => {
       isApplying = false;
     });
   }
   // Aplica usando requestAnimationFrame para garantir que o DOM esteja renderizado
   requestAnimationFrame(() => {
     applyOffsetXOnce();
     // Reaplica após pequenos delays para garantir
     setTimeout(applyOffsetXOnce, 50);
     setTimeout(applyOffsetXOnce, 200);
   });
   // Também aplica quando o DOM estiver pronto
   if (document.readyState === "loading") {
     document.addEventListener("DOMContentLoaded", () => {
       requestAnimationFrame(applyOffsetXOnce);
     });
   }
   // Observa mudanças no DOM para reaplicar se necessário (apenas para novos elementos)
   if (window.MutationObserver) {
     const observer = new MutationObserver((mutations) => {
       // Só reaplica se houver mudanças relevantes
       const hasRelevantChanges = mutations.some(
         (m) =>
           m.type === "childList" ||
           (m.type === "attributes" &&
             (m.attributeName === "data-offset-x" ||
               m.attributeName === "style"))
       );
       if (hasRelevantChanges) {
         clearTimeout(observer.timeout);
         observer.timeout = setTimeout(applyOffsetXOnce, 50);
       }
     });
     observer.observe(podium, {
       childList: true,
       subtree: false, // Apenas observa filhos diretos
       attributes: true,
       attributeFilter: ["data-offset-x"],
     });
   }
   // ---------- Tooltip único ----------
   function ensureTip() {
     let tip = document.querySelector(".skin-tooltip");
     if (!tip) {
       tip = document.createElement("div");
       tip.className = "skin-tooltip";
       tip.setAttribute("role", "tooltip");
       tip.setAttribute("aria-hidden", "true");
       tip.style.position = "fixed";
       tip.style.transform = "translate(-9999px,-9999px)";
       tip.style.opacity = "0";
       tip.style.transition = "opacity .15s ease";
       document.body.appendChild(tip);
     }
     return tip;
   }
   const tip = ensureTip();
   let hoveredSlot = null;
   function place(card) {
     if (!card || tip.getAttribute("aria-hidden") === "true") return;
     // Calcula nova posição - tooltip centralizada em relação à imagem do piso
     tip.style.transform = "translate(-9999px,-9999px)";
     const tr = tip.getBoundingClientRect();
     // Pega a posição da imagem do tile (piso) para centralizar
     const platformImg = card.querySelector(".podium-platform-top img");
     let platformRect = card.getBoundingClientRect(); // Fallback para o card se não encontrar
     if (platformImg) {
       platformRect = platformImg.getBoundingClientRect();
     } else {
       // Se não encontrar a img, tenta o container do tile
       const platform = card.querySelector(".podium-platform");
       if (platform) {
         platformRect = platform.getBoundingClientRect();
       }
     }
     // Centraliza horizontalmente baseado na imagem do tile
     let leftPos = Math.round(
       platformRect.left + (platformRect.width - tr.width) / 2
     );
     leftPos = Math.max(
       8,
       Math.min(leftPos, window.innerWidth - tr.width - 8)
     );
     // Posiciona logo abaixo da imagem do tile, com pequeno espaçamento
     let top = Math.round(platformRect.bottom + 15);
     // Se não couber embaixo, coloca em cima
     if (top + tr.height > window.innerHeight - 8) {
       top = Math.round(platformRect.top - tr.height - 15);
       if (top < 8) top = 8; // Fallback se não couber em cima também
     }
     tip.style.transform = `translate(${leftPos}px, ${top}px)`;
   }
   function show(card) {
     const tooltipText = card.getAttribute("data-skin-tooltip") || "";
     tip.innerHTML = tooltipText;
     tip.setAttribute("aria-hidden", "false");
     place(card);
     tip.style.opacity = "1";
   }
   function hide() {
     tip.setAttribute("aria-hidden", "true");
     tip.style.opacity = "0";
     tip.style.transform = "translate(-9999px,-9999px)";
   }
   // Função para restaurar z-index original baseado na posição do slot
   function restoreOriginalZIndex(slot) {
     if (!slot) return;
     // Determina a posição do slot (1, 2, 3, 4, etc)
     const allSlots = Array.from(podium.querySelectorAll(".podium-slot"));
     const slotIndex = allSlots.indexOf(slot);
     // Z-index: esquerda (0) = menor, direita (último) = maior (direita passa na frente)
     const originalZIndex = slotIndex + 1;
     const originalSpriteZIndex = (slotIndex + 1) * 10;
     slot.style.zIndex = originalZIndex.toString();
     const spriteContainer = slot.querySelector(".podium-sprite-container");
     if (spriteContainer)
       spriteContainer.style.zIndex = originalSpriteZIndex.toString();
     // CRÍTICO: Garante que TODOS os tiles sempre fiquem atrás de TODAS as sprites
     // Força z-index negativo nos tiles de todos os slots
     const platform = slot.querySelector(".podium-platform");
     const platformTop = slot.querySelector(".podium-platform-top");
     const platformImg = slot.querySelector(".podium-platform-top img");
     if (platform) platform.style.zIndex = "-1";
     if (platformTop) platformTop.style.zIndex = "-2";
     if (platformImg) platformImg.style.zIndex = "-2";
   }
   function setHovered(card) {
     if (hoveredSlot === card) {
       // Se já está hovered, não reposiciona - mantém posição fixa
       return;
     }
     // Remove hover anterior e restaura z-index original
     if (hoveredSlot) {
       hoveredSlot.classList.remove("hovered");
       restoreOriginalZIndex(hoveredSlot);
       // Garante que tiles continuem atrás após restaurar z-index
       forceTilesBehind();
     }
     podium.classList.remove("hovering");
     podium
       .querySelectorAll(".podium-slot.dim")
       .forEach((n) => n.classList.remove("dim"));
     if (!card) {
       hoveredSlot = null;
       hide();
       return;
     }
     hoveredSlot = card;
     hoveredSlot.classList.add("hovered");
     podium.classList.add("hovering");
     podium.querySelectorAll(".podium-slot").forEach((n) => {
       if (n !== hoveredSlot) n.classList.add("dim");
     });
     // Qualquer skin com hover fica acima de tudo
     card.style.zIndex = "9999";
     const spriteContainer = card.querySelector(".podium-sprite-container");
     if (spriteContainer) spriteContainer.style.zIndex = "9999";
     // CRÍTICO: Garante que tiles continuem atrás mesmo durante hover
     forceTilesBehind();
     show(card);
   }
   // Função para verificar se o pixel na posição do mouse é transparente
   function isPixelTransparent(img, x, y) {
     if (!img.complete || img.naturalWidth === 0) return true;
     try {
       const canvas = document.createElement("canvas");
       canvas.width = img.naturalWidth;
       canvas.height = img.naturalHeight;
       const ctx = canvas.getContext("2d");
       ctx.drawImage(img, 0, 0);
       // Calcula a posição relativa na imagem
       const rect = img.getBoundingClientRect();
       const scaleX = img.naturalWidth / rect.width;
       const scaleY = img.naturalHeight / rect.height;
       const imgX = Math.floor((x - rect.left) * scaleX);
       const imgY = Math.floor((y - rect.top) * scaleY);
       // Verifica se está dentro dos limites
       if (
         imgX < 0 ||
         imgX >= img.naturalWidth ||
         imgY < 0 ||
         imgY >= img.naturalHeight
       ) {
         return true;
       }
       // Obtém o pixel
       const pixelData = ctx.getImageData(imgX, imgY, 1, 1).data;
       const alpha = pixelData[3]; // Canal alpha
       return alpha < 10; // Considera transparente se alpha < 10
     } catch (e) {
       return false; // Em caso de erro, permite o hover
     }
   }
   // ---------- Clique YouTube (sem duplicar) ----------
   podium.addEventListener(
     "click",
     (ev) => {
       const slot = ev.target?.closest(".podium-slot[data-youtube]");
       if (!slot) return;
       const url = (slot.dataset.youtube || "").trim();
       if (!url) return;
       if (slot.dataset._opening === "1") return;
       slot.dataset._opening = "1";
       ev.preventDefault();
       ev.stopPropagation();
       ev.stopImmediatePropagation();
       try {
         window.open(url, "_blank", "noopener,noreferrer");
       } catch (e) {
         location.href = url;
       }
       setTimeout(() => {
         delete slot.dataset._opening;
       }, 500);
     },
     { capture: true }
   );
   podium.addEventListener(
     "keydown",
     (ev) => {
       if (ev.key !== "Enter" && ev.key !== " ") return;
       const slot = ev.target?.closest(".podium-slot[data-youtube]");
       if (!slot) return;
       const url = (slot.dataset.youtube || "").trim();
       if (!url) return;
       if (slot.dataset._opening === "1") return;
       slot.dataset._opening = "1";
       ev.preventDefault();
       ev.stopPropagation();
       ev.stopImmediatePropagation();
       try {
         window.open(url, "_blank", "noopener,noreferrer");
       } catch (e) {
         location.href = url;
       }
       setTimeout(() => {
         delete slot.dataset._opening;
       }, 500);
     },
     { capture: true }
   );
   // ---------- Hitbox pixel-perfect por sprite ----------
   // CRÍTICO: Move tiles para fora do sprite-container para separar contexto de empilhamento
   function moveTilesOutOfSpriteContainer() {
     const allSlots = Array.from(podium.querySelectorAll(".podium-slot"));
     allSlots.forEach((slot) => {
       const spriteContainer = slot.querySelector(".podium-sprite-container");
       const platform = slot.querySelector(".podium-platform");
       // Se o tile ainda está dentro do sprite-container, move para o slot
       if (platform && spriteContainer && spriteContainer.contains(platform)) {
         // Salva os estilos inline atuais antes de mover
         const currentRight = platform.style.right || "";
         const currentBottom = platform.style.bottom || "";
         const computedRight = getComputedStyle(platform).right;
         const computedBottom = getComputedStyle(platform).bottom;
         // Move o tile para fora do sprite-container, mas mantém dentro do slot
         slot.appendChild(platform);
         // Restaura a posição (os valores já estão corretos, apenas precisa manter)
         platform.style.position = "absolute";
         if (currentRight) {
           platform.style.right = currentRight;
         } else if (computedRight && computedRight !== "auto") {
           platform.style.right = computedRight;
         } else {
           // Usa o valor padrão do CSS
           platform.style.right = "-25px";
         }
         if (currentBottom) {
           platform.style.bottom = currentBottom;
         } else if (computedBottom && computedBottom !== "auto") {
           platform.style.bottom = computedBottom;
         } else {
           // Usa o valor padrão do CSS
           platform.style.bottom = "-15px";
         }
       }
     });
   }
   // CRÍTICO: Força todos os tiles a terem z-index negativo na inicialização
   function forceTilesBehind() {
     const allSlots = Array.from(podium.querySelectorAll(".podium-slot"));
     allSlots.forEach((slot) => {
       const platform = slot.querySelector(".podium-platform");
       const platformTop = slot.querySelector(".podium-platform-top");
       const platformImg = slot.querySelector(".podium-platform-top img");
       if (platform) {
         platform.style.zIndex = "0";
         platform.style.setProperty("z-index", "0", "important");
       }
       if (platformTop) {
         platformTop.style.zIndex = "0";
         platformTop.style.setProperty("z-index", "0", "important");
       }
       if (platformImg) {
         platformImg.style.zIndex = "0";
         platformImg.style.setProperty("z-index", "0", "important");
       }
     });
   }
   // Move tiles para fora do sprite-container primeiro
   moveTilesOutOfSpriteContainer();
   setTimeout(moveTilesOutOfSpriteContainer, 10);
   setTimeout(moveTilesOutOfSpriteContainer, 100);
   // Depois força z-index negativo
   forceTilesBehind();
   setTimeout(forceTilesBehind, 10);
   setTimeout(forceTilesBehind, 100);
   const slots = Array.from(podium.querySelectorAll(".podium-slot"));
   slots.forEach((slot) => {
     const spriteImg = slot.querySelector(".podium-sprite img");
     // Hitbox apenas na imagem do sprite, verificando transparência
     if (spriteImg) {
       spriteImg.addEventListener(
         "pointermove",
         (ev) => {
           if (!slot.hasAttribute("data-skin-tooltip")) return;
           // Verifica se o pixel é transparente
           if (isPixelTransparent(spriteImg, ev.clientX, ev.clientY)) {
             // Se for transparente e estiver hovered, remove o hover
             if (hoveredSlot === slot) {
               setHovered(null);
             }
             return;
           }
           // Se não for transparente, ativa o hover
           if (hoveredSlot !== slot) {
             setHovered(slot);
           }
         },
         { passive: true }
       );
       spriteImg.addEventListener(
         "pointerenter",
         (ev) => {
           if (!slot.hasAttribute("data-skin-tooltip")) return;
           // Verifica transparência no enter também
           if (!isPixelTransparent(spriteImg, ev.clientX, ev.clientY)) {
             setHovered(slot);
           }
         },
         { passive: true }
       );
       spriteImg.addEventListener(
         "pointerleave",
         (ev) => {
           const toCard =
             ev.relatedTarget &&
             ev.relatedTarget.closest &&
             ev.relatedTarget.closest(".podium-slot");
           if (toCard && podium.contains(toCard)) {
             // Se está indo para outro slot, verifica transparência
             const otherImg = toCard.querySelector(".podium-sprite img");
             if (
               otherImg &&
               ev.relatedTarget &&
               !isPixelTransparent(otherImg, ev.clientX, ev.clientY)
             ) {
               return; // Não remove hover se está indo para pixel não-transparente
             }
           }
           setHovered(null);
         },
         { passive: true }
       );
     }
   });
   podium.addEventListener(
     "pointerleave",
     () => {
       setHovered(null);
     },
     { passive: true }
   );
   // Só atualiza em scroll/resize, não em mousemove
   window.addEventListener(
     "scroll",
     () => {
       if (hoveredSlot) place(hoveredSlot);
     },
     true
   );
   window.addEventListener("resize", () => {
     if (hoveredSlot) place(hoveredSlot);
   });
   // Função para ajustar sombra ao tamanho exato da imagem do tile
   function updateShadows() {
     const platformTops = document.querySelectorAll(".podium-platform-top");
     platformTops.forEach((top, index) => {
       const img = top.querySelector("img");
       if (img) {
         const updateShadow = () => {
           // Usa naturalWidth/naturalHeight primeiro (mais rápido)
           let imgWidth = img.naturalWidth || img.offsetWidth || 0;
           let imgHeight = img.naturalHeight || img.offsetHeight || 0;
           // Se ainda não tem dimensões, tenta forçar o carregamento
           if (imgWidth === 0 || imgHeight === 0) {
             // Força o recálculo das dimensões
             imgWidth = img.naturalWidth || img.width || img.offsetWidth || 0;
             imgHeight =
               img.naturalHeight || img.height || img.offsetHeight || 0;
           }
           if (imgWidth > 0 && imgHeight > 0) {
             top.style.setProperty("--img-width", imgWidth + "px");
             top.style.setProperty("--img-height", imgHeight + "px");
           } else {
             // Se ainda não tem dimensões, agenda nova tentativa
             // Especialmente importante para a última skin que pode carregar por último
             setTimeout(() => {
               const retryWidth =
                 img.naturalWidth || img.offsetWidth || img.width || 0;
               const retryHeight =
                 img.naturalHeight || img.offsetHeight || img.height || 0;
               if (retryWidth > 0 && retryHeight > 0) {
                 top.style.setProperty("--img-width", retryWidth + "px");
                 top.style.setProperty("--img-height", retryHeight + "px");
               }
             }, 100 + index * 20); // Delay progressivo para cada tile
           }
         };
         // Tenta atualizar imediatamente
         updateShadow();
         // Se a imagem já carregou, atualiza novamente para garantir
         if (img.complete && img.naturalWidth > 0) {
           requestAnimationFrame(updateShadow);
         } else {
           // Usa 'load' e também verifica periodicamente
           img.addEventListener(
             "load",
             () => {
               requestAnimationFrame(updateShadow);
             },
             { once: true }
           );
           // Fallback: verifica após um tempo curto (com delay progressivo para última skin)
           setTimeout(() => {
             if (img.complete || img.naturalWidth > 0) {
               requestAnimationFrame(updateShadow);
             }
           }, 50 + index * 10);
           // Fallback adicional para garantir que a última skin seja atualizada
           if (index === platformTops.length - 1) {
             setTimeout(() => {
               updateShadow();
             }, 200);
             setTimeout(() => {
               updateShadow();
             }, 500);
           }
         }
       }
     });
   }
   // Executa imediatamente e também após DOMContentLoaded
   updateShadows();
   if (document.readyState === "loading") {
     document.addEventListener("DOMContentLoaded", updateShadows);
     window.addEventListener("load", updateShadows);
   } else {
     // Se já carregou, executa imediatamente e depois de um frame
     requestAnimationFrame(updateShadows);
   }
   // Garante que todas as imagens dos tiles sejam atualizadas após o carregamento completo
   window.addEventListener("load", () => {
     setTimeout(updateShadows, 100);
     setTimeout(updateShadows, 300);
     setTimeout(updateShadows, 500);
   });
   // Observa mudanças nas imagens
   if ("MutationObserver" in window) {
     const observer = new MutationObserver(() => {
       updateShadows();
     });
     observer.observe(podium, { childList: true, subtree: true });
   }
   // Observa quando imagens dos tiles são carregadas
   const tileImages = document.querySelectorAll(".podium-platform-top img");
   tileImages.forEach((img, index) => {
     if (img.complete) {
       // Se já carregou, força atualização
       setTimeout(() => updateShadows(), 50 + index * 20);
     } else {
       img.addEventListener(
         "load",
         () => {
           updateShadows();
         },
         { once: true }
       );
     }
   });
 })();

</script> <style>

 /* Container escuro para área de skins - igual ao content-card */
 .card-skins {
   width: min(1600px, 96vw);
   max-width: 96vw;
   margin: 10px auto;
   background: rgba(28, 28, 34, 0.95);
   border-radius: 12px;
   box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
   padding: 18px;
   z-index: 2;
   box-sizing: border-box;
   overflow-x: hidden;
   overflow-y: visible;
 }
 /* Regras globais para filhos do card-skins - igual ao content-card */
 .card-skins,
 .skins-podium {
   box-sizing: border-box;
   max-width: 100%;
 }
 .card-skins * {
   max-width: 100%;
   box-sizing: border-box;
 }
 /* Exceção: imagens do tile e sprite mantêm tamanho natural (exceto no mobile) */
 .podium-platform-top img,
 .podium-sprite img {
   max-width: none;
 }
 /* Podium de skins - layout isométrico */
 .skins-podium {
   display: flex;
   align-items: flex-end;
   /* Alinha todos os slots pelo bottom */
   justify-content: center;
   gap: 30px;
   padding: 20px 0 50px 0;
   /* Padding extra na parte inferior para os tiles */
   position: relative;
   width: 100%;
   flex-wrap: wrap;
   box-sizing: border-box;
   overflow-x: hidden;
   overflow-y: visible;
 }
 .podium-slot {
   position: relative;
   display: flex;
   flex-direction: column;
   align-items: center;
   justify-content: flex-end;
   /* Alinha pelo bottom */
   cursor: pointer;
   transition: filter 0.14s ease, box-shadow 0.14s ease;
   flex-shrink: 0;
   max-width: 100%;
   box-sizing: border-box;
   overflow: visible;
   /* Permite que os tiles saiam do slot se necessário */
   /* Permite margin-left negativo para offset_x */
 }
 /* Z-index: sprites da direita passam na frente das da esquerda */
 /* Aplicado dinamicamente via JS, mas CSS base para primeiros slots */
 .podium-slot:nth-child(1) {
   z-index: 1;
   /* Esquerda: mais atrás */
 }
 .podium-slot:nth-child(2) {
   z-index: 2;
 }
 .podium-slot:nth-child(3) {
   z-index: 3;
 }
 .podium-slot:nth-child(4) {
   z-index: 4;
   /* Direita: mais na frente */
 }
 /* Z-index para sprite-containers: direita passa na frente da esquerda */
 /* IMPORTANTE: z-index alto para garantir que sprites sempre fiquem acima dos tiles (z-index negativo) */
 .podium-slot:nth-child(1) .podium-sprite-container {
   z-index: 1000 !important;
   /* Esquerda: mais atrás */
 }
 .podium-slot:nth-child(2) .podium-sprite-container {
   z-index: 2000 !important;
 }
 .podium-slot:nth-child(3) .podium-sprite-container {
   z-index: 3000 !important;
 }
 .podium-slot:nth-child(4) .podium-sprite-container {
   z-index: 4000 !important;
   /* Direita: mais na frente, acima de todos os tiles */
 }
 /* Hitbox baseada na imagem, não no container */
 .podium-slot>* {
   pointer-events: none;
 }
 /* Apenas a imagem do sprite tem hitbox - container não interfere */
 .podium-sprite img {
   pointer-events: auto;
 }
 /* Container e sprite não têm hitbox para não interferir */
 .podium-sprite-container,
 .podium-sprite {
   pointer-events: none;
 }
 /* Piso nunca tem hitbox */
 .podium-platform,
 .podium-platform-top,
 .podium-platform-top img {
   pointer-events: none !important;
 }
 /* Container do sprite - tamanho natural, não afetado pelo tile */
 .podium-sprite-container {
   position: relative;
   z-index: 10;
   display: flex;
   flex-direction: column;
   align-items: flex-end;
   /* Alinha pelo bottom (pés) - horizontalmente */
   justify-content: center;
   /* Centraliza horizontalmente */
   filter: drop-shadow(0 6px 20px rgba(0, 0, 0, 0.5));
   transform: none !important;
   flex-shrink: 0;
   max-width: 100%;
   box-sizing: border-box;
   /* REMOVIDO isolation: isolate - estava criando contexto que impedia tiles de ficarem atrás */
 }
 /* Garante que TODAS as sprites fiquem acima de TODOS os tiles */
 /* IMPORTANTE: z-index mínimo de 1 para garantir que sprites sempre fiquem acima dos tiles (z-index negativo) */
 .podium-slot .podium-sprite-container {
   position: relative;
   z-index: 1 !important;
 }
 .podium-sprite {
   display: block;
   position: relative;
   transform: none !important;
   flex-shrink: 0;
 }
 .podium-sprite img {
   width: auto;
   height: auto;
   max-width: none;
   max-height: none;
   image-rendering: pixelated;
   image-rendering: -moz-crisp-edges;
   image-rendering: -webkit-optimize-contrast;
   image-rendering: crisp-edges;
   display: block;
   position: relative;
   z-index: 10 !important;
   /* Imagem sempre acima do piso (z-index maior que tiles) */
   transform: none !important;
   will-change: auto;
   flex-shrink: 0;
 }
 /* Tile isométrico nos pés da sprite - atrás da sprite */
 /* IMPORTANTE: z-index 0 para ficar acima do background do card-skins, mas abaixo das sprites (z-index 10-40) */
 .podium-platform {
   position: absolute;
   width: auto;
   height: auto;
   bottom: -15px;
   right: -25px;
   z-index: 0 !important;
   /* z-index 0 fica acima do background do card-skins, mas abaixo das sprites */
 }
 /* Todos os pisos com z-index 0 - acima do background, mas abaixo das sprites */
 .podium-slot .podium-platform {
   z-index: 0 !important;
 }
 /* CRÍTICO: Garante que tiles fiquem acima do background do card, mas abaixo de TODAS as sprites */
 .podium-slot .podium-platform,
 .podium-slot .podium-platform-top,
 .podium-slot .podium-platform-top img {
   /* z-index 0 garante que fiquem acima do background do card-skins */
   /* mas as sprites têm z-index 10-40, então ficam na frente */
   z-index: 0 !important;
 }
 /* Tile - usando imagem no tamanho natural */
 .podium-platform-top {
   position: absolute;
   width: auto;
   height: auto;
   transform-origin: center bottom;
   transform: rotateX(15deg);
   /* Inclinação fixa em 15 graus */
   z-index: 0 !important;
   /* z-index 0 fica acima do background do card, mas abaixo das sprites */
 }
 .podium-platform-top img {
   display: block;
   width: auto;
   height: auto;
   max-width: none;
   max-height: none;
   image-rendering: pixelated;
   image-rendering: -moz-crisp-edges;
   image-rendering: -webkit-optimize-contrast;
   image-rendering: crisp-edges;
   position: relative;
   z-index: 0 !important;
   /* z-index 0 fica acima do background do card, mas abaixo das sprites (z-index 10-40) */
   border: none !important;
   outline: none;
   box-shadow: none;
   opacity: 1 !important;
   /* Garante que a imagem do tile sempre esteja visível */
 }
 /* Sombra quadrada sólida - perfeitamente alinhada com a imagem */
 .podium-platform-top::before {
   content: "";
   position: absolute;
   top: 0;
   left: 0;
   width: var(--img-width, 100%);
   height: var(--img-height, 100%);
   background: rgba(0, 0, 0, 0.5);
   z-index: -1 !important;
   /* z-index -1 para ficar atrás da imagem do tile, mas ainda acima do background do card */
   transform: translate(3px, 3px);
   pointer-events: none;
   opacity: 0;
   transition: opacity 0.1s ease;
 }
 /* Mostra a sombra quando as dimensões estão definidas */
 .podium-platform-top[style*="--img-width"]::before {
   opacity: 1;
 }
 /* Sistema de hover - dim outras skins, destaque na hovered */
 .skins-podium.hovering .podium-slot.dim {
   filter: brightness(0.55) saturate(0.85);
   transition: filter 0.14s ease;
 }
 .skins-podium.hovering .podium-slot.hovered {
   filter: none;
 }
 /* CRÍTICO: Remove efeito de hover da imagem do piso (sem "borda fantasma") */
 .skins-podium.hovering .podium-slot.dim .podium-platform-top,
 .skins-podium.hovering .podium-slot.hovered .podium-platform-top,
 .skins-podium.hovering .podium-slot.dim .podium-platform-top img,
 .skins-podium.hovering .podium-slot.hovered .podium-platform-top img {
   filter: none !important;
   box-shadow: none !important;
 }
 /* Borda no tile quando hovered - apenas no container, não na imagem */
 .skins-podium.hovering .podium-slot.hovered .podium-platform-top {
   box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.12),
     0 10px 28px rgba(0, 0, 0, 0.45);
 }
 /* Remove sombra da imagem do tile no hover */
 .skins-podium.hovering .podium-slot.hovered .podium-platform-top img {
   box-shadow: none !important;
   filter: none !important;
 }
 /* Tooltip */
 .skin-tooltip {
   position: fixed;
   z-index: 9999;
   left: 0;
   top: 0;
   pointer-events: none;
   padding: 10px 12px;
   border-radius: 8px;
   background: rgba(40, 45, 60, 0.98);
   /* Azul escuro para melhor contraste */
   color: #f0f0f0;
   font-size: 13px;
   line-height: 1.4;
   box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6),
     0 0 0 1px rgba(80, 90, 120, 0.4),
     /* Borda azulada para definição */
     inset 0 0 0 1px rgba(255, 255, 255, 0.08);
   transform: translate(-9999px, -9999px);
   opacity: 0;
   transition: opacity 0.15s ease;
   text-align: center;
   white-space: normal;
   max-width: 280px;
   min-width: 200px;
 }
 .skin-tooltip b {
   color: #ffffff;
   font-weight: 600;
 }
 .podium-slot.is-clickable {
   cursor: pointer;
 }
 .podium-slot.is-clickable:focus {
   outline: 2px solid #156bc7;
   outline-offset: 2px;
 }
 /* Responsivo */
 @media (max-width: 1100px) {
   .skins-podium {
     gap: 24px;
   }
 }
 @media (max-width: 768px) {
   .card-skins {
     padding: 14px;
   }
   .skins-podium {
     gap: 20px;
     padding: 15px 0;
   }
 }
 @media (max-width: 600px) {
   .card-skins {
     box-sizing: border-box;
     max-width: calc(100vw - env(safe-area-inset-left) - env(safe-area-inset-right) - 16px);
     width: 100%;
     margin: 10px auto;
     padding: 12px;
     border-radius: 10px;
     overflow-x: hidden;
     overflow-y: visible;
   }
   .skins-podium {
     gap: 16px;
     padding: 10px 8px 50px 8px;
     /* Padding extra na parte inferior para os tiles */
     justify-content: center;
     overflow-y: visible;
   }
   .podium-slot {
     max-width: calc(50% - 8px);
     flex: 0 0 auto;
     min-width: 0;
   }
   .podium-sprite-container {
     max-width: 100%;
     min-width: 0;
   }
   .podium-sprite img {
     max-width: 100%;
     height: auto;
   }
   .podium-platform-top img {
     max-width: 100%;
     height: auto;
   }
 }
 @media (max-width: 400px) {
   .skins-podium {
     gap: 12px;
     padding-left: 4px;
     padding-right: 4px;
   }
   .podium-slot {
     max-width: calc(50% - 6px);
   }
 }

</style>