SurveyVista/Web/Areas/Admin/Views/SurveyAnalysis/Dashboard.cshtml
2026-03-07 02:37:33 +01:00

558 lines
38 KiB
Text

@* Views/Admin/SurveyAnalysis/Dashboard.cshtml *@
@model Services.AIViewModel.QuestionnaireAnalysisOverview
@{
ViewData["Title"] = $"Executive Dashboard — {Model.QuestionnaireTitle}";
}
@section Styles {
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
<style>
@@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Space+Grotesk:wght@300;400;500;600;700&display=swap');
:root{
--neon-blue:#60a5fa;--neon-purple:#c084fc;--neon-green:#34d399;--neon-pink:#f472b6;
--neon-yellow:#fbbf24;--neon-red:#f87171;--neon-cyan:#22d3ee;--neon-indigo:#818cf8;
--neon-teal:#33b3ae;--neon-amber:#f59e0b;--neon-orange:#fb923c;
--dark-900:#0f172a;--dark-800:#1e293b;--dark-700:#334155;--dark-600:#475569;
--dark-500:#64748b;--dark-400:#94a3b8;--dark-300:#cbd5e1;--dark-200:#e2e8f0;
--glass-bg:rgba(255,255,255,0.04);--glass-border:rgba(255,255,255,0.08);
--font-main:'Space Grotesk',sans-serif;--font-mono:'JetBrains Mono',monospace;
}
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:var(--font-main);background:var(--dark-900);color:#e2e8f0;overflow-x:hidden}
/* ===== BG — indigo/blue executive ===== */
.nex-bg{position:fixed;inset:0;z-index:-1;overflow:hidden}
.nex-bg .grid{position:absolute;inset:0;background-image:linear-gradient(rgba(129,140,248,0.04) 1px,transparent 1px),linear-gradient(90deg,rgba(129,140,248,0.04) 1px,transparent 1px);background-size:60px 60px;animation:gridDrift 25s linear infinite}
.nex-bg .mesh{position:absolute;inset:0;background:radial-gradient(ellipse at 20% 20%,rgba(96,165,250,0.06) 0%,transparent 55%),radial-gradient(ellipse at 80% 55%,rgba(192,132,252,0.05) 0%,transparent 55%),radial-gradient(ellipse at 45% 85%,rgba(52,211,153,0.04) 0%,transparent 55%);animation:meshFloat 18s ease-in-out infinite}
@@keyframes gridDrift{0%{transform:translate(0,0)}100%{transform:translate(60px,60px)}}
@@keyframes meshFloat{0%,100%{filter:hue-rotate(0deg);transform:scale(1)}50%{filter:hue-rotate(8deg);transform:scale(1.02)}}
@@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(1.15)}}
@@keyframes barGrow{from{width:0}to{width:var(--w)}}
.container{max-width:1400px;margin:0 auto;padding:0 2rem}
/* ===== HEADER ===== */
.page-header{position:relative;z-index:10;padding:2rem 0 1.5rem;border-bottom:1px solid rgba(129,140,248,0.12)}
.breadcrumb-nex{display:flex;align-items:center;gap:.7rem;margin-bottom:1.8rem;font-family:var(--font-mono);font-size:.65rem;letter-spacing:.08em;flex-wrap:wrap}
.breadcrumb-nex a{color:var(--dark-400);text-decoration:none;display:flex;align-items:center;gap:.4rem;transition:color .2s}
.breadcrumb-nex a:hover{color:var(--neon-indigo)}
.breadcrumb-nex .sep{color:var(--dark-600);font-size:.5rem}
.breadcrumb-nex .current{color:var(--neon-indigo);font-weight:600}
.header-row{display:flex;justify-content:space-between;align-items:flex-start;gap:2rem}
.header-left{flex:1}
.header-badge{display:inline-flex;align-items:center;gap:.5rem;padding:.4rem 1rem;background:rgba(129,140,248,0.08);border:1px solid rgba(129,140,248,0.25);border-radius:50px;margin-bottom:1.5rem;font-family:var(--font-mono);font-size:.6rem;font-weight:600;letter-spacing:.1em;color:var(--neon-indigo)}
.header-badge .dot{width:6px;height:6px;background:var(--neon-indigo);border-radius:50%;animation:pulse 1.5s infinite}
.header-title{font-size:2.8rem;font-weight:700;line-height:1.1;margin-bottom:.8rem;color:#fff}
.header-title .grad{background:linear-gradient(135deg,var(--neon-blue),var(--neon-indigo),var(--neon-cyan));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
.header-sub{font-size:.95rem;color:var(--dark-300);line-height:1.6}
.header-actions{display:flex;flex-wrap:wrap;gap:.7rem;align-items:flex-start;padding-top:.5rem}
.h-btn{display:flex;align-items:center;gap:.6rem;padding:.65rem 1.2rem;border-radius:10px;text-decoration:none;font-family:var(--font-mono);font-size:.68rem;font-weight:600;letter-spacing:.04em;transition:all .25s;border:1px solid;cursor:pointer;background:none}
.h-btn:hover{transform:translateY(-2px);text-decoration:none}
.h-btn.sec{background:rgba(255,255,255,0.04);border-color:rgba(255,255,255,0.1);color:var(--dark-300)}.h-btn.sec:hover{background:rgba(129,140,248,0.08);border-color:rgba(129,140,248,0.25);color:var(--neon-indigo)}
.h-btn.indigo{background:rgba(129,140,248,0.08);border-color:rgba(129,140,248,0.25);color:var(--neon-indigo)}.h-btn.indigo:hover{background:rgba(129,140,248,0.15)}
.h-btn.red-fill{background:linear-gradient(135deg,var(--neon-red),#dc2626);border-color:transparent;color:#fff}.h-btn.red-fill:hover{box-shadow:0 10px 24px rgba(248,113,113,0.25);color:#fff}
/* ===== CARDS ===== */
.nex-card{background:rgba(30,41,59,0.45);backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.07);border-radius:18px;overflow:hidden;position:relative;margin-bottom:1.5rem}
.nex-card .top-glow{position:absolute;top:0;left:0;right:0;height:2px;opacity:0;transition:opacity .3s}
.nex-card:hover .top-glow{opacity:1}
.c-head{padding:1.5rem 1.8rem 1rem;display:flex;align-items:center;gap:1.2rem;border-bottom:1px solid rgba(255,255,255,0.05)}
.c-icon{width:42px;height:42px;border-radius:11px;display:flex;align-items:center;justify-content:center;color:#fff;font-size:1rem;flex-shrink:0}
.c-icon.blue{background:linear-gradient(135deg,var(--neon-blue),var(--neon-cyan))}
.c-icon.green{background:linear-gradient(135deg,var(--neon-green),var(--neon-teal))}
.c-icon.red{background:linear-gradient(135deg,var(--neon-red),#dc2626)}
.c-icon.indigo{background:linear-gradient(135deg,var(--neon-indigo),var(--neon-purple))}
.c-icon.amber{background:linear-gradient(135deg,var(--neon-amber),var(--neon-orange))}
.c-icon.pink{background:linear-gradient(135deg,var(--neon-pink),var(--neon-purple))}
.c-head h3{font-size:1rem;font-weight:700;color:#fff;margin-bottom:.15rem}
.c-head p{color:var(--dark-400);font-size:.72rem}
.c-body{padding:1.5rem 1.8rem 1.8rem}
/* ===== KPI GRID ===== */
.kpi-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:1.5rem;margin-bottom:1.5rem}
.kpi-card{text-align:center;padding:1.8rem 1.2rem;position:relative}
.kpi-card .top-glow.blue{background:linear-gradient(90deg,var(--neon-blue),var(--neon-cyan))}
.kpi-card .top-glow.green{background:linear-gradient(90deg,var(--neon-green),var(--neon-teal))}
.kpi-card .top-glow.red{background:linear-gradient(90deg,var(--neon-red),#dc2626)}
.kpi-card .top-glow.indigo{background:linear-gradient(90deg,var(--neon-indigo),var(--neon-purple))}
.kpi-card .top-glow.amber{background:linear-gradient(90deg,var(--neon-amber),var(--neon-orange))}
.kpi-circle{width:68px;height:68px;border-radius:50%;display:flex;align-items:center;justify-content:center;margin:0 auto 1.2rem;font-size:1.6rem;color:#fff}
.kpi-circle.blue{background:linear-gradient(135deg,var(--neon-blue),var(--neon-cyan))}
.kpi-circle.green{background:linear-gradient(135deg,var(--neon-green),var(--neon-teal))}
.kpi-circle.red{background:linear-gradient(135deg,var(--neon-red),#dc2626)}
.kpi-circle.indigo{background:linear-gradient(135deg,var(--neon-indigo),var(--neon-purple))}
.kpi-circle.amber{background:linear-gradient(135deg,var(--neon-amber),var(--neon-orange))}
.kpi-val{font-family:var(--font-mono);font-size:2.2rem;font-weight:700;color:#fff;line-height:1;margin-bottom:.4rem}
.kpi-lbl{font-size:.88rem;font-weight:500;color:var(--dark-300);margin-bottom:.3rem}
.kpi-sub{font-family:var(--font-mono);font-size:.58rem;color:var(--dark-500);letter-spacing:.06em}
/* ===== CHART SECTION ===== */
.chart-row{display:grid;grid-template-columns:2fr 1fr;gap:1.5rem;margin-bottom:1.5rem}
.chart-box{position:relative;height:250px}
.sent-chart-box{position:relative;height:260px;margin-bottom:1.2rem}
/* Risk stat chips */
.risk-stats{display:grid;grid-template-columns:repeat(4,1fr);gap:.8rem;margin-bottom:1.2rem}
.risk-stat{text-align:center;padding:.8rem .5rem;border-radius:10px;background:rgba(255,255,255,0.025);border:1px solid rgba(255,255,255,0.06)}
.risk-stat.low{border-color:rgba(52,211,153,0.25)}.risk-stat.moderate{border-color:rgba(251,191,36,0.25)}.risk-stat.high{border-color:rgba(248,113,113,0.25)}.risk-stat.critical{border-color:rgba(127,29,29,0.25)}
.risk-stat .rs-icon{font-size:1.2rem;margin-bottom:.3rem}
.risk-stat.low .rs-icon{color:var(--neon-green)}.risk-stat.moderate .rs-icon{color:var(--neon-yellow)}.risk-stat.high .rs-icon{color:var(--neon-red)}.risk-stat.critical .rs-icon{color:#ef4444}
.risk-stat .rs-val{font-family:var(--font-mono);font-size:1.3rem;font-weight:700;color:#fff;margin-bottom:.15rem}
.risk-stat .rs-lbl{font-size:.55rem;color:var(--dark-500);text-transform:uppercase;letter-spacing:.08em}
/* Sentiment legend */
.sent-leg{display:flex;flex-direction:column;gap:.6rem}
.leg-item{display:flex;align-items:center;gap:.8rem;padding:.6rem .8rem;background:rgba(255,255,255,0.025);border-radius:8px}
.leg-dot{width:12px;height:12px;border-radius:50%;flex-shrink:0}
.leg-dot.pos{background:var(--neon-green)}.leg-dot.neu{background:var(--dark-500)}.leg-dot.neg{background:var(--neon-red)}
.leg-lbl{flex:1;font-size:.78rem;color:var(--dark-300)}
.leg-val{font-family:var(--font-mono);font-weight:700;color:#fff;font-size:.82rem}
/* ===== INSIGHTS SECTION ===== */
.insights-row{display:grid;grid-template-columns:2fr 1fr;gap:1.5rem;margin-bottom:1.5rem}
.issue-item{padding:1.2rem;margin-bottom:.8rem;border-radius:12px;background:rgba(255,255,255,0.025);border-left:4px solid;position:relative}
.issue-item:last-child{margin-bottom:0}
.issue-item.p5{border-color:var(--neon-red);background:rgba(248,113,113,0.03)}
.issue-item.p4{border-color:var(--neon-yellow);background:rgba(251,191,36,0.03)}
.issue-item.p3{border-color:var(--neon-blue);background:rgba(96,165,250,0.03)}
.issue-item.p2{border-color:var(--neon-cyan);background:rgba(34,211,238,0.03)}
.issue-top{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem;margin-bottom:.6rem}
.issue-cat{font-weight:600;color:#fff;font-size:.82rem;display:flex;align-items:center;gap:.5rem}
.issue-cat i{color:var(--neon-blue);font-size:.7rem}
.issue-desc{font-size:.72rem;color:var(--dark-400);margin-bottom:.5rem;line-height:1.5}
.issue-action{font-size:.72rem;color:var(--dark-200);line-height:1.5}
.p-badge{padding:.2rem .6rem;border-radius:12px;font-family:var(--font-mono);font-size:.5rem;font-weight:700;letter-spacing:.05em;border:1px solid;white-space:nowrap}
.p-badge.p5{background:rgba(248,113,113,0.12);border-color:rgba(248,113,113,0.3);color:var(--neon-red)}
.p-badge.p4{background:rgba(251,191,36,0.12);border-color:rgba(251,191,36,0.3);color:var(--neon-yellow)}
.p-badge.p3{background:rgba(96,165,250,0.12);border-color:rgba(96,165,250,0.3);color:var(--neon-blue)}
.p-badge.p2{background:rgba(34,211,238,0.12);border-color:rgba(34,211,238,0.3);color:var(--neon-cyan)}
.issue-date{font-family:var(--font-mono);font-size:.5rem;color:var(--dark-500);letter-spacing:.05em;margin-top:.3rem}
.no-data{text-align:center;padding:2.5rem 1rem;color:var(--dark-400)}
.no-data i{font-size:2.2rem;color:var(--neon-green);margin-bottom:.8rem;display:block}
.no-data h4{font-size:.95rem;color:#fff;margin-bottom:.4rem}
.no-data p{font-size:.78rem}
/* Metrics panel */
.metric-item{margin-bottom:1.4rem}
.metric-item:last-child{margin-bottom:0}
.metric-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:.5rem}
.metric-lbl{font-size:.72rem;color:var(--dark-400)}
.metric-val{font-family:var(--font-mono);font-weight:700;font-size:.88rem}
.metric-val.green{color:var(--neon-green)}.metric-val.yellow{color:var(--neon-yellow)}.metric-val.red{color:var(--neon-red)}.metric-val.blue{color:var(--neon-blue)}.metric-val.white{color:#fff}
.bar-track{height:6px;background:rgba(255,255,255,0.06);border-radius:3px;overflow:hidden}
.bar-fill{height:100%;border-radius:3px;animation:barGrow .8s ease both}
.bar-fill.green{background:linear-gradient(90deg,var(--neon-green),var(--neon-teal))}
.bar-fill.yellow{background:linear-gradient(90deg,var(--neon-yellow),var(--neon-orange))}
.bar-fill.red{background:linear-gradient(90deg,var(--neon-red),#dc2626)}
.bar-fill.blue{background:linear-gradient(90deg,var(--neon-blue),var(--neon-indigo))}
/* ===== EXECUTIVE SUMMARY ===== */
.exec-head{background:linear-gradient(135deg,rgba(129,140,248,0.9),rgba(96,165,250,0.9));padding:1.5rem 1.8rem;display:flex;justify-content:space-between;align-items:center;position:relative}
.exec-head::before{content:'';position:absolute;inset:0;background:linear-gradient(135deg,rgba(255,255,255,0.08) 0%,transparent 50%)}
.exec-head h3{position:relative;z-index:2;font-family:var(--font-mono);font-size:.88rem;font-weight:700;letter-spacing:.05em;color:#fff;display:flex;align-items:center;gap:.7rem}
.exec-badge{position:relative;z-index:2;background:rgba(255,255,255,0.18);border:1px solid rgba(255,255,255,0.25);border-radius:20px;padding:.3rem .8rem;font-family:var(--font-mono);font-size:.5rem;font-weight:700;letter-spacing:.08em;color:#fff;display:flex;align-items:center;gap:.4rem}
.exec-body{padding:1.8rem;font-size:.92rem;line-height:1.8;color:var(--dark-200)}
/* ===== ACTIONS SECTION ===== */
.actions-row{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem;margin-bottom:1.5rem}
.act-item{padding:1.2rem;margin-bottom:.8rem;border-radius:12px;background:rgba(255,255,255,0.025);border-left:4px solid;display:flex;align-items:flex-start;gap:1rem}
.act-item:last-child{margin-bottom:0}
.act-item.urgent{border-color:var(--neon-red);background:rgba(248,113,113,0.03)}
.act-item.warning{border-color:var(--neon-yellow);background:rgba(251,191,36,0.03)}
.act-item.info{border-color:var(--neon-blue);background:rgba(96,165,250,0.03)}
.act-icon{width:36px;height:36px;border-radius:8px;display:flex;align-items:center;justify-content:center;color:#fff;font-size:.9rem;flex-shrink:0}
.act-icon.red{background:linear-gradient(135deg,var(--neon-red),#dc2626)}.act-icon.yellow{background:linear-gradient(135deg,var(--neon-yellow),var(--neon-orange))}.act-icon.blue{background:linear-gradient(135deg,var(--neon-blue),var(--neon-indigo))}
.act-title{font-weight:600;font-size:.82rem;margin-bottom:.4rem}
.act-title.red{color:var(--neon-red)}.act-title.yellow{color:var(--neon-yellow)}.act-title.white{color:#fff}
.act-desc{font-size:.72rem;color:var(--dark-300);line-height:1.5;margin-bottom:.6rem}
.strat-item{padding:1.2rem;margin-bottom:.8rem;border-radius:12px;background:rgba(255,255,255,0.025);border-left:4px solid var(--neon-cyan)}
.strat-item:last-child{margin-bottom:0}
.strat-top{display:flex;justify-content:space-between;align-items:flex-start;gap:.8rem;margin-bottom:.5rem}
.strat-title{font-weight:600;color:var(--neon-cyan);font-size:.82rem}
.strat-badge{background:rgba(34,211,238,0.12);border:1px solid rgba(34,211,238,0.3);border-radius:12px;padding:.2rem .6rem;font-family:var(--font-mono);font-size:.5rem;font-weight:700;letter-spacing:.05em;color:var(--neon-cyan);white-space:nowrap}
.strat-desc{font-size:.72rem;color:var(--dark-300);line-height:1.5}
/* ===== PHRASES CLOUD ===== */
.tag-cloud{display:flex;flex-wrap:wrap;gap:.7rem;justify-content:center}
.phrase-tag{padding:.6rem 1.2rem;background:rgba(129,140,248,0.08);border:1px solid rgba(129,140,248,0.25);border-radius:50px;font-family:var(--font-mono);font-weight:600;color:var(--neon-indigo);transition:all .25s;font-size:.72rem;letter-spacing:.04em}
.phrase-tag:hover{background:rgba(129,140,248,0.15);transform:translateY(-2px);box-shadow:0 8px 20px rgba(129,140,248,0.2)}
/* ===== FOOTER ===== */
.foot-row{display:flex;align-items:center;gap:1.5rem}
.foot-icon{width:44px;height:44px;background:linear-gradient(135deg,var(--neon-indigo),var(--neon-purple));border-radius:10px;display:flex;align-items:center;justify-content:center;color:#fff;font-size:1rem;flex-shrink:0}
.foot-text{flex:1}
.foot-text strong{color:#fff;font-size:.85rem}
.foot-text span{color:var(--dark-300);font-size:.78rem}
.foot-btns{display:flex;gap:.6rem;flex-shrink:0}
/* ===== RESPONSIVE ===== */
@@media(max-width:1200px){.kpi-grid{grid-template-columns:repeat(2,1fr)}.chart-row,.insights-row,.actions-row{grid-template-columns:1fr}}
@@media(max-width:768px){.header-row{flex-direction:column}.header-title{font-size:2rem}.kpi-grid{grid-template-columns:1fr}.risk-stats{grid-template-columns:repeat(2,1fr)}.foot-row{flex-direction:column;text-align:center}.foot-btns{width:100%;justify-content:center}.exec-head{flex-direction:column;gap:.8rem;text-align:center}}
@@media(max-width:480px){.risk-stats{grid-template-columns:1fr}.foot-btns{flex-direction:column}}
@@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}
@@media print{.nex-bg,.h-btn,.foot-btns,.header-actions{display:none!important}body{background:#fff;color:#000}.nex-card{border:1px solid #ccc;background:#fff}}
</style>
}
<div class="nex-bg"><div class="grid"></div><div class="mesh"></div></div>
<!-- Header -->
<section class="page-header">
<div class="container">
<div class="breadcrumb-nex">
<a href="@Url.Action("Index")"><i class="fa-solid fa-brain"></i> Analysis Dashboard</a>
<i class="fa-solid fa-chevron-right sep"></i>
<span class="current">Executive Dashboard</span>
</div>
<div class="header-row">
<div class="header-left">
<div class="header-badge"><span class="dot"></span> CLAUDE AI EXECUTIVE INTELLIGENCE</div>
<h1 class="header-title">Executive <span class="grad">Intelligence</span> Dashboard</h1>
<p class="header-sub">Strategic overview of workplace mental health metrics for C-level decision making — @Model.QuestionnaireTitle</p>
</div>
<div class="header-actions">
<a href="@Url.Action("GenerateReport", new { id = Model.QuestionnaireId })" class="h-btn indigo"><i class="fa-solid fa-file-lines"></i> Executive Report</a>
<a href="@Url.Action("ExportAnalysis", new { id = Model.QuestionnaireId })" class="h-btn sec"><i class="fa-solid fa-chart-pie"></i> Export</a>
</div>
</div>
</div>
</section>
<section style="position:relative;z-index:10;padding:2rem 0 3rem">
<div class="container">
@* ===== KPIs ===== *@
<div class="kpi-grid">
<div class="nex-card kpi-card"><div class="top-glow blue"></div>
<div class="kpi-circle blue"><i class="fa-solid fa-users"></i></div>
<div class="kpi-val">@Model.TotalResponses</div>
<div class="kpi-lbl">Total Participants</div>
<div class="kpi-sub">@Model.AnalyzedResponses AI ANALYZED</div>
</div>
<div class="nex-card kpi-card"><div class="top-glow @GetHealthGlowClass()"></div>
<div class="kpi-circle @GetHealthGlowClass()"><i class="fa-solid @GetOverallHealthIcon()"></i></div>
<div class="kpi-val">@GetOverallHealthScore()%</div>
<div class="kpi-lbl">Mental Health Score</div>
<div class="kpi-sub">@GetOverallHealthStatus().ToUpper()</div>
</div>
<div class="nex-card kpi-card"><div class="top-glow @(Model.HighRiskResponses + Model.CriticalRiskResponses > 0 ? "red" : "green")"></div>
<div class="kpi-circle @(Model.HighRiskResponses + Model.CriticalRiskResponses > 0 ? "red" : "green")"><i class="fa-solid fa-shield-halved"></i></div>
<div class="kpi-val">@(Model.HighRiskResponses + Model.CriticalRiskResponses)</div>
<div class="kpi-lbl">High Risk Cases</div>
<div class="kpi-sub">
@if (Model.CriticalRiskResponses > 0) { <text>@Model.CriticalRiskResponses CRITICAL</text> }
else if (Model.HighRiskResponses > 0) { <text>IMMEDIATE ATTENTION</text> }
else { <text>NO CRITICAL CASES</text> }
</div>
</div>
<div class="nex-card kpi-card"><div class="top-glow indigo"></div>
<div class="kpi-circle indigo"><i class="fa-solid fa-chart-line"></i></div>
<div class="kpi-val">@Math.Round(Model.OverallPositiveSentiment * 100, 0)%</div>
<div class="kpi-lbl">Positive Sentiment</div>
<div class="kpi-sub">EMPLOYEE SATISFACTION</div>
</div>
</div>
@* ===== CHARTS ===== *@
<div class="chart-row">
<div class="nex-card"><div class="top-glow blue"></div>
<div class="c-head"><div class="c-icon blue"><i class="fa-solid fa-chart-column"></i></div><div><h3>Mental Health Risk Distribution</h3><p>Breakdown by risk level</p></div></div>
<div class="c-body">
<div class="risk-stats">
<div class="risk-stat low"><div class="rs-icon"><i class="fa-solid fa-face-smile"></i></div><div class="rs-val">@Model.LowRiskResponses</div><div class="rs-lbl">Low Risk</div></div>
<div class="risk-stat moderate"><div class="rs-icon"><i class="fa-solid fa-face-meh"></i></div><div class="rs-val">@Model.ModerateRiskResponses</div><div class="rs-lbl">Moderate</div></div>
<div class="risk-stat high"><div class="rs-icon"><i class="fa-solid fa-face-frown"></i></div><div class="rs-val">@Model.HighRiskResponses</div><div class="rs-lbl">High Risk</div></div>
<div class="risk-stat critical"><div class="rs-icon"><i class="fa-solid fa-triangle-exclamation"></i></div><div class="rs-val">@Model.CriticalRiskResponses</div><div class="rs-lbl">Critical</div></div>
</div>
<div class="chart-box"><canvas id="riskDistributionChart"></canvas></div>
</div>
</div>
<div class="nex-card"><div class="top-glow green"></div>
<div class="c-head"><div class="c-icon green"><i class="fa-solid fa-heart-pulse"></i></div><div><h3>Sentiment Overview</h3><p>Emotional health distribution</p></div></div>
<div class="c-body">
<div class="sent-chart-box"><canvas id="sentimentChart"></canvas></div>
<div class="sent-leg">
<div class="leg-item"><div class="leg-dot pos"></div><div class="leg-lbl">Positive</div><div class="leg-val">@Math.Round(Model.OverallPositiveSentiment * 100, 1)%</div></div>
<div class="leg-item"><div class="leg-dot neu"></div><div class="leg-lbl">Neutral</div><div class="leg-val">@Math.Round(Model.OverallNeutralSentiment * 100, 1)%</div></div>
<div class="leg-item"><div class="leg-dot neg"></div><div class="leg-lbl">Negative</div><div class="leg-val">@Math.Round(Model.OverallNegativeSentiment * 100, 1)%</div></div>
</div>
</div>
</div>
</div>
@* ===== INSIGHTS + METRICS ===== *@
<div class="insights-row">
<div class="nex-card"><div class="top-glow amber"></div>
<div class="c-head"><div class="c-icon amber"><i class="fa-solid fa-lightbulb"></i></div><div><h3>Strategic Workplace Interventions</h3><p>AI-identified priorities</p></div></div>
<div class="c-body">
@if (Model.TopWorkplaceIssues?.Any() == true)
{
@foreach (var issue in Model.TopWorkplaceIssues.Take(4))
{
<div class="issue-item p@(issue.Priority)">
<div class="issue-top">
<div>
<div class="issue-cat"><i class="fa-solid fa-arrow-right"></i> @issue.Category</div>
<div class="issue-desc">@issue.Issue</div>
<div class="issue-action"><strong>Action:</strong> @issue.RecommendedIntervention</div>
</div>
<div style="text-align:right">
<span class="p-badge p@(issue.Priority)">P@issue.Priority</span>
<div class="issue-date">@issue.IdentifiedAt.ToString("MMM dd").ToUpper()</div>
</div>
</div>
</div>
}
}
else
{
<div class="no-data"><i class="fa-solid fa-circle-check"></i><h4>No Major Issues Identified</h4><p>Claude AI indicates a generally healthy workplace mental health environment.</p></div>
}
</div>
</div>
<div class="nex-card"><div class="top-glow indigo"></div>
<div class="c-head"><div class="c-icon indigo"><i class="fa-solid fa-bullseye"></i></div><div><h3>Key Metrics</h3><p>Performance indicators</p></div></div>
<div class="c-body">
<div class="metric-item">
<div class="metric-row"><span class="metric-lbl">Mental Health Score</span><span class="metric-val @GetHealthMetricClass()">@GetOverallHealthScore()%</span></div>
<div class="bar-track"><div class="bar-fill @GetHealthMetricClass()" style="--w:@(GetOverallHealthScore())%;width:var(--w)"></div></div>
</div>
<div class="metric-item">
<div class="metric-row"><span class="metric-lbl">Response Rate</span><span class="metric-val blue">@Math.Round((double)Model.AnalyzedResponses / Model.TotalResponses * 100, 1)%</span></div>
<div class="bar-track"><div class="bar-fill blue" style="--w:@((double)Model.AnalyzedResponses / Model.TotalResponses * 100)%;width:var(--w)"></div></div>
</div>
<div class="metric-item">
<div class="metric-row"><span class="metric-lbl">Cases Requiring Attention</span><span class="metric-val @(Model.HighRiskResponses + Model.CriticalRiskResponses > 0 ? "red" : "green")">@(Model.HighRiskResponses + Model.CriticalRiskResponses)</span></div>
</div>
<div class="metric-item">
<div class="metric-row"><span class="metric-lbl">Last Analysis</span><span class="metric-val white">@Model.LastAnalyzedAt.ToString("MMM dd, HH:mm").ToUpper()</span></div>
</div>
</div>
</div>
</div>
@* ===== EXECUTIVE SUMMARY ===== *@
@if (!string.IsNullOrEmpty(Model.ExecutiveSummary))
{
<div class="nex-card">
<div class="exec-head">
<h3><i class="fa-solid fa-clipboard-list"></i> Executive Summary for Leadership</h3>
<div class="exec-badge"><i class="fa-solid fa-user-tie"></i> C-LEVEL SUMMARY</div>
</div>
<div class="exec-body">@Html.Raw(Model.ExecutiveSummary.Replace("\n", "<br />"))</div>
</div>
}
@* ===== ACTIONS ===== *@
<div class="actions-row">
<div class="nex-card"><div class="top-glow red"></div>
<div class="c-head"><div class="c-icon red"><i class="fa-solid fa-list-check"></i></div><div><h3>Immediate Action Items</h3><p>Urgent interventions needed</p></div></div>
<div class="c-body">
@if (Model.CriticalRiskResponses > 0 || Model.HighRiskResponses > 0)
{
<div class="act-item urgent">
<div class="act-icon red"><i class="fa-solid fa-triangle-exclamation"></i></div>
<div>
<div class="act-title red">URGENT: Mental Health Interventions Required</div>
<div class="act-desc">@(Model.CriticalRiskResponses + Model.HighRiskResponses) employees require immediate professional attention.</div>
<a href="@Url.Action("HighRiskResponses", new { id = Model.QuestionnaireId })" class="h-btn red-fill" style="display:inline-flex;padding:.5rem 1rem;font-size:.6rem"><i class="fa-solid fa-user-doctor"></i> REVIEW HIGH RISK CASES</a>
</div>
</div>
}
@if (Model.TopWorkplaceIssues?.Any() == true)
{
@foreach (var issue in Model.TopWorkplaceIssues.Where(i => i.Priority >= 4).Take(3))
{
<div class="act-item warning">
<div class="act-icon yellow"><i class="fa-solid fa-arrow-right"></i></div>
<div>
<div class="act-title yellow">@issue.Category</div>
<div class="act-desc">@issue.RecommendedIntervention</div>
<span class="p-badge p@(issue.Priority)">P@issue.Priority</span>
</div>
</div>
}
}
@if (Model.CriticalRiskResponses == 0 && Model.HighRiskResponses == 0 && !Model.TopWorkplaceIssues.Any(i => i.Priority >= 4))
{
<div class="no-data"><i class="fa-solid fa-circle-check"></i><h4>No Immediate Actions Required</h4><p>Mental health status is stable with no urgent interventions needed.</p></div>
}
</div>
</div>
<div class="nex-card"><div class="top-glow green"></div>
<div class="c-head"><div class="c-icon green"><i class="fa-solid fa-arrow-trend-up"></i></div><div><h3>Strategic Recommendations</h3><p>Long-term improvements</p></div></div>
<div class="c-body">
@{ var strategicActions = GetStrategicRecommendations(); }
@foreach (var action in strategicActions)
{
<div class="strat-item">
<div class="strat-top"><div class="strat-title">@action.Title</div><span class="strat-badge">@action.Timeline</span></div>
<div class="strat-desc">@action.Description</div>
</div>
}
</div>
</div>
</div>
@* ===== KEY PHRASES ===== *@
@if (Model.MostCommonKeyPhrases?.Any() == true)
{
<div class="nex-card"><div class="top-glow" style="background:linear-gradient(90deg,var(--neon-pink),var(--neon-purple))"></div>
<div class="c-head"><div class="c-icon pink"><i class="fa-solid fa-cloud"></i></div><div><h3>Most Common Employee Concerns</h3><p>Trending themes from responses</p></div></div>
<div class="c-body"><div class="tag-cloud">@foreach (var phrase in Model.MostCommonKeyPhrases.Take(12)) { <span class="phrase-tag">@phrase</span> }</div></div>
</div>
}
@* ===== FOOTER ===== *@
<div class="nex-card">
<div class="c-body">
<div class="foot-row">
<div class="foot-icon"><i class="fa-solid fa-circle-info"></i></div>
<div class="foot-text">
<strong>Dashboard Summary</strong><br />
<span>Analysis of @Model.TotalResponses employee responses shows @GetOverallHealthStatus().ToLower() workplace mental health with @(Model.HighRiskResponses + Model.CriticalRiskResponses) cases requiring attention.</span>
</div>
<div class="foot-btns">
<a href="@Url.Action("AnalyzeTrends", new { id = Model.QuestionnaireId })" class="h-btn indigo"><i class="fa-solid fa-chart-area"></i> Trends</a>
<a href="@Url.Action("AnalyzeQuestionnaire", new { id = Model.QuestionnaireId })" class="h-btn sec"><i class="fa-solid fa-magnifying-glass"></i> Detail</a>
</div>
</div>
</div>
</div>
</div>
</section>
@functions {
private string GetHealthGlowClass()
{
var score = GetOverallHealthScore();
if (score >= 75) return "green";
if (score >= 50) return "amber";
return "red";
}
private string GetHealthMetricClass()
{
var score = GetOverallHealthScore();
if (score >= 75) return "green";
if (score >= 50) return "yellow";
return "red";
}
private string GetOverallHealthIcon()
{
var score = GetOverallHealthScore();
if (score >= 75) return "fa-heart";
if (score >= 50) return "fa-heart-pulse";
return "fa-heart-crack";
}
private int GetOverallHealthScore()
{
var sentimentScore = Model.OverallPositiveSentiment * 100;
var riskPenalty = (Model.HighRiskResponses + Model.CriticalRiskResponses * 2) * 10;
return Math.Max(0, (int)(sentimentScore - riskPenalty));
}
private string GetOverallHealthStatus()
{
var score = GetOverallHealthScore();
if (score >= 75) return "Excellent";
if (score >= 50) return "Good";
if (score >= 25) return "Concerning";
return "Critical";
}
private double GetTagSize(string phrase)
{
return phrase.Length > 10 ? 1.1 : 0.9;
}
private List<dynamic> GetStrategicRecommendations()
{
var recommendations = new List<dynamic>();
if (Model.HighRiskResponses + Model.CriticalRiskResponses > 0)
{
recommendations.Add(new { Title = "Immediate Mental Health Support", Description = "Deploy emergency mental health resources and professional counseling", Timeline = "24-48 HOURS" });
}
if (Model.OverallNegativeSentiment > 0.4)
{
recommendations.Add(new { Title = "Workplace Culture Assessment", Description = "Conduct comprehensive review of workplace environment and management practices", Timeline = "2-4 WEEKS" });
}
recommendations.Add(new { Title = "Preventive Mental Health Program", Description = "Implement ongoing mental health awareness and stress management programs", Timeline = "1-3 MONTHS" });
recommendations.Add(new { Title = "Regular Mental Health Monitoring", Description = "Establish quarterly mental health assessments and trend monitoring", Timeline = "ONGOING" });
return recommendations;
}
}
@section Scripts {
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
Chart.defaults.color = '#94a3b8';
Chart.defaults.borderColor = 'rgba(255,255,255,0.04)';
// Risk Distribution Bar Chart
new Chart(document.getElementById('riskDistributionChart').getContext('2d'), {
type: 'bar',
data: {
labels: ['Low Risk', 'Moderate', 'High Risk', 'Critical'],
datasets: [{
label: 'Responses',
data: [@Model.LowRiskResponses, @Model.ModerateRiskResponses, @Model.HighRiskResponses, @Model.CriticalRiskResponses],
backgroundColor: ['rgba(52,211,153,0.35)','rgba(251,191,36,0.35)','rgba(248,113,113,0.35)','rgba(239,68,68,0.35)'],
borderColor: ['rgba(52,211,153,0.6)','rgba(251,191,36,0.6)','rgba(248,113,113,0.6)','rgba(239,68,68,0.6)'],
borderWidth: 2, borderRadius: 8, borderSkipped: false
}]
},
options: {
responsive: true, maintainAspectRatio: false,
plugins: { legend: { display: false }, tooltip: { backgroundColor: 'rgba(15,23,42,0.92)', titleFont: { family: 'JetBrains Mono', weight: 'bold' }, bodyFont: { family: 'Space Grotesk' }, borderColor: 'rgba(129,140,248,0.3)', borderWidth: 1, cornerRadius: 8 } },
scales: {
x: { grid: { display: false }, ticks: { font: { family: 'JetBrains Mono', size: 10 } } },
y: { beginAtZero: true, grid: { color: 'rgba(255,255,255,0.04)' }, ticks: { stepSize: 1, font: { family: 'JetBrains Mono', size: 10 } } }
}
}
});
// Sentiment Doughnut
new Chart(document.getElementById('sentimentChart').getContext('2d'), {
type: 'doughnut',
data: {
labels: ['Positive', 'Neutral', 'Negative'],
datasets: [{
data: [@Math.Round(Model.OverallPositiveSentiment * 100, 1), @Math.Round(Model.OverallNeutralSentiment * 100, 1), @Math.Round(Model.OverallNegativeSentiment * 100, 1)],
backgroundColor: ['rgba(52,211,153,0.8)','rgba(100,116,139,0.6)','rgba(248,113,113,0.8)'],
borderColor: ['#34d399','#64748b','#f87171'],
borderWidth: 2, hoverBorderWidth: 3, hoverBorderColor: '#ffffff'
}]
},
options: {
responsive: true, maintainAspectRatio: false,
plugins: { legend: { display: false }, tooltip: { backgroundColor: 'rgba(15,23,42,0.92)', titleFont: { family: 'JetBrains Mono', weight: 'bold' }, bodyFont: { family: 'Space Grotesk' }, borderColor: 'rgba(129,140,248,0.3)', borderWidth: 1, cornerRadius: 8 } },
cutout: '70%'
}
});
});
</script>
}