| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| <title>{% block title %}IrisAI{% endblock %}</title> |
| <link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=DM+Mono:wght@400;500&family=DM+Sans:wght@300;400;500;600&display=swap" rel="stylesheet" /> |
| <style> |
| |
| *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } |
| |
| :root { |
| --bg: #0d0f14; |
| --surface: #13161e; |
| --surface2: #1a1e2a; |
| --border: #252836; |
| --accent: #7c6fff; |
| --accent2: #ff6f91; |
| --green: #4ade80; |
| --text: #e8eaf0; |
| --muted: #6b7280; |
| --radius: 12px; |
| --radius-lg: 20px; |
| } |
| |
| html, body { |
| height: 100%; |
| background: var(--bg); |
| color: var(--text); |
| font-family: 'DM Sans', sans-serif; |
| font-size: 20px; |
| line-height: 1.6; |
| } |
| |
| |
| body::before { |
| content: ''; |
| position: fixed; inset: 0; z-index: 0; |
| background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E"); |
| pointer-events: none; |
| } |
| |
| |
| .blob { |
| position: fixed; border-radius: 50%; |
| filter: blur(80px); opacity: 0.12; pointer-events: none; z-index: 0; |
| } |
| .blob-1 { width: 500px; height: 500px; background: var(--accent); top: -150px; left: -150px; } |
| .blob-2 { width: 400px; height: 400px; background: var(--accent2); bottom: -100px; right: -100px; } |
| |
| |
| nav { |
| position: sticky; top: 0; z-index: 100; |
| display: flex; align-items: center; justify-content: space-between; |
| padding: 0 2rem; |
| height: 60px; |
| background: rgba(13,15,20,.85); |
| backdrop-filter: blur(16px); |
| border-bottom: 1px solid var(--border); |
| } |
| .nav-logo { |
| font-family: 'DM Serif Display', serif; |
| font-size: 1.9rem; |
| background: linear-gradient(135deg, var(--accent), var(--accent2)); |
| -webkit-background-clip: text; -webkit-text-fill-color: transparent; |
| text-decoration: none; |
| } |
| .nav-links { display: flex; gap: 0.5rem; align-items: center; } |
| .nav-links a { |
| color: var(--muted); text-decoration: none; padding: 0.35rem 0.75rem; |
| border-radius: 8px; font-size: 0.875rem; font-weight: 500; |
| transition: color .2s, background .2s; |
| } |
| .nav-links a:hover { color: var(--text); background: var(--surface2); } |
| .nav-badge { |
| font-family: 'DM Mono', monospace; font-size: 0.9rem; |
| background: var(--surface2); border: 1px solid var(--border); |
| color: var(--muted); padding: 0.2rem 0.6rem; border-radius: 20px; |
| } |
| |
| |
| .page { |
| position: relative; z-index: 1; |
| min-height: calc(100vh - 60px); |
| padding: 3rem 1.5rem; |
| } |
| .container { max-width: 860px; margin: 0 auto; } |
| .container-sm { max-width: 440px; margin: 0 auto; } |
| |
| |
| .flashes { margin-bottom: 1.5rem; display: flex; flex-direction: column; gap: .5rem; } |
| .flash { |
| padding: .75rem 1rem; border-radius: var(--radius); font-size: .875rem; |
| border-left: 3px solid; |
| } |
| .flash.success { background: rgba(74,222,128,.08); border-color: var(--green); color: #86efac; } |
| .flash.danger { background: rgba(255,111,145,.08); border-color: var(--accent2); color: #fda4af; } |
| .flash.warning { background: rgba(250,204, 21,.08); border-color: #facc15; color: #fde68a; } |
| .flash.info { background: rgba(124,111,255,.08); border-color: var(--accent); color: #c4b5fd; } |
| |
| |
| .card { |
| background: var(--surface); |
| border: 1px solid var(--border); |
| border-radius: var(--radius-lg); |
| padding: 2rem; |
| } |
| .card + .card { margin-top: 1.5rem; } |
| |
| |
| .form-group { margin-bottom: 1.25rem; } |
| label { |
| display: block; margin-bottom: .4rem; |
| font-size: .9rem; font-weight: 600; letter-spacing: .05em; |
| text-transform: uppercase; color: var(--muted); |
| } |
| input[type="text"], input[type="password"], input[type="number"] { |
| width: 100%; padding: .75rem 1rem; |
| background: var(--surface2); border: 1px solid var(--border); |
| border-radius: var(--radius); color: var(--text); |
| font-family: inherit; font-size: .95rem; |
| transition: border-color .2s, box-shadow .2s; |
| outline: none; |
| } |
| input:focus { |
| border-color: var(--accent); |
| box-shadow: 0 0 0 3px rgba(124,111,255,.15); |
| } |
| .input-hint { font-size: .9rem; color: var(--muted); margin-top: .3rem; } |
| |
| |
| .btn { |
| display: inline-flex; align-items: center; justify-content: center; |
| gap: .5rem; padding: .75rem 1.5rem; |
| border: none; border-radius: var(--radius); cursor: pointer; |
| font-family: inherit; font-size: .9rem; font-weight: 600; |
| text-decoration: none; transition: all .2s; |
| } |
| .btn-primary { |
| background: linear-gradient(135deg, var(--accent), #9d8fff); |
| color: #fff; |
| box-shadow: 0 4px 20px rgba(124,111,255,.3); |
| } |
| .btn-primary:hover { transform: translateY(-1px); box-shadow: 0 6px 24px rgba(124,111,255,.4); } |
| .btn-primary:active { transform: translateY(0); } |
| .btn-outline { |
| background: transparent; color: var(--muted); |
| border: 1px solid var(--border); |
| } |
| .btn-outline:hover { color: var(--text); border-color: var(--accent); background: rgba(124,111,255,.06); } |
| .btn-full { width: 100%; } |
| |
| |
| .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; } |
| @media (max-width: 540px) { .grid-2 { grid-template-columns: 1fr; } } |
| |
| |
| .divider { border: none; border-top: 1px solid var(--border); margin: 1.5rem 0; } |
| |
| |
| .serif { font-family: 'DM Serif Display', serif; } |
| .mono { font-family: 'DM Mono', monospace; } |
| .muted { color: var(--muted); } |
| .small { font-size: .9rem; } |
| |
| |
| .result-card { |
| border-radius: var(--radius-lg); |
| padding: 2rem; |
| border: 1px solid var(--border); |
| animation: slideUp .4s ease; |
| } |
| @keyframes slideUp { |
| from { opacity: 0; transform: translateY(16px); } |
| to { opacity: 1; transform: translateY(0); } |
| } |
| .result-name { |
| font-family: 'DM Serif Display', serif; |
| font-size: 2.5rem; |
| margin-bottom: .25rem; |
| } |
| .confidence-bar-wrap { |
| background: var(--surface2); border-radius: 100px; |
| height: 8px; margin: .75rem 0 .4rem; |
| overflow: hidden; |
| } |
| .confidence-bar { |
| height: 100%; border-radius: 100px; |
| background: linear-gradient(90deg, var(--accent), var(--accent2)); |
| transition: width .8s ease; |
| } |
| |
| |
| .prob-grid { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: 1rem; } |
| .prob-pill { |
| font-family: 'DM Mono', monospace; font-size: .9rem; |
| padding: .3rem .75rem; border-radius: 100px; |
| border: 1px solid var(--border); background: var(--surface2); |
| color: var(--muted); |
| } |
| .prob-pill.active { border-color: var(--accent); color: var(--accent); background: rgba(124,111,255,.1); } |
| |
| |
| table { width: 100%; border-collapse: collapse; font-size: .85rem; } |
| th { color: var(--muted); font-weight: 600; font-size: .75rem; |
| text-transform: uppercase; letter-spacing: .05em; |
| padding: .5rem .75rem; text-align: left; border-bottom: 1px solid var(--border); } |
| td { padding: .6rem .75rem; border-bottom: 1px solid var(--border); color: var(--text); } |
| tr:last-child td { border-bottom: none; } |
| .badge { |
| display: inline-block; font-size: .72rem; font-weight: 600; |
| padding: .15rem .6rem; border-radius: 100px; font-family: 'DM Mono', monospace; |
| } |
| .badge-setosa { background: rgba(249,168,212,.15); color: #f9a8d4; } |
| .badge-versicolor { background: rgba(196,181,253,.15); color: #c4b5fd; } |
| .badge-virginica { background: rgba(110,231,183,.15); color: #6ee7b7; } |
| |
| |
| .page-header { margin-bottom: 2rem; } |
| .page-header h1 { |
| font-family: 'DM Serif Display', serif; font-size: 3rem; |
| background: linear-gradient(135deg, var(--text) 30%, var(--muted)); |
| -webkit-background-clip: text; -webkit-text-fill-color: transparent; |
| } |
| .page-header p { color: var(--muted); margin-top: .4rem; } |
| |
| |
| .auth-wrap { |
| display: flex; flex-direction: column; align-items: center; |
| justify-content: center; min-height: calc(100vh - 60px); |
| padding: 2rem 1.5rem; |
| } |
| .auth-logo { |
| font-family: 'DM Serif Display', serif; font-size: 2.8rem; text-align: center; |
| background: linear-gradient(135deg, var(--accent), var(--accent2)); |
| -webkit-background-clip: text; -webkit-text-fill-color: transparent; |
| margin-bottom: 2rem; |
| } |
| .auth-logo span { display: block; font-size: 3rem; opacity: .7; |
| font-family: 'DM Sans', sans-serif; font-weight: 400; |
| -webkit-text-fill-color: var(--muted); } |
| </style> |
| {% block head %}{% endblock %} |
| </head> |
| <body> |
| <div class="blob blob-1"></div> |
| <div class="blob blob-2"></div> |
|
|
| {% if session.username %} |
| <nav> |
| <a class="nav-logo" href="{{ url_for('predict') }}">πΈ IrisAI</a> |
| <div class="nav-links"> |
| <span class="nav-badge">{{ session.username }}</span> |
| <a href="{{ url_for('predict') }}">Predict</a> |
| {% if session.username == 'admin' %} |
| <a href="{{ url_for('admin') }}" style="color:var(--accent)">β Admin</a> |
| {% endif %} |
| <a href="{{ url_for('logout') }}">Logout</a> |
| </div> |
| </nav> |
| {% endif %} |
|
|
| {% block body %}{% endblock %} |
| </body> |
| </html> |
|
|