File size: 10,380 Bytes
e4fd6e0 e3566c9 ae34acf e3566c9 e4fd6e0 e3566c9 e4fd6e0 9fc36aa e4fd6e0 e3566c9 e4fd6e0 9fc36aa e4fd6e0 9fc36aa e4fd6e0 9fc36aa e4fd6e0 e3566c9 e4fd6e0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Login β AI Medical Intelligence Pipeline</title>
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}" />
<link rel="icon" type="image/png" sizes="32x32" href="{{ url_for('static', filename='favicon-192.png') }}" />
<link rel="apple-touch-icon" sizes="180x180" href="{{ url_for('static', filename='apple-touch-icon.png') }}" />
<meta name="description" content="Sign in to the AI Medical Intelligence Pipeline dashboard."/>
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
<link rel="stylesheet" href="{{ url_for('static', filename='css/base.css') }}"/>
<link rel="stylesheet" href="{{ url_for('static', filename='css/auth.css') }}"/>
</head>
<body>
<div class="auth-page">
<!-- ββ Left brand panel ββ -->
<aside class="auth-brand">
<div class="auth-brand-logo">
<div class="auth-brand-icon">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M22 12h-4l-3 9L9 3l-3 9H2"/>
</svg>
</div>
<span class="auth-brand-name">AI Medical Intelligence Pipeline</span>
</div>
<div class="auth-headline">
<h2>AI-Powered <span class="grad">Hemorrhage</span> Detection</h2>
<p>Clinical-grade CT scan analysis with Grad-CAM explainability β built for speed, precision, and trust.</p>
</div>
<ul class="auth-features">
<li>
<span class="feat-icon">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M12 1v4M12 19v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M1 12h4M19 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83"/></svg>
</span>
AI medical intelligence for CT analysis
</li>
<li>
<span class="feat-icon">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>
</span>
Grad-CAM heatmap visualisation
</li>
<li>
<span class="feat-icon">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
</span>
Automated clinical PDF reports
</li>
<li>
<span class="feat-icon">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
</span>
Secure, per-user data isolation
</li>
</ul>
<!-- CT Scanner Radar Illustration -->
<div class="auth-illustration">
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<radialGradient id="scanGlow" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#6ea8fe" stop-opacity=".18"/>
<stop offset="100%" stop-color="#6ea8fe" stop-opacity="0"/>
</radialGradient>
<clipPath id="scanClip">
<circle cx="100" cy="100" r="96"/>
</clipPath>
</defs>
<!-- Scanner frame -->
<circle cx="100" cy="100" r="96" fill="#07101f" stroke="#243356" stroke-width="2"/>
<!-- Brain tissue layers (filled β depth via lightness) -->
<circle cx="100" cy="100" r="80" fill="#0b1728"/>
<circle cx="100" cy="100" r="64" fill="#0e1d32"/>
<circle cx="100" cy="100" r="46" fill="#111e34"/>
<circle cx="100" cy="100" r="26" fill="#09131e"/>
<!-- Layer stroke rings -->
<circle cx="100" cy="100" r="80" stroke="#1a2d4e" stroke-width="1"/>
<circle cx="100" cy="100" r="64" stroke="#162244" stroke-width=".75"/>
<circle cx="100" cy="100" r="46" stroke="#162244" stroke-width=".5"/>
<!-- Crosshair guide lines (clipped to scanner) -->
<g clip-path="url(#scanClip)" opacity=".22">
<line x1="4" y1="100" x2="196" y2="100" stroke="#6ea8fe" stroke-width=".75"/>
<line x1="100" y1="4" x2="100" y2="196" stroke="#6ea8fe" stroke-width=".75"/>
<line x1="29" y1="29" x2="171" y2="171" stroke="#6ea8fe" stroke-width=".5"/>
<line x1="171" y1="29" x2="29" y2="171" stroke="#6ea8fe" stroke-width=".5"/>
</g>
<!-- Radar sweep wedge: top-right quarter (0Β° β 90Β°) -->
<!-- Wedge fill -->
<path d="M100,100 L100,20 A80,80 0 0,1 180,100 Z" fill="#6ea8fe" opacity=".07"/>
<!-- Trailing edge (vertical) -->
<line x1="100" y1="100" x2="100" y2="20" stroke="#6ea8fe" stroke-width="1" opacity=".4"/>
<!-- Leading edge (horizontal) -->
<line x1="100" y1="100" x2="180" y2="100" stroke="#6ea8fe" stroke-width="1.5" opacity=".85"/>
<!-- Arc from top to right β A80,80 0 0,1 means clockwise, rx=ry=80 -->
<path d="M100,20 A80,80 0 0,1 180,100" stroke="#6ea8fe" stroke-width="2" stroke-linecap="round" opacity=".9"/>
<!-- Anchor dots at sweep endpoints -->
<circle cx="100" cy="20" r="2.5" fill="#6ea8fe" opacity=".6"/>
<circle cx="180" cy="100" r="3.5" fill="#6ea8fe" opacity=".9"/>
<!-- Cardinal tick marks -->
<line x1="100" y1="4" x2="100" y2="14" stroke="#6ea8fe" stroke-width="2" stroke-linecap="round" opacity=".7"/>
<line x1="100" y1="186" x2="100" y2="196" stroke="#6ea8fe" stroke-width="2" stroke-linecap="round" opacity=".7"/>
<line x1="4" y1="100" x2="14" y2="100" stroke="#6ea8fe" stroke-width="2" stroke-linecap="round" opacity=".7"/>
<line x1="186" y1="100" x2="196" y2="100" stroke="#6ea8fe" stroke-width="2" stroke-linecap="round" opacity=".7"/>
<!-- Outer scanner ring overlay -->
<circle cx="100" cy="100" r="96" fill="none" stroke="#6ea8fe" stroke-width="1" opacity=".35"/>
<!-- Center reticle -->
<circle cx="100" cy="100" r="17" stroke="#6ea8fe" stroke-width=".75" fill="none" opacity=".2"/>
<circle cx="100" cy="100" r="10" stroke="#6ea8fe" stroke-width="1" fill="none" opacity=".45"/>
<circle cx="100" cy="100" r="4" fill="#6ea8fe" opacity=".95"/>
<!-- Radial glow overlay -->
<circle cx="100" cy="100" r="96" fill="url(#scanGlow)"/>
</svg>
</div>
</aside>
<!-- ββ Right form panel ββ -->
<main class="auth-form-panel">
<div class="auth-card">
<div class="auth-card-header">
<h2>Welcome back</h2>
<p>Enter your credentials to access your dashboard</p>
</div>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class="auth-alerts">
{% for category, message in messages %}
<div class="alert alert-{{ category }}">
{% if category == 'error' %}
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" flex-shrink="0"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
{% else %}
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
{% endif %}
{{ message }}
</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<form method="POST" class="auth-form" id="loginForm">
<div class="form-group">
<label for="identifier">Username or Email</label>
<div class="input-wrap">
<svg class="input-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
<input type="text" id="identifier" name="identifier" required autofocus
placeholder="Enter your username or email" autocomplete="username"/>
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<div class="input-wrap">
<svg class="input-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
<input type="password" id="password" name="password" required
class="has-toggle" placeholder="Enter your password" autocomplete="current-password"/>
<button type="button" class="btn-pw-toggle" id="togglePw" aria-label="Toggle password visibility">
<svg id="eyeIcon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
</button>
</div>
</div>
<div class="auth-row">
<label class="form-check">
<input type="checkbox" name="remember" id="remember" class="form-check-input"/>
<span class="form-check-label">Remember me</span>
</label>
<a href="{{ url_for('auth.forgot_password') }}" class="auth-link-sm">Forgot password?</a>
</div>
<button type="submit" class="btn-auth-submit" id="loginBtn">Sign In</button>
</form>
<div class="auth-footer">
New to the pipeline? <a href="{{ url_for('auth.register') }}">Create a free account</a>
</div>
</div>
</main>
</div>
<script src="{{ url_for('static', filename='js/auth-shared.js') }}" defer></script>
<script src="{{ url_for('static', filename='js/login.js') }}" defer></script>
</body>
</html>
|