F24nT ai

Welcome back

Sign in to continue your conversations

or
Don't have an account? Sign up
Guest sessions are temporary and not saved
Incognito
0/100

How can I help you?

F24nT ai
Paling efisien untuk tugas sehari-hari
Upaya
Rendah
Model lainnya
Upaya yang lebih tinggi berarti respons yang lebih menyeluruh, tetapi membutuhkan waktu lebih lama dan menggunakan batas Anda lebih cepat.
Rendah
Sedang
Bawaan
Tinggi
Ekstra
Maks
Pemikiran
Berpikir untuk tugas yang lebih kompleks
AI Models - Powered by YoeNw24
F24nT ai
Balanced · everyday tasks
F24nT ai Pro
Most powerful · complex tasks
PRO
F24nT ai Lite
Fastest · quick replies
Claude Series
Claude Opus 4.5
Reasoning kompleks
PRO
Claude Sonnet 4.6
Balanced serba guna
PRO
DeepSeek Series
DeepSeek R1
Chain-of-thought reasoning
Dolphin AI
Cepat, jawaban langsung to-the-point
Other AI
Grok 4.1
Witty, uncensored & real-time
PRO
Unlimited AI
AI serba guna terbaik
OpenAI & Google
Gemini 3.1 Flash
Google multimodal - image & text
PRO
Mistral
Ingat percakapan otomatis (native memory)
Qwen3 Coder
Khusus coding & pemrograman
Qwen AI
qwen-2.5-7b-instruct
Grok AI
grok-4.20
Llama AI
llama-4-scout
Claude AI
claude-haiku-4.5 (via Rewind)
Nemotron AI
nemotron-3-ultra-550b
GLM AI
glm-4.7-flash
Bible AI
Tanya jawab seputar Alkitab dengan referensi ayat
Felo
Model chat serba guna
SufrSense
Model chat cepat & ringkas
HackAI
GPT-5.4 mini dengan memori sesi
GPT Image
Generate gambar dari deskripsi teks
Google Gemma
Model chat ringan dengan sesi
GPT-5 Mini
Model chat cepat by IkyyXD
AI Tools
NanoBanana Edit
Edit gambar dengan prompt
DeepSearch
Search web dengan referensi
AndiSearch
Search dengan hasil + snippet
To Anime
Upload foto, ubah jadi gaya anime
Pinterest
Cari & tampilkan gambar Pinterest
Bing Image
Cari & tampilkan gambar Bing
Copilot
Copilot AI
Microsoft Copilot - coding assistant
NoTrack AI
Chat AI tanpa tracking
FAA
Blackbox AI
Coding assistant dari FAA
Jeeves AI
Chat AI serba guna
GPT Promt
Bisa diberi nama & konteks custom
PowerBrain AI
Kalkulasi & penalaran matematis
Islam AI
Tanya jawab seputar Islam
Text2Img Pro
Generate gambar AI dari teks
Epsilon AI
Chat AI serba guna
F24nT ai v9 · Powered by YoeNw24 · Support teks panjang + AI Tools
Index · HTML
Belum ada pesan console.
U
User
user@email.com
Free Plan
Upgrade ke Abyz Plan Rp15.000/bln
Unlimited pesan + Semua AI Pro + AI Tools
My Profile
Edit name and preferences
Settings
Theme, privacy, providers
Message usage0 / 100
Resets every 30 minutes
Starred
0 starred
Projects
0 projects
Export Conversations
Download as JSON
Clear All Conversations
Sign out
PREMIUM
Abyz Plan
Unlimited AI · Semua Model Pro · AI Tools
Rp15.000/bulan
dari Rp39.999 · Hemat 62%!
Unlimited PesanTanpa batas 100 msg/30 menit
Semua Model ProClaude, GPT, DeepSeek, dll
AI Tools Full AccessNanoBanana, Ideogram/DeepImage, Search
Badge PremiumRing Abyz di profil & sidebar
Cara Upgrade
1
Hubungi admin via WhatsApp
2
Transfer Rp15.000 + kirim bukti
3
Dapat username & password → Aktifkan
WhatsApp
GOKIL
Gokil Plan
Custom API · AI Persona · Fitur Eksklusif
Rp35.000/bulan
dari Rp99.000 · Hemat 65%!
Semua Fitur Abyz PlanUnlimited + semua model premium + AI Tools
Custom API KeysTambah API kamu sendiri
Custom AI PersonaAtur kepribadian AI
Badge GOKIL EksklusifProfil bintang emas
Cara Upgrade
1
Hubungi admin via WhatsApp
2
Transfer Rp35.000 + kirim bukti
3
Aktifkan kode → Setup API & Persona
WhatsApp
Aktifkan Plan
Masukkan username dan password yang diberikan admin.
Gokil Settings
Custom API Keys
AI Persona
Nama AI
Gaya Bahasa
Custom System Prompt
Instruksi khusus untuk AI kamu (opsional)
0 / 1000
Share conversation
Anyone with this link can view a snapshot of this conversation.
https://f24nt.ai/share/…
New Project
Clear all conversations?
This will permanently delete all your conversation history. Cannot be undone.
Edit Profile
Star
Rename
Delete
Batas Pesan Tercapai
Kamu sudah mencapai 100 pesan dalam 30 menit.
Tunggu reset atau upgrade ke Abyz Plan untuk unlimited.
30:00
Artefak
TXT
function showTyping(){ const e=document.getElementById("msgs"),t=document.createElement("div"); t.className="mg",t.id="typing-g"; const isTool=!!G.activeTool; const lbl=isTool?"Memproses...":"Mengetik..."; t.innerHTML=`
${logoSVG(22)}F24nT ai${G.model}
${lbl}${isTool?'0%':''}
${isTool?'
':''}
`; e.appendChild(t),scrollBot(); if(isTool){ clearInterval(_typingProgTimer); let pct=0;const cap=95; _typingProgTimer=setInterval(()=>{ const bar=document.getElementById("typing-bar"),pctEl=document.getElementById("typing-pct"); if(!bar){clearInterval(_typingProgTimer);return} pct+=Math.max(0.4,(cap-pct)*0.05);if(pct>cap)pct=cap; bar.style.width=pct+"%";if(pctEl)pctEl.textContent=Math.floor(pct)+"%"; },200); } } function _clearTypingProgress(){clearInterval(_typingProgTimer)}function regenLast(){if(G.isBusy||!G.activeChatId)return;const e=document.getElementById("msgs");e.querySelector(".mg:last-child .ma")&&(e.querySelector(".mg:last-child").remove(),cs()[G.activeChatId]&&cs()[G.activeChatId].msgs.pop());const t=e.querySelector(".mg:last-child .mu-b");if(t){G.isBusy=!0,updateSend(),showTyping();const e=G.activeChatId||G.sessionId;callAI(t.textContent,G.modelEp||"overchat",e).then(e=>{const t=document.getElementById("typing-g");t&&t.remove(),renderAssist(e,G.model),addToChat("assistant",e,G.model),G.isBusy=!1,updateSend()})}}function thumbUp(e){e.querySelector("svg").setAttribute("fill","currentColor"),e.style.color="rgb(34,197,94)",showToast("Respons bagus, terima kasih!","success")}function thumbDown(e){e.querySelector("svg").setAttribute("fill","currentColor"),e.style.color="rgb(239,68,68)",showToast("Feedback diterima, terima kasih!","info")}function starCurrent(){G.activeChatId&&cs()[G.activeChatId]&&(G.ctxId=G.activeChatId,ctxStar())}function fmtMd(e){const t=[];let n=(e=e.replace(/```(\w*)\n?([\s\S]*?)```/g,(e,n,a)=>{const o=t.length;return t.push({lang:n||"plaintext",code:a.trim()}),`\0CB${o}\0`})).replace(/&/g,"&").replace(//g,">");n=n.replace(/`([^`\n]+)`/g,"$1"),n=n.replace(/\*\*(.+?)\*\*/g,"$1"),n=n.replace(/\*(.+?)\*/g,"$1"),n=n.replace(/^### (.+)$/gm,"

$1

"),n=n.replace(/^## (.+)$/gm,"

$1

"),n=n.replace(/^# (.+)$/gm,"

$1

"),n=n.replace(/^---$/gm,"
"),n=n.replace(/^> (.+)$/gm,"
$1
"),n=n.replace(/!\[(.*?)\]\((https?:\/\/[^\)\s]+)\)/g,(m,alt,url)=>`${alt}`),n=n.replace(/^[-*+] (.+)$/gm,"
  • $1
  • "),n=n.replace(/(
  • [\s\S]*?<\/li>)+/g,e=>``),n=n.replace(/^\d+\. (.+)$/gm,"
  • $1
  • "),n=n.replace(/\[(.+?)\]\((https?:\/\/[^\)]+)\)/g,(m,label,url)=>`${label}`),n=n.replace(/\n\n+/g,"

    "),n=n.replace(/\n/g,"
    "),n.match(/^<[hup]/)||(n=`

    ${n}

    `);return n=n.replace(/\x00CB(\d+)\x00/g,(e,n)=>{const{lang:a,code:o}=t[+n],s=o.split("\n").length;if(s>=12){const e="art_"+Date.now().toString(36)+Math.random().toString(36).slice(2,8),t=guessArtifactTitle(o,a);return registerArtifact({id:e,title:t,lang:a,code:o}),renderArtifactCardHtml(e,t,a,s)}const i=o.replace(/&/g,"&").replace(//g,">"),r=["html","htm","svg"].includes(a.toLowerCase()),l="cb"+Math.random().toString(36).slice(2,9);return`
    ${a}
    ${r?``:""}
    ${i}
    `}),n}function guessArtifactTitle(e,t){const n=e.split("\n").slice(0,5).join("\n").match(/(?:title|filename)\s*:\s*([^\n\*\->]{2,60})/i);if(n)return n[1].trim()+" - F24nT ai";if(/html|htm/i.test(t)){const t=e.match(/([^<]{2,60})<\/title>/i);if(t&&t[1].trim())return t[1].trim()+" - F24nT ai";const n=e.match(/<h1[^>]*>([^<]{2,60})<\/h1>/i);if(n&&n[1].trim())return n[1].trim()+" - F24nT ai"}return({html:"Halaman Web",htm:"Halaman Web",js:"Skrip JavaScript",javascript:"Skrip JavaScript",py:"Skrip Python",python:"Skrip Python",css:"Stylesheet",json:"Data JSON",svg:"Ilustrasi SVG",ts:"Skrip TypeScript",tsx:"Komponen TSX",jsx:"Komponen JSX"}[t.toLowerCase()]||t.toUpperCase()||"Kode")+" - F24nT ai"}function fileIconIsZip(e){return["zip","archive"].includes((e||"").toLowerCase())}function renderArtifactCardHtml(e,t,n,a){const o=(n||"txt").toUpperCase();return`<div class="art-card" onclick="openArtifactPanel('${e}')" role="button" tabindex="0">\n <div class="art-card-ic"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg></div>\n <div class="art-card-body">\n <div class="art-card-title">${esc(t)}</div>\n <div class="art-card-sub">${o} · ${a} baris</div>\n </div>\n <button class="art-card-dl" onclick="event.stopPropagation();downloadArtifact('${e}')" title="Unduh">\n <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>\n </button>\n </div>`}function esc(e){return String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}window.addEventListener("message",e=>{if(!e.data||!e.data.__pvConsole)return;const t=document.getElementById("pv-console-body"),n=t.querySelector(".pv-console-empty");n&&n.remove();const a=e.data.level||"log",o=document.createElement("div");o.className="pv-log "+a;if(o.innerHTML=`<span class="pv-log-ic">${{error:"⛔",warn:"⚠️",info:"ℹ️",log:"▸"}[a]||"▸"}</span><span class="pv-log-txt"></span>`,o.querySelector(".pv-log-txt").textContent=e.data.text||"",t.appendChild(o),t.scrollTop=t.scrollHeight,"error"===a){_pvState.errCount=(_pvState.errCount||0)+1;const e=document.getElementById("pv-console-count");e.textContent=String(_pvState.errCount),e.style.display="inline-block"}});let _dlgResolve=null;function _dlgShow({title:e,msg:t,isPrompt:n,defaultValue:a,okLabel:o,okDanger:s}){return new Promise(i=>{_dlgResolve=i,document.getElementById("dlg-title").textContent=e||"",document.getElementById("dlg-msg").textContent=t||"";const r=document.getElementById("dlg-input");r.classList.toggle("show",!!n),r.value=n&&a||"";const l=document.getElementById("dlg-ok");l.textContent=o||"OK",l.className="dlg-btn "+(s?"danger":"primary"),document.getElementById("dlg-ov").classList.add("on"),document.getElementById("dlg-box").classList.add("on"),n&&setTimeout(()=>r.focus(),50)})}function _dlgClose(){document.getElementById("dlg-ov").classList.remove("on"),document.getElementById("dlg-box").classList.remove("on")}function _dlgConfirm(){const e=!document.getElementById("dlg-input").classList.contains("show")||document.getElementById("dlg-input").value;_dlgClose(),_dlgResolve&&_dlgResolve(e),_dlgResolve=null}function _dlgCancel(){const e=document.getElementById("dlg-input").classList.contains("show");_dlgClose(),_dlgResolve&&_dlgResolve(!!e&&null),_dlgResolve=null}function showConfirm(e,t={}){return _dlgShow({title:t.title||"Konfirmasi",msg:e,isPrompt:!1,okLabel:t.okLabel||"OK",okDanger:t.danger})}function showPrompt(e,t="",n={}){return _dlgShow({title:n.title||"Masukkan teks",msg:e,isPrompt:!0,defaultValue:t,okLabel:n.okLabel||"OK"})}function getArtifactStore(){try{return JSON.parse(localStorage.getItem("f24t-artifacts")||"{}")}catch(e){return{}}}function saveArtifactStore(e){try{localStorage.setItem("f24t-artifacts",JSON.stringify(e))}catch(e){console.warn("Gagal menyimpan artefak (localStorage penuh?)")}}function registerArtifact({id:e,title:t,lang:n,code:a}){const o=getArtifactStore();o[e]={id:e,title:t,lang:n,code:a,chatId:G.activeChatId||null,createdAt:Date.now()},saveArtifactStore(o)}function artifactExtFor(e){return{html:"html",htm:"html",javascript:"js",js:"js",python:"py",py:"py",css:"css",json:"json",svg:"svg",typescript:"ts",ts:"ts",tsx:"tsx",jsx:"jsx",markdown:"md",md:"md"}[(e||"").toLowerCase()]||"txt"}function openArtifactPanel(e){const t=getArtifactStore()[e];if(!t)return void showToast("Artefak tidak ditemukan (mungkin riwayat sudah dihapus)","error");const n=document.getElementById("art-panel"),a=["html","htm","svg"].includes((t.lang||"").toLowerCase());document.getElementById("art-panel-title").textContent=t.title,document.getElementById("art-panel-sub").textContent=(t.lang||"txt").toUpperCase();const o=document.getElementById("art-panel-code");o.textContent=t.code,o.className="language-"+(t.lang||"plaintext");try{G.hlOn&&hljs.highlightElement(o)}catch(e){}document.getElementById("art-tab-preview").style.display=a?"flex":"none",document.getElementById("art-panel-dl").onclick=()=>downloadArtifact(e),document.getElementById("art-panel-copy").onclick=()=>copyArtifactCode(e),n.dataset.artId=e,artShowTab(a?"preview":"code"),n.classList.add("open"),document.getElementById("art-panel-ov").classList.add("on")}function closeArtifactPanel(){document.getElementById("art-panel").classList.remove("open"),document.getElementById("art-panel-ov").classList.remove("on")}function artShowTab(e){const t=getArtifactStore()[document.getElementById("art-panel").dataset.artId];document.getElementById("art-tab-code").classList.toggle("act","code"===e),document.getElementById("art-tab-preview").classList.toggle("act","preview"===e),document.getElementById("art-panel-codewrap").style.display="code"===e?"block":"none";if(document.getElementById("art-panel-previewwrap").style.display="preview"===e?"block":"none","preview"===e&&t){const e=document.getElementById("art-panel-iframe"),n="svg"===(t.lang||"").toLowerCase();e.srcdoc=n?`<!DOCTYPE html><html><body style="margin:0;display:flex;align-items:center;justify-content:center;min-height:100vh;background:#fff">${t.code} </body></html>`:t.code}}function downloadArtifact(e){const t=getArtifactStore()[e];if(!t)return void showToast("Artefak tidak ditemukan","error");const n=artifactExtFor(t.lang),a=new Blob([t.code],{type:"text/plain"}),o=URL.createObjectURL(a),s=document.createElement("a");s.href=o,s.download=(t.title||"artefak").replace(/[^\w\-. ]/g,"_")+"."+n,document.body.appendChild(s),s.click(),s.remove(),setTimeout(()=>URL.revokeObjectURL(o),1e3),showToast("Mengunduh "+t.title,"success")}function copyArtifactCode(e){const t=getArtifactStore()[e];t?copyTxt(t.code):showToast("Artefak tidak ditemukan","error")}function deleteArtifact(e){const t=getArtifactStore();delete t[e],saveArtifactStore(t)}function copyTxt(e){const t=String(e||"");t?navigator.clipboard&&window.isSecureContext?navigator.clipboard.writeText(t).then(()=>showToast("Teks berhasil disalin","success")).catch(()=>_execCopy(t)):_execCopy(t):showToast("Tidak ada teks untuk disalin","warning")}function _execCopy(e){try{const t=document.createElement("textarea");t.value=e,t.style.cssText="position:fixed;left:-9999px;top:-9999px;opacity:0",document.body.appendChild(t),t.focus(),t.select();const n=document.execCommand("copy");document.body.removeChild(t),showToast(n?"Teks berhasil disalin":"Tekan Ctrl+C untuk menyalin",n?"success":"info")}catch(e){showToast("Tekan Ctrl+C untuk menyalin","info")}}function scrollBot(){const e=document.getElementById("ca");setTimeout(()=>{e.scrollTop=e.scrollHeight},30)} let _mjActive=-1,_mjResizeBound=false; function mjRefresh(){ const wrap=document.getElementById("msg-jump"); const ca=document.getElementById("ca"); const msgs=document.getElementById("msgs"); if(!wrap||!ca||!msgs)return; const items=Array.from(msgs.children); if(items.length<2){wrap.classList.remove("show");return} wrap.classList.add("show"); const dotsWrap=document.getElementById("mj-dots"); if(dotsWrap.children.length!==items.length){ dotsWrap.innerHTML=""; items.forEach((_,i)=>{ const d=document.createElement("div"); d.className="mj-dot"; d.onclick=()=>mjGoTo(i); dotsWrap.appendChild(d); }); } if(!_mjResizeBound){_mjResizeBound=true;ca.addEventListener("scroll",mjUpdateActive,{passive:true});window.addEventListener("resize",mjUpdateActive);} mjUpdateActive(); } function mjUpdateActive(){ const ca=document.getElementById("ca"); const msgs=document.getElementById("msgs"); if(!ca||!msgs)return; const items=Array.from(msgs.children); if(!items.length)return; const caRect=ca.getBoundingClientRect(); const mid=caRect.top+caRect.height/2; let closest=0,closestDist=Infinity; items.forEach((el,i)=>{ const r=el.getBoundingClientRect(); const c=r.top+r.height/2; const d=Math.abs(c-mid); if(d<closestDist){closestDist=d;closest=i} }); _mjActive=closest; document.querySelectorAll("#mj-dots .mj-dot").forEach((d,i)=>d.classList.toggle("act",i===closest)); document.getElementById("mj-up").classList.toggle("disabled",closest<=0); document.getElementById("mj-down").classList.toggle("disabled",closest>=items.length-1); } function mjGoTo(i){ const msgs=document.getElementById("msgs"); if(!msgs)return; const items=Array.from(msgs.children); const el=items[i]; if(!el)return; el.scrollIntoView({behavior:"smooth",block:"start"}); } function mjNav(dir){ const msgs=document.getElementById("msgs"); if(!msgs)return; const items=Array.from(msgs.children); let target=_mjActive+dir; target=Math.max(0,Math.min(items.length-1,target)); mjGoTo(target); } const _mjObserver=new MutationObserver(()=>mjRefresh()); document.addEventListener("DOMContentLoaded",()=>{ const msgs=document.getElementById("msgs"); if(msgs){_mjObserver.observe(msgs,{childList:true});mjRefresh()} });function logoSVG(e){return`<svg class="ma-logo" width="${e}" height="${e}" viewBox="0 0 100 100" fill="none"><circle cx="50" cy="50" r="44" stroke="rgb(207,100,58)" stroke-width="7" stroke-linecap="round" stroke-dasharray="210 60" opacity=".9"/><circle cx="50" cy="50" r="30" stroke="rgb(195,85,40)" stroke-width="5.5" stroke-linecap="round" stroke-dasharray="140 38" opacity=".7"/><circle cx="50" cy="50" r="16" stroke="rgb(207,100,58)" stroke-width="4" stroke-linecap="round" stroke-dasharray="78 18"/><circle cx="50" cy="50" r="7" fill="rgb(207,100,58)" opacity=".85"/></svg>`}document.addEventListener("keydown",e=>{document.getElementById("dlg-box").classList.contains("on")&&("Enter"===e.key&&_dlgConfirm(),"Escape"===e.key&&_dlgCancel())});const TOAST_ICONS={success:'<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>',error:'<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',info:'<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>',warning:'<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>'};function showToast(e,t="info",n=2800){const a=document.getElementById("toast-wrap");if(!a)return;const o=String(e).replace(/^[✅❌⚠️👍👎🎉🔥⚡💾📖🔍⭐]+\s*/,"").replace(/\s*[✅❌⚠️👍👎🎉🔥⚡💾📖🔍⭐]+$/,"");let s=t;e.startsWith("✅")||e.startsWith("👍")?s="success":e.startsWith("❌")?s="error":e.startsWith("⚠️")&&(s="warning");const i=document.createElement("div");i.className="toast-item",i.innerHTML=`<div class="toast-ic ${s}">${TOAST_ICONS[s]||TOAST_ICONS.info}</div><span class="toast-msg">${esc(o||e)}</span><span class="toast-close" onclick="this.parentElement.remove()"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></span>`,a.appendChild(i),requestAnimationFrame(()=>requestAnimationFrame(()=>i.classList.add("show")));const r=setTimeout(()=>{i.classList.add("out"),setTimeout(()=>i.remove(),280)},n);i.querySelector(".toast-close").addEventListener("click",()=>{clearTimeout(r),i.remove()})}function loginGoogle(){fbOk&&auth?auth.signInWithPopup(new firebase.auth.GoogleAuthProvider).catch(e=>showToast(e.message,"error")):dLogin({displayName:"Google User",email:"user@gmail.com"})}function loginGithub(){fbOk&&auth?auth.signInWithPopup(new firebase.auth.GithubAuthProvider).catch(e=>showToast(e.message,"error")):dLogin({displayName:"GitHub User",email:"user@github.com"})}function loginGuest(){fbOk&&auth?auth.signInAnonymously().catch(e=>showToast(e.message,"error")):dLogin({displayName:"Guest",email:null})}function loginEmail(){const e=document.getElementById("ae").value.trim(),t=document.getElementById("ap-pass").value;e&&t?(setErr(""),setSub(!0),fbOk&&auth?G.isSignup?auth.createUserWithEmailAndPassword(e,t).catch(e=>{setErr(e.message),setSub(!1)}):auth.signInWithEmailAndPassword(e,t).catch(e=>{setErr(e.message),setSub(!1)}):setTimeout(()=>{dLogin({displayName:e.split("@")[0],email:e}),setSub(!1)},700)):setErr("Isi semua kolom.")}function dLogin(e){G.user=e,sessionStorage.setItem("f24t-su",JSON.stringify(e)),onLogin(e)}function onLogin(e){const t=document.getElementById("auth");t&&(t.style.display="none");const n=document.getElementById("app");n&&n.classList.add("on");const a=e.displayName||e.name||e.email||"Guest",o=a[0].toUpperCase();["unm","ppnm"].forEach(e=>{const t=document.getElementById(e);t&&(t.textContent=a)}),["uav","ppav"].forEach(e=>{const t=document.getElementById(e);if(!t)return;let n=null;t.childNodes.forEach(e=>{3!==e.nodeType||n||(n=e)}),n?n.textContent=o:t.prepend(document.createTextNode(o))});const s=document.getElementById("ppem");s&&(s.textContent=e.email||"Guest session"),(function(){let av=e.photoURL;if(!av){try{av=localStorage.getItem("f24t-avatar")}catch(_){}if(av)e.photoURL=av}if(av)["uav","ppav"].forEach(t=>{const n=document.getElementById(t);n&&(n.style.backgroundImage=`url(${av})`,n.style.backgroundSize="cover",n.style.backgroundPosition="center",n.childNodes.forEach(e=>{3===e.nodeType&&(e.textContent="")}))})})(),applyAbyzUI(),renderHist(),updateThemeUI(),updateHLToggle(),updateUsageUI(),updateProfileStats(),syncPlanFromServer(),document.querySelectorAll(".mo").forEach(e=>{const t=e.dataset.m===G.model;e.classList.toggle("sel",t);const n=e.querySelector(".mochk");if(n&&n.remove(),t){const t=document.createElementNS("http://www.w3.org/2000/svg","svg");t.setAttribute("class","mochk"),t.setAttribute("width","13"),t.setAttribute("height","13"),t.setAttribute("viewBox","0 0 24 24"),t.setAttribute("fill","none"),t.setAttribute("stroke","currentColor"),t.setAttribute("stroke-width","2.5");const n=document.createElementNS("http://www.w3.org/2000/svg","polyline");n.setAttribute("points","20 6 9 17 4 12"),t.appendChild(n),e.appendChild(t)}});const i=document.getElementById("mnm");i&&(i.textContent=G.model),updateModelUI()}function showAuth(){document.getElementById("auth").style.display="flex"}function setErr(e){const t=document.getElementById("aerr");t.textContent=e,t.style.display=e?"block":"none"}function setSub(e){const t=document.getElementById("asb");t.disabled=e,t.textContent=e?"Processing...":G.isSignup?"Create account":"Sign in"}function toggleMode(){G.isSignup=!G.isSignup,document.getElementById("ah").textContent=G.isSignup?"Create account":"Welcome back",document.getElementById("asub").textContent=G.isSignup?"Join F24nT ai today":"Sign in to continue",document.getElementById("atgt").textContent=G.isSignup?"Already have an account?":"Don't have an account?",document.getElementById("atgl").textContent=G.isSignup?" Sign in":" Sign up",document.getElementById("asb").textContent=G.isSignup?"Create account":"Sign in",setErr("")}function doSignOut(){closeProfile(),fbOk&&auth&&auth.signOut(),sessionStorage.removeItem("f24t-su"),location.reload()}function applyAbyzUI(){const $=e=>document.getElementById(e),e=$("sb-abyz-badge"),t=$("pp-upgrade-cta"),n=$("pp-abyz-info"),a=$("ppplan"),o=$("stg-abyz-status"),s=$("upgrade-topbtn"),i=$("pp-reset-note");if(G.isAbyz){const r=G.isGokil?"Gokil Plan":"Abyz Plan";e&&(e.style.display="inline-flex",e.textContent=G.isGokil?"GOKIL":"ABYZ"),t&&(t.style.display="none"),n&&(n.style.display="block",n.innerHTML=`<div style="display:flex;align-items:center;gap:8px;font-size:13.5px;font-weight:600;color:var(--abyz)"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>${r} aktif</div><div style="font-size:12px;color:rgb(var(--tx3));margin-top:4px">Akun: ${esc(G.abyzUser||"-")}</div>`),a&&(a.className="ppplan abyz",a.innerHTML=`<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>${r}`),o&&(o.textContent=`${r} aktif`),s&&(s.style.display="none"),i&&(i.textContent="Unlimited — tanpa batas pesan"),document.querySelectorAll(".mo-lock").forEach(e=>e.style.display="none");const l=$("sb-gokil-btn");l&&(l.style.display=G.isGokil?"flex":"none")}else{e&&(e.style.display="none"),t&&(t.style.display=""),n&&(n.style.display="none"),a&&(a.className="ppplan",a.innerHTML='<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>Free Plan'),o&&(o.textContent="Upgrade to Abyz Plan"),s&&(s.style.display=""),i&&(i.textContent="Resets every 30 minutes"),document.querySelectorAll(".mo-lock").forEach(e=>e.style.display="");const r=$("sb-gokil-btn");r&&(r.style.display="none")}updateUsageUI()}function updateUsageUI(){const $=e=>document.getElementById(e);if(G.isAbyz)return $("usage-txt")&&($("usage-txt").textContent="∞"),$("usage-pill")&&($("usage-pill").className=""),$("pp-usage")&&($("pp-usage").textContent="Unlimited"),void($("pp-ubar")&&($("pp-ubar").style.width="0%"));const e=Math.min(100,G.usage/100*100);$("usage-txt")&&($("usage-txt").textContent=`${G.usage}/100`),$("pp-usage")&&($("pp-usage").textContent=`${G.usage} / 100`),$("pp-ubar")&&($("pp-ubar").style.width=e+"%"),$("usage-pill")&&($("usage-pill").className=e>=100?"full":e>=80?"warn":"")}function checkUsage(){return!!G.isAbyz||(G.usageStart||(G.usageStart=Date.now()),Date.now()-G.usageStart>18e5&&(G.usage=0,G.usageStart=Date.now()),!(G.usage>=100)||(showRateLimit(),!1))}function showRateLimit(){document.getElementById("rate-overlay").classList.add("on");const e=Math.max(0,18e5-(Date.now()-G.usageStart));let t=Math.ceil(e/1e3);const n=document.getElementById("ro-timer");clearInterval(G.resetTimer),G.resetTimer=setInterval(()=>{t--;const e=Math.floor(t/60),a=t%60;n.textContent=`${String(e).padStart(2,"0")}:${String(a).padStart(2,"0")}`,t<=0&&(clearInterval(G.resetTimer),G.usage=0,G.usageStart=0,save(),closeRateLimit(),showToast("Pesan sudah direset!"))},1e3)}function closeRateLimit(){document.getElementById("rate-overlay").classList.remove("on"),clearInterval(G.resetTimer)}function usePill(e){const t=document.getElementById("ita");t.value=e.textContent.trim(),onInput(t),t.focus()}function openUpgrade(){location.href="/plan"}function closeUpgrade(){const e=document.getElementById("upgrade-modal");e&&e.classList.remove("on")}function openCodeModal(e){location.href="/plan"} // Catatan: aktivasi plan lewat kredensial hardcoded (ABYZ_CREDS/GOKIL_CREDS) sudah dihapus demi keamanan. // Upgrade plan sekarang HARUS lewat pembayaran QRIS asli di /plan (terverifikasi otomatis via XentralPay). async function syncPlanFromServer(){ try{ let devId=localStorage.getItem("f24t-device-id"); if(!devId){devId="dev_"+Date.now().toString(36)+"_"+Math.random().toString(36).slice(2,10);localStorage.setItem("f24t-device-id",devId)} const res=await fetch("/api/user/plan?deviceId="+encodeURIComponent(devId)); const result=await res.json(); if(result.success&&result.data.active){ G.isAbyz=!0;G.abyzUser=devId;G.isGokil=result.data.plan==="gokil"; applyAbyzUI();save() } }catch(e){} }const API_PROVIDERS=["OpenAI","Gemini","Claude","Groq","Together","Mistral","Custom"];function openGokilSettings(){if(!G.isGokil)return showToast("Fitur ini khusus untuk Gokil Plan","warning"),void openUpgrade();const e=document.getElementById("ai-name-inp");e&&(e.value=G.aiName||"");const t=document.getElementById("sys-prompt-ta");t&&(t.value=G.sysPrompt||"");const n=document.getElementById("sys-prompt-count");n&&(n.textContent=`${(G.sysPrompt||"").length} / 1000`),document.querySelectorAll(".pers-opt").forEach(e=>e.classList.toggle("sel",e.dataset.v===G.aiPersonality));const a=document.getElementById("api-rows");if(a){a.innerHTML="";(G.gokilApis&&G.gokilApis.length?G.gokilApis:[{provider:"OpenAI",key:""}]).forEach(e=>addApiRow(e.provider,e.key))}t&&(t.oninput=()=>{n&&(n.textContent=`${t.value.length} / 1000`)});const o=document.getElementById("pers-opts");o&&!o._wired&&(o._wired=!0,o.addEventListener("click",e=>{const t=e.target.closest(".pers-opt");t&&(document.querySelectorAll(".pers-opt").forEach(e=>e.classList.remove("sel")),t.classList.add("sel"))})),openModal("gokil-modal")}function addApiRow(e,t){const n=document.getElementById("api-rows");if(!n)return;const a=document.createElement("div");a.className="api-row";const o=API_PROVIDERS.map(t=>`<option value="${t}"${t===(e||"OpenAI")?" selected":""}>${t}</option>`).join("");a.innerHTML=`<select>${o}</select><input type="text" placeholder="Masukkan API key…" value="${esc(t||"")}" autocomplete="off"/><button class="api-del" onclick="this.closest('.api-row').remove()" title="Hapus"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>`,n.appendChild(a)}function saveGokilSettings(){if(!G.isGokil)return void showToast("Fitur ini khusus untuk Gokil Plan","warning");const e=[];document.querySelectorAll("#api-rows .api-row").forEach(t=>{const n=t.querySelector("select")?.value||"OpenAI",a=t.querySelector("input")?.value.trim()||"";a&&e.push({provider:n,key:a})}),G.gokilApis=e;const t=document.getElementById("ai-name-inp");G.aiName=t?.value.trim()||"F24nT ai";const n=document.querySelector(".pers-opt.sel");G.aiPersonality=n?.dataset.v||"helpful";const a=document.getElementById("sys-prompt-ta");G.sysPrompt=a?.value.trim()||"",save(),closeModal("gokil-modal"),showToast("Pengaturan Gokil berhasil disimpan","success");const o=document.getElementById("mnm");o&&G.aiName&&(o.textContent=G.model)}const ADM_KEY="f24t_adm_users",ADM_BANNED_IPS="f24t_adm_bips",ADM_SESSIONS="f24t_adm_sess";let _admFilter="all",_userIP="";async function getMyIP(){try{const e=await fetch("https://api.ipify.org?format=json",{signal:AbortSignal.timeout(4e3)});return(await e.json()).ip||""}catch(e){try{const e=await fetch("https://api64.ipify.org?format=json",{signal:AbortSignal.timeout(3e3)});return(await e.json()).ip||""}catch(e){return""}}}function admGetUsers(){try{return JSON.parse(localStorage.getItem(ADM_KEY)||"{}")}catch(e){return{}}}function admSaveUsers(e){localStorage.setItem(ADM_KEY,JSON.stringify(e))}function admGetBannedIPs(){try{return JSON.parse(localStorage.getItem(ADM_BANNED_IPS)||"[]")}catch(e){return[]}}function admSaveBannedIPs(e){localStorage.setItem(ADM_BANNED_IPS,JSON.stringify(e))}function admGetSessions(){try{return JSON.parse(localStorage.getItem(ADM_SESSIONS)||"{}")}catch(e){return{}}}function admSaveSessions(e){localStorage.setItem(ADM_SESSIONS,JSON.stringify(e))}async function bootBanCheck(){_userIP=await getMyIP();const e=admGetBannedIPs();if(_userIP&&e.includes(_userIP))return showBanScreen("IP Anda telah diblokir oleh administrator.","IP:"+_userIP),!1;const t=localStorage.getItem("f24t-adm-username")||"";if(t){const e=admGetUsers()[t];if(e){if(e.ipBanned&&_userIP)return showBanScreen("Akun dan perangkat Anda telah diblokir secara permanen.","USR:"+t+"/IP:"+_userIP),!1;if(e.banned)return showBanScreen(e.bannedReason||"Akun Anda telah ditangguhkan oleh administrator.","BAN:"+t),!1}}return!0}function showBanScreen(e,t){document.getElementById("ban-reason").textContent=e,document.getElementById("ban-code").textContent=t||"";document.getElementById("ban-screen").style.display="flex",["ls","auth","app"].forEach(e=>{const t=document.getElementById(e);t&&(t.style.display="none")})}function checkAdminRoute(){if((location.hash||location.search).includes("yoenadmin")||location.pathname.endsWith("/yoenadmin")){location.href="/yoenadmin";return!0}return!1}function admLogin(){console.warn("Panel admin lama sudah dinonaktifkan demi keamanan. Gunakan /yoenadmin (panel baru dengan auth server-side).")}function admLogout(){document.getElementById("adm-login").style.display="flex",document.getElementById("adm-dash").style.display="none",document.getElementById("adm-pw").value=""}function admRender(){admRenderStats(),admRenderList(),admRenderIPs()}function admRenderStats(){const e=admGetUsers(),t=Object.values(e),n=[{label:"Total User",val:t.length,color:"var(--clay)"},{label:"Abyz Plan",val:t.filter(e=>"abyz"===e.plan&&!e.banned).length,color:"rgb(139,92,246)"},{label:"Gokil Plan",val:t.filter(e=>"gokil"===e.plan&&!e.banned).length,color:"rgb(245,158,11)"},{label:"Dibanned",val:t.filter(e=>e.banned||e.ipBanned).length,color:"rgb(220,38,38)"}],a=document.getElementById("adm-stats");a&&(a.innerHTML=n.map(e=>`<div style="background:rgb(var(--bg0));border:1px solid rgba(var(--br1),.6);border-radius:12px;padding:14px 16px"><div style="font-size:24px;font-weight:700;color:${e.color};letter-spacing:-.02em">${e.val}</div><div style="font-size:12px;color:rgb(var(--tx4));margin-top:3px">${e.label}</div></div>`).join(""))}function admSetFilter(e){_admFilter=e,document.querySelectorAll(".adm-tab").forEach(t=>{const n=t.dataset.f===e;t.style.background=n?"rgb(var(--tx0))":"rgb(var(--bg0))",t.style.color=n?"rgb(var(--bg0))":"rgb(var(--tx2))"}),admRenderList()}function admRenderList(){const e=admGetUsers(),t=(document.getElementById("adm-search")?.value||"").toLowerCase();let n=Object.entries(e);t&&(n=n.filter(([e])=>e.toLowerCase().includes(t))),"abyz"===_admFilter?n=n.filter(([,e])=>"abyz"===e.plan&&!e.banned&&!e.ipBanned):"gokil"===_admFilter?n=n.filter(([,e])=>"gokil"===e.plan&&!e.banned&&!e.ipBanned):"banned"===_admFilter&&(n=n.filter(([,e])=>e.banned||e.ipBanned));const a=document.getElementById("adm-list");a&&(n.length?a.innerHTML=n.map(([e,t])=>{const n=t.banned||t.ipBanned,a="gokil"===t.plan?"rgb(245,158,11)":"rgb(139,92,246)",o=t.addedAt?new Date(t.addedAt).toLocaleDateString("id-ID",{day:"2-digit",month:"short",year:"numeric"}):"—";return`<div style="background:rgb(var(--bg0));border:1px solid rgba(var(--br1),${n?".9":".6"});border-radius:12px;padding:14px 16px;${n?"border-color:rgba(220,38,38,.3);background:rgba(220,38,38,.03)":""}"><div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap"><div style="width:34px;height:34px;border-radius:50%;background:${n?"rgba(220,38,38,.15)":"rgba(var(--bg3),1)"};display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;color:${n?"rgb(220,38,38)":a};flex-shrink:0">${e[0].toUpperCase()}</div><div style="flex:1;min-width:0"><div style="display:flex;align-items:center;gap:7px;flex-wrap:wrap"><span style="font-size:14px;font-weight:600;color:rgb(var(--tx0))">${e}</span>${n?'<span style="font-size:10px;font-weight:700;background:rgba(220,38,38,.1);color:rgb(220,38,38);padding:1px 7px;border-radius:10px;border:1px solid rgba(220,38,38,.2)">BANNED</span>':""}<span style="font-size:10px;font-weight:700;background:rgba(var(--bg2),1);color:${a};padding:1px 7px;border-radius:10px;border:1px solid rgba(var(--br1),.5)">${(t.plan||"abyz").toUpperCase()}</span></div><div style="font-size:11.5px;color:rgb(var(--tx4));margin-top:2px">IP: ${t.ip||"Belum digunakan"} · Ditambah: ${o}${t.bannedReason?` · Alasan: ${t.bannedReason}`:""}</div></div><div style="display:flex;gap:6px;flex-wrap:wrap;flex-shrink:0">${n?`<button onclick="admUnban('${e}')" style="padding:5px 11px;border-radius:7px;border:1px solid rgba(34,197,94,.4);font-size:12px;color:rgb(22,163,74);background:rgba(34,197,94,.05);cursor:pointer">Unban</button>`:`<button onclick="admRevokePlan('${e}')" style="padding:5px 11px;border-radius:7px;border:1px solid rgba(var(--br1),.8);font-size:12px;color:rgb(var(--tx2));background:rgb(var(--bg1));cursor:pointer" title="Cabut plan">Cabut Plan</button><button onclick="admBanUser('${e}')" style="padding:5px 11px;border-radius:7px;border:1px solid rgba(245,158,11,.4);font-size:12px;color:rgb(217,119,6);background:rgba(245,158,11,.05);cursor:pointer" title="Banned akun">Ban Akun</button><button onclick="admBanIPUser('${e}')" style="padding:5px 11px;border-radius:7px;border:1px solid rgba(220,38,38,.3);font-size:12px;color:rgb(220,38,38);background:rgba(220,38,38,.05);cursor:pointer" title="Ban IP">Ban IP</button>`}<button onclick="admDeleteUser('${e}')" style="padding:5px 11px;border-radius:7px;border:1px solid rgba(220,38,38,.3);font-size:12px;color:rgb(220,38,38);background:rgba(220,38,38,.04);cursor:pointer">Hapus</button></div></div></div>`}).join(""):a.innerHTML='<div style="text-align:center;padding:32px;color:rgb(var(--tx4));font-size:13.5px">Tidak ada pengguna ditemukan</div>')}function admRenderIPs(){const e=admGetBannedIPs(),t=document.getElementById("adm-ip-list");t&&(e.length?t.innerHTML=e.map(e=>`<span style="display:inline-flex;align-items:center;gap:5px;padding:3px 10px;background:rgba(220,38,38,.07);border:1px solid rgba(220,38,38,.2);border-radius:20px;font-size:12px;color:rgb(220,38,38)">${e}<button onclick="admUnbanIP('${e}')" style="background:none;border:none;cursor:pointer;color:rgb(220,38,38);font-size:11px;padding:0;line-height:1" title="Unban IP">✕</button></span>`).join(""):t.innerHTML='<span style="font-size:12.5px;color:rgb(var(--tx4))">Tidak ada IP yang diblokir</span>')}function admAddUser(){const e=(document.getElementById("adm-new-user")?.value||"").trim().toLowerCase(),t=(document.getElementById("adm-new-pass")?.value||"").trim(),n=document.getElementById("adm-new-plan")?.value||"abyz",a=document.getElementById("adm-add-msg");if(!e||!t)return void(a&&(a.textContent="Username dan password wajib diisi.",a.style.color="rgb(220,38,38)",a.style.display="block"));const o=admGetUsers();o[e]?a&&(a.textContent="Username sudah ada.",a.style.color="rgb(220,38,38)",a.style.display="block"):(o[e]={pass:t,plan:n,ip:null,banned:!1,ipBanned:!1,bannedReason:"",addedAt:Date.now(),lastActive:null},admSaveUsers(o),document.getElementById("adm-new-user").value="",document.getElementById("adm-new-pass").value="",a&&(a.textContent=`Pengguna "${e}" berhasil ditambahkan dengan ${n.toUpperCase()} Plan.`,a.style.color="rgb(22,163,74)",a.style.display="block"),setTimeout(()=>{a&&(a.style.display="none")},3e3),admRender())}async function admRevokePlan(e){if(!await showConfirm(`Cabut plan dari "${e}"?`,{title:"Cabut plan",okLabel:"Cabut",danger:!0}))return;const t=admGetUsers();t[e]&&(t[e].plan=null,admSaveUsers(t),admRender())}async function admBanUser(e){const t=await showPrompt(`Alasan ban untuk "${e}" (opsional):`,"",{title:"Ban pengguna"})||"Pelanggaran kebijakan penggunaan.",n=admGetUsers();n[e]&&(n[e].banned=!0,n[e].bannedReason=t,n[e].plan=null,admSaveUsers(n),admRender())}async function admBanIPUser(e){const t=admGetUsers();if(!t[e])return;const n=t[e].ip,a=await showPrompt(`Ban IP + akun "${e}"? IP: ${n||"(belum ada)"}\nAlasan (opsional):`,"",{title:"Ban IP + akun"})||"Pelanggaran berat.";if(t[e].banned=!0,t[e].ipBanned=!0,t[e].bannedReason=a,t[e].plan=null,admSaveUsers(t),n){const e=admGetBannedIPs();e.includes(n)||e.push(n),admSaveBannedIPs(e)}admRender()}function admBanIPManual(){const e=(document.getElementById("adm-ban-ip-inp")?.value||"").trim();if(!e)return;const t=admGetBannedIPs();t.includes(e)||t.push(e),admSaveBannedIPs(t),document.getElementById("adm-ban-ip-inp").value="",admRender()}function admUnban(e){const t=admGetUsers();t[e]&&(t[e].banned=!1,t[e].ipBanned=!1,t[e].bannedReason="",admSaveUsers(t),admRender())}function admUnbanIP(e){admSaveBannedIPs(admGetBannedIPs().filter(t=>t!==e)),admRender()}async function admDeleteUser(e){if(!await showConfirm(`Hapus permanen pengguna "${e}"? Tindakan ini tidak bisa dibatalkan.`,{title:"Hapus pengguna",okLabel:"Hapus",danger:!0}))return;const t=admGetUsers();delete t[e],admSaveUsers(t),admRender()}function openChatFromUrl(){const e=location.pathname.match(/^\/chat\/([A-Za-z0-9_-]+)/);if(!e)return;const t=e[1];cs()[t]?loadChat(t):(showToast("Percakapan tidak ditemukan","warning"),syncUrl("/app"))}function bnavSetActive(e){document.querySelectorAll(".bn-item").forEach(e=>e.classList.remove("act")),e&&e.classList.add("act")}function bnavGo(e,t){switch(e){case"chats":bnavSetActive(t),closeAllPanels(),"function"==typeof showChats&&showChats(),document.getElementById("sb").classList.contains("open")&&closeSb();break;case"star":bnavSetActive(t),closeAllPanels(),"function"==typeof showStarred&&showStarred(),openSb();break;case"new":bnavSetActive(document.getElementById("bn-chats")),closeAllPanels(),"function"==typeof newChat&&newChat(),closeSb();break;case"tools":location.href="/tools";break;case"profile":bnavSetActive(t),"function"==typeof openProfile&&openProfile()}}function openSb(){const e=document.getElementById("sb"),t=document.getElementById("sbov");e&&e.classList.add("open"),t&&t.classList.add("on")}window.addEventListener("popstate",()=>{const e=location.pathname.match(/^\/chat\/([A-Za-z0-9_-]+)/);e&&cs()[e[1]]?loadChat(e[1]):(location.pathname.startsWith("/app")||"/"===location.pathname)&&newChat()}),// ── FAILSAFE: loading screen ALWAYS dismisses regardless of JS errors ── (function(){function _dismissLS(){var ls=document.getElementById('ls');if(ls&&ls.style.display!=='none'){ls.classList.add('out');setTimeout(function(){ls.style.display='none'},500)}}setTimeout(_dismissLS,2500);document.addEventListener('DOMContentLoaded',function(){setTimeout(_dismissLS,1600)})})(); window.addEventListener("DOMContentLoaded",()=>{try{load(),applyTheme(G.theme),initDesktopSb(),renderHist(),openChatFromUrl()}catch(e){console.warn('[F24nT] boot error',e)}try{const e=new URLSearchParams(location.search).get("tool");e&&setTimeout(()=>{"function"==typeof useTool&&useTool(e),openPanel("p-tools"),history.replaceState({},"",location.pathname)},50);new URLSearchParams(location.search).get("openProfile")&&setTimeout(()=>{"function"==typeof openProfile&&openProfile(),history.replaceState({},"",location.pathname)},400)}catch(e){console.warn('[F24nT] url params error',e)}try{const t=document.getElementById("mnm");if(t&&(t.textContent=G.model),fbOk&&auth)auth.onAuthStateChanged(e=>{e?(G.user=e,onLogin(e)):showAuth()});else{const e=sessionStorage.getItem("f24t-su");if(e){const t=JSON.parse(e);G.user=t,onLogin(t)}else showAuth()}}catch(e){console.warn('[F24nT] auth error',e);try{showAuth()}catch(_){}}}),function initKeyboardAware(){if(!window.visualViewport)return;const e=window.visualViewport;let t=e.height;const n=document.getElementById("app"),a=document.getElementById("bnav-wrap");let o=!1;e.addEventListener("resize",function onVVResize(){const s=t-e.height;window.innerWidth<=768&&(s>120?(o=!0,n&&(n.style.height=e.height+"px"),a&&(a.style.display="none"),document.body.classList.add("kb-open"),setTimeout(()=>{const e=document.getElementById("ita");e&&e.scrollIntoView({block:"end",behavior:"smooth"}),scrollBot()},120)):(o&&(o=!1,n&&(n.style.height=""),a&&(a.style.display=""),document.body.classList.remove("kb-open")),t=e.height))}),e.addEventListener("resize",function(){["mdd-main","mdd","mdd-effort"].forEach(function(e){const t=document.getElementById(e);t&&t.classList.contains("on")&&positionComposerDD(t)})}),window.addEventListener("orientationchange",()=>{setTimeout(()=>{t=e.height},300)})}(); // ── KEYBOARD SHORTCUTS (PC only) ── // Shortcuts are for desktop/laptop users. On phones/tablets the virtual // keyboard never dispatches a real "Control"/"Meta" keydown event, so we // gate everything behind actually having seen a physical modifier key at // least once. This means a wireless/bluetooth keyboard connected to a // phone or tablet still works (it sends real key events), while the // on-screen keyboard never triggers shortcuts. const KBD = { hasPhysicalKeyboard: false, helpShown: false }; function _isTouchPrimary(){ try{ return matchMedia('(pointer:coarse)').matches && !matchMedia('(pointer:fine)').matches; } catch(_){ return false; } } // The very first keydown that includes a real modifier (Ctrl/Meta/Alt) or // arrives from a non-touch pointer environment marks this device as having // a usable physical keyboard, enabling the shortcuts from then on. document.addEventListener('keydown', function(e){ if(KBD.hasPhysicalKeyboard) return; if(!_isTouchPrimary()){ KBD.hasPhysicalKeyboard = true; return; } if(e.ctrlKey || e.metaKey || e.altKey){ KBD.hasPhysicalKeyboard = true; } }, true); const SHORTCUT_LIST = [ {keys:'Ctrl + K', label:'Fokus ke kotak chat'}, {keys:'Ctrl + N', label:'Obrolan baru'}, {keys:'Ctrl + O', label:'Upload file/gambar'}, {keys:'Ctrl + J', label:'Buka artefak terakhir'}, {keys:'Ctrl + B', label:'Buka/tutup sidebar'}, {keys:'Ctrl + F', label:'Aktifkan/nonaktifkan mode Search'}, {keys:'Ctrl + Shift + O', label:'Buka AI Tools (tab baru)'}, {keys:'Ctrl + Shift + P', label:'Buka Profil'}, {keys:'Ctrl + Shift + A', label:'Buka Artefak'}, {keys:'Ctrl + Shift + S', label:'Simpan/bintangi obrolan aktif'}, {keys:'Ctrl + Shift + I', label:'Mode Incognito'}, {keys:'Ctrl + /', label:'Tampilkan daftar shortcut ini'}, {keys:'Esc', label:'Tutup panel/modal yang terbuka'} ]; function showShortcutHelp(){ if(KBD.helpShown) return; const existing = document.getElementById('kbd-help-ov'); if(existing){ existing.remove(); KBD.helpShown=false; return; } KBD.helpShown = true; const ov = document.createElement('div'); ov.id = 'kbd-help-ov'; ov.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:9999;display:flex;align-items:center;justify-content:center;backdrop-filter:blur(2px)'; const rows = SHORTCUT_LIST.map(s=>`<div style="display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid rgba(var(--br1),.4)"><span style="font-size:13px;color:rgb(var(--tx2))">${esc(s.label)}</span><kbd style="font-size:12px;font-family:inherit;background:rgb(var(--bg2));border:1px solid rgba(var(--br1),.7);border-radius:6px;padding:3px 8px;color:rgb(var(--tx0))">${esc(s.keys)}</kbd></div>`).join(''); ov.innerHTML = `<div style="background:rgb(var(--bg0));border-radius:16px;max-width:380px;width:92%;max-height:80vh;overflow:auto;padding:20px;box-shadow:var(--s3)"> <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px"> <div style="font-size:15px;font-weight:700;color:rgb(var(--tx0))">Keyboard Shortcuts</div> <button onclick="closeShortcutHelp()" style="background:none;border:none;cursor:pointer;color:rgb(var(--tx3))"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button> </div> <div style="font-size:11.5px;color:rgb(var(--tx4));margin-bottom:10px">Khusus untuk pengguna PC/laptop (atau keyboard wireless yang terhubung).</div> ${rows} </div>`; ov.addEventListener('click', function(e){ if(e.target===ov) closeShortcutHelp(); }); document.body.appendChild(ov); } function closeShortcutHelp(){ const ov = document.getElementById('kbd-help-ov'); if(ov) ov.remove(); KBD.helpShown = false; } document.addEventListener('keydown', function(e){ if('Escape'===e.key){ closeModal('share-modal');closeModal('pm');closeModal('cm');closeModal('epm'); closeModal('code-modal');closeModal('gokil-modal');closeUpgrade();closeMDD();closeProfile(); closeShortcutHelp(); var ctxEl=document.getElementById('ctx'); if(ctxEl) ctxEl.classList.remove('on'); } // Every shortcut below is PC-only: on a touch-primary device without a // physical/wireless keyboard, KBD.hasPhysicalKeyboard never flips true, // so Ctrl/Meta combos silently do nothing there (as intended). if(!KBD.hasPhysicalKeyboard) return; const mod = e.ctrlKey || e.metaKey; if(!mod) return; const k = e.key.toLowerCase(); if(k==='k' && !e.shiftKey){ e.preventDefault(); const t=document.getElementById('ita'); if(t){ t.focus(); showToast('⌨️ Ctrl+K — fokus ke kotak chat','info',1600); } return; } if(k==='n' && !e.shiftKey){ e.preventDefault(); newChat(); showToast('⌨️ Ctrl+N — obrolan baru','info',1600); return; } if(k==='o' && !e.shiftKey){ e.preventDefault(); triggerFile(); showToast('⌨️ Ctrl+O — buka dialog upload file','info',1600); return; } if(k==='j' && !e.shiftKey){ e.preventDefault(); const ap=document.querySelector('.art-card'); if(ap){ ap.click(); showToast('⌨️ Ctrl+J — membuka artefak terakhir','info',1600); } else showToast('⌨️ Ctrl+J — belum ada artefak di obrolan ini','warning',1800); return; } if(k==='b' && !e.shiftKey){ e.preventDefault(); if(typeof toggleDesktopSb==='function') toggleDesktopSb(); else toggleSb(); showToast('⌨️ Ctrl+B — sidebar dibuka/ditutup','info',1600); return; } if(k==='f' && !e.shiftKey){ e.preventDefault(); if(typeof toggleSearch==='function'){ toggleSearch(); } return; } if(e.shiftKey && k==='o'){ e.preventDefault(); window.open('/tools','_blank'); showToast('⌨️ Ctrl+Shift+O — membuka AI Tools','info',1600); return; } if(e.shiftKey && k==='p'){ e.preventDefault(); if(typeof openProfile==='function'){ openProfile(); showToast('⌨️ Ctrl+Shift+P — membuka Profil','info',1600); } return; } if(e.shiftKey && k==='a'){ e.preventDefault(); window.location.href='/artifacts'; return; } if(e.shiftKey && k==='s'){ e.preventDefault(); if(typeof starCurrent==='function'){ starCurrent(); showToast('⌨️ Ctrl+Shift+S — obrolan ditandai','info',1600); } return; } if(e.shiftKey && k==='i'){ e.preventDefault(); if(typeof toggleIncog==='function'){ toggleIncog(); showToast('⌨️ Ctrl+Shift+I — mode Incognito diubah','info',1600); } return; } if(k==='/'){ e.preventDefault(); showShortcutHelp(); return; } }); ["share-modal","pm","cm","epm"].forEach(function(e){var t=document.getElementById(e);t&&t.addEventListener("click",function(n){n.target===t&&closeModal(e)})});var um=document.getElementById("upgrade-modal");um&&um.addEventListener("click",function(e){e.target===um&&closeUpgrade()});var cm2=document.getElementById("code-modal");cm2&&cm2.addEventListener("click",function(e){e.target===cm2&&closeModal("code-modal")}),document.addEventListener("click",function(e){const menu=document.getElementById("slash-menu"),ita=document.getElementById("ita");menu&&ita&&!menu.contains(e.target)&&e.target!==ita&&hideSlashMenu()}),function(){var e=document.getElementById("ita");e&&e.addEventListener("keydown",function(e){if("Enter"===e.key&&!e.shiftKey){const menu=document.getElementById("slash-menu");if(menu&&menu.style.display!=="none"&&menu._items&&menu._items.length)return;e.preventDefault(),e.stopPropagation();var t=document.getElementById("send");t&&!t.disabled&&sendMsg()}})}();</script> </body> </html>