diff --git a/docz/static/electron/index.html b/docz/static/electron/index.html
index 872a07d..cb3fd57 100644
--- a/docz/static/electron/index.html
+++ b/docz/static/electron/index.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <!-- sheetjs (C) 2013-present  SheetJS https://sheetjs.com -->
-<!-- vim: set ts=2: -->
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
@@ -27,6 +26,7 @@
     </div>
   </section>
   <div id="fileStatus" class="file-status"></div>
+  <div id="onError"></div>
   <section id="htmlout" class="table-responsive"></section>
   <section class="export">
     <p><input type="submit" value="Export" id="exportBtn" disabled="true" tabindex="0" aria-label="Export spreadsheet"></p>
@@ -39,5 +39,5 @@
   </ul>
 </footer>
 <script src="index.js"></script>
-<!-- Cloudflare Pages Analytics --><script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "5045fe4c2b784ddb8c3c6ee7fa0593e5"}'></script><!-- Cloudflare Pages Analytics --></body>
+</body>
 </html>
diff --git a/docz/static/electron/index.js b/docz/static/electron/index.js
index 2bd606f..9cf5f8c 100644
--- a/docz/static/electron/index.js
+++ b/docz/static/electron/index.js
@@ -1,21 +1,37 @@
 const XLSX = require("xlsx");
+// TODO: Replace deprecated @electron/remote with contextBridge‑based IPC in production.
 const electron = require("@electron/remote");
-const { ipcRenderer } = require('electron');
+const { ipcRenderer } = require("electron");
+const path = require("path");
 
-// --- Supported Extensions ---
+// ---------------------------------------------------------------------------
+// Supported file extensions
+// ---------------------------------------------------------------------------
 const EXTENSIONS =
   "xls|xlsx|xlsm|xlsb|xml|csv|txt|dif|sylk|slk|prn|ods|fods|htm|html|numbers".split(
-    "|"
+    "|",
   );
 
-const dropContainer = document.getElementById("drop-container");
-const dropzone = document.getElementById("drop");
-const fileStatus = document.getElementById("fileStatus");
-const exportBtn = document.getElementById("exportBtn");
+// ---------------------------------------------------------------------------
+// DOM references
+// ---------------------------------------------------------------------------
+const dropContainer  = document.getElementById("drop-container");
+const fileStatus     = document.getElementById("fileStatus");
+const exportBtn      = document.getElementById("exportBtn");
 const spinnerOverlay = document.getElementById("spinner-overlay");
-const htmlout = document.getElementById("htmlout");
+const htmlout        = document.getElementById("htmlout");
+const onError        = document.getElementById("onError");
 
-// open external links in default browser
+// ---------------------------------------------------------------------------
+// State & helpers
+// ---------------------------------------------------------------------------
+let currentWorkbook = null;              // SheetJS workbook in memory
+const isSpreadsheet = (ext) => EXTENSIONS.includes(ext.toLowerCase());
+const nextPaint     = () => new Promise(requestAnimationFrame);
+
+// ---------------------------------------------------------------------------
+// Open external links in default browser (security)
+// ---------------------------------------------------------------------------
 document.addEventListener("click", (e) => {
   if (e.target.tagName === "A" && e.target.href.startsWith("http")) {
     e.preventDefault();
@@ -23,195 +39,190 @@ document.addEventListener("click", (e) => {
   }
 });
 
-/**
- * Export current HTML table as a spreadsheet file using Electron API.
- */
-async function exportFile() {
-  const wb = XLSX.utils.table_to_book(htmlout.getElementsByTagName("TABLE")[0]);
-  const o = await electron.dialog.showSaveDialog({
+// ---------------------------------------------------------------------------
+// Export logic – uses cached workbook (no DOM traversal)
+// ---------------------------------------------------------------------------
+async function exportWorkbookAsFile() {
+  if (!currentWorkbook) return displayError("No workbook loaded!");
+  // -- 1. use electron save as dialog to get file path
+  const { filePath, canceled } = await electron.dialog.showSaveDialog({
     title: "Save file as",
     filters: [{ name: "Spreadsheets", extensions: EXTENSIONS }],
   });
-  XLSX.writeFile(wb, o.filePath);
-  electron.dialog.showMessageBox({
-    message: "Exported data to " + o.filePath,
-    buttons: ["OK"],
-  });
+  // -- 2. if canceled or no file path, return
+  if (canceled || !filePath) return;
+  // -- 3. write workbook to file
+  try {
+    XLSX.writeFile(currentWorkbook, filePath);
+    electron.dialog.showMessageBox({ message: `Exported to ${filePath}` });
+  } catch (err) {
+    // -- 4. if error, display error
+    displayError(`Failed to export: ${err.message}`);
+  }
 }
+exportBtn.addEventListener("click", exportWorkbookAsFile);
 
-exportBtn.addEventListener("click", exportFile, false);
-
+// ---------------------------------------------------------------------------
+// Render workbook --> HTML tables
+// ---------------------------------------------------------------------------
 function renderWorkbookToTables(wb) {
-  htmlout.innerHTML = "";
-  const sheetNames = wb.SheetNames;
-  sheetNames.forEach((sheetName) => {
-    const sheet = wb.Sheets[sheetName];
-    const table = XLSX.utils.sheet_to_html(sheet);
-    htmlout.innerHTML += `<details class="sheetjs-sheet-container">
-    <summary class="sheetjs-sheet-name">${sheetName}</summary>
-    <div class="sheetjs-tab-content">${table}</div>
-  </details>`;
-  });
+  // -- 1. convert each sheet to HTML
+  const html = wb.SheetNames.map((name) => {
+    const sheet = wb.Sheets[name];
+    const table = XLSX.utils.sheet_to_html(sheet, { id: `${name}-tbl` });
+    // -- 2. wrap in details element
+    return `<details class="sheetjs-sheet-container">
+              <summary class="sheetjs-sheet-name">${name}</summary>
+              <div class="sheetjs-tab-content">${table}</div>
+            </details>`;
+  }).join(""); // -- 3. join into single string
+  // -- 4. render to DOM
+  htmlout.innerHTML = html; // single write → single re‑flow of the DOM
 }
 
-// --- File Import Logic ---
-/**
- * Handle file selection dialog and render the selected spreadsheet.
- */
+// ---------------------------------------------------------------------------
+// Generic UI helpers
+// ---------------------------------------------------------------------------
+const displayError   = (msg) => (onError ? ((onError.textContent = msg), (onError.hidden = false)) : console.error(msg));
+const hideDropUI     = () => dropContainer && (dropContainer.style.display = "none");
+const showDropUI     = () => dropContainer && (dropContainer.style.display = "block");
+const hideExportBtn  = () => (exportBtn.disabled = true);
+const showExportBtn  = () => (exportBtn.disabled = false);
+const showSpinner    = () => (spinnerOverlay.style.display = "flex");
+const hideSpinner    = () => (spinnerOverlay.style.display = "none");
+const hideOutputUI   = () => (htmlout.innerHTML = "");
+const hideLoadedFileUI = () => (fileStatus.innerHTML = "");
+const getLoadedFileUI = (fileName) => `<div class="file-loaded">
+  <span class="file-name text-muted text-small">${fileName}</span>
+  <button type="button" class="unload-btn">Unload</button>
+</div>`;
+
+function showLoadedFileUI(fileName) {
+  fileStatus.innerHTML = getLoadedFileUI(fileName);
+  hideDropUI();
+  showExportBtn();
+}
+
+// ---------------------------------------------------------------------------
+// Event delegation for unload button – avoids per‑render listener leaks
+// ---------------------------------------------------------------------------
+fileStatus.addEventListener("click", (e) => {
+  if (e.target.classList.contains("unload-btn")) {
+    hideLoadedFileUI();
+    hideExportBtn();
+    showDropUI();
+    hideOutputUI();
+    currentWorkbook = null;
+  }
+});
+
+// ---------------------------------------------------------------------------
+// File‑open dialog handler
+// ---------------------------------------------------------------------------
 async function handleReadBtn() {
-  const o = await electron.dialog.showOpenDialog({
+  // -- 1. show file open dialog to get the file path
+  const { filePaths, canceled } = await electron.dialog.showOpenDialog({
     title: "Select a file",
     filters: [{ name: "Spreadsheets", extensions: EXTENSIONS }],
     properties: ["openFile"],
   });
-  if (o.filePaths.length == 0) throw new Error("No file was selected!");
+  // -- 2. if canceled or no file path, return
+  if (canceled || !filePaths.length) return;
+  // -- 3. if multiple files selected, return error
+  if (filePaths.length !== 1) return displayError("Please choose a single file.");
+
   showSpinner();
-  // yield to event loop to render spinner
-  await new Promise((resolve) => setTimeout(resolve, 200));
+  await nextPaint();          // ensure spinner paints
   try {
-    const filePath = o.filePaths[0];
-    const fileName = filePath.split(/[/\\]/).pop();
-    renderWorkbookToTables(XLSX.readFile(filePath));
-    showLoadedFileUI(fileName);
-    showExportBtn();
+    // -- 4. read the first selected file
+    const filePath = filePaths[0];
+    currentWorkbook = XLSX.readFile(filePath);
+    renderWorkbookToTables(currentWorkbook);
+    showLoadedFileUI(path.basename(filePath));
   } finally {
     hideSpinner();
     hideDropUI();
+    // -- 5. reset error UI state
+    onError && (onError.hidden = true);
   }
 }
 
-// --- UI Templates and Helpers ---
-
-const getLoadedFileUI = (fileName) => {
-  return `<div class="file-loaded">
-      <span class="file-name text-muted text-small">${fileName}</span>
-      <button type="button" id="unloadBtn" class="unload-btn">Unload</button>
-    </div>`;
-};
-
-const hideDropUI = () => {
-  if (dropContainer) dropContainer.style.display = "none";
-};
-
-const showDropUI = () => {
-  if (dropContainer) dropContainer.style.display = "block";
-};
-
-const hideLoadedFileUI = () => {
-  if (fileStatus) fileStatus.innerHTML = "";
-};
-
-const hideOutputUI = () => {
-  if (htmlout) htmlout.innerHTML = "";
-};
-
-const showLoadedFileUI = (fileName) => {
-  const loadedFileUI = getLoadedFileUI(fileName);
-  fileStatus.innerHTML = loadedFileUI;
-  const unloadBtn = fileStatus.querySelector("#unloadBtn");
-  if (unloadBtn) {
-    unloadBtn.addEventListener("click", () => {
-      hideLoadedFileUI();
-      hideExportBtn();
-      showDropUI();
-      hideOutputUI();
-    });
-  }
-  hideDropUI();
-  showExportBtn();
-};
-
-const hideExportBtn = () => {
-  if (exportBtn) exportBtn.disabled = true;
-};
-
-const showExportBtn = () => {
-  if (exportBtn) exportBtn.disabled = false;
-};
-
-function showSpinner() {
-  if (spinnerOverlay) spinnerOverlay.style.display = "flex";
-}
-
-function hideSpinner() {
-  if (spinnerOverlay) spinnerOverlay.style.display = "none";
-}
-
-// --- Event Listener Helpers ---
-/**
- * Add an event listener to an element if it exists.
- */
-function addListener(id, event, handler) {
+// ---------------------------------------------------------------------------
+// Drag‑and‑drop + file input
+// ---------------------------------------------------------------------------
+function addListener(id, evt, fn) {
   const el = document.getElementById(id);
-  if (el) el.addEventListener(event, handler, false);
+  if (el) el.addEventListener(evt, fn);
 }
 
-/**
- * Attach drag-and-drop and file input listeners to the UI.
- */
-function attachDropListeners() {
+function attachFileListeners() {
+  // file input element
   addListener("readIn", "change", (e) => {
     showSpinner();
-    // Defer to next tick to ensure spinner renders before heavy work
-    setTimeout(() => readFile(e.target.files), 0);
+    nextPaint().then(() => readFile(e.target.files));
   });
   addListener("readBtn", "click", handleReadBtn);
-  const handleDrag = (e) => {
-    e.stopPropagation();
+
+  // drag‑and‑drop (applied to whole window for simplicity)
+  const onDrag = (e) => {
     e.preventDefault();
     e.dataTransfer.dropEffect = "copy";
-    document.body.classList.add("drag-over");
-  };
-  const handleDragLeave = (e) => {
-    e.stopPropagation();
-    e.preventDefault();
-    document.body.classList.remove("drag-over");
   };
+
+  ["dragenter", "dragover"].forEach((t) =>
+    document.body.addEventListener(t, onDrag, { passive: false })
+  );
+
   document.body.addEventListener(
     "drop",
     (e) => {
-      e.stopPropagation();
       e.preventDefault();
-      document.body.classList.remove("drag-over");
-      readFile(e.dataTransfer.files);
+      readFile(e.dataTransfer.files).catch((err) => displayError(err.message));
     },
-    false
+    { passive: false }
   );
-  document.body.addEventListener("dragenter", handleDrag, false);
-  document.body.addEventListener("dragover", handleDrag, false);
-  document.body.addEventListener("dragleave", handleDragLeave, false);
-  document.body.addEventListener("dragend", handleDragLeave, false);
 }
 
-// --- File Reader for Drag-and-Drop and Input ---
-/**
- * Read file(s) from input or drag-and-drop and render as table.
- */
+// ---------------------------------------------------------------------------
+// Read File from input or DnD
+// ---------------------------------------------------------------------------
 async function readFile(files) {
-  if (!files || files.length === 0) return;
-  const f = files[0];
+  // -- 1. if no files, return
+  if (!files || !files.length) return;
+  // -- 2. get the first file
+  const file = files[0];
+  // -- 3. if not a spreadsheet, return error
+  const ext  = path.extname(file.name).slice(1);
+  if (!isSpreadsheet(ext)) return displayError(`Unsupported file type .${ext}`);
+
   showSpinner();
   try {
-    const data = await f.arrayBuffer();
-    renderWorkbookToTables(XLSX.read(data));
-    showLoadedFileUI(f.name);
+    // -- 4. read the file
+    const data = await file.arrayBuffer();
+    currentWorkbook = XLSX.read(data);
+    // -- 5. render the workbook to tables
+    renderWorkbookToTables(currentWorkbook);
+    // -- 6. show the loaded file UI
+    showLoadedFileUI(file.name);
   } finally {
     hideSpinner();
+    // reset error UI state
+    onError && (onError.hidden = true);
   }
 }
 
-// --- Initial Setup ---
-attachDropListeners();
-
-// handle file opening events from the main process
-ipcRenderer.on('file-opened', async (_evt, filePath) => {
-  console.log('Received file-opened event:', filePath);
+// ---------------------------------------------------------------------------
+// Init
+// ---------------------------------------------------------------------------
+attachFileListeners();
+// the file-opened event is sent from the main process when a file is opened using "open with"
+ipcRenderer.on("file-opened", async (_e, filePath) => {
   showSpinner();
-  // yield to event loop to render spinner
-  await new Promise(r => setTimeout(r, 50));
-  renderWorkbookToTables(XLSX.readFile(filePath));            // already in your helper list
-  showLoadedFileUI(filePath.split(/[/\\]/).pop());
+  await nextPaint(); // ensure spinner paints
+  currentWorkbook = XLSX.readFile(filePath); 
+  renderWorkbookToTables(currentWorkbook);
+  showLoadedFileUI(path.basename(filePath));
   hideSpinner();
   hideDropUI();
   showExportBtn();
-});
\ No newline at end of file
+});
diff --git a/docz/static/electron/styles.css b/docz/static/electron/styles.css
index 1f3bc0c..f138a05 100644
--- a/docz/static/electron/styles.css
+++ b/docz/static/electron/styles.css
@@ -333,6 +333,12 @@ summary:focus-within {
   animation: spin 1s linear infinite;
 }
 
+#onError {
+  color: var(--danger);
+  width: 100%;
+  text-align: center;
+}
+
 @keyframes spin {
   0% { transform: rotate(0deg); }
   100% { transform: rotate(360deg); }