Files
cpas/demo/index.html

894 lines
41 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CPAS Tracker — Demo Preview</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Syne:wght@700;800&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--gold: #d4af37;
--gold-lt: #ffdf8a;
--gold-dk: #a88520;
--bg: #050608;
--bg-nav: #000000;
--bg-card: #111217;
--bg-section: #181924;
--border: #222;
--border-lt: #2a2b3a;
--text: #f8f9fa;
--text-muted: #9ca0b8;
--text-dim: #d1d3e0;
--green: #28a745;
--green-bg: #d4edda;
--yellow: #856404;
--yellow-bg: #fff3cd;
--red: #d9534f;
--red-bg: #f8d7da;
--red-dk: #721c24;
--red-dk-bg: #f5c6cb;
--sep: #721c24;
}
html { scroll-behavior: smooth; }
body {
background: var(--bg);
color: var(--text);
font-family: 'Inter', sans-serif;
min-height: 100vh;
overflow-x: hidden;
}
/* ── DEMO BANNER ── */
.demo-banner {
background: linear-gradient(90deg, #1a1200 0%, #2a1f00 50%, #1a1200 100%);
border-bottom: 1px solid var(--gold-dk);
padding: 8px 40px;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
font-family: 'DM Mono', monospace;
font-size: 11px;
color: var(--gold-lt);
letter-spacing: 0.8px;
position: sticky;
top: 0;
z-index: 1000;
}
.demo-banner .dot {
width: 6px; height: 6px; border-radius: 50%;
background: var(--gold);
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.4; transform: scale(0.7); }
}
/* ── NAV ── */
nav {
background: var(--bg-nav);
padding: 0 40px;
display: flex;
align-items: center;
gap: 0;
border-bottom: 1px solid #333;
position: sticky;
top: 33px;
z-index: 999;
}
.logo-wrap {
display: flex; align-items: center;
margin-right: 32px; padding: 14px 0;
gap: 10px;
}
.logo-icon {
width: 28px; height: 28px;
background: linear-gradient(135deg, var(--gold), var(--gold-lt));
border-radius: 6px;
display: flex; align-items: center; justify-content: center;
font-size: 14px; font-weight: 900; color: #000;
font-family: 'Syne', sans-serif;
flex-shrink: 0;
}
.logo-text {
color: var(--text);
font-weight: 800;
font-size: 18px;
letter-spacing: 0.5px;
font-family: 'Syne', sans-serif;
}
.nav-tab {
padding: 18px 22px;
color: rgba(248,249,250,0.55);
border-bottom: 3px solid transparent;
cursor: pointer;
font-weight: 400;
font-size: 14px;
background: none;
border-top: none; border-left: none; border-right: none;
transition: color 0.2s;
text-decoration: none;
display: inline-block;
}
.nav-tab.active {
color: var(--text);
border-bottom-color: var(--gold);
font-weight: 700;
}
.nav-tab:hover { color: var(--text); }
.nav-docs {
margin-left: auto;
background: none;
border: 1px solid var(--border-lt);
color: var(--text-muted);
border-radius: 6px;
padding: 6px 14px;
font-size: 12px;
cursor: pointer;
font-weight: 600;
}
/* ── MAIN LAYOUT ── */
.main {
max-width: 1100px;
margin: 30px auto;
padding: 0 20px 60px;
}
/* ── HERO ── */
.hero {
background: var(--bg-card);
border-radius: 10px;
border: 1px solid var(--border);
padding: 48px 48px 40px;
margin-bottom: 24px;
position: relative;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
height: 3px;
background: linear-gradient(90deg, transparent, var(--gold), var(--gold-lt), var(--gold), transparent);
}
.hero::after {
content: 'DEMO';
position: absolute;
top: 20px; right: 24px;
font-family: 'DM Mono', monospace;
font-size: 10px;
letter-spacing: 2px;
color: var(--gold-dk);
border: 1px solid var(--gold-dk);
padding: 2px 8px;
border-radius: 3px;
}
.hero-eyebrow {
font-family: 'DM Mono', monospace;
font-size: 11px;
letter-spacing: 2px;
color: var(--gold);
text-transform: uppercase;
margin-bottom: 14px;
}
.hero h1 {
font-family: 'Syne', sans-serif;
font-size: 36px;
font-weight: 800;
color: var(--text);
line-height: 1.1;
margin-bottom: 14px;
}
.hero h1 span { color: var(--gold); }
.hero p {
font-size: 15px;
color: var(--text-dim);
max-width: 580px;
line-height: 1.7;
margin-bottom: 28px;
}
.hero-stats {
display: flex;
gap: 32px;
flex-wrap: wrap;
}
.hero-stat {
display: flex; flex-direction: column; gap: 3px;
}
.hero-stat .val {
font-family: 'Syne', sans-serif;
font-size: 28px;
font-weight: 800;
color: var(--gold-lt);
line-height: 1;
}
.hero-stat .lbl {
font-size: 11px;
color: var(--text-muted);
letter-spacing: 0.5px;
text-transform: uppercase;
font-family: 'DM Mono', monospace;
}
.hero-stat-divider {
width: 1px; background: var(--border-lt);
align-self: stretch; margin: 4px 0;
}
/* ── SECTION TITLE ── */
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
.section-title {
font-family: 'Syne', sans-serif;
font-size: 13px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1.5px;
color: var(--text-muted);
display: flex;
align-items: center;
gap: 8px;
}
.section-title::before {
content: '';
display: block;
width: 3px; height: 14px;
background: var(--gold);
border-radius: 2px;
}
/* ── KPI CARDS ROW ── */
.kpi-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 14px;
margin-bottom: 24px;
}
.kpi-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 10px;
padding: 20px 22px;
position: relative;
overflow: hidden;
transition: border-color 0.2s, transform 0.15s;
}
.kpi-card:hover { border-color: var(--border-lt); transform: translateY(-1px); }
.kpi-card .kpi-label {
font-size: 11px;
font-family: 'DM Mono', monospace;
letter-spacing: 0.8px;
color: var(--text-muted);
text-transform: uppercase;
margin-bottom: 10px;
}
.kpi-card .kpi-val {
font-family: 'Syne', sans-serif;
font-size: 32px;
font-weight: 800;
color: var(--text);
line-height: 1;
margin-bottom: 6px;
}
.kpi-card .kpi-sub { font-size: 11px; color: var(--text-muted); }
.kpi-card .kpi-accent { position: absolute; bottom: 0; left: 0; right: 0; height: 3px; }
.kpi-accent-gold { background: linear-gradient(90deg, var(--gold-dk), var(--gold)); }
.kpi-accent-red { background: linear-gradient(90deg, #a02020, #e74c3c); }
.kpi-accent-blue { background: linear-gradient(90deg, #1a3a6a, #3b82f6); }
.kpi-accent-green{ background: linear-gradient(90deg, #0a3d20, #28a745); }
/* ── TWO COLUMNS ── */
.two-col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 24px;
}
.panel {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 10px;
overflow: hidden;
}
.panel-head {
background: var(--bg-section);
border-bottom: 1px solid var(--border);
padding: 14px 20px;
display: flex;
align-items: center;
justify-content: space-between;
}
.panel-title {
font-size: 13px; font-weight: 700;
color: var(--text); font-family: 'Syne', sans-serif;
}
/* ── EMPLOYEE TABLE ── */
.emp-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.emp-table th {
padding: 10px 16px; text-align: left;
font-size: 10px; font-family: 'DM Mono', monospace;
letter-spacing: 1px; text-transform: uppercase;
color: var(--text-muted); border-bottom: 1px solid var(--border);
background: var(--bg-section);
}
.emp-table td { padding: 11px 16px; border-bottom: 1px solid #18191f; vertical-align: middle; }
.emp-table tr:last-child td { border-bottom: none; }
.emp-table tr:hover td { background: rgba(255,255,255,0.02); }
.emp-name { font-weight: 600; color: var(--text); }
/* ── TIER BADGES ── */
.tier-badge {
display: inline-block; padding: 3px 9px; border-radius: 10px;
font-size: 11px; font-weight: 700; white-space: nowrap; border: 1px solid;
}
.tier-0 { color: #28a745; background: #d4edda; border-color: #28a745; }
.tier-1 { color: #856404; background: #fff3cd; border-color: #c9a000; }
.tier-2 { color: #d9534f; background: #f8d7da; border-color: #d9534f; }
.tier-3 { color: #d9534f; background: #f8d7da; border-color: #d9534f; }
.tier-4 { color: #721c24; background: #f5c6cb; border-color: #c0392b; }
.tier-5 { color: #721c24; background: #f5c6cb; border-color: #c0392b; }
.tier-6 { color: #fff; background: #721c24; border-color: #5a1520; }
/* ── VIOLATION FEED ── */
.viol-item {
padding: 13px 18px; border-bottom: 1px solid #18191f;
display: flex; align-items: flex-start; gap: 12px;
}
.viol-item:last-child { border-bottom: none; }
.viol-dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 5px; flex-shrink: 0; }
.viol-dot-red { background: #e74c3c; box-shadow: 0 0 6px rgba(231,76,60,0.5); }
.viol-dot-yellow { background: var(--gold); box-shadow: 0 0 6px rgba(212,175,55,0.5); }
.viol-dot-green { background: #28a745; }
.viol-info { flex: 1; min-width: 0; }
.viol-name { font-size: 13px; font-weight: 600; color: var(--text); }
.viol-type { font-size: 11px; color: var(--text-muted); margin-top: 2px; }
.viol-meta { display: flex; align-items: center; gap: 8px; margin-top: 4px; font-size: 11px; color: var(--text-muted); font-family: 'DM Mono', monospace; }
.viol-pts { font-family: 'Syne', sans-serif; font-size: 18px; font-weight: 800; color: var(--gold-lt); flex-shrink: 0; }
.repeat-tag { display: inline-block; padding: 1px 6px; border-radius: 8px; font-size: 10px; font-weight: 700; background: #3b2e00; color: #ffd666; border: 1px solid var(--gold-dk); margin-left: 4px; }
/* ── DEPT BREAKDOWN ── */
.dept-row { padding: 12px 18px; border-bottom: 1px solid #18191f; display: flex; align-items: center; gap: 12px; }
.dept-row:last-child { border-bottom: none; }
.dept-name { font-size: 13px; color: var(--text-dim); min-width: 160px; }
.dept-bar-track { flex: 1; height: 6px; background: var(--border-lt); border-radius: 3px; overflow: hidden; }
.dept-bar-fill { height: 100%; border-radius: 3px; background: linear-gradient(90deg, var(--gold-dk), var(--gold)); }
.dept-count { font-family: 'DM Mono', monospace; font-size: 12px; color: var(--text-muted); min-width: 28px; text-align: right; }
/* ── FORM PREVIEW ── */
.form-preview { background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px; margin-bottom: 24px; overflow: hidden; }
.form-section { background: var(--bg-section); border-left: 4px solid var(--gold); padding: 20px 24px; margin: 20px; border-radius: 4px; border-top: 1px solid var(--border-lt); border-right: 1px solid var(--border-lt); border-bottom: 1px solid var(--border-lt); }
.form-section-title { font-family: 'Syne', sans-serif; font-size: 18px; font-weight: 700; color: var(--text); margin-bottom: 14px; }
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; }
.form-item { display: flex; flex-direction: column; gap: 5px; }
.form-label { font-size: 12px; font-weight: 600; color: #e5e7f1; }
.form-input { padding: 9px 12px; border: 1px solid var(--border-lt); border-radius: 4px; font-size: 13px; background: #050608; color: var(--text-muted); font-family: 'Inter', sans-serif; pointer-events: none; }
.form-input.filled { color: var(--text); border-color: #3a3d52; }
.point-val { font-family: 'Syne', sans-serif; font-size: 28px; font-weight: 800; color: var(--gold-lt); }
/* ── TIER SCALE ── */
.tier-timeline { display: flex; align-items: stretch; border-radius: 8px; border: 1px solid var(--border); overflow: hidden; }
.tier-seg { flex: 1; padding: 12px 8px 10px; text-align: center; border-right: 1px solid rgba(255,255,255,0.05); }
.tier-seg:last-child { border-right: none; }
.tier-seg .ts-pts { font-family: 'Syne', sans-serif; font-size: 15px; font-weight: 800; margin-bottom: 3px; }
.tier-seg .ts-label { font-size: 9px; font-family: 'DM Mono', monospace; letter-spacing: 0.5px; opacity: 0.8; line-height: 1.3; }
.ts-0 { background: rgba(40,167,69,0.12); color: #28a745; }
.ts-1 { background: rgba(133,100,4,0.15); color: #c9a000; }
.ts-2 { background: rgba(217,83,79,0.15); color: #d9534f; }
.ts-3 { background: rgba(217,83,79,0.18); color: #d9534f; }
.ts-4 { background: rgba(114,28,36,0.20); color: #e87070; }
.ts-5 { background: rgba(114,28,36,0.25); color: #e87070; }
.ts-6 { background: rgba(114,28,36,0.50); color: #ff9999; }
/* ── AUDIT LOG ── */
.audit-item { padding: 11px 18px; border-bottom: 1px solid #18191f; display: flex; align-items: center; gap: 12px; font-size: 12px; }
.audit-item:last-child { border-bottom: none; }
.audit-time { font-family: 'DM Mono', monospace; color: var(--text-muted); font-size: 11px; min-width: 80px; }
.audit-action { flex: 1; color: var(--text-dim); }
.audit-action strong { color: var(--text); font-weight: 600; }
.audit-pts { font-family: 'DM Mono', monospace; font-size: 11px; color: var(--gold); font-weight: 700; }
/* ── FEATURES ── */
.features-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 24px; }
.feature-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px; padding: 22px; transition: border-color 0.2s, transform 0.15s; }
.feature-card:hover { border-color: var(--border-lt); transform: translateY(-2px); }
.feature-icon { font-size: 22px; margin-bottom: 12px; display: block; }
.feature-title { font-family: 'Syne', sans-serif; font-size: 14px; font-weight: 700; color: var(--text); margin-bottom: 6px; }
.feature-desc { font-size: 12px; color: var(--text-muted); line-height: 1.6; }
/* ── FOOTER ── */
footer {
border-top: 1px solid var(--border);
padding: 20px 40px;
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
font-size: 11px;
color: var(--text-muted);
font-family: 'DM Mono', monospace;
background: var(--bg-nav);
}
.footer-left {
display: flex;
align-items: center;
gap: 18px;
}
.footer-brand {
font-family: 'Syne', sans-serif;
font-size: 13px;
font-weight: 700;
color: var(--text-dim);
}
.footer-copy {
color: var(--text-muted);
font-size: 11px;
}
.footer-gitea {
display: flex;
align-items: center;
gap: 6px;
color: var(--text-muted);
text-decoration: none;
padding: 4px 10px;
border: 1px solid var(--border-lt);
border-radius: 5px;
transition: border-color 0.2s, color 0.2s;
font-size: 11px;
}
.footer-gitea:hover {
border-color: var(--gold-dk);
color: var(--gold-lt);
}
.footer-gitea svg {
width: 14px;
height: 14px;
fill: currentColor;
flex-shrink: 0;
}
.footer-right {
display: flex;
align-items: center;
gap: 18px;
}
.footer-ticker {
display: flex;
align-items: center;
gap: 8px;
background: rgba(212,175,55,0.06);
border: 1px solid rgba(212,175,55,0.2);
border-radius: 5px;
padding: 4px 12px;
}
.footer-ticker-label {
font-size: 10px;
color: var(--text-muted);
letter-spacing: 0.5px;
text-transform: uppercase;
}
.footer-ticker-time {
font-family: 'DM Mono', monospace;
font-size: 12px;
color: var(--gold);
font-weight: 500;
letter-spacing: 1px;
}
.footer-ticker-dot {
width: 5px; height: 5px; border-radius: 50%;
background: var(--gold);
animation: pulse 2s infinite;
flex-shrink: 0;
}
.footer-divider {
width: 1px;
height: 16px;
background: var(--border-lt);
}
/* ── ANIMATIONS ── */
.fade-in { opacity: 0; transform: translateY(16px); animation: fadeUp 0.5s ease forwards; }
@keyframes fadeUp { to { opacity: 1; transform: translateY(0); } }
.fade-in:nth-child(1) { animation-delay: 0.05s; }
.fade-in:nth-child(2) { animation-delay: 0.10s; }
.fade-in:nth-child(3) { animation-delay: 0.15s; }
.fade-in:nth-child(4) { animation-delay: 0.20s; }
.tab-pane { display: none; }
.tab-pane.active { display: block; }
@media (max-width: 768px) {
.kpi-row { grid-template-columns: repeat(2, 1fr); }
.two-col { grid-template-columns: 1fr; }
.features-grid { grid-template-columns: 1fr 1fr; }
.hero { padding: 30px 24px; }
.hero h1 { font-size: 26px; }
nav { padding: 0 16px; }
.main { padding: 0 12px 60px; }
footer { padding: 16px 20px; flex-direction: column; align-items: flex-start; }
.footer-right { flex-wrap: wrap; }
}
</style>
</head>
<body>
<!-- Demo Banner -->
<div class="demo-banner">
<div class="dot"></div>
DEMO ENVIRONMENT — Simulated data for stakeholder preview only — Not connected to live database
<div class="dot"></div>
</div>
<!-- Navigation -->
<nav>
<div class="logo-wrap">
<div class="logo-icon">C</div>
<div class="logo-text">CPAS Tracker</div>
</div>
<a class="nav-tab active" href="#" onclick="switchTab('dashboard', this); return false;">📊 Dashboard</a>
<a class="nav-tab" href="#" onclick="switchTab('violations', this); return false;">+ New Violation</a>
<button class="nav-docs">? Docs</button>
</nav>
<div class="main">
<!-- ── DASHBOARD TAB ── -->
<div id="tab-dashboard" class="tab-pane active">
<div class="hero fade-in">
<div class="hero-eyebrow">Corrective Performance Action System</div>
<h1>Employee <span>Compliance</span> Dashboard</h1>
<p>Real-time visibility into workforce disciplinary standing. Track violations, monitor tier escalations, and generate signed documentation — all in one place.</p>
<div class="hero-stats">
<div class="hero-stat"><div class="val">47</div><div class="lbl">Total Employees</div></div>
<div class="hero-stat-divider"></div>
<div class="hero-stat"><div class="val">23</div><div class="lbl">Active Violations (90d)</div></div>
<div class="hero-stat-divider"></div>
<div class="hero-stat"><div class="val">3</div><div class="lbl">At-Risk (Tier 3+)</div></div>
<div class="hero-stat-divider"></div>
<div class="hero-stat"><div class="val">91%</div><div class="lbl">In Good Standing</div></div>
</div>
</div>
<div class="kpi-row">
<div class="kpi-card fade-in">
<div class="kpi-label">New This Week</div>
<div class="kpi-val">6</div>
<div class="kpi-sub">+2 vs prior week</div>
<div class="kpi-accent kpi-accent-gold"></div>
</div>
<div class="kpi-card fade-in">
<div class="kpi-label">Tier 3+ Employees</div>
<div class="kpi-val">3</div>
<div class="kpi-sub">Requires attention</div>
<div class="kpi-accent kpi-accent-red"></div>
</div>
<div class="kpi-card fade-in">
<div class="kpi-label">PDFs Generated</div>
<div class="kpi-val">18</div>
<div class="kpi-sub">This month</div>
<div class="kpi-accent kpi-accent-blue"></div>
</div>
<div class="kpi-card fade-in">
<div class="kpi-label">Expiring (30d)</div>
<div class="kpi-val">9</div>
<div class="kpi-sub">Points rolling off</div>
<div class="kpi-accent kpi-accent-green"></div>
</div>
</div>
<div class="two-col">
<!-- Employee Roster -->
<div class="panel">
<div class="panel-head">
<span class="panel-title">Employee Roster</span>
<span style="font-size:11px;color:var(--text-muted);font-family:'DM Mono',monospace;">47 total</span>
</div>
<table class="emp-table">
<thead><tr><th>Employee</th><th>Dept</th><th>Standing</th></tr></thead>
<tbody>
<tr><td><div class="emp-name">Marcus T.</div></td><td><div style="font-size:11px;color:var(--text-muted);">Operations</div></td><td><span class="tier-badge tier-4">22 pts — Tier 4</span></td></tr>
<tr><td><div class="emp-name">Janelle R.</div></td><td><div style="font-size:11px;color:var(--text-muted);">Production</div></td><td><span class="tier-badge tier-3">17 pts — Tier 3</span></td></tr>
<tr><td><div class="emp-name">Devon H.</div></td><td><div style="font-size:11px;color:var(--text-muted);">Operations</div></td><td><span class="tier-badge tier-3">15 pts — Tier 3</span></td></tr>
<tr><td><div class="emp-name">Priya S.</div></td><td><div style="font-size:11px;color:var(--text-muted);">Impl &amp; Support</div></td><td><span class="tier-badge tier-2">12 pts — Tier 2</span></td></tr>
<tr><td><div class="emp-name">Carlos M.</div></td><td><div style="font-size:11px;color:var(--text-muted);">Production</div></td><td><span class="tier-badge tier-1">7 pts — Tier 1</span></td></tr>
<tr><td><div class="emp-name">Aisha W.</div></td><td><div style="font-size:11px;color:var(--text-muted);">Administrative</div></td><td><span class="tier-badge tier-1">5 pts — Tier 1</span></td></tr>
<tr><td><div class="emp-name">Tom B.</div></td><td><div style="font-size:11px;color:var(--text-muted);">Design &amp; Content</div></td><td><span class="tier-badge tier-0">2 pts — Elite</span></td></tr>
<tr><td><div class="emp-name">Sandra K.</div></td><td><div style="font-size:11px;color:var(--text-muted);">Business Dev</div></td><td><span class="tier-badge tier-0">0 pts — Elite</span></td></tr>
</tbody>
</table>
</div>
<!-- Recent Violations -->
<div class="panel">
<div class="panel-head">
<span class="panel-title">Recent Violations</span>
<span style="font-size:11px;color:var(--text-muted);font-family:'DM Mono',monospace;">Last 7 days</span>
</div>
<div>
<div class="viol-item">
<div class="viol-dot viol-dot-red"></div>
<div class="viol-info">
<div class="viol-name">Marcus T. <span class="repeat-tag">☆ REPEAT</span></div>
<div class="viol-type">Unauthorized Absence — Operations</div>
<div class="viol-meta"><span>Mar 6</span><span>·</span><span>D. Williams</span></div>
</div>
<div class="viol-pts">+5</div>
</div>
<div class="viol-item">
<div class="viol-dot viol-dot-red"></div>
<div class="viol-info">
<div class="viol-name">Janelle R.</div>
<div class="viol-type">Insubordination — Production</div>
<div class="viol-meta"><span>Mar 5</span><span>·</span><span>K. Thompson</span></div>
</div>
<div class="viol-pts">+4</div>
</div>
<div class="viol-item">
<div class="viol-dot viol-dot-yellow"></div>
<div class="viol-info">
<div class="viol-name">Devon H.</div>
<div class="viol-type">Tardiness (3×) — Operations</div>
<div class="viol-meta"><span>Mar 4</span><span>·</span><span>D. Williams</span></div>
</div>
<div class="viol-pts">+3</div>
</div>
<div class="viol-item">
<div class="viol-dot viol-dot-yellow"></div>
<div class="viol-info">
<div class="viol-name">Carlos M.</div>
<div class="viol-type">Cell Phone Policy — Production</div>
<div class="viol-meta"><span>Mar 3</span><span>·</span><span>K. Thompson</span></div>
</div>
<div class="viol-pts">+2</div>
</div>
<div class="viol-item">
<div class="viol-dot viol-dot-yellow"></div>
<div class="viol-info">
<div class="viol-name">Priya S.</div>
<div class="viol-type">Dress Code Violation — Impl &amp; Support</div>
<div class="viol-meta"><span>Mar 2</span><span>·</span><span>M. Johnson</span></div>
</div>
<div class="viol-pts">+1</div>
</div>
<div class="viol-item">
<div class="viol-dot viol-dot-green"></div>
<div class="viol-info">
<div class="viol-name">Aisha W.</div>
<div class="viol-type">Late Return from Break — Administrative</div>
<div class="viol-meta"><span>Mar 1</span><span>·</span><span>S. Martinez</span></div>
</div>
<div class="viol-pts">+1</div>
</div>
</div>
</div>
</div>
<div class="two-col">
<!-- Dept Breakdown -->
<div class="panel">
<div class="panel-head">
<span class="panel-title">Violations by Department</span>
<span style="font-size:11px;color:var(--text-muted);font-family:'DM Mono',monospace;">90-day window</span>
</div>
<div style="padding:8px 0;">
<div class="dept-row"><div class="dept-name">Operations</div><div class="dept-bar-track"><div class="dept-bar-fill" style="width:88%"></div></div><div class="dept-count">8</div></div>
<div class="dept-row"><div class="dept-name">Production</div><div class="dept-bar-track"><div class="dept-bar-fill" style="width:66%"></div></div><div class="dept-count">6</div></div>
<div class="dept-row"><div class="dept-name">Impl &amp; Support</div><div class="dept-bar-track"><div class="dept-bar-fill" style="width:44%"></div></div><div class="dept-count">4</div></div>
<div class="dept-row"><div class="dept-name">Administrative</div><div class="dept-bar-track"><div class="dept-bar-fill" style="width:22%"></div></div><div class="dept-count">2</div></div>
<div class="dept-row"><div class="dept-name">Business Dev</div><div class="dept-bar-track"><div class="dept-bar-fill" style="width:11%"></div></div><div class="dept-count">1</div></div>
<div class="dept-row"><div class="dept-name">Design &amp; Content</div><div class="dept-bar-track"><div class="dept-bar-fill" style="width:11%"></div></div><div class="dept-count">1</div></div>
<div class="dept-row"><div class="dept-name">Executive</div><div class="dept-bar-track"><div class="dept-bar-fill" style="width:0%"></div></div><div class="dept-count">0</div></div>
</div>
</div>
<!-- Audit Log -->
<div class="panel">
<div class="panel-head">
<span class="panel-title">Audit Log</span>
<span style="font-size:11px;color:var(--text-muted);font-family:'DM Mono',monospace;">System activity</span>
</div>
<div>
<div class="audit-item"><div class="audit-time">03/06 2:14p</div><div class="audit-action"><strong>Violation #41</strong> created — Marcus T.</div><div class="audit-pts">+5 pts</div></div>
<div class="audit-item"><div class="audit-time">03/06 2:15p</div><div class="audit-action">PDF generated for <strong>Violation #41</strong></div><div class="audit-pts"></div></div>
<div class="audit-item"><div class="audit-time">03/05 9:40a</div><div class="audit-action"><strong>Violation #40</strong> created — Janelle R.</div><div class="audit-pts">+4 pts</div></div>
<div class="audit-item"><div class="audit-time">03/04 11:20a</div><div class="audit-action">Employee <strong>Devon H.</strong> record updated</div><div class="audit-pts"></div></div>
<div class="audit-item"><div class="audit-time">03/04 8:55a</div><div class="audit-action"><strong>Violation #39</strong> created — Devon H.</div><div class="audit-pts">+3 pts</div></div>
<div class="audit-item"><div class="audit-time">03/03 3:30p</div><div class="audit-action"><strong>Violation #38</strong> amended — Carlos M.</div><div class="audit-pts">1 pt</div></div>
<div class="audit-item"><div class="audit-time">03/02 1:05p</div><div class="audit-action"><strong>Duplicate record</strong> merged — R. Johnson</div><div class="audit-pts"></div></div>
</div>
</div>
</div>
<!-- CPAS Tier Scale -->
<div style="margin-bottom:24px;">
<div class="section-header">
<div class="section-title">CPAS Tier Scale</div>
</div>
<div class="tier-timeline">
<div class="tier-seg ts-0"><div class="ts-pts">04</div><div class="ts-label">Elite<br/>Standing</div></div>
<div class="tier-seg ts-1"><div class="ts-pts">59</div><div class="ts-label">Tier 1<br/>Realignment</div></div>
<div class="tier-seg ts-2"><div class="ts-pts">1014</div><div class="ts-label">Tier 2<br/>Admin Lockdown</div></div>
<div class="tier-seg ts-3"><div class="ts-pts">1519</div><div class="ts-label">Tier 3<br/>Verification</div></div>
<div class="tier-seg ts-4"><div class="ts-pts">2024</div><div class="ts-label">Tier 4<br/>Risk Mitigation</div></div>
<div class="tier-seg ts-5"><div class="ts-pts">2529</div><div class="ts-label">Tier 5<br/>Final Decision</div></div>
<div class="tier-seg ts-6"><div class="ts-pts">30+</div><div class="ts-label">Tier 6<br/>Separation</div></div>
</div>
</div>
<!-- System Capabilities -->
<div class="section-header"><div class="section-title">System Capabilities</div></div>
<div class="features-grid">
<div class="feature-card fade-in"><span class="feature-icon"></span><div class="feature-title">Repeat Offense Detection</div><div class="feature-desc">Automatically flags prior violations for the same type and escalates point recommendations per recidivist policy.</div></div>
<div class="feature-card fade-in"><span class="feature-icon">📄</span><div class="feature-title">One-Click PDF Generation</div><div class="feature-desc">Generates signed, professional violation documents instantly — with or without employee acknowledgment signatures.</div></div>
<div class="feature-card fade-in"><span class="feature-icon">📀</span><div class="feature-title">Duplicate Record Merge</div><div class="feature-desc">Consolidate duplicate employee records while preserving full violation history under the canonical profile.</div></div>
<div class="feature-card fade-in"><span class="feature-icon">🕊</span><div class="feature-title">90-Day Rolling Window</div><div class="feature-desc">Points automatically expire after 90 days. Active standing reflects only the current compliance window.</div></div>
<div class="feature-card fade-in"><span class="feature-icon">🏷️</span><div class="feature-title">Tier Escalation Warnings</div><div class="feature-desc">Real-time alerts when a new violation would push an employee across a tier boundary before you submit.</div></div>
<div class="feature-card fade-in"><span class="feature-icon">🗂️</span><div class="feature-title">Full Audit Trail</div><div class="feature-desc">Every create, amendment, merge, and PDF generation is logged with timestamp and operator attribution.</div></div>
</div>
</div><!-- /tab-dashboard -->
<!-- ── VIOLATION FORM TAB ── -->
<div id="tab-violations" class="tab-pane">
<div style="margin-bottom:20px;">
<div style="background:#181200;border:1px solid var(--gold-dk);border-radius:8px;padding:12px 18px;font-size:12px;color:var(--gold-lt);font-family:'DM Mono',monospace;letter-spacing:0.4px;">
⚡ DEMO VIEW — Form fields shown with sample data. Submission is disabled in demo mode.
</div>
</div>
<div class="form-preview">
<div class="form-section">
<div class="form-section-title">Employee Information</div>
<div style="margin-bottom:16px;">
<div class="form-label" style="margin-bottom:6px;">Quick-Select Existing Employee:</div>
<div class="form-input filled" style="display:flex;align-items:center;justify-content:space-between;">
<span>Marcus Thompson — Operations</span><span style="color:var(--text-muted);font-size:11px;"></span>
</div>
<div style="margin-top:8px;display:flex;align-items:center;gap:10px;flex-wrap:wrap;">
<span style="font-size:12px;color:var(--text-dim);font-weight:600;">Current Standing:</span>
<span class="tier-badge tier-4">22 pts — Tier 4 · Risk Mitigation</span>
<span style="font-size:11px;color:var(--text-muted);">4 violations in last 90 days</span>
</div>
</div>
<div class="form-grid">
<div class="form-item"><div class="form-label">Employee Name:</div><div class="form-input filled">Marcus Thompson</div></div>
<div class="form-item"><div class="form-label">Department:</div><div class="form-input filled" style="display:flex;align-items:center;justify-content:space-between;"><span>Operations</span><span style="color:var(--text-muted);font-size:11px;"></span></div></div>
<div class="form-item"><div class="form-label">Supervisor Name:</div><div class="form-input filled">D. Williams</div></div>
<div class="form-item"><div class="form-label">Witness Name (Officer):</div><div class="form-input">Officer Name</div></div>
</div>
</div>
<div class="form-section">
<div class="form-section-title">Violation Details</div>
<div class="form-grid">
<div class="form-item" style="grid-column:1 / -1;">
<div class="form-label">Violation Type:</div>
<div class="form-input filled" style="display:flex;align-items:center;justify-content:space-between;">
<span>Unauthorized Absence ☆ 2x in 90 days</span><span style="color:var(--text-muted);font-size:11px;"></span>
</div>
<div style="background:#141623;border:1px solid var(--border-lt);border-radius:4px;padding:10px;font-size:12px;color:var(--text-dim);margin-top:6px;">
<strong>Unauthorized Absence</strong> <span class="repeat-tag">☆ Repeat — 2x prior</span><br/>
Absence from scheduled work without prior approval or acceptable documentation.<br/>
<span style="font-size:10px;color:#a0a3ba;">Chapter 4, Section 4.1 — Attendance &amp; Punctuality</span>
</div>
<div style="background:#3b2e00;border:1px solid var(--gold-dk);border-radius:4px;padding:8px 12px;margin-top:6px;font-size:12px;color:#ffdf8a;">
<strong>Repeat offense detected.</strong> Point slider set to maximum (5 pts) per recidivist policy. Adjust if needed.
</div>
</div>
<div class="form-item"><div class="form-label">Incident Date:</div><div class="form-input filled">2026-03-06</div></div>
</div>
<div style="background:#2d1a00;border:1px solid #a06000;border-radius:6px;padding:12px 16px;margin-top:16px;font-size:13px;color:#ffc107;">
<strong>Tier escalation warning:</strong> Adding 5 pts will bring Marcus to <strong>27 pts (Tier 5 — Final Decision)</strong>. This is one tier below Separation. Review carefully.
</div>
<div style="background:#181200;border:2px solid var(--gold);padding:14px;border-radius:6px;margin:16px 0 0;text-align:center;">
<div style="color:#ffdf8a;font-weight:700;margin-bottom:8px;">CPAS Point Assessment</div>
<div style="font-size:13px;color:var(--text-dim);">Unauthorized Absence: 35 Points</div>
<div style="width:100%;height:6px;background:var(--border-lt);border-radius:3px;margin:12px 0 4px;overflow:hidden;"><div style="width:100%;height:100%;background:linear-gradient(90deg,var(--gold-dk),var(--gold));border-radius:3px;"></div></div>
<div class="point-val">5 Points</div>
<div style="font-size:12px;color:var(--text-dim);margin-top:4px;">Adjust to reflect severity and context</div>
</div>
</div>
<div style="background:var(--bg-section);border-left:4px solid #2196F3;padding:20px 24px;margin:20px;border-radius:4px;border:1px solid var(--border-lt);">
<div style="font-family:'Syne',sans-serif;font-size:16px;font-weight:700;margin-bottom:8px;">Employee Acknowledgment</div>
<div style="font-size:12px;color:var(--text-muted);margin-bottom:14px;line-height:1.6;">If the employee is present and acknowledges receipt of this violation, enter their name and the date below.</div>
<div class="form-grid">
<div class="form-item"><div class="form-label">Acknowledged By:</div><div class="form-input">Employee's printed name</div></div>
<div class="form-item"><div class="form-label">Acknowledgment Date:</div><div class="form-input">yyyy-mm-dd</div></div>
</div>
</div>
<div style="display:flex;gap:14px;justify-content:center;padding:20px 20px 28px;">
<button style="padding:14px 36px;font-size:15px;font-weight:700;border:none;border-radius:6px;cursor:not-allowed;background:linear-gradient(135deg,#d4af37,#ffdf8a);color:#000;text-transform:uppercase;opacity:0.5;">Submit Violation</button>
<button style="padding:14px 36px;font-size:15px;font-weight:700;border:1px solid var(--border-lt);border-radius:6px;cursor:not-allowed;background:#050608;color:var(--text);text-transform:uppercase;opacity:0.5;">Clear Form</button>
</div>
</div>
</div><!-- /tab-violations -->
</div><!-- /main -->
<footer>
<div class="footer-left">
<div class="footer-brand">CPAS Tracker</div>
<div class="footer-divider"></div>
<div class="footer-copy">© 2026 Jason Stedwell</div>
<div class="footer-divider"></div>
<div style="font-size:11px;color:var(--text-muted);">DEMO BUILD — All data synthetic</div>
</div>
<div class="footer-right">
<a class="footer-gitea" href="https://git.alwisp.com/jason/cpas" target="_blank" rel="noopener">
<!-- Gitea logo SVG -->
<svg viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg">
<path d="M321.6 3.2C146.4 3.2 3.2 146.4 3.2 321.6c0 141.6 91.8 261.9 219.7 304.1 16.1 3 22-7 22-15.5 0-7.6-.3-32.8-.4-59.5-89.5 19.4-108.4-38.4-108.4-38.4-14.6-37.2-35.7-47.1-35.7-47.1-29.2-20 2.2-19.6 2.2-19.6 32.3 2.3 49.3 33.1 49.3 33.1 28.7 49.2 75.3 35 93.7 26.7 2.9-20.8 11.2-35 20.4-43-71.4-8.1-146.5-35.7-146.5-158.9 0-35.1 12.5-63.8 33.1-86.3-3.3-8.1-14.4-40.8 3.1-85.1 0 0 27-8.7 88.4 32.9 25.6-7.1 53.1-10.7 80.4-10.8 27.3.1 54.8 3.7 80.5 10.8 61.3-41.6 88.3-32.9 88.3-32.9 17.6 44.3 6.5 77 3.2 85.1 20.6 22.5 33 51.2 33 86.3 0 123.5-75.2 150.7-146.8 158.7 11.5 10 21.8 29.7 21.8 59.8 0 43.2-.4 78-0.4 88.6 0 8.6 5.8 18.6 22.1 15.5C524.8 583.2 616.8 463.1 616.8 321.6 616.8 146.4 473.6 3.2 298.4 3.2z"/>
</svg>
jason/cpas
</a>
<div class="footer-divider"></div>
<div class="footer-ticker">
<div class="footer-ticker-dot"></div>
<div class="footer-ticker-label">Dev Time</div>
<div class="footer-ticker-time" id="dev-ticker"></div>
</div>
</div>
</footer>
<script>
function switchTab(name, el) {
document.querySelectorAll('.tab-pane').forEach(p => p.classList.remove('active'));
document.querySelectorAll('.nav-tab').forEach(t => t.classList.remove('active'));
document.getElementById('tab-' + name).classList.add('active');
el.classList.add('active');
}
// ── DEV TIME TICKER ──────────────────────────────────────────────────────────
// Base dev time calculated from real commit sessions (30-min gap = new session).
// Each session timed as (last_commit - first_commit) + 15min overhead.
//
// Session 1: 2026-03-06 11:33 → 12:05 = 32min + 15 = 47min
// Session 2: 2026-03-06 12:19 → 18:00 = 341min + 15 = 356min
// Session 3: 2026-03-06 23:18 → 23:41 = 23min + 15 = 38min
// Session 4: 2026-03-07 09:22 → 09:53 = 31min + 15 = 46min
// Session 5: 2026-03-07 18:31 → 19:02 = 31min + 15 = 46min
// Session 6: 2026-03-07 21:28 → 22:02 = 34min + 15 = 49min
// Session 7: 2026-03-07 23:13 → 23:59 = 46min + 15 = 61min
// Session 8: 2026-03-08 00:11 → 00:12 = 1min + 15 = 16min
// Total: 659min = 39,540 seconds
//
// Anchor: last commit timestamp 2026-03-08T06:12:11Z (UTC)
// Ticker ticks up every second from that base.
const BASE_SECONDS = 39540;
const ANCHOR_UTC = new Date('2026-03-08T06:12:11Z').getTime();
function formatDevTime(totalSec) {
const h = Math.floor(totalSec / 3600);
const m = Math.floor((totalSec % 3600) / 60);
const s = totalSec % 60;
return `${String(h).padStart(2,'0')}h ${String(m).padStart(2,'0')}m ${String(s).padStart(2,'0')}s`;
}
function updateTicker() {
const elapsed = Math.floor((Date.now() - ANCHOR_UTC) / 1000);
const total = BASE_SECONDS + Math.max(0, elapsed);
document.getElementById('dev-ticker').textContent = formatDevTime(total);
}
updateTicker();
setInterval(updateTicker, 1000);
</script>
</body>
</html>