Files
ecw-charge-validation/web/templates/base.html
T
ManikandanandClaude Opus 5.5 ba15a574ab Initial import: eCW Charge Validation bot and results Portal
Snapshot of the working project as of 2026-10-23 (local 2d4d4fc), one
commit with no earlier history: the tracked files were de-identified
first (synthetic claim ids and patient data only; see Context.md
section 7). Credentials, run logs, screenshots, claim reports and client
workbooks are gitignored and not included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 18:38:17 +05:30

193 lines
10 KiB
HTML
Raw 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">
<meta name="run-token" content="{{ run_token }}">
<title>{% block title %}Charge Validation{% endblock %} · eCW</title>
{% block head %}{% endblock %}
<style>
/* Navy & blue (operator, 2026-10-19): navy header, white cards on light
grey, blue buttons; Pass green, Fail red, Review amber everywhere. */
:root {
--navy: #12355b; --navy-2: #0f2a47; --bg: #f4f6fa; --panel: #ffffff;
--text: #1f2a37; --muted: #6b7785; --line: #dde3ec; --head: #e8edf4;
--accent: #1565c0; --accent-dark: #0d4f9e;
--pass: #2e7d32; --pass-bg: #e8f5e9;
--fail: #c62828; --fail-bg: #fdecea;
--review: #b45309; --review-bg: #fff3e0; --review-bar: #ef6c00;
--stripe: #f9fafc; --hilite: #eef4ff; --sel: #dbe7fb;
--shadow: 0 1px 2px rgba(18, 53, 91, .06), 0 2px 8px rgba(18, 53, 91, .05);
}
* { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--text);
font: 14px/1.45 "Segoe UI", system-ui, sans-serif; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
header.top { background: var(--navy); color: #fff; padding: 12px 24px;
display: flex; align-items: center; gap: 14px; }
header.top .brand { color: #fff; font-size: 17px; font-weight: 600;
letter-spacing: .2px; }
header.top .brand:hover { text-decoration: none; }
.pill { border-radius: 12px; padding: 2px 10px; font-size: 11px;
font-weight: 700; letter-spacing: .4px; background: var(--pass);
color: #fff; }
.pill.LIVE-WRITE { background: var(--fail); }
header.top nav.links { margin-left: auto; display: flex; gap: 18px;
align-items: center; }
header.top nav.links a { color: #e3ecf7; font-weight: 600; }
header.top .who { color: #b9c6d6; font-size: 13px; }
header.top .who b { color: #fff; }
header.top form.out { margin: 0; }
header.top form.out button { background: transparent; border-color: #6f86a3;
font-weight: 400; padding: 4px 10px; }
.msg { border-radius: 8px; padding: 10px 14px; margin-bottom: 14px; }
.msg.bad { background: var(--fail-bg); color: var(--fail); }
.msg.good { background: var(--pass-bg); color: var(--pass); }
nav.crumbs { background: var(--navy-2); color: #b9c6d6; padding: 7px 24px;
font-size: 13px; }
nav.crumbs a { color: #e3ecf7; }
nav.crumbs .sep { margin: 0 8px; color: #7d8ea3; }
nav.crumbs .here { color: #fff; font-weight: 600; }
main { max-width: 1180px; margin: 0 auto; padding: 22px 24px 40px; }
h1 { font-size: 20px; margin: 0 0 4px; }
.sub { color: var(--muted); margin: 0 0 16px; }
.card { background: var(--panel); border: 1px solid var(--line);
border-radius: 10px; padding: 16px 18px; box-shadow: var(--shadow);
margin-bottom: 18px; }
.card h2 { font-size: 15px; margin: 0 0 10px; }
.tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px; margin-bottom: 18px; }
.tile { background: var(--panel); border: 1px solid var(--line);
border-radius: 10px; padding: 12px 16px; box-shadow: var(--shadow);
color: var(--text); display: block; }
.tile .n { font-size: 26px; font-weight: 700; display: block; }
.tile .l { color: var(--muted); font-size: 12px; text-transform: uppercase;
letter-spacing: .5px; }
.tile.Pass .n { color: var(--pass); }
.tile.Fail .n { color: var(--fail); }
.tile.Review .n { color: var(--review); }
a.tile:hover { text-decoration: none; border-color: var(--accent); }
a.tile.on { border: 2px solid var(--accent); padding: 11px 15px; }
select, input, button { font: inherit; padding: 7px 10px;
border: 1px solid #c9d2de; border-radius: 6px;
background: var(--panel); color: var(--text); }
button, .btn { background: var(--accent); color: #fff;
border: 1px solid var(--accent); border-radius: 6px;
padding: 7px 14px; cursor: pointer; font-weight: 600;
display: inline-block; }
button:hover, .btn:hover { background: var(--accent-dark);
text-decoration: none; }
button.plain { background: var(--panel); color: var(--text);
border-color: #c9d2de; font-weight: 400; }
button.plain:hover { background: var(--hilite); }
button[disabled] { opacity: .5; cursor: default; }
.cat { display: inline-block; padding: 2px 9px; border-radius: 10px;
font-weight: 600; font-size: 12px; }
.cat.Pass { background: var(--pass-bg); color: var(--pass); }
.cat.Fail { background: var(--fail-bg); color: var(--fail); }
.cat.Review { background: var(--review-bg); color: var(--review); }
.empty { background: var(--panel); border: 1px dashed #c9d2de;
border-radius: 10px; padding: 26px; color: var(--muted);
text-align: center; }
.note { color: var(--muted); font-size: 12px; }
footer.note { max-width: 1180px; margin: 0 auto; padding: 0 24px 24px; }
/* Tables: short, no sideways scroll; long text cut on one line. */
table.list { width: 100%; border-collapse: separate; border-spacing: 0;
background: var(--panel); border: 1px solid var(--line);
border-radius: 10px; overflow: hidden; table-layout: fixed; }
table.list th, table.list td { padding: 9px 12px; text-align: left;
border-bottom: 1px solid var(--line);
overflow: hidden; text-overflow: ellipsis;
white-space: nowrap; }
table.list th { background: var(--head); font-size: 12px; color: #3b4757;
font-weight: 600; text-transform: uppercase;
letter-spacing: .4px; }
table.list tbody tr { cursor: pointer; }
table.list tbody tr:nth-child(even) td { background: var(--stripe); }
table.list tbody tr:hover td { background: var(--hilite); }
table.list tbody tr.sel td { background: var(--sel); }
table.list tbody tr:last-child td { border-bottom: 0; }
td.claim { font-weight: 600; }
.pager { display: flex; gap: 6px; align-items: center; flex-wrap: wrap;
margin: 12px 0; }
.pager button { padding: 4px 10px; background: var(--panel);
color: var(--text); border-color: #c9d2de; font-weight: 400; }
.pager button.cur { background: var(--accent); color: #fff;
border-color: var(--accent); }
.pager button[disabled]:not(.cur) { opacity: .4; }
.pager .info { color: var(--muted); margin-left: 8px; }
form.search { display: flex; gap: 8px; align-items: center;
flex-wrap: wrap; }
form.search input { min-width: 220px; }
/* Side panels. The page under an open panel does not scroll: one scroll
bar, the panel's (operator, 2026-10-15; review 2026-10-19). */
body.drawer-open { overflow: hidden; }
.drawer { position: fixed; top: 0; right: 0; height: 100vh;
width: min(480px, 100vw); background: var(--panel);
border-left: 1px solid var(--line); z-index: 20;
box-shadow: -8px 0 24px rgba(18, 53, 91, .12);
padding: 0 0 30px; overflow-y: auto; }
.drawer[hidden] { display: none; }
.drawer .top { display: flex; align-items: center; gap: 10px;
background: var(--navy); color: #fff; padding: 12px 18px;
position: sticky; top: 0; }
.drawer .top h2 { font-size: 16px; margin: 0; }
.drawer .top .close { margin-left: auto; background: transparent;
border-color: #6f86a3; font-weight: 400; }
.drawer .body { padding: 14px 18px; }
.drawer dl { display: grid; grid-template-columns: 140px 1fr;
gap: 6px 12px; margin: 0; font-size: 13px; }
.drawer dt { color: var(--muted); }
.drawer dd { margin: 0; white-space: pre-wrap; word-break: break-word; }
.drawer h3 { font-size: 14px; margin: 16px 0 6px; }
.drawer pre { background: var(--head); padding: 10px; border-radius: 6px;
white-space: pre-wrap; font-size: 12px; margin: 0; }
@media (max-width: 760px) {
.tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
main { padding: 16px; }
header.top, nav.crumbs { padding-left: 16px; padding-right: 16px; }
}
{% block style %}{% endblock %}
</style>
<script>
// Shared by every page, defined before any page script runs: one side
// panel open at a time; Escape and every Close button shut it.
const $ = id => document.getElementById(id);
const CATEGORIES = {{ categories | list | tojson }};
function openPanel(id) {
document.querySelectorAll('.drawer').forEach(p => p.hidden = p.id !== id);
document.body.classList.toggle('drawer-open', id !== null);
}
const closePanels = () => openPanel(null);
document.addEventListener('click', e => {
if (e.target.closest('.drawer .close')) closePanels();
});
document.addEventListener('keydown', e => {
if (e.key === 'Escape') closePanels();
});
</script>
</head>
<body>
<header class="top">
<a class="brand" href="/">eCW Charge Validation</a>
<span class="pill {{ mode }}" title="SAVE_CORRECTIONS mode">{{ mode }}</span>
{% if user %}<nav class="links">
<a href="/days">Claim status</a><a href="/runs">Runs</a>
{% if is_admin %}<a href="/admin/users">Users</a><a href="/admin/signins">Sign-ins</a>{% endif %}
<a class="who" href="/account/password" title="Change password"><b>{{ user.display_name }}</b> · {{ user.role }}</a>
<form class="out" method="post" action="/signout"><input type="hidden" name="token" value="{{ run_token }}"><button type="submit">Sign out</button></form>
</nav>{% endif %}
</header>
<nav class="crumbs">
{% for label, link in crumbs %}{% if not loop.first %}<span class="sep">›</span>{% endif %}{% if link %}<a href="{{ link }}">{{ label }}</a>{% else %}<span class="here">{{ label }}</span>{% endif %}{% endfor %}
</nav>
<main>
{% block content %}{% endblock %}
</main>
<footer class="note">Local page (127.0.0.1) — contains patient data; do not
share screenshots outside the team.</footer>
{% block scripts %}{% endblock %}
</body>
</html>