:root { --bg: #eef1f6; --surface: #ffffff; --surface-muted: #f5f7fb; --line: #dfe5ee; --text: #5d6a7d; --heading: #33445b; --sidebar: #31435f; --sidebar-deep: #25354c; --sidebar-active: #1f90ff; --accent: #4ea0ff; --accent-strong: #3f97f7; --danger: #ff5e5e; --success: #3e9b61; } * { box-sizing: border-box; } html, body { margin: 0; padding: 0; font-family: "Segoe UI", "Malgun Gothic", sans-serif; background: var(--bg); color: var(--text); } a { text-decoration: none; color: inherit; } button, input, select, textarea { font: inherit; } .login-body { min-height: 100vh; background: radial-gradient(circle at top left, rgba(78,160,255,0.22), transparent 30%), linear-gradient(180deg, #1f2f45 0%, #2f4260 100%); } .login-shell { min-height: 100vh; display: grid; place-items: center; padding: 24px; } .login-panel { position: relative; width: min(440px, 100%); background: rgba(255,255,255,0.97); border: 1px solid rgba(223,229,238,0.9); border-radius: 18px; padding: 28px; box-shadow: 0 26px 70px rgba(16, 28, 44, 0.35); } .login-brand { display: flex; align-items: center; gap: 12px; margin-bottom: 22px; } .login-brand .brand-mark { background: #25354c; color: #ffffff; border: 1px solid #1f2f45; box-shadow: 0 5px 14px rgba(37, 53, 76, 0.22); } .login-brand .brand-title { color: #25354c; } .login-brand .brand-subtitle { color: #6e7d92; opacity: 1; } .login-copy h1 { margin: 0; font-size: 28px; color: var(--heading); } .login-copy p { margin: 8px 0 0; font-size: 14px; color: #6e7d92; } .login-form { display: grid; gap: 14px; margin-top: 22px; } .login-submit { min-height: 40px; } .login-progress { display: grid; gap: 8px; padding: 11px 12px; border: 1px solid #cadbf0; border-radius: 8px; background: #f4f8fd; } .login-progress[hidden] { display: none; } .login-progress-track { height: 7px; overflow: hidden; border-radius: 999px; background: #dce7f5; } .login-progress-track span { display: block; width: 42%; height: 100%; border-radius: inherit; background: #3f97f7; /* Update only when readiness changes; continuous compositing is costly on the device. */ animation: none; } .login-progress[data-state="ready"] { border-color: #b9dec8; background: #f0faf4; } .login-progress[data-state="ready"] .login-progress-track { background: #d7ecdf; } .login-progress[data-state="ready"] .login-progress-track span { width: 100%; transform: none; animation: none; background: #3e9b61; } .login-progress[data-state="ready"] p { color: #34754e; } .login-progress p { margin: 0; color: #536b89; font-size: 12px; } .login-error { margin-top: 18px; border: 1px solid #f1c6c6; background: #fff1f1; color: #b14e4e; border-radius: 10px; padding: 12px 14px; font-size: 13px; } .login-hint { margin-top: 16px; font-size: 13px; color: #6f7d91; } .app-shell { display: flex; min-height: 100vh; } .sidebar { width: 200px; background: linear-gradient(180deg, var(--sidebar-deep), var(--sidebar)); color: #dbe4f0; padding: 18px 0 24px; flex: 0 0 200px; overflow-x: hidden; overflow-y: auto; scrollbar-color: rgba(255,255,255,0.22) transparent; scrollbar-width: thin; } .brand { display: flex; align-items: center; gap: 10px; padding: 0 18px 16px; border-bottom: 1px solid rgba(255,255,255,0.08); } .brand-mark { width: 34px; height: 34px; border-radius: 999px; background: rgba(255,255,255,0.12); display: flex; align-items: center; justify-content: center; font-weight: 700; color: #fff; } .brand-title { color: #fff; font-size: 20px; font-weight: 700; line-height: 1; } .brand-subtitle { margin-top: 4px; font-size: 11px; opacity: 0.7; } .nav { padding: 10px 10px 0; } .nav-group { margin-bottom: 2px; } .nav-item, .nav-child { display: flex; align-items: center; width: 100%; min-height: 42px; border-radius: 4px; color: #dbe4f0; } .nav-item { gap: 12px; justify-content: flex-start; padding: 0 10px; } .nav-item.active, .nav-child.active { background: rgba(78,160,255,0.18); color: #58a5ff; font-weight: 600; } .nav-label { min-width: 0; overflow: hidden; font-size: 14px; text-overflow: ellipsis; white-space: nowrap; } .nav-caret { width: 8px; height: 8px; flex: 0 0 auto; margin-right: 2px; margin-left: auto; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg); transition: transform 0.18s ease; } .nav-children { display: none; margin: 2px 0 7px 12px; padding: 2px 0 2px 8px; border-left: 1px solid rgba(191, 210, 234, 0.24); } .nav-group.expanded .nav-children { display: block; } .nav-group.expanded .nav-caret { transform: rotate(225deg); } .nav-child { min-height: 36px; padding: 0 10px; color: #c4d1e1; font-size: 13px; } .main { flex: 1; min-width: 0; display: flex; flex-direction: column; } .topbar { height: 56px; background: #243349; color: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 16px; } .topbar-left, .topbar-right { display: flex; align-items: center; gap: 12px; } .language-switch { display: inline-flex; align-items: center; gap: 6px; color: inherit; font-size: 12px; font-weight: 700; } .language-switch select { height: 30px; border: 1px solid rgba(255,255,255,0.35); border-radius: 4px; background: rgba(15, 23, 42, 0.32); color: #fff; padding: 0 26px 0 9px; font-size: 12px; } .language-switch select option { color: #172033; background: #fff; } .login-language { position: absolute; top: 18px; right: 18px; color: #475569; } .login-language select { border-color: #cbd5e1; background: #fff; color: #172033; } .menu-toggle { display: none; border: 0; background: transparent; color: #fff; font-size: 20px; } .topbar-crumbs { font-size: 13px; opacity: 0.92; } .crumb-sep { margin: 0 6px; opacity: 0.55; } .legacy-link { font-size: 12px; padding: 6px 10px; border-radius: 4px; background: rgba(255,255,255,0.1); } .user-pill { font-size: 14px; } .theme-pill { border: 0; background: var(--accent-strong); color: #fff; border-radius: 3px; padding: 6px 12px; font-size: 12px; } .reboot-button { border: 1px solid #ef8d8d; background: #b93737; color: #fff; border-radius: 4px; padding: 6px 12px; font-size: 12px; cursor: pointer; } .logout-form { margin: 0; } .logout-button { border: 1px solid rgba(255,255,255,0.18); background: rgba(255,255,255,0.06); color: #fff; border-radius: 4px; padding: 6px 10px; font-size: 12px; cursor: pointer; } .workspace-tabs { display: flex; gap: 2px; overflow-x: auto; padding: 6px 8px 0; background: #f5f6f8; border-bottom: 1px solid #e0e4eb; } .workspace-tab { display: inline-flex; align-items: center; gap: 8px; padding: 6px 10px; background: #fff; border: 1px solid #dce3eb; border-bottom: 0; border-radius: 4px 4px 0 0; font-size: 12px; color: #6d7b90; white-space: nowrap; } .workspace-tab-link { color: inherit; } .workspace-tab.active { background: var(--accent-strong); color: #fff; border-color: var(--accent-strong); } .workspace-close { border: 0; background: transparent; color: inherit; opacity: 0.7; cursor: pointer; padding: 0; line-height: 1; } .workspace-close:hover { opacity: 1; } .content { padding: 14px 8px 20px; } .page-header { display: flex; align-items: center; gap: 12px; padding: 8px 10px 10px; } .page-kicker { font-size: 13px; color: #7b8798; } .page-header h1 { margin: 0; font-size: 20px; color: var(--heading); } .mock-badge { margin-left: auto; padding: 5px 8px; background: #fff2cc; color: #8c6b00; border: 1px solid #f0d889; border-radius: 999px; font-size: 11px; font-weight: 700; } .subtabs { display: flex; gap: 20px; padding: 0 22px 0 22px; border-bottom: 1px solid var(--line); margin: 0 10px 0; } .subtabs.embedded { padding: 0 0 12px; margin: 0 0 12px; } .subtab { position: relative; padding: 12px 0; font-size: 13px; font-weight: 600; color: #5f6e84; } .subtab.active { color: var(--accent-strong); } .subtab.active::after { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; background: var(--accent-strong); } /* Dashboard-only rules keep administration and terminal layouts unchanged. */ body[data-current-path="/"] .content { padding: 20px 22px 30px; } body[data-current-path="/"] .page-header { padding: 0; margin-bottom: 5px; } body[data-current-path="/"] .page-kicker { display: none; } body[data-current-path="/"] .page-header h1 { font-size: 25px; letter-spacing: -0.6px; color: #20334d; } .dashboard { display: grid; gap: 18px; color: #475a73; font-size: 13px; } .dashboard [hidden] { display: none !important; } .dashboard-toolbar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; } .dashboard-toolbar > p { margin: 0; color: #63738a; line-height: 1.6; } .dashboard-sync { display: flex; align-items: center; gap: 7px; font-size: 11px; color: #52647a; } .dashboard-sync time { font-variant-numeric: tabular-nums; border-left: 1px solid #cdd6e1; padding-left: 8px; } .dashboard-status-dot { display: inline-block; flex: 0 0 7px; width: 7px; height: 7px; border-radius: 50%; background: #96a3b3; } .dashboard-sync[data-state="ready"] .dashboard-status-dot { background: #188562; } .dashboard-sync[data-state="error"] { color: #a33333; } .dashboard-sync[data-state="error"] .dashboard-status-dot { background: #be4545; } .dashboard-metrics { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; } .dashboard-metric { min-width: 0; display: flex; flex-direction: column; align-items: stretch; padding: 17px 19px; background: #fff; border: 1px solid #dce4ef; border-radius: 12px; box-shadow: 0 3px 12px #20334d04; } .dashboard-metric-label { display: flex; align-items: center; gap: 9px; } .dashboard-metric-label h2 { margin: 0; font-size: 13px; font-weight: 600; } .dashboard-metric-icon { display: inline-flex; align-items: center; justify-content: center; width: 33px; height: 29px; border-radius: 7px; color: #2863ab; background: #edf4ff; font-size: 9px; font-weight: 800; letter-spacing: .4px; } .dashboard-metric[data-metric="memory"] .dashboard-metric-icon { background: #f0effd; color: #7053af; } .dashboard-metric[data-metric="sessions"] .dashboard-metric-icon { background: #eaf6f3; color: #217b64; } .dashboard-metric[data-metric="alarms"] .dashboard-metric-icon { background: #f2f4f8; color: #64748b; } .dashboard-metric-value { margin: 9px 0 10px; font-size: 32px; font-weight: 700; line-height: 1.15; letter-spacing: -1px; color: #233a57; font-variant-numeric: tabular-nums; } .dashboard-metric p { margin: 8px 0 0; font-size: 11px; color: #67768a; display: flex; flex-wrap: wrap; gap: 4px 8px; line-height: 1.6; } .dashboard-metric p strong { color: #455970; font-weight: 600; font-variant-numeric: tabular-nums; } .dashboard-metric .dashboard-metric-description { margin-top: auto; min-height: 25px; align-items: flex-end; } .dashboard-metric[data-attention="true"] { border-color: #e4b9b9; background: #fffafa; } .dashboard-metric[data-attention="true"] .dashboard-metric-value, .dashboard-metric[data-attention="true"] .dashboard-metric-description { color: #ac3636; } .dashboard-metric meter { display: block; appearance: none; width: 100%; height: 6px; border: 0; border-radius: 5px; background: #eaf0f7; overflow: hidden; } .dashboard-metric meter::-webkit-meter-bar { background: #eaf0f7; border: 0; border-radius: 5px; height: 6px; } .dashboard-metric meter::-webkit-meter-optimum-value { background: #4488d8; border-radius: 5px; } .dashboard-metric meter::-moz-meter-bar { background: #4488d8; border-radius: 5px; } .dashboard-metric[data-metric="memory"] meter::-webkit-meter-optimum-value { background: #8b75c5; } .dashboard-metric[data-metric="memory"] meter::-moz-meter-bar { background: #8b75c5; } .dashboard .panel { padding: 19px 20px; border-radius: 12px; border-color: #dce4ef; min-width: 0; box-shadow: 0 3px 12px #20334d03; } .dashboard .panel-header { padding-bottom: 13px; margin-bottom: 15px; } .dashboard .panel-header h2 { color: #283e59; font-size: 15px; } .dashboard .panel-header p { color: #65758b; font-size: 11px; } .dashboard-panel-heading { display: flex; align-items: center; justify-content: space-between; gap: 10px; } .dashboard-detail-link { color: #2968b4; font-size: 12px; font-weight: 600; flex-shrink: 0; } .dashboard-detail-link span { margin-left: 5px; } .dashboard a:focus-visible, .dashboard button:focus-visible { outline: 3px solid #397fce; outline-offset: 3px; } .dashboard-port-toolbar { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px; margin-bottom: 17px; } .dashboard-port-summary { display: flex; align-items: baseline; gap: 8px; color: #65758b; font-size: 12px; } .dashboard-port-summary strong { font-size: 24px; font-weight: 700; color: #168061; font-variant-numeric: tabular-nums; } .dashboard-filters { display: flex; flex-wrap: wrap; gap: 5px; } .dashboard-filters button { display: flex; align-items: center; gap: 6px; padding: 7px 9px; background: #fff; border: 1px solid #e1e7ef; border-radius: 7px; color: #50627a; font-size: 11px; cursor: pointer; } .dashboard-filters button:hover { background: #f3f7fc; border-color: #b8cce5; } .dashboard-filters button[aria-pressed="true"] { color: #215eaa; background: #edf4ff; border-color: #8fb5e6; } .dashboard-filters b { min-width: 13px; font-variant-numeric: tabular-nums; } .dashboard [data-port-filter="up"] .dashboard-status-dot, .dashboard [data-port-state="up"] .dashboard-status-dot { background: #188562; } .dashboard [data-port-filter="session"] .dashboard-status-dot, .dashboard [data-port-state="session"] .dashboard-status-dot { background: #397cce; } .dashboard [data-port-filter="down"] .dashboard-status-dot, .dashboard [data-port-state="down"] .dashboard-status-dot { background: #bf4848; } .dashboard .port-link-grid { grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 7px; } .dashboard .port-link { display: flex; flex-direction: column; gap: 6px; padding: 9px 10px; border: 1px solid #e1e7ef; background: #f6f8fb; border-radius: 7px; text-align: left; min-width: 0; } .dashboard .port-link:hover { border-color: #6897d1; box-shadow: 0 0 0 2px #4488d815; } .dashboard-port-top { display: flex; align-items: center; justify-content: space-between; gap: 5px; } .dashboard .port-link-number { font-size: 13px; font-variant-numeric: tabular-nums; color: #3b4f69; } .dashboard .port-link-state { font-size: 10px; margin: 0; color: #6a788c; line-height: 1.3; overflow-wrap: anywhere; } .dashboard .port-link[data-port-state="up"] { background: #ecf8f2; border-color: #8dc6af; } .dashboard .port-link[data-port-state="up"] .port-link-state { color: #126d4e; font-weight: 700; } .dashboard .port-link[data-port-state="session"] { background: #edf4ff; border-color: #94b6e3; } .dashboard .port-link[data-port-state="session"] .port-link-state { color: #235faa; font-weight: 700; } .dashboard .port-link[data-port-state="down"] { background: #fff1f1; border-color: #dfabab; } .dashboard .port-link[data-port-state="down"] .port-link-state { color: #aa3535; font-weight: 700; } .dashboard-port-note { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 6px 14px; color: #65758b; font-size: 11px; line-height: 1.6; padding-top: 13px; } .dashboard-port-empty { padding: 25px 10px; text-align: center; color: #65758b; background: #f6f8fb; border-radius: 8px; } .dashboard-details { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; gap: 18px; } .dashboard-section-tag { font-size: 9px; font-weight: 700; color: #667992; letter-spacing: 1.2px; } .dashboard-interface { border: 1px solid #e1e8f1; border-radius: 8px; padding: 12px 14px; margin-bottom: 10px; background: #fbfcfe; } .dashboard-interface-heading { display: flex; justify-content: space-between; align-items: center; gap: 8px; } .dashboard-interface-heading strong { font-size: 12px; color: #465b77; } .dashboard-network-badge { font-size: 10px; border-radius: 4px; padding: 3px 6px; background: #e9eef5; color: #586b84; } .dashboard-network-badge[data-state="up"] { color: #146b4f; background: #e7f4ed; } .dashboard-network-badge[data-state="down"] { color: #a33333; background: #fae8e8; } .dashboard-interface-address { margin: 5px 0; color: #2a415f; font-size: 19px; letter-spacing: -.3px; font-weight: 600; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; } .dashboard-interface-meta { display: flex; justify-content: space-between; gap: 8px; font-size: 11px; color: #6b7d93; } .dashboard-facts { margin: 0; } .dashboard-facts > div { display: grid; grid-template-columns: minmax(100px, .85fr) minmax(0, 1.4fr); gap: 12px; padding: 9px 0; border-bottom: 1px solid #edf1f6; line-height: 1.5; } .dashboard-facts > div:last-child { border-bottom: 0; } .dashboard-facts dt { color: #65758b; font-size: 12px; } .dashboard-facts dd { margin: 0; color: #344c6a; overflow-wrap: anywhere; font-size: 12px; font-variant-numeric: tabular-nums; } .dashboard-network-meta { margin-top: 11px; } .dashboard-traffic-totals { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; border-bottom: 1px solid #e9eef5; padding-bottom: 18px; } .dashboard-traffic-totals > div { display: flex; flex-direction: column; gap: 7px; } .dashboard-traffic-totals span { font-size: 12px; color: #65758b; } .dashboard-traffic-totals strong { font-size: 24px; font-weight: 650; color: #2a588f; font-variant-numeric: tabular-nums; } .dashboard-traffic-totals > div:last-child strong { color: #59659b; } .dashboard-traffic h3 { font-size: 12px; color: #536780; margin: 17px 0 14px; } .dashboard-ranking { list-style: none; padding: 0; margin: 0; display: grid; gap: 14px; } .dashboard-rank-heading { display: flex; align-items: center; gap: 10px; font-size: 12px; } .dashboard-rank-heading a { color: #2968b4; font-weight: 600; } .dashboard-rank-heading strong { margin-left: auto; font-variant-numeric: tabular-nums; font-size: 12px; font-weight: 500; } .dashboard-rank-number { width: 17px; height: 17px; display: grid; place-items: center; background: #edf3fa; border-radius: 4px; color: #617895; font-size: 10px; } .dashboard-rank-track { margin: 7px 0 0 27px; background: #edf2f8; height: 5px; border-radius: 5px; overflow: hidden; } .dashboard-rank-track span { display: block; height: 100%; background: #77a1d3; border-radius: inherit; } .dashboard-footnote { margin: 19px 0 0; font-size: 11px; color: #65758b; line-height: 1.7; } .dashboard-system { grid-column: 1 / -1; } .dashboard-device { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; } .dashboard-device > strong { font-size: 18px; font-weight: 650; color: #2e4562; } .dashboard-device > span { padding: 6px 10px; border-radius: 6px; background: #f2f6fb; font-size: 11px; } .dashboard-device b { margin-left: 8px; font-weight: 500; color: #344c6a; } .dashboard-system-facts { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 36px; } .dashboard-placeholder { margin: 12px 0; color: #65758b; font-size: 12px; } @media (min-width: 1600px) { .dashboard-details { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.2fr); } .dashboard-system { grid-column: auto; } .dashboard-system-facts { grid-template-columns: 1fr; } } @media (max-width: 1100px) { .dashboard .port-link-grid { grid-template-columns: repeat(8, minmax(0, 1fr)); } .dashboard-metric { padding: 14px; } } @media (max-width: 650px) { body[data-current-path="/"] .content { padding: 16px 12px 24px; } .dashboard-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; } .dashboard-details { grid-template-columns: 1fr; } .dashboard-system-facts { grid-template-columns: 1fr; } .dashboard .panel { padding: 16px 13px; } .dashboard .port-link-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 5px; } .dashboard .port-link { padding: 8px 6px; } .dashboard-panel-heading { flex-wrap: wrap; } .dashboard-metric-value { font-size: 28px; } } @media (max-width: 400px) { .dashboard .port-link-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } } .blocks { display: grid; gap: 14px; padding: 0 10px; } .panel { background: var(--surface); border: 1px solid var(--line); border-radius: 4px; padding: 14px 22px 20px; } .panel-header { padding-bottom: 12px; border-bottom: 1px solid #edf1f6; margin-bottom: 14px; } .panel-header h2 { margin: 0; font-size: 14px; font-weight: 700; color: #5f6e84; } .panel-header p { margin: 6px 0 0; font-size: 12px; color: #8996a8; } .panel-header-actions { display: flex; justify-content: space-between; align-items: center; gap: 12px; } .port-link-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 8px; } .port-link { border: 1px solid #aeb7c4; background: #f8fafc; border-radius: 6px; padding: 8px 4px; text-align: center; font-size: 11px; } .port-link.up { border-color: #6da884; background: #edf9f1; } .port-link.down { border-color: #b7bec8; background: #f5f6f8; } .port-link.session { border-color: #5b8fd9; background: #eef5ff; } .port-link.signal { border-color: #d3a64f; background: #fff8e8; } .port-link.error { border-color: #c86a6a; background: #fff1f1; } .port-link.blink { box-shadow: 0 0 0 2px rgba(78,160,255,0.18); } .port-link-card { border: 1px solid #aeb7c4; background: #f8fafc; border-radius: 8px; overflow: hidden; } .port-link-card.up { border-color: #6da884; background: #edf9f1; } .port-link-card.down { border-color: #b7bec8; background: #f5f6f8; } .port-link-card.session { border-color: #5b8fd9; background: #eef5ff; } .port-link-card.signal { border-color: #d3a64f; background: #fff8e8; } .port-link-card.error { border-color: #c86a6a; background: #fff1f1; } .port-link-card.blink { box-shadow: 0 0 0 2px rgba(78,160,255,0.18); } .port-link-card.active { box-shadow: 0 0 0 2px rgba(63,151,247,0.32); } .port-link-view { border: 0; background: transparent; padding: 8px 4px; text-align: center; font-size: 11px; width: 100%; cursor: pointer; } .port-link-view { min-height: 78px; display: grid; align-content: center; gap: 4px; } .port-link-number { font-weight: 700; color: #44546a; } .port-link-state { margin-top: 4px; color: #718197; } .port-link-caption { font-size: 10px; color: #4f86d6; font-weight: 700; } .port-link-apply { width: 100%; border: 0; border-top: 1px solid rgba(94, 112, 135, 0.16); background: rgba(255,255,255,0.7); color: #4c627d; font-size: 11px; font-weight: 700; padding: 7px 4px; cursor: pointer; } .port-link-apply.selected { background: #3f97f7; color: #fff; } body[data-current-path^="/ports/"] .blocks { grid-template-columns: clamp(360px, 23vw, 400px) minmax(0, 1fr); column-gap: 18px; align-items: stretch; min-height: calc(100vh - 205px); position: relative; } body[data-current-path^="/ports/"]:not([data-port-load-state="ready"]) .blocks > .panel { visibility: hidden; } body[data-current-path^="/ports/"]:not([data-port-load-state="ready"]) .blocks::after { position: absolute; inset: 0; z-index: 2; display: grid; place-items: center; min-height: 360px; border: 1px solid #dfe5ee; border-radius: 4px; background: #fff; color: #66768d; font-size: 14px; content: "포트 설정과 상태를 불러오는 중입니다."; } body[data-current-path^="/ports/"][data-port-load-state="error"] .blocks::after { border-color: #f1b8b8; background: #fff7f7; color: #ba3f3f; content: "포트 정보를 불러오지 못했습니다. 잠시 후 새로고침하세요."; } body[data-current-path^="/ports/"] .port-selector-panel { grid-column: 1; padding: 11px 12px 13px; height: 100%; box-sizing: border-box; } body[data-current-path^="/ports/"] .form-panel { grid-column: 2; min-width: 0; height: 100%; box-sizing: border-box; } body[data-current-path^="/ports/"] .port-selector-panel .panel-header { padding-bottom: 5px; margin-bottom: 5px; } body[data-current-path^="/ports/"] .port-selector-panel .port-link-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 5px; } body[data-current-path^="/ports/"] .port-selector-panel .port-link-card { border-radius: 5px; } body[data-current-path^="/ports/"] .port-selector-panel .port-link-view { min-height: 42px; padding: 5px 3px; gap: 1px; font-size: 10px; } body[data-current-path^="/ports/"] .port-selector-panel .port-link-number { font-size: 11px; } body[data-current-path^="/ports/"] .port-selector-panel .port-link-state { margin-top: 0; font-size: 9.5px; overflow: hidden; text-overflow: ellipsis; } body[data-current-path^="/ports/"] .port-selector-panel .port-link-caption { display: none; } body[data-current-path^="/ports/"] .port-selector-panel .port-link-apply { min-height: 21px; padding: 4px 3px; font-size: 10px; } body[data-current-path^="/ports/"] .form-panel .form-grid { grid-template-columns: repeat(2, minmax(240px, 360px)); } body[data-current-path^="/ports/"] .form-panel .mock-form { gap: 10px; } .kv-table { display: grid; } .kv-row { display: grid; grid-template-columns: 240px 1fr; min-height: 44px; align-items: center; border-bottom: 1px solid #eef2f6; } .kv-row:last-child { border-bottom: 0; } .kv-key { color: #67778d; } .kv-value { color: #4b5c73; } .mock-form { display: grid; gap: 14px; } .form-grid { display: grid; grid-template-columns: 360px; gap: 14px 24px; } .compact-grid { grid-template-columns: repeat(2, minmax(240px, 360px)); } .form-row { display: grid; gap: 7px; } .form-row label { font-size: 13px; color: #6b7b91; } .required { color: #ef7e7e; } .form-row input[type="text"], .form-row input[type="password"], .form-row input[type="number"], .form-row select, .form-row textarea { width: 100%; min-height: 32px; border: 1px solid #d9e0ea; border-radius: 4px; background: #fff; padding: 6px 10px; color: #607188; } .form-row textarea { resize: vertical; min-height: 110px; } .field-hint { font-size: 11px; color: #97a4b3; } .form-fixed { padding: 0; border: 0; border-radius: 0; background: transparent; } .form-fixed label { color: inherit; font-weight: 600; } .form-fixed input[type="text"]:disabled { border-color: #d9e0ea; background: #f6f7f9; color: #607188; opacity: 1; cursor: not-allowed; } .fixed-value-badge { display: inline-flex; align-items: center; margin-left: 5px; padding: 2px 6px; border-radius: 999px; background: #d9e8f8; color: #376897; font-size: 10px; font-weight: 700; line-height: 1; } [hidden] { display: none !important; } .network-mode-context, .network-ipv6-disclosure, .operating-mode-context { grid-column: 1 / -1; width: 720px; max-width: 100%; box-sizing: border-box; } body[data-current-path^="/network/interface-"] .form-panel .form-grid { grid-template-columns: minmax(0, 780px); } body[data-current-path^="/network/interface-"] .network-mode-context { width: 780px; } .network-interface-columns { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(2, minmax(0, 360px)); gap: 24px; width: 780px; max-width: 100%; box-sizing: border-box; } .network-interface-column { display: grid; align-content: start; gap: 14px; width: 100%; min-width: 0; } .network-interface-column > .form-row, .network-interface-column > .network-ipv6-disclosure { width: 100%; min-width: 0; } .network-interface-column .form-row input, .network-interface-column .form-row select, .network-interface-column .form-row textarea { max-width: 100%; } .network-interface-column.ipv6-column { padding-left: 16px; border-left: 2px solid transparent; transition: border-color 160ms ease; } .network-interface-columns.ipv6-open .ipv6-column { border-left-color: #8ab9ef; background: none; } .network-mode-context { display: grid; gap: 4px; padding: 11px 13px; border: 1px solid #dce5ef; border-left: 3px solid #6aa7ef; border-radius: 4px; background: #f7faff; color: #53677f; } .network-mode-context strong { font-size: 13px; color: #40556f; } .network-mode-context span { font-size: 12px; } .network-mode-context[data-mode="oob"] { border-left-color: #e1a94a; background: #fffbf2; } .network-ipv6-disclosure { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-top: 2px; padding: 11px 13px; border: 1px dashed #cfd9e6; border-radius: 4px; background: #fafbfd; } .network-ipv6-disclosure > div { display: grid; gap: 3px; } .network-ipv6-disclosure strong { color: #50647c; font-size: 13px; } .network-ipv6-disclosure span { color: #8a98a9; font-size: 11px; } .btn.compact { padding: 6px 11px; white-space: nowrap; } .operating-mode-context { display: grid; gap: 9px; padding: 14px; border: 1px solid #dce5ef; border-radius: 4px; background: #f8fbff; } .operating-mode-context > strong { color: #40556f; font-size: 14px; } .operating-mode-context > p { margin: 0; color: #697b90; font-size: 12px; line-height: 1.55; } .operating-mode-context[data-mode="oob"] { border-color: #efd69d; background: #fffbf2; } .operating-mode-roles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; } .operating-mode-roles > div { display: grid; gap: 3px; padding: 10px 11px; border: 1px solid #dfe6ef; border-radius: 4px; background: #fff; } .operating-mode-roles strong { color: #4c6078; font-size: 12px; } .operating-mode-roles span { color: #7c8b9d; font-size: 11px; } .oob-runtime-summary { padding: 8px 10px; border-radius: 3px; background: #eef4fb; color: #58708a; font-size: 11px; } .oob-runtime-summary[data-fallback-active="true"] { background: #fff0d5; color: #966915; } .switch { position: relative; width: 34px; height: 18px; display: inline-flex; } .switch input { display: none; } .slider { width: 34px; height: 18px; border-radius: 999px; background: #d8dee8; position: relative; } .slider::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,0.14); } .switch input:checked + .slider { background: #72b1ff; } .switch input:checked + .slider::after { transform: translateX(16px); } .target-grid-wrap { border-top: 1px solid #edf1f6; padding-top: 10px; } .target-title { margin-bottom: 10px; font-size: 13px; color: #67778d; font-weight: 600; } .target-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 10px; } .target-chip { position: relative; display: grid; gap: 4px; min-height: 72px; padding: 12px 8px; border: 1px solid #b8c2cf; border-radius: 10px; background: #f8fafc; color: #5f6e84; text-align: center; cursor: pointer; transition: border-color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease; } .target-chip:hover { transform: translateY(-1px); border-color: #7bb0f5; } .target-chip input { position: absolute; opacity: 0; pointer-events: none; } .target-chip.selected { border-color: #6da884; background: #edf9f1; box-shadow: 0 0 0 2px rgba(78,160,255,0.16); } .target-chip-number { font-size: 13px; font-weight: 700; color: #44546a; } .target-chip-state { font-size: 11px; color: #718197; } .panel-actions { display: flex; gap: 12px; align-items: center; } .panel-actions.compact { margin-bottom: 0; } .modal-form .panel-actions, .group-modal .panel-actions { margin-top: 18px; } .btn { border: 1px solid transparent; border-radius: 3px; padding: 8px 18px; font-size: 12px; cursor: pointer; } .btn.primary { background: var(--accent-strong); color: #fff; } .btn.secondary { background: #fff; border-color: #d7dee9; color: #6b7c91; } .btn.danger { background: var(--danger); color: #fff; } .btn:disabled { cursor: not-allowed; opacity: 0.55; } .note-list { display: grid; gap: 6px; } .firmware-status { margin-top: 14px; padding: 12px 14px; border: 1px solid #cbd5e1; border-radius: 4px; background: #f8fafc; color: #334155; } .firmware-status.is-success { border-color: #86c89c; background: #edf8f0; color: #176b37; } .firmware-status progress { display: block; width: 100%; margin-top: 12px; height: 16px; } .firmware-status progress[hidden] { display: none; } .firmware-status p { margin: 10px 0 0; line-height: 1.6; overflow-wrap: anywhere; } .firmware-status a { display: inline-block; margin-top: 10px; } .firmware-status a[hidden] { display: none; } .firmware-status.is-error { border-color: #ef9a9a; background: #fff1f1; color: #b42318; } .note-item { font-size: 12px; color: #8a97a6; } .table-wrap { overflow-x: auto; } .data-table { width: 100%; border-collapse: collapse; font-size: 13px; } .data-table th, .data-table td { padding: 12px 14px; border-bottom: 1px solid #eef2f6; text-align: left; color: #5e7087; } .data-table th { background: #f3f6fa; font-weight: 700; color: #6d7d94; } body[data-current-path="/port-status"] .blocks { justify-items: start; } body[data-current-path="/port-status"] .panel { width: min(100%, 1120px); } body[data-current-path="/port-status"] .data-table { table-layout: fixed; } body[data-current-path="/port-status"] .data-table th, body[data-current-path="/port-status"] .data-table td { padding: 8px 12px; } body[data-current-path="/port-status"] .data-table th:nth-child(1), body[data-current-path="/port-status"] .data-table td:nth-child(1) { width: 12%; } body[data-current-path="/port-status"] .data-table th:nth-child(2), body[data-current-path="/port-status"] .data-table td:nth-child(2) { width: 18%; } body[data-current-path="/port-status"] .data-table th:nth-child(3), body[data-current-path="/port-status"] .data-table td:nth-child(3) { width: 28%; } body[data-current-path="/port-status"] .data-table th:nth-child(4), body[data-current-path="/port-status"] .data-table td:nth-child(4) { width: 14%; } body[data-current-path="/port-status"] .data-table th:nth-child(5), body[data-current-path="/port-status"] .data-table td:nth-child(5) { width: 28%; } .form-row.automation-hidden { display: none; } .port-status-badge { display: inline-flex; align-items: center; gap: 5px; min-width: 66px; padding: 2px 8px; border: 1px solid #d9dee5; border-radius: 999px; background: #f7f8fa; color: #687587; font-size: 12px; line-height: 1.25; white-space: nowrap; } .port-status-dot { width: 8px; height: 8px; flex: 0 0 8px; border-radius: 50%; background: #9aa1a9; } .port-status-badge.up { border-color: #add9bc; background: #edf9f1; color: #247b43; } .port-status-badge.up .port-status-dot { background: #35a85b; } .port-status-badge.down { border-color: #efb5b5; background: #fff1f1; color: #bf3f3f; } .port-status-badge.down .port-status-dot { background: #df4a4a; } .port-status-badge.session { border-color: #a9c7ef; background: #eef5ff; color: #2b66ad; } .port-status-badge.session .port-status-dot { background: #3f8de0; } .port-status-badge.unknown .port-status-dot { background: #9aa1a9; } .row-actions { white-space: nowrap; } .link-action { border: 0; background: transparent; padding: 0 2px; font-size: 12px; cursor: pointer; } .link-action.primary { color: var(--accent-strong); } .link-action.secondary { color: #61748d; } .link-action.danger { color: var(--danger); } .user-row-actions { display: flex; align-items: center; gap: 10px; } .account-status-badge, .password-state-badge, .system-group-label { display: inline-flex; align-items: center; gap: 5px; min-height: 22px; padding: 2px 8px; border: 1px solid #d8dee7; border-radius: 999px; background: #f7f8fa; color: #66758a; font-size: 11px; line-height: 1.2; white-space: nowrap; } .account-status-dot { width: 7px; height: 7px; flex: 0 0 7px; border-radius: 50%; background: #98a2b1; } .account-status-badge.enabled { border-color: #acd9bb; background: #edf9f1; color: #247b43; } .account-status-badge.enabled .account-status-dot { background: #35a85b; } .account-status-badge.disabled { border-color: #efb6b6; background: #fff1f1; color: #bf3f3f; } .account-status-badge.disabled .account-status-dot { background: #df4a4a; } .password-state-badge.required { border-color: #efd39b; background: #fff8e8; color: #9a6a10; } .password-state-badge.normal { border-color: #cfd9e6; background: #f6f8fb; color: #60728a; } .system-group-label { border-color: #cfd9e6; background: #f3f6fa; color: #61748d; } .empty-state { text-align: center; color: #98a5b3; } body[data-current-path^="/logs/"] .blocks { gap: 10px; } body[data-current-path^="/logs/"] .form-panel { padding: 14px 18px; } body[data-current-path^="/logs/"] .form-panel .panel-header { padding-bottom: 8px; margin-bottom: 10px; } body[data-current-path^="/logs/"] .form-panel .form-grid { grid-template-columns: repeat(auto-fit, minmax(165px, 1fr)); gap: 10px 14px; } body[data-current-path^="/settings/system-log/"] .form-panel .form-grid { grid-template-columns: repeat(2, minmax(260px, 420px)); max-width: 880px; } body[data-current-path="/settings/system-log/remote"] .form-panel .form-grid { grid-template-columns: minmax(300px, 520px); } body[data-current-path^="/logs/"] .form-panel .mock-form { gap: 12px; } body[data-current-path^="/logs/"] .form-panel .panel-actions { justify-content: flex-end; } body[data-current-path^="/logs/"] .table-wrap { max-height: calc(100vh - 430px); min-height: 240px; overflow: auto; } body[data-current-path^="/logs/"] .data-table th { position: sticky; top: 0; z-index: 1; } body[data-current-path^="/logs/"] .data-table th:not(:last-child), body[data-current-path^="/logs/"] .data-table td:not(:last-child) { white-space: nowrap; } body[data-current-path^="/logs/"] .data-table td:last-child { min-width: 300px; overflow-wrap: anywhere; } .log-type-tabs { display: flex; align-items: center; gap: 6px; padding: 10px 14px; border-bottom: 1px solid #e8edf4; background: #fbfcfe; } .log-type-tabs > strong { margin-right: 6px; color: #566a83; font-size: 12px; } .log-type-tab { min-width: 62px; padding: 6px 12px; border: 1px solid #d6dfeb; border-radius: 999px; background: #fff; color: #6c7e94; font-size: 11px; cursor: pointer; } .log-type-tab:hover { border-color: #8eb9ed; color: #3979c8; } .log-type-tab.active { border-color: #4e9cf4; background: #eaf4ff; color: #2469b8; font-weight: 700; } .log-live-status { display: inline-flex; align-items: center; min-height: 24px; padding: 3px 9px; border-radius: 999px; background: #edf3fa; color: #60738b; font-size: 11px; white-space: nowrap; } .log-live-status.loading { background: #fff6df; color: #9a711d; } .log-live-status.success { background: #e9f7ee; color: #287a49; } .log-live-status.error { background: #fff0f0; color: #b64949; } .log-clock-banner { margin: 12px 14px 0; padding: 9px 12px; border: 1px solid #d9e3ee; border-radius: 4px; background: #f6f8fb; color: #536980; font-size: 11px; line-height: 1.45; } .log-clock-banner.success { border-color: #b9dfc8; background: #eef9f2; color: #287a49; } .log-clock-banner.warning { border-color: #ecd69d; background: #fff8e8; color: #916b1c; } .log-severity-info { color: #287a49 !important; font-weight: 700; } .log-severity-warning { color: #a76f12 !important; font-weight: 700; } .log-severity-critical { color: #c54444 !important; font-weight: 700; } .log-direction-rx { color: #287a49 !important; font-weight: 700; } .log-direction-tx { color: #3979c8 !important; font-weight: 700; } .log-state-up { color: #287a49 !important; font-weight: 700; } .log-state-down { color: #c54444 !important; font-weight: 700; } .log-state-unknown { color: #7f8b99 !important; font-weight: 700; } /* Log explorer: compact filters, readable rows and preserved original messages. */ body[data-current-path^="/logs/"] .content { padding: 14px 16px 24px; } body[data-current-path^="/logs/"] .blocks { gap: 12px; } body[data-current-path^="/logs/"] .panel { border-radius: 10px; } .log-overview { display: flex; align-items: center; flex-wrap: wrap; gap: 12px 22px; padding: 12px 18px; border: 1px solid #dbe5f1; border-radius: 10px; background: #f8fbff; color: #52677f; } .log-overview-total { display: flex; align-items: baseline; gap: 7px; font-size: 12px; } .log-overview-total strong { font-size: 24px; line-height: 1; font-weight: 700; color: #244e7d; font-variant-numeric: tabular-nums; } .log-overview-breakdown { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; } .log-overview-scope { margin-left: auto; font-size: 11px; color: #65758b; } .log-badge { display: inline-flex; align-items: center; gap: 7px; padding: 4px 8px; border-radius: 5px; background: #edf1f6; color: #516379; font-size: 11px; font-weight: 600; line-height: 1.4; white-space: nowrap; } .log-badge strong { font-variant-numeric: tabular-nums; font-size: 12px; } .log-badge[data-tone="info"], .log-badge[data-tone="tx"] { background: #eaf2ff; color: #245f9d; } .log-badge[data-tone="warning"] { background: #fff3d6; color: #865500; } .log-badge[data-tone="critical"], .log-badge[data-tone="down"], .log-badge[data-tone="error"] { background: #ffecec; color: #ad3232; } .log-badge[data-tone="rx"], .log-badge[data-tone="up"], .log-badge[data-tone="connected"] { background: #e6f5ee; color: #176948; } .log-badge[data-tone="session"] { background: #f0ebfa; color: #6b4b9a; } body[data-current-path^="/logs/"] .log-filter-panel { padding: 12px 18px; } body[data-current-path^="/logs/"] .log-filter-panel .panel-header { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px; padding-bottom: 0; border: 0; margin-bottom: 12px; } .log-filter-panel .panel-header h2 { color: #354d69; font-size: 13px; } .log-filter-panel .panel-header p { margin: 0; color: #65758b; font-size: 11px; line-height: 1.5; } body[data-current-path^="/logs/"] .log-filter-panel .mock-form { gap: 10px; } .log-filter-line { display: flex; align-items: flex-end; gap: 16px; } body[data-current-path^="/logs/"] .log-filter-panel .form-grid { flex: 1; width: auto; max-width: none; grid-template-columns: minmax(90px, .8fr) minmax(180px, 2.6fr) minmax(90px, .8fr); gap: 12px; } body[data-current-path="/logs/ports"] .log-filter-panel .form-grid, body[data-current-path="/logs/links"] .log-filter-panel .form-grid { grid-template-columns: minmax(90px, 1fr) minmax(80px, .8fr) minmax(180px, 2fr) minmax(85px, .8fr); } .log-filter-panel .form-row { min-width: 0; gap: 5px; } .log-filter-panel .form-row[hidden] { display: none; } .log-filter-panel .form-row > label { font-size: 11px; color: #52677f; } .log-filter-panel input[type="text"], .log-filter-panel input[type="datetime-local"], .log-filter-panel select { box-sizing: border-box; width: 100%; min-width: 0; height: 35px; padding: 7px 9px; border: 1px solid #cfdbe9; border-radius: 6px; background: #fff; color: #344c6a; font-family: inherit; font-size: 12px; } .log-filter-panel .panel-actions { flex-shrink: 0; gap: 7px; } .log-filter-panel .btn, .log-result-panel .btn { border-radius: 6px; padding: 8px 12px; font-size: 12px; min-height: 34px; } .log-filter-footer { position: relative; display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; } .log-advanced { flex: 1; min-width: 0; } .log-advanced > summary { cursor: pointer; color: #376496; font-size: 11px; padding: 5px 0; width: fit-content; } .log-advanced-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; padding-top: 12px; } .log-search-note { color: #65758b; font-size: 11px; margin: 10px 0 0; } .log-advanced .note-list { margin-top: 10px; } .log-filter-panel .log-auto-refresh { display: flex; flex-direction: row-reverse; align-items: center; flex-shrink: 0; gap: 7px; padding: 3px 0; } .log-auto-refresh .switch { margin: 0; } body[data-current-path^="/logs/"] .log-result-panel { padding: 0; overflow: hidden; } .log-result-panel .panel-header { margin: 0; padding: 13px 18px; } .log-result-panel .panel-header h2 { color: #354d69; } .log-result-panel .panel-header p { color: #65758b; font-size: 11px; } .log-result-panel .panel-actions { gap: 7px; flex-wrap: wrap; justify-content: flex-end; } .log-result-panel .panel-header-actions { flex-wrap: wrap; } .log-result-panel .port-log-clear { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; width: 100%; box-sizing: border-box; margin-top: 12px; padding: 12px 14px; background: #fafbfe; border: 1px solid #dfe6ef; border-radius: 8px; } .port-log-clear-copy { flex: 1 1 360px; min-width: 0; } .port-log-clear-target { display: block; color: #425873; font-size: 12px; line-height: 1.6; } .log-result-panel .port-log-clear p { margin: 5px 0 0; line-height: 1.6; overflow-wrap: anywhere; } .port-log-clear .btn { flex-shrink: 0; } .port-log-clear[data-ready="true"] { border-color: #e9c6c6; background: #fffafa; } .port-log-clear[data-ready="true"] .port-log-clear-target { color: #a33d3d; } .log-result-panel .log-type-tabs { padding: 8px 18px; gap: 5px; overflow-x: auto; } .log-result-panel .log-type-tab { min-width: 54px; padding: 5px 10px; border-radius: 5px; } body[data-current-path^="/logs/"] .log-result-panel .table-wrap { max-height: max(280px, calc(100vh - 450px)); min-height: 220px; scrollbar-gutter: stable; } .log-result-panel .data-table { table-layout: fixed; min-width: 840px; } .log-result-panel .data-table th { background: #f0f4f9; color: #52677f; font-size: 11px; padding: 11px 12px; box-shadow: inset 0 -1px #e0e8f1; } .log-result-panel .data-table th:first-child { width: 113px; } .log-result-panel[data-log-kind="system"] th:nth-child(2) { width: 76px; } .log-result-panel[data-log-kind="system"] th:nth-child(3) { width: 84px; } .log-result-panel[data-log-kind="system"] th:nth-child(4) { width: 118px; } .log-result-panel:not([data-log-kind="system"]) .data-table { min-width: 890px; } .log-result-panel:not([data-log-kind="system"]) th:nth-child(2) { width: 76px; } .log-result-panel:not([data-log-kind="system"]) th:nth-child(3) { width: 84px; } .log-result-panel:not([data-log-kind="system"]) th:nth-child(4) { width: 114px; } .log-result-panel:not([data-log-kind="system"]) th:nth-child(5) { width: 92px; } .log-result-panel[data-log-kind="link"] th:nth-child(3) { width: 96px; } .log-result-panel[data-log-kind="link"] th:nth-child(4) { width: 190px; } .log-result-panel .data-table td { padding: 11px 12px; vertical-align: top; color: #3f536b; font-size: 12px; line-height: 1.6; border-bottom: 1px solid #eaf0f6; } body[data-current-path^="/logs/"] .log-result-panel .data-table td:not(:last-child) { white-space: normal; overflow-wrap: anywhere; } .log-event-row:hover, .log-event-row:focus-within { background: #f8fbff; } .log-event-row[data-tone="critical"] .log-time-cell { box-shadow: inset 3px 0 #d45b5b; } .log-event-row[data-tone="warning"] .log-time-cell { box-shadow: inset 3px 0 #e2ad46; } .log-time-cell time { display: block; font-size: 13px; color: #344c6a; font-weight: 600; font-variant-numeric: tabular-nums; } .log-date { display: block; color: #728199; font-size: 10px; font-variant-numeric: tabular-nums; } .log-time-unset { display: block; color: #90631a; font-size: 10px; } .log-channel { display: inline-block; color: #365e8c; font-family: ui-monospace, Consolas, monospace; font-weight: 600; } .log-source { color: #60738b; font-size: 11px; } .log-message-details > summary { display: flex; align-items: flex-start; gap: 12px; cursor: pointer; list-style: none; } .log-message-details > summary::-webkit-details-marker { display: none; } .log-message-preview { flex: 1; min-width: 0; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; overflow-wrap: anywhere; white-space: pre-line; } .log-message-details[open] .log-message-preview { display: block; } .log-detail-hint { flex-shrink: 0; font-size: 10px; color: #4776aa; padding: 1px 0; } .log-detail-hint::after { content: " +"; } .log-message-details[open] .log-detail-hint::after { content: " −"; } .log-event-detail { margin-top: 12px; padding: 12px; border: 1px solid #dae5f1; border-radius: 7px; background: #f3f7fc; } .log-event-metadata { margin: 0; display: grid; gap: 5px; } .log-event-metadata > div { display: grid; grid-template-columns: 75px minmax(0, 1fr); gap: 8px; } .log-event-metadata dt { color: #687b94; font-size: 10px; } .log-event-metadata dd { margin: 0; font-size: 11px; overflow-wrap: anywhere; } .log-event-detail h3 { margin: 10px 0 5px; color: #5b708b; font-size: 10px; font-weight: 600; } .log-event-detail pre { margin: 0; padding: 10px; background: #fff; border: 1px solid #e1e8f1; border-radius: 5px; white-space: pre-wrap; overflow-wrap: anywhere; max-height: 260px; overflow: auto; color: #344c6a; font: 11px/1.65 ui-monospace, Consolas, monospace; } .log-event-detail > .log-badge { margin-top: 8px; } .log-result-panel mark { background: #ffedac; color: inherit; border-radius: 2px; } .log-result-feedback { margin: 0; padding: 9px 18px; color: #5c7290; background: #f0f5fc; font-size: 11px; line-height: 1.5; } .log-result-feedback[data-tone="error"] { color: #a13a3a; background: #fff0f0; } .log-result-feedback[hidden] { display: none; } .log-result-footer { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 18px; padding: 10px 18px; border-top: 1px solid #e2e9f2; color: #65758b; background: #fcfdff; font-size: 10px; } .log-result-footer .log-clock-banner { flex-basis: 100%; border: 0; border-radius: 0; padding: 0; margin: 0; background: none; color: #65758b; font-size: 10px; } .log-result-footer .log-clock-banner.warning { color: #8b6219; background: #fff5df; padding: 7px 9px; border-radius: 4px; } .log-updated { display: inline-flex; gap: 7px; font-variant-numeric: tabular-nums; } .log-live-status.paused { color: #5a6b83; background: #edf1f6; } .log-result-panel .log-empty-state { padding: 45px 18px; text-align: center; } .log-empty-state strong { font-size: 13px; color: #4e647f; } .log-empty-state p { font-size: 11px; color: #6f8098; margin: 8px 0 0; } .log-filter-panel :is(input, select, button, summary):focus-visible, .log-result-panel :is(button, summary):focus-visible { outline: 2px solid #377ccc; outline-offset: 3px; } @media (max-width: 1100px) { .log-filter-line { flex-wrap: wrap; gap: 10px; } .log-filter-line .panel-actions { margin-left: auto; } .log-overview-scope { flex-basis: 100%; margin-left: 0; } .log-advanced-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } } @media (max-width: 700px) { body[data-current-path^="/logs/"] .content { padding: 12px 4px 20px; } body[data-current-path^="/logs/"] .log-filter-panel .form-grid { flex-basis: 100%; grid-template-columns: repeat(2, minmax(0, 1fr)); } .log-keyword-field { grid-column: 1 / -1; } .log-overview { gap: 10px; padding: 12px; } .log-advanced-grid { grid-template-columns: minmax(0, 1fr); } .log-filter-footer { flex-wrap: wrap; } .log-advanced { flex-basis: 100%; } .log-result-panel .panel-header-actions { flex-wrap: wrap; } .log-result-panel .panel-actions { justify-content: flex-start; } } .action-panel .action-copy { margin-bottom: 16px; font-size: 13px; color: #6b7b90; } body[data-current-path="/tools/nettest/ping"] .mock-form .form-grid { grid-template-columns: repeat(2, minmax(260px, 360px)); width: min(744px, 100%); } body[data-current-path="/tools/nettest/ping"] .mock-form .form-row:nth-child(1) { grid-column: 1; grid-row: 1; } body[data-current-path="/tools/nettest/ping"] .mock-form .form-row:nth-child(2) { grid-column: 1; grid-row: 2; } body[data-current-path="/tools/nettest/ping"] .mock-form .form-row:nth-child(3) { grid-column: 2; grid-row: 1; } body[data-current-path="/tools/nettest/ping"] .mock-form .form-row:nth-child(4) { grid-column: 2; grid-row: 2; } body[data-current-path="/tools/alias"] .mock-form .form-grid { grid-template-columns: repeat(2, minmax(260px, 360px)); width: min(744px, 100%); } .diagnostic-console { margin-top: 14px; overflow: hidden; border: 1px solid #202b3a; border-radius: 5px; background: #070b11; box-shadow: 0 8px 24px rgba(18, 26, 38, 0.1); } .diagnostic-console-titlebar { display: grid; grid-template-columns: 42px 1fr auto; align-items: center; min-height: 36px; padding: 0 13px; border-bottom: 1px solid #253142; background: #111820; color: #aebccc; font: 11px/1 Consolas, "Courier New", monospace; } .diagnostic-console-titlebar > span:first-child { color: #7ee787; font-weight: 700; } .diagnostic-console-titlebar strong { color: #d8e0ea; font-weight: 600; } .diagnostic-console-titlebar > span:last-child { color: #738398; } .result-box { height: 250px; min-height: 250px; max-height: 250px; margin: 0; overflow: auto; border: 0; border-radius: 0; background: #070b11; padding: 15px 16px; white-space: pre-wrap; overflow-wrap: anywhere; color: #d7e0e9; scrollbar-color: #46566b #0a1018; scrollbar-width: thin; font: 13px/1.5 Consolas, "Courier New", monospace; } .result-box[data-state="running"] { color: #e7d38a; } .result-box[data-state="succeeded"] { color: #d7e0e9; } .result-box[data-state="failed"] { color: #ff9b9b; } .serial-console { display: flex; flex-direction: column; min-height: 0; overflow: hidden; border: 1px solid #202b3a; border-radius: 5px; background: #111827; box-shadow: 0 10px 30px rgba(18, 26, 38, 0.12); } .serial-console-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 12px 16px; border-bottom: 1px solid #344155; background: #1e293b; color: #e5edf7; } .serial-console-heading { display: flex; align-items: center; gap: 12px; min-width: 240px; } .serial-console-heading h2 { margin: 0; font-size: 14px; color: #f8fafc; } .serial-console-heading p { margin: 3px 0 0; font-size: 11px; color: #9fb0c5; } .serial-console-icon { display: inline-flex; align-items: center; justify-content: center; width: 48px; height: 34px; border: 1px solid #4b5c72; border-radius: 4px; background: #0b1220; color: #7ee787; font: 700 12px/1 Consolas, "Courier New", monospace; } .serial-console-controls { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; } .serial-console-controls label { color: #b7c5d7; font-size: 12px; font-weight: 700; } .serial-console-controls select { min-width: 150px; height: 32px; border: 1px solid #4b5c72; border-radius: 3px; background: #111827; color: #f1f5f9; padding: 0 28px 0 10px; font-size: 12px; } .serial-console-controls select option:disabled { color: #758296; } .terminal-button { height: 32px; border: 1px solid #4c5e75; border-radius: 3px; background: #2c3a4e; color: #e6edf6; padding: 0 12px; font-size: 11px; font-weight: 700; cursor: pointer; } .terminal-button:hover { background: #394a61; } .terminal-button.connect { border-color: #218c52; background: #19713f; color: #fff; } .terminal-button.disconnect { border-color: #a54343; background: #833838; color: #fff; } .terminal-button:disabled { cursor: not-allowed; opacity: 0.45; } .terminal-window { display: flex; flex: 0 0 560px; height: 560px; min-height: 560px; max-height: 560px; flex-direction: column; background: #070b11; } .terminal-helpbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 38px; padding: 0 12px; border-bottom: 1px solid #283548; background: #0f1724; color: #aebdce; } .terminal-help-message { overflow: hidden; font-size: 11px; line-height: 1.35; text-overflow: ellipsis; white-space: nowrap; } .terminal-advanced-toggle { display: inline-flex; flex: 0 0 auto; align-items: center; gap: 6px; height: 28px; border: 1px solid #435269; border-radius: 3px; background: #172235; color: #d8e2ef; padding: 0 10px; font-size: 11px; font-weight: 700; cursor: pointer; } .terminal-advanced-toggle::after { content: "▾"; transition: transform 0.15s ease; } .terminal-advanced-toggle[aria-expanded="true"]::after { transform: rotate(180deg); } .terminal-advanced-toggle:hover { background: #223149; } .terminal-batch-toolbar { display: flex; align-items: end; gap: 8px; flex-wrap: wrap; padding: 8px 12px; border-bottom: 1px solid #283548; background: #0f1724; color: #afbdd0; } .terminal-batch-toolbar[hidden] { display: none; } .terminal-batch-toolbar label { display: grid; gap: 3px; font-size: 10px; font-weight: 700; } .terminal-batch-toolbar select, .terminal-batch-toolbar input { height: 30px; border: 1px solid #435269; border-radius: 3px; background: #172235; color: #f1f5f9; padding: 0 8px; font: 12px/1 Consolas, "Courier New", monospace; } .terminal-batch-value { flex: 1 1 260px; } .terminal-batch-value input { width: 100%; } .terminal-log-state { align-self: center; min-width: 72px; color: #7ee787; font: 11px/1.2 Consolas, "Courier New", monospace; text-align: right; } .terminal-titlebar { display: flex; align-items: center; justify-content: space-between; min-height: 34px; padding: 0 14px; border-bottom: 1px solid #253142; background: #111820; color: #d8e0ea; font: 12px/1 Consolas, "Courier New", monospace; } .terminal-connection-state { display: inline-flex; align-items: center; gap: 6px; color: #98a6b8; font: 11px/1.2 Arial, sans-serif; } .terminal-state-dot { width: 8px; height: 8px; border-radius: 50%; background: #718096; box-shadow: 0 0 0 2px rgba(113, 128, 150, 0.16); } .terminal-connection-state[data-state="connecting"] { color: #e7b75e; } .terminal-connection-state[data-state="connecting"] .terminal-state-dot { background: #e7b75e; } .terminal-connection-state[data-state="ready"] { color: #66d38b; } .terminal-connection-state[data-state="ready"] .terminal-state-dot { background: #42c978; box-shadow: 0 0 8px rgba(66, 201, 120, 0.45); } .terminal-connection-state[data-state="connected"] { color: #66d38b; } .terminal-connection-state[data-state="connected"] .terminal-state-dot { background: #42c978; box-shadow: 0 0 8px rgba(66, 201, 120, 0.62); } .terminal-connection-state[data-state="error"] { color: #f07777; } .terminal-connection-state[data-state="error"] .terminal-state-dot { background: #e25555; } .terminal-connection-state[data-state="unavailable"] { color: #f07777; } .terminal-connection-state[data-state="unavailable"] .terminal-state-dot { background: #e25555; } .terminal-screen { display: block; flex: 1; min-height: 0; overflow-x: auto; overflow-y: scroll; padding: 16px; background: #070b11; cursor: text; user-select: text; scrollbar-color: #46566b #0a1018; scrollbar-width: thin; outline: none; } .terminal-output { display: inline; margin: 0; padding: 0; overflow: visible; background: transparent; color: #d7e0e9; white-space: pre-wrap; overflow-wrap: anywhere; tab-size: 4; font: 13px/1.48 Consolas, "Courier New", monospace; } .terminal-command-line { display: inline; align-items: baseline; min-height: 20px; margin: 0; background: transparent; } .terminal-command-line[hidden] { display: none; } .terminal-command-input { display: inline; min-width: 0; min-height: 20px; padding: 0; border: 0; background: transparent; color: #f5f7fa; caret-color: transparent; outline: none; white-space: pre-wrap; overflow-wrap: anywhere; user-select: text; font: 13px/1.48 Consolas, "Courier New", monospace; } .terminal-command-input[contenteditable="false"] { color: #657386; } .terminal-block-cursor { display: inline-block; position: relative; width: 0; height: 1.02em; padding: 0; line-height: 1.02em; vertical-align: -0.16em; pointer-events: none; } .terminal-block-cursor::after { position: absolute; z-index: 1; top: 0; left: 0; width: 0.62em; height: 1.02em; background: rgba(126, 231, 135, 0.82); content: ""; animation: terminal-cursor-blink 1s steps(1, end) infinite; } .terminal-command-input.has-terminal-selection .terminal-block-cursor::after { display: none; } .terminal-command-input::selection, .terminal-command-input *::selection { background: #2f81f7; color: #ffffff; } @keyframes terminal-cursor-blink { 0%, 48% { opacity: 1; } 49%, 100% { opacity: 0; } } @media (prefers-reduced-motion: reduce) { .terminal-block-cursor::after { animation: none; } } .serial-console-footer { display: flex; gap: 18px; padding: 8px 14px; border-top: 1px solid #2e3a4b; background: #182334; color: #8fa1b7; font-size: 10px; } .modal-layer { position: fixed; inset: 0; display: grid; place-items: center; z-index: 1200; } .modal-layer[hidden] { display: none; } .modal-backdrop { position: absolute; inset: 0; background: rgba(27, 40, 58, 0.42); backdrop-filter: blur(2px); } .modal-box { position: relative; z-index: 1; width: min(720px, calc(100vw - 32px)); border: 1px solid #dfe5ee; background: #fbfcfe; border-radius: 10px; padding: 18px; box-shadow: 0 24px 60px rgba(20, 33, 52, 0.24); } .modal-form { display: grid; gap: 18px; } .modal-form .form-grid { gap: 18px 24px; } .group-modal { width: min(920px, calc(100vw - 32px)); } .group-modal .form-grid { gap: 18px 24px; margin-bottom: 18px; } .modal-header { display: flex; align-items: center; justify-content: space-between; gap: 16px; } .modal-close { border: 0; background: transparent; color: #6b7c91; cursor: pointer; font-size: 18px; line-height: 1; padding: 4px; } .modal-message { margin: 0 0 18px; font-size: 13px; color: #6d7c91; } .group-permission-grid, .group-permission-checks { display: grid; grid-template-columns: repeat(9, minmax(0, 1fr)); gap: 8px; } .group-permission-grid { margin-top: 18px; } .group-permission-checks { margin-top: 14px; margin-bottom: 18px; } .group-permission-cell { min-height: 64px; border: 1px solid #dfe5ee; border-radius: 8px; background: #f8fbff; padding: 12px 8px; text-align: center; font-size: 12px; color: #6b7c91; display: flex; align-items: center; justify-content: center; line-height: 1.45; } .group-permission-cell.heading { font-weight: 700; color: #607188; background: #f3f7fc; } .permission-chip { min-height: 44px; border: 1px solid #d9e3ef; border-radius: 8px; background: #fff; display: flex; align-items: center; justify-content: center; gap: 6px; font-size: 12px; color: #5f6e84; } .permission-chip input { margin: 0; } .permission-chip.selected { border-color: #5aa57a; background: #edf8f1; color: #24523a; } .toast-root { position: fixed; right: 18px; bottom: 18px; display: grid; gap: 10px; z-index: 1000; } .toast { min-width: 260px; max-width: 360px; background: #243349; color: #fff; border: 1px solid #3a4c65; border-left-width: 5px; border-radius: 6px; padding: 12px 14px; box-shadow: 0 12px 24px rgba(0,0,0,0.18); font-size: 13px; font-weight: 600; } .toast-success { background: #e7f6ed; border-color: #42a66b; color: #22633d; box-shadow: 0 12px 24px rgba(38, 119, 70, 0.18); } .toast-error { background: #fdeaea; border-color: #df5656; color: #982f2f; box-shadow: 0 12px 24px rgba(178, 45, 45, 0.18); } .toast-info { background: #243349; border-color: #6d8098; color: #fff; } @media (max-width: 1100px) { .compact-grid { grid-template-columns: 1fr; } .port-link-grid { grid-template-columns: repeat(8, minmax(0, 1fr)); } .target-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); } .group-permission-grid, .group-permission-checks { grid-template-columns: repeat(3, minmax(0, 1fr)); } } @media (max-width: 920px) { .sidebar { position: fixed; inset: 0 auto 0 0; transform: translateX(-100%); z-index: 30; } body.sidebar-open .sidebar { transform: translateX(0); } .menu-toggle { display: inline-flex; } .compact-grid, .form-grid { grid-template-columns: 1fr; } body[data-current-path="/tools/nettest/ping"] .mock-form .form-grid { grid-template-columns: 1fr; width: 100%; } body[data-current-path="/tools/nettest/ping"] .mock-form .form-row:nth-child(1), body[data-current-path="/tools/nettest/ping"] .mock-form .form-row:nth-child(2), body[data-current-path="/tools/nettest/ping"] .mock-form .form-row:nth-child(3), body[data-current-path="/tools/nettest/ping"] .mock-form .form-row:nth-child(4) { grid-column: 1; grid-row: auto; } .network-ipv6-disclosure { align-items: flex-start; flex-direction: column; } body[data-current-path^="/network/interface-"] .form-panel .form-grid { grid-template-columns: 1fr; } .network-interface-columns { grid-template-columns: 1fr; gap: 18px; width: 100%; } .network-interface-column.ipv6-column { padding-top: 16px; padding-left: 0; border-top: 2px solid transparent; border-left: 0; } .network-interface-columns.ipv6-open .ipv6-column { border-top-color: #8ab9ef; } .operating-mode-roles { grid-template-columns: 1fr; } .target-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } .group-permission-grid, .group-permission-checks { grid-template-columns: repeat(2, minmax(0, 1fr)); } body[data-current-path^="/ports/"] .blocks { grid-template-columns: 1fr; min-height: 0; } body[data-current-path^="/ports/"] .port-selector-panel, body[data-current-path^="/ports/"] .form-panel { grid-column: 1; } body[data-current-path^="/ports/"] .port-selector-panel .port-link-grid { grid-template-columns: repeat(8, minmax(0, 1fr)); } body[data-current-path^="/ports/"] .form-panel .form-grid { grid-template-columns: 1fr; } .serial-console { min-height: 0; } .serial-console-toolbar { align-items: flex-start; flex-direction: column; } .serial-console-controls { justify-content: flex-start; } .terminal-window { flex-basis: 440px; height: 440px; min-height: 440px; max-height: 440px; } .serial-console-footer { flex-wrap: wrap; gap: 6px 14px; } } .login-captcha[hidden], .login-captcha img[hidden] { display: none; } .login-captcha-image-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } .login-captcha-image-row img { display: block; max-width: 100%; width: 140px; height: auto; border: 1px solid #d6deea; border-radius: 6px; background: white; } .login-captcha .login-captcha-hint { margin: 0; font-size: 12px; line-height: 1.5; color: #64748b; } .btn.danger { color: #fff; background: #c93641; border: 1px solid #c93641; } .btn.danger:hover:not(:disabled) { background: #aa2530; border-color: #aa2530; } .btn.danger:disabled { opacity: .5; cursor: not-allowed; } .login-progress[data-measured="true"] .login-progress-track span { animation: none; transform: none; transition: width .2s ease; } .login-progress[data-state="failed"] { border-color: #d5a3a3; background: #fff4f4; } .login-progress[data-state="failed"] p { color: #a12828; } .login-progress[data-state="failed"] .login-progress-track span { background: #b83a3a; animation: none; } .login-progress[data-state="delayed"] { border-color: #e4c58d; background: #fff9ed; } .login-progress[data-state="delayed"] p { color: #875d13; } .login-progress[data-state="delayed"] .login-progress-track span { background: #c88b23; animation: none; }