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

664 lines
40 KiB
Text

@model IEnumerable<QuestionnaireViewModel>
@{
ViewData["Title"] = "Questionnaire Management";
}
<!-- Font Awesome 6 CDN -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
@section Styles {
<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;
--dark-900: #0f172a;
--dark-800: #1e293b;
--dark-700: #334155;
--dark-600: #475569;
--dark-500: #64748b;
--dark-400: #94a3b8;
--dark-300: #cbd5e1;
--glass-bg: rgba(255,255,255,0.05);
--glass-border: rgba(255,255,255,0.1);
--glass-shadow: 0 8px 32px rgba(0,0,0,0.12);
--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;
}
.nxg-page { min-height: 100vh; position: relative; }
/* ===== ANIMATED BACKGROUND ===== */
.bg-pattern { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: -1; overflow: hidden; }
.grid-overlay {
position: absolute; inset: 0;
background-image: linear-gradient(rgba(96,165,250,0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(96,165,250,0.1) 1px, transparent 1px);
background-size: 60px 60px;
animation: gridMove 20s linear infinite;
}
.gradient-mesh {
position: absolute; inset: 0;
background: radial-gradient(circle at 20% 20%, rgba(96,165,250,0.15) 0%, transparent 50%),
radial-gradient(circle at 80% 60%, rgba(192,132,252,0.15) 0%, transparent 50%),
radial-gradient(circle at 40% 80%, rgba(52,211,153,0.15) 0%, transparent 50%);
animation: meshShift 15s ease-in-out infinite;
}
/* ===== HERO SECTION ===== */
.hero-section { padding: 4rem 0 2rem; text-align: center; position: relative; z-index: 10; }
.hero-badge {
display: inline-flex; align-items: center; gap: 0.6rem;
padding: 0.5rem 1.2rem; background: rgba(96,165,250,0.1);
border: 1px solid rgba(96,165,250,0.3); border-radius: 50px;
margin-bottom: 2rem; font-family: var(--font-mono);
font-size: 0.7rem; font-weight: 600; letter-spacing: 0.1em; color: var(--neon-blue);
}
.badge-dot { width: 6px; height: 6px; background: var(--neon-green); border-radius: 50%; animation: pulse 2s infinite; }
.hero-title { font-size: 3.5rem; font-weight: 700; line-height: 1.1; margin-bottom: 1.5rem; color: #ffffff; }
.title-gradient {
background: linear-gradient(135deg, var(--neon-blue), var(--neon-purple), var(--neon-pink));
-webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
}
.hero-desc { font-size: 1.05rem; color: var(--dark-300); max-width: 600px; margin: 0 auto 2rem; line-height: 1.6; }
/* ===== STATS STRIP ===== */
.stats-strip {
display: grid; grid-template-columns: repeat(6, 1fr); gap: 0.75rem;
margin-bottom: 2.5rem; position: relative; z-index: 10;
}
.stat-chip {
background: var(--glass-bg); backdrop-filter: blur(20px);
border: 1px solid var(--glass-border); border-radius: 16px;
padding: 1.1rem 0.5rem; text-align: center;
transition: all 0.3s ease; position: relative; overflow: hidden;
}
.stat-chip:hover { transform: translateY(-4px); border-color: rgba(96,165,250,0.3); box-shadow: 0 12px 30px rgba(96,165,250,0.1); }
.stat-chip::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px; }
.stat-chip:nth-child(1)::before { background: linear-gradient(90deg, var(--neon-blue), var(--neon-cyan)); }
.stat-chip:nth-child(2)::before { background: linear-gradient(90deg, var(--dark-500), var(--dark-400)); }
.stat-chip:nth-child(3)::before { background: linear-gradient(90deg, var(--neon-green), var(--neon-cyan)); }
.stat-chip:nth-child(4)::before { background: linear-gradient(90deg, var(--dark-700), var(--dark-500)); }
.stat-chip:nth-child(5)::before { background: linear-gradient(90deg, var(--neon-blue), var(--neon-purple)); }
.stat-chip:nth-child(6)::before { background: linear-gradient(90deg, var(--neon-yellow), var(--neon-pink)); }
.stat-chip-icon {
width: 36px; height: 36px; border-radius: 10px;
display: flex; align-items: center; justify-content: center;
font-size: 0.95rem; color: white; margin: 0 auto 0.5rem;
}
.stat-chip:nth-child(1) .stat-chip-icon { background: linear-gradient(135deg, var(--neon-blue), var(--neon-cyan)); }
.stat-chip:nth-child(2) .stat-chip-icon { background: linear-gradient(135deg, var(--dark-500), var(--dark-400)); }
.stat-chip:nth-child(3) .stat-chip-icon { background: linear-gradient(135deg, var(--neon-green), var(--neon-cyan)); }
.stat-chip:nth-child(4) .stat-chip-icon { background: linear-gradient(135deg, var(--dark-700), var(--dark-500)); }
.stat-chip:nth-child(5) .stat-chip-icon { background: linear-gradient(135deg, var(--neon-blue), var(--neon-purple)); }
.stat-chip:nth-child(6) .stat-chip-icon { background: linear-gradient(135deg, var(--neon-yellow), var(--neon-pink)); }
.stat-chip-num { font-size: 1.6rem; font-weight: 700; color: #ffffff; display: block; line-height: 1.2; }
.stat-chip-label { font-family: var(--font-mono); font-size: 0.6rem; font-weight: 600; letter-spacing: 0.1em; color: var(--dark-400); margin-top: 3px; }
/* ===== SECTION TITLE ===== */
.section-header { text-align: center; margin-bottom: 2.5rem; position: relative; z-index: 10; }
.section-header h2 { font-family: var(--font-mono); font-size: 1.4rem; font-weight: 700; letter-spacing: 0.1em; color: #ffffff; margin-bottom: 0.75rem; }
.title-line { width: 80px; height: 3px; background: linear-gradient(90deg, var(--neon-blue), var(--neon-purple)); margin: 0 auto; border-radius: 2px; }
/* ===== CARDS GRID — 2 COL ===== */
.cards-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.5rem; position: relative; z-index: 10; }
.q-card {
background: var(--glass-bg); backdrop-filter: blur(20px);
border: 1px solid var(--glass-border); border-radius: 20px;
overflow: hidden; transition: all 0.3s cubic-bezier(0.4,0,0.2,1);
position: relative; opacity: 0; transform: translateY(30px);
}
.q-card.animate-in { opacity: 1; transform: translateY(0); }
.q-card:hover { transform: translateY(-5px); border-color: rgba(96,165,250,0.4); box-shadow: 0 20px 40px rgba(96,165,250,0.1); }
.card-glow {
position: absolute; top: 0; left: 0; right: 0; height: 2px;
background: linear-gradient(90deg, var(--neon-blue), var(--neon-purple), var(--neon-pink));
opacity: 0; transition: opacity 0.3s ease;
}
.q-card:hover .card-glow { opacity: 1; }
/* Status badge */
.q-status {
position: absolute; top: 1rem; right: 1rem;
padding: 0.3rem 0.8rem; border-radius: 8px;
font-family: var(--font-mono); font-weight: 700; font-size: 0.6rem;
text-transform: uppercase; letter-spacing: 0.08em; z-index: 5;
display: flex; align-items: center; gap: 0.35rem;
}
.q-status.draft { background: rgba(100,116,139,0.3); border: 1px solid rgba(100,116,139,0.5); color: var(--dark-300); }
.q-status.published { background: rgba(52,211,153,0.15); border: 1px solid rgba(52,211,153,0.4); color: var(--neon-green); }
.q-status.archived { background: rgba(100,116,139,0.15); border: 1px solid rgba(100,116,139,0.3); color: var(--dark-400); }
/* Card header */
.q-card-head { padding: 1.5rem 1.5rem 1rem; position: relative; z-index: 2; padding-right: 6rem; }
.q-card-id {
font-family: var(--font-mono); font-size: 0.6rem; font-weight: 600;
letter-spacing: 0.08em; color: var(--neon-yellow);
background: rgba(251,191,36,0.1); border: 1px solid rgba(251,191,36,0.25);
padding: 0.15rem 0.55rem; border-radius: 6px; display: inline-block; margin-bottom: 0.4rem;
}
.q-card-title { font-size: 1.3rem; font-weight: 700; color: #ffffff; line-height: 1.3; word-break: break-word; }
/* Info metrics */
.q-metrics {
display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.75rem;
padding: 0 1.5rem; margin-bottom: 1rem;
}
.q-metric {
background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.08);
border-radius: 12px; padding: 0.85rem; display: flex; align-items: center; gap: 0.75rem;
transition: all 0.2s ease;
}
.q-metric:hover { background: rgba(255,255,255,0.05); border-color: rgba(255,255,255,0.15); }
.q-metric-icon {
width: 32px; height: 32px; border-radius: 8px;
display: flex; align-items: center; justify-content: center;
color: white; font-size: 0.85rem;
}
.q-metric:nth-child(1) .q-metric-icon { background: linear-gradient(135deg, var(--neon-blue), var(--neon-cyan)); }
.q-metric:nth-child(2) .q-metric-icon { background: linear-gradient(135deg, var(--neon-green), var(--neon-cyan)); }
.q-metric:nth-child(3) .q-metric-icon { background: linear-gradient(135deg, var(--neon-purple), var(--neon-pink)); }
.q-metric-num { font-size: 1.2rem; font-weight: 700; color: #ffffff; line-height: 1; }
.q-metric-label { font-family: var(--font-mono); font-size: 0.55rem; font-weight: 600; letter-spacing: 0.1em; color: var(--dark-400); }
.q-pub-date {
display: flex; align-items: center; gap: 0.6rem;
padding: 0.6rem 1.5rem; font-family: var(--font-mono);
font-size: 0.65rem; font-weight: 500; letter-spacing: 0.05em; color: var(--dark-400);
}
.q-pub-dot { width: 6px; height: 6px; background: var(--neon-green); border-radius: 50%; animation: pulse 2s infinite; }
/* Question count bar */
.q-count-bar {
margin: 0 1.5rem 1rem; padding: 0.65rem 1.2rem;
background: linear-gradient(135deg, var(--neon-blue), var(--neon-purple));
border-radius: 12px; display: flex; align-items: center; justify-content: center; gap: 0.5rem;
box-shadow: 0 8px 20px rgba(96,165,250,0.2);
}
.q-count-bar i { font-size: 1rem; color: rgba(255,255,255,0.85); }
.q-count-num { font-size: 1.2rem; font-weight: 800; color: #fff; }
.q-count-label { font-size: 0.75rem; font-weight: 500; color: rgba(255,255,255,0.85); }
/* Preview */
.q-preview {
margin: 0 1.5rem 0.75rem; background: rgba(255,255,255,0.02);
border: 1px solid rgba(255,255,255,0.08); border-radius: 12px; padding: 0.85rem;
}
.q-preview-head { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; }
.q-preview-icon {
width: 22px; height: 22px; border-radius: 6px;
background: linear-gradient(135deg, var(--neon-cyan), var(--neon-blue));
display: flex; align-items: center; justify-content: center;
font-size: 0.6rem; color: white;
}
.q-preview-title { font-family: var(--font-mono); font-size: 0.65rem; font-weight: 600; letter-spacing: 0.08em; color: var(--dark-300); }
.q-preview-question {
background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.08);
border-radius: 8px; padding: 0.6rem 0.75rem; margin-bottom: 0.35rem;
}
.q-badge {
padding: 0.18rem 0.55rem; border-radius: 6px; font-size: 0.65rem;
font-weight: 600; display: inline-block; border: 1px solid;
}
.q-badge.question { background: rgba(96,165,250,0.2); border-color: var(--neon-blue); color: var(--neon-blue); }
.q-badge.type { background: rgba(34,211,238,0.2); border-color: var(--neon-cyan); color: var(--neon-cyan); margin-left: 0.3rem; }
.q-answers { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.5rem; }
.q-answer-tag {
background: rgba(52,211,153,0.15); border: 1px solid rgba(52,211,153,0.35);
color: var(--neon-green); padding: 0.15rem 0.5rem; border-radius: 6px;
font-size: 0.6rem; font-weight: 500;
}
.q-preview-more {
text-align: center; padding: 0.4rem; font-size: 0.7rem; color: var(--dark-400);
font-style: italic; border: 1px dashed rgba(255,255,255,0.1); border-radius: 6px;
}
.q-preview-empty { font-size: 0.7rem; color: var(--dark-500); font-style: italic; display: flex; align-items: center; gap: 0.3rem; }
/* Actions */
.q-actions { padding: 1.25rem 1.5rem; display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.5rem; }
.q-act {
padding: 0.55rem 0.8rem; border-radius: 10px;
font-family: var(--font-mono); font-weight: 600; font-size: 0.65rem;
letter-spacing: 0.05em; text-decoration: none;
display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
transition: all 0.25s ease; border: 1px solid; cursor: pointer;
background: transparent; position: relative; overflow: hidden;
}
.q-act::before {
content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.08), transparent);
transition: left 0.4s;
}
.q-act:hover::before { left: 100%; }
.q-act:hover { transform: translateY(-2px); text-decoration: none; }
.q-act.details { border-color: rgba(34,211,238,0.4); color: var(--neon-cyan); }
.q-act.details:hover { background: rgba(34,211,238,0.1); color: var(--neon-cyan); }
.q-act.edit { border-color: rgba(96,165,250,0.4); color: var(--neon-blue); }
.q-act.edit:hover { background: rgba(96,165,250,0.1); color: var(--neon-blue); }
.q-act.send { border-color: rgba(52,211,153,0.4); color: var(--neon-green); }
.q-act.send:hover { background: rgba(52,211,153,0.1); color: var(--neon-green); }
.q-act.delete { border-color: rgba(248,113,113,0.4); color: var(--neon-red); }
.q-act.delete:hover { background: rgba(248,113,113,0.1); color: var(--neon-red); }
.q-act.publish { border-color: rgba(52,211,153,0.4); color: var(--neon-green); }
.q-act.publish:hover { background: rgba(52,211,153,0.1); color: var(--neon-green); }
.q-act.archive { border-color: rgba(100,116,139,0.4); color: var(--dark-300); }
.q-act.archive:hover { background: rgba(100,116,139,0.1); }
.q-act.revert { border-color: rgba(251,191,36,0.4); color: var(--neon-yellow); }
.q-act.revert:hover { background: rgba(251,191,36,0.1); color: var(--neon-yellow); }
.q-act.logic {
grid-column: 1 / -1; border-color: rgba(192,132,252,0.4); color: var(--neon-purple);
background: linear-gradient(135deg, rgba(192,132,252,0.08), rgba(96,165,250,0.08));
}
.q-act.logic:hover { background: linear-gradient(135deg, rgba(192,132,252,0.15), rgba(96,165,250,0.15)); }
.q-act.disabled { border-color: rgba(100,116,139,0.2); color: var(--dark-500); cursor: not-allowed; opacity: 0.5; }
.q-act.disabled:hover { transform: none; background: transparent; }
.q-act.disabled::before { display: none; }
.q-edit-note {
text-align: center; padding: 0.35rem 1rem; font-size: 0.6rem;
font-family: var(--font-mono); color: var(--neon-yellow);
background: rgba(251,191,36,0.05); letter-spacing: 0.03em;
}
/* ===== ALERTS ===== */
.alert-nxg {
display: flex; align-items: center; gap: 1rem;
padding: 1rem 1.5rem; border-radius: 12px; margin-bottom: 1rem;
backdrop-filter: blur(10px); position: relative; overflow: hidden;
}
.alert-stripe { position: absolute; left: 0; top: 0; bottom: 0; width: 4px; }
.alert-nxg.success { background: rgba(52,211,153,0.1); border: 1px solid rgba(52,211,153,0.3); }
.alert-nxg.success .alert-stripe { background: var(--neon-green); }
.alert-nxg.error { background: rgba(248,113,113,0.1); border: 1px solid rgba(248,113,113,0.3); }
.alert-nxg.error .alert-stripe { background: var(--neon-red); }
.alert-nxg.warning { background: rgba(251,191,36,0.1); border: 1px solid rgba(251,191,36,0.3); }
.alert-nxg.warning .alert-stripe { background: var(--neon-yellow); }
.alert-nxg .alert-icon { font-size: 1.1rem; }
.alert-nxg.success .alert-icon { color: var(--neon-green); }
.alert-nxg.error .alert-icon { color: var(--neon-red); }
.alert-nxg.warning .alert-icon { color: var(--neon-yellow); }
.alert-label { font-family: var(--font-mono); font-size: 0.65rem; font-weight: 700; letter-spacing: 0.1em; color: var(--dark-300); margin-bottom: 0.15rem; }
.alert-text { font-size: 0.85rem; color: var(--dark-300); }
.alert-dismiss { background: none; border: none; color: var(--dark-400); cursor: pointer; margin-left: auto; padding: 0.5rem; border-radius: 6px; transition: background 0.2s ease; }
.alert-dismiss:hover { background: rgba(255,255,255,0.1); }
/* ===== MODAL ===== */
.cm-overlay {
position: fixed; inset: 0; background: rgba(15,23,42,0.8); backdrop-filter: blur(12px);
z-index: 1000; display: flex; align-items: center; justify-content: center;
opacity: 0; visibility: hidden; transition: all 0.3s ease;
}
.cm-overlay.show { opacity: 1; visibility: visible; }
.cm-modal {
background: rgba(15,23,42,0.95); backdrop-filter: blur(20px);
border: 1px solid rgba(96,165,250,0.2); border-radius: 20px;
box-shadow: 0 25px 50px rgba(0,0,0,0.5); max-width: 460px; width: 90%;
overflow: hidden; transform: translateY(20px) scale(0.95);
transition: all 0.3s cubic-bezier(0.4,0,0.2,1);
}
.cm-overlay.show .cm-modal { transform: translateY(0) scale(1); }
.cm-head {
position: relative; padding: 2rem 2rem 1.25rem; text-align: center;
background: linear-gradient(135deg, rgba(96,165,250,0.1), rgba(192,132,252,0.1));
}
.cm-icon {
width: 64px; height: 64px; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: 1.4rem; margin: 0 auto 1rem; color: white; position: relative;
}
.cm-icon::after { content: ''; position: absolute; inset: -4px; border-radius: 50%; z-index: -1; opacity: 0.25; }
.cm-icon.publish { background: linear-gradient(135deg, var(--neon-green), #059669); box-shadow: 0 12px 28px rgba(52,211,153,0.35); }
.cm-icon.publish::after { background: var(--neon-green); }
.cm-icon.archive { background: linear-gradient(135deg, var(--dark-600), var(--dark-700)); box-shadow: 0 12px 28px rgba(71,85,105,0.35); }
.cm-icon.archive::after { background: var(--dark-500); }
.cm-icon.revert { background: linear-gradient(135deg, var(--neon-yellow), #d97706); box-shadow: 0 12px 28px rgba(245,158,11,0.35); }
.cm-icon.revert::after { background: var(--neon-yellow); }
.cm-title { font-size: 1.25rem; font-weight: 700; color: #ffffff; margin: 0 0 0.25rem; }
.cm-sub { color: var(--dark-400); font-size: 0.8rem; }
.cm-body { padding: 1rem 2rem 1.25rem; }
.cm-qinfo {
background: linear-gradient(135deg, rgba(96,165,250,0.15), rgba(192,132,252,0.15));
border: 1px solid rgba(96,165,250,0.2); color: white;
padding: 0.75rem 1rem; border-radius: 12px; text-align: center; margin-bottom: 0.75rem;
}
.cm-qinfo .title { font-size: 0.9rem; font-weight: 700; }
.cm-qinfo .meta { font-size: 0.7rem; color: var(--dark-300); margin-top: 2px; }
.cm-desc {
background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.08);
border-radius: 12px; padding: 0.85rem 1rem;
}
.cm-desc h4 { font-size: 0.75rem; font-weight: 700; color: var(--dark-300); margin: 0 0 0.5rem; display: flex; align-items: center; gap: 0.35rem; }
.cm-desc ul { margin: 0; padding-left: 1rem; }
.cm-desc li { margin-bottom: 0.25rem; font-size: 0.72rem; line-height: 1.5; color: var(--dark-400); }
.cm-footer {
display: flex; gap: 0.75rem; padding: 1.25rem 2rem;
background: rgba(30,41,59,0.6); border-top: 1px solid rgba(255,255,255,0.08);
}
.cm-btn {
flex: 1; padding: 0.7rem 1rem; border-radius: 10px;
font-family: var(--font-mono); font-weight: 600; font-size: 0.75rem;
letter-spacing: 0.05em; cursor: pointer; transition: all 0.25s ease;
display: flex; align-items: center; justify-content: center; gap: 0.4rem;
}
.cm-btn:hover { transform: translateY(-2px); }
.cm-btn.cancel { background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.15); color: var(--dark-300); }
.cm-btn.cancel:hover { background: rgba(255,255,255,0.1); }
.cm-btn.confirm { border: none; color: white; }
.cm-btn.confirm.publish { background: linear-gradient(135deg, var(--neon-green), #059669); }
.cm-btn.confirm.archive { background: linear-gradient(135deg, var(--dark-600), var(--dark-700)); }
.cm-btn.confirm.revert { background: linear-gradient(135deg, var(--neon-yellow), #d97706); }
/* ===== EMPTY STATE ===== */
.empty-nxg {
grid-column: 1 / -1; text-align: center; padding: 4rem 2rem;
background: var(--glass-bg); backdrop-filter: blur(20px);
border: 1px solid var(--glass-border); border-radius: 20px;
}
.empty-icon-wrap {
width: 90px; height: 90px; border-radius: 50%;
background: rgba(100,116,139,0.1); display: flex; align-items: center; justify-content: center;
font-size: 2.2rem; color: var(--dark-400); margin: 0 auto 1.5rem; position: relative;
}
.empty-ring { position: absolute; border: 1px solid; border-radius: 50%; opacity: 0.3; }
.empty-ring.r1 { width: 110px; height: 110px; top: -10px; left: -10px; border-color: var(--neon-blue); animation: ringPulse 3s infinite; }
.empty-ring.r2 { width: 130px; height: 130px; top: -20px; left: -20px; border-color: var(--neon-purple); animation: ringPulse 3s infinite 1s; }
.empty-nxg h3 { font-family: var(--font-mono); font-size: 1.2rem; font-weight: 700; letter-spacing: 0.05em; color: #ffffff; margin-bottom: 0.6rem; }
.empty-nxg p { color: var(--dark-300); font-size: 0.9rem; margin-bottom: 1.5rem; }
.create-btn {
display: inline-flex; align-items: center; gap: 0.6rem;
padding: 0.85rem 1.8rem; background: linear-gradient(135deg, var(--neon-green), var(--neon-cyan));
color: white; text-decoration: none; border-radius: 12px;
font-family: var(--font-mono); font-size: 0.75rem; font-weight: 700; letter-spacing: 0.05em;
transition: all 0.3s ease;
}
.create-btn:hover { transform: translateY(-2px); box-shadow: 0 15px 30px rgba(52,211,153,0.3); color: white; }
/* ===== BANNER ACTIONS ===== */
.banner-actions {
display: flex; gap: 0.75rem; justify-content: center; margin-bottom: 2.5rem;
position: relative; z-index: 10;
}
.banner-btn {
display: inline-flex; align-items: center; gap: 0.5rem;
padding: 0.6rem 1.3rem; border-radius: 10px;
font-size: 0.8rem; font-weight: 600; text-decoration: none;
transition: all 0.25s ease; border: 1px solid;
}
.banner-btn:hover { transform: translateY(-2px); text-decoration: none; }
.banner-btn.green { background: rgba(52,211,153,0.15); border-color: rgba(52,211,153,0.4); color: var(--neon-green); }
.banner-btn.green:hover { background: rgba(52,211,153,0.25); color: var(--neon-green); }
.banner-btn.info { background: rgba(96,165,250,0.1); border-color: rgba(96,165,250,0.3); color: var(--neon-blue); }
.banner-btn.info:hover { background: rgba(96,165,250,0.2); color: var(--neon-blue); }
/* Animations */
@@keyframes gridMove { 0% { transform: translate(0,0); } 100% { transform: translate(60px,60px); } }
@@keyframes meshShift { 0%,100% { filter: hue-rotate(0deg); transform: scale(1); } 50% { filter: hue-rotate(30deg); transform: scale(1.05); } }
@@keyframes pulse { 0%,100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.7; transform: scale(1.1); } }
@@keyframes ringPulse { 0% { transform: scale(1); opacity: 0.3; } 50% { transform: scale(1.1); opacity: 0.1; } 100% { transform: scale(1); opacity: 0.3; } }
@@media (max-width: 1024px) { .cards-grid { grid-template-columns: 1fr; } .stats-strip { grid-template-columns: repeat(3, 1fr); } }
@@media (max-width: 768px) {
.hero-title { font-size: 2.5rem; }
.cards-grid { grid-template-columns: 1fr; }
.stats-strip { grid-template-columns: repeat(2, 1fr); }
.q-metrics { grid-template-columns: 1fr; }
.q-actions { grid-template-columns: 1fr; }
.q-act.logic { grid-column: 1; }
.cm-modal { width: 95%; }
.cm-footer { flex-direction: column; }
.banner-actions { flex-direction: column; align-items: center; }
}
@@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }
</style>
}
<div class="nxg-page">
<!-- Animated Background -->
<div class="bg-pattern">
<div class="grid-overlay"></div>
<div class="gradient-mesh"></div>
</div>
<!-- Hero Section -->
<section class="hero-section">
<div class="container">
<div class="hero-badge"><span class="badge-dot"></span><span>QUESTIONNAIRE MANAGEMENT</span></div>
<h1 class="hero-title">Survey <span class="title-gradient">Builder</span> Hub</h1>
<p class="hero-desc">Create, deploy, and manage your workplace wellness questionnaires with advanced question types and conditional logic.</p>
</div>
</section>
<!-- Action Buttons -->
<div class="banner-actions">
<a asp-action="Create" class="banner-btn green"><i class="fa-solid fa-plus"></i> Create New</a>
<a asp-action="StatusGuide" class="banner-btn info" target="_blank"><i class="fa-solid fa-circle-info"></i> Status Guide</a>
</div>
<main class="container" style="padding-bottom:4rem;">
<partial name="_Notification" />
@if (TempData["Success"] != null)
{ <div class="alert-nxg success"><div class="alert-stripe"></div><div class="alert-icon"><i class="fa-solid fa-check-circle"></i></div><div><div class="alert-label">SUCCESS</div><div class="alert-text">@TempData["Success"]</div></div><button class="alert-dismiss" onclick="this.parentElement.remove()"><i class="fa-solid fa-times"></i></button></div> }
@if (TempData["Error"] != null)
{ <div class="alert-nxg error"><div class="alert-stripe"></div><div class="alert-icon"><i class="fa-solid fa-triangle-exclamation"></i></div><div><div class="alert-label">ERROR</div><div class="alert-text">@TempData["Error"]</div></div><button class="alert-dismiss" onclick="this.parentElement.remove()"><i class="fa-solid fa-times"></i></button></div> }
@if (TempData["Warning"] != null)
{ <div class="alert-nxg warning"><div class="alert-stripe"></div><div class="alert-icon"><i class="fa-solid fa-circle-exclamation"></i></div><div><div class="alert-label">ADVISORY</div><div class="alert-text">@TempData["Warning"]</div></div><button class="alert-dismiss" onclick="this.parentElement.remove()"><i class="fa-solid fa-times"></i></button></div> }
@if (Model.Any())
{
<!-- Stats -->
<div class="stats-strip">
<div class="stat-chip"><div class="stat-chip-icon"><i class="fa-solid fa-layer-group"></i></div><span class="stat-chip-num">@Model.Count()</span><span class="stat-chip-label">TOTAL</span></div>
<div class="stat-chip"><div class="stat-chip-icon"><i class="fa-solid fa-pen-ruler"></i></div><span class="stat-chip-num">@Model.Count(q => q.Status == QuestionnaireStatus.Draft)</span><span class="stat-chip-label">DRAFT</span></div>
<div class="stat-chip"><div class="stat-chip-icon"><i class="fa-solid fa-tower-broadcast"></i></div><span class="stat-chip-num">@Model.Count(q => q.Status == QuestionnaireStatus.Published)</span><span class="stat-chip-label">PUBLISHED</span></div>
<div class="stat-chip"><div class="stat-chip-icon"><i class="fa-solid fa-box-archive"></i></div><span class="stat-chip-num">@Model.Count(q => q.Status == QuestionnaireStatus.Archived)</span><span class="stat-chip-label">ARCHIVED</span></div>
<div class="stat-chip"><div class="stat-chip-icon"><i class="fa-solid fa-circle-question"></i></div><span class="stat-chip-num">@Model.Sum(q => q.ActiveQuestionCount)</span><span class="stat-chip-label">QUESTIONS</span></div>
<div class="stat-chip"><div class="stat-chip-icon"><i class="fa-solid fa-chart-column"></i></div><span class="stat-chip-num">@Model.Count(q => q.HasResponses)</span><span class="stat-chip-label">RESPONSES</span></div>
</div>
<!-- Section Header -->
<div class="section-header">
<h2>ACTIVE QUESTIONNAIRES</h2>
<div class="title-line"></div>
</div>
<!-- Cards Grid -->
<div class="cards-grid">
@foreach (var item in Model)
{
<div class="q-card">
<div class="card-glow"></div>
@switch (item.Status)
{
case QuestionnaireStatus.Draft:
<div class="q-status draft"><i class="fa-solid fa-pen" style="font-size:0.5rem;"></i> DRAFT</div>
break;
case QuestionnaireStatus.Published:
<div class="q-status published"><i class="fa-solid fa-signal" style="font-size:0.5rem;"></i> LIVE</div>
break;
case QuestionnaireStatus.Archived:
<div class="q-status archived"><i class="fa-solid fa-box-archive" style="font-size:0.5rem;"></i> ARCHIVED</div>
break;
}
<div class="q-card-head">
<span class="q-card-id">ID: @item.Id</span>
<h3 class="q-card-title">@item.Title</h3>
</div>
<div class="q-metrics">
<div class="q-metric">
<div class="q-metric-icon"><i class="fa-solid fa-calendar-days"></i></div>
<div><div class="q-metric-num">@item.CreatedDate.ToString("MMM dd")</div><div class="q-metric-label">CREATED</div></div>
</div>
<div class="q-metric">
<div class="q-metric-icon"><i class="fa-solid fa-list-ol"></i></div>
<div><div class="q-metric-num">@item.ActiveQuestionCount</div><div class="q-metric-label">QUESTIONS</div></div>
</div>
<div class="q-metric">
<div class="q-metric-icon"><i class="fa-solid fa-users"></i></div>
<div><div class="q-metric-num">@(item.HasResponses ? "Yes" : "—")</div><div class="q-metric-label">RESPONSES</div></div>
</div>
</div>
@if (item.PublishedDate.HasValue)
{ <div class="q-pub-date"><div class="q-pub-dot"></div> PUBLISHED: @item.PublishedDate.Value.ToString("MMM dd, yyyy")</div> }
<div class="q-count-bar">
<i class="fa-solid fa-clipboard-check"></i>
<span class="q-count-num">@(item.Questions?.Count ?? 0)</span>
<span class="q-count-label">Question@(item.Questions?.Count != 1 ? "s" : "")</span>
</div>
<div class="q-actions">
<a asp-action="Details" asp-route-id="@item.Id" class="q-act details"><i class="bi bi-eye-fill"></i> Details</a>
@switch (item.Status)
{
case QuestionnaireStatus.Draft:
<a asp-action="Edit" asp-route-id="@item.Id" class="q-act edit"><i class="bi bi-pencil-fill"></i> Edit</a>
@if (item.ActiveQuestionCount > 0)
{ <button type="button" class="q-act publish" onclick="showModal('publish','@item.Id','@Html.Raw(Html.Encode(item.Title))','@item.ActiveQuestionCount')"><i class="bi bi-broadcast"></i> Publish</button> }
else
{ <div class="q-act disabled"><i class="bi bi-broadcast"></i> Publish</div> }
<a asp-action="Delete" asp-route-id="@item.Id" class="q-act delete"><i class="bi bi-trash3-fill"></i> Delete</a>
<a asp-action="SetLogic" asp-route-id="@item.Id" class="q-act logic"><i class="bi bi-diagram-3-fill"></i> Set Logic</a>
break;
case QuestionnaireStatus.Published:
<a asp-action="Edit" asp-route-id="@item.Id" class="q-act edit"><i class="bi bi-pencil-square"></i> Edit*</a>
<a asp-action="SendQuestionnaire" asp-route-id="@item.Id" class="q-act send"><i class="bi bi-envelope-fill"></i> Send</a>
<button type="button" class="q-act archive" onclick="showModal('archive','@item.Id','@Html.Raw(Html.Encode(item.Title))','@item.ActiveQuestionCount',@item.HasResponses.ToString().ToLower())"><i class="bi bi-archive"></i> Archive</button>
<a asp-action="SetLogic" asp-route-id="@item.Id" class="q-act logic"><i class="bi bi-diagram-3-fill"></i> Set Logic</a>
break;
case QuestionnaireStatus.Archived:
<div class="q-act disabled"><i class="bi bi-lock"></i> Read Only</div>
@if (!item.HasResponses)
{ <button type="button" class="q-act revert" onclick="showModal('revert','@item.Id','@Html.Raw(Html.Encode(item.Title))','@item.ActiveQuestionCount')"><i class="bi bi-arrow-counterclockwise"></i> Revert</button> }
else
{ <div class="q-act disabled"><i class="bi bi-arrow-counterclockwise"></i> Revert</div> }
<div class="q-act disabled"><i class="bi bi-envelope"></i> Send</div>
<div class="q-act disabled"><i class="bi bi-diagram-3"></i> Logic</div>
break;
}
</div>
@if (item.Status == QuestionnaireStatus.Published)
{ <div class="q-edit-note"><i class="fa-solid fa-circle-info" style="font-size:0.5rem;margin-right:0.3rem;"></i> Limited editing — responses locked</div> }
</div>
}
</div>
}
else
{
<div class="cards-grid">
<div class="empty-nxg">
<div class="empty-icon-wrap">
<i class="fa-solid fa-clipboard-question"></i>
<div class="empty-ring r1"></div>
<div class="empty-ring r2"></div>
</div>
<h3>NO QUESTIONNAIRES FOUND</h3>
<p>Deploy your first questionnaire to begin collecting insights</p>
<a asp-action="Create" class="create-btn"><i class="fa-solid fa-plus"></i> CREATE QUESTIONNAIRE</a>
</div>
</div>
}
</main>
</div>
<!-- Modal -->
<div id="confirmModal" class="cm-overlay">
<div class="cm-modal">
<div class="cm-head">
<div class="cm-icon" id="cmIcon"><i id="cmIconSym" class="fa-solid"></i></div>
<h2 class="cm-title" id="cmTitle"></h2>
<p class="cm-sub" id="cmSub"></p>
</div>
<div class="cm-body">
<div class="cm-qinfo"><div class="title" id="cmQTitle"></div><div class="meta" id="cmQMeta"></div></div>
<div class="cm-desc"><h4 id="cmDescTitle"></h4><ul id="cmDescList"></ul></div>
</div>
<div class="cm-footer">
<button type="button" class="cm-btn cancel" id="cmCancel"><i class="bi bi-x-circle"></i> Cancel</button>
<button type="button" class="cm-btn confirm" id="cmConfirm"><i id="cmConfIcon" class="bi"></i> <span id="cmConfText"></span></button>
</div>
</div>
</div>
<form id="publishForm" asp-action="PublishQuestionnaire" method="post" style="display:none;"><input type="hidden" name="id" id="publishId" /></form>
<form id="archiveForm" asp-action="ArchiveQuestionnaire" method="post" style="display:none;"><input type="hidden" name="id" id="archiveId" /></form>
<form id="revertForm" asp-action="RevertToDraft" method="post" style="display:none;"><input type="hidden" name="id" id="revertId" /></form>
@section Scripts {
<script>
const modal = document.getElementById('confirmModal');
let curAction = '', curId = '';
const configs = {
publish: { icon: 'fa-tower-broadcast', cls: 'publish', title: 'Publish Questionnaire', sub: 'Make it live and collect responses', conf: 'Publish Now', confIcon: 'bi-broadcast', descTitle: 'What happens:', items: ['Questionnaire becomes accessible','Response collection begins','Editing becomes limited'] },
archive: { icon: 'fa-box-archive', cls: 'archive', title: 'Archive Questionnaire', sub: 'Stop collecting and preserve data', conf: 'Archive Now', confIcon: 'bi-archive', descTitle: 'What happens:', items: ['Stops accepting responses','All data preserved','Becomes read-only'] },
revert: { icon: 'fa-rotate-left', cls: 'revert', title: 'Revert to Draft', sub: 'Return to editing mode', conf: 'Revert to Draft', confIcon: 'bi-arrow-counterclockwise', descTitle: 'What happens:', items: ['Returns to draft status','Full editing restored','Must republish after'] }
};
function showModal(action, id, title, qCount, hasResp) {
curAction = action; curId = id;
const c = configs[action];
document.getElementById('cmIcon').className = 'cm-icon ' + c.cls;
document.getElementById('cmIconSym').className = 'fa-solid ' + c.icon;
document.getElementById('cmTitle').textContent = c.title;
document.getElementById('cmSub').textContent = c.sub;
document.getElementById('cmQTitle').textContent = title;
document.getElementById('cmQMeta').textContent = qCount + ' question' + (qCount !== '1' ? 's' : '') + (hasResp ? ' \u2022 Has responses' : '');
document.getElementById('cmDescTitle').innerHTML = '<i class="fa-solid fa-circle-info" style="color:var(--neon-blue);"></i> ' + c.descTitle;
document.getElementById('cmDescList').innerHTML = c.items.map(i => '<li>' + i + '</li>').join('');
document.getElementById('cmConfirm').className = 'cm-btn confirm ' + c.cls;
document.getElementById('cmConfIcon').className = 'bi ' + c.confIcon;
document.getElementById('cmConfText').textContent = c.conf;
modal.classList.add('show');
document.body.style.overflow = 'hidden';
}
function hideModal() { modal.classList.remove('show'); document.body.style.overflow = ''; }
document.getElementById('cmCancel').addEventListener('click', hideModal);
modal.addEventListener('click', e => { if (e.target === modal) hideModal(); });
document.addEventListener('keydown', e => { if (e.key === 'Escape' && modal.classList.contains('show')) hideModal(); });
modal.querySelector('.cm-modal').addEventListener('click', e => e.stopPropagation());
document.getElementById('cmConfirm').addEventListener('click', function () {
if (curAction === 'publish') { document.getElementById('publishId').value = curId; document.getElementById('publishForm').submit(); }
else if (curAction === 'archive') { document.getElementById('archiveId').value = curId; document.getElementById('archiveForm').submit(); }
else if (curAction === 'revert') { document.getElementById('revertId').value = curId; document.getElementById('revertForm').submit(); }
hideModal();
});
// Animate cards on scroll
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => { if (entry.isIntersecting) entry.target.classList.add('animate-in'); });
}, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' });
document.querySelectorAll('.q-card').forEach(card => observer.observe(card));
</script>
}