File: //opt/wpsites/alumni.dataconn.net/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Alumni Database</title>
<style>
:root{ --bg:#f7f9fb; --panel:#ffffff; --ink:#1e293b; --muted:#64748b; --accent:#2563eb; --accent-2:#e2e8f0; --accent-3:#eff6ff; --shadow:0 10px 25px rgba(15,23,42,.08); --radius:16px; --danger:#dc2626; }
html, body{ height:100%; margin:0; background:var(--bg); color:var(--ink); font-family:Inter, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial; overflow-x:hidden; }
.app{ display:flex; min-height:100%; }
.sidebar{ width:310px; background:linear-gradient(180deg,#fff,#f3f6fb); border-right:1px solid var(--accent-2); padding:18px; box-shadow:var(--shadow); display:flex; flex-direction:column; gap:16px; position:sticky; top:0; height:100vh; overflow:auto; z-index:10; }
.brand{ display:flex; align-items:center; gap:10px; }
.logo{ width:36px; height:36px; border-radius:12px; background:var(--accent); box-shadow:inset 0 0 0 2px rgba(255,255,255,.7), 0 10px 18px rgba(37,99,235,.25); }
.brand h1{ margin:0; font-size:18px; letter-spacing:.3px; }
.role-badge{ font-size:12px; color:#fff; background:var(--accent); padding:3px 8px; border-radius:999px; }
.panel{ background:var(--panel); border:1px solid var(--accent-2); border-radius:var(--radius); box-shadow:var(--shadow); padding:14px; }
.panel h2{ margin:0 0 8px 0; font-size:15px; color:var(--muted); font-weight:600; text-transform:uppercase; letter-spacing:.08em; }
.btn{ appearance:none; border:none; cursor:pointer; background:var(--accent); color:#fff; padding:10px 14px; border-radius:12px; font-weight:600; box-shadow:0 8px 16px rgba(37,99,235,.22); transition:transform 0.1s; }
.btn:hover:not([disabled]){ transform:translateY(-1px); }
.btn.ghost{ background:#fff; color:var(--ink); border:1px solid var(--accent-2); box-shadow:none; }
.btn.danger{ background:var(--danger); box-shadow:0 8px 16px rgba(220,38,38,.22); }
.btn[disabled]{ opacity:.5; cursor:not-allowed; }
.btn-delete{ background:var(--danger); color:#fff; border:none; padding:4px 8px; border-radius:6px; font-size:12px; cursor:pointer; }
.row{ display:flex; gap:10px; align-items:center; flex-wrap:wrap; }
.stack{ display:flex; flex-direction:column; gap:10px; }
.cols-wrap{ display:flex; flex-direction:column; gap:8px; max-height:220px; overflow:auto; padding-right:2px; }
.col-item{ display:flex; gap:8px; align-items:center; padding:4px; }
.col-item input[type="checkbox"]{ flex-shrink:0; }
.col-item span{ font-size:13px; line-height:1.3; word-break:break-word; }
.main{ flex:1; padding:22px; display:flex; flex-direction:column; gap:16px; overflow:hidden; }
.toolbar{ display:flex; gap:12px; align-items:center; justify-content:space-between; }
.tablewrap{ background:#fff; border:1px solid var(--accent-2); border-radius:var(--radius); box-shadow:var(--shadow); overflow-x:auto; overflow-y:auto; display:flex; flex-direction:column; min-height:300px; max-width:100%; }
table{ width:100%; border-collapse:collapse; min-width:max-content; }
thead{ background:#f1f5f9; position:sticky; top:0; z-index:2; }
th, td{ padding:10px 12px; border-bottom:1px solid #e5e7eb; font-size:14px; vertical-align:top; white-space:nowrap; }
.filters-row{ background:#f8fafc; }
.filters-row input{ width:100%; border:1px solid var(--accent-2); border-radius:8px; padding:6px 8px; font-size:13px; background:#fff; }
.editable-cell{ cursor:text; position:relative; min-height:20px; }
.editable-cell:hover{ background:#f0f9ff; }
.editable-cell input{ width:100%; border:2px solid var(--accent); border-radius:4px; padding:4px 6px; font-size:14px; }
.row-edited{ background:#fef3c7; }
.pager{ display:flex; gap:8px; align-items:center; padding:10px; justify-content:flex-end; }
.report-grid{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:12px; }
.card{ background:#fff; border:1px solid var(--accent-2); border-radius:14px; box-shadow:var(--shadow); padding:14px; min-width:0; }
.metric{ font-size:24px; font-weight:800; color:var(--accent); }
.label{ font-size:12px; color:var(--muted); text-transform:uppercase; letter-spacing:.08em; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.note{ font-size:12px; color:var(--muted); }
.modal{ display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); z-index:100; align-items:center; justify-content:center; }
.modal.active{ display:flex; }
.modal-content{ background:#fff; border-radius:16px; padding:24px; max-width:600px; width:90%; max-height:80vh; overflow:auto; box-shadow:0 20px 50px rgba(0,0,0,0.3); }
.modal-content h3{ margin:0 0 16px 0; }
.form-grid{ display:grid; gap:12px; }
.form-field{ display:flex; flex-direction:column; gap:4px; }
.form-field label{ font-size:13px; font-weight:600; color:var(--muted); }
.form-field input{ border:1px solid var(--accent-2); border-radius:8px; padding:8px 10px; font-size:14px; }
.hidden{ display:none !important; }
@media (max-width:1100px){ .report-grid{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
@media (max-width:760px){ .sidebar{ width:100%; height:auto; position:static; } .app{ flex-direction:column; } }
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<div class="brand">
<div class="logo"></div>
<div>
<h1>Alumni Database</h1>
<div id="roleBadge" class="role-badge">Not Logged In</div>
</div>
</div>
<div class="panel stack">
<h2>Login</h2>
<div class="row">
<input id="loginUser" type="text" placeholder="username" />
<input id="loginPass" type="password" placeholder="password" />
</div>
<div class="row">
<button class="btn" id="btnLogin">Sign In</button>
<button class="btn ghost" id="btnLogout">Sign Out</button>
</div>
</div>
<div class="panel stack hidden" id="dataPanel">
<h2>Data</h2>
<div class="row">
<button class="btn ghost" id="btnReloadDefault">Reload CSV</button>
</div>
<div class="row">
<button class="btn" id="btnAddRecord">Add New Record</button>
</div>
<div class="row">
<button class="btn" id="btnSaveChanges">Save All Changes</button>
</div>
<div class="row">
<button class="btn ghost" id="btnDownloadLog">Download Change Log</button>
</div>
<div id="dataNote" class="note"></div>
<div id="changeNote" class="note" style="color:var(--accent); font-weight:600;"></div>
</div>
<div class="panel stack hidden" id="colPanel">
<h2>Columns</h2>
<div id="colChooser" class="cols-wrap"></div>
<div class="row">
<button class="btn ghost" id="selectAllCols">Select All</button>
<button class="btn ghost" id="clearCols">Clear</button>
</div>
</div>
<div class="panel stack hidden" id="exportPanel">
<h2>Exports</h2>
<div class="row">
<button class="btn" id="exportSelected">Export Selected Columns (CSV)</button>
</div>
<div class="divider" style="height:1px;background:#e5e7eb;margin:6px 0 10px 0;"></div>
<div class="stack">
<label class="row" style="gap:6px; align-items:center;">
<span class="label" style="letter-spacing:normal">Emails:</span>
<select id="emailMode">
<option value="primary">Primary Email</option>
<option value="secondary">Secondary Email</option>
<option value="all">All Emails</option>
</select>
</label>
<div class="row">
<button class="btn" id="copyEmails">Copy to Clipboard</button>
<button class="btn ghost" id="downloadEmails">Download TXT</button>
</div>
</div>
</div>
<div class="panel stack hidden" id="reportPanel">
<h2>Reports</h2>
<div class="note">Reports displayed below the table.</div>
<div class="row">
<select id="reportSelect">
<option value="">Select Report Type</option>
<option value="gradYear">Graduates by Year</option>
<option value="degree">Count by Degree</option>
<option value="concentration">Count by Concentration</option>
<option value="state">Count by State</option>
</select>
<button class="btn" id="runReport">Run</button>
</div>
<div class="row">
<button class="btn ghost" id="clearReport">Clear Report</button>
</div>
</div>
</aside>
<main class="main">
<div class="toolbar hidden" id="mainToolbar">
<div class="row">
<div class="label">Search:</div>
<input id="globalSearch" type="text" placeholder="Search all visible columns" />
<button class="btn ghost" id="clearSearch">Clear</button>
</div>
<div class="row">
<label class="row" style="gap:6px; align-items:center;">
<span class="label" style="letter-spacing:normal">Rows per page:</span>
<select id="pageSize">
<option>10</option>
<option selected>25</option>
<option>50</option>
<option>100</option>
</select>
</label>
</div>
</div>
<div class="tablewrap hidden" id="mainTable">
<table id="dataTable">
<thead>
<tr id="headerRow"></tr>
<tr id="filterRow" class="filters-row"></tr>
</thead>
<tbody id="tableBody"></tbody>
</table>
<div class="pager">
<button class="btn ghost" id="prevPage">◀</button>
<span id="pageInfo" class="note"></span>
<button class="btn ghost" id="nextPage">▶</button>
</div>
</div>
<section class="stack hidden" id="hintsSection">
<h2 style="margin:6px 0 0 0; color:var(--muted); font-size:16px;">Hints</h2>
<div class="note">Click on any cell to edit (Admin/Editor only). Changes highlighted in yellow.</div>
</section>
<section id="reportSection" class="hidden">
<h2 style="margin:6px 0 8px 0; color:var(--muted); font-size:16px;">Report Results</h2>
<div id="reportOut" class="report-grid"></div>
</section>
<section class="stack" id="welcomeSection">
<h2 style="margin:6px 0 0 0; color:var(--muted); font-size:18px;">Welcome to Alumni Database</h2>
<div class="note">Please log in to view and manage alumni data.</div>
</section>
</main>
</div>
<div id="addModal" class="modal">
<div class="modal-content">
<h3>Add New Record</h3>
<div id="addForm" class="form-grid"></div>
<div class="row" style="margin-top:16px; justify-content:flex-end;">
<button class="btn ghost" id="cancelAdd">Cancel</button>
<button class="btn" id="confirmAdd">Add Record</button>
</div>
</div>
</div>
<script src="app.js?v=5"></script>
</body>
</html>