(function(){constr=document.createElement("link").relList;if(r&&r.supports&&r.supports("modulepreload"))return;for(constsofdocument.querySelectorAll('link[rel="modulepreload"]'))o(s);newMutationObserver(s=>{for(constcofs)if(c.type==="childList")for(constuofc.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&o(u)}).observe(document,{childList:!0,subtree:!0});functiona(s){constc={};returns.integrity&&(c.integrity=s.integrity),s.referrerPolicy&&(c.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?c.credentials="include":s.crossOrigin==="anonymous"?c.credentials="omit":c.credentials="same-origin",c}functiono(s){if(s.ep)return;s.ep=!0;constc=a(s);fetch(s.href,c)}})();constRe=newWorker(newURL("/assets/db-worker-DFFhVJkA.js",import.meta.url),{type:"module"});letfr=0,Ae=null;constet=newMap;functionRn(){returnAe||(Ae=newPromise((e,r)=>{Re.onmessage=o=>{consts=o.data;if(s.type==="ready")return;constc=et.get(s.id);c&&(et.delete(s.id),s.type=="success"?c.resolve(s.data):c.reject(newError(s.error??s.message??"Неизвестная ошибка Worker")))},Re.onerror=o=>{console.error("[SQLite Worker] Ошибка:",o),r(newError("Ошибка Worker"))};consta=++fr;et.set(a,{resolve:e,reject:r}),Re.postMessage({type:"start",id:a})}),Ae)}functionpr(e,r){returnnewPromise((a,o)=>{if(!Re){o(newError("Worker не создан"));return}consts=++fr;et.set(s,{resolve:a,reject:o}),Re.postMessage({type:e,id:s,...r})})}asyncfunctionie(e,r){returnawaitpr("query",{sql:e,params:r??[]})}asyncfunctionhr(e,r){awaitpr("command",{sql:e,params:r??[]})}functionwr(e){returnnewDate(e*1e3)}functionIn(){returnMath.floor(Date.now()/1e3)}functionJn(e){constr=wr(e),a=String(r.getDate()).padStart(2,"0"),o=String(r.getMonth()+1).padStart(2,"0");return`${a}.${o}.${r.getFullYear()}`}functionOn(e){constr=wr(e),a=String(r.getHours()).padStart(2,"0"),o=String(r.getMinutes()).padStart(2,"0");return`${Jn(e)}${a}:${o}`}functionKn(e){if(e==null)return[];constr=String(e).trim();returnr?r.split(/[,\s;]+/).map(a=>a.trim()).filter(a=>a.length>0):[]}functionDn(e){constr=newMap;if(e==null)returnr;consta=String(e);if(!a)returnr;consto=a.split("");for(lets=0;s+1<o.length;s+=2){constc=Number(o[s]),u=o[s+1]??"";!Number.isFinite(c)||!Number.isInteger(c)||u&&r.set(c,u)}returnr}functiongr(e){constr=Number(e.id??0),a=String(e.key??""),o=String(e.value??""),s=e.tags==null?"":String(e.tags),c=Number(e.group_id??1);return{id:r,key:a,value:o,tags:s,tagsList:Kn(s),more:Dn(e.more),group_id:Number.isFinite(c)?c:1}}functionmr(e){constr=[],a=[],o=(e.search??"").trim();if(o){r.push("(key LIKE ? ESCAPE '\\' OR value LIKE ? ESCAPE '\\' OR tags LIKE ? ESCAPE '\\')");consts=`%${o.replace(/\\/g,"\\\\").replace(/%/g,"\\%").replace(/_/g,"\\_")}%`;a.push(s,s,s)}returne.groupId!=null&&(r.push("group_id = ?"),a.push(e.groupId)),{clause:r.length>0?`WHERE ${r.join(" AND ")}`:"",params:a}}asyncfunctionXn(e={}){const{clause:r,params:a}=mr(e),s=(awaitie(`SELECT COUNT(*) as cnt FROM words ${r}`,a))[0]?.cnt;returntypeofs=="number"?s:Number(s??0)}asyncfunctiontr(e={}){const{clause:r,params:a}=mr(e),o=Math.max(1,Math.min(e.limit??50,500)),s=Math.max(0,e.offset??0);return(awaitie(`SELECT id, key, value, tags, more, group_id FROM words ${r} ORDER BY id LIMIT ? OFFSET ?`,[...a,o,s])).map(gr)}asyncfunctionzn(){return(awaitie("SELECT id, name FROM word_groups ORDER BY id")).map(r=>({id:Number(r.id),name:String(r.name??"")}))}asyncfunctionBn(){return(awaitie("SELECT id, name, forward, backward, filter FROM decks ORDER BY id")).map(r=>({id:Number(r.id),name:String(r.name??""),forward:String(r.forward??""),backward:String(r.backward??""),filter:String(r.filter??"")}))}asyncfunctionVn(e,r){returnawaithr("UPDATE decks SET forward = ?, backward = ?, filter = ? WHERE id = ?",[r.forward,r.backward,r.filter,e]),nt(e)}asyncfunctionnt(e){consta=(awaitie("SELECT id, name, forward, backward, filter FROM decks WHERE id = ? LIMIT 1",[e]))[0];returna?{id:Number(a.id),name:String(a.name??""),forward:String(a.forward?
w.keyaswkey,w.valueaswvalue
FROMhistoryhLEFTJOINwordswONw.id=h.word_id
WHEREh.deck_id=?ORDERBYh.timestampDESC,h.idDESCLIMIT?OFFSET?`,[e,a,o])).map(c=>({id:Number(c.id),deck_id:Number(c.deck_id),word_id:Number(c.word_id),timestamp:Number(c.timestamp??0),answer:Number(c.answer??0),before:Number(c.before??0),after:Number(c.after??0),fsrs:Number(c.fsrs??0),wordKey:c.wkey==null?"":String(c.wkey),wordValue:c.wvalue==null?"":String(c.wvalue)}))}const Ut="japanese_app.db";async function xt(){return navigator.storage.getDirectory()}async function ta(e){e[18]=1,e[19]=1;const a=await(await xt()).getFileHandle(Ut,{create:!0}),o=a.createSyncAccessHandle;if(typeof o=="function")try{const c=await o.call(a);try{c.truncate(0),c.write(e,{at:0}),c.flush()}finally{c.close()}return}catch{}const s=await a.createWritable();try{await s.truncate(0);const c=new Uint8Array(e.length);c.set(e),await s.write(c)}finally{await s.close()}}async function ra(){const e=await xt();let r;try{r=await e.getFileHandle(Ut)}catch{throw new Error("Локальная база не найдена — сначала скачай сохранение")}const a=await r.getFile();if(a.size===0)throw new Error("Локальная база пуста");return new Uint8Array(await a.arrayBuffer())}async function Je(){try{return(await(await(await xt()).getFileHandle(Ut)).getFile()).size>0}catch{return!1}}var na=ArrayBuffer,G=Uint8Array,tt=Uint16Array,aa=Int16Array,at=Int32Array,mt=function(e,r,a){if(G.prototype.slice)return G.prototype.slice.call(e,r,a);(r==null||r<0)&&(r=0),(a==null||a>e.length)&&(a=e.length);var o=new G(a-r);return o.set(e.subarray(r,a)),o},Ie=function(e,r,a,o){if(G.prototype.fill)return G.prototype.fill.call(e,r,a,o);for((a==null||a<0)&&(a=0),(o==null||o>e.length)&&(o=e.length);a<o;++a)e[a]=r;return e},sa=function(e,r,a,o){if(G.prototype.copyWithin)return G.prototype.copyWithin.call(e,r,a,o);for((a==null||a<0)&&(a=0),(o==null||o>e.length)&&(o=e.length);a<o;)e[r++]=e[a++]},ia=["invalid zstd data","window size too large (>2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],A=function(e,r,a){var o=new Error(r||ia[e]);if(o.code=e,Error.captureStackTrace&&Error.captureStackTrace(o,A),!a)throw o;return o},sr=function(e,r,a){for(var o=0,s=0;o<a;++o)s|=e[r++]<<(o<<3);return s},oa=function(e,r){return(e[r]|e[r+1]<<8|e[r+2]<<16|e[r+3]<<24)>>>0},ca=function(e,r){var a=e[0]|e[1]<<8|e[2]<<16;if(a==3126568&&e[3]==253){var o=e[4],s=o>>5&1,c=o>>2&1,u=o&3,g=o>>6;o&8&&A(0);var y=6-s,m=u==3?4:u,b=sr(e,y,m);y+=m;var T=g?1<<g:s,k=sr(e,y,T)+(g==1&&256),U=k;if(!s){var N=1<<10+(e[5]>>3);U=N+(N>>3)*(e[5]&7)}U>2145386496&&A(1);var w=new G((r==1?k||U:r?0:U)+12);return w[0]=1,w[4]=4,w[8]=8,{b:y+T,y:0,l:0,d:b,w:r&&r!=1?r:w.subarray(12),e:U,o:new at(w.buffer,0,3),u:k,c,m:Math.min(131072,U)}}else if((a>>4|e[3]<<20)==25481893)return oa(e,4)+8;A(0)},Ce=function(e){for(var r=0;1<<r<=e;++r);return r-1},Oe=function(e,r,a){var o=(r<<3)+4,s=(e[r]&15)+5;s>a&&A(3);for(var c=1<<s,u=c,g=-1,y=-1,m=-1,b=c,T=new na(512+(c<<2)),k=new aa(T,0,256),U=new tt(T,0,256),N=new tt(T,512,c),w=512+(c<<1),E=new G(T,w,c),I=new G(T,w+c);g<255&&u>0;){var J=Ce(u+1),L=o>>3,z=(1<<J+1)-1,P=(e[L]|e[L+1]<<8|e[L+2]<<16)>>(o&7)&z,C=(1<<J)-1,_=z-u-1,R=P&C;if(R<_?(o+=J,P=R):(o+=J+1,P>C&&(P-=_)),k[++g]=--P,P==-1?(u+=P,E[--b]=g):u-=P,!P)do{var F=o>>3;y=(e[F]|e[F+1]<<8)>>(o&7)&3,o+=2,g+=y}while(y==3)}(g>255||u)&&A(0);for(var X=0,j=(c>>1)+(c>>3)+3,V=c-1,B=0;B<=g;++B){var H=k[B];if(H<1){U[B]=-H;continue}for(m=0;m<H;++m){E[X]=B;do X=X+j&V;while(X>=b)}}for(X&&A(0),m=0;m<c;++m){var v=U[E[m]]++,x=I[m]=s-Ce(v);N[m]=(v<<x)-c}return[o+7>>3,{b:s,s:E,n:I,t:N}]},la=function(e,r){var a=0,o=-1,s=new G(292),c=e[r],u=s.subarray(0,256),g=s.subarray(256,268),y=new tt(s.buffer,268);if(c<128){var m=Oe(e,r+1,6),b=m[0],T=m[1];r+=c;var k=b<<3,U=e[r];U||A(0);for(var N=0,w=0,E=T.b,I=E,J=(++r<<3)-8+Ce(U);J-=E,!(J<k);){var L=J>>3;if(N+=(e[L]|e[L+1]<<8)>>(J&7)&(1<<E)-1,u[++o]=T.s[N],J-=I,J<k)break;L=J>>3,w+=(e[L]|e[L+1]<<8)>>(J&7)&(1<<I)-1,u[++o]=T.s[w],E=T.n[N],N=T.t[N],I=T.n[w],w=T.t[w]}++o>255&&A(0)}else{for(o=c-127;a<o;a+=2){var z=e[++r];u[a]=z>>4,u[
`;consta=e.querySelector("#home-db-banner"),o=e.querySelector("#home-db-text"),s=e.querySelector("#home-db-go"),c=e.querySelector("#words-search"),u=e.querySelector("#words-group"),g=e.querySelector("#words-count"),y=e.querySelector("#words-status"),m=e.querySelector("#words-list"),b=e.querySelector("#words-more");functionT(v,x){a.hidden=!1,o.textContent=v,s.hidden=!1}functionk(){a.hidden=!0}s.addEventListener("click",()=>{document.querySelector('.drawer-btn[data-page="sync"]')?.click()});letU=!1,N=newMap,w=0,E=[],I=null,J=0,L=!1,z=0,P=0;functionC(){constv=u.value;if(v==="")return{search:c.value.trim(),groupId:null};constx=Number(v);return{search:c.value.trim(),groupId:Number.isFinite(x)?x:null}}function_(){b.hidden=!(U&&E.length<w),b.hidden||(b.textContent=`Показать ещё (${w-E.length} осталось)`)}functionR(){m.innerHTML=E.map(v=>or(v,N,v.id===I)).join(""),g.textContent=w>0?`Показано ${E.length} из ${w}`:"",_()}functionF(v){if(I===v){v!=null&&X(v),I=null;return}I!=null&&X(I),I=v,v!=null&&j(v)}functionX(v){constx=m.querySelector(`.word-row-wrap[data-word-id="${v}"]`);if(!x)return;constM=x.querySelector(".word-row"),Q=x.querySelector(".word-extra");M&&(M.classList.remove("open"),M.setAttribute("aria-expanded","false")),Q&&(Q.hidden=!0,Q.innerHTML="")}functionj(v){constx=E.find(he=>he.id===v),M=m.querySelector(`.word-row-wrap[data-word-id="${v}"]`);if(!x||!M)return;constQ=M.querySelector(".word-row"),O=M.querySelector(".word-extra");Q&&(Q.classList.add("open"),Q.setAttribute("aria-expanded","true")),O&&(O.hidden=!1,O.innerHTML=kr(x,N))}functionV(v){y.textContent=v,y.hidden=v===""}asyncfunctionB(){if(!U||L)return;L=!0;constv=++z,x=C();b.disabled=!0,E.length===0&&V("Загрузка слов…");try{const[M,Q]=awaitPromise.all([Xn({search:x.search,groupId:x.groupId??void0}),tr({search:x.search,groupId:x.groupId??void0,limit:ir,offset:0})]);if(v!==z)return;w=M,E=Q,J=Q.length,I!=null&&!E.some(O=>O.id===I)&&(I=null),R(),V(Q.length===0?"По этому запросу слов нет.":""),Q.length===0&&w===0&&(g.textContent="Слов в базе пока нет.")}catch(M){if(v!==z)return;V(`Не удалось загрузить слова: ${MinstanceofError?M.message:String(M)}`)}finally{v===z&&(L=!1,b.disabled=!1,_())}}asyncfunctionH(){if(!U||L||E.length>=w)return;L=!0;constv=++z,x=C();b.disabled=!0,b.textContent="Загрузка…";try{constM=awaittr({search:x.search,groupId:x.groupId??void0,limit:ir,offset:J});if(v!==z)return;E=E.concat(M),J+=M.length,m.insertAdjacentHTML("beforeend",M.map(Q=>or(Q,N,Q.id===I)).join("")),g.textContent=`Показано ${E.length} из ${w}`,_()}catch(M){if(v!==z)return;V(`Не удалось догрузить: ${MinstanceofError?M.message:String(M)}`)}finally{v===z&&(L=!1,b.disabled=!1,_())}}c.addEventListener("input",()=>{window.clearTimeout(P),P=window.setTimeout(()=>{B()},300)}),c.addEventListener("keydown",v=>{v.key==="Enter"&&(window.clearTimeout(P),B())}),u.addEventListener("change",()=>{B()}),b.addEventListener("click",()=>{H()}),m.addEventListener("click",v=>{constx=v.target.closest(".word-row");if(!x||x.disabled)return;constM=Number(x.dataset.wordId);Number.isFinite(M)&&F(I===M?null:M)}),(async()=>{if(!awaitJe()){T("Локальной базы нет — скачай сохранение."),V("Нет локальной базы — скачай сохранение на странице «Синхронизация»."),g.textContent="";return}try{constx=awaitra();if(!$t(x)){T("Файл в OPFS не похож на SQLite — перекачай сохранение.",!0),V("Файл в OPFS не похож на SQLite — перекачай сохранение.");return}k();try{const[Q,O]=awaitPromise.all([zn(),vr()]),he=Q;N=newMap(O.map(ue=>[ue.id,ue])),u.innerHTML='<option value="">Все группы</option>'+he.map(ue=>`<option value="${ue.id}">${Ee(ue.name)}</option>`).join(""),U=!0,awaitB(),u.options[0].textContent=`Все группы (${w})`}catch(Q){V(`БД есть, но слова не про
`;consta=e.querySelector("#decks-count"),o=e.querySelector("#decks-status"),s=e.querySelector("#decks-list");functionc(u){o.textContent=u,o.hidden=u===""}s.addEventListener("click",u=>{constg=u.target.closest("[data-act]");if(!g)return;consty=Number(g.dataset.deckId);Number.isFinite(y)&&(g.dataset.act==="review"?r.goReview(y):r.goDeck(y))}),(async()=>{if(!awaitJe()){c("Нет локальной базы — скачай сохранение на странице «Синхронизация»."),a.textContent="";return}c("Загрузка колод…");try{const[g,y]=awaitPromise.all([Bn(),Yn()]);if(g.length===0){a.textContent="Колоды пока отсутствуют.",c(""),s.innerHTML="";return}a.textContent=`Всего: ${g.length}`,c(""),s.innerHTML=g.map(m=>Fa(m,y.get(m.id)??0)).join("")}catch(g){c(`Не удалось загрузить колоды: ${ginstanceofError?g.message:String(g)}`)}})()}functionQa(e){returne?Pa(e):'<span class="empty-val">—</span>'}functionPa(e){returne.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}functionbt(e){returne.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}functionRa(e){constr=e%10,a=e%100;returnr===1&&a!==11?"слово":r>=2&&r<=4&&(a<12||a>14)?"слова":"слов"}functionIa(e,r,a){e.innerHTML=`
<button id="deck-back" class="btn btn-ghost" type="button">← Назад к колодам</button>
`;consto=e.querySelector("#deck-back"),s=e.querySelector("#deck-title"),c=e.querySelector("#deck-status"),u=e.querySelector("#deck-body");o.addEventListener("click",()=>a.goDecks()),(async()=>{if(!awaitJe()){s.textContent="Колода недоступна",c.textContent="Нет локальной базы — скачай сохранение на странице «Синхронизация».";return}lety=null;try{y=awaitnt(r)}catch(C){s.textContent="Колода недоступна",c.textContent=`Не удалось загрузить колоду: ${CinstanceofError?C.message:String(C)}`;return}if(!y){s.textContent="Колода не найдена",c.textContent=`Колоды с id=${r} нет в локальной базе. Возможно, база обновилась — вернись к списку.`;return}constm=y;s.textContent=m.name||`Колода #${m.id}`,c.hidden=!0;letb=null;try{b=awaitZn(m.id)}catch(C){c.hidden=!1,c.textContent=`Данные колоды загружены, а количество слов — нет: ${CinstanceofError?C.message:String(C)}`}u.innerHTML=`
`;consto=e.querySelector("#hist-back"),s=e.querySelector("#hist-title"),c=e.querySelector("#hist-count"),u=e.querySelector("#hist-status"),g=e.querySelector("#hist-list"),y=e.querySelector("#hist-more");o.addEventListener("click",()=>a.goDeck(r));functionm(w){u.textContent=w,u.hidden=w===""}letb=0,T=0,k=!1;functionU(){constw=b-T;y.hidden=w<=0,w>0&&(y.textContent=`Показать ещё (${w} осталось)`)}asyncfunctionN(){if(!(k||T>=b)){k=!0,y.disabled=!0,y.textContent="Загрузка…";try{constw=awaitea(r,{limit:Ja,offset:T});T+=w.length,g.insertAdjacentHTML("beforeend",w.map(Ka).join("")),c.textContent=`Показано ${T} из ${b}`}catch(w){m(`Не удалось загрузить историю: ${winstanceofError?w.message:String(w)}`)}finally{k=!1,y.disabled=!1,U()}}}y.addEventListener("click",()=>{N()}),(async()=>{if(!awaitJe()){s.textContent="История недоступна",m("Нет локальной базы — скачай сохранение на странице «Синхронизация».");return}try{constE=awaitnt(r);if(!E){s.textContent="Колода не найдена",m(`Колоды с id=${r} нет в локальной базе.`);return}if(s.textContent=E.name||`Колода #${E.id}`,b=awaitAn(E.id),b===0){c.textContent="Ответов пока нет — начни повторение.",m("");return}m(""),awaitN()}catch(E){s.textContent="История недоступна",m(`Не удалось загрузить историю: ${EinstanceofError?E.message:String(E)}`)}})()}functionXa(e){returne.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}constza=[{value:0,label:"Не получилось",cls:"grade-fail"},{value:1,label:"Тяжело",cls:"grade-hard"},{value:2,label:"Хорошо",cls:"grade-good"},{value:3,label:"Легко",cls:"grade-easy"}];functionBa(e,r,a){e.innerHTML=`
`,g.querySelector("#review-card").addEventListener("click",()=>{w||(w=!0,z())}),g.querySelectorAll(".review-grade").forEach(M=>{M.addEventListener("click",()=>{constQ=Number(M.dataset.grade);P(Q,j)})})}asyncfunctionP(R,F){if(J)return;J=!0;constX=m[N],j=E??1,V=[...g.querySelectorAll(".review-grade")];for(constBofV)B.disabled=!0;try{awaitWn({deckId:r,wordId:X,answer:R,before:j,after:j})}catch(B){y(`Ответ не записался: ${BinstanceofError?B.message:String(B)}${F}`),J=!1;for(constHofV)H.disabled=!1;return}N+=1,w=!1,E=null,N>=m.length?C():awaitz()}functionC(){c.textContent=`Готово: ${m.length} из ${m.length}`,y(""),g.innerHTML=`
<p class="card-hint">Все карточки сессии просмотрены, ответы записаны в history.</p>
`,g.querySelector("#review-again").addEventListener("click",()=>{_()})}asyncfunction_(){if(y("Перемешиваю…"),g.innerHTML="",c.textContent="",m=awaitar(r),N=0,w=!1,m.length===0){y("В колоде нет слов для повторения.");return}b=awaitrr(m),z()}(async()=>{if(!awaitJe()){s.textContent="Повторение недоступно",y("Нет локальной базы — скачай сохранение на странице «Синхронизация».");return}try{const[F,X]=awaitPromise.all([nt(r),vr()]);if(!F){s.textContent="Колода не найдена",y(`Колоды с id=${r} нет в локальной базе. Вернись к списку.`);return}if(T=X,k=F.forward,U=F.backward,s.textContent=F.name||`Колода #${F.id}`,m=awaitar(F.id),m.length===0){c.textContent="",y("В колоде нет слов для повторения.");return}b=awaitrr(m),N=0,w=!1,awaitz()}catch(F){s.textContent="Повторение недоступно",y(`Не удалось загрузить карточки: ${FinstanceofError?F.message:String(F)}`)}})()}constlr=24,Va=/^[A-Za-z0-9]{24}$/,Er="japlearn_sync_token";functionur(e){returne.trim().replace(/\s+/g,"")}functionQe(e){returnVa.test(e)}functionYa(){try{returnlocalStorage.getItem(Er)??""}catch{return""}}functiondr(e){try{localStorage.setItem(Er,e)}catch{}}constCr="https://learning.micialware.ru";functionZa(e,r=Cr){return`${r.replace(/\/+$/,"")}/download/${encodeURIComponent(e)}`}asyncfunctionGa(e,r,a=Cr){consto=Za(e,a);lets;try{s=awaitfetch(o,{method:"GET",...r})}catch(u){thrownewError(`Нет связи с сервером: ${uinstanceofError?u.message:String(u)}`)}if(!s.ok)throws.status===404?newError("Сохранение не найдено (404). Проверь токен."):newError(`Сервер ответил ${s.status}${s.statusText}`);constc=awaits.arrayBuffer();if(c.byteLength===0)thrownewError("Сервер вернул пустой файл");returnnewUint8Array(c)}functionja(e){e.innerHTML=`
<p id="status" class="status-bar" role="status">Введите токен из 24 символов</p>
</main>
`;constr=e.querySelector("#token-input"),a=e.querySelector("#token-error"),o=e.querySelector("#token-counter"),s=e.querySelector("#btn-download"),c=e.querySelector("#status");functionu(k){c.textContent=k,console.log(`[JapLearn] ${k}`)}functiong(){returnur(r.value)}functiony(k){s.disabled=k||!Qe(g()),r.disabled=k}functionm(){constk=g(),U=k.length;o.textContent=`${U} / ${lr}`;constN=Qe(k),w=U===0;r.classList.toggle("invalid",!w&&!N),r.setAttribute("aria-invalid",String(!w&&!N)),w?a.textContent="":U!==lr?a.textContent=`Нужно 24 символа, сейчас ${U}`:a.textContent=N?"":"Только латинские буквы и цифры",s.disabled=!N}asyncfunctionb(){constk=g();if(Qe(k)){dr(k),y(!0),u("Скачивание сохранения...");try{constU=awaitGa(k);u(`Скачано ${(U.length/1024).toFixed(1)} КБ, распаковка...`);constN=awaitHa(U);u(`Распаковано ${(N.length/1024).toFixed(1)} КБ, сохранение в OPFS...`),awaitta(N),u(`Готово: база ${(N.length/1024).toFixed(1)} КБ сохранена локально (OPFS).`)}catch(U){u(`Ошибка скачивания: ${UinstanceofError?U.message:String(U)}`)}finally{y(!1),m()}}}r.addEventListener("input",()=>{m()}),r.addEventListener("change",()=>{constk=g();r.value=k,Qe(k)&&(dr(k),u("Токен сохранён локально. Можно скачивать.")),m()}),s.addEventListener("click",()=>{b()});constT=Ya();T&&(r.value=T),m(),Qe(ur(T))&&u("Токен восстановлен. Нажми «Скачать», чтобы получить базу.")}constWa={home:"Главная",decks:"Колоды",deck:"Колода",review:"Повторение",history:"История",sync:"Синхронизация"};functionKe(e){constr=document.getElementById(e);if(!r)thrownewError(`[JapLearn] Не найден элемент #${e}`);returnr}const$r=Ke("burger-btn"),rt=Ke("drawer"),Ur=Ke("drawer-overlay"),Aa=Ke("page-title"),Ue=Ke("page");letMt=!1;functionDe(e){Mt=e,rt.classList.toggle("open",e),Ur.hidden=!e,$r.setAttribute("aria-expanded",String(e)),rt.setAttribute("aria-hidden",String(!e)),document.body.classList.toggle("drawer-open",e)}functiones(e){rt.querySelectorAll(".drawer-btn").forEach(r=>{r.classList.toggle("active",r.dataset.page===e)})}functionme(e,r){Aa.textContent=Wa[e],es(e==="deck"||e==="review"||e==="history"?"decks":e),e==="home"?qa(Ue):e==="decks"?_a(Ue,{goDeck:a=>me("deck",a),goReview:a=>me("review",a)}):e==="deck"?Ia(Ue,r??0,{goDecks:()=>me("decks"),goReview:a=>me("review",a),goHistory:a=>me("history",a)}):e==="review"?Ba(Ue,r??0,{goDecks:()=>me("decks")}):e==="history"?Da(Ue,r??0,{goDeck:a=>me("deck",a)}):ja(Ue)}$r.addEventListener("click",()=>{De(!Mt)});Ur.addEventListener("click",()=>{De(!1)});document.addEventListener("keydown",e=>{e.key==="Escape"&&Mt&&De(!1)});rt.querySelectorAll(".drawer-btn").forEach(e=>{e.addEventListener("click",()=>{constr=e.dataset.page;(r==="home"||r==="decks"||r==="sync")&&me(r),De(!1)})});awaitRn();De(!1);me("home");console.log("[JapLearn] crossOriginIsolated =",window.crossOriginIsolated);