/** * INTERCEPT UI Components * Reusable component styles for buttons, cards, badges, etc. * Requires: variables.css and base.css */ /* ============================================ BUTTONS ============================================ */ /* Base button */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); padding: var(--space-2) var(--space-4); font-size: var(--text-sm); font-weight: var(--font-medium); border-radius: var(--radius-md); border: 1px solid transparent; cursor: pointer; transition: all var(--transition-fast); white-space: nowrap; text-decoration: none; font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 0.06em; } .btn:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 2px; } .btn:disabled { opacity: 0.5; cursor: not-allowed; } /* Button variants */ .btn-primary { background: var(--accent-cyan); color: var(--text-inverse); border-color: var(--accent-cyan); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08); } .btn-primary:hover:not(:disabled) { background: var(--accent-cyan-hover); border-color: var(--accent-cyan-hover); } .btn-secondary { background: var(--bg-secondary); color: var(--text-primary); border-color: var(--border-color); } .btn-secondary:hover:not(:disabled) { background: var(--bg-tertiary); border-color: var(--border-light); } .btn-ghost { background: transparent; color: var(--text-secondary); border-color: var(--border-color); } .btn-ghost:hover:not(:disabled) { background: var(--bg-elevated); color: var(--text-primary); } .btn-danger { background: var(--accent-red); color: var(--text-inverse); border-color: var(--accent-red); } .btn-danger:hover:not(:disabled) { background: #dc2626; border-color: #dc2626; } .btn-success { background: var(--accent-green); color: var(--text-inverse); border-color: var(--accent-green); } .btn-success:hover:not(:disabled) { background: #16a34a; border-color: #16a34a; } /* Button sizes */ .btn-sm { padding: var(--space-1) var(--space-2); font-size: var(--text-xs); } .btn-lg { padding: var(--space-3) var(--space-6); font-size: var(--text-base); } /* Icon button */ .btn-icon { padding: var(--space-2); width: 36px; height: 36px; } .btn-icon.btn-sm { width: 28px; height: 28px; padding: var(--space-1); } /* ============================================ CARDS / PANELS ============================================ */ .card { background: var(--surface-panel-gradient); border: 1px solid rgba(74, 163, 255, 0.24); border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255, 255, 255, 0.04); backdrop-filter: blur(5px); } .card-header { display: flex; align-items: center; justify-content: space-between; padding: var(--space-3) var(--space-4); border-bottom: 1px solid rgba(74, 163, 255, 0.18); background: linear-gradient(180deg, rgba(25, 38, 55, 0.88) 0%, rgba(17, 27, 40, 0.9) 100%); position: relative; } .card-header-title { font-size: var(--text-xs); font-weight: var(--font-semibold); text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-secondary); } .card-body { padding: var(--space-4); } .card-footer { padding: var(--space-3) var(--space-4); border-top: 1px solid var(--border-color); background: var(--bg-secondary); } /* Panel variant (used in dashboards) */ .panel { background: var(--surface-panel-gradient); border: 1px solid rgba(74, 163, 255, 0.24); border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255, 255, 255, 0.04); backdrop-filter: blur(5px); } @supports (clip-path: polygon(0 0)) { .card, .panel { --notch-size: 6px; border-radius: 0; clip-path: polygon( var(--notch-size) 0, calc(100% - var(--notch-size)) 0, 100% var(--notch-size), 100% calc(100% - var(--notch-size)), calc(100% - var(--notch-size)) 100%, var(--notch-size) 100%, 0 calc(100% - var(--notch-size)), 0 var(--notch-size) ); } } .panel-header { display: flex; align-items: center; justify-content: space-between; padding: var(--space-2) var(--space-3); border-bottom: 1px solid rgba(74, 163, 255, 0.18); background: linear-gradient(180deg, rgba(25, 38, 55, 0.88) 0%, rgba(17, 27, 40, 0.9) 100%); font-size: var(--text-xs); font-weight: var(--font-semibold); text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-secondary); position: relative; } .card-header::before, .panel-header::before { content: ''; position: absolute; top: 0; left: var(--space-3); width: 36px; height: 2px; background: var(--accent-cyan); opacity: 0.7; } .panel-indicator { width: 8px; height: 8px; border-radius: var(--radius-full); background: var(--status-offline); } .panel-indicator.active { background: var(--status-online); box-shadow: 0 0 8px var(--status-online); } .panel-content { padding: var(--space-3); } /* ============================================ BADGES ============================================ */ .badge { display: inline-flex; align-items: center; gap: var(--space-1); padding: 2px var(--space-2); font-size: var(--text-xs); font-weight: var(--font-medium); border-radius: var(--radius-full); background: var(--bg-tertiary); color: var(--text-secondary); border: 1px solid var(--border-color); } .badge-primary { background: var(--accent-cyan-dim); color: var(--accent-cyan); } .badge-success { background: var(--accent-green-dim); color: var(--accent-green); } .badge-warning { background: var(--accent-orange-dim); color: var(--accent-orange); } .badge-danger { background: var(--accent-red-dim); color: var(--accent-red); } /* ============================================ DATA TAGS ============================================ */ .data-tag { display: inline-flex; align-items: center; gap: var(--space-1); padding: 2px var(--space-2); font-size: 10px; font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 0.12em; border-radius: var(--radius-sm); border: 1px solid var(--border-color); background: var(--bg-tertiary); color: var(--text-secondary); box-shadow: inset 0 0 0 1px var(--border-glow); } .data-tag--accent { border-color: var(--accent-cyan); color: var(--accent-cyan); background: var(--accent-cyan-dim); } .data-tag--warning { border-color: var(--accent-amber); color: var(--accent-amber); background: var(--accent-amber-dim); } .data-tag--success { border-color: var(--accent-green); color: var(--accent-green); background: var(--accent-green-dim); } .data-tag--danger { border-color: var(--accent-red); color: var(--accent-red); background: var(--accent-red-dim); } /* ============================================ STATUS INDICATORS ============================================ */ .status-dot { width: 8px; height: 8px; border-radius: var(--radius-full); background: var(--status-offline); flex-shrink: 0; } .status-dot.online, .status-dot.active { background: var(--status-online); box-shadow: 0 0 4px var(--status-online); } .status-dot.warning { background: var(--status-warning); box-shadow: 0 0 4px var(--status-warning); } .status-dot.error, .status-dot.offline { background: var(--status-error); } .status-dot.inactive { background: var(--status-offline); } /* Pulse animation for active status */ .status-dot.pulse { animation: statusPulse 2s ease-in-out infinite; } @keyframes statusPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } /* ============================================ EMPTY STATE ============================================ */ .empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: var(--space-8) var(--space-4); text-align: center; color: var(--text-muted); } .empty-state-icon { width: 48px; height: 48px; margin-bottom: var(--space-4); opacity: 0.5; } .empty-state-title { font-size: var(--text-base); font-weight: var(--font-medium); color: var(--text-secondary); margin-bottom: var(--space-2); } .empty-state-description { font-size: var(--text-sm); color: var(--text-dim); max-width: 300px; } .empty-state-action { margin-top: var(--space-4); } /* ============================================ LOADING STATES ============================================ */ .spinner { width: 20px; height: 20px; border: 2px solid var(--border-color); border-top-color: var(--accent-cyan); border-radius: var(--radius-full); animation: spin 0.8s linear infinite; } .spinner-sm { width: 14px; height: 14px; border-width: 2px; } .spinner-lg { width: 32px; height: 32px; border-width: 3px; } @keyframes spin { to { transform: rotate(360deg); } } /* Loading overlay */ .loading-overlay { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: var(--bg-overlay); z-index: var(--z-modal); } /* Skeleton loader */ .skeleton { background: linear-gradient( 90deg, var(--bg-tertiary) 25%, var(--bg-elevated) 50%, var(--bg-tertiary) 75% ); background-size: 200% 100%; animation: shimmer 1.5s infinite; border-radius: var(--radius-sm); } @keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } /* ============================================ STATS STRIP ============================================ */ .stats-strip { display: flex; align-items: center; background: var(--bg-secondary); border-bottom: 1px solid var(--border-color); padding: 0 var(--space-4); height: var(--stats-strip-height); overflow-x: auto; gap: var(--space-1); } .strip-stat { display: flex; flex-direction: column; align-items: center; padding: 0 var(--space-3); min-width: fit-content; } .strip-value { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--accent-cyan); line-height: 1; } .strip-label { font-size: 9px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.05em; line-height: 1; margin-top: 2px; } .strip-divider { width: 1px; height: 20px; background: var(--border-color); margin: 0 var(--space-2); } /* ============================================ FORM GROUPS ============================================ */ .form-group { margin-bottom: var(--space-4); } .form-group label { display: block; margin-bottom: var(--space-1); font-size: var(--text-sm); font-weight: var(--font-medium); color: var(--text-secondary); } .form-group input, .form-group select, .form-group textarea { width: 100%; } .form-help { margin-top: var(--space-1); font-size: var(--text-xs); color: var(--text-dim); } .form-error { margin-top: var(--space-1); font-size: var(--text-xs); color: var(--accent-red); } /* Inline checkbox/radio */ .form-check { display: flex; align-items: center; gap: var(--space-2); cursor: pointer; } .form-check input { width: auto; } .form-check label { margin-bottom: 0; cursor: pointer; } /* ============================================ ALERTS / TOASTS ============================================ */ .alert { display: flex; align-items: flex-start; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); border: 1px solid; font-size: var(--text-sm); } .alert-info { background: var(--accent-cyan-dim); border-color: var(--accent-cyan); color: var(--accent-cyan); } .alert-success { background: var(--accent-green-dim); border-color: var(--accent-green); color: var(--accent-green); } .alert-warning { background: var(--accent-orange-dim); border-color: var(--accent-orange); color: var(--accent-orange); } .alert-danger { background: var(--accent-red-dim); border-color: var(--accent-red); color: var(--accent-red); } /* ============================================ TOOLTIPS ============================================ */ [data-tooltip] { position: relative; } [data-tooltip]::after { content: attr(data-tooltip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); padding: var(--space-1) var(--space-2); background: var(--bg-elevated); color: var(--text-primary); font-size: var(--text-xs); border-radius: var(--radius-sm); white-space: nowrap; opacity: 0; visibility: hidden; transition: opacity var(--transition-fast), visibility var(--transition-fast); z-index: var(--z-tooltip); pointer-events: none; margin-bottom: var(--space-1); box-shadow: var(--shadow-md); } [data-tooltip]:hover::after { opacity: 1; visibility: visible; } /* ============================================ ICONS ============================================ */ .icon { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; flex-shrink: 0; } .icon svg { width: 100%; height: 100%; } .icon--sm { width: 16px; height: 16px; } .icon--lg { width: 24px; height: 24px; } /* ============================================ SECTION HEADERS ============================================ */ .section-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-4); padding-bottom: var(--space-2); border-bottom: 1px solid var(--border-color); } .section-title { font-size: var(--text-sm); font-weight: var(--font-semibold); text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-secondary); position: relative; padding-left: var(--space-3); } .section-title::before { content: ''; position: absolute; left: 0; top: 50%; width: 2px; height: 6px; background: var(--accent-cyan); transform: translateY(-50%); opacity: 0.7; box-shadow: 0 6px 0 var(--accent-cyan); } /* ============================================ DIVIDERS ============================================ */ .divider { height: 1px; background-image: repeating-linear-gradient( 90deg, var(--border-light), var(--border-light) 6px, transparent 6px, transparent 12px ); margin: var(--space-4) 0; } .divider-vertical { width: 1px; height: 100%; background-image: repeating-linear-gradient( 180deg, var(--border-light), var(--border-light) 6px, transparent 6px, transparent 12px ); margin: 0 var(--space-3); } /* ============================================ UX POLISH - ENHANCED INTERACTIONS ============================================ */ /* Button hover lift */ .btn:hover:not(:disabled) { box-shadow: 0 0 0 1px var(--border-light); } .btn:active:not(:disabled) { box-shadow: inset 0 0 0 1px var(--border-light); } /* Card/Panel hover effects */ .card, .panel { transition: box-shadow var(--transition-base), border-color var(--transition-base), transform var(--transition-base); } .card:hover, .panel:hover { border-color: var(--border-glow); box-shadow: var(--shadow-md), var(--shadow-glow), inset 0 1px 0 rgba(255, 255, 255, 0.06); transform: translateY(-1px); } [data-theme="light"] .card, [data-theme="light"] .panel { border-color: rgba(31, 95, 168, 0.24); } [data-theme="light"] .card-header, [data-theme="light"] .panel-header { border-bottom-color: rgba(31, 95, 168, 0.2); background: linear-gradient(180deg, rgba(243, 247, 252, 0.96) 0%, rgba(233, 239, 247, 0.95) 100%); } /* Stats strip value highlight on hover */ .strip-stat { transition: background-color var(--transition-fast); border-radius: var(--radius-sm); cursor: default; } .strip-stat:hover { background: var(--bg-tertiary); } /* Status dot pulse animation */ .status-dot.online, .status-dot.active { animation: statusGlow 2s ease-in-out infinite; } @keyframes statusGlow { 0%, 100% { box-shadow: 0 0 4px var(--status-online); } 50% { box-shadow: 0 0 8px var(--status-online), 0 0 12px var(--status-online); } } /* Badge hover effect */ .badge { transition: transform var(--transition-fast), box-shadow var(--transition-fast); } .badge:hover { transform: scale(1.02); } /* Alert entrance animation */ .alert { animation: alertSlideIn 0.3s ease-out; } @keyframes alertSlideIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } /* Loading spinner smooth appearance */ .spinner { animation: spin 0.8s linear infinite, fadeIn 0.3s ease-out; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } /* Input focus glow */ input:focus, select:focus, textarea:focus { border-color: var(--accent-cyan); box-shadow: 0 0 0 2px var(--accent-cyan-dim); } /* Nav item active indicator */ .nav-item, .mode-nav-btn, .mobile-nav-btn { position: relative; } .nav-item.active::after, .mode-nav-btn.active::after, .mobile-nav-btn.active::after { content: ''; position: absolute; left: 12%; right: 12%; bottom: 2px; height: 1px; background: linear-gradient(90deg, transparent, var(--accent-cyan), transparent); opacity: 0.75; animation: railPulse 2.6s ease-in-out infinite; } @keyframes railPulse { 0%, 100% { opacity: 0.45; } 50% { opacity: 0.9; } } /* Smooth tooltip appearance */ [data-tooltip]::after { transition: opacity var(--transition-fast), visibility var(--transition-fast), transform var(--transition-fast); transform: translateX(-50%) translateY(-4px); } [data-tooltip]:hover::after { transform: translateX(-50%) translateY(0); } /* Disabled state with better visual feedback */ :disabled, .disabled { opacity: 0.5; cursor: not-allowed; filter: grayscale(30%); }