codexmeter 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/assets/index-DhDq9dI8.css +1 -0
- package/dist/assets/index-_br3iqvd.js +117 -0
- package/dist/index.html +2 -2
- package/package.json +2 -1
- package/server/aggregator.js +9 -5
- package/server/export-replay.js +2 -2
- package/server/export-video.js +546 -63
- package/server/index.js +21 -6
- package/server/live-state.js +9 -6
- package/src/utils/animationsDefault.js +42 -6
- package/dist/assets/index-C0qLYGUY.css +0 -1
- package/dist/assets/index-M87czq50.js +0 -113
package/server/index.js
CHANGED
|
@@ -2,12 +2,13 @@ import express from 'express';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { attachLiveSubscriber, createIngestState, detachLiveSubscriber, getLatestReplay, restartIngest, runIngest } from './ingest.js';
|
|
5
|
-
import { createJobSummary, createVideoExportManager, getActiveVideoExportJob, getVideoExportJob, startOverviewVideoExport } from './export-video.js';
|
|
5
|
+
import { createJobSummary, createVideoExportManager, getActiveVideoExportJob, getVideoExportJob, getVideoExportSupport, startOverviewVideoExport } from './export-video.js';
|
|
6
6
|
|
|
7
7
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
8
|
|
|
9
9
|
export function createServer(codexHome, opts = {}) {
|
|
10
10
|
const app = express();
|
|
11
|
+
app.use(express.json());
|
|
11
12
|
const state = createIngestState();
|
|
12
13
|
const exportManager = createVideoExportManager();
|
|
13
14
|
const distDir = path.join(__dirname, '..', 'dist');
|
|
@@ -80,13 +81,18 @@ export function createServer(codexHome, opts = {}) {
|
|
|
80
81
|
app.get('/api/families', wrap('families'));
|
|
81
82
|
|
|
82
83
|
app.post('/api/export/overview-video', async (req, res) => {
|
|
84
|
+
const activeJob = getActiveVideoExportJob(exportManager);
|
|
85
|
+
if (activeJob) {
|
|
86
|
+
res.status(409).json({ error: 'Another export job is already running.' });
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
83
89
|
const replay = getLatestReplay(state);
|
|
84
90
|
if (!replay) {
|
|
85
91
|
res.status(409).json({ error: 'No completed ingest replay is available yet.' });
|
|
86
92
|
return;
|
|
87
93
|
}
|
|
88
94
|
|
|
89
|
-
const appBaseUrl =
|
|
95
|
+
const appBaseUrl = opts.frontendBaseUrl || `${req.protocol}://${req.get('host')}`;
|
|
90
96
|
const settledEnvelope = state.aggregates ? {
|
|
91
97
|
overview: { data: state.aggregates.overview },
|
|
92
98
|
repos: { data: state.aggregates.repos },
|
|
@@ -96,8 +102,13 @@ export function createServer(codexHome, opts = {}) {
|
|
|
96
102
|
heatmap: { data: state.aggregates.heatmap },
|
|
97
103
|
} : null;
|
|
98
104
|
try {
|
|
99
|
-
const job = await startOverviewVideoExport(exportManager, {
|
|
100
|
-
|
|
105
|
+
const job = await startOverviewVideoExport(exportManager, {
|
|
106
|
+
replay,
|
|
107
|
+
settledEnvelope,
|
|
108
|
+
appBaseUrl,
|
|
109
|
+
installPortableBrowser: Boolean(req.body?.install_portable_browser),
|
|
110
|
+
});
|
|
111
|
+
res.status(202).json(createJobSummary(job));
|
|
101
112
|
} catch (err) {
|
|
102
113
|
res.status(err.statusCode || 500).json({ error: err.message || String(err) });
|
|
103
114
|
}
|
|
@@ -109,7 +120,11 @@ export function createServer(codexHome, opts = {}) {
|
|
|
109
120
|
res.json({ job: null });
|
|
110
121
|
return;
|
|
111
122
|
}
|
|
112
|
-
res.json({ job: createJobSummary(job
|
|
123
|
+
res.json({ job: createJobSummary(job) });
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
app.get('/api/export/support', async (_req, res) => {
|
|
127
|
+
res.json(await getVideoExportSupport());
|
|
113
128
|
});
|
|
114
129
|
|
|
115
130
|
app.get('/api/export/:jobId/status', (req, res) => {
|
|
@@ -118,7 +133,7 @@ export function createServer(codexHome, opts = {}) {
|
|
|
118
133
|
res.status(404).json({ error: 'Export job not found.' });
|
|
119
134
|
return;
|
|
120
135
|
}
|
|
121
|
-
res.json(createJobSummary(job
|
|
136
|
+
res.json(createJobSummary(job));
|
|
122
137
|
});
|
|
123
138
|
|
|
124
139
|
app.get('/api/export/:jobId/render-data', (req, res) => {
|
package/server/live-state.js
CHANGED
|
@@ -82,7 +82,7 @@ export function buildLiveBootstrap(live) {
|
|
|
82
82
|
export function buildLivePatch(live, patch) {
|
|
83
83
|
return {
|
|
84
84
|
overview: Object.fromEntries(
|
|
85
|
-
[...patch.overview].map((rangeKey) => [rangeKey, serializeOverviewBucket(live.overview[rangeKey])])
|
|
85
|
+
[...patch.overview].map((rangeKey) => [rangeKey, serializeOverviewBucket(live.overview[rangeKey], live.lowerBounds[rangeKey])])
|
|
86
86
|
),
|
|
87
87
|
repos: serializePatchedTopRanges(live.repos, live.repoTopKeys, patch.repos, serializeRepoSummary),
|
|
88
88
|
models: serializePatchedTopRanges(live.models, live.modelTopKeys, patch.models, serializeModelSummary),
|
|
@@ -352,14 +352,17 @@ function ensureHeatmapDay(dayMap, dayKey) {
|
|
|
352
352
|
|
|
353
353
|
function serializeOverview(live) {
|
|
354
354
|
return {
|
|
355
|
-
total: serializeOverviewBucket(live.overview.total),
|
|
356
|
-
d7: serializeOverviewBucket(live.overview.d7),
|
|
357
|
-
d30: serializeOverviewBucket(live.overview.d30),
|
|
355
|
+
total: serializeOverviewBucket(live.overview.total, live.lowerBounds.total),
|
|
356
|
+
d7: serializeOverviewBucket(live.overview.d7, live.lowerBounds.d7),
|
|
357
|
+
d30: serializeOverviewBucket(live.overview.d30, live.lowerBounds.d30),
|
|
358
358
|
cost_assumptions: CACHE_ASSUMPTIONS,
|
|
359
359
|
};
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
function serializeOverviewBucket(bucket) {
|
|
362
|
+
function serializeOverviewBucket(bucket, lowerBound = 0) {
|
|
363
|
+
const boundedFrom = bucket.earliest === Infinity
|
|
364
|
+
? null
|
|
365
|
+
: Math.max(bucket.earliest, lowerBound || 0);
|
|
363
366
|
return {
|
|
364
367
|
total_tokens: bucket.total_tokens,
|
|
365
368
|
total_cost: bucket.total_cost,
|
|
@@ -368,7 +371,7 @@ function serializeOverviewBucket(bucket) {
|
|
|
368
371
|
active_models: bucket.modelSet.size,
|
|
369
372
|
total_elapsed_seconds: bucket.total_elapsed_seconds,
|
|
370
373
|
date_range: {
|
|
371
|
-
from:
|
|
374
|
+
from: boundedFrom,
|
|
372
375
|
to: bucket.latest === -Infinity ? null : bucket.latest,
|
|
373
376
|
},
|
|
374
377
|
coverage: {
|
|
@@ -20,7 +20,7 @@ const AUTO = 'auto';
|
|
|
20
20
|
export const OVERVIEW_INGEST_ANIMATION = {
|
|
21
21
|
speed: 1,
|
|
22
22
|
main: {
|
|
23
|
-
presentationDurationMs:
|
|
23
|
+
presentationDurationMs: 300,
|
|
24
24
|
chartAppearDurationMs: 0,
|
|
25
25
|
chartUpdateDurationMs: 200,
|
|
26
26
|
easing: 'linear',
|
|
@@ -34,7 +34,7 @@ export const OVERVIEW_INGEST_ANIMATION = {
|
|
|
34
34
|
// Fixed presentation duration in ms during the tail; use AUTO to derive it from main.durationScale.
|
|
35
35
|
durationMs: AUTO,
|
|
36
36
|
// Multiplier applied to the normal presentation duration when durationMs is AUTO.
|
|
37
|
-
durationScale:
|
|
37
|
+
durationScale: 20,
|
|
38
38
|
// Shared easing applied by the Overview presentation animator during the tail.
|
|
39
39
|
easing: 'cubicOut',
|
|
40
40
|
// Backend Overview live-update cadence during the tail, in patches per second.
|
|
@@ -72,16 +72,52 @@ export const OVERVIEW_INGEST_ANIMATION = {
|
|
|
72
72
|
nearMaxRatio: 0.985,
|
|
73
73
|
},
|
|
74
74
|
videoExport: {
|
|
75
|
+
// Video export settings
|
|
75
76
|
width: 1080,
|
|
76
77
|
height: 864,
|
|
77
78
|
fps: 60,
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
frontloadSettledFrameCount: 1,
|
|
80
|
+
|
|
81
|
+
// Intro fade-in effect
|
|
82
|
+
introFadeEnabled: true,
|
|
83
|
+
introFadeStartOpacity: 0.95,
|
|
84
|
+
introContentStartOpacity: 0.05,
|
|
85
|
+
introFadeDurationMs: 400,
|
|
86
|
+
introFadeDelayMs: 0,
|
|
87
|
+
introFadeEasing: 'cubicOut',
|
|
88
|
+
|
|
89
|
+
// Start Delay for the animation
|
|
90
|
+
startHoldDurationMs: 100,
|
|
91
|
+
|
|
92
|
+
// Replay duration
|
|
93
|
+
replayDurationMs: 10000,
|
|
94
|
+
|
|
95
|
+
// Tail Settings
|
|
80
96
|
tailDurationMs: 5000,
|
|
81
|
-
|
|
97
|
+
replayEasing: 'cubicIn',
|
|
98
|
+
tailSourceFraction: 0.55,
|
|
99
|
+
tailEasing: 'cubicOut',
|
|
100
|
+
finalHoldDurationMs: 5000,
|
|
101
|
+
|
|
102
|
+
// Final Flash Settings
|
|
103
|
+
finalFlashDurationMs: 1000,
|
|
104
|
+
finalFlashMaxOpacity: 0.35,
|
|
105
|
+
|
|
106
|
+
// Display Tween Settings
|
|
107
|
+
displayTweenStartMs: 200,
|
|
108
|
+
displayTweenBaseMs: 240,
|
|
109
|
+
displayTweenLateMs: 420,
|
|
110
|
+
displayTweenLateWindowMs: 2200,
|
|
111
|
+
barsChartUpdateDurationMs: 50,
|
|
112
|
+
barsChartTailUpdateDurationMs: 240,
|
|
113
|
+
donutsChartUpdateDurationMs: 50,
|
|
114
|
+
donutsChartTailUpdateDurationMs: 240,
|
|
115
|
+
|
|
116
|
+
// Render settings
|
|
117
|
+
supersampleScale: 2,
|
|
82
118
|
captureFormat: 'png',
|
|
83
119
|
jpegQuality: 92,
|
|
84
|
-
crf:
|
|
120
|
+
crf: 5,
|
|
85
121
|
encoderPreset: 'veryfast',
|
|
86
122
|
},
|
|
87
123
|
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
:root{--bg-base: #06080f;--bg-surface: #0d1117;--bg-card: #161b22;--bg-card-hover: #1c2333;--bg-elevated: #21262d;--border: #30363d;--border-accent: rgba(99, 102, 241, .25);--text-primary: #e6edf3;--text-secondary: #8b949e;--text-muted: #484f58;--accent: #6366f1;--accent-dim: rgba(99, 102, 241, .12);--green: #3fb950;--yellow: #d29922;--red: #f85149;--orange: #f97316;--cyan: #39d2f5;--pink: #f472b6;--font-sans: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;--font-mono: "JetBrains Mono", "Fira Code", monospace;--radius: 8px;--radius-lg: 12px}*{box-sizing:border-box;margin:0;padding:0}body{font-family:var(--font-sans);background:var(--bg-base);color:var(--text-primary);line-height:1.6;-webkit-font-smoothing:antialiased}.app{min-height:100vh;display:flex;flex-direction:column}.app-content{opacity:0;display:flex;flex-direction:column;min-height:100vh}.app-content-revealed{opacity:1;animation:contentReveal .5s ease forwards}@keyframes contentReveal{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.navbar{background:var(--bg-surface);border-bottom:1px solid var(--border);position:sticky;top:0;z-index:100;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.navbar-inner{display:flex;align-items:center;gap:1.5rem;padding:0 2rem;height:48px;max-width:1400px;margin:0 auto;width:100%;box-sizing:border-box}.navbar-brand{font-weight:700;font-size:.95rem;letter-spacing:-.03em;background:linear-gradient(135deg,#818cf8,#6366f1);-webkit-background-clip:text;-webkit-text-fill-color:transparent}.navbar-tabs{display:flex;gap:2px}.navbar-tab{padding:.35rem .85rem;border-radius:6px;cursor:pointer;font-size:.8rem;font-weight:500;color:var(--text-secondary);background:none;border:none;transition:all .15s,opacity .35s ease}.navbar-tab:hover{color:var(--text-primary);background:var(--bg-card)}.navbar-tab.active{color:#fff;background:var(--accent)}.navbar-tab.navbar-tab-dimmed,.navbar-tab.navbar-tab-dimmed:hover{opacity:.4;color:var(--text-muted)}.navbar-meta{margin-left:auto;display:flex;align-items:center;gap:.75rem;flex:1;min-width:0}.navbar-ingest-wrap{display:flex;align-items:center;gap:.75rem;flex:1;min-width:0;transition:opacity .3s ease}.navbar-ingest-wrap.navbar-ingest-fade-out{opacity:0;pointer-events:none}.navbar-date-wrap{display:flex;align-items:center;gap:.75rem;margin-left:auto;flex-shrink:0;transition:opacity .3s ease}.navbar-date-wrap-dimmed{opacity:.5;pointer-events:none}.navbar-date{display:inline-block;width:22ch;min-width:22ch;font-variant-numeric:tabular-nums;text-align:right;overflow:hidden;text-overflow:ellipsis}.navbar-progress-wrap{flex:1;height:4px;background:var(--bg-elevated);border-radius:2px;overflow:hidden}.navbar-progress-bar{height:100%;background:linear-gradient(90deg,var(--accent),#818cf8);border-radius:2px;transition:width .4s ease}.navbar-status{font-size:.7rem;color:var(--text-muted);font-family:var(--font-mono)}.main-content{flex:1;padding:1.5rem 2rem 1.25rem;max-width:1400px;margin:0 auto;width:100%;min-width:0;container-type:inline-size;container-name:main}.app-footer{padding:.5rem 2rem .75rem;font-size:.7rem;color:var(--text-muted);text-align:center;max-width:1400px;margin:auto auto 0;width:100%;box-sizing:border-box}.section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.25rem}.section-title{font-size:1rem;font-weight:600;letter-spacing:-.01em}.stat-row{display:flex;flex-wrap:wrap;gap:1rem;align-items:stretch;margin-bottom:1.5rem}.stat-cards{display:grid;grid-template-columns:repeat(4,minmax(160px,1fr));gap:.75rem;flex:0 0 auto;min-width:0}@media(max-width:920px){.stat-cards{flex:1 1 auto;grid-template-columns:repeat(2,minmax(160px,1fr))}}@media(max-width:500px){.stat-cards{grid-template-columns:1fr}}.stat-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:1rem 1.1rem;transition:border-color .2s}.stat-card:hover{border-color:var(--border-accent)}.stat-label{font-size:.65rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);margin-bottom:.35rem}.stat-value{font-size:1.6rem;font-weight:700;font-family:var(--font-mono);letter-spacing:-.03em;line-height:1.1}.stat-sub{font-size:.72rem;color:var(--text-muted);margin-top:.2rem}.stat-per-day{font-size:.72rem;color:var(--text-muted);margin-top:.25rem;font-family:var(--font-mono)}.stat-per-day .stat-per-day-value{font-weight:600;color:var(--text-secondary)}.range-toggle{display:inline-flex;background:var(--bg-card);border:1px solid var(--border);border-radius:6px;overflow:hidden}.range-btn{padding:.3rem .7rem;font-size:.72rem;font-weight:600;color:var(--text-muted);background:none;border:none;cursor:pointer;transition:all .15s}.range-btn:hover{color:var(--text-secondary)}.range-btn.active{color:#fff;background:var(--accent)}.heatmap-wrap{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:1.25rem;margin-bottom:1.5rem;overflow-x:auto}.heatmap-grid{display:grid;grid-auto-flow:column;grid-template-rows:repeat(7,1fr);gap:3px}.heatmap-cell{width:13px;height:13px;border-radius:2px;background:var(--bg-elevated);opacity:.4;transform:scale(.82);transition:background .18s ease,opacity .22s ease,transform .22s ease}.heatmap-cell.active{opacity:1;transform:scale(1)}.heatmap-cell:hover{outline:1px solid var(--text-muted)}.heatmap-cell.heatmap-cell-pop{animation:heatmap-cell-pop .38s cubic-bezier(.34,1.56,.64,1)}@keyframes heatmap-cell-pop{0%{transform:scale(1);box-shadow:none}40%{transform:scale(1.4);box-shadow:0 0 10px #6366f1b3,0 0 0 1.5px #0003}70%{transform:scale(1.1);box-shadow:0 0 4px #6366f159,0 0 0 .5px #0000001a}to{transform:scale(1);box-shadow:none}}.heatmap-cell.heatmap-cell-pop-dim{animation:heatmap-cell-pop-dim .32s cubic-bezier(.34,1.56,.64,1)}@keyframes heatmap-cell-pop-dim{0%{transform:scale(1)}50%{transform:scale(.85)}to{transform:scale(1)}}.heatmap-labels{display:flex;justify-content:space-between;margin-top:.5rem;font-size:.65rem;color:var(--text-muted)}.chart-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:1.25rem;margin-bottom:1.5rem;position:relative}.chart-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:.75rem}.chart-title{font-size:.85rem;font-weight:600}.chart-badge{font-size:.62rem;color:var(--yellow);background:#d299221a;padding:.15rem .5rem;border-radius:4px}.export-btn{position:absolute;top:.75rem;right:.75rem;padding:.25rem .5rem;border-radius:4px;border:1px solid var(--border);background:var(--bg-surface);color:var(--text-muted);font-size:.65rem;cursor:pointer;opacity:0;transition:all .15s;z-index:2}.chart-card:hover .export-btn{opacity:.7}.export-btn:hover{opacity:1!important;color:var(--text-primary);border-color:var(--accent)}.grid-2{display:grid;grid-template-columns:1fr 1fr;gap:1.25rem;margin-bottom:1.5rem;min-width:0}.grid-3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1.25rem;margin-bottom:1.5rem;min-width:0}.grid-3>.chart-card{min-width:0;overflow:hidden}@media(max-width:900px){.grid-2,.grid-3{grid-template-columns:1fr}}.btn-group{display:flex;gap:2px}.btn{padding:.3rem .65rem;border-radius:5px;border:1px solid var(--border);background:var(--bg-surface);color:var(--text-muted);font-size:.72rem;font-weight:500;cursor:pointer;transition:all .12s}.btn:hover{color:var(--text-secondary);border-color:var(--text-muted)}.btn.active{color:#fff;background:var(--accent);border-color:var(--accent)}.icon-btn{width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;border-radius:6px;border:1px solid var(--border);background:var(--bg-card);color:var(--text-muted);font-size:.9rem;line-height:1;cursor:pointer;transition:color .12s,border-color .12s,background .12s,transform .12s}.icon-btn:hover:not(:disabled){color:var(--text-primary);border-color:var(--accent);background:var(--bg-elevated);transform:rotate(20deg)}.icon-btn:disabled{opacity:.55;cursor:wait}.overview-daily-spark{flex:1 1 140px;min-width:140px;min-height:0;position:relative;background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);overflow:visible}.overview-daily-spark-title{position:absolute;top:1rem;left:1.1rem;font-size:.65rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);z-index:1;pointer-events:none}.overview-daily-spark-chart{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden}.overview-daily-spark-empty{display:flex;align-items:center;justify-content:center}.overview-daily-spark-empty-text{font-size:.7rem;color:var(--text-muted)}@media(max-width:920px){.overview-daily-spark{flex:1 1 100%;min-width:100%;min-height:140px}}.table-wrap{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);overflow:hidden}.model-detail-wrap{display:flex;flex-direction:column;gap:.85rem}.model-detail-note{color:var(--text-muted);font-size:.74rem;line-height:1.4}.model-detail-footer{display:flex;justify-content:flex-start;margin-top:.25rem}.model-detail-toggle{display:inline-flex;align-items:center;gap:.35rem;width:fit-content;padding:.35rem .6rem;font-size:.72rem;font-weight:500;color:var(--text-muted);background:#ffffff0a;border:1px solid var(--border);border-radius:6px;cursor:pointer;transition:color .2s,background .2s,border-color .2s}.model-detail-toggle:hover{color:var(--text-secondary);background:#ffffff0f;border-color:#6366f14d}.model-detail-toggle-text{font-family:var(--font-sans)}.model-detail-toggle-arrow{font-size:.6rem;opacity:.8;transition:transform .25s ease}.model-detail-toggle-arrow.expanded{transform:rotate(180deg)}.model-detail-charts{display:flex;gap:.25rem;flex-wrap:wrap;align-items:flex-start;width:100%;overflow:visible;position:relative;z-index:10}.model-detail-donut{flex:0 0 200px;width:200px;min-width:200px;height:200px;overflow:visible;z-index:10;display:flex;flex-direction:column}.model-detail-donut .chart-title{flex-shrink:0}.model-detail-donut .echarts-for-react{flex:1;min-height:0}.model-detail-wrap .model-detail-donut{flex:0 0 340px;width:340px;min-width:340px;height:220px}.model-detail-donut .echarts-for-react,.model-detail-donut .echarts-for-react>div,.model-detail-bar .echarts-for-react,.model-detail-bar .echarts-for-react>div{overflow:visible!important}.model-detail-bar{flex:1 1 300px;min-width:300px;height:200px;overflow:visible;display:flex;flex-direction:column}.model-detail-bar .chart-title{flex-shrink:0}.model-detail-bar .echarts-for-react{flex:1;min-height:0}.model-detail-summary-wrap{max-height:0;overflow:hidden;transition:max-height .2s ease-out}.model-detail-summary-wrap.expanded{max-height:400px}.model-detail-summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:.6rem;padding-top:.5rem}.model-detail-summary-card{background:#ffffff05;border:1px solid var(--border);border-radius:10px;padding:.65rem .75rem}.model-detail-summary-head{display:flex;align-items:center;gap:.45rem;margin-bottom:.45rem;font-size:.76rem;font-weight:600;color:var(--text-primary);text-transform:capitalize;min-width:0}.model-detail-summary-head .model-detail-summary-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.model-detail-swatch{width:9px;height:9px;border-radius:999px;flex:0 0 auto}.model-detail-summary-line{font-size:.72rem;color:var(--text-muted);line-height:1.45}.detail-summary-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:.75rem;margin-bottom:1rem}.detail-summary-stat{background:#ffffff08;border:1px solid var(--border);border-radius:10px;padding:.8rem .9rem}.detail-summary-label{font-size:.68rem;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-bottom:.25rem}.detail-summary-value{font-size:1.1rem;font-family:var(--font-mono);color:var(--text-primary)}.table-search{padding:.75rem 1rem;border-bottom:1px solid var(--border)}.table-search input{width:100%;padding:.5rem .85rem;border-radius:6px;border:1px solid var(--border);background:var(--bg-surface);color:var(--text-primary);font-size:.82rem;font-family:var(--font-sans);outline:none}.table-search input:focus{border-color:var(--accent)}.table-search input::placeholder{color:var(--text-muted)}table{width:100%;border-collapse:collapse;font-size:.78rem}th{text-align:left;padding:.55rem .85rem;font-weight:600;color:var(--text-muted);border-bottom:1px solid var(--border);font-size:.68rem;text-transform:uppercase;letter-spacing:.05em;cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}td{padding:.5rem .85rem;border-bottom:1px solid rgba(48,54,61,.5);color:var(--text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:240px}tr:hover td{color:var(--text-primary);background:#6366f108}.tag{display:inline-block;padding:.1rem .4rem;border-radius:4px;font-size:.66rem;font-family:var(--font-mono);font-weight:500}.tag-review{background:#06b6d41f;color:var(--cyan)}.tag-exploration{background:#f973161f;color:var(--orange)}.tag-planning{background:#eab3081f;color:var(--yellow)}.tag-memory{background:#ec48991f;color:var(--pink)}.tag-generic{background:#64748b1f;color:var(--text-secondary)}.loading-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#06080feb;-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:999;transition:opacity .6s ease}.loading-overlay.fading{opacity:0;pointer-events:none}.loading-logo{font-size:1.5rem;font-weight:700;background:linear-gradient(135deg,#818cf8,#6366f1);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;margin-bottom:1.5rem}.loading-bar-wrap{width:260px;height:4px;background:var(--bg-elevated);border-radius:2px;overflow:hidden;margin-bottom:1rem}.loading-bar{height:100%;background:linear-gradient(90deg,var(--accent),#818cf8);border-radius:2px;transition:width .4s ease}.loading-phase{font-size:.82rem;font-weight:500;color:var(--text-secondary);margin-bottom:.2rem}.loading-detail{font-family:var(--font-mono);font-size:.72rem;color:var(--text-muted)}.loading-footer{position:absolute;bottom:1.5rem;font-size:.7rem;color:var(--text-muted)}.loading-heart{color:#f43f5e}.coverage-subtle{display:flex;align-items:center;gap:1.5rem;font-size:.68rem;color:var(--text-muted);padding:.25rem 0;margin-top:-.5rem;margin-bottom:.5rem}.coverage-item{display:flex;align-items:center;gap:.35rem;font-variant-numeric:tabular-nums}.coverage-nums{display:inline-block;min-width:9ch;text-align:right}.coverage-nums-single{min-width:4ch}.coverage-dot{width:6px;height:6px;border-radius:50%}html{scrollbar-width:none}::-webkit-scrollbar{display:none;width:0;height:0}@keyframes fadeUp{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.animate-in{animation:fadeUp .35s ease forwards}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.incomplete-badge{font-size:.65rem;color:var(--yellow);background:#d299221a;padding:.12rem .45rem;border-radius:3px;animation:pulse 2s infinite}.ingesting-badge .ingesting-pct{display:inline-block;min-width:4ch;text-align:right;font-variant-numeric:tabular-nums}.echarts-tooltip,[class*=ec-component-tooltip]{max-width:90vw!important;max-height:80vh!important;overflow:auto!important}
|