Files
MOPC-Portal/prototypes/observer-dashboard-redesign.html

1523 lines
47 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Observer Dashboard — MOPC Redesign</title>
<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=Montserrat:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
<script src="https://mcp.figma.com/mcp/html-to-design/capture.js" async></script>
<style>
/* ============================================================
DESIGN SYSTEM — Nautical Precision
Ocean conservation context. Maritime instrument clarity.
Swiss typographic rigor meets research-vessel command panel.
============================================================ */
:root {
--red: #de0f1e;
--dark-blue: #053d57;
--dark-blue-90: rgba(5, 61, 87, 0.9);
--white: #fefefe;
--teal: #557f8c;
--teal-dim: rgba(85, 127, 140, 0.12);
--teal-glow: rgba(85, 127, 140, 0.25);
--bg: #f5f6f8;
--bg-subtle: #eceef2;
--card: #ffffff;
--border: #e2e4e9;
--border-hover: #c9cdd4;
--ink: #0f172a;
--ink-secondary: #334155;
--ink-muted: #64748b;
--ink-faint: #94a3b8;
--green: #059669;
--green-bg: #ecfdf5;
--amber: #d97706;
--amber-bg: #fffbeb;
--blue: #2563eb;
--blue-bg: #eff6ff;
--purple: #7c3aed;
--purple-bg: #f3e8ff;
--pink: #db2777;
--pink-bg: #fce7f3;
--red-bg: #fef2f2;
--radius: 10px;
--radius-lg: 14px;
--shadow-card: 0 1px 2px rgba(15, 23, 42, 0.04), 0 0 0 1px rgba(15, 23, 42, 0.02);
--shadow-hover: 0 4px 12px rgba(15, 23, 42, 0.08), 0 0 0 1px rgba(15, 23, 42, 0.04);
--transition: 0.18s cubic-bezier(0.4, 0, 0.2, 1);
--font-display: 'Montserrat', system-ui, sans-serif;
--font-mono: 'DM Mono', 'Menlo', monospace;
}
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: var(--font-display);
background: var(--bg);
color: var(--ink);
font-weight: 400;
font-size: 14px;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Subtle bathymetric texture on body */
body::before {
content: '';
position: fixed;
inset: 0;
pointer-events: none;
z-index: 0;
opacity: 0.018;
background:
radial-gradient(ellipse 800px 600px at 20% 40%, var(--dark-blue), transparent),
radial-gradient(ellipse 600px 400px at 80% 70%, var(--teal), transparent);
}
/* ================================================================
NAVIGATION
================================================================ */
.nav {
position: sticky;
top: 0;
z-index: 100;
height: 52px;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
padding: 0 24px;
backdrop-filter: blur(12px);
background: #ffffff;
}
.nav-brand {
display: flex;
align-items: center;
gap: 10px;
text-decoration: none;
color: var(--dark-blue);
}
.nav-logo {
width: 30px;
height: 30px;
background: var(--red);
border-radius: 7px;
display: grid;
place-items: center;
color: white;
font-weight: 700;
font-size: 12px;
letter-spacing: -0.02em;
box-shadow: 0 1px 3px rgba(222, 15, 30, 0.3);
}
.nav-brand-text {
font-weight: 700;
font-size: 14px;
letter-spacing: -0.01em;
}
.nav-brand-role {
font-weight: 400;
font-size: 11px;
color: var(--ink-faint);
letter-spacing: 0.06em;
text-transform: uppercase;
margin-left: 2px;
}
.nav-links {
display: flex;
gap: 2px;
margin-left: 28px;
}
.nav-link {
padding: 6px 14px;
border-radius: 7px;
font-size: 12.5px;
font-weight: 500;
color: var(--ink-muted);
text-decoration: none;
transition: all var(--transition);
letter-spacing: 0.01em;
}
.nav-link:hover {
background: var(--bg);
color: var(--ink-secondary);
}
.nav-link.active {
background: var(--dark-blue);
color: white;
font-weight: 600;
}
.nav-spacer { flex: 1; }
.nav-avatar {
width: 30px;
height: 30px;
border-radius: 50%;
background: var(--dark-blue);
color: white;
font-size: 11px;
font-weight: 600;
display: grid;
place-items: center;
letter-spacing: 0.02em;
}
/* ================================================================
LAYOUT
================================================================ */
.container {
position: relative;
z-index: 1;
max-width: 1200px;
margin: 0 auto;
padding: 28px 24px 48px;
}
/* ================================================================
HEADER
================================================================ */
.header {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 24px;
}
.header h1 {
font-size: 24px;
font-weight: 700;
letter-spacing: -0.025em;
color: var(--ink);
line-height: 1.15;
}
.header-sub {
font-size: 13px;
font-weight: 300;
color: var(--ink-muted);
margin-top: 3px;
letter-spacing: 0.005em;
}
.header-controls {
display: flex;
align-items: center;
gap: 10px;
}
.refresh-badge {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 10.5px;
font-weight: 500;
color: var(--ink-faint);
letter-spacing: 0.03em;
background: var(--card);
border: 1px solid var(--border);
border-radius: 20px;
padding: 5px 12px;
}
.refresh-pulse {
width: 6px;
height: 6px;
background: var(--green);
border-radius: 50%;
position: relative;
}
.refresh-pulse::after {
content: '';
position: absolute;
inset: -3px;
border-radius: 50%;
border: 1.5px solid var(--green);
animation: sonar 2.4s ease-out infinite;
}
@keyframes sonar {
0% { transform: scale(0.6); opacity: 0.8; }
100% { transform: scale(2.2); opacity: 0; }
}
.edition-picker {
font-family: var(--font-display);
font-size: 12.5px;
font-weight: 600;
padding: 7px 30px 7px 12px;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--card);
color: var(--ink-secondary);
appearance: none;
cursor: pointer;
transition: border-color var(--transition);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 10px center;
}
.edition-picker:hover { border-color: var(--border-hover); }
.edition-picker:focus { outline: 2px solid var(--teal-glow); border-color: var(--teal); }
/* ================================================================
STAT TILES - 6 column grid
================================================================ */
.stats {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 12px;
margin-bottom: 22px;
}
.stat {
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 16px 16px 14px;
box-shadow: var(--shadow-card);
transition: box-shadow var(--transition), transform var(--transition);
position: relative;
overflow: hidden;
}
.stat:hover {
box-shadow: var(--shadow-hover);
transform: translateY(-1px);
}
.stat-label {
font-size: 9.5px;
font-weight: 600;
color: var(--ink-faint);
text-transform: uppercase;
letter-spacing: 0.08em;
line-height: 1;
}
.stat-value {
font-family: var(--font-mono);
font-size: 28px;
font-weight: 500;
color: var(--ink);
margin-top: 6px;
line-height: 1;
letter-spacing: -0.03em;
}
.stat-value .unit {
font-size: 14px;
font-weight: 400;
color: var(--ink-faint);
margin-left: 1px;
}
.stat-delta {
display: inline-flex;
align-items: center;
gap: 3px;
font-size: 10px;
font-weight: 600;
margin-top: 8px;
padding: 2px 6px;
border-radius: 4px;
letter-spacing: 0.01em;
}
.stat-delta.up {
color: var(--green);
background: var(--green-bg);
}
.stat-delta.neutral {
color: var(--ink-faint);
background: var(--bg-subtle);
}
.stat-delta svg { width: 8px; height: 8px; }
/* Active Round tile */
.stat-round-name {
font-family: var(--font-display);
font-size: 14px;
font-weight: 600;
color: var(--ink);
margin-top: 6px;
line-height: 1.25;
letter-spacing: -0.01em;
}
.stat-type-badge {
display: inline-block;
font-size: 9px;
font-weight: 700;
padding: 2px 7px;
border-radius: 4px;
background: var(--teal);
color: white;
text-transform: uppercase;
letter-spacing: 0.08em;
margin-top: 6px;
}
/* Sparkline */
.sparkline {
display: flex;
align-items: flex-end;
gap: 2px;
height: 24px;
margin-top: 8px;
}
.spark {
width: 4px;
border-radius: 2px;
background: var(--teal);
transition: opacity 0.2s;
}
.spark:nth-child(odd) { opacity: 0.4; }
.spark:nth-child(even) { opacity: 0.6; }
.spark:last-child { opacity: 1; background: var(--dark-blue); }
/* Progress ring */
.stat-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.progress-ring {
width: 40px;
height: 40px;
flex-shrink: 0;
}
.progress-ring svg { transform: rotate(-90deg); }
.ring-track {
fill: none;
stroke: var(--bg-subtle);
stroke-width: 3.5;
}
.ring-fill {
fill: none;
stroke: var(--green);
stroke-width: 3.5;
stroke-linecap: round;
transition: stroke-dashoffset 0.8s cubic-bezier(0.4, 0, 0.2, 1);
}
.stat-sub {
font-size: 10px;
font-weight: 400;
color: var(--ink-faint);
margin-top: 6px;
font-family: var(--font-mono);
letter-spacing: 0.01em;
}
/* ================================================================
PIPELINE
================================================================ */
.pipeline-section {
margin-bottom: 22px;
}
.section-title {
font-size: 10px;
font-weight: 700;
color: var(--ink-faint);
text-transform: uppercase;
letter-spacing: 0.12em;
margin-bottom: 10px;
}
.pipeline-track {
display: flex;
align-items: center;
overflow-x: auto;
padding: 6px 0 10px;
gap: 0;
scrollbar-width: thin;
scrollbar-color: var(--border) transparent;
}
.pipeline-track::-webkit-scrollbar { height: 4px; }
.pipeline-track::-webkit-scrollbar-track { background: transparent; }
.pipeline-track::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
.p-node {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 14px;
border: 1px solid var(--border);
border-radius: var(--radius);
background: var(--card);
flex-shrink: 0;
cursor: pointer;
text-decoration: none;
color: inherit;
transition: all var(--transition);
box-shadow: var(--shadow-card);
min-width: 190px;
}
.p-node:hover {
box-shadow: var(--shadow-hover);
border-color: var(--border-hover);
transform: translateY(-1px);
}
.p-node.active {
border-color: var(--teal);
background: linear-gradient(135deg, rgba(85, 127, 140, 0.03) 0%, rgba(85, 127, 140, 0.06) 100%);
box-shadow: 0 0 0 1px var(--teal-glow), var(--shadow-card);
}
.p-icon {
width: 30px;
height: 30px;
border-radius: 7px;
display: grid;
place-items: center;
flex-shrink: 0;
}
.p-icon svg { width: 14px; height: 14px; }
.p-icon.intake { background: #eff6ff; color: #2563eb; }
.p-icon.filter { background: #fef3c7; color: #d97706; }
.p-icon.eval { background: #ecfdf5; color: #059669; }
.p-icon.submit { background: #f3e8ff; color: #7c3aed; }
.p-icon.semi { background: #fce7f3; color: #db2777; }
.p-info { display: flex; flex-direction: column; gap: 3px; }
.p-name {
font-size: 11px;
font-weight: 600;
white-space: nowrap;
letter-spacing: -0.005em;
line-height: 1;
}
.p-meta-row {
display: flex;
align-items: center;
gap: 6px;
}
.p-status {
font-size: 9px;
font-weight: 600;
padding: 2px 6px;
border-radius: 3px;
display: inline-block;
width: fit-content;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.p-status.closed { background: #f1f5f9; color: #64748b; }
.p-status.active { background: var(--green-bg); color: var(--green); }
.p-status.draft { background: var(--amber-bg); color: var(--amber); }
.p-count {
font-size: 10px;
color: var(--ink-faint);
font-family: var(--font-mono);
font-weight: 400;
}
/* Pipeline progress mini bar */
.p-progress {
width: 100%;
height: 3px;
background: var(--bg-subtle);
border-radius: 2px;
margin-top: 4px;
overflow: hidden;
}
.p-progress-fill {
height: 100%;
border-radius: 2px;
transition: width 0.6s ease;
}
.p-progress-fill.complete { background: var(--teal); width: 100%; }
.p-progress-fill.partial { background: var(--green); }
.p-progress-fill.empty { background: var(--bg-subtle); width: 0%; }
.p-pulse {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--teal);
flex-shrink: 0;
position: relative;
}
.p-pulse::before {
content: '';
position: absolute;
inset: -4px;
border-radius: 50%;
background: var(--teal);
opacity: 0;
animation: ping 2s cubic-bezier(0, 0, 0.2, 1) infinite;
}
@keyframes ping {
0% { transform: scale(0.8); opacity: 0.6; }
75%, 100% { transform: scale(2.4); opacity: 0; }
}
.p-connector {
display: flex;
align-items: center;
padding: 0 3px;
flex-shrink: 0;
}
.p-line {
width: 20px;
height: 2px;
background: var(--border);
border-radius: 1px;
}
.p-line.completed {
background: var(--teal);
opacity: 0.4;
}
.p-chevron {
width: 0;
height: 0;
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
border-left: 5px solid var(--border);
margin-left: -1px;
}
.p-chevron.completed {
border-left-color: var(--teal);
opacity: 0.4;
}
/* ================================================================
MIDDLE ROW: 3-COLUMN
================================================================ */
.mid-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 12px;
margin-bottom: 16px;
}
.card {
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-card);
overflow: hidden;
}
.card-head {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 16px 0;
}
.card-title {
font-size: 12px;
font-weight: 700;
color: var(--ink);
letter-spacing: -0.01em;
}
.card-action {
font-size: 11px;
font-weight: 600;
color: var(--teal);
text-decoration: none;
letter-spacing: 0.01em;
transition: color var(--transition);
}
.card-action:hover { color: var(--dark-blue); }
/* ---- SCORE DISTRIBUTION ---- */
.score-bars {
padding: 14px 16px 16px;
}
.score-bar-row {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}
.score-bar-row:last-child { margin-bottom: 0; }
.score-bar-label {
font-size: 11px;
font-weight: 500;
color: var(--ink-muted);
min-width: 38px;
text-align: right;
font-family: var(--font-mono);
}
.score-bar-track {
flex: 1;
height: 20px;
background: var(--bg-subtle);
border-radius: 4px;
overflow: hidden;
position: relative;
}
.score-bar-fill {
height: 100%;
border-radius: 4px;
transition: width 0.8s ease;
display: flex;
align-items: center;
padding-left: 8px;
}
.score-bar-fill .bar-count {
font-size: 10px;
font-weight: 600;
color: white;
font-family: var(--font-mono);
}
.score-bar-fill.high { background: var(--green); }
.score-bar-fill.mid { background: var(--teal); }
.score-bar-fill.low { background: var(--amber); }
.score-bar-fill.none { background: var(--bg-subtle); }
.score-bar-count-outside {
font-size: 10px;
font-weight: 600;
color: var(--ink-faint);
font-family: var(--font-mono);
min-width: 18px;
}
/* ---- JUROR WORKLOAD ---- */
.juror-list {
padding: 10px 16px 14px;
}
.juror-row {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 0;
border-bottom: 1px solid #f8f9fb;
}
.juror-row:last-child { border-bottom: none; }
.juror-avatar {
width: 26px;
height: 26px;
border-radius: 50%;
display: grid;
place-items: center;
font-size: 9px;
font-weight: 700;
color: white;
flex-shrink: 0;
}
.juror-info {
flex: 1;
min-width: 0;
}
.juror-name {
font-size: 11.5px;
font-weight: 600;
color: var(--ink);
letter-spacing: -0.005em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.juror-progress-track {
width: 100%;
height: 4px;
background: var(--bg-subtle);
border-radius: 2px;
margin-top: 3px;
overflow: hidden;
}
.juror-progress-fill {
height: 100%;
border-radius: 2px;
background: var(--teal);
}
.juror-count {
font-size: 10px;
font-family: var(--font-mono);
font-weight: 500;
color: var(--ink-faint);
flex-shrink: 0;
}
/* ---- GEO MAP ---- */
.geo-placeholder {
height: 140px;
margin: 12px 16px;
border-radius: 8px;
position: relative;
overflow: hidden;
background: linear-gradient(170deg, #e8edf3 0%, #d4dce6 50%, #c0cad6 100%);
}
.geo-placeholder::before {
content: '';
position: absolute;
inset: 0;
opacity: 0.15;
background:
radial-gradient(ellipse 200px 140px at 30% 50%, var(--dark-blue), transparent 70%),
radial-gradient(ellipse 160px 120px at 65% 40%, var(--teal), transparent 70%),
radial-gradient(ellipse 100px 80px at 50% 70%, var(--dark-blue), transparent 70%);
}
.geo-placeholder::after {
content: '';
position: absolute;
inset: 0;
background-image:
radial-gradient(ellipse 180px 130px at 30% 50%, transparent 50%, rgba(5,61,87,0.04) 50.5%, transparent 51.5%),
radial-gradient(ellipse 220px 160px at 30% 50%, transparent 50%, rgba(5,61,87,0.03) 50.5%, transparent 51.5%),
radial-gradient(ellipse 260px 190px at 30% 50%, transparent 50%, rgba(5,61,87,0.02) 50.5%, transparent 51.5%),
radial-gradient(ellipse 140px 100px at 65% 40%, transparent 50%, rgba(85,127,140,0.04) 50.5%, transparent 51.5%),
radial-gradient(ellipse 180px 130px at 65% 40%, transparent 50%, rgba(85,127,140,0.03) 50.5%, transparent 51.5%);
}
.geo-inner {
position: relative;
z-index: 1;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.geo-label {
font-size: 11px;
font-weight: 500;
color: var(--ink-faint);
font-style: italic;
background: rgba(255,255,255,0.7);
backdrop-filter: blur(4px);
padding: 4px 12px;
border-radius: 6px;
}
.geo-countries {
display: flex;
gap: 5px;
padding: 0 16px 14px;
flex-wrap: wrap;
}
.country-pill {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 10px;
font-weight: 500;
padding: 3px 8px;
border-radius: 5px;
background: var(--bg);
border: 1px solid var(--border);
color: var(--ink-secondary);
}
.country-pill strong {
font-family: var(--font-mono);
font-size: 11px;
font-weight: 500;
color: var(--dark-blue);
}
/* ================================================================
BOTTOM ROW: FULL-WIDTH TABLE + ACTIVITY
================================================================ */
.bottom-grid {
display: grid;
grid-template-columns: 1fr 320px;
gap: 12px;
}
/* ---- PROJECT TABLE ---- */
.ptable {
width: 100%;
border-collapse: collapse;
}
.ptable thead th {
text-align: left;
font-size: 9.5px;
font-weight: 700;
color: var(--ink-faint);
text-transform: uppercase;
letter-spacing: 0.1em;
padding: 10px 16px 8px;
border-bottom: 1px solid var(--border);
}
.ptable thead th:last-child { text-align: right; }
.ptable tbody tr {
cursor: pointer;
transition: background var(--transition);
}
.ptable tbody tr:hover { background: var(--bg); }
.ptable td {
padding: 9px 16px;
border-bottom: 1px solid #f1f5f9;
vertical-align: middle;
font-size: 12.5px;
}
.ptable td:last-child {
text-align: right;
font-family: var(--font-mono);
font-size: 12.5px;
font-weight: 500;
}
.p-project-name {
font-weight: 600;
color: var(--ink);
letter-spacing: -0.005em;
}
.p-org-name {
font-size: 10.5px;
color: var(--ink-faint);
font-weight: 400;
display: block;
margin-top: 1px;
}
.p-round-tag {
font-size: 10px;
font-weight: 500;
color: var(--ink-faint);
letter-spacing: 0.02em;
}
.p-badge {
display: inline-block;
font-size: 9px;
font-weight: 700;
padding: 2px 7px;
border-radius: 3px;
text-transform: uppercase;
letter-spacing: 0.06em;
}
.p-badge.eligible { background: var(--green-bg); color: var(--green); border: 1px solid #a7f3d0; }
.p-badge.in-progress { background: var(--blue-bg); color: var(--blue); border: 1px solid #bfdbfe; }
.p-badge.pending { background: var(--amber-bg); color: var(--amber); border: 1px solid #fde68a; }
.p-badge.passed { background: var(--green-bg); color: var(--green); border: 1px solid #a7f3d0; }
.p-badge.completed { background: var(--teal-dim); color: var(--teal); border: 1px solid rgba(85, 127, 140, 0.3); }
.score-val { color: var(--dark-blue); }
.score-na { color: var(--ink-faint); }
.table-footer {
display: flex;
align-items: center;
justify-content: center;
padding: 12px;
border-top: 1px solid var(--border);
}
.table-footer a {
font-size: 12px;
font-weight: 600;
color: var(--teal);
text-decoration: none;
letter-spacing: 0.01em;
transition: color var(--transition);
}
.table-footer a:hover { color: var(--dark-blue); }
/* ---- ACTIVITY TIMELINE ---- */
.activity-list {
padding: 12px 16px 14px;
}
.activity-item {
display: flex;
gap: 10px;
padding: 8px 0;
border-bottom: 1px solid #f8f9fb;
position: relative;
}
.activity-item:last-child { border-bottom: none; }
.activity-dot {
width: 7px;
height: 7px;
border-radius: 50%;
flex-shrink: 0;
margin-top: 5px;
}
.activity-dot.eval { background: var(--green); }
.activity-dot.assign { background: var(--blue); }
.activity-dot.round { background: var(--teal); }
.activity-dot.coi { background: var(--amber); }
.activity-dot.system { background: var(--ink-faint); }
.activity-content {
flex: 1;
min-width: 0;
}
.activity-text {
font-size: 11.5px;
color: var(--ink-secondary);
line-height: 1.4;
}
.activity-text strong {
font-weight: 600;
color: var(--ink);
}
.activity-time {
font-size: 10px;
font-family: var(--font-mono);
color: var(--ink-faint);
margin-top: 2px;
font-weight: 400;
}
/* ================================================================
STAGGERED ENTRY ANIMATION
================================================================ */
@keyframes slideUp {
from { opacity: 0; transform: translateY(14px); }
to { opacity: 1; transform: translateY(0); }
}
.animate-in {
opacity: 0;
animation: slideUp 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
/* ================================================================
RESPONSIVE
================================================================ */
@media (max-width: 1100px) {
.stats { grid-template-columns: repeat(3, 1fr); }
.mid-grid { grid-template-columns: 1fr 1fr; }
.bottom-grid { grid-template-columns: 1fr; }
}
@media (max-width: 768px) {
.stats { grid-template-columns: repeat(2, 1fr); }
.mid-grid { grid-template-columns: 1fr; }
.nav-links { gap: 0; }
}
@media (max-width: 500px) {
.stats { grid-template-columns: 1fr; }
.header { flex-direction: column; gap: 14px; }
.header-controls { width: 100%; justify-content: flex-start; flex-wrap: wrap; }
.nav-links { display: none; }
.container { padding: 20px 16px; }
}
</style>
</head>
<body>
<!-- ================================================================
NAV
================================================================ -->
<nav class="nav">
<a class="nav-brand" href="#">
<div class="nav-logo">M</div>
<span class="nav-brand-text">MOPC</span>
<span class="nav-brand-role">Observer</span>
</a>
<div class="nav-links">
<a class="nav-link active" href="#">Dashboard</a>
<a class="nav-link" href="#">Projects</a>
<a class="nav-link" href="#">Reports</a>
</div>
<div class="nav-spacer"></div>
<div class="nav-avatar">MC</div>
</nav>
<div class="container">
<!-- ================================================================
HEADER
================================================================ -->
<div class="header animate-in" style="animation-delay: 0.05s">
<div>
<h1>Dashboard</h1>
<p class="header-sub">Welcome, Matthew Ciaccio</p>
</div>
<div class="header-controls">
<div class="refresh-badge">
<div class="refresh-pulse"></div>
Auto-refresh: 30s
</div>
<select class="edition-picker">
<option>2026 Edition</option>
<option>2025 Edition</option>
</select>
</div>
</div>
<!-- ================================================================
STAT TILES — 6 tiles
================================================================ -->
<div class="stats">
<!-- Total Projects -->
<div class="stat animate-in" style="animation-delay: 0.08s">
<div class="stat-label">Total Projects</div>
<div class="stat-value">84</div>
<div class="stat-delta up">
<svg viewBox="0 0 10 10"><path d="M5 1.5L8.5 6.5H1.5L5 1.5Z" fill="currentColor"/></svg>
+12 from intake
</div>
</div>
<!-- Active Round -->
<div class="stat animate-in" style="animation-delay: 0.11s">
<div class="stat-label">Active Round</div>
<div class="stat-round-name">R3 — Expert Evaluation</div>
<div class="stat-type-badge">Evaluation</div>
</div>
<!-- Avg Score -->
<div class="stat animate-in" style="animation-delay: 0.14s">
<div class="stat-label">Avg Score</div>
<div class="stat-value">8.6<span class="unit">/10</span></div>
<div class="sparkline">
<div class="spark" style="height:5px"></div>
<div class="spark" style="height:8px"></div>
<div class="spark" style="height:7px"></div>
<div class="spark" style="height:12px"></div>
<div class="spark" style="height:8px"></div>
<div class="spark" style="height:14px"></div>
<div class="spark" style="height:16px"></div>
<div class="spark" style="height:12px"></div>
<div class="spark" style="height:18px"></div>
<div class="spark" style="height:20px"></div>
<div class="spark" style="height:24px"></div>
</div>
</div>
<!-- Completion Rate -->
<div class="stat animate-in" style="animation-delay: 0.17s">
<div class="stat-label">Completion Rate</div>
<div class="stat-row">
<div class="stat-value">15<span class="unit">%</span></div>
<div class="progress-ring">
<svg width="40" height="40" viewBox="0 0 40 40">
<circle class="ring-track" cx="20" cy="20" r="16"/>
<circle class="ring-fill" cx="20" cy="20" r="16"
stroke-dasharray="100.5"
stroke-dashoffset="85.4"/>
</svg>
</div>
</div>
<div class="stat-sub">26 / 168 evaluations</div>
</div>
<!-- Active Jurors -->
<div class="stat animate-in" style="animation-delay: 0.2s">
<div class="stat-label">Active Jurors</div>
<div class="stat-value">13</div>
<div class="stat-delta neutral">
<svg viewBox="0 0 10 10"><circle cx="5" cy="5" r="3" fill="currentColor"/></svg>
12.9 avg/juror
</div>
</div>
<!-- Countries -->
<div class="stat animate-in" style="animation-delay: 0.23s">
<div class="stat-label">Countries</div>
<div class="stat-value">22</div>
<div class="stat-delta up">
<svg viewBox="0 0 10 10"><path d="M5 1.5L8.5 6.5H1.5L5 1.5Z" fill="currentColor"/></svg>
+3 new this round
</div>
</div>
</div>
<!-- ================================================================
PIPELINE
================================================================ -->
<div class="pipeline-section animate-in" style="animation-delay: 0.26s">
<div class="section-title">Competition Pipeline</div>
<div class="pipeline-track">
<!-- R1 Intake (Closed) -->
<a class="p-node" href="#">
<div class="p-icon intake">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 12H16L14 15H10L8 12H2"/><path d="M5.45 5.11L2 12v6a2 2 0 002 2h16a2 2 0 002-2v-6l-3.45-6.89A2 2 0 0016.76 4H7.24a2 2 0 00-1.79 1.11z"/></svg>
</div>
<div class="p-info">
<span class="p-name">R1 — Application Intake</span>
<div class="p-meta-row">
<span class="p-status closed">Closed</span>
<span class="p-count">96 received</span>
</div>
<div class="p-progress"><div class="p-progress-fill complete"></div></div>
</div>
</a>
<div class="p-connector">
<div class="p-line completed"></div>
<div class="p-chevron completed"></div>
</div>
<!-- R2 Filtering (Closed) -->
<a class="p-node" href="#">
<div class="p-icon filter">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/></svg>
</div>
<div class="p-info">
<span class="p-name">R2 — AI Screening</span>
<div class="p-meta-row">
<span class="p-status closed">Closed</span>
<span class="p-count">84 passed</span>
</div>
<div class="p-progress"><div class="p-progress-fill complete"></div></div>
</div>
</a>
<div class="p-connector">
<div class="p-line completed"></div>
<div class="p-chevron completed"></div>
</div>
<!-- R3 Evaluation (ACTIVE) -->
<a class="p-node active" href="#">
<div class="p-icon eval">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 01-2 2H5a2 2 0 01-2-2V5a2 2 0 012-2h11"/></svg>
</div>
<div class="p-info">
<span class="p-name">R3 — Expert Evaluation</span>
<div class="p-meta-row">
<span class="p-status active">Active</span>
<span class="p-count">26/168</span>
</div>
<div class="p-progress"><div class="p-progress-fill partial" style="width: 15%"></div></div>
</div>
<div class="p-pulse"></div>
</a>
<div class="p-connector">
<div class="p-line"></div>
<div class="p-chevron"></div>
</div>
<!-- R4 Submission (Draft) -->
<a class="p-node" href="#">
<div class="p-icon submit">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
</div>
<div class="p-info">
<span class="p-name">R4 — Document Submission</span>
<div class="p-meta-row">
<span class="p-status draft">Draft</span>
<span class="p-count">0 submitted</span>
</div>
<div class="p-progress"><div class="p-progress-fill empty"></div></div>
</div>
</a>
<div class="p-connector">
<div class="p-line"></div>
<div class="p-chevron"></div>
</div>
<!-- R5 Semi-Final (Draft) -->
<a class="p-node" href="#">
<div class="p-icon semi">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 01-2 2H5a2 2 0 01-2-2V5a2 2 0 012-2h11"/></svg>
</div>
<div class="p-info">
<span class="p-name">R5 — Semi-Final Evaluation</span>
<div class="p-meta-row">
<span class="p-status draft">Draft</span>
<span class="p-count">0 assigned</span>
</div>
<div class="p-progress"><div class="p-progress-fill empty"></div></div>
</div>
</a>
</div>
</div>
<!-- ================================================================
MID ROW: SCORE DISTRIBUTION + JUROR WORKLOAD + GEO
================================================================ -->
<div class="mid-grid">
<!-- SCORE DISTRIBUTION -->
<div class="card animate-in" style="animation-delay: 0.3s">
<div class="card-head">
<div class="card-title">Score Distribution</div>
<span style="font-size: 10px; font-family: var(--font-mono); color: var(--ink-faint)">26 scored</span>
</div>
<div class="score-bars">
<div class="score-bar-row">
<span class="score-bar-label">9-10</span>
<div class="score-bar-track">
<div class="score-bar-fill high" style="width: 50%">
<span class="bar-count">13</span>
</div>
</div>
</div>
<div class="score-bar-row">
<span class="score-bar-label">7-8</span>
<div class="score-bar-track">
<div class="score-bar-fill mid" style="width: 23%">
<span class="bar-count">6</span>
</div>
</div>
</div>
<div class="score-bar-row">
<span class="score-bar-label">5-6</span>
<div class="score-bar-track">
<div class="score-bar-fill low" style="width: 27%">
<span class="bar-count">7</span>
</div>
</div>
</div>
<div class="score-bar-row">
<span class="score-bar-label">&lt; 5</span>
<div class="score-bar-track">
<div class="score-bar-fill none" style="width: 0%"></div>
</div>
<span class="score-bar-count-outside">0</span>
</div>
</div>
</div>
<!-- JUROR WORKLOAD -->
<div class="card animate-in" style="animation-delay: 0.33s">
<div class="card-head">
<div class="card-title">Juror Workload</div>
<a class="card-action" href="#">All Jurors &rarr;</a>
</div>
<div class="juror-list">
<div class="juror-row">
<div class="juror-avatar" style="background: #2563eb">PL</div>
<div class="juror-info">
<div class="juror-name">Prof. Laurent</div>
<div class="juror-progress-track"><div class="juror-progress-fill" style="width: 60%"></div></div>
</div>
<span class="juror-count">8/13</span>
</div>
<div class="juror-row">
<div class="juror-avatar" style="background: #059669">SM</div>
<div class="juror-info">
<div class="juror-name">Dr. Moreau</div>
<div class="juror-progress-track"><div class="juror-progress-fill" style="width: 38%"></div></div>
</div>
<span class="juror-count">5/13</span>
</div>
<div class="juror-row">
<div class="juror-avatar" style="background: #7c3aed">AD</div>
<div class="juror-info">
<div class="juror-name">A. Dubois</div>
<div class="juror-progress-track"><div class="juror-progress-fill" style="width: 31%"></div></div>
</div>
<span class="juror-count">4/13</span>
</div>
<div class="juror-row">
<div class="juror-avatar" style="background: #d97706">CB</div>
<div class="juror-info">
<div class="juror-name">C. Blanc</div>
<div class="juror-progress-track"><div class="juror-progress-fill" style="width: 23%"></div></div>
</div>
<span class="juror-count">3/13</span>
</div>
<div class="juror-row">
<div class="juror-avatar" style="background: #db2777">MR</div>
<div class="juror-info">
<div class="juror-name">M. Renard</div>
<div class="juror-progress-track"><div class="juror-progress-fill" style="width: 15%"></div></div>
</div>
<span class="juror-count">2/13</span>
</div>
</div>
</div>
<!-- GEO MAP -->
<div class="card animate-in" style="animation-delay: 0.36s">
<div class="card-head">
<div class="card-title">Project Origins</div>
<span style="font-size: 10px; font-family: var(--font-mono); color: var(--ink-faint)">22 countries</span>
</div>
<div class="geo-placeholder">
<div class="geo-inner">
<span class="geo-label">Leaflet map — interactive</span>
</div>
</div>
<div class="geo-countries">
<span class="country-pill">France <strong>18</strong></span>
<span class="country-pill">Monaco <strong>12</strong></span>
<span class="country-pill">USA <strong>9</strong></span>
<span class="country-pill">Italy <strong>7</strong></span>
<span class="country-pill">UK <strong>6</strong></span>
<span class="country-pill">Spain <strong>5</strong></span>
<span class="country-pill">+16 more</span>
</div>
</div>
</div>
<!-- ================================================================
BOTTOM: PROJECTS TABLE + ACTIVITY FEED
================================================================ -->
<div class="bottom-grid">
<!-- PROJECTS TABLE -->
<div class="card animate-in" style="animation-delay: 0.4s">
<div class="card-head">
<div class="card-title">Recent Projects</div>
<a class="card-action" href="#">View All 84 Projects &rarr;</a>
</div>
<table class="ptable">
<thead>
<tr>
<th>Project</th>
<th>Round</th>
<th>Status</th>
<th>Evaluations</th>
<th>Score</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span class="p-project-name">Algae Scope</span>
<span class="p-org-name">OceanTech Labs, France</span>
</td>
<td><span class="p-round-tag">R3 — Expert Eval</span></td>
<td><span class="p-badge eligible">Eligible</span></td>
<td><span class="p-round-tag">3/3 complete</span></td>
<td><span class="score-val">10.00</span></td>
</tr>
<tr>
<td>
<span class="p-project-name">Blue crabs</span>
<span class="p-org-name">Marine Bio Institute, Monaco</span>
</td>
<td><span class="p-round-tag">R3 — Expert Eval</span></td>
<td><span class="p-badge eligible">Eligible</span></td>
<td><span class="p-round-tag">2/3 complete</span></td>
<td><span class="score-val">10.00</span></td>
</tr>
<tr>
<td>
<span class="p-project-name">Blue Miles Index</span>
<span class="p-org-name">Sustainability Co., USA</span>
</td>
<td><span class="p-round-tag">R3 — Expert Eval</span></td>
<td><span class="p-badge in-progress">In Progress</span></td>
<td><span class="p-round-tag">2/3 complete</span></td>
<td><span class="score-val">9.00</span></td>
</tr>
<tr>
<td>
<span class="p-project-name">BlueReturn</span>
<span class="p-org-name">Ocean Analytics, UK</span>
</td>
<td><span class="p-round-tag">R3 — Expert Eval</span></td>
<td><span class="p-badge in-progress">In Progress</span></td>
<td><span class="p-round-tag">1/3 complete</span></td>
<td><span class="score-val">9.00</span></td>
</tr>
<tr>
<td>
<span class="p-project-name">BlueVault</span>
<span class="p-org-name">AquaSec, Italy</span>
</td>
<td><span class="p-round-tag">R3 — Expert Eval</span></td>
<td><span class="p-badge in-progress">In Progress</span></td>
<td><span class="p-round-tag">1/3 complete</span></td>
<td><span class="score-val">9.00</span></td>
</tr>
<tr>
<td>
<span class="p-project-name">AquaAdvisor</span>
<span class="p-org-name">WaterWise Tech, Spain</span>
</td>
<td><span class="p-round-tag">R3 — Expert Eval</span></td>
<td><span class="p-badge in-progress">In Progress</span></td>
<td><span class="p-round-tag">2/3 complete</span></td>
<td><span class="score-val">7.00</span></td>
</tr>
<tr>
<td>
<span class="p-project-name">Aegir by Navier USN</span>
<span class="p-org-name">NavierUSN, Norway</span>
</td>
<td><span class="p-round-tag">R3 — Expert Eval</span></td>
<td><span class="p-badge pending">Pending</span></td>
<td><span class="p-round-tag">0/3 complete</span></td>
<td><span class="score-na">&mdash;</span></td>
</tr>
<tr>
<td>
<span class="p-project-name">CoralGuard AI</span>
<span class="p-org-name">Reef Systems, Australia</span>
</td>
<td><span class="p-round-tag">R3 — Expert Eval</span></td>
<td><span class="p-badge pending">Pending</span></td>
<td><span class="p-round-tag">0/3 complete</span></td>
<td><span class="score-na">&mdash;</span></td>
</tr>
<tr>
<td>
<span class="p-project-name">DeepClean</span>
<span class="p-org-name">CleanOcean SA, Monaco</span>
</td>
<td><span class="p-round-tag">R3 — Expert Eval</span></td>
<td><span class="p-badge in-progress">In Progress</span></td>
<td><span class="p-round-tag">1/3 complete</span></td>
<td><span class="score-val">6.50</span></td>
</tr>
<tr>
<td>
<span class="p-project-name">TidalPower Pro</span>
<span class="p-org-name">EnergieSea, France</span>
</td>
<td><span class="p-round-tag">R3 — Expert Eval</span></td>
<td><span class="p-badge eligible">Eligible</span></td>
<td><span class="p-round-tag">3/3 complete</span></td>
<td><span class="score-val">8.33</span></td>
</tr>
</tbody>
</table>
<div class="table-footer">
<a href="#">View All 84 Projects &rarr;</a>
</div>
</div>
<!-- ACTIVITY FEED -->
<div class="card animate-in" style="animation-delay: 0.43s">
<div class="card-head">
<div class="card-title">Recent Activity</div>
</div>
<div class="activity-list">
<div class="activity-item">
<div class="activity-dot eval"></div>
<div class="activity-content">
<div class="activity-text"><strong>Prof. Laurent</strong> submitted evaluation for <strong>Algae Scope</strong> — 10/10</div>
<div class="activity-time">12 min ago</div>
</div>
</div>
<div class="activity-item">
<div class="activity-dot eval"></div>
<div class="activity-content">
<div class="activity-text"><strong>Dr. Moreau</strong> submitted evaluation for <strong>Blue crabs</strong> — 10/10</div>
<div class="activity-time">28 min ago</div>
</div>
</div>
<div class="activity-item">
<div class="activity-dot coi"></div>
<div class="activity-content">
<div class="activity-text"><strong>A. Dubois</strong> declared COI for <strong>DeepClean</strong> — reassignment triggered</div>
<div class="activity-time">1h ago</div>
</div>
</div>
<div class="activity-item">
<div class="activity-dot eval"></div>
<div class="activity-content">
<div class="activity-text"><strong>C. Blanc</strong> submitted evaluation for <strong>TidalPower Pro</strong> — 8/10</div>
<div class="activity-time">2h ago</div>
</div>
</div>
<div class="activity-item">
<div class="activity-dot assign"></div>
<div class="activity-content">
<div class="activity-text">Jury reshuffled for <strong>DeepClean</strong><strong>M. Renard</strong> assigned</div>
<div class="activity-time">2h ago</div>
</div>
</div>
<div class="activity-item">
<div class="activity-dot eval"></div>
<div class="activity-content">
<div class="activity-text"><strong>Prof. Laurent</strong> submitted evaluation for <strong>BlueVault</strong> — 9/10</div>
<div class="activity-time">3h ago</div>
</div>
</div>
<div class="activity-item">
<div class="activity-dot eval"></div>
<div class="activity-content">
<div class="activity-text"><strong>M. Renard</strong> submitted evaluation for <strong>AquaAdvisor</strong> — 7/10</div>
<div class="activity-time">5h ago</div>
</div>
</div>
<div class="activity-item">
<div class="activity-dot round"></div>
<div class="activity-content">
<div class="activity-text"><strong>R3 Expert Evaluation</strong> activated — 168 assignments created</div>
<div class="activity-time">2 days ago</div>
</div>
</div>
<div class="activity-item">
<div class="activity-dot round"></div>
<div class="activity-content">
<div class="activity-text"><strong>R2 AI Screening</strong> closed — 84 of 96 projects passed</div>
<div class="activity-time">3 days ago</div>
</div>
</div>
<div class="activity-item">
<div class="activity-dot system"></div>
<div class="activity-content">
<div class="activity-text">AI screening completed — all 96 projects scored and ranked</div>
<div class="activity-time">4 days ago</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>