Files
ecw-charge-validation/web/templates/signin.html
T
2026-10-30 10:58:35 +05:30

142 lines
8.5 KiB
HTML

{% extends "base.html" %}
{% block title %}Sign in{% endblock %}
{% block style %}
/* The approved mockup (operator, 2026-10-30): a deep sage panel with
what the Portal is, the form in a white card; one column on a phone. */
footer.foot { display: none; }
main { padding: 0; }
nav.crumbs { display: none; }
.auth { display: flex; flex-wrap: wrap; gap: 20px;
min-height: calc(100vh - 40px); }
.auth-brand { flex: 1 1 520px; background: var(--navy); color: #f2f4f1;
border-radius: 28px; padding: 44px 52px; display: flex;
flex-direction: column; justify-content: space-between;
gap: 32px; }
.auth-brand .logo { display: flex; align-items: center; gap: 12px;
font-family: var(--display); font-weight: 500;
font-size: 18px; }
.auth-brand .big { display: inline-grid; place-items: center; width: 42px;
height: 42px; border-radius: 12px; background: var(--lime);
color: var(--navy); font-size: 14px; font-weight: 800; }
.auth-brand h1 { font-family: var(--display); font-weight: 200;
font-size: clamp(52px, 7vw, 88px); line-height: .95;
letter-spacing: -2px; margin: 0 0 18px; color: #f2f4f1; }
.auth-brand h1 span { color: var(--lime); font-weight: 300; }
.auth-brand p.lead { margin: 0; font-size: 17px; line-height: 1.55;
color: #c9d4cd; max-width: 520px; }
.auth-brand ul { list-style: none; margin: 0; padding: 0; display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 14px; }
.auth-brand li { background: rgba(242, 244, 241, .08); border-radius: 18px;
padding: 16px; display: flex; flex-direction: column;
gap: 8px; animation: rise .5s ease both; }
.auth-brand li:nth-child(2) { animation-delay: .1s; }
.auth-brand li:nth-child(3) { animation-delay: .2s; }
.auth-brand li svg { color: var(--lime); }
.auth-brand li b { color: #f2f4f1; font-size: 15px; }
.auth-brand li small { color: #c9d4cd; font-size: 13px; line-height: 1.45; }
.auth-side { flex: 999 1 400px; display: flex; align-items: center;
justify-content: center; padding: 24px 8px; }
.auth-form { width: 100%; max-width: 420px; background: var(--panel);
border-radius: 28px; padding: 40px; box-shadow: var(--shadow);
animation: rise .5s ease both; }
.auth-form h2 { font-family: var(--display); font-weight: 500;
font-size: 32px; letter-spacing: -.5px; margin: 0 0 6px; }
.auth-form .intro { color: var(--muted); margin: 0 0 22px; font-size: 15px; }
.field { margin-bottom: 18px; }
.field label { display: block; font-weight: 500; margin-bottom: 8px;
font-size: 14px; }
.field .box { display: flex; align-items: center; height: 48px;
border: 1px solid #d5dbd6; border-radius: 12px;
background: var(--panel);
transition: border-color .15s, box-shadow .15s; }
.field .box:focus-within { border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(74, 107, 88, .18); }
.field .ic { padding: 0 2px 0 14px; color: var(--muted); display: flex; }
.field input { flex: 1; border: 0; padding: 0 10px; height: 100%;
min-width: 0; background: transparent; outline: none; }
.field button.eye { background: transparent; border: 0; color: var(--accent);
font-weight: 600; font-size: 13px; padding: 0 14px; }
.field button.eye:hover { background: transparent; text-decoration: underline; }
#caps { color: var(--review); font-size: 12px; margin-top: 6px; }
.auth-form button[type="submit"] { width: 100%; height: 52px;
font-size: 16px; border-radius: 14px;
margin-top: 4px;
transition: transform .15s, box-shadow .15s; }
.auth-form button[type="submit"]:hover { transform: translateY(-1px);
box-shadow: 0 8px 18px rgba(74, 107, 88, .3); }
.auth-form .rules { margin: 20px 0 0; padding: 12px 14px;
background: var(--bg); border-radius: 12px;
line-height: 1.5; }
@media (max-width: 760px) {
.auth-brand { padding: 28px 24px; }
.auth-brand ul { display: none; }
.auth-form { padding: 28px 22px; }
}
{% endblock %}
{% block content %}
<div class="auth">
<section class="auth-brand">
<div class="logo"><span class="big" aria-hidden="true">CV</span>Ecare OTS</div>
<div>
<h1>Charge<br><span>Validation</span></h1>
<p class="lead">Agent run monitoring for the eCW Medcor Ready queue:
every claim checked against the Charge Condition Document.</p>
</div>
<ul>
<li><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3 8 4-16 3 8h4"></path></svg><b>Daily run status</b><small>Live progress of the agent and each run.</small></li>
<li><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"></rect><path d="M3 10h18M9 4v16"></path></svg><b>Claim results</b><small>Pass, Fail and Review with the reason.</small></li>
<li><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l8 4v5c0 5-3.5 8-8 9-4.5-1-8-4-8-9V7z"></path></svg><b>{{ mode }} mode</b><small>{% if mode == "VERIFY" %}Nothing is saved to eCW claims.{% else %}Corrections are saved after a person confirms.{% endif %}</small></li>
</ul>
</section>
<section class="auth-side">
<div class="auth-form">
<h2>Welcome back</h2>
<p class="intro">Sign in to the Charge Validation portal.</p>
{% if ecare_on %}<p class="note">Ecare staff: your Ecare office username and password.</p>{% endif %}
{% if error %}<div class="msg bad" role="alert">{{ error }}</div>{% endif %}
{% if no_users %}<div class="msg bad">No Portal Users yet. On this PC run
<code>python tools\add_portal_user.py</code> to add the first Admin.</div>{% endif %}
<form method="post" action="/signin" autocomplete="off">
<input type="hidden" name="token" value="{{ run_token }}">
<input type="hidden" name="next" value="{{ next_url }}">
<div class="field">
<label for="username">Username</label>
<div class="box"><span class="ic" aria-hidden="true"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="8" r="4"></circle><path d="M4 21c1-4 4-6 8-6s7 2 8 6"></path></svg></span><input id="username" name="username" autocomplete="username" required autofocus></div>
</div>
<div class="field">
<label for="pw">Password</label>
<div class="box"><span class="ic" aria-hidden="true"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="4" y="11" width="16" height="10" rx="2"></rect><path d="M8 11V7a4 4 0 0 1 8 0v4"></path></svg></span><input id="pw" name="password" type="password" autocomplete="current-password" required><button type="button" class="eye" id="pw-toggle" aria-controls="pw" aria-pressed="false">Show</button></div>
<div id="caps" role="status" hidden>Caps Lock is on</div>
</div>
<button type="submit">Sign in</button>
</form>
<p class="note rules">Ecare network or VPN only. Signed out after
{{ idle_minutes }} minutes idle. {{ lock_after }} wrong passwords lock
the account for {{ lock_minutes }} minutes. Forgot a Portal password?
An Admin can reset it.</p>
</div>
</section>
</div>
{% endblock %}
{% block scripts %}
<script>
(() => {
const pw = $('pw'), eye = $('pw-toggle'), caps = $('caps');
eye.addEventListener('click', () => {
const show = pw.type === 'password';
pw.type = show ? 'text' : 'password';
eye.textContent = show ? 'Hide' : 'Show';
eye.setAttribute('aria-pressed', String(show));
pw.focus();
});
const capsCheck = e => {
if (e.getModifierState) caps.hidden = !e.getModifierState('CapsLock');
};
pw.addEventListener('keydown', capsCheck);
pw.addEventListener('keyup', capsCheck);
pw.addEventListener('blur', () => { caps.hidden = true; });
})();
</script>
{% endblock %}