Mudanças entre as edições de "Widget:Character.Subskills"
Ir para navegação
Ir para pesquisar
m |
m |
||
| Linha 6: | Linha 6: | ||
const imagePreloadCache = new Map(); | const imagePreloadCache = new Map(); | ||
let subRail, subBar, spacer; | let subRail, subBar, spacer; | ||
// Cache das skills principais (capturado na carga da página) | |||
let cachedMainSkills = null; | |||
// ===== HERANÇA DE ATRIBUTOS: busca dados das skills principais ===== | // ===== HERANÇA DE ATRIBUTOS: busca dados das skills principais ===== | ||
function getMainSkillsMap() { | function getMainSkillsMap() { | ||
// Retorna cache se já foi construído | |||
if (cachedMainSkills) return cachedMainSkills; | |||
const maps = { | const maps = { | ||
byName: new Map(), | byName: new Map(), | ||
| Linha 45: | Linha 50: | ||
const data = { | const data = { | ||
name: name, // Inclui o nome para herança completa | |||
icon: iconFile, | icon: iconFile, | ||
level: icon.dataset.level || '', | level: icon.dataset.level || '', | ||
| Linha 65: | Linha 71: | ||
} | } | ||
}); | }); | ||
// Cacheia para uso futuro (importante: as skills principais não mudam) | |||
cachedMainSkills = maps; | |||
return maps; | return maps; | ||
} | } | ||
// Aplica herança: se | // Aplica herança COMPLETA: se subskill só tem refM, busca TUDO da skill principal | ||
function applyInheritance(sub, mainSkills) { | function applyInheritance(sub, mainSkills) { | ||
let name = (sub.name || sub.n || '').trim(); | |||
const refIndex = ((sub.refM || sub.m || sub.M || '') + '').trim(); | const refIndex = ((sub.refM || sub.m || sub.M || '') + '').trim(); | ||
| Linha 80: | Linha 89: | ||
main = mainSkills.byName.get(name); | main = mainSkills.byName.get(name); | ||
} | } | ||
// Se não tem main skill para herdar, retorna como está | |||
if (!main) return sub; | if (!main) return sub; | ||
// Se não tem nome mas tem refM, herda o nome da skill principal | |||
if (!name && refIndex && main.name) { | |||
name = main.name; | |||
} | |||
return { | return { | ||
...sub, | ...sub, | ||
icon: sub.icon && sub.icon !== 'Nada.png' ? sub.icon : main.icon || | name: name || main.name || sub.name, | ||
icon: (sub.icon && sub.icon !== 'Nada.png' && sub.icon !== '') ? sub.icon : (main.icon || 'Nada.png'), | |||
level: sub.level || main.level, | level: sub.level || main.level, | ||
video: sub.video || main.video, | video: sub.video || main.video, | ||
| Linha 325: | Linha 342: | ||
// Busca mapa das skills principais para herança | // Busca mapa das skills principais para herança | ||
const mainSkills = getMainSkillsMap(); | const mainSkills = getMainSkillsMap(); | ||
// Aplica herança ANTES de processar - isso resolve nome, icon, etc. | |||
subs = subs.map(sub => applyInheritance(sub, mainSkills)); | subs = subs.map(sub => applyInheritance(sub, mainSkills)); | ||
// Remove subskills que ficaram sem nome após herança (herança falhou) | |||
subs = subs.filter(s => (s.name || s.n || '').trim() !== ''); | |||
subRail.classList.add('hidden'); | subRail.classList.add('hidden'); | ||
subBar.innerHTML = ''; | subBar.innerHTML = ''; | ||
// Usa a ordem natural das subskills após herança | |||
let order = subs.map(s => s.name || s.n || ''); | let order = subs.map(s => s.name || s.n || ''); | ||
if (rawOrder.trim()) { | if (rawOrder.trim()) { | ||
| Linha 472: | Linha 495: | ||
return Promise.resolve(); | return Promise.resolve(); | ||
}; | }; | ||
// Inicialização: constrói cache das skills principais e pré-carrega imagens | |||
function init() { | |||
// Constrói cache das skills principais ANTES de qualquer interação | |||
getMainSkillsMap(); | |||
// Pré-carrega imagens das subskills | |||
api.preloadAllSubskillImages(); | |||
} | |||
if (document.readyState === 'loading') { | if (document.readyState === 'loading') { | ||
document.addEventListener('DOMContentLoaded', () => { | document.addEventListener('DOMContentLoaded', () => { | ||
setTimeout( | setTimeout(init, 100); | ||
}); | }); | ||
} else { | } else { | ||
setTimeout( | setTimeout(init, 100); | ||
} | } | ||
})(); | })(); | ||
Edição das 17h03min de 30 de novembro de 2025
<script>
(function () {
const api = (window.__subskills ||= {});
const subCache = new Map();
const imagePreloadCache = new Map();
let subRail, subBar, spacer;
// Cache das skills principais (capturado na carga da página)
let cachedMainSkills = null;
// ===== HERANÇA DE ATRIBUTOS: busca dados das skills principais =====
function getMainSkillsMap() {
// Retorna cache se já foi construído
if (cachedMainSkills) return cachedMainSkills;
const maps = {
byName: new Map(),
byIndex: new Map()
};
const icons = document.querySelectorAll('.icon-bar .skill-icon[data-nome]');
icons.forEach(icon => {
const name = (icon.dataset.nome || ).trim();
if (!name) return;
// Extrai atributos do data-atr (formato: "pve, pvp, energy, cd")
const atrRaw = icon.dataset.atr || ;
const parts = atrRaw.split(',').map(x => (x || ).trim());
const powerpve = parts[0] && parts[0] !== '-' ? parts[0] : ;
const powerpvp = parts[1] && parts[1] !== '-' ? parts[1] : ;
const energy = parts[2] && parts[2] !== '-' ? parts[2] : ;
const cooldown = parts[3] && parts[3] !== '-' ? parts[3] : ;
// Nome original do arquivo de ícone (armazenado no dataset pelo widget de skills)
let iconFile = (icon.dataset.iconFile || ).trim();
if (!iconFile) {
const imgSrc = icon.querySelector('img')?.src || ;
const iconMatch = imgSrc.match(/(?:FilePath|images)\/([^\/?]+)$/);
iconFile = iconMatch ? decodeURIComponent(iconMatch[1]) : ;
}
// Nome original do arquivo de vídeo (caso exista)
let videoFile = (icon.dataset.videoFile || ).trim();
if (!videoFile) {
const videoUrl = icon.dataset.video || ;
const videoMatch = videoUrl.match(/FilePath\/([^&?]+)/);
videoFile = videoMatch ? decodeURIComponent(videoMatch[1]) : ;
}
const index = (icon.dataset.index || ).trim();
const data = {
name: name, // Inclui o nome para herança completa
icon: iconFile,
level: icon.dataset.level || ,
video: videoFile,
powerpve: powerpve,
powerpvp: powerpvp,
cooldown: cooldown,
energy: energy
};
// Mantém descrições caso precise como fallback extra
if (icon.dataset.descPt) data.descPt = icon.dataset.descPt;
if (icon.dataset.descEn) data.descEn = icon.dataset.descEn;
if (icon.dataset.descEs) data.descEs = icon.dataset.descEs;
if (icon.dataset.descPl) data.descPl = icon.dataset.descPl;
maps.byName.set(name, data);
if (index) {
maps.byIndex.set(index, data);
}
});
// Cacheia para uso futuro (importante: as skills principais não mudam)
cachedMainSkills = maps;
return maps;
}
// Aplica herança COMPLETA: se subskill só tem refM, busca TUDO da skill principal
function applyInheritance(sub, mainSkills) {
let name = (sub.name || sub.n || ).trim();
const refIndex = ((sub.refM || sub.m || sub.M || ) + ).trim();
let main = null;
if (refIndex && mainSkills.byIndex.has(refIndex)) {
main = mainSkills.byIndex.get(refIndex);
}
if (!main && name && mainSkills.byName.has(name)) {
main = mainSkills.byName.get(name);
}
// Se não tem main skill para herdar, retorna como está
if (!main) return sub;
// Se não tem nome mas tem refM, herda o nome da skill principal
if (!name && refIndex && main.name) {
name = main.name;
}
return {
...sub,
name: name || main.name || sub.name,
icon: (sub.icon && sub.icon !== 'Nada.png' && sub.icon !== ) ? sub.icon : (main.icon || 'Nada.png'),
level: sub.level || main.level,
video: sub.video || main.video,
powerpve: sub.powerpve || main.powerpve,
powerpvp: sub.powerpvp || main.powerpvp,
cooldown: sub.cooldown || main.cooldown,
energy: sub.energy || main.energy,
descPt: sub.descPt || (sub.desc_i18n?.pt) || main.descPt,
descEn: sub.descEn || (sub.desc_i18n?.en) || main.descEn,
descEs: sub.descEs || (sub.desc_i18n?.es) || main.descEs,
descPl: sub.descPl || (sub.desc_i18n?.pl) || main.descPl
};
}
function filePathURL(fileName) {
const f = encodeURIComponent((fileName || 'Nada.png').replace(/^Arquivo:|^File:/, ));
const base = (window.mw && mw.util && typeof mw.util.wikiScript === 'function')
? mw.util.wikiScript()
: (window.mw && mw.config ? (mw.config.get('wgScript') || '/index.php') : '/index.php');
return `${base}?title=Especial:FilePath/${f}`;
}
function preloadImage(iconFile) {
const url = filePathURL(iconFile || 'Nada.png');
if (imagePreloadCache.has(url)) {
return imagePreloadCache.get(url);
}
const promise = new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(url);
img.onerror = () => resolve(url);
img.src = url;
});
imagePreloadCache.set(url, promise);
return promise;
}
function getLabels() {
const skillsRoot = document.getElementById('skills');
const i18nMap = skillsRoot ? JSON.parse(skillsRoot.dataset.i18nAttrs || '{}') : {};
const raw = (document.documentElement.lang || skillsRoot?.dataset.i18nDefault || 'pt').toLowerCase();
const lang = raw === 'pt-br' ? 'pt' : (raw.split('-')[0] || 'pt');
return i18nMap[lang] || i18nMap.pt || {
cooldown: 'Recarga',
energy_gain: 'Ganho de energia',
energy_cost: 'Custo de energia',
power: 'Poder',
power_pvp: 'Poder PvP',
level: 'Nível'
};
}
function renderSubAttrs(s, L) {
const chip = (label, val) => (val ? `
${label}${val}
` : );
const pve = (s.powerpve || ).toString().trim();
const pvp = (s.powerpvp || ).toString().trim();
const en = (s.energy || ).toString().trim();
const cd = (s.cooldown || ).toString().trim();
const rows = [
cd ? chip(L.cooldown, cd) : ,
en ? chip((en.startsWith('-') ? L.energy_cost : L.energy_gain), en.startsWith('-') ? en.replace(/^-/, ) : en.replace(/^\+?/, )) : ,
pve ? chip(L.power, pve) : ,
pvp ? chip(L.power_pvp, pvp) : ,
].filter(Boolean);
return rows.length ? `
${rows.join()}
` : ;
}
function renderFlagsRow(flags) {
const map = {
aggro: 'Enemyaggro-icon.png',
bridge: 'Bridgemaker-icon.png',
wall: 'Destroywall-icon.png',
quickcast: 'Quickcast-icon.png'
};
const arr = (flags || []).filter(Boolean);
if (!arr.length) return ;
const items = arr.map(k => `<img class="skill-flag" data-flag="${k}" alt="" src="${filePathURL(map[k])}">`).join();
return `
${items}
`;
}
function applyFlagTooltips(container) {
const skillsRoot = document.getElementById('skills');
if (!skillsRoot) return;
let pack = {};
try { pack = JSON.parse(skillsRoot.dataset.i18nFlags || '{}'); } catch (e) { }
const raw = (document.documentElement.lang || 'pt').toLowerCase();
const lang = raw === 'pt-br' ? 'pt' : (raw.split('-')[0] || 'pt');
const dict = pack[lang] || pack.pt || {};
const flags = container.querySelectorAll('.skill-flags .skill-flag[data-flag]');
const tooltip = window.__globalSkillTooltip;
if (!tooltip) return;
flags.forEach(el => {
const key = el.getAttribute('data-flag');
const tip = (dict && dict[key]) || ;
if (!tip) return;
if (el.dataset.flagTipWired) return;
el.dataset.flagTipWired = '1';
el.setAttribute('aria-label', tip);
if (el.hasAttribute('title')) el.removeAttribute('title');
el.addEventListener('mouseenter', () => {
const tipEl = document.querySelector('.skill-tooltip');
if (tipEl) tipEl.classList.add('flag-tooltip');
tooltip.show(el, tip);
});
el.addEventListener('mousemove', () => {
if (performance.now() >= tooltip.lockUntil.value) {
tooltip.measureAndPos(el);
}
});
el.addEventListener('click', () => {
tooltip.lockUntil.value = performance.now() + 240;
tooltip.measureAndPos(el);
});
el.addEventListener('mouseleave', () => {
const tipEl = document.querySelector('.skill-tooltip');
if (tipEl) tipEl.classList.remove('flag-tooltip');
tooltip.hide();
});
});
}
function ensureRail(iconsBar) {
const rail = iconsBar.closest('.top-rail');
if (!rail) return null;
if (!subRail) {
subRail = document.createElement('div');
subRail.className = 'subskills-rail collapsed hidden';
rail.appendChild(subRail);
}
if (!subBar) {
subBar = document.createElement('div');
subBar.className = 'subicon-bar';
subRail.appendChild(subBar);
}
if (!spacer) {
spacer = document.createElement('div');
spacer.className = 'subskills-spacer';
rail.parentNode.insertBefore(spacer, rail.nextSibling);
}
return rail;
}
function ensureSubVideoCached(s, parentIdx, videoBox) {
const key = `sub:${parentIdx}:${(s.name || s.n || ).trim()}`;
if (window.__subskillVideosCache && window.__subskillVideosCache.has(key)) {
const precreated = window.__subskillVideosCache.get(key);
if (!subCache.has(key)) {
subCache.set(key, precreated);
}
return key;
}
if (subCache.has(key)) return key;
if (!s.video) return key;
const v = document.createElement('video');
v.className = 'skill-video';
v.dataset.sub = '1';
v.setAttribute('controls', );
v.setAttribute('preload', 'auto');
v.setAttribute('playsinline', );
Object.assign(v.style, { display: 'none', width: '100%', height: 'auto', aspectRatio: '16/9', objectFit: 'cover' });
const src = document.createElement('source');
src.src = filePathURL(s.video);
src.type = 'video/webm';
v.appendChild(src);
videoBox.appendChild(v);
subCache.set(key, v);
v.load();
return key;
}
function showSubVideo(key, videoBox) {
videoBox.querySelectorAll('.skill-video').forEach(v => {
try { v.pause(); } catch { }
v.style.display = 'none';
});
let v = null;
if (window.__subskillVideosCache && window.__subskillVideosCache.has(key)) {
v = window.__subskillVideosCache.get(key);
}
if (!v) {
v = subCache.get(key);
}
if (!v) {
videoBox.style.display = 'none';
return;
}
videoBox.style.display = 'block';
v.style.display = 'block';
try { v.currentTime = 0; } catch { }
const suppress = document.body.dataset.suppressSkillPlay === '1';
if (!suppress) {
v.play?.().catch(() => { });
}
}
api.refreshCurrentSubSafe = function () {
const btn = document.querySelector('.subskills-rail .subicon.active');
if (!btn) return false;
const had = document.body.dataset.suppressSkillPlay;
document.body.dataset.suppressSkillPlay = '1';
try {
btn.dispatchEvent(new Event('click', { bubbles: true }));
} finally {
if (had) document.body.dataset.suppressSkillPlay = had;
else delete document.body.dataset.suppressSkillPlay;
}
return true;
};
api.renderBarFrom = function (el, { iconsBar, descBox, videoBox }) {
const rail = ensureRail(iconsBar);
if (!rail) return;
const rawSubs = el.getAttribute('data-subs') || ;
const rawOrder = el.getAttribute('data-suborder') || ;
const parentIdx = el.dataset.index || ;
if (!rawSubs.trim()) {
subRail.classList.add('collapsed');
subRail.classList.add('hidden');
subBar.innerHTML = ;
if (spacer) spacer.style.height = '0px';
return;
}
let subs;
try { subs = JSON.parse(rawSubs); } catch { subs = []; }
if (!Array.isArray(subs) || subs.length === 0) {
subRail.classList.add('collapsed');
subRail.classList.add('hidden');
subBar.innerHTML = ;
if (spacer) spacer.style.height = '0px';
return;
}
// Busca mapa das skills principais para herança
const mainSkills = getMainSkillsMap();
// Aplica herança ANTES de processar - isso resolve nome, icon, etc.
subs = subs.map(sub => applyInheritance(sub, mainSkills));
// Remove subskills que ficaram sem nome após herança (herança falhou)
subs = subs.filter(s => (s.name || s.n || ).trim() !== );
subRail.classList.add('hidden');
subBar.innerHTML = ;
// Usa a ordem natural das subskills após herança
let order = subs.map(s => s.name || s.n || );
if (rawOrder.trim()) {
try {
const preferred = JSON.parse(rawOrder);
if (Array.isArray(preferred) && preferred.length) {
const byName = new Map(subs.map(s => [(s.name || s.n || ), s]));
order = preferred.filter(n => byName.has(n));
}
} catch { }
}
order.forEach(nm => {
const s = subs.find(x => (x.name || x.n || ) === nm);
if (s) {
if (s.video) ensureSubVideoCached(s, parentIdx, videoBox);
if (s.icon) preloadImage(s.icon);
}
});
order.forEach(nm => {
const s = subs.find(x => (x.name || x.n || ) === nm);
if (!s) return;
const item = document.createElement('div');
item.className = 'subicon';
item.title = s.name || nm;
const slugify = window.__skillSlugify || ((str) => (str || ).toLowerCase().replace(/[^\w]+/g, '-').replace(/^-+|-+$/g, ));
item.dataset.slug = slugify(s.name || nm);
const img = document.createElement('img');
img.alt = ;
img.src = filePathURL(s.icon || 'Nada.png');
item.appendChild(img);
item.addEventListener('click', () => {
const L = getLabels();
const descI18n = {
pt: s.descPt || (s.desc_i18n && s.desc_i18n.pt) || ,
en: s.descEn || (s.desc_i18n && s.desc_i18n.en) || ,
es: s.descEs || (s.desc_i18n && s.desc_i18n.es) || ,
pl: s.descPl || (s.desc_i18n && s.desc_i18n.pl) ||
};
const raw = (document.documentElement.lang || 'pt').toLowerCase();
const lang = raw === 'pt-br' ? 'pt' : (raw.split('-')[0] || 'pt');
const chosen = descI18n[lang] || descI18n.pt || ;
if (descBox) {
const level = (s.level || ).toString().trim();
let flagsHTML = ;
if (Array.isArray(s.flags) && s.flags.length > 0) {
flagsHTML = renderFlagsRow(s.flags);
}
descBox.innerHTML = `
${s.name || nm}
${level ? `
${L.level} ${level}
` : }${renderSubAttrs(s, L)}
${chosen.replace(/(.*?)/g, '$1')}
`;
}
if (videoBox) {
const oldFlags = videoBox.querySelector('.skill-flags');
if (oldFlags) oldFlags.remove();
if (flagsHTML) {
videoBox.insertAdjacentHTML('beforeend', flagsHTML);
applyFlagTooltips(videoBox);
}
}
const key = `sub:${parentIdx}:${(s.name || s.n || ).trim()}`;
showSubVideo(key, videoBox);
Array.from(subBar.children).forEach(c => c.classList.remove('active'));
item.classList.add('active');
window.__lastActiveSkillIcon = item;
});
if (window.__globalSkillTooltip) {
const { show, hide, measureAndPos, lockUntil } = window.__globalSkillTooltip;
const label = item.title || ;
item.setAttribute('aria-label', label);
if (item.hasAttribute('title')) item.removeAttribute('title');
item.addEventListener('mouseenter', () => show(item, label));
item.addEventListener('mousemove', () => { if (performance.now() >= lockUntil.value) measureAndPos(item); });
item.addEventListener('click', () => { lockUntil.value = performance.now() + 240; measureAndPos(item); });
item.addEventListener('mouseleave', hide);
}
subBar.appendChild(item);
});
requestAnimationFrame(() => {
subRail.classList.remove('collapsed');
subRail.classList.remove('hidden');
const h = subRail.offsetHeight || 48;
if (spacer) spacer.style.height = h + 'px';
});
};
api.hideAll = function (videoBox) {
videoBox?.querySelectorAll('.skill-video[data-sub="1"]').forEach(v => {
try { v.pause(); } catch { }
v.style.display = 'none';
});
};
window.renderSubskillsBarFrom = function (el, ctx) { api.renderBarFrom(el, ctx); };
api.preloadAllSubskillImages = function () {
const allSkillIcons = document.querySelectorAll('.icon-bar .skill-icon[data-subs]');
const preloadPromises = [];
let totalImages = 0;
allSkillIcons.forEach(icon => {
try {
const subsRaw = icon.getAttribute('data-subs');
if (!subsRaw) return;
const subs = JSON.parse(subsRaw);
if (!Array.isArray(subs)) return;
subs.forEach(s => {
if (s && s.icon) {
preloadPromises.push(preloadImage(s.icon));
totalImages++;
}
if (s && Array.isArray(s.subs)) {
s.subs.forEach(nested => {
if (nested && nested.icon) {
preloadPromises.push(preloadImage(nested.icon));
totalImages++;
}
});
}
});
} catch (e) {
console.warn('Erro ao pré-carregar imagens de subskill:', e);
}
});
if (totalImages > 0) {
console.log(`🖼️ Pré-carregando ${totalImages} imagens de subskills...`);
return Promise.all(preloadPromises).then(() => {
console.log(`✅ ${totalImages} imagens de subskills pré-carregadas com sucesso!`);
});
}
return Promise.resolve();
};
// Inicialização: constrói cache das skills principais e pré-carrega imagens
function init() {
// Constrói cache das skills principais ANTES de qualquer interação
getMainSkillsMap();
// Pré-carrega imagens das subskills
api.preloadAllSubskillImages();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
setTimeout(init, 100);
});
} else {
setTimeout(init, 100);
}
})();
</script> <style>
.subicon-bar {
display: flex;
gap: 10px;
padding: 6px 6px;
overflow-x: auto;
/* Firefox */
scrollbar-width: thin;
scrollbar-color: #ababab transparent;
}
.subicon-bar::-webkit-scrollbar {
height: 6px;
}
.subicon-bar::-webkit-scrollbar-thumb {
background: #151515;
border-radius: 3px;
}
.subicon {
width: var(--icon-size, 42px);
height: var(--icon-size, 42px);
border-radius: var(--icon-radius, 10px);
overflow: hidden;
position: relative;
flex: 0 0 auto;
cursor: pointer;
isolation: isolate;
}
.subicon img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
border-radius: inherit;
}
.subicon::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
box-shadow: inset 0 0 0 var(--icon-ring-w, 2px) var(--icon-idle, #cfcfcf);
pointer-events: none;
z-index: 2;
transition: box-shadow .12s ease;
}
.subicon:hover::after {
box-shadow: inset 0 0 0 var(--icon-ring-w, 2px) #e6e6e6;
}
.subicon.active::after {
box-shadow: inset 0 0 0 var(--icon-ring-w, 2px) var(--icon-active, #FFD95A);
}
.subicon.active::before {
content: "";
position: absolute;
inset: -4px;
border-radius: calc(var(--icon-radius, 10px) + 4px);
pointer-events: none;
z-index: 1;
opacity: 1;
box-shadow: 0 0 12px 3px var(--icon-active-glow, rgba(255, 217, 90, .30)),
0 0 0 calc(var(--icon-ring-w, 2px) * 2) var(--icon-active-ring, rgba(255, 217, 90, .50));
}
.top-rail.skills {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
overflow: visible;
}
.top-rail.skills .icon-bar {
margin-bottom: 0;
position: relative;
z-index: 2;
}
.subskills-rail {
position: absolute;
left: 50%;
transform: translateX(-50%);
top: calc(100% - 1px);
z-index: 3;
display: inline-flex;
justify-content: center;
align-items: center;
width: auto;
max-width: 100%;
padding: 3px 5px;
background: rgba(0, 0, 0, .38);
border: 1px solid rgba(255, 255, 255, .10);
border-top: 1px solid rgba(255, 255, 255, .08);
border-radius: 0 0 10px 10px;
box-shadow: 0 3px 9px rgba(0, 0, 0, .22);
-webkit-backdrop-filter: blur(2px);
backdrop-filter: blur(2px);
overflow: hidden;
transition: opacity .14s ease, transform .14s ease;
opacity: 1;
}
.subskills-rail::before {
content: "";
position: absolute;
top: -6px;
left: 0;
right: 0;
height: 6px;
background: linear-gradient(to bottom, rgba(0, 0, 0, .20), rgba(0, 0, 0, 0));
pointer-events: none;
}
.subskills-rail.collapsed {
opacity: 0;
pointer-events: none;
transform: translate(-50%, -6px);
}
.subskills-rail.hidden {
visibility: hidden;
}
.subskills-spacer {
height: 0;
transition: height .2s ease;
}
.subskills-rail .subicon-bar {
display: inline-flex;
align-items: center;
gap: 0;
overflow-x: auto;
/* Firefox */
scrollbar-width: thin;
scrollbar-color: #ababab transparent;
}
.subskills-rail .subicon-bar::-webkit-scrollbar {
height: 6px;
}
.subskills-rail .subicon-bar::-webkit-scrollbar-thumb {
background: #151515;
border-radius: 3px;
}
.subskills-rail .subicon {
width: 42px;
height: 42px;
border-radius: 6px;
position: relative;
overflow: hidden;
flex: 0 0 auto;
cursor: pointer;
isolation: isolate;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
transform: translateZ(0);
}
.subskills-rail .subicon+.subicon {
margin-left: 4px;
}
.subskills-rail .subicon img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
border-radius: inherit;
}
.subskills-rail .subicon::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
box-shadow: inset 0 0 0 2px var(--icon-idle, #cfcfcf);
pointer-events: none;
z-index: 2;
transition: box-shadow .12s ease;
}
.subskills-rail .subicon:hover::after {
box-shadow: inset 0 0 0 2px #e6e6e6;
}
.subskills-rail .subicon.active::after {
box-shadow: inset 0 0 0 2px var(--icon-active, #FFD95A);
}
.video-container .skill-video {
width: 100%;
height: auto;
aspect-ratio: 16 / 9;
object-fit: cover;
background: #000;
border-radius: 10px;
}
@media (max-width: 900px) {
.subskills-rail {
position: static;
transform: none;
margin-top: -2px;
border-top: 0;
border-radius: 0 0 10px 10px;
}
.subskills-spacer {
height: 0 !important;
}
}
.skills-rail-wrap {
position: relative;
display: block;
width: max-content;
margin: 0 auto;
}
</style>