Widget:C.Skins
Ir para navegação
Ir para pesquisar
<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, .95);
border-radius: 12px;
box-shadow: 0 8px 24px rgba(0, 0, 0, .30);
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(.55) saturate(.85);
transition: filter .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, .12),
0 10px 28px rgba(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(28, 28, 34, .98);
color: #eaeaea;
font-size: 13px;
line-height: 1.4;
box-shadow: 0 8px 24px rgba(0, 0, 0, .5), inset 0 0 0 1px rgba(255, 255, 255, .06);
transform: translate(-9999px, -9999px);
opacity: 0;
transition: opacity .15s ease;
text-align: center;
white-space: normal;
max-width: 280px;
min-width: 200px;
}
.skin-tooltip b {
color: #fff;
}
.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>