/* CourseHub SPA — hash router + fetch API + Plyr player. * Routes: #/ home (courses, continue watching) * #/folder/N browse a folder * #/watch/N video player */ (function () { 'use strict'; const app = document.getElementById('app'); const state = { user: null }; let cleanupView = null; // teardown hook for the active view (player etc.) /* ---------- helpers ---------- */ const esc = (s) => String(s ?? '').replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c])); function fmt(seconds) { if (!seconds || seconds <= 0) return ''; const s = Math.round(seconds); const h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60; return h ? `${h}:${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')}` : `${m}:${String(sec).padStart(2, '0')}`; } function toast(message, kind = 'success') { const wrap = document.createElement('div'); wrap.innerHTML = `