/* ══════════════════════════════════════════════════════════════════════ GANDALF – Terminal aesthetic (Pulse / TinkerTickets style) ══════════════════════════════════════════════════════════════════════ */ /* ── Variables ────────────────────────────────────────────────────── */ :root { --bg: #0a0a0a; --bg2: #1a1a1a; --bg3: #2a2a2a; --bg-hover: rgba(0,255,65,.07); --green: #00ff41; --green-dim: rgba(0,255,65,.15); --green-dark: #00cc33; --green-muted: #008822; --amber: #ffb000; --amber-dim: rgba(255,176,0,.15); --cyan: #00ffff; --cyan-dim: rgba(0,255,255,.12); --red: #ff4444; --red-dim: rgba(255,68,68,.15); --orange: #ff8c00; --orange-dim: rgba(255,140,0,.15); --border: rgba(0,255,65,.35); --border-hi: #00ff41; --text: #00ff41; --text-dim: #00cc33; --text-muted: #008822; --font: 'Courier New','Consolas','Monaco','Menlo',monospace; --glow: 0 0 5px #00ff41, 0 0 10px rgba(0,255,65,.4); --glow-xl: 0 0 8px #00ff41, 0 0 20px rgba(0,255,65,.35); --glow-amber: 0 0 5px #ffb000, 0 0 10px rgba(255,176,0,.4); --glow-red: 0 0 5px #ff4444, 0 0 10px rgba(255,68,68,.4); --glow-cyan: 0 0 5px #00ffff, 0 0 10px rgba(0,255,255,.35); } /* ── Reset ────────────────────────────────────────────────────────── */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } html { scrollbar-color: var(--green-muted) var(--bg2); scrollbar-width: thin; } ::-webkit-scrollbar { width: 6px; height: 6px; } ::-webkit-scrollbar-track { background: var(--bg2); } ::-webkit-scrollbar-thumb { background: var(--green-muted); } ::-webkit-scrollbar-thumb:hover { background: var(--green); } /* ── Body / CRT ───────────────────────────────────────────────────── */ body { font-family: var(--font); background: var(--bg); color: var(--text); font-size: 13px; line-height: 1.5; min-height: 100vh; position: relative; animation: flicker .25s ease-in-out 45s infinite; } /* CRT scanline overlay */ body::before { content: ''; position: fixed; inset: 0; background: repeating-linear-gradient( 0deg, rgba(0,0,0,.13) 0px, rgba(0,0,0,.13) 1px, transparent 1px, transparent 2px ); pointer-events: none; z-index: 9999; animation: scanline 8s linear infinite; } /* Binary data stream corner */ body::after { content: '10101010'; position: fixed; bottom: 10px; right: 14px; font-family: var(--font); font-size: .55rem; color: var(--green); opacity: .07; pointer-events: none; letter-spacing: 2px; animation: data-stream 3s steps(1) infinite; } @keyframes scanline { to { transform: translateY(4px); } } @keyframes flicker { 0%,100%{opacity:1} 10%{opacity:.96} 50%{opacity:.98} } @keyframes data-stream { 0% { content:'10101010'; } 25% { content:'01010101'; } 50% { content:'11001100'; } 75% { content:'00110011'; } } @keyframes pulse-glow { 0%,100% { text-shadow: var(--glow); } 50% { text-shadow: var(--glow-xl); } } @keyframes pulse-red { 0%,100% { box-shadow: 0 0 0 0 rgba(255,68,68,.5); } 50% { box-shadow: 0 0 6px 3px rgba(255,68,68,.2); } } @keyframes blink { 0%,49%{opacity:1} 50%,100%{opacity:0} } @keyframes slide-in { from { transform: translateX(110%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } a { color: var(--amber); text-decoration: none; } a:hover { text-decoration: underline; text-shadow: var(--glow-amber); } /* ── Header ───────────────────────────────────────────────────────── */ .header { background: var(--bg2); border-bottom: 2px solid var(--green); box-shadow: 0 2px 16px rgba(0,255,65,.12); padding: 0 28px; height: 58px; display: flex; align-items: center; justify-content: space-between; position: relative; z-index: 100; } .header::before { content:'╔'; position:absolute; top:-1px; left:-1px; font-size:1.4rem; color:var(--green); text-shadow:var(--glow); line-height:1; } .header::after { content:'╗'; position:absolute; top:-1px; right:-1px; font-size:1.4rem; color:var(--green); text-shadow:var(--glow); line-height:1; } .header-left { display:flex; align-items:center; gap:24px; } .header-brand { display:flex; flex-direction:column; } .header-title { font-size: 1.35em; font-weight: bold; color: var(--amber); text-shadow: var(--glow-amber); letter-spacing: .08em; } .header-title::before { content:'>> '; color:var(--green); text-shadow:var(--glow); } .header-sub { font-size: .65em; color: var(--text-muted); letter-spacing: .12em; text-transform: uppercase; } .header-nav { display:flex; gap:3px; } .nav-link { color: var(--text-muted); padding: 5px 12px; border: 1px solid transparent; font-size: .8em; letter-spacing: .06em; text-transform: uppercase; transition: all .15s; } .nav-link::before { content:'[ '; } .nav-link::after { content:' ]'; } .nav-link:hover, .nav-link.active { color: var(--green); border-color: var(--border); background: var(--green-dim); text-shadow: var(--glow); text-decoration: none; } .header-right { display:flex; align-items:center; gap:10px; } .header-user { font-size: .78em; color: var(--text-muted); } .header-user::before { content:'[USER: '; } .header-user::after { content:']'; } /* ── Main ─────────────────────────────────────────────────────────── */ .main { max-width: 1500px; margin: 0 auto; padding: 22px 20px; } /* ── Section ──────────────────────────────────────────────────────── */ .section { margin-bottom: 26px; } .section-header { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; border-bottom: 1px solid var(--border); padding-bottom: 5px; } .section-title { font-size: .9em; font-weight: bold; color: var(--amber); text-shadow: var(--glow-amber); text-transform: uppercase; letter-spacing: .1em; } .section-title::before { content:'╠══ '; color:var(--green); text-shadow:var(--glow); } .section-badge { font-size: .72em; font-weight: bold; color: var(--red); border: 1px solid var(--red); padding: 0 5px; text-shadow: var(--glow-red); } .section-badge::before { content:'['; } .section-badge::after { content:']'; } /* ── Page header ──────────────────────────────────────────────────── */ .page-header { margin-bottom: 18px; } .page-title { font-size: 1.05em; font-weight: bold; color: var(--amber); text-shadow: var(--glow-amber); letter-spacing: .06em; } .page-title::before { content:'>> '; color:var(--green); text-shadow:var(--glow); } .page-sub { font-size: .75em; color: var(--text-muted); margin-top: 3px; } /* ── Status bar ───────────────────────────────────────────────────── */ .status-bar { display: flex; align-items: center; justify-content: space-between; background: var(--bg2); border: 1px solid var(--border); padding: 9px 16px; margin-bottom: 18px; gap: 12px; flex-wrap: wrap; position: relative; } .status-bar::before { content:'┌'; position:absolute; top:-1px; left:-1px; color:var(--green); font-size:.85rem; line-height:1; } .status-bar::after { content:'┐'; position:absolute; top:-1px; right:-1px; color:var(--green); font-size:.85rem; line-height:1; } .status-chips { display:flex; gap:7px; flex-wrap:wrap; align-items:center; } .chip { font-size: .78em; font-weight: bold; padding: 2px 9px; border: 1px solid; letter-spacing: .04em; } .chip::before { content:'['; } .chip::after { content:']'; } .chip-critical { color:var(--red); border-color:var(--red); text-shadow:var(--glow-red); animation:pulse-glow 2s infinite; } .chip-warning { color:var(--orange); border-color:var(--orange); } .chip-ok { color:var(--green); border-color:var(--border); text-shadow:var(--glow); } .status-meta { display:flex; align-items:center; gap:10px; white-space:nowrap; } .last-check { font-size: .72em; color: var(--text-muted); } .btn-refresh { background: transparent; border: 1px solid var(--border); color: var(--text-muted); padding: 2px 10px; font-family: var(--font); font-size: .75em; cursor: pointer; transition: all .15s; } .btn-refresh:hover { color:var(--green); border-color:var(--green); background:var(--green-dim); text-shadow:var(--glow); } /* ── Topology ─────────────────────────────────────────────────────── */ .topology { background: var(--bg2); border: 1px solid var(--border); padding: 20px 16px 16px; margin-bottom: 16px; text-align: center; overflow-x: auto; position: relative; } .topology::before { content:'┌'; position:absolute; top:-1px; left:-1px; color:var(--green); font-size:.85rem; line-height:1; } .topology::after { content:'┐'; position:absolute; top:-1px; right:-1px; color:var(--green); font-size:.85rem; line-height:1; } .topo-row { display:flex; justify-content:center; gap:16px; flex-wrap:wrap; align-items:center; } .topo-row-internet { margin-bottom:2px; } .topo-hosts-row { flex-wrap:wrap; gap:10px; } .topo-connectors { display:flex; justify-content:center; gap:80px; height:22px; margin:0; } .topo-connectors.single { gap:0; } .topo-connectors.wide { gap:44px; } .topo-line { width:1px; height:100%; background:var(--green); opacity:.4; } .topo-line-labeled { position:relative; } .topo-line-labeled::after { content: attr(data-link-label); position: absolute; left: 6px; top: 50%; transform: translateY(-50%); font-size: .62em; color: var(--amber); text-shadow: var(--glow-amber); white-space: nowrap; letter-spacing: .05em; } .topo-node { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 7px 12px; border: 1px solid var(--border); background: var(--bg3); min-width: 94px; font-size: .75em; position: relative; transition: border-color .2s; } .topo-node::before { content:'┌'; position:absolute; top:-1px; left:-1px; color:var(--green); font-size:.8rem; line-height:1; } .topo-node::after { content:'┐'; position:absolute; top:-1px; right:-1px; color:var(--green); font-size:.8rem; line-height:1; } .topo-internet { border-color:var(--cyan); color:var(--cyan); text-shadow:var(--glow-cyan); font-weight:bold; } .topo-switch { border-color:var(--amber); color:var(--amber); text-shadow:var(--glow-amber); } .topo-host { cursor:default; } .topo-icon { font-size:1.1em; } .topo-label { font-weight:bold; letter-spacing:.03em; } .topo-badge { font-size:.68em; padding:1px 5px; border:1px solid; letter-spacing:.03em; } .topo-badge-up { color:var(--green); border-color:var(--green); text-shadow:var(--glow); } .topo-badge-down { color:var(--red); border-color:var(--red); text-shadow:var(--glow-red); animation:pulse-glow 1.5s infinite; } .topo-badge-degraded { color:var(--orange); border-color:var(--orange); } .topo-status-up { border-color:var(--green); box-shadow:0 0 8px rgba(0,255,65,.2); } .topo-status-down { border-color:var(--red); box-shadow:0 0 8px rgba(255,68,68,.3); } .topo-status-degraded { border-color:var(--orange); box-shadow:0 0 8px rgba(255,140,0,.2); } .topo-status-dot { width:7px; height:7px; border:1px solid var(--text-muted); background:transparent; position:absolute; top:5px; right:5px; } /* ── Host cards ───────────────────────────────────────────────────── */ .host-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(248px, 1fr)); gap: 12px; } .host-card { background: var(--bg2); border: 1px solid var(--border); padding: 12px; position: relative; transition: border-color .2s, box-shadow .2s; } .host-card::before { content:'┌'; position:absolute; top:-1px; left:-1px; color:var(--green); font-size:.85rem; line-height:1; } .host-card::after { content:'┐'; position:absolute; top:-1px; right:-1px; color:var(--green); font-size:.85rem; line-height:1; } .host-card:hover { border-color:var(--green); box-shadow:0 0 12px rgba(0,255,65,.12); } .host-card-up { border-left: 3px solid var(--green); } .host-card-down { border-left: 3px solid var(--red); box-shadow: inset 3px 0 10px rgba(255,68,68,.08); } .host-card-degraded { border-left: 3px solid var(--orange); } .host-card-header { margin-bottom: 8px; } .host-name-row { display:flex; align-items:center; gap:6px; margin-bottom:3px; } .host-name { font-weight: bold; font-size: .88em; color: var(--amber); text-shadow: var(--glow-amber); letter-spacing: .04em; } .host-meta { display:flex; gap:6px; align-items:center; flex-wrap:wrap; } .host-ip { font-size:.72em; color:var(--text-muted); letter-spacing:.02em; } .host-source { font-size: .65em; padding: 1px 5px; border: 1px solid; letter-spacing: .04em; font-weight: bold; } .source-prometheus { color:#e8703a; border-color:rgba(232,112,58,.4); } .source-ping { color:var(--cyan); border-color:var(--cyan-dim); } .iface-list { border-top:1px solid var(--border); padding-top:6px; margin-bottom:8px; } .iface-row { display:flex; align-items:center; gap:6px; padding:2px 0; } .iface-name { font-size:.78em; flex:1; color:var(--text-dim); letter-spacing:.01em; } .iface-state { font-size:.72em; font-weight:bold; letter-spacing:.04em; } .state-up { color:var(--green); text-shadow:var(--glow); } .state-down { color:var(--red); text-shadow:var(--glow-red); } .state-initial_down { color:var(--text-muted); } .host-ping-note { font-size:.72em; color:var(--text-muted); border-top:1px solid var(--border); padding-top:6px; margin-bottom:8px; } .host-actions { border-top:1px solid var(--border); padding-top:7px; display:flex; gap:5px; flex-wrap:wrap; } /* ── Status dots ──────────────────────────────────────────────────── */ .host-status-dot, .iface-dot, .dot-up, .dot-down, .dot-degraded, .dot-unknown, .dot-initial_down { display: inline-block; width: 8px; height: 8px; border: 1px solid; flex-shrink: 0; } .dot-up, .host-status-dot.dot-up { border-color:var(--green); background:var(--green); box-shadow:0 0 4px var(--green); } .dot-down, .host-status-dot.dot-down { border-color:var(--red); background:var(--red); animation:pulse-red 1.5s infinite; } .dot-degraded { border-color:var(--orange); background:var(--orange); } .dot-unknown, .dot-initial_down { border-color:var(--text-muted); background:transparent; } /* ── Badges ───────────────────────────────────────────────────────── */ .badge { display: inline-block; font-size: .7em; font-weight: bold; padding: 1px 6px; border: 1px solid; letter-spacing: .05em; text-transform: uppercase; } .badge::before { content:'['; } .badge::after { content:']'; } .badge-critical { color:var(--red); border-color:var(--red); text-shadow:var(--glow-red); } .badge-warning { color:var(--orange); border-color:var(--orange); } .badge-info { color:var(--cyan); border-color:var(--cyan-dim); } .badge-ok { color:var(--green); border-color:var(--border); text-shadow:var(--glow); } .badge-neutral { color:var(--text-muted); border-color:var(--text-muted); } .badge-suppressed{ font-size:.9em; padding:0; border:none; color:var(--text-muted); } /* ── Tables ───────────────────────────────────────────────────────── */ .table-wrap { background: var(--bg2); border: 1px solid var(--border); overflow: hidden; position: relative; } .table-wrap::before { content:'┌'; position:absolute; top:-1px; left:-1px; color:var(--green); font-size:.85rem; line-height:1; } .table-wrap::after { content:'┐'; position:absolute; top:-1px; right:-1px; color:var(--green); font-size:.85rem; line-height:1; } .data-table { width:100%; border-collapse:collapse; } .data-table th { background: var(--bg3); padding: 8px 12px; text-align: left; font-size: .7em; font-weight: bold; color: var(--amber); text-transform: uppercase; letter-spacing: .08em; border-bottom: 1px solid var(--border); white-space: nowrap; text-shadow: var(--glow-amber); } .data-table th::before { content:'> '; color:var(--green); } .data-table td { padding: 7px 12px; border-bottom: 1px solid rgba(0,255,65,.08); vertical-align: middle; font-size: .83em; } .data-table tr:last-child td { border-bottom:none; } .data-table tr:hover td { background:var(--bg-hover); } .row-critical td { background:rgba(255,68,68,.03); } .row-critical td:first-child { border-left:2px solid var(--red); } .row-warning td { background:rgba(255,140,0,.03); } .row-warning td:first-child { border-left:2px solid var(--orange); } .row-resolved td { opacity:.5; } .data-table-sm td, .data-table-sm th { padding:5px 10px; } .ts-cell { color:var(--text-muted); font-size:.75em; white-space:nowrap; } .desc-cell { max-width:280px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; } .ticket-link{ color:var(--amber); text-shadow:var(--glow-amber); font-weight:bold; } .empty-state { padding:28px; text-align:center; color:var(--text-muted); font-size:.82em; } .empty-row td{ text-align:center; color:var(--text-muted); } /* ── Buttons ──────────────────────────────────────────────────────── */ .btn { display: inline-flex; align-items: center; gap: 5px; padding: 6px 14px; border: 1px solid; cursor: pointer; font-family: var(--font); font-size: .8em; font-weight: bold; letter-spacing: .05em; text-transform: uppercase; background: transparent; transition: all .15s; } .btn:hover { transform: translateY(-1px); } .btn-primary { color:var(--green); border-color:var(--green); text-shadow:var(--glow); } .btn-primary::before { content:'> '; color:var(--amber); } .btn-primary:hover { background:var(--green-dim); box-shadow:var(--glow); } .btn-secondary { color:var(--text-dim); border-color:var(--border); } .btn-secondary:hover { color:var(--green); border-color:var(--green); background:var(--bg-hover); } .btn-danger { color:var(--red); border-color:rgba(255,68,68,.35); } .btn-danger:hover { background:var(--red-dim); border-color:var(--red); text-shadow:var(--glow-red); } .btn-lg { padding:8px 18px; font-size:.85em; } .btn-sm { padding: 2px 8px; font-family: var(--font); font-size: .7em; font-weight: bold; border: 1px solid; cursor: pointer; background: transparent; letter-spacing: .04em; transition: all .15s; } .btn-suppress { color:var(--text-muted); border-color:var(--text-muted); } .btn-suppress:hover { color:var(--amber); border-color:var(--amber); } .btn-danger.btn-sm { color:var(--red); border-color:rgba(255,68,68,.35); } .btn-danger.btn-sm:hover{ color:var(--red); border-color:var(--red); text-shadow:var(--glow-red); } /* ── Modal ────────────────────────────────────────────────────────── */ .modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.8); z-index: 200; display: flex; align-items: center; justify-content: center; } .modal { background: var(--bg2); border: 1px solid var(--green); box-shadow: 0 0 30px rgba(0,255,65,.18); width: 480px; max-width: 95vw; padding: 20px; position: relative; } .modal::before { content:'┌'; position:absolute; top:-1px; left:-1px; color:var(--green); text-shadow:var(--glow); font-size:.9rem; line-height:1; } .modal::after { content:'┐'; position:absolute; top:-1px; right:-1px; color:var(--green); text-shadow:var(--glow); font-size:.9rem; line-height:1; } .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; border-bottom: 1px solid var(--border); padding-bottom: 10px; } .modal-header h3 { font-size:.88em; color:var(--amber); text-shadow:var(--glow-amber); text-transform:uppercase; letter-spacing:.08em; } .modal-header h3::before { content:'>> '; color:var(--green); } .modal-close { background: none; border: 1px solid var(--border); cursor: pointer; font-size: .82em; color: var(--text-muted); padding: 2px 8px; font-family: var(--font); transition: all .15s; } .modal-close:hover { color:var(--red); border-color:var(--red); } .modal-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--border); } /* ── Forms ────────────────────────────────────────────────────────── */ .form-card { background: var(--bg2); border: 1px solid var(--border); padding: 16px; position: relative; } .form-card::before { content:'┌'; position:absolute; top:-1px; left:-1px; color:var(--green); font-size:.85rem; line-height:1; } .form-card::after { content:'┐'; position:absolute; top:-1px; right:-1px; color:var(--green); font-size:.85rem; line-height:1; } .form-row { display:flex; gap:12px; flex-wrap:wrap; margin-bottom:10px; } .form-row-align { align-items:flex-end; } .form-group { display:flex; flex-direction:column; gap:4px; min-width:150px; flex:1; } .form-group-wide{ flex:3; } .form-group-submit { flex:0 0 auto; min-width:unset; } .form-group label { font-size: .7em; font-weight: bold; color: var(--amber); text-transform: uppercase; letter-spacing: .07em; text-shadow: var(--glow-amber); } .form-group input, .form-group select { padding: 6px 9px; border: 1px solid var(--border); font-family: var(--font); font-size: .8em; background: var(--bg3); color: var(--text); transition: border-color .15s, box-shadow .15s; } .form-group input::placeholder { color: var(--text-muted); } .form-group input:focus, .form-group select:focus { outline: none; border-color: var(--amber); box-shadow: 0 0 6px rgba(255,176,0,.18); } .form-group select option { background: var(--bg3); color: var(--text); } .form-hint { font-size:.7em; color:var(--text-muted); margin-top:2px; } .required { color:var(--red); } /* ── Duration pills ───────────────────────────────────────────────── */ .duration-pills { display:flex; gap:5px; flex-wrap:wrap; margin-bottom:5px; } .pill { padding: 3px 10px; border: 1px solid var(--border); background: transparent; font-family: var(--font); font-size: .72em; font-weight: bold; cursor: pointer; color: var(--text-muted); transition: all .15s; letter-spacing: .04em; } .pill:hover { border-color:var(--green); color:var(--green); background:var(--green-dim); } .pill.active, .pill-manual.active { border-color:var(--amber); color:var(--amber); background:var(--amber-dim); text-shadow:var(--glow-amber); } /* ── Targets grid ─────────────────────────────────────────────────── */ .targets-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(180px, 1fr)); gap:10px; } .target-card { background: var(--bg2); border: 1px solid var(--border); padding: 10px; position: relative; } .target-card::before { content:'┌'; position:absolute; top:-1px; left:-1px; color:var(--green); font-size:.78rem; line-height:1; } .target-card::after { content:'┐'; position:absolute; top:-1px; right:-1px; color:var(--green); font-size:.78rem; line-height:1; } .target-name { font-weight:bold; font-size:.82em; margin-bottom:3px; color:var(--amber); } .target-type { font-size:.7em; color:var(--text-muted); margin-bottom:6px; } .target-ifaces{ display:flex; flex-wrap:wrap; gap:3px; } .iface-chip { font-family:var(--font); font-size:.65em; background:var(--bg3); border:1px solid var(--border); padding:1px 5px; color:var(--text-dim); } /* ── Toast ────────────────────────────────────────────────────────── */ .toast-container { position:fixed; bottom:20px; right:20px; z-index:300; display:flex; flex-direction:column; gap:7px; } .toast { padding: 9px 16px; border: 1px solid; font-family: var(--font); font-size: .8em; font-weight: bold; background: var(--bg2); animation: slide-in .15s ease; letter-spacing: .04em; } .toast::before { content:'>> '; } .toast-success { color:var(--green); border-color:var(--green); text-shadow:var(--glow); } .toast-error { color:var(--red); border-color:var(--red); text-shadow:var(--glow-red); } /* ── Link debug page ──────────────────────────────────────────────── */ .link-host-list { display:flex; flex-direction:column; gap:18px; } .link-host-panel { background: var(--bg2); border: 1px solid var(--border); position: relative; } .link-host-panel::before { content:'╔'; position:absolute; top:-1px; left:-1px; color:var(--green); text-shadow:var(--glow); font-size:1rem; line-height:1; } .link-host-panel::after { content:'╗'; position:absolute; top:-1px; right:-1px; color:var(--green); text-shadow:var(--glow); font-size:1rem; line-height:1; } .link-host-title { display: flex; align-items: center; gap: 12px; padding: 9px 16px; background: var(--bg3); border-bottom: 1px solid var(--border); } .link-host-name { font-weight:bold; font-size:.88em; color:var(--amber); text-shadow:var(--glow-amber); letter-spacing:.05em; } .link-host-name::before { content:'>> '; color:var(--green); } .link-host-ip { font-size:.72em; color:var(--text-muted); } .link-host-upd { font-size:.65em; color:var(--text-muted); margin-left:auto; } .link-ifaces-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); } .link-iface-card { border-right: 1px solid rgba(0,255,65,.15); border-bottom: 1px solid rgba(0,255,65,.15); padding: 12px 14px; } .link-iface-card:last-child { border-right:none; } .link-iface-header { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; padding-bottom: 6px; border-bottom: 1px solid rgba(0,255,65,.12); } .link-iface-name { font-weight:bold; font-size:.84em; color:var(--amber); text-shadow:var(--glow-amber); flex:1; } .link-iface-speed { font-size:.75em; color:var(--cyan); text-shadow:var(--glow-cyan); font-weight:bold; } .link-iface-type { font-size:.65em; color:var(--text-muted); padding:1px 5px; border:1px solid var(--text-muted); letter-spacing:.04em; } .link-iface-type.type-fibre { color:var(--cyan); border-color:var(--cyan-dim); text-shadow:var(--glow-cyan); } .link-iface-type.type-copper{ color:var(--green); border-color:var(--border); } .link-iface-type.type-da { color:var(--amber); border-color:var(--amber-dim); } /* Link stats 2-column grid */ .link-stats-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 16px; margin-bottom: 10px; } .link-stat { display:flex; flex-direction:column; gap:1px; } .link-stat-label { font-size:.6em; color:var(--text-muted); text-transform:uppercase; letter-spacing:.07em; } .link-stat-value { font-size:.78em; font-weight:bold; color:var(--text-dim); } .val-good { color:var(--green); text-shadow:var(--glow); } .val-warn { color:var(--orange); } .val-crit { color:var(--red); text-shadow:var(--glow-red); } .val-neutral { color:var(--text-muted); } .val-cyan { color:var(--cyan); text-shadow:var(--glow-cyan); } /* Traffic bars */ .traffic-section { margin-top:8px; padding-top:8px; border-top:1px solid rgba(0,255,65,.1); } .traffic-row { display:flex; align-items:center; gap:8px; margin-bottom:5px; } .traffic-label { font-size:.62em; color:var(--text-muted); width:20px; text-transform:uppercase; letter-spacing:.04em; flex-shrink:0; } .traffic-bar-track { flex:1; height:5px; background:var(--bg); border:1px solid rgba(0,255,65,.2); position:relative; overflow:hidden; } .traffic-bar-fill { height:100%; position:absolute; left:0; top:0; transition:width .4s; } .traffic-tx { background:var(--cyan); box-shadow:0 0 3px rgba(0,255,255,.4); } .traffic-rx { background:var(--green); box-shadow:0 0 3px rgba(0,255,65,.4); } .traffic-value { font-size:.7em; color:var(--text-dim); width:68px; text-align:right; flex-shrink:0; } /* SFP / optical panel */ .sfp-panel { margin-top: 10px; padding: 10px 10px 8px; background: var(--bg3); border: 1px solid rgba(0,255,255,.2); position: relative; } .sfp-panel::before { content: '[ SFP / OPTICAL ]'; position: absolute; top: -8px; left: 10px; font-size: .6em; color: var(--cyan); text-shadow: var(--glow-cyan); background: var(--bg3); padding: 0 4px; letter-spacing: .09em; font-weight: bold; } .sfp-vendor-row { font-size:.7em; color:var(--text-muted); margin-bottom:8px; } .sfp-vendor-row span { color:var(--text-dim); } .sfp-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px 12px; } .sfp-stat { display:flex; flex-direction:column; gap:1px; } .sfp-stat-label { font-size:.58em; color:var(--text-muted); text-transform:uppercase; letter-spacing:.07em; } .sfp-stat-value { font-size:.78em; font-weight:bold; } /* Power level with bar */ .power-row { display:flex; align-items:center; gap:5px; margin-top:1px; } .power-track { flex:1; height:3px; background:var(--bg); border:1px solid rgba(0,255,65,.2); position:relative; overflow:hidden; } .power-fill { height:100%; position:absolute; left:0; top:0; transition:width .4s; } .power-ok { background:var(--green); box-shadow:0 0 3px var(--green); } .power-warn { background:var(--orange); } .power-crit { background:var(--red); box-shadow:0 0 3px var(--red); } /* Link panel states */ .link-no-data { padding:14px; color:var(--text-muted); font-size:.78em; text-align:center; } .link-loading { padding:20px; text-align:center; color:var(--text-muted); font-size:.8em; } .link-loading::after { content:' ...'; animation:blink 1s step-end infinite; } /* Counters (errors/drops) */ .counter-zero { color:var(--green); } .counter-nonzero { color:var(--red); text-shadow:var(--glow-red); } /* ── Responsive ───────────────────────────────────────────────────── */ @media (max-width: 768px) { .host-grid { grid-template-columns:1fr; } .topology { display:none; } .form-row { flex-direction:column; } .status-bar { flex-direction:column; align-items:flex-start; } .link-ifaces-grid { grid-template-columns:1fr; } .sfp-grid { grid-template-columns:1fr 1fr; } .header-nav { display:none; } }