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

De Wiki Gla
Ir para navegação Ir para pesquisar
m
m
 
Linha 35: Linha 35:
                 "style",
                 "style",
                 cleanedStyle +
                 cleanedStyle +
                  (cleanedStyle.endsWith(";") ? " " : "; ") +
                (cleanedStyle.endsWith(";") ? " " : "; ") +
                  newMargin +
                newMargin +
                  ";"
                ";"
               );
               );
             } else {
             } else {
Linha 752: Linha 752:


   /* Hitbox baseada na imagem, não no container */
   /* Hitbox baseada na imagem, não no container */
   .podium-slot > * {
   .podium-slot>* {
     pointer-events: none;
     pointer-events: none;
   }
   }
Linha 944: Linha 944:
     padding: 10px 12px;
     padding: 10px 12px;
     border-radius: 8px;
     border-radius: 8px;
     background: rgba(40, 45, 60, 0.98); /* Azul escuro para melhor contraste */
     background: rgba(40, 45, 60, 0.98);
    /* Azul escuro para melhor contraste */
     color: #f0f0f0;
     color: #f0f0f0;
     font-size: 13px;
     font-size: 13px;
     line-height: 1.4;
     line-height: 1.4;
     box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6),
     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 */
       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);
       inset 0 0 0 1px rgba(255, 255, 255, 0.08);
     transform: translate(-9999px, -9999px);
     transform: translate(-9999px, -9999px);
Linha 995: Linha 997:
     .card-skins {
     .card-skins {
       box-sizing: border-box;
       box-sizing: border-box;
       max-width: calc(
       max-width: calc(100vw - env(safe-area-inset-left) - env(safe-area-inset-right) - 16px);
        100vw - env(safe-area-inset-left) - env(safe-area-inset-right) - 16px
      );
       width: 100%;
       width: 100%;
       margin: 10px auto;
       margin: 10px auto;

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>