🧾 MeistarPro Rēķinu ģenerators · bezmaksas

Izveido rēķinu vienā minūtē

Aizpildi laukus pa kreisi — rēķins veidojas tiešraidē pa labi. Lejupielādē kā PDF un nosūti klientam. Bez reģistrācijas, bez maksas.

✨ 100% bez maksas

🎨 Šablona izvēle

🏢 Tava informācija (pārdevējs)

🏦 Bankas rekvizīti (apmaksai)

👤 Klients (pircējs)

📄 Rēķina dati

🧱 Darbi un pakalpojumi

Kods
Apraksts
Daudz.
Mērv.
Cena
Atl.%

💶 PVN

“Apgrieztā PVN” — būvniecības pakalpojumiem starp PVN maksātājiem (142. pants)

📝 Piezīmes

Priekšskatījums Tā izskatīsies PDF
RĒĶINS
Nr. —
Datums: —
Piegādes datums: —
Apmaksāt līdz: —
Tavs uzņēmums
Pārdevējs
Tavs uzņēmums
Pircējs
Klients
Kods Apraksts Daudz. Mērv. Cena Atl.% Summa
Summa bez PVN0,00 €
PVN 21%0,00 €
Kopā apmaksai0,00 €
Apmaksas rekvizīti
Banka: —
IBAN: —
SWIFT: —
Apmaksas veids: —
Summa: 0,00 €
Paldies par sadarbību! Izveidots ar MeistarPro

Vajag vairāk nekā rēķinus? 🚀

MeistarPro ir pilna būvniecības vadības sistēma: projekti, GPS brigāžu uzskaite, materiāli, tāmes un rēķini — vienuviet.

Apskatīt MeistarPro →

Vajag mājaslapu uzņēmumam? 🌐

SiteAI uzbūvē profesionālu mājaslapu dažās minūtēs ar mākslīgo intelektu. Domēns un e-pasts iekļauts.

Izmēģināt SiteAI →

Bezmaksas rēķinu ģenerators online

Bezmaksas rēķinu ģenerators Latvijā

Kas ir šis rīks

Šis ir bezmaksas rēķinu ģenerators, veidots Latvijas mazajiem uzņēmumiem, būvniekiem, amatniekiem un pašnodarbinātajiem. Aizpildi formu pārlūkā — rēķins veidojas tiešraidē blakus — un lejupielādē to PDF formātā. Reģistrācija nav vajadzīga, ūdenszīmju nav, maksas plāna nav.

Rēķins tiek noformēts atbilstoši Grāmatvedības likuma prasībām attaisnojuma dokumentam: numurs un datums, abu pušu rekvizīti, pozīciju saraksts, PVN aprēķins, kopsumma un apmaksas termiņš ar bankas kontu.

Ko ģenerators izdara tavā vietā

  • Aprēķina PVN — standarta 21% likme, variants bez PVN un apgrieztā PVN režīms būvniecībai;
  • uzraksta summu vārdiem latviešu valodā — tieši tā, kā to prasa grāmatvedība;
  • numurē rēķinus pēc kārtas, lai numerācijā nerastos caurumi;
  • saglabā klientu rekvizītus — otro rēķinu tam pašam klientam izrakstīsi 30 sekundēs;
  • rēķina atlaides katrai pozīcijai atsevišķi;
  • izveido PDF ar vienu klikšķi — bez Word un Excel veidnēm.

Kāpēc nevis Word vai Excel veidne

Veidnē katrs rēķins jāpārraksta ar roku: jāmaina numurs, jāpārrēķina PVN, jāizlabo summa vārdiem. Tieši šeit rodas biežākās kļūdas — dublēts rēķina numurs, nesakrītoša PVN summa vai iztrūkstošs PVN reģistrācijas numurs. Ģenerators šos laukus aizpilda un pārbauda pats.

Kam tas paredzēts

Rīku ikdienā izmanto SIA un individuālie komersanti, pašnodarbinātie un mikrouzņēmumu nodokļa maksātāji, kā arī būvnieki, kuriem rēķins seko tāmei un iet pirms pieņemšanas-nodošanas akta. Ārvalstu ģeneratori neņem vērā Latvijas PVN likmes, apgriezto PVN un summu vārdiem latviski — šeit tas viss ir iebūvēts.

Rēķins būvniecībā

Būvdarbu pakalpojumos starp diviem PVN maksātājiem parasti piemēro apgriezto PVN (PVN likuma 142. pants) — nodokli aprēķina un maksā pakalpojuma saņēmējs. Forma šo režīmu atbalsta un pievieno rēķinam nepieciešamo norādi. Tāmi vari sagatavot tāmju ģeneratorā, bet darbu nodošanu noformēt ar pieņemšanas-nodošanas aktu.

📑 Rēķinu veidi un paraugi

Katram rēķina veidam — atsevišķa lapa ar obligātajiem rekvizītiem, piemēriem un biežākajiem jautājumiem.

❓ Biežāk uzdotie jautājumi

Vai rēķinu ģenerators ir bez maksas?

Jā. Rēķina izveide un lejupielāde PDF formātā ir pilnībā bez maksas, bez ūdenszīmēm un bez reģistrācijas.

Vai rēķins atbilst Latvijas likumdošanai?

Rēķinā ir visi obligātie rekvizīti, ko attaisnojuma dokumentam nosaka Grāmatvedības likums, un PVN rēķina rekvizīti pēc PVN likuma.

Vai var izrakstīt rēķinu ar apgriezto PVN būvniecībā?

Jā. Atbalstīts būvniecības pakalpojumu apgrieztās PVN maksāšanas režīms starp PVN maksātājiem (PVN likuma 142. pants).

Kādās valodās var izveidot rēķinu?

Rēķinu var izveidot un lejupielādēt latviešu, krievu un angļu valodā.

Vai mani dati tiek saglabāti?

Rekvizīti pēc noklusējuma paliek tavā pārlūkā. Ja izveido kontu, rēķini un klienti tiek saglabāti, lai tos varētu atkārtot un pārskatīt.

💡 Tavi dati saglabājas šajā pārlūkā līdz nākamajai reizei
'); idoc.close(); await new Promise(res=>{ const go=()=>res(); if(idoc.readyState==='complete') setTimeout(go,90); else iframe.onload=()=>setTimeout(go,90); setTimeout(go,800); }); try{ if(idoc.fonts && idoc.fonts.ready) await idoc.fonts.ready; }catch(e){} const ipaper=idoc.getElementById('paper'); if(ipaper){ ipaper.style.transform='none'; ipaper.style.transformOrigin=''; ipaper.style.margin='0'; } const W=794, H=Math.max(1123, Math.ceil((ipaper&&ipaper.offsetHeight)||1123)); iframe.style.height=H+'px'; try{ const canvas=await html2canvas(ipaper||idoc.body,{ scale:2, useCORS:true, backgroundColor:'#ffffff', width:W, height:H, windowWidth:W, windowHeight:H }); const imgData=canvas.toDataURL('image/jpeg',0.98); const JsPDF=(window.jspdf&&window.jspdf.jsPDF)||window.jsPDF; const pdf=new JsPDF({ unit:'px', format:[W,H], orientation:'portrait', compress:true }); pdf.addImage(imgData,'JPEG',0,0,W,H,undefined,'FAST'); if(mode==='blob') return { blob: pdf.output('blob'), filename }; pdf.save(filename); } finally { iframe.remove(); } } // Scale the fixed 794px invoice down to fit the phone screen in the mobile preview. function fitPreview(){ const scroll=document.querySelector('.paper-scroll'); const paper=document.getElementById('paper'); if(!scroll||!paper) return; // The invoice is a fixed 794px sheet. Scale it to fit the preview column on // BOTH desktop (right column ~600px) and mobile, so nothing is cut off and // there is no sideways scrolling. transform:scale is visual only, so we also // pin the scroll container's box to the available width and clip it. scroll.style.width=''; scroll.style.overflow=''; let avail=(scroll.parentElement&&scroll.parentElement.clientWidth)||scroll.clientWidth||0; if(window.innerWidth<=980){ const vw=document.documentElement.clientWidth||window.innerWidth||360; avail=Math.min(avail||vw, vw-28); // never exceed the phone viewport } if(!avail||avail<2) return; const scale=Math.min(1, avail/794); if(scale<1){ paper.style.transformOrigin='top left'; paper.style.transform='scale('+scale+')'; scroll.style.overflow='hidden'; scroll.style.width=avail+'px'; scroll.style.height=Math.ceil(paper.offsetHeight*scale)+'px'; }else{ paper.style.transform=''; paper.style.transformOrigin=''; scroll.style.height=''; scroll.style.width=''; scroll.style.overflow=''; } } $('#dl').onclick = async function(){ const btn=this; btn.disabled=true; const t=T[lang]; btn.textContent = lang==='ru'?'⏳ Готовим PDF…':lang==='en'?'⏳ Building PDF…':'⏳ Veido PDF…'; try{ await document.fonts.ready; }catch(e){} try{ await buildInvoicePdf('save'); } catch(err){ alert((lang==='ru'?'Ошибка при создании PDF: ':lang==='en'?'PDF error: ':'PDF kļūda: ')+err.message); } btn.disabled=false; btn.innerHTML = t.act_dl; }; /* ============ AUTH + CABINET (Phase 2b) ============ */ const API = '/api'; function authMsg(code){ const t=T[lang]; const map={invalid_email:'e_invalid_email',weak_password:'e_weak_password',email_taken:'e_email_taken',bad_credentials:'e_bad_credentials'}; return t[map[code]] || t.t_err; } async function api(path, opts={}){ const headers = Object.assign({'Content-Type':'application/json'}, opts.headers||{}); if(token) headers.Authorization = 'Bearer '+token; const r = await fetch(API+path, {method:opts.method||'GET', headers, body:opts.body?JSON.stringify(opts.body):undefined}); let data={}; try{ data=await r.json(); }catch(e){} if(r.status===401){ doLogout(true); throw new Error('unauth'); } if(!r.ok) throw new Error(data.error||'error'); return data; } function toast(msg){ const el=$('#toast'); el.textContent=msg; el.classList.add('show'); clearTimeout(el._t); el._t=setTimeout(()=>el.classList.remove('show'),2200); } /* ---- header authbox ---- */ function renderAuthbox(){ const t=T[lang], box=$('#authbox'); if(!box) return; if(token && me){ box.innerHTML = '' + ''+esc(me.user.email)+'' + ''; $('#cabBtn').onclick=openCabinet; $('#logoutBtn').onclick=()=>doLogout(); $('#save').classList.remove('hidden'); } else { box.innerHTML = ''; $('#loginBtn').onclick=()=>openAuth('login'); $('#save').classList.add('hidden'); } const cb=$('#clientbar'); if(cb) cb.classList.toggle('hidden', !(token&&me)); } /* ---- auth modal ---- */ let authMode='login'; function openAuth(mode){ authMode=mode||'login'; $('#authErr').classList.remove('show'); setAuthMode(); $('#authModal').classList.add('open'); $('#au_email').focus(); } function closeAuth(){ $('#authModal').classList.remove('open'); } function setAuthMode(){ const t=T[lang]; $('#authTitle').textContent = authMode==='login'?t.au_login:t.au_register; $('#authSub').textContent = authMode==='login'?t.au_sub_login:t.au_sub_register; $('#authSubmit').textContent= authMode==='login'?t.au_login:t.au_register; $('#authSwitch').innerHTML = authMode==='login' ? ''+t.au_to_register+'' : ''+t.au_to_login+''; const r=$('#auToReg'); if(r) r.onclick=()=>openAuth('register'); const l=$('#auToLog'); if(l) l.onclick=()=>openAuth('login'); } async function submitAuth(){ const email=$('#au_email').value.trim(); const password=$('#au_pass').value; const btn=$('#authSubmit'); btn.disabled=true; try{ const r=await api('/auth/'+authMode,{method:'POST',body:{email,password}}); token=r.token; localStorage.setItem('mp_inv_token',token); $('#au_pass').value=''; closeAuth(); await afterLogin(); toast(T[lang].t_saved); }catch(e){ const err=$('#authErr'); err.textContent=authMsg(e.message); err.classList.add('show'); }finally{ btn.disabled=false; } } async function afterLogin(){ try{ const d=await api('/auth/me'); me=d; if(d.profile) fillProfile(d.profile); } catch(e){ if(e.message==='unauth') return; } renderAuthbox(); if(token) loadClients(); } function doLogout(silent){ token=null; me=null; currentInvoiceId=null; localStorage.removeItem('mp_inv_token'); renderAuthbox(); if(!silent) toast(T[lang].au_logout); } /* ---- profile sync ---- */ function fillProfile(p){ if(!p) return; const set=(id,v)=>{ if(v!=null && v!=='' && $('#'+id)) $('#'+id).value=v; }; set('s_name',p.company_name); set('s_reg',p.reg_no); set('s_vat',p.vat_no); set('s_addr',p.address); set('s_email',p.email); set('s_phone',p.phone); set('b_name',p.bank_name); set('b_iban',p.bank_iban); set('b_swift',p.bank_swift); if(p.default_lang && T[p.default_lang]){ lang=p.default_lang; localStorage.setItem('mp_inv_lang',lang); } if(p.default_template){ tpl=p.default_template; localStorage.setItem('mp_inv_tpl',tpl); } if(p.default_vat_mode){ vatMode=p.default_vat_mode; } $$('#vatsw button').forEach(x=>x.classList.toggle('on',x.dataset.mode===vatMode)); applyTpl(); applyLang(); } function collectProfile(){ const g=id=>($('#'+id)?.value||'').trim(); return { company_name:g('s_name'),reg_no:g('s_reg'),vat_no:g('s_vat'),address:g('s_addr'), email:g('s_email'),phone:g('s_phone'),bank_name:g('b_name'),bank_iban:g('b_iban'),bank_swift:g('b_swift'), default_lang:lang,default_template:tpl,default_vat_mode:vatMode }; } let _profT; function scheduleProfileSave(){ if(!token) return; clearTimeout(_profT); _profT=setTimeout(()=>{ api('/profile',{method:'PUT',body:collectProfile()}).catch(()=>{}); },1200); } /* ---- invoice collect / save / load ---- */ function collectInvoice(){ const g=id=>($('#'+id)?.value||'').trim(); const items=[...$$('.item')].map(it=>{ const code=it.querySelector('.code-i').value.trim(); const qty=parseFloat(it.querySelector('.qty-i').value)||0; const price=parseFloat(it.querySelector('.price-i').value)||0; const discount=parseFloat(it.querySelector('.disc-i').value)||0; return { code, description:it.querySelector('.desc-i').value.trim(), qty, unit:it.querySelector('.unit-i').value.trim(), unit_price:price, discount, line_total:+(qty*price*(1-discount/100)).toFixed(2) }; }).filter(x=>x.description||x.unit_price||x.qty||x.code); const subtotal=items.reduce((a,x)=>a+x.line_total,0); const rate=vatMode==='std'?21:0; const vat_amount=+(subtotal*rate/100).toFixed(2); return { invoice_number:g('i_num'),lang,template:tpl,vat_mode:vatMode,doc_type:($('#i_doctype')?.value)||'invoice',payment_method:g('i_paymethod')||null, issue_date:g('i_date')||null,supply_date:g('i_supply')||null,due_date:g('i_due')||null,currency:'EUR', client_name:g('c_name')||null,client_reg:g('c_reg')||null,client_vat:g('c_vat')||null, client_address:g('c_addr')||null,client_email:g('c_email')||null, subtotal:+subtotal.toFixed(2),vat_rate:rate,vat_amount,total:+(subtotal+vat_amount).toFixed(2), notes:g('i_note')||null,status:'draft',items }; } async function saveInvoice(){ if(!token){ openAuth('login'); return; } const btn=$('#save'); btn.disabled=true; try{ const payload=collectInvoice(); if(currentInvoiceId){ await api('/invoices/'+currentInvoiceId,{method:'PUT',body:payload}); } else { const r=await api('/invoices',{method:'POST',body:payload}); currentInvoiceId=r.id; } api('/profile',{method:'PUT',body:collectProfile()}).catch(()=>{}); const g=id=>($('#'+id)?.value||'').trim(); if(g('c_name')) api('/clients',{method:'POST',body:{name:g('c_name'),reg_no:g('c_reg'),vat_no:g('c_vat'),address:g('c_addr'),email:g('c_email')}}).then(()=>loadClients()).catch(()=>{}); toast(T[lang].t_saved); }catch(e){ toast(T[lang].t_err); } finally{ btn.disabled=false; } } /* ---- cabinet ---- */ function openCabinet(){ $('#cabModal').classList.add('open'); cabTab('inv'); loadList(); loadClients(); } function closeCabinet(){ $('#cabModal').classList.remove('open'); } async function loadList(){ const wrap=$('#invlist'); wrap.innerHTML='
…
'; try{ const {invoices}=await api('/invoices'); let paid=0, totalAll=0; invoices.forEach(i=>{ totalAll+=+i.total||0; if(i.status==='paid') paid+=+i.total||0; }); const st=$('#invstats'); if(st){ st.innerHTML = invoices.length ? '
'+T[lang].cab_paid+'
' +'
'+T[lang].cab_unpaid+''+fmt(totalAll-paid)+'
' +'
'+T[lang].cab_total+''+fmt(totalAll)+'
' : ''; } if(!invoices.length){ wrap.innerHTML='
'+T[lang].cab_empty+'
'; return; } wrap.innerHTML=''; invoices.forEach(inv=>{ const isPaid=inv.status==='paid'; const row=document.createElement('div'); row.className='invrow'; row.innerHTML='
' +'
'+esc(inv.invoice_number||'—')+'
' +'
'+esc(inv.client_name||'')+(inv.issue_date?(' · '+inv.issue_date):'')+'
' +'
'+fmt(+inv.total)+'
' +'
' +'
' +'' +'' +'' +'' +'' +'
'; row.querySelector('.meta').onclick=()=>openInvoice(inv.id); row.querySelector('.badge').onclick=async(e)=>{ e.stopPropagation(); try{ await api('/invoices/'+inv.id+'/status',{method:'PUT',body:{status:isPaid?'unpaid':'paid'}}); loadList(); }catch(err){ toast(T[lang].t_err); } }; row.querySelector('.view').onclick=()=>viewInvoice(inv.id); row.querySelector('.dl').onclick=()=>downloadInvoice(inv.id); row.querySelector('.del').onclick=async()=>{ if(!confirm((inv.invoice_number||'')+' ✕?')) return; try{ await api('/invoices/'+inv.id,{method:'DELETE'}); if(currentInvoiceId===inv.id) currentInvoiceId=null; loadList(); }catch(e){ toast(T[lang].t_err); } }; wrap.appendChild(row); }); }catch(e){ wrap.innerHTML='
'+T[lang].t_err+'
'; } } async function openInvoice(id){ try{ const {invoice,items}=await api('/invoices/'+id); currentInvoiceId=id; const set=(k,v)=>{ if($('#'+k)) $('#'+k).value=v||''; }; set('i_num',invoice.invoice_number); set('i_date',invoice.issue_date); set('i_supply',invoice.supply_date); set('i_due',invoice.due_date); set('c_name',invoice.client_name); set('c_reg',invoice.client_reg); set('c_vat',invoice.client_vat); set('c_addr',invoice.client_address); set('c_email',invoice.client_email); set('i_note',invoice.notes); set('i_paymethod',invoice.payment_method); if($('#i_doctype')) $('#i_doctype').value=invoice.doc_type||'invoice'; vatMode=invoice.vat_mode||'std'; tpl=invoice.template||'classic'; if(invoice.lang&&T[invoice.lang]) lang=invoice.lang; itemsEl.innerHTML=''; (items||[]).forEach(it=>addItem(it.code||'',it.description||'',String(it.qty),it.unit||'',String(it.unit_price),it.discount?String(it.discount):'')); if(!itemsEl.children.length) addItem(); $$('#vatsw button').forEach(x=>x.classList.toggle('on',x.dataset.mode===vatMode)); applyTpl(); applyLang(); closeCabinet(); }catch(e){ toast(T[lang].t_err); } } // Open a saved invoice and show it in preview (a "window with it") async function viewInvoice(id){ await openInvoice(id); if(window.innerWidth<=980){ $$('.mtabs button').forEach(x=>x.classList.toggle('on', x.dataset.tab==='preview')); document.body.className='show-preview'; setTimeout(fitPreview,40); } const pv=document.querySelector('.col-preview'); if(pv) pv.scrollIntoView({behavior:'smooth',block:'start'}); } // Open a saved invoice and download its PDF directly async function downloadInvoice(id){ await openInvoice(id); await new Promise(r=>setTimeout(r,60)); await buildInvoicePdf('save'); } /* ============ CLIENTS (Phase 3) ============ */ let clientsCache=[]; function populateClientPick(){ const sel=$('#clientpick'); if(!sel) return; const cur=sel.value; sel.innerHTML='' + clientsCache.map(c=>'').join(''); sel.value=cur; } async function loadClients(){ if(!token) return; try{ const d=await api('/clients'); clientsCache=d.clients||[]; populateClientPick(); renderClientList(); }catch(e){} } function fillClient(c){ if(!c) return; const set=(id,v)=>{ if($('#'+id)) $('#'+id).value=v||''; }; set('c_name',c.name); set('c_reg',c.reg_no); set('c_vat',c.vat_no); set('c_addr',c.address); set('c_email',c.email); render(); } async function saveClient(){ const g=id=>($('#'+id)?.value||'').trim(); if(!g('c_name')){ toast(T[lang].cli_name_req); return; } try{ await api('/clients',{method:'POST',body:{name:g('c_name'),reg_no:g('c_reg'),vat_no:g('c_vat'),address:g('c_addr'),email:g('c_email')}}); await loadClients(); toast(T[lang].cli_saved); }catch(e){ toast(T[lang].t_err); } } async function deleteClient(id){ try{ await api('/clients/'+id,{method:'DELETE'}); await loadClients(); }catch(e){ toast(T[lang].t_err); } } function renderClientList(){ const wrap=$('#clientlist'); if(!wrap) return; if(!clientsCache.length){ wrap.innerHTML='
'+T[lang].cli_empty+'
'; return; } wrap.innerHTML=''; clientsCache.forEach(c=>{ const row=document.createElement('div'); row.className='invrow'; row.innerHTML='
'+esc(c.name)+'
' +'
'+esc([c.vat_no,c.email].filter(Boolean).join(' · '))+'
' +''; row.querySelector('.meta').onclick=()=>{ fillClient(c); closeCabinet(); }; row.querySelector('.del').onclick=()=>{ if(confirm(c.name+' ✕?')) deleteClient(c.id); }; wrap.appendChild(row); }); } function cabTab(which){ $$('.cabtab').forEach(b=>b.classList.toggle('on',b.dataset.cab===which)); $('#invlist').classList.toggle('hidden', which!=='inv'); $('#clientlist').classList.toggle('hidden', which!=='cli'); const st=$('#invstats'); if(st) st.classList.toggle('hidden', which!=='inv'); } /* ---------- init ---------- */ function initDates(){ const today=new Date(); const due=new Date(); due.setDate(due.getDate()+10); if(!$('#i_date').value) $('#i_date').value=today.toISOString().slice(0,10); if(!$('#i_due').value) $('#i_due').value=due.toISOString().slice(0,10); if(!$('#i_num').value) $('#i_num').value=today.getFullYear()+'-001'; if($('#i_paymethod') && !$('#i_paymethod').value) $('#i_paymethod').value=T[lang].pay_method_default; } $$('input,textarea').forEach(el=>el.addEventListener('input',render)); loadLocal(); addItem(); initDates(); applyLang(); applyTpl(); render(); applyHandoff(); setTimeout(fitPreview,300); /* ---- preview collapse toggle (like tame) ---- */ function updatePvText(){ const b=document.getElementById('pvToggle'); if(!b) return; const w=document.querySelector('.wrap'); const solo=w&&w.classList.contains('solo'); const span=b.querySelector('.pvtxt'); if(span) span.textContent = solo ? (T[lang].showPrev||'Show preview') : (T[lang].hidePrev||'Hide preview'); } (function(){ const b=document.getElementById('pvToggle'); const w=document.querySelector('.wrap'); if(w && localStorage.getItem('mp_inv_prev')==='1') w.classList.add('solo'); if(b) b.onclick=()=>{ w.classList.toggle('solo'); localStorage.setItem('mp_inv_prev', w.classList.contains('solo')?'1':'0'); updatePvText(); setTimeout(fitPreview,60); }; updatePvText(); })(); /* ---- Phase 2b wiring ---- */ $('#save').onclick = saveInvoice; $('#i_doctype').onchange = render; $('#dlxml').onclick = downloadEinvoice; $('#newinv').onclick = newInvoice; $('#saveclient').onclick = saveClient; $('#clientpick').onchange = e=>{ const c=clientsCache.find(x=>String(x.id)===String(e.target.value)); if(c) fillClient(c); }; $$('.cabtab').forEach(b=>b.onclick=()=>cabTab(b.dataset.cab)); $('#authSubmit').onclick = submitAuth; $('#authClose').onclick = closeAuth; $('#cabClose').onclick = closeCabinet; $('#authModal').onclick = e=>{ if(e.target.id==='authModal') closeAuth(); }; $('#cabModal').onclick = e=>{ if(e.target.id==='cabModal') closeCabinet(); }; $('#au_pass').addEventListener('keydown', e=>{ if(e.key==='Enter') submitAuth(); }); $$('[data-save]').forEach(el=>el.addEventListener('input', scheduleProfileSave)); renderAuthbox(); if(token) afterLogin();