(function (){
'use strict';
var C=window.VBUS;
if(!C||!C.api||window.__vbus) return;
window.__vbus=true;
var RM=window.matchMedia&&window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var EASE='cubic-bezier(.22,.8,.24,1)';
var PAGE=24;
var IDLE=4;
function norm(s){
return String(s||'').toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g, '').replace(/[^a-z0-9]+/g, ' ').trim();
}
function esc(s){
return String(s).replace(/[&<>"']/g, function (c){
return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
});
}
var STOP=new Set('de del la las el los con y en para un una unos unas the of with and a piedra piedras joya joyas'.split(' '));
var SYN={
collar: ['necklace'], collares: ['necklace'], cadena: ['necklace', 'chain'], gargantilla: ['necklace', 'choker'], dije: ['charm', 'pendant'],
arete: ['earing', 'earring'], aretes: ['earing', 'earring'], pendiente: ['earing'], pendientes: ['earing'], zarcillo: ['earing'], zarcillos: ['earing'], earring: ['earing'], earrings: ['earing'], topos: ['earing', 'stud'],
anillo: ['ring'], anillos: ['ring'], sortija: ['ring'],
pulsera: ['bracelet'], pulseras: ['bracelet'], manilla: ['bracelet'], manillas: ['bracelet'],
brazalete: ['bangle'], brazaletes: ['bangle'], esclava: ['bangle'], esclavas: ['bangle'],
perfume: ['nnt', 'perfume'], perfumes: ['nnt', 'perfume'], fragancia: ['nnt', 'perfume'], verano: ['summer'],
agate: ['agata'], amethyst: ['amatista'], amazonite: ['amazonita'], amber: ['ambar'], aguamarina: ['aquamarine'], kyanite: ['cianita'],
citrine: ['citrino'], quartz: ['cuarzo'], smoky: ['cuarzo ahumado'], emerald: ['esmeralda'], fluorite: ['fluorita'], granate: ['garnet'],
hematita: ['hematite'], labradorite: ['labradorita'], lapis: ['lapiz'], malachite: ['malaquita'], luna: ['moonstone', 'moon'],
tiger: ['ojo de tigre', 'tiger'], tigre: ['ojo de tigre', 'tiger'], onix: ['onyx'], opal: ['opalo', 'opal'], peridoto: ['peridot'], olivino: ['peridot'],
pearl: ['perla', 'pearl'], pearls: ['perla', 'pearl'], perlas: ['perla', 'pearl'], perla: ['perla', 'pearl'], prehnite: ['prehnita'], ruby: ['rubi', 'ruby'],
sodalite: ['sodalita'], sol: ['sunstone', 'sun'], topaz: ['topacio'], tourmaline: ['turmalina'], turquoise: ['turquesa'], sapphire: ['zafiro'],
rosa: ['rose', 'pink'], dorado: ['gold'], dorada: ['gold'], oro: ['gold'], plata: ['silver'], negro: ['black', 'onyx'], negra: ['black', 'onyx'],
blanco: ['white'], blanca: ['white'], azul: ['blue'], verde: ['green'], rojo: ['red'], serpiente: ['serpent', 'snake'], corazon: ['heart'],
estrella: ['star'], flor: ['flower', 'flor'], flores: ['flower', 'flor'], mariposa: ['butterfly'], ojo: ['eye', 'ojo']
};
function tokens(q){
return norm(q).split(' ').filter(function (t){ return t&&!STOP.has(t); });
}
function alts(t){
var a=[t];
if(SYN[t]) a=a.concat(SYN[t]);
if(t.length > 4&&/es$/.test(t)) a.push(t.slice(0, -2));
if(t.length > 3&&/s$/.test(t)) a.push(t.slice(0, -1));
return a;
}
function has(h, list){
for (var i=0; i < list.length; i++) if(h.indexOf(' ' + list[i]) >=0) return true;
return false;
}
function lev(a, b, max){
if(Math.abs(a.length - b.length) > max) return max + 1;
var prev=[], cur, i, j;
for (j=0; j <=b.length; j++) prev[j]=j;
for (i=1; i <=a.length; i++){
cur=[i];
var low=i;
for (j=1; j <=b.length; j++){
cur[j]=Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (a[i - 1]===b[j - 1] ? 0:1));
if(cur[j] < low) low=cur[j];
}
if(low > max) return max + 1;
prev=cur;
}
return prev[b.length];
}
var GEMS={
'agata': ['#dca678', '#7a3f22'], 'amatista': ['#c9a3e6', '#55277f'], 'amazonita': ['#a4e3d2', '#2c8574'], 'ambar': ['#ffc85c', '#a84f0c'],
'aquamarine': ['#d2f3f9', '#5aaecb'], 'blue opal': ['#c4e6f8', '#4a86c2', 'iri'], 'cianita': ['#8cabea', '#233f7e'], 'citrino': ['#ffe27d', '#d4850f'],
'cuarzo': ['#ffffff', '#c3beb5'], 'cuarzo ahumado': ['#baa18c', '#44342a'], 'cuarzo blanco': ['#ffffff', '#d5d0c7'], 'cuarzo rosa': ['#fdd8dd', '#d78a9a'],
'esmeralda': ['#66e3a6', '#0a6a41'], 'fluorita': ['#bda2e8', '#39a891', 'iri'], 'garnet': ['#d23a52', '#470612'], 'gold sandstone': ['#d89b5c', '#4a210e', 'spark'],
'hematite': ['#a4a8ae', '#232529'], 'jade': ['#a3dfb0', '#2a7346'], 'labradorita': ['#86bccf', '#252e3a', 'iri'], 'lapiz lazuli': ['#5277e0', '#141f68', 'spark'],
'malaquita': ['#4bc98c', '#094832'], 'moonstone': ['#f5f8fc', '#a8b7d3', 'iri'], 'ojo de tigre': ['#e6aa48', '#512d06'], 'onyx': ['#55555a', '#09090a'],
'onyx verde': ['#93cda2', '#2a5839'], 'opalo': ['#faf5ef', '#c5d6f2', 'iri'], 'peridot': ['#d9ec6c', '#68870e'], 'perla': ['#fffef9', '#d8cab6', 'pearl'],
'pink opal': ['#fdd5dc', '#d68b9e'], 'prehnita': ['#e0eeb5', '#83a255'], 'rubi': ['#f0435f', '#640418'], 'sodalita': ['#5a78cc', '#192350'],
'sunstone': ['#f9b479', '#ad4219', 'spark'], 'topacio': ['#b5e3f6', '#3789bf'], 'turmalina': ['#f286a6', '#3a8b58'], 'turmalina rainbow': ['#f8abbf', '#69bc9b', 'iri'],
'turquesa': ['#66ded2', '#12807a'], 'turquesa blanca': ['#f7f8f4', '#95a8a4'], 'zafiro': ['#5171e3', '#0d1964']
};
function gem(name){
var k=norm(name);
if(GEMS[k]) return GEMS[k];
var h=0;
for (var i=0; i < k.length; i++) h=(h * 31 + k.charCodeAt(i)) % 360;
return ['hsl(' + h + ' 60% 74%)', 'hsl(' + h + ' 50% 26%)'];
}
function orbStyle(name){
var g=gem(name);
return '--a:' + g[0] + ';--b:' + g[1];
}
function orbClass(name){
var fx=gem(name)[2];
return 'vb-orb' + (fx ? ' is-' + fx:'');
}
function orb(i, inner){
var f=FACS[i];
if(f.img){
return '<span class="vb-orb has-img" style="' + orbStyle(f.n) + '"><img src="' + esc(f.img) + '" alt="" loading="lazy" decoding="async">' + (inner||'') + '</span>';
}
return '<span class="' + orbClass(f.n) + '" style="' + orbStyle(f.n) + '">' + (inner||'') + '</span>';
}
var D=null, P=[], CATS=[], FACS=[], VOCAB=null, loading=null, IMG='', MONEY=null, PMAX=100;
function load(){
if(D) return Promise.resolve(D);
if(loading) return loading;
var key='vbus:' + C.ver;
try {
var cached=JSON.parse(localStorage.getItem(key)||'null');
if(cached&&cached.t > Date.now() - 6e5) return Promise.resolve(prep(cached.d));
} catch (e){  }
var url=C.api + (C.api.indexOf('?') < 0 ? '?':'&') + 'v=' + encodeURIComponent(C.ver);
loading=fetch(url, { credentials: 'omit' })
.then(function (r){ if(!r.ok) throw new Error(r.status); return r.json(); })
.then(function (d){
try {
for (var i=localStorage.length - 1; i >=0; i--){
var k=localStorage.key(i);
if(k&&k.indexOf('vbus:')===0&&k!=='vbus:scroll') localStorage.removeItem(k);
}
localStorage.setItem(key, JSON.stringify({ t: Date.now(), d: d }));
} catch (e){  }
return prep(d);
})
.catch(function (e){ loading=null; throw e; });
return loading;
}
function prep(d){
D=d;
IMG=d.img;
MONEY=d.money;
CATS=d.cats.map(function (c, i){ return { i: i, n: c.n, s: c.s, hide: !!c.hide, o: c.o, total: 0 };});
FACS=d.facets.map(function (f, i){ return { i: i, n: f.n, s: f.s, img: f.img||'', total: 0 };});
var max=0;
P=d.p.map(function (t){
var cn=t[7].map(function (i){ return CATS[i].n + ' ' + CATS[i].s.replace(/-/g, ' '); }).join(' ');
var fn=t[8].map(function (i){ return FACS[i].n; }).join(' ');
t[7].forEach(function (i){ CATS[i].total++; });
t[8].forEach(function (i){ FACS[i].total++; });
if(t[3] > max) max=t[3];
return {
id: t[0], n: t[1], u: /^https?:/.test(t[2]) ? t[2]:d.home + t[2], pr: t[3], rg: t[4], is: t[5], im: t[6],
c: t[7], s: t[8], st: t[9], dt: t[10], sl: t[11],
nh: ' ' + norm(t[1]), fh: ' ' + norm(fn), h: ' ' + norm(t[1] + ' ' + cn + ' ' + fn)
};});
PMAX=Math.max(50, Math.ceil(max / 50) * 50);
return D;
}
function vocab(){
if(VOCAB) return VOCAB;
VOCAB=new Map();
P.forEach(function (p){
p.h.split(' ').forEach(function (w){ if(w.length > 2) VOCAB.set(w, (VOCAB.get(w)||0) + 1); });
});
Object.keys(SYN).forEach(function (w){ if(!VOCAB.has(w)) VOCAB.set(w, 1); });
return VOCAB;
}
function fuzzy(t){
if(t.length < 3) return null;
var max=t.length <=4 ? 1:2, best=null, bd=max + 1, bf=0;
vocab().forEach(function (f, w){
var d=Math.min(lev(t, w, max), w.length > t.length ? lev(t, w.slice(0, t.length), max) + 0.5:99);
if(d < bd||(d===bd&&f > bf)){ best=w; bd=d; bf=f; }});
return bd <=max ? best:null;
}
function fmt(n){
var m=MONEY||{ sym: '$', pos: 'left', dec: 2, ds: '.', ts: ',' };
var dec=Math.round(n)===n ? 0:m.dec;
var parts=n.toFixed(dec).split('.');
var s=parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, m.ts) + (parts[1] ? m.ds + parts[1]:'');
switch (m.pos){
case 'right': return s + m.sym;
case 'right_space': return s + ' ' + m.sym;
case 'left_space': return m.sym + ' ' + s;
default: return m.sym + s;
}}
function num(n){
return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, (MONEY&&MONEY.ts)||'.');
}
var S={ q: '', cat: -1, fac: new Set(), min: 0, max: null, sort: '', out: false };
var R=null;
function match(q){
var toks=tokens(q);
if(!toks.length) return { all: true, groups: [] };
var fixed=[];
var groups=toks.map(function (t){
var g={ t: t, alts: alts(t) };
if(!P.some(function (p){ return has(p.h, g.alts); })){
var f=fuzzy(t);
if(f&&f!==t){ g.alts=alts(f); g.fix=f; fixed.push(f); }}
return g;
});
var scores=new Map();
P.forEach(function (p){
var total=0;
for (var i=0; i < groups.length; i++){
var sc=0, a=groups[i].alts;
for (var j=0; j < a.length; j++){
var k=' ' + a[j];
if(p.nh.indexOf(k)===0) sc=Math.max(sc, 14);
else if(p.nh.indexOf(k) > 0) sc=Math.max(sc, 10);
else if(p.fh.indexOf(k) >=0) sc=Math.max(sc, 7);
else if(p.h.indexOf(k) >=0) sc=Math.max(sc, 4);
}
if(!sc) return;
total +=sc;
}
scores.set(p.id, total);
});
return { all: false, groups: groups, scores: scores, fixed: fixed };}
function compute(){
var m=match(S.q);
var hi=S.max==null ? Infinity:S.max;
var catCount=CATS.map(function (){ return 0; });
var facCount=FACS.map(function (){ return 0; });
var prices=[], res=[], all=0;
P.forEach(function (p){
if(!m.all&&!m.scores.has(p.id)) return;
var a=p.pr >=S.min&&p.pr <=hi;
var b=S.cat < 0||p.c.indexOf(S.cat) >=0;
var c = !S.fac.size||p.s.some(function (i){ return S.fac.has(i); });
var d = !S.out||p.st;
if(a&&c && d){ all++; p.c.forEach(function (i){ catCount[i]++; });}
if(a&&b && d) p.s.forEach(function (i){ facCount[i]++; });
if(b&&c && d) prices.push(p.pr);
if(a&&b && c&&d) res.push(p);
});
var mode=sortMode(m);
var cmp={
rel: function (x, y){ return m.scores.get(y.id) - m.scores.get(x.id)||x.dt - y.dt; },
new: function (x, y){ return x.dt - y.dt||y.id - x.id; },
asc: function (x, y){ return x.pr - y.pr; },
desc: function (x, y){ return y.pr - x.pr; },
pop: function (x, y){ return y.sl - x.sl||x.dt - y.dt; }}[mode];
res.sort(function (x, y){ return y.st - x.st||cmp(x, y); });
var idle=m.all&&S.cat < 0&&!S.fac.size&&S.min <=0&&S.max==null&&!S.out&&!S.sort;
return { res: res, all: all, catCount: catCount, facCount: facCount, prices: prices, m: m, idle: idle };}
function sortMode(m){
if(S.sort&&!(S.sort==='rel'&&m.all)) return S.sort;
return m.all ? 'new':'rel';
}
var I={
search: '<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="6.5"/><path d="m20 20-4.2-4.2"/></svg>',
close: '<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18"/></svg>',
x: '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><path d="M7 7l10 10M17 7 7 17"/></svg>',
sliders: '<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" aria-hidden="true"><path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="16" cy="7" r="2"/><circle cx="10" cy="17" r="2"/></svg>',
arrow: '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>',
check: '<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m5 12.5 4.5 4.5L19 7.5"/></svg>',
gem: '<svg viewBox="0 0 120 100" width="120" height="100" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round" aria-hidden="true"><path class="vb-draw" d="M30 10h60l22 26-52 58L8 36z"/><path class="vb-draw" d="M8 36h104M30 10l14 26 16-26 16 26 14-26M44 36l16 58 16-58"/></svg>'
};
var hint, root, panel, top, input, ph, clearBtn, suggest, catsEl, catInd, facsEl, bar, countEl, chipsEl, filterBtn, note, grid, empty, sentinel,
sheet, sheetScrim, sortEl, hist, rangeLo, rangeHi, loLbl, hiLbl, outToggle, applyBtn;
var compact=false, built=false, isOpen=false, limit=PAGE, trigger=null, pushed=false, shownCount=0, io=null, typer=null;
function after(anim, ms, fn){
var done=false;
var run=function (){ if(!done){ done=true; fn(); }};
anim.onfinish=run;
setTimeout(run, ms + 80);
}
function h(html){
var t=document.createElement('template');
t.innerHTML=html.trim();
return t.content.firstChild;
}
function build(){
built=true;
root=h(
'<div id="vbus" class="vb" role="dialog" aria-modal="true" aria-label="Buscador de joyas" hidden>' +
'<div class="vb-panel">' +
'<div class="vb-top"><div class="vb-wrap">' +
'<div class="vb-head" data-in><span class="vb-eyebrow">' +
(C.logo ? '<img class="vb-logo" src="' + esc(C.logo) + '" alt="' + esc(C.site||'') + '">':esc(C.site||'') + '<i></i>Buscador') +
'</span></div>' +
'<form class="vb-form" role="search" data-in>' +
'<span class="vb-icon">' + I.search + '</span>' +
'<input class="vb-input" type="search" autocomplete="off" autocorrect="off" spellcheck="false" enterkeyhint="search" aria-label="¿Qué pieza buscas?" aria-controls="vb-grid">' +
'<span class="vb-ph" aria-hidden="true"></span>' +
'<button type="button" class="vb-clear" aria-label="Borrar búsqueda">' + I.x + '</button>' +
'<button type="button" class="vb-close" aria-label="Cerrar buscador">' + I.close + '</button>' +
'<i class="vb-line"></i>' +
'</form>' +
'<div class="vb-suggest" aria-label="Sugerencias"></div>' +
'</div></div>' +
'<div class="vb-wrap vb-body">' +
'<nav class="vb-cats" aria-label="Categorías" data-in><span class="vb-cats-ind" aria-hidden="true"></span></nav>' +
'<section class="vb-facs-wrap" data-in><h2 class="vb-label vb-facs-label"></h2>' +
'<div class="vb-facs-scroller"><button type="button" class="vb-arrow is-prev" aria-label="Ver piedras anteriores" tabindex="-1">' + I.arrow + '</button>' +
'<div class="vb-facs" role="group"></div>' +
'<button type="button" class="vb-arrow is-next" aria-label="Ver más piedras" tabindex="-1">' + I.arrow + '</button></div></section>' +
'<div class="vb-bar" data-in>' +
'<p class="vb-count" aria-live="polite"><b>0</b> <span>piezas</span></p>' +
'<div class="vb-chips"></div>' +
'<button type="button" class="vb-filter-btn" aria-haspopup="dialog" aria-label="Filtrar y ordenar">' + I.sliders + '<span>Filtrar y ordenar</span><em hidden></em></button>' +
'</div>' +
'<p class="vb-note" hidden></p>' +
'<div class="vb-grid" id="vb-grid"></div>' +
'<p class="vb-hint" hidden>Escribe el nombre de una pieza o elige una piedra para ver todo el catálogo.</p>' +
'<div class="vb-empty" hidden></div>' +
'<div class="vb-sentinel" aria-hidden="true"></div>' +
'</div>' +
'</div>' +
'<div class="vb-sheet-scrim" hidden></div>' +
'<div class="vb-sheet" role="dialog" aria-modal="true" aria-label="Filtrar y ordenar" hidden>' +
'<div class="vb-sheet-head"><i class="vb-grab" aria-hidden="true"></i><h2>Filtrar y ordenar</h2><button type="button" class="vb-sheet-x" aria-label="Cerrar filtros">' + I.close + '</button></div>' +
'<div class="vb-sheet-body">' +
'<h3 class="vb-label">Ordenar por</h3>' +
'<div class="vb-sort" role="radiogroup" aria-label="Ordenar por"></div>' +
'<h3 class="vb-label">Precio</h3>' +
'<div class="vb-pricebox">' +
'<div class="vb-hist" aria-hidden="true"></div>' +
'<div class="vb-range"><input type="range" class="vb-lo" aria-label="Precio mínimo"><input type="range" class="vb-hi" aria-label="Precio máximo"></div>' +
'<div class="vb-range-lbl"><span class="vb-lo-lbl"></span><span class="vb-hi-lbl"></span></div>' +
'</div>' +
'<label class="vb-switch"><input type="checkbox" class="vb-out"><span class="vb-switch-ui" aria-hidden="true"></span><span>Ocultar piezas agotadas</span></label>' +
'</div>' +
'<div class="vb-sheet-foot"><button type="button" class="vb-reset">Limpiar</button><button type="button" class="vb-apply">Ver piezas</button></div>' +
'</div>' +
'</div>'
);
document.body.appendChild(root);
var q=function (s){ return root.querySelector(s); };
panel=q('.vb-panel'); top=q('.vb-top'); input=q('.vb-input'); ph=q('.vb-ph'); clearBtn=q('.vb-clear');
suggest=q('.vb-suggest'); catsEl=q('.vb-cats'); catInd=q('.vb-cats-ind'); facsEl=q('.vb-facs');
bar=q('.vb-bar'); countEl=q('.vb-count b'); chipsEl=q('.vb-chips'); filterBtn=q('.vb-filter-btn');
note=q('.vb-note'); hint=q('.vb-hint'); grid=q('.vb-grid'); empty=q('.vb-empty'); sentinel=q('.vb-sentinel');
sheet=q('.vb-sheet'); sheetScrim=q('.vb-sheet-scrim'); sortEl=q('.vb-sort'); hist=q('.vb-hist');
rangeLo=q('.vb-lo'); rangeHi=q('.vb-hi'); loLbl=q('.vb-lo-lbl'); hiLbl=q('.vb-hi-lbl');
outToggle=q('.vb-out'); applyBtn=q('.vb-apply');
skeleton();
bindUI();
}
function skeleton(){
var s='';
for (var i=0; i < 8; i++) s +='<div class="vb-card is-skel"><div class="vb-media"></div><div class="vb-info"><i></i><i></i></div></div>';
grid.innerHTML=s;
}
var ready=false;
function setup(){
if(ready) return;
ready=true;
root.querySelector('.vb-facs-label').textContent=D.facet||'';
var cats=CATS.filter(function (c){ return !c.hide&&c.total; }).sort(function (a, b){ return a.o - b.o||b.total - a.total; });
catsEl.insertAdjacentHTML('beforeend',
'<button type="button" class="vb-cat" data-cat="-1" aria-pressed="true">Todo</button>' +
cats.map(function (c){
return '<button type="button" class="vb-cat" data-cat="' + c.i + '" aria-pressed="false">' + esc(c.n) + '</button>';
}).join(''));
var facs=FACS.filter(function (f){ return f.total; }).sort(function (a, b){ return b.total - a.total; });
facsEl.innerHTML=facs.map(function (f){
return '<button type="button" class="vb-fac" data-fac="' + f.i + '" aria-pressed="false">' +
orb(f.i, '<svg class="vb-ring" viewBox="0 0 60 60" aria-hidden="true"><circle cx="30" cy="30" r="28"/></svg><span class="vb-tick">' + I.check + '</span>') +
'<span class="vb-fac-n">' + esc(f.n) + '</span></button>';
}).join('');
var sorts=[['rel', 'Relevancia'], ['new', 'Novedades'], ['pop', 'Más vendidas'], ['asc', 'Menor precio'], ['desc', 'Mayor precio']];
sortEl.innerHTML=sorts.map(function (s){
return '<button type="button" role="radio" aria-checked="false" data-sort="' + s[0] + '">' + s[1] + '</button>';
}).join('');
[rangeLo, rangeHi].forEach(function (r){ r.min=0; r.max=PMAX; r.step=5; });
rangeLo.value=0; rangeHi.value=PMAX;
var bins='';
for (var i=0; i < 32; i++) bins +='<i></i>';
hist.innerHTML=bins;
placeholders();
}
function update(opts){
opts=opts||{};
if(!D) return;
var prevLen=R ? R.res.length:-1, prevIdle=R ? R.idle:true;
R=compute();
if(opts.resetLimit!==false) limit=PAGE;
clearBtn.classList.toggle('is-on', !!S.q);
ph.classList.toggle('is-off', !!S.q);
renderCats();
renderFacs();
renderBar(prevLen, prevIdle);
renderSheet();
renderSuggest();
renderNote();
renderGrid(opts.animate!==false);
syncHash();
}
function renderCats(){
catsEl.querySelectorAll('.vb-cat').forEach(function (b){
var i=+b.dataset.cat;
var n=i < 0 ? R.all:R.catCount[i];
var on=i===S.cat;
b.setAttribute('aria-pressed', on ? 'true':'false');
b.classList.toggle('is-empty', !n&&!on);
});
moveIndicator();
}
function moveIndicator(instant){
var on=catsEl.querySelector('[aria-pressed="true"]');
if(!on) return;
catInd.style.transition=instant||RM ? 'none':'';
catInd.style.width=on.offsetWidth + 'px';
catInd.style.transform='translateX(' + on.offsetLeft + 'px)';
var left=on.offsetLeft - catsEl.clientWidth / 2 + on.offsetWidth / 2;
if(catsEl.scrollWidth > catsEl.clientWidth) catsEl.scrollTo({ left: left, behavior: RM ? 'auto':'smooth' });
}
function renderFacs(){
facsEl.querySelectorAll('.vb-fac').forEach(function (b){
var i=+b.dataset.fac, n=R.facCount[i], on=S.fac.has(i);
b.setAttribute('aria-pressed', on ? 'true':'false');
b.classList.toggle('is-empty', !n&&!on);
b.setAttribute('aria-disabled', !n&&!on ? 'true':'false');
b.setAttribute('aria-label', FACS[i].n + (n ? '':', sin piezas con estos filtros'));
});
}
var countAnim=0;
function renderBar(prevLen, prevIdle){
var to=R.res.length, from=prevLen < 0||prevIdle ? to:prevLen;
cancelAnimationFrame(countAnim);
countEl.parentNode.classList.toggle('is-idle', R.idle);
hint.hidden = !R.idle;
if(R.idle){
countEl.nextElementSibling.textContent='Recién llegadas';
}else if(RM||from===to){
countEl.textContent=num(to);
}else{
var t0=performance.now();
var step=function (t){
var k=Math.min(1, (t - t0) / 420), e=1 - Math.pow(1 - k, 3);
countEl.textContent=num(Math.round(from + (to - from) * e));
if(k < 1) countAnim=requestAnimationFrame(step);
};
countAnim=requestAnimationFrame(step);
}
if(!R.idle) countEl.nextElementSibling.textContent=to===1 ? 'pieza':'piezas';
var chips=[];
S.fac.forEach(function (i){
chips.push({ k: 'f' + i, html: orb(i) + esc(FACS[i].n), label: 'Quitar ' + FACS[i].n });
});
if(S.min > 0||S.max!=null){
chips.push({ k: 'price', html: fmt(S.min) + ' – ' + fmt(S.max==null ? PMAX:S.max), label: 'Quitar filtro de precio' });
}
if(S.out) chips.push({ k: 'out', html: 'Solo disponibles', label: 'Mostrar también agotadas' });
if(chips.length > 1) chips.push({ k: 'all', html: 'Limpiar todo', label: 'Limpiar todos los filtros', cls: ' is-clear' });
var have={};
chipsEl.querySelectorAll('.vb-chip').forEach(function (el){ have[el.dataset.k]=el; });
var keep={};
chips.forEach(function (c){
keep[c.k]=1;
if(have[c.k]){ have[c.k].querySelector('.vb-chip-t').innerHTML=c.html; return; }
var el=h('<button type="button" class="vb-chip' + (c.cls||'') + '" data-k="' + c.k + '" aria-label="' + esc(c.label) + '"><span class="vb-chip-t">' + c.html + '</span>' + I.x + '</button>');
if(c.k==='all') chipsEl.appendChild(el);
else chipsEl.insertBefore(el, chipsEl.querySelector('[data-k="all"]'));
if(!RM) el.animate([{ opacity: 0, transform: 'scale(.6)' }, { opacity: 1, transform: 'none' }], { duration: 320, easing: 'cubic-bezier(.3,1.5,.5,1)' });
});
Object.keys(have).forEach(function (k){
if(keep[k]) return;
var el=have[k];
if(RM){ el.remove(); return; }
el.style.pointerEvents='none';
after(el.animate([{ opacity: 1, transform: 'none' }, { opacity: 0, transform: 'scale(.6)' }], { duration: 200, easing: 'ease-in' }), 200, function (){ el.remove(); });
});
var extra=(S.min > 0||S.max!=null ? 1:0) + (S.out ? 1:0) + (S.sort ? 1:0);
var badge=filterBtn.querySelector('em');
badge.hidden = !extra;
badge.textContent=extra;
}
function renderSheet(){
var mode=sortMode(R.m);
sortEl.querySelectorAll('button').forEach(function (b){
var on=b.dataset.sort===mode;
b.setAttribute('aria-checked', on ? 'true':'false');
b.hidden=b.dataset.sort==='rel'&&R.m.all;
});
var lo=S.min, hi=S.max==null ? PMAX:S.max;
rangeLo.value=lo; rangeHi.value=hi;
loLbl.textContent=fmt(lo);
hiLbl.textContent=S.max==null ? fmt(PMAX) + '+':fmt(hi);
var pct=function (v){ return (v / PMAX) * 100 + '%'; };
root.style.setProperty('--lo', pct(lo));
root.style.setProperty('--hi', pct(hi));
var bins=hist.children, n=bins.length, counts=new Array(n).fill(0), w=PMAX / n, peak=1;
R.prices.forEach(function (p){ counts[Math.min(n - 1, Math.floor(p / w))]++; });
counts.forEach(function (c){ if(c > peak) peak=c; });
for (var i=0; i < n; i++){
var inside=(i + 1) * w > lo&&i * w < hi;
bins[i].style.transform='scaleY(' + (counts[i] ? 0.08 + 0.92 * Math.sqrt(counts[i] / peak):0.03) + ')';
bins[i].classList.toggle('is-in', inside);
}
outToggle.checked=S.out;
applyBtn.textContent=R.idle ? 'Ver piezas':R.res.length ? 'Ver ' + num(R.res.length) + (R.res.length===1 ? ' pieza':' piezas'):'Sin resultados';
}
function renderSuggest(){
var toks=tokens(S.q), items=[];
if(toks.length){
var whole=norm(S.q);
var hit=function (name){
var n=' ' + norm(name);
if(n.indexOf(' ' + whole) >=0) return true;
return toks.some(function (t){
return t.length >=2&&(n.indexOf(' ' + t) >=0||has(n, (SYN[t]||[]).filter(function (s){ return s.length > 3; })));
});
};
FACS.forEach(function (f){
if(f.total&&!S.fac.has(f.i)&&hit(f.n)) items.push({ t: 'f', i: f.i, n: f.n, c: f.total });
});
CATS.forEach(function (c){
if(!c.hide&&c.total&&S.cat!==c.i&&(hit(c.n)||hit(c.s.replace(/-/g, ' ')))) items.push({ t: 'c', i: c.i, n: c.n, c: c.total });
});
}
items=items.slice(0, 5);
var sig=items.map(function (x){ return x.t + x.i; }).join();
if(suggest.dataset.sig===sig) return;
suggest.dataset.sig=sig;
suggest.innerHTML=items.map(function (x, k){
var icon=x.t==='f' ? orb(x.i):'';
return '<button type="button" class="vb-sug" data-t="' + x.t + '" data-i="' + x.i + '" style="--k:' + k + '">' +
icon + '<span><small>' + (x.t==='f' ? esc(String(D.facet||'').replace(/s$/, '')):'Categoría') + '</small>' + esc(x.n) + '</span></button>';
}).join('');
suggest.classList.toggle('is-on', !!items.length);
}
function renderNote(){
var f=R.m.fixed||[];
note.hidden = !f.length;
if(f.length) note.innerHTML='Mostrando resultados para <b>' + esc(f.join(' ')) + '</b>';
}
function marks(){
var list=[];
(R.m.groups||[]).forEach(function (g){ list=list.concat(g.alts); });
return list.filter(function (a){ return a.indexOf(' ') < 0; }).sort(function (a, b){ return b.length - a.length; });
}
function highlight(name, list){
if(!list.length) return esc(name);
return name.split(/(\s+)/).map(function (w){
var nw=norm(w);
for (var i=0; i < list.length; i++){
if(list[i]&&nw.indexOf(list[i])===0){
var cut=Math.min(w.length, list[i].length);
return '<mark>' + esc(w.slice(0, cut)) + '</mark>' + esc(w.slice(cut));
}}
return esc(w);
}).join('');
}
function cardHTML(p, hl){
var badge = !p.st ? '<span class="vb-badge is-out">Agotada</span>'
: p.rg ? '<span class="vb-badge is-sale">−' + Math.round((1 - p.pr / p.rg) * 100) + '%</span>'
: p.dt <=45 ? '<span class="vb-badge">Nueva</span>':'';
var img=p.is
? '<img alt="" loading="lazy" decoding="async" src="' + esc(IMG + p.is) + '" srcset="' + esc(IMG + p.is) + ' 300w, ' + esc(IMG + p.im) + ' 768w" sizes="(min-width:1280px) 250px, (min-width:900px) 22vw, (min-width:600px) 30vw, 46vw">'
: '';
var orbs=p.s.slice(0, 4).map(function (i){
return orb(i);
}).join('') + (p.s.length > 4 ? '<em>+' + (p.s.length - 4) + '</em>':'');
var stones=p.s.map(function (i){ return FACS[i].n; }).join(', ');
return '<div class="vb-media">' + img + badge + '<span class="vb-cta">Ver pieza ' + I.arrow + '</span></div>' +
'<div class="vb-info"><h3 class="vb-name">' + highlight(p.n, hl) + '</h3>' +
'<div class="vb-meta"><span class="vb-price">' + (p.rg ? '<del>' + fmt(p.rg) + '</del> ':'') + fmt(p.pr) + '</span>' +
(orbs ? '<span class="vb-orbs" aria-label="' + esc(stones) + '">' + orbs + '</span>':'') + '</div></div>';
}
function cardEl(p, hl){
var a=document.createElement('a');
a.className='vb-card' + (p.st ? '':' is-out');
a.href=p.u;
a.dataset.id=p.id;
a.innerHTML=cardHTML(p, hl);
return a;
}
function inView(r){
return r&&r.bottom > -40&&r.top < window.innerHeight + 40;
}
function renderGrid(animate){
var shown=R.res.slice(0, R.idle ? IDLE:limit);
var hl=marks();
var old=new Map();
Array.from(grid.children).forEach(function (el){
if(el.dataset.id) old.set(el.dataset.id, el); else el.remove();
});
var flip=animate&&!RM&&old.size&&old.size <=120;
var first=new Map();
if(flip) old.forEach(function (el, id){ first.set(id, el.getBoundingClientRect()); });
var keep=new Set(shown.map(function (p){ return String(p.id); }));
old.forEach(function (el, id){
if(keep.has(id)) return;
var r=first.get(id);
if(flip&&inView(r)) ghost(el, r);
el.remove();
});
var fresh=[];
shown.forEach(function (p, i){
var id=String(p.id), el=old.get(id);
if(el){
el.querySelector('.vb-name').innerHTML=highlight(p.n, hl);
}else{
el=cardEl(p, hl);
fresh.push(el);
}
if(grid.children[i]!==el) grid.insertBefore(el, grid.children[i]||null);
});
shownCount=shown.length;
if(!RM){
var k=0;
fresh.forEach(function (el){
var r=el.getBoundingClientRect();
if(!inView(r)) return;
el.animate([{ opacity: 0, transform: 'translateY(22px) scale(.97)' }, { opacity: 1, transform: 'none' }],
{ duration: 560, delay: Math.min(k++, 12) * 38, easing: EASE, fill: 'backwards' }
);
});
if(flip){
first.forEach(function (r0, id){
if(!keep.has(id)) return;
var el=old.get(id), r1=el.getBoundingClientRect();
var dx=r0.left - r1.left, dy=r0.top - r1.top;
if((!dx&&!dy)||(!inView(r0)&&!inView(r1))) return;
el.animate([{ transform: 'translate(' + dx + 'px,' + dy + 'px)' }, { transform: 'none' }],
{ duration: 560, easing: EASE }
);
});
}}
var none = !R.res.length;
empty.hidden = !none;
if(none) renderEmpty();
sentinel.hidden=R.idle||shownCount >=R.res.length;
}
function ghost(el, r){
var g=el.cloneNode(true);
g.classList.add('vb-ghost');
g.style.cssText='position:fixed;left:' + r.left + 'px;top:' + r.top + 'px;width:' + r.width + 'px;height:' + r.height + 'px;margin:0;';
root.appendChild(g);
after(g.animate([{ opacity: 1, transform: 'none' }, { opacity: 0, transform: 'scale(.9)' }], { duration: 280, easing: 'ease-in' }), 280, function (){ g.remove(); });
}
function renderEmpty(){
var top=FACS.filter(function (f){ return f.total; }).sort(function (a, b){ return b.total - a.total; }).slice(0, 6);
var filtered=S.cat >=0||S.fac.size||S.min > 0||S.max!=null||S.out;
empty.innerHTML =
'<div class="vb-empty-art">' + I.gem + '</div>' +
'<h3>' + (S.q ? 'No encontramos «' + esc(S.q.trim()) + '»':'Nada con esa combinación') + '</h3>' +
'<p>' + (filtered ? 'Prueba quitando algún filtro, o explora otra piedra.':'Revisa cómo se escribe o prueba con una piedra.') + '</p>' +
'<div class="vb-empty-actions">' +
(filtered ? '<button type="button" class="vb-btn" data-act="clear-filters">Quitar filtros</button>':'') +
top.map(function (f){
return '<button type="button" class="vb-sug" data-t="f" data-i="' + f.i + '" data-replace="1">' + orb(f.i) + '<span>' + esc(f.n) + '</span></button>';
}).join('') +
'</div>';
}
var phrases=[];
function placeholders(){
var combos={};
P.forEach(function (p){
p.c.forEach(function (c){
if(CATS[c].hide) return;
p.s.forEach(function (f){ var k=c + ':' + f; combos[k]=(combos[k]||0) + 1; });
});
});
var used={};
phrases=Object.keys(combos).sort(function (a, b){ return combos[b] - combos[a]; }).filter(function (k){
var parts=k.split(':');
if(used['c' + parts[0]]||used['f' + parts[1]]) return false;
used['c' + parts[0]]=used['f' + parts[1]]=1;
return true;
}).slice(0, 5).map(function (k){
var parts=k.split(':');
return (CATS[parts[0]].n + ' de ' + FACS[parts[1]].n).toLowerCase();
});
FACS.slice().sort(function (a, b){ return b.total - a.total; }).slice(0, 2).forEach(function (f, i){
phrases.splice(i * 2 + 1, 0, f.n.toLowerCase());
});
if(!phrases.length) phrases=['tu pieza favorita'];
}
function typeLoop(){
clearTimeout(typer);
if(!isOpen||!phrases.length) return;
if(RM){ ph.innerHTML='<span class="vb-ph-pre">Busca </span>“' + esc(phrases[0]) + '”'; return; }
var i=0, pos=0, dir=1;
var tick=function (){
if(!isOpen) return;
var word=phrases[i % phrases.length];
pos +=dir;
ph.innerHTML='<span class="vb-ph-pre">Busca </span>“' + esc(word.slice(0, pos)) + '<i class="vb-caret"></i>”';
var wait=dir > 0 ? 55 + Math.random() * 60:22;
if(dir > 0&&pos >=word.length){ dir=-1; wait=1900; }
else if(dir < 0&&pos <=0){ dir=1; i++; wait=350; }
typer=setTimeout(tick, wait);
};
typer=setTimeout(tick, 500);
}
var sheetOpen=false;
function openSheet(){
sheetOpen=true;
sheet.hidden=false;
sheetScrim.hidden=false;
var mobile=window.innerWidth < 900;
if(!RM){
sheet.animate(mobile ? [{ transform: 'translateY(100%)' }, { transform: 'none' }]:[{ transform: 'translateX(100%)' }, { transform: 'none' }],
{ duration: 520, easing: 'cubic-bezier(.2,.9,.2,1)' }
);
sheetScrim.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 300 });
hist.querySelectorAll('i').forEach(function (b, k){
b.animate([{ transform: 'scaleY(0)' }, { transform: b.style.transform }], { duration: 600, delay: 120 + k * 14, easing: EASE, fill: 'backwards' });
});
}
setTimeout(function (){ var b=sortEl.querySelector('[aria-checked="true"]'); if(b) b.focus({ preventScroll: true });}, 60);
}
function closeSheet(){
if(!sheetOpen) return;
sheetOpen=false;
var done=function (){
if(sheetOpen) return;
sheet.hidden=true; sheetScrim.hidden=true; sheet.style.transform='';
};
if(RM){ done(); }else{
var mobile=window.innerWidth < 900;
var from=sheet.style.transform||'none';
after(sheet.animate([{ transform: from }, { transform: mobile ? 'translateY(100%)':'translateX(100%)' }],
{ duration: 320, easing: 'cubic-bezier(.5,0,.8,.4)' }
), 320, done);
sheetScrim.animate([{ opacity: 1 }, { opacity: 0 }], { duration: 300 });
}
filterBtn.focus({ preventScroll: true });
}
var qTimer=0;
function bindUI(){
root.querySelector('.vb-close').addEventListener('click', function (){ close(); });
root.querySelector('.vb-form').addEventListener('submit', function (e){
e.preventDefault();
if(window.matchMedia('(hover: none)').matches) input.blur();
scrollToResults(true);
});
input.addEventListener('input', function (){
S.q=input.value;
clearTimeout(qTimer);
qTimer=setTimeout(function (){ update(); scrollToResults(); }, 90);
});
input.addEventListener('keydown', function (e){
if(e.key==='ArrowDown'){
var first=suggest.querySelector('.vb-sug')||grid.querySelector('.vb-card');
if(first){ e.preventDefault(); first.focus(); }}
});
clearBtn.addEventListener('click', function (){
input.value=S.q='';
update();
input.focus();
});
root.addEventListener('click', function (e){
var t=e.target.closest('button');
if(!t||!root.contains(t)) return;
if(t.classList.contains('vb-cat')){
S.cat=+t.dataset.cat;
update();
scrollToResults();
}else if(t.classList.contains('vb-fac')){
if(t.getAttribute('aria-disabled')==='true') return;
var i=+t.dataset.fac;
if(S.fac.has(i)) S.fac.delete(i); else { S.fac.add(i); sparkle(t); }
update();
scrollToResults();
}else if(t.classList.contains('vb-sug')){
applySuggestion(t);
}else if(t.classList.contains('vb-chip')){
var k=t.dataset.k;
if(k==='all') resetFilters();
else if(k==='price'){ S.min=0; S.max=null; }
else if(k==='out') S.out=false;
else S.fac.delete(+k.slice(1));
update();
}else if(t===filterBtn){
openSheet();
}else if(t.classList.contains('vb-sheet-x')||t===applyBtn){
closeSheet();
scrollToResults();
}else if(t.classList.contains('vb-reset')){
S.sort=''; S.min=0; S.max=null; S.out=false;
update();
}else if(t.dataset.sort){
S.sort=t.dataset.sort;
update();
}else if(t.dataset.act==='clear-filters'){
resetFilters();
update();
}});
sheetScrim.addEventListener('click', closeSheet);
var onRange=function (e){
var lo=+rangeLo.value, hi=+rangeHi.value;
if(lo > hi - 10){
if(e.target===rangeLo) lo=rangeLo.value=hi - 10; else hi=rangeHi.value=lo + 10;
}
S.min=Math.max(0, lo);
S.max=hi >=PMAX ? null:hi;
update({ animate: false });
};
rangeLo.addEventListener('input', onRange);
rangeHi.addEventListener('input', onRange);
outToggle.addEventListener('change', function (){ S.out=outToggle.checked; update(); });
dragToClose();
var edges=function (){
var max=facsEl.scrollWidth - facsEl.clientWidth;
facsEl.parentNode.classList.toggle('at-start', facsEl.scrollLeft < 8);
facsEl.parentNode.classList.toggle('at-end', facsEl.scrollLeft > max - 8);
};
facsEl.addEventListener('scroll', edges, { passive: true });
root.querySelectorAll('.vb-arrow').forEach(function (b){
b.addEventListener('click', function (e){
e.stopPropagation();
var dir=b.classList.contains('is-prev') ? -1:1;
facsEl.scrollBy({ left: dir * facsEl.clientWidth * 0.8, behavior: RM ? 'auto':'smooth' });
});
});
root._edges=edges;
var raf=0, lockUntil=0, recheck=0;
var onPanelScroll=function (){
raf=0;
var y=panel.scrollTop, now=Date.now();
root.classList.toggle('is-scrolled', y > 2);
if(now < lockUntil){
clearTimeout(recheck);
recheck=setTimeout(onPanelScroll, lockUntil - now + 20);
return;
}
var room=panel.scrollHeight - panel.clientHeight;
var want=compact ? y > 8:y > 140&&room > 320;
if(want!==compact){
compact=want;
root.classList.toggle('is-compact', want);
lockUntil=now + 500;
}};
panel.addEventListener('scroll', function (){
if(!raf) raf=requestAnimationFrame(onPanelScroll);
}, { passive: true });
io=new IntersectionObserver(function (entries){
if(entries[0].isIntersecting) more();
}, { root: panel, rootMargin: '0px 0px 900px 0px' });
io.observe(sentinel);
grid.addEventListener('load', function (e){
if(e.target.tagName==='IMG') e.target.classList.add('is-in');
}, true);
grid.addEventListener('click', function (e){
if(e.target.closest('.vb-card')){
try { sessionStorage.setItem('vbus:scroll', JSON.stringify({ h: location.hash, y: panel.scrollTop, l: limit })); } catch (err){  }}
});
window.addEventListener('resize', function (){ if(isOpen) moveIndicator(true); });
}
function more(){
if(!R||R.idle||shownCount >=R.res.length) return;
limit +=PAGE;
renderGrid(false);
requestAnimationFrame(function (){
if(!sentinel.hidden&&sentinel.getBoundingClientRect().top < window.innerHeight + 900) more();
});
}
function resetFilters(){
S.cat=-1; S.fac.clear(); S.min=0; S.max=null; S.out=false;
}
function applySuggestion(t){
var i=+t.dataset.i;
if(t.dataset.t==='f'){ if(t.dataset.replace) S.fac.clear(); S.fac.add(i); } else S.cat=i;
var name=t.dataset.t==='f' ? FACS[i].n:CATS[i].n;
var nn=' ' + norm(name) + ' ' + (t.dataset.t==='c' ? norm(CATS[i].s):'');
var rest=S.q.split(/\s+/).filter(function (w){
var n=norm(w);
if(!n) return false;
return !(nn.indexOf(' ' + n) >=0||has(nn, SYN[n]||[])||STOP.has(n));
});
S.q=input.value=t.dataset.replace ? '':rest.join(' ');
update();
scrollToResults();
if(t.dataset.t==='f'){
var b=facsEl.querySelector('[data-fac="' + i + '"]');
if(b){ sparkle(b); b.scrollIntoView({ block: 'nearest', inline: 'center', behavior: RM ? 'auto':'smooth' });}}
}
function sparkle(btn){
if(RM) return;
var orb=btn.querySelector('.vb-orb');
if(!orb) return;
for (var k=0; k < 8; k++){
var s=document.createElement('i');
s.className='vb-spark';
orb.appendChild(s);
var ang=(k / 8) * Math.PI * 2, d=34 + Math.random() * 10;
after(s.animate([
{ transform: 'translate(-50%,-50%) scale(1)', opacity: 1 },
{ transform: 'translate(calc(-50% + ' + Math.cos(ang) * d + 'px), calc(-50% + ' + Math.sin(ang) * d + 'px)) scale(0)', opacity: 0 }
], { duration: 620, easing: 'cubic-bezier(.2,.8,.3,1)' }), 620, (function (el){ return function (){ el.remove(); };})(s));
}}
function scrollToResults(force){
var y=bar.offsetTop - top.offsetHeight + 4;
if(force ? panel.scrollTop < y - 2||panel.scrollTop > y + 2:panel.scrollTop > y + 2){
panel.scrollTo({ top: y, behavior: RM ? 'auto':'smooth' });
}}
function dragToClose(){
var head=sheet.querySelector('.vb-sheet-head'), y0=null, dy=0;
head.addEventListener('touchstart', function (e){ if(window.innerWidth < 900){ y0=e.touches[0].clientY; dy=0; sheet.style.transition='none'; }}, { passive: true });
head.addEventListener('touchmove', function (e){
if(y0==null) return;
dy=Math.max(0, e.touches[0].clientY - y0);
sheet.style.transform='translateY(' + dy + 'px)';
}, { passive: true });
head.addEventListener('touchend', function (){
if(y0==null) return;
y0=null;
sheet.style.transition='';
if(dy > 90) closeSheet();
else if(!RM) sheet.animate([{ transform: sheet.style.transform }, { transform: 'none' }], { duration: 300, easing: EASE }).onfinish=function (){ sheet.style.transform=''; };
else sheet.style.transform='';
});
}
function syncHash(){
if(!isOpen) return;
var p=new URLSearchParams();
if(S.q.trim()) p.set('q', S.q.trim());
if(S.cat >=0) p.set('c', CATS[S.cat].s);
if(S.fac.size) p.set('p', Array.from(S.fac).map(function (i){ return FACS[i].s; }).join('.'));
if(S.min > 0) p.set('min', S.min);
if(S.max!=null) p.set('max', S.max);
if(S.sort) p.set('o', S.sort);
if(S.out) p.set('a', '1');
var s=p.toString();
var hash='#buscar' + (s ? '?' + s:'');
if(location.hash!==hash) history.replaceState(history.state, '', location.pathname + location.search + hash);
}
function readHash(){
var m=location.hash.match(/^#buscar(?:\?(.*))?$/);
if(!m) return false;
var p=new URLSearchParams(m[1]||'');
var bySlug=function (list, s){ for (var i=0; i < list.length; i++) if(list[i].s===s) return i; return -1; };
S.q=p.get('q')||'';
S.cat=p.get('c') ? bySlug(CATS, p.get('c')):-1;
S.fac=new Set((p.get('p')||'').split('.').map(function (s){ return bySlug(FACS, s); }).filter(function (i){ return i >=0; }));
S.min=+p.get('min')||0;
S.max=p.get('max') ? +p.get('max'):null;
S.sort=p.get('o')||'';
S.out=p.get('a')==='1';
return true;
}
function origin(el){
if(el&&el.getBoundingClientRect){
var r=el.getBoundingClientRect();
if(r.width) return { x: r.left + r.width / 2, y: r.top + r.height / 2 };}
return { x: window.innerWidth - 60, y: 36 };}
function open(opts){
opts=opts||{};
if(isOpen) return;
if(!built) build();
isOpen=true;
trigger=opts.trigger||null;
if(!opts.fromHash&&!/^#buscar/.test(location.hash)){
history.pushState({ vbus: 1 }, '', location.pathname + location.search + '#buscar');
pushed=true;
}
root.hidden=false;
document.documentElement.classList.add('vb-lock');
if(opts.q!=null){ S.q=opts.q; input.value=opts.q; }
if(!opts.fromHash) input.focus({ preventScroll: true });
if(!RM){
var o=origin(trigger), W=window.innerWidth, H=window.innerHeight;
var rad=Math.hypot(Math.max(o.x, W - o.x), Math.max(o.y, H - o.y));
root._o=o;
panel.animate([{ clipPath: 'circle(0px at ' + o.x + 'px ' + o.y + 'px)' }, { clipPath: 'circle(' + rad + 'px at ' + o.x + 'px ' + o.y + 'px)' }],
{ duration: 760, easing: 'cubic-bezier(.76,0,.24,1)' }
);
root.querySelectorAll('[data-in]').forEach(function (el, k){
el.animate([{ opacity: 0, transform: 'translateY(26px)' }, { opacity: 1, transform: 'none' }],
{ duration: 700, delay: 240 + k * 70, easing: EASE, fill: 'backwards' });
});
}
load().then(function (){
setup();
var restore=null;
if(opts.fromHash){
readHash();
input.value=S.q;
try {
restore=JSON.parse(sessionStorage.getItem('vbus:scroll')||'null');
sessionStorage.removeItem('vbus:scroll');
} catch (e){  }
if(restore&&restore.h!==location.hash) restore=null;
}
if(restore) limit=restore.l;
update({ resetLimit: !restore });
moveIndicator(true);
root._edges();
if(restore) panel.scrollTop=restore.y;
typeLoop();
}).catch(function (){
grid.innerHTML='';
empty.hidden=false;
empty.innerHTML='<div class="vb-empty-art">' + I.gem + '</div><h3>No pudimos cargar el catálogo</h3><p>Revisa tu conexión e inténtalo otra vez.</p><div class="vb-empty-actions"><button type="button" class="vb-btn" data-act="retry">Reintentar</button></div>';
empty.querySelector('[data-act="retry"]').onclick=function (){ close(true); open(); };});
typeLoop();
}
function close(fromPop){
if(!isOpen) return;
if(!fromPop&&pushed&&history.state&&history.state.vbus){
history.back();
return;
}
isOpen=false;
pushed=false;
clearTimeout(typer);
closeSheet();
if(/^#buscar/.test(location.hash)) history.replaceState(history.state, '', location.pathname + location.search);
var done=function (){
if(isOpen) return;
root.hidden=true;
root.classList.remove('is-compact', 'is-scrolled');
compact=false;
document.documentElement.classList.remove('vb-lock');
if(trigger&&trigger.tagName==='BUTTON') trigger.focus({ preventScroll: true });
};
input.blur();
if(RM){ done(); return; }
var o=root._o||origin(trigger);
var rad=Math.hypot(Math.max(o.x, window.innerWidth - o.x), Math.max(o.y, window.innerHeight - o.y));
var shut=panel.animate([{ clipPath: 'circle(' + rad + 'px at ' + o.x + 'px ' + o.y + 'px)' }, { clipPath: 'circle(0px at ' + o.x + 'px ' + o.y + 'px)' }],
{ duration: 560, easing: 'cubic-bezier(.76,0,.24,1)', fill: 'forwards' }
);
after(shut, 560, function (){ done(); shut.cancel(); });
}
function mount(){
if(C.mount){
var host=document.querySelector(C.mount);
if(host&&!host.querySelector('.vb-trigger')){
var b=document.createElement('button');
b.type='button';
b.className='vb-trigger';
b.setAttribute('aria-label', 'Buscar joyas');
b.setAttribute('aria-keyshortcuts', '/');
b.innerHTML=I.search;
host.insertBefore(b, host.firstChild);
}}
document.addEventListener('click', function (e){
var t=e.target.closest('.vb-trigger, [data-vbus-open], a[href$="#buscar"]');
if(!t||(root&&root.contains(t))) return;
e.preventDefault();
var field=t.querySelector&&t.querySelector('input[type="search"]');
open({ trigger: t, q: field&&field.value ? field.value:null });
});
document.addEventListener('submit', function (e){
var f=e.target.closest('[data-vbus-open]');
if(!f) return;
e.preventDefault();
var field=f.querySelector('input[type="search"]');
open({ trigger: f, q: field ? field.value:null });
});
var warm=function (){ load().catch(function (){});};
document.addEventListener('pointerover', function (e){
if(e.target.closest&&e.target.closest('.vb-trigger, [data-vbus-open]')) warm();
}, { passive: true });
document.addEventListener('touchstart', function (e){
if(e.target.closest&&e.target.closest('.vb-trigger, [data-vbus-open]')) warm();
}, { passive: true });
var saveData=navigator.connection&&navigator.connection.saveData;
if(!saveData){
var idle=window.requestIdleCallback||function (fn){ return setTimeout(fn, 1); };
var later=function (){ setTimeout(function (){ idle(warm); }, 2500); };
if(document.readyState==='complete') later(); else window.addEventListener('load', later);
}
document.addEventListener('keydown', function (e){
var typing=/^(INPUT|TEXTAREA|SELECT)$/.test(e.target.tagName)||e.target.isContentEditable;
if(!isOpen){
if((e.key==='/'&&!typing)||((e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==='k')){
e.preventDefault();
open({ trigger: document.querySelector('.vb-trigger') });
}
return;
}
if(e.key==='Escape'){
e.preventDefault();
if(sheetOpen) closeSheet(); else close();
}else if(e.key==='Tab'){
trapFocus(e);
}});
window.addEventListener('popstate', function (){
var want=/^#buscar/.test(location.hash);
if(isOpen&&!want) close(true);
else if(!isOpen&&want) open({ fromHash: true });
});
if(/^#buscar/.test(location.hash)) open({ fromHash: true });
}
function trapFocus(e){
var scope=sheetOpen ? sheet:root;
var list=Array.prototype.filter.call(scope.querySelectorAll('a[href], button:not([disabled]), input:not([disabled])'),
function (el){ return el.offsetParent!==null&&!el.closest('[hidden]')&&!(scope===root&&sheet.contains(el)); }
);
if(!list.length) return;
var first=list[0], last=list[list.length - 1];
if(e.shiftKey&&document.activeElement===first){ e.preventDefault(); last.focus(); }
else if(!e.shiftKey&&document.activeElement===last){ e.preventDefault(); first.focus(); }}
if(document.readyState==='loading') document.addEventListener('DOMContentLoaded', mount); else mount();
})();