(function(){
var ROOT='cmpad6ad9b9-6e5d-410a-b208-3f619e0fd973';
var root=document.getElementById(ROOT);
if(!root||root.getAttribute('data-fx-init')==='1')return;
root.setAttribute('data-fx-init','1');
var API='/api/data?tableId=3f82414a-872c-4da7-8376-55f67d236550';
var KEY='fxp_catalog_cart_v1';
var PER=24, PRICE=45000;
/* боевая форма заказа Битрикс24: тот же снипет, что стоит на страницах проектов */
var B24_FORM='inline/145/8751iq';
var B24_LOADER='https://cdn-ru.bitrix24.ru/b21036460/crm/form/loader_145.js';
/* состав заказа уезжает в CRM параметрами URL (у формы 145 скрытых полей нет — их читает trace.url) */
var B24_PARAMS=['nomerproektaizbran','nomerproektazakaz','sostavproekta','utm'];
var INIT_UTM=new URLSearchParams(location.search).get('utm')||'';
var $=function(id){return root.querySelector('#'+id);};
var CATP={cat0:'type',cat3:'floors',cat1:'style',cat2:'wall',cat5:'tech',cat4:'roof',
cat17:'rooft',cat16:'size',cat6:'garage',cat7:'terrace',cat8:'balcony',
cat9:'sauna',cat10:'base',cat11:'attic',cat12:'light',cat13:'pool',
cat14:'gym',cat15:'video'};
var NUMP={filter0:'area',filter3:'bed',filter4:'bath',filter5:'len',
filter6:'wid',filter7:'barea',filter8:'park',filter9:'rate'};
var FEATS=['cat6','cat7','cat8','cat9','cat10','cat11','cat12','cat13','cat14','cat15'];
var GROUPS=[
{k:'g0',t:'Тип объекта', open:true, items:[{s:'cat0',ui:'chips'}]},
{k:'g1',t:'Этажность', open:true, items:[{s:'cat3',ui:'chips'}]},
{k:'g2',t:'Площадь', open:true, items:[{s:'filter0',ui:'range',step:1,dec:0}]},
{k:'g3',t:'Комнаты', open:false, items:[{s:'filter3',ui:'range',step:1,dec:0},{s:'filter4',ui:'range',step:1,dec:0}]},
{k:'g4',t:'Габариты пятна',open:false,items:[{s:'filter5',ui:'range',step:.5,dec:1},{s:'filter6',ui:'range',step:.5,dec:1},{s:'cat16',ui:'list',lim:10}]},
{k:'g5',t:'Материал и технология',open:false,items:[{s:'cat2',ui:'list'},{s:'cat5',ui:'list'}]},
{k:'g6',t:'Архитектура', open:false, items:[{s:'cat1',ui:'list'},{s:'cat4',ui:'list'},{s:'cat17',ui:'list'}]},
{k:'g7',t:'Оснащение', open:true, items:[{s:'__feats',ui:'feats'}]},
{k:'g8',t:'Дополнительно',open:false,items:[{s:'filter7',ui:'range',step:5,dec:0},{s:'filter8',ui:'range',step:1,dec:0},{s:'filter9',ui:'range',step:1,dec:0}]}
];
var SORTS={'area-desc':['filter0','DESC'],'area-asc':['filter0','ASC'],'bed-desc':['filter3','DESC'],
'bath-desc':['filter4','DESC'],'rate-desc':['filter9','DESC'],'name-asc':['text0','ASC'],'sku-asc':['text1','ASC']};
var LIST_F='id text0 text1 text3 text5 filter0 filter2 filter3 filter4 images0 images1 cat0';
var FULL_F='id text0 text1 text2 text3 text4 text5 text6 text7 text8 text9 text12 text13 text15 '+
'html0 images0 images1 cat0 cat1 cat2 cat3 cat4 cat5 cat6 cat7 cat8 cat9 cat10 cat11 cat12 cat13 cat14 cat15 cat16 cat17 '+
'filter0 filter2 filter3 filter4 filter5 filter6 filter7 filter8 filter9';
var FACET_Q='facets{slot label type unit values{value count} range{min max}}';
var S={q:'',cats:{},nums:{},sort:'',page:1,open:'',cart:false};
var BOUNDS={},LABELS={},UNITS={},OPTS={},LIVE={},LIVER={},OPEN={},SHOWALL={},CACHE={};
var liveOn=false; /* снимок фасетов под текущие фильтры получен */
var ready=false,busy=false,lastKey='',modalItem=null,gal=[],galIdx=0;
var B24V={}; /* уже введённые значения полей боевой формы — переносим между открытиями */
function esc(v){return String(v==null?'':v).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');}
function money(n){return (Number(n)||0).toLocaleString('ru-RU')+' ₽';}
function nfmt(v,d){if(v==null||v==='')return '';var n=Number(v);if(!isFinite(n))return '';return d?n.toFixed(d).replace(/\.?0+$/,''):String(Math.round(n));}
function img(p,w){return p?(p+'&scale='+w):'';}
function first(a){return (a&&a.length)?a[0]:'';}
function plural(n,a,b,c){var m=n%100;if(m>=11&&m<=14)return c;m=n%10;return m===1?a:(m>=2&&m<=4?b:c);}
function floorName(i,n){return n===1?'Планировка':(i===0?'1-й этаж':(i===1?'2-й этаж':(i+1)+'-й этаж'));}
function gql(q,vars){
return fetch(API,{method:'POST',headers:{'Content-Type':'application/json'},
body:JSON.stringify({query:q,variables:vars||{}})})
.then(function(r){return r.json();})
.then(function(d){if(d.errors)throw new Error((d.errors[0]&&d.errors[0].message)||'GraphQL error');return d.data;});
}
function readUrl(){
var p=new URLSearchParams(location.search);
S.q=p.get('q')||''; S.cats={}; S.nums={};
Object.keys(CATP).forEach(function(s){
var v=p.get(CATP[s]);
if(v){var a=v.split(',').map(function(x){return x.trim();}).filter(Boolean); if(a.length)S.cats[s]=a;}
});
Object.keys(NUMP).forEach(function(s){
var v=p.get(NUMP[s]); if(!v)return;
var m=v.split('~'),o={};
if(m[0]&&isFinite(Number(m[0])))o.gte=Number(m[0]);
if(m[1]&&isFinite(Number(m[1])))o.lte=Number(m[1]);
if(o.gte!=null||o.lte!=null)S.nums[s]=o;
});
S.sort=SORTS[p.get('sort')]?p.get('sort'):'';
S.page=Math.max(1,parseInt(p.get('page'),10)||1);
S.open=p.get('p')||'';
S.cart=p.get('cart')==='1';
}
function buildUrl(){
var p=new URLSearchParams(), mine={q:1,sort:1,page:1,p:1,cart:1};
Object.keys(CATP).forEach(function(s){mine[CATP[s]]=1;});
Object.keys(NUMP).forEach(function(s){mine[NUMP[s]]=1;});
B24_PARAMS.forEach(function(k){mine[k]=1;}); /* параметры заказа ставим и снимаем сами */
new URLSearchParams(location.search).forEach(function(v,k){if(!mine[k])p.append(k,v);});
if(S.q)p.set('q',S.q);
Object.keys(CATP).forEach(function(s){var a=S.cats[s];if(a&&a.length)p.set(CATP[s],a.join(','));});
Object.keys(NUMP).forEach(function(s){var o=S.nums[s];if(o)p.set(NUMP[s],(o.gte!=null?o.gte:'')+'~'+(o.lte!=null?o.lte:''));});
if(S.sort)p.set('sort',S.sort);
if(S.page>1)p.set('page',String(S.page));
if(S.open)p.set('p',S.open);
if(S.cart){
p.set('cart','1');
var sku=orderSkus(), comp=orderComposition();
if(sku){p.set('nomerproektaizbran',sku);p.set('nomerproektazakaz',sku);}
if(comp)p.set('sostavproekta',comp);
p.set('utm',utmVal());
}else if(INIT_UTM){
p.set('utm',INIT_UTM); /* пришедшую с рекламы метку не съедаем */
}
var qs=p.toString();
return location.pathname+(qs?'?'+qs:'')+location.hash;
}
/* ── состав заказа для передачи в Битрикс24 ─────────────
Форма 145 скрытых полей не имеет: и артикулы, и состав доезжают в CRM
внутри trace.url — полным адресом страницы, с которой ушёл сабмит. */
function plainTxt(s){return String(s==null?'':s).replace(/[\u00a0\u202f\u2009]/g,' ');}
function utmVal(){
try{
return localStorage.getItem('nooverride_referrer')||localStorage.getItem('utm_nooverride')||INIT_UTM||'site';
}catch(e){return INIT_UTM||'site';}
}
function orderSkus(){
return cartList().map(function(i){return i.sku;}).filter(Boolean).join(',');
}
function orderComposition(){
var list=cartList(); if(!list.length)return '';
var s=list.map(function(i){
return plainTxt(i.sku)+' x'+(i.qty||1)+' - '+plainTxt(money((i.qty||1)*PRICE));
}).join('; ');
if(s.length>1200)s=s.slice(0,1197)+'...';
var n=cartQty();
return s+' | ИТОГО: '+n+' '+plural(n,'проект','проекта','проектов')+' - '+plainTxt(money(cartSum()));
}
function push(replace){
var u=buildUrl();
if(u===location.pathname+location.search+location.hash)return;
try{history[replace?'replaceState':'pushState']({fx:1},'',u);}catch(e){}
}
function where(){
var w={};
Object.keys(S.cats).forEach(function(s){if(S.cats[s].length)w[s]=S.cats[s].slice();});
Object.keys(S.nums).forEach(function(s){
var o=S.nums[s],b=BOUNDS[s]||{},r={};
if(o.gte!=null&&(b.min==null||o.gte>b.min))r.gte=o.gte;
if(o.lte!=null&&(b.max==null||o.lte<b.max))r.lte=o.lte;
if(r.gte!=null||r.lte!=null)w[s]=r;
});
return w;
}
function activeCount(){
var n=0;
Object.keys(S.cats).forEach(function(s){n+=S.cats[s].length;});
Object.keys(S.nums).forEach(function(s){
var o=S.nums[s],b=BOUNDS[s]||{};
if((o.gte!=null&&(b.min==null||o.gte>b.min))||(o.lte!=null&&(b.max==null||o.lte<b.max)))n++;
});
if(S.q)n++;
return n;
}
var CHK='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3.4"><path d="M5 13l4 4L19 7" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
var CHEV='<svg class="fx-chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
var X='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M5 5l14 14M19 5L5 19" stroke-linecap="round"></path></svg>';
/* ── доступность значений ───────────────────────────────────────────
Значение с нулём под текущими фильтрами кликнуть нельзя: клик по нему
заведомо даёт пустую выдачу. Пока снимок фасетов не получен (до первой
загрузки) возвращаем null — тогда рисуются общие числа каталога.
Когда снимок есть, ОТСУТСТВИЕ фасета в ответе означает «значений нет»:
при total=0 платформа отдаёт facets:[], и без этого весь фильтр
оставался кликабельным со старыми числами. */
function liveCount(slot,val){
if(!liveOn)return null;
var f=LIVE[slot]; if(!f)return 0;
for(var i=0;i<f.length;i++)if(f[i].value===val)return f[i].count;
return 0;
}
function isOn(slot,val){return (S.cats[slot]||[]).indexOf(val)>=0;}
/* значение доступно, если оно что-то даёт или уже выбрано (иначе его не снять) */
function usable(slot,val){var c=liveCount(slot,val);return c==null||c>0||isOn(slot,val);}
function catDead(slot){
return !(OPTS[slot]||[]).some(function(v){return usable(slot,v.value);});
}
function numDead(s){
if(!liveOn||S.nums[s])return false;
var r=LIVER[s];
return !r||r.min==null||r.max==null;
}
function noneHtml(label){
return '<div class="fx-none">'+(label?'<div class="fx-sub">'+esc(label)+'</div>':'')+
'Под выбранные условия значений нет</div>';
}
function grpActive(g){
var n=0;
g.items.forEach(function(i){
if(i.s==='__feats'){FEATS.forEach(function(s){n+=(S.cats[s]||[]).length;});return;}
if(i.ui==='range'){
var o=S.nums[i.s],b=BOUNDS[i.s]||{};
if(o&&((o.gte!=null&&(b.min==null||o.gte>b.min))||(o.lte!=null&&(b.max==null||o.lte<b.max))))n++;
return;
}
n+=(S.cats[i.s]||[]).length;
});
return n;
}
function chipsHtml(slot){
if(catDead(slot))return noneHtml(LABELS[slot]);
var out='<div class="fx-chips">';
(OPTS[slot]||[]).forEach(function(v){
var c=liveCount(slot,v.value),on=isOn(slot,v.value),dis=!usable(slot,v.value);
out+='<button type="button" class="fx-chip'+(on?' on':'')+(dis?' dis':'')+'" data-cat="'+esc(slot)+'" data-val="'+esc(v.value)+'"'+
(dis?' disabled aria-disabled="true" title="Нет проектов с этим значением при текущих фильтрах"':'')+'>'+
esc(v.value)+'<i>'+(c==null?v.count:c)+'</i></button>';
});
return out+'</div>';
}
function listHtml(slot,lim){
if(catDead(slot))return noneHtml(LABELS[slot]||slot);
var all=SHOWALL[slot];
/* доступные вперёд: иначе под фильтром первые lim строк — сплошные нули,
а живые значения оказываются спрятаны за «Показать все» */
var vals=(OPTS[slot]||[]).slice().sort(function(a,b){
var ua=usable(slot,a.value)?1:0, ub=usable(slot,b.value)?1:0;
if(ua!==ub)return ub-ua;
var ca=liveCount(slot,a.value), cb=liveCount(slot,b.value);
if(ca==null||cb==null)return 0;
return cb-ca;
});
var out='';
if(vals.length>1)out+='<div class="fx-sub">'+esc(LABELS[slot]||slot)+'</div>';
vals.forEach(function(v,i){
var c=liveCount(slot,v.value),on=isOn(slot,v.value),dis=!usable(slot,v.value);
var hid=lim&&!all&&i>=lim&&!on;
out+='<label class="fx-opt'+(dis?' dis':'')+(hid?' hid':'')+'"'+
(dis?' title="Нет проектов с этим значением при текущих фильтрах"':'')+'>'+
'<input type="checkbox" data-cat="'+esc(slot)+'" data-val="'+esc(v.value)+'"'+(on?' checked':'')+(dis?' disabled':'')+'>'+
'<span class="fx-box">'+CHK+'</span><span class="fx-opt-t">'+esc(v.value)+'</span>'+
'<span class="fx-opt-n">'+(c==null?v.count:c)+'</span></label>';
});
if(lim&&vals.length>lim)
out+='<button type="button" class="fx-more-b" data-all="'+esc(slot)+'">'+(all?'Свернуть':'Показать все ('+vals.length+')')+'</button>';
return out;
}
function featsHtml(){
var live=FEATS.filter(function(s){var v=(OPTS[s]||[])[0];return v&&usable(s,v.value);});
if(!live.length)return noneHtml('');
var out='<div class="fx-chips">';
FEATS.forEach(function(s){
var v=(OPTS[s]||[])[0]; if(!v)return;
var c=liveCount(s,v.value),on=isOn(s,v.value),dis=!usable(s,v.value);
out+='<button type="button" class="fx-chip'+(on?' on':'')+(dis?' dis':'')+'" data-cat="'+esc(s)+'" data-val="'+esc(v.value)+'"'+
(dis?' disabled aria-disabled="true" title="Нет проектов с этим признаком при текущих фильтрах"':'')+'>'+
esc(v.value)+'<i>'+(c==null?v.count:c)+'</i></button>';
});
return out+'</div>';
}
function rangeHtml(it){
var s=it.s;
if(numDead(s))return noneHtml((LABELS[s]||s)+(UNITS[s]?', '+UNITS[s]:''));
var b=BOUNDS[s]||{min:0,max:100},o=S.nums[s]||{};
var lo=o.gte!=null?o.gte:b.min, hi=o.lte!=null?o.lte:b.max;
return '<div class="fx-rng" data-rng="'+esc(s)+'" data-min="'+b.min+'" data-max="'+b.max+'" data-dec="'+it.dec+'">'+
'<div class="fx-sub">'+esc(LABELS[s]||s)+(UNITS[s]?', '+esc(UNITS[s]):'')+'</div>'+
'<div class="fx-rng-in">'+
'<label><span>от</span><input type="number" data-k="lo" value="'+nfmt(lo,it.dec)+'" min="'+b.min+'" max="'+b.max+'" step="'+it.step+'" inputmode="decimal"></label>'+
'<label><span>до</span><input type="number" data-k="hi" value="'+nfmt(hi,it.dec)+'" min="'+b.min+'" max="'+b.max+'" step="'+it.step+'" inputmode="decimal"></label>'+
'</div>'+
'<div class="fx-sl"><div class="fx-sl-track"></div><div class="fx-sl-fill"></div>'+
'<input type="range" data-k="lo" min="'+b.min+'" max="'+b.max+'" step="'+it.step+'" value="'+lo+'" aria-label="'+esc(LABELS[s])+' от">'+
'<input type="range" data-k="hi" min="'+b.min+'" max="'+b.max+'" step="'+it.step+'" value="'+hi+'" aria-label="'+esc(LABELS[s])+' до">'+
'</div></div>';
}
function paintFill(box){
var mn=+box.getAttribute('data-min'),mx=+box.getAttribute('data-max');
var rs=box.querySelectorAll('.fx-sl input'),f=box.querySelector('.fx-sl-fill');
var lo=+rs[0].value,hi=+rs[1].value,d=(mx-mn)||1;
f.style.left='calc('+((lo-mn)/d*100)+'% - 8px)';
f.style.width=((hi-lo)/d*100)+'%';
}
function renderFilters(){
var h='';
GROUPS.forEach(function(g){
var n=grpActive(g),body='';
g.items.forEach(function(i){
if(i.ui==='chips')body+=chipsHtml(i.s);
else if(i.ui==='list')body+=listHtml(i.s,i.lim);
else if(i.ui==='feats')body+=featsHtml();
else if(i.ui==='range')body+=rangeHtml(i);
});
/* в группе не осталось ни одного доступного элемента — гасим её целиком
и не раскрываем сами, но открыть и прочитать причину человек может */
var dead=body.indexOf('class="fx-chips"')<0&&body.indexOf('class="fx-opt')<0&&body.indexOf('class="fx-rng"')<0;
var open=OPEN[g.k]!=null?OPEN[g.k]:(dead?false:g.open);
h+='<div class="fx-grp'+(open?' open':'')+(dead?' dead':'')+'" data-g="'+g.k+'">'+
'<button type="button" class="fx-grp-t"><span>'+esc(g.t)+'</span>'+
(n?'<span class="fx-cnt">'+n+'</span>':(dead?'<span class="fx-nil">нет значений</span>':''))+CHEV+'</button>'+
'<div class="fx-grp-b">'+body+'</div></div>';
});
$('fx-filters').innerHTML=h;
root.querySelectorAll('.fx-rng').forEach(paintFill);
var ac=activeCount();
$('fx-reset').disabled=!ac;
var fb=$('fx-fbtn-n'); fb.textContent=ac; fb.style.display=ac?'inline-flex':'none';
}
function renderActive(){
var h='';
if(S.q)h+='<span class="fx-pill">Поиск: <b>'+esc(S.q)+'</b><button type="button" data-drop="q" aria-label="Сбросить поиск">'+X+'</button></span>';
Object.keys(CATP).forEach(function(s){
(S.cats[s]||[]).forEach(function(v){
h+='<span class="fx-pill">'+esc(v)+'<button type="button" data-drop="cat" data-s="'+esc(s)+'" data-v="'+esc(v)+'" aria-label="Убрать фильтр">'+X+'</button></span>';
});
});
Object.keys(NUMP).forEach(function(s){
var o=S.nums[s],b=BOUNDS[s]||{}; if(!o)return;
var lo=o.gte!=null&&(b.min==null||o.gte>b.min),hi=o.lte!=null&&(b.max==null||o.lte<b.max);
if(!lo&&!hi)return;
h+='<span class="fx-pill">'+esc((LABELS[s]||s)+': '+(lo?nfmt(o.gte,1):'—')+'–'+(hi?nfmt(o.lte,1):'—')+(UNITS[s]?' '+UNITS[s]:''))+
'<button type="button" data-drop="num" data-s="'+esc(s)+'" aria-label="Убрать фильтр">'+X+'</button></span>';
});
if(h)h+='<button type="button" class="fx-pill clr" data-drop="all">Сбросить всё</button>';
$('fx-active').innerHTML=h;
}
var ICO_CART='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><path d="M3 4h2l2.2 10.4A2 2 0 0 0 9.2 16h7.9a2 2 0 0 0 2-1.6L20.5 7H6" stroke-linecap="round" stroke-linejoin="round"></path><circle cx="10" cy="20" r="1.4"></circle><circle cx="18" cy="20" r="1.4"></circle></svg>';
var ICO_OK='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M5 13l4 4L19 7" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
function cardHtml(n,idx){
var shot=first(n.images0), plans=n.images1||[], inc=!!cartRead().items[n.id];
var eager=idx<3;
var pl='';
if(plans.length){
pl=plans.slice(0,3).map(function(p,i){
return '<button type="button" class="fx-plan" data-open="'+esc(n.id)+'" title="'+esc(floorName(i,plans.length))+'">'+
'<img src="'+esc(img(p,190))+'" alt="'+esc(floorName(i,plans.length))+'" loading="lazy" decoding="async" width="70" height="52"></button>';
}).join('')+'<span class="fx-plan-lbl"><b>'+plans.length+'</b>'+(plans.length===1?'планировка':'планировки')+'</span>';
} else {
pl='<span class="fx-plan-none">Планировка уточняется</span>';
}
return '<article class="fx-card">'+
'<button type="button" class="fx-shot" data-open="'+esc(n.id)+'" aria-label="Открыть проект '+esc(n.text1)+'">'+
(shot?'<img src="'+esc(img(shot,620))+'" alt="'+esc(n.text0)+'" width="620" height="349" '+(eager?'fetchpriority="high"':'loading="lazy"')+' decoding="async">':'')+
'<span class="fx-sku">'+esc(n.text1)+'</span><span class="fx-type">'+esc(first(n.cat0))+'</span>'+
'</button>'+
'<div class="fx-plans">'+pl+'</div>'+
'<div class="fx-card-b">'+
'<button type="button" class="fx-card-h" data-open="'+esc(n.id)+'">'+esc(n.text0)+'</button>'+
'<div class="fx-specs">'+
'<div class="fx-spec"><b>'+nfmt(n.filter0,0)+'</b><span>м²</span></div>'+
'<div class="fx-spec"><b>'+nfmt(n.filter2,1)+'</b><span>этаж</span></div>'+
'<div class="fx-spec"><b>'+(n.filter3!=null?nfmt(n.filter3,0):'—')+'</b><span>спал.</span></div>'+
'<div class="fx-spec"><b>'+(n.filter4!=null?nfmt(n.filter4,0):'—')+'</b><span>с/у</span></div>'+
'</div>'+
'<div class="fx-card-f">'+
'<span class="fx-price"><b>'+esc(n.text3)+'</b><span>'+esc(n.text5)+'</span></span>'+
'<button type="button" class="fx-more" data-open="'+esc(n.id)+'" aria-label="Подробнее"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"></circle><path d="M12 11v5M12 8h.01" stroke-linecap="round"></path></svg></button>'+
'<button type="button" class="fx-add'+(inc?' in':'')+'" data-add="'+esc(n.id)+'">'+(inc?ICO_OK+'В корзине':ICO_CART+'В корзину')+'</button>'+
'</div>'+
'</div></article>';
}
var SK='<div class="fx-sk"><div class="fx-sk-shot"></div><div class="fx-sk-plans"><i></i><i></i></div>'+
'<div class="fx-sk-b"><div class="fx-sk-l"></div><div class="fx-sk-l w70"></div>'+
'<div class="fx-sk-sp"></div><div class="fx-sk-f"></div></div></div>';
function skeleton(){
var h=''; for(var i=0;i<PER;i++)h+=SK;
$('fx-grid').innerHTML=h;
}
function pager(total){
var pages=Math.max(1,Math.ceil(total/PER));
if(pages<2){$('fx-pager').innerHTML='';return;}
var cur=Math.min(S.page,pages),list=[],i;
for(i=1;i<=pages;i++)if(i===1||i===pages||Math.abs(i-cur)<=1)list.push(i);
var h='<button type="button" class="fx-pg" data-pg="'+(cur-1)+'"'+(cur<=1?' disabled':'')+' aria-label="Назад"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M15 5l-7 7 7 7" stroke-linecap="round" stroke-linejoin="round"></path></svg></button>';
var prev=0;
list.forEach(function(p){
if(prev&&p-prev>1)h+='<span class="fx-dots">…</span>';
h+='<button type="button" class="fx-pg'+(p===cur?' on':'')+'" data-pg="'+p+'">'+p+'</button>'; prev=p;
});
h+='<button type="button" class="fx-pg" data-pg="'+(cur+1)+'"'+(cur>=pages?' disabled':'')+' aria-label="Вперёд"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M9 5l7 7-7 7" stroke-linecap="round" stroke-linejoin="round"></path></svg></button>';
$('fx-pager').innerHTML=h;
}
function scrollToGrid(){
var g=$('fx-grid'); if(!g)return;
var y=g.getBoundingClientRect().top+window.pageYOffset-14;
if(window.pageYOffset>y)window.scrollTo(0,Math.max(0,y));
}
function skuIds(q){
var m=/^\s*[Ff]\s*-?\s*(\d{1,6})([A-Za-z])?\s*$/.exec(q||'');
if(!m)return null;
var d=String(m[1]).replace(/^0+/,'')||'0',sfx=m[2]?m[2].toLowerCase():'';
var out=[],seen={};
[d.length,4,5].forEach(function(wd){
var s=d; while(s.length<wd)s='0'+s;
var id='F-'+s+sfx; if(!seen[id]){seen[id]=1;out.push(id);}
});
return out;
}
function absorbFacets(fs){
(fs||[]).forEach(function(f){
LABELS[f.slot]=f.label; UNITS[f.slot]=f.unit||'';
if(f.type==='number'&&f.range)BOUNDS[f.slot]={min:f.range.min,max:f.range.max};
if(f.values&&f.values.length)OPTS[f.slot]=f.values.slice();
});
}
function load(opt){
opt=opt||{};
var w=where(),st=SORTS[S.sort];
var ids=opt.plain?null:skuIds(S.q);
if(ids)w.id=ids;
var vars={w:Object.keys(w).length?w:null,s:ids?null:(S.q||null),o:(S.page-1)*PER,l:PER};
if(st)vars.so={slot:st[0],dir:st[1]};
var q='query($w:Where,$s:String,$o:Int,$l:Int'+(st?',$so:Sort':'')+'){items(where:$w,search:$s,offset:$o,limit:$l'+
(st?',sort:$so':'')+'){total nodes{'+LIST_F+'} '+FACET_Q+'}}';
var key=JSON.stringify(vars);
if(key===lastKey&&!busy&&ready)return Promise.resolve();
lastKey=key; busy=true;
if(!opt.silent)skeleton();
var need=(!ready||!Object.keys(OPTS).length)&&(Object.keys(w).length>0||!!vars.s);
var jobs=[gql(q,vars)];
if(need)jobs.push(gql('{items(limit:0){'+FACET_Q+'}}'));
return Promise.all(jobs).then(function(res){
var it=res[0].items;
var tot=it.total||0;
if(ids&&!tot){busy=false;lastKey='';return load({plain:true,scroll:opt.scroll});}
if(!ready||!Object.keys(OPTS).length){absorbFacets(need?res[1].items.facets:it.facets); ready=true;}
LIVE={}; LIVER={};
(it.facets||[]).forEach(function(f){
if(f.values)LIVE[f.slot]=f.values;
if(f.range)LIVER[f.slot]=f.range;
});
liveOn=true; /* дальше отсутствие фасета в ответе означает «значений нет», а не «неизвестно» */
$('fx-total').textContent=tot.toLocaleString('ru-RU');
$('fx-total-w').textContent=plural(tot,'проект','проекта','проектов');
if(!tot){
$('fx-grid').innerHTML='<div class="fx-empty" style="grid-column:1/-1"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.4"><circle cx="11" cy="11" r="7"></circle><path d="M20 20l-4-4" stroke-linecap="round"></path></svg><h3>Ничего не нашлось</h3><p>Под выбранные условия не подходит ни один проект. Ослабьте фильтры или сбросьте их полностью.</p><button type="button" data-drop="all">Сбросить все фильтры</button></div>';
$('fx-pager').innerHTML='';
}else{
$('fx-grid').innerHTML=(it.nodes||[]).map(cardHtml).join('');
pager(tot);
}
renderFilters(); renderActive();
if(opt.scroll)scrollToGrid();
}).catch(function(e){
$('fx-grid').innerHTML='<div class="fx-empty" style="grid-column:1/-1"><h3>Данные не загрузились</h3><p>'+esc(e.message)+'</p><button type="button" id="fx-retry">Повторить</button></div>';
var b=root.querySelector('#fx-retry'); if(b)b.addEventListener('click',function(){lastKey='';load();});
}).then(function(){busy=false;});
}
function cartRead(){
try{var r=localStorage.getItem(KEY); if(!r)return {items:{}};
var c=JSON.parse(r);
if(!c||typeof c!=='object'||!c.items||typeof c.items!=='object')return {items:{}};
return c;}catch(e){return {items:{}};}
}
function cartWrite(c){try{localStorage.setItem(KEY,JSON.stringify(c));}catch(e){}cartPaint();}
function cartList(){var c=cartRead();return Object.keys(c.items).map(function(k){return c.items[k];});}
function cartQty(){return cartList().reduce(function(s,i){return s+(Number(i.qty)||0);},0);}
function cartSum(){return cartQty()*PRICE;}
function cartAdd(n){
var c=cartRead();
if(c.items[n.id])c.items[n.id].qty=(Number(c.items[n.id].qty)||0)+1;
else c.items[n.id]={id:n.id,sku:n.text1||n.id,name:n.text0||'',type:first(n.cat0)||'',
area:n.filter0!=null?nfmt(n.filter0,0):'',img:first(n.images0)||'',qty:1};
cartWrite(c); toast('«'+(n.text1||n.id)+'» в корзине');
}
function cartSet(id,q){
var c=cartRead(); if(!c.items[id])return;
q=Math.max(0,Math.min(99,q));
if(!q)delete c.items[id]; else c.items[id].qty=q;
cartWrite(c); refreshOrder();
}
function cartPaint(){
var c=cartRead(),n=cartQty();
$('fx-cart-n').textContent=n;
root.querySelectorAll('[data-add]').forEach(function(b){
var inc=!!c.items[b.getAttribute('data-add')];
b.className='fx-add'+(inc?' in':'');
b.innerHTML=inc?(ICO_OK+'В корзине'):(ICO_CART+'В корзину');
});
}
/* ── штатная модалка платформы ───────────────────
Контент уходит событием cbs-show-modal и рендерится ВНЕ этого компонента,
поэтому стили модалки живут отдельным листом с префиксом .fxm-,
а обработчики висят на document и фильтруются по [data-fxm].
Скроллером является контейнер платформы — внутри контента overflow нет. */
var MODAL_CSS=
'.fxm{--k:#0f1e2a;--k2:#3d5566;--mut:#7d8f9c;--ln:#dde5ea;--ln2:#eef2f5;--bl:#0069a8;--am:#ffb900;--gr:#00a63e;'+
'background:#fff;color:var(--k);font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Arial,sans-serif;'+
'font-size:15px;line-height:1.5;text-align:left;width:1120px;max-width:100%}'+
'.fxm.cart{width:620px}.fxm.zoom{width:1280px}'+
'.fxm *{box-sizing:border-box}'+
/* :not([class*="b24-"]) — чтобы наш сброс не съедал оформление боевой формы Битрикса */
'.fxm button:not([class*="b24-"]){font:inherit;color:inherit;cursor:pointer;border:0;background:none}'+
'.fxm input:not([class*="b24-"]),.fxm textarea:not([class*="b24-"]){font:inherit;color:inherit}'+
'.fxm-hd{display:flex;align-items:flex-start;gap:14px;padding:16px 20px;border-bottom:1px solid var(--ln)}'+
'.fxm-hd.dark{background:var(--k);color:#fff;border-bottom:0}'+
'.fxm-hd-t{flex:1 1 auto;min-width:0}'+
'.fxm-x{flex:0 0 34px;width:34px;height:34px;border-radius:50%;background:#eef2f5;color:var(--k2);display:inline-flex;align-items:center;justify-content:center}'+
'.fxm-hd.dark .fxm-x{background:rgba(255,255,255,.14);color:#fff}'+
'.fxm-x:hover{background:var(--k);color:#fff}.fxm-hd.dark .fxm-x:hover{background:rgba(255,255,255,.28)}'+
'.fxm-x svg{width:15px;height:15px}'+
'.fxm-back{display:inline-flex;align-items:center;gap:7px;height:34px;padding:0 13px;border:1px solid var(--ln);border-radius:3px;font-size:12.5px;font-weight:700;color:var(--k2)}'+
'.fxm-back:hover{border-color:var(--k);color:var(--k)}.fxm-back svg{width:14px;height:14px}'+
'.fxm-badges{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:9px}'+
'.fxm-b{padding:4px 9px;border-radius:3px;font-size:10px;font-weight:800;letter-spacing:.06em;text-transform:uppercase}'+
'.fxm-b.t{background:var(--am);color:#26201a}.fxm-b.s{background:#eef3f6;color:var(--k2)}'+
'.fxm-h{margin:0;font-size:19px;line-height:1.3;font-weight:800;letter-spacing:-.015em}'+
'@media(min-width:900px){.fxm-h{font-size:22px}}'+
'.fxm-top{display:grid;grid-template-columns:minmax(0,1fr)}'+
'@media(min-width:900px){.fxm-top{grid-template-columns:minmax(0,1.35fr) minmax(0,1fr)}}'+
'.fxm-gal{min-width:0;background:#f2f5f7}'+
'.fxm-shot{position:relative;aspect-ratio:16/9;background:#fff;width:100%;border:0;padding:0;display:block;cursor:zoom-in}'+
'.fxm-shot img{width:100%;height:100%;object-fit:contain;display:block}'+
'.fxm-shot.cover img{object-fit:cover}'+
'.fxm-tag{position:absolute;left:10px;top:10px;padding:4px 9px;border-radius:3px;background:rgba(11,26,37,.8);color:#fff;font-size:10.5px;font-weight:800;letter-spacing:.06em;text-transform:uppercase}'+
'.fxm-zoomhint{position:absolute;right:10px;bottom:10px;padding:4px 9px;border-radius:3px;background:rgba(255,255,255,.92);color:var(--k2);font-size:11px;font-weight:700;display:inline-flex;align-items:center;gap:5px}'+
'.fxm-zoomhint svg{width:12px;height:12px}'+
'.fxm-nav{position:absolute;top:50%;transform:translateY(-50%);width:36px;height:36px;border-radius:50%;background:rgba(255,255,255,.92);color:var(--k);display:inline-flex;align-items:center;justify-content:center;box-shadow:0 2px 10px rgba(0,0,0,.22)}'+
'.fxm-nav svg{width:16px;height:16px}.fxm-nav.p{left:10px}.fxm-nav.n{right:10px}'+
'.fxm-thumbs{display:flex;flex-wrap:wrap;gap:6px;padding:8px;background:#e9eef2}'+
'.fxm-thumbs button{flex:0 0 auto;width:70px;height:52px;border-radius:3px;overflow:hidden;border:2px solid transparent;background:#fff;opacity:.65;padding:1px}'+
'.fxm-thumbs button.on{border-color:var(--am);opacity:1}.fxm-thumbs button:hover{opacity:1}'+
'.fxm-thumbs img{width:100%;height:100%;object-fit:contain;display:block}'+
'.fxm-thumbs button.cover img{object-fit:cover}'+
'.fxm-side{padding:18px 20px 20px;min-width:0}'+
'@media(min-width:900px){.fxm-side{padding:22px 26px}}'+
'.fxm-sub{margin:9px 0 0;font-size:13.5px;color:var(--k2);line-height:1.55}'+
'.fxm-key{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;margin:15px 0 0;background:var(--ln2);border:1px solid var(--ln2);border-radius:4px;overflow:hidden}'+
'.fxm-key div{background:#fbfcfd;padding:10px 12px}'+
'.fxm-key b{display:block;font-size:16px;font-weight:800;font-variant-numeric:tabular-nums}'+
'.fxm-key span{display:block;margin-top:1px;font-size:10px;letter-spacing:.05em;text-transform:uppercase;color:var(--mut)}'+
'.fxm-tags{display:flex;flex-wrap:wrap;gap:5px;margin-top:12px}'+
'.fxm-tg{padding:3px 7px;border-radius:2px;background:#eef3f6;font-size:11px;font-weight:600;color:var(--k2)}'+
'.fxm-price{display:flex;align-items:flex-end;justify-content:space-between;gap:12px;margin-top:16px;padding:13px 15px;border-radius:4px;background:#f4f7f9;border:1px solid var(--ln)}'+
'.fxm-price b{font-size:24px;font-weight:800;letter-spacing:-.025em;line-height:1;font-variant-numeric:tabular-nums}'+
'.fxm-price span{display:block;font-size:10.5px;color:var(--mut);margin-top:4px}'+
'.fxm-price em{font-style:normal;font-size:11px;color:var(--k2);text-align:right;line-height:1.35}'+
'.fxm-acts{display:flex;gap:8px;margin-top:10px;flex-wrap:wrap}'+
'.fxm-acts .p{flex:1 1 190px;height:46px;border-radius:3px;background:var(--gr);color:#fff;font-size:12.5px;font-weight:800;letter-spacing:.03em;text-transform:uppercase;display:inline-flex;align-items:center;justify-content:center;gap:8px}'+
'.fxm-acts .p:hover{background:#008236}.fxm-acts .p.in{background:var(--k)}.fxm-acts .p svg{width:16px;height:16px}'+
'.fxm-acts .s{height:46px;padding:0 14px;border:1px solid var(--ln);border-radius:3px;display:inline-flex;align-items:center;gap:7px;font-size:12px;font-weight:700;color:var(--k2);text-decoration:none;background:#fff}'+
'.fxm-acts .s:hover{border-color:var(--k);color:var(--k)}.fxm-acts .s svg{width:15px;height:15px}'+
'.fxm-bot{border-top:1px solid var(--ln);padding:0 20px 24px}'+
'@media(min-width:900px){.fxm-bot{padding:0 26px 28px}}'+
'.fxm-tabs{display:flex;flex-wrap:wrap;gap:2px;margin:0 -20px 18px;padding:0 20px;border-bottom:1px solid var(--ln)}'+
'@media(min-width:900px){.fxm-tabs{margin:0 -26px 20px;padding:0 26px}}'+
'.fxm-tab{padding:13px 13px;font-size:13px;font-weight:700;color:var(--mut);border-bottom:2px solid transparent;margin-bottom:-1px}'+
'.fxm-tab.on{color:var(--k);border-color:var(--am)}.fxm-tab:hover{color:var(--k)}'+
'.fxm-pane{display:none}.fxm-pane.on{display:block}'+
'.fxm-dl{display:grid;grid-template-columns:1fr;border:1px solid var(--ln);border-radius:4px;overflow:hidden}'+
'@media(min-width:700px){.fxm-dl{grid-template-columns:1fr 1fr}}'+
'.fxm-dl-r{display:flex;align-items:baseline;justify-content:space-between;gap:14px;padding:9px 13px;border-bottom:1px solid var(--ln2);font-size:13.5px}'+
'@media(min-width:700px){.fxm-dl-r:nth-child(odd){border-right:1px solid var(--ln2)}}'+
'.fxm-dl-r dt{color:var(--mut)}.fxm-dl-r dd{margin:0;font-weight:700;text-align:right;font-variant-numeric:tabular-nums}'+
'.fxm-plans{display:grid;grid-template-columns:1fr;gap:16px}'+
'@media(min-width:760px){.fxm-plans.two{grid-template-columns:1fr 1fr}}'+
'.fxm-plans figure{margin:0;border:1px solid var(--ln);border-radius:4px;overflow:hidden;background:#fff}'+
'.fxm-plans button{display:block;width:100%;padding:0;border:0;background:#fff;cursor:zoom-in}'+
'.fxm-plans img{width:100%;display:block;background:#fff;aspect-ratio:4/3;object-fit:contain}'+
'.fxm-plans figcaption{display:flex;align-items:baseline;justify-content:space-between;gap:10px;padding:9px 13px;border-top:1px solid var(--ln2);font-size:12.5px;font-weight:700}'+
'.fxm-plans figcaption span{font-weight:600;color:var(--mut);font-size:11.5px}'+
'.fxm-expl h4{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin:18px 0 8px;font-size:13.5px;font-weight:800;padding-bottom:6px;border-bottom:2px solid var(--k)}'+
'.fxm-expl h4:first-child{margin-top:0}'+
'.fxm-expl h4 span{font-size:12px;font-weight:700;color:var(--bl);font-variant-numeric:tabular-nums}'+
'.fxm-expl table{width:100%;border-collapse:collapse;font-size:13px}'+
'.fxm-expl th{text-align:left;padding:6px 10px;font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--mut);font-weight:700;background:#f7fafb}'+
'.fxm-expl th:last-child,.fxm-expl td:last-child{text-align:right;font-variant-numeric:tabular-nums;font-weight:700}'+
'.fxm-expl td{padding:7px 10px;border-top:1px solid var(--ln2);color:var(--k2)}'+
'.fxm-zi{display:block;width:100%;background:#fff}'+
'.fxm-zi img{display:block;width:100%;height:auto}'+
'.fxm-body{padding:4px 20px 0}'+
'.fxm-ci{display:flex;gap:11px;padding:13px 0;border-bottom:1px solid var(--ln2)}'+
'.fxm-ci-i{flex:0 0 86px;width:86px;aspect-ratio:16/9;border-radius:3px;overflow:hidden;background:#eef2f5}'+
'.fxm-ci-i img{width:100%;height:100%;object-fit:cover;display:block}'+
'.fxm-ci-b{flex:1 1 auto;min-width:0}'+
'.fxm-ci-s{font-size:10px;font-weight:800;letter-spacing:.06em;color:var(--bl)}'+
'.fxm-ci-n{display:block;margin:2px 0 0;font-size:13px;line-height:1.4;font-weight:600;text-align:left;padding:0;color:var(--k)}'+
'.fxm-ci-n:hover{color:var(--bl)}'+
'.fxm-ci-r{display:flex;align-items:center;gap:9px;margin-top:8px}'+
'.fxm-qty{display:inline-flex;align-items:center;border:1px solid var(--ln);border-radius:3px;overflow:hidden}'+
'.fxm-qty button{width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;color:var(--k2);font-size:15px;line-height:1}'+
'.fxm-qty button:hover{background:#eef2f5;color:var(--k)}'+
'.fxm-qty span{min-width:28px;text-align:center;font-size:13px;font-weight:800;font-variant-numeric:tabular-nums}'+
'.fxm-ci-p{margin-left:auto;font-size:13.5px;font-weight:800;font-variant-numeric:tabular-nums;white-space:nowrap}'+
'.fxm-ci-d{width:28px;height:28px;border-radius:3px;display:inline-flex;align-items:center;justify-content:center;color:var(--mut);flex:0 0 28px}'+
'.fxm-ci-d:hover{background:#fdecec;color:#c0392b}.fxm-ci-d svg{width:13px;height:13px}'+
'.fxm-empty{padding:46px 20px;text-align:center;color:var(--k2)}'+
'.fxm-empty svg{width:40px;height:40px;color:#c8d5de;margin:0 auto}'+
'.fxm-empty h3{margin:12px 0 5px;font-size:16px;font-weight:800;color:var(--k)}'+
'.fxm-empty p{margin:0;font-size:13.5px}'+
'.fxm-foot{border-top:3px solid var(--am);background:#f4f7f9;padding:15px 20px 18px;margin-top:14px}'+
'.fxm-sum{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:13px}'+
'.fxm-sum span{font-size:13px;color:var(--k2);font-weight:600}'+
'.fxm-sum b{font-size:23px;font-weight:800;font-variant-numeric:tabular-nums}'+
'.fxm-sum-n{margin:9px 0 0;font-size:11.5px;line-height:1.45;color:var(--k2)}'+
/* боевая форма Битрикс24 внутри корзины */
'.fxo-form .b24-form-content{padding-top:2px}'+
'.fxo-form .b24-form-wrapper{box-shadow:none;border-radius:0}'+
'.fxo-form .b24-form-header-padding{display:none}'+
'.fxo-form .b24-form-field-layout-section{font-size:15px;font-weight:800;color:var(--k)}'+
/* пустая корзина — форму заказа не показываем */
'.fxm.cart:has(#fxo-empty) .fxo-form{display:none}';
function ensureModalCss(){
if(document.getElementById('fxm-css'))return;
var s=document.createElement('style');
s.id='fxm-css'; s.textContent=MODAL_CSS;
document.head.appendChild(s);
}
var swapping=0;
function showModal(html){
ensureModalCss();
/* при подмене содержимого узел на кадр исчезает — не считаем это закрытием */
swapping=Date.now();
window.dispatchEvent(new CustomEvent('cbs-show-modal',{detail:html}));
}
function hideModal(){
/* штатное закрытие модалки платформы */
document.dispatchEvent(new KeyboardEvent('keydown',{key:'Escape',code:'Escape',keyCode:27,which:27,bubbles:true}));
}
function modalAlive(){return !!document.querySelector('.fxm');}
var ICO_X='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M5 5l14 14M19 5L5 19" stroke-linecap="round"></path></svg>';
var ICO_BACK='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M15 5l-7 7 7 7" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
function specRows(n){
var r=[
['Артикул',n.text1],['Тип объекта',first(n.cat0)],
['Общая площадь',n.filter0!=null?nfmt(n.filter0,2)+' м²':''],
['Площадь застройки',n.filter7!=null?nfmt(n.filter7,2)+' м²':''],
['Габариты (Д×Ш)',n.text5],['Этажность',first(n.cat3)||nfmt(n.filter2,1)],
['Спален',n.filter3!=null?nfmt(n.filter3,0):''],['Санузлов',n.filter4!=null?nfmt(n.filter4,0):''],
['Стиль проекта',first(n.cat1)],['Материал стен',first(n.cat2)],
['Технология',first(n.cat5)],['Тип кровли',first(n.cat17)],
['Форма крыши',n.text7],['Машиноместа',n.text6],
['Габаритная группа',first(n.cat16)],
['Рейтинг проекта',n.filter9!=null?nfmt(n.filter9,0)+' из 3':''],
['Срок изготовления',n.text4]
],o='';
r.forEach(function(p){if(p[1])o+='<div class="fxm-dl-r"><dt>'+esc(p[0])+'</dt><dd>'+esc(p[1])+'</dd></div>';});
return '<dl class="fxm-dl">'+o+'</dl>';
}
function featList(n){
var f=[];
[n.cat6,n.cat7,n.cat8,n.cat9,n.cat10,n.cat11,n.cat12,n.cat13,n.cat14,n.cat15].forEach(function(a){
var v=first(a); if(v)f.push(v);
});
return f;
}
function buildGal(n){
var g=[],plans=n.images1||[],shots=n.images0||[];
shots.forEach(function(p,i){g.push({src:p,kind:'shot',label:i===0?'Общий вид':'Внешний вид '+(i+1)});});
plans.forEach(function(p,i){g.push({src:p,kind:'plan',label:floorName(i,plans.length)});});
return g;
}
function plansPane(n){
var plans=n.images1||[];
if(!plans.length)return '<p style="margin:0;color:#7d8f9c;font-size:14px">Планировка по этому проекту пока не передана в каталог.</p>';
return '<div class="fxm-plans'+(plans.length>1?' two':'')+'">'+plans.map(function(p,i){
return '<figure><button type="button" data-fxm="zoom" data-src="'+esc(p)+'" data-lbl="'+esc(floorName(i,plans.length))+'" aria-label="Увеличить: '+esc(floorName(i,plans.length))+'">'+
'<img src="'+esc(img(p,900))+'" alt="'+esc(floorName(i,plans.length))+'" loading="lazy" decoding="async"></button>'+
'<figcaption>'+esc(floorName(i,plans.length))+'<span>нажмите, чтобы увеличить</span></figcaption></figure>';
}).join('')+'</div>';
}
function itemHtml(n){
gal=buildGal(n); galIdx=0;
var inc=!!cartRead().items[n.id], feats=featList(n), plans=n.images1||[], g0=gal[0]||null;
var galHtml=g0?('<div class="fxm-gal"><button type="button" class="fxm-shot'+(g0.kind==='shot'?' cover':'')+'" data-fxm="zoomcur" id="fxm-shot" aria-label="Увеличить изображение">'+
'<img id="fxm-img" src="'+esc(img(g0.src,1280))+'" alt="'+esc(n.text0)+'" decoding="async">'+
'<span class="fxm-tag" id="fxm-tag">'+esc(g0.label)+'</span>'+
'<span class="fxm-zoomhint"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"></circle><path d="M20 20l-3.5-3.5M11 8v6M8 11h6" stroke-linecap="round"></path></svg>увеличить</span>'+
(gal.length>1?'<span class="fxm-nav p" data-fxm="gal" data-d="-1" role="button" aria-label="Предыдущее"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M15 5l-7 7 7 7" stroke-linecap="round" stroke-linejoin="round"></path></svg></span>'+
'<span class="fxm-nav n" data-fxm="gal" data-d="1" role="button" aria-label="Следующее"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M9 5l7 7-7 7" stroke-linecap="round" stroke-linejoin="round"></path></svg></span>':'')+
'</button>'+
(gal.length>1?'<div class="fxm-thumbs">'+gal.map(function(x,i){
return '<button type="button" class="'+(i===0?'on ':'')+(x.kind==='shot'?'cover':'')+'" data-fxm="gi" data-i="'+i+'" title="'+esc(x.label)+'">'+
'<img src="'+esc(img(x.src,180))+'" alt="" loading="lazy"></button>';}).join('')+'</div>':'')+
'</div>'):'<div class="fxm-gal"></div>';
return '<div class="fxm item">'+
'<div class="fxm-hd"><div class="fxm-hd-t">'+
'<div class="fxm-badges"><span class="fxm-b t">'+esc(first(n.cat0))+'</span><span class="fxm-b s">'+esc(n.text1)+'</span>'+
(first(n.cat3)?'<span class="fxm-b s">'+esc(first(n.cat3))+'</span>':'')+
(first(n.cat2)?'<span class="fxm-b s">'+esc(first(n.cat2))+'</span>':'')+'</div>'+
'<h2 class="fxm-h">'+esc(n.text0)+'</h2></div>'+
'<button type="button" class="fxm-x" data-fxm="close" aria-label="Закрыть">'+ICO_X+'</button></div>'+
'<div class="fxm-top">'+galHtml+
'<div class="fxm-side">'+
(n.text9?'<p class="fxm-sub" style="margin-top:0">'+esc(n.text9)+'</p>':'')+
'<div class="fxm-key">'+
'<div><b>'+nfmt(n.filter0,1)+' м²</b><span>общая площадь</span></div>'+
'<div><b>'+esc(n.text5||'—')+'</b><span>габариты</span></div>'+
'<div><b>'+(n.filter3!=null?nfmt(n.filter3,0):'—')+'</b><span>спален</span></div>'+
'<div><b>'+(n.filter4!=null?nfmt(n.filter4,0):'—')+'</b><span>санузлов</span></div>'+
'</div>'+
(feats.length?'<div class="fxm-tags">'+feats.map(function(t){return '<span class="fxm-tg">'+esc(t)+'</span>';}).join('')+'</div>':'')+
'<div class="fxm-price"><div><b>'+esc(n.text3)+'</b><span>цена фиксированная, не зависит от площади</span></div><em>Срок<br>'+esc(n.text4||'—')+'</em></div>'+
'<div class="fxm-acts">'+
'<button type="button" class="p'+(inc?' in':'')+'" data-fxm="add" data-id="'+esc(n.id)+'">'+(inc?ICO_OK+'<span>Уже в корзине</span>':ICO_CART+'<span>Добавить в корзину</span>')+'</button>'+
(n.text13?'<a class="s" href="https://www.youtube.com/watch?v='+encodeURIComponent(n.text13)+'" target="_blank" rel="noopener"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="5" width="18" height="14" rx="3"></rect><path d="M11 9l4 3-4 3z" fill="currentColor" stroke-linejoin="round"></path></svg>Видеообзор</a>':'')+
(n.text12?'<a class="s" href="'+esc(n.text12)+'" target="_blank" rel="noopener"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 3v5h5M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8l-5-5z" stroke-linecap="round" stroke-linejoin="round"></path></svg>PDF</a>':'')+
'</div>'+
'</div>'+
'</div>'+
'<div class="fxm-bot">'+
'<div class="fxm-tabs">'+
'<button type="button" class="fxm-tab on" data-fxm="tab" data-t="t1">Планировки'+(plans.length?' ('+plans.length+')':'')+'</button>'+
(n.html0?'<button type="button" class="fxm-tab" data-fxm="tab" data-t="t2">Экспликация помещений</button>':'')+
'<button type="button" class="fxm-tab" data-fxm="tab" data-t="t3">Характеристики</button>'+
'</div>'+
'<div class="fxm-pane on" data-pane="t1">'+plansPane(n)+'</div>'+
(n.html0?'<div class="fxm-pane" data-pane="t2"><div class="fxm-expl">'+n.html0+'</div></div>':'')+
'<div class="fxm-pane" data-pane="t3">'+specRows(n)+'</div>'+
'</div></div>';
}
function zoomHtml(src,label){
return '<div class="fxm zoom">'+
'<div class="fxm-hd"><div class="fxm-hd-t">'+
(modalItem?'<button type="button" class="fxm-back" data-fxm="reopen">'+ICO_BACK+'К проекту</button>':'')+
'<h2 class="fxm-h" style="margin-top:8px">'+esc(label||'Изображение')+'</h2></div>'+
'<button type="button" class="fxm-x" data-fxm="close" aria-label="Закрыть">'+ICO_X+'</button></div>'+
'<div class="fxm-zi"><img src="'+esc(img(src,1600))+'" alt="'+esc(label||'')+'"></div></div>';
}
/* ── корзина ─────────────────────────────────────────────
Оболочка (orderHtml) уходит в штатную модалку ОДИН раз за открытие и больше
не пересобирается: внутри неё живёт боевая форма Битрикс24, пересоздавать её
на каждое изменение количества нельзя. Меняющаяся часть — состав и сумма —
рендерится в собственный узел #fxo-in, который мы сами добавляем внутрь
пустого React-узла #fxo-live. React о наших детях не знает и их не трогает,
а мы не трогаем узлы React — поэтому removeChild-падения не происходит. */
function orderBody(){
var list=cartList(),n=cartQty(),body='';
if(!list.length){
body='<div class="fxm-empty" id="fxo-empty"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M3 4h2l2.2 10.4A2 2 0 0 0 9.2 16h7.9a2 2 0 0 0 2-1.6L20.5 7H6" stroke-linecap="round" stroke-linejoin="round"></path><circle cx="10" cy="20" r="1.3"></circle><circle cx="18" cy="20" r="1.3"></circle></svg><h3>Корзина пуста</h3><p>Добавляйте проекты — потом отправите их одной заявкой.</p></div>';
}else{
body='<div class="fxm-body">'+list.map(function(i){
return '<div class="fxm-ci"><div class="fxm-ci-i">'+(i.img?'<img src="'+esc(img(i.img,220))+'" alt="" loading="lazy">':'')+'</div>'+
'<div class="fxm-ci-b"><div class="fxm-ci-s">'+esc(i.sku)+(i.type?' · '+esc(i.type):'')+(i.area?' · '+esc(i.area)+' м²':'')+'</div>'+
'<button type="button" class="fxm-ci-n" data-fxm="open" data-id="'+esc(i.id)+'">'+esc(i.name)+'</button>'+
'<div class="fxm-ci-r"><span class="fxm-qty"><button type="button" data-fxm="qty" data-d="-1" data-id="'+esc(i.id)+'" aria-label="Меньше">−</button><span>'+(i.qty||1)+'</span><button type="button" data-fxm="qty" data-d="1" data-id="'+esc(i.id)+'" aria-label="Больше">+</button></span>'+
'<span class="fxm-ci-p">'+money((i.qty||1)*PRICE)+'</span>'+
'<button type="button" class="fxm-ci-d" data-fxm="del" data-id="'+esc(i.id)+'" aria-label="Убрать"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 7h16M9 7V5h6v2M6 7l1 13h10l1-13" stroke-linecap="round" stroke-linejoin="round"></path></svg></button>'+
'</div></div></div>';
}).join('')+'</div>'+
'<div class="fxm-foot">'+
'<div class="fxm-sum"><span>Итого за '+n+' '+plural(n,'проект','проекта','проектов')+'</span><b>'+money(cartSum())+'</b></div>'+
'<p class="fxm-sum-n">Артикулы выбранных проектов, количество и сумма уходят в заявку вместе с контактами.</p>'+
'</div>';
}
return body;
}
function orderHtml(){
return '<section class="fxm cart">'+
'<div class="fxm-hd dark"><div class="fxm-hd-t"><h2 class="fxm-h" style="color:#fff">Корзина</h2></div>'+
'<button type="button" class="fxm-x" data-fxm="close" aria-label="Закрыть">'+ICO_X+'</button></div>'+
'<div id="fxo-live"></div>'+
'<div class="fxo-form">'+
'<script data-b24-form="'+B24_FORM+'" data-skip-moving="true">'+
'(function(w,d,u){'+
'var s=d.createElement("script");s.async=true;s.src=u+"?"+(Date.now()/180000|0);'+
'var h=d.getElementsByTagName("script")[0];h.parentNode.insertBefore(s,h);'+
'})(window,document,"'+B24_LOADER+'");'+
'<\/script>'+
'</div>'+
'</section>';
}
/* свой узел внутри пустого React-узла: его содержимое принадлежит нам */
function liveHost(){
var box=document.getElementById('fxo-live'); if(!box)return null;
var host=box.querySelector('#fxo-in');
if(!host){host=document.createElement('div');host.id='fxo-in';box.appendChild(host);}
return host;
}
function paintOrder(){
var host=liveHost(); if(!host)return false;
host.innerHTML=orderBody(); return true;
}
function paintOrderSoon(){
var t=0;
(function tick(){ if(paintOrder()||++t>120)return; requestAnimationFrame(tick); })();
}
/* переносим уже введённые контакты в заново смонтированную форму Битрикса */
function b24Restore(){
var t=0;
(function tick(){
var f=document.querySelector('.fxm.cart .b24-form');
if(f){
/* даём Битриксу закончить свой автозаполнитель, только потом возвращаем ввод пользователя */
setTimeout(function(){
var box=document.querySelector('.fxm.cart .b24-form'); if(!box)return;
Object.keys(B24V).forEach(function(k){
var i=box.querySelector('[name="'+k+'"]');
if(!i||!B24V[k]||i.value===B24V[k])return;
i.value=B24V[k];
i.dispatchEvent(new Event('input',{bubbles:true}));
i.dispatchEvent(new Event('change',{bubbles:true}));
});
},500);
return;
}
if(++t>150)return; setTimeout(tick,60);
})();
}
function openItem(id,pushIt){
S.open=id; S.cart=false; if(pushIt!==false)push();
var go=function(n){
if(!n){showModal('<div class="fxm"><div class="fxm-hd"><div class="fxm-hd-t"><h2 class="fxm-h">Проект не найден</h2></div><button type="button" class="fxm-x" data-fxm="close">'+ICO_X+'</button></div><div style="padding:24px 20px;color:#7d8f9c">Артикул '+esc(id)+' отсутствует в каталоге.</div></div>');return;}
modalItem=n; showModal(itemHtml(n));
};
if(CACHE[id])return go(CACHE[id]);
showModal('<div class="fxm"><div style="padding:70px 20px;text-align:center;color:#7d8f9c">Загрузка проекта…</div></div>');
gql('query($w:Where){items(where:$w,limit:1){nodes{'+FULL_F+'}}}',{w:{id:[id]}})
.then(function(d){var n=(d.items.nodes||[])[0]; if(n)CACHE[id]=n; go(n);})
.catch(function(e){showModal('<div class="fxm"><div style="padding:60px 20px;text-align:center"><h3>Не удалось загрузить</h3><p style="color:#7d8f9c">'+esc(e.message)+'</p></div></div>');});
}
function openCart(pushIt){
S.cart=true; S.open='';
push(pushIt===false); /* параметры заказа встают в URL до монтирования формы */
showModal(orderHtml());
paintOrderSoon(); b24Restore();
}
/* изменилось количество — обновляем состав, сумму и параметры URL,
форму Битрикса при этом не трогаем */
function refreshOrder(){
if(!document.querySelector('.fxm.cart'))return;
paintOrder(); push(true);
}
function showGal(i){
if(!gal.length)return;
galIdx=(i+gal.length)%gal.length;
var g=gal[galIdx];
var im=document.getElementById('fxm-img'); if(im)im.src=img(g.src,1280);
var sh=document.getElementById('fxm-shot'); if(sh)sh.className='fxm-shot'+(g.kind==='shot'?' cover':'');
var t=document.getElementById('fxm-tag'); if(t)t.textContent=g.label;
document.querySelectorAll('[data-fxm="gi"]').forEach(function(b){
var k=+b.getAttribute('data-i'), on=k===galIdx;
b.className=(on?'on ':'')+(gal[k].kind==='shot'?'cover':'');
});
}
/* следим за штатным закрытием (фон/Esc), чтобы почистить URL */
var wasAlive=false;
new MutationObserver(function(){
if(modalAlive()){wasAlive=true;return;}
if(!wasAlive||!(S.open||S.cart))return; /* до первого открытия ничего не чистим */
setTimeout(function(){
if(modalAlive()||Date.now()-swapping<500)return;
wasAlive=false;
S.open=''; S.cart=false; modalItem=null; gal=[]; push();
},260);
}).observe(document.body,{childList:true,subtree:true});
/* делегирование: контент модалки лежит вне компонента */
document.addEventListener('click',function(e){
var t=e.target, b=t&&t.closest?t.closest('[data-fxm]'):null;
if(!b)return;
var a=b.getAttribute('data-fxm');
if(a==='close'){e.preventDefault();return hideModal();}
if(a==='gal'){e.preventDefault();e.stopPropagation();return showGal(galIdx+(+b.getAttribute('data-d')));}
if(a==='gi'){e.preventDefault();return showGal(+b.getAttribute('data-i'));}
if(a==='zoom'){e.preventDefault();e.stopPropagation();return showModal(zoomHtml(b.getAttribute('data-src'),b.getAttribute('data-lbl')));}
if(a==='zoomcur'){e.preventDefault();var g=gal[galIdx];if(g)showModal(zoomHtml(g.src,g.label));return;}
if(a==='reopen'){e.preventDefault();if(modalItem)showModal(itemHtml(modalItem));return;}
if(a==='tab'){
e.preventDefault();
var k=b.getAttribute('data-t');
document.querySelectorAll('[data-fxm="tab"]').forEach(function(x){x.className='fxm-tab'+(x===b?' on':'');});
document.querySelectorAll('[data-pane]').forEach(function(x){x.className='fxm-pane'+(x.getAttribute('data-pane')===k?' on':'');});
return;
}
if(a==='add'){
e.preventDefault();
var id=b.getAttribute('data-id');
if(cartRead().items[id])return openCart();
if(modalItem&&modalItem.id===id){cartAdd(modalItem);showModal(itemHtml(modalItem));}
return;
}
if(a==='open'){e.preventDefault();return openItem(b.getAttribute('data-id'));}
if(a==='qty'){
e.preventDefault();
var id2=b.getAttribute('data-id'),c=cartRead();
var cur=c.items[id2]?(Number(c.items[id2].qty)||1):0;
return cartSet(id2,cur+(+b.getAttribute('data-d')));
}
if(a==='del'){e.preventDefault();return cartSet(b.getAttribute('data-id'),0);}
},true);
/* запоминаем контакты, введённые в боевую форму, чтобы вернуть их при повторном открытии */
document.addEventListener('input',function(e){
var t=e.target;
if(!t||!t.name||!t.classList||!t.classList.contains('b24-form-control'))return;
B24V[t.name]=t.value;
},true);
/* мобильная шторка фильтров — единственное место, где прокруткой управляем сами */
function openSheet(){
var b=root.querySelector('.fx-aside-in'); if(b)b.scrollTop=0;
$('fx-aside').classList.add('on'); $('fx-veil').classList.add('on');
if(root.__ov==null)root.__ov=document.body.style.overflow;
document.body.style.overflow='hidden';
}
function closeSheet(){
$('fx-aside').classList.remove('on'); $('fx-veil').classList.remove('on');
document.body.style.overflow=root.__ov||''; root.__ov=null;
}
var toastT;
function toast(t){
$('fx-toast-t').textContent=t; $('fx-toast').classList.add('on');
clearTimeout(toastT); toastT=setTimeout(function(){$('fx-toast').classList.remove('on');},2200);
}
var qT;
$('fx-q').addEventListener('input',function(){
var v=this.value; $('fx-qx').classList[v?'add':'remove']('on');
clearTimeout(qT); qT=setTimeout(function(){S.q=v.trim();S.page=1;push();load();},380);
});
$('fx-qx').addEventListener('click',function(){$('fx-q').value='';this.classList.remove('on');S.q='';S.page=1;push();load();});
$('fx-sort').addEventListener('change',function(){S.sort=SORTS[this.value]?this.value:'';S.page=1;push();load({scroll:true});});
$('fx-reset').addEventListener('click',resetAll);
$('fx-sheet-reset').addEventListener('click',resetAll);
$('fx-sheet-ok').addEventListener('click',closeSheet);
$('fx-sheet-x').addEventListener('click',closeSheet);
$('fx-fbtn').addEventListener('click',openSheet);
$('fx-cart-open').addEventListener('click',function(){openCart();});
$('fx-veil').addEventListener('click',function(){ closeSheet(); });
function resetAll(){
S.q='';S.cats={};S.nums={};S.page=1;
$('fx-q').value='';$('fx-qx').classList.remove('on');
push();load({scroll:true});
}
function toggleCat(slot,val){
var a=(S.cats[slot]||[]).slice(),i=a.indexOf(val);
if(i>=0)a.splice(i,1); else a.push(val);
if(a.length)S.cats[slot]=a; else delete S.cats[slot];
S.page=1;push();load();
}
function commitRange(box,fromNumber){
var s=box.getAttribute('data-rng'),mn=+box.getAttribute('data-min'),mx=+box.getAttribute('data-max');
var rs=box.querySelectorAll('.fx-sl input'),ins=box.querySelectorAll('.fx-rng-in input'),lo,hi;
if(fromNumber){
lo=parseFloat(ins[0].value); hi=parseFloat(ins[1].value);
if(!isFinite(lo))lo=mn; if(!isFinite(hi))hi=mx;
lo=Math.max(mn,Math.min(mx,lo)); hi=Math.max(mn,Math.min(mx,hi));
if(lo>hi){var t=lo;lo=hi;hi=t;}
rs[0].value=lo; rs[1].value=hi;
}else{
lo=+rs[0].value; hi=+rs[1].value;
if(lo>hi){var z=lo;lo=hi;hi=z;rs[0].value=lo;rs[1].value=hi;}
}
var dec=+box.getAttribute('data-dec');
ins[0].value=nfmt(lo,dec); ins[1].value=nfmt(hi,dec); paintFill(box);
if(lo<=mn&&hi>=mx)delete S.nums[s]; else S.nums[s]={gte:lo,lte:hi};
S.page=1;push();load();
}
$('fx-filters').addEventListener('click',function(e){
var t=e.target;
var g=t.closest?t.closest('.fx-grp-t'):null;
if(g){var box=g.parentNode;box.classList.toggle('open');OPEN[box.getAttribute('data-g')]=box.classList.contains('open');return;}
var mb=t.closest?t.closest('[data-all]'):null;
if(mb){var s=mb.getAttribute('data-all');SHOWALL[s]=!SHOWALL[s];renderFilters();return;}
var chip=t.closest?t.closest('.fx-chip'):null;
if(chip&&!chip.disabled)toggleCat(chip.getAttribute('data-cat'),chip.getAttribute('data-val'));
});
$('fx-filters').addEventListener('change',function(e){
var t=e.target;
if(t.type==='checkbox'&&t.getAttribute('data-cat'))return toggleCat(t.getAttribute('data-cat'),t.getAttribute('data-val'));
if(t.type==='range')return commitRange(t.closest('.fx-rng'));
if(t.type==='number'&&t.closest('.fx-rng'))return commitRange(t.closest('.fx-rng'),true);
});
$('fx-filters').addEventListener('input',function(e){
var t=e.target;
if(t.type!=='range')return;
var box=t.closest('.fx-rng'),rs=box.querySelectorAll('.fx-sl input'),k=t.getAttribute('data-k');
var lo=+rs[0].value,hi=+rs[1].value;
if(k==='lo'&&lo>hi){rs[1].value=lo;hi=lo;}
if(k==='hi'&&hi<lo){rs[0].value=hi;lo=hi;}
var dec=+box.getAttribute('data-dec'),ins=box.querySelectorAll('.fx-rng-in input');
ins[0].value=nfmt(lo,dec); ins[1].value=nfmt(hi,dec); paintFill(box);
});
$('fx-active').addEventListener('click',function(e){
var b=e.target.closest?e.target.closest('[data-drop]'):null; if(!b)return;
var d=b.getAttribute('data-drop');
if(d==='all')return resetAll();
if(d==='q'){S.q='';$('fx-q').value='';$('fx-qx').classList.remove('on');}
if(d==='cat'){
var s=b.getAttribute('data-s'),v=b.getAttribute('data-v');
var a=(S.cats[s]||[]).filter(function(x){return x!==v;});
if(a.length)S.cats[s]=a; else delete S.cats[s];
}
if(d==='num')delete S.nums[b.getAttribute('data-s')];
S.page=1;push();load();
});
$('fx-grid').addEventListener('click',function(e){
var t=e.target;
var o=t.closest?t.closest('[data-open]'):null;
if(o)return openItem(o.getAttribute('data-open'));
var a=t.closest?t.closest('[data-add]'):null;
if(a){
var id=a.getAttribute('data-add');
if(cartRead().items[id])return openCart();
if(CACHE[id])return cartAdd(CACHE[id]);
return gql('query($w:Where){items(where:$w,limit:1){nodes{id text0 text1 filter0 images0 cat0}}}',{w:{id:[id]}})
.then(function(d){var n=(d.items.nodes||[])[0]; if(n)cartAdd(n);});
}
var dr=t.closest?t.closest('[data-drop]'):null;
if(dr&&dr.getAttribute('data-drop')==='all')resetAll();
});
$('fx-pager').addEventListener('click',function(e){
var b=e.target.closest?e.target.closest('[data-pg]'):null;
if(!b||b.disabled)return;
S.page=Math.max(1,+b.getAttribute('data-pg'));
push(); load({scroll:true});
});
document.addEventListener('keydown',function(e){
if(e.key==='Escape'&&$('fx-aside').classList.contains('on')&&!modalAlive())return closeSheet();
if(!modalAlive()||!gal.length)return;
if(e.key==='ArrowLeft')showGal(galIdx-1);
if(e.key==='ArrowRight')showGal(galIdx+1);
});
window.addEventListener('popstate',function(){
var po=S.open,pc=S.cart;
readUrl();
$('fx-q').value=S.q; $('fx-qx').classList[S.q?'add':'remove']('on');
$('fx-sort').value=S.sort;
if(S.open!==po||S.cart!==pc){
if(S.open)openItem(S.open,false);
else if(S.cart)openCart(false);
else if(modalAlive())hideModal();
}
load();
});
readUrl();
$('fx-q').value=S.q; $('fx-qx').classList[S.q?'add':'remove']('on');
$('fx-sort').value=S.sort;
cartPaint();
load().then(function(){
if(S.open)openItem(S.open,false);
if(S.cart)openCart(false);
push(true);
});
})();