809 lines
30 KiB
HTML
809 lines
30 KiB
HTML
|
|
<!doctype html>
|
||
|
|
<html lang="en">
|
||
|
|
<head>
|
||
|
|
<meta charset="utf-8" />
|
||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
|
|
<title>AI + Compliance Hub - Dashboard</title>
|
||
|
|
<style>
|
||
|
|
:root {
|
||
|
|
--bg: #fafafa;
|
||
|
|
--surface: #ffffff;
|
||
|
|
--surface-warm: var(--surface);
|
||
|
|
--fg: #111111;
|
||
|
|
--fg-2: var(--fg);
|
||
|
|
--muted: #6b6b6b;
|
||
|
|
--meta: var(--muted);
|
||
|
|
--border: #e5e5e5;
|
||
|
|
--border-soft: var(--border);
|
||
|
|
--primary: #e20074;
|
||
|
|
--accent: var(--primary);
|
||
|
|
--accent-on: #ffffff;
|
||
|
|
--accent-hover: color-mix(in oklab, var(--accent), black 8%);
|
||
|
|
--accent-active: color-mix(in oklab, var(--accent), black 14%);
|
||
|
|
--success: #17a34a;
|
||
|
|
--warn: #d97706;
|
||
|
|
--danger: #dc2626;
|
||
|
|
--font-display: "TeleNeoWeb-Bold", "TeleNeoWeb-Medium", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||
|
|
--font-body: "TeleNeoWeb-Regular", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||
|
|
--font-mono: ui-monospace, "JetBrains Mono", "SF Mono", Menlo, monospace;
|
||
|
|
--text-xs: 11px;
|
||
|
|
--text-sm: 13px;
|
||
|
|
--text-base: 15px;
|
||
|
|
--text-lg: 18px;
|
||
|
|
--text-xl: 22px;
|
||
|
|
--text-2xl: 28px;
|
||
|
|
--leading-body: 1.55;
|
||
|
|
--leading-tight: 1.2;
|
||
|
|
--tracking-display: -0.01em;
|
||
|
|
--space-1: 4px;
|
||
|
|
--space-2: 8px;
|
||
|
|
--space-3: 12px;
|
||
|
|
--space-4: 16px;
|
||
|
|
--space-5: 20px;
|
||
|
|
--space-6: 24px;
|
||
|
|
--space-8: 32px;
|
||
|
|
--radius-sm: 6px;
|
||
|
|
--radius-md: 10px;
|
||
|
|
--radius-lg: 14px;
|
||
|
|
--radius-pill: 9999px;
|
||
|
|
--elev-flat: none;
|
||
|
|
--elev-ring: 0 0 0 1px var(--border);
|
||
|
|
--elev-raised: 0 2px 8px color-mix(in oklab, var(--fg), transparent 92%);
|
||
|
|
--focus-ring: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 70%);
|
||
|
|
--motion-fast: 140ms;
|
||
|
|
--motion-base: 200ms;
|
||
|
|
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||
|
|
--sidebar-w: 240px;
|
||
|
|
color-scheme: light;
|
||
|
|
}
|
||
|
|
|
||
|
|
@media (prefers-color-scheme: dark) {
|
||
|
|
:root:not([data-theme="light"]) {
|
||
|
|
--bg: #0f1014;
|
||
|
|
--surface: #17181d;
|
||
|
|
--fg: #f2f4f8;
|
||
|
|
--fg-2: #e2e6ef;
|
||
|
|
--muted: #9aa2b0;
|
||
|
|
--border: #252830;
|
||
|
|
--border-soft: #1e2028;
|
||
|
|
--accent-hover: color-mix(in oklab, var(--accent), white 12%);
|
||
|
|
--accent-active: color-mix(in oklab, var(--accent), black 6%);
|
||
|
|
--success: #22c55e;
|
||
|
|
--warn: #facc15;
|
||
|
|
--danger: #f87171;
|
||
|
|
--elev-raised: 0 14px 36px color-mix(in oklab, black, transparent 72%);
|
||
|
|
color-scheme: dark;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
:root[data-theme="dark"] {
|
||
|
|
--bg: #0f1014; --surface: #17181d; --fg: #f2f4f8; --fg-2: #e2e6ef;
|
||
|
|
--muted: #9aa2b0; --border: #252830; --border-soft: #1e2028;
|
||
|
|
--accent-hover: color-mix(in oklab, var(--accent), white 12%);
|
||
|
|
--accent-active: color-mix(in oklab, var(--accent), black 6%);
|
||
|
|
--success: #22c55e; --warn: #facc15; --danger: #f87171;
|
||
|
|
--elev-raised: 0 14px 36px color-mix(in oklab, black, transparent 72%);
|
||
|
|
color-scheme: dark;
|
||
|
|
}
|
||
|
|
:root[data-theme="light"] { color-scheme: light; }
|
||
|
|
|
||
|
|
* { box-sizing: border-box; margin: 0; }
|
||
|
|
html { -webkit-text-size-adjust: 100%; height: 100%; }
|
||
|
|
body {
|
||
|
|
height: 100%;
|
||
|
|
background: var(--bg);
|
||
|
|
color: var(--fg);
|
||
|
|
font-family: var(--font-body);
|
||
|
|
font-size: var(--text-base);
|
||
|
|
line-height: var(--leading-body);
|
||
|
|
text-rendering: optimizeLegibility;
|
||
|
|
-webkit-font-smoothing: antialiased;
|
||
|
|
}
|
||
|
|
h1,h2,h3,h4 {
|
||
|
|
font-family: var(--font-display);
|
||
|
|
line-height: var(--leading-tight);
|
||
|
|
letter-spacing: var(--tracking-display);
|
||
|
|
text-wrap: balance;
|
||
|
|
}
|
||
|
|
p { text-wrap: pretty; }
|
||
|
|
a { color: inherit; text-decoration: none; }
|
||
|
|
a:hover { text-decoration: underline; }
|
||
|
|
button, input, select, textarea { font: inherit; }
|
||
|
|
|
||
|
|
/* ── App chrome ─────────────────────────────── */
|
||
|
|
.app-shell {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: var(--sidebar-w) 1fr;
|
||
|
|
min-height: 100vh;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ── Sidebar ────────────────────────────────── */
|
||
|
|
.sidebar {
|
||
|
|
position: sticky;
|
||
|
|
top: 0;
|
||
|
|
height: 100vh;
|
||
|
|
overflow-y: auto;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
background: var(--surface);
|
||
|
|
border-right: 1px solid var(--border);
|
||
|
|
padding: 0;
|
||
|
|
z-index: 10;
|
||
|
|
}
|
||
|
|
.sidebar-brand {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 10px;
|
||
|
|
height: 56px;
|
||
|
|
padding: 0 16px;
|
||
|
|
border-bottom: 1px solid var(--border);
|
||
|
|
flex-shrink: 0;
|
||
|
|
}
|
||
|
|
.brand-logo {
|
||
|
|
width: 26px;
|
||
|
|
height: 26px;
|
||
|
|
background: var(--accent);
|
||
|
|
border-radius: 6px;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
flex-shrink: 0;
|
||
|
|
}
|
||
|
|
.brand-logo svg { color: #fff; }
|
||
|
|
.sidebar-brand-name {
|
||
|
|
font-family: var(--font-display);
|
||
|
|
font-size: var(--text-sm);
|
||
|
|
font-weight: 700;
|
||
|
|
line-height: 1.2;
|
||
|
|
color: var(--fg);
|
||
|
|
}
|
||
|
|
.sidebar-brand-sub {
|
||
|
|
font-size: 10px;
|
||
|
|
color: var(--muted);
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
letter-spacing: 0.04em;
|
||
|
|
}
|
||
|
|
|
||
|
|
.sidebar-nav {
|
||
|
|
flex: 1;
|
||
|
|
padding: 12px 0;
|
||
|
|
overflow-y: auto;
|
||
|
|
}
|
||
|
|
.nav-group {
|
||
|
|
padding: 0 8px 4px;
|
||
|
|
}
|
||
|
|
.nav-group + .nav-group {
|
||
|
|
margin-top: 12px;
|
||
|
|
padding-top: 12px;
|
||
|
|
border-top: 1px solid var(--border);
|
||
|
|
}
|
||
|
|
.nav-group-label {
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
font-size: 10px;
|
||
|
|
text-transform: uppercase;
|
||
|
|
letter-spacing: 0.1em;
|
||
|
|
color: var(--muted);
|
||
|
|
padding: 0 8px 6px;
|
||
|
|
display: block;
|
||
|
|
}
|
||
|
|
.nav-item {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 10px;
|
||
|
|
height: 36px;
|
||
|
|
padding: 0 8px;
|
||
|
|
border-radius: var(--radius-sm);
|
||
|
|
color: var(--muted);
|
||
|
|
font-size: var(--text-sm);
|
||
|
|
cursor: pointer;
|
||
|
|
transition: background var(--motion-fast) var(--ease-standard),
|
||
|
|
color var(--motion-fast) var(--ease-standard);
|
||
|
|
position: relative;
|
||
|
|
}
|
||
|
|
.nav-item:hover {
|
||
|
|
background: color-mix(in oklab, var(--fg), transparent 94%);
|
||
|
|
color: var(--fg);
|
||
|
|
text-decoration: none;
|
||
|
|
}
|
||
|
|
.nav-item.active {
|
||
|
|
background: color-mix(in oklab, var(--accent), transparent 90%);
|
||
|
|
color: var(--accent);
|
||
|
|
font-weight: 600;
|
||
|
|
}
|
||
|
|
.nav-item.active::before {
|
||
|
|
content: "";
|
||
|
|
position: absolute;
|
||
|
|
left: 0;
|
||
|
|
top: 6px;
|
||
|
|
bottom: 6px;
|
||
|
|
width: 3px;
|
||
|
|
border-radius: 0 3px 3px 0;
|
||
|
|
background: var(--accent);
|
||
|
|
}
|
||
|
|
.nav-icon {
|
||
|
|
width: 16px;
|
||
|
|
height: 16px;
|
||
|
|
flex-shrink: 0;
|
||
|
|
opacity: 0.7;
|
||
|
|
}
|
||
|
|
.nav-item.active .nav-icon { opacity: 1; }
|
||
|
|
.nav-badge {
|
||
|
|
margin-left: auto;
|
||
|
|
min-width: 20px;
|
||
|
|
height: 18px;
|
||
|
|
padding: 0 6px;
|
||
|
|
border-radius: var(--radius-pill);
|
||
|
|
background: color-mix(in oklab, var(--accent), transparent 84%);
|
||
|
|
color: var(--accent);
|
||
|
|
font-size: 10px;
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
font-weight: 700;
|
||
|
|
}
|
||
|
|
|
||
|
|
.sidebar-footer {
|
||
|
|
border-top: 1px solid var(--border);
|
||
|
|
padding: 10px 8px;
|
||
|
|
flex-shrink: 0;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 4px;
|
||
|
|
}
|
||
|
|
.sidebar-user {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 10px;
|
||
|
|
padding: 8px 8px;
|
||
|
|
border-radius: var(--radius-sm);
|
||
|
|
cursor: pointer;
|
||
|
|
}
|
||
|
|
.sidebar-user:hover { background: color-mix(in oklab, var(--fg), transparent 94%); }
|
||
|
|
.avatar {
|
||
|
|
width: 30px;
|
||
|
|
height: 30px;
|
||
|
|
border-radius: 50%;
|
||
|
|
background: var(--accent);
|
||
|
|
color: #fff;
|
||
|
|
font-size: 12px;
|
||
|
|
font-weight: 700;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
flex-shrink: 0;
|
||
|
|
}
|
||
|
|
.sidebar-user-info { min-width: 0; }
|
||
|
|
.sidebar-user-name {
|
||
|
|
font-size: var(--text-sm);
|
||
|
|
font-weight: 600;
|
||
|
|
color: var(--fg);
|
||
|
|
white-space: nowrap;
|
||
|
|
overflow: hidden;
|
||
|
|
text-overflow: ellipsis;
|
||
|
|
}
|
||
|
|
.sidebar-user-role {
|
||
|
|
font-size: 11px;
|
||
|
|
color: var(--muted);
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
}
|
||
|
|
.sidebar-action {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 10px;
|
||
|
|
height: 34px;
|
||
|
|
padding: 0 8px;
|
||
|
|
border-radius: var(--radius-sm);
|
||
|
|
color: var(--muted);
|
||
|
|
font-size: var(--text-sm);
|
||
|
|
cursor: pointer;
|
||
|
|
border: none;
|
||
|
|
background: transparent;
|
||
|
|
width: 100%;
|
||
|
|
text-align: left;
|
||
|
|
transition: background var(--motion-fast), color var(--motion-fast);
|
||
|
|
}
|
||
|
|
.sidebar-action:hover {
|
||
|
|
background: color-mix(in oklab, var(--fg), transparent 94%);
|
||
|
|
color: var(--fg);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ── Content area ─────────────────────────── */
|
||
|
|
.content-area {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
min-width: 0;
|
||
|
|
min-height: 100vh;
|
||
|
|
}
|
||
|
|
.content-topbar {
|
||
|
|
position: sticky;
|
||
|
|
top: 0;
|
||
|
|
z-index: 5;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 12px;
|
||
|
|
height: 56px;
|
||
|
|
padding: 0 24px;
|
||
|
|
border-bottom: 1px solid var(--border);
|
||
|
|
background: color-mix(in oklab, var(--bg), transparent 4%);
|
||
|
|
backdrop-filter: blur(10px);
|
||
|
|
}
|
||
|
|
.topbar-title {
|
||
|
|
font-weight: 600;
|
||
|
|
font-size: var(--text-base);
|
||
|
|
color: var(--fg);
|
||
|
|
flex: 1;
|
||
|
|
}
|
||
|
|
.search {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 8px;
|
||
|
|
border: 1px solid var(--border);
|
||
|
|
border-radius: var(--radius-sm);
|
||
|
|
background: var(--surface);
|
||
|
|
padding: 0 12px;
|
||
|
|
height: 34px;
|
||
|
|
width: 260px;
|
||
|
|
}
|
||
|
|
.search input {
|
||
|
|
border: 0; outline: none; background: transparent;
|
||
|
|
width: 100%; color: var(--fg); font-size: var(--text-sm);
|
||
|
|
}
|
||
|
|
.search input::placeholder { color: var(--muted); }
|
||
|
|
|
||
|
|
.btn {
|
||
|
|
height: 34px;
|
||
|
|
border-radius: var(--radius-sm);
|
||
|
|
border: 1px solid var(--border);
|
||
|
|
padding: 0 14px;
|
||
|
|
background: var(--surface);
|
||
|
|
color: var(--fg);
|
||
|
|
font-size: var(--text-sm);
|
||
|
|
cursor: pointer;
|
||
|
|
transition: background var(--motion-fast), border-color var(--motion-fast);
|
||
|
|
white-space: nowrap;
|
||
|
|
}
|
||
|
|
.btn:hover { border-color: var(--fg); }
|
||
|
|
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
||
|
|
.btn-primary {
|
||
|
|
background: var(--accent); border-color: var(--accent); color: var(--accent-on);
|
||
|
|
}
|
||
|
|
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
|
||
|
|
|
||
|
|
/* ── Page ─────────────────────────────────── */
|
||
|
|
.page {
|
||
|
|
padding: 24px;
|
||
|
|
display: grid;
|
||
|
|
gap: 20px;
|
||
|
|
flex: 1;
|
||
|
|
}
|
||
|
|
.page-head {
|
||
|
|
display: flex;
|
||
|
|
align-items: end;
|
||
|
|
justify-content: space-between;
|
||
|
|
gap: 16px;
|
||
|
|
}
|
||
|
|
.eyebrow {
|
||
|
|
color: var(--accent);
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
font-size: var(--text-xs);
|
||
|
|
text-transform: uppercase;
|
||
|
|
letter-spacing: 0.08em;
|
||
|
|
margin-bottom: 6px;
|
||
|
|
}
|
||
|
|
.page-head h1 { font-size: clamp(22px, 3vw, 32px); }
|
||
|
|
.page-head p { color: var(--muted); max-width: 68ch; font-size: var(--text-sm); }
|
||
|
|
|
||
|
|
/* ── Cards ────────────────────────────────── */
|
||
|
|
.card {
|
||
|
|
background: var(--surface);
|
||
|
|
border: 1px solid var(--border);
|
||
|
|
border-radius: var(--radius-md);
|
||
|
|
padding: 18px 20px;
|
||
|
|
}
|
||
|
|
.stats-grid {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(4, minmax(0,1fr));
|
||
|
|
gap: 14px;
|
||
|
|
}
|
||
|
|
.stat-card .label {
|
||
|
|
color: var(--muted); font-size: var(--text-xs);
|
||
|
|
font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 0.08em;
|
||
|
|
}
|
||
|
|
.stat-card .value {
|
||
|
|
margin-top: 12px; font-size: 32px; line-height: 1;
|
||
|
|
font-family: var(--font-display); font-variant-numeric: tabular-nums;
|
||
|
|
}
|
||
|
|
.stat-card .sub {
|
||
|
|
margin-top: 10px; color: var(--muted); font-size: var(--text-xs); line-height: 1.5;
|
||
|
|
}
|
||
|
|
.panel-grid {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: 1.4fr 0.9fr;
|
||
|
|
gap: 20px;
|
||
|
|
}
|
||
|
|
.stack { display: grid; gap: 20px; }
|
||
|
|
.section-head {
|
||
|
|
display: flex; align-items: center;
|
||
|
|
justify-content: space-between; gap: 12px; margin-bottom: 14px;
|
||
|
|
}
|
||
|
|
.section-head h2 { font-size: var(--text-lg); }
|
||
|
|
.ghost-link {
|
||
|
|
color: var(--muted); font-size: var(--text-sm);
|
||
|
|
border-radius: var(--radius-sm); padding: 4px 0;
|
||
|
|
transition: color var(--motion-fast);
|
||
|
|
}
|
||
|
|
.ghost-link:hover { color: var(--fg); text-decoration: none; }
|
||
|
|
|
||
|
|
/* ── Data rows ─────────────────────────────── */
|
||
|
|
.task-list, .program-list, .event-list { display: grid; gap: 10px; }
|
||
|
|
.task-row, .program-row, .event-row {
|
||
|
|
display: grid; gap: 10px;
|
||
|
|
border: 1px solid var(--border); border-radius: var(--radius-sm);
|
||
|
|
padding: 12px 14px;
|
||
|
|
background: color-mix(in oklab, var(--surface), var(--bg) 20%);
|
||
|
|
}
|
||
|
|
.task-row { grid-template-columns: 1.5fr 0.9fr 0.9fr 0.7fr; align-items: center; }
|
||
|
|
.program-row { grid-template-columns: 1fr auto; align-items: start; }
|
||
|
|
.event-row { grid-template-columns: 90px 1fr; align-items: start; }
|
||
|
|
|
||
|
|
.kpi-strip { display: grid; grid-template-columns: repeat(3,1fr); gap: 10px; margin-top: 14px; }
|
||
|
|
.kpi {
|
||
|
|
border: 1px solid var(--border); border-radius: var(--radius-sm);
|
||
|
|
padding: 12px; background: color-mix(in oklab, var(--surface), var(--bg) 18%);
|
||
|
|
}
|
||
|
|
.kpi strong { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 18px; }
|
||
|
|
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
|
||
|
|
|
||
|
|
.status {
|
||
|
|
display: inline-flex; align-items: center; gap: 6px;
|
||
|
|
width: fit-content; padding: 3px 9px; border-radius: var(--radius-pill);
|
||
|
|
font-size: var(--text-xs); border: 1px solid var(--border); font-family: var(--font-mono);
|
||
|
|
}
|
||
|
|
.status::before {
|
||
|
|
content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor;
|
||
|
|
}
|
||
|
|
.status.ok { color: var(--success); }
|
||
|
|
.status.warn { color: var(--warn); }
|
||
|
|
.status.risk { color: var(--danger); }
|
||
|
|
|
||
|
|
.meter {
|
||
|
|
height: 6px; border-radius: 999px;
|
||
|
|
background: color-mix(in oklab, var(--fg), transparent 94%);
|
||
|
|
overflow: hidden; margin-top: 10px;
|
||
|
|
}
|
||
|
|
.meter > span {
|
||
|
|
display: block; height: 100%;
|
||
|
|
background: color-mix(in oklab, var(--accent), white 30%);
|
||
|
|
border-radius: inherit;
|
||
|
|
}
|
||
|
|
|
||
|
|
.pill {
|
||
|
|
display: inline-flex; align-items: center; justify-content: center;
|
||
|
|
height: 20px; padding: 0 7px; border-radius: var(--radius-pill);
|
||
|
|
border: 1px solid var(--border); color: var(--muted);
|
||
|
|
font-size: var(--text-xs); font-family: var(--font-mono);
|
||
|
|
}
|
||
|
|
|
||
|
|
.footer-note { color: var(--muted); font-size: var(--text-xs); line-height: 1.5; }
|
||
|
|
|
||
|
|
/* ── Footer ───────────────────────────────── */
|
||
|
|
.footer {
|
||
|
|
display: flex; align-items: center; justify-content: space-between;
|
||
|
|
gap: 16px; min-height: 34px; padding: 0 24px;
|
||
|
|
border-top: 1px solid var(--border);
|
||
|
|
color: var(--muted); font-size: var(--text-xs);
|
||
|
|
font-family: var(--font-mono); letter-spacing: 0.1em; text-transform: uppercase;
|
||
|
|
background: color-mix(in oklab, var(--bg), var(--surface) 12%);
|
||
|
|
}
|
||
|
|
.footer-status { display: inline-flex; align-items: center; gap: 8px; }
|
||
|
|
.footer-dot {
|
||
|
|
width: 7px; height: 7px; border-radius: 50%; background: #19d3a2;
|
||
|
|
box-shadow: 0 0 0 3px color-mix(in oklab, #19d3a2, transparent 82%);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ── Responsive ───────────────────────────── */
|
||
|
|
@media (max-width: 1180px) {
|
||
|
|
.stats-grid, .panel-grid, .kpi-strip { grid-template-columns: 1fr 1fr; }
|
||
|
|
.task-row { grid-template-columns: 1fr; }
|
||
|
|
}
|
||
|
|
@media (max-width: 900px) {
|
||
|
|
:root { --sidebar-w: 200px; }
|
||
|
|
}
|
||
|
|
@media (max-width: 700px) {
|
||
|
|
.app-shell { grid-template-columns: 1fr; }
|
||
|
|
.sidebar { display: none; }
|
||
|
|
.stats-grid, .panel-grid, .kpi-strip { grid-template-columns: 1fr; }
|
||
|
|
.page-head { flex-direction: column; align-items: start; }
|
||
|
|
.event-row, .program-row { grid-template-columns: 1fr; }
|
||
|
|
}
|
||
|
|
</style>
|
||
|
|
</head>
|
||
|
|
<body data-page="dashboard">
|
||
|
|
<div class="app-shell">
|
||
|
|
|
||
|
|
<!-- ── Sidebar ── -->
|
||
|
|
<aside class="sidebar" aria-label="Primary navigation">
|
||
|
|
<div class="sidebar-brand">
|
||
|
|
<div class="brand-logo">
|
||
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
||
|
|
<path d="M2 3.5h12v1.5H2zm5.25 1.5h1.5v8h-1.5zm-3 2h2.25v1.5H4.25zm5.25 0h2.25v1.5H9.5zm-3 3h2.5v1.5H6.5z" fill="currentColor"/>
|
||
|
|
</svg>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<div class="sidebar-brand-name">T-Systems</div>
|
||
|
|
<div class="sidebar-brand-sub">Regulation Hub</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<nav class="sidebar-nav" aria-label="Primary">
|
||
|
|
<div class="nav-group">
|
||
|
|
<span class="nav-group-label">主导航</span>
|
||
|
|
<a class="nav-item" href="index.html">
|
||
|
|
<svg class="nav-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
||
|
|
<path d="M2 2h5v5H2zm7 0h5v5H9zM2 9h5v5H2zm7 0h5v5H9z" fill="currentColor" opacity=".7"/>
|
||
|
|
</svg>
|
||
|
|
概览
|
||
|
|
</a>
|
||
|
|
<a class="nav-item active" href="dashboard.html">
|
||
|
|
<svg class="nav-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
||
|
|
<path d="M1.5 2.5h13v1H1.5zm0 3h13v1H1.5zm0 3h8v1h-8zm0 3h6v1h-6zM12 8.5a3.5 3.5 0 110 7 3.5 3.5 0 010-7zm0 1a2.5 2.5 0 100 5 2.5 2.5 0 000-5zm.5 1v2h1.5v1H11v-3h1.5z" fill="currentColor"/>
|
||
|
|
</svg>
|
||
|
|
系统状态
|
||
|
|
<span class="nav-badge">3</span>
|
||
|
|
</a>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="nav-group">
|
||
|
|
<span class="nav-group-label">工作台</span>
|
||
|
|
<a class="nav-item" href="document-management.html">
|
||
|
|
<svg class="nav-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
||
|
|
<path d="M3 1h7l3 3v11H3V1zm1 1v12h8V5h-3V2H4zm5 .5V4h1.5L9 1.5zM6 7h4v1H6zm0 2h4v1H6zm0 2h3v1H6z" fill="currentColor"/>
|
||
|
|
</svg>
|
||
|
|
文档管理
|
||
|
|
</a>
|
||
|
|
<a class="nav-item" href="compliance-analysis.html">
|
||
|
|
<svg class="nav-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
||
|
|
<path d="M8 1l7 3-1 6a7 7 0 01-6 5A7 7 0 011 10L0 4l8-3zm0 1.2L1.3 4.8l.8 5.1A6 6 0 008 14.8a6 6 0 005.9-4.9l.8-5.1L8 2.2zM7.5 5h1v4.5l-1 .5V5zm0 5.5h1v1h-1v-1z" fill="currentColor"/>
|
||
|
|
</svg>
|
||
|
|
合规分析
|
||
|
|
</a>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="nav-group">
|
||
|
|
<span class="nav-group-label">对话</span>
|
||
|
|
<a class="nav-item" href="regulation-chat.html">
|
||
|
|
<svg class="nav-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
||
|
|
<path d="M2 2h12a1 1 0 011 1v8a1 1 0 01-1 1H5l-3 2.5V3a1 1 0 011-1zm0 1v9.5L4.5 11H14V3H2zm2 2h8v1H4zm0 2h6v1H4z" fill="currentColor"/>
|
||
|
|
</svg>
|
||
|
|
法规对话
|
||
|
|
</a>
|
||
|
|
</div>
|
||
|
|
</nav>
|
||
|
|
|
||
|
|
<div class="sidebar-footer">
|
||
|
|
<div class="sidebar-user">
|
||
|
|
<div class="avatar">TS</div>
|
||
|
|
<div class="sidebar-user-info">
|
||
|
|
<div class="sidebar-user-name">T-Systems User</div>
|
||
|
|
<div class="sidebar-user-role">Compliance Analyst</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<button class="sidebar-action od-theme-toggle" type="button" data-od-theme aria-label="Toggle theme">
|
||
|
|
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
||
|
|
<path d="M8 3a5 5 0 100 10A5 5 0 008 3zM2 8a6 6 0 1112 0A6 6 0 012 8z" fill="currentColor"/>
|
||
|
|
</svg>
|
||
|
|
主题
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</aside>
|
||
|
|
|
||
|
|
<!-- ── Content area ── -->
|
||
|
|
<div class="content-area">
|
||
|
|
<header class="content-topbar">
|
||
|
|
<div class="topbar-title">系统状态</div>
|
||
|
|
<div class="search">
|
||
|
|
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
||
|
|
<path d="M6.5 1a5.5 5.5 0 014.23 9.02l3.62 3.62-.7.71-3.63-3.63A5.5 5.5 0 116.5 1zm0 1a4.5 4.5 0 100 9 4.5 4.5 0 000-9z" fill="currentColor" opacity=".5"/>
|
||
|
|
</svg>
|
||
|
|
<input type="search" placeholder="Search regulations, documents…" aria-label="Search" />
|
||
|
|
</div>
|
||
|
|
<button class="btn">Export status</button>
|
||
|
|
<a class="btn btn-primary" href="upload-modal.html">New upload</a>
|
||
|
|
</header>
|
||
|
|
|
||
|
|
<main class="page">
|
||
|
|
<section class="page-head" data-od-id="dashboard-head">
|
||
|
|
<div>
|
||
|
|
<div class="eyebrow">Operations dashboard</div>
|
||
|
|
<h1>Track ingestion health and active compliance work.</h1>
|
||
|
|
<p style="margin-top:6px;">Designed for the team lead who needs to know which documents are blocked, which standards changed, and which program teams need intervention today.</p>
|
||
|
|
</div>
|
||
|
|
<span class="pill">v1.0.0</span>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<section class="stats-grid" data-od-id="dashboard-stats">
|
||
|
|
<article class="card stat-card">
|
||
|
|
<div class="label">Documents total</div>
|
||
|
|
<div class="value mono">--</div>
|
||
|
|
<div class="sub">Live document totals populate here from the operations snapshot.</div>
|
||
|
|
</article>
|
||
|
|
<article class="card stat-card">
|
||
|
|
<div class="label">Vector chunks</div>
|
||
|
|
<div class="value mono">--</div>
|
||
|
|
<div class="sub">Dense collection `regulations_dense_1024_v2` currently serving retrieval</div>
|
||
|
|
</article>
|
||
|
|
<article class="card stat-card">
|
||
|
|
<div class="label">Analysis backlog</div>
|
||
|
|
<div class="value mono">--</div>
|
||
|
|
<div class="sub">Open investigations, reviewer backlog, and blocked runs roll up here.</div>
|
||
|
|
</article>
|
||
|
|
<article class="card stat-card">
|
||
|
|
<div class="label">Average ingest time</div>
|
||
|
|
<div class="value mono">--</div>
|
||
|
|
<div class="sub">Aliyun parse plus embedding latency trends appear here once runs are active.</div>
|
||
|
|
</article>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<section class="panel-grid" data-od-id="dashboard-main">
|
||
|
|
<div class="stack">
|
||
|
|
<article class="card">
|
||
|
|
<div class="section-head">
|
||
|
|
<h2>Workflow queue</h2>
|
||
|
|
<a class="ghost-link" href="document-management.html">Open documents →</a>
|
||
|
|
</div>
|
||
|
|
<div class="task-list">
|
||
|
|
<div class="task-row">
|
||
|
|
<div>
|
||
|
|
<strong>GB/T 31484-2015 battery density revision</strong>
|
||
|
|
<div class="footer-note">Uploaded by EV Safety Team · version 2026-04 addendum</div>
|
||
|
|
</div>
|
||
|
|
<span class="status warn">Embedding</span>
|
||
|
|
<span class="mono" style="font-size:12px;">chunk build active</span>
|
||
|
|
<a class="ghost-link" href="document-detail.html">Inspect</a>
|
||
|
|
</div>
|
||
|
|
<div class="task-row">
|
||
|
|
<div>
|
||
|
|
<strong>UNECE R155 annex interpretation note</strong>
|
||
|
|
<div class="footer-note">Parser artifacts ready · waiting for compliance analyst assignment</div>
|
||
|
|
</div>
|
||
|
|
<span class="status ok">Ready</span>
|
||
|
|
<span class="mono" style="font-size:12px;">19 clauses linked</span>
|
||
|
|
<a class="ghost-link" href="compliance-analysis.html">Analyze</a>
|
||
|
|
</div>
|
||
|
|
<div class="task-row">
|
||
|
|
<div>
|
||
|
|
<strong>GB 26112-2010 roof strength scan</strong>
|
||
|
|
<div class="footer-note">OCR confidence dropped below threshold on 6 pages</div>
|
||
|
|
</div>
|
||
|
|
<span class="status risk">Failed</span>
|
||
|
|
<span class="mono" style="font-size:12px;">Retry #2</span>
|
||
|
|
<a class="ghost-link" href="document-management.html">Resolve</a>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</article>
|
||
|
|
|
||
|
|
<article class="card">
|
||
|
|
<div class="section-head">
|
||
|
|
<h2>Active compliance programs</h2>
|
||
|
|
<a class="ghost-link" href="compliance-analysis.html">Review findings →</a>
|
||
|
|
</div>
|
||
|
|
<div class="program-list">
|
||
|
|
<div class="program-row">
|
||
|
|
<div>
|
||
|
|
<strong>Intelligent cockpit homologation</strong>
|
||
|
|
<p class="footer-note">42 related standards across driver monitoring, EMC, and child safety. Four findings still open for MY27 platform.</p>
|
||
|
|
</div>
|
||
|
|
<span class="status risk">High risk</span>
|
||
|
|
</div>
|
||
|
|
<div class="program-row">
|
||
|
|
<div>
|
||
|
|
<strong>Battery swap certification dossier</strong>
|
||
|
|
<p class="footer-note">Clause mapping complete. Thermal event test evidence package still awaiting supplier document refresh.</p>
|
||
|
|
</div>
|
||
|
|
<span class="status warn">Pending</span>
|
||
|
|
</div>
|
||
|
|
<div class="program-row">
|
||
|
|
<div>
|
||
|
|
<strong>Connected fleet cybersecurity</strong>
|
||
|
|
<p class="footer-note">RAG checks aligned with UNECE R155. Chat follow-up requested on remote key rotation obligations.</p>
|
||
|
|
</div>
|
||
|
|
<span class="status ok">On track</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="kpi-strip">
|
||
|
|
<div class="kpi">
|
||
|
|
<div class="footer-note">Retrieval hit rate</div>
|
||
|
|
<strong>87%</strong>
|
||
|
|
<div class="meter"><span style="width:87%"></span></div>
|
||
|
|
</div>
|
||
|
|
<div class="kpi">
|
||
|
|
<div class="footer-note">Evidence coverage</div>
|
||
|
|
<strong>72%</strong>
|
||
|
|
<div class="meter"><span style="width:72%"></span></div>
|
||
|
|
</div>
|
||
|
|
<div class="kpi">
|
||
|
|
<div class="footer-note">Reviewer SLA</div>
|
||
|
|
<strong>18h</strong>
|
||
|
|
<div class="meter"><span style="width:64%"></span></div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</article>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="stack">
|
||
|
|
<article class="card">
|
||
|
|
<div class="section-head">
|
||
|
|
<h2>System health</h2>
|
||
|
|
<a class="ghost-link" href="#">Refresh</a>
|
||
|
|
</div>
|
||
|
|
<div class="task-list">
|
||
|
|
<div class="task-row" style="grid-template-columns: 1fr auto;">
|
||
|
|
<div>
|
||
|
|
<strong>Aliyun parser backend</strong>
|
||
|
|
<div class="footer-note">Poll interval 5 s · timeout 900 s</div>
|
||
|
|
</div>
|
||
|
|
<span class="status warn">Queue depth 7</span>
|
||
|
|
</div>
|
||
|
|
<div class="task-row" style="grid-template-columns: 1fr auto;">
|
||
|
|
<div>
|
||
|
|
<strong>Embedding model</strong>
|
||
|
|
<div class="footer-note">text-embedding-v3 · dimension 1024</div>
|
||
|
|
</div>
|
||
|
|
<span class="status ok">Healthy</span>
|
||
|
|
</div>
|
||
|
|
<div class="task-row" style="grid-template-columns: 1fr auto;">
|
||
|
|
<div>
|
||
|
|
<strong>Vector store</strong>
|
||
|
|
<div class="footer-note">Milvus `regulations_dense_1024_v2`</div>
|
||
|
|
</div>
|
||
|
|
<span class="status ok">Serving</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</article>
|
||
|
|
|
||
|
|
<article class="card">
|
||
|
|
<div class="section-head">
|
||
|
|
<h2>Regulatory watch</h2>
|
||
|
|
<a class="ghost-link" href="regulation-chat.html">Ask chat →</a>
|
||
|
|
</div>
|
||
|
|
<div class="event-list">
|
||
|
|
<div class="event-row">
|
||
|
|
<span class="mono footer-note">Recent</span>
|
||
|
|
<div>
|
||
|
|
<strong>GB 38031 thermal propagation draft updated</strong>
|
||
|
|
<p class="footer-note">Potential impact on current battery enclosure narrative. Evidence gap flagged in two supplier submissions.</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="event-row">
|
||
|
|
<span class="mono footer-note">Recent</span>
|
||
|
|
<div>
|
||
|
|
<strong>UNECE R155 Q&A added note on incident response logs</strong>
|
||
|
|
<p class="footer-note">Connected fleet program must confirm retention windows and ownership controls.</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="event-row">
|
||
|
|
<span class="mono footer-note">Recent</span>
|
||
|
|
<div>
|
||
|
|
<strong>GB/T 18487 charging interface interpretation circulated</strong>
|
||
|
|
<p class="footer-note">No blocker yet, but three documents should be re-run against the new clause wording.</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</article>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
</main>
|
||
|
|
|
||
|
|
<footer class="footer">
|
||
|
|
<span>T-Systems Regulation Hub</span>
|
||
|
|
<div class="footer-status">
|
||
|
|
<span class="footer-dot" aria-hidden="true"></span>
|
||
|
|
<span>Online</span>
|
||
|
|
</div>
|
||
|
|
</footer>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<script src="ui-preferences.js"></script>
|
||
|
|
</body>
|
||
|
|
</html>
|