antigravity-tc 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/tunnel.js ADDED
@@ -0,0 +1,198 @@
1
+ const { spawn, execSync } = require('child_process');
2
+ const https = require('https');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { EventEmitter } = require('events');
6
+ const { CLOUDFLARED_BIN, BIN_DIR, ensureAppDirs } = require('./paths');
7
+
8
+ class TunnelManager extends EventEmitter {
9
+ constructor({ config, port }) {
10
+ super();
11
+ this.config = config;
12
+ this.port = Number(port) || 3456;
13
+ this.childProcess = null;
14
+ this.url = null;
15
+ this.status = 'stopped';
16
+ }
17
+
18
+ get binaryPath() { return CLOUDFLARED_BIN; }
19
+
20
+ // NOTE: async karena download binary butuh await sebelum extract/rename.
21
+ async ensureBinary() {
22
+ ensureAppDirs();
23
+ if (fs.existsSync(this.binaryPath)) {
24
+ try {
25
+ if (process.platform !== 'win32') fs.chmodSync(this.binaryPath, 0o755);
26
+ this.emit('log', 'Binary cloudflared sudah tersedia — melewati download.', 'ok');
27
+ return this.binaryPath;
28
+ } catch (e) {}
29
+ }
30
+ const plat = process.platform;
31
+ const arch = process.arch;
32
+ let url, isTgz = false;
33
+ if (plat === 'darwin' && arch === 'arm64') { url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-darwin-arm64.tgz'; isTgz = true; }
34
+ else if (plat === 'darwin' && arch === 'x64') { url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-darwin-amd64.tgz'; isTgz = true; }
35
+ else if (plat === 'linux' && arch === 'arm64') { url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64'; }
36
+ else if (plat === 'linux' && arch === 'x64') { url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64'; }
37
+ else if (plat === 'win32' && arch === 'x64') { url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.exe'; }
38
+ else throw new Error(`Unsupported platform: ${plat}-${arch}`);
39
+
40
+ const tmpPath = this.binaryPath + (isTgz ? '.tgz' : '.tmp');
41
+ this.emit('log', `Mendownload cloudflared dari GitHub releases (±30 MB)... mohon tunggu.`, 'info');
42
+
43
+ // Progres download dilaporkan maksimal tiap kenaikan 5% agar log mudah dibaca.
44
+ let lastPercent = -5;
45
+ let lastReportedBytes = 0;
46
+ await this._downloadFile(url, tmpPath, (received, total) => {
47
+ if (total > 0) {
48
+ const percent = Math.floor((received / total) * 100);
49
+ if (percent - lastPercent >= 5) {
50
+ lastPercent = percent;
51
+ this.emit('log', `Mendownload cloudflared... ${percent}% (${(received / 1048576).toFixed(1)} / ${(total / 1048576).toFixed(1)} MB)`, 'info');
52
+ }
53
+ } else if (received - lastReportedBytes >= 5 * 1048576) {
54
+ lastReportedBytes = received;
55
+ this.emit('log', `Mendownload cloudflared... ${(received / 1048576).toFixed(1)} MB`, 'info');
56
+ }
57
+ });
58
+ this.emit('log', 'Download selesai.', 'ok');
59
+
60
+ if (isTgz) {
61
+ this.emit('log', 'Mengextract archive...', 'info');
62
+ execSync(`tar -xzf "${tmpPath}" -C "${BIN_DIR}"`, { stdio: 'pipe' });
63
+ fs.unlinkSync(tmpPath);
64
+ // hasil extract biasanya nama: cloudflared (linux) atau cloudflared (darwin)
65
+ const extracted = path.join(BIN_DIR, 'cloudflared');
66
+ if (extracted !== this.binaryPath && fs.existsSync(extracted)) {
67
+ fs.renameSync(extracted, this.binaryPath);
68
+ }
69
+ } else {
70
+ if (tmpPath !== this.binaryPath) fs.renameSync(tmpPath, this.binaryPath);
71
+ }
72
+ if (process.platform !== 'win32') fs.chmodSync(this.binaryPath, 0o755);
73
+ this.emit('log', 'Binary cloudflared siap digunakan.', 'ok');
74
+ return this.binaryPath;
75
+ }
76
+
77
+ _downloadFile(url, dest, onProgress) {
78
+ return new Promise((resolve, reject) => {
79
+ const file = fs.createWriteStream(dest);
80
+ const request = (u, redirects = 0) => {
81
+ if (redirects > 5) return reject(new Error('Too many redirects'));
82
+ https.get(u, (res) => {
83
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
84
+ res.resume();
85
+ return request(res.headers.location, redirects + 1);
86
+ }
87
+ if (res.statusCode !== 200) {
88
+ res.resume();
89
+ return reject(new Error(`Download failed: HTTP ${res.statusCode}`));
90
+ }
91
+ const total = Number(res.headers['content-length'] || 0);
92
+ let received = 0;
93
+ if (onProgress) res.on('data', (chunk) => {
94
+ received += chunk.length;
95
+ onProgress(received, total);
96
+ });
97
+ res.pipe(file);
98
+ file.on('finish', () => file.close((err) => (err ? reject(err) : resolve())));
99
+ }).on('error', reject);
100
+ };
101
+ request(url);
102
+ }).then(() => {});
103
+ }
104
+
105
+ async start() {
106
+ if (this.status === 'running') return this.url;
107
+ this.status = 'starting';
108
+ try {
109
+ await this.ensureBinary();
110
+ } catch (e) {
111
+ this.status = 'stopped';
112
+ this.emit('log', `Gagal menyiapkan binary: ${e.message}`, 'error');
113
+ throw e;
114
+ }
115
+ this.emit('log', `Menjalankan cloudflared tunnel --url http://localhost:${this.port}...`, 'info');
116
+ this._urlPromise = new Promise((resolve, reject) => {
117
+ const timeout = setTimeout(() => {
118
+ reject(new Error('Tunnel URL not received within 30s'));
119
+ this.stop();
120
+ }, 30000);
121
+
122
+ this.childProcess = spawn(this.binaryPath, ['tunnel', '--url', `http://localhost:${this.port}`], {
123
+ stdio: ['ignore', 'pipe', 'pipe'],
124
+ });
125
+
126
+ const handleData = (data) => {
127
+ const text = data.toString();
128
+ const match = text.match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/i);
129
+ if (match && !this.url) {
130
+ clearTimeout(timeout);
131
+ this.url = match[0];
132
+ this.status = 'running';
133
+ this.config.set('tunnelEnabled', true);
134
+ this.emit('log', `Tunnel aktif: ${this.url}`, 'ok');
135
+ this.emit('url', this.url);
136
+ resolve(this.url);
137
+ }
138
+ };
139
+ this.childProcess.stdout.on('data', handleData);
140
+ this.childProcess.stderr.on('data', handleData);
141
+ this.childProcess.on('error', (err) => {
142
+ clearTimeout(timeout);
143
+ reject(err);
144
+ });
145
+ this.childProcess.on('exit', (code) => {
146
+ // cloudflared mati sebelum URL diterima → gagalkan promise lebih cepat dari timeout 30s.
147
+ if (this.status === 'starting') {
148
+ clearTimeout(timeout);
149
+ reject(new Error(`cloudflared exited before tunnel URL was received (code ${code})`));
150
+ }
151
+ if (this.status !== 'stopped') {
152
+ this.status = 'stopped';
153
+ this.url = null;
154
+ }
155
+ });
156
+ });
157
+ this.emit('log', 'Menunggu URL publik dari Cloudflare (maksimal 30 detik)...', 'info');
158
+ return this._urlPromise;
159
+ }
160
+
161
+ async stop() {
162
+ this.config.set('tunnelEnabled', false);
163
+ this.url = null;
164
+ this.status = 'stopped';
165
+
166
+ const child = this.childProcess;
167
+ this.childProcess = null;
168
+ if (!child) return;
169
+ try { child.kill('SIGTERM'); } catch (e) {}
170
+ setTimeout(() => {
171
+ try { child.kill('SIGKILL'); } catch (e) {}
172
+ }, 5000);
173
+ }
174
+
175
+ // Dipakai saat aplikasi keluar: matikan cloudflared TANPA mereset preferensi
176
+ // tunnelEnabled, supaya tunnel auto-start lagi di launch berikutnya.
177
+ async dispose() {
178
+ const child = this.childProcess;
179
+ this.childProcess = null;
180
+ this.url = null;
181
+ this.status = 'stopped';
182
+ if (!child) return;
183
+ try { child.kill('SIGTERM'); } catch (e) {}
184
+ setTimeout(() => {
185
+ try { child.kill('SIGKILL'); } catch (e) {}
186
+ }, 5000);
187
+ }
188
+
189
+ getStatus() {
190
+ return {
191
+ enabled: this.status === 'running',
192
+ url: this.url,
193
+ status: this.status,
194
+ };
195
+ }
196
+ }
197
+
198
+ module.exports = { TunnelManager };
@@ -0,0 +1,22 @@
1
+ <!DOCTYPE html>
2
+ <html lang="id">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Dashboard - Token Manager</title>
7
+ <link rel="icon" href="/favicon.ico?v=2" type="image/png" />
8
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
+ <link
11
+ href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=Space+Grotesk:wght@400;500;700&display=swap"
12
+ rel="stylesheet"
13
+ />
14
+ <script type="module" crossorigin src="/assets/admin-Boto8g_O.js"></script>
15
+ <link rel="modulepreload" crossorigin href="/assets/styles-pGt3BQwq.js">
16
+ <link rel="stylesheet" crossorigin href="/assets/styles-WqBkvfmY.css">
17
+ <link rel="stylesheet" crossorigin href="/assets/admin-DPInPm4J.css">
18
+ </head>
19
+ <body>
20
+ <div id="app"></div>
21
+ </body>
22
+ </html>
@@ -0,0 +1,4 @@
1
+ import{B as e,C as t,E as n,F as r,G as i,H as a,I as o,J as s,K as c,L as l,M as u,N as d,O as f,P as p,R as m,S as h,T as g,V as _,W as v,_ as y,a as b,b as x,c as S,d as C,f as w,g as T,i as E,j as D,k as O,l as k,m as A,n as j,o as ee,p as te,q as ne,r as M,s as re,t as ie,u as ae,v as oe,w as N,x as P,y as F}from"./styles-pGt3BQwq.js";function I(e,t=`success`){L.message=e,L.type=t,L.visible=!0,clearTimeout(R),R=setTimeout(()=>{L.visible=!1},3e3)}var L,R,z=s((()=>{w(),L=e({message:``,type:`success`,visible:!1}),R=null})),se,ce=s((()=>{w(),z(),se={__name:`ToastHost`,setup(e){return(e,t)=>(p(),n(`div`,{class:v([`toast`,[a(L).type,{show:a(L).visible}]])},c(a(L).message),3))}}}));function le({title:e,message:t,confirmLabel:n=`Ya, Lanjutkan`,cancelLabel:r=`Batal`,danger:i=!1}={}){return new Promise(a=>{V.title=e,V.message=t,V.confirmLabel=n,V.cancelLabel=r,V.danger=i,V.resolve=a,V.open=!0})}function B(e){V.resolve&&V.resolve(e),V.resolve=null,V.open=!1}var V,ue=s((()=>{w(),V=e({open:!1,title:``,message:``,confirmLabel:`Ya, Lanjutkan`,cancelLabel:`Batal`,danger:!1,resolve:null})})),de=s((()=>{})),H,fe,pe,me,he,ge,_e=s((()=>{w(),k(),ue(),de(),M(),H={class:`confirm-card`,role:`dialog`,"aria-modal":`true`},fe={class:`confirm-title`},pe={class:`confirm-message`},me={class:`confirm-actions`},he={__name:`ConfirmDialog`,setup(e){function r(e){e.key===`Escape`&&B(!1)}return d(()=>document.addEventListener(`keydown`,r)),u(()=>document.removeEventListener(`keydown`,r)),(e,r)=>(p(),N(P,{to:`body`},[a(V).open?(p(),n(`div`,{key:0,class:`confirm-overlay`,onClick:r[2]||=F(e=>a(B)(!1),[`self`])},[t(`div`,H,[t(`div`,{class:v([`confirm-icon`,{danger:a(V).danger}])},[O(S,{name:a(V).danger?`alert`:`check-circle`,size:26},null,8,[`name`])],2),t(`h2`,fe,c(a(V).title),1),t(`p`,pe,c(a(V).message),1),t(`div`,me,[t(`button`,{class:`btn btn-secondary`,onClick:r[0]||=e=>a(B)(!1)},[O(S,{name:`x`,size:16}),f(` `+c(a(V).cancelLabel),1)]),t(`button`,{class:v([`btn`,a(V).danger?`btn-danger`:`btn-primary`]),onClick:r[1]||=e=>a(B)(!0)},[O(S,{name:a(V).danger?`trash`:`check`,size:16},null,8,[`name`]),f(` `+c(a(V).confirmLabel),1)],2)])])])):g(``,!0)]))}},ge=j(he,[[`__scopeId`,`data-v-2e9843c0`]])}));function ve(){return new Date().toLocaleString(`id-ID`)}async function ye(){try{let e=await E(`/api/password-status`);K.passwordIsDefault=e.isDefault}catch{K.passwordIsDefault=!1}}async function be(){try{let e=await E(`/api/session`);K.authed=!!e.success}catch{K.authed=!1}K.authChecked=!0,ye()}async function xe(e){if(!(await b(`/api/verify-password`,{password:e})).success)throw Error(`Password salah`);K.authed=!0,K.connStatus=`Terhubung`,await Promise.all([U(!1),W()])}async function Se(){try{await fetch(`/api/logout`,{method:`POST`})}catch{}Be(),K.authed=!1,K.view=`dashboard`,ye(),I(`🚪 Logout berhasil`,`success`)}async function U(e=!0){let t=await E(`/api/donations?page=${K.page}&pageSize=10`);if(!t.success)throw Error(t.error||`Gagal memuat donation logs`);K.donations=t.donations||[],K.page=t.page,K.pageCount=t.pageCount,K.total=t.total,K.stats=t.stats||K.stats,K.lastSync=ve(),e&&I(`✅ Dashboard diperbarui`,`success`)}async function Ce(e){let t=K.page+e;t<1||t>K.pageCount||(K.page=t,await U(!1))}async function we(e){let t=K.donations.find(t=>t.id===e);if(await le({title:`Hapus Log Donasi?`,message:t?`Log donasi dari "${t.name}" (${t.email}) akan dihapus permanen. Token yang sudah tersimpan di 9Router tidak ikut terhapus.`:`Log donasi ini akan dihapus permanen.`,confirmLabel:`Ya, Hapus`,danger:!0}))try{let t=await re(await fetch(`/api/donations/${encodeURIComponent(e)}`,{method:`DELETE`}));if(!t.success)throw Error(t.error);K.page>1&&K.donations.length===1&&--K.page,await U(!1),I(`✅ Log donasi dihapus`,`success`)}catch(e){I(`❌ `+e.message,`error`)}}async function Te(e){K.ceLoadingId=e;try{let t=await b(`/api/donations/${encodeURIComponent(e)}/check-eligibility`);if(!t.success)throw Error(t.error||`Check eligibility gagal`);K.eligibilityLog={data:t,id:e},I(t.eligible?`✅ Token eligible`:`⚠️ Token belum eligible`,t.eligible?`success`:`error`)}catch(e){I(`❌ `+e.message,`error`)}finally{K.ceLoadingId=null}}async function Ee(e){try{let t=await b(`/api/donations/${encodeURIComponent(e)}/sync`);if(!t.success)throw Error(t.error);I(`🔄 ${t.message} (${t.email})`,`success`)}catch(e){I(`❌ Sync gagal: `+e.message,`error`)}}function De(){let e=[[`Name`,`Email`,`RequestedFor`,`Source`,`Status`,`CreatedAt`,`AccessToken`,`RefreshToken`,`Expiry`],...K.donations.map(e=>[e.name,e.email,e.requestedFor||`sahabat`,e.source,e.status,e.createdAt,e.accessToken||``,e.refreshToken||``,e.expiry||``])].map(e=>e.map(e=>`"${String(e).replace(/"/g,`""`)}"`).join(`,`)).join(`
2
+ `),t=new Blob([e],{type:`text/csv;charset=utf-8;`}),n=URL.createObjectURL(t),r=document.createElement(`a`);r.href=n,r.download=`donasi-token-${Date.now()}.csv`,r.click(),I(`✅ Data berhasil diexport`,`success`)}async function Oe(e){if(e)try{let t=await e.text();I(`✅ ${(await b(`/api/donations/import`,{csv:t})).message}`,`success`),await U(!1)}catch(e){I(`❌ Import gagal: `+e.message,`error`)}}function ke(){let e=screen.width/2-250,t=screen.height/2-300,n=window.open(`/auth/google`,`g`,`width=500,height=600,top=${t},left=${e}`);if(!n)return I(`Popup diblokir`,`error`);let r=setInterval(()=>{n.closed&&(clearInterval(r),window.removeEventListener(`message`,i))},500);function i(e){e.source===n&&(!e.data||typeof e.data!=`object`||!Object.prototype.hasOwnProperty.call(e.data,`success`)||(clearInterval(r),window.removeEventListener(`message`,i),e.data.success?(K.tokenData=e.data.token,e.data.user&&(K.name=e.data.user.name||``,K.email=e.data.user.email||``),K.eligibilityResult=null,I(`✅ Login berhasil`,`success`)):I(`❌ Login gagal: `+(e.data.error||`Tidak diketahui`),`error`)))}window.addEventListener(`message`,i)}async function Ae(){try{let e=await b(`/api/keychain`);K.tokenData=e.token,K.eligibilityResult=null,I(`✅ Token diambil`,`success`)}catch(e){I(`❌ `+e.message,`error`)}}async function je(){let e=K.pasteInput.trim();if(!e)return I(`Paste dulu`,`error`);try{let t=await b(`/api/decode`,{raw:e});K.tokenData=t.token,K.eligibilityResult=null,I(`✅ Decode berhasil`,`success`)}catch(e){I(`❌ `+e.message,`error`)}}async function Me(){if(K.tokenData)try{let e=await b(`/api/check-eligibility`,{accessToken:K.tokenData.accessToken});if(!e.success)throw Error(e.error);K.eligibilityResult={eligible:e.eligible,message:e.message,verificationUrl:e.verificationUrl||null}}catch(e){I(`❌ `+e.message,`error`)}}function Ne(){return K.name.trim()?K.email.trim()?K.tokenData?!0:(I(`Ambil token`,`error`),!1):(I(`Email wajib`,`error`),!1):(I(`Name wajib`,`error`),!1)}async function Pe(){if(Ne())try{let e=await b(`/api/generate`,{name:K.name.trim(),email:K.email.trim(),accessToken:K.tokenData.accessToken,refreshToken:K.tokenData.refreshToken,expiry:K.tokenData.expiry,scope:K.scope.trim(),projectId:K.projectId.trim()});if(!e.success)throw Error(e.error);K.output=e.query,I(`✅ ${e.isUpdate?`Query UPDATE`:`Query INSERT`}!`,`success`)}catch(e){I(`❌ `+e.message,`error`)}}async function Fe(){if(Ne())try{let e=await b(`/api/insert`,{name:K.name.trim(),email:K.email.trim(),accessToken:K.tokenData.accessToken,refreshToken:K.tokenData.refreshToken,expiry:K.tokenData.expiry,scope:K.scope.trim(),projectId:K.projectId.trim(),requestedFor:`admin-panel`,source:`admin`});if(!e.success)throw Error(e.error);await U(!1),I(`✅ `+e.message,`success`)}catch(e){I(`❌ `+e.message,`error`)}}function Ie(){navigator.clipboard.writeText(K.output),I(`Copied!`,`success`)}function Le(){let e=new Blob([K.output],{type:`text/sql`}),t=URL.createObjectURL(e),n=document.createElement(`a`);n.href=t,n.download=`insert-${Date.now()}.sql`,n.click()}function Re(){K.name=``,K.email=``,K.scope=``,K.projectId=``,K.pasteInput=``,K.output=``,K.tokenData=null,K.eligibilityResult=null,I(`🔄 Reset selesai`,`success`)}async function W(){try{let e=await E(`/api/settings`);K.settings=e,K.passwordIsDefault=e.passwordIsDefault}catch(e){I(`❌ Gagal memuat pengaturan: `+e.message,`error`)}}function ze(){q||=setInterval(async()=>{try{let e=await E(`/api/settings`);e.success&&(K.settings=e,K.passwordIsDefault=e.passwordIsDefault)}catch{}},4e3)}function Be(){q&&=(clearInterval(q),null)}async function Ve(e,t){let n=await b(`/api/password`,{currentPassword:e,newPassword:t});if(!n.success)throw Error(n.error||`Gagal mengganti password`);I(`✅ `+n.message+`. Tunnel sekarang bisa diaktifkan.`,`success`),await W()}async function He(e){I(`✅ `+(await b(`/api/settings`,{nineRouterDbPath:e})).message,`success`),await W()}async function Ue(){let e=!(K.settings&&K.settings.autoStart);try{let t=await b(`/api/autostart`,{enabled:e});if(!t.success)throw Error(t.error||`Gagal mengubah auto start`);I(`✅ `+t.message,`success`)}catch(e){I(`❌ `+e.message,`error`)}await W()}function G(e){K.settings&&(K.settings.tunnel=e)}async function We(){let e=!(K.settings&&K.settings.tunnel&&K.settings.tunnel.enabled);G({enabled:!1,url:null,status:e?`starting`:`stopping`}),Ge();try{let t=await b(`/api/tunnel`,{enabled:e});if(!t.success)throw Error(t.error||`Gagal mengubah status tunnel`);G(t.tunnel),I(e?`✅ Tunnel aktif: `+(t.tunnel.url||`-`):`✅ Tunnel dimatikan`,`success`)}catch(e){I(`❌ `+e.message,`error`);try{let e=await E(`/api/tunnel`);e.success&&G(e.tunnel)}catch{}}}function Ge(){J||=setInterval(async()=>{try{let e=await E(`/api/tunnel`);e.success&&(G(e.tunnel),e.tunnel.status!==`starting`&&Ke())}catch{}},2e3)}function Ke(){J&&=(clearInterval(J),null)}var K,q,J,Y=s((()=>{w(),ee(),z(),ue(),K=e({authed:!1,authChecked:!1,view:`dashboard`,passwordIsDefault:!0,connStatus:`Belum login`,lastSync:`-`,donations:[],page:1,pageCount:1,total:0,stats:{tokenCount:0,donorCount:0,todayCount:0},eligibilityLog:null,ceLoadingId:null,tokenData:null,tokenTab:`google`,name:``,email:``,scope:``,projectId:``,pasteInput:``,output:``,advancedOpen:!1,eligibilityResult:null,settings:null}),q=null,J=null})),qe=s((()=>{})),Je,Ye,Xe,Ze,Qe,$e,et,tt,nt,rt,it,at=s((()=>{w(),C(),k(),Y(),z(),qe(),M(),Je={class:`mx-auto mt-8 max-w-md neo-card p-8 text-center sm:p-10`},Ye={class:`neo-display mt-4 inline-flex items-center justify-center gap-3 text-2xl`},Xe={class:`login-lock`},Ze={class:`mt-6 text-left`},Qe={class:`field`},$e=[`disabled`],et=[`disabled`],tt={key:0,class:`spinner`},nt={key:0,class:`default-pass-hint`},rt={__name:`LoginCard`,setup(e){let r=_(``),i=_(!1);async function o(){if(!i.value){i.value=!0;try{await xe(r.value),r.value=``}catch(e){I(`❌ `+(e.message||`Password salah`),`error`)}finally{i.value=!1}}}return(e,s)=>(p(),n(`div`,Je,[O(ae,{width:150,class:`mx-auto`}),t(`h2`,Ye,[t(`span`,Xe,[O(S,{name:`lock`,size:22})]),s[1]||=f(` Dashboard Manager `,-1)]),s[5]||=t(`p`,{class:`mt-3 text-sm font-medium`},`Masukkan password untuk mengakses dashboard.`,-1),t(`div`,Ze,[t(`div`,Qe,[s[2]||=t(`label`,{for:`adminPass`},`Password`,-1),m(t(`input`,{id:`adminPass`,"onUpdate:modelValue":s[0]||=e=>r.value=e,type:`password`,placeholder:`Password`,disabled:i.value,onKeydown:oe(o,[`enter`])},null,40,$e),[[T,r.value]])])]),t(`button`,{class:`btn btn-primary mt-2 w-full`,disabled:i.value,onClick:o},[i.value?(p(),n(`span`,tt)):(p(),N(S,{key:1,name:`arrow-right`,size:16})),s[3]||=t(`span`,null,`Masuk`,-1)],8,et),a(K).passwordIsDefault?(p(),n(`div`,nt,[...s[4]||=[t(`strong`,null,`Password default:`,-1),f(),t(`code`,null,`1234567890`,-1),t(`br`,null,null,-1),f(` Demi keamanan, segera ganti password di menu `,-1),t(`strong`,null,`Pengaturan → Keamanan`,-1),f(` setelah login. `,-1)]])):g(``,!0)]))}},it=j(rt,[[`__scopeId`,`data-v-8cb9a1a5`]])})),ot=s((()=>{})),st,ct,X,lt,ut,dt,ft=s((()=>{w(),k(),ot(),M(),st={class:`dd-root`},ct=[`onClick`],X=e({id:null}),lt=0,ut={__name:`DropdownMenu`,props:{items:{type:Array,required:!0}},emits:[`select`],setup(e,{emit:a}){let o=a,s=++lt,f=h(()=>X.id===s),m=_(null),y=_(null),b=_({});async function C(){if(f.value){X.id=null;return}X.id=s,await D(),w()}function w(){let e=m.value,t=y.value;if(!e||!t)return;let n=e.getBoundingClientRect(),r=t.getBoundingClientRect(),i=n.bottom+8;i+r.height>window.innerHeight-8&&(i=Math.max(8,n.top-r.height-8));let a=n.right-r.width;a=Math.min(Math.max(a,8),window.innerWidth-8-r.width),b.value={top:`${Math.round(i)}px`,left:`${Math.round(a)}px`}}function T(e){X.id=null,o(`select`,e.key)}function E(e){if(!f.value)return;let t=e.target;m.value?.contains(t)||y.value?.contains(t)||(X.id=null)}function k(e){e.key===`Escape`&&f.value&&(X.id=null)}function A(){f.value&&(X.id=null)}return d(()=>{document.addEventListener(`click`,E),document.addEventListener(`keydown`,k),window.addEventListener(`scroll`,A,!0),window.addEventListener(`resize`,A)}),u(()=>{document.removeEventListener(`click`,E),document.removeEventListener(`keydown`,k),window.removeEventListener(`scroll`,A,!0),window.removeEventListener(`resize`,A)}),(a,o)=>(p(),n(`div`,st,[t(`button`,{ref_key:`triggerRef`,ref:m,class:`btn btn-secondary btn-icon dd-trigger`,title:`Aksi`,onClick:F(C,[`stop`])},[O(S,{name:`more`,size:18})],512),(p(),N(P,{to:`body`},[O(te,{name:`dd`},{default:l(()=>[f.value?(p(),n(`div`,{key:0,ref_key:`panelRef`,ref:y,class:`dd-panel`,style:i(b.value)},[(p(!0),n(x,null,r(e.items,e=>(p(),n(`button`,{key:e.key,class:v([`dd-item`,{danger:e.danger}]),onClick:F(t=>T(e),[`stop`])},[O(S,{name:e.icon,size:16},null,8,[`name`]),t(`span`,null,c(e.label),1)],10,ct))),128))],4)):g(``,!0)]),_:1})]))]))}},dt=j(ut,[[`__scopeId`,`data-v-ecad6e79`]])})),pt=s((()=>{})),mt,ht,gt,_t,vt,yt,bt,Z,xt=s((()=>{w(),pt(),M(),mt={class:`terminal`},ht={class:`terminal-head`},gt={class:`terminal-name`},_t={class:`ttime`},vt={class:`ttext`},yt={key:0,class:`tline t-info`},bt={__name:`Terminal`,props:{name:{type:String,default:`log`},lines:{type:Array,default:()=>[]},height:{type:String,default:`230px`}},setup(e){let a=e,s=_(null);return o(()=>a.lines.length,()=>{D(()=>{let e=s.value;e&&(e.scrollTop=e.scrollHeight)})}),(a,o)=>(p(),n(`div`,mt,[t(`div`,ht,[o[0]||=t(`span`,{class:`tdot td-r`},null,-1),o[1]||=t(`span`,{class:`tdot td-y`},null,-1),o[2]||=t(`span`,{class:`tdot td-g`},null,-1),t(`span`,gt,c(e.name),1)]),t(`div`,{ref_key:`bodyRef`,ref:s,class:`terminal-body`,style:i({height:e.height})},[(p(!0),n(x,null,r(e.lines,(e,r)=>(p(),n(`div`,{key:r,class:v([`tline`,e.cls||`t-info`])},[t(`span`,_t,c(e.time),1),t(`span`,vt,c(e.text),1)],2))),128)),e.lines.length?g(``,!0):(p(),n(`div`,yt,[...o[3]||=[t(`span`,{class:`ttext`},`menunggu output…`,-1)]]))],4)]))}},Z=j(bt,[[`__scopeId`,`data-v-5b0ac08c`]])})),St=s((()=>{})),Ct,wt,Tt,Et,Dt,Ot,kt,At,jt,Mt,Nt,Pt,Ft,It=s((()=>{w(),k(),xt(),z(),St(),M(),Ct={class:`sync-card`,role:`dialog`,"aria-modal":`true`},wt={class:`sync-head`},Tt={class:`sync-head-icon`},Et={key:0,class:`sync-body`},Dt={class:`sync-actions`},Ot={key:1,class:`sync-body`},kt={class:`sync-progress`},At={class:`sync-progress-bar`},jt={class:`sync-progress-text`},Mt={key:0,class:`sync-done`},Nt={class:`sync-actions`},Pt={__name:`SyncAllDialog`,props:{open:{type:Boolean,default:!1}},emits:[`close`],setup(r,{emit:a}){let o=r,s=a,l=e({phase:`confirm`,total:0,processed:0,inserted:0,updated:0,errors:0,doneMessage:``}),m=e([]),_=null,v=h(()=>l.total?Math.round(l.processed/l.total*100):0);function y(e,t=`t-info`){m.push({time:new Date().toLocaleTimeString(`id-ID`),text:e,cls:t})}function b(e){e.type===`start`?(l.total=e.total,y(`Mulai sync ${e.total} data ke 9Router…`)):e.type===`log`?(l.processed=e.index,e.action===`inserted`?(l.inserted++,y(`[${e.index}/${l.total}] INSERT ${e.email}`,`t-ok`)):e.action===`updated`?(l.updated++,y(`[${e.index}/${l.total}] UPDATE ${e.email}`,`t-warn`)):(l.errors++,y(`[${e.index}/${l.total}] ERROR ${e.email} — ${e.message}`,`t-error`))):e.type===`done`?y(`Selesai: ${e.inserted} baru, ${e.updated} diupdate, ${e.errors} error.`):e.type===`error`&&y(`GAGAL: ${e.message}`,`t-error`)}async function x(){l.phase=`running`,m.length=0,l.total=0,l.processed=0,l.inserted=0,l.updated=0,l.errors=0,_=new AbortController;try{let e=await fetch(`/api/donations/sync-all`,{method:`POST`,signal:_.signal});if(!e.ok){let t=`HTTP ${e.status}`;try{let n=await e.json();n&&n.error&&(t=n.error)}catch{}y(`GAGAL: ${t}`,`t-error`),l.phase=`done`,l.doneMessage=`Sync gagal dijalankan.`;return}let t=e.body.getReader(),n=new TextDecoder,r=``;for(;;){let{done:e,value:i}=await t.read();if(e)break;r+=n.decode(i,{stream:!0});let a=r.split(`
3
+ `);r=a.pop();for(let e of a)e.trim()&&b(JSON.parse(e))}}catch(e){e.name===`AbortError`?y(`Sync dibatalkan.`,`t-error`):y(`GAGAL: ${e.message}`,`t-error`),l.phase=`done`,l.doneMessage=`Sync berhenti di tengah jalan.`;return}l.phase=`done`,l.doneMessage=`Selesai: ${l.inserted} baru, ${l.updated} diupdate, ${l.errors} error dari ${l.total} data.`,I(`✅ `+l.doneMessage,`success`)}function C(){_&&_.abort()}function w(){l.phase!==`running`&&s(`close`)}function T(e){e.key===`Escape`&&o.open&&l.phase!==`running`&&s(`close`)}return d(()=>document.addEventListener(`keydown`,T)),u(()=>document.removeEventListener(`keydown`,T)),(e,a)=>(p(),N(P,{to:`body`},[r.open?(p(),n(`div`,{key:0,class:`sync-overlay`,onClick:F(w,[`self`])},[t(`div`,Ct,[t(`div`,wt,[t(`span`,Tt,[O(S,{name:`database`,size:20})]),a[3]||=t(`div`,null,[t(`h2`,{class:`sync-title`},`Sync Semua ke 9Router`),t(`p`,{class:`sync-sub`},`Upsert seluruh donasi (key: email) ke providerConnections`)],-1),l.phase===`running`?g(``,!0):(p(),n(`button`,{key:0,class:`btn btn-secondary btn-icon`,title:`Tutup`,onClick:a[0]||=e=>s(`close`)},[O(S,{name:`x`,size:15})]))]),l.phase===`confirm`?(p(),n(`div`,Et,[a[6]||=t(`p`,{class:`sync-message`},[f(` Seluruh data donasi yang memiliki token akan dimasukkan ke database 9Router. Cocok setelah `),t(`strong`,null,`export → import di tempat lain`),f(`: data yang belum ada akan di-`),t(`strong`,null,`INSERT`),f(` (priority urutan terakhir), yang sudah ada akan di-`),t(`strong`,null,`UPDATE`),f(`. `)],-1),t(`div`,Dt,[t(`button`,{class:`btn btn-secondary`,onClick:a[1]||=e=>s(`close`)},[O(S,{name:`x`,size:15}),a[4]||=f(` Batal `,-1)]),t(`button`,{class:`btn btn-primary`,onClick:x},[O(S,{name:`play`,size:15}),a[5]||=f(` Mulai Sync `,-1)])])])):(p(),n(`div`,Ot,[t(`div`,kt,[t(`div`,At,[t(`div`,{class:`sync-progress-fill`,style:i({width:`${v.value}%`})},null,4)]),t(`span`,jt,c(l.processed)+`/`+c(l.total||`…`)+` (`+c(v.value)+`%)`,1)]),O(Z,{name:`sync-9router.log`,lines:m},null,8,[`lines`]),l.phase===`done`?(p(),n(`p`,Mt,c(l.doneMessage),1)):g(``,!0),t(`div`,Nt,[l.phase===`running`?(p(),n(`button`,{key:0,class:`btn btn-secondary`,onClick:C},[O(S,{name:`x`,size:15}),a[7]||=f(` Batalkan `,-1)])):g(``,!0),l.phase===`done`?(p(),n(`button`,{key:1,class:`btn btn-primary`,onClick:a[2]||=e=>s(`close`)},[O(S,{name:`check`,size:15}),a[8]||=f(` Selesai `,-1)])):g(``,!0)])]))])])):g(``,!0)]))}},Ft=j(Pt,[[`__scopeId`,`data-v-79db2475`]])})),Lt=s((()=>{})),Rt,zt,Bt,Vt,Ht,Ut,Wt,Gt,Kt,qt,Jt,Yt,Xt,Zt,Qt,$t,en,tn,nn,rn,an,on,sn,cn,ln,un,dn,fn,pn,mn,hn,gn,_n,vn,yn,bn,xn,Sn,Cn,wn,Tn,En,Dn,On,kn,An,jn,Mn,Nn,Pn,Fn,In,Ln,Rn,zn,Bn,Vn,Hn,Un,Wn,Gn,Kn,qn,Jn,Yn,Xn,Zn,Qn,$n,er,tr,nr,rr,ir,ar,or,sr,cr,lr,ur,dr,fr,pr,mr,hr,gr,_r,vr,yr,br,xr,Sr,Cr,wr,Tr,Er,Dr,Or,kr=s((()=>{w(),k(),ft(),It(),Y(),z(),Lt(),M(),Rt={class:`space-y-10`},zt={class:`grid gap-6 md:grid-cols-3`},Bt={class:`neo-card stat-card bg-[#fef08a] p-6`},Vt={class:`stat-icon`},Ht={class:`neo-display mt-3 text-3xl`},Ut={class:`neo-card stat-card bg-[#bbf7d0] p-6`},Wt={class:`stat-icon`},Gt={class:`neo-display mt-3 text-3xl`},Kt={class:`neo-card stat-card bg-[#fdba74] p-6`},qt={class:`stat-icon`},Jt={class:`neo-display mt-3 text-3xl`},Yt={class:`neo-card p-6 sm:p-8`},Xt={class:`card-title`},Zt={class:`step step-pink`},Qt={class:`link-grid`},$t={class:`field !mb-0`},en={class:`link-result`},tn=[`disabled`],nn=[`href`],rn={class:`link-basis`},an={class:`neo-card p-6 sm:p-8`},on={class:`card-title`},sn={class:`step`},cn={class:`overflow-x-auto rounded-[6px] border-4 border-black`},ln={class:`data-table min-w-full border-collapse bg-white`},un={class:`border-2 border-black font-bold`},dn={class:`border-2 border-black`},fn={class:`border-2 border-black`},pn={class:`border-2 border-black`},mn={class:`border-2 border-black`},hn={class:`border-2 border-black`},gn={class:`border-2 border-black`},_n={key:0},vn={class:`mt-5 flex flex-wrap items-center justify-between gap-3`},yn={class:`text-sm font-bold`},bn={class:`flex gap-3`},xn=[`disabled`],Sn=[`disabled`],Cn={key:0,class:`temporary-check-log p-6 sm:p-8`,"aria-live":`polite`},wn={class:`flex flex-wrap items-center justify-between gap-3`},Tn={class:`flex items-center gap-3`},En={class:`step`},Dn={class:`mt-5`},On={class:`mt-2 text-sm font-bold`},kn={class:`mt-1 text-xs`},An={key:0,class:`mt-2 flex items-start gap-2 text-sm font-bold`},jn={key:1,class:`mt-3 flex flex-wrap gap-2`},Mn=[`href`],Nn={class:`mt-4`},Pn={class:`grid gap-10 lg:grid-cols-2`},Fn={class:`space-y-10`},In={class:`neo-card p-6 sm:p-8`},Ln={class:`card-title`},Rn={class:`step step-teal`},zn={class:`grid gap-5 sm:grid-cols-2`},Bn={class:`field`},Vn={class:`field`},Hn={class:`neo-card p-6 sm:p-8`},Un={class:`card-title`},Wn={class:`step step-green`},Gn={class:`mb-5 grid gap-3 sm:grid-cols-3`},Kn={key:0},qn={key:1},Jn={key:2},Yn={class:`field`},Xn={key:0,class:`neo-card p-6 sm:p-8`},Zn={class:`card-title`},Qn={class:`step step-blue`},$n={class:`ml-auto`},er={class:`token-preview`},tr={class:`row`},nr={class:`value truncate`},rr={class:`row`},ir={class:`value truncate`},ar={class:`row`},or={class:`value`},sr={key:1,class:`neo-card p-6 sm:p-8`},cr={class:`card-title`},lr={class:`step step-orange`},ur={key:1},dr=[`href`],fr={class:`space-y-10`},pr={class:`neo-card p-6 sm:p-8`},mr={class:`inline-flex items-center gap-2`},hr={class:`mt-5`},gr={class:`field`},_r={class:`field`},vr={class:`neo-card p-6 sm:p-8`},yr={class:`card-title`},br={class:`step step-yellow`},xr={class:`space-y-4`},Sr={key:0,class:`neo-card p-6 sm:p-8`},Cr={class:`card-title`},wr={class:`step step-blue`},Tr=[`value`],Er={class:`mt-5 flex flex-wrap gap-3`},Dr={__name:`DashboardView`,setup(e){let i=_(``),o=window.location.origin,s=h(()=>{let e=i.value.trim();return e?`${o}/?for=${encodeURIComponent(e)}`:``});async function l(){let e=s.value;if(e)try{await navigator.clipboard.writeText(e),I(`📋 Link donasi tersalin`,`success`)}catch{I(`❌ Gagal menyalin link`,`error`)}}let u=h(()=>K.tokenData?.expiry?new Date(K.tokenData.expiry)<new Date:!1),d=h(()=>K.eligibilityLog?.data||null),b=h(()=>K.eligibilityLog?.id||null),C=_(!1),w=[{key:`ce`,label:`Check Eligibility`,icon:`check-circle`},{key:`sync`,label:`Sync ke 9Router`,icon:`refresh`},{key:`delete`,label:`Hapus`,icon:`trash`,danger:!0}];function E(e,t){e===`ce`?Te(t.id):e===`sync`?Ee(t.id):e===`delete`&&we(t.id)}function D(e){return e===`Success`?`badge-success`:e===`Pending`?`badge-warning`:`badge-error`}function k(e){try{return new Date(e).toLocaleString(`id-ID`)}catch{return e}}return(e,h)=>(p(),n(`div`,Rt,[t(`section`,zt,[t(`article`,Bt,[t(`span`,Vt,[O(S,{name:`bolt`,size:20})]),h[26]||=t(`p`,{class:`text-xs font-bold uppercase`},`Total Token Terkumpul`,-1),t(`p`,Ht,c(a(K).stats?.tokenCount??0),1)]),t(`article`,Ut,[t(`span`,Wt,[O(S,{name:`user`,size:20})]),h[27]||=t(`p`,{class:`text-xs font-bold uppercase`},`Total Donatur`,-1),t(`p`,Gt,c(a(K).stats?.donorCount??0),1)]),t(`article`,Kt,[t(`span`,qt,[O(S,{name:`clock`,size:20})]),h[28]||=t(`p`,{class:`text-xs font-bold uppercase`},`Donasi Hari Ini`,-1),t(`p`,Jt,c(a(K).stats?.todayCount??0),1)])]),t(`section`,Yt,[t(`div`,Xt,[t(`span`,Zt,[O(S,{name:`link`,size:14})]),h[29]||=f(` Generate Link Donasi `,-1)]),t(`div`,Qt,[t(`div`,$t,[h[30]||=t(`label`,{for:`linkName`},`Nama Calon Donatur (penerima link)`,-1),m(t(`input`,{id:`linkName`,"onUpdate:modelValue":h[0]||=e=>i.value=e,type:`text`,placeholder:`cth: Sahabat Terbaikku`},null,512),[[T,i.value]])]),t(`div`,en,[t(`div`,{class:v([`url-box`,{empty:!s.value}])},[O(S,{name:`link`,size:14,class:`url-icon`}),t(`span`,null,c(s.value||`Link muncul otomatis setelah nama diisi…`),1)],2),t(`button`,{class:`btn btn-primary link-copy`,disabled:!s.value,onClick:l},[O(S,{name:`copy`,size:15}),h[31]||=f(` Copy `,-1)],8,tn),s.value?(p(),n(`a`,{key:0,class:`btn btn-secondary link-open`,href:s.value,target:`_blank`,rel:`noopener`,title:`Buka link di tab baru`},[O(S,{name:`external`,size:15})],8,nn)):g(``,!0)])]),t(`p`,rn,[O(S,{name:`bolt`,size:13}),h[32]||=f(` Link otomatis mengikuti alamat yang Anda buka sekarang: `,-1),t(`strong`,null,c(a(o)),1),h[33]||=f(` — localhost, tunnel, maupun domain custom Anda. `,-1)])]),t(`section`,an,[t(`div`,on,[t(`span`,sn,[O(S,{name:`list`,size:14})]),h[35]||=f(` Daftar Donasi `,-1),h[36]||=t(`span`,{class:`badge badge-warning`},`Live Table`,-1),t(`button`,{class:`btn btn-primary ml-auto px-4 py-2 text-xs`,title:`Sinkronkan SEMUA donasi ke database 9Router (upsert by email)`,onClick:h[1]||=e=>C.value=!0},[O(S,{name:`database`,size:14}),h[34]||=f(` Sync Semua `,-1)])]),t(`div`,cn,[t(`table`,ln,[h[38]||=t(`thead`,null,[t(`tr`,{class:`bg-black text-white`},[t(`th`,{class:`border-2 border-black text-left`},`Nama`),t(`th`,{class:`border-2 border-black text-left`},`Email`),t(`th`,{class:`border-2 border-black text-left`},`Diminta untuk`),t(`th`,{class:`border-2 border-black text-left`},`Sumber`),t(`th`,{class:`border-2 border-black text-left`},`Status`),t(`th`,{class:`border-2 border-black text-left`},`Waktu`),t(`th`,{class:`border-2 border-black text-left`},`Aksi`)])],-1),t(`tbody`,null,[(p(!0),n(x,null,r(a(K).donations,(e,r)=>(p(),n(`tr`,{key:e.id,class:v(r%2==0?`bg-[#fffef0]`:`bg-white`)},[t(`td`,un,c(e.name),1),t(`td`,dn,c(e.email),1),t(`td`,fn,c(e.requestedFor||`sahabat`),1),t(`td`,pn,c(e.source),1),t(`td`,mn,[t(`span`,{class:v([`badge`,D(e.status)])},c(e.status),3)]),t(`td`,hn,c(k(e.createdAt)),1),t(`td`,gn,[O(dt,{items:w,onSelect:t=>E(t,e)},null,8,[`onSelect`])])],2))),128)),a(K).donations.length?g(``,!0):(p(),n(`tr`,_n,[...h[37]||=[t(`td`,{colspan:`7`,class:`border-2 border-black px-3 py-4 text-center text-sm font-bold`},`Belum ada data donasi.`,-1)]]))])])]),t(`div`,vn,[t(`span`,yn,`Halaman `+c(a(K).page)+` / `+c(a(K).pageCount)+` (`+c(a(K).total)+` data)`,1),t(`div`,bn,[t(`button`,{class:`btn btn-secondary px-4 py-2 text-sm`,disabled:a(K).page<=1,onClick:h[2]||=e=>a(Ce)(-1)},`← Sebelumnya`,8,xn),t(`button`,{class:`btn btn-secondary px-4 py-2 text-sm`,disabled:a(K).page>=a(K).pageCount,onClick:h[3]||=e=>a(Ce)(1)},`Berikutnya →`,8,Sn)])])]),O(Ft,{open:C.value,onClose:h[4]||=e=>C.value=!1},null,8,[`open`]),d.value?(p(),n(`section`,Cn,[t(`div`,wn,[t(`div`,Tn,[t(`span`,En,[O(S,{name:`check-circle`,size:14})]),h[39]||=t(`div`,null,[t(`h2`,{class:`neo-display text-xl`},`Temporary Eligibility Test Log`),t(`p`,{class:`mt-2 text-xs font-bold`},`Hasil ini hanya tampil sementara di browser dan tidak disimpan ke database.`)],-1)]),t(`button`,{class:`btn btn-secondary px-4 py-2 text-xs`,onClick:h[5]||=e=>a(K).eligibilityLog=null},[O(S,{name:`x`,size:14}),h[40]||=f(` Close `,-1)])]),t(`div`,Dn,[t(`span`,{class:v([`badge`,d.value.eligible?`badge-success`:`badge-error`])},c(d.value.status||(d.value.eligible?`Eligible`:`Not eligible`)),3),t(`p`,On,c(d.value.message||`-`),1),t(`p`,kn,`Checked at: `+c(d.value.checkedAt||`-`),1),d.value.tokenRefreshed?(p(),n(`p`,An,[O(S,{name:`refresh`,size:16}),t(`span`,null,[h[41]||=f(`Access token expired/nearly expired. Token berhasil di-refresh dan diperbarui di donation logs.`,-1),h[42]||=t(`br`,null,null,-1),f(`Expiry baru: `+c(d.value.expiry||`-`),1)])])):g(``,!0),d.value.status===`verification_required`&&d.value.validationUrl?(p(),n(`div`,jn,[t(`a`,{class:`btn btn-google`,href:d.value.validationUrl,target:`_blank`,rel:`noopener`},[O(S,{name:`check-circle`,size:16}),h[43]||=f(` Verify Account `,-1)],8,Mn),t(`button`,{class:`btn btn-secondary`,type:`button`,onClick:h[6]||=e=>a(Te)(b.value)},[O(S,{name:`refresh`,size:16}),h[44]||=f(` Recheck `,-1)])])):g(``,!0)]),t(`pre`,Nn,c(JSON.stringify(d.value.details||{},null,2)),1)])):g(``,!0),t(`div`,Pn,[t(`section`,Fn,[t(`div`,In,[t(`div`,Ln,[t(`span`,Rn,[O(S,{name:`user`,size:14})]),h[45]||=f(` Informasi Akun 9Router`,-1)]),t(`div`,zn,[t(`div`,Bn,[h[46]||=t(`label`,{for:`name`},`Name`,-1),m(t(`input`,{id:`name`,"onUpdate:modelValue":h[7]||=e=>a(K).name=e,type:`text`,placeholder:`Akan terisi otomatis`},null,512),[[T,a(K).name]])]),t(`div`,Vn,[h[47]||=t(`label`,{for:`email`},`Email`,-1),m(t(`input`,{id:`email`,"onUpdate:modelValue":h[8]||=e=>a(K).email=e,type:`email`,placeholder:`Akan terisi otomatis`},null,512),[[T,a(K).email]])])])]),t(`div`,Hn,[t(`div`,Un,[t(`span`,Wn,[O(S,{name:`key`,size:14})]),h[48]||=f(` Ambil Token`,-1)]),t(`div`,Gn,[t(`div`,{class:v([`tab`,{active:a(K).tokenTab===`google`}]),onClick:h[9]||=e=>a(K).tokenTab=`google`},[O(S,{name:`globe`,size:15}),h[49]||=f(` Login Google `,-1)],2),t(`div`,{class:v([`tab`,{active:a(K).tokenTab===`keychain`}]),onClick:h[10]||=e=>a(K).tokenTab=`keychain`},[O(S,{name:`key`,size:15}),h[50]||=f(` Keychain `,-1)],2),t(`div`,{class:v([`tab`,{active:a(K).tokenTab===`paste`}]),onClick:h[11]||=e=>a(K).tokenTab=`paste`},[O(S,{name:`clipboard`,size:15}),h[51]||=f(` Paste Base64 `,-1)],2)]),a(K).tokenTab===`google`?(p(),n(`div`,Kn,[t(`button`,{class:`btn btn-google`,onClick:h[12]||=e=>a(ke)()},[O(S,{name:`globe`,size:16}),h[52]||=f(` Login dengan Google `,-1)])])):a(K).tokenTab===`keychain`?(p(),n(`div`,qn,[t(`button`,{class:`btn btn-primary w-full`,onClick:h[13]||=e=>a(Ae)()},[O(S,{name:`key`,size:16}),h[53]||=f(` Ambil dari Keychain `,-1)])])):(p(),n(`div`,Jn,[t(`div`,Yn,[h[54]||=t(`label`,{for:`pasteInput`},`Paste Keychain Backup`,-1),m(t(`textarea`,{id:`pasteInput`,"onUpdate:modelValue":h[14]||=e=>a(K).pasteInput=e,rows:`4`,placeholder:`go-keyring-base64:...`},null,512),[[T,a(K).pasteInput]])]),t(`button`,{class:`btn btn-primary w-full`,onClick:h[15]||=e=>a(je)()},[O(S,{name:`unlock`,size:16}),h[55]||=f(` Decode `,-1)])]))]),a(K).tokenData?(p(),n(`div`,Xn,[t(`div`,Zn,[t(`span`,Qn,[O(S,{name:`eye`,size:14})]),h[56]||=f(` Token Preview `,-1),t(`span`,$n,[t(`span`,{class:v([`badge`,u.value?`badge-warning`:`badge-success`])},c(u.value?`EXPIRED`:`VALID`),3)])]),t(`div`,er,[t(`div`,tr,[h[57]||=t(`span`,{class:`label`},`Access Token:`,-1),t(`span`,nr,c(a(K).tokenData.accessToken),1)]),t(`div`,rr,[h[58]||=t(`span`,{class:`label`},`Refresh Token:`,-1),t(`span`,ir,c(a(K).tokenData.refreshToken),1)]),t(`div`,ar,[h[59]||=t(`span`,{class:`label`},`Expiry:`,-1),t(`span`,or,c(a(K).tokenData.expiry),1)])])])):g(``,!0),a(K).tokenData?(p(),n(`div`,sr,[t(`div`,cr,[t(`span`,lr,[O(S,{name:`check-circle`,size:14})]),h[60]||=f(` Eligibility Check`,-1)]),a(K).eligibilityResult?(p(),n(`div`,ur,[t(`div`,{class:v([`badge`,a(K).eligibilityResult.eligible?`badge-success`:`badge-error`])},c(a(K).eligibilityResult.eligible?`OK`:`GAGAL`)+` — `+c(a(K).eligibilityResult.message||`Gagal`),3),a(K).eligibilityResult.verificationUrl?(p(),n(`a`,{key:0,href:a(K).eligibilityResult.verificationUrl,target:`_blank`,class:`btn btn-google mt-3`,style:{"text-decoration":`none`}},[O(S,{name:`external`,size:16}),h[62]||=f(` Verifikasi Manual`,-1)],8,dr)):g(``,!0),a(K).eligibilityResult.verificationUrl?(p(),n(`button`,{key:1,class:`btn btn-secondary mt-3 w-full`,onClick:h[17]||=e=>a(Me)()},[O(S,{name:`refresh`,size:16}),h[63]||=f(` Cek Ulang `,-1)])):g(``,!0)])):(p(),n(`button`,{key:0,class:`btn btn-primary w-full`,onClick:h[16]||=e=>a(Me)()},[O(S,{name:`check-circle`,size:16}),h[61]||=f(` Cek Eligibility Akun `,-1)]))])):g(``,!0)]),t(`section`,fr,[t(`div`,pr,[t(`div`,{class:`cursor-pointer text-sm font-bold`,onClick:h[18]||=e=>a(K).advancedOpen=!a(K).advancedOpen},[t(`span`,mr,[O(S,{name:`sliders`,size:15}),f(` `+c(a(K).advancedOpen?`▼`:`▶`)+` Advanced Options `,1)])]),m(t(`div`,hr,[t(`div`,gr,[h[64]||=t(`label`,{for:`scope`},`Scope`,-1),m(t(`textarea`,{id:`scope`,"onUpdate:modelValue":h[19]||=e=>a(K).scope=e,rows:`2`},null,512),[[T,a(K).scope]])]),t(`div`,_r,[h[65]||=t(`label`,{for:`projectId`},`Project ID`,-1),m(t(`input`,{id:`projectId`,"onUpdate:modelValue":h[20]||=e=>a(K).projectId=e,type:`text`,placeholder:`fresh-catcher-x5fd2`},null,512),[[T,a(K).projectId]])])],512),[[y,a(K).advancedOpen]])]),t(`div`,vr,[t(`div`,yr,[t(`span`,br,[O(S,{name:`bolt`,size:14})]),h[66]||=f(` Generate & Execute`,-1)]),t(`div`,xr,[t(`button`,{class:`btn btn-primary w-full`,onClick:h[21]||=e=>a(Pe)()},[O(S,{name:`bolt`,size:16}),h[67]||=f(` Generate SQL Query Only `,-1)]),t(`button`,{class:`btn btn-success w-full`,onClick:h[22]||=e=>a(Fe)()},[O(S,{name:`database`,size:16}),h[68]||=f(` Generate & Insert ke 9Router `,-1)])])]),a(K).output?(p(),n(`div`,Sr,[t(`div`,Cr,[t(`span`,wr,[O(S,{name:`file`,size:14})]),h[69]||=f(` Output SQL Query`,-1)]),t(`textarea`,{value:a(K).output,readonly:``,rows:`12`,class:`output-textarea`},null,8,Tr),t(`div`,Er,[t(`button`,{class:`btn btn-primary`,onClick:h[23]||=e=>a(Ie)()},[O(S,{name:`copy`,size:16}),h[70]||=f(` Copy`,-1)]),t(`button`,{class:`btn btn-secondary`,onClick:h[24]||=e=>a(Le)()},[O(S,{name:`download`,size:16}),h[71]||=f(` Download .sql`,-1)]),t(`button`,{class:`btn btn-success`,onClick:h[25]||=e=>a(Re)()},[O(S,{name:`undo`,size:16}),h[72]||=f(` Reset`,-1)])])])):g(``,!0)])])]))}},Or=j(Dr,[[`__scopeId`,`data-v-d630ffa5`]])})),Ar=s((()=>{})),jr,Mr,Nr,Pr,Fr,Ir,Lr,Rr,zr,Br,Vr,Hr,Ur,Wr,Gr=s((()=>{w(),k(),xt(),z(),Y(),Ar(),M(),jr={class:`tun-card`,role:`dialog`,"aria-modal":`true`},Mr={class:`tun-head`},Nr={class:`tun-head-icon`},Pr={key:0,class:`tun-body`},Fr={class:`tun-actions`},Ir={key:1,class:`tun-body`},Lr={key:0,class:`tun-result`},Rr={class:`tun-url`},zr={key:1,class:`tun-ok`},Br={key:2,class:`tun-fail`},Vr={class:`tun-actions`},Hr={key:1,class:`tun-running`},Ur={__name:`TunnelDialog`,props:{open:{type:Boolean,default:!1}},emits:[`close`],setup(r,{emit:i}){let a=r,o=i,s=e({phase:`confirm`,resultUrl:``,errorMessage:``,doneMessage:``}),l=e([]);function m(e,t=`t-info`){l.push({time:new Date().toLocaleTimeString(`id-ID`),text:e,cls:t})}function h(e){if(e.type===`start`)m(`Memulai aktivasi tunnel publik…`);else if(e.type===`log`){let t=e.level===`ok`?`t-ok`:e.level===`error`?`t-error`:e.level===`warn`?`t-warn`:`t-info`;m(e.text,t)}else e.type===`done`?(s.resultUrl=e.url||``,s.doneMessage=e.already?`Tunnel sudah aktif sebelumnya.`:`Tunnel aktif dan siap dibagikan!`,m(`URL publik: ${e.url}`,`t-ok`)):e.type===`error`&&(s.errorMessage=e.message,m(`GAGAL: ${e.message}`,`t-error`))}async function _(){s.phase=`running`,l.length=0,s.resultUrl=``,s.errorMessage=``;try{let e=await fetch(`/api/tunnel`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({enabled:!0})});if(!e.ok){let t=`HTTP ${e.status}`;try{let n=await e.json();n&&n.error&&(t=n.error)}catch{}m(`GAGAL: ${t}`,`t-error`),s.errorMessage=t,s.phase=`done`;return}let t=e.body.getReader(),n=new TextDecoder,r=``;for(;;){let{done:e,value:i}=await t.read();if(e)break;r+=n.decode(i,{stream:!0});let a=r.split(`
4
+ `);r=a.pop();for(let e of a)e.trim()&&h(JSON.parse(e))}}catch(e){m(`GAGAL: ${e.message}`,`t-error`),s.errorMessage=e.message}s.phase=`done`,s.resultUrl&&(I(`🌐 Tunnel aktif: `+s.resultUrl,`success`),Ke(),await W())}async function v(){if(s.resultUrl)try{await navigator.clipboard.writeText(s.resultUrl),I(`📋 URL tunnel tersalin`,`success`)}catch{I(`❌ Gagal menyalin URL`,`error`)}}function y(){s.phase!==`running`&&o(`close`)}function b(e){e.key===`Escape`&&a.open&&s.phase!==`running`&&o(`close`)}return d(()=>document.addEventListener(`keydown`,b)),u(()=>document.removeEventListener(`keydown`,b)),(e,i)=>(p(),N(P,{to:`body`},[r.open?(p(),n(`div`,{key:0,class:`tun-overlay`,onClick:F(y,[`self`])},[t(`div`,jr,[t(`div`,Mr,[t(`span`,Nr,[O(S,{name:`globe`,size:20})]),i[3]||=t(`div`,null,[t(`h2`,{class:`tun-title`},`Aktivasi Tunnel Publik`),t(`p`,{class:`tun-sub`},`Cloudflare Quick Tunnel — gratis, tanpa akun`)],-1),s.phase===`running`?g(``,!0):(p(),n(`button`,{key:0,class:`btn btn-secondary btn-icon`,title:`Tutup`,onClick:i[0]||=e=>o(`close`)},[O(S,{name:`x`,size:15})]))]),s.phase===`confirm`?(p(),n(`div`,Pr,[i[6]||=t(`p`,{class:`tun-message`},[f(` Mengaktifkan tunnel akan membuat dashboard & halaman donasi Anda bisa diakses publik lewat URL `),t(`strong`,null,`*.trycloudflare.com`),f(`. Aktivasi pertama `),t(`strong`,null,`mendownload cloudflared ±30 MB`),f(` — progresnya akan tampil di terminal, jadi Anda bisa melihat sampai mana prosesnya. `)],-1),t(`div`,Fr,[t(`button`,{class:`btn btn-secondary`,onClick:i[1]||=e=>o(`close`)},[O(S,{name:`x`,size:15}),i[4]||=f(` Batal `,-1)]),t(`button`,{class:`btn btn-primary`,onClick:_},[O(S,{name:`play`,size:15}),i[5]||=f(` Aktifkan Tunnel `,-1)])])])):(p(),n(`div`,Ir,[O(Z,{name:`tunnel-activation.log`,lines:l,height:`260px`},null,8,[`lines`]),s.phase===`done`&&s.resultUrl?(p(),n(`div`,Lr,[t(`div`,Rr,c(s.resultUrl),1),t(`button`,{class:`btn btn-primary`,onClick:v},[O(S,{name:`copy`,size:15}),i[7]||=f(` Copy URL `,-1)])])):g(``,!0),s.phase===`done`&&s.resultUrl?(p(),n(`p`,zr,c(s.doneMessage)+` Bagikan URL ini ke calon donatur.`,1)):g(``,!0),s.phase===`done`&&s.errorMessage?(p(),n(`p`,Br,c(s.errorMessage),1)):g(``,!0),t(`div`,Vr,[s.phase===`done`?(p(),n(`button`,{key:0,class:`btn btn-primary`,onClick:i[2]||=e=>o(`close`)},[O(S,{name:`check`,size:15}),i[8]||=f(` Selesai `,-1)])):(p(),n(`span`,Hr,[...i[9]||=[t(`span`,{class:`spinner`},null,-1),f(` Memproses…`,-1)]]))])]))])])):g(``,!0)]))}},Wr=j(Ur,[[`__scopeId`,`data-v-c6ed99b8`]])})),Kr=s((()=>{})),qr,Jr,Yr,Xr,Zr,Qr,$r,ei,ti,ni,ri,ii,ai,oi,si,ci,li,ui,di,fi,pi,mi,Q,hi,gi,_i,vi,yi,bi,xi,Si,Ci=s((()=>{w(),k(),Gr(),Y(),z(),Kr(),M(),qr={class:`space-y-10`},Jr={class:`grid gap-10 lg:grid-cols-2`},Yr={class:`neo-card p-6 sm:p-8`},Xr={class:`card-title`},Zr={class:`step step-yellow`},Qr={class:`field`},$r={class:`field`},ei={class:`field`},ti=[`disabled`],ni={key:0,class:`spinner`},ri={class:`neo-card p-6 sm:p-8`},ii={class:`card-title`},ai={class:`step step-blue`},oi={key:0,class:`warning-box mt-4`},si={class:`wb-icon`},ci={key:1,class:`tunnel-url-box mt-4`},li=[`href`],ui={class:`mt-5`},di=[`disabled`],fi={key:0,class:`spinner`},pi={class:`neo-card p-6 sm:p-8`},mi={class:`card-title`},Q={class:`step step-teal`},hi={class:`field`},gi=[`value`],_i={class:`flex flex-wrap gap-3`},vi={class:`neo-card p-6 sm:p-8`},yi={class:`card-title`},bi={class:`step step-green`},xi={__name:`SettingsView`,setup(e){let r=_(``),i=_(``),o=_(``),s=_(!1),l=_(!1),u=_(``),d=_(!1),y=h(()=>K.settings?.tunnel||{enabled:!1,url:null,status:`stopped`}),b=h(()=>!!K.settings?.passwordIsDefault),x=h(()=>y.value.status===`starting`||y.value.status===`stopping`),C=h(()=>{let e={running:[`badge-success`,`AKTIF`],starting:[`badge-warning`,`MEMULAI...`],stopping:[`badge-warning`,`MENGHENTIKAN...`],stopped:[`badge-error`,`MATI`]};return e[y.value.status]||e.stopped}),w=h(()=>{let e=K.settings;return e?e.nineRouterDbPendingPath?e.nineRouterDbPendingExists?[`badge-warning`,`TERSIMPAN · FILE ADA · TUNGGU RESTART`]:[`badge-error`,`TERSIMPAN · FILE TIDAK ADA · TUNGGU RESTART`]:e.nineRouterDbExists?[`badge-success`,`FILE DITEMUKAN`]:[`badge-error`,`FILE TIDAK DITEMUKAN`]:[`badge-warning`,`Memuat...`]}),E=h(()=>{if(d.value)return u.value;let e=K.settings;return e?.nineRouterDbPendingPath||e?.nineRouterDbPath||``});function D(e){d.value=!0,u.value=e.target.value}async function k(){if(!s.value){if(!r.value)return I(`❌ Password lama wajib diisi`,`error`);if(i.value.trim().length<8)return I(`❌ Password baru minimal 8 karakter`,`error`);if(i.value.trim()!==o.value.trim())return I(`❌ Konfirmasi password tidak sama`,`error`);if(i.value.trim()===`1234567890`)return I(`❌ Tidak boleh sama dengan password default`,`error`);s.value=!0;try{await Ve(r.value,i.value.trim()),r.value=``,i.value=``,o.value=``}catch(e){I(`❌ `+e.message,`error`)}finally{s.value=!1}}}async function A(){await He(E.value.trim()),d.value=!1}async function j(){d.value=!0,u.value=``,await A()}async function ee(){if(y.value.url)try{await navigator.clipboard.writeText(y.value.url),I(`📋 URL tunnel tersalin`,`success`)}catch{I(`❌ Gagal menyalin URL`,`error`)}}function te(){y.value.enabled?We():l.value=!0}return(e,u)=>(p(),n(`div`,qr,[t(`div`,Jr,[t(`section`,Yr,[t(`div`,Xr,[t(`span`,Zr,[O(S,{name:`lock`,size:14})]),u[5]||=f(` Keamanan — Ganti Password`,-1)]),t(`div`,{class:v([`badge mb-5`,a(K).settings?.passwordIsDefault?`badge-error`:`badge-success`])},c(a(K).settings?.passwordIsDefault?`PASSWORD DEFAULT`:`PASSWORD CUSTOM`),3),t(`div`,Qr,[u[6]||=t(`label`,{for:`currentPassword`},`Password Lama`,-1),m(t(`input`,{id:`currentPassword`,"onUpdate:modelValue":u[0]||=e=>r.value=e,type:`password`,placeholder:`Password saat ini`},null,512),[[T,r.value]])]),t(`div`,$r,[u[7]||=t(`label`,{for:`newPassword`},`Password Baru`,-1),m(t(`input`,{id:`newPassword`,"onUpdate:modelValue":u[1]||=e=>i.value=e,type:`password`,placeholder:`Minimal 8 karakter`},null,512),[[T,i.value]])]),t(`div`,ei,[u[8]||=t(`label`,{for:`confirmPassword`},`Ulangi Password Baru`,-1),m(t(`input`,{id:`confirmPassword`,"onUpdate:modelValue":u[2]||=e=>o.value=e,type:`password`,placeholder:`Ketik ulang password baru`},null,512),[[T,o.value]]),u[9]||=t(`p`,{class:`hint`},`Password baru minimal 8 karakter dan tidak boleh sama dengan password default.`,-1)]),t(`button`,{class:`btn btn-primary w-full`,disabled:s.value,onClick:k},[s.value?(p(),n(`span`,ni)):(p(),N(S,{key:1,name:`lock`,size:16})),u[10]||=t(`span`,null,`Ganti Password`,-1)],8,ti)]),t(`section`,ri,[t(`div`,ii,[t(`span`,ai,[O(S,{name:`globe`,size:14})]),u[11]||=f(` Tunnel Publik (Cloudflare)`,-1)]),t(`span`,{class:v([`badge`,C.value[0]])},c(C.value[1]),3),b.value?(p(),n(`div`,oi,[t(`span`,si,[O(S,{name:`alert`,size:20})]),u[12]||=t(`span`,null,[t(`strong`,null,`Tunnel terkunci.`),f(` Password masih default sehingga tunnel tidak bisa diaktifkan. Ganti password di menu `),t(`strong`,null,`Keamanan`),f(` terlebih dahulu.`)],-1)])):g(``,!0),y.value.url&&y.value.status===`running`?(p(),n(`div`,ci,[t(`a`,{href:y.value.url,target:`_blank`,rel:`noopener`},c(y.value.url),9,li),t(`button`,{class:`btn btn-secondary px-4 py-2 text-xs`,onClick:ee},[O(S,{name:`copy`,size:14}),u[13]||=f(` Copy `,-1)])])):g(``,!0),t(`div`,ui,[t(`button`,{class:`btn btn-primary w-full`,disabled:x.value||b.value,onClick:te},[x.value?(p(),n(`span`,fi)):(p(),N(S,{key:1,name:y.value.enabled?`stop`:`play`,size:16},null,8,[`name`])),t(`span`,null,c(y.value.enabled?`Matikan Tunnel`:`Aktifkan Tunnel`),1)],8,di)]),u[14]||=t(`div`,{class:`field mt-5`},[t(`p`,{class:`hint`},[f(`Bagikan URL `),t(`strong`,null,`*.trycloudflare.com`),f(` ke donatur supaya bisa membuka halaman donasi tanpa tahu IP/komputer Anda. Aktivasi pertama mendownload cloudflared ±30 MB.`)])],-1)]),t(`section`,pi,[t(`div`,mi,[t(`span`,Q,[O(S,{name:`database`,size:14})]),u[15]||=f(` Database 9Router`,-1)]),t(`div`,{class:v([`badge mb-5`,w.value[0]])},c(w.value[1]),3),t(`div`,hi,[u[16]||=t(`label`,{for:`nineRouterDbPath`},`Lokasi file data.sqlite`,-1),t(`input`,{id:`nineRouterDbPath`,type:`text`,spellcheck:`false`,placeholder:`/Users/you/.9router/db/data.sqlite`,value:E.value,onInput:D},null,40,gi),u[17]||=t(`p`,{class:`hint`},`Ubah kalau 9Router ter-install di lokasi non-standar. Kosongkan untuk memakai default. Perubahan berlaku setelah aplikasi direstart.`,-1)]),t(`div`,_i,[t(`button`,{class:`btn btn-primary`,onClick:A},[O(S,{name:`check`,size:16}),u[18]||=f(` Simpan`,-1)]),t(`button`,{class:`btn btn-secondary`,onClick:j},[O(S,{name:`undo`,size:16}),u[19]||=f(` Path Default`,-1)])])]),t(`section`,vi,[t(`div`,yi,[t(`span`,bi,[O(S,{name:`power`,size:14})]),u[20]||=f(` Auto Start (Saat Login)`,-1)]),t(`div`,{class:v([`badge mb-5`,a(K).settings?.autoStart?`badge-success`:`badge-error`])},c(a(K).settings?.autoStart?`AKTIF`:`NONAKTIF`),3),t(`button`,{class:`btn btn-primary w-full`,onClick:u[3]||=(...e)=>a(Ue)&&a(Ue)(...e)},[O(S,{name:a(K).settings?.autoStart?`stop`:`play`,size:16},null,8,[`name`]),f(` `+c(a(K).settings?.autoStart?`Matikan Auto Start`:`Aktifkan Auto Start`),1)]),u[21]||=t(`div`,{class:`field mt-5`},[t(`p`,{class:`hint`},`Aplikasi berjalan otomatis di mode tray saat macOS login. Bisa juga di-toggle dari icon tray.`)],-1)])]),O(Wr,{open:l.value,onClose:u[4]||=e=>l.value=!1},null,8,[`open`])]))}},Si=j(xi,[[`__scopeId`,`data-v-1ed6ed88`]])})),wi=s((()=>{})),Ti,Ei,Di,Oi,ki,Ai,ji,Mi,Ni,Pi,Fi,$,Ii=s((()=>{w(),C(),ce(),_e(),k(),at(),kr(),Ci(),Y(),wi(),M(),Ti={class:`p-4 sm:p-6 lg:p-8`},Ei={key:1,class:`mx-auto max-w-6xl space-y-10`},Di={class:`neo-card p-6 sm:p-8`},Oi={class:`flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between`},ki={class:`flex items-center gap-5`},Ai={class:`flex flex-wrap gap-3`},ji={class:`mt-6 grid gap-3 sm:grid-cols-2`},Mi={class:`neo-card-soft bg-[#fef08a] px-4 py-3 text-sm font-bold`},Ni={class:`neo-card-soft bg-[#bbf7d0] px-4 py-3 text-sm font-bold`},Pi={class:`nav-tabs`,"aria-label":`Menu utama`},Fi={__name:`App`,setup(e){let r=_(null);function i(e){K.view=e,e===`dashboard`?(Be(),U(!1).catch(()=>{})):(W(),ze())}function o(e){let t=e.target.files&&e.target.files[0];e.target.value=``,Oe(t)}return d(()=>{be().then(()=>{K.authed&&(K.connStatus=`Terhubung`,U(!1).catch(()=>{}))})}),(e,s)=>(p(),n(`div`,Ti,[a(K).authed?(p(),n(`main`,Ei,[t(`header`,Di,[t(`div`,Oi,[t(`div`,ki,[O(ae,{width:92,class:`hidden sm:block`}),s[6]||=t(`div`,null,[t(`p`,{class:`text-sm font-bold`},`Bismillah, Selamat Datang Admin`),t(`h1`,{class:`neo-display mt-2 text-3xl sm:text-4xl`},`Dashboard Donasi Antigravity`),t(`p`,{class:`mt-3 text-sm font-medium`},`Kelola token dari Google / Keychain ke 9Router Database.`)],-1)]),t(`div`,Ai,[t(`button`,{class:`btn btn-secondary`,onClick:s[0]||=e=>a(De)()},[O(S,{name:`download`,size:16}),s[7]||=f(` Export Data`,-1)]),t(`button`,{class:`btn btn-secondary`,onClick:s[1]||=e=>r.value.click()},[O(S,{name:`upload`,size:16}),s[8]||=f(` Import Data`,-1)]),t(`button`,{class:`btn btn-primary`,onClick:s[2]||=e=>a(U)()},[O(S,{name:`refresh`,size:16}),s[9]||=f(` Refresh`,-1)]),t(`button`,{class:`btn btn-success`,onClick:s[3]||=e=>a(Se)()},[O(S,{name:`logout`,size:16}),s[10]||=f(` Logout`,-1)])]),t(`input`,{ref_key:`importFileInput`,ref:r,type:`file`,accept:`.csv,text/csv`,class:`hidden`,onChange:o},null,544)]),t(`div`,ji,[t(`div`,Mi,[s[11]||=f(`Status Koneksi: `,-1),t(`span`,null,c(a(K).connStatus),1)]),t(`div`,Ni,[s[12]||=f(`Sinkron Terakhir: `,-1),t(`span`,null,c(a(K).lastSync),1)])])]),t(`nav`,Pi,[t(`div`,{class:v([`tab`,{active:a(K).view===`dashboard`}]),onClick:s[4]||=e=>i(`dashboard`)},[O(S,{name:`home`,size:16}),s[13]||=f(` Dashboard `,-1)],2),t(`div`,{class:v([`tab`,{active:a(K).view===`settings`}]),onClick:s[5]||=e=>i(`settings`)},[O(S,{name:`sliders`,size:16}),s[14]||=f(` Pengaturan `,-1)],2)]),a(K).view===`dashboard`?(p(),N(Or,{key:0})):(p(),N(Si,{key:1}))])):(p(),N(it,{key:0})),O(ge),O(se)]))}},$=j(Fi,[[`__scopeId`,`data-v-108271c8`]])}));ne((()=>{w(),Ii(),ie(),A($).mount(`#app`)}))();
@@ -0,0 +1 @@
1
+ .confirm-overlay[data-v-2e9843c0]{z-index:60;background:#000000b8;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.confirm-card[data-v-2e9843c0]{text-align:center;background:#fff;border:4px solid #000;border-radius:8px;width:min(100%,440px);padding:28px;box-shadow:10px 10px #000}.confirm-icon[data-v-2e9843c0]{background:#bbf7d0;border:3px solid #000;border-radius:8px;justify-content:center;align-items:center;width:54px;height:54px;margin-bottom:16px;display:inline-flex;box-shadow:4px 4px #000}.confirm-icon.danger[data-v-2e9843c0]{background:#fecaca}.confirm-title[data-v-2e9843c0]{margin:0 0 10px;font-family:Archivo Black,Impact,sans-serif;font-size:20px}.confirm-message[data-v-2e9843c0]{word-break:break-word;margin:0 0 22px;font-size:14px;line-height:1.6}.confirm-actions[data-v-2e9843c0]{flex-wrap:wrap;justify-content:center;gap:14px;display:flex}.btn-danger[data-v-2e9843c0]{color:#000;background:#f87171}.login-lock[data-v-8cb9a1a5]{background:var(--neo-yellow,#fef08a);border:3px solid #000;border-radius:8px;justify-content:center;align-items:center;width:44px;height:44px;display:inline-flex;box-shadow:4px 4px #000}.default-pass-hint[data-v-8cb9a1a5]{background:var(--neo-yellow,#fef08a);text-align:left;border:3px dashed #000;border-radius:6px;margin-top:1.5rem;padding:12px 14px;font-size:13px;font-weight:500;line-height:1.6}.default-pass-hint code[data-v-8cb9a1a5]{background:#fff;border:2px solid #000;border-radius:4px;padding:2px 8px;font-family:JetBrains Mono,Courier New,monospace;font-weight:700}.dd-root[data-v-ecad6e79]{display:inline-block;position:relative}.dd-panel[data-v-ecad6e79]{z-index:80;background:#fff;border:3px solid #000;border-radius:6px;gap:4px;min-width:210px;padding:6px;display:grid;position:fixed;box-shadow:6px 6px #000}.dd-item[data-v-ecad6e79]{text-align:left;cursor:pointer;white-space:nowrap;background:0 0;border:2px solid #0000;border-radius:4px;align-items:center;gap:10px;width:100%;padding:10px 12px;font-size:13px;font-weight:700;display:flex}.dd-item[data-v-ecad6e79]:hover{background:#fef08a;border-color:#000}.dd-item.danger[data-v-ecad6e79]{color:#b91c1c}.dd-item.danger[data-v-ecad6e79]:hover{background:#fecaca}.dd-enter-active[data-v-ecad6e79],.dd-leave-active[data-v-ecad6e79]{transition:opacity .12s,transform .12s}.dd-enter-from[data-v-ecad6e79],.dd-leave-to[data-v-ecad6e79]{opacity:0;transform:translateY(-4px)}.terminal[data-v-5b0ac08c]{background:#0c0c0c;border:3px solid #000;border-radius:6px;overflow:hidden;box-shadow:5px 5px #000}.terminal-head[data-v-5b0ac08c]{background:#000;border-bottom:3px solid #2a2a2a;align-items:center;gap:6px;padding:8px 12px;display:flex}.tdot[data-v-5b0ac08c]{border:2px solid #000;border-radius:50%;width:11px;height:11px}.td-r[data-v-5b0ac08c]{background:#f87171}.td-y[data-v-5b0ac08c]{background:#fbbf24}.td-g[data-v-5b0ac08c]{background:#4ade80}.terminal-name[data-v-5b0ac08c]{color:#9ca3af;margin-left:8px;font:11px JetBrains Mono,Courier New,monospace}.terminal-body[data-v-5b0ac08c]{flex-direction:column;gap:3px;height:230px;padding:10px 12px;display:flex;overflow-y:auto}.tline[data-v-5b0ac08c]{color:#e5e5e5;word-break:break-all;gap:10px;font:12px/1.5 JetBrains Mono,Courier New,monospace;display:flex}.ttime[data-v-5b0ac08c]{color:#6b7280;flex:none}.t-info .ttext[data-v-5b0ac08c]{color:#e5e5e5}.t-ok .ttext[data-v-5b0ac08c]{color:#4ade80}.t-warn .ttext[data-v-5b0ac08c]{color:#fbbf24}.t-error .ttext[data-v-5b0ac08c]{color:#f87171}.sync-overlay[data-v-79db2475]{z-index:70;background:#000000b8;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.sync-card[data-v-79db2475]{background:#fff;border:4px solid #000;border-radius:8px;width:min(100%,640px);padding:24px;box-shadow:10px 10px #000}.sync-head[data-v-79db2475]{border-bottom:3px solid #000;align-items:center;gap:14px;margin-bottom:18px;padding-bottom:16px;display:flex}.sync-head-icon[data-v-79db2475]{background:#bfdbfe;border:3px solid #000;border-radius:8px;flex:none;justify-content:center;align-items:center;width:48px;height:48px;display:inline-flex;box-shadow:4px 4px #000}.sync-title[data-v-79db2475]{margin:0;font-family:Archivo Black,Impact,sans-serif;font-size:19px}.sync-sub[data-v-79db2475]{margin:4px 0 0;font-size:12px;font-weight:500}.sync-head .btn-icon[data-v-79db2475]{margin-left:auto}.sync-body[data-v-79db2475]{gap:16px;display:grid}.sync-message[data-v-79db2475]{margin:0;font-size:14px;line-height:1.65}.sync-progress[data-v-79db2475]{align-items:center;gap:12px;display:flex}.sync-progress-bar[data-v-79db2475]{background:#fff;border:3px solid #000;border-radius:4px;flex:1;height:20px;overflow:hidden}.sync-progress-fill[data-v-79db2475]{background:#22c55e;border-right:3px solid #000;height:100%;transition:width .15s}.sync-progress-text[data-v-79db2475]{white-space:nowrap;font-size:13px;font-weight:700}.sync-done[data-v-79db2475]{background:#bbf7d0;border:3px solid #000;border-radius:6px;margin:0;padding:10px 12px;font-size:13px;font-weight:700}.sync-actions[data-v-79db2475]{flex-wrap:wrap;justify-content:flex-end;gap:12px;display:flex}.stat-card[data-v-d630ffa5]{position:relative}.stat-icon[data-v-d630ffa5]{background:#fff;border:3px solid #000;border-radius:8px;justify-content:center;align-items:center;width:38px;height:38px;display:inline-flex;position:absolute;top:18px;right:18px;box-shadow:3px 3px #000}.step-pink[data-v-d630ffa5]{background:#f9a8d4}.link-grid[data-v-d630ffa5]{grid-template-columns:minmax(0,1fr) minmax(0,1.4fr);align-items:end;gap:20px;display:grid}@media (width<=767px){.link-grid[data-v-d630ffa5]{grid-template-columns:1fr;align-items:stretch}.link-result[data-v-d630ffa5]{flex-direction:column;align-items:stretch}.link-copy[data-v-d630ffa5],.link-open[data-v-d630ffa5]{width:100%}}.link-result[data-v-d630ffa5]{align-items:stretch;gap:10px;min-width:0;display:flex}.url-box[data-v-d630ffa5]{word-break:break-all;background:#f4f4f0;border:3px solid #000;border-radius:6px;flex:1;align-items:center;gap:8px;min-width:0;padding:11px 13px;font:700 12.5px/1.4 JetBrains Mono,Courier New,monospace;display:flex}.url-box.empty[data-v-d630ffa5]{color:#666;font-family:Space Grotesk,sans-serif;font-weight:500}.url-icon[data-v-d630ffa5],.link-copy[data-v-d630ffa5],.link-open[data-v-d630ffa5]{flex:none}.link-basis[data-v-d630ffa5]{background:#fef08a;border:2px solid #000;border-radius:4px;align-items:center;gap:8px;margin-top:16px;padding:10px 12px;font-size:12px;line-height:1.5;display:flex}.step-teal[data-v-d630ffa5]{background:#99f6e4}.step-green[data-v-d630ffa5]{background:#bbf7d0}.step-blue[data-v-d630ffa5]{background:#bfdbfe}.step-orange[data-v-d630ffa5]{background:#fdba74}.step-yellow[data-v-d630ffa5]{background:#fef08a}.data-table th[data-v-d630ffa5]{text-transform:uppercase;letter-spacing:.05em;padding:12px 14px;font-size:11px}.data-table td[data-v-d630ffa5]{padding:10px 14px;font-size:13px}.temporary-check-log[data-v-d630ffa5]{background:#fff;border:4px solid #000;box-shadow:6px 6px #000}.temporary-check-log pre[data-v-d630ffa5]{white-space:pre-wrap;word-break:break-word;background:#f4f4f0;border:2px solid #000;max-height:320px;padding:12px;font:12px/1.45 JetBrains Mono,Courier New,monospace;overflow:auto}.token-preview[data-v-d630ffa5]{background:#fff;border:3px solid #000;border-radius:6px;padding:14px;font-family:JetBrains Mono,Courier New,monospace;font-size:12px;line-height:1.55;box-shadow:5px 5px #000}.token-preview .row[data-v-d630ffa5]{gap:8px;margin-bottom:6px;display:flex}.token-preview .label[data-v-d630ffa5]{min-width:120px;font-weight:700}.token-preview .value[data-v-d630ffa5]{word-break:break-all}.token-preview .value.truncate[data-v-d630ffa5]{text-overflow:ellipsis;white-space:nowrap;max-width:500px;overflow:hidden}.output-textarea[data-v-d630ffa5]{min-height:200px;font-family:JetBrains Mono,Courier New,monospace;font-size:12px}.tun-overlay[data-v-c6ed99b8]{z-index:70;background:#000000b8;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.tun-card[data-v-c6ed99b8]{background:#fff;border:4px solid #000;border-radius:8px;width:min(100%,620px);padding:24px;box-shadow:10px 10px #000}.tun-head[data-v-c6ed99b8]{border-bottom:3px solid #000;align-items:center;gap:14px;margin-bottom:18px;padding-bottom:16px;display:flex}.tun-head-icon[data-v-c6ed99b8]{background:#bfdbfe;border:3px solid #000;border-radius:8px;flex:none;justify-content:center;align-items:center;width:48px;height:48px;display:inline-flex;box-shadow:4px 4px #000}.tun-title[data-v-c6ed99b8]{margin:0;font-family:Archivo Black,Impact,sans-serif;font-size:19px}.tun-sub[data-v-c6ed99b8]{margin:4px 0 0;font-size:12px;font-weight:500}.tun-head .btn-icon[data-v-c6ed99b8]{margin-left:auto}.tun-body[data-v-c6ed99b8]{gap:16px;display:grid}.tun-message[data-v-c6ed99b8]{margin:0;font-size:14px;line-height:1.65}.tun-result[data-v-c6ed99b8]{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.tun-url[data-v-c6ed99b8]{word-break:break-all;background:#f4f4f0;border:3px solid #000;border-radius:6px;flex:1;min-width:0;padding:10px 12px;font:700 12.5px/1.4 JetBrains Mono,Courier New,monospace}.tun-ok[data-v-c6ed99b8]{background:#bbf7d0;border:3px solid #000;border-radius:6px;margin:0;padding:10px 12px;font-size:13px;font-weight:700}.tun-fail[data-v-c6ed99b8]{word-break:break-word;background:#fecaca;border:3px solid #000;border-radius:6px;margin:0;padding:10px 12px;font-size:13px;font-weight:700}.tun-actions[data-v-c6ed99b8]{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:12px;display:flex}.tun-running[data-v-c6ed99b8]{align-items:center;gap:8px;font-size:13px;font-weight:700;display:inline-flex}.step-teal[data-v-1ed6ed88]{background:#99f6e4}.step-green[data-v-1ed6ed88]{background:#bbf7d0}.step-blue[data-v-1ed6ed88]{background:#bfdbfe}.step-yellow[data-v-1ed6ed88]{background:#fef08a}.tunnel-url-box[data-v-1ed6ed88]{background:#f4f4f0;border:3px solid #000;border-radius:6px;flex-wrap:wrap;align-items:center;gap:10px;padding:10px 12px;display:flex}.tunnel-url-box a[data-v-1ed6ed88]{word-break:break-all;font:700 12px/1.4 JetBrains Mono,Courier New,monospace}.warning-box[data-v-1ed6ed88]{background:#fde68a;border:3px solid #000;border-radius:6px;align-items:flex-start;gap:10px;padding:12px 14px;font-size:13px;font-weight:500;line-height:1.55;display:flex}.wb-icon[data-v-1ed6ed88]{background:#fecaca;border:2px solid #000;border-radius:6px;flex:none;justify-content:center;align-items:center;width:34px;height:34px;display:inline-flex}body[data-v-108271c8]{background:radial-gradient(circle at 8% 8%, #fde68a 0 150px, transparent 151px), radial-gradient(circle at 92% 88%, #86efac 0 130px, transparent 131px), var(--neo-cream-2,#fdf6e2)}
@@ -0,0 +1 @@
1
+ import{C as e,D as t,E as n,J as r,K as i,N as a,O as o,P as s,R as ee,T as c,V as l,W as te,a as ne,c as u,d,f,g as re,i as ie,k as p,l as m,m as h,n as g,o as _,q as v,r as y,t as b,u as ae}from"./styles-pGt3BQwq.js";var x=r((()=>{})),S=r((()=>{})),oe,se,ce,le,ue,C,w,T,E,D,O,k,A,j,M,N,P,F,I,L,R,z,B,V,H,U,W,de,fe,pe,me,he,ge,_e,ve,G,ye,K,q,J,Y=r((()=>{f(),x(),d(),m(),_(),S(),y(),oe={class:`px-4 py-10 sm:px-8`},se={class:`mx-auto w-full max-w-2xl`},ce={class:`neo-card hero-card p-7 sm:p-10`},le={class:`hero-deco hero-deco-1`},ue={class:`hero-deco hero-deco-2`},C={class:`hero-deco hero-deco-3`},w={class:`sticker-row`},T={class:`sticker sticker-green`},E={class:`sticker sticker-yellow`},D={class:`sticker sticker-teal`},O={class:`neo-display mb-3 text-3xl leading-tight sm:text-4xl`},k={id:`recipientName`,class:`bg-[#fef08a] px-2`},A={class:`mb-6 text-sm font-medium`},j={class:`mb-6 border-4 border-black bg-[#fef08a] p-4 shadow-[5px_5px_0_0_rgba(0,0,0,1)]`},M={class:`mb-3 text-sm font-medium leading-relaxed`},N=[`disabled`],P={key:0,class:`spinner`},F={key:1,class:`g-logo`,width:`24`,height:`24`,viewBox:`0 0 24 24`,"aria-hidden":`true`},I={key:1,class:`manual-flow`},L=[`disabled`],R=[`disabled`],z={key:0,class:`spinner`},B={key:1},V={class:`privacy-note`},H=[`innerHTML`],U={key:0,class:`eligibility-modal`,role:`dialog`,"aria-modal":`true`},W={class:`eligibility-dialog`},de=[`innerHTML`],fe={key:1,class:`mt-3`},pe=[`href`],me=[`disabled`],he={key:0,class:`spinner`},ge={key:1},_e={key:2,class:`mt-3`},ve={key:3,class:`mt-3`},G=`antigravity_oauth_transaction`,ye=6e5,K=`antigravity_eligibility_state`,q={__name:`App`,setup(r){let d=l(`sahabat`),f=l(`tab`),m=`1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com`,h=`https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/cclog https://www.googleapis.com/auth/experimentsandconfigs openid`,g=l(!1),_=l(!1),v=l(``),y=l(!1),b=l(!1),x=l(null),S=l(null),q=l(!1);function J(e){return String(e).replace(/[&<>'"]/g,e=>({"&":`&amp;`,"<":`&lt;`,">":`&gt;`,"'":`&#39;`,'"':`&quot;`})[e])}function Y(e,t){x.value={type:e,html:t}}function X(e,t=null){localStorage.setItem(K,JSON.stringify({eligibilityStatus:e.status,needVerification:!!e.needVerification,validationUrl:e.validationUrl||null,currentTier:e.currentTier||null,checkedAt:e.checkedAt||new Date().toISOString(),checkId:t||e.checkId||null,message:e.message||null}))}function Z(e){let t=e.status===`verification_required`;S.value={mode:`fail`,title:t?`Account Verification Required`:`Account Not Eligible`,message:t?`Akun Google Anda perlu diverifikasi sebelum dapat menggunakan Antigravity.`:e.message||`Akun tidak eligible untuk Antigravity.`,reason:t?`Google meminta verifikasi tambahan untuk memastikan akun memenuhi persyaratan Antigravity.`:``,validationUrl:e.validationUrl||null,checkId:e.checkId||null}}function Q(e){X({...e,status:`eligible`}),S.value={mode:`success`,title:`Terimakasih!`,message:`Partisipasi dukungan token Antigravity dari kamu sangat membantu.`,reason:`Current Tier: ${J(e.currentTier?.id||`Unknown`)}`}}function $(e){let t=``;return e.forEach(e=>{t+=String.fromCharCode(e)}),btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}async function be(){let e=new Uint8Array(32);crypto.getRandomValues(e);let t=$(e);crypto.getRandomValues(e);let n=$(e),r=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(t)),i=$(new Uint8Array(r));sessionStorage.setItem(G,JSON.stringify({codeVerifier:t,state:n,timestamp:Date.now()}));let a=new URL(`https://accounts.google.com/o/oauth2/auth`);return a.searchParams.set(`access_type`,`offline`),a.searchParams.set(`client_id`,m),a.searchParams.set(`code_challenge`,i),a.searchParams.set(`code_challenge_method`,`S256`),a.searchParams.set(`prompt`,`consent`),a.searchParams.set(`redirect_uri`,`https://antigravity.google/oauth-callback`),a.searchParams.set(`response_type`,`code`),a.searchParams.set(`scope`,h),a.searchParams.set(`state`,n),a.toString()}async function xe(){Y(`info`,`<strong>Menyiapkan login...</strong><br>Jendela autentikasi sedang dibuka.`),g.value=!0;let e;try{if(f.value===`popup`){let t=Math.max(0,(window.screen.width-520)/2),n=Math.max(0,(window.screen.height-700)/2);e=window.open(`about:blank`,`googleOAuth`,`width=520,height=700,left=${t},top=${n}`)}else e=window.open(`about:blank`,`_blank`);if(!e){Y(`error`,`<strong>Jendela login diblokir browser.</strong><br>Izinkan popup/tab baru, lalu tekan tombol Login dengan Google lagi.`);return}e.location.href=await be()}finally{g.value=!1}y.value=!0,Y(`info`,`<strong>Menunggu kode autentikasi</strong><br>Login selesai? Salin kode pada halaman Antigravity, lalu kembali ke sini. Kalau jendelanya tertutup, tekan tombol Login lagi.`)}function Se(){try{return JSON.parse(sessionStorage.getItem(G)||`null`)}catch{return null}}async function Ce(){let e=v.value.trim();if(!e){Y(`error`,`<strong>Authentication code diperlukan.</strong><br>Tempel kode dari halaman Antigravity terlebih dahulu.`);return}let t=Se();if(!t||!t.codeVerifier||!t.state||Date.now()-t.timestamp>ye){Y(`error`,`<strong>Tidak valid OAuth state.</strong><br>Tekan Login dengan Google untuk memulai ulang.`),g.value=!1;return}b.value=!0,Y(`sending`,`<strong>Memeriksa dan menyimpan token...</strong><br>Mohon tunggu sebentar.`);try{let n=await ne(`/oauth/exchange`,{code:e,code_verifier:t.codeVerifier,state:t.state,requestedFor:d.value,source:`public`});sessionStorage.removeItem(G),Q(n),_.value=!0}catch(e){let t=e.payload;if(t?.status===`verification_required`&&t.validationUrl&&t.checkId){let e={...t,checkedAt:new Date().toISOString()};X(e,t.checkId),Z({...e,checkId:t.checkId}),b.value=!1;return}if(t?.status===`failed`){let e={...t,checkedAt:new Date().toISOString()};X(e),Z(e),b.value=!1;return}Y(`error`,`<strong>${J(e.message.includes(`state`)?`Tidak valid OAuth state.`:e.message.includes(`eligible`)?e.message:`Tukar token gagal. Pastikan kode masih valid lalu coba lagi.`)}</strong>`),b.value=!1}}async function we(){q.value=!0,Y(`sending`,`<strong>Rechecking eligibility...</strong><br>Mohon tunggu sebentar.`);try{Q(await ne(`/oauth/eligibility/recheck`,{checkId:S.value.checkId})),_.value=!0}catch(e){let t=e.payload;if(t?.status===`verification_required`&&t.validationUrl){X(t,S.value.checkId),Z({...t,checkId:S.value.checkId});return}if(t?.status===`failed`){X(t),Z(t);return}Y(`error`,`<strong>${J(e.message||`Eligibility recheck gagal.`)}</strong>`)}finally{q.value=!1}}function Te(){localStorage.removeItem(K),S.value=null}function Ee(){localStorage.removeItem(K),sessionStorage.removeItem(G),window.location.reload()}return a(async()=>{let e=new URLSearchParams(window.location.search);d.value=(e.get(`for`)||``).trim()||`sahabat`;try{let e=await ie(`/api/oauth-config`);e.success&&((e.method===`tab`||e.method===`popup`)&&(f.value=e.method),e.clientId&&(m=e.clientId),e.scope&&(h=e.scope))}catch{}try{let e=JSON.parse(localStorage.getItem(K)||`null`);if(!e)return;e.eligibilityStatus===`eligible`?(Q(e),_.value=!0):(e.eligibilityStatus===`verification_required`||e.eligibilityStatus===`failed`)&&Z(e)}catch{localStorage.removeItem(K)}}),(r,a)=>(s(),n(`div`,oe,[e(`main`,se,[e(`div`,ce,[e(`span`,le,[p(u,{name:`star`,size:22})]),e(`span`,ue,[p(u,{name:`sparkle`,size:18})]),e(`span`,C,[p(u,{name:`sparkle`,size:16})]),p(ae,{width:128,class:`mx-auto`}),e(`div`,w,[e(`span`,T,[p(u,{name:`bolt`,size:14}),a[1]||=o(` 100% Gratis`,-1)]),e(`span`,E,[p(u,{name:`clock`,size:14}),a[2]||=o(` Cuma ±2 Menit`,-1)]),e(`span`,D,[p(u,{name:`shield`,size:14}),a[3]||=o(` Aman & Privat`,-1)])]),a[18]||=e(`p`,{class:`mb-3 mt-6 text-sm font-bold`},`Assalamu'alaikum Warahmatullahi Wabarakatuh,`,-1),e(`h1`,O,[a[4]||=o(` Hai `,-1),e(`span`,k,i(d.value),1),a[5]||=o(`, Boleh Titipkan Token Antigravity-mu? `,-1)]),e(`p`,A,[a[6]||=o(` Link ini khusus untuk kamu, `,-1),e(`strong`,null,i(d.value),1),a[7]||=o(` — token Antigravity dari akunmu akan membantu kelangsungan proyek ini. `,-1)]),e(`div`,j,[e(`p`,M,[a[8]||=o(` Terima kasih banyak `,-1),e(`strong`,null,i(d.value),1),a[9]||=o(` sudah menyempatkan waktu dan kebaikannya sampai di halaman ini. Link ini memang saya kirim khusus untuk meminta partisipasi dukungan token Antigravity dari kamu, dan itu sangat berarti untuk membantu pengerjaan serta kelangsungan proyek ini. `,-1)]),a[10]||=e(`p`,{class:`text-sm font-medium leading-relaxed`},[o(` InsyaAllah setiap dukungan dari kamu jadi berkah dan amal jariyah. `),e(`br`),e(`strong`,null,`Jazakallahu Khairan!`)],-1)]),a[19]||=t(`<div class="tutorial" aria-labelledby="tutorialTitle" data-v-94ec5ef7><h2 id="tutorialTitle" data-v-94ec5ef7>Cara menyelesaikan login</h2><ol class="tutorial-list" data-v-94ec5ef7><li class="tutorial-step" data-v-94ec5ef7><span class="step-number step-c-1" data-v-94ec5ef7>1</span><p data-v-94ec5ef7>Tekan <strong data-v-94ec5ef7>Login dengan Google</strong>. Halaman Google akan terbuka di tab atau popup baru.</p></li><li class="tutorial-step" data-v-94ec5ef7><span class="step-number step-c-2" data-v-94ec5ef7>2</span><p data-v-94ec5ef7>Login dan izinkan akses sampai muncul halaman Google Antigravity seperti contoh di bawah.</p></li><li class="tutorial-step" data-v-94ec5ef7><span class="step-number step-c-3" data-v-94ec5ef7>3</span><p data-v-94ec5ef7>Tekan tombol <strong data-v-94ec5ef7>Copy to Clipboard</strong> pada halaman tersebut.</p></li><li class="tutorial-step" data-v-94ec5ef7><span class="step-number step-c-4" data-v-94ec5ef7>4</span><p data-v-94ec5ef7>Kembali ke halaman ini, tempel kode, lalu tekan <strong data-v-94ec5ef7>Submit Token</strong>.</p></li></ol><img class="tutorial-image" src="/ex.jpeg" alt="Contoh halaman Google Antigravity dengan tombol Copy to Clipboard" data-v-94ec5ef7></div>`,1),_.value?c(``,!0):(s(),n(`button`,{key:0,class:`g-btn neo-button`,type:`button`,disabled:g.value,onClick:xe},[g.value?(s(),n(`span`,P)):(s(),n(`svg`,F,[...a[11]||=[e(`path`,{fill:`#4285F4`,d:`M23.49 12.27c0-.79-.07-1.54-.19-2.27H12v4.51h6.47c-.29 1.48-1.14 2.73-2.4 3.58v3h3.86c2.26-2.09 3.56-5.17 3.56-8.82z`},null,-1),e(`path`,{fill:`#34A853`,d:`M12 24c3.24 0 5.95-1.08 7.93-2.91l-3.86-3c-1.08.72-2.45 1.16-4.07 1.16-3.13 0-5.78-2.11-6.73-4.96H1.29v3.09C3.26 21.3 7.31 24 12 24z`},null,-1),e(`path`,{fill:`#FBBC05`,d:`M5.27 14.29c-.25-.72-.38-1.49-.38-2.29s.14-1.57.38-2.29V6.62H1.29C.47 8.24 0 10.06 0 12s.47 3.76 1.29 5.38l3.98-3.09z`},null,-1),e(`path`,{fill:`#EA4335`,d:`M12 4.75c1.77 0 3.35.61 4.6 1.8l3.42-3.42C17.95 1.19 15.24 0 12 0 7.31 0 3.26 2.7 1.29 6.62l3.98 3.09C6.22 6.86 8.87 4.75 12 4.75z`},null,-1)]])),a[12]||=e(`span`,{class:`g-label`},`Login dengan Google`,-1),a[13]||=e(`svg`,{class:`g-arrow`,width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`3`,"stroke-linecap":`round`,"stroke-linejoin":`round`,"aria-hidden":`true`},[e(`path`,{d:`M5 12h14`}),e(`path`,{d:`M13 6l6 6-6 6`})],-1)],8,N)),_.value?c(``,!0):(s(),n(`div`,I,[a[15]||=e(`h2`,null,`Tempel kode autentikasi`,-1),a[16]||=e(`p`,null,` Kode ini dipakai satu kali untuk menukar akses secara aman di server. Jangan membagikan kode tersebut kepada orang lain. `,-1),a[17]||=e(`label`,{for:`authCode`},`Authentication Code`,-1),ee(e(`textarea`,{id:`authCode`,"onUpdate:modelValue":a[0]||=e=>v.value=e,class:`code-input`,rows:`3`,autocomplete:`off`,spellcheck:`false`,placeholder:`Tempel kode dari halaman Antigravity di sini`,disabled:!y.value},null,8,L),[[re,v.value]]),e(`button`,{class:`neo-button btn-secondary`,type:`button`,disabled:!y.value||b.value,onClick:Ce},[b.value?(s(),n(`span`,z)):(s(),n(`span`,B,`Submit Token`))],8,R),e(`p`,V,[p(u,{name:`shield`,size:14,class:`privacy-icon`}),a[14]||=o(` Client secret tidak pernah dikirim ke browser. Server akan mengecek token terlebih dahulu sebelum menyimpannya. `,-1)])])),x.value?(s(),n(`div`,{key:2,class:te([`status-box`,`show status-${x.value.type}`]),innerHTML:x.value.html},null,10,H)):c(``,!0)])]),S.value?(s(),n(`div`,U,[e(`div`,W,[e(`h2`,null,i(S.value.title),1),e(`p`,null,i(S.value.message),1),S.value.reason?(s(),n(`p`,{key:0,class:`text-sm`,innerHTML:S.value.reason},null,8,de)):c(``,!0),S.value.mode===`fail`&&S.value.validationUrl?(s(),n(`div`,fe,[e(`a`,{class:`neo-button btn-secondary`,href:S.value.validationUrl,target:`_blank`,rel:`noopener`},`✅ Verify Account`,8,pe),e(`button`,{class:`neo-button btn-secondary`,type:`button`,disabled:q.value,onClick:we},[q.value?(s(),n(`span`,he)):(s(),n(`span`,ge,`🔄 Check Again`))],8,me)])):S.value.mode===`fail`?(s(),n(`div`,_e,[e(`button`,{class:`neo-button btn-secondary`,type:`button`,onClick:Te},`Coba Login Lagi`)])):(s(),n(`div`,ve,[e(`button`,{class:`neo-button btn-secondary`,type:`button`,onClick:Ee},`Tambah Lagi`)]))])])):c(``,!0)]))}},J=g(q,[[`__scopeId`,`data-v-94ec5ef7`]])}));v((()=>{f(),Y(),b(),h(J).mount(`#app`)}))();
@@ -0,0 +1 @@
1
+ .hero-card[data-v-94ec5ef7]{position:relative;overflow:visible}.hero-deco[data-v-94ec5ef7]{z-index:1;border:3px solid #000;border-radius:8px;justify-content:center;align-items:center;width:38px;height:38px;display:inline-flex;position:absolute;box-shadow:3px 3px #000}.hero-deco-1[data-v-94ec5ef7]{background:#fdba74;top:18px;left:16px;transform:rotate(-8deg)}.hero-deco-2[data-v-94ec5ef7]{background:#f9a8d4;top:60px;right:20px;transform:rotate(10deg)}.hero-deco-3[data-v-94ec5ef7]{background:#bfdbfe;bottom:130px;left:-14px;transform:rotate(6deg)}.sticker-row[data-v-94ec5ef7]{flex-wrap:wrap;justify-content:center;gap:12px;margin-top:18px;display:flex}.sticker[data-v-94ec5ef7]{border:3px solid #000;border-radius:6px;align-items:center;gap:7px;padding:8px 13px;font-size:12.5px;font-weight:700;display:inline-flex;box-shadow:3px 3px #000}.sticker-green[data-v-94ec5ef7]{background:#bbf7d0;transform:rotate(-2deg)}.sticker-yellow[data-v-94ec5ef7]{background:#fef08a;transform:rotate(1.5deg)}.sticker-teal[data-v-94ec5ef7]{background:#99f6e4;transform:rotate(-1deg)}.step-c-1[data-v-94ec5ef7]{background:#fef08a}.step-c-2[data-v-94ec5ef7]{background:#bbf7d0}.step-c-3[data-v-94ec5ef7]{background:#99f6e4}.step-c-4[data-v-94ec5ef7]{background:#fdba74}.privacy-note[data-v-94ec5ef7]{align-items:flex-start;gap:8px;display:flex}.privacy-icon[data-v-94ec5ef7]{flex:none;margin-top:1px}body[data-v-94ec5ef7]{background:radial-gradient(circle at 12% 20%, #fde68a 0 140px, transparent 141px), radial-gradient(circle at 88% 84%, #86efac 0 120px, transparent 121px), var(--neo-cream-2,#fdf6e2)}.neo-button[data-v-94ec5ef7]{border:3px solid #000;border-radius:6px;transition:transform .1s,box-shadow .1s;box-shadow:5px 5px #000}.neo-button[data-v-94ec5ef7]:hover{transform:translate(-2px,-2px);box-shadow:7px 7px #000}.neo-button[data-v-94ec5ef7]:active{transform:translate(2px,2px);box-shadow:2px 2px #000}.neo-button[data-v-94ec5ef7]:disabled{opacity:.75;cursor:not-allowed;transform:none;box-shadow:5px 5px #000}.g-btn[data-v-94ec5ef7]{color:#000;background:#fff;border:4px solid #000;justify-content:center;align-items:center;gap:12px;width:100%;margin-top:24px;padding:16px 20px;font-size:16px;font-weight:700;display:flex;box-shadow:6px 6px #000}.g-btn[data-v-94ec5ef7]:hover{background:#fef08a;transform:translate(-2px,-2px);box-shadow:8px 8px #000}.g-btn[data-v-94ec5ef7]:active{transform:translate(2px,2px);box-shadow:2px 2px #000}.g-btn[data-v-94ec5ef7]:disabled{opacity:.75;cursor:not-allowed;transform:none;box-shadow:6px 6px #000}.g-logo[data-v-94ec5ef7]{background:#fff;border:2px solid #000;border-radius:4px;flex:none;padding:3px}.g-btn:hover .g-logo[data-v-94ec5ef7]{background:#fff}.g-label[data-v-94ec5ef7]{white-space:nowrap}.g-arrow[data-v-94ec5ef7]{flex:none;transition:transform .15s}.g-btn:hover .g-arrow[data-v-94ec5ef7]{transform:translate(4px)}.btn-secondary[data-v-94ec5ef7]{background:var(--neo-teal,#14b8a6);color:#000;text-align:center;justify-content:center;align-items:center;gap:10px;width:100%;margin-top:12px;padding:14px 16px;font-weight:700;text-decoration:none;display:flex}.status-box[data-v-94ec5ef7]{text-align:left;word-break:break-word;border:3px solid #000;border-radius:6px;margin-top:20px;padding:16px;font-size:14px;line-height:1.55;box-shadow:5px 5px #000}.status-info[data-v-94ec5ef7]{background:#bfdbfe}.status-sending[data-v-94ec5ef7]{background:var(--neo-orange,#fb923c)}.status-success[data-v-94ec5ef7]{background:#bbf7d0}.status-error[data-v-94ec5ef7]{background:#fecaca}.status-warning[data-v-94ec5ef7]{background:var(--neo-yellow,#fef08a)}.tutorial[data-v-94ec5ef7]{background:#f4f4f0;border:3px solid #000;margin-top:24px;margin-bottom:24px;padding:18px}.tutorial h2[data-v-94ec5ef7]{margin:0 0 14px;font-size:20px}.tutorial-list[data-v-94ec5ef7]{gap:12px;margin:0;padding:0;list-style:none;display:grid}.tutorial-step[data-v-94ec5ef7]{grid-template-columns:32px 1fr;align-items:start;gap:10px;display:grid}.step-number[data-v-94ec5ef7]{background:var(--neo-yellow,#fef08a);border:2px solid #000;place-items:center;width:30px;height:30px;font-weight:700;display:grid}.tutorial-step p[data-v-94ec5ef7]{margin:3px 0 0;font-size:14px;line-height:1.45}.tutorial-image[data-v-94ec5ef7]{border:3px solid #000;width:100%;max-width:360px;margin:16px auto 4px;display:block;box-shadow:4px 4px #000}.manual-flow[data-v-94ec5ef7]{border-top:3px solid #000;margin-top:24px;padding-top:24px}.manual-flow h2[data-v-94ec5ef7]{margin:0 0 8px;font-size:20px}.manual-flow p[data-v-94ec5ef7]{margin:8px 0;font-size:14px;line-height:1.5}.code-input[data-v-94ec5ef7]{resize:vertical;min-height:58px;margin:12px 0;font:14px/1.4 JetBrains Mono,monospace}.privacy-note[data-v-94ec5ef7]{color:#333;margin-top:14px;font-size:12px;line-height:1.45}.eligibility-modal[data-v-94ec5ef7]{z-index:20;background:#000000b8;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.eligibility-dialog[data-v-94ec5ef7]{background:#fff;border:4px solid #000;width:min(100%,520px);padding:24px;box-shadow:10px 10px #000}.eligibility-dialog h2[data-v-94ec5ef7]{margin:0 0 12px;font:28px/1 Archivo Black,Impact,sans-serif}.eligibility-dialog p[data-v-94ec5ef7]{line-height:1.5}.eligibility-dialog .neo-button[data-v-94ec5ef7]{width:100%;margin-top:12px;font-weight:700}
@@ -0,0 +1 @@
1
+ *,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (width>=640px){.container{max-width:640px}}@media (width>=768px){.container{max-width:768px}}@media (width>=1024px){.container{max-width:1024px}}@media (width>=1280px){.container{max-width:1280px}}@media (width>=1536px){.container{max-width:1536px}}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.mx-auto{margin-left:auto;margin-right:auto}.\!mb-0{margin-bottom:0!important}.mb-3{margin-bottom:.75rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.ml-auto{margin-left:auto}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.w-full{width:100%}.min-w-full{min-width:100%}.max-w-2xl{max-width:42rem}.max-w-6xl{max-width:72rem}.max-w-md{max-width:28rem}.border-collapse{border-collapse:collapse}.transform{transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.resize{resize:both}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-10{gap:2.5rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.space-y-10>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2.5rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.overflow-x-auto{overflow-x:auto}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.rounded-\[6px\]{border-radius:6px}.border{border-width:1px}.border-2{border-width:2px}.border-4{border-width:4px}.border-black{--tw-border-opacity:1;border-color:rgb(0 0 0/var(--tw-border-opacity,1))}.bg-\[\#bbf7d0\]{--tw-bg-opacity:1;background-color:rgb(187 247 208/var(--tw-bg-opacity,1))}.bg-\[\#fdba74\]{--tw-bg-opacity:1;background-color:rgb(253 186 116/var(--tw-bg-opacity,1))}.bg-\[\#fef08a\]{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity,1))}.bg-\[\#fffef0\]{--tw-bg-opacity:1;background-color:rgb(255 254 240/var(--tw-bg-opacity,1))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-7{padding:1.75rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.uppercase{text-transform:uppercase}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.shadow{--tw-shadow:0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-\[5px_5px_0_0_rgba\(0\,0\,0\,1\)\]{--tw-shadow:5px 5px 0 0 #000;--tw-shadow-colored:5px 5px 0 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow,0 0 #0000)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter,backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}:root{--neo-black:#000;--neo-cream-2:#fdf6e2;--neo-white:#fff;--neo-green:#22c55e;--neo-teal:#14b8a6;--neo-orange:#fb923c;--neo-yellow:#fef08a;--space-sm:.625rem;--space-md:1rem;--space-lg:1.5rem}body{color:var(--neo-black);min-height:100vh;font-family:Space Grotesk,sans-serif}.neo-display{letter-spacing:-.01em;font-family:Archivo Black,Impact,sans-serif}.neo-card{background:var(--neo-white);border:4px solid var(--neo-black);box-shadow:8px 8px 0 var(--neo-black);border-radius:6px}.neo-card-soft{background:var(--neo-white);border:3px solid var(--neo-black);box-shadow:5px 5px 0 var(--neo-black);border-radius:6px}.card-title{align-items:center;gap:var(--space-sm);text-transform:uppercase;letter-spacing:.04em;padding-bottom:var(--space-md);border-bottom:3px solid var(--neo-black);margin-bottom:var(--space-lg);font-size:.8rem;font-weight:700;display:flex}.card-title .step{border:2px solid var(--neo-black);background:var(--neo-yellow);flex:none;justify-content:center;align-items:center;width:26px;height:26px;font-size:.8rem;display:inline-flex}.nav-tabs{gap:var(--space-md);flex-wrap:wrap;display:flex}.tab{border:3px solid var(--neo-black);box-shadow:4px 4px 0 var(--neo-black);color:#000;cursor:pointer;text-align:center;-webkit-user-select:none;user-select:none;background:#fff;border-radius:6px;justify-content:center;align-items:center;gap:8px;padding:12px 20px;font-weight:700;transition:transform .1s,box-shadow .1s;display:inline-flex}.tab:hover{box-shadow:6px 6px 0 var(--neo-black);transform:translate(-2px,-2px)}.tab.active{background:var(--neo-yellow)}.btn{border:3px solid var(--neo-black);box-shadow:5px 5px 0 var(--neo-black);white-space:nowrap;cursor:pointer;border-radius:6px;justify-content:center;align-items:center;gap:8px;padding:12px 20px;font-size:14px;font-weight:700;transition:transform .1s,box-shadow .1s;display:inline-flex}.btn:hover{box-shadow:7px 7px 0 var(--neo-black);transform:translate(-2px,-2px)}.btn:active{box-shadow:2px 2px 0 var(--neo-black);transform:translate(2px,2px)}.btn-primary{background:var(--neo-green);color:var(--neo-black)}.btn-secondary{background:var(--neo-teal);color:var(--neo-black)}.btn-success{background:var(--neo-orange);color:var(--neo-black)}.btn-google{background:var(--neo-yellow);color:var(--neo-black);width:100%}.btn:disabled{opacity:.7;cursor:not-allowed;box-shadow:5px 5px 0 var(--neo-black);transform:none}.btn-icon{flex:none;width:40px;height:36px;padding:0;font-size:15px}.badge{border:2px solid var(--neo-black);border-radius:4px;padding:5px 12px;font-size:12px;font-weight:700;display:inline-block}.badge-success{color:#000;background:#bbf7d0}.badge-warning{color:#000;background:#fde68a}.badge-error{color:#000;background:#fecaca}.field{margin-bottom:var(--space-lg)}.field:last-child{margin-bottom:0}.field>label{text-transform:uppercase;letter-spacing:.05em;margin-bottom:var(--space-sm);font-size:.72rem;font-weight:700;display:block}.field .hint{margin-top:var(--space-sm);border:2px solid var(--neo-black);background:#f4f4f0;border-radius:4px;padding:10px 12px;font-size:12px;line-height:1.55}input,textarea{border:3px solid var(--neo-black);color:#000;background:#fff;border-radius:6px;width:100%;padding:12px 14px;font-size:14px}input:focus,textarea:focus{box-shadow:4px 4px 0 var(--neo-black);outline:none}.spinner{border:2px solid #0000004d;border-top-color:#000;border-radius:50%;width:14px;height:14px;animation:.6s linear infinite spin;display:inline-block}@keyframes spin{to{transform:rotate(360deg)}}.toast{border:3px solid var(--neo-black);box-shadow:5px 5px 0 var(--neo-black);opacity:0;z-index:9999;border-radius:6px;padding:12px 16px;font-weight:700;transition:all .2s;position:fixed;bottom:20px;right:20px;transform:translateY(10px)}.toast.show{opacity:1;transform:translateY(0)}.toast.success{color:#000;background:#bbf7d0}.toast.error{color:#000;background:#fecaca}.mascot{display:block}.mascot .floaty{animation:2.4s ease-in-out infinite floaty}.mascot .floaty-2{animation:3.1s ease-in-out .4s infinite floaty}@keyframes floaty{0%,to{transform:translateY(0)}50%{transform:translateY(-5px)}}@media (prefers-reduced-motion:reduce){.mascot .floaty,.mascot .floaty-2{animation:none}}@media (width<=768px){.neo-card{box-shadow:6px 6px 0 var(--neo-black)}.tab{box-shadow:3px 3px 0 var(--neo-black)}}@media (width>=640px){.sm\:block{display:block}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:p-10{padding:2.5rem}.sm\:p-6{padding:1.5rem}.sm\:p-8{padding:2rem}.sm\:px-8{padding-left:2rem;padding-right:2rem}.sm\:text-4xl{font-size:2.25rem;line-height:2.5rem}}@media (width>=768px){.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (width>=1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:flex-row{flex-direction:row}.lg\:items-center{align-items:center}.lg\:justify-between{justify-content:space-between}.lg\:p-8{padding:2rem}}