/* CrowdSec SOC Dashboard - Minimal Professional Theme */ /* Version: 1.0.0 - SOC Compliant */ :root { --soc-bg: #0d1117; --soc-surface: #161b22; --soc-border: #30363d; --soc-text: #c9d1d9; --soc-text-muted: #8b949e; --soc-primary: #58a6ff; --soc-success: #3fb950; --soc-warning: #d29922; --soc-danger: #f85149; --soc-info: #79c0ff; } /* Hide LuCI sidebar for full-width SOC view */ body.cs-soc-fullwidth #maincontainer > .pull-left, body.cs-soc-fullwidth #mainmenu { display: none !important; } body.cs-soc-fullwidth #maincontent { margin: 0 !important; width: 100% !important; } .soc-dashboard { background: var(--soc-bg); min-height: 100vh; padding: 16px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, monospace; color: var(--soc-text); } /* Header */ .soc-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; padding-bottom: 16px; border-bottom: 1px solid var(--soc-border); } .soc-title { font-size: 20px; font-weight: 600; display: flex; align-items: center; gap: 12px; } .soc-title svg { width: 28px; height: 28px; fill: var(--soc-primary); } .soc-status { display: flex; align-items: center; gap: 8px; font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; } .soc-status-dot { width: 8px; height: 8px; border-radius: 50%; animation: pulse 2s infinite; } .soc-status-dot.online { background: var(--soc-success); } .soc-status-dot.offline { background: var(--soc-danger); animation: none; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } /* Stats Grid */ .soc-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin-bottom: 24px; } .soc-stat { background: var(--soc-surface); border: 1px solid var(--soc-border); border-radius: 6px; padding: 16px; text-align: center; } .soc-stat-value { font-size: 28px; font-weight: 700; font-family: 'JetBrains Mono', monospace; color: var(--soc-primary); } .soc-stat-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--soc-text-muted); margin-top: 4px; } .soc-stat.danger .soc-stat-value { color: var(--soc-danger); } .soc-stat.warning .soc-stat-value { color: var(--soc-warning); } .soc-stat.success .soc-stat-value { color: var(--soc-success); } /* Cards */ .soc-card { background: var(--soc-surface); border: 1px solid var(--soc-border); border-radius: 6px; margin-bottom: 16px; } .soc-card-header { padding: 12px 16px; border-bottom: 1px solid var(--soc-border); font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; display: flex; justify-content: space-between; align-items: center; } .soc-card-body { padding: 16px; } /* Tables */ .soc-table { width: 100%; border-collapse: collapse; font-size: 13px; } .soc-table th { text-align: left; padding: 8px 12px; background: var(--soc-bg); color: var(--soc-text-muted); font-weight: 500; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; border-bottom: 1px solid var(--soc-border); } .soc-table td { padding: 10px 12px; border-bottom: 1px solid var(--soc-border); vertical-align: middle; } .soc-table tr:last-child td { border-bottom: none; } .soc-table tr:hover { background: rgba(88, 166, 255, 0.05); } /* IP & Geo */ .soc-ip { font-family: 'JetBrains Mono', Consolas, monospace; font-size: 12px; background: var(--soc-bg); padding: 2px 6px; border-radius: 3px; } .soc-geo { display: flex; align-items: center; gap: 6px; } .soc-flag { font-size: 16px; } .soc-country { font-size: 11px; color: var(--soc-text-muted); } /* Severity Badges */ .soc-severity { display: inline-block; padding: 2px 8px; border-radius: 3px; font-size: 10px; font-weight: 600; text-transform: uppercase; } .soc-severity.critical { background: var(--soc-danger); color: #fff; } .soc-severity.high { background: #b62324; color: #fff; } .soc-severity.medium { background: var(--soc-warning); color: #000; } .soc-severity.low { background: var(--soc-info); color: #000; } /* Scenario Tags */ .soc-scenario { font-size: 11px; color: var(--soc-primary); background: rgba(88, 166, 255, 0.1); padding: 2px 6px; border-radius: 3px; } /* Time */ .soc-time { font-size: 11px; color: var(--soc-text-muted); font-family: monospace; } /* Actions */ .soc-btn { background: var(--soc-surface); border: 1px solid var(--soc-border); color: var(--soc-text); padding: 6px 12px; border-radius: 4px; font-size: 12px; cursor: pointer; transition: all 0.15s; } .soc-btn:hover { background: var(--soc-border); border-color: var(--soc-text-muted); } .soc-btn.primary { background: var(--soc-primary); border-color: var(--soc-primary); color: #000; } .soc-btn.danger { background: var(--soc-danger); border-color: var(--soc-danger); color: #fff; } .soc-btn-sm { padding: 3px 8px; font-size: 11px; } /* Geo Distribution */ .soc-geo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 8px; } .soc-geo-item { display: flex; align-items: center; gap: 8px; padding: 8px; background: var(--soc-bg); border-radius: 4px; } .soc-geo-count { font-weight: 600; font-family: monospace; min-width: 30px; } /* Empty State */ .soc-empty { text-align: center; padding: 40px; color: var(--soc-text-muted); } .soc-empty-icon { font-size: 32px; margin-bottom: 12px; opacity: 0.5; } /* Threat Types */ .soc-threat-types { } .soc-threat-icon { display: inline-block; width: 24px; height: 24px; line-height: 24px; text-align: center; border-radius: 4px; margin-right: 8px; font-size: 14px; } .soc-threat-icon.critical { background: rgba(248, 81, 73, 0.2); } .soc-threat-icon.high { background: rgba(182, 35, 36, 0.2); } .soc-threat-icon.medium { background: rgba(210, 153, 34, 0.2); } .soc-threat-icon.low { background: rgba(88, 166, 255, 0.2); } .soc-threat-count { font-weight: 600; font-family: 'JetBrains Mono', Consolas, monospace; color: var(--soc-danger); } .soc-bar-wrap { display: flex; align-items: center; gap: 8px; height: 20px; } .soc-bar { height: 8px; border-radius: 4px; min-width: 4px; transition: width 0.3s ease; } .soc-bar.critical { background: var(--soc-danger); } .soc-bar.high { background: #b62324; } .soc-bar.medium { background: var(--soc-warning); } .soc-bar.low { background: var(--soc-info); } .soc-bar-pct { font-size: 11px; color: var(--soc-text-muted); font-family: monospace; min-width: 35px; } .soc-threat-total { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--soc-border); text-align: right; font-size: 12px; color: var(--soc-text-muted); } /* Nav */ .soc-nav { display: flex; gap: 4px; margin-bottom: 20px; border-bottom: 1px solid var(--soc-border); padding-bottom: 12px; } .soc-nav a { color: var(--soc-text-muted); text-decoration: none; padding: 8px 16px; border-radius: 4px; font-size: 13px; transition: all 0.15s; } .soc-nav a:hover { color: var(--soc-text); background: var(--soc-surface); } .soc-nav a.active { color: var(--soc-primary); background: rgba(88, 166, 255, 0.1); } /* Health Check */ .soc-health { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; } .soc-health-item { display: flex; align-items: center; gap: 12px; padding: 12px; background: var(--soc-bg); border-radius: 4px; } .soc-health-icon { width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 14px; } .soc-health-icon.ok { background: rgba(63, 185, 80, 0.2); color: var(--soc-success); } .soc-health-icon.error { background: rgba(248, 81, 73, 0.2); color: var(--soc-danger); } .soc-health-icon.warn { background: rgba(210, 153, 34, 0.2); color: var(--soc-warning); } .soc-health-label { font-size: 12px; color: var(--soc-text-muted); } .soc-health-value { font-size: 13px; font-weight: 500; } /* Two Column Layout */ .soc-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } @media (max-width: 900px) { .soc-grid-2 { grid-template-columns: 1fr; } } /* Loading */ .soc-loading { display: flex; align-items: center; justify-content: center; padding: 40px; color: var(--soc-text-muted); } .soc-spinner { width: 20px; height: 20px; border: 2px solid var(--soc-border); border-top-color: var(--soc-primary); border-radius: 50%; animation: spin 0.8s linear infinite; margin-right: 12px; } @keyframes spin { to { transform: rotate(360deg); } } /* Toast */ .soc-toast { position: fixed; bottom: 20px; right: 20px; background: var(--soc-surface); border: 1px solid var(--soc-border); padding: 12px 20px; border-radius: 6px; font-size: 13px; z-index: 9999; animation: slideIn 0.3s ease; } .soc-toast.success { border-left: 3px solid var(--soc-success); } .soc-toast.error { border-left: 3px solid var(--soc-danger); } @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }