/* ── Google Fonts ──────────────────────────────────────────────────────────── */ @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400;500;600&display=swap'); /* ── Design Tokens ─────────────────────────────────────────────────────────── */ :root { --bg0: #090909; --bg1: #0e0e0e; --bg2: #141414; --bg3: #1c1c1c; --bg4: #242424; --border: #252525; --border-hi: #383838; --amber: #f0a500; --amber-lo: rgba(240,165,0,0.12); --amber-dim: #7a5200; --red: #e03434; --red-lo: rgba(224,52,52,0.12); --green: #00c87a; --green-lo: rgba(0,200,122,0.12); --cyan: #00b8d4; --cyan-lo: rgba(0,184,212,0.12); --purple: #a78bfa; --purple-lo: rgba(167,139,250,0.12); --white: #e8e4d9; --muted: #5a5a54; --muted2: #38382e; --font: 'IBM Plex Mono','Courier New',monospace; --r: 3px; } /* ── Reset ─────────────────────────────────────────────────────────────────── */ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } html, body { height: 100%; overflow: hidden; } body { background: var(--bg0); color: var(--white); font-family: var(--font); font-size: 11px; line-height: 1.5; display: flex; flex-direction: column; } /* ── Scrollbar ─────────────────────────────────────────────────────────────── */ ::-webkit-scrollbar { width: 3px; height: 3px; } ::-webkit-scrollbar-track { background: var(--bg0); } ::-webkit-scrollbar-thumb { background: var(--muted2); } /* ── Loading Overlay ───────────────────────────────────────────────────────── */ #loading-overlay { position: fixed; inset: 0; background: var(--bg0); z-index: 9999; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px; transition: opacity 0.4s ease; } #loading-overlay.hidden { opacity: 0; pointer-events: none; } .loading-brand { color: var(--amber); font-size: 16px; font-weight: 600; letter-spacing: 4px; } .loading-bar-wrap { width: 220px; height: 2px; background: var(--bg3); border-radius: 2px; overflow: hidden; } .loading-bar-fill { height: 2px; background: var(--amber); border-radius: 2px; animation: loadbar 1.6s ease-in-out forwards; } @keyframes loadbar { 0% { width: 0%; } 60% { width: 80%; } 100% { width: 100%; } } .loading-status { font-size: 9px; color: var(--muted); letter-spacing: 1.5px; } /* ── Top Bar ───────────────────────────────────────────────────────────────── */ .topbar { height: 38px; background: var(--bg1); border-bottom: 1px solid var(--amber); display: flex; align-items: center; justify-content: space-between; padding: 0 14px; flex-shrink: 0; z-index: 200; } .brand { color: var(--amber); font-weight: 600; font-size: 12px; letter-spacing: 3px; } .tabs { display: flex; gap: 1px; } .tab { background: none; border: none; color: var(--muted); font-family: var(--font); font-size: 10px; padding: 0 14px; height: 38px; cursor: pointer; letter-spacing: 1.5px; text-transform: uppercase; border-bottom: 2px solid transparent; transition: color 0.15s, border-color 0.15s; } .tab:hover { color: var(--white); } .tab.active { color: var(--amber); border-bottom-color: var(--amber); } .topbar-right { display: flex; align-items: center; gap: 12px; font-size: 9px; color: var(--muted); } .live-dot { width: 5px; height: 5px; background: var(--green); border-radius: 50%; display: inline-block; animation: blink 2s infinite; } @keyframes blink { 0%,100% { opacity: 1; } 50% { opacity: 0.3; } } /* ── API Status Banner ─────────────────────────────────────────────────────── */ #api-banner { height: 22px; background: var(--bg2); border-bottom: 1px solid var(--border); display: flex; align-items: center; padding: 0 14px; gap: 14px; flex-shrink: 0; font-size: 9px; letter-spacing: 1px; } .api-chip { display: flex; align-items: center; gap: 4px; color: var(--muted); } .api-chip.ok .api-dot { background: var(--green); } .api-chip.err .api-dot { background: var(--red); } .api-chip.busy .api-dot { background: var(--amber); animation: blink 1s infinite; } .api-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--muted2); } /* ── Body Layout ───────────────────────────────────────────────────────────── */ .body { flex: 1; display: grid; grid-template-columns: 200px 1fr 260px; overflow: hidden; min-height: 0; } /* ── Left Sidebar ──────────────────────────────────────────────────────────── */ .sidebar { background: var(--bg1); border-right: 1px solid var(--border); display: flex; flex-direction: column; overflow: hidden; } .sb-header { padding: 7px 10px; background: var(--bg2); border-bottom: 1px solid var(--border); color: var(--amber); font-size: 9px; letter-spacing: 2px; text-transform: uppercase; display: flex; justify-content: space-between; align-items: center; flex-shrink: 0; } .sb-seg { padding: 6px 8px; border-bottom: 1px solid var(--border); flex-shrink: 0; } .seg-btn { display: flex; gap: 3px; } .seg-btn button { flex: 1; background: var(--bg3); border: 1px solid var(--border); color: var(--muted); font-family: var(--font); font-size: 9px; padding: 4px; cursor: pointer; border-radius: var(--r); letter-spacing: 1px; transition: all 0.15s; } .seg-btn button.active { background: var(--amber); color: #000; border-color: var(--amber); font-weight: 600; } .sb-search { padding: 6px 8px; border-bottom: 1px solid var(--border); flex-shrink: 0; } .sb-search input { width: 100%; background: var(--bg3); border: 1px solid var(--border); color: var(--white); font-family: var(--font); font-size: 10px; padding: 4px 8px; outline: none; border-radius: var(--r); transition: border-color 0.15s; } .sb-search input:focus { border-color: var(--amber-dim); } .ticker-list { overflow-y: auto; flex: 1; } .ticker-row { display: flex; align-items: center; padding: 5px 10px; cursor: pointer; border-bottom: 1px solid var(--border); transition: background 0.1s; gap: 6px; } .ticker-row:hover { background: var(--bg3); } .ticker-row.sel { background: var(--amber-lo); border-left: 2px solid var(--amber); } .ticker-row.rippling { animation: rowripple 0.6s ease-out; } .ticker-row.rippling-up { animation: rowripple-up 0.6s ease-out; } @keyframes rowripple { 0% { background: rgba(224,52,52,.35); } 100% { background: transparent; } } @keyframes rowripple-up { 0% { background: rgba(0,200,122,.35); } 100% { background: transparent; } } .t-sym { color: var(--amber); font-size: 10px; font-weight: 600; width: 62px; flex-shrink: 0; } .t-phi { font-size: 9px; text-align: right; flex-shrink: 0; width: 32px; } .t-bar { flex: 1; height: 3px; background: var(--bg4); border-radius: 2px; overflow: hidden; } .t-bar-fill { height: 3px; border-radius: 2px; transition: width 0.3s; } /* ── Center Panel ──────────────────────────────────────────────────────────── */ .center { display: flex; flex-direction: column; overflow: hidden; background: var(--bg0); position: relative; } .view { display: none; flex: 1; flex-direction: column; overflow: hidden; } .view.active { display: flex; } .view-header { padding: 8px 14px; background: var(--bg2); border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; } .vh-title { color: var(--amber); font-size: 10px; letter-spacing: 2px; font-weight: 600; } .vh-meta { color: var(--muted); font-size: 9px; } .view-body { flex: 1; overflow: auto; padding: 12px; position: relative; } /* ── Legend ────────────────────────────────────────────────────────────────── */ .legend { display: flex; gap: 14px; align-items: center; padding: 6px 12px; border-bottom: 1px solid var(--border); flex-shrink: 0; flex-wrap: wrap; } .leg-item { display: flex; align-items: center; gap: 5px; font-size: 9px; color: var(--muted); } .leg-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } .leg-line { width: 18px; height: 2px; flex-shrink: 0; } /* ── Heatmap ───────────────────────────────────────────────────────────────── */ .hm-wrap { overflow: auto; padding: 0; } #heatmap-svg { display: block; } .hm-cell { cursor: pointer; transition: opacity 0.15s; } .hm-cell:hover { opacity: 0.75; stroke: #fff !important; stroke-width: 1.5 !important; } .hm-cell.ripple-out { animation: hmripple 1s ease-out forwards; } .hm-cell.ripple-in { animation: hmripple-in 0.8s ease-out forwards; } .hm-cell.ripple-pulse { animation: hmpulse 1.2s ease-in-out 3; } @keyframes hmripple { 0% { opacity:1; fill: rgba(224,52,52,0.9); } 100% { opacity: 1; } } @keyframes hmripple-in { 0% { opacity:1; fill: rgba(0,200,122,0.9); } 100% { opacity: 1; } } @keyframes hmpulse { 0%,100% { opacity:1; } 50% { opacity: 0.3; } } /* ── Network ───────────────────────────────────────────────────────────────── */ #net-svg { display: block; width: 100%; height: 100%; } .net-node { cursor: pointer; } .net-node:hover circle { stroke-width: 2; } .net-edge { transition: stroke-width 0.2s, stroke-opacity 0.2s; } /* ── Right Panel ───────────────────────────────────────────────────────────── */ .rpanel { background: var(--bg1); border-left: 1px solid var(--border); display: flex; flex-direction: column; overflow: hidden; } .rp-sec { border-bottom: 1px solid var(--border); flex-shrink: 0; } .rp-head { padding: 6px 10px; background: var(--bg2); border-bottom: 1px solid var(--border); font-size: 9px; letter-spacing: 2px; color: var(--cyan); font-weight: 600; text-transform: uppercase; display: flex; justify-content: space-between; align-items: center; } .rp-row { display: flex; justify-content: space-between; padding: 4px 10px; border-bottom: 1px solid var(--border); font-size: 10px; } .rp-k { color: var(--muted); } .rp-v { color: var(--white); } .rp-v.up { color: var(--green); } .rp-v.dn { color: var(--red); } .rp-v.am { color: var(--amber); } /* ── Inference Panel ───────────────────────────────────────────────────────── */ .infer-panel { padding: 10px; } .infer-mode { display: flex; gap: 4px; margin-bottom: 10px; } .infer-mode button { flex: 1; background: var(--bg3); border: 1px solid var(--border); color: var(--muted); font-family: var(--font); font-size: 9px; padding: 5px; cursor: pointer; border-radius: var(--r); letter-spacing: 1px; transition: all 0.15s; } .infer-mode button.active { font-weight: 600; } .infer-mode button.m-assert.active { background: var(--cyan-lo); color: var(--cyan); border-color: var(--cyan); } .infer-mode button.m-intervene.active { background: var(--amber-lo); color: var(--amber); border-color: var(--amber); } .infer-mode button.m-counter.active { background: var(--purple-lo); color: var(--purple); border-color: var(--purple); } .infer-form { background: var(--bg2); border: 1px solid var(--border); border-radius: var(--r); padding: 10px; margin-bottom: 8px; } .infer-label { font-size: 9px; color: var(--muted); letter-spacing: 1.5px; text-transform: uppercase; margin-bottom: 5px; } .infer-select { width: 100%; background: var(--bg3); border: 1px solid var(--border); color: var(--white); font-family: var(--font); font-size: 10px; padding: 5px 8px; outline: none; border-radius: var(--r); margin-bottom: 8px; cursor: pointer; } .infer-select:focus { border-color: var(--amber-dim); } .slider-wrap { margin-bottom: 10px; } .slider-row { display: flex; justify-content: space-between; margin-bottom: 4px; } .slider-val { color: var(--amber); font-weight: 600; font-size: 10px; } input[type=range] { width: 100%; accent-color: var(--amber); cursor: pointer; height: 3px; } .run-btn { width: 100%; padding: 8px; border: none; font-family: var(--font); font-size: 10px; font-weight: 600; letter-spacing: 2px; cursor: pointer; border-radius: var(--r); transition: opacity 0.2s, transform 0.2s; } .run-btn.assert { background: var(--cyan); color: #000; } .run-btn.intervene { background: var(--amber); color: #000; } .run-btn.counter { background: var(--purple); color: #000; } .run-btn:hover { opacity: 0.85; transform: translateY(-1px); } .run-btn:active { transform: translateY(0); } .run-btn:disabled { opacity: 0.4; cursor: not-allowed; } /* ── Result Cards ──────────────────────────────────────────────────────────── */ .result-card { background: var(--bg2); border: 1px solid var(--border); border-radius: var(--r); padding: 10px; margin-bottom: 8px; position: relative; overflow: hidden; } .result-card::before { content: ''; position: absolute; top: 0; left: 0; width: 3px; height: 100%; } .result-card.assert::before { background: var(--cyan); } .result-card.intervene::before { background: var(--amber); } .result-card.counter::before { background: var(--purple); } .rc-head { font-size: 9px; letter-spacing: 1.5px; margin-bottom: 6px; font-weight: 600; } .rc-head.assert { color: var(--cyan); } .rc-head.intervene { color: var(--amber); } .rc-head.counter { color: var(--purple); } .rc-row { display: flex; justify-content: space-between; font-size: 10px; padding: 2px 0; } .rc-k { color: var(--muted); } .rc-v { color: var(--white); } .rc-v.up { color: var(--green); } .rc-v.dn { color: var(--red); } .rc-v.am { color: var(--amber); } .ate-track { height: 4px; background: var(--bg4); border-radius: 2px; margin-top: 6px; overflow: hidden; } .ate-fill { height: 4px; border-radius: 2px; transition: width 0.8s ease; } .ripple-effects { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border); } .ripple-title { font-size: 9px; color: var(--muted); letter-spacing: 1px; margin-bottom: 5px; } .ripple-chip { display: inline-flex; align-items: center; gap: 4px; padding: 2px 7px; border-radius: 2px; font-size: 9px; margin: 2px; border: 1px solid; } .ripple-chip.up { background: var(--green-lo); border-color: var(--green); color: var(--green); } .ripple-chip.dn { background: var(--red-lo); border-color: var(--red); color: var(--red); } /* ── News Feed ─────────────────────────────────────────────────────────────── */ .news-item { padding: 7px 10px; border-bottom: 1px solid var(--border); cursor: pointer; transition: background 0.1s; } .news-item:hover { background: var(--bg3); } .news-top { display: flex; align-items: center; gap: 6px; margin-bottom: 3px; } .news-score { font-size: 8px; padding: 1px 5px; border-radius: 2px; font-weight: 600; } .news-score.hi { background: var(--green-lo); color: var(--green); } .news-score.md { background: var(--amber-lo); color: var(--amber); } .news-score.lo { background: var(--red-lo); color: var(--red); } .news-sym { color: var(--amber); font-size: 9px; font-weight: 600; } .news-text { font-size: 9px; color: var(--muted); line-height: 1.5; margin-bottom: 4px; } .news-tags { display: flex; gap: 3px; flex-wrap: wrap; } .news-tag { font-size: 8px; padding: 1px 5px; border: 1px solid var(--border); color: var(--muted); border-radius: 2px; } /* ── HHKD View ─────────────────────────────────────────────────────────────── */ .phi-row { display: flex; align-items: center; gap: 8px; padding: 4px 10px; border-bottom: 1px solid var(--border); cursor: pointer; transition: background 0.1s; } .phi-row:hover { background: var(--bg3); } .phi-sym { width: 66px; font-size: 10px; color: var(--amber); font-weight: 600; flex-shrink: 0; } .phi-bar-wrap { flex: 1; height: 8px; background: var(--bg4); border-radius: 4px; overflow: hidden; } .phi-bar-fill { height: 8px; border-radius: 4px; transition: width 0.4s; } .phi-val { width: 36px; text-align: right; font-size: 10px; flex-shrink: 0; } /* ── Sector View ───────────────────────────────────────────────────────────── */ .sector-grid { padding: 10px; display: flex; flex-direction: column; gap: 8px; } .sec-card { background: var(--bg2); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; } .sec-card-head { padding: 7px 12px; display: flex; align-items: center; justify-content: space-between; cursor: pointer; transition: background 0.1s; } .sec-card-head:hover { background: var(--bg3); } .sec-name { font-size: 11px; font-weight: 600; letter-spacing: 1px; color: var(--white); } .sec-phi { font-size: 10px; } .sec-members { display: flex; flex-wrap: wrap; gap: 4px; padding: 8px; } .sec-chip { padding: 3px 9px; border: 1px solid var(--border); font-size: 9px; border-radius: 2px; cursor: pointer; transition: all 0.15s; } .sec-chip:hover { border-color: var(--amber); color: var(--amber); } .sec-chip.rippling { animation: chipripple 0.7s ease-out; } .sec-chip.rippling-up { animation: chipripple-up 0.7s ease-out; } @keyframes chipripple { 0% { background: rgba(224,52,52,.4); border-color: var(--red); } 100% { background: transparent; } } @keyframes chipripple-up { 0% { background: rgba(0,200,122,.4); border-color: var(--green); } 100% { background: transparent; } } /* ── Node Popup ────────────────────────────────────────────────────────────── */ .node-popup { position: fixed; z-index: 500; background: var(--bg2); border: 1px solid var(--amber); border-radius: var(--r); padding: 12px; min-width: 200px; max-width: 260px; pointer-events: none; display: none; box-shadow: 0 8px 32px rgba(0,0,0,.6); } .np-head { color: var(--amber); font-size: 12px; font-weight: 600; margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; } .np-row { display: flex; justify-content: space-between; padding: 3px 0; border-bottom: 1px solid var(--border); font-size: 10px; } .np-row:last-child { border: none; } .np-k { color: var(--muted); } .np-v { color: var(--white); } .np-v.up { color: var(--green); } .np-v.dn { color: var(--red); } .np-v.am { color: var(--amber); } /* ── Status Strip ──────────────────────────────────────────────────────────── */ .status-strip { height: 22px; background: var(--bg2); border-top: 1px solid var(--border); display: flex; align-items: center; padding: 0 10px; gap: 16px; flex-shrink: 0; overflow: hidden; } .ss-chip { font-size: 9px; display: flex; gap: 5px; white-space: nowrap; } .ss-k { color: var(--muted); } .ss-v { color: var(--white); } .ss-v.am { color: var(--amber); } .ss-v.up { color: var(--green); } /* ── Accordion ─────────────────────────────────────────────────────────────── */ .accordion { border: 1px solid var(--border); border-radius: var(--r); margin-bottom: 6px; overflow: hidden; } .acc-head { display: flex; align-items: center; justify-content: space-between; padding: 7px 10px; cursor: pointer; background: var(--bg2); user-select: none; } .acc-head:hover { background: var(--bg3); } .acc-title { font-size: 10px; color: var(--white); font-weight: 500; letter-spacing: 0.5px; } .acc-badge { font-size: 8px; padding: 1px 6px; border-radius: 2px; font-weight: 600; letter-spacing: 1px; } .acc-badge.up { background: var(--green-lo); color: var(--green); } .acc-badge.dn { background: var(--red-lo); color: var(--red); } .acc-badge.am { background: var(--amber-lo); color: var(--amber); } .acc-badge.cy { background: var(--cyan-lo); color: var(--cyan); } .acc-chevron { color: var(--muted); font-size: 10px; transition: transform 0.2s; } .acc-chevron.open { transform: rotate(180deg); } .acc-body { display: none; border-top: 1px solid var(--border); } .acc-body.open { display: block; } .acc-row { display: flex; justify-content: space-between; padding: 4px 10px; border-bottom: 1px solid var(--border); font-size: 10px; } .acc-k { color: var(--muted); } .acc-v { color: var(--white); } .acc-v.up { color: var(--green); } .acc-v.dn { color: var(--red); } .acc-v.am { color: var(--amber); } /* ── Ripple Ring ───────────────────────────────────────────────────────────── */ @keyframes pulse-ring { 0% { transform: scale(.8); opacity: 1; } 100% { transform: scale(2.5); opacity: 0; } } .ripple-ring { position: absolute; border-radius: 50%; pointer-events: none; animation: pulse-ring 0.8s ease-out forwards; } /* ── Error toast ───────────────────────────────────────────────────────────── */ #error-toast { position: fixed; bottom: 28px; left: 50%; transform: translateX(-50%) translateY(60px); background: var(--red-lo); border: 1px solid var(--red); color: var(--red); font-size: 10px; padding: 8px 16px; border-radius: var(--r); z-index: 9000; transition: transform 0.3s ease; letter-spacing: 0.5px; } #error-toast.show { transform: translateX(-50%) translateY(0); }