Mri-Prediction / static /css /style.css
Mri-1243's picture
feat: show styled Invalid MRI notice instead of running models on non-MRI images
25056c7
/* ═══════════════════════════════════════════════════════════════
BRATS β€” Brain Tumor Segmentation Interface
Minimalistic Β· Sharp Edges Β· Dark Theme
═══════════════════════════════════════════════════════════════ */
/* ── Reset & Base ──────────────────────────────────────────────── */
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
/* Palette */
--bg: #0a0a0f;
--surface: #111118;
--surface-2: #18181f;
--border: #222230;
--border-hover: #33334a;
--text: #e4e4ef;
--text-dim: #6e6e82;
--text-muted: #3c3c50;
--accent: #6c5ce7;
--accent-glow: rgba(108, 92, 231, .25);
--danger: #e74c3c;
--danger-bg: rgba(231, 76, 60, .08);
--success: #00d2a0;
--success-bg: rgba(0, 210, 160, .08);
/* Type */
--font: 'Inter', system-ui, -apple-system, sans-serif;
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
/* Spacing */
--gap: 20px;
}
html {
font-size: 15px;
scroll-behavior: smooth;
}
body {
font-family: var(--font);
background: var(--bg);
color: var(--text);
min-height: 100vh;
display: flex;
flex-direction: column;
-webkit-font-smoothing: antialiased;
overflow-x: hidden;
}
/* ── Ambient Background ────────────────────────────────────────── */
.ambient-bg {
position: fixed;
inset: 0;
z-index: 0;
pointer-events: none;
overflow: hidden;
}
.ambient-orb {
position: absolute;
border-radius: 50%;
filter: blur(140px);
opacity: .25;
}
.ambient-orb--1 {
width: 700px;
height: 700px;
background: #6c5ce7;
top: -250px;
left: -150px;
animation: drift 25s ease-in-out infinite alternate;
}
.ambient-orb--2 {
width: 600px;
height: 600px;
background: #00d2a0;
bottom: -200px;
right: -150px;
animation: drift 30s ease-in-out infinite alternate-reverse;
}
.ambient-orb--3 {
width: 500px;
height: 500px;
background: #e74c8b;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
animation: pulse-orb 20s ease-in-out infinite alternate;
}
@keyframes pulse-orb {
0% { filter: blur(140px); opacity: .1; }
100% { filter: blur(160px); opacity: .25; }
}
.ambient-orb--1 {
width: 600px;
height: 600px;
background: var(--accent);
top: -200px;
left: -100px;
animation: drift 20s ease-in-out infinite alternate;
}
.ambient-orb--2 {
width: 500px;
height: 500px;
background: #e74c8b;
bottom: -150px;
right: -150px;
animation: drift 25s ease-in-out infinite alternate-reverse;
}
@keyframes drift {
0% { transform: translate(0, 0); }
100% { transform: translate(60px, 40px); }
}
/* ── Header ────────────────────────────────────────────────────── */
#main-header {
position: relative;
z-index: 10;
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 32px;
border-bottom: 1px solid var(--border);
background: rgba(10, 10, 15, .85);
backdrop-filter: blur(20px);
}
.header-left {
display: flex;
align-items: center;
gap: 12px;
}
.logo-mark {
width: 28px;
height: 28px;
background: var(--accent);
position: relative;
}
.logo-mark::after {
content: '';
position: absolute;
inset: 5px;
background: var(--bg);
}
#main-header h1 {
font-size: 1.25rem;
font-weight: 700;
letter-spacing: .08em;
text-transform: uppercase;
}
.header-tag {
font-size: .72rem;
color: var(--text-dim);
letter-spacing: .06em;
text-transform: uppercase;
padding-left: 12px;
border-left: 1px solid var(--border);
}
.header-right {
display: flex;
align-items: center;
gap: 8px;
}
.status-dot {
width: 8px;
height: 8px;
background: var(--success);
animation: pulse-dot 2s ease-in-out infinite;
}
.status-dot.processing {
background: var(--accent);
}
.status-dot.error {
background: var(--danger);
animation: none;
}
.status-label {
font-size: .75rem;
font-family: var(--font-mono);
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: .05em;
}
@keyframes pulse-dot {
0%, 100% { opacity: 1; }
50% { opacity: .4; }
}
/* ── Main ──────────────────────────────────────────────────────── */
#app-main {
position: relative;
z-index: 10;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 48px 24px 64px;
gap: 32px;
width: 100%;
}
/* πŸ§ͺ Experimental: Expanded mode when comparing */
#app-main:has(.panel--compare:not(.hidden)) {
padding-left: 5%;
padding-right: 5%;
}
/* ── Panel ─────────────────────────────────────────────────────── */
.panel {
width: 100%;
max-width: 600px;
background: rgba(17, 17, 24, 0.65);
backdrop-filter: blur(28px);
-webkit-backdrop-filter: blur(28px);
border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.4), inset 0 1px 1px rgba(255, 255, 255, 0.05);
border-radius: 16px;
padding: 36px;
display: flex;
flex-direction: column;
gap: 28px;
transition: opacity .4s, transform .4s, box-shadow .4s, max-width .6s cubic-bezier(0.4, 0, 0.2, 1);
}
.panel--compare {
max-width: 1600px !important;
}
.panel:hover {
box-shadow: 0 20px 56px rgba(0, 0, 0, 0.5), inset 0 1px 1px rgba(255, 255, 255, 0.08);
}
.panel.hidden {
display: none;
}
.panel-header {
display: flex;
align-items: baseline;
gap: 14px;
}
.panel-number {
font-family: var(--font-mono);
font-size: .7rem;
color: var(--accent);
letter-spacing: .1em;
}
.panel-header h2 {
font-size: 1.1rem;
font-weight: 600;
letter-spacing: .02em;
}
/* ── Field / Select ────────────────────────────────────────────── */
.field label {
display: block;
font-size: .7rem;
text-transform: uppercase;
letter-spacing: .08em;
color: var(--text-dim);
margin-bottom: 8px;
}
.select-wrapper {
position: relative;
}
.select-wrapper select {
width: 100%;
appearance: none;
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: 0;
color: var(--text);
font-family: var(--font-mono);
font-size: .82rem;
padding: 10px 14px;
cursor: pointer;
transition: border-color .2s;
}
.select-wrapper select:focus {
outline: none;
border-color: var(--accent);
}
.select-arrow {
position: absolute;
right: 14px;
top: 50%;
transform: translateY(-50%);
color: var(--text-dim);
font-size: .65rem;
pointer-events: none;
}
/* ── Dropzone ──────────────────────────────────────────────────── */
.dropzone {
border: 2px dashed var(--border);
background: var(--surface-2);
min-height: 220px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
position: relative;
transition: border-color .2s, background .2s;
}
.dropzone:hover,
.dropzone.dragover {
border-color: var(--accent);
background: rgba(108, 92, 231, .04);
}
.dropzone-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
padding: 24px;
}
.dropzone-icon {
color: var(--text-muted);
transition: color .2s;
}
.dropzone:hover .dropzone-icon {
color: var(--accent);
}
.dropzone-text {
font-size: .88rem;
font-weight: 500;
color: var(--text-dim);
}
.dropzone-sub {
font-size: .7rem;
color: var(--text-muted);
font-family: var(--font-mono);
letter-spacing: .03em;
}
/* Preview inside dropzone */
.dropzone-preview {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: var(--surface-2);
}
.dropzone-preview img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.btn-clear {
position: absolute;
top: 8px;
right: 8px;
width: 28px;
height: 28px;
background: var(--bg);
border: 1px solid var(--border);
color: var(--text-dim);
font-size: 1rem;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background .2s, color .2s;
}
.btn-clear:hover {
background: var(--danger);
color: #fff;
border-color: var(--danger);
}
/* ── Buttons ───────────────────────────────────────────────────── */
.btn-primary {
width: 100%;
padding: 16px;
background: linear-gradient(135deg, #6c5ce7, #8e44ad);
border: none;
border-radius: 8px;
color: #fff;
font-family: var(--font);
font-size: .88rem;
font-weight: 700;
letter-spacing: .08em;
text-transform: uppercase;
cursor: pointer;
position: relative;
overflow: hidden;
box-shadow: 0 4px 15px rgba(108, 92, 231, 0.4);
transition: all .3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
.btn-primary:hover:not(:disabled) {
background: linear-gradient(135deg, #7d6cf0, #9b59b6);
box-shadow: 0 6px 20px rgba(108, 92, 231, 0.6);
transform: translateY(-2px);
}
.btn-primary:active:not(:disabled) {
transform: translateY(0px);
}
.btn-primary:disabled {
opacity: .35;
cursor: not-allowed;
}
.btn-primary .btn-label {
transition: opacity .2s;
}
.btn-primary.loading .btn-label {
opacity: 0;
}
.btn-primary.loading .btn-loader {
display: block !important;
}
.btn-loader {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 20px;
height: 20px;
border: 2px solid rgba(255,255,255,.3);
border-top-color: #fff;
animation: spin .6s linear infinite;
}
@keyframes spin {
to { transform: translate(-50%, -50%) rotate(360deg); }
}
.btn-secondary {
width: 100%;
padding: 12px;
background: transparent;
border: 1px solid var(--border);
color: var(--text-dim);
font-family: var(--font);
font-size: .78rem;
font-weight: 500;
letter-spacing: .06em;
text-transform: uppercase;
cursor: pointer;
transition: border-color .2s, color .2s;
}
.btn-secondary:hover {
border-color: var(--text-dim);
color: var(--text);
}
/* ── Verdict Banner ────────────────────────────────────────────── */
.verdict {
display: flex;
align-items: center;
gap: 16px;
padding: 20px 24px;
border: 1px solid var(--border);
border-radius: 12px;
background: rgba(24, 24, 31, 0.7);
backdrop-filter: blur(10px);
transition: all .4s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.verdict.detected {
border-color: rgba(231, 76, 60, 0.4);
background: rgba(231, 76, 60, 0.05);
box-shadow: 0 0 20px rgba(231, 76, 60, 0.15), inset 0 0 10px rgba(231, 76, 60, 0.05);
}
.verdict.clear {
border-color: rgba(0, 210, 160, 0.4);
background: rgba(0, 210, 160, 0.05);
box-shadow: 0 0 20px rgba(0, 210, 160, 0.15), inset 0 0 10px rgba(0, 210, 160, 0.05);
}
.verdict.clear {
border-color: var(--success);
background: var(--success-bg);
}
.verdict-icon {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
font-size: 1.3rem;
}
.verdict-text {
display: flex;
flex-direction: column;
gap: 2px;
}
.verdict-title {
font-weight: 700;
font-size: .92rem;
letter-spacing: .02em;
}
.verdict.detected .verdict-title { color: var(--danger); }
.verdict.clear .verdict-title { color: var(--success); }
.verdict-confidence {
font-size: .72rem;
color: var(--text-dim);
font-family: var(--font-mono);
}
/* ── Image Comparison ──────────────────────────────────────────── */
.comparison {
display: flex;
gap: 2px;
align-items: stretch;
}
.comparison-card {
flex: 1;
display: flex;
flex-direction: column;
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
transition: transform .3s, box-shadow .3s;
}
.comparison-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
}
.comparison-label {
display: block;
font-size: .65rem;
text-transform: uppercase;
letter-spacing: .1em;
color: var(--text-dim);
padding: 8px 12px;
border-bottom: 1px solid var(--border);
font-family: var(--font-mono);
}
.comparison-card img {
width: 100%;
aspect-ratio: 1 / 1;
object-fit: contain;
background: #000;
display: block;
}
.comparison-divider {
width: 2px;
background: var(--border);
flex-shrink: 0;
}
/* ── Toast ─────────────────────────────────────────────────────── */
.toast {
position: fixed;
bottom: 32px;
left: 50%;
transform: translateX(-50%) translateY(20px);
background: var(--danger);
color: #fff;
font-size: .78rem;
padding: 12px 24px;
z-index: 1000;
opacity: 0;
transition: opacity .3s, transform .3s;
max-width: 460px;
text-align: center;
}
.toast.show {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
/* ── Footer ────────────────────────────────────────────────────── */
#main-footer {
position: relative;
z-index: 10;
text-align: center;
padding: 18px;
border-top: 1px solid var(--border);
font-size: .68rem;
color: var(--text-muted);
letter-spacing: .04em;
background: rgba(10, 10, 15, .85);
backdrop-filter: blur(20px);
}
/* ── Utilities ─────────────────────────────────────────────────── */
.hidden {
display: none !important;
}
/* ── Responsive ────────────────────────────────────────────────── */
@media (max-width: 600px) {
#main-header {
padding: 16px 18px;
}
.header-tag {
display: none;
}
#app-main {
padding: 28px 12px 48px;
}
.panel {
padding: 20px 16px;
}
.comparison {
flex-direction: column;
}
.comparison-divider {
width: 100%;
height: 2px;
}
}
/* ── Animations ────────────────────────────────────────────────── */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
.panel--results:not(.hidden) {
animation: fadeIn .45s ease-out;
}
.panel--compare:not(.hidden) {
animation: fadeIn .45s ease-out;
}
/* ── Compare Button ────────────────────────────────────────────── */
.btn-compare {
width: 100%;
padding: 14px 24px;
margin-top: 8px;
font-family: var(--font);
font-size: .92rem;
font-weight: 600;
letter-spacing: .03em;
border: 2px solid var(--accent);
border-radius: 0;
background: transparent;
color: var(--accent);
cursor: pointer;
transition: all .2s ease;
position: relative;
overflow: hidden;
}
.btn-compare:hover:not(:disabled) {
background: var(--accent);
color: #fff;
box-shadow: 0 0 24px var(--accent-glow);
}
.btn-compare:disabled {
opacity: .35;
cursor: not-allowed;
}
.btn-compare.loading .btn-label {
opacity: 0;
}
.btn-compare.loading .btn-loader {
display: inline-block;
}
/* ── Compare Panel ─────────────────────────────────────────────── */
.compare-subtitle {
color: var(--text-dim);
font-size: .88rem;
margin-bottom: 20px;
font-weight: 500;
}
.compare-grid {
display: flex;
overflow-x: auto;
gap: 16px;
padding-bottom: 20px;
margin-bottom: 24px;
/* Custom scrollbar for premium feel */
scrollbar-width: thin;
scrollbar-color: var(--border-hover) transparent;
}
.compare-grid::-webkit-scrollbar {
height: 6px;
}
.compare-grid::-webkit-scrollbar-track {
background: transparent;
}
.compare-grid::-webkit-scrollbar-thumb {
background: var(--border-hover);
border-radius: 10px;
}
.compare-card {
flex: 0 0 420px; /* Fixed width for horizontal scrolling cards */
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: 0;
overflow: hidden;
transition: border-color .2s, box-shadow .2s;
}
.compare-card:hover {
border-color: var(--border-hover);
box-shadow: 0 4px 24px rgba(0,0,0,.3);
}
.compare-card--detected {
border-color: rgba(231, 76, 60, .4);
}
.compare-card--detected:hover {
border-color: var(--danger);
box-shadow: 0 4px 24px rgba(231, 76, 60, .15);
}
.compare-card--clear {
border-color: rgba(0, 210, 160, .3);
}
.compare-card--clear:hover {
border-color: var(--success);
box-shadow: 0 4px 24px rgba(0, 210, 160, .1);
}
.compare-card--error {
border-color: rgba(255, 165, 0, .3);
opacity: .7;
}
.compare-card-header {
padding: 10px 14px;
font-family: var(--font-mono);
font-size: .78rem;
font-weight: 500;
color: var(--text-dim);
text-transform: capitalize;
background: rgba(0,0,0,.2);
border-bottom: 1px solid var(--border);
letter-spacing: .02em;
}
.compare-card-body {
padding: 12px;
display: flex; /* Horizontal Card Content */
gap: 16px;
align-items: flex-start;
}
.compare-card-img {
width: 160px; /* Square fixed size for comparison */
height: 160px;
flex-shrink: 0;
border-radius: 0;
border: 1px solid var(--border);
object-fit: cover;
}
.compare-card-stats {
flex-grow: 1;
display: flex;
flex-direction: column;
gap: 6px;
}
.compare-badge {
display: inline-block;
padding: 3px 10px;
font-size: .75rem;
font-weight: 700;
letter-spacing: .05em;
text-transform: uppercase;
border-radius: 0;
margin-bottom: 4px;
width: fit-content;
}
.compare-badge--tumor {
background: var(--danger-bg);
color: var(--danger);
border: 1px solid rgba(231,76,60,.25);
}
.compare-badge--clear {
background: var(--success-bg);
color: var(--success);
border: 1px solid rgba(0,210,160,.25);
}
.compare-badge--error {
background: rgba(255,165,0,.1);
color: #ffa500;
border: 1px solid rgba(255,165,0,.25);
}
.compare-stat {
font-size: .8rem;
color: var(--text-dim);
}
.compare-stat strong {
color: var(--text);
}
.compare-error-msg {
font-size: .75rem;
color: var(--text-muted);
margin-top: 6px;
word-break: break-word;
}
.compare-card-error-body {
min-height: 60px;
display: flex;
flex-direction: column;
justify-content: center;
}
@media (max-width: 600px) {
.compare-grid {
grid-template-columns: 1fr;
}
}
/* ── Invalid MRI Notice ────────────────────────────────────── */
.invalid-mri-notice {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 48px 32px;
width: 100%;
animation: fadeIn .5s ease-out;
}
.invalid-mri-icon {
font-size: 4rem;
margin-bottom: 16px;
filter: grayscale(40%);
animation: pulse-orb 3s ease-in-out infinite alternate;
}
.invalid-mri-title {
font-family: var(--font);
font-size: 1.6rem;
font-weight: 700;
color: #ff6b6b;
margin: 0 0 12px 0;
letter-spacing: -.01em;
}
.invalid-mri-desc {
font-size: .95rem;
color: var(--text-dim);
max-width: 500px;
line-height: 1.6;
margin: 0 0 20px 0;
}
.invalid-mri-hint {
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.08);
border-left: 3px solid var(--accent);
padding: 14px 20px;
font-size: .82rem;
color: var(--text-dim);
line-height: 1.7;
text-align: left;
max-width: 460px;
margin-bottom: 24px;
border-radius: 0 8px 8px 0;
}
.invalid-mri-hint strong {
color: var(--text);
}
.invalid-mri-preview {
max-width: 180px;
max-height: 180px;
border-radius: 8px;
border: 1px solid var(--border);
opacity: .35;
filter: grayscale(80%);
transition: opacity .3s, filter .3s;
}
.invalid-mri-preview:hover {
opacity: .7;
filter: grayscale(30%);
}