diff --git a/popup.css b/popup.css
new file mode 100644
index 0000000..fa33166
--- /dev/null
+++ b/popup.css
@@ -0,0 +1,64 @@
+* { box-sizing: border-box; }
+body {
+ width: 360px;
+ margin: 0;
+ font-family: system-ui, sans-serif;
+ font-size: 13px;
+ color: #222;
+}
+.top {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 10px 12px;
+ background: #006699;
+ color: #fff;
+}
+.top h1 { margin: 0; font-size: 16px; }
+.master { display: flex; align-items: center; gap: 6px; }
+.switch { position: relative; display: inline-block; width: 40px; height: 22px; }
+.switch input { display: none; }
+.slider {
+ position: absolute; cursor: pointer; inset: 0;
+ background: #ccc; border-radius: 22px; transition: 0.2s;
+}
+.slider::before {
+ content: ""; position: absolute; height: 18px; width: 18px;
+ left: 2px; top: 2px; background: #fff; border-radius: 50%; transition: 0.2s;
+}
+.switch input:checked + .slider { background: #4caf50; }
+.switch input:checked + .slider::before { transform: translateX(18px); }
+.tabs { display: flex; border-bottom: 1px solid #ddd; }
+.tabs button {
+ flex: 1; padding: 8px; border: none; background: #f5f5f5; cursor: pointer;
+}
+.tabs button.active { background: #fff; font-weight: bold; border-bottom: 2px solid #006699; }
+.tab { padding: 12px; }
+.tab h2 { margin: 0 0 8px; font-size: 14px; }
+.tab h3 { margin: 12px 0 6px; font-size: 12px; color: #555; }
+.profile-list { list-style: none; margin: 0 0 8px; padding: 0; }
+.profile-list li {
+ display: flex; align-items: center; gap: 6px;
+ padding: 6px; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 6px;
+}
+.profile-list .name { flex: 1; }
+.profile-list .user { color: #777; font-size: 11px; }
+.btn {
+ padding: 6px 10px; border: 1px solid #ccc; border-radius: 4px;
+ background: #fff; cursor: pointer;
+}
+.btn.primary { background: #006699; color: #fff; border-color: #006699; }
+.btn-row { display: flex; gap: 6px; margin-top: 6px; }
+.form input {
+ width: 100%; padding: 6px; margin-bottom: 6px;
+ border: 1px solid #ccc; border-radius: 4px;
+}
+.form .row { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
+.course-row {
+ border: 1px solid #ddd; border-radius: 4px; padding: 6px; margin-bottom: 6px;
+}
+.course-row .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
+.course-row input { margin-bottom: 4px; }
+.status { margin-top: 8px; font-size: 12px; }
+.status.error { color: #c00; }
+.status.ok { color: #080; }
diff --git a/popup.html b/popup.html
new file mode 100644
index 0000000..6d3f939
--- /dev/null
+++ b/popup.html
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Profiles
+
+
+
+
+
+
+ Study Load PDF
+
+
+
+
+
+
+
+
diff --git a/popup.js b/popup.js
new file mode 100644
index 0000000..6b75100
--- /dev/null
+++ b/popup.js
@@ -0,0 +1,212 @@
+'use strict';
+
+const $ = (sel) => document.querySelector(sel);
+
+const MASTER_KEY = 'enabled';
+const PROFILES_KEY = 'profiles';
+
+let editingProfileId = null;
+
+// ---- Master toggle ----
+async function loadMaster() {
+ const { enabled } = await browser.storage.local.get(MASTER_KEY);
+ $('#masterToggle').checked = enabled !== false;
+ $('#masterLabel').textContent = enabled === false ? 'Disabled' : 'Enabled';
+}
+$('#masterToggle').addEventListener('change', async (e) => {
+ await browser.storage.local.set({ [MASTER_KEY]: e.target.checked });
+ $('#masterLabel').textContent = e.target.checked ? 'Enabled' : 'Disabled';
+});
+
+// ---- Profiles ----
+async function getProfiles() {
+ const { profiles } = await browser.storage.local.get(PROFILES_KEY);
+ return profiles || [];
+}
+async function saveProfiles(profiles) {
+ await browser.storage.local.set({ [PROFILES_KEY]: profiles });
+}
+
+function renderProfiles(profiles) {
+ const list = $('#profileList');
+ list.innerHTML = '';
+ for (const p of profiles) {
+ const li = document.createElement('li');
+ const name = document.createElement('div');
+ name.className = 'name';
+ name.innerHTML = '' + escapeHtml(p.name) + '
' + escapeHtml(p.username) + '';
+ const toggle = document.createElement('input');
+ toggle.type = 'checkbox';
+ toggle.checked = !!p.enabled;
+ toggle.title = 'Enable/disable';
+ toggle.addEventListener('change', async () => {
+ p.enabled = toggle.checked;
+ await saveProfiles(profiles);
+ });
+ const edit = document.createElement('button');
+ edit.className = 'btn';
+ edit.textContent = 'Edit';
+ edit.addEventListener('click', () => openProfileForm(p));
+ const del = document.createElement('button');
+ del.className = 'btn';
+ del.textContent = 'Delete';
+ del.addEventListener('click', async () => {
+ await saveProfiles(profiles.filter((x) => x.id !== p.id));
+ renderProfiles(await getProfiles());
+ });
+ li.append(toggle, name, edit, del);
+ list.appendChild(li);
+ }
+}
+
+function escapeHtml(s) {
+ return String(s).replace(/[&<>"']/g, (c) => ({
+ '&': '&', '<': '<', '>': '>', '"': '"', "'": '''
+ }[c]));
+}
+
+function openProfileForm(p) {
+ editingProfileId = p ? p.id : null;
+ $('#pName').value = p ? p.name : '';
+ $('#pUsername').value = p ? p.username : '';
+ $('#pPassword').value = p ? p.password : '';
+ $('#pEnabled').checked = p ? !!p.enabled : true;
+ $('#profileForm').hidden = false;
+}
+$('#addProfile').addEventListener('click', () => openProfileForm(null));
+$('#cancelProfile').addEventListener('click', () => { $('#profileForm').hidden = true; });
+$('#saveProfile').addEventListener('click', async () => {
+ const profiles = await getProfiles();
+ const data = {
+ id: editingProfileId || Date.now().toString(),
+ name: $('#pName').value.trim(),
+ username: $('#pUsername').value.trim(),
+ password: $('#pPassword').value,
+ enabled: $('#pEnabled').checked
+ };
+ if (!data.name || !data.username) return;
+ if (editingProfileId) {
+ const i = profiles.findIndex((x) => x.id === editingProfileId);
+ if (i >= 0) profiles[i] = data;
+ } else {
+ profiles.push(data);
+ }
+ await saveProfiles(profiles);
+ $('#profileForm').hidden = true;
+ renderProfiles(profiles);
+});
+
+// ---- Tabs ----
+document.querySelectorAll('.tabs button').forEach((btn) => {
+ btn.addEventListener('click', () => {
+ document.querySelectorAll('.tabs button').forEach((b) => b.classList.remove('active'));
+ btn.classList.add('active');
+ $('#tab-login').hidden = btn.dataset.tab !== 'login';
+ $('#tab-studyload').hidden = btn.dataset.tab !== 'studyload';
+ });
+});
+
+// ---- Study Load ----
+function setStatus(msg, cls) {
+ const el = $('#status');
+ el.textContent = msg;
+ el.className = 'status ' + (cls || '');
+}
+
+function renderCourses(courses) {
+ const box = $('#coursesEditor');
+ box.innerHTML = '';
+ courses.forEach((c, i) => {
+ const row = document.createElement('div');
+ row.className = 'course-row';
+ row.innerHTML =
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '
' +
+ '' +
+ '';
+ box.appendChild(row);
+ });
+ box.querySelectorAll('input').forEach((inp) => {
+ inp.addEventListener('input', () => {
+ const i = +inp.dataset.i;
+ const f = inp.dataset.f;
+ studyLoadCourses[i][f] = inp.value;
+ });
+ });
+ box.querySelectorAll('.remove-course').forEach((btn) => {
+ btn.addEventListener('click', () => {
+ studyLoadCourses.splice(+btn.dataset.i, 1);
+ renderCourses(studyLoadCourses);
+ });
+ });
+}
+
+let studyLoadCourses = [];
+
+$('#loadFromPortal').addEventListener('click', async () => {
+ setStatus('Loading from portal...');
+ try {
+ const res = await browser.runtime.sendMessage({ type: 'scrape-study-load' });
+ if (!res || !res.ok) throw new Error((res && res.error) || 'Scrape failed');
+ const d = res.data;
+ $('#hFullName').value = d.header.fullName || '';
+ $('#hStudentId').value = d.header.studentId || '';
+ $('#hProgram').value = d.header.program || '';
+ $('#hYearLevel').value = d.header.yearLevel || '';
+ $('#hSemester').value = d.header.semester || '';
+ $('#hDateEnrolled').value = d.header.dateEnrolled || '';
+ $('#hDateRange').value = d.header.dateRange || '';
+ $('#totalUnits').value = d.totalUnits || '';
+ studyLoadCourses = d.courses || [];
+ renderCourses(studyLoadCourses);
+ $('#studyLoadForm').hidden = false;
+ setStatus('Loaded. Review and generate.', 'ok');
+ } catch (err) {
+ setStatus('Could not load from portal: ' + err.message + ' — enter manually below.', 'error');
+ studyLoadCourses = [];
+ renderCourses(studyLoadCourses);
+ $('#studyLoadForm').hidden = false;
+ }
+});
+
+$('#addCourse').addEventListener('click', () => {
+ studyLoadCourses.push({ group: '', courseCode: '', description: '', units: '', teacher: '', schedule: '', status: '' });
+ renderCourses(studyLoadCourses);
+});
+
+$('#generatePdf').addEventListener('click', async () => {
+ const data = {
+ header: {
+ fullName: $('#hFullName').value.trim(),
+ studentId: $('#hStudentId').value.trim(),
+ program: $('#hProgram').value.trim(),
+ yearLevel: $('#hYearLevel').value.trim(),
+ semester: $('#hSemester').value.trim(),
+ dateEnrolled: $('#hDateEnrolled').value.trim(),
+ dateRange: $('#hDateRange').value.trim()
+ },
+ courses: studyLoadCourses,
+ totalUnits: $('#totalUnits').value.trim()
+ };
+ if (!data.courses.length) { setStatus('Add at least one course.', 'error'); return; }
+ setStatus('Generating PDF...');
+ try {
+ const res = await browser.runtime.sendMessage({ type: 'generate-pdf', data });
+ if (!res || !res.ok) throw new Error((res && res.error) || 'Generation failed');
+ setStatus('PDF downloaded.', 'ok');
+ } catch (err) {
+ setStatus('Error: ' + err.message, 'error');
+ }
+});
+
+// ---- Init ----
+(async function init() {
+ await loadMaster();
+ renderProfiles(await getProfiles());
+})();