codexmeter 1.0.0 → 1.0.2
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/bin/codexmeter.js +1 -0
- package/dist/assets/index-C0qLYGUY.css +1 -0
- package/dist/assets/index-M87czq50.js +113 -0
- package/dist/index.html +2 -2
- package/package.json +5 -2
- package/server/aggregator.js +79 -7
- package/server/cost-catalog.js +1 -1
- package/server/export-replay.js +80 -0
- package/server/export-video.js +313 -0
- package/server/index.js +68 -1
- package/server/ingest.js +147 -42
- package/server/live-state.js +61 -2
- package/server/rollout-reader.js +87 -5
- package/src/utils/animationsDefault.js +244 -0
- package/dist/assets/index-DJWqyRDh.css +0 -1
- package/dist/assets/index-DZKogILW.js +0 -113
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
const AUTO = 'auto';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Overview ingest animation control panel.
|
|
5
|
+
*
|
|
6
|
+
* This is the single source of truth for:
|
|
7
|
+
* - Overview client-side presentation timing
|
|
8
|
+
* - Overview ECharts timing defaults
|
|
9
|
+
* - Overview server-side tail pacing
|
|
10
|
+
*
|
|
11
|
+
* `speed` scales the main timings:
|
|
12
|
+
* - `1` = baseline
|
|
13
|
+
* - `2` = 2x faster
|
|
14
|
+
* - `0.5` = 2x slower
|
|
15
|
+
*
|
|
16
|
+
* Per-chart overrides use:
|
|
17
|
+
* - `'auto'` to inherit the scaled main value
|
|
18
|
+
* - a number to force an explicit value in ms
|
|
19
|
+
*/
|
|
20
|
+
export const OVERVIEW_INGEST_ANIMATION = {
|
|
21
|
+
speed: 1,
|
|
22
|
+
main: {
|
|
23
|
+
presentationDurationMs: 190,
|
|
24
|
+
chartAppearDurationMs: 0,
|
|
25
|
+
chartUpdateDurationMs: 200,
|
|
26
|
+
easing: 'linear',
|
|
27
|
+
easingUpdate: 'linear',
|
|
28
|
+
},
|
|
29
|
+
tail: {
|
|
30
|
+
// Master switch for the end-of-ingest slowdown behavior.
|
|
31
|
+
enabled: true,
|
|
32
|
+
// Progress threshold where the tail mode starts, expressed from 0..1.
|
|
33
|
+
startPercent: 0.85,
|
|
34
|
+
// Fixed presentation duration in ms during the tail; use AUTO to derive it from main.durationScale.
|
|
35
|
+
durationMs: AUTO,
|
|
36
|
+
// Multiplier applied to the normal presentation duration when durationMs is AUTO.
|
|
37
|
+
durationScale: 100,
|
|
38
|
+
// Shared easing applied by the Overview presentation animator during the tail.
|
|
39
|
+
easing: 'cubicOut',
|
|
40
|
+
// Backend Overview live-update cadence during the tail, in patches per second.
|
|
41
|
+
overviewHz: 5,
|
|
42
|
+
},
|
|
43
|
+
daily: {
|
|
44
|
+
chartAppearDurationMs: AUTO,
|
|
45
|
+
chartUpdateDurationMs: 30,
|
|
46
|
+
easing: AUTO,
|
|
47
|
+
easingUpdate: AUTO,
|
|
48
|
+
},
|
|
49
|
+
bars: {
|
|
50
|
+
chartAppearDurationMs: AUTO,
|
|
51
|
+
chartUpdateDurationMs: 20,
|
|
52
|
+
easing: AUTO,
|
|
53
|
+
easingUpdate: AUTO,
|
|
54
|
+
},
|
|
55
|
+
donuts: {
|
|
56
|
+
chartAppearDurationMs: AUTO,
|
|
57
|
+
chartUpdateDurationMs: AUTO,
|
|
58
|
+
easing: AUTO,
|
|
59
|
+
easingUpdate: 'linear',
|
|
60
|
+
seriesAnimation: false,
|
|
61
|
+
},
|
|
62
|
+
heatmap: {
|
|
63
|
+
/** Duration (ms) of the pop animation when a cell gets new data during ingest */
|
|
64
|
+
popDurationMs: 380,
|
|
65
|
+
/** Don't trigger pop when ingest progress is above this (avoids burst at settle) */
|
|
66
|
+
settleThreshold: 0.998,
|
|
67
|
+
/** Min relative intensity rise (0–1) to trigger pop – e.g. 0.08 = cell turning white */
|
|
68
|
+
intensityRiseThreshold: 0.08,
|
|
69
|
+
/** Relative intensity (0–1) that counts as "white" – crossing this triggers pop */
|
|
70
|
+
whiteThreshold: 0.88,
|
|
71
|
+
/** Cell is "new winner" if val >= maxVal * this when max increased */
|
|
72
|
+
nearMaxRatio: 0.985,
|
|
73
|
+
},
|
|
74
|
+
videoExport: {
|
|
75
|
+
width: 1080,
|
|
76
|
+
height: 864,
|
|
77
|
+
fps: 60,
|
|
78
|
+
introDurationMs: 900,
|
|
79
|
+
replayDurationMs: 8000,
|
|
80
|
+
tailDurationMs: 5000,
|
|
81
|
+
tailReplayFraction: 0.72,
|
|
82
|
+
captureFormat: 'png',
|
|
83
|
+
jpegQuality: 92,
|
|
84
|
+
crf: 10,
|
|
85
|
+
encoderPreset: 'veryfast',
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/** Shared ECharts animation defaults for non-Overview charts */
|
|
90
|
+
export const ECHARTS_ANIMATION = {
|
|
91
|
+
animationDuration: 750,
|
|
92
|
+
animationDurationUpdate: 220,
|
|
93
|
+
animationEasing: 'cubicOut',
|
|
94
|
+
animationEasingUpdate: 'cubicOut',
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/** Label animation - fade in after chart finishes */
|
|
98
|
+
export const ECHARTS_LABEL_ANIMATION = {
|
|
99
|
+
show: true,
|
|
100
|
+
animationDuration: 250,
|
|
101
|
+
animationDurationUpdate: 220,
|
|
102
|
+
animationDelay: 250,
|
|
103
|
+
animationDelayUpdate: 180,
|
|
104
|
+
animationEasing: 'cubicOut',
|
|
105
|
+
animationEasingUpdate: 'cubicOut',
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/** Detail donut charts (Repos/Models/Daily) */
|
|
109
|
+
export const ECHARTS_DONUT_ANIMATION = {
|
|
110
|
+
...ECHARTS_ANIMATION,
|
|
111
|
+
animationDurationUpdate: 200,
|
|
112
|
+
animationDelayUpdate: 0,
|
|
113
|
+
animationEasingUpdate: 'cubicOut',
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/** Detail bar charts (Repos/Models/Daily) */
|
|
117
|
+
export const ECHARTS_DETAIL_BAR_ANIMATION = {
|
|
118
|
+
animationDuration: 700,
|
|
119
|
+
animationDurationUpdate: 220,
|
|
120
|
+
animationDelay: 250,
|
|
121
|
+
animationDelayUpdate: 140,
|
|
122
|
+
animationEasing: 'cubicOut',
|
|
123
|
+
animationEasingUpdate: 'cubicOut',
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/** Detail bar labels */
|
|
127
|
+
export const ECHARTS_DETAIL_BAR_LABEL_ANIMATION = {
|
|
128
|
+
...ECHARTS_LABEL_ANIMATION,
|
|
129
|
+
animationDelay: 950,
|
|
130
|
+
animationDelayUpdate: 360,
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
function safeSpeed(value) {
|
|
134
|
+
return Number.isFinite(value) && value > 0 ? value : 1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function scaledMainDuration(ms) {
|
|
138
|
+
return Math.max(0, Math.round(ms / safeSpeed(OVERVIEW_INGEST_ANIMATION.speed)));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function resolveOverviewValue(overrideValue, mainValue) {
|
|
142
|
+
return overrideValue === AUTO ? scaledMainDuration(mainValue) : overrideValue;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function resolveOverviewString(overrideValue, mainValue) {
|
|
146
|
+
return overrideValue === AUTO ? mainValue : overrideValue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function buildOverviewChartAnimation(overrides) {
|
|
150
|
+
return {
|
|
151
|
+
animation: true,
|
|
152
|
+
animationDuration: resolveOverviewValue(
|
|
153
|
+
overrides.chartAppearDurationMs,
|
|
154
|
+
OVERVIEW_INGEST_ANIMATION.main.chartAppearDurationMs
|
|
155
|
+
),
|
|
156
|
+
animationDurationUpdate: resolveOverviewValue(
|
|
157
|
+
overrides.chartUpdateDurationMs,
|
|
158
|
+
OVERVIEW_INGEST_ANIMATION.main.chartUpdateDurationMs
|
|
159
|
+
),
|
|
160
|
+
animationEasing: resolveOverviewString(
|
|
161
|
+
overrides.easing,
|
|
162
|
+
OVERVIEW_INGEST_ANIMATION.main.easing
|
|
163
|
+
),
|
|
164
|
+
animationEasingUpdate: resolveOverviewString(
|
|
165
|
+
overrides.easingUpdate,
|
|
166
|
+
OVERVIEW_INGEST_ANIMATION.main.easingUpdate
|
|
167
|
+
),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export const OVERVIEW_PRESENTATION_DURATION_MS = scaledMainDuration(
|
|
172
|
+
OVERVIEW_INGEST_ANIMATION.main.presentationDurationMs
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
export function resolveOverviewPresentationDuration(progress = 0, isIngestActive = false) {
|
|
176
|
+
const base = OVERVIEW_PRESENTATION_DURATION_MS;
|
|
177
|
+
const tail = OVERVIEW_INGEST_ANIMATION.tail;
|
|
178
|
+
|
|
179
|
+
if (!isIngestActive || !tail?.enabled) return base;
|
|
180
|
+
|
|
181
|
+
const start = Math.min(Math.max(tail.startPercent ?? 0.9, 0), 0.999);
|
|
182
|
+
const clampedProgress = Math.min(Math.max(progress || 0, 0), 1);
|
|
183
|
+
if (clampedProgress <= start) return base;
|
|
184
|
+
|
|
185
|
+
const normalized = (clampedProgress - start) / Math.max(1 - start, 0.001);
|
|
186
|
+
const durationTarget = tail.durationMs === AUTO
|
|
187
|
+
? Math.round(base * Math.max(tail.durationScale || 1, 1))
|
|
188
|
+
: tail.durationMs;
|
|
189
|
+
|
|
190
|
+
return Math.round(base + (durationTarget - base) * cubicOut(normalized));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function resolveOverviewPresentationEasing(progress = 0, isIngestActive = false) {
|
|
194
|
+
const tail = OVERVIEW_INGEST_ANIMATION.tail;
|
|
195
|
+
if (!isIngestActive || !tail?.enabled) return 'linear';
|
|
196
|
+
|
|
197
|
+
const start = Math.min(Math.max(tail.startPercent ?? 0.9, 0), 0.999);
|
|
198
|
+
const clampedProgress = Math.min(Math.max(progress || 0, 0), 1);
|
|
199
|
+
if (clampedProgress <= start) return 'linear';
|
|
200
|
+
|
|
201
|
+
return tail.easing || 'cubicOut';
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function isOverviewTailActive(progress = 0, isIngestActive = false) {
|
|
205
|
+
const tail = OVERVIEW_INGEST_ANIMATION.tail;
|
|
206
|
+
if (!isIngestActive || !tail?.enabled) return false;
|
|
207
|
+
|
|
208
|
+
const start = Math.min(Math.max(tail.startPercent ?? 0.9, 0), 0.999);
|
|
209
|
+
const clampedProgress = Math.min(Math.max(progress || 0, 0), 1);
|
|
210
|
+
return clampedProgress > start;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Overview page - resolved main animation config */
|
|
214
|
+
export const ECHARTS_OVERVIEW_ANIMATION = buildOverviewChartAnimation({
|
|
215
|
+
chartAppearDurationMs: AUTO,
|
|
216
|
+
chartUpdateDurationMs: AUTO,
|
|
217
|
+
easing: AUTO,
|
|
218
|
+
easingUpdate: AUTO,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
/** Overview DailySpark - compact stacked bar */
|
|
222
|
+
export const ECHARTS_OVERVIEW_DAILY = buildOverviewChartAnimation(
|
|
223
|
+
OVERVIEW_INGEST_ANIMATION.daily
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
/** Overview Top Repos - horizontal bar chart */
|
|
227
|
+
export const ECHARTS_OVERVIEW_BARS = buildOverviewChartAnimation(
|
|
228
|
+
OVERVIEW_INGEST_ANIMATION.bars
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
/** Overview Work Type & Models - donut charts */
|
|
232
|
+
export const ECHARTS_OVERVIEW_DONUTS = buildOverviewChartAnimation(
|
|
233
|
+
OVERVIEW_INGEST_ANIMATION.donuts
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
export const ECHARTS_OVERVIEW_DONUT_SERIES_ANIMATION =
|
|
237
|
+
OVERVIEW_INGEST_ANIMATION.donuts.seriesAnimation;
|
|
238
|
+
|
|
239
|
+
export { AUTO as OVERVIEW_ANIMATION_AUTO };
|
|
240
|
+
|
|
241
|
+
function cubicOut(t) {
|
|
242
|
+
const x = Math.min(Math.max(t, 0), 1);
|
|
243
|
+
return 1 - Math.pow(1 - x, 3);
|
|
244
|
+
}
|
|
@@ -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}.navbar-tab:hover{color:var(--text-primary);background:var(--bg-card)}.navbar-tab.active{color:#fff;background:var(--accent)}.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 3rem;max-width:1400px;margin:0 auto;width:100%;min-width:0;container-type:inline-size;container-name:main}.app-footer{padding:.75rem 2rem 1rem;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-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:.5rem 0;margin-bottom:1rem}.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}
|