diff --git a/public/assets/donna-export.css b/public/assets/donna-export.css
new file mode 100644
index 0000000..0d4065a
--- /dev/null
+++ b/public/assets/donna-export.css
@@ -0,0 +1,32 @@
+/* ============================================================
+ * Donna — UI compartida para botón "Exportar" con menú dropdown
+ * ============================================================ */
+.export-wrap { position:relative; display:inline-block; }
+.btn-export {
+ display:inline-flex; align-items:center; gap:7px;
+ padding:8px 16px; background:#fff; color:var(--navy, #1B3A6B);
+ border:1px solid var(--navy, #1B3A6B); border-radius:8px;
+ font-family:'DM Sans',sans-serif; font-size:13px; font-weight:500;
+ cursor:pointer; transition:background .15s; white-space:nowrap;
+}
+.btn-export:hover { background:var(--off, #F7F6F3); }
+.btn-export svg { width:14px; height:14px; }
+.export-menu {
+ position:absolute; right:0; top:calc(100% + 6px);
+ background:#fff; border:1px solid var(--gray-200, #D6D4CC);
+ border-radius:8px; box-shadow:0 4px 20px rgba(0,0,0,0.1);
+ min-width:210px; z-index:300; overflow:hidden; display:none;
+}
+.export-menu.open { display:block; }
+.export-menu button {
+ width:100%; display:flex; align-items:center; gap:10px;
+ padding:11px 16px; background:transparent; border:none;
+ font-family:'DM Sans',sans-serif; font-size:13px; color:var(--gray-700, #4A4946);
+ cursor:pointer; text-align:left; transition:background .12s;
+}
+.export-menu button:hover { background:var(--off, #F7F6F3); color:var(--navy, #1B3A6B); }
+.export-menu button svg { width:15px; height:15px; flex-shrink:0; }
+.export-menu button.xl { color:#1D6F42; }
+.export-menu button.xl:hover { background:#EAF3DE; }
+.export-menu button.pdf { color:#C0392B; }
+.export-menu button.pdf:hover { background:#FCEBEB; }
diff --git a/public/assets/donna-export.js b/public/assets/donna-export.js
new file mode 100644
index 0000000..30e119f
--- /dev/null
+++ b/public/assets/donna-export.js
@@ -0,0 +1,179 @@
+/* ============================================================
+ * Donna — Helpers compartidos para exportación a Excel y PDF
+ * ============================================================
+ * Requiere XLSX (https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js)
+ * cargado antes de este script.
+ *
+ * Uso:
+ *
…botón + menú…
+ * DonnaExport.attach('export-wrap', { onExcel, onPDF });
+ * DonnaExport.toExcel({ filename, sheetName, headers, rows, columnWidths });
+ * DonnaExport.toPDF({ filename, title, subtitle, headers, rows,
+ * pdfCols, orientation, statusColIndex, statusColors, footer });
+ */
+(function(){
+ 'use strict';
+
+ const NAVY = '#1B3A6B';
+ const GOLD = '#C9A84C';
+ const FIRM = 'AALN Law — Arias, Abrego, López & Noriega';
+ const ADDR = 'P.H. Midtown, Piso 16, Of. 1605, Calle 74 Este, San Francisco, Ciudad de Panamá';
+
+ function escHtml(s){
+ return (s==null?'':String(s))
+ .replace(/&/g,'&').replace(/"/g,'"')
+ .replace(//g,'>');
+ }
+
+ function todayStamp(){
+ const d = new Date();
+ const pad = n => String(n).padStart(2,'0');
+ return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`;
+ }
+
+ function attach(wrapId, handlers){
+ const wrap = document.getElementById(wrapId);
+ if (!wrap) return;
+ const btn = wrap.querySelector('.btn-export');
+ const menu = wrap.querySelector('.export-menu');
+ const xl = wrap.querySelector('.export-menu button.xl');
+ const pdf = wrap.querySelector('.export-menu button.pdf');
+ if (btn && menu) {
+ btn.addEventListener('click', e => {
+ e.stopPropagation();
+ menu.classList.toggle('open');
+ });
+ }
+ document.addEventListener('click', e => {
+ if (!wrap.contains(e.target)) menu && menu.classList.remove('open');
+ });
+ if (xl && handlers.onExcel) xl.addEventListener('click', () => { menu.classList.remove('open'); handlers.onExcel(); });
+ if (pdf && handlers.onPDF) pdf.addEventListener('click', () => { menu.classList.remove('open'); handlers.onPDF(); });
+ }
+
+ function toExcel(opts){
+ if (typeof XLSX === 'undefined') { alert('XLSX no está cargado'); return; }
+ const headers = opts.headers || [];
+ const rows = opts.rows || [];
+ const sheetName = opts.sheetName || 'Datos';
+ const fileBase = opts.filename || 'Donna_Export';
+ if (!rows.length) { opts.onEmpty && opts.onEmpty(); return; }
+
+ const wb = XLSX.utils.book_new();
+ const data = [headers, ...rows];
+ const ws = XLSX.utils.aoa_to_sheet(data);
+
+ const widths = opts.columnWidths || headers.map(() => 18);
+ ws['!cols'] = widths.map(w => ({ wch: w }));
+
+ const range = XLSX.utils.decode_range(ws['!ref']);
+ for (let C = range.s.c; C <= range.e.c; C++) {
+ const addr = XLSX.utils.encode_cell({r:0, c:C});
+ if (!ws[addr]) continue;
+ ws[addr].s = {
+ fill: { fgColor: { rgb: '1B3A6B' } },
+ font: { bold: true, color: { rgb: 'FFFFFF' }, sz: 11 },
+ alignment: { horizontal: 'center', vertical: 'center', wrapText: true }
+ };
+ }
+ XLSX.utils.book_append_sheet(wb, ws, sheetName);
+ XLSX.writeFile(wb, `${fileBase}_${todayStamp()}.xlsx`);
+ }
+
+ function toPDF(opts){
+ const headers = opts.headers || [];
+ const rows = opts.rows || [];
+ const title = opts.title || 'Reporte';
+ const subtitle = opts.subtitle || '';
+ const orientation = opts.orientation || 'landscape';
+ const fileBase = opts.filename || 'Donna_Export';
+ const footer = opts.footer != null ? opts.footer : ADDR;
+ const pdfCols = opts.pdfCols || headers.map((_,i) => i);
+ const statusCol = opts.statusColIndex;
+ const statusColors = opts.statusColors || {};
+ if (!rows.length) { opts.onEmpty && opts.onEmpty(); return; }
+
+ const pdfHeaders = pdfCols.map(i => headers[i]);
+ const styledRows = rows.map((r, ri) => {
+ const cells = pdfCols.map(ci => {
+ const val = r[ci] == null ? '' : String(r[ci]);
+ if (statusCol === ci && statusColors[val]) {
+ const [bg, fg] = statusColors[val];
+ return `${escHtml(val)} | `;
+ }
+ return `${escHtml(val)} | `;
+ }).join('');
+ return `${cells}
`;
+ }).join('');
+
+ const fechaStr = new Date().toLocaleDateString('es-PA');
+ const html = `
+
+${escHtml(title)} — AALN Law
+
+
+
+
+ ${pdfHeaders.map(h => `| ${escHtml(h)} | `).join('')}
+ ${styledRows}
+
+
+
+
+
+
+