feat: enhance demo footer with copyright, Gitea link, and live dev-time ticker

This commit is contained in:
2026-03-08 00:19:59 -06:00
parent 87649b59d0
commit 232814db93

View File

@@ -407,8 +407,94 @@
.feature-desc { font-size: 12px; color: var(--text-muted); line-height: 1.6; }
/* ── FOOTER ── */
footer { border-top: 1px solid var(--border); padding: 24px 40px; display: flex; align-items: center; justify-content: space-between; font-size: 11px; color: var(--text-muted); font-family: 'DM Mono', monospace; }
.footer-brand { font-family: 'Syne', sans-serif; font-size: 13px; font-weight: 700; color: var(--text-dim); }
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; }
@@ -429,6 +515,8 @@
.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>
@@ -531,7 +619,7 @@
<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-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>
@@ -643,8 +731,8 @@
<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">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>
@@ -656,7 +744,7 @@
<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.
DEMO VIEW — Form fields shown with sample data. Submission is disabled in demo mode.
</div>
</div>
@@ -688,10 +776,10 @@
<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>
<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/>
<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>
@@ -702,7 +790,7 @@
<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.
<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>
@@ -733,9 +821,28 @@
</div><!-- /main -->
<footer>
<div class="footer-left">
<div class="footer-brand">CPAS Tracker</div>
<div>DEMO BUILD — All data synthetic — Not for operational use</div>
<div>© 2026 MPM</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>
@@ -745,6 +852,42 @@
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>