PageSourceSearch

https://alintagar-official-website.web.app/js/admin.js

js alintagar-official-website.web.app collected 2026-10-03 12:16:20 UTC 302,192 bytes, 5,585 lines download raw bytes

1/* ==========================================
2   4. ATVEO-STYLE ADMIN SIDEBAR & WORKSPACE
3   ========================================== */
4
5function injectAdminSidebar() {
6    if (document.getElementById('admin-gear-btn')) return;
7
8    // 🟢 NEW: Dynamically load post-creator.js ONLY for verified Admins
9    if (!document.getElementById('post-creator-script')) {
10        const postScript = document.createElement('script');
11        postScript.id = 'post-creator-script';
12        postScript.src = 'js/post-creator.js';
13        postScript.defer = true;
14        document.body.appendChild(postScript);
15    }
16
17    const sidebarHTML = `
18    <!-- Floating Admin Gear Button -->
19    <button id="admin-gear-btn" title="Admin Control Center" class="fixed right-6 bottom-16 z-[100] bg-amber-500 hover:bg-amber-600 text-white w-14 h-14 rounded-full shadow-2xl flex items-center justify-center text-2xl transition-all transform hover:scale-110 border-2 border-white">
20        <i class="fa-solid fa-gear"></i>
21    </button>
22
23    <!-- Admin Slide-over Menu Drawer -->
24    <div id="admin-sidebar-drawer" class="fixed inset-y-0 right-0 w-80 bg-slate-900 shadow-2xl z-[110] transform translate-x-full transition-transform duration-300 flex flex-col border-l border-slate-800">
25        <div class="bg-slate-950 text-white p-5 flex items-center justify-between border-b border-slate-800">
26            <div class="flex items-center gap-3">
27                <i class="fa-solid fa-shield-halved text-amber-400 text-xl"></i>
28                <h3 class="font-black text-base text-white">Platform Admin</h3>
29            </div>
30            <button id="close-admin-sidebar" class="text-gray-400 hover:text-white text-xl w-8 h-8 rounded-full hover:bg-slate-800 flex items-center justify-center transition-colors"><i class="fa-solid fa-xmark"></i></button>
31        </div>
32
33        <div class="p-6 overflow-y-auto flex-1 space-y-4">
34            <p class="text-[11px] font-extrabold text-gray-400 uppercase tracking-wider mb-2">Platform Content & Pages</p>
35            
36            <div id="admin-sidebar-nav-buttons" class="space-y-3">
37                <!-- Navigation buttons injected dynamically -->
38            </div>
39
40            <div class="pt-6 border-t border-slate-800 space-y-3">
41
42                <!-- 🟢 PAGE CREATOR STUDIO BUTTON -->
43                <button onclick="openPageCreatorStudio()" class="admin-menu-btn" style="background: #d97706;">
44                    <i class="fa-solid fa-wand-magic-sparkles w-5 text-center"></i> Page Creator Studio
45                </button>
46
47                <!-- 🟢 POST CREATOR STUDIO BUTTON -->
48                <button onclick="openPostCreatorStudio()" class="admin-menu-btn" style="background: #8b5cf6;">
49                    <i class="fa-solid fa-feather-pointed w-5 text-center"></i> Post Creator Studio
50                </button>
51
52                <!-- 🟢 MENU MANAGEMENT BUTTON -->
53                <button id="sidebar-btn-menu" class="admin-menu-btn" style="background: #e11d48;">
54                    <i class="fa-solid fa-bars-staggered w-5 text-center"></i> Menu Management
55                </button>
56
57                <!-- 🟢 USER MANAGEMENT BUTTON -->
58                <button id="sidebar-btn-users" class="admin-menu-btn" style="background: #1d4ed8;">
59                    <i class="fa-solid fa-users-gear w-5 text-center"></i> User Management
60                </button>
61
62                <!-- 🟢 PAGE MANAGEMENT PANEL BUTTON -->
63                <button onclick="openFullscreenPageManager()" class="admin-menu-btn" style="background: #10b981;">
64                    <i class="fa-solid fa-file-lines w-5 text-center"></i> Page Management Panel
65                </button>
66
67                <!-- 🟢 POST MANAGEMENT BUTTON -->
68                <button id="sidebar-btn-posts" class="admin-menu-btn" style="background: #9333ea;">
69                    <i class="fa-solid fa-newspaper w-5 text-center"></i> Post Management Panel
70                </button>
71
72                <!-- 🟢 COMMENT MODERATION BUTTON -->
73                <button id="sidebar-btn-comments" class="admin-menu-btn" style="background: #eab308; color: #0f172a;">
74                    <i class="fa-solid fa-comments w-5 text-center"></i> Comment Moderation Panel
75                </button>
76
77                <!-- 🟢 Student Registrations BUTTON -->
78                <button id="sidebar-btn-regs" class="admin-menu-btn" style="background: #047857;">
79                    <i class="fa-solid fa-users-rectangle w-5 text-center"></i> Student Registrations
80                </button>
81
82                <!-- 🟢 NEW LIBRARY MANAGEMENT BUTTON -->
83                <button id="sidebar-btn-library" class="admin-menu-btn" style="background: #0284c7;">
84                    <i class="fa-solid fa-book-bookmark w-5 text-center"></i> Library Management Panel
85                </button>
86
87                <!-- 🟢 CENTRALIZED PAYMENT METHOD PANEL BUTTON -->
88                <button id="sidebar-btn-payments" class="admin-menu-btn" style="background: #0ea5e9;">
89                    <i class="fa-solid fa-credit-card w-5 text-center"></i> Payment Method Panel
90                </button>
91
92                <!-- 🟢 NEW SITEMAP GENERATOR BUTTON -->
93                <button id="sidebar-btn-sitemap" class="admin-menu-btn" style="background: #b45309;">
94                    <i class="fa-solid fa-sitemap w-5 text-center"></i> Sitemap Generator
95                </button>
96
97                <!-- 🟢 UNIVERSAL BACKUP & RESTORE PANEL BUTTON -->
98                <button onclick="openFullscreenBackupManager()" class="admin-menu-btn" style="background: #0d9488;">
99                    <i class="fa-solid fa-database w-5 text-center"></i> Database Backup & Restore
100                </button>
101            </div>
102        </div>
103    </div>
104    `;
105
106    document.body.insertAdjacentHTML('beforeend', sidebarHTML);
107
108    const gearBtn = document.getElementById('admin-gear-btn');
109    const drawer = document.getElementById('admin-sidebar-drawer');
110    const closeBtn = document.getElementById('close-admin-sidebar');
111
112    gearBtn.addEventListener('click', () => {
113        drawer.classList.remove('translate-x-full');
114        renderAdminSidebarNavList();
115    });
116
117    closeBtn.addEventListener('click', () => {
118        drawer.classList.add('translate-x-full');
119    });
120
121    // 🟢 Menu Manager Button Event
122    document.getElementById('sidebar-btn-menu')?.addEventListener('click', () => {
123        drawer.classList.add('translate-x-full');
124        openFullscreenMenuManager();
125    });
126
127    // Post Panel Button
128    document.getElementById('sidebar-btn-posts').addEventListener('click', () => {
129        drawer.classList.add('translate-x-full');
130        openFullscreenPostManager();
131    });
132
133    // Comment Panel Button
134    document.getElementById('sidebar-btn-comments').addEventListener('click', () => {
135        drawer.classList.add('translate-x-full');
136        openFullscreenCommentModeration();
137    });
138
139    // Registrations Button
140    document.getElementById('sidebar-btn-regs').addEventListener('click', () => {
141        drawer.classList.add('translate-x-full');
142        openFullscreenRegistrationsManager();
143    });
144
145    // Users Button
146    document.getElementById('sidebar-btn-users').addEventListener('click', () => {
147        drawer.classList.add('translate-x-full');
148        openFullscreenUsersManager();
149    });
150
151    // Library Panel Button Event
152    document.getElementById('sidebar-btn-library')?.addEventListener('click', () => {
153        drawer.classList.add('translate-x-full');
154        openFullscreenLibraryManager();
155    });
156
157    // Centralized Payment Panel Button Event
158    document.getElementById('sidebar-btn-payments')?.addEventListener('click', () => {
159        drawer.classList.add('translate-x-full');
160        openFullscreenPaymentManager();
161    });
162
163    // 🟢 Sitemap Generator Button Event
164    document.getElementById('sidebar-btn-sitemap').addEventListener('click', () => {
165        drawer.classList.add('translate-x-full');
166        openFullscreenSitemapGenerator();
167    });
168}
169
170// Render Admin Menu
171function renderAdminSidebarNavList() {
172    const container = document.getElementById('admin-sidebar-nav-buttons');
173    if (!container) return;
174
175    container.innerHTML = `
176    <div class="p-4 bg-slate-900 border border-slate-800 rounded-xl text-center shadow-md">
177        <i class="fa-solid fa-pen-nib text-3xl text-amber-500 mb-3 block"></i>
178        <h4 class="text-white font-bold mb-1">Live Page Editor</h4>
179        <p class="text-[11px] text-gray-400 mb-4 leading-relaxed">Edit text and images directly on the live website.</p>
180        
181        <button onclick="enableLiveEditMode()" class="w-full inline-flex items-center justify-center gap-2 bg-amber-500 hover:bg-amber-400 text-slate-950 font-black py-2.5 px-4 rounded-lg transition shadow-lg text-sm">
182            Enable Live Editing
183        </button>
184    </div>
185    `;
186}
187
188// 🟢 Full-Screen Page Editor Workspace (Like your screenshot 2)
189window.openFullscreenPageEditor = async function(pageId, pageName, pageUrl) {
190    // Close sidebar drawer
191    const drawer = document.getElementById('admin-sidebar-drawer');
192    if (drawer) drawer.classList.add('translate-x-full');
193
194    // Remove existing workspace if any
195    const existingWs = document.getElementById('admin-fullscreen-workspace');
196    if (existingWs) existingWs.remove();
197
198    let savedTitle = "";
199    let savedVideo = "";
200    let savedDesc = "";
201
202    try {
203        const doc = await db.collection("site_pages").doc(pageId).get();
204        if (doc.exists) {
205            const data = doc.data();
206            savedTitle = data.title || "";
207            savedVideo = data.video || "";
208            savedDesc = data.desc || "";
209        }
210    } catch(e) {}
211
212    const workspaceHTML = `
213    <div id="admin-fullscreen-workspace">
214        <div class="bg-slate-950 text-white px-8 py-5 flex items-center justify-between border-b border-slate-800 shadow-xl">
215            <div class="flex items-center gap-4">
216                <div class="w-10 h-10 bg-amber-500 text-slate-950 rounded-xl flex items-center justify-center font-black text-xl">
217                    <i class="fa-solid fa-pen-to-square"></i>
218                </div>
219                <div>
220                    <h2 class="font-black text-xl text-white">Edit Page: ${pageName}</h2>
221                    <p class="text-xs text-gray-400">Modify title, video links, and content for /${pageUrl}</p>
222                </div>
223            </div>
224            
225            <div class="flex items-center gap-4">
226                <a href="/${pageUrl}" target="_blank" class="bg-blue-600/30 text-blue-300 border border-blue-500/30 px-4 py-2.5 rounded-xl text-xs font-bold hover:bg-blue-600/50 transition flex items-center gap-2">
227                    <i class="fa-solid fa-external-link"></i> Preview Page
228                </a>
229                <button onclick="document.getElementById('admin-fullscreen-workspace').remove()" class="bg-red-600/20 text-red-400 border border-red-500/30 px-5 py-2.5 rounded-xl text-xs font-bold hover:bg-red-600/40 transition">
230                    ✕ Close Editor
231                </button>
232            </div>
233        </div>
234
235        <div class="p-8 md:p-12 max-w-5xl mx-auto w-full flex-1 space-y-6">
236            <div class="bg-slate-900 p-8 rounded-3xl border border-slate-800 shadow-2xl space-y-6">
237                <div>
238                    <label class="block text-xs font-extrabold text-gray-400 uppercase tracking-wider mb-2">Page Title / Heading</label>
239                    <input type="text" id="fs-edit-title" value="${savedTitle}" class="w-full p-4 bg-slate-950 border border-slate-800 rounded-2xl text-base text-white focus:ring-2 focus:ring-amber-500 focus:outline-none">
240                </div>
241
242                <div>
243                    <label class="block text-xs font-extrabold text-gray-400 uppercase tracking-wider mb-2">YouTube Video / Media URL</label>
244                    <input type="text" id="fs-edit-video" value="${savedVideo}" placeholder="https://www.youtube.com/embed/..." class="w-full p-4 bg-slate-950 border border-slate-800 rounded-2xl text-base text-white focus:ring-2 focus:ring-amber-500 focus:outline-none">
245                </div>
246
247                <div>
248                    <label class="block text-xs font-extrabold text-gray-400 uppercase tracking-wider mb-2">Page Description / Main Content</label>
249                    <textarea id="fs-edit-desc" rows="10" class="w-full p-4 bg-slate-950 border border-slate-800 rounded-2xl text-base text-white focus:ring-2 focus:ring-amber-500 focus:outline-none leading-relaxed">${savedDesc}</textarea>
250                </div>
251
252                <button id="fs-save-btn" class="w-full bg-amber-500 hover:bg-amber-600 text-slate-950 font-black py-4 rounded-2xl transition shadow-xl text-base flex items-center justify-center gap-3">
253                    <i class="fa-solid fa-cloud-arrow-up text-lg"></i> Save Changes to Firebase
254                </button>
255            </div>
256        </div>
257    </div>
258    `;
259
260    document.body.insertAdjacentHTML('beforeend', workspaceHTML);
261
262    document.getElementById('fs-save-btn').addEventListener('click', async () => {
263        const title = document.getElementById('fs-edit-title').value;
264        const video = document.getElementById('fs-edit-video').value;
265        const desc = document.getElementById('fs-edit-desc').value;
266
267        try {
268            await db.collection("site_pages").doc(pageId).set({
269                title, video, desc, updatedAt: new Date()
270            }, { merge: true });
271
272            customToast(`Successfully saved changes for ${pageName}!`, "success");
273        } catch(e) {
274            customToast(e.message, "error");
275        }
276    });
277};
278
279// Full-Screen Registrations Manager
280function openFullscreenRegistrationsManager() {
281    const existingWs = document.getElementById('admin-fullscreen-workspace');
282    if (existingWs) existingWs.remove();
283
284    const workspaceHTML = `
285    <div id="admin-fullscreen-workspace">
286        <div class="bg-slate-950 text-white px-8 py-5 flex items-center justify-between border-b border-slate-800 shadow-xl">
287            <div class="flex items-center gap-4">
288                <div class="w-10 h-10 bg-emerald-500 text-slate-950 rounded-xl flex items-center justify-center font-black text-xl">
289                    <i class="fa-solid fa-users-rectangle"></i>
290                </div>
291                <div>
292                    <h2 class="font-black text-xl text-white">Student Course Registrations</h2>
293                    <p class="text-xs text-gray-400">Review and approve incoming student enrolments</p>
294                </div>
295            </div>
296            <button onclick="document.getElementById('admin-fullscreen-workspace').remove()" class="bg-red-600/20 text-red-400 border border-red-500/30 px-5 py-2.5 rounded-xl text-xs font-bold hover:bg-red-600/40 transition">
297                ✕ Close Dashboard
298            </button>
299        </div>
300
301        <div class="p-8 md:p-12 max-w-6xl mx-auto w-full flex-1 space-y-6">
302            <div id="fs-registrations-list" class="grid grid-cols-1 md:grid-cols-2 gap-4">
303                <p class="italic text-gray-400">Loading registrations...</p>
304            </div>
305        </div>
306    </div>
307    `;
308
309    document.body.insertAdjacentHTML('beforeend', workspaceHTML);
310    loadFullscreenRegistrations();
311}
312
313async function loadFullscreenRegistrations() {
314    const container = document.getElementById('fs-registrations-list');
315    if (!container) return;
316
317    try {
318        const snapshot = await db.collection("course_registrations").orderBy("createdAt", "desc").get();
319        if (snapshot.empty) {
320            container.innerHTML = `<p class="italic text-gray-400">No course registrations found.</p>`;
321            return;
322        }
323
324        let html = '';
325        snapshot.forEach(doc => {
326            const reg = doc.data();
327            const docId = doc.id;
328
329            html += `
330            <div class="bg-slate-900 p-5 rounded-2xl border border-slate-800 space-y-3">
331                <div class="flex justify-between items-start">
332                    <div>
333                        <h4 class="font-black text-white text-base">${reg.courseName}</h4>
334                        <p class="text-gray-300 text-sm font-semibold">${reg.studentName} (${reg.studentEmail})</p>
335                    </div>
336                    <span class="text-xs font-bold px-3 py-1 rounded-full ${reg.status === 'Approved' ? 'bg-green-500/20 text-green-400 border border-green-500/30' : reg.status === 'Rejected' ? 'bg-red-500/20 text-red-400 border border-red-500/30' : 'bg-amber-500/20 text-amber-400 border border-amber-500/30'}">
337                        ${reg.status}
338                    </span>
339                </div>
340                <p class="text-gray-400 text-xs">Phone: ${reg.studentPhone} | Schedule: ${reg.batch} | Payment: ${reg.paymentMethod}</p>
341                <div class="flex gap-3 pt-2 border-t border-slate-800">
342                    <button onclick="updateFullscreenRegStatus('${docId}', 'Approved')" class="bg-green-600 hover:bg-green-500 text-white text-xs font-bold px-4 py-2 rounded-xl transition">
343                        ✓ Approve Enrolment
344                    </button>
345                    <button onclick="updateFullscreenRegStatus('${docId}', 'Rejected')" class="bg-red-600 hover:bg-red-500 text-white text-xs font-bold px-4 py-2 rounded-xl transition">
346                        ✕ Reject
347                    </button>
348                </div>
349            </div>`;
350        });
351        container.innerHTML = html;
352    } catch(e) {
353        container.innerHTML = `<p class="text-red-400 text-xs">Error: ${e.message}</p>`;
354    }
355}
356
357window.updateFullscreenRegStatus = async function(docId, newStatus) {
358    try {
359        await db.collection("course_registrations").doc(docId).update({ status: newStatus, reviewedAt: new Date() });
360        customToast(`Registration set to '${newStatus}'!`, "success");
361        loadFullscreenRegistrations();
362    } catch(e) {
363        customToast(e.message, "error");
364    }
365};
366
367/* ==========================================
368   ATVEO-STYLE 1280px USER MANAGEMENT PANEL
369   (With Stats, Search, Full ID & Pagination)
370   ========================================== */
371
372window.allUsersData = [];
373window.currentUsersStatusFilter = 'all';
374window.currentUsersPage = 1;
375window.usersPerPage = 10;
376
377window.openFullscreenUsersManager = function() {
378    const existingWs = document.getElementById('admin-fullscreen-workspace');
379    if (existingWs) existingWs.remove();
380
381    const workspaceHTML = `
382    <div id="admin-fullscreen-workspace" class="fixed inset-0 z-[999999] bg-[#0b0f19] text-white flex flex-col font-sans overflow-hidden">
383        
384        <!-- Top Bar -->
385        <div class="bg-slate-950 text-gray-300 h-14 px-8 flex items-center justify-between border-b border-slate-800 shadow-xl">
386            <div class="flex items-center gap-3">
387                <div class="w-9 h-9 bg-blue-600 text-white rounded-xl flex items-center justify-center font-black text-lg">
388                    <i class="fa-solid fa-users-gear"></i>
389                </div>
390                <div>
391                    <h2 class="font-black text-lg text-white leading-none">User Management</h2>
392                    <p class="text-[11px] text-gray-400">Manage user accounts, roles, registration approvals, and permissions.</p>
393                </div>
394            </div>
395            
396            <button onclick="document.getElementById('admin-fullscreen-workspace').remove(); document.body.classList.remove('overflow-hidden');" class="bg-red-600/20 text-red-400 border border-red-500/30 px-5 py-2 rounded-xl text-xs font-bold hover:bg-red-600/40 transition">
397                ✕ Close Dashboard
398            </button>
399        </div>
400
401        <!-- Main Panel Container (1280px Max Width) -->
402        <div class="flex-1 overflow-y-auto p-6 md:p-10 flex justify-center">
403            <div class="w-full max-w-[1280px] space-y-6">
404                
405                <!-- Table Card -->
406                <div class="bg-[#131927] border border-slate-800 rounded-3xl p-6 md:p-8 shadow-2xl">
407                    <div class="mb-6 flex flex-col md:flex-row md:items-center justify-between gap-4">
408                        <div>
409                            <h3 class="text-2xl font-black text-white mb-1">User Management</h3>
410                            <p class="text-xs text-gray-400">Review new account signups, assign roles, approve accounts, or ban/delete users.</p>
411                        </div>
412                    </div>
413
414                    <!-- 🟢 1. TOP STATISTICS COUNT PILLS -->
415                    <div class="flex flex-wrap items-center gap-2 text-xs font-semibold text-gray-400 mb-6 pb-4 border-b border-slate-800/80">
416                        <button onclick="filterUsersByStatus('all')" id="usr-pill-all" class="text-blue-400 hover:text-white transition font-bold">Total Users - <span id="usr-count-total">0</span></button>
417                        <span class="text-slate-700">|</span>
418                        <button onclick="filterUsersByStatus('Approved')" id="usr-pill-approved" class="text-gray-400 hover:text-white transition">Approved - <span id="usr-count-approved">0</span></button>
419                        <span class="text-slate-700">|</span>
420                        <button onclick="filterUsersByStatus('Pending')" id="usr-pill-pending" class="text-gray-400 hover:text-white transition">Pending - <span id="usr-count-pending">0</span></button>
421                        <span class="text-slate-700">|</span>
422                        <button onclick="filterUsersByStatus('Banned')" id="usr-pill-banned" class="text-gray-400 hover:text-white transition">Banned Users - <span id="usr-count-banned">0</span></button>
423                        <span class="text-slate-700">|</span>
424                        <button onclick="filterUsersByStatus('Deleted')" id="usr-pill-deleted" class="text-gray-400 hover:text-white transition">Deleted Users - <span id="usr-count-deleted">0</span></button>
425                    </div>
426
427                    <!-- 🟢 2. FILTER & REAL-TIME SEARCH BAR -->
428                    <div class="flex flex-wrap justify-between items-center mb-6 gap-4 text-xs">
429                        <div class="flex items-center gap-2">
430                            <label class="text-gray-400 font-bold uppercase text-[10px]">Role Filter:</label>
431                            <select id="usr-filter-role" onchange="renderUsersTable()" class="bg-slate-950 border border-slate-700 text-amber-400 font-bold rounded-xl px-3 py-2 focus:outline-none focus:border-amber-400 text-xs cursor-pointer">
432                                <option value="all">All Roles</option>
433                                <option value="Subscriber">Subscriber</option>
434                                <option value="Student">Student</option>
435                                <option value="Teacher">Teacher</option>
436                                <option value="Admin">Admin</option>
437                                <option value="Others">Others</option>
438                            </select>
439                        </div>
440                        
441                        <div class="flex items-center gap-2">
442                            <input type="text" id="usr-search-input" placeholder="Search by Name, Email, or Full ID..." onkeyup="renderUsersTable()" class="bg-slate-950 border border-slate-700 text-white rounded-xl px-4 py-2 text-xs focus:ring-2 focus:ring-blue-500 focus:outline-none w-64 sm:w-80">
443                            <button onclick="renderUsersTable()" class="bg-blue-600 hover:bg-blue-500 text-white font-bold px-4 py-2 rounded-xl transition text-xs shadow-md">
444                                <i class="fa-solid fa-search mr-1"></i> Search
445                            </button>
446                        </div>
447                    </div>
448
449                    <!-- 1280px Table -->
450                    <div class="overflow-x-auto">
451                        <table class="w-full text-left text-xs border-collapse">
452                            <thead>
453                                <tr class="text-gray-400 font-extrabold uppercase border-b border-slate-800 pb-3">
454                                    <th class="py-3 px-4">Status</th>
455                                    <th class="py-3 px-4">Name / Full ID</th>
456                                    <th class="py-3 px-4">Email Address</th>
457                                    <th class="py-3 px-4">Joined Date</th>
458                                    <th class="py-3 px-4">Role</th>
459                                    <th class="py-3 px-4 text-center">Action</th>
460                                </tr>
461                            </thead>
462                            <tbody id="admin-users-table-body" class="divide-y divide-slate-800/80">
463                                <tr>
464                                    <td colspan="6" class="py-8 text-center text-gray-400 italic">Loading users...</td>
465                                </tr>
466                            </tbody>
467                        </table>
468                    </div>
469
470                    <!-- 🟢 3. BOTTOM PAGE NAVIGATION -->
471                    <div class="flex flex-wrap justify-between items-center pt-6 border-t border-slate-800/80 text-xs text-gray-400 gap-4 mt-6">
472                        <div class="flex items-center gap-2">
473                            <span>Showing <span id="usr-showing-start" class="font-bold text-white">0</span> - <span id="usr-showing-end" class="font-bold text-white">0</span> of <span id="usr-showing-total" class="font-bold text-white">0</span> Users</span>
474                        </div>
475                        <div class="flex items-center gap-3">
476                            <button onclick="changeUsersPage(-1)" id="usr-prev-btn" class="bg-slate-800 hover:bg-slate-700 disabled:opacity-40 disabled:cursor-not-allowed text-white font-bold px-4 py-2 rounded-xl transition shadow">
477                                ‹ Previous
478                            </button>
479                            <span class="font-bold text-white px-2">Page <span id="usr-current-page" class="text-amber-400">1</span> of <span id="usr-total-pages">1</span></span>
480                            <button onclick="changeUsersPage(1)" id="usr-next-btn" class="bg-slate-800 hover:bg-slate-700 disabled:opacity-40 disabled:cursor-not-allowed text-white font-bold px-4 py-2 rounded-xl transition shadow">
481                                Next ›
482                            </button>
483                        </div>
484                    </div>
485
486                </div>
487
488            </div>
489        </div>
490    </div>
491    `;
492
493    document.body.insertAdjacentHTML('beforeend', workspaceHTML);
494    window.currentUsersStatusFilter = 'all';
495    window.currentUsersPage = 1;
496    loadFullscreenUsers();
497};
498
499// 🟢 FIXED: Removed 'async' and added .onSnapshot() for real-time live updates
500function loadFullscreenUsers() {
501    const tableBody = document.getElementById('admin-users-table-body');
502    if (!tableBody) return;
503
504    // Listen to Firestore in real-time
505    db.collection("users").onSnapshot((snapshot) => {
506        window.allUsersData = [];
507
508        let totalCount = 0;
509        let approvedCount = 0;
510        let pendingCount = 0;
511        let bannedCount = 0;
512        let deletedCount = 0;
513
514        snapshot.forEach(doc => {
515            const u = doc.data();
516            u.uid = doc.id;
517
518            // 🟢 Safe condition (Strict email/UID check only):
519            const uEmailLower = (u.email || u.userEmail || '').toLowerCase();
520            u.isSuperAdmin = (uEmailLower === '[email protected]') || (u.uid === 'qpJ1ojwul2YL6LO1udqJOkQzUI23');
521
522            // Email Fallback
523            let userEmail = u.email || u.userEmail || '';
524            if (!userEmail && u.isSuperAdmin) userEmail = '[email protected]';
525            u.displayEmail = userEmail || 'N/A';
526
527            // Status Calculation
528            if (u.isSuperAdmin) u.status = 'Approved';
529            else if (!u.status) u.status = 'Pending';
530
531            // Counts
532            totalCount++;
533            if (u.status === 'Approved') approvedCount++;
534            else if (u.status === 'Pending') pendingCount++;
535            else if (u.status === 'Banned') bannedCount++;
536            else if (u.status === 'Deleted') deletedCount++;
537
538            window.allUsersData.push(u);
539        });
540
541        // Ensure the panel is still open before trying to update text
542        if (document.getElementById('usr-count-total')) {
543            document.getElementById('usr-count-total').innerText = totalCount;
544            document.getElementById('usr-count-approved').innerText = approvedCount;
545            document.getElementById('usr-count-pending').innerText = pendingCount;
546            document.getElementById('usr-count-banned').innerText = bannedCount;
547            document.getElementById('usr-count-deleted').innerText = deletedCount;
548
549            renderUsersTable();
550        }
551
552    }, (error) => {
553        if (tableBody) {
554            tableBody.innerHTML = `<tr><td colspan="6" class="py-8 text-center text-red-400 italic">Error loading users: ${error.message}</td></tr>`;
555        }
556    });
557}
558
559window.filterUsersByStatus = function(status) {
560    window.currentUsersStatusFilter = status;
561    window.currentUsersPage = 1;
562
563    const pills = ['all', 'approved', 'pending', 'banned', 'deleted'];
564    pills.forEach(p => {
565        const btn = document.getElementById(`usr-pill-${p}`);
566        if (btn) {
567            btn.className = (p.toLowerCase() === status.toLowerCase())
568                ? 'text-blue-400 hover:text-white transition font-black underline'
569                : 'text-gray-400 hover:text-white transition font-medium';
570        }
571    });
572
573    renderUsersTable();
574};
575
576window.renderUsersTable = function() {
577    const tableBody = document.getElementById('admin-users-table-body');
578    if (!tableBody) return;
579
580    const roleFilter = document.getElementById('usr-filter-role').value;
581    const searchQuery = (document.getElementById('usr-search-input').value || '').trim().toLowerCase();
582
583    // 🟢 FILTER DATA
584    const filteredUsers = window.allUsersData.filter(u => {
585        let match = true;
586
587        // Status Filter
588        if (window.currentUsersStatusFilter !== 'all') {
589            if (u.status.toLowerCase() !== window.currentUsersStatusFilter.toLowerCase()) match = false;
590        }
591
592        // Role Filter
593        if (roleFilter !== 'all') {
594            const uRole = u.isSuperAdmin ? 'Admin' : (u.role || 'Student');
595            if (uRole.toLowerCase() !== roleFilter.toLowerCase()) match = false;
596        }
597
598        // Search Query (Name, Email, or Full User ID)
599        if (searchQuery) {
600            const nameMatch = (u.fullName || '').toLowerCase().includes(searchQuery);
601            const emailMatch = (u.displayEmail || '').toLowerCase().includes(searchQuery);
602            const idMatch = (u.uid || '').toLowerCase().includes(searchQuery);
603            if (!nameMatch && !emailMatch && !idMatch) match = false;
604        }
605
606        return match;
607    });
608
609    if (filteredUsers.length === 0) {
610        tableBody.innerHTML = `<tr><td colspan="6" class="py-8 text-center text-gray-500 italic">No users match your filters or search query.</td></tr>`;
611        updatePaginationControls(0, 0, 0);
612        return;
613    }
614
615    // 🟢 PAGINATION CALCULATION
616    const totalUsers = filteredUsers.length;
617    const totalPages = Math.ceil(totalUsers / window.usersPerPage);
618    if (window.currentUsersPage > totalPages) window.currentUsersPage = totalPages;
619    if (window.currentUsersPage < 1) window.currentUsersPage = 1;
620
621    const startIndex = (window.currentUsersPage - 1) * window.usersPerPage;
622    const endIndex = Math.min(startIndex + window.usersPerPage, totalUsers);
623    const paginatedUsers = filteredUsers.slice(startIndex, endIndex);
624
625    let html = '';
626    paginatedUsers.forEach(u => {
627        const uid = u.uid;
628
629        // 🟢 Dynamic fallback:
630        let joinedDateStr = "Recently";
631        if (u.createdAt && typeof u.createdAt.toDate === 'function') {
632            const d = u.createdAt.toDate();
633            const day = String(d.getDate()).padStart(2, '0');
634            const month = String(d.getMonth() + 1).padStart(2, '0');
635            const year = d.getFullYear();
636            joinedDateStr = `${day}/${month}/${year}`;
637        }
638
639        // Status Badge
640        let statusBadge = '';
641        if (u.isSuperAdmin) {
642            statusBadge = `<span class="bg-amber-500/20 text-amber-400 border border-amber-500/30 text-[10px] font-black px-2.5 py-1 rounded-full uppercase">Super Admin</span>`;
643        } else if (u.status === 'Approved') {
644            statusBadge = `<span class="bg-green-500/20 text-green-400 border border-green-500/30 text-[10px] font-black px-2.5 py-1 rounded-full uppercase">Approved</span>`;
645        } else if (u.status === 'Banned') {
646            statusBadge = `<span class="bg-red-500/20 text-red-400 border border-red-500/30 text-[10px] font-black px-2.5 py-1 rounded-full uppercase">Banned</span>`;
647        } else if (u.status === 'Deleted') {
648            statusBadge = `<span class="bg-gray-500/20 text-gray-400 border border-gray-500/30 text-[10px] font-black px-2.5 py-1 rounded-full uppercase">Deleted</span>`;
649        } else {
650            statusBadge = `<span class="bg-amber-500/20 text-amber-400 border border-amber-500/30 text-[10px] font-black px-2.5 py-1 rounded-full uppercase animate-pulse">Pending</span>`;
651        }
652
653        // Role Dropdown
654        const currentRole = u.isSuperAdmin ? 'Admin' : (u.role || 'Student');
655        const roles = ['Subscriber', 'Student', 'Teacher', 'Admin', 'Others'];
656        let roleHtml = '';
657        if (u.isSuperAdmin) {
658            roleHtml = `<span class="text-amber-400 font-extrabold text-xs px-3 py-1.5 bg-slate-950 border border-amber-500/30 rounded-xl inline-block">Admin (Owner)</span>`;
659        } else {
660            let roleOptions = '';
661            roles.forEach(r => {
662                roleOptions += `<option value="${r}" ${currentRole.toLowerCase() === r.toLowerCase() ? 'selected' : ''}>${r}</option>`;
663            });
664            roleHtml = `
665            <select onchange="updateUserRole('${uid}', this.value)" class="bg-slate-950 border border-slate-700 text-amber-400 font-bold text-xs rounded-xl px-2.5 py-1.5 focus:outline-none focus:border-amber-400 cursor-pointer">
666                ${roleOptions}
667            </select>`;
668        }
669
670        // Actions
671        let actionHtml = '';
672        if (u.isSuperAdmin) {
673            actionHtml = `<span class="text-gray-500 text-xs italic font-bold">🔒 System Protected</span>`;
674        } else {
675            actionHtml = `<div class="flex items-center justify-center gap-1.5">`;
676
677            if (u.status === 'Banned') {
678                // 🟢 UNBAN BUTTON: Restores user to Approved status
679                actionHtml += `<button onclick="updateUserStatus('${uid}', 'Approved')" class="bg-blue-600 hover:bg-blue-500 text-white font-extrabold px-2.5 py-1.5 rounded-lg transition text-[11px]">Unban</button>`;
680            } else if (u.status === 'Approved') {
681                // 🟢 DISAPPROVE BUTTON: Reverts user status back to Pending
682                actionHtml += `<button onclick="updateUserStatus('${uid}', 'Pending')" class="bg-slate-700 hover:bg-slate-600 text-amber-300 font-extrabold px-2.5 py-1.5 rounded-lg transition text-[11px]" title="Revert user to Pending status">✕ Disapprove</button>`;
683                actionHtml += `<button onclick="updateUserStatus('${uid}', 'Banned')" class="bg-orange-600 hover:bg-orange-500 text-white font-extrabold px-2.5 py-1.5 rounded-lg transition text-[11px]">Ban</button>`;
684            } else {
685                // PENDING USERS: Show Approve and Ban
686                actionHtml += `<button onclick="updateUserStatus('${uid}', 'Approved')" class="bg-green-600 hover:bg-green-500 text-white font-extrabold px-2.5 py-1.5 rounded-lg transition text-[11px]">✓ Approve</button>`;
687                actionHtml += `<button onclick="updateUserStatus('${uid}', 'Banned')" class="bg-orange-600 hover:bg-orange-500 text-white font-extrabold px-2.5 py-1.5 rounded-lg transition text-[11px]">Ban</button>`;
688            }
689
690            // Always show Warn and Delete buttons
691            actionHtml += `<button onclick="openAdminWarningModal('${uid}', '${(u.fullName || 'User').replace(/'/g, "\\'")}', '${uid}')" class="bg-amber-400 hover:bg-amber-300 text-slate-950 font-extrabold px-2.5 py-1.5 rounded-lg transition text-[11px]">Warn</button>`;
692            actionHtml += `<button onclick="deleteUserAccount('${uid}', '${u.displayEmail}')" class="bg-red-600 hover:bg-red-500 text-white font-extrabold px-2.5 py-1.5 rounded-lg transition text-[11px]">Delete</button>`;
693
694            actionHtml += `</div>`;
695        }
696
697        const studentIdBadge = u.studentId ? `<p class="text-[10px] text-amber-400 font-bold">Student ID: ${u.studentId}</p>` : '';
698
699        html += `
700        <tr class="hover:bg-slate-900/50 transition border-b border-slate-800/50">
701            <td class="py-4 px-4 align-middle">${statusBadge}</td>
702            
703            <td class="py-4 px-4 align-middle">
704                <div class="flex items-center gap-3">
705                    <div class="w-8 h-8 rounded-full ${u.isSuperAdmin ? 'bg-amber-500 text-slate-950' : 'bg-blue-600 text-white'} font-bold flex items-center justify-center text-xs flex-shrink-0">
706                        ${(u.fullName || u.displayEmail || 'U')[0].toUpperCase()}
707                    </div>
708                    <div>
709                        <p class="font-bold text-white text-xs">${u.fullName || 'Alin Tagar User'}</p>
710                        ${studentIdBadge}
711                        <p class="text-[10px] text-gray-400 font-mono select-all hover:text-amber-400 transition cursor-pointer" title="Click to select Full ID">ID: ${uid}</p>
712                    </div>
713                </div>
714            </td>
715
716            <td class="py-4 px-4 align-middle text-gray-300 font-medium">${u.displayEmail}</td>
717            <td class="py-4 px-4 align-middle text-gray-400 font-mono">${joinedDateStr}</td>
718            <td class="py-4 px-4 align-middle">${roleHtml}</td>
719            <td class="py-4 px-4 align-middle text-center">${actionHtml}</td>
720        </tr>`;
721    });
722
723    tableBody.innerHTML = html;
724    updatePaginationControls(startIndex + 1, endIndex, totalUsers, totalPages);
725};
726
727function updatePaginationControls(start, end, total, totalPages = 1) {
728    document.getElementById('usr-showing-start').innerText = start;
729    document.getElementById('usr-showing-end').innerText = end;
730    document.getElementById('usr-showing-total').innerText = total;
731
732    document.getElementById('usr-current-page').innerText = window.currentUsersPage;
733    document.getElementById('usr-total-pages').innerText = totalPages || 1;
734
735    const prevBtn = document.getElementById('usr-prev-btn');
736    const nextBtn = document.getElementById('usr-next-btn');
737
738    if (prevBtn) prevBtn.disabled = window.currentUsersPage <= 1;
739    if (nextBtn) nextBtn.disabled = window.currentUsersPage >= totalPages || totalPages === 0;
740}
741
742window.changeUsersPage = function(delta) {
743    window.currentUsersPage += delta;
744    renderUsersTable();
745};
746
747// 🟢 UPDATED: UPDATE USER STATUS & DISPATCH TAILORED EMAILS
748window.updateUserStatus = async function(uid, newStatus) {
749    try {
750        const uDoc = await db.collection("users").doc(uid).get();
751        if (!uDoc.exists) return;
752
753        const userData = uDoc.data();
754        const currentRole = userData.role || 'Subscriber'; 
755        const userEmail = userData.email || userData.displayEmail || '';
756        const userName = userData.fullName || userData.firstName || 'Student';
757
758        await db.collection("users").doc(uid).set({
759            status: newStatus,
760            role: currentRole,
761            updatedAt: new Date()
762        }, { merge: true });
763
764        // 🟢 DISPATCH STATUS-SPECIFIC EMAIL NOTIFICATION
765        if (userEmail) {
766            await sendAccountStatusEmail(userEmail, userName, newStatus);
767        }
768
769        customToast(`User set to ${newStatus} successfully!`, "success");
770        loadFullscreenUsers();
771    } catch(e) {
772        customToast(e.message, "error");
773    }
774};
775
776// 🟢 COMPREHENSIVE ACCOUNT STATUS EMAIL DISPATCHER
777async function sendAccountStatusEmail(email, name, status) {
778    const logoUrl = "https://firebasestorage.googleapis.com/v0/b/alintagar-official-website.firebasestorage.app/o/photos%2FAlintagarlogosmall.png?alt=media&token=68c0cef0-b24c-4e40-9deb-17ebe6cfc10b";
779    
780    let subject = "";
781    let statusHeading = "";
782    let statusBodyText = "";
783    let highlightColor = "#05396b";
784
785    if (status === 'Approved') {
786        subject = "Your Alin Tagar Account is Approved & Ready! 🎉";
787        statusHeading = "Account Approved!";
788        statusBodyText = "Great news! Your student account registration has been reviewed and <strong>APPROVED</strong> by our Administration team. You now have full student access to log in, enrol in courses, and access learning materials.";
789        highlightColor = "#16a34a"; // Green
790    } else if (status === 'Pending') {
791        subject = "Alin Tagar Account Status Update: Pending Review";
792        statusHeading = "Account Under Review";
793        statusBodyText = "Your account status has been updated to <strong>Pending Review</strong> by the Administrator. Please allow some time for verification.";
794        highlightColor = "#d97706"; // Amber
795    } else if (status === 'Banned') {
796        subject = "Important Notice Regarding Your Alin Tagar Account ⚠️";
797        statusHeading = "Account Access Restricted";
798        statusBodyText = "Your account access has been restricted by the Administrator due to a violation of our terms and conditions. If you believe this is a mistake, please contact our support desk.";
799        highlightColor = "#dc2626"; // Red
800    } else {
801        return; // Exit if status is unhandled
802    }
803
804    try {
805        await db.collection("email_queue").add({
806            to: email,
807            message: {
808                subject: subject,
809                text: `Hello ${name},\n\nYour Alin Tagar account status has been updated to: ${status}.\n\nVisit your profile: https://alintagar-official-website.web.app/profile`,
810                html: `
811                <div style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; max-width: 650px; margin: 0 auto; background-color: #ffffff; overflow: hidden;">
812                    
813                    <!-- Header -->
814                    <div style="padding: 20px 10px; border-bottom: 2px solid #05396b;">
815                        <table style="width: 100%; border-collapse: collapse;">
816                            <tr>
817                                <td style="vertical-align: middle; width: 70px;">
818                                    <img src="${logoUrl}" alt="Alin Tagar Logo" style="height: 50px;">
819                                </td>
820                                <td style="vertical-align: middle; text-align: right;">
821                                    <h2 style="color: #05396b; margin: 0; font-size: 18px; font-weight: 900; letter-spacing: 1px;">ALIN TAGAR</h2>
822                                    <p style="color: #64748b; margin: 2px 0 0 0; font-size: 10px; text-transform: uppercase; letter-spacing: 1px; font-weight: bold;">
822Alin Tagar English Language Training School</p>
823                                </td>
824                            </tr>
825                        </table>
826                    </div>
827
828                    <!-- Body -->
829                    <div style="padding: 30px 10px;">
830                        <h3 style="color: ${highlightColor}; margin-top: 0; font-size: 20px; font-weight: 800;">${statusHeading}</h3>
831                        <p style="color: #0f172a; font-size: 16px;">Hello <strong>${name}</strong>,</p>
832                        <p style="color: #334155; font-size: 14px; line-height: 1.6;">${statusBodyText}</p>
833                        
834                        ${status === 'Approved' ? `
835                        <div style="margin-top: 25px;">
836                            <a href="https://alintagar-official-website.web.app/profile" style="background: #05396b; color: white; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: bold; display: inline-block; font-size: 14px;">Log In to Your Profile &rarr;</a>
837                        </div>` : ''}
838                    </div>
839
840                    <!-- Signature -->
841                    <div style="padding: 0 10px 30px 10px;">
842                        <p style="color: #333333; font-size: 14px; margin-bottom: 15px;">Best regards,</p>
843                        <table style="width: 100%; border-collapse: collapse;">
844                            <tr>
845                                <td style="width: 90px; vertical-align: top; padding-right: 15px;">
846                                    <img src="${logoUrl}" alt="Alin Tagar Logo" style="width: 90px; height: auto;">
847                                </td>
848                                <td style="vertical-align: top; font-size: 13px; color: #333333; line-height: 1.5;">
849                                    <strong style="font-size: 15px; color: #000000;">Administrator</strong><br>
850                                    CEO, Admin, Customer Relations Manager (CRM)<br>
851                                    <strong>☎️</strong> +95 (0) 9 781 010 356<br>
852                                    <strong>📧</strong> <a href="mailto:[email protected]" style="color: #05396b; text-decoration: none;">[email protected]</a><br>
853                                    <strong>🌐</strong> <a href="https://alintagar.com" style="color: #05396b; text-decoration: none;">alintagar.com</a><br>
854                                    
855                                    <div style="margin-top: 8px;">
856                                        <span style="background-color: #00b67a; color: white; font-size: 10px; font-weight: bold; padding: 3px 8px; border-radius: 4px; display: inline-block;">✓ Trustindex</span><br>
857                                        <span style="color: #00b67a; font-size: 18px; letter-spacing: 2px;">★★★★★</span><br>
858                                        <span style="font-size: 12px; font-weight: bold; color: #000000;">40 reviews</span>
859                                    </div>
860                                </td>
861                            </tr>
862                        </table>
863                        
864                        <div style="margin-top: 30px; font-size: 10px; color: #777777; line-height: 1.5; text-align: justify; border-top: 1px solid #e2e8f0; padding-top: 15px;">
865                            <p style="margin-bottom: 8px;">Please do not print this e-mail unless it is necessary. Every unprinted e-mail helps the environment.</p>
866                            <p style="margin: 0;">This e-mail and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. Please notify the sender immediately by e-mail if you have received this e-mail by mistake and delete this e-mail from your system. If you are not the intended recipient you are notified that disclosing, copying, distributing or taking any action in reliance on the contents of this information is strictly prohibited.</p>
867                        </div>
868                    </div>
869                </div>`
870            },
871            status: "queued",
872            createdAt: new Date()
873        });
874        console.log("Status update email queued successfully for:", email);
875    } catch(e) {
876        console.error("Email queue error:", e);
877    }
878}
879
880// 🟢 ACCOUNT APPROVAL EMAIL DISPATCHER
881async function sendAccountApprovalEmail(email, name) {
882    try {
883        // Queue approval email in Firestore for Cloud Functions / Extension
884        await db.collection("email_queue").add({
885            to: email,
886            message: {
887                subject: "Your Alin Tagar Account is Approved & Ready!",
888                text: `Hello ${name},\n\nGreat news! Your account registration at Alin Tagar English Training School has been APPROVED by the Administrator.\n\nYou can now log in to your account and enrol in courses:\nhttps://alintagar-official-website.web.app/profile\n\nWelcome to Alin Tagar!`,
889                html: `
890                <div style="font-family: sans-serif; padding: 24px; background: #f8fafc; color: #0f172a; border-radius: 16px; border: 1px solid #e2e8f0;">
891                    <div style="text-align: center; margin-bottom: 20px;">
892                        <h2 style="color: #05396b; margin: 0; font-size: 22px;">Alin Tagar English Training School</h2>
893                        <p style="color: #64748b; font-size: 13px;">Official Account Approval Notification</p>
894                    </div>
895                    <div style="background: white; padding: 20px; border-radius: 12px; border: 1px solid #cbd5e1;">
896                        <h3 style="color: #16a34a; margin-top: 0;">Account Approved! 🎉</h3>
897                        <p>Hello <strong>${name}</strong>,</p>
898                        <p>Great news! Your student account registration has been reviewed and <strong>APPROVED</strong> by our Administration team.</p>
899                        <p>You now have full student access to enrol in courses and access learning materials.</p>
900                        <p style="margin-top: 24px;">
901                            <a href="https://alintagar-official-website.web.app/profile" style="background: #05396b; color: white; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: bold; display: inline-block;">Log In to Your Profile &rarr;</a>
902                        </p>
903                    </div>
904                    <p style="font-size: 12px; color: #94a3b8; text-align: center; margin-top: 20px;">
905                        Alin Tagar English Training School • Dawei, Myanmar
906                    </p>
907                </div>`
908            },
909            status: "queued",
910            createdAt: new Date()
911        });
912        console.log("Approval email queued successfully for:", email);
913    } catch(e) {
914        console.error("Email queue error:", e);
915    }
916}
917
918// 🟢 UPDATE USER ROLE
919window.updateUserRole = async function(uid, newRole) {
920    try {
921        await db.collection("users").doc(uid).set({
922            role: newRole,
923            updatedAt: new Date()
924        }, { merge: true });
925        customToast(`User role updated to ${newRole}!`, "success");
926    } catch(e) {
927        customToast(e.message, "error");
928    }
929};
930
931// 🟢 FIXED: DELETE USER ACCOUNT (Clean Firestore deletion that triggers auto-delete Auth)
932window.deleteUserAccount = async function(uid, email) {
933    const confirmed = await customConfirm(
934        "Delete User Account 🗑️", 
935        `Are you sure you want to permanently delete account for ${email || 'this user'}?\n\nThis will remove their login from Authentication and delete their profile forever.`
936    );
937    if (!confirmed) return;
938
939    try {
940        customToast("Deleting account...", "info");
941
942        // Deleting the Firestore document automatically triggers the backend to delete Auth!
943        await db.collection("users").doc(uid).delete();
944
945        customToast("User account permanently deleted!", "success");
946        loadFullscreenUsers();
947
948    } catch(e) {
949        console.error("Delete error:", e);
950        customToast("Error deleting user: " + e.message, "error");
951    }
952};
953
954// 🟢 Load All Student Registrations for Admin Approval
955async function loadAdminRegistrations() {
956    const container = document.getElementById('admin-registrations-list');
957    if (!container) return;
958
959    try {
960        const snapshot = await db.collection("course_registrations")
961            .orderBy("createdAt", "desc")
962            .get();
963
964        if (snapshot.empty) {
965            container.innerHTML = `<p class="italic text-gray-400 text-xs bg-gray-50 p-3 rounded-xl border">No course registrations found.</p>`;
966            return;
967        }
968
969        let html = '';
970        snapshot.forEach(doc => {
971            const reg = doc.data();
972            const docId = doc.id;
973
974            html += `
975            <div class="bg-gray-50 p-3.5 rounded-xl border border-gray-200 text-xs space-y-2">
976                <div class="flex justify-between items-start">
977                    <div>
978                        <p class="font-bold text-gray-900 text-sm">${reg.courseName}</p>
979                        <p class="text-gray-600 font-medium">${reg.studentName} (${reg.studentEmail})</p>
980                    </div>
981                    <span class="text-[10px] font-bold px-2 py-0.5 rounded-full ${reg.status === 'Approved' ? 'bg-green-100 text-green-800' : reg.status === 'Rejected' ? 'bg-red-100 text-red-800' : 'bg-amber-100 text-amber-800'}">
982                        ${reg.status}
983                    </span>
984                </div>
985                <p class="text-gray-500">Phone: ${reg.studentPhone} | Schedule: ${reg.batch}</p>
986                
987                <div class="flex gap-2 pt-1 border-t">
988                    <button onclick="updateRegistrationStatus('${docId}', 'Approved')" class="bg-green-700 text-white text-[11px] font-bold px-3 py-1 rounded-lg hover:bg-green-800 transition">
989                        ✓ Approve
990                    </button>
991                    <button onclick="updateRegistrationStatus('${docId}', 'Rejected')" class="bg-red-600 text-white text-[11px] font-bold px-3 py-1 rounded-lg hover:bg-red-700 transition">
992                        ✕ Reject
993                    </button>
994                </div>
995            </div>`;
996        });
997
998        container.innerHTML = html;
999
1000    } catch(e) {
1001        container.innerHTML = `<p class="text-xs text-red-500">Error loading registrations: ${e.message}</p>`;
1002    }
1003}
1004
1005// 🟢 Admin Action: Update Student Registration Status
1006window.updateRegistrationStatus = async function(docId, newStatus) {
1007    try {
1008        await db.collection("course_registrations").doc(docId).update({
1009            status: newStatus,
1010            reviewedAt: new Date()
1011        });
1012        customToast(`Registration set to '${newStatus}'!`, "success");
1013        loadAdminRegistrations();
1014    } catch(e) {
1015        customToast(e.message, "error");
1016    }
1017};
1018
1019// Render Page Nav Buttons inside Sidebar
1020function renderAdminPageNavButtons() {
1021    const listContainer = document.getElementById('admin-page-nav-list');
1022    if (!listContainer) return;
1023
1024    let html = '';
1025    defaultPages.forEach(p => {
1026        const isActive = p.id === activeEditingPageId;
1027        html += `
1028        <button onclick="selectAdminEditingPage('${p.id}', '${p.name}', '${p.url}')" class="flex items-center gap-2 text-left p-2.5 rounded-xl border text-xs font-bold transition-all ${isActive ? 'bg-brandBlue text-white border-brandBlue shadow-md' : 'bg-white text-gray-700 hover:bg-blue-50 hover:text-brandBlue'}">
1029            <i class="fa-solid ${p.icon} text-sm"></i>
1030            <span class="truncate">${p.name}</span>
1031        </button>`;
1032    });
1033
1034    listContainer.innerHTML = html;
1035}
1036
1037// Handle Selecting a Page to Edit in Sidebar
1038window.selectAdminEditingPage = function(id, name, url) {
1039    activeEditingPageId = id;
1040    renderAdminPageNavButtons();
1041    
1042    document.getElementById('active-editing-badge').innerText = `Editing: ${name}`;
1043    document.getElementById('admin-view-page-link').href = url;
1044
1045    loadAdminPageEditorData(id);
1046};
1047
1048// Load Page Data from Firebase Firestore
1049async function loadAdminPageEditorData(pageId) {
1050    const titleInput = document.getElementById('admin-edit-title');
1051    const videoInput = document.getElementById('admin-edit-video');
1052    const descInput = document.getElementById('admin-edit-desc');
1053
1054    if (!titleInput) return;
1055
1056    try {
1057        const doc = await db.collection("site_pages").doc(pageId).get();
1058        if (doc.exists) {
1059            const data = doc.data();
1060            titleInput.value = data.title || "";
1061            videoInput.value = data.video || "";
1062            descInput.value = data.desc || "";
1063        } else {
1064            // Default placeholder values
1065            titleInput.value = `Alin Tagar ${pageId.toUpperCase()} Page`;
1066            videoInput.value = "https://www.youtube.com/embed/l0uEFPhIwgA";
1067            descInput.value = "Explore a new learning experience at Alin Tagar English Centre...";
1068        }
1069    } catch(e) {
1070        console.error("Error loading page data:", e);
1071    }
1072}
1073
1074// Load Registered User List for Admin
1075async function loadAdminUserData() {
1076    const listContainer = document.getElementById('admin-user-list');
1077    if (!listContainer) return;
1078
1079    try {
1080        const snapshot = await db.collection("users").get();
1081        if (snapshot.empty) {
1082            listContainer.innerHTML = `<p class="italic text-gray-500">No registered users found.</p>`;
1083            return;
1084        }
1085
1086        let html = `<ul class="divide-y border rounded-xl overflow-hidden bg-gray-50">`;
1087        snapshot.forEach(doc => {
1088            const u = doc.data();
1089            html += `
1090            <li class="p-3 bg-white flex items-center justify-between">
1091                <div>
1092                    <p class="font-bold text-gray-900">${u.fullName || 'User'}</p>
1093                    <p class="text-gray-500 text-[11px]">${u.email}</p>
1094                </div>
1095                <span class="text-[10px] font-bold px-2 py-0.5 rounded-full ${u.role === 'admin' ? 'bg-amber-100 text-amber-800' : 'bg-blue-100 text-blue-800'}">
1096                    ${u.role || 'student'}
1097                </span>
1098            </li>`;
1099        });
1100        html += `</ul>`;
1101        listContainer.innerHTML = html;
1102    } catch(e) {
1103        listContainer.innerHTML = `<p class="text-red-500">Error loading users: ${e.message}</p>`;
1104    }
1105}
1106
1107/* ==========================================
1108   ADVANCED AUTOMATED SITEMAP GENERATOR WORKSPACE
1109   ========================================== */
1110
1111let discoveredSitemapUrls = [];
1112
1113function openFullscreenSitemapGenerator() {
1114    const existingWs = document.getElementById('admin-fullscreen-workspace');
1115    if (existingWs) existingWs.remove();
1116
1117    const workspaceHTML = `
1118    <div id="admin-fullscreen-workspace">
1119        <div class="bg-slate-950 text-white px-8 py-5 flex items-center justify-between border-b border-slate-800 shadow-xl">
1120            <div class="flex items-center gap-4">
1121                <div class="w-10 h-10 bg-amber-600 text-white rounded-xl flex items-center justify-center font-black text-xl">
1122                    <i class="fa-solid fa-sitemap"></i>
1123                </div>
1124                <div>
1125                    <h2 class="font-black text-xl text-white">Dynamic SEO Sitemap & Index Manager</h2>
1126                    <p class="text-xs text-gray-400">Scan database, manage index permissions, and export XML for Google</p>
1127                </div>
1128            </div>
1129            
1130            <div class="flex items-center gap-3">
1131                <button id="sitemap-copy-url-btn" class="bg-blue-600 hover:bg-blue-500 text-white font-black px-4 py-2.5 rounded-xl text-xs transition flex items-center gap-2 shadow-lg">
1132                    <i class="fa-solid fa-link"></i> Copy Sitemap URL
1133                </button>
1134                <button id="sitemap-copy-btn" class="bg-amber-500 hover:bg-amber-400 text-slate-950 font-black px-4 py-2.5 rounded-xl text-xs transition flex items-center gap-2 shadow-lg">
1135                    <i class="fa-solid fa-copy"></i> Copy XML Code
1136                </button>
1137                <button onclick="document.getElementById('admin-fullscreen-workspace').remove()" class="bg-red-600/20 text-red-400 border border-red-500/30 px-5 py-2.5 rounded-xl text-xs font-bold hover:bg-red-600/40 transition">
1138                    ✕ Close Panel
1139                </button>
1140            </div>
1141        </div>
1142
1143        <div class="p-8 md:p-12 max-w-7xl mx-auto w-full flex-1 grid grid-cols-1 lg:grid-cols-12 gap-8 overflow-y-auto">
1144            
1145            <!-- LEFT COLUMN: URL INDEX & PROHIBITION TOGGLES (7 Cols) -->
1146            <div class="lg:col-span-7 bg-slate-900 p-6 rounded-3xl border border-slate-800 shadow-2xl flex flex-col space-y-4">
1147                <div class="flex justify-between items-center border-b border-slate-800 pb-3">
1148                    <h3 class="font-black text-sm text-white flex items-center gap-2">
1149                        <i class="fa-solid fa-list-check text-amber-400"></i> Discovered Pages, Categories & Posts
1150                    </h3>
1151                    <span id="sitemap-discovered-count" class="text-xs bg-slate-800 text-gray-300 px-3 py-1 rounded-full font-semibold">Scanning...</span>
1152                </div>
1153                <p class="text-xs text-gray-400 leading-relaxed">
1154                    Check or uncheck items below to <strong>include</strong> or <strong>prohibit (exclude)</strong> them from your generated sitemap XML.
1155                </p>
1156                
1157                <div id="sitemap-url-checklist" class="space-y-2.5 max-h-[420px] overflow-y-auto pr-2 divide-y divide-slate-800/50">
1158                    <p class="italic text-gray-500 text-xs py-4 text-center">Loading database records...</p>
1159                </div>
1160            </div>
1161
1162            <!-- RIGHT COLUMN: LIVE XML OUTPUT (5 Cols) -->
1163            <div class="lg:col-span-5 bg-slate-900 p-6 rounded-3xl border border-slate-800 shadow-2xl flex flex-col space-y-4">
1164                <div class="flex justify-between items-center border-b border-slate-800 pb-3">
1165                    <h3 class="font-black text-sm text-white flex items-center gap-2">
1166                        <i class="fa-solid fa-code text-emerald-400"></i> Live XML Preview
1167                    </h3>
1168                    <span class="text-[10px] bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 px-2.5 py-0.5 rounded-full font-bold">Auto-Updating</span>
1169                </div>
1170                
1171                <textarea id="sitemap-output-textarea" readonly rows="16" class="w-full p-4 bg-slate-950 border border-slate-800 rounded-2xl font-mono text-xs text-emerald-400 focus:outline-none leading-relaxed select-all flex-1"></textarea>
1172            </div>
1173
1174        </div>
1175    </div>
1176    `;
1177
1178    document.body.insertAdjacentHTML('beforeend', workspaceHTML);
1179    scanDatabaseAndBuildSitemap();
1180
1181     setTimeout(() => {
1182        autoSyncSitemapToDatabase();
1183    }, 1000);
1184
1185    document.getElementById('sitemap-copy-btn').addEventListener('click', () => {
1186        const textarea = document.getElementById('sitemap-output-textarea');
1187        textarea.select();
1188        textarea.setSelectionRange(0, 99999); 
1189        navigator.clipboard.writeText(textarea.value).then(() => {
1190            customToast("Sitemap XML code copied to clipboard!", "success");
1191        }).catch(err => {
1192            customToast("Failed to copy: " + err, "error");
1193        });
1194    });
1195
1196    document.getElementById('sitemap-copy-url-btn').addEventListener('click', () => {
1197        const sitemapUrl = "https://alintagar-official-website.web.app/sitemap.xml";
1198        navigator.clipboard.writeText(sitemapUrl).then(() => {
1199            customToast("Sitemap URL copied: " + sitemapUrl, "success");
1200        }).catch(err => {
1201            customToast("Failed to copy URL", "error");
1202        });
1203    });
1204}
1205
1206/* ==========================================
1207   AUTO-SYNC SITEMAP TO FIREBASE
1208   ========================================== */
1209
1210async function autoSyncSitemapToDatabase() {
1211    const textarea = document.getElementById('sitemap-output-textarea');
1212    if (!textarea || !textarea.value) return;
1213
1214    try {
1215        // Save the raw XML string into Firestore under a public document
1216        await db.collection("site_seo").doc("sitemap_xml").set({
1217            xmlContent: textarea.value,
1218            updatedAt: new Date()
1219        });
1220        customToast("Sitemap automatically synced to Firebase Database!", "success");
1221    } catch(e) {
1222        console.error("Error auto-syncing sitemap:", e);
1223    }
1224}
1225
1226async function scanDatabaseAndBuildSitemap() {
1227    const domain = "https://alintagar-official-website.web.app";
1228    discoveredSitemapUrls = [];
1229
1230    // 1. Add Static System Pages
1231    defaultPages.forEach(p => {
1232        let route = p.url === '/' ? '' : `/${p.url}`;
1233        discoveredSitemapUrls.push({
1234            url: `${domain}${route}`,
1235            type: 'System Page',
1236            title: p.name,
1237            enabled: true,
1238            priority: p.id === 'home' ? '1.0' : '0.8'
1239        });
1240    });
1241
1242    // 2. Scan Firestore: site_builder_pages (Custom builder pages)
1243    try {
1244        const builderSnap = await db.collection("site_builder_pages").get();
1245        builderSnap.forEach(doc => {
1246            const slug = doc.id;
1247            if (!defaultPages.some(p => p.url === slug || p.id === slug)) {
1248                discoveredSitemapUrls.push({
1249                    url: `${domain}/${slug}`,
1250                    type: 'Custom Builder Page',
1251                    title: `Builder Page (${slug})`,
1252                    enabled: true,
1253                    priority: '0.7'
1254                });
1255            }
1256        });
1257    } catch(e) { console.error(e); }
1258
1259    // 3. Scan Firestore: blog_posts (If you have a blog collection)
1260    try {
1261        const blogSnap = await db.collection("blog_posts").get();
1262        blogSnap.forEach(doc => {
1263            const post = doc.data();
1264            discoveredSitemapUrls.push({
1265                url: `${domain}/blog/${doc.id}`,
1266                type: 'Blog Post',
1267                title: post.title || 'Untitled Post',
1268                enabled: true,
1269                priority: '0.6'
1270            });
1271        });
1272    } catch(e) {}
1273
1274    // 4. Scan Firestore: categories (If you have categories)
1275    try {
1276        const catSnap = await db.collection("categories").get();
1277        catSnap.forEach(doc => {
1278            const cat = doc.data();
1279            discoveredSitemapUrls.push({
1280                url: `${domain}/category/${doc.id}`,
1281                type: 'Category',
1282                title: cat.name || doc.id,
1283                enabled: true,
1284                priority: '0.5'
1285            });
1286        });
1287    } catch(e) {}
1288
1289    renderSitemapChecklist();
1290    generateSitemapXML();
1291}
1292
1293function renderSitemapChecklist() {
1294    const container = document.getElementById('sitemap-url-checklist');
1295    const countBadge = document.getElementById('sitemap-discovered-count');
1296    if (!container) return;
1297
1298    if (discoveredSitemapUrls.length === 0) {
1299        container.innerHTML = `<p class="text-xs text-gray-500 italic py-4 text-center">No URLs discovered.</p>`;
1300        if (countBadge) countBadge.innerText = `0 URLs`;
1301        return;
1302    }
1303
1304    let html = '';
1305    discoveredSitemapUrls.forEach((item, index) => {
1306        let badgeColor = 'bg-blue-500/10 text-blue-400 border-blue-500/20';
1307        if (item.type === 'Blog Post') badgeColor = 'bg-purple-500/10 text-purple-400 border-purple-500/20';
1308        if (item.type === 'Category') badgeColor = 'bg-amber-500/10 text-amber-400 border-amber-500/20';
1309        if (item.type === 'Custom Builder Page') badgeColor = 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20';
1310
1311        html += `
1312        <div class="pt-2.5 flex items-center justify-between gap-3">
1313            <div class="flex items-center gap-3 truncate">
1314                <input type="checkbox" id="sitemap-chk-${index}" ${item.enabled ? 'checked' : ''} onchange="toggleSitemapUrl(${index}, this.checked)" class="w-4 h-4 rounded text-amber-500 focus:ring-amber-500 bg-slate-950 border-slate-700 cursor-pointer">
1315                <div class="truncate">
1316                    <p class="text-xs font-bold text-white truncate">${item.title}</p>
1317                    <p class="text-[10px] text-gray-400 font-mono truncate">${item.url}</p>
1318                </div>
1319            </div>
1320            <span class="text-[10px] font-bold px-2.5 py-0.5 rounded-full border ${badgeColor} flex-shrink-0">${item.type}</span>
1321        </div>`;
1322    });
1323
1324    container.innerHTML = html;
1325    if (countBadge) countBadge.innerText = `${discoveredSitemapUrls.length} Discovered`;
1326}
1327
1328window.toggleSitemapUrl = function(index, isEnabled) {
1329    if (discoveredSitemapUrls[index]) {
1330        discoveredSitemapUrls[index].enabled = isEnabled;
1331        generateSitemapXML();
1332    }
1333};
1334
1335function generateSitemapXML() {
1336    const textarea = document.getElementById('sitemap-output-textarea');
1337    if (!textarea) return;
1338
1339    let xml = `<?xml version="1.0" encoding="UTF-8"?>\n`;
1340    xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n`;
1341
1342    discoveredSitemapUrls.forEach(item => {
1343        if (item.enabled) {
1344            xml += `    <url>\n`;
1345            xml += `        <loc>${item.url}</loc>\n`;
1346            xml += `        <changefreq>weekly</changefreq>\n`;
1347            xml += `        <priority>${item.priority}</priority>\n`;
1348            xml += `    </url>\n`;
1349        }
1350    });
1351
1352    xml += `</urlset>`;
1353    textarea.value = xml;
1354}
1355
1356/* ==========================================
1357   DYNAMIC SITEMAP.XML ROUTE HANDLER
1358   ========================================== */
1359document.addEventListener('DOMContentLoaded', async () => {
1360    if (window.location.pathname === '/sitemap.xml' || window.location.pathname === 'sitemap.xml') {
1361        const domain = "https://alintagar-official-website.web.app";
1362        let urls = [...defaultPages];
1363
1364        // Scan builder pages too
1365        try {
1366            const builderSnap = await db.collection("site_builder_pages").get();
1367            builderSnap.forEach(doc => {
1368                const slug = doc.id;
1369                if (!urls.some(p => p.url === slug || p.id === slug)) {
1370                    urls.push({ id: slug, url: slug });
1371                }
1372            });
1373        } catch(e) {}
1374
1375        let xml = `<?xml version="1.0" encoding="UTF-8"?>\n`;
1376        xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n`;
1377
1378        urls.forEach(p => {
1379            let route = p.url === '/' ? '' : `/${p.url.replace(/^\//, '')}`;
1380            let priority = p.id === 'home' ? '1.0' : p.url.includes('course') ? '0.9' : '0.8';
1381            
1382            xml += `    <url>\n`;
1383            xml += `        <loc>${domain}${route}</loc>\n`;
1384            xml += `        <changefreq>weekly</changefreq>\n`;
1385            xml += `        <priority>${priority}</priority>\n`;
1386            xml += `    </url>\n`;
1387        });
1388
1389        xml += `</urlset>`;
1390
1391        // Output raw XML to browser
1392        document.open();
1393        document.write(`<pre style="word-wrap: break-word; white-space: pre-wrap; font-family: monospace; padding: 20px;">${xml.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')}</pre>`);
1394        document.close();
1395        
1396        // Change document content type context visually
1397        document.contentType = 'application/xml';
1398    }
1399});
1400
1401/* ==========================================
1402   DYNAMIC MENU MANAGEMENT PANEL
1403   ========================================== */
1404
1405window.openFullscreenMenuManager = function() {
1406    const existingWs = document.getElementById('admin-fullscreen-workspace');
1407    if (existingWs) existingWs.remove();
1408
1409    const workspaceHTML = `
1410    <!-- 🟢 Shifted overflow-y-auto to the outermost wrapper -->
1411    <div id="admin-fullscreen-workspace" class="fixed inset-0 z-[999999] bg-[#0b0f19] text-white flex flex-col font-sans overflow-y-auto">
1412        
1413        <!-- 🟢 Added sticky top-0 and z-50 so the header stays visible while scrolling -->
1414        <div class="sticky top-0 z-50 bg-slate-950 text-gray-300 py-4 px-8 flex items-center justify-between border-b border-slate-800 shadow-xl">
1415            <div class="flex items-center gap-3">
1416                <div class="w-9 h-9 bg-rose-600 text-white rounded-xl flex items-center justify-center font-black text-lg">
1417                    <i class="fa-solid fa-bars-staggered"></i>
1418                </div>
1419                <div>
1420                    <h2 class="font-black text-lg text-white leading-none">Navigation Menu Manager</h2>
1421                    <p class="text-[11px] text-gray-400">Reorder pages, create dropdowns, and manage your main header navigation.</p>
1422                </div>
1423            </div>
1424            
1425            <div class="flex items-center gap-3">
1426                <button onclick="saveMenuToFirebase()" class="bg-emerald-600 hover:bg-emerald-500 text-white font-black px-5 py-2 rounded-xl text-xs transition shadow-lg flex items-center gap-2">
1427                    <i class="fa-solid fa-cloud-arrow-up"></i> Save Menu Live
1428                </button>
1429                <button onclick="document.getElementById('admin-fullscreen-workspace').remove()" class="bg-red-600/20 text-red-400 border border-red-500/30 px-5 py-2 rounded-xl text-xs font-bold hover:bg-red-600/40 transition">
1430                    ✕ Close
1431                </button>
1432            </div>
1433        </div>
1434
1435        <!-- Main Panel -->
1436        <div class="flex-1 p-6 md:p-10 flex justify-center items-start">
1437
1438            <!-- 🟢 1. Changed to lg:grid-cols-3 for 3 equal-width columns -->
1439            <div class="w-full max-w-[1280px] grid grid-cols-1 lg:grid-cols-3 gap-8">
1440                
1441                <!-- 🟢 COLUMN 1: Pick Existing Content -->
1442                <!-- Added h-[650px] to lock the height -->
1443                <div class="bg-[#131927] border border-slate-800 rounded-3xl p-6 shadow-2xl h-[650px] flex flex-col space-y-4">
1444                    <div>
1445                        <h3 class="font-black text-white text-lg mb-1">Pick Content</h3>
1446                        <p class="text-xs text-gray-400">Select multiple pages or posts to bulk-add to your menu.</p>
1447                    </div>
1448
1449                    <div class="bg-slate-900 p-4 rounded-2xl border border-slate-800 flex flex-col flex-1 min-h-0">
1450                        <div class="flex justify-between items-center mb-4">
1451                            <label class="flex items-center gap-2 cursor-pointer group">
1452                                <input type="checkbox" id="menu-select-all-cb" onchange="toggleAllMenuContent(this)" class="w-3.5 h-3.5 rounded text-rose-500 bg-slate-950 border-slate-600 focus:ring-rose-500">
1453                                <span class="text-xs font-bold text-gray-300 uppercase group-hover:text-white transition">Select All</span>
1454                            </label>
1455                            
1456                            <select id="existing-content-type" onchange="renderExistingContentList()" class="bg-slate-950 border border-slate-700 rounded-lg text-gray-300 text-[10px] p-1.5 focus:outline-none">
1457                                <option value="all">All Types</option>
1458                                <option value="physical">System Pages</option>
1459                                <option value="builder">Custom Pages</option>
1460                                <option value="post">Blog Posts</option>
1461                            </select>
1462                        </div>
1463                        
1464                        <!-- 🟢 Added flex-1, overflow-y-auto, and min-h-0 so it scrolls perfectly inside the box -->
1465                        <div id="existing-content-list" class="flex-1 overflow-y-auto space-y-1.5 mb-4 pr-2 min-h-0">
1466                            <p class="text-xs text-gray-500 italic text-center py-4">Loading database...</p>
1467                        </div>
1468                        
1469                        <button onclick="addSelectedContentToMenu()" id="load-content-btn" class="w-full mt-auto bg-rose-600/20 hover:bg-rose-600/30 text-rose-400 font-bold py-2.5 rounded-lg text-xs transition border border-rose-500/30 shadow-sm flex items-center justify-center gap-2 shrink-0">
1470                            <span>+ Add Selected to Menu</span>
1471                        </button>
1472                    </div>
1473                </div>
1474
1475                <!-- 🟢 COLUMN 2: Create Custom Link / Dropdown -->
1476                <!-- Added h-[650px] to lock the height -->
1477                <div class="bg-[#131927] border border-slate-800 rounded-3xl p-6 shadow-2xl h-[650px] flex flex-col space-y-4">
1478                    <div>
1479                        <h3 class="font-black text-white text-lg mb-1">Link Builder</h3>
1480                        <p class="text-xs text-gray-400">Create a standard link or a dropdown folder.</p>
1481                    </div>
1482
1483                    <div class="space-y-4 overflow-y-auto pr-2 flex-1 min-h-0">
1484                        <!-- Box 1 -->
1485                        <div class="bg-slate-900 p-4 rounded-2xl border border-slate-800 transition-colors" id="link-builder-box">
1486                            <h4 class="text-xs font-bold text-gray-300 uppercase mb-3">1. Add Standard Link</h4>
1487                            <input type="text" id="new-link-title" placeholder="Link Title (e.g. About Us)" class="w-full p-2.5 mb-2 bg-slate-950 border border-slate-700 rounded-lg text-white text-xs focus:border-rose-500 outline-none transition">
1488                            <input type="text" id="new-link-url" placeholder="URL Slug (e.g. about)" class="w-full p-2.5 mb-3 bg-slate-950 border border-slate-700 rounded-lg text-white text-xs focus:border-rose-500 outline-none transition">
1489                            <button onclick="addStandardLinkToMenu()" class="w-full bg-slate-800 hover:bg-slate-700 text-rose-400 font-bold py-2.5 rounded-lg text-xs transition border border-slate-700 shadow-sm">
1490                                + Add Link to Menu
1491                            </button>
1492                        </div>
1493
1494                        <!-- Box 2 -->
1495                        <div class="bg-slate-900 p-4 rounded-2xl border border-slate-800">
1496                            <h4 class="text-xs font-bold text-gray-300 uppercase mb-3">2. Add Dropdown Folder</h4>
1497                            <input type="text" id="new-dropdown-title" placeholder="Folder Title (e.g. Learn English)" class="w-full p-2.5 mb-3 bg-slate-950 border border-slate-700 rounded-lg text-white text-xs focus:border-rose-500 outline-none transition">
1498                            <button onclick="addDropdownToMenu()" class="w-full bg-slate-800 hover:bg-slate-700 text-rose-400 font-bold py-2.5 rounded-lg text-xs transition border border-slate-700 shadow-sm">
1499                                + Add Dropdown to Menu
1500                            </button>
1501                        </div>
1502                    </div>
1503                </div>
1504
1505                <!-- 🟢 COLUMN 3: Menu Structure -->
1506                <!-- Removed lg:col-span-2 and added h-[650px] -->
1507                <div class="bg-[#131927] border border-slate-800 rounded-3xl p-6 shadow-2xl h-[650px] flex flex-col">
1508                    <div class="flex justify-between items-center mb-6">
1509                        <h3 class="font-black text-white text-lg">Menu Structure</h3>
1510                        <span class="text-xs bg-rose-500/20 text-rose-400 border border-rose-500/30 px-3 py-1 rounded-full font-bold">Drag to Reorder</span>
1511                    </div>
1512
1513                    <!-- Builder List Container -->
1514                    <!-- Added flex-1 overflow-y-auto and min-h-0 -->
1515                    <div id="menu-builder-list" class="space-y-2 flex-1 overflow-y-auto pr-2 min-h-0">
1516                        
1517                        <!-- Visual Mockup -->
1518                        <div class="bg-slate-900 border border-slate-700 p-3 rounded-xl flex items-center justify-between group">
1519                            <div class="flex items-center gap-3">
1520                                <i class="fa-solid fa-grip-vertical text-gray-600 cursor-grab"></i>
1521                                <span class="font-bold text-sm text-white">Home</span>
1522                                <span class="text-[10px] text-gray-500 font-mono">/</span>
1523                            </div>
1524                            <div class="flex gap-2 opacity-50 group-hover:opacity-100 transition">
1525                                <button class="text-gray-400 hover:text-blue-400"><i class="fa-solid fa-pen-to-square"></i></button>
1526                                <button class="text-gray-400 hover:text-red-400">
1526<i class="fa-solid fa-trash-can"></i></button>
1527                            </div>
1528                        </div>
1529
1530                        <div class="bg-slate-900 border border-slate-700 p-3 rounded-xl flex flex-col gap-2 group">
1531                            <div class="flex items-center justify-between">
1532                                <div class="flex items-center gap-3">
1533                                    <i class="fa-solid fa-grip-vertical text-gray-600 cursor-grab"></i>
1534                                    <span class="font-bold text-sm text-amber-400"><i class="fa-solid fa-folder-open mr-1"></i> Learn English (Dropdown)</span>
1535                                </div>
1536                                <div class="flex gap-2 opacity-50 group-hover:opacity-100 transition">
1537                                    <button class="text-gray-400 hover:text-blue-400"><i class="fa-solid fa-pen-to-square"></i></button>
1538                                    <button class="text-gray-400 hover:text-red-400"><i class="fa-solid fa-trash-can"></i></button>
1539                                </div>
1540                            </div>
1541                            
1542                            <div class="ml-6 pl-3 border-l-2 border-slate-700 space-y-2 mt-2">
1543                                <div class="bg-slate-950 border border-slate-800 p-2.5 rounded-lg flex items-center justify-between">
1544                                    <div class="flex items-center gap-3">
1545                                        <i class="fa-solid fa-grip-vertical text-gray-600 cursor-grab text-xs"></i>
1546                                        <span class="font-semibold text-xs text-gray-300">Our Courses</span>
1547                                        <span class="text-[10px] text-gray-500 font-mono">/courses</span>
1548                                    </div>
1549                                    <button class="text-gray-500 hover:text-red-400 text-xs"><i class="fa-solid fa-xmark"></i></button>
1550                                </div>
1551                                <button class="w-full text-left p-2 border border-dashed border-slate-700 rounded-lg text-[11px] font-bold text-gray-500 hover:text-rose-400 hover:border-rose-500/50 transition">
1552                                    + Add sub-link
1553                                </button>
1554                            </div>
1555                        </div>
1556
1557                    </div>
1558                </div>
1559
1560            </div>
1561        </div>
1562
1563        <!-- 🟢 MENU ACCESS MODAL -->
1564        <div id="menu-access-modal" class="fixed inset-0 z-[1000006] bg-black/80 backdrop-blur-sm hidden flex items-center justify-center p-4">
1565            <div class="bg-[#181d2a] border border-slate-800 rounded-3xl p-6 w-full max-w-sm shadow-2xl space-y-4">
1566                <div class="flex justify-between items-center border-b border-slate-800 pb-3">
1567                    <h3 class="text-lg font-black text-amber-400"><i class="fa-solid fa-eye mr-2"></i> Menu Visibility</h3>
1568                    <button type="button" onclick="closeMenuAccessModal()" class="text-gray-400 hover:text-white text-lg w-8 h-8 rounded-full hover:bg-slate-800 flex items-center justify-center transition-colors"><i class="fa-solid fa-xmark"></i></button>
1569                </div>
1570                <p class="text-xs text-gray-400">Who can see <strong id="menu-access-target-name" class="text-white">this item</strong> in the header?</p>
1571                
1572                <div class="space-y-2 pt-2">
1573                    <label class="flex items-center gap-3 p-3 bg-slate-900 border border-slate-700 rounded-xl cursor-pointer hover:border-amber-500 transition">
1574                        <input type="radio" name="menu_vis_option" value="public" class="w-4 h-4 text-amber-500 bg-slate-950 border-slate-600 focus:ring-amber-500">
1575                        <div class="flex flex-col">
1576                            <span class="text-white text-xs font-bold">Public (Everyone)</span>
1577                            <span class="text-gray-500 text-[10px]">Visible to all visitors.</span>
1578                        </div>
1579                    </label>
1580                    <label class="flex items-center gap-3 p-3 bg-slate-900 border border-slate-700 rounded-xl cursor-pointer hover:border-amber-500 transition">
1581                        <input type="radio" name="menu_vis_option" value="logged_in" class="w-4 h-4 text-amber-500 bg-slate-950 border-slate-600 focus:ring-amber-500">
1582                        <div class="flex flex-col">
1583                            <span class="text-white text-xs font-bold">Logged In Users Only</span>
1584                            <span class="text-gray-500 text-[10px]">Hidden from public guests.</span>
1585                        </div>
1586                    </label>
1587                    <label class="flex items-center gap-3 p-3 bg-slate-900 border border-slate-700 rounded-xl cursor-pointer hover:border-amber-500 transition">
1588                        <input type="radio" name="menu_vis_option" value="admin_only" class="w-4 h-4 text-amber-500 bg-slate-950 border-slate-600 focus:ring-amber-500">
1589                        <div class="flex flex-col">
1590                            <span class="text-white text-xs font-bold">Admins Only</span>
1591                            <span class="text-gray-500 text-[10px]">Only visible to administrators.</span>
1592                        </div>
1593                    </label>
1594                </div>
1595
1596                <div class="pt-4 border-t border-slate-800 flex justify-end gap-2">
1597                    <button onclick="closeMenuAccessModal()" class="px-4 py-2 bg-slate-800 text-gray-300 text-xs font-bold rounded-xl hover:bg-slate-700">Cancel</button>
1598                    <button onclick="saveMenuAccess()" class="px-4 py-2 bg-amber-500 text-slate-950 text-xs font-black rounded-xl hover:bg-amber-400 shadow-lg">Save Visibility</button>
1599                </div>
1600            </div>
1601        </div>
1602    </div>
1603    `;
1604
1605    document.body.insertAdjacentHTML('beforeend', workspaceHTML);
1606    
1607    // 🟢 Lock background page scrolling to kill the duplicate outer scrollbar
1608    document.body.classList.add('overflow-hidden');
1609    
1610    // Load data for the left column (Database Fetcher)
1611    loadAvailableContentForMenu(); 
1612    
1613    // 🟢 Load data for the right column (Menu Structure)
1614    loadMenuBuilderData(); 
1615};
1616
1617let availableMenuContent = [];
1618
1619async function loadAvailableContentForMenu() {
1620    availableMenuContent = [];
1621    const listEl = document.getElementById('existing-content-list');
1622    if (!listEl) return;
1623
1624    // 1. Fetch Physical / System Pages (From your hardcoded array)
1625    if (typeof defaultPages !== 'undefined') {
1626        defaultPages.forEach(p => {
1627            availableMenuContent.push({
1628                type: 'physical', label: 'System Page', title: p.name, url: p.url === '/' ? '/' : p.url
1629            });
1630        });
1631    }
1632
1633    // 2. Fetch Custom Page Creator Pages
1634    try {
1635        const builderSnap = await db.collection("site_builder_pages").get();
1636        builderSnap.forEach(doc => {
1637            // Prevent duplicates if a builder page overwrites a physical page slug
1638            if (!availableMenuContent.some(c => c.url === doc.id)) {
1639                availableMenuContent.push({
1640                    type: 'builder', label: 'Custom Page', title: `Builder: ${doc.id}`, url: doc.id
1641                });
1642            }
1643        });
1644    } catch(e) { console.error(e); }
1645
1646    // 3. Fetch Dynamic Posts & Categories
1647    try {
1648        const postSnap = await db.collection("dynamic_posts").where("isPublished", "==", true).get();
1649        postSnap.forEach(doc => {
1650            const data = doc.data();
1651            availableMenuContent.push({
1652                type: 'post', label: 'Blog Post', title: data.title || doc.id, url: `post.html?id=${doc.id}`
1653            });
1654        });
1655    } catch(e) { console.error(e); }
1656
1657    renderExistingContentList();
1658}
1659
1660window.renderExistingContentList = function() {
1661    const listEl = document.getElementById('existing-content-list');
1662    const filter = document.getElementById('existing-content-type').value;
1663    if (!listEl) return;
1664
1665    // Reset the Select All checkbox when the filter changes
1666    const selectAllCb = document.getElementById('menu-select-all-cb');
1667    if (selectAllCb) selectAllCb.checked = false;
1668
1669    let html = '';
1670    availableMenuContent.forEach((item, index) => {
1671        if (filter === 'all' || item.type === filter) {
1672            let badgeColor = 'bg-gray-600';
1673            if (item.type === 'physical') badgeColor = 'bg-blue-600';
1674            if (item.type === 'builder') badgeColor = 'bg-emerald-600';
1675            if (item.type === 'post') badgeColor = 'bg-purple-600';
1676
1677            // 🟢 Swapped radio input for checkbox input
1678            html += `
1679            <label class="flex items-center gap-3 p-2 bg-slate-950 border border-slate-800 rounded-lg cursor-pointer hover:border-rose-500 transition group">
1680                <input type="checkbox" name="menu_content_cb" value="${index}" class="w-3.5 h-3.5 rounded text-rose-500 bg-slate-900 border-slate-700 focus:ring-rose-500 focus:ring-offset-slate-950 cursor-pointer">
1681                <div class="flex-1 truncate">
1682                    <p class="text-xs text-white font-bold truncate group-hover:text-rose-400 transition">${item.title}</p>
1683                    <p class="text-[9px] text-gray-500 font-mono truncate">${item.url}</p>
1684                </div>
1685                <span class="text-[8px] font-bold px-1.5 py-0.5 rounded text-white ${badgeColor} shadow-sm">${item.label}</span>
1686            </label>
1687            `;
1688        }
1689    });
1690
1691    listEl.innerHTML = html || '<p class="text-xs text-gray-500 italic text-center py-4">No content found.</p>';
1692};
1693
1694// 🟢 NEW: Select All Logic
1695window.toggleAllMenuContent = function(source) {
1696    const checkboxes = document.querySelectorAll('input[name="menu_content_cb"]');
1697    checkboxes.forEach(cb => {
1698        cb.checked = source.checked;
1699    });
1700};
1701
1702// 🟢 NEW: Bulk Add Logic (Directly to Menu)
1703window.addSelectedContentToMenu = function() {
1704    const checkedBoxes = document.querySelectorAll('input[name="menu_content_cb"]:checked');
1705    if (checkedBoxes.length === 0) {
1706        customToast("Please check at least one item from the list.", "error");
1707        return;
1708    }
1709
1710    // Push every selected item directly into the live menu array
1711    checkedBoxes.forEach(cb => {
1712        const item = availableMenuContent[cb.value];
1713        window.liveMenuData.push({
1714            type: 'link',
1715            title: item.title.replace('Builder: ', ''),
1716            url: item.url,
1717            icon: 'fa-link' // Default icon
1718        });
1719        cb.checked = false; // Uncheck after adding
1720    });
1721
1722    // Re-render the menu structure immediately
1723    renderMenuBuilderList();
1724    
1725    // Uncheck "Select All" toggle
1726    const selectAllCb = document.getElementById('menu-select-all-cb');
1727    if (selectAllCb) selectAllCb.checked = false;
1728
1729    // Button success feedback
1730    const btn = document.getElementById('load-content-btn');
1731    const originalHTML = btn.innerHTML;
1732    btn.innerHTML = '✓ Added to Menu!';
1733    btn.classList.replace('text-rose-400', 'text-white');
1734    btn.classList.replace('bg-rose-600/20', 'bg-green-600');
1735    
1736    setTimeout(() => {
1737        btn.innerHTML = originalHTML;
1738        btn.classList.replace('text-white', 'text-rose-400');
1739        btn.classList.replace('bg-green-600', 'bg-rose-600/20');
1740    }, 1500);
1741};
1742
1743/* ==========================================
1744   MENU BUILDER: DRAG, DROP & RENDER LOGIC
1745   ========================================== */
1746
1747window.liveMenuData = [];
1748let draggedMenuIndex = null;
1749
1750// 1. Load Initial Data (Called when panel opens)
1751window.loadMenuBuilderData = async function() {
1752    const container = document.getElementById('menu-builder-list');
1753    if (container) container.innerHTML = '<p class="text-center text-gray-500 italic py-8">Loading menu data...</p>';
1754
1755    try {
1756        const menuDoc = await db.collection("site_settings").doc("navigation").get();
1757        if (menuDoc.exists && menuDoc.data().menuItems) {
1758            window.liveMenuData = menuDoc.data().menuItems;
1759        } else {
1760            window.liveMenuData = []; // Empty fallback
1761        }
1762        renderMenuBuilderList();
1763    } catch (e) {
1764        console.error("Error loading menu:", e);
1765        if (container) container.innerHTML = '<p class="text-center text-red-400 italic py-8">Error loading menu.</p>';
1766    }
1767};
1768
1769// 2. Render the Array to HTML
1770window.renderMenuBuilderList = function() {
1771    const container = document.getElementById('menu-builder-list');
1772    if (!container) return;
1773
1774    let html = '';
1775    window.liveMenuData.forEach((item, index) => {
1776        // 🟢 FIXED: Split color classes from the FontAwesome icon class
1777        const isPublic = (!item.visibility || item.visibility === 'public');
1778        const visIcon = isPublic ? 'fa-eye' : 'fa-eye-slash';
1779        const visColor = isPublic ? 'text-gray-400 hover:text-amber-400' : 'text-amber-500 hover:text-amber-400';
1780        
1781        if (item.type === 'link') {
1782            const displayUrl = item.url === '/' ? '/' : (item.url.startsWith('/') ? item.url : `/${item.url}`);
1783            
1784            html += `
1785            <div class="menu-item-row bg-slate-900 border border-slate-700 p-3 rounded-xl flex items-center justify-between group transition-all"
1786                 draggable="true" 
1787                 ondragstart="menuDragStart(event, ${index})"
1788                 ondragover="menuDragOver(event)"
1789                 ondrop="menuDrop(event, ${index})"
1790                 ondragend="menuDragEnd(event)">
1791                <div class="flex items-center gap-3">
1792                    <i class="fa-solid fa-grip-vertical text-gray-600 cursor-grab active:cursor-grabbing"></i>
1793                    <span class="font-bold text-sm text-white">${item.title}</span>
1794                    <span class="text-[10px] text-gray-500 font-mono">${displayUrl}</span>
1795                </div>
1796                <div class="flex gap-2 opacity-50 group-hover:opacity-100 transition">
1797                    <!-- 🟢 FIXED: Placed ${visIcon} inside the <i> tag -->
1798                    <button onclick="openMenuAccessModal(${index})" class="${visColor}" title="Visibility Settings"><i class="fa-solid ${visIcon} fa-fw"></i></button>
1799                    <button onclick="removeMenuItem(${index})" class="text-gray-400 hover:text-red-400" title="Delete"><i class="fa-solid fa-trash-can fa-fw"></i></button>
1800                </div>
1801            </div>`;
1802            
1803        } else if (item.type === 'dropdown') {
1804            let subHtml = '';
1805            if (item.subItems && item.subItems.length > 0) {
1806                item.subItems.forEach((sub, subIndex) => {
1807                    const subDisplayUrl = sub.url === '/' ? '/' : (sub.url.startsWith('/') ? sub.url : `/${sub.url}`);
1808                    
1809                    // 🟢 FIXED: Same fix for sub-links
1810                    const isSubPublic = (!sub.visibility || sub.visibility === 'public');
1811                    const subVisIcon = isSubPublic ? 'fa-eye' : 'fa-eye-slash';
1812                    const subVisColor = isSubPublic ? 'text-gray-500 hover:text-amber-400' : 'text-amber-500 hover:text-amber-400';
1813                    
1814                    subHtml += `
1815                    <div class="bg-slate-950 border border-slate-800 p-2.5 rounded-lg flex items-center justify-between group/sub">
1816                        <div class="flex items-center gap-3">
1817                            <i class="fa-solid fa-minus text-gray-700 text-xs"></i>
1818                            <span class="font-semibold text-xs text-gray-300">${sub.title}</span>
1819                            <span class="text-[10px] text-gray-500 font-mono">${subDisplayUrl}</span>
1820                        </div>
1821                        <div class="flex items-center gap-2 opacity-50 group-hover/sub:opacity-100 transition">
1822                            <!-- 🟢 FIXED -->
1823                            <button onclick="openMenuAccessModal(${index}, ${subIndex})" class="${subVisColor} text-xs px-1" title="Visibility"><i class="fa-solid ${subVisIcon} fa-fw"></i></button>
1824                            <button onclick="moveSubMenuItem(${index}, ${subIndex}, -1)" class="text-gray-500 hover:text-amber-400 text-xs px-1" title="Move Up"><i class="fa-solid fa-arrow-up fa-fw"></i></button>
1825                            <button onclick="moveSubMenuItem(${index}, ${subIndex}, 1)" class="text-gray-500 hover:text-amber-400 text-xs px-1" title="Move Down"><i class="fa-solid fa-arrow-down fa-fw"></i></button>
1826                            <button onclick="removeSubMenuItem(${index}, ${subIndex})" class="text-gray-500 hover:text-red-400 text-xs ml-1" title="Remove Sub-link"><i class="fa-solid fa-xmark fa-fw"></i></button>
1827                        </div>
1828                    </div>`;
1829                });
1830            } else {
1831                subHtml = `<p class="text-[10px] text-gray-500 italic py-1">No sub-links added yet.</p>`;
1832            }
1833
1834            html += `
1835            <div class="menu-item-row bg-slate-900 border border-slate-700 p-3 rounded-xl flex flex-col gap-2 group transition-all"
1836                 draggable="true" 
1837                 ondragstart="menuDragStart(event, ${index})"
1838                 ondragover="menuDragOver(event)"
1839                 ondrop="menuDrop(event, ${index})"
1840                 ondragend="menuDragEnd(event)">
1841                <div class="flex items-center justify-between">
1842                    <div class="flex items-center gap-3">
1843                        <i class="fa-solid fa-grip-vertical text-gray-600 cursor-grab active:cursor-grabbing"></i>
1844                        <span class="font-bold text-sm text-amber-400"><i class="fa-solid fa-folder-open mr-1"></i> ${item.title}</span>
1845                    </div>
1846                    <div class="flex gap-2 opacity-50 group-hover:opacity-100 transition">
1847                        <!-- 🟢 FIXED -->
1848                        <button onclick="openMenuAccessModal(${index})" class="${visColor}" title="Visibility Settings"><i class="fa-solid ${visIcon} fa-fw"></i></button>
1849                        <button onclick="removeMenuItem(${index})" class="text-gray-400 hover:text-red-400" title="Delete Folder">
1849<i class="fa-solid fa-trash-can fa-fw"></i></button>
1850                    </div>
1851                </div>
1852                
1853                <div class="ml-6 pl-3 border-l-2 border-slate-700 space-y-2 mt-2" ondragover="event.stopPropagation();" ondrop="event.stopPropagation();">
1854                    ${subHtml}
1855                    <button onclick="addSubLinkPrompt(${index})" class="w-full text-left p-2 border border-dashed border-slate-700 rounded-lg text-[11px] font-bold text-gray-500 hover:text-rose-400 hover:border-rose-500/50 transition">
1856                        + Add sub-link
1857                    </button>
1858                </div>
1859            </div>`;
1860        }
1861    });
1862
1863    container.innerHTML = html || '<div class="text-center py-8"><p class="text-gray-500 italic text-sm mb-2">Your menu is completely empty.</p></div>';
1864};
1865
1866window.customDoublePrompt = function(title, message, placeholder1 = "Title", placeholder2 = "URL") {
1867    return new Promise((resolve) => {
1868        injectUniversalUI();
1869        const overlay = document.getElementById('universal-dialog-overlay');
1870        document.getElementById('dialog-icon').innerHTML = '<i class="fa-solid fa-link text-brandBlue"></i>';
1871        document.getElementById('dialog-title').innerText = title;
1872        
1873        // 🟢 Injects two separate inputs into the same dialog box
1874        document.getElementById('dialog-message').innerHTML = `
1875            <p class="text-gray-600 text-sm mb-4">${message}</p>
1876            <div class="space-y-3 text-left">
1877                <div>
1878                    <label class="block text-xs font-bold text-gray-500 mb-1">Link Title</label>
1879                    <input type="text" id="prompt-input-1" placeholder="${placeholder1}" class="w-full px-4 py-2.5 border border-gray-300 rounded-xl focus:ring-2 focus:ring-brandBlue focus:outline-none text-sm text-gray-800">
1880                </div>
1881                <div>
1882                    <label class="block text-xs font-bold text-gray-500 mb-1">URL Slug</label>
1883                    <input type="text" id="prompt-input-2" placeholder="${placeholder2}" class="w-full px-4 py-2.5 border border-gray-300 rounded-xl focus:ring-2 focus:ring-brandBlue focus:outline-none text-sm text-gray-800">
1884                </div>
1885            </div>
1886        `;
1887
1888        document.getElementById('dialog-buttons').innerHTML = `
1889            <button id="dialog-cancel-btn" class="w-1/2 bg-gray-200 text-gray-800 font-bold py-2.5 rounded-xl hover:bg-gray-300 transition text-sm">Cancel</button>
1890            <button id="dialog-submit-btn" class="w-1/2 bg-brandBlue text-white font-bold py-2.5 rounded-xl hover:bg-blue-900 transition shadow-md text-sm">Add Link</button>
1891        `;
1892
1893        overlay.classList.remove('hidden');
1894        const input1 = document.getElementById('prompt-input-1');
1895        const input2 = document.getElementById('prompt-input-2');
1896        input1.focus();
1897
1898        const submitFn = () => {
1899            const val1 = input1.value;
1900            const val2 = input2.value;
1901            if (!val1 || !val2) {
1902                customToast("Both fields are required.", "error");
1903                return;
1904            }
1905            overlay.classList.add('hidden');
1906            resolve({ title: val1, url: val2 });
1907        };
1908
1909        input2.onkeyup = (e) => { if (e.key === 'Enter') submitFn(); };
1910        document.getElementById('dialog-submit-btn').onclick = submitFn;
1911        
1912        document.getElementById('dialog-cancel-btn').onclick = () => { 
1913            overlay.classList.add('hidden'); 
1914            resolve(null); 
1915        };
1916    });
1917};
1918
1919// 3. HTML5 Drag & Drop Handlers
1920window.menuDragStart = function(e, index) {
1921    draggedMenuIndex = index;
1922    e.dataTransfer.effectAllowed = 'move';
1923    // Delay adding the class so the dragged ghost image looks normal
1924    setTimeout(() => {
1925        e.target.classList.add('opacity-40', 'border-rose-500', 'border-dashed');
1926    }, 0);
1927};
1928
1929window.menuDragOver = function(e) {
1930    e.preventDefault();
1931    e.dataTransfer.dropEffect = 'move';
1932};
1933
1934window.menuDrop = function(e, targetIndex) {
1935    e.preventDefault();
1936    e.stopPropagation();
1937    
1938    if (draggedMenuIndex !== null && draggedMenuIndex !== targetIndex) {
1939        // Remove the dragged item from its original position
1940        const movedItem = window.liveMenuData.splice(draggedMenuIndex, 1)[0];
1941        // Insert it into the new target position
1942        window.liveMenuData.splice(targetIndex, 0, movedItem);
1943        
1944        // Re-render the UI to reflect the new array order
1945        renderMenuBuilderList();
1946    }
1947};
1948
1949window.menuDragEnd = function(e) {
1950    e.target.classList.remove('opacity-40', 'border-rose-500', 'border-dashed');
1951    draggedMenuIndex = null;
1952    renderMenuBuilderList(); // Clean up any lingering visual artifacts
1953};
1954
1955// 4. Delete Functions
1956window.removeMenuItem = async function(index) {
1957    const confirmed = await customConfirm("Remove Item", "Are you sure you want to remove this item from the menu?");
1958    if (confirmed) {
1959        window.liveMenuData.splice(index, 1);
1960        renderMenuBuilderList();
1961    }
1962};
1963
1964window.removeSubMenuItem = async function(parentIndex, subIndex) {
1965    const confirmed = await customConfirm("Remove Sub-link", "Remove this link from the dropdown folder?");
1966    if (confirmed) {
1967        window.liveMenuData[parentIndex].subItems.splice(subIndex, 1);
1968        renderMenuBuilderList();
1969    }
1970};
1971
1972// 5. Move Sub-Links Up and Down
1973window.moveSubMenuItem = function(parentIndex, subIndex, direction) {
1974    const subItems = window.liveMenuData[parentIndex].subItems;
1975    const newIndex = subIndex + direction;
1976
1977    // Stop if trying to move out of bounds (above the top or below the bottom)
1978    if (newIndex < 0 || newIndex >= subItems.length) return;
1979
1980    // Swap the items in the array
1981    const temp = subItems[subIndex];
1982    subItems[subIndex] = subItems[newIndex];
1983    subItems[newIndex] = temp;
1984
1985    // Instantly re-render the UI
1986    renderMenuBuilderList();
1987};
1988
1989// 🟢 6. Menu Item Visibility Logic
1990window.activeMenuAccessParent = null;
1991window.activeMenuAccessSub = null;
1992
1993window.openMenuAccessModal = function(parentIndex, subIndex = null) {
1994    window.activeMenuAccessParent = parentIndex;
1995    window.activeMenuAccessSub = subIndex;
1996
1997    let targetItem;
1998    if (subIndex === null) {
1999        targetItem = window.liveMenuData[parentIndex];
2000    } else {
2001        targetItem = window.liveMenuData[parentIndex].subItems[subIndex];
2002    }
2003
2004    document.getElementById('menu-access-target-name').innerText = targetItem.title;
2005    
2006    // Check the correct radio button
2007    const currentVis = targetItem.visibility || 'public';
2008    const radio = document.querySelector(`input[name="menu_vis_option"][value="${currentVis}"]`);
2009    if (radio) radio.checked = true;
2010
2011    document.getElementById('menu-access-modal').classList.remove('hidden');
2012};
2013
2014window.closeMenuAccessModal = function() {
2015    document.getElementById('menu-access-modal').classList.add('hidden');
2016};
2017
2018window.saveMenuAccess = function() {
2019    const selected = document.querySelector('input[name="menu_vis_option"]:checked').value;
2020    
2021    if (window.activeMenuAccessSub === null) {
2022        window.liveMenuData[window.activeMenuAccessParent].visibility = selected;
2023    } else {
2024        window.liveMenuData[window.activeMenuAccessParent].subItems[window.activeMenuAccessSub].visibility = selected;
2025    }
2026
2027    renderMenuBuilderList(); // Re-render to update the icons
2028    closeMenuAccessModal();
2029    customToast("Visibility updated. Don't forget to 'Save Menu Live'!", "success");
2030};
2031
2032/* ==========================================
2033   MENU BUILDER: ADD & SAVE LOGIC
2034   ========================================== */
2035
2036window.addStandardLinkToMenu = function() {
2037    const titleInput = document.getElementById('new-link-title');
2038    const urlInput = document.getElementById('new-link-url');
2039    
2040    if (!titleInput.value.trim() || !urlInput.value.trim()) {
2041        return customToast("Please enter both a Title and a URL.", "error");
2042    }
2043    
2044    window.liveMenuData.push({
2045        type: 'link',
2046        title: titleInput.value.trim(),
2047        url: urlInput.value.trim(),
2048        icon: 'fa-link' // Default icon for custom links
2049    });
2050    
2051    // Clear inputs and re-render
2052    titleInput.value = ''; 
2053    urlInput.value = '';
2054    renderMenuBuilderList();
2055    customToast("Link added to menu!", "success");
2056};
2057
2058window.addDropdownToMenu = function() {
2059    const titleInput = document.getElementById('new-dropdown-title');
2060    
2061    if (!titleInput.value.trim()) {
2062        return customToast("Please enter a folder title.", "error");
2063    }
2064    
2065    window.liveMenuData.push({
2066        type: 'dropdown',
2067        title: titleInput.value.trim(),
2068        icon: 'fa-folder',
2069        subItems: []
2070    });
2071    
2072    // Clear input and re-render
2073    titleInput.value = '';
2074    renderMenuBuilderList();
2075    customToast("Dropdown folder created!", "success");
2076};
2077
2078window.addSubLinkPrompt = async function(parentIndex) {
2079    const result = await customDoublePrompt(
2080        "Add Sub-Link", 
2081        "Enter the link title and URL slug below:",
2082        "e.g. Grammar Classes",
2083        "e.g. grammar"
2084    );
2085    
2086    // If the user hits cancel, do nothing
2087    if (!result) return;
2088
2089    window.liveMenuData[parentIndex].subItems.push({
2090        title: result.title.trim(),
2091        url: result.url.trim()
2092    });
2093    
2094    renderMenuBuilderList();
2095    customToast("Sub-link added to folder!", "success");
2096};
2097
2098// 🟢 Save the Live Menu to Firebase!
2099window.saveMenuToFirebase = async function() {
2100    try {
2101        const btn = document.querySelector('button[onclick="saveMenuToFirebase()"]');
2102        const origHtml = btn.innerHTML;
2103        btn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Saving...';
2104        
2105        await db.collection("site_settings").doc("navigation").set({
2106            menuItems: window.liveMenuData,
2107            updatedAt: new Date()
2108        });
2109        
2110        customToast("Menu saved successfully! It is now live.", "success");
2111        btn.innerHTML = origHtml;
2112    } catch (e) {
2113        customToast("Error saving menu: " + e.message, "error");
2114    }
2115};
2116
2117/* ==========================================
2118   DYNAMIC LIBRARY MANAGEMENT PANEL
2119   ========================================== */
2120
2121window.allBookshelvesData = [];
2122
2123window.openFullscreenLibraryManager = function() {
2124    const existingWs = document.getElementById('admin-fullscreen-workspace');
2125    if (existingWs) existingWs.remove();
2126
2127    const workspaceHTML = `
2128    <div id="admin-fullscreen-workspace" class="fixed inset-0 z-[999999] bg-[#0b0f19] text-white flex flex-col font-sans overflow-hidden">
2129        
2130        <!-- Top Bar -->
2131        <div class="bg-slate-950 text-gray-300 h-14 px-8 flex items-center justify-between border-b border-slate-800 shadow-xl">
2132            <div class="flex items-center gap-3">
2133                <div class="w-9 h-9 bg-sky-600 text-white rounded-xl flex items-center justify-center font-black text-lg">
2134                    <i class="fa-solid fa-book-bookmark"></i>
2135                </div>
2136                <div>
2137                    <h2 class="font-black text-lg text-white leading-none">Digital Library Management</h2>
2138                    <p class="text-[11px] text-gray-400">Build 3D bookshelves, manage flipbooks, categories, themes, and pricing.</p>
2139                </div>
2140            </div>
2141            
2142            <div class="flex items-center gap-3">
2143                <button onclick="openBookshelfEditorModal()" class="bg-amber-500 hover:bg-amber-400 text-slate-950 font-black px-4 py-2 rounded-xl text-xs transition shadow-lg flex items-center gap-2">
2144                    <i class="fa-solid fa-plus"></i> Create New Bookshelf
2145                </button>
2146                <button onclick="document.getElementById('admin-fullscreen-workspace').remove()" class="bg-red-600/20 text-red-400 border border-red-500/30 px-5 py-2.5 rounded-xl text-xs font-bold hover:bg-red-600/40 transition">
2147                    ✕ Close Panel
2148                </button>
2149            </div>
2150        </div>
2151
2152        <!-- Main Panel Container (1280px Max Width) -->
2153        <div class="flex-1 overflow-y-auto p-6 md:p-10 flex justify-center">
2154            <div class="w-full max-w-[1280px] space-y-6">
2155                
2156                <div class="bg-[#131927] border border-slate-800 rounded-3xl p-6 md:p-8 shadow-2xl space-y-6">
2157                    <div class="flex justify-between items-center border-b border-slate-800/80 pb-4">
2158                        <div>
2159                            <h3 class="text-2xl font-black text-white mb-1">Bookshelves & Digital Collections</h3>
2160                            <p class="text-xs text-gray-400">Published bookshelves appear live on /library with 3D perspective themes.</p>
2161                        </div>
2162                    </div>
2163
2164                    <!-- Bookshelves Grid List -->
2165                    <div id="admin-bookshelves-list" class="grid grid-cols-1 md:grid-cols-2 gap-6">
2166                        <p class="text-xs text-gray-500 italic py-8 text-center col-span-2">Loading bookshelves...</p>
2167                    </div>
2168                </div>
2169
2170            </div>
2171        </div>
2172    </div>
2173
2174    <!-- 🟢 1280px BOOKSHELF EDITOR MODAL WITH SHORTENED INSET SCROLLBAR -->
2175    <div id="bookshelf-editor-modal" class="fixed inset-0 z-[1000000] bg-black/80 backdrop-blur-sm hidden flex items-center justify-center p-4 sm:p-6 overflow-y-auto">
2176        
2177        <style>
2178            /* 🟢 Shortened Inset Custom Dark Scrollbar (20px top/bottom gap prevents corner clipping) */
2179            #bookshelf-modal-box::-webkit-scrollbar {
2180                width: 12px;
2181            }
2182            #bookshelf-modal-box::-webkit-scrollbar-track {
2183                background: #0f172a;
2184                border-radius: 10px;
2185                /* 20px gap at top & bottom keeps track away from rounded corners */
2186                border-top: 20px solid transparent;
2187                border-bottom: 20px solid transparent;
2188                background-clip: padding-box;
2189            }
2190            #bookshelf-modal-box::-webkit-scrollbar-thumb {
2191                background: #334155;
2192                border-radius: 10px;
2193                border: 3px solid transparent;
2194                /* 20px gap at top & bottom */
2195                border-top: 20px solid transparent;
2196                border-bottom: 20px solid transparent;
2197                background-clip: padding-box;
2198            }
2199            #bookshelf-modal-box::-webkit-scrollbar-thumb:hover {
2200                background: #f59e0b;
2201                background-clip: padding-box;
2202            }
2203        </style>
2204
2205        <div id="bookshelf-modal-box" class="bg-[#181d2a] border border-slate-800 rounded-3xl p-6 sm:p-8 max-w-[1280px] w-full shadow-2xl my-auto space-y-6 max-h-[90vh] overflow-y-auto text-xs relative">
2206            
2207            <!-- Sticky Modal Header -->
2208            <div class="flex justify-between items-center border-b border-slate-800 pb-4 sticky -top-6 sm:-top-8 bg-[#181d2a] z-30 pt-2">
2209                <h3 class="text-xl sm:text-2xl font-black text-white" id="bs-modal-title">+ Create New Bookshelf</h3>
2210                
2211                <!-- 🟢 NEW: SHELF LEVEL ACCESS BUTTON -->
2212                <div class="flex items-center gap-3 mr-4">
2213                    <button type="button" onclick="openAccessManager('shelf')" class="bg-indigo-600 hover:bg-indigo-500 text-white font-bold px-4 py-2 rounded-xl text-xs sm:text-sm transition shadow-md flex items-center gap-2">
2214                        <i class="fa-solid fa-users-lock"></i>
2214 Shelf Access
2215                    </button>
2216                    <button type="button" onclick="closeBookshelfEditorModal()" class="text-gray-400 hover:text-white text-xl w-8 h-8 rounded-full hover:bg-slate-800 flex items-center justify-center transition-colors"><i class="fa-solid fa-xmark"></i></button>
2217                </div>
2218            </div>
2219
2220            <form id="bookshelf-editor-form" class="space-y-6">
2221                <input type="hidden" id="bs-edit-id" value="">
2222                <!-- 🟢 NEW: Hidden input to store allowed user IDs for the shelf -->
2223                <input type="hidden" id="bs-allowed-users" value="[]">
2224
2225                <!-- Category & Pricing -->
2226                <div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
2227                    <div class="sm:col-span-2">
2228                        <label class="block font-bold text-gray-300 uppercase mb-1">Category / Bookshelf Title *</label>
2229                        <input type="text" id="bs-title" placeholder="e.g. Young Learners YLE Series" required class="w-full p-3 bg-slate-950 border border-slate-700 rounded-xl text-white focus:outline-none focus:border-amber-400 text-xs sm:text-sm">
2230                    </div>
2231                    <div>
2232                        <label class="block font-bold text-gray-300 uppercase mb-1">Bookshelf Access Price</label>
2233                        <input type="text" id="bs-price" placeholder="Free or e.g. 25,000 MMK" value="Free" class="w-full p-3 bg-slate-950 border border-slate-700 rounded-xl text-amber-400 font-bold focus:outline-none focus:border-amber-400 text-xs sm:text-sm">
2234                    </div>
2235                </div>
2236
2237                <div>
2238                    <label class="block font-bold text-gray-300 uppercase mb-1">Category Description</label>
2239                    <textarea id="bs-desc" rows="2" placeholder="Brief explanation of books in this shelf..." class="w-full p-3 bg-slate-950 border border-slate-700 rounded-xl text-white focus:outline-none focus:border-amber-400 text-xs sm:text-sm"></textarea>
2240
2241                    <label class="flex items-center gap-2.5 mt-2.5 font-bold text-amber-400 text-xs cursor-pointer select-none">
2242                        <input type="checkbox" id="bs-collapse-desc" class="w-4 h-4 rounded text-amber-500 bg-slate-950 border-slate-700 cursor-pointer focus:ring-amber-500">
2243                        Collapse long description (Show "Read More" button)
2244                    </label>
2245                </div>
2246
2247                <!-- Style / Theme Selector -->
2248                <div>
2249                    <label class="block font-bold text-gray-300 uppercase mb-2">3D Bookshelf Theme & Material *</label>
2250                    <div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3 text-xs">
2251                        <label class="p-3 border rounded-xl bg-slate-950 border-slate-700 text-gray-300 flex items-center justify-center gap-2 cursor-pointer has-[:checked]:border-amber-400 has-[:checked]:text-amber-400 font-bold text-center">
2252                            <input type="radio" name="bs_theme" value="theme-oak" checked class="hidden"> 🌲 Natural Oak
2253                        </label>
2254                        <label class="p-3 border rounded-xl bg-slate-950 border-slate-700 text-gray-300 flex items-center justify-center gap-2 cursor-pointer has-[:checked]:border-amber-400 has-[:checked]:text-amber-400 font-bold text-center">
2255                            <input type="radio" name="bs_theme" value="theme-walnut" class="hidden"> 🌑 Dark Walnut
2256                        </label>
2257                        <label class="p-3 border rounded-xl bg-slate-950 border-slate-700 text-gray-300 flex items-center justify-center gap-2 cursor-pointer has-[:checked]:border-amber-400 has-[:checked]:text-amber-400 font-bold text-center">
2258                            <input type="radio" name="bs_theme" value="theme-silver" class="hidden"> 💎 Silver Metallic
2259                        </label>
2260                        <label class="p-3 border rounded-xl bg-slate-950 border-slate-700 text-gray-300 flex items-center justify-center gap-2 cursor-pointer has-[:checked]:border-amber-400 has-[:checked]:text-amber-400 font-bold text-center">
2261                            <input type="radio" name="bs_theme" value="theme-glass" class="hidden"> 🧊 Frosted Glass
2262                        </label>
2263                        <label class="p-3 border rounded-xl bg-slate-950 border-slate-700 text-gray-300 flex items-center justify-center gap-2 cursor-pointer has-[:checked]:border-amber-400 has-[:checked]:text-amber-400 font-bold text-center">
2264                            <input type="radio" name="bs_theme" value="theme-gold" class="hidden"> 🪙 Luxury Gold
2265                        </label>
2266                        <label class="p-3 border rounded-xl bg-slate-950 border-slate-700 text-gray-300 flex items-center justify-center gap-2 cursor-pointer has-[:checked]:border-amber-400 has-[:checked]:text-amber-400 font-bold text-center">
2267                            <input type="radio" name="bs_theme" value="theme-white" class="hidden"> ⚪ Minimal White
2268                        </label>
2269                    </div>
2270                </div>
2271
2272                <!-- DYNAMIC BOOKS LIST BUILDER -->
2273                <div class="space-y-4 pt-4 border-t border-slate-800">
2274                    <div class="flex justify-between items-center">
2275                        <h4 class="font-black text-amber-400 text-sm sm:text-base"><i class="fa-solid fa-books mr-1.5"></i> Books on this Shelf</h4>
2276                        <button type="button" onclick="addBookRowToEditor()" class="bg-blue-600 hover:bg-blue-500 text-white font-bold px-4 py-2 rounded-xl text-xs sm:text-sm transition shadow-md">
2277                            + Add Book Item
2278                        </button>
2279                    </div>
2280
2281                    <div id="bs-books-container" class="space-y-3">
2282                        <!-- Book Items Injected Here -->
2283                    </div>
2284                </div>
2285
2286                <!-- Action Buttons -->
2287                <div class="flex gap-3 pt-4 border-t border-slate-800 justify-end sticky -bottom-6 sm:-bottom-8 bg-[#181d2a] z-30 pb-2">
2288                    <button type="button" onclick="closeBookshelfEditorModal()" class="px-5 py-3 bg-slate-800 hover:bg-slate-700 text-gray-300 font-bold rounded-xl transition">Cancel</button>
2289                    <button type="submit" name="status" value="draft" class="px-5 py-3 bg-slate-700 hover:bg-slate-600 text-amber-300 font-bold rounded-xl transition">Save as Draft</button>
2290                    <button type="submit" name="status" value="published" class="px-6 py-3 bg-sky-600 hover:bg-sky-500 text-white font-black rounded-xl transition shadow-lg">✓ Publish Live</button>
2291                </div>
2292            </form>
2293        </div>
2294    </div>
2295
2296    <!-- 🟢 NEW: USER ACCESS MANAGER MODAL -->
2297    <div id="user-access-modal" class="fixed inset-0 z-[1000006] bg-black/90 backdrop-blur-sm hidden flex items-center justify-center p-4">
2298        <div class="bg-[#181d2a] border border-slate-800 rounded-3xl p-6 w-full max-w-lg shadow-2xl space-y-4 flex flex-col max-h-[80vh]">
2299            <div class="flex justify-between items-center border-b border-slate-800 pb-3">
2300                <h3 class="text-lg font-black text-indigo-400" id="access-modal-title"><i class="fa-solid fa-users-lock mr-2"></i> Manage Access</h3>
2301                <button type="button" onclick="closeAccessManager()" class="text-gray-400 hover:text-white text-lg w-8 h-8 rounded-full hover:bg-slate-800 flex items-center justify-center transition-colors"><i class="fa-solid fa-xmark"></i></button>
2302            </div>
2303            
2304            <div class="flex items-center gap-3 pr-2">
2305                <input type="text" id="access-user-search" placeholder="Search by name or email..." onkeyup="filterAccessUsers()" class="flex-1 p-3 bg-slate-950 border border-slate-700 rounded-xl text-white text-xs focus:outline-none focus:border-indigo-500">
2306                
2307                <label class="flex items-center gap-3 p-3 bg-slate-800/60 border border-slate-700 rounded-xl cursor-pointer hover:border-indigo-500 transition whitespace-nowrap shrink-0">
2308                    <span class="text-white text-xs font-black">Select All</span>
2309                    <input type="checkbox" id="access-select-all-cb" onchange="toggleAllAccessUsers(this)" class="w-4 h-4 rounded text-indigo-600 bg-slate-950 border-slate-600">
2310                </label>
2311            </div>
2312
2313            <!-- 🟢 NEW: REQUIRE LOGIN TOGGLE -->
2314            <label class="flex items-center justify-between p-3 bg-indigo-900/20 border border-indigo-500/30 rounded-xl cursor-pointer hover:border-indigo-500 transition mr-2">
2315                <div>
2316                    <span class="text-indigo-300 text-xs font-black block">Require Login to View</span>
2317                    <span class="text-gray-500 text-[10px]">If checked, random public visitors cannot see this.</span>
2318                </div>
2319                <input type="checkbox" id="access-require-login-cb" class="w-4 h-4 rounded text-indigo-600 bg-slate-950 border-slate-600">
2320            </label>
2321            
2322            <div id="access-users-list" class="flex-1 overflow-y-auto space-y-2 pr-2 border-t border-slate-800 pt-3">
2323                <p class="text-gray-500 italic text-xs text-center py-4">Loading users...</p>
2324            </div>
2325            
2326            <button type="button" onclick="saveAccessManager()" class="w-full bg-indigo-600 hover:bg-indigo-500 text-white font-black py-3 rounded-xl transition shadow-lg text-sm">
2327                Save Access Permissions
2328            </button>
2329        </div>
2330    </div>
2331    `; 
2332
2333    document.body.insertAdjacentHTML('beforeend', workspaceHTML);
2334    loadAdminBookshelves();
2335};
2336
2337async function loadAdminBookshelves() {
2338    const list = document.getElementById('admin-bookshelves-list');
2339    if (!list) return;
2340
2341    try {
2342        const snapshot = await db.collection("library_bookshelves").orderBy("createdAt", "desc").get();
2343        window.allBookshelvesData = [];
2344
2345        if (snapshot.empty) {
2346            list.innerHTML = `<p class="text-sm text-gray-500 italic py-8 text-center col-span-2">No bookshelves created yet. Click "+ Create New Bookshelf" to build one!</p>`;
2347            return;
2348        }
2349
2350        let html = '';
2351        snapshot.forEach(doc => {
2352            const data = doc.data();
2353            data.id = doc.id;
2354            window.allBookshelvesData.push(data);
2355
2356            const isPub = data.isPublished !== false;
2357            const statusBadge = isPub 
2358                ? `<span class="bg-emerald-500/20 text-emerald-400 border border-emerald-500/30 text-xs font-black px-3 py-1 rounded-full uppercase">Published</span>`
2359                : `<span class="bg-amber-500/20 text-amber-400 border border-amber-500/30 text-xs font-black px-3 py-1 rounded-full uppercase">Draft</span>`;
2360
2361            const bookCount = (data.books || []).length;
2362            const rawDesc = data.categoryDescription || '';
2363            const shouldCollapse = data.collapseDesc !== false && rawDesc.length > 120; // Only collapse if long text & enabled
2364
2365            let descBlock = '';
2366            const safeShelfId = data.id.replace(/[^a-zA-Z0-9]/g, '_');
2367
2368            if (rawDesc.trim() !== '') {
2369                if (shouldCollapse) {
2370                    descBlock = `
2371                    <div class="space-y-2 mt-1">
2372                        <p id="admin-desc-${safeShelfId}" class="text-gray-300 text-sm leading-relaxed line-clamp-2 whitespace-pre-line overflow-hidden transition-all duration-300">${rawDesc}</p>
2373                        <button type="button" onclick="toggleAdminShelfDescription('${safeShelfId}')" id="admin-desc-btn-${safeShelfId}" class="inline-flex items-center gap-1.5 text-xs font-black bg-slate-800 hover:bg-slate-700 text-amber-400 px-3 py-1 rounded-xl border border-slate-700 transition cursor-pointer select-none">
2374                            <span>Read More ▼</span>
2375                        </button>
2376                    </div>`;
2377                } else {
2378                    descBlock = `<p class="text-gray-300 text-sm leading-relaxed whitespace-pre-line mt-1">${rawDesc}</p>`;
2379                }
2380            } else {
2381                descBlock = `<p class="text-gray-500 text-sm italic mt-1">
2381No description provided.</p>`;
2382            }
2383
2384            html += `
2385            <div class="bg-slate-900 border border-slate-800 rounded-2xl p-6 space-y-4 relative group">
2386                <div class="flex justify-between items-start gap-4">
2387                    <div>
2388                        <h4 class="font-black text-white text-xl sm:text-2xl mb-1">${data.categoryName}</h4>
2389                        ${descBlock}
2390                    </div>
2391                    ${statusBadge}
2392                </div>
2393
2394                <div class="flex flex-wrap items-center gap-3 text-sm text-gray-300 pt-1 font-medium">
2395                    <span class="bg-slate-950 px-3.5 py-1.5 rounded-xl border border-slate-800">📚 Books: <strong class="text-white font-extrabold ml-1">${bookCount}</strong></span>
2396                    <span class="bg-slate-950 px-3.5 py-1.5 rounded-xl border border-slate-800">🎨 Theme: <strong class="text-amber-400 font-extrabold ml-1">${data.theme || 'theme-oak'}</strong></span>
2397                    <span class="bg-slate-950 px-3.5 py-1.5 rounded-xl border border-slate-800">🏷️ Price: <strong class="text-sky-400 font-extrabold ml-1">${data.shelfPrice || 'Free'}</strong></span>
2398                </div>
2399
2400                <div class="flex gap-3 pt-3 border-t border-slate-800/80 justify-end">
2401                    <button onclick="editBookshelf('${data.id}')" class="bg-sky-600 hover:bg-sky-500 text-white font-bold px-4 py-2 rounded-xl text-xs sm:text-sm transition shadow-md">Edit Shelf</button>
2402                    <button onclick="deleteBookshelf('${data.id}')" class="bg-slate-800 hover:bg-red-600 text-gray-300 hover:text-white font-bold px-4 py-2 rounded-xl text-xs sm:text-sm transition">Delete</button>
2403                </div>
2404            </div>`;
2405        });
2406
2407        list.innerHTML = html;
2408    } catch(e) {
2409        list.innerHTML = `<p class="text-sm text-red-400 py-8 text-center col-span-2">Error loading bookshelves: ${e.message}</p>`;
2410    }
2411}
2412
2413window.toggleAdminShelfDescription = function(safeId) {
2414    const textEl = document.getElementById(`admin-desc-${safeId}`);
2415    const btnEl = document.getElementById(`admin-desc-btn-${safeId}`);
2416    if (!textEl || !btnEl) return;
2417
2418    if (textEl.classList.contains('line-clamp-2')) {
2419        textEl.classList.remove('line-clamp-2');
2420        btnEl.innerHTML = `<span>Show Less ▲</span>`;
2421    } else {
2422        textEl.classList.add('line-clamp-2');
2423        btnEl.innerHTML = `<span>Read More ▼</span>`;
2424    }
2425};
2426
2427window.openBookshelfEditorModal = function(editId = null) {
2428    // 🟢 FIX: Always ensure the background Admin Library Management panel exists first!
2429    if (!document.getElementById('admin-fullscreen-workspace')) {
2430        if (typeof openFullscreenLibraryManager === 'function') {
2431            openFullscreenLibraryManager();
2432        }
2433    }
2434
2435    // 🟢 Automatically inject Bookshelf Editor Modal HTML if it got wiped out
2436    if (!document.getElementById('bookshelf-editor-modal')) {
2437        // Re-inject modal template if needed or ensure it's present
2438        loadAdminBookshelves(); // Refreshes container structure
2439    }
2440
2441    const editInput = document.getElementById('bs-edit-id');
2442    const modalTitle = document.getElementById('bs-modal-title');
2443    const form = document.getElementById('bookshelf-editor-form');
2444    const booksContainer = document.getElementById('bs-books-container');
2445
2446    if (!editInput || !form) return;
2447
2448    editInput.value = editId || '';
2449    if (modalTitle) modalTitle.innerText = editId ? 'Edit Bookshelf' : '+ Create New Bookshelf';
2450    form.reset();
2451    if (booksContainer) booksContainer.innerHTML = '';
2452
2453    if (editId) {
2454        const data = (window.allBookshelvesData && window.allBookshelvesData.find(b => b.id === editId)) ||
2455                     (window.allPublicShelves && window.allPublicShelves.find(b => b.id === editId));
2456
2457        if (data) {
2458            document.getElementById('bs-title').value = data.categoryName || '';
2459            document.getElementById('bs-price').value = data.shelfPrice || 'Free';
2460            document.getElementById('bs-desc').value = data.categoryDescription || '';
2461            
2462            // If editing, use saved value. Default to true if undefined.
2463            document.getElementById('bs-collapse-desc').checked = data.collapseDesc !== false;
2464            
2465            const radio = document.querySelector(`input[name="bs_theme"][value="${data.theme || 'theme-oak'}"]`);
2466            if (radio) radio.checked = true;
2467
2468            if (data.books && data.books.length > 0) {
2469                data.books.forEach(b => addBookRowToEditor(b));
2470            }
2471        }
2472    } else {
2473        document.getElementById('bs-collapse-desc').checked = true;
2474        addBookRowToEditor();
2475        addBookRowToEditor();
2476        addBookRowToEditor();
2477    }
2478
2479    const modal = document.getElementById('bookshelf-editor-modal');
2480    if (modal) {
2481        modal.classList.remove('hidden');
2482        document.body.classList.add('overflow-hidden'); // Locks background scrolling
2483    }
2484};
2485
2486window.closeBookshelfEditorModal = function() {
2487    const modal = document.getElementById('bookshelf-editor-modal');
2488    if (modal) {
2489        modal.classList.add('hidden');
2490        document.body.classList.remove('overflow-hidden'); // 🟢 Unlocks background scrolling
2491    }
2492};
2493
2494let draggedBookRow = null;
2495
2496// 🟢 Helper to Renumber Book Labels (Book #1, Book #2, etc.)
2497window.renumberBookRows = function() {
2498    const container = document.getElementById('bs-books-container');
2499    if (!container) return;
2500    const rows = container.querySelectorAll('.book-item-row');
2501    rows.forEach((r, idx) => {
2502        const label = r.querySelector('.book-row-label');
2503        if (label) label.innerText = `Book #${idx + 1}`;
2504    });
2505};
2506
2507// 🟢 Helper for Up/Down Arrow Buttons
2508window.moveBookRow = function(btn, direction) {
2509    const row = btn.closest('.book-item-row');
2510    if (!row) return;
2511    const container = document.getElementById('bs-books-container');
2512
2513    if (direction === -1 && row.previousElementSibling) {
2514        container.insertBefore(row, row.previousElementSibling);
2515        renumberBookRows();
2516    } else if (direction === 1 && row.nextElementSibling) {
2517        container.insertBefore(row.nextElementSibling, row);
2518        renumberBookRows();
2519    }
2520};
2521
2522// 🟢 Helper for Remove Row Button
2523window.removeBookRow = function(btn) {
2524    const row = btn.closest('.book-item-row');
2525    if (row) {
2526        row.remove();
2527        renumberBookRows();
2528    }
2529};
2530
2531window.addBookRowToEditor = function(bookData = {}) {
2532    const container = document.getElementById('bs-books-container');
2533    const index = container.children.length + 1;
2534
2535    // 🟢 FIX: Clean JSON Object with isbn and publishedDate included
2536    const extDataJson = JSON.stringify({
2537        author: bookData.author || '',
2538        isbn: bookData.isbn || '',
2539        publishedDate: bookData.publishedDate || '',
2540        publisher: bookData.publisher || '',
2541        level: bookData.level || '',
2542        type: bookData.type || '',
2543        cefr: bookData.cefr || '',
2544        language: bookData.language || 'British English',
2545        series: bookData.series || '',
2546        formats: bookData.formats || ['PDF Document'],
2547        description: bookData.description || ''
2548    });
2549
2550    const row = document.createElement('div');
2551    row.className = 'bg-slate-950 p-4 rounded-xl border border-slate-800 space-y-3 relative group book-item-row transition-all duration-200';
2552    row.setAttribute('data-ext-info', extDataJson);
2553    row.setAttribute('draggable', 'true'); // 🟢 Enable HTML5 Dragging
2554
2555    row.innerHTML = `
2556        <div class="flex justify-between items-center border-b border-slate-800/80 pb-2 select-none">
2557            <div class="flex items-center gap-2">
2558                <span class="cursor-grab active:cursor-grabbing text-gray-500 hover:text-amber-400 p-1" title="Click & Drag to reorder">
2559                    <i class="fa-solid fa-grip-lines text-sm"></i>
2560                </span>
2561                <span class="book-row-label font-extrabold text-amber-400 text-xs">Book #${index}</span>
2562            </div>
2563            <div class="flex items-center gap-1.5">
2564                <!-- 🟢 NEW: Hidden input to store allowed user IDs for this specific book -->
2565                <input type="hidden" class="book-input-access" value='${JSON.stringify(bookData.allowedUsers || [])}'>
2566
2567                <button type="button" onclick="moveBookRow(this, -1)" class="bg-slate-900 hover:bg-slate-800 text-gray-400 hover:text-amber-400 px-2 py-1 rounded-lg text-xs font-bold transition" title="Move Up"><i class="fa-solid fa-arrow-up"></i></button>
2568                <button type="button" onclick="moveBookRow(this, 1)" class="bg-slate-900 hover:bg-slate-800 text-gray-400 hover:text-amber-400 px-2 py-1 rounded-lg text-xs font-bold transition" title="Move Down"><i class="fa-solid fa-arrow-down"></i></button>
2569                
2570                <!-- 🟢 NEW: BOOK LEVEL ACCESS BUTTON -->
2571                <button type="button" onclick="openAccessManager('book', this)" class="bg-indigo-600/30 text-indigo-300 border border-indigo-500/30 hover:bg-indigo-600 hover:text-white px-3 py-1 rounded-lg text-xs font-bold transition flex items-center gap-1.5 ml-1">
2572                    <i class="fa-solid fa-users-lock"></i> User Access
2573                </button>
2574
2575                <button type="button" onclick="openAdminMoreBookInfoModal(this)" class="bg-amber-600/30 text-amber-300 border border-amber-500/30 hover:bg-amber-600 hover:text-white px-3 py-1 rounded-lg text-xs font-bold transition flex items-center gap-1.5 ml-1">
2576                    <i class="fa-solid fa-circle-info"></i> More Book Info
2577                </button>
2578                <button type="button" onclick="removeBookRow(this)" class="bg-red-600/30 text-red-400 border border-red-500/30 hover:bg-red-600 hover:text-white px-3 py-1 rounded-lg text-xs font-bold transition flex items-center gap-1.5 ml-1">
2579                    <i class="fa-solid fa-xmark"></i> Remove
2580                </button>
2581            </div>
2582        </div>
2583
2584        <div class="grid grid-cols-1 sm:grid-cols-4 gap-3">
2585            <div>
2586                <label class="block text-[10px] font-bold text-gray-400 uppercase mb-1">Book Title *</label>
2587                <input type="text" class="book-input-title w-full p-2.5 bg-slate-900 border border-slate-700 rounded-lg text-white text-xs" value="${bookData.title || ''}" placeholder="e.g. Troy" required>
2588            </div>
2589            <div>
2590                <label class="block text-[10px] font-bold text-gray-400 uppercase mb-1">Cover Image URL *</label>
2591                <input type="url" class="book-input-cover w-full p-2.5 bg-slate-900 border border-slate-700 rounded-lg text-white text-xs" value="${bookData.coverUrl || ''}" placeholder="https://..." required>
2592            </div>
2593            <div>
2594                <label class="block text-[10px] font-bold text-gray-400 uppercase mb-1">Flipbook / PDF Link *</label>
2595                <input type="url" class="book-input-link w-full p-2.5 bg-slate-900 border border-slate-700 rounded-lg text-white text-xs" value="${bookData.bookUrl || ''}" placeholder="https://..." required>
2596            </div>
2597            <div>
2598                <label class="block text-[10px] font-bold text-gray-400 uppercase mb-1">Book Price (Optional)</label>
2599                <input type="text" class="book-input-price w-full p-2.5 bg-slate-900 border border-slate-700 rounded-lg text-amber-400 font-bold text-xs" value="${bookData.price || 'Free'}" placeholder="e.g. Free or 5,000 MMK">
2600            </div>
2601        </div>
2602    `;
2603
2604    // 🟢 Attach HTML5 Drag & Drop Event Listeners
2605    row.addEventListener('dragstart', (e) => {
2606        draggedBookRow = row;
2607        e.dataTransfer.effectAllowed = 'move';
2608        row.classList.add('opacity-40', 'border-amber-400');
2609    });
2610
2611    row.addEventListener('dragover', (e) => {
2612        e.preventDefault();
2613        e.dataTransfer.dropEffect = 'move';
2614        const targetRow = e.target.closest('.book-item-row');
2615        if (targetRow && targetRow !== draggedBookRow) {
2616            const bounding = targetRow.getBoundingClientRect();
2617            const offset = e.clientY - bounding.top - (bounding.height / 2);
2618            if (offset > 0) {
2619                container.insertBefore(draggedBookRow, targetRow.nextSibling);
2620            } else {
2621                container.insertBefore(draggedBookRow, targetRow);
2622            }
2623        }
2624    });
2625
2626    row.addEventListener('drop', (e) => {
2627        e.preventDefault();
2628        renumberBookRows();
2629    });
2630
2631    row.addEventListener('dragend', () => {
2632        row.classList.remove('opacity-40', 'border-amber-400');
2633        draggedBookRow = null;
2634        renumberBookRows();
2635    });
2636
2637    container.appendChild(row);
2638};
2639
2640// Handle Bookshelf Form Submit
2641document.addEventListener('submit', async (e) => {
2642    if (e.target && e.target.id === 'bookshelf-editor-form') {
2643        e.preventDefault();
2644
2645        const editId = document.getElementById('bs-edit-id').value;
2646        const categoryName = document.getElementById('bs-title').value.trim();
2647        const categoryDescription = document.getElementById('bs-desc').value.trim();
2648        const shelfPrice = document.getElementById('bs-price').value.trim() || 'Free';
2649        const theme = document.querySelector('input[name="bs_theme"]:checked')?.value || 'theme-oak';
2650
2651        const submitBtn = e.submitter;
2652        
2653        // 🟢 FIXED: Prevent Firebase 'undefined' crash during background auto-saves
2654        let isPublished = true; 
2655        if (submitBtn) {
2656            isPublished = (submitBtn.value === 'published');
2657        }
2658
2659        // 🟢 Get Shelf Level Access
2660        let shelfAllowedUsers = [];
2661        try { shelfAllowedUsers = JSON.parse(document.getElementById('bs-allowed-users').value || '[]'); } catch(e){}
2662
2663        // Collect Books
2664        const bookRows = document.querySelectorAll('#bs-books-container > .book-item-row');
2665        const books = [];
2666        bookRows.forEach(row => {
2667            const title = row.querySelector('.book-input-title').value.trim();
2668            const coverUrl = row.querySelector('.book-input-cover').value.trim();
2669            const bookUrl = row.querySelector('.book-input-link').value.trim();
2670            const price = row.querySelector('.book-input-price')?.value.trim() || 'Free';
2671            
2672            // 🟢 Get Book Level Access
2673            let bookAllowedUsers = [];
2674            try { bookAllowedUsers = JSON.parse(row.querySelector('.book-input-access').value || '[]'); } catch(e){}
2675
2676            let extData = {};
2677            try { extData = JSON.parse(row.getAttribute('data-ext-info') || '{}'); } catch(e) {}
2678
2679            if (title && coverUrl && bookUrl) {
2680                books.push({
2681                    title, 
2682                    coverUrl, 
2683                    bookUrl, 
2684                    price,
2685                    author: extData.author || '',
2686                    isbn: extData.isbn || '',
2687                    publishedDate: extData.publishedDate || '',
2688                    publisher: extData.publisher || '',
2689                    level: extData.level || '',
2690                    type: extData.type || '',
2691                    cefr: extData.cefr || '',
2692                    language: extData.language || 'British English',
2693                    series: extData.series || '',
2694                    formats: extData.formats || ['PDF Document'],
2695                    description: extData.description || '',
2696                    
2697                    // 🟢 Package Toggles for Database
2698                    enableDownload: extData.enableDownload || false,
2699                    enableShare: extData.enableShare || false,
2700                    allowedUsers: bookAllowedUsers // 🟢 Save book access to DB
2701                });
2702            }
2703        });
2704
2705        const docId = editId || categoryName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)+/g, '');
2706
2707        try {
2708            await db.collection("library_bookshelves").doc(docId).set({
2709                categoryName,
2710                categoryDescription,
2711                shelfPrice,
2712                theme,
2713                books,
2714                isPublished,
2715                allowedUsers: shelfAllowedUsers,
2716                collapseDesc: document.getElementById('bs-collapse-desc')?.checked || false, // 🟢 Save setting
2717                createdAt: new Date()
2718            }, { merge: true });
2719
2720            customToast("Bookshelf saved successfully!", "success");
2721            closeBookshelfEditorModal();
2722            loadAdminBookshelves();
2723        } catch(err) {
2724            customToast(err.message, "error");
2725        }
2726    }
2727});
2728
2729window.editBookshelf = function(id) {
2730    openBookshelfEditorModal(id);
2731};
2732
2733window.deleteBookshelf = async function(id) {
2734    const confirmed = await customConfirm("Delete Bookshelf", "Are you sure you want to delete this entire bookshelf?");
2735    if (confirmed) {
2736        try {
2737            await db.collection("library_bookshelves").doc(id).delete();
2738            customToast("Bookshelf deleted.", "info");
2739            loadAdminBookshelves();
2740        } catch(e) {
2741            customToast(e.message, "error");
2742        }
2743    }
2744};
2745
2746
2747// ==========================================
2748// DYNAMIC PAGE MANAGEMENT SYSTEM (With System Files & Pagination)
2749// ==========================================
2750
2751window.allPagesData = [];
2752window.currentPageStatusFilter = 'all';
2753window.currentPageManagerPage = 1;
2754window.pagesPerPage = 10;
2755
2756window.openFullscreenPageManager = function() {
2757    const existingWs = document.getElementById('admin-fullscreen-workspace');
2758    if (existingWs) existingWs.remove();
2759
2760    const workspaceHTML = `
2761    <div id="admin-fullscreen-workspace" class="fixed inset-0 z-[999999] bg-[#0b0f19] text-white flex flex-col font-sans overflow-hidden">
2762        <div class="bg-slate-950 text-gray-300 h-14 px-8 flex items-center justify-between border-b border-slate-800 shadow-xl flex-shrink-0">
2763            <div class="flex items-center gap-3">
2764                <div class="w-9 h-9 bg-emerald-600 text-white rounded-xl flex items-center justify-center font-black text-lg"><i class="fa-solid fa-file-lines"></i></div>
2765                <div>
2766                    <h2 class="font-black text-lg text-white leading-none">Page Management Panel</h2>
2767                    <p class="text-[11px] text-gray-400">View, manage, and delete custom website pages.</p>
2768                </div>
2769            </div>
2770            <div class="flex items-center gap-3">
2771                <button onclick="openPageCreatorStudio()" class="bg-emerald-600 hover:bg-emerald-500 text-white font-black px-4 py-2 rounded-xl text-xs transition shadow-lg flex items-center gap-2"><i class="fa-solid fa-wand-magic-sparkles"></i> Open Page Creator</button>
2772                <button onclick="document.getElementById('admin-fullscreen-workspace').remove(); document.body.classList.remove('overflow-hidden');" class="bg-red-600/20 text-red-400 border border-red-500/30 px-5 py-2 rounded-xl text-xs font-bold hover:bg-red-600/40 transition">✕ Close</button>
2773            </div>
2774        </div>
2775
2776        <div class="flex-1 overflow-y-auto p-6 md:p-10 pb-24 flex justify-center items-start">
2777            <div class="w-full max-w-[1280px] space-y-6">
2778                
2779                <div class="bg-[#131927] border border-slate-800 rounded-3xl p-6 md:p-8 shadow-2xl">
2780                    <div class="mb-6">
2781                        <h3 class="text-2xl font-black text-white mb-1">Page Manager</h3>
2782                        <p class="text-xs text-gray-400">Filter, search, and manage your website pages.</p>
2783                    </div>
2784
2785                    <div class="flex flex-wrap items-center gap-2 text-xs font-semibold text-gray-400 mb-6 pb-4 border-b border-slate-800/80">
2786                        <button onclick="filterPagesByStatus('all')" id="page-pill-all" class="text-blue-400 hover:text-white transition font-black underline">Total Pages - <span id="page-stat-total">0</span></button> <span class="text-slate-700">|</span>
2787                        <button onclick="filterPagesByStatus('published')" id="page-pill-pub" class="text-gray-400 hover:text-white transition font-medium">Published - <span id="page-stat-published">0</span></button> <span class="text-slate-700">|</span>
2788                        <button onclick="filterPagesByStatus('draft')" id="page-pill-draft" class="text-gray-400 hover:text-white transition font-medium">Hidden / Drafts - <span id="page-stat-drafts">0</span></button>
2789                    </div>
2790
2791                    <div class="flex flex-wrap justify-between items-center mb-6 gap-4 text-xs">
2792                        <div class="flex items-center gap-2">
2793                            <select id="page-bulk-action" class="bg-slate-950 border border-slate-700 text-white rounded-xl px-3 py-2 focus:outline-none focus:border-emerald-500 cursor-pointer">
2794                                <option value="">Bulk actions</option>
2795                                <option value="publish">Set to Public</option>
2796                                <option value="unpublish">Set to Hidden</option>
2797                                <option value="delete">Move to Trash</option>
2798                            </select>
2799                            <button onclick="executePageBulkAction()" class="bg-slate-800 hover:bg-slate-700 text-white font-bold px-4 py-2 rounded-xl transition shadow">Apply</button>
2800                        </div>
2801                        
2802                        <div class="flex items-center gap-3">
2803                            <div class="flex items-center gap-2">
2804                                <span class="text-gray-400 font-bold">Per Page:</span>
2805                                <select id="page-per-page" onchange="changePagesPerPage()" class="bg-slate-950 border border-slate-700 text-white rounded-xl px-3 py-2 focus:outline-none focus:border-emerald-500 cursor-pointer">
2806                                    <option value="10">10</option>
2807                                    <option value="20">20</option>
2808                                    <option value="50">50</option>
2809                                    <option value="100">100</option>
2810                                </select>
2811                            </div>
2812                            <input type="text" id="page-filter-search" onkeyup="renderPagesTable()" class="bg-slate-950 border border-slate-700 text-white rounded-xl px-4 py-2 text-xs focus:ring-2 focus:ring-emerald-500 focus:outline-none w-56" placeholder="Search page slugs...">
2813                        </div>
2814                    </div>
2815
2816                    <div class="overflow-x-auto">
2817                        <table class="w-full text-left text-xs border-collapse">
2818                            <thead>
2819                                <tr class="text-gray-400 font-extrabold uppercase border-b border-slate-800 pb-3">
2820                                    <th class="py-3 px-4 w-10 text-center"><input type="checkbox" id="page-cb-all" onchange="toggleAllPageCheckboxes(this)" class="w-4 h-4 rounded text-emerald-600 bg-slate-950 border-slate-600 cursor-pointer"></th>
2821                                    <th class="py-3 px-4 w-1/3">Page Slug / Name</th>
2822                                    <th class="py-3 px-4">Builder Tool</th>
2823                                    <th class="py-3 px-4 text-center">Header</th>
2824                                    <th class="py-3 px-4 text-center">Footer</th>
2825                                    <th class="py-3 px-4">Last Updated</th>
2826                                </tr>
2827                            </thead>
2828                            <tbody id="dynamic-pages-list" class="divide-y divide-slate-800/80">
2829                                <tr><td colspan="6" class="py-8 text-center text-gray-500 italic">Loading pages...</td></tr>
2830                            </tbody>
2831                        </table>
2832                    </div>
2833
2834                    <!-- Pagination Controls -->
2835                    <div class="flex flex-wrap justify-between items-center pt-6 border-t border-slate-800/80 text-xs text-gray-400 gap-4 mt-6">
2836                        <div class="flex items-center gap-2">
2837                            <span>Showing <span id="page-showing-start" class="font-bold text-white">0</span> - <span id="page-showing-end" class="font-bold text-white">0</span> of <span id="page-showing-total" class="font-bold text-white">0</span></span>
2838                        </div>
2839                        <div class="flex items-center gap-3">
2840                            <button onclick="changePageManagerPage(-1)" id="page-prev-btn" class="bg-slate-800 hover:bg-slate-700 disabled:opacity-40 disabled:cursor-not-allowed text-white font-bold px-4 py-2 rounded-xl transition shadow">‹ Prev</button>
2841                            <span class="font-bold text-white px-2">Page <span id="page-current-page" class="text-emerald-400">1</span> of <span id="page-total-pages">1</span></span>
2842                            <button onclick="changePageManagerPage(1)" id="page-next-btn" class="bg-slate-800 hover:bg-slate-700 disabled:opacity-40 disabled:cursor-not-allowed text-white font-bold px-4 py-2 rounded-xl transition shadow">Next ›</button>
2843                        </div>
2844                    </div>
2845
2846                </div>
2847            </div>
2848        </div>
2849    </div>
2850    `;
2851
2852    document.body.insertAdjacentHTML('beforeend', workspaceHTML);
2853    document.body.classList.add('overflow-hidden');
2854    window.currentPageStatusFilter = 'all'; 
2855    window.currentPageManagerPage = 1;
2856    loadAdminPages();
2857};
2858
2859window.changePagesPerPage = function() {
2860    window.pagesPerPage = parseInt(document.getElementById('page-per-page').value);
2861    window.currentPageManagerPage = 1;
2862    renderPagesTable();
2863};
2864
2865window.changePageManagerPage = function(delta) {
2866    window.currentPageManagerPage += delta;
2867    renderPagesTable();
2868};
2869
2870async function loadAdminPages() {
2871    const container = document.getElementById('dynamic-pages-list');
2872    if (!container) return;
2873
2874    window.allPagesData = [];
2875    
2876    // 🟢 1. Inject physical system HTML files from defaultPages array
2877    if (typeof defaultPages !== 'undefined') {
2878        defaultPages.forEach(p => {
2879            const slug = p.url === '/' ? 'index' : p.url.replace(/^\//, '');
2880            window.allPagesData.push({
2881                id: slug,
2882                name: p.name,
2883                isPublished: true,
2884                type: 'system',
2885                parsedDate: new Date(0), // Set older base date for system files to help sorting
2886                showHeader: true,
2887                showFooter: true
2888            });
2889        });
2890    }
2891
2892    try {
2893        // 🟢 2. Inject custom pages from Firestore
2894        const snapshot = await db.collection("site_builder_pages").get();
2895        snapshot.forEach(doc => {
2896            const data = doc.data();
2897            data.id = doc.id;
2898            data.type = 'builder';
2899            
2900            if (data.updatedAt && typeof data.updatedAt.toDate === 'function') {
2901                data.parsedDate = data.updatedAt.toDate();
2902            } else if (data.createdAt && typeof data.createdAt.toDate === 'function') {
2903                data.parsedDate = data.createdAt.toDate();
2904            } else {
2905                data.parsedDate = new Date();
2906            }
2907            
2908            data.isPublished = data.isPublished !== false; 
2909            
2910            // Prevent duplicates if builder overrides a system page
2911            if (!window.allPagesData.some(p => p.id === data.id)) {
2912                window.allPagesData.push(data);
2913            }
2914        });
2915
2916        // 🟢 FIX: Sort first by type ('builder' on top), then by newest date
2917        window.allPagesData.sort((a, b) => {
2918            if (a.type === 'builder' && b.type === 'system') return -1;
2919            if (a.type === 'system' && b.type === 'builder') return 1;
2920            return b.parsedDate - a.parsedDate;
2921        });
2922
2923        renderPagesTable();
2924
2925    } catch(e) {
2926        container.innerHTML = `<tr><td colspan="6" class="py-6 text-center text-red-500">Error loading pages: ${e.message}</td></tr>`;
2927    }
2928}
2929
2930window.filterPagesByStatus = function(status) {
2931    window.currentPageStatusFilter = status;
2932    document.getElementById('page-pill-all').className = status === 'all' ? 'text-blue-400 hover:text-white transition font-black underline' : 'text-gray-400 hover:text-white transition font-medium';
2933    document.getElementById('page-pill-pub').className = status === 'published' ? 'text-green-400 hover:text-white transition font-black underline' : 'text-gray-400 hover:text-white transition font-medium';
2934    document.getElementById('page-pill-draft').className = status === 'draft' ? 'text-amber-400 hover:text-white transition font-black underline' : 'text-gray-400 hover:text-white transition font-medium';
2935    renderPagesTable();
2936};
2937
2938window.renderPagesTable = function() {
2939    const container = document.getElementById('dynamic-pages-list');
2940    const searchFilter = document.getElementById('page-filter-search').value.toLowerCase();
2941
2942    const filteredData = window.allPagesData.filter(page => {
2943        let match = true;
2944        if (window.currentPageStatusFilter === 'published' && !page.isPublished) match = false;
2945        if (window.currentPageStatusFilter === 'draft' && page.isPublished) match = false;
2946        if (searchFilter && !page.id.toLowerCase().includes(searchFilter)) match = false;
2947        return match;
2948    });
2949
2950    // Update Top Counts
2951    let pubCount = 0, draftCount = 0;
2952    window.allPagesData.forEach(p => p.isPublished ? pubCount++ : draftCount++);
2953    document.getElementById('page-stat-total').innerText = window.allPagesData.length;
2954    document.getElementById('page-stat-published').innerText = pubCount;
2955    document.getElementById('page-stat-drafts').innerText = draftCount;
2956
2957    if (filteredData.length === 0) {
2958        container.innerHTML = `<tr><td colspan="6" class="py-8 text-center text-gray-500 italic">No pages match your filters.</td></tr>`;
2959        updatePagePaginationControls(0, 0, 0, 1);
2960        return;
2961    }
2962
2963    // Pagination Calculation
2964    const totalItems = filteredData.length;
2965    const totalPages = Math.ceil(totalItems / window.pagesPerPage);
2966    if (window.currentPageManagerPage > totalPages) window.currentPageManagerPage = totalPages;
2967    if (window.currentPageManagerPage < 1) window.currentPageManagerPage = 1;
2968
2969    const startIndex = (window.currentPageManagerPage - 1) * window.pagesPerPage;
2970    const endIndex = Math.min(startIndex + window.pagesPerPage, totalItems);
2971    const paginatedData = filteredData.slice(startIndex, endIndex);
2972
2973    let html = '';
2974    paginatedData.forEach(page => {
2975        const isSystem = page.type === 'system';
2976        const fileExt = isSystem ? '.html' : '';
2977        const titleDisplay = page.isPublished ? page.id : `${page.id} <span class="bg-amber-500/20 text-amber-400 border border-amber-500/30 text-[10px] font-black px-2 py-0.5 rounded-full uppercase ml-2">Hidden</span>`;
2978        const publishActionText = page.isPublished ? 'Hide Page' : 'Make Public';
2979        
2980        const headerIcon = page.showHeader !== false ? '<i class="fa-solid fa-check text-emerald-500"></i>' : '<i class="fa-solid fa-xmark text-gray-600"></i>';
2981        const footerIcon = page.showFooter !== false ? '<i class="fa-solid fa-check text-emerald-500"></i>' : '<i class="fa-solid fa-xmark text-gray-600"></i>';
2982
2983        const builderBadge = isSystem 
2984            ? `<span class="bg-blue-900/30 border border-blue-700 text-blue-400 px-2.5 py-1 rounded-lg text-[10px] uppercase font-bold flex items-center gap-1.5 w-max"><i class="fa-solid fa-code"></i> Core System File</span>`
2985            : `<span class="bg-slate-950 border border-slate-700 text-gray-400 px-2.5 py-1 rounded-lg text-[10px] uppercase font-bold flex items-center gap-1.5 w-max"><i class="fa-solid fa-wand-magic-sparkles text-emerald-500"></i> Creator Studio</span>`;
2986
2987        html += `
2988        <tr class="hover:bg-slate-800/40 transition group">
2989            <td class="py-4 px-4 align-top text-center">
2990                <input type="checkbox" class="page-checkbox w-4 h-4 rounded text-emerald-600 bg-slate-950 border-slate-600 cursor-pointer focus:ring-emerald-500 mt-0.5" value="${page.id}" ${isSystem ? 'disabled' : ''}>
2991            </td>
2992            <td class="py-4 px-4 align-top">
2993                <a href="${isSystem ? '/' + page.id + '.html' : '/page.html?slug=' + page.id}" target="_blank" class="font-bold text-white hover:text-emerald-400 transition block mb-1 text-sm">/${titleDisplay}${fileExt}</a>
2994                <div class="text-[11px] text-gray-500 invisible group-hover:visible flex gap-2 mt-2 font-medium transition-all">
2995                    <a href="${isSystem ? '/' + page.id + '.html' : '/page.html?slug=' + page.id}" target="_blank" class="hover:text-emerald-400 transition">View Live</a> 
2996                    ${!isSystem ? `
2997                    <span class="text-slate-700">|</span> <button onclick="togglePageStatus('${page.id}', ${page.isPublished})" class="hover:text-amber-400 transition">${publishActionText}</button> 
2998                    <span class="text-slate-700">|</span> <button onclick="deleteAdminPage('${page.id}')" class="hover:text-red-400 transition">Trash</button>` : ''}
2999                </div>
3000            </td>
3001            <td class="py-4 px-4 align-top">${builderBadge}</td>
3002            <td class="py-4 px-4 align-top text-center">${headerIcon}</td>
3003            <td class="py-4 px-4 align-top text-center">${footerIcon}</td>
3004            <td class="py-4 px-4 align-top leading-tight text-gray-400 text-[11px]">System Defaults<br><span class="text-gray-500 text-[10px]">Managed by Admin</span></td>
3005        </tr>`;
3006    });
3007    
3008    container.innerHTML = html;
3009    updatePagePaginationControls(startIndex + 1, endIndex, totalItems, totalPages);
3010};
3011
3012function updatePagePaginationControls(start, end, total, totalPages) {
3013    document.getElementById('page-showing-start').innerText = start;
3014    document.getElementById('page-showing-end').innerText = end;
3015    document.getElementById('page-showing-total').innerText = total;
3016    document.getElementById('page-current-page').innerText = window.currentPageManagerPage;
3017    document.getElementById('page-total-pages').innerText = totalPages;
3018    document.getElementById('page-prev-btn').disabled = window.currentPageManagerPage <= 1;
3019    document.getElementById('page-next-btn').disabled = window.currentPageManagerPage >= totalPages || totalPages === 0;
3020}
3021
3022window.toggleAllPageCheckboxes = function(source) {
3023    document.querySelectorAll('.page-checkbox').forEach(cb => cb.checked = source.checked);
3024};
3025
3026window.executePageBulkAction = async function() {
3027    const action = document.getElementById('page-bulk-action').value;
3028    if (!action) return alert("Please select a bulk action.");
3029
3030    const checkedBoxes = document.querySelectorAll('.page-checkbox:checked:not([disabled])');
3031    if (checkedBoxes.length === 0) return alert("Please check at least one valid custom page. System files cannot be bulk edited.");
3032
3033    const pageIds = Array.from(checkedBoxes).map(cb => cb.value);
3034
3035    if (action === 'delete') {
3036        if(!confirm(`Are you sure you want to permanently delete ${pageIds.length} custom page(s)?`)) return;
3037        try {
3038            await Promise.all(pageIds.map(id => db.collection("site_builder_pages").doc(id).delete()));
3039            if(typeof customToast === 'function') customToast(`Successfully deleted ${pageIds.length} page(s).`, "success");
3040            loadAdminPages();
3041        } catch(e) { alert("Error: " + e.message); }
3042    } else if (action === 'publish' || action === 'unpublish') {
3043        const isPub = action === 'publish';
3044        try {
3045            await Promise.all(pageIds.map(id => db.collection("site_builder_pages").doc(id).update({ isPublished: isPub })));
3046            if(typeof customToast === 'function') customToast(`Updated ${pageIds.length} page(s).`, "success");
3047            loadAdminPages();
3048        } catch(e) { alert("Error: " + e.message); }
3049    }
3050
3051    document.getElementById('page-bulk-action').value = "";
3052    document.getElementById('page-cb-all').checked = false;
3053};
3054
3055window.togglePageStatus = async function(pageId, currentState) {
3056    try {
3057        await db.collection("site_builder_pages").doc(pageId).update({ isPublished: !currentState });
3058        if(typeof customToast === 'function') customToast(!currentState ? "Page is now Public!" : "Page is now Hidden.", "success");
3059        loadAdminPages(); 
3060    } catch (e) {
3061        alert("Error: " + e.message);
3062    }
3063};
3064
3065window.deleteAdminPage = async function(pageId) {
3066    const confirmed = confirm("Are you sure you want to permanently delete this page? This cannot be undone.");
3067    if (confirmed) {
3068        try {
3069            await db.collection("site_builder_pages").doc(pageId).delete();
3070            if(typeof customToast === 'function') customToast("Page deleted.", "success");
3071            loadAdminPages();
3072        } catch (e) {
3073            alert("Error: " + e.message);
3074        }
3075    }
3076};
3077
3078
3079/* ==========================================
3080   ATVEO-STYLE COMMENT MODERATION PANEL (1280px)
3081   ========================================== */
3082
3083window.openFullscreenCommentModeration = function() {
3084    const existingWs = document.getElementById('admin-fullscreen-workspace');
3085    if (existingWs) existingWs.remove();
3086
3087    const workspaceHTML = `
3088    <div id="admin-fullscreen-workspace" class="fixed inset-0 z-[999999] bg-[#0b0f19] text-white flex flex-col font-sans overflow-hidden">
3089        
3090        <!-- Top Bar -->
3091        <div class="bg-slate-950 text-gray-300 h-14 px-8 flex items-center justify-between border-b border-slate-800 shadow-xl">
3092            <div class="flex items-center gap-3">
3093                <div class="w-9 h-9 bg-amber-500 text-slate-950 rounded-xl flex items-center justify-center font-black text-lg">
3094                    <i class="fa-solid fa-comments"></i>
3095                </div>
3096                <div>
3097                    <h2 class="font-black text-lg text-white leading-none">Comment Moderation</h2>
3098                    <p class="text-[11px] text-gray-400">Review, edit, reply, or remove community discussions.</p>
3099                </div>
3100            </div>
3101            
3102            <button onclick="document.getElementById('admin-fullscreen-workspace').remove()" class="bg-red-600/20 text-red-400 border border-red-500/30 px-5 py-2 rounded-xl text-xs font-bold hover:bg-red-600/40 transition">
3103                ✕ Close Panel
3104            </button>
3105        </div>
3106
3107        <!-- Main Panel Container (1280px Max Width) -->
3108        <div class="flex-1 overflow-y-auto p-6 md:p-10 flex justify-center">
3109            <div class="w-full max-w-[1280px] space-y-6">
3110                
3111                <!-- Comment Table Card (ATVEO Dark Theme) -->
3112                <div class="bg-[#131927] border border-slate-800 rounded-3xl p-6 md:p-8 shadow-2xl">
3113                    <div class="mb-6">
3114                        <h3 class="text-2xl font-black text-white mb-1">Comment Moderation</h3>
3115                        <p class="text-xs text-gray-400">Review, edit, reply, or remove community discussions across all website pages.</p>
3116                    </div>
3117
3118                    <!-- Table -->
3119                    <div class="overflow-x-auto">
3120                        <table class="w-full text-left text-xs border-collapse">
3121                            <thead>
3122                                <tr class="text-gray-400 font-extrabold uppercase border-b border-slate-800 pb-3">
3123                                    <th class="py-3 px-4">User Info</th>
3124                                    <th class="py-3 px-4">Page / Post</th>
3125                                    <th class="py-3 px-4">Comment & Rating</th>
3126                                    <th class="py-3 px-4">Posted Date</th>
3127                                    <th class="py-3 px-4 text-center">Action</th>
3128                                </tr>
3129                            </thead>
3130                            <tbody id="admin-comments-table-body" class="divide-y divide-slate-800/80">
3131                                <tr>
3132                                    <td colspan="5" class="py-8 text-center text-gray-400 italic">Loading comments...</td>
3133                                </tr>
3134                            </tbody>
3135                        </table>
3136                    </div>
3137                </div>
3138
3139            </div>
3140        </div>
3141    </div>
3142
3143    <!-- ADMIN WARNING MODAL (ATVEO STYLE) -->
3144    <div id="admin-warning-modal" class="fixed inset-0 z-[1000000] bg-black/80 backdrop-blur-sm hidden flex items-center justify-center p-4">
3145        <div class="bg-[#181d2a] border border-slate-800 rounded-3xl p-8 max-w-lg w-full shadow-2xl space-y-6">
3146            <h3 class="text-2xl font-black text-white text-center">Admin Warning</h3>
3147            
3148            <div class="bg-slate-900/90 border border-slate-800 p-4 rounded-2xl">
3149                <p class="text-[10px] font-extrabold text-amber-400 uppercase tracking-wider mb-1">TARGET USER:</p>
3150                <p class="text-base font-black text-white" id="warn-target-name">User Name</p>
3151                <p class="text-xs text-gray-400" id="warn-target-id">ID: USER_ID</p>
3152            </div>
3153
3154            <div>
3155                <label class="block text-xs font-bold text-gray-300 mb-2">Enter private message for this user:</label>
3156                <textarea id="warn-message-text" rows="4" placeholder="Type your warning here..." class="w-full p-4 bg-slate-950 border border-amber-500/50 rounded-2xl text-white text-sm focus:outline-none focus:border-amber-400"></textarea>
3157            </div>
3158
3159            <div class="flex gap-4">
3160                <button onclick="closeAdminWarningModal()" class="w-1/2 bg-slate-800 hover:bg-slate-700 text-gray-300 font-bold py-3.5 rounded-2xl text-xs transition">Cancel</button>
3161                <button id="send-warning-btn" class="w-1/2 bg-amber-400 hover:bg-amber-300 text-slate-950 font-black py-3.5 rounded-2xl text-xs transition shadow-lg">Send Warning</button>
3162            </div>
3163        </div>
3164    </div>
3165
3166    <!-- ADMIN REPLY MODAL -->
3167    <div id="admin-reply-modal" class="fixed inset-0 z-[1000000] bg-black/80 backdrop-blur-sm hidden flex items-center justify-center p-4">
3168        <div class="bg-[#181d2a] border border-slate-800 rounded-3xl p-8 max-w-lg w-full shadow-2xl space-y-6">
3169            <h3 class="text-2xl font-black text-white text-center">Reply to Comment</h3>
3170            
3171            <div class="bg-slate-900/90 border border-slate-800 p-4 rounded-2xl">
3172                <p class="text-[10px] font-extrabold text-blue-400 uppercase tracking-wider mb-1">USER COMMENT:</p>
3173                <p class="text-xs text-gray-300 italic" id="reply-user-comment">"Comment text..."</p>
3174            </div>
3175
3176            <div>
3177                <label class="block text-xs font-bold text-gray-300 mb-2">Type your Official Admin Reply:</label>
3178                <textarea id="reply-message-text" rows="4" placeholder="Type official reply here..." class="w-full p-4 bg-slate-950 border border-blue-500/50 rounded-2xl text-white text-sm focus:outline-none focus:border-blue-400"></textarea>
3179            </div>
3180
3181            <div class="flex gap-4">
3182                <button onclick="closeAdminReplyModal()" class="w-1/2 bg-slate-800 hover:bg-slate-700 text-gray-300 font-bold py-3.5 rounded-2xl text-xs transition">Cancel</button>
3183                <button id="send-reply-btn" class="w-1/2 bg-blue-600 hover:bg-blue-500 text-white font-black py-3.5 rounded-2xl text-xs transition shadow-lg">Post Reply</button>
3184            </div>
3185        </div>
3186    </div>
3187    `;
3188
3189    document.body.insertAdjacentHTML('beforeend', workspaceHTML);
3190    loadAdminCommentsTable();
3191};
3192
3193async function loadAdminCommentsTable() {
3194    const tableBody = document.getElementById('admin-comments-table-body');
3195    if (!tableBody) return;
3196
3197    try {
3198        const snapshot = await db.collection("site_comments").orderBy("createdAt", "desc").get();
3199        if (snapshot.empty) {
3200            tableBody.innerHTML = `<tr><td colspan="5" class="py-8 text-center text-gray-500 italic">No comments or reviews found.</td></tr>`;
3201            return;
3202        }
3203
3204        let html = '';
3205        snapshot.forEach(doc => {
3206            const c = doc.data();
3207            const commentId = doc.id;
3208
3209            let dateStr = "Recently";
3210            if (c.createdAt && typeof c.createdAt.toDate === 'function') {
3211                const d = c.createdAt.toDate();
3212                dateStr = d.toLocaleDateString('en-GB') + ', ' + d.toLocaleTimeString('en-US', { hour12: false });
3213            }
3214
3215            // Star Rating HTML
3216            let starsHtml = '';
3217            if (c.rating) {
3218                starsHtml = `<div class="text-amber-400 text-xs mb-1">` + '★'.repeat(c.rating) + '☆'.repeat(5 - c.rating) + `</div>`;
3219            }
3220
3221            // Admin Replies badge
3222            let replyBadge = '';
3223            if (c.replies && c.replies.length > 0) {
3224                replyBadge = `<div class="mt-2 pl-3 border-l-2 border-blue-500 text-[11px] text-blue-300"><strong>Admin Reply:</strong> ${c.replies[c.replies.length - 1].text}</div>`;
3225            }
3226
3227            html += `
3228            <tr class="hover:bg-slate-900/50 transition border-b border-slate-800/50">
3229                <td class="py-4 px-4 align-top">
3230                    <div class="flex items-center gap-3">
3231                        <div class="w-8 h-8 rounded-full bg-brandBlue text-white font-bold flex items-center justify-center text-xs flex-shrink-0 border border-blue-400/30">
3232                            ${(c.userName || 'User')[0].toUpperCase()}
3233                        </div>
3234                        <div>
3235                            <p class="font-bold text-white text-xs">${c.userName || 'Anonymous'}</p>
3236                            <p class="text-[10px] text-gray-400">${c.userEmail || ''}</p>
3237                        </div>
3238                    </div>
3239                </td>
3240                <td class="py-4 px-4 align-top">
3241                    <p class="font-bold text-white text-xs truncate max-w-[180px]">${c.pageTitle || 'Website Page'}</p>
3242                    <p class="text-[10px] text-blue-400 font-mono truncate max-w-[180px]">${c.pageUrl || '/'}</p>
3243                </td>
3244                <td class="py-4 px-4 align-top">
3245                    ${starsHtml}
3246                    <p class="text-gray-200 text-xs leading-relaxed max-w-sm">${c.commentText || ''}</p>
3247                    ${replyBadge}
3248                </td>
3249                <td class="py-4 px-4 align-top text-gray-400 text-xs font-mono">
3250                    ${dateStr}
3251                </td>
3252                <td class="py-4 px-4 align-top text-center">
3253                    <div class="flex items-center justify-center gap-2">
3254                        <button onclick="openAdminWarningModal('${commentId}', '${c.userName || 'User'}', '${c.userId || commentId}')" class="bg-amber-400 hover:bg-amber-300 text-slate-950 font-extrabold px-3 py-1.5 rounded-lg transition text-[11px]">
3255                            Warn
3256                        </button>
3257                        <button onclick="openAdminReplyModal('${commentId}', '${(c.commentText || '').replace(/'/g, "\\'")}')" class="bg-blue-600 hover:bg-blue-500 text-white font-extrabold px-3 py-1.5 rounded-lg transition text-[11px]">
3258                            Reply
3259                        </button>
3260                        <button onclick="deleteAdminComment('${commentId}')" class="bg-slate-800 hover:bg-red-600 text-gray-300 hover:text-white font-extrabold px-3 py-1.5 rounded-lg transition text-[11px]">
3261                            Remove
3262                        </button>
3263                    </div>
3264                </td>
3265            </tr>`;
3266        });
3267
3268        tableBody.innerHTML = html;
3269
3270    } catch(e) {
3271        tableBody.innerHTML = `<tr><td colspan="5" class="py-8 text-center text-red-400 italic">Error loading comments: ${e.message}</td></tr>`;
3272    }
3273}
3274
3275// Warn Modal Logic (Upgraded with Automated Email Dispatch)
3276let activeWarnCommentId = null;
3277window.openAdminWarningModal = function(commentId, userName, userId) {
3278    activeWarnCommentId = commentId;
3279    document.getElementById('warn-target-name').innerText = userName;
3280    document.getElementById('warn-target-id').innerText = 'ID: ' + userId;
3281    document.getElementById('warn-message-text').value = '';
3282    document.getElementById('admin-warning-modal').classList.remove('hidden');
3283
3284    document.getElementById('send-warning-btn').onclick = async () => {
3285        const msg = document.getElementById('warn-message-text').value.trim();
3286        if (!msg) return customToast("Please enter a warning message.", "error");
3287
3288        const logoUrl = "https://firebasestorage.googleapis.com/v0/b/alintagar-official-website.firebasestorage.app/o/photos%2FAlintagarlogosmall.png?alt=media&token=68c0cef0-b24c-4e40-9deb-17ebe6cfc10b";
3289
3290        try {
3291            // 1. Update comment/user status in Firestore
3292            await db.collection("site_comments").doc(activeWarnCommentId).update({
3293                status: 'warned',
3294                warningMessage: msg,
3295                warnedAt: new Date()
3296            });
3297
3298            // 2. Fetch user email to send the warning notification
3299            let userEmail = "";
3300            let targetName = userName;
3301            
3302            // Try fetching from users collection if comment contains a userId
3303            const commentDoc = await db.collection("site_comments").doc(activeWarnCommentId).get();
3304            if (commentDoc.exists) {
3305                const cData = commentDoc.data();
3306                if (cData.userEmail) userEmail = cData.userEmail;
3307                if (cData.userName) targetName = cData.userName;
3308                
3309                if (!userEmail && cData.userId) {
3310                    const uDoc = await db.collection("users").doc(cData.userId).get();
3311                    if (uDoc.exists) {
3312                        userEmail = uDoc.data().email || "";
3313                        targetName = uDoc.data().fullName || targetName;
3314                    }
3315                }
3316            }
3317
3318            // 3. Queue the Branded Warning Email
3319            if (userEmail) {
3320                await db.collection("email_queue").add({
3321                    to: userEmail,
3322                    message: {
3323                        subject: "Important Notice from Alin Tagar Administration ⚠️",
3324                        text: `Hello ${targetName},\n\nYou have received a formal warning from the Alin Tagar Administration:\n\n"${msg}"\n\nPlease ensure you follow our terms and conditions.`,
3325                        html: `
3326                        <div style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; max-width: 650px; margin: 0 auto; background-color: #ffffff; overflow: hidden;">
3327                            
3328                            <!-- Header -->
3329                            <div style="padding: 20px 10px; border-bottom: 2px solid #05396b;">
3330                                <table style="width: 100%; border-collapse: collapse;">
3331                                    <tr>
3332                                        <td style="vertical-align: middle; width: 70px;">
3333                                            <img src="${logoUrl}" alt="Alin Tagar Logo" style="height: 50px;">
3334                                        </td>
3335                                        <td style="vertical-align: middle; text-align: right;">
3336                                            <h2 style="color: #05396b; margin: 0; font-size: 18px; font-weight: 900; letter-spacing: 1px;">ALIN TAGAR</h2>
3337                                            <p style="color: #64748b; margin: 2px 0 0 0; font-size: 10px; text-transform: uppercase; letter-spacing: 1px; font-weight: bold;">Alin Tagar English Language Training School</p>
3338                                        </td>
3339                                    </tr>
3340                                </table>
3341                            </div>
3342
3343                            <!-- Body -->
3344                            <div style="padding: 30px 10px;">
3345                                <h3 style="color: #d97706; margin-top: 0; font-size: 20px; font-weight: 800;">Administrator Warning Notice ⚠️</h3>
3346                                <p style="color: #0f172a; font-size: 16px;">Hello <strong>${targetName}</strong>,</p>
3347                                <p style="color: #334155; font-size: 14px; line-height: 1.6;">You have received a formal notice regarding your recent activity or comments on the Alin Tagar platform.</p>
3348                                
3349                                <div style="background-color: #fefce8; border-left: 4px solid #f59e0b; padding: 18px; border-radius: 8px; border-top: 1px solid #fef3c7; border-right: 1px solid #fef3c7; border-bottom: 1px solid #fef3c7; margin: 20px 0; color: #78350f; font-size: 14px; line-height: 1.6; white-space: pre-wrap;"><strong>Admin Message:</strong><br>"${msg}"</div>
3350                                
3351                                <p style="color: #334155; font-size: 14px; line-height: 1.6;">Please review our community guidelines and ensure your future interactions comply with our terms and conditions. Continued violations may lead to account suspension.</p>
3352                            </div>
3353
3354                            <!-- Signature -->
3355                            <div style="padding: 0 10px 30px 10px;">
3356                                <p style="color: #333333; font-size: 14px; margin-bottom: 15px;">Best regards,</p>
3357                                <table style="width: 100%; border-collapse: collapse;">
3358                                    <tr>
3359                                        <td style="width: 90px; vertical-align: top; padding-right: 15px;">
3360                                            <img src="${logoUrl}" alt="Alin Tagar Logo" style="width: 90px; height: auto;">
3361                                        </td>
3362                                        <td style="vertical-align: top; font-size: 13px; color: #333333; line-height: 1.5;">
3363                                            <strong style="font-size: 15px; color: #000000;">Administrator</strong><br>
3364                                            CEO, Admin, Customer Relations Manager (CRM)<br>
3365                                            <strong>☎️</strong> +95 (0) 9 781 010 356<br>
3366                                            <strong>📧</strong> <a href="mailto:[email protected]" style="color: #05396b; text-decoration: none;">[email protected]</a><br>
3367                                            <strong>🌐</strong> <a href="https://alintagar.com" style="color: #05396b; text-decoration: none;">alintagar.com</a><br>
3368                                            
3369                                            <div style="margin-top: 8px;">
3370                                                <span style="background-color: #00b67a; color: white; font-size: 10px; font-weight: bold; padding: 3px 8px; border-radius: 4px; display: inline-block;">✓ Trustindex</span><br>
3371                                                <span style="color: #00b67a; font-size: 18px; letter-spacing: 2px;">★★★★★</span><br>
3372                                                <span style="font-size: 12px; font-weight: bold; color: #000000;">40 reviews</span>
3373                                            </div>
3374                                        </td>
3375                                    </tr>
3376                                </table>
3377                                
3378                                <div style="margin-top: 30px; font-size: 10px; color: #777777; line-height: 1.5; text-align: justify; border-top: 1px solid #e2e8f0; padding-top: 15px;">
3379                                    <p style="margin-bottom: 8px;">Please do not print this e-mail unless it is necessary. Every unprinted e-mail helps the environment.</p>
3380                                    <p style="margin: 0;">This e-mail and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. Please notify the sender immediately by e-mail if you have received this e-mail by mistake and delete this e-mail from your system. If you are not the intended recipient you are notified that disclosing, copying, distributing or taking any action in reliance on the contents of this information is strictly prohibited.</p>
3381                                </div>
3382                            </div>
3383                        </div>`
3384                    },
3385                    status: "queued",
3386                    createdAt: new Date()
3387                });
3388            }
3389
3390            customToast(`Warning sent to ${userName}!`, "success");
3391            closeAdminWarningModal();
3392            loadAdminCommentsTable();
3393        } catch(e) {
3394            customToast(e.message, "error");
3395        }
3396    };
3397};
3398
3399window.closeAdminWarningModal = function() {
3400    document.getElementById('admin-warning-modal').classList.add('hidden');
3401};
3402
3403// Reply Modal Logic
3404let activeReplyCommentId = null;
3405window.openAdminReplyModal = function(commentId, commentText) {
3406    activeReplyCommentId = commentId;
3407    document.getElementById('reply-user-comment').innerText = `"${commentText}"`;
3408    document.getElementById('reply-message-text').value = '';
3409    document.getElementById('admin-reply-modal').classList.remove('hidden');
3410
3411    document.getElementById('send-reply-btn').onclick = async () => {
3412        const replyMsg = document.getElementById('reply-message-text').value.trim();
3413        if (!replyMsg) return customToast("Please enter a reply message.", "error");
3414
3415        // 🟢 FIXED: Declared BEFORE calling update()
3416        const currentAdminName = (auth.currentUser && auth.currentUser.displayName) 
3417            ? `${auth.currentUser.displayName} (Admin)` 
3418            : 'School Admin';
3419
3420        try {
3421            await db.collection("site_comments").doc(activeReplyCommentId).update({
3422                replies: firebase.firestore.FieldValue.arrayUnion({
3423                    adminName: currentAdminName,
3424                    text: replyMsg,
3425                    date: new Date().toLocaleDateString('en-GB')
3426                })
3427            });
3428            customToast("Official reply posted!", "success");
3429            closeAdminReplyModal();
3430            loadAdminCommentsTable();
3431        } catch(e) {
3432            customToast(e.message, "error");
3433        }
3434    };
3435};
3436
3437window.closeAdminReplyModal = function() {
3438    document.getElementById('admin-reply-modal').classList.add('hidden');
3439};
3440
3441// Remove Comment Logic
3442window.deleteAdminComment = async function(commentId) {
3443    const confirmed = await customConfirm("Delete Comment", "Are you sure you want to delete this comment forever?");
3444    if (confirmed) {
3445        try {
3446            await db.collection("site_comments").doc(commentId).delete();
3447            customToast("Comment removed.", "success");
3448            loadAdminCommentsTable();
3449        } catch(e) {
3450            customToast(e.message, "error");
3451        }
3452    }
3453};
3454
3455/* ==========================================
3456   ATVEO-STYLE COMMENT MODERATION PANEL
3457   ========================================== */
3458
3459window.openFullscreenCommentModeration = function() {
3460    const existingWs = document.getElementById('admin-fullscreen-workspace');
3461    if (existingWs) existingWs.remove();
3462
3463    const workspaceHTML = `
3464    <div id="admin-fullscreen-workspace" class="fixed inset-0 z-[999999] bg-[#0b0f19] text-white flex flex-col font-sans overflow-hidden">
3465        
3466        <div class="bg-slate-950 text-gray-300 h-14 px-8 flex items-center justify-between border-b border-slate-800 shadow-xl">
3467            <div class="flex items-center gap-3">
3468                <div class="w-9 h-9 bg-amber-500 text-slate-950 rounded-xl flex items-center justify-center font-black text-lg">
3469                    <i class="fa-solid fa-comments"></i>
3470                </div>
3471                <div>
3472                    <h2 class="font-black text-lg text-white leading-none">Comment Moderation</h2>
3473                    <p class="text-[11px] text-gray-400">Review, edit, approve, or remove community discussions.</p>
3474                </div>
3475            </div>
3476            
3477            <button onclick="document.getElementById('admin-fullscreen-workspace').remove()" class="bg-red-600/20 text-red-400 border border-red-500/30 px-5 py-2 rounded-xl text-xs font-bold hover:bg-red-600/40 transition">
3478                ✕ Close Panel
3479            </button>
3480        </div>
3481
3482        <div class="flex-1 overflow-y-auto p-6 md:p-10 flex justify-center">
3483            <div class="w-full max-w-[1280px] space-y-6">
3484                <div class="bg-[#131927] border border-slate-800 rounded-3xl p-6 md:p-8 shadow-2xl">
3485                    <div class="mb-6 flex justify-between items-center">
3486                        <div>
3487                            <h3 class="text-2xl font-black text-white mb-1">Comment Moderation Panel</h3>
3488                            <p class="text-xs text-gray-400">Approve pending reviews to publish them live to your website.</p>
3489                        </div>
3490                    </div>
3491
3492                    <div class="overflow-x-auto">
3493                        <table class="w-full text-left text-xs border-collapse">
3494                            <thead>
3495                                <tr class="text-gray-400 font-extrabold uppercase border-b border-slate-800 pb-3">
3496                                    <th class="py-3 px-4">User Info</th>
3497                                    <th class="py-3 px-4">Page / Post</th>
3498                                    <th class="py-3 px-4">Comment & Rating</th>
3499                                    <th class="py-3 px-4">Status</th>
3500                                    <th class="py-3 px-4">Posted Date</th>
3501                                    <th class="py-3 px-4 text-center">Action</th>
3502                                </tr>
3503                            </thead>
3504                            <tbody id="admin-comments-table-body" class="divide-y divide-slate-800/80">
3505                                <tr>
3506                                    <td colspan="6" class="py-8 text-center text-gray-400 italic">Loading comments...</td>
3507                                </tr>
3508                            </tbody>
3509                        </table>
3510                    </div>
3511                </div>
3512            </div>
3513        </div>
3514    </div>
3515
3516    <!-- ADMIN WARNING MODAL -->
3517    <div id="admin-warning-modal" class="fixed inset-0 z-[1000000] bg-black/80 backdrop-blur-sm hidden flex items-center justify-center p-4">
3518        <div class="bg-[#181d2a] border border-slate-800 rounded-3xl p-8 max-w-lg w-full shadow-2xl space-y-6">
3519            <h3 class="text-2xl font-black text-white text-center">Admin Warning</h3>
3520            <div class="bg-slate-900/90 border border-slate-800 p-4 rounded-2xl">
3521                <p class="text-[10px] font-extrabold text-amber-400 uppercase tracking-wider mb-1">TARGET USER:</p>
3522                <p class="text-base font-black text-white" id="warn-target-name">User Name</p>
3523                <p class="text-xs text-gray-400" id="warn-target-id">
3523ID: USER_ID</p>
3524            </div>
3525            <div>
3526                <label class="block text-xs font-bold text-gray-300 mb-2">Enter private message for this user:</label>
3527                <textarea id="warn-message-text" rows="4" placeholder="Type your warning here..." class="w-full p-4 bg-slate-950 border border-amber-500/50 rounded-2xl text-white text-sm focus:outline-none focus:border-amber-400"></textarea>
3528            </div>
3529            <div class="flex gap-4">
3530                <button onclick="closeAdminWarningModal()" class="w-1/2 bg-slate-800 hover:bg-slate-700 text-gray-300 font-bold py-3.5 rounded-2xl text-xs transition">Cancel</button>
3531                <button id="send-warning-btn" class="w-1/2 bg-amber-400 hover:bg-amber-300 text-slate-950 font-black py-3.5 rounded-2xl text-xs transition shadow-lg">Send Warning</button>
3532            </div>
3533        </div>
3534    </div>
3535
3536    <!-- ADMIN REPLY MODAL -->
3537    <div id="admin-reply-modal" class="fixed inset-0 z-[1000000] bg-black/80 backdrop-blur-sm hidden flex items-center justify-center p-4">
3538        <div class="bg-[#181d2a] border border-slate-800 rounded-3xl p-8 max-w-lg w-full shadow-2xl space-y-6">
3539            <h3 class="text-2xl font-black text-white text-center">Reply to Comment</h3>
3540            <div class="bg-slate-900/90 border border-slate-800 p-4 rounded-2xl">
3541                <p class="text-[10px] font-extrabold text-blue-400 uppercase tracking-wider mb-1">USER COMMENT:</p>
3542                <p class="text-xs text-gray-300 italic" id="reply-user-comment">"Comment text..."</p>
3543            </div>
3544            <div>
3545                <label class="block text-xs font-bold text-gray-300 mb-2">Type your Official Admin Reply:</label>
3546                <textarea id="reply-message-text" rows="4" placeholder="Type official reply here..." class="w-full p-4 bg-slate-950 border border-blue-500/50 rounded-2xl text-white text-sm focus:outline-none focus:border-blue-400"></textarea>
3547            </div>
3548            <div class="flex gap-4">
3549                <button onclick="closeAdminReplyModal()" class="w-1/2 bg-slate-800 hover:bg-slate-700 text-gray-300 font-bold py-3.5 rounded-2xl text-xs transition">Cancel</button>
3550                <button id="send-reply-btn" class="w-1/2 bg-blue-600 hover:bg-blue-500 text-white font-black py-3.5 rounded-2xl text-xs transition shadow-lg">Post Reply</button>
3551            </div>
3552        </div>
3553    </div>
3554    `;
3555
3556    document.body.insertAdjacentHTML('beforeend', workspaceHTML);
3557    loadAdminCommentsTable();
3558};
3559
3560async function loadAdminCommentsTable() {
3561    const tableBody = document.getElementById('admin-comments-table-body');
3562    if (!tableBody) return;
3563
3564    try {
3565        const snapshot = await db.collection("site_comments").orderBy("createdAt", "desc").get();
3566        if (snapshot.empty) {
3567            tableBody.innerHTML = `<tr><td colspan="6" class="py-8 text-center text-gray-500 italic">No comments found.</td></tr>`;
3568            return;
3569        }
3570
3571        let html = '';
3572        snapshot.forEach(doc => {
3573            const c = doc.data();
3574            const commentId = doc.id;
3575
3576            let dateStr = "Recently";
3577            if (c.createdAt && typeof c.createdAt.toDate === 'function') {
3578                const d = c.createdAt.toDate();
3579                dateStr = d.toLocaleDateString('en-GB') + ', ' + d.toLocaleTimeString('en-US', { hour12: false });
3580            }
3581
3582            let starsHtml = '';
3583            if (c.rating) {
3584                starsHtml = `<div class="text-amber-400 text-xs mb-1">` + '★'.repeat(c.rating) + '☆'.repeat(5 - c.rating) + `</div>`;
3585            }
3586
3587            let replyBadge = '';
3588            if (c.replies && c.replies.length > 0) {
3589                replyBadge = `<div class="mt-2 pl-3 border-l-2 border-blue-500 text-[11px] text-blue-300"><strong>Admin Reply:</strong> ${c.replies[c.replies.length - 1].text}</div>`;
3590            }
3591
3592            // Status Badge
3593            const isApproved = c.status === 'approved';
3594            const statusBadge = isApproved 
3595                ? `<span class="bg-green-500/20 text-green-400 border border-green-500/30 text-[10px] font-black px-2.5 py-1 rounded-full uppercase">Approved</span>`
3596                : `<span class="bg-amber-500/20 text-amber-400 border border-amber-500/30 text-[10px] font-black px-2.5 py-1 rounded-full uppercase animate-pulse">Pending</span>`;
3597
3598            html += `
3599            <tr class="hover:bg-slate-900/50 transition border-b border-slate-800/50">
3600                <td class="py-4 px-4 align-top">
3601                    <div class="flex items-center gap-3">
3602                        <div class="w-8 h-8 rounded-full bg-brandBlue text-white font-bold flex items-center justify-center text-xs flex-shrink-0 border border-blue-400/30">
3603                            ${(c.userName || 'U')[0].toUpperCase()}
3604                        </div>
3605                        <div>
3606                            <!-- 🟢 USER FULL NAME -->
3607                            <p class="font-bold text-white text-xs">${c.userName || 'Anonymous'}</p>
3608                            <p class="text-[10px] text-gray-400">${c.userEmail || ''}</p>
3609                        </div>
3610                    </div>
3611                </td>
3612                <td class="py-4 px-4 align-top">
3613                    <p class="font-bold text-white text-xs truncate max-w-[180px]">${c.pageTitle || 'Website Page'}</p>
3614                    <p class="text-[10px] text-blue-400 font-mono truncate max-w-[180px]">${c.pageUrl || '/'}</p>
3615                </td>
3616                <td class="py-4 px-4 align-top">
3617                    ${starsHtml}
3618                    <p class="text-gray-200 text-xs leading-relaxed max-w-sm">${c.commentText || ''}</p>
3619                    ${replyBadge}
3620                </td>
3621                <td class="py-4 px-4 align-top">
3622                    ${statusBadge}
3623                </td>
3624                <td class="py-4 px-4 align-top text-gray-400 text-xs font-mono">
3625                    ${dateStr}
3626                </td>
3627                <td class="py-4 px-4 align-top text-center">
3628                    <div class="flex items-center justify-center gap-2">
3629                        <!-- 🟢 APPROVE BUTTON -->
3630                        ${!isApproved ? `<button onclick="approveAdminComment('${commentId}')" class="bg-green-600 hover:bg-green-500 text-white font-extrabold px-3 py-1.5 rounded-lg transition text-[11px]">✓ Approve</button>` : ''}
3631                        
3632                        <button onclick="openAdminReplyModal('${commentId}', '${(c.commentText || '').replace(/'/g, "\\'")}')" class="bg-blue-600 hover:bg-blue-500 text-white font-extrabold px-3 py-1.5 rounded-lg transition text-[11px]">
3633                            Reply
3634                        </button>
3635                        <button onclick="openAdminWarningModal('${commentId}', '${c.userName || 'User'}', '${c.userId || commentId}')" class="bg-amber-400 hover:bg-amber-300 text-slate-950 font-extrabold px-3 py-1.5 rounded-lg transition text-[11px]">
3636                            Warn
3637                        </button>
3638                        <button onclick="deleteAdminComment('${commentId}')" class="bg-slate-800 hover:bg-red-600 text-gray-300 hover:text-white font-extrabold px-3 py-1.5 rounded-lg transition text-[11px]">
3639                            Remove
3640                        </button>
3641                    </div>
3642                </td>
3643            </tr>`;
3644        });
3645
3646        tableBody.innerHTML = html;
3647
3648    } catch(e) {
3649        tableBody.innerHTML = `<tr><td colspan="6" class="py-8 text-center text-red-400 italic">Error loading comments: ${e.message}</td></tr>`;
3650    }
3651}
3652
3653// 🟢 ADMIN APPROVE COMMENT ACTION
3654window.approveAdminComment = async function(commentId) {
3655    try {
3656        await db.collection("site_comments").doc(commentId).update({
3657            status: 'approved',
3658            approvedAt: new Date()
3659        });
3660        customToast("Comment Approved & Published Live!", "success");
3661        loadAdminCommentsTable();
3662    } catch(e) {
3663        customToast(e.message, "error");
3664    }
3665};
3666
3667/* ==========================================
3668   ADVANCED LIVE PAGE BUILDER ENGINE (V6 - CUSTOM MODALS)
3669   ========================================== */
3670
3671let savedSelectionRange = null;
3672let currentSelectedBlock = null;
3673
3674// HISTORY STACK FOR UNDO / REDO
3675let historyStack = [];
3676let historyIndex = -1;
3677let isSnapshotSuppressed = false;
3678
3679function saveHistorySnapshot() {
3680    if (isSnapshotSuppressed) return;
3681    const wrapper = document.getElementById('live-editable-content');
3682    if (!wrapper) return;
3683
3684    const currentHTML = wrapper.innerHTML;
3685
3686    if (historyStack[historyIndex] === currentHTML) return;
3687
3688    if (historyIndex < historyStack.length - 1) {
3689        historyStack = historyStack.slice(0, historyIndex + 1);
3690    }
3691
3692    historyStack.push(currentHTML);
3693    historyIndex++;
3694
3695    if (historyStack.length > 30) {
3696        historyStack.shift();
3697        historyIndex--;
3698    }
3699}
3700
3701window.undo = function() {
3702    if (historyIndex > 0) {
3703        isSnapshotSuppressed = true;
3704        historyIndex--;
3705        const wrapper = document.getElementById('live-editable-content');
3706        wrapper.innerHTML = historyStack[historyIndex];
3707        isSnapshotSuppressed = false;
3708        customToast("Undo ⏪", "info");
3709    } else {
3710        customToast("Nothing to undo", "info");
3711    }
3712};
3713
3714window.redo = function() {
3715    if (historyIndex < historyStack.length - 1) {
3716        isSnapshotSuppressed = true;
3717        historyIndex++;
3718        const wrapper = document.getElementById('live-editable-content');
3719        wrapper.innerHTML = historyStack[historyIndex];
3720        isSnapshotSuppressed = false;
3721        customToast("Redo ⏩", "info");
3722    } else {
3723        customToast("Nothing to redo", "info");
3724    }
3725};
3726
3727// KEYBOARD SHORTCUTS (Ctrl+Z, Ctrl+Shift+Z, Ctrl+Y)
3728document.addEventListener('keydown', (e) => {
3729    if (!document.getElementById('live-edit-toolbar')) return;
3730
3731    const isCtrlOrCmd = e.ctrlKey || e.metaKey;
3732    if (isCtrlOrCmd) {
3733        if (e.key.toLowerCase() === 'z') {
3734            e.preventDefault();
3735            if (e.shiftKey) {
3736                redo();
3737            } else {
3738                undo();
3739            }
3740        } else if (e.key.toLowerCase() === 'y') {
3741            e.preventDefault();
3742            redo();
3743        }
3744    }
3745});
3746
3747document.addEventListener('selectionchange', () => {
3748    const sel = window.getSelection();
3749    const wrapper = document.getElementById('live-editable-content');
3750    if (sel.rangeCount > 0 && wrapper && wrapper.contains(sel.anchorNode)) {
3751        savedSelectionRange = sel.getRangeAt(0);
3752    }
3753});
3754
3755let preventLinkClick = function(e) { e.preventDefault(); };
3756
3757window.enableLiveEditMode = function() {
3758    const drawer = document.getElementById('admin-sidebar-drawer');
3759    if (drawer) drawer.classList.add('translate-x-full');
3760
3761    const wrapper = document.getElementById('live-editable-content');
3762    if (!wrapper) {
3763        customToast("Error: Missing <main id='live-editable-content'> wrapper on this page.", "error");
3764        return;
3765    }
3766
3767    historyStack = [];
3768    historyIndex = -1;
3769
3770    // 1. Make Text Editable
3771    const textElements = wrapper.querySelectorAll('h1, h2, h3, h4, p, span, li, a, button');
3772    textElements.forEach(el => {
3773        el.contentEditable = "true";
3774        el.style.outline = "2px dashed #f59e0b"; // Amber outline
3775        el.style.outlineOffset = "2px";
3776        el.style.cursor = "text";
3777        
3778        if(el.tagName === 'A') {
3779            el.title = "Edit text, or double-click to edit URL";
3780            el.addEventListener('click', preventLinkClick);
3781            el.ondblclick = async (e) => { 
3782                e.preventDefault();
3783                const newUrl = await customPrompt("Update Link URL", "Enter destination web address:", el.href);
3784                if(newUrl !== null) {
3785                    el.href = newUrl;
3786                    saveHistorySnapshot();
3787                }
3788            };
3789        }
3790    });
3791
3792    // 2. Make Images Editable
3793    const images = wrapper.querySelectorAll('img');
3794    images.forEach(img => {
3795        img.style.outline = "3px dashed #3b82f6"; // Blue outline
3796        img.style.cursor = "pointer";
3797        img.title = "Double-click to replace image URL";
3798        img.ondblclick = async (e) => {
3799            e.preventDefault();
3800            const newUrl = await customPrompt("Update Image URL", "Enter new image web address:", img.src);
3801            if(newUrl) {
3802                img.src = newUrl;
3803                saveHistorySnapshot();
3804            }
3805        };
3806    });
3807
3808    // 3. YouTube iFrames Overlay
3809    const iframes = wrapper.querySelectorAll('iframe');
3810    iframes.forEach(iframe => {
3811        if(window.getComputedStyle(iframe.parentElement).position === 'static') {
3812            iframe.parentElement.style.position = 'relative';
3813        }
3814        const overlay = document.createElement('div');
3815        overlay.className = 'iframe-edit-overlay absolute inset-0 bg-blue-500/40 flex items-center justify-center cursor-pointer border-4 border-dashed border-blue-500 z-40 rounded-xl';
3816        overlay.innerHTML = '<span class="bg-blue-900 text-white font-bold px-4 py-2 rounded-full shadow-lg"><i class="fa-brands fa-youtube mr-2"></i>Double-click to Change Video</span>';
3817        
3818        overlay.ondblclick = async () => {
3819            const newUrl = await customPrompt("Update Video URL", "Enter new YouTube embed URL:", iframe.src);
3820            if(newUrl) {
3821                iframe.src = newUrl;
3822                saveHistorySnapshot();
3823            }
3824        };
3825        iframe.parentElement.appendChild(overlay);
3826    });
3827
3828    // 4. INJECT SECTION CONTROL BADGES
3829    const sections = wrapper.querySelectorAll('section, article');
3830    sections.forEach((sec, idx) => {
3831        if (window.getComputedStyle(sec).position === 'static') {
3832            sec.style.position = 'relative';
3833        }
3834        
3835        sec.style.outline = '3px dashed #8b5cf6'; // Purple dashed outline
3836        sec.style.outlineOffset = '-3px';
3837
3838        const badge = document.createElement('div');
3839        badge.className = 'live-section-badge absolute top-3 left-3 z-[60] bg-slate-900/90 text-white text-xs font-bold px-3 py-1.5 rounded-xl shadow-2xl backdrop-blur border border-slate-700 flex items-center gap-2 select-none';
3840        badge.innerHTML = `
3841            <span class="text-amber-400 font-extrabold flex items-center gap-1">
3842                <i class="fa-solid fa-layer-group"></i> Section ${idx + 1}
3843            </span>
3844            <div class="h-3 w-[1px] bg-slate-700 mx-1"></div>
3845            <button onclick="event.stopPropagation(); moveSection(this, -1)" class="hover:text-amber-400 p-1" title="Move Section Up"><i class="fa-solid fa-arrow-up"></i></button>
3846            <button onclick="event.stopPropagation(); moveSection(this, 1)" class="hover:text-amber-400 p-1" title="Move Section Down"><i class="fa-solid fa-arrow-down"></i></button>
3847            <button onclick="event.stopPropagation(); deleteSection(this)" class="hover:text-red-400 p-1 ml-1" title="Delete Section"><i class="fa-solid fa-trash-can"></i></button>
3848        `;
3849        sec.appendChild(badge);
3850    });
3851
3852    // 5. INNER BLOCK SELECTION
3853    wrapper.addEventListener('click', function(e) {
3854        if (e.target.closest('.live-section-badge') || e.target.closest('.iframe-edit-overlay')) return;
3855
3856        const target = e.target.closest('section, article, img, a, .grid > div, .flex > div');
3857        
3858        if (target && target !== wrapper) {
3859            deselectBlock(); 
3860            currentSelectedBlock = target;
3861            currentSelectedBlock.style.outline = '4px solid #a855f7'; 
3862            currentSelectedBlock.style.outlineOffset = '-4px';
3863        } else {
3864            deselectBlock(); 
3865        }
3866    });
3867
3868    // Debounce Typing Input to Save History Snapshots
3869    let typingTimer = null;
3870    wrapper.addEventListener('input', () => {
3871        clearTimeout(typingTimer);
3872        typingTimer = setTimeout(() => {
3873            saveHistorySnapshot();
3874        }, 500);
3875    });
3876
3877    saveHistorySnapshot();
3878
3879    // 6. Inject Floating Toolbar
3880    if(!document.getElementById('live-edit-toolbar')) {
3881        const toolbar = document.createElement('div');
3882        toolbar.id = "live-edit-toolbar";
3883        toolbar.style.cssText = "position: fixed; top: 80px; left: 20px; z-index: 10000; width: 64px;";
3884        toolbar.className = "bg-slate-900 text-white rounded-2xl shadow-2xl border border-slate-700 flex flex-col items-center py-3 overflow-hidden select-none";
3885        
3886        toolbar.innerHTML = `
3887            <!-- Drag Handle -->
3888            <div id="drag-handle" class="w-full text-center cursor-grab active:cursor-grabbing text-gray-500 hover:text-white pb-3 border-b border-slate-800 mb-2" title="Drag to move panel">
3889                <i class="fa-solid fa-grip-lines text-xl"></i>
3890            </div>
3891            
3892            <!-- History Tools -->
3893            <div class="flex flex-col gap-1 w-full px-2 mb-2 border-b border-slate-800 pb-2">
3894                <button onclick="undo()" class="w-10 h-10 flex items-center justify-center text-gray-400 hover:bg-slate-800 hover:text-amber-400 rounded-xl transition" title="Undo (Ctrl+Z)"><i class="fa-solid fa-rotate-left"></i></button>
3895                <button onclick="redo()" class="w-10 h-10 flex items-center justify-center text-gray-400 hover:bg-slate-800 hover:text-amber-400 rounded-xl transition" title="Redo (Ctrl+Shift+Z / Ctrl+Y)"><i class="fa-solid fa-rotate-right"></i></button>
3896            </div>
3897
3898            <!-- Text Formatting Tools -->
3899            <div class="flex flex-col gap-1 w-full px-2 mb-2 border-b border-slate-800 pb-2">
3900                <button onmousedown="event.preventDefault(); document.execCommand('bold'); saveHistorySnapshot();" class="w-10 h-10 flex items-center justify-center text-gray-300 hover:bg-slate-800 hover:text-amber-400 rounded-xl transition" title="Bold"><i class="fa-solid fa-bold"></i></button>
3901                <button onmousedown="event.preventDefault(); document.execCommand('italic'); saveHistorySnapshot();" class="w-10 h-10 flex items-center justify-center text-gray-300 hover:bg-slate-800 hover:text-amber-400 rounded-xl transition" title="Italic"><i class="fa-solid fa-italic"></i></button>
3902                <button onmousedown="event.preventDefault(); document.execCommand('insertUnorderedList'); saveHistorySnapshot();" class="w-10 h-10 flex items-center justify-center text-gray-300 hover:bg-slate-800 hover:text-amber-400 rounded-xl transition" title="Bullet List"><i class="fa-solid fa-list-ul"></i></button>
3903                
3904                <!-- Color Picker -->
3905                <div class="relative w-10 h-10 flex items-center justify-center hover:bg-slate-800 rounded-xl transition cursor-pointer" title="Change Text Color">
3906                    <i class="fa-solid fa-palette text-amber-400 absolute pointer-events-none"></i>
3907                    <input type="color" id="text-color-picker" class="opacity-0 w-full h-full cursor-pointer">
3908                </div>
3909            </div>
3910
3911            <!-- Inner Element Actions -->
3912            <div class="flex flex-col gap-1 w-full px-2 mb-3 border-b border-slate-800 pb-2">
3913                <button onclick="deselectBlock()" class="w-10 h-10 flex items-center justify-center text-gray-400 hover:bg-slate-800 hover:text-white rounded-xl transition" title="Deselect Item"><i class="fa-regular fa-square"></i></button>
3914                <button onclick="moveSelectedBlock(-1)" class="w-10 h-10 flex items-center justify-center text-blue-400 hover:bg-blue-900/50 rounded-xl transition" title="Move Selected Item UP"><i class="fa-solid fa-arrow-up"></i></button>
3915                <button onclick="moveSelectedBlock(1)" class="w-10 h-10 flex items-center justify-center text-blue-400 hover:bg-blue-900/50 rounded-xl transition" title="Move Selected Item DOWN"><i class="fa-solid fa-arrow-down"></i></button>
3916                <button onclick="deleteSelectedBlock()" class="w-10 h-10 flex items-center justify-center text-red-500 hover:bg-red-900/50 rounded-xl transition" title="Delete Selected Item">
3916<i class="fa-solid fa-trash-can"></i></button>
3917            </div>
3918            
3919            <!-- Save / Cancel Actions -->
3920            <div class="flex flex-col gap-2 w-full px-2 mt-1">
3921                <button onclick="saveLiveEdits()" class="w-10 h-10 flex items-center justify-center bg-green-600 hover:bg-green-500 rounded-xl shadow-lg transition" title="Save Changes to Firebase">
3922                    <i class="fa-solid fa-cloud-arrow-up text-white"></i>
3923                </button>
3924                <button onclick="cancelLiveEdits()" class="w-10 h-10 flex items-center justify-center bg-red-600/20 text-red-400 hover:bg-red-600/40 rounded-xl transition" title="Cancel & Exit">
3925                    <i class="fa-solid fa-xmark text-lg"></i>
3926                </button>
3927            </div>
3928        `;
3929        document.body.appendChild(toolbar);
3930
3931        // Color Picker Event
3932        document.getElementById('text-color-picker').addEventListener('change', (e) => {
3933            if (savedSelectionRange) {
3934                const sel = window.getSelection();
3935                sel.removeAllRanges();
3936                sel.addRange(savedSelectionRange);
3937                document.execCommand('foreColor', false, e.target.value);
3938                saveHistorySnapshot();
3939            }
3940        });
3941
3942        // Make Panel Draggable
3943        dragElement(toolbar);
3944    }
3945    
3946    customToast("Live Edit Mode Activated!", "success");
3947};
3948
3949/* --- SECTION BADGE FUNCTIONS --- */
3950window.moveSection = function(btn, direction) {
3951    const sec = btn.closest('section, article');
3952    if (!sec) return;
3953    const parent = sec.parentNode;
3954    
3955    if (direction === -1 && sec.previousElementSibling) { 
3956        parent.insertBefore(sec, sec.previousElementSibling);
3957        sec.scrollIntoView({ behavior: 'smooth', block: 'center' });
3958        saveHistorySnapshot();
3959        customToast("Section moved UP", "success");
3960    } else if (direction === 1 && sec.nextElementSibling) { 
3961        parent.insertBefore(sec.nextElementSibling, sec);
3962        sec.scrollIntoView({ behavior: 'smooth', block: 'center' });
3963        saveHistorySnapshot();
3964        customToast("Section moved DOWN", "success");
3965    } else {
3966        customToast("Cannot move section further.", "info");
3967    }
3968};
3969
3970window.deleteSection = async function(btn) {
3971    const sec = btn.closest('section, article');
3972    if (!sec) return;
3973    const confirmed = await customConfirm("Delete Section", "Are you sure you want to delete this ENTIRE section?");
3974    if (confirmed) {
3975        sec.remove();
3976        saveHistorySnapshot();
3977        customToast("Section deleted.", "success");
3978    }
3979};
3980
3981/* --- INNER BLOCK FUNCTIONS --- */
3982window.deselectBlock = function() {
3983    if (currentSelectedBlock) {
3984        currentSelectedBlock.style.outline = '';
3985        currentSelectedBlock.style.outlineOffset = '';
3986        currentSelectedBlock = null;
3987    }
3988};
3989
3990window.moveSelectedBlock = function(direction) {
3991    if(!currentSelectedBlock) return customToast("Click an item to select it first!", "info");
3992    
3993    const parent = currentSelectedBlock.parentNode;
3994    if (direction === -1 && currentSelectedBlock.previousElementSibling) {
3995        parent.insertBefore(currentSelectedBlock, currentSelectedBlock.previousElementSibling);
3996        currentSelectedBlock.scrollIntoView({behavior: "smooth", block: "center"});
3997        saveHistorySnapshot();
3998    } else if (direction === 1 && currentSelectedBlock.nextElementSibling) {
3999        parent.insertBefore(currentSelectedBlock.nextElementSibling, currentSelectedBlock);
4000        currentSelectedBlock.scrollIntoView({behavior: "smooth", block: "center"});
4001        saveHistorySnapshot();
4002    } else {
4003        customToast("Cannot move any further.", "info");
4004    }
4005};
4006
4007window.deleteSelectedBlock = async function() {
4008    if(!currentSelectedBlock) return customToast("Click an item to select it first!", "info");
4009    const confirmed = await customConfirm("Delete Element", "Are you sure you want to delete this element?");
4010    if (confirmed) {
4011        currentSelectedBlock.remove();
4012        currentSelectedBlock = null;
4013        saveHistorySnapshot();
4014        customToast("Element deleted.", "success");
4015    }
4016};
4017
4018window.cancelLiveEdits = async function() {
4019    const confirmed = await customConfirm("Cancel Live Editing", "Discard all unsaved changes and exit edit mode?");
4020    if (confirmed) {
4021        window.location.reload();
4022    }
4023};
4024
4025// Panel Draggable Logic
4026function dragElement(elmnt) {
4027    let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
4028    document.getElementById("drag-handle").onmousedown = dragMouseDown;
4029
4030    function dragMouseDown(e) {
4031        e.preventDefault();
4032        pos3 = e.clientX;
4033        pos4 = e.clientY;
4034        document.onmouseup = closeDragElement;
4035        document.onmousemove = elementDrag;
4036    }
4037
4038    function elementDrag(e) {
4039        e.preventDefault();
4040        pos1 = pos3 - e.clientX;
4041        pos2 = pos4 - e.clientY;
4042        pos3 = e.clientX;
4043        pos4 = e.clientY;
4044        
4045        let newTop = elmnt.offsetTop - pos2;
4046        let newLeft = elmnt.offsetLeft - pos1;
4047        
4048        if(newTop < 0) newTop = 0;
4049        if(newLeft < 0) newLeft = 0;
4050        if(newTop + elmnt.offsetHeight > window.innerHeight) newTop = window.innerHeight - elmnt.offsetHeight;
4051        if(newLeft + elmnt.offsetWidth > window.innerWidth) newLeft = window.innerWidth - elmnt.offsetWidth;
4052
4053        elmnt.style.top = newTop + "px";
4054        elmnt.style.left = newLeft + "px";
4055    }
4056
4057    function closeDragElement() {
4058        document.onmouseup = null;
4059        document.onmousemove = null;
4060    }
4061}
4062
4063window.saveLiveEdits = async function() {
4064    const wrapper = document.getElementById('live-editable-content');
4065    if(!wrapper) return;
4066
4067    // 1. CLEANUP SWIPER
4068    const swipers = wrapper.querySelectorAll('.swiper');
4069    swipers.forEach(s => {
4070        if(s.swiper) s.swiper.destroy(true, true);
4071        const pag = s.querySelector('.swiper-pagination');
4072        if(pag) pag.innerHTML = ''; 
4073    });
4074
4075    // 2. CLEANUP ALL EDITOR TRASH
4076    deselectBlock();
4077    wrapper.querySelectorAll('.live-section-badge').forEach(b => b.remove());
4078    wrapper.querySelectorAll('.iframe-edit-overlay').forEach(el => el.remove());
4079
4080    wrapper.querySelectorAll('*').forEach(el => {
4081        el.contentEditable = "false";
4082        el.style.outline = "";
4083        el.style.outlineOffset = "";
4084        el.style.cursor = "";
4085        el.title = "";
4086        if(el.tagName === 'IMG') el.ondblclick = null;
4087        if(el.tagName === 'A') {
4088            el.removeEventListener('click', preventLinkClick);
4089            el.ondblclick = null;
4090        }
4091    });
4092
4093    // 3. SAVE TO FIREBASE
4094    const finalHTML = wrapper.innerHTML;
4095    const pageSlug = window.location.pathname.replace(/^\/|\.html$/g, '') || 'home';
4096
4097    try {
4098        const saveBtn = document.querySelector('.fa-cloud-arrow-up').parentNode;
4099        saveBtn.innerHTML = "<i class='fa-solid fa-spinner fa-spin text-white'></i>";
4100        
4101        await db.collection("live_pages").doc(pageSlug).set({
4102            htmlContent: finalHTML, updatedAt: new Date()
4103        });
4104        
4105        customToast("Page successfully saved!", "success");
4106        setTimeout(() => window.location.reload(), 1000); 
4107    } catch(e) {
4108        customToast("Error saving: " + e.message, "error");
4109    }
4110};
4111
4112// ⚡ LOAD SAVED CONTENT INSTANTLY FROM CACHE ON PAGE LOAD
4113document.addEventListener('DOMContentLoaded', async () => {
4114    const wrapper = document.getElementById('live-editable-content');
4115    if (!wrapper) return;
4116
4117    const pageSlug = window.location.pathname.replace(/^\/|\.html$/g, '') || 'home';
4118    
4119    try {
4120        // Read from local cache first for 0ms instant loading
4121        let doc;
4122        try {
4123            doc = await db.collection("live_pages").doc(pageSlug).get({ source: 'cache' });
4124        } catch(cacheErr) {
4125            doc = await db.collection("live_pages").doc(pageSlug).get();
4126        }
4127
4128        if (doc && doc.exists && doc.data().htmlContent) {
4129            wrapper.innerHTML = doc.data().htmlContent;
4130        }
4131    } catch(e) {
4132        console.log("Live page load:", e);
4133    }
4134
4135    // Initialize Swiper Carousel if present
4136    if (document.querySelector('.testimonial-swiper')) {
4137        new Swiper('.testimonial-swiper', {
4138            slidesPerView: 1, spaceBetween: 24, loop: true,
4139            autoplay: { delay: 4000, disableOnInteraction: false },
4140            pagination: { el: '.swiper-pagination', clickable: true },
4141            navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev' },
4142            breakpoints: { 640: { slidesPerView: 1 }, 768: { slidesPerView: 2 }, 1024: { slidesPerView: 3 } }
4143        });
4144    }
4145});
4146
4147
4148/* ==========================================
4149   UNIVERSAL DYNAMIC LIST MANAGER FOR BOOKS (A-Z SORTED)
4150   ========================================== */
4151
4152const libraryDefaults = {
4153    publishers: ["Alin Tagar School", "Cambridge University Press", "Macmillan Education", "Oxford University Press", "Pearson Education", "Scholastic"],
4154    levels: ["Beginner A1", "Elementary A2", "Intermediate B1+", "Level 1", "Level 2", "Pre-Intermediate B1", "Quick Starter", "Starter (YLE)", "Upper-Intermediate B2"],
4155    types: ["Audiobook", "Coursebook", "Graded Reader", "Grammar Guide", "Workbook"],
4156    cefrs: ["A1 Starter", "A1+ Elementary", "A2 Elementary", "B1 Pre-Intermediate", "B1+ Intermediate", "B2 Upper-Intermediate", "C1 Advanced"],
4157    languages: ["American English", "British English", "International English", "Myanmar & English"],
4158    seriesList: ["Bookworms", "Dominoes", "Express Publishing", "Penguin Readers"],
4159    formats: ["App", "Downloadable Pack", "MP3 Audio", "MP4 Video", "Paperback", "PDF Document", "Software", "Zip Archive"]
4160};
4161
4162// 🟢 Get Merged List Sorted Alphabetically (A-Z)
4163window.getSortedLibList = function(key) {
4164    const defaults = libraryDefaults[key] || [];
4165    let custom = [];
4166    try { custom = JSON.parse(localStorage.getItem('custom_' + key) || '[]'); } catch(e){}
4167
4168    const merged = Array.from(new Set([...defaults, ...custom]));
4169    merged.sort((a, b) => a.localeCompare(b)); // A-Z Sort
4170    return merged;
4171};
4172
4173// 🟢 Save Custom Item
4174window.saveCustomLibItem = function(key, typedVal) {
4175    if (!typedVal) return;
4176    let custom = [];
4177    try { custom = JSON.parse(localStorage.getItem('custom_' + key) || '[]'); } catch(e){}
4178    if (!custom.includes(typedVal)) {
4179        custom.push(typedVal);
4180        localStorage.setItem('custom_' + key, JSON.stringify(custom));
4181    }
4182};
4183
4184// 🟢 Populate Any Dropdown with A-Z Items + Add New Option
4185window.populateLibDropdown = function(selectId, key, selectedVal = '') {
4186    const selectEl = document.getElementById(selectId);
4187    if (!selectEl) return;
4188
4189    const items = window.getSortedLibList(key);
4190    let label = key.toUpperCase();
4191    if (key === 'seriesList') label = 'SERIES';
4192
4193    let html = `<option value="">Select ${label}...</option>`;
4194    
4195    items.forEach(item => {
4196        html += `<option value="${item}">${item}</option>`;
4197    });
4198    html += `<option value="NEW" class="font-bold text-amber-400">+ Add New...</option>`;
4199
4200    selectEl.innerHTML = html;
4201
4202    const inputBox = document.getElementById(`new-${key}-box`);
4203    const inputEl = document.getElementById(`m-book-${key}-new`);
4204
4205    if (selectedVal && items.includes(selectedVal)) {
4206        selectEl.value = selectedVal;
4207        if (inputBox) inputBox.classList.add('hidden');
4208    } else if (selectedVal) {
4209        selectEl.value = 'NEW';
4210        if (inputBox) inputBox.classList.remove('hidden');
4211        if (inputEl) inputEl.value = selectedVal;
4212    } else {
4213        if (inputBox) inputBox.classList.add('hidden');
4214    }
4215};
4216
4217// 🟢 Interactive Prompt Handler for "+ Add New..." Dropdown Option
4218window.handleLibDropdownSelect = async function(key, val, selectEl) {
4219    if (val === 'NEW') {
4220        let label = key.toUpperCase();
4221        if (key === 'seriesList') label = 'SERIES';
4222        if (key === 'publishers') label = 'PUBLISHER';
4223        if (key === 'levels') label = 'LEVEL';
4224        if (key === 'types') label = 'TYPE';
4225        if (key === 'cefrs') label = 'CEFR LEVEL';
4226        if (key === 'languages') label = 'LANGUAGE';
4227
4228        const newItem = await customPrompt(`Add New ${label}`, `Enter new ${label.toLowerCase()} name:`, "");
4229        
4230        if (newItem && newItem.trim() !== '') {
4231            const cleanVal = newItem.trim();
4232            window.saveCustomLibItem(key, cleanVal);
4233            
4234            // Re-populate dropdown with new item included & selected
4235            window.populateLibDropdown(selectEl.id, key, cleanVal);
4236            if (typeof customToast === 'function') customToast(`Added "${cleanVal}" to ${label.toLowerCase()} list!`, "success");
4237        } else {
4238            // Reset selection if cancelled
4239            selectEl.value = '';
4240        }
4241    }
4242};
4243
4244// 🟢 Render Dynamic Format Chip Tags
4245window.renderFormatChips = function(selectedFormats = ['PDF Document']) {
4246    const container = document.getElementById('format-tags-container');
4247    if (!container) return;
4248
4249    const formats = window.getSortedLibList('formats');
4250    let html = '';
4251
4252    formats.forEach(f => {
4253        const isSelected = selectedFormats.includes(f);
4254        const btnClass = isSelected
4255            ? 'format-chip-btn px-3.5 py-2 rounded-xl border text-xs font-bold transition flex items-center gap-1.5 bg-blue-600 text-white border-blue-500'
4256            : 'format-chip-btn px-3.5 py-2 rounded-xl border text-xs font-bold transition flex items-center gap-1.5 bg-slate-900 text-gray-300 border-slate-700';
4257
4258        html += `<button type="button" onclick="toggleFormatTag(this)" data-format="${f}" class="${btnClass}">${f}</button>`;
4259    });
4260
4261    // Add "+ Add New Format" button
4262    html += `<button type="button" onclick="addNewFormatTagPrompt()" class="px-3.5 py-2 rounded-xl border border-dashed border-amber-500/60 text-amber-400 hover:bg-amber-500/10 text-xs font-bold transition flex items-center gap-1.5">+ Add New Format</button>`;
4263
4264    container.innerHTML = html;
4265};
4266
4267window.addNewFormatTagPrompt = async function() {
4268    const newFormat = await customPrompt("Add New Format Tag", "Enter format name (e.g. EPUB, Flashcards, Interactive HTML):", "");
4269    if (newFormat && newFormat.trim() !== '') {
4270        const cleanVal = newFormat.trim();
4271        window.saveCustomLibItem('formats', cleanVal);
4272        
4273        const selected = [];
4274        document.querySelectorAll('.format-chip-btn.bg-blue-600').forEach(b => selected.push(b.getAttribute('data-format')));
4275        selected.push(cleanVal);
4276        
4277        window.renderFormatChips(selected);
4278        customToast(`Added "${cleanVal}" to formats!`, "success");
4279    }
4280};
4281
4282window.toggleFormatTag = function(btn) {
4283    if (btn.classList.contains('bg-blue-600')) {
4284        btn.className = 'format-chip-btn px-3.5 py-2 rounded-xl border text-xs font-bold transition flex items-center gap-1.5 bg-slate-900 text-gray-300 border-slate-700';
4285    } else {
4286        btn.className = 'format-chip-btn px-3.5 py-2 rounded-xl border text-xs font-bold transition flex items-center gap-1.5 bg-blue-600 text-white border-blue-500';
4287    }
4288};
4289
4290// Helper to get final value from dropdown or new input
4291window.getFinalLibValue = function(key, selectId, inputId) {
4292    let val = document.getElementById(selectId)?.value;
4293    if (val === 'NEW') {
4294        const typed = document.getElementById(inputId)?.value.trim();
4295        if (typed) {
4296            window.saveCustomLibItem(key, typed);
4297            return typed;
4298        }
4299        return '';
4300    }
4301    return val || '';
4302};
4303
4304/* ==========================================
4305   1280px ADMIN MORE BOOK INFO MODAL (SAMPLE 2)
4306   ========================================== */
4307
4308let activeEditingRow = null;
4309
4310/* 🟢 CORRECT SYNTAX (Single catch block): */
4311window.openAdminMoreBookInfoModal = function(btn) {
4312    activeEditingRow = btn.closest('.book-item-row');
4313    if (!activeEditingRow) return;
4314
4315    let extData = {};
4316    try {
4317        let rawJson = activeEditingRow.getAttribute('data-ext-info') || '{}';
4318        rawJson = rawJson.replace(/&quot;/g, '"');
4319        extData = JSON.parse(rawJson);
4320    } catch(e) {
4321        console.error("Error parsing book metadata JSON:", e);
4322    }
4323
4324    // Inject modal HTML if missing
4325    if (!document.getElementById('admin-book-details-modal')) {
4326        const modalHtml = `
4327        <div id="admin-book-details-modal" class="fixed inset-0 z-[1000005] bg-black/80 backdrop-blur-sm hidden flex items-center justify-center p-4 sm:p-6 overflow-y-auto">
4328            
4329            <style>
4330                /* Shortened Inset Dark Scrollbar (20px top & bottom gap) */
4331                #admin-book-details-content::-webkit-scrollbar {
4332                    width: 10px;
4333                }
4334                #admin-book-details-content::-webkit-scrollbar-track {
4335                    background: #0f172a;
4336                    border-radius: 10px;
4337                    border-top: 20px solid transparent;
4338                    border-bottom: 20px solid transparent;
4339                    background-clip: padding-box;
4340                }
4341                #admin-book-details-content::-webkit-scrollbar-thumb {
4342                    background: #334155;
4343                    border-radius: 10px;
4344                    border: 2px solid transparent;
4345                    border-top: 20px solid transparent;
4346                    border-bottom: 20px solid transparent;
4347                    background-clip: padding-box;
4348                }
4349                #admin-book-details-content::-webkit-scrollbar-thumb:hover {
4350                    background: #f59e0b;
4351                    background-clip: padding-box;
4352                }
4353            </style>
4354
4355            <div id="admin-book-details-content" class="bg-[#181d2a] border border-slate-800 rounded-3xl p-6 sm:p-8 max-w-[1280px] w-full shadow-2xl space-y-6 text-xs text-white my-auto max-h-[90vh] overflow-y-auto relative">
4356                
4357                <!-- Sticky Header -->
4358                <div class="flex justify-between items-center border-b border-slate-800 pb-4 sticky -top-6 sm:-top-8 bg-[#181d2a] z-30 pt-2">
4359                    <h3 class="text-xl sm:text-2xl font-black text-amber-400"><i class="fa-solid fa-book mr-2"></i> Extended Book Details (Sample 2)</h3>
4360                    <button type="button" onclick="document.getElementById('admin-book-details-modal').classList.add('hidden')" class="text-gray-400 hover:text-white text-xl w-10 h-10 rounded-full hover:bg-slate-800 flex items-center justify-center transition-colors focus:outline-none">
4361                        <i class="fa-solid fa-xmark"></i>
4362                    </button>
4363                </div>
4364
4365                <!-- 🟢 4-COLUMN ROW 1: Author | Publisher (+ Add) | Level (+ Add) | Type (+ Add) 
4365-->
4366                <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
4367                    <div>
4368                        <label class="block font-bold text-gray-300 uppercase mb-1">Author Name</label>
4369                        <input type="text" id="m-book-author" placeholder="e.g. Bill Bowler" class="w-full p-3 bg-slate-950 border border-slate-700 rounded-xl text-white text-xs focus:outline-none focus:border-amber-400">
4370                    </div>
4371                    <div>
4372                        <label class="block font-bold text-gray-300 uppercase mb-1">Publisher (A–Z)</label>
4373                        <!-- 🟢 FIXED: Added 'this' parameter -->
4374                        <select id="m-book-publisher" onchange="handleLibDropdownSelect('publishers', this.value, this)" class="w-full p-3 bg-slate-950 border border-slate-700 rounded-xl text-white text-xs focus:outline-none focus:border-amber-400"></select>
4375                        <div id="new-publishers-box" class="hidden mt-2">
4376                            <input type="text" id="m-book-publishers-new" placeholder="Type new publisher..." class="w-full p-2.5 bg-slate-900 border border-amber-500/50 rounded-xl text-amber-300 text-xs focus:outline-none">
4377                        </div>
4378                    </div>
4379                    <div>
4380                        <label class="block font-bold text-gray-300 uppercase mb-1">Level (A–Z)</label>
4381                        <!-- 🟢 FIXED: Added 'this' parameter -->
4382                        <select id="m-book-level" onchange="handleLibDropdownSelect('levels', this.value, this)" class="w-full p-3 bg-slate-950 border border-slate-700 rounded-xl text-white text-xs focus:outline-none focus:border-amber-400"></select>
4383                        <div id="new-levels-box" class="hidden mt-2">
4384                            <input type="text" id="m-book-levels-new" placeholder="Type new level..." class="w-full p-2.5 bg-slate-900 border border-amber-500/50 rounded-xl text-amber-300 text-xs focus:outline-none">
4385                        </div>
4386                    </div>
4387                    <div>
4388                        <label class="block font-bold text-gray-300 uppercase mb-1">Type (A–Z)</label>
4389                        <!-- 🟢 FIXED: Added 'this' parameter -->
4390                        <select id="m-book-type" onchange="handleLibDropdownSelect('types', this.value, this)" class="w-full p-3 bg-slate-950 border border-slate-700 rounded-xl text-white text-xs focus:outline-none focus:border-amber-400"></select>
4391                        <div id="new-types-box" class="hidden mt-2">
4392                            <input type="text" id="m-book-types-new" placeholder="Type new type..." class="w-full p-2.5 bg-slate-900 border border-amber-500/50 rounded-xl text-amber-300 text-xs focus:outline-none">
4393                        </div>
4394                    </div>
4395                </div>
4396
4397                <!-- Formats Available Clickable Tags + Add New Format -->
4398                <div>
4399                    <label class="block font-bold text-gray-300 uppercase mb-2">Formats Available (Click to Toggle)</label>
4400                    <div class="flex flex-wrap gap-2" id="format-tags-container">
4401                        <!-- Rendered Dynamically -->
4402                    </div>
4403                </div>
4404
4405                <!-- 🟢 3-COLUMN ROW 2: CEFR (+ Add) | Language (+ Add) | Series (+ Add) -->
4406                <div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
4407                    <div>
4408                        <label class="block font-bold text-gray-300 uppercase mb-1">CEFR Level (A–Z)</label>
4409                        <!-- 🟢 FIXED: Added 'this' parameter -->
4410                        <select id="m-book-cefr" onchange="handleLibDropdownSelect('cefrs', this.value, this)" class="w-full p-3 bg-slate-950 border border-slate-700 rounded-xl text-white text-xs focus:outline-none focus:border-amber-400"></select>
4411                        <div id="new-cefrs-box" class="hidden mt-2">
4412                            <input type="text" id="m-book-cefrs-new" placeholder="Type new CEFR..." class="w-full p-2.5 bg-slate-900 border border-amber-500/50 rounded-xl text-amber-300 text-xs focus:outline-none">
4413                        </div>
4414                    </div>
4415                    <div>
4416                        <label class="block font-bold text-gray-300 uppercase mb-1">Language (A–Z)</label>
4417                        <!-- 🟢 FIXED: Added 'this' parameter -->
4418                        <select id="m-book-language" onchange="handleLibDropdownSelect('languages', this.value, this)" class="w-full p-3 bg-slate-950 border border-slate-700 rounded-xl text-white text-xs focus:outline-none focus:border-amber-400"></select>
4419                        <div id="new-languages-box" class="hidden mt-2">
4420                            <input type="text" id="m-book-languages-new" placeholder="Type new language..." class="w-full p-2.5 bg-slate-900 border border-amber-500/50 rounded-xl text-amber-300 text-xs focus:outline-none">
4421                        </div>
4422                    </div>
4423                    <div>
4424                        <label class="block font-bold text-gray-300 uppercase mb-1">Series (A–Z)</label>
4425                        <!-- 🟢 FIXED: Added 'this' parameter -->
4426                        <select id="m-book-seriesList" onchange="handleLibDropdownSelect('seriesList', this.value, this)" class="w-full p-3 bg-slate-950 border border-slate-700 rounded-xl text-white text-xs focus:outline-none focus:border-amber-400"></select>
4427                        <div id="new-seriesList-box" class="hidden mt-2">
4428                            <input type="text" id="m-book-seriesList-new" placeholder="Type new series..." class="w-full p-2.5 bg-slate-900 border border-amber-500/50 rounded-xl text-amber-300 text-xs focus:outline-none">
4429                        </div>
4430                    </div>
4431                </div>
4432
4433                <!-- 🟢 NEW ROW: ISBN & Published Date (with Calendar Picker) -->
4434                <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
4435                    <div>
4436                        <label class="block font-bold text-gray-300 uppercase mb-1">ISBN Number</label>
4437                        <input type="text" id="m-book-isbn" placeholder="e.g. 978-0-19-450000-0" class="w-full p-3 bg-slate-950 border border-slate-700 rounded-xl text-white text-xs focus:outline-none focus:border-amber-400">
4438                    </div>
4439                    <div>
4440                        <label class="block font-bold text-gray-300 uppercase mb-1">Published Date (Calendar Picker)</label>
4441                        <input type="date" id="m-book-pubdate" onclick="this.showPicker()" class="w-full p-3 bg-slate-950 border border-slate-700 rounded-xl text-amber-400 text-xs focus:outline-none focus:border-amber-400 cursor-pointer [color-scheme:dark]">
4442                    </div>
4443                </div>
4444
4445                <!-- 🟢 NEW ROW: Flipbook Viewer Settings -->
4446                <div class="bg-slate-900 p-4 rounded-xl border border-slate-700 flex flex-col sm:flex-row gap-6 mt-2">
4447                    <label class="flex items-center gap-2.5 font-bold text-amber-400 text-xs cursor-pointer">
4448                        <input type="checkbox" id="m-book-enable-download" class="w-4 h-4 rounded text-amber-500 bg-slate-950 border-slate-700 cursor-pointer focus:ring-amber-500 focus:ring-offset-slate-900">
4449                        Enable PDF Download Button
4450                    </label>
4451                    <label class="flex items-center gap-2.5 font-bold text-amber-400 text-xs cursor-pointer">
4452                        <input type="checkbox" id="m-book-enable-share" class="w-4 h-4 rounded text-amber-500 bg-slate-950 border-slate-700 cursor-pointer focus:ring-amber-500 focus:ring-offset-slate-900">
4453                        Enable Social Share Button
4454                    </label>
4455                </div>
4456
4457                <!-- 🟢 2-VERSION DESCRIPTION EDITOR (VISUAL MODE & HTML MODE) -->
4458                <div class="space-y-2">
4459                    <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-2 border-b border-slate-800 pb-2">
4460                        <label class="block font-bold text-gray-300 uppercase">Description / Extra Info</label>
4461                        
4462                        <div class="flex items-center gap-2">
4463                            <!-- Version Tab Switcher -->
4464                            <div class="flex bg-slate-950 p-1 rounded-xl border border-slate-800 text-[11px] font-bold">
4465                                <button type="button" id="desc-tab-visual" onclick="switchDescTab('visual')" class="px-3 py-1 rounded-lg bg-amber-500 text-slate-950 shadow-sm transition">Visual Version</button>
4466                                <button type="button" id="desc-tab-html" onclick="switchDescTab('html')" class="px-3 py-1 rounded-lg text-gray-400 hover:text-white transition">HTML Version</button>
4467                            </div>
4468
4469                            <!-- Visual Toolbar Buttons -->
4470                            <div id="desc-visual-toolbar" class="flex items-center gap-1">
4471                                <button type="button" onclick="formatVisualDesc('bold')" class="px-2.5 py-1 bg-slate-800 hover:bg-amber-500 hover:text-slate-950 text-white rounded-lg font-black text-xs transition" title="Bold">B</button>
4472                                <button type="button" onclick="formatVisualDesc('heading')" class="px-2.5 py-1 bg-slate-800 hover:bg-amber-500 hover:text-slate-950 text-white rounded-lg font-black text-xs transition" title="Heading">H (Heading)</button>
4473                                <button type="button" onclick="formatVisualDesc('insertUnorderedList')" class="px-2.5 py-1 bg-slate-800 hover:bg-amber-500 hover:text-slate-950 text-white rounded-lg font-bold text-xs transition" title="List">• List</button>
4474                            </div>
4475                        </div>
4476                    </div>
4477
4478                    <!-- 1. VISUAL EDITOR CONTAINER (ContentEditable Live WYSIWYG) -->
4479                    <div id="m-book-desc-visual" contenteditable="true" class="w-full min-h-[130px] max-h-[250px] overflow-y-auto p-3 bg-slate-950 border border-slate-700 rounded-xl text-white text-xs focus:outline-none focus:border-amber-400 leading-relaxed font-sans" placeholder="Type book description visually..."></div>
4480
4481                    <!-- 2. HTML CODE EDITOR CONTAINER (Raw Source Code Textarea) -->
4482                    <textarea id="m-book-desc-html" rows="6" class="hidden w-full p-3 bg-slate-950 border border-slate-700 rounded-xl text-emerald-400 text-xs focus:outline-none focus:border-amber-400 leading-relaxed font-mono" placeholder="<p>Write raw HTML code here...</p>"></textarea>
4483                </div>
4484
4485                <!-- Sticky Action Buttons -->
4486                <div class="flex gap-3 pt-4 border-t border-slate-800 justify-end sticky -bottom-6 sm:-bottom-8 bg-[#181d2a] z-30 pb-2">
4487                    <button type="button" onclick="document.getElementById('admin-book-detail
4487s-modal').classList.add('hidden')" class="px-5 py-3 bg-slate-800 text-gray-300 font-bold rounded-xl text-xs">Cancel</button>
4488                    <button type="button" onclick="saveAdminMoreBookInfo()" class="px-6 py-3 bg-amber-500 hover:bg-amber-400 text-slate-950 font-black rounded-xl text-xs shadow-lg">✓ Save Book Info</button>
4489                </div>
4490            </div>
4491        </div>`;
4492        document.body.insertAdjacentHTML('beforeend', modalHtml);
4493    }
4494
4495    // Populate all A-Z dropdowns with + Add New
4496    populateLibDropdown('m-book-publisher', 'publishers', extData.publisher || '');
4497    populateLibDropdown('m-book-level', 'levels', extData.level || '');
4498    populateLibDropdown('m-book-type', 'types', extData.type || '');
4499    populateLibDropdown('m-book-cefr', 'cefrs', extData.cefr || '');
4500    populateLibDropdown('m-book-language', 'languages', extData.language || 'British English');
4501    populateLibDropdown('m-book-seriesList', 'seriesList', extData.series || '');
4502
4503    // Render format chips
4504    renderFormatChips(extData.formats || ['PDF Document']);
4505
4506    // Other values
4507    if (document.getElementById('m-book-author')) document.getElementById('m-book-author').value = extData.author || '';
4508    if (document.getElementById('m-book-isbn')) document.getElementById('m-book-isbn').value = extData.isbn || '';
4509    if (document.getElementById('m-book-pubdate')) document.getElementById('m-book-pubdate').value = extData.publishedDate || '';
4510
4511    // 🟢 Load Checkbox States
4512    if (document.getElementById('m-book-enable-download')) document.getElementById('m-book-enable-download').checked = extData.enableDownload === true;
4513    if (document.getElementById('m-book-enable-share')) document.getElementById('m-book-enable-share').checked = extData.enableShare === true;
4514
4515    // Description (Visual & HTML Versions)
4516    const descContent = extData.description || '';
4517    const visualEl = document.getElementById('m-book-desc-visual');
4518    const htmlEl = document.getElementById('m-book-desc-html');
4519
4520    if (visualEl) visualEl.innerHTML = descContent;
4521    if (htmlEl) htmlEl.value = descContent;
4522
4523    // Reset to Visual Version tab by default
4524    if (typeof switchDescTab === 'function') switchDescTab('visual');
4525
4526    document.getElementById('admin-book-details-modal').classList.remove('hidden');
4527};
4528
4529// 🟢 Helper to format text inside Description Textarea
4530window.formatDescText = function(tag) {
4531    const textarea = document.getElementById('m-book-desc');
4532    if (!textarea) return;
4533
4534    const start = textarea.selectionStart;
4535    const end = textarea.selectionEnd;
4536    const selected = textarea.value.substring(start, end);
4537
4538    let formatted = '';
4539    if (tag === 'bold') {
4540        formatted = `<strong>${selected || 'Bold Text'}</strong>`;
4541    } else if (tag === 'heading') {
4542        formatted = `<h4 class="text-base font-extrabold text-brandBlue mt-2 mb-1">${selected || 'Larger Heading Title'}</h4>`;
4543    } else if (tag === 'list') {
4544        formatted = `<ul class="list-disc pl-5 my-2"><li>${selected || 'List Item'}</li></ul>`;
4545    }
4546
4547    textarea.value = textarea.value.substring(0, start) + formatted + textarea.value.substring(end);
4548    textarea.focus();
4549};
4550
4551window.activeDescTab = 'visual';
4552
4553// 🟢 Switch between Visual Version & HTML Version
4554window.switchDescTab = function(tab) {
4555    const visualEl = document.getElementById('m-book-desc-visual');
4556    const htmlEl = document.getElementById('m-book-desc-html');
4557    const btnVisual = document.getElementById('desc-tab-visual');
4558    const btnHtml = document.getElementById('desc-tab-html');
4559    const toolbar = document.getElementById('desc-visual-toolbar');
4560
4561    if (!visualEl || !htmlEl) return;
4562
4563    if (tab === 'html') {
4564        // Sync Visual -> HTML
4565        htmlEl.value = visualEl.innerHTML;
4566        
4567        visualEl.classList.add('hidden');
4568        htmlEl.classList.remove('hidden');
4569        if (toolbar) toolbar.classList.add('hidden');
4570
4571        btnHtml.className = "px-3 py-1 rounded-lg bg-amber-500 text-slate-950 shadow-sm transition";
4572        btnVisual.className = "px-3 py-1 rounded-lg text-gray-400 hover:text-white transition";
4573        window.activeDescTab = 'html';
4574    } else {
4575        // Sync HTML -> Visual
4576        visualEl.innerHTML = htmlEl.value;
4577
4578        htmlEl.classList.add('hidden');
4579        visualEl.classList.remove('hidden');
4580        if (toolbar) toolbar.classList.remove('hidden');
4581
4582        btnVisual.className = "px-3 py-1 rounded-lg bg-amber-500 text-slate-950 shadow-sm transition";
4583        btnHtml.className = "px-3 py-1 rounded-lg text-gray-400 hover:text-white transition";
4584        window.activeDescTab = 'visual';
4585    }
4586};
4587
4588// 🟢 Visual Toolbar Formatter
4589window.formatVisualDesc = function(command) {
4590    const visualEl = document.getElementById('m-book-desc-visual');
4591    if (!visualEl) return;
4592    visualEl.focus();
4593
4594    if (command === 'heading') {
4595        document.execCommand('formatBlock', false, '<h4>');
4596    } else {
4597        document.execCommand(command, false, null);
4598    }
4599};
4600
4601// 🟢 Instant Cloud Auto-Save Version
4602window.saveAdminMoreBookInfo = async function() {
4603    if (!activeEditingRow) {
4604        if (typeof customToast === 'function') customToast("Error: No active book row selected.", "error");
4605        return;
4606    }
4607
4608    const publisherVal = getFinalLibValue('publishers', 'm-book-publisher', 'm-book-publishers-new');
4609    const levelVal = getFinalLibValue('levels', 'm-book-level', 'm-book-levels-new');
4610    const typeVal = getFinalLibValue('types', 'm-book-type', 'm-book-types-new');
4611    const cefrVal = getFinalLibValue('cefrs', 'm-book-cefr', 'm-book-cefrs-new');
4612    const languageVal = getFinalLibValue('languages', 'm-book-language', 'm-book-languages-new');
4613    const seriesVal = getFinalLibValue('seriesList', 'm-book-seriesList', 'm-book-seriesList-new');
4614
4615    const selectedFormats = [];
4616    document.querySelectorAll('.format-chip-btn.bg-blue-600').forEach(btn => {
4617        selectedFormats.push(btn.getAttribute('data-format'));
4618    });
4619
4620    const visualEl = document.getElementById('m-book-desc-visual');
4621    const htmlEl = document.getElementById('m-book-desc-html');
4622
4623    let finalDescription = '';
4624    if (window.activeDescTab === 'html' && htmlEl) {
4625        finalDescription = htmlEl.value.trim();
4626    } else if (visualEl) {
4627        finalDescription = visualEl.innerHTML.trim();
4628    }
4629
4630    const extData = {
4631        author: (document.getElementById('m-book-author')?.value || '').trim(),
4632        isbn: (document.getElementById('m-book-isbn')?.value || '').trim(),
4633        publishedDate: (document.getElementById('m-book-pubdate')?.value || '').trim(),
4634        publisher: publisherVal,
4635        level: levelVal,
4636        type: typeVal,
4637        cefr: cefrVal,
4638        language: languageVal,
4639        series: seriesVal,
4640        formats: selectedFormats.length > 0 ? selectedFormats : ['PDF Document'],
4641        description: finalDescription,
4642        
4643        // 🟢 Save Checkbox States
4644        enableDownload: document.getElementById('m-book-enable-download')?.checked || false,
4645        enableShare: document.getElementById('m-book-enable-share')?.checked || false
4646    };
4647
4648    // 1. Update row attribute locally
4649    activeEditingRow.setAttribute('data-ext-info', JSON.stringify(extData));
4650    document.getElementById('admin-book-details-modal').classList.add('hidden');
4651
4652    // 2. 🟢 INSTANT AUTO-SAVE TO CLOUD FIRESTORE
4653    const bsForm = document.getElementById('bookshelf-editor-form');
4654    if (bsForm) {
4655        // Automatically triggers form submission directly to Cloud Firestore!
4656        bsForm.dispatchEvent(new Event('submit', { cancelable: true, bubbles: true }));
4657    } else {
4658        if (typeof customToast === 'function') customToast("Book details saved successfully!", "success");
4659    }
4660};
4661
4662// 🟢 USER ACCESS MANAGER LOGIC
4663let activeAccessTargetType = null;
4664let activeAccessTargetInput = null;
4665let loadedAccessUsers = [];
4666
4667window.openAccessManager = async function(type, btn = null) {
4668    activeAccessTargetType = type;
4669    
4670    if (type === 'shelf') {
4671        document.getElementById('access-modal-title').innerHTML = '<i class="fa-solid fa-users-lock mr-2"></i> Manage Entire Shelf Access';
4672        activeAccessTargetInput = document.getElementById('bs-allowed-users');
4673    } else {
4674        document.getElementById('access-modal-title').innerHTML = '<i class="fa-solid fa-users-lock mr-2"></i> Manage Specific Book Access';
4675        const row = btn.closest('.book-item-row');
4676        activeAccessTargetInput = row.querySelector('.book-input-access');
4677    }
4678
4679    document.getElementById('user-access-modal').classList.remove('hidden');
4680
4681    const selectAllCb = document.getElementById('access-select-all-cb');
4682    if (selectAllCb) selectAllCb.checked = false;
4683
4684    const listEl = document.getElementById('access-users-list');
4685    const requireLoginCb = document.getElementById('access-require-login-cb');
4686    
4687    // Parse currently allowed users
4688    let currentAllowed = [];
4689    try { currentAllowed = JSON.parse(activeAccessTargetInput.value || '[]'); } catch(e){}
4690
4691    // 🟢 NEW: If "LOGGED_IN_USERS_ONLY" is in the array, check the box!
4692    if (requireLoginCb) {
4693        requireLoginCb.checked = currentAllowed.includes('LOGGED_IN_USERS_ONLY');
4694    }
4695
4696    try {
4697        if (loadedAccessUsers.length === 0) {
4698            const snap = await db.collection("users").get();
4699            snap.forEach(doc => loadedAccessUsers.push({ id: doc.id, ...doc.data() }));
4700        }
4701
4702        let html = '';
4703        loadedAccessUsers.forEach(u => {
4704            const isChecked = currentAllowed.includes(u.id) ? 'checked' : '';
4705            html += `
4706            <label class="access-user-item flex items-center justify-between p-3 bg-slate-900 border border-slate-700 rounded-xl cursor-pointer hover:border-indigo-500 transition">
4707                <div>
4708                    <p class="text-white text-xs font-bold user-name">${u.fullName || 'Unknown User'}</p>
4709                    <p class="text-gray-400 text-[10px] user-email">${u.email || u.displayEmail || 'No Email'}</p>
4710                </div>
4711                <input type="checkbox" value="${u.id}" class="user-access-cb w-4 h-4 rounded text-indigo-600 bg-slate-950 border-slate-600" ${isChecked}>
4712            </label>`;
4713        });
4714        listEl.innerHTML = html;
4715    } catch(e) {
4716        listEl.innerHTML = `<p class="text-red-400 text-xs text-center">Error loading users.</p>`;
4717    }
4718};
4719
4720window.closeAccessManager = function() {
4721    document.getElementById('user-access-modal').classList.add('hidden');
4722};
4723
4724window.saveAccessManager = function() {
4725    const checkboxes = document.querySelectorAll('.user-access-cb:checked');
4726    const selectedIds = Array.from(checkboxes).map(cb => cb.value);
4727    
4728    // 🟢 NEW: Add the special flag if the require login box is checked
4729    const requireLoginCb = document.getElementById('access-require-login-cb');
4730    if (requireLoginCb && requireLoginCb.checked) {
4731        selectedIds.push('LOGGED_IN_USERS_ONLY');
4732    }
4733    
4734    if (activeAccessTargetInput) {
4735        activeAccessTargetInput.value = JSON.stringify(selectedIds);
4736        activeAccessTargetInput.setAttribute('value', JSON.stringify(selectedIds));
4737    }
4738    
4739    customToast(`Access settings saved!`, "success");
4740    closeAccessManager();
4741};
4742
4743window.filterAccessUsers = function() {
4744    const query = document.getElementById('access-user-search').value.toLowerCase();
4745    document.querySelectorAll('.access-user-item').forEach(item => {
4746        const name = item.querySelector('.user-name').innerText.toLowerCase();
4747        const email = item.querySelector('.user-email').innerText.toLowerCase();
4748        item.style.display = (name.includes(query) || email.includes(query)) ? 'flex' : 'none';
4749    });
4750};
4751
4752// 🟢 NEW: SELECT ALL VISIBLE USERS LOGIC
4753window.toggleAllAccessUsers = function(source) {
4754    const checkboxes = document.querySelectorAll('.user-access-cb');
4755    checkboxes.forEach(cb => {
4756        const parentLabel = cb.closest('.access-user-item');
4757        // Only check/uncheck if the user is currently visible in the search list
4758        if (parentLabel && parentLabel.style.display !== 'none') {
4759            cb.checked = source.checked;
4760        }
4761    });
4762};
4763
4764/* ==========================================
4765   ATVEO-STYLE CENTRALIZED PAYMENT PANEL
4766   ========================================== */
4767window.allPaymentMethods = [];
4768window.activePaymentTab = 'methods';
4769
4770window.openFullscreenPaymentManager = function() {
4771    const existingWs = document.getElementById('admin-fullscreen-workspace');
4772    if (existingWs) existingWs.remove();
4773
4774    const workspaceHTML = `
4775    <div id="admin-fullscreen-workspace" class="fixed inset-0 z-[999999] bg-[#0b0f19] text-white flex flex-col font-sans overflow-hidden">
4776        
4777        <!-- Top Bar -->
4778        <div class="bg-slate-950 text-gray-300 h-14 px-8 flex items-center justify-between border-b border-slate-800 shadow-xl flex-shrink-0 z-50">
4779            <div class="flex items-center gap-3">
4780                <div class="w-9 h-9 bg-sky-500 text-white rounded-xl flex items-center justify-center font-black text-lg">
4781                    <i class="fa-solid fa-credit-card"></i>
4782                </div>
4783                <div>
4784                    <h2 class="font-black text-lg text-white leading-none">Payment Control & Transactions</h2>
4785                    <p class="text-[11px] text-gray-400">Manage global payment methods and review student transaction ledgers.</p>
4786                </div>
4787            </div>
4788            
4789            <button onclick="document.getElementById('admin-fullscreen-workspace').remove()" class="bg-red-600/20 text-red-400 border border-red-500/30 px-5 py-2 rounded-xl text-xs font-bold hover:bg-red-600/40 transition">
4790                ✕ Close Panel
4791            </button>
4792        </div>
4793
4794        <!-- Dynamic Header Switch Tabs -->
4795        <div class="bg-slate-900 border-b border-slate-800 h-12 flex items-center px-8 gap-4 flex-shrink-0">
4796            <button onclick="switchPaymentPanelTab('methods')" id="pay-tab-methods" class="h-full px-4 border-b-2 border-sky-500 text-sky-400 text-xs font-bold uppercase tracking-wider transition focus:outline-none">
4797                💳 Payment Methods
4798            </button>
4799            <button onclick="switchPaymentPanelTab('transactions')" id="pay-tab-transactions" class="h-full px-4 border-b-2 border-transparent text-gray-400 hover:text-white text-xs font-bold uppercase tracking-wider transition focus:outline-none">
4800                📜 Transaction History Ledger
4801            </button>
4802        </div>
4803
4804        <!-- Main Workspace Area -->
4805        <div class="flex-1 overflow-y-auto p-6 md:p-10 flex justify-center items-start">
4806            <div class="w-full max-w-[1280px]">
4807                
4808                <!-- TAB 1: PAYMENT METHOD MANAGER -->
4809                <div id="pay-view-methods" class="space-y-6">
4810                    <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 bg-slate-900 border border-slate-800 p-6 rounded-3xl">
4811                        <div>
4812                            <h3 class="text-xl font-black text-white">Centralized Payment Settings</h3>
4813                            <p class="text-xs text-gray-400">Configured methods are automatically loaded into site checkout forms.</p>
4814                        </div>
4815                        <button onclick="openPaymentMethodFormModal()" class="bg-sky-500 hover:bg-sky-400 text-slate-950 font-black px-4 py-2.5 rounded-xl text-xs transition shadow-lg flex items-center gap-1.5 self-start sm:self-ce
4815nter">
4816                            <i class="fa-solid fa-plus"></i> Add Payment Method
4817                        </button>
4818                    </div>
4819
4820                    <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
4821                        <!-- Left Container: Online Methods -->
4822                        <div class="bg-[#131927] border border-slate-800 rounded-3xl p-6 shadow-2xl space-y-4">
4823                            <h4 class="text-sm font-black text-amber-400 uppercase tracking-wider border-b border-slate-800 pb-2 flex items-center gap-2">
4824                                <i class="fa-solid fa-globe"></i> Online Payment gateways
4825                            </h4>
4826                            <div id="online-gateways-list" class="space-y-3">
4827                                <p class="text-xs text-gray-500 italic py-4 text-center">Loading gateways...</p>
4828                            </div>
4829                        </div>
4830
4831                        <!-- Right Container: Offline Methods -->
4832                        <div class="bg-[#131927] border border-slate-800 rounded-3xl p-6 shadow-2xl space-y-4">
4833                            <h4 class="text-sm font-black text-sky-400 uppercase tracking-wider border-b border-slate-800 pb-2 flex items-center gap-2">
4834                                <i class="fa-solid fa-wallet"></i> Offline & Local Mobile Transfers
4835                            </h4>
4836                            <div id="offline-transfers-list" class="space-y-3">
4837                                <p class="text-xs text-gray-500 italic py-4 text-center">Loading mobile transfers...</p>
4838                            </div>
4839                        </div>
4840                    </div>
4841                </div>
4842
4843                <!-- TAB 2: TRANSACTION LEDGER -->
4844                <div id="pay-view-transactions" class="hidden space-y-6">
4845                    <div class="bg-[#131927] border border-slate-800 rounded-3xl p-6 md:p-8 shadow-2xl space-y-6">
4846                        <div>
4847                            <h3 class="text-xl font-black text-white mb-1">Dynamic Transaction Ledger</h3>
4848                            <p class="text-xs text-gray-400">Review enrolments, verify transaction reference numbers (TxID), and approve access.</p>
4849                        </div>
4850
4851                        <div class="overflow-x-auto">
4852                        <table class="w-full text-left text-xs border-collapse">
4853                            <thead>
4854                                <tr class="text-gray-400 font-extrabold uppercase border-b border-slate-800 pb-3">
4855                                    <th class="py-3 px-4">Student Info</th>
4856                                    <th class="py-3 px-4">Course Package</th>
4857                                    <th class="py-3 px-4">Method / Transaction ID</th>
4858                                    <th class="py-3 px-4">Date</th>
4859                                    <th class="py-3 px-4">Status</th>
4860                                    <th class="py-3 px-4 text-center">Actions</th>
4861                                </tr>
4862                            </thead>
4863                            <tbody id="pay-ledger-table-body" class="divide-y divide-slate-800/80">
4864                                <tr>
4865                                    <td colspan="6" class="py-8 text-center text-gray-500 italic">Loading ledger transactions...</td>
4866                                </tr>
4867                            </tbody>
4868                        </table>
4869                    </div>
4870                </div>
4871
4872            </div>
4873        </div>
4874    </div>
4875
4876    <!-- 🟢 DYNAMIC PAYMENT METHOD FORM MODAL -->
4877    <div id="payment-method-form-modal" class="fixed inset-0 z-[1000000] bg-black/80 backdrop-blur-xs hidden flex items-center justify-center p-4">
4878        <div class="bg-[#181d2a] border border-slate-800 rounded-3xl p-6 sm:p-8 max-w-2xl w-full shadow-2xl space-y-6 text-xs text-white">
4879            <div class="flex justify-between items-center border-b border-slate-800 pb-3">
4880                <h3 class="text-lg font-black text-sky-400" id="method-modal-title">+ Add Payment Method</h3>
4881                <button type="button" onclick="closePaymentMethodFormModal()" class="text-gray-400 hover:text-white text-lg w-8 h-8 rounded-full hover:bg-slate-800 flex items-center justify-center transition-colors"><i class="fa-solid fa-xmark"></i></button>
4882            </div>
4883
4884            <form id="payment-method-editor-form" class="space-y-4" onsubmit="savePaymentMethod(event)">
4885                <input type="hidden" id="method-edit-id" value="">
4886                
4887                <div class="grid grid-cols-2 gap-3">
4888                    <div class="control-group">
4889                        <label class="block font-bold text-gray-300 uppercase mb-1">Method Type *</label>
4890                        <select id="method-type" required onchange="togglePaymentFormFields(this.value)" class="w-full p-2.5 bg-slate-950 border border-slate-700 rounded-xl text-white outline-none">
4891                            <option value="offline">Offline / Local Transfer</option>
4892                            <option value="online">Online Payment Gateway</option>
4893                        </select>
4894                    </div>
4895                    <div class="control-group">
4896                        <label class="block font-bold text-gray-300 uppercase mb-1">Method Name *</label>
4897                        <input type="text" id="method-name" placeholder="e.g. KBZ Pay" required class="w-full p-2.5 bg-slate-950 border border-slate-700 rounded-xl text-white outline-none">
4898                    </div>
4899                </div>
4900
4901                <div class="control-group">
4902                    <label class="block font-bold text-gray-300 uppercase mb-1">Official Logo URL</label>
4903                    <input type="text" id="method-logo" placeholder="https://... (Leave empty to auto-detect)" class="w-full p-2.5 bg-slate-950 border border-slate-700 rounded-xl text-white outline-none">
4904                </div>
4905
4906                <!-- Fields for Offline Type -->
4907                <div id="method-offline-fields" class="space-y-4">
4908                    <div class="grid grid-cols-2 gap-3">
4909                        <div class="control-group">
4910                            <label class="block font-bold text-gray-300 uppercase mb-1">Account Holder Name *</label>
4911                            <input type="text" id="method-account-name" placeholder="e.g. Saya Victor" class="w-full p-2.5 bg-slate-950 border border-slate-700 rounded-xl text-white outline-none">
4912                        </div>
4913                        <div class="control-group">
4914                            <label class="block font-bold text-gray-300 uppercase mb-1">Account / Phone Number *</label>
4915                            <input type="text" id="method-account-number" placeholder="e.g. 09781010356" class="w-full p-2.5 bg-slate-950 border border-slate-700 rounded-xl text-white outline-none">
4916                        </div>
4917                    </div>
4918                    <div class="control-group">
4919                        <label class="block font-bold text-gray-300 uppercase mb-1">Instructions / Note</label>
4920                        <textarea id="method-note" rows="2" placeholder="e.g. Please transfer the fee and take a screenshot." class="w-full p-2.5 bg-slate-950 border border-slate-700 rounded-xl text-white outline-none"></textarea>
4921                    </div>
4922                </div>
4923
4924                <!-- Fields for Online Type -->
4925                <div id="method-online-fields" class="hidden space-y-4">
4926                    <div class="control-group">
4927                        <label class="block font-bold text-gray-300 uppercase mb-1">PayPal Merchant Email *</label>
4928                        <input type="email" id="method-paypal-email" placeholder="e.g. [email protected]" class="w-full p-2.5 bg-slate-950 border border-slate-700 rounded-xl text-white outline-none">
4929                    </div>
4930                </div>
4931
4932                <div class="pt-4 border-t border-slate-800 flex justify-end gap-2">
4933                    <button type="button" onclick="closePaymentMethodFormModal()" class="px-4 py-2 bg-slate-800 hover:bg-slate-700 text-gray-300 font-bold rounded-xl transition">Cancel</button>
4934                    <button type="submit" class="px-5 py-2 bg-sky-600 hover:bg-sky-500 text-white font-black rounded-xl shadow-lg transition">Save Method</button>
4935                </div>
4936            </form>
4937        </div>
4938    </div>
4939    `;
4940
4941    document.body.insertAdjacentHTML('beforeend', workspaceHTML);
4942    loadPaymentMethodsData();
4943    loadTransactionsLedger();
4944};
4945
4946window.switchPaymentPanelTab = function(tab) {
4947    const tabMethods = document.getElementById('pay-tab-methods');
4948    const tabTrans = document.getElementById('pay-tab-transactions');
4949    const viewMethods = document.getElementById('pay-view-methods');
4950    const viewTrans = document.getElementById('pay-view-transactions');
4951
4952    if (tab === 'methods') {
4953        tabMethods.className = 'h-full px-4 border-b-2 border-sky-500 text-sky-400 text-xs font-bold uppercase tracking-wider transition focus:outline-none';
4954        tabTrans.className = 'h-full px-4 border-b-2 border-transparent text-gray-400 hover:text-white text-xs font-bold uppercase tracking-wider transition focus:outline-none';
4955        viewMethods.classList.remove('hidden');
4956        viewTrans.classList.add('hidden');
4957    } else {
4958        tabTrans.className = 'h-full px-4 border-b-2 border-sky-500 text-sky-400 text-xs font-bold uppercase tracking-wider transition focus:outline-none';
4959        tabMethods.className = 'h-full px-4 border-b-2 border-transparent text-gray-400 hover:text-white text-xs font-bold uppercase tracking-wider transition focus:outline-none';
4960        viewTrans.classList.remove('hidden');
4961        viewMethods.classList.add('hidden');
4962    }
4963};
4964
4965window.togglePaymentFormFields = function(type) {
4966    const offBlock = document.getElementById('method-offline-fields');
4967    const onBlock = document.getElementById('method-online-fields');
4968    if (type === 'online') {
4969        onBlock.classList.remove('hidden');
4970        offBlock.classList.add('hidden');
4971    } else {
4972        offBlock.classList.remove('hidden');
4973        onBlock.classList.add('hidden');
4974    }
4975};
4976
4977window.openPaymentMethodFormModal = function(editId = null) {
4978    const modal = document.getElementById('payment-method-form-modal');
4979    const form = document.getElementById('payment-method-editor-form');
4980    const titleEl = document.getElementById('method-modal-title');
4981    const idInput = document.getElementById('method-edit-id');
4982
4983    form.reset();
4984    idInput.value = editId || '';
4985    titleEl.innerText = editId ? 'Edit Payment Method' : '+ Add Payment Method';
4986    togglePaymentFormFields('offline');
4987
4988    if (editId) {
4989        const item = window.allPaymentMethods.find(p => p.id === editId);
4990        if (item) {
4991            document.getElementById('method-type').value = item.type;
4992            document.getElementById('method-name').value = item.name;
4993            document.getElementById('method-logo').value = item.logo || '';
4994            togglePaymentFormFields(item.type);
4995
4996            if (item.type === 'online') {
4997                document.getElementById('method-paypal-email').value = item.paypalEmail || '';
4998            } else {
4999                document.getElementById('method-account-name').value = item.accountName || '';
5000                document.getElementById('method-account-number').value = item.accountNumber || '';
5001                document.getElementById('method-note').value = item.note || '';
5002            }
5003        }
5004    }
5005
5006    modal.classList.remove('hidden');
5007};
5008
5009window.closePaymentMethodFormModal = function() {
5010    document.getElementById('payment-method-form-modal').classList.add('hidden');
5011};
5012
5013window.loadPaymentMethodsData = function() {
5014    const onlineList = document.getElementById('online-gateways-list');
5015    const offlineList = document.getElementById('offline-transfers-list');
5016    if (!onlineList || !offlineList) return;
5017
5018    db.collection("payment_methods").orderBy("createdAt", "asc").onSnapshot(snap => {
5019        window.allPaymentMethods = [];
5020        let onlineHtml = '';
5021        let offlineHtml = '';
5022
5023        snap.forEach(doc => {
5024            const data = doc.data();
5025            data.id = doc.id;
5026            window.allPaymentMethods.push(data);
5027
5028            const resolvedLogo = data.logo || getPaymentMethodLogo(data.name);
5029            const statusColor = data.enabled ? 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30' : 'bg-slate-800 text-gray-500 border-slate-700';
5030            const statusLabel = data.enabled ? 'Enabled' : 'Disabled';
5031
5032            const cardHtml = `
5033            <div class="bg-slate-900/90 border border-slate-800 p-4 rounded-2xl flex items-center justify-between gap-4">
5034                <div class="flex items-center gap-3 min-w-0">
5035                    <img src="${resolvedLogo}" class="w-10 h-10 object-contain rounded-lg flex-shrink-0" onerror="this.src='https://img.icons8.com/color/100/bank-card.png'">
5036                    <div class="min-w-0">
5037                        <h5 class="font-bold text-white text-xs truncate">${data.name}</h5>
5038                        <p class="text-[10px] text-gray-500 truncate">${data.type === 'online' ? (data.paypalEmail || 'PayPal Gateway') : (data.accountNumber || 'Transfer details')}</p>
5039                    </div>
5040                </div>
5041                <div class="flex items-center gap-2">
5042                    <button onclick="togglePaymentMethodStatus('${data.id}', ${data.enabled})" class="border px-2.5 py-1 rounded-full text-[10px] font-black uppercase transition ${statusColor}">
5043                        ${statusLabel}
5044                    </button>
5045                    <button onclick="openPaymentMethodFormModal('${data.id}')" class="text-sky-400 hover:text-sky-300 p-1.5"><i class="fa-solid fa-pen-to-square"></i></button>
5046                    <button onclick="deletePaymentMethod('${data.id}')" class="text-red-500 hover:text-red-400 p-1.5"><i class="fa-solid fa-trash-can"></i></button>
5047                </div>
5048            </div>`;
5049
5050            if (data.type === 'online') {
5051                onlineHtml += cardHtml;
5052            } else {
5053                offlineHtml += cardHtml;
5054            }
5055        });
5056
5057        onlineList.innerHTML = onlineHtml || '<p class="text-xs text-gray-500 italic text-center py-4">No online payment gateways configured.</p>';
5058        offlineList.innerHTML = offlineHtml || '<p class="text-xs text-gray-500 italic text-center py-4">No offline transfer methods configured.</p>';
5059    });
5060};
5061
5062window.savePaymentMethod = async function(e) {
5063    e.preventDefault();
5064    const id = document.getElementById('method-edit-id').value;
5065    const type = document.getElementById('method-type').value;
5066    const name = document.getElementById('method-name').value.trim();
5067    const logo = document.getElementById('method-logo').value.trim();
5068
5069    let payData = {
5070        type,
5071        name,
5072        logo,
5073        enabled: true,
5074        updatedAt: new Date()
5075    };
5076
5077    if (type === 'online') {
5078        payData.paypalEmail = document.getElementById('method-paypal-email').value.trim();
5079    } else {
5080        payData.accountName = document.getElementById('method-account-name').value.trim();
5081        payData.accountNumber = document.getElementById('method-account-number').value.trim();
5082        payData.note = document.getElementById('method-note').value.trim();
5083    }
5084
5085    try {
5086        const docId = id || name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)+/g, '');
5087        if (!id) payData.createdAt = new Date();
5088
5089        await db.collection("payment_methods").doc(docId).set(payData, { merge: true });
5090        closePaymentMethodFormModal();
5091        customToast("Payment method saved globally!", "success");
5092    } catch(err) {
5093        customToast(err.message, "error");
5094    }
5095};
5096
5097window.togglePaymentMethodStatus = async function(id, currentStatus) {
5098    try {
5099        await db.collection("payment_methods").doc(id).update({ enabled: !currentStatus });
5100        customToast(`Payment method ${!currentStatus ? 'enabled' : 'disabled'} globally!`, "success");
5101    } catch(e) {
5102        customToast(e.message, "error");
5103    }
5104};
5105
5106window.deletePaymentMethod = async function(id) {
5107    const confirmed = await customConfirm("Delete Method", "Are you sure you want to permanently delete this payment option? It will be removed from your checkout popup.");
5108    if (confirmed) {
5109        try {
5110            await db.collection("payment_methods").doc(id).delete();
5111            customToast("Payment method deleted.", "info");
5112        } catch(e) {
5113            customToast(e.message, "error");
5114        }
5115    }
5116};
5117
5118window.loadTransactionsLedger = function() {
5119    const tbody = document.getElementById('pay-ledger-table-body');
5120    if (!tbody) return;
5121
5122    db.collection("course_registrations").orderBy("createdAt", "desc").onSnapshot(snap => {
5123        if (snap.empty) {
5124            tbody.innerHTML = `<tr><td colspan="6" class="py-8 text-center text-gray-500 italic">No transactions or course enrolments logged.</td></tr>`;
5125            return;
5126        }
5127
5128        let html = '';
5129        snap.forEach(doc => {
5130            const reg = doc.data();
5131            const docId = doc.id;
5132
5133            let dateStr = "Recently";
5134            if (reg.createdAt && typeof reg.createdAt.toDate === 'function') {
5135                const d = reg.createdAt.toDate();
5136                dateStr = d.toLocaleDateString('en-GB') + ' ' + d.toLocaleTimeString('en-US', { hour12: false, hour: 'numeric', minute: '2-digit' });
5137            }
5138
5139            const isApproved = reg.status === 'Approved';
5140            const isRejected = reg.status === 'Rejected';
5141
5142            const statusBadge = isApproved 
5143                ? `<span class="bg-emerald-500/20 text-emerald-400 border border-emerald-500/30 text-[10px] font-black px-2.5 py-1 rounded-full uppercase">Approved</span>`
5144                : isRejected 
5145                    ? `<span class="bg-red-500/20 text-red-400 border border-red-500/30 text-[10px] font-black px-2.5 py-1 rounded-full uppercase">Rejected</span>`
5146                    : `<span class="bg-amber-500/20 text-amber-400 border border-amber-500/30 text-[10px] font-black px-2.5 py-1 rounded-full uppercase animate-pulse">Pending Review</span>`;
5147
5148            html += `
5149            <tr class="hover:bg-slate-900/50 transition border-b border-slate-800/50">
5150                <td class="py-4 px-4 align-middle">
5151                    <div class="flex items-center gap-3">
5152                        <div class="w-8 h-8 rounded-full bg-blue-600 text-white font-bold flex items-center justify-center text-xs flex-shrink-0">
5153                            ${(reg.studentName || 'S')[0].toUpperCase()}
5154                        </div>
5155                        <div>
5156                            <p class="font-bold text-white text-xs">${reg.studentName || 'Student'}</p>
5157                            <p class="text-[10px] text-gray-400">${reg.studentEmail || ''}</p>
5158                        </div>
5159                    </div>
5160                </td>
5161                <td class="py-4 px-4 align-middle text-gray-200 font-medium">${reg.courseName || 'N/A'}</td>
5162                <td class="py-4 px-4 align-middle text-gray-300 font-mono select-all hover:text-amber-400 transition cursor-pointer" title="Double click to copy Transaction detail">${reg.paymentMethod || 'Local Transfer'}</td>
5163                <td class="py-4 px-4 align-middle text-gray-400 font-mono">${dateStr}</td>
5164                <td class="py-4 px-4 align-middle">${statusBadge}</td>
5165                <td class="py-4 px-4 align-middle text-center">
5166                    <div class="flex items-center justify-center gap-1.5">
5167                        ${!isApproved ? `<button onclick="updatePaymentLedgerStatus('${docId}', 'Approved')" class="bg-emerald-600 hover:bg-emerald-500 text-white font-extrabold px-2.5 py-1.5 rounded-lg transition text-[11px]">Approve</button>` : ''}
5168                        ${!isRejected ? `<button onclick="updatePaymentLedgerStatus('${docId}', 'Rejected')" class="bg-slate-800 hover:bg-red-600 text-gray-300 hover:text-white font-extrabold px-2.5 py-1.5 rounded-lg transition text-[11px]">Reject</button>` : ''}
5169                    </div>
5170                </td>
5171            </tr>`;
5172        });
5173
5174        tbody.innerHTML = html;
5175    }, err => {
5176        tbody.innerHTML = `<tr><td colspan="6" class="py-8 text-center text-red-400 italic">Error loading transactions: ${err.message}</td></tr>`;
5177    });
5178};
5179
5180window.updatePaymentLedgerStatus = async function(docId, newStatus) {
5181    try {
5182        await db.collection("course_registrations").doc(docId).update({
5183            status: newStatus,
5184            reviewedAt: new Date()
5185        });
5186        customToast(`Enrolment set to '${newStatus}'!`, "success");
5187    } catch(e) {
5188        customToast(e.message, "error");
5189    }
5190};
5191
5192
5193//===================================//
5194//--- DATABASE BACKUP AND RESTORE ---//
5195//===================================//
5196window.openFullscreenBackupManager = function() {
5197    const existingWs = document.getElementById('admin-fullscreen-workspace');
5198    if (existingWs) existingWs.remove();
5199
5200    const workspaceHTML = `
5201    <div id="admin-fullscreen-workspace" class="fixed inset-0 z-[999999] bg-[#0b0f19] text-white flex flex-col font-sans overflow-hidden">
5202        
5203        <!-- Top Bar -->
5204        <div class="bg-slate-950 text-gray-300 h-14 px-8 flex items-center justify-between border-b border-slate-800 shadow-xl flex-shrink-0">
5205            <div class="flex items-center gap-3">
5206                <div class="w-9 h-9 bg-teal-600 text-white rounded-xl flex items-center justify-center font-black text-lg">
5207                    <i class="fa-solid fa-database"></i>
5208                </div>
5209                <div>
5210                    <h2 class="font-black text-lg text-white leading-none">Universal Database Backup & Restore Suite</h2>
5211                    <p class="text-[11px] text-gray-400">Granular partial export, selective restore, and clean database wipeout.</p>
5212                </div>
5213            </div>
5214            
5215            <button onclick="document.getElementById('admin-fullscreen-workspace').remove(); document.body.classList.remove('overflow-hidden');" class="bg-red-600/20 text-red-400 border border-red-500/30 px-5 py-2 rounded-xl text-xs font-bold hover:bg-red-600/40 transition">
5216                ✕ Close Panel
5217            </button>
5218        </div>
5219
5220        <!-- Main Panel Container (1280px Max Width - 2 Column Grid) -->
5221        <div class="flex-1 overflow-y-auto p-6 md:p-10 flex justify-center items-start">
5222            <div class="w-full max-w-[1280px] grid grid-cols-1 lg:grid-cols-12 gap-8">
5223                
5224                <!-- LEFT COLUMN: Collections Table of Contents with Checkboxes (7 Cols) -->
5225                <div class="lg:col-span-7 bg-[#131927] border border-slate-800 rounded-3xl p-6 shadow-2xl flex flex-col space-y-4">
5226                    <div class="flex justify-between items-center border-b border-slate-800 pb-3">
5227                        <div class="flex items-center gap-2">
5228                            <h3 class="font-black text-sm text-white flex items-center gap-2">
5229                                <i class="fa-solid fa-table-cells text-teal-400"></i> Collections Selector & Total Sizes
5230                            </h3>
5231                        </div>
5232                        <span id="total-db-size-badge" class="text-xs bg-slate-800 text-teal-400 border border-slate-700 px-3 py-1 rounded-full font-bold">Total Footprint: Calculating...</span>
5233                    </div>
5234                    <p class="text-[11px] text-gray-400 leading-relaxed">
5235                        Check or uncheck specific tables below to include or exclude them from your <strong>Partial Backup</strong> or <strong>Partial Restore</strong> operations.
5236                    </p>
5237
5238                    <!-- Expanded table view without harsh internal cutoffs -->
5239                    <div class="overflow-x-auto rounded-2xl border border-slate-800 bg-slate-950/50">
5240                        <table class="w-full text-left text-xs border-collapse">
5241                            <thead>
5242                                <tr class="text-gray-400 font-extrabold uppercase border-b border-slate-800 bg-slate-950">
5243                                    <!-- 🟢 Master Checkbox moved into the header column -->
5244                                    <th class="py-3.5 px-4 w-12 text-center">
5245                                        <input type="checkbox" id="backup-select-all-cb" checked onchange="toggleAllBackupCollections(this)" class="w-4 h-4 rounded text-teal-600 bg-slate-900 border-slate-700 cursor-pointer" title="Select All">
5246                                    </th>
5247                                    <th class="py-3.5 px-4">Collection Name</th>
5248                                    <th class="py-3.5 px-4 text-center">Records (Size)</th>
5249                                    <th class="py-3.5 px-4 text-right">Status</th>
5250                                </tr>
5251                            </thead>
5252                            <tbody id="backup-schema-table-body" class="divide-y divide-slate-800/60">
5253                                <tr>
5254                                    <td colspan="4" class="py-8 text-center text-gray-400 italic">Scanning database schema...</td>
5255                                </tr>
5256                            </tbody>
5257                        </table>
5258                    </div>
5259                </div>
5260
5261                <!-- RIGHT COLUMN: Database Management Actions (5 Cols) -->
5262                <div class="lg:col-span-5 space-y-6">
5263                    
5264                    <!-- Action Card 1: Partial / Full Export -->
5265                    <div class="bg-[#131927] border border-slate-800 rounded-3xl p-6 shadow-2xl space-y-4">
5266                        <h3 class="text-base font-black text-white flex items-center gap-2 border-b border-slate-800 pb-3">
5267                            <i class="fa-solid fa-cloud-arrow-down text-teal-400"></i> Export Selected Data
5268                        </h3>
5269                        <p class="text-xs text-gray-400 leading-relaxed">
5270                            Downloads a <code>.json</code> file containing only the checked collections on the left.
5271                        </p>
5272                        <button onclick="executeDynamicDatabaseExport()" class="w-full bg-teal-600 hover:bg-teal-500 text-white font-black py-3 rounded-xl text-xs transition shadow-lg flex items-center justify-center gap-2">
5273                            <i class="fa-solid fa-download"></i> Download Partial/Full Backup (.json)
5274                        </button>
5275                    </div>
5276
5277                    <!-- Action Card 2: Partial / Full Restore -->
5278                    <div class="bg-[#131927] border border-slate-800 rounded-3xl p-6 shadow-2xl space-y-4">
5279                        <h3 class="text-base font-black text-white flex items-center gap-2 border-b border-slate-800 pb-3">
5280                            <i class="fa-solid fa-cloud-arrow-up text-amber-400"></i> Restore Selected Data
5281                        </h3>
5282                        <p class="text-xs text-gray-400 leading-relaxed">
5283                            Upload a backup file. Only the checked collections on the left will be restored into Firestore.
5284                        </p>
5285                        <input type="file" id="restore-json-file-input" accept=".json" class="w-full text-xs text-gray-400 file:mr-4 file:py-2.5 file:px-4 file:rounded-xl file:border-0 file:text-xs file:font-bold file:bg-slate-800 file:text-white hover:file:bg-slate-700 cursor-pointer mb-2">
5286                        <button onclick="executeDynamicDatabaseRestore()" class="w-full bg-amber-500 hover:bg-amber-400 text-slate-950 font-black py-3 rounded-xl text-xs transition shadow-lg flex items-center justify-center gap-2">
5287                            <i class="fa-solid fa-upload"></i> Restore Selected Collections
5288                        </button>
5289                    </div>
5290
5291                    <!-- Action Card 3: Danger Zone - Database Wipeout -->
5292                    <div class="bg-slate-950 border border-red-900/40 rounded-3xl p-6 shadow-2xl space-y-4">
5293                        <h3 class="text-base font-black text-red-400 flex items-center gap-2 border-b border-slate-800 pb-3">
5294                            <i class="fa-solid fa-triangle-exclamation"></i> Danger Zone: Database Wipeout
5295                        </h3>
5296                        <p class="text-xs text-gray-400 leading-relaxed">
5297                            Permanently delete all documents inside the checked collections on the left. This action cannot be undone!
5298                        </p>
5299                        <button onclick="executeDatabaseWipeout()" class="w-full bg-red-600 hover:bg-red-500 text-white font-black py-3 rounded-xl text-xs transition shadow-lg flex items-center justify-center gap-2">
5300                            <i class="fa-solid fa-skull"></i> Wipe Out Selected Collections
5301                        </button>
5302                    </div>
5303
5304                </div>
5305
5306            </div>
5307        </div>
5308    </div>
5309    `;
5310
5311    document.body.insertAdjacentHTML('beforeend', workspaceHTML);
5312    document.body.classList.add('overflow-hidden');
5313    loadBackupSchemaTable();
5314};
5315
5316const collectionsMeta = [
5317    { name: "users", desc: "User accounts & roles" },
5318    { name: "site_builder_pages", desc: "Custom visual builder pages" },
5319    { name: "blog_posts", desc: "Articles & event posts" },
5320    { name: "library_bookshelves", desc: "Digital library 3D shelves" },
5321    { name: "course_registrations", desc: "Student course enrollments" },
5322    { name: "site_comments", desc: "Community reviews & ratings" },
5323    { name: "payment_methods", desc: "Payment gateways" },
5324    { name: "site_settings", desc: "Navigation menus & settings" },
5325    { name: "site_seo", desc: "Sitemap XML strings" },
5326    { name: "live_pages", desc: "Cached live edits" },
5327    { name: "email_queue", desc: "Notification emails queue" },
5328    { name: "contact_messages", desc: "Contact inquiries" }
5329];
5330
5331async function loadBackupSchemaTable() {
5332    const tbody = document.getElementById('backup-schema-table-body');
5333    const sizeBadge = document.getElementById('total-db-size-badge');
5334    if (!tbody) return;
5335
5336    try {
5337        let html = '';
5338        let totalDatabaseBytes = 0;
5339        let totalRecordsCount = 0;
5340
5341        for (let [idx, col] of collectionsMeta.entries()) {
5342            let count = 0;
5343            let collectionBytes = 0;
5344            let statusHtml = '<span class="text-gray-500 font-medium">Empty</span>';
5345            
5346            try {
5347                const snap = await db.collection(col.name).get();
5348                count = snap.size;
5349                totalRecordsCount += count;
5350
5351                snap.forEach(doc => {
5352                    const docString = JSON.stringify(doc.data());
5353                    const docBytes = new TextEncoder().encode(docString).length;
5354                    collectionBytes += docBytes;
5355                });
5356
5357                totalDatabaseBytes += collectionBytes;
5358
5359                if (count > 0) {
5360                    statusHtml = '<span class="text-teal-400 font-bold bg-teal-500/10 px-2 py-0.5 rounded text-[10px]">Active</span>';
5361                }
5362            } catch(err) {
5363                statusHtml = '<span class="text-red-400 font-medium">Restricted</span>';
5364            }
5365
5366            let formattedSize = '0 B';
5367            if (collectionBytes > 1024 * 1024) {
5368                formattedSize = (collectionBytes / (1024 * 1024)).toFixed(2) + ' MB';
5369            } else if (collectionBytes > 1024) {
5370                formattedSize = (collectionBytes / 1024).toFixed(1) + ' KB';
5371            } else if (collectionBytes > 0) {
5372                formattedSize = collectionBytes + ' B';
5373            }
5374
5375            html += `
5376            <tr class="hover:bg-slate-900/40 transition">
5377                <td class="py-3 px-4 text-center">
5378                    <input type="checkbox" name="backup_col_cb" value="${col.name}" checked class="w-4 h-4 rounded text-teal-600 bg-slate-900 border-slate-700 cursor-pointer">
5379                </td>
5380                <td class="py-3 px-4 font-mono font-bold text-amber-400">${col.name}</td>
5381                <td class="py-3 px-4 text-center font-black text-white">${count} <span class="text-[10px] text-gray-500 font-normal">(${formattedSize})</span></td>
5382                <td class="py-3 px-4 text-right">${statusHtml}</td>
5383            </tr>`;
5384        }
5385
5386        tbody.innerHTML = html;
5387
5388        // Display entire website database size badge at the top
5389        let totalFormatted = totalDatabaseBytes > 1024 * 1024 
5390            ? (totalDatabaseBytes / (1024 * 1024)).toFixed(2) + ' MB' 
5391            : (totalDatabaseBytes / 1024).toFixed(1) + ' KB';
5392
5393        if (sizeBadge) {
5394            sizeBadge.innerText = `Total Footprint: ${totalFormatted} (${totalRecordsCount} Records)`;
5395        }
5396
5397    } catch(e) {
5398        tbody.innerHTML = `<tr><td colspan="4" class="py-6 text-center text-red-400 italic">Error scanning schema: ${e.message}</td></tr>`;
5399    }
5400}
5401
5402window.toggleAllBackupCollections = function(source) {
5403    const checkboxes = document.querySelectorAll('input[name="backup_col_cb"]');
5404    checkboxes.forEach(cb => cb.checked = source.checked);
5405};
5406
5407// 🟢 PARTIAL EXPORT FUNCTION (Using custom toast)
5408window.executeDynamicDatabaseExport = async function() {
5409    try {
5410        const checkedBoxes = document.querySelectorAll('input[name="backup_col_cb"]:checked');
5411        if (checkedBoxes.length === 0) {
5412            if (typeof customToast === 'function') customToast("Please check at least one collection to export.", "error");
5413            else alert("Please check at least one collection to export.");
5414            return;
5415        }
5416
5417        if (typeof customToast === 'function') customToast("Scanning selected collections for export...", "info");
5418        let backupData = {};
5419
5420        for (let cb of checkedBoxes) {
5421            const colName = cb.value;
5422            const snap = await db.collection(colName).get();
5423            if (!snap.empty) {
5424                backupData[colName] = {};
5425                snap.forEach(doc => {
5426                    const docData = doc.data();
5427                    
5428                    // 🟢 SAFETY: Skip exporting the master admin user account
5429                    if (colName === 'users' && (docData.email || '').toLowerCase() === '[email protected]') {
5430                        return; 
5431                    }
5432
5433                    backupData[colName][doc.id] = docData;
5434                });
5435            }
5436        }
5437
5438        const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(backupData, null, 2));
5439        const downloadAnchor = document.createElement('a');
5440        const dateStr = new Date().toISOString().split('T')[0];
5441        
5442        downloadAnchor.setAttribute("href", dataStr);
5443        downloadAnchor.setAttribute("download", `alin-tagar-partial-backup-${dateStr}.json`);
5444        document.body.appendChild(downloadAnchor);
5445        downloadAnchor.click();
5446        downloadAnchor.remove();
5447
5448        if (typeof customToast === 'function') customToast("Database exported successfully as JSON!", "success");
5449        else alert("Database exported successfully as JSON!");
5450    } catch(e) {
5451        console.error("Export error:", e);
5452        if (typeof customToast === 'function') customToast("Export error: " + e.message, "error");
5453        else alert("Export error: " + e.message);
5454    }
5455};
5456
5457// 🟢 PARTIAL RESTORE FUNCTION (Using custom modal confirm & toast)
5458window.executeDynamicDatabaseRestore = async function() {
5459    const fileInput = document.getElementById('restore-json-file-input');
5460    if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
5461        if (typeof customToast === 'function') customToast("Please select a valid backup .json file first.", "error");
5462        else alert("Please select a valid backup .json file first.");
5463        return;
5464    }
5465
5466    const checkedBoxes = document.querySelectorAll('input[name="backup_col_cb"]:checked');
5467    if (checkedBoxes.length === 0) {
5468        if (typeof customToast === 'function') customToast("Please check at least one collection on the left to restore into.", "error");
5469        else alert("Please check at least one collection on the left to restore into.");
5470        return;
5471    }
5472    const allowedCols = Array.from(checkedBoxes).map(cb => cb.value);
5473
5474    const file = fileInput.files[0];
5475    const reader = new FileReader();
5476
5477    reader.onload = async function(e) {
5478        try {
5479            const backupData = JSON.parse(e.target.result);
5480            
5481            const confirmed = typeof customConfirm === 'function'
5482                ? await customConfirm("Restore Database", "Are you sure you want to restore selected collections? Existing records with matching IDs will be updated.")
5483                : confirm("Are you sure you want to restore selected collections? Existing records with matching IDs will be updated.");
5484
5485            if (!confirmed) return;
5486
5487            if (typeof customToast === 'function') customToast("Restoring selected records... Please wait.", "info");
5488
5489            let restoredCount = 0;
5490            for (let colName in backupData) {
5491                if (allowedCols.includes(colName)) {
5492                    const colDocs = backupData[colName];
5493                    for (let docId in colDocs) {
5494                        let docData = colDocs[docId];
5495                        
5496                        // 🟢 SAFETY: Never touch or overwrite the master admin user account during restore
5497                        if (colName === 'users' && (docData.email || '').toLowerCase() === '[email protected]') {
5498                            continue; 
5499                        }
5500
5501                        await db.collection(colName).doc(docId).set(docData, { merge: true });
5502                        restoredCount++;
5503                    }
5504                }
5505            }
5506
5507            if (typeof customToast === 'function') customToast(`Successfully restored ${restoredCount} document(s)! Refreshing...`, "success");
5508            else alert(`Successfully restored ${restoredCount} document(s)!`);
5509
5510            // 🟢 Auto-refresh the page to reflect restored counts instantly
5511            setTimeout(() => {
5512                window.location.reload();
5513            }, 1500);
5514        } catch(err) {
5515            console.error("Restore error:", err);
5516            if (typeof customToast === 'function') customToast("Restore error: " + err.message, "error");
5517            else alert("Restore error: " + err.message);
5518        }
5519    };
5520
5521    reader.readAsText(file);
5522};
5523
5524// 🟢 DATABASE WIPEOUT FUNCTION (Using custom modal confirm & toast)
5525window.executeDatabaseWipeout = async function() {
5526    const checkedBoxes = document.querySelectorAll('input[name="backup_col_cb"]:checked');
5527    if (checkedBoxes.length === 0) {
5528        if (typeof customToast === 'function') customToast("Please check at least one collection to wipe out.", "error");
5529        else alert("Please check at least one collection to wipe out.");
5530        return;
5531    }
5532
5533    const confirmed = typeof customConfirm === 'function'
5534        ? await customConfirm("⚠️ DANGER: Database Wipeout", "Are you completely sure you want to delete ALL documents inside the selected collections? This cannot be undone!")
5535        : confirm("⚠️ DANGER: Are you completely sure you want to delete ALL documents inside the selected collections?");
5536
5537    if (!confirmed) return;
5538
5539    const userVerification = await customPrompt(
5540        "🔒 Final Security Verification", 
5541        "To protect your data, this action requires explicit confirmation. Please type the word 'WIPE' below to unlock deletion:", 
5542        ""
5543    );
5544
5545    if (!userVerification || userVerification.trim().toUpperCase() !== 'WIPE') {
5546        if (typeof customToast === 'function') customToast("Wipeout cancelled. Verification word did not match.", "info");
5547        else alert("Wipeout cancelled. Verification word did not match.");
5548        return;
5549    }
5550
5551    try {
5552        if (typeof customToast === 'function') customToast("Wiping out selected collections... Please wait.", "info");
5553
5554        for (let cb of checkedBoxes) {
5555            const colName = cb.value;
5556            const snap = await db.collection(colName).get();
5557            
5558            const batch = db.batch();
5559            snap.docs.forEach(doc => {
5560                const docData = doc.data();
5561                
5562                // 🟢 ULTIMATE ADMIN SAFETY LOCK: Never delete the admin account document!
5563                if (colName === 'users') {
5564                    const docEmail = (docData.email || '').toLowerCase().trim();
5565                    if (docEmail === '[email protected]' || doc.id === 'qpJ1ojwul2YL6LO1udqJOkQzUI23') {
5566                        return; // Skips deleting the admin document entirely!
5567                    }
5568                }
5569
5570                batch.delete(doc.ref);
5571            });
5572            await batch.commit();
5573        }
5574
5575        if (typeof customToast === 'function') customToast("Selected collections have been wiped out safely (Admin protected).", "success");
5576        else alert("Selected collections have been wiped out safely.");
5577
5578        loadBackupSchemaTable();
5579    } catch(err) {
5580        console.error("Wipeout error:", err);
5581        if (typeof customToast === 'function') customToast("Wipeout error: " + err.message, "error");
5582        else alert("Wipeout error: " + err.message);
5583    }
5584};
5585

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.