Branding, Excel watermark, live run progress, and uv

- Login and Reports pages: eCare logo, Waystar and Aquilaehr logos (light
  versions for the dark pages), eCare favicon.
- Excel reports: faded eCare/Waystar/Aquila watermark as the sheet
  background on both sheets. Report writer moves to xlsxwriter, the only
  engine that can set a sheet background.
- Reports page: animated run progress (both download lanes piped into the
  Excel sheet) and a plain-language activity feed built from the run log;
  the raw log stays under "Technical log". /status now returns the
  location count.
- Dependencies move from requirements.txt to pyproject.toml + uv.lock;
  Dockerfile installs uv from PyPI and runs uv sync --frozen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
VasanthandClaude Opus 5.5 committed 2026-10-28 14:43:31 +05:30
1 parent 2e1f28967e
commit 6616c91b7f
17 files changed
+816 -31

No files matched your search

+31 -1
View File
@@ -4,6 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Sign in · MEK Charge Reconciliation</title>
<link rel="icon" href="/static/ecare-logo.png">
<style>
:root {
--night: #040b26;
@@ -45,6 +46,14 @@
.sky .tw { animation: twinkle 4s ease-in-out infinite; animation-delay: var(--d); }
@keyframes twinkle { 50% { opacity: .15; } }
.brand {
position: absolute;
top: 20px;
left: 24px;
z-index: 1;
}
.brand img { display: block; width: 72px; height: auto; background: #000; border-radius: 16px; box-shadow: 0 6px 16px rgba(0, 3, 15, .45); }
.stage {
position: relative;
min-height: 100%;
@@ -87,6 +96,18 @@
overflow: visible;
}
.sources {
display: flex;
align-items: center;
gap: 20px;
margin-top: 28px;
}
.sources img { display: block; height: auto; }
.sources .waystar { width: 132px; }
.sources .sep { width: 1px; height: 26px; background: var(--panel-line); }
.aquila { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 16px; color: #dfe6f7; letter-spacing: .01em; }
.aquila img { width: 30px; }
label { display: block; font-weight: 600; margin-bottom: 8px; }
.field { position: relative; }
input {
@@ -195,6 +216,8 @@
@media (max-width: 420px) {
:root { --owl-w: 160px; }
.brand { top: 16px; left: 16px; }
.brand img { width: 52px; border-radius: 12px; }
}
@media (prefers-reduced-motion: reduce) {
.sky .tw, .owl, .owl * { animation: none !important; transition: none !important; }
@@ -204,6 +227,7 @@
</head>
<body>
<div class="sky" id="sky" aria-hidden="true"></div>
<header class="brand"><img src="/static/ecare-logo.png" alt="eCare Services" width="206" height="199"></header>
<main class="stage">
<section class="card">
@@ -272,6 +296,12 @@
</form>
</section>
<footer class="sources">
<img src="/static/waystar-logo-light.png" alt="Waystar" width="362" height="61" class="waystar">
<span class="sep" aria-hidden="true"></span>
<span class="aquila"><img src="/static/aquilaehr-logo-light.png" alt="" width="86" height="75">Aquilaehr</span>
</footer>
</main>
<script>
@@ -293,7 +323,7 @@ function drawSky() {
let seed = 7;
const rand = () => (seed = (seed * 16807) % 2147483647) / 2147483647;
const colors = ["#6ea8ff", "#4fd1c5", "#f29c4b", "#dfe7ff"];
const keepOut = [...document.querySelectorAll(".card, .owl")].map(e => e.getBoundingClientRect());
const keepOut = [...document.querySelectorAll(".card, .owl, .brand, .sources")].map(e => e.getBoundingClientRect());
let html = "";
for (let i = 0; i < 60; i++) {
const tw = rand() < .35, x = rand() * innerWidth, y = rand() * innerHeight;