:root { --bg: #f5f7fb; --card: #ffffff; --border: #e3e6ed; --text: #1f2937; --muted: #6b7280; --primary: #2563eb; --primary-dark: #1d4ed8; --success: #16a34a; --warn: #f59e0b; --danger: #dc2626; --off: #9ca3af; --radius: 8px; --shadow: 0 1px 2px rgba(0,0,0,0.04), 0 4px 12px rgba(0,0,0,0.04); } * { box-sizing: border-box; } body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif; background: var(--bg); color: var(--text); font-size: 14px; line-height: 1.55; } /* Nav */ .navbar { background: linear-gradient(135deg, #1e293b, #0f172a); color: #fff; padding: 0 24px; position: sticky; top: 0; z-index: 10; box-shadow: 0 2px 8px rgba(0,0,0,0.08); } .nav-inner { display: flex; align-items: center; max-width: 1280px; margin: 0 auto; gap: 24px; height: 56px; } .brand { font-size: 18px; font-weight: 600; color: #fff; text-decoration: none; letter-spacing: 0.3px; } .nav-links { list-style: none; display: flex; gap: 4px; margin: 0; padding: 0; flex: 1; } .nav-links a { display: block; padding: 8px 12px; color: #cbd5e1; text-decoration: none; border-radius: 6px; font-size: 14px; } .nav-links a:hover { color: #fff; background: rgba(255,255,255,0.08); } .nav-links a.active { color: #fff; background: rgba(255,255,255,0.12); } .nav-user { display: flex; align-items: center; gap: 12px; font-size: 13px; } .nav-user a { color: #cbd5e1; text-decoration: none; padding: 4px 8px; border-radius: 4px; } .nav-user a:hover { color: #fff; background: rgba(255,255,255,0.08); } .user-badge { display: inline-flex; align-items: center; gap: 6px; background: rgba(255,255,255,0.08); padding: 4px 10px; border-radius: 999px; font-weight: 500; } .container { max-width: 1280px; margin: 24px auto; padding: 0 24px; } h1 { font-size: 22px; margin: 0 0 20px; font-weight: 600; } h2 { font-size: 16px; margin: 24px 0 12px; font-weight: 600; } h1 + section, h2 + section, section + section { margin-top: 16px; } .page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; } .page-header h1 { margin: 0; } /* Buttons */ .btn { display: inline-block; padding: 6px 14px; background: #fff; border: 1px solid var(--border); border-radius: 6px; color: var(--text); font-size: 13px; text-decoration: none; cursor: pointer; transition: all 0.15s ease; } .btn:hover { background: #f9fafb; border-color: #d1d5db; } .btn-primary { background: var(--primary); color: #fff; border-color: var(--primary); } .btn-primary:hover { background: var(--primary-dark); border-color: var(--primary-dark); } .btn-warning { background: var(--warn); color: #fff; border-color: var(--warn); } .btn-warning:hover { background: #d97706; border-color: #d97706; } .link-btn { background: none; border: none; color: var(--primary); cursor: pointer; font-size: inherit; padding: 0; } .link-btn:hover { text-decoration: underline; } .link-btn.link-danger { color: var(--danger); } /* Tables */ .table { width: 100%; border-collapse: collapse; background: var(--card); border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow); } .table th, .table td { padding: 10px 14px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; } .table thead th { background: #f8fafc; font-weight: 600; font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.3px; } .table tbody tr:last-child td { border-bottom: none; } .table tbody tr:hover { background: #f9fafb; } .table code { font-size: 12px; background: #f1f5f9; padding: 1px 6px; border-radius: 3px; } .token-cell { font-family: ui-monospace, SFMono-Regular, "SF Mono", monospace; font-size: 11px !important; word-break: break-all; display: inline-block; max-width: 240px; } .actions { white-space: nowrap; } .actions form, .actions a { margin-right: 8px; } /* Cards & stats */ .stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; margin-bottom: 20px; } .stat-card { background: var(--card); border-radius: var(--radius); padding: 14px 18px; box-shadow: var(--shadow); border-left: 3px solid var(--primary); } .stat-label { color: var(--muted); font-size: 12px; } .stat-value { font-size: 20px; font-weight: 600; margin-top: 4px; } .actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; } /* Form */ .form-card { background: var(--card); padding: 24px; border-radius: var(--radius); box-shadow: var(--shadow); max-width: 720px; } .form-card label { display: block; margin-bottom: 12px; font-weight: 500; color: #374151; } .form-card input[type=text], .form-card input[type=password], .form-card input[type=number], .form-card input:not([type]), .form-card select, .form-card textarea { display: block; width: 100%; padding: 7px 10px; margin-top: 4px; border: 1px solid var(--border); border-radius: 6px; font-size: 14px; font-family: inherit; background: #fff; color: var(--text); } .form-card input:focus, .form-card select:focus, .form-card textarea:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(37,99,235,0.15); } .form-card input[disabled] { background: #f3f4f6; color: var(--muted); } .form-card label.checkbox { font-weight: normal; display: flex; align-items: center; gap: 6px; } .form-card label.checkbox input { width: auto; margin: 0; } .form-card fieldset { border: 1px solid var(--border); border-radius: 6px; padding: 12px 16px; margin: 16px 0; } .form-card fieldset legend { padding: 0 8px; color: var(--muted); font-size: 13px; font-weight: 600; } .form-actions { display: flex; gap: 8px; margin-top: 16px; } /* Badges & tags */ .badge { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: 11px; font-weight: 600; } .badge-ok { background: #dcfce7; color: #166534; } .badge-off { background: #f3f4f6; color: var(--off); } .tag { display: inline-block; padding: 1px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; text-transform: uppercase; } .tag-tcp { background: #dbeafe; color: #1e40af; } .tag-udp { background: #fef3c7; color: #92400e; } .tag-http { background: #dcfce7; color: #166534; } .tag-https { background: #f3e8ff; color: #6b21a8; } .tag-tcpmux { background: #fee2e2; color: #991b1b; } .role-tag { display: inline-block; padding: 1px 6px; border-radius: 3px; font-size: 10px; background: rgba(255,255,255,0.15); color: #e2e8f0; text-transform: uppercase; letter-spacing: 0.5px; } .role-admin { background: #fee2e2; color: #991b1b; } .role-tenant_admin { background: #fef3c7; color: #92400e; } .role-user { background: #dbeafe; color: #1e40af; } .action-tag { display: inline-block; padding: 1px 8px; border-radius: 4px; font-size: 11px; background: #f3f4f6; color: #374151; font-family: ui-monospace, monospace; } /* Flash messages */ .flash-area { margin-bottom: 16px; } .flash { padding: 10px 14px; border-radius: 6px; margin-bottom: 8px; border-left: 3px solid var(--primary); background: #eff6ff; color: #1e40af; } .flash-success { border-color: var(--success); background: #f0fdf4; color: #166534; } .flash-error { border-color: var(--danger); background: #fef2f2; color: #991b1b; } .alert { padding: 12px 16px; border-radius: 6px; margin: 12px 0; } .alert-error { background: #fef2f2; color: #991b1b; border-left: 3px solid var(--danger); } /* Login */ .login-card { max-width: 360px; margin: 80px auto; background: var(--card); padding: 32px; border-radius: var(--radius); box-shadow: var(--shadow); text-align: center; } .login-card h1 { margin: 0 0 4px; } .login-card form { text-align: left; margin-top: 20px; } .login-card form label { display: block; margin-bottom: 12px; } .login-card form input { display: block; width: 100%; padding: 8px 10px; margin-top: 4px; border: 1px solid var(--border); border-radius: 6px; font-size: 14px; } .login-card button { width: 100%; margin-top: 8px; } /* Misc */ .muted { color: var(--muted); } .muted.small { font-size: 12px; } .offline { color: var(--danger); font-weight: 600; } .filter-bar { display: flex; gap: 12px; margin-bottom: 12px; align-items: center; } .filter-bar label { display: flex; align-items: center; gap: 6px; font-size: 13px; } .filter-bar select { padding: 5px 8px; border: 1px solid var(--border); border-radius: 6px; font-size: 13px; } .pagination { display: flex; justify-content: center; gap: 12px; margin-top: 16px; align-items: center; font-size: 13px; } .pagination a { padding: 4px 10px; border: 1px solid var(--border); border-radius: 4px; color: var(--primary); text-decoration: none; background: #fff; } .error-card { text-align: center; padding: 60px 0; } .error-card h1 { font-size: 60px; color: var(--muted); margin: 0; } .footer { text-align: center; color: var(--muted); font-size: 12px; padding: 24px 0; }