* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; background: linear-gradient(135deg, #2c3e50 0%, #34495e 50%, #1a252f 100%); min-height: 100vh; padding: 2rem; color: #ecf0f1; } .container { max-width: 1200px; margin: 0 auto; } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 2rem; padding: 1.5rem 0; border-bottom: 1px solid rgba(255, 255, 255, 0.05); } h1 { font-size: 2.5rem; margin: 0; font-weight: 700; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); } p { font-size: 1.2rem; opacity: 0.9; margin-bottom: 2rem; } .status { background: rgba(0, 0, 0, 0.4); padding: 0.75rem 1.5rem; border-radius: 25px; font-weight: 500; display: inline-block; margin: 0; font-size: 1rem; border: 1px solid rgba(255, 255, 255, 0.1); } .cluster-section { background: rgba(0, 0, 0, 0.3); border-radius: 20px; backdrop-filter: blur(10px); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); border: 1px solid rgba(255, 255, 255, 0.1); padding: 2rem; margin-bottom: 2rem; } .cluster-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; } .cluster-title { font-size: 1.5rem; font-weight: 600; } .refresh-btn { background: rgba(0, 0, 0, 0.4); border: 1px solid rgba(255, 255, 255, 0.2); color: #ecf0f1; padding: 0.5rem 1rem; border-radius: 8px; cursor: pointer; font-size: 0.9rem; transition: all 0.3s ease; } .refresh-btn:hover { background: rgba(0, 0, 0, 0.6); border-color: rgba(255, 255, 255, 0.3); transform: translateY(-2px); } .refresh-btn:active { transform: translateY(0); } .members-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1rem; } .member-card { background: rgba(0, 0, 0, 0.2); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 12px; padding: 1.5rem; transition: all 0.3s ease; cursor: pointer; position: relative; margin-bottom: 0.5rem; } .member-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(255, 255, 255, 0.08); border-radius: 12px; opacity: 0; transition: opacity 0.3s ease; pointer-events: none; } .member-card:hover::before { opacity: 1; } .member-card:hover { box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2); } .member-card.expanded { background: rgba(0, 0, 0, 0.6); border-color: rgba(255, 255, 255, 0.2); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6); transform: scale(1.02); } .member-card.expanded:hover { transform: none; } .member-card.expanded .expand-icon { transform: rotate(90deg); } .member-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 1rem; } .member-info { flex: 1; } .expand-icon { font-size: 1.2rem; opacity: 0.7; transition: transform 0.3s ease; } .member-details { display: none; opacity: 0; margin-top: 0; padding-top: 0; border-top: 1px solid transparent; transition: opacity 0.3s ease; } .member-card.expanded .member-details { display: block; opacity: 1; margin-top: 1rem; padding-top: 1rem; border-top: 1px solid rgba(255, 255, 255, 0.2); } .detail-row { display: flex; justify-content: space-between; margin-bottom: 0.5rem; font-size: 0.9rem; } .detail-label { opacity: 0.7; font-weight: 500; } .detail-value { font-family: 'Courier New', monospace; opacity: 0.9; } .api-endpoints { margin-top: 1rem; } .api-endpoints h4 { margin-bottom: 0.5rem; font-size: 0.9rem; opacity: 0.8; } .endpoint-item { background: rgba(0, 0, 0, 0.3); padding: 0.5rem; border-radius: 6px; margin-bottom: 0.5rem; font-size: 0.8rem; font-family: 'Courier New', monospace; border: 1px solid rgba(255, 255, 255, 0.05); } .loading-details { text-align: center; padding: 1rem; opacity: 0.7; font-size: 0.9rem; } .member-name { font-size: 1.2rem; font-weight: 600; margin-bottom: 0.5rem; color: #fff; } .member-ip { font-size: 0.9rem; opacity: 0.8; margin-bottom: 0.5rem; font-family: 'Courier New', monospace; } .member-status { display: inline-block; padding: 0.25rem 0.75rem; border-radius: 20px; font-size: 0.8rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; } .status-online { background: rgba(76, 175, 80, 0.3); color: #4caf50; border: 1px solid rgba(76, 175, 80, 0.5); } .status-offline { background: rgba(244, 67, 54, 0.3); color: #f44336; border: 1px solid rgba(244, 67, 54, 0.5); } .member-latency { font-size: 0.85rem; margin-top: 0.5rem; display: flex; align-items: center; gap: 0.5rem; } .latency-label { color: rgba(255, 255, 255, 0.7); font-weight: 500; } .latency-value { color: #ecf0f1; font-weight: 600; background: rgba(0, 0, 0, 0.3); padding: 0.2rem 0.5rem; border-radius: 4px; border: 1px solid rgba(255, 255, 255, 0.1); } /* Tab Styles */ .tabs-container { margin-top: 1rem; } .tabs-header { display: flex; border-bottom: 1px solid rgba(255, 255, 255, 0.1); margin-bottom: 1rem; gap: 0.5rem; } .tab-button { background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.7); padding: 0.5rem 1rem; border-radius: 8px 8px 0 0; cursor: pointer; font-size: 0.9rem; transition: all 0.3s ease; border-bottom: none; } .tab-button:hover { background: rgba(0, 0, 0, 0.5); color: rgba(255, 255, 255, 0.9); } .tab-button.active { background: rgba(255, 255, 255, 0.1); color: #ecf0f1; border-color: rgba(255, 255, 255, 0.2); } .tab-content { display: none; padding: 1rem 0; } .tab-content.active { display: block; } /* Task Styles */ .task-item { background: rgba(0, 0, 0, 0.2); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 8px; padding: 1rem; margin-bottom: 0.75rem; } .task-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; } .task-name { font-weight: 600; color: #ecf0f1; } .task-status { font-size: 0.85rem; padding: 0.25rem 0.5rem; border-radius: 4px; font-weight: 500; } .task-status.running { background: rgba(76, 175, 80, 0.2); color: #4caf50; border: 1px solid rgba(76, 175, 80, 0.3); } .task-status.stopped { background: rgba(244, 67, 54, 0.2); color: #f44336; border: 1px solid rgba(244, 67, 54, 0.3); } .task-details { display: flex; gap: 1rem; font-size: 0.8rem; opacity: 0.8; } .task-interval, .task-enabled { background: rgba(0, 0, 0, 0.2); padding: 0.2rem 0.5rem; border-radius: 4px; border: 1px solid rgba(255, 255, 255, 0.05); } /* Firmware Upload Styles */ .firmware-upload h4 { margin-bottom: 1rem; color: #ecf0f1; } .upload-area { text-align: center; padding: 2rem; border: 2px dashed rgba(255, 255, 255, 0.2); border-radius: 12px; background: rgba(0, 0, 0, 0.2); } .upload-btn { background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); color: #ecf0f1; padding: 0.75rem 1.5rem; border-radius: 8px; cursor: pointer; font-size: 1rem; transition: all 0.3s ease; margin-bottom: 1rem; } .upload-btn:hover { background: rgba(255, 255, 255, 0.2); transform: translateY(-2px); } .upload-info { font-size: 0.9rem; opacity: 0.7; color: rgba(255, 255, 255, 0.8); } .no-tasks { text-align: center; padding: 2rem; opacity: 0.7; } .loading-tasks { text-align: center; padding: 1rem; opacity: 0.7; font-style: italic; } .loading { text-align: center; padding: 2rem; opacity: 0.7; } .error { background: rgba(244, 67, 54, 0.2); border: 1px solid rgba(244, 67, 54, 0.3); color: #ffcdd2; padding: 1rem; border-radius: 8px; margin-top: 1rem; } .empty-state { text-align: center; padding: 2rem; opacity: 0.7; } .empty-state-icon { font-size: 3rem; margin-bottom: 1rem; opacity: 0.5; } /* Responsive design for smaller screens */ @media (max-width: 768px) { .header { flex-direction: column; gap: 1rem; text-align: center; } h1 { font-size: 2rem; } .status { padding: 0.5rem 1rem; font-size: 0.9rem; } }