/* Copyright Epic Games, Inc. All Rights Reserved. */ :root, :root[data-theme="dark"] { --bg0: #0d1117; --bg1: #161b22; --bg2: #1c2128; --bg3: #21262d; --border: #30363d; --border-soft: #21262d; --fg0: #f0f6fc; --fg1: #c9d1d9; --fg2: #8b949e; --accent: #58a6ff; --accent-soft: #1c2128; --warn: #d29922; --ok: #3fb950; --fail: #f85149; --highlight: #e3b34166; } @media (prefers-color-scheme: light) { :root:not([data-theme]), :root[data-theme="system"] { --bg0: #ffffff; --bg1: #f6f8fa; --bg2: #ffffff; --bg3: #eaeef2; --border: #d0d7de; --border-soft: #d8dee4; --fg0: #1f2328; --fg1: #24292f; --fg2: #656d76; --accent: #0969da; --accent-soft: #ddf4ff; --warn: #9a6700; --ok: #1a7f37; --fail: #cf222e; --highlight: #b8860b44; } } :root[data-theme="light"] { --bg0: #ffffff; --bg1: #f6f8fa; --bg2: #ffffff; --bg3: #eaeef2; --border: #d0d7de; --border-soft: #d8dee4; --fg0: #1f2328; --fg1: #24292f; --fg2: #656d76; --accent: #0969da; --accent-soft: #ddf4ff; --warn: #9a6700; --ok: #1a7f37; --fail: #cf222e; --highlight: #b8860b44; } * { box-sizing: border-box; } html, body { margin: 0; padding: 0; height: 100%; background: var(--bg0); color: var(--fg1); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; font-size: 13px; overflow: hidden; } body { display: flex; flex-direction: column; } pre, code, .mono { font-family: 'SF Mono', 'Cascadia Mono', Consolas, 'DejaVu Sans Mono', monospace; font-size: 12px; } /* -- header ---------------------------------------------------------------- */ .header { display: flex; align-items: stretch; gap: 16px; padding: 0 16px; background: var(--bg1); border-bottom: 1px solid var(--border); flex-shrink: 0; min-height: 40px; } .header > .header-title, .header > .header-file, .header > .header-stats, .header > .header-btn { align-self: center; } .header-title { font-weight: 600; color: var(--fg0); font-size: 14px; white-space: nowrap; } .header-file { color: var(--fg2); font-family: 'SF Mono', 'Cascadia Mono', Consolas, monospace; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; } .header-stats { color: var(--fg2); font-size: 12px; display: flex; gap: 16px; } .header-stats .k { color: var(--fg2); margin-right: 4px; } .header-stats .v { color: var(--fg0); font-weight: 500; } .header-btn { background: var(--bg2); color: var(--fg1); border: 1px solid var(--border); border-radius: 6px; padding: 6px 10px; font-size: 12px; cursor: pointer; flex-shrink: 0; } .header-btn:hover { background: var(--bg3); color: var(--fg0); } /* -- layout ---------------------------------------------------------------- */ .layout { display: flex; flex: 1; min-height: 0; } .sidebar { width: 260px; flex-shrink: 0; background: var(--bg1); border-right: 1px solid var(--border); display: flex; flex-direction: column; min-height: 0; } .content { flex: 1; min-width: 0; display: flex; flex-direction: column; background: var(--bg0); } /* -- tabs ------------------------------------------------------------------ */ /* Tabs live inside the header bar at the top, alongside the title / file * path / stats. Each tab is a button that owns its own underline so the * active state aligns flush with the header's bottom border. */ .tabs { display: flex; flex-shrink: 0; height: 100%; margin-left: -8px; /* let first tab sit closer to the left edge */ } .tab { padding: 0 14px; background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--fg2); font-size: 12px; font-weight: 500; cursor: pointer; text-transform: uppercase; letter-spacing: 0.5px; white-space: nowrap; display: flex; align-items: center; margin-bottom: -1px; /* overlap header's bottom border so the underline sits flush */ } .tab:hover { color: var(--fg0); background: var(--bg2); } .tab.active { color: var(--accent); border-bottom-color: var(--accent); } /* -- sidebar sections ------------------------------------------------------ */ .sidebar-section { padding: 12px 12px; border-bottom: 1px solid var(--border-soft); flex-shrink: 0; min-height: 0; display: flex; flex-direction: column; } .sidebar-section:last-child { flex: 1; overflow-y: auto; } .sidebar-label { display: flex; align-items: baseline; gap: 6px; font-size: 10px; color: var(--fg2); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 6px; font-weight: 600; } .sidebar-action { font-size: 9px; color: var(--fg2); background: none; border: none; cursor: pointer; padding: 0; text-transform: lowercase; letter-spacing: 0; font-weight: 400; opacity: 0.7; } .sidebar-action:hover { color: var(--fg0); opacity: 1; } #search-input { width: 100%; background: var(--bg2); border: 1px solid var(--border); color: var(--fg0); padding: 5px 8px; border-radius: 4px; font-size: 12px; } #search-input:focus { outline: none; border-color: var(--accent); } .search-results { margin-top: 6px; max-height: 180px; overflow-y: auto; font-size: 12px; } .search-results .hit { padding: 3px 6px; border-radius: 3px; cursor: pointer; color: var(--fg1); display: flex; justify-content: space-between; align-items: baseline; gap: 8px; } .search-results .hit:hover { background: var(--accent-soft); color: var(--fg0); } .search-results .hit-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .search-results .hit-count { color: var(--fg2); font-size: 11px; flex-shrink: 0; } /* -- threads list ---------------------------------------------------------- */ .threads-list, .regions-list { display: flex; flex-direction: column; gap: 2px; overflow-y: auto; } .thread-group-header { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: var(--fg2); padding: 6px 4px 2px; user-select: none; } .thread-group-header[data-group] { cursor: pointer; border-radius: 3px; } .thread-group-header[data-group]:hover { color: var(--fg1); background: var(--bg2); } .thread-group-header:first-child { padding-top: 0; } .group-checkbox { margin: 0 2px 0 0; accent-color: var(--accent); cursor: pointer; } .group-chevron { display: inline-block; margin-right: 2px; transition: transform 0.15s; } .thread-group-header.collapsed .group-chevron { transform: rotate(-90deg); } .thread-row { display: flex; align-items: center; gap: 6px; padding: 3px 4px; border-radius: 3px; cursor: pointer; font-size: 12px; color: var(--fg1); } .thread-row.lane .thread-name { font-style: italic; } .thread-row:hover { background: var(--bg2); } .thread-row.empty { color: var(--fg2); opacity: 0.6; } .thread-row input[type=checkbox] { margin: 0; accent-color: var(--accent); } .thread-row .thread-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .thread-row .thread-count { color: var(--fg2); font-size: 11px; flex-shrink: 0; } /* -- views ----------------------------------------------------------------- */ .view { flex: 1; display: flex; flex-direction: column; min-height: 0; min-width: 0; overflow: hidden; } .view[hidden] { display: none; } /* -- timeline -------------------------------------------------------------- */ .view-timeline { position: relative; } .timeline-toolbar { display: flex; align-items: center; gap: 12px; padding: 6px 12px; border-bottom: 1px solid var(--border-soft); background: var(--bg1); flex-shrink: 0; } .viewport-info { color: var(--fg2); font-size: 11px; flex: 1; font-family: 'SF Mono', 'Cascadia Mono', Consolas, monospace; } .toolbar-toggle { display: flex; align-items: center; gap: 4px; font-size: 11px; color: var(--fg2); cursor: pointer; user-select: none; } .toolbar-toggle input[type="checkbox"] { margin: 0; } .btn { background: var(--bg2); border: 1px solid var(--border); color: var(--fg1); padding: 3px 10px; border-radius: 4px; font-size: 11px; cursor: pointer; } .btn:hover { background: var(--bg3); color: var(--fg0); } .timeline-frame { flex: 1; position: relative; min-height: 0; overflow: hidden; } #timeline-canvas { display: block; width: 100%; height: 100%; cursor: grab; } #timeline-canvas:active { cursor: grabbing; } .tooltip { position: absolute; background: var(--bg1); border: 1px solid var(--border); border-radius: 4px; padding: 6px 10px; font-size: 11px; color: var(--fg0); pointer-events: none; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); max-width: 360px; z-index: 10; } .tooltip .tt-name { font-weight: 600; margin-bottom: 2px; } .tooltip .tt-meta { color: var(--fg2); font-family: 'SF Mono', 'Cascadia Mono', Consolas, monospace; font-size: 10px; } .selection-panel { background: var(--bg1); border-top: 1px solid var(--border-soft); padding: 10px 14px; flex-shrink: 0; min-height: 56px; max-height: 140px; overflow-y: auto; } .selection-hint { color: var(--fg2); font-size: 11px; font-style: italic; } .selection-title { color: var(--fg0); font-weight: 600; font-size: 13px; margin-bottom: 4px; word-break: break-all; } .selection-meta { color: var(--fg2); font-size: 11px; font-family: 'SF Mono', 'Cascadia Mono', Consolas, monospace; display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 4px 16px; } .selection-meta .k { color: var(--fg2); } .selection-meta .v { color: var(--fg1); } /* -- stats table ----------------------------------------------------------- */ .view-stats { overflow-y: auto; padding: 12px; } .stats-table { width: 100%; border-collapse: collapse; font-size: 12px; } .stats-table th { text-align: left; padding: 8px 10px; background: var(--bg1); color: var(--fg2); font-weight: 600; text-transform: uppercase; font-size: 10px; letter-spacing: 0.5px; border-bottom: 1px solid var(--border); cursor: pointer; user-select: none; position: sticky; top: 0; } .stats-table th.num { text-align: right; } .stats-table th:hover { color: var(--fg0); } .stats-table th.sorted::after { content: ' ▾'; color: var(--accent); } .stats-table th.sorted.asc::after { content: ' ▴'; } .stats-table td { padding: 5px 10px; border-bottom: 1px solid var(--border-soft); color: var(--fg1); } .stats-table td.num { text-align: right; font-variant-numeric: tabular-nums; color: var(--fg0); } .stats-table tbody tr { cursor: pointer; } .stats-table tbody tr:hover { background: var(--bg1); } .stats-table tbody tr.selected { background: var(--accent-soft); } /* -- session view ---------------------------------------------------------- */ .view-session { overflow-y: auto; padding: 20px 24px; } .session-content h2 { font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: var(--fg2); margin: 24px 0 10px; border-bottom: 1px solid var(--border-soft); padding-bottom: 4px; } .session-content h2:first-child { margin-top: 0; } .session-content dl { display: grid; grid-template-columns: 150px 1fr; gap: 6px 16px; margin: 0 0 12px; font-size: 12px; } .session-content dt { color: var(--fg2); } .session-content dd { margin: 0; color: var(--fg1); font-family: 'SF Mono', 'Cascadia Mono', Consolas, monospace; word-break: break-all; } .session-content table { width: 100%; border-collapse: collapse; font-size: 12px; } .session-content table th { text-align: left; padding: 6px 10px; color: var(--fg2); font-weight: 600; font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px; border-bottom: 1px solid var(--border-soft); } .session-content table th.num { text-align: right; } .session-content table td { padding: 4px 10px; border-bottom: 1px solid var(--border-soft); color: var(--fg1); } .session-content table td.num { text-align: right; font-variant-numeric: tabular-nums; } .chan-enabled { color: var(--ok); } .chan-disabled { color: var(--fg2); } .chan-readonly { color: var(--warn); font-size: 10px; margin-left: 8px; } /* -- logs view ------------------------------------------------------------- */ .view-logs { display: flex; flex-direction: column; min-height: 0; } #logs-content { display: flex; flex-direction: column; flex: 1; min-height: 0; } .logs-toolbar { display: flex; align-items: center; gap: 16px; padding: 8px 12px; background: var(--bg1); border-bottom: 1px solid var(--border-soft); flex-shrink: 0; } .logs-filter { display: flex; align-items: center; gap: 6px; } .logs-filter-grow { flex: 1; } .logs-filter-label { color: var(--fg2); font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px; font-weight: 600; } .logs-toolbar select, .logs-toolbar input { background: var(--bg2); border: 1px solid var(--border); color: var(--fg0); padding: 4px 8px; border-radius: 4px; font-size: 12px; } .logs-toolbar select:focus, .logs-toolbar input:focus { outline: none; border-color: var(--accent); } .logs-toolbar input { width: 100%; box-sizing: border-box; } .logs-count { color: var(--fg2); font-size: 11px; font-family: 'SF Mono', 'Cascadia Mono', Consolas, monospace; white-space: nowrap; } .logs-list-wrap { flex: 1; overflow: auto; min-height: 0; } .logs-table { width: 100%; border-collapse: collapse; font-size: 12px; } .logs-table th { text-align: left; padding: 6px 10px; background: var(--bg1); color: var(--fg2); font-weight: 600; text-transform: uppercase; font-size: 10px; letter-spacing: 0.5px; border-bottom: 1px solid var(--border); position: sticky; top: 0; z-index: 1; } .logs-table td { padding: 4px 10px; border-bottom: 1px solid var(--border-soft); vertical-align: top; } .logs-table .col-time { white-space: nowrap; color: var(--fg2); width: 1%; } .logs-table .col-verb { white-space: nowrap; width: 1%; font-weight: 500; } .logs-table .col-cat { white-space: nowrap; width: 1%; color: var(--fg1); } .logs-table .col-msg { color: var(--fg0); word-break: break-word; } .logs-table .col-loc { white-space: nowrap; color: var(--fg2); width: 1%; font-size: 11px; } .logs-table tr.vb-fatal td, .logs-table tr.vb-error td { color: var(--fail); } .logs-table tr.vb-error .col-msg { color: var(--fail); } .logs-table tr.vb-warn .col-verb, .logs-table tr.vb-warn .col-msg { color: var(--warn); } .logs-table tr.vb-display .col-verb { color: var(--accent); } .logs-table tr.vb-verbose .col-verb, .logs-table tr.vb-verbose .col-msg { color: var(--fg2); } .logs-table tr.bm-row .col-verb { color: #e3b341; font-weight: 600; } .logs-table tr.bm-row .col-msg { color: #f0d078; } .logs-table tr.bm-row .col-time { color: #e3b341; } .logs-empty, .logs-error { padding: 20px; text-align: center; color: var(--fg2); } .logs-error { color: var(--fail); } /* -- loading overlay ------------------------------------------------------- */ .loading { position: fixed; inset: 0; background: var(--bg0); color: var(--fg2); display: flex; align-items: center; justify-content: center; font-size: 14px; z-index: 100; } .loading.hidden { display: none; } /* ── CSV Stats view ───────────────────────────────────────────────── */ .view-csv { display: flex; flex-direction: column; min-height: 0; } #csv-content { flex: 1; display: flex; flex-direction: column; min-height: 0; } .csv-layout { display: flex; flex: 1; min-height: 0; } .csv-tree-panel { width: 240px; flex-shrink: 0; border-right: 1px solid var(--border); display: flex; flex-direction: column; overflow-y: auto; padding: 8px; } .csv-chart-panel { flex: 1; position: relative; min-width: 0; } .csv-chart-canvas { width: 100%; height: 100%; display: block; } .csv-chart-tooltip { position: absolute; background: var(--bg1); border: 1px solid var(--border); border-radius: 4px; padding: 6px 8px; font-size: 11px; color: var(--fg1); pointer-events: none; z-index: 10; white-space: nowrap; } .csv-cat-header { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: var(--fg2); padding: 8px 4px 2px; } .csv-stat-row { display: flex; align-items: center; gap: 6px; padding: 2px 4px; border-radius: 3px; cursor: pointer; font-size: 12px; color: var(--fg1); } .csv-stat-row:hover { background: var(--bg2); } .csv-stat-row input[type=checkbox] { margin: 0; accent-color: var(--accent); } .csv-stat-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .csv-empty { color: var(--fg2); font-size: 12px; padding: 12px 4px; } /* -- memory view ---------------------------------------------------------- */ .view-memory { overflow: auto; padding: 16px; } .memory-view { display: flex; flex-direction: column; gap: 16px; } .memory-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; } .memory-card, .memory-panel { background: var(--bg1); border: 1px solid var(--border); border-radius: 8px; } .memory-card { padding: 12px 14px; } .memory-card-label, .memory-panel-subtitle, .memory-empty, .memory-frame-path { color: var(--fg2); } .memory-chart-axis, .memory-chart-text { fill: var(--fg2); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; font-size: 11px; } .memory-card-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.4px; margin-bottom: 6px; } .memory-card-value { font-size: 20px; font-weight: 600; color: var(--fg0); } .memory-panel-header { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 12px 14px; border-bottom: 1px solid var(--border-soft); } .memory-panel-header-wrap { flex-wrap: wrap; } .memory-panel-title { font-weight: 600; color: var(--fg0); } .memory-controls { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; color: var(--fg2); font-size: 12px; } .memory-controls label { display: flex; align-items: center; gap: 6px; } .memory-filter-input, .memory-controls select { background: var(--bg2); color: var(--fg1); border: 1px solid var(--border); border-radius: 4px; padding: 4px 6px; font-size: 12px; } .memory-filter-input { min-width: 180px; } .memory-direction-btn, .memory-clear-btn { background: var(--bg2); color: var(--fg1); border: 1px solid var(--border); border-radius: 4px; padding: 4px 8px; font-size: 12px; cursor: pointer; } .memory-direction-btn:hover, .memory-clear-btn:hover:not(:disabled) { background: var(--bg3); } .memory-clear-btn:disabled { opacity: 0.5; cursor: default; } .memory-chart-wrap { padding: 10px 12px 12px; } .memory-chart { display: block; width: 100%; height: 220px; } .memory-chart-bg { fill: var(--bg1); } .memory-chart-grid { stroke: var(--border-soft); stroke-width: 1; } .memory-chart-grid-vert { stroke-opacity: 0.45; } .memory-chart-line { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; } .memory-histogram { height: 260px; } .memory-histogram-bar { fill: var(--accent); fill-opacity: 0.78; } .memory-histogram-bar:hover { fill-opacity: 1; } .memory-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; } .memory-callstack-panel { grid-column: 1 / -1; } .memory-tabbed { display: flex; flex-direction: column; gap: 0; } .memory-tab-bar { display: flex; flex-wrap: wrap; gap: 4px; padding: 0 4px; border-bottom: 1px solid var(--border-soft); margin-bottom: -1px; } .memory-tab { padding: 8px 14px; background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--fg2); font-size: 12px; font-weight: 500; cursor: pointer; text-transform: uppercase; letter-spacing: 0.5px; white-space: nowrap; margin-bottom: -1px; } .memory-tab:hover { color: var(--fg0); background: var(--bg2); } .memory-tab.active { color: var(--accent); border-bottom-color: var(--accent); } .memory-table-wrap { overflow: auto; max-height: 360px; } .memory-table { width: 100%; border-collapse: collapse; } .memory-table th, .memory-table td { padding: 8px 10px; border-bottom: 1px solid var(--border-soft); text-align: left; vertical-align: top; } .memory-table th { position: sticky; top: 0; background: var(--bg1); z-index: 1; font-size: 11px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--fg2); } .memory-table .num { text-align: right; white-space: nowrap; } .memory-table tbody tr { cursor: pointer; } .memory-table tbody tr:hover { background: var(--bg2); } .memory-table tbody tr.selected { background: var(--accent-soft); } .memory-group-row td { background: var(--bg2); color: var(--fg2); font-size: 11px; text-transform: uppercase; letter-spacing: 0.4px; font-weight: 600; } .memory-summary-top-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; } .memory-summary-top { color: var(--fg0); font-weight: 500; word-break: break-word; min-width: 0; flex: 1; } .memory-summary-secondary { margin-top: 3px; color: var(--fg2); font-size: 12px; word-break: break-word; } .memory-summary-badges { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; flex-shrink: 0; } .memory-badge { display: inline-block; padding: 1px 6px; border-radius: 999px; background: var(--accent-soft); color: var(--fg2); font-size: 11px; } .memory-mark { background: color-mix(in srgb, var(--accent) 28%, transparent); color: inherit; padding: 0 1px; border-radius: 2px; } .memory-callstack-body { padding: 12px 14px; max-height: 320px; overflow: auto; } .memory-callstack-list { margin: 0; padding-left: 22px; } .memory-callstack-list li { margin: 0 0 8px; word-break: break-word; } .memory-frame-index { color: var(--fg2); margin-right: 8px; } .memory-frame-display { font-family: 'SF Mono', 'Cascadia Mono', Consolas, 'DejaVu Sans Mono', monospace; color: var(--fg0); } .memory-frame-path { margin-left: 8px; font-size: 12px; }