thevoidforge 21.0.0 → 21.0.1

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.
@@ -0,0 +1,626 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Danger Room — VoidForge</title>
7
+ <link rel="icon" type="image/svg+xml" href="favicon.svg">
8
+ <link rel="stylesheet" href="styles.css">
9
+ <style>
10
+ body { min-height: 100vh; display: flex; flex-direction: column; background: var(--bg); color: var(--text); }
11
+
12
+ /* Danger Room Layout — 5-row grid: header, tab-bar, banner, main+sidebar, ticker */
13
+ .danger-room { display: grid; grid-template-columns: 1fr 280px; grid-template-rows: auto auto auto 1fr auto; height: 100vh; }
14
+ .danger-room-header { grid-column: 1 / -1; grid-row: 1; padding: 12px 20px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; }
15
+ .danger-room-title { font-size: 16px; font-weight: 700; color: var(--accent); }
16
+ .danger-room-version { font-size: 12px; color: var(--text-dim); }
17
+ .danger-room-nav { display: flex; gap: 8px; }
18
+ .danger-room-nav a { color: var(--text-dim); text-decoration: none; font-size: 13px; padding: 4px 10px; border-radius: 4px; }
19
+ .danger-room-nav a:hover { background: var(--bg-card); color: var(--text); }
20
+
21
+ /* Main Panel Area */
22
+ .main-panels { grid-column: 1; grid-row: 4; padding: 16px; overflow-y: auto; display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-content: start; }
23
+
24
+ /* Sidebar */
25
+ .sidebar { grid-column: 2; grid-row: 4; border-left: 1px solid var(--border); padding: 16px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; }
26
+
27
+ /* Panel Card */
28
+ .panel { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 14px; }
29
+ .panel-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-dim); margin-bottom: 8px; }
30
+ .panel-full { grid-column: 1 / -1; }
31
+
32
+ /* Campaign Timeline */
33
+ .timeline { display: flex; gap: 4px; flex-wrap: wrap; }
34
+ .timeline-item { width: 28px; height: 28px; border-radius: 4px; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; }
35
+ .timeline-complete { background: #065f46; color: var(--success); }
36
+ .timeline-active { background: #713f12; color: var(--warning); animation: pulse 2s infinite; }
37
+ .timeline-pending { background: var(--bg); color: var(--text-dim); border: 1px solid var(--border); }
38
+ .timeline-blocked { background: #7f1d1d; color: #fca5a5; }
39
+ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } }
40
+
41
+ /* Phase Pipeline */
42
+ .pipeline { display: flex; flex-direction: column; gap: 3px; }
43
+ .pipeline-phase { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 3px 0; }
44
+ .pipeline-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
45
+ .pipeline-dot.complete { background: var(--success); }
46
+ .pipeline-dot.active { background: var(--warning); animation: pulse 2s infinite; }
47
+ .pipeline-dot.pending { background: var(--border); }
48
+ .pipeline-dot.skipped { background: var(--text-dim); opacity: 0.5; }
49
+ .pipeline-label { color: var(--text-dim); }
50
+
51
+ /* Finding Scoreboard */
52
+ .scoreboard { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
53
+ .score-item { text-align: center; padding: 8px 4px; border-radius: 4px; }
54
+ .score-critical { background: #7f1d1d; }
55
+ .score-high { background: #713f12; }
56
+ .score-medium { background: #1e3a5f; }
57
+ .score-low { background: #1a2e1a; }
58
+ .score-count { font-size: 20px; font-weight: 700; }
59
+ .score-label { font-size: 9px; text-transform: uppercase; color: var(--text-dim); margin-top: 2px; }
60
+
61
+ /* Context Gauge */
62
+ .gauge { position: relative; width: 80px; height: 80px; margin: 0 auto; }
63
+ .gauge svg { width: 80px; height: 80px; transform: rotate(-90deg); }
64
+ .gauge-track { fill: none; stroke: var(--border); stroke-width: 6; }
65
+ .gauge-fill { fill: none; stroke: var(--success); stroke-width: 6; stroke-linecap: round; transition: stroke-dashoffset 0.5s, stroke 0.5s; }
66
+ .gauge-text { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700; }
67
+
68
+ /* Agent Activity Ticker */
69
+ .ticker { grid-column: 1 / -1; grid-row: 5; border-top: 1px solid var(--border); padding: 6px 20px; font-size: 11px; color: var(--text-dim); overflow: hidden; white-space: nowrap; }
70
+ .ticker-item { display: inline; margin-right: 24px; }
71
+ .ticker-agent { color: var(--accent); font-weight: 600; }
72
+
73
+ /* ── Data Tier Sections (v13.0 Information Architecture) ── */
74
+ .tier-section { grid-column: 1 / -1; margin-top: 4px; }
75
+ .tier-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-dim); opacity: 0.85; padding: 4px 0; border-bottom: 1px solid var(--border); margin-bottom: 8px; display: flex; align-items: center; gap: 6px; }
76
+ .tier-label::before { content: ''; width: 8px; height: 8px; flex-shrink: 0; }
77
+ .tier-live .tier-label::before { background: var(--success); border-radius: 50%; animation: pulse 2s infinite; }
78
+ .tier-campaign .tier-label::before { background: var(--warning); border-radius: 2px; } /* square = campaign */
79
+ .tier-system .tier-label::before { opacity: 0.5; border-radius: 50%; border: 1px solid var(--text-dim); background: none; } /* hollow circle = system */
80
+ .tier-live .tier-content { display: grid; grid-template-columns: auto 1fr; gap: 12px; align-items: center; }
81
+ .tier-campaign .tier-content { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
82
+ .tier-system .tier-content { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 8px; }
83
+ .tier-system .panel { padding: 10px; }
84
+ .tier-system .panel-title { font-size: 9px; margin-bottom: 4px; }
85
+ .tier-system .score-count { font-size: 12px; }
86
+
87
+ /* Empty state with guidance */
88
+ .empty-guidance { font-size: 11px; color: var(--text-dim); margin-top: 4px; }
89
+ .empty-guidance code { background: var(--bg); padding: 2px 5px; border-radius: 3px; font-size: 10px; }
90
+
91
+ /* Deploy Status */
92
+ .deploy-badge { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; }
93
+ .deploy-dot { width: 8px; height: 8px; border-radius: 50%; }
94
+ .deploy-dot.live { background: var(--success); }
95
+ .deploy-dot.down { background: var(--error); }
96
+ .deploy-dot.unknown { background: var(--border); }
97
+
98
+ /* Version Badge */
99
+ .version-badge { font-size: 13px; font-weight: 600; color: var(--accent); }
100
+ .branch-status { font-size: 11px; color: var(--text-dim); margin-top: 4px; }
101
+
102
+ /* Focus management */
103
+ a:focus-visible, .panel:focus-visible, .tab-panel:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
104
+
105
+ /* ── Tab Navigation (§9.20.2) ── */
106
+ .tab-bar { display: none; gap: 2px; padding: 0 20px; border-bottom: 1px solid var(--border); background: var(--bg); grid-column: 1 / -1; grid-row: 2; }
107
+ .tab-bar.active { display: flex; }
108
+ .tab-bar [role="tab"] {
109
+ padding: 8px 16px; font-size: 12px; font-weight: 600; color: var(--text-dim);
110
+ background: none; border: none; border-bottom: 2px solid transparent;
111
+ cursor: pointer; text-transform: uppercase; letter-spacing: 0.05em;
112
+ }
113
+ .tab-bar [role="tab"]:hover { color: var(--text); }
114
+ .tab-bar [role="tab"][aria-selected="true"] { color: var(--accent); border-bottom-color: var(--accent); }
115
+ .tab-bar [role="tab"]:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
116
+ .tab-panel { display: none; }
117
+ .tab-panel.active { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-content: start; }
118
+
119
+ /* Financial Color Tokens — defined in styles.css :root (§9.15.3) */
120
+
121
+ /* ── Growth Tab Panels ── */
122
+ .kpi-row { display: flex; gap: 12px; grid-column: 1 / -1; }
123
+ .kpi-card { flex: 1; background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 14px; text-align: center; }
124
+ .kpi-value { font-size: 22px; font-weight: 700; }
125
+ .kpi-label { font-size: 10px; text-transform: uppercase; color: var(--text-dim); margin-top: 4px; }
126
+ .kpi-trend { font-size: 11px; margin-top: 2px; }
127
+ .kpi-trend.up { color: var(--fin-positive); }
128
+ .kpi-trend.down { color: var(--fin-negative); }
129
+ .kpi-trend.flat { color: var(--fin-neutral); }
130
+
131
+ .empty-state { grid-column: 1 / -1; text-align: center; padding: 48px 24px; color: var(--text-dim); font-size: 14px; }
132
+ .empty-state-action { margin-top: 12px; color: var(--accent); text-decoration: none; font-size: 13px; }
133
+
134
+ /* ── Freeze Button (§9.20.8) ── */
135
+ .freeze-btn { display: none; padding: 6px 14px; font-size: 12px; font-weight: 600; border-radius: 4px; cursor: pointer; }
136
+ .freeze-btn.visible { display: inline-flex; align-items: center; gap: 6px; }
137
+ .freeze-btn:not(.frozen) { background: none; border: 1px solid var(--fin-negative); color: var(--fin-negative); }
138
+ .freeze-btn:not(.frozen):hover { background: var(--fin-negative); color: white; }
139
+ .freeze-btn.frozen { background: var(--fin-frozen); border: 1px solid var(--fin-frozen); color: white; }
140
+ .freeze-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
141
+
142
+ /* ── Reconnection Banner (§9.19.9) ── */
143
+ .reconnect-banner { display: none; grid-column: 1 / -1; grid-row: 3; padding: 8px 20px; font-size: 12px; text-align: center; }
144
+ .reconnect-banner.reconnecting { display: block; background: var(--fin-warning); color: #000; }
145
+ .reconnect-banner.failed { display: block; background: var(--fin-negative); color: white; }
146
+
147
+ /* ── System Status Summary ── */
148
+ .system-status { font-size: 11px; color: var(--text-dim); padding: 4px 0; border-bottom: 1px solid var(--border); margin-bottom: 8px; }
149
+
150
+ /* ── Responsive ── */
151
+ @media (max-width: 700px) {
152
+ .danger-room { grid-template-columns: 1fr; grid-template-rows: auto auto auto 1fr auto auto; }
153
+ .danger-room-header { grid-column: 1; grid-row: 1; }
154
+ .tab-bar { grid-column: 1; grid-row: 2; }
155
+ .reconnect-banner { grid-column: 1; grid-row: 3; }
156
+ .main-panels { grid-column: 1; grid-row: 4; grid-template-columns: 1fr; }
157
+ .sidebar { grid-column: 1; grid-row: 5; border-left: none; border-top: 1px solid var(--border); }
158
+ .ticker { grid-column: 1; grid-row: 6; }
159
+ .tab-panel.active { grid-template-columns: 1fr; }
160
+ .tier-live .tier-content { grid-template-columns: 1fr; }
161
+ .tier-campaign .tier-content { grid-template-columns: 1fr; }
162
+ .tier-system .tier-content { grid-template-columns: 1fr 1fr; }
163
+ .kpi-row { flex-direction: column; }
164
+ .tab-bar { overflow-x: auto; -webkit-overflow-scrolling: touch; }
165
+ /* Mobile freeze FAB (§9.20.8) */
166
+ .freeze-fab { display: none; position: fixed; bottom: max(16px, env(safe-area-inset-bottom, 16px)); right: 16px; width: 56px; height: 56px; border-radius: 50%; font-size: 20px; z-index: 100; border: none; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,0.4); }
167
+ .freeze-fab.visible { display: flex; align-items: center; justify-content: center; }
168
+ .freeze-fab:not(.frozen) { background: var(--fin-negative); color: white; }
169
+ .freeze-fab.frozen { background: var(--fin-frozen); color: white; }
170
+ }
171
+ @media (min-width: 701px) { .freeze-fab { display: none !important; } }
172
+
173
+ /* Reduced motion */
174
+ @media (prefers-reduced-motion: reduce) {
175
+ .timeline-active, .pipeline-dot.active { animation: none; }
176
+ }
177
+ </style>
178
+ </head>
179
+ <body>
180
+ <a href="#danger-room-grid" class="skip-nav">Skip to main content</a>
181
+ <noscript><div class="noscript-msg">VoidForge requires JavaScript to run.</div></noscript>
182
+ <div class="danger-room">
183
+ <!-- Header -->
184
+ <header class="danger-room-header">
185
+ <div>
186
+ <div class="danger-room-title">Danger Room</div>
187
+ <div class="danger-room-version" id="version-display">VoidForge v—</div>
188
+ </div>
189
+ <div style="display:flex;align-items:center;gap:12px;">
190
+ <span id="header-context" style="font-size:11px;font-weight:600;color:var(--text-dim);padding:2px 8px;border:1px solid var(--border);border-radius:4px;" title="Context usage (always visible)" aria-label="Context usage">—%</span>
191
+ <button class="freeze-btn" id="freeze-btn" role="button"
192
+ aria-label="Emergency freeze: pause all automated spending" aria-pressed="false">❄ Freeze Spend</button>
193
+ <nav class="danger-room-nav" aria-label="Danger Room navigation">
194
+ <a href="lobby.html">Lobby</a>
195
+ <a href="danger-room.html" aria-current="page" style="background:var(--bg-card);color:var(--text);">Danger Room</a>
196
+ </nav>
197
+ </div>
198
+ </header>
199
+
200
+ <!-- Tab Bar (§9.20.2 — shown when Cultivation is installed) -->
201
+ <div class="tab-bar" id="tab-bar" role="tablist" aria-label="Danger Room tabs">
202
+ <button role="tab" id="tab-ops" aria-selected="true" aria-controls="panel-ops" data-tab="ops">Ops</button>
203
+ <button role="tab" id="tab-growth" aria-selected="false" aria-controls="panel-growth" data-tab="growth">Growth</button>
204
+ <button role="tab" id="tab-campaigns" aria-selected="false" aria-controls="panel-campaigns" data-tab="campaigns">Campaigns</button>
205
+ <button role="tab" id="tab-treasury" aria-selected="false" aria-controls="panel-treasury" data-tab="treasury">Treasury</button>
206
+ <button role="tab" id="tab-heartbeat" aria-selected="false" aria-controls="panel-heartbeat" data-tab="heartbeat">Heartbeat</button>
207
+ <button role="tab" id="tab-current" aria-selected="false" aria-controls="panel-current" data-tab="current">Deep Current</button>
208
+ </div>
209
+
210
+ <!-- Reconnection Banner (§9.19.9) -->
211
+ <div class="reconnect-banner" id="reconnect-banner" role="status" aria-live="polite"></div>
212
+
213
+ <!-- Mobile Freeze FAB (§9.20.8) -->
214
+ <button class="freeze-fab" id="freeze-fab" aria-label="Emergency freeze: pause all automated spending">❄</button>
215
+
216
+ <!-- Main Panels -->
217
+ <main class="main-panels" id="danger-room-grid">
218
+ <!-- ═══ OPS TAB ═══ -->
219
+ <div class="tab-panel active" id="panel-ops" role="tabpanel" aria-labelledby="tab-ops" tabindex="0">
220
+
221
+ <!-- ═══ TIER 1: LIVE FEED (real-time, changes per-second) ═══ -->
222
+ <div class="tier-section tier-live" role="region" aria-label="Live Feed">
223
+ <div class="tier-label">Live Feed</div>
224
+ <div class="tier-content">
225
+ <!-- Context Gauge (inline — moved from sidebar for prominence) -->
226
+ <div class="panel" role="region" aria-label="Context Usage">
227
+ <div class="gauge" id="context-gauge" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-label="Context window usage">
228
+ <svg viewBox="0 0 36 36"><circle class="gauge-track" cx="18" cy="18" r="14" /><circle class="gauge-fill" id="gauge-fill" cx="18" cy="18" r="14" stroke-dasharray="88" stroke-dashoffset="88" /></svg>
229
+ <div class="gauge-text" id="gauge-text">&mdash;%</div>
230
+ </div>
231
+ <div style="text-align:center;margin-top:4px;font-size:10px;color:var(--text-dim);" id="context-model"></div>
232
+ <div class="empty-guidance" id="context-empty" style="text-align:center;">Add <code>statusLine</code> to <code>~/.claude/settings.json</code></div>
233
+ </div>
234
+ <!-- Agent Activity (live ticker — was at bottom, now prominent) -->
235
+ <div class="panel" role="region" aria-label="Agent Activity" aria-live="polite">
236
+ <h2 class="panel-title">Agent Activity</h2>
237
+ <div id="agent-ticker-panel" style="font-size:12px;min-height:60px;">
238
+ <span class="ticker-item"><span class="ticker-agent">Sisko</span> standing by...</span>
239
+ <div class="empty-guidance">Run <code>/assemble</code> or <code>/campaign</code> to see live agent activity</div>
240
+ </div>
241
+ </div>
242
+ </div>
243
+ </div>
244
+
245
+ <!-- ═══ TIER 2: CAMPAIGN STATE (changes per-mission, ~30min cycles) ═══ -->
246
+ <div class="tier-section tier-campaign" role="region" aria-label="Campaign State">
247
+ <div class="tier-label">Campaign State</div>
248
+ <div class="tier-content">
249
+ <!-- Campaign Timeline -->
250
+ <div class="panel panel-full" role="region" aria-label="Campaign Timeline">
251
+ <h2 class="panel-title" id="title-timeline">Campaign Timeline</h2>
252
+ <div class="timeline" id="campaign-timeline" aria-labelledby="title-timeline">
253
+ <div class="timeline-item timeline-pending">—</div>
254
+ </div>
255
+ </div>
256
+
257
+ <!-- Phase Pipeline -->
258
+ <div class="panel" role="region" aria-label="Phase Pipeline">
259
+ <h2 class="panel-title" id="title-pipeline">Phase Pipeline</h2>
260
+ <div class="pipeline" id="phase-pipeline">
261
+ <div class="pipeline-phase"><span class="pipeline-dot pending"></span><span class="pipeline-label">No active build</span></div>
262
+ </div>
263
+ </div>
264
+
265
+ <!-- Finding Scoreboard -->
266
+ <div class="panel" role="region" aria-label="Finding Scoreboard">
267
+ <h2 class="panel-title" id="title-findings">Open Findings</h2>
268
+ <div class="scoreboard" id="finding-scoreboard" aria-labelledby="title-findings" role="group">
269
+ <div class="score-item score-critical"><div class="score-count" id="score-critical">0</div><div class="score-label">Critical</div></div>
270
+ <div class="score-item score-high"><div class="score-count" id="score-high">0</div><div class="score-label">High</div></div>
271
+ <div class="score-item score-medium"><div class="score-count" id="score-medium">0</div><div class="score-label">Medium</div></div>
272
+ <div class="score-item score-low"><div class="score-count" id="score-low">0</div><div class="score-label">Low</div></div>
273
+ </div>
274
+ </div>
275
+
276
+ <!-- PRD Coverage -->
277
+ <div class="panel panel-full" role="region" aria-label="PRD Coverage">
278
+ <h2 class="panel-title" id="title-prd">PRD Coverage</h2>
279
+ <div id="prd-coverage" style="font-size:13px;color:var(--text-dim);">No campaign active</div>
280
+ </div>
281
+
282
+ <!-- Prophecy Graph -->
283
+ <div class="panel panel-full" role="region" aria-label="Prophecy Graph">
284
+ <h2 class="panel-title" id="title-prophecy">Prophecy Graph</h2>
285
+ <div id="prophecy-graph" style="min-height:100px;"></div>
286
+ <div id="prophecy-detail" style="font-size:12px;margin-top:6px;min-height:40px;color:var(--text-dim);"></div>
287
+ </div>
288
+ </div>
289
+ </div>
290
+
291
+ <!-- ═══ TIER 3: SYSTEM STATUS (changes rarely, background monitoring) ═══ -->
292
+ <div class="tier-section tier-system" role="region" aria-label="System Status">
293
+ <div class="tier-label">System Status</div>
294
+ <div class="tier-content">
295
+ <div class="panel" role="region" aria-label="Version">
296
+ <h2 class="panel-title">Version</h2>
297
+ <div class="version-badge" id="version-badge">—</div>
298
+ <div class="branch-status" id="branch-status">—</div>
299
+ </div>
300
+ <div class="panel" role="region" aria-label="Deploy">
301
+ <h2 class="panel-title">Deploy</h2>
302
+ <div class="deploy-badge" id="deploy-status"><span class="deploy-dot unknown"></span><span>No deploy data</span></div>
303
+ </div>
304
+ <div class="panel" role="region" aria-label="Tests">
305
+ <h2 class="panel-title">Tests</h2>
306
+ <div id="test-status" style="font-size:12px;color:var(--text-dim);">No test data</div>
307
+ </div>
308
+ <div class="panel" role="region" aria-label="Experiments">
309
+ <h2 class="panel-title" id="title-experiments">Experiments</h2>
310
+ <div id="experiment-dashboard" aria-labelledby="title-experiments" style="font-size:12px;color:var(--text-dim);">No experiments</div>
311
+ </div>
312
+ </div>
313
+ </div>
314
+
315
+ </div><!-- /panel-ops -->
316
+
317
+ <!-- ═══ GROWTH TAB (§9.10 — read-only, placeholder data) ═══ -->
318
+ <div class="tab-panel" id="panel-growth" role="tabpanel" aria-labelledby="tab-growth" tabindex="0">
319
+ <!-- System Status Summary (§9.20.2) -->
320
+ <div class="system-status" id="growth-system-status" aria-live="polite" style="grid-column:1/-1;">
321
+ Cultivation: not installed — run <code>/cultivation install</code> to begin
322
+ </div>
323
+
324
+ <!-- Empty State (§9.15.7) -->
325
+ <div class="empty-state" id="growth-empty-state">
326
+ <div>No growth data yet.</div>
327
+ <div style="margin-top:8px;">Run <code>/grow</code> to start your first growth campaign.</div>
328
+ <a href="https://github.com/tmcleod3/voidforge#grow" class="empty-state-action">Learn about /grow →</a>
329
+ </div>
330
+
331
+ <!-- KPI Cards (hidden until data exists) -->
332
+ <div class="kpi-row" id="growth-kpi-row" style="display:none;">
333
+ <div class="kpi-card">
334
+ <div class="kpi-value" id="kpi-revenue">$0</div>
335
+ <div class="kpi-label">Revenue</div>
336
+ <div class="kpi-trend flat" id="kpi-revenue-trend">— MoM</div>
337
+ </div>
338
+ <div class="kpi-card">
339
+ <div class="kpi-value" id="kpi-spend">$0</div>
340
+ <div class="kpi-label">Spend</div>
341
+ <div class="kpi-trend flat" id="kpi-spend-trend">— MoM</div>
342
+ </div>
343
+ <div class="kpi-card">
344
+ <div class="kpi-value" id="kpi-net">$0</div>
345
+ <div class="kpi-label">Net</div>
346
+ <div class="kpi-trend flat" id="kpi-roas">0.0x</div>
347
+ </div>
348
+ </div>
349
+
350
+ <!-- Funding Indicators (v19.0 — hidden until stablecoin data exists) -->
351
+ <div class="kpi-row" id="growth-funding-row" style="display:none;">
352
+ <div class="kpi-card">
353
+ <div class="kpi-value" id="growth-runway-badge" style="font-size:18px;">&mdash;</div>
354
+ <div class="kpi-label">Runway</div>
355
+ </div>
356
+ <div class="kpi-card">
357
+ <div class="kpi-value" id="growth-funding-risk" style="font-size:14px;">&mdash;</div>
358
+ <div class="kpi-label">Funding Risk</div>
359
+ </div>
360
+ <div class="kpi-card">
361
+ <div class="kpi-value" id="growth-next-event" style="font-size:12px;font-weight:400;">&mdash;</div>
362
+ <div class="kpi-label">Next Event</div>
363
+ </div>
364
+ </div>
365
+
366
+ <!-- ROAS by Platform (placeholder) -->
367
+ <div class="panel panel-full" id="growth-roas-panel" style="display:none;" role="region" aria-label="ROAS by Platform">
368
+ <h2 class="panel-title">ROAS by Platform</h2>
369
+ <div style="font-size:13px;color:var(--text-dim);">No platform data</div>
370
+ </div>
371
+
372
+ <!-- Traffic Sources (placeholder) -->
373
+ <div class="panel" id="growth-traffic-panel" style="display:none;" role="region" aria-label="Traffic Sources">
374
+ <h2 class="panel-title">Traffic Sources</h2>
375
+ <div style="font-size:13px;color:var(--text-dim);">No traffic data</div>
376
+ </div>
377
+
378
+ <!-- Conversion Funnel (placeholder) -->
379
+ <div class="panel" id="growth-funnel-panel" style="display:none;" role="region" aria-label="Conversion Funnel">
380
+ <h2 class="panel-title">Conversion Funnel</h2>
381
+ <div style="font-size:13px;color:var(--text-dim);">No conversion data</div>
382
+ </div>
383
+ </div><!-- /panel-growth -->
384
+
385
+ <!-- ═══ AD CAMPAIGNS TAB (§9.10, §9.20.2 — v11.2) ═══ -->
386
+ <div class="tab-panel" id="panel-campaigns" role="tabpanel" aria-labelledby="tab-campaigns" tabindex="0">
387
+ <!-- Empty State -->
388
+ <div class="empty-state" id="campaigns-empty-state">
389
+ <div>No ad campaigns yet.</div>
390
+ <div style="margin-top:8px;">Run <code>/grow --distribute</code> to create campaigns.</div>
391
+ </div>
392
+
393
+ <!-- Campaign Table (hidden until data — becomes card layout on mobile §9.15.6) -->
394
+ <div class="panel panel-full" id="campaigns-table-panel" style="display:none;" role="region" aria-label="Ad Campaigns">
395
+ <h2 class="panel-title">Active Campaigns</h2>
396
+ <table style="width:100%;font-size:12px;border-collapse:collapse;" aria-label="Ad campaign performance">
397
+ <thead>
398
+ <tr style="text-align:left;color:var(--text-dim);border-bottom:1px solid var(--border);">
399
+ <th scope="col" style="padding:6px 8px;">Platform</th>
400
+ <th scope="col" style="padding:6px 8px;">Campaign</th>
401
+ <th scope="col" style="padding:6px 8px;">Spend</th>
402
+ <th scope="col" style="padding:6px 8px;">Conv</th>
403
+ <th scope="col" style="padding:6px 8px;" aria-sort="none">ROAS</th>
404
+ <th scope="col" style="padding:6px 8px;">Status</th>
405
+ </tr>
406
+ </thead>
407
+ <tbody id="campaigns-tbody">
408
+ <tr><td colspan="6" style="padding:12px;color:var(--text-dim);text-align:center;">Loading...</td></tr>
409
+ </tbody>
410
+ </table>
411
+ </div>
412
+
413
+ <!-- A/B Test Groups (§9.20.3) -->
414
+ <div class="panel" id="campaigns-ab-panel" style="display:none;" role="region" aria-label="A/B Test Groups">
415
+ <h2 class="panel-title">A/B Tests</h2>
416
+ <div id="campaigns-ab-tests" style="font-size:13px;color:var(--text-dim);">No active tests</div>
417
+ </div>
418
+
419
+ <!-- Agent Recommendations (§9.20.6) -->
420
+ <div class="panel" id="campaigns-recommendations-panel" style="display:none;" role="region" aria-label="Agent Recommendations">
421
+ <h2 class="panel-title">Recommendations</h2>
422
+ <div id="campaigns-recommendations" style="font-size:13px;color:var(--text-dim);">No recommendations</div>
423
+ </div>
424
+ </div><!-- /panel-campaigns -->
425
+
426
+ <!-- ═══ TREASURY TAB (§9.10 — financial summary) ═══ -->
427
+ <div class="tab-panel" id="panel-treasury" role="tabpanel" aria-labelledby="tab-treasury" tabindex="0">
428
+ <!-- Empty State -->
429
+ <div class="empty-state" id="treasury-empty-state">
430
+ <div>No treasury data yet.</div>
431
+ <div style="margin-top:8px;">Run <code>/treasury setup</code> to connect revenue sources.</div>
432
+ </div>
433
+
434
+ <!-- Stablecoin Funding Rail (v19.0 — hidden until configured) -->
435
+ <div class="panel panel-full" id="treasury-funding-panel" style="display:none;" role="region" aria-label="Stablecoin Funding Rail">
436
+ <h2 class="panel-title">Funding Rail</h2>
437
+ <div id="treasury-funding-content" style="font-size:13px;"></div>
438
+ </div>
439
+
440
+ <!-- Financial Summary (hidden until data) -->
441
+ <div class="kpi-row" id="treasury-kpi-row" style="display:none;">
442
+ <div class="kpi-card">
443
+ <div class="kpi-value" id="treasury-revenue">$0</div>
444
+ <div class="kpi-label">Revenue</div>
445
+ </div>
446
+ <div class="kpi-card">
447
+ <div class="kpi-value" id="treasury-spend">$0</div>
448
+ <div class="kpi-label">Spend</div>
449
+ </div>
450
+ <div class="kpi-card">
451
+ <div class="kpi-value" id="treasury-net">$0</div>
452
+ <div class="kpi-label">Net</div>
453
+ </div>
454
+ <div class="kpi-card">
455
+ <div class="kpi-value" id="treasury-roas">0.0x</div>
456
+ <div class="kpi-label">ROAS</div>
457
+ </div>
458
+ </div>
459
+
460
+ <!-- Budget Utilization -->
461
+ <div class="panel panel-full" id="treasury-budget-panel" style="display:none;" role="region" aria-label="Budget Utilization">
462
+ <h2 class="panel-title">Budget</h2>
463
+ <div style="background:var(--bg);border-radius:4px;height:24px;overflow:hidden;position:relative;">
464
+ <div id="treasury-budget-bar" style="height:100%;background:var(--fin-positive);width:0%;transition:width 0.5s;" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" aria-valuetext="0% of budget used"></div>
465
+ </div>
466
+ <div style="display:flex;justify-content:space-between;font-size:11px;color:var(--text-dim);margin-top:4px;">
467
+ <span id="treasury-budget-used">$0 used</span>
468
+ <span id="treasury-budget-total">$0 total</span>
469
+ </div>
470
+ </div>
471
+
472
+ <!-- Platform Connections -->
473
+ <div class="panel" id="treasury-connections-panel" style="display:none;" role="region" aria-label="Platform Connections">
474
+ <h2 class="panel-title">Connections</h2>
475
+ <div id="treasury-connections" style="font-size:13px;"></div>
476
+ </div>
477
+
478
+ <!-- Reconciliation Status -->
479
+ <div class="panel" id="treasury-reconciliation-panel" style="display:none;" role="region" aria-label="Reconciliation">
480
+ <h2 class="panel-title">Reconciliation</h2>
481
+ <div id="treasury-reconciliation" style="font-size:13px;color:var(--text-dim);">No reconciliation data</div>
482
+ </div>
483
+ </div><!-- /panel-treasury -->
484
+
485
+ <!-- ═══ HEARTBEAT TAB (§9.10, §9.20.2 — v11.3) ═══ -->
486
+ <div class="tab-panel" id="panel-heartbeat" role="tabpanel" aria-labelledby="tab-heartbeat" tabindex="0">
487
+ <!-- Empty State -->
488
+ <div class="empty-state" id="heartbeat-empty-state">
489
+ <div>Heartbeat daemon not running.</div>
490
+ <div style="margin-top:8px;">Run <code>voidforge heartbeat start</code> to begin monitoring.</div>
491
+ </div>
492
+
493
+ <!-- Daemon Status (hidden until data) -->
494
+ <div class="panel panel-full" id="heartbeat-status-panel" style="display:none;" role="region" aria-label="Daemon Status" aria-live="polite">
495
+ <h2 class="panel-title">Status</h2>
496
+ <div style="display:flex;gap:24px;font-size:13px;">
497
+ <div><span style="color:var(--text-dim);">State:</span> <span id="hb-state">—</span></div>
498
+ <div><span style="color:var(--text-dim);">PID:</span> <span id="hb-pid">—</span></div>
499
+ <div><span style="color:var(--text-dim);">Uptime:</span> <span id="hb-uptime">—</span></div>
500
+ <div><span style="color:var(--text-dim);">Last beat:</span> <span id="hb-last-beat">—</span></div>
501
+ </div>
502
+ </div>
503
+
504
+ <!-- Token Health -->
505
+ <div class="panel" id="heartbeat-tokens-panel" style="display:none;" role="region" aria-label="Token Health">
506
+ <h2 class="panel-title">Token Health</h2>
507
+ <div id="hb-token-list" style="font-size:13px;">
508
+ <!-- Dynamically populated: platform + status + expiry -->
509
+ </div>
510
+ </div>
511
+
512
+ <!-- Scheduled Jobs -->
513
+ <div class="panel" id="heartbeat-jobs-panel" style="display:none;" role="region" aria-label="Scheduled Jobs">
514
+ <h2 class="panel-title">Next Scheduled Jobs</h2>
515
+ <div id="hb-jobs-list" style="font-size:13px;color:var(--text-dim);">
516
+ <!-- Dynamically populated: job name + next run time -->
517
+ </div>
518
+ </div>
519
+
520
+ <!-- Anomaly Alerts (aria-live="assertive" for financial alerts §9.15.8) -->
521
+ <div class="panel panel-full" id="heartbeat-alerts-panel" style="display:none;" role="region" aria-label="Alerts" aria-live="assertive">
522
+ <h2 class="panel-title">Alerts</h2>
523
+ <div id="hb-alerts" style="font-size:13px;">No alerts</div>
524
+ </div>
525
+ <!-- Funding Operations (v19.0 — provider sync, pending ops, reconciliation) -->
526
+ <div class="panel panel-full" id="heartbeat-funding-ops-panel" style="display:none;" role="region" aria-label="Funding Operations">
527
+ <h2 class="panel-title">Funding Operations</h2>
528
+ <div id="hb-funding-ops" style="font-size:13px;color:var(--text-dim);">No funding operations data</div>
529
+ </div>
530
+ </div><!-- /panel-heartbeat -->
531
+
532
+ <!-- ═══ DEEP CURRENT TAB (v12.1 — Tuvok's advisory) ═══ -->
533
+ <div class="tab-panel" id="panel-current" role="tabpanel" aria-labelledby="tab-current" tabindex="0">
534
+ <!-- Empty State -->
535
+ <div class="empty-state" id="current-empty-state">
536
+ <div>Deep Current not initialized.</div>
537
+ <div style="margin-top:8px;">Run <code>/current --scan</code> to analyze your project, or <code>/current --intake</code> for a new project.</div>
538
+ </div>
539
+
540
+ <!-- Situation Model (5-dimension radar display) -->
541
+ <div class="panel panel-full" id="current-situation-panel" style="display:none;" role="region" aria-label="Situation Model">
542
+ <h2 class="panel-title">Situation Model</h2>
543
+ <div style="display:flex;gap:16px;flex-wrap:wrap;" id="current-dimensions">
544
+ <div class="kpi-card" style="flex:1;min-width:120px;">
545
+ <div class="kpi-value" id="dim-feature">—</div>
546
+ <div class="kpi-label">Feature</div>
547
+ </div>
548
+ <div class="kpi-card" style="flex:1;min-width:120px;">
549
+ <div class="kpi-value" id="dim-quality">—</div>
550
+ <div class="kpi-label">Quality</div>
551
+ </div>
552
+ <div class="kpi-card" style="flex:1;min-width:120px;">
553
+ <div class="kpi-value" id="dim-performance">—</div>
554
+ <div class="kpi-label">Performance</div>
555
+ </div>
556
+ <div class="kpi-card" style="flex:1;min-width:120px;">
557
+ <div class="kpi-value" id="dim-growth">—</div>
558
+ <div class="kpi-label">Growth</div>
559
+ </div>
560
+ <div class="kpi-card" style="flex:1;min-width:120px;">
561
+ <div class="kpi-value" id="dim-revenue">—</div>
562
+ <div class="kpi-label">Revenue</div>
563
+ </div>
564
+ </div>
565
+ </div>
566
+
567
+ <!-- Active Proposal -->
568
+ <div class="panel panel-full" id="current-proposal-panel" style="display:none;" role="region" aria-label="Campaign Recommendation">
569
+ <h2 class="panel-title">Tuvok Recommends</h2>
570
+ <div id="current-proposal-name" style="font-size:16px;font-weight:700;margin-bottom:8px;"></div>
571
+ <div id="current-proposal-case" style="font-size:13px;color:var(--text-dim);margin-bottom:12px;"></div>
572
+ <div id="current-proposal-impact" style="font-size:13px;color:var(--fin-positive);margin-bottom:12px;"></div>
573
+ <div style="display:flex;gap:8px;">
574
+ <button style="padding:6px 16px;background:var(--accent);color:white;border:none;border-radius:4px;cursor:pointer;font-size:12px;" aria-label="Launch recommended campaign">Launch Campaign</button>
575
+ <button style="padding:6px 16px;background:none;border:1px solid var(--border);color:var(--text-dim);border-radius:4px;cursor:pointer;font-size:12px;" aria-label="Dismiss recommendation">Dismiss</button>
576
+ </div>
577
+ </div>
578
+
579
+ <!-- Prediction History -->
580
+ <div class="panel" id="current-predictions-panel" style="display:none;" role="region" aria-label="Prediction Accuracy">
581
+ <h2 class="panel-title">Prediction Accuracy</h2>
582
+ <div id="current-predictions" style="font-size:13px;color:var(--text-dim);">No campaigns with tracked predictions yet.</div>
583
+ </div>
584
+
585
+ <!-- Autonomy Status -->
586
+ <div class="panel" id="current-autonomy-panel" style="display:none;" role="region" aria-label="Autonomy Status">
587
+ <h2 class="panel-title">Autonomy</h2>
588
+ <div style="font-size:13px;">
589
+ <span style="color:var(--text-dim);">Tier:</span> <span id="current-tier">1 (Advisor)</span><br>
590
+ <span style="color:var(--text-dim);">Campaigns run:</span> <span id="current-campaign-count">0</span><br>
591
+ <span style="color:var(--text-dim);">Last scan:</span> <span id="current-last-scan">Never</span>
592
+ </div>
593
+ </div>
594
+ </div><!-- /panel-current -->
595
+ </main>
596
+
597
+ <!-- Sidebar -->
598
+ <aside class="sidebar">
599
+ <!-- Session Cost (compact — data from Status Line bridge) -->
600
+ <div class="panel">
601
+ <h2 class="panel-title">Session Cost</h2>
602
+ <div id="cost-display" style="font-size:18px;font-weight:700;color:var(--text);">—</div>
603
+ <div class="empty-guidance" id="cost-empty">Wired via Status Line bridge</div>
604
+ </div>
605
+
606
+ <!-- Quick Links -->
607
+ <div class="panel">
608
+ <h2 class="panel-title">Quick Actions</h2>
609
+ <div style="font-size:11px;color:var(--text-dim);line-height:1.8;">
610
+ <code>/campaign --blitz</code> — Build everything<br>
611
+ <code>/gauntlet</code> — Full review<br>
612
+ <code>/debrief --inbox</code> — Triage reports
613
+ </div>
614
+ </div>
615
+ </aside>
616
+
617
+ <!-- Agent Activity Ticker (scrolling footer — mirrors Tier 1 panel) -->
618
+ <footer class="ticker" id="agent-ticker" aria-live="polite" aria-label="Agent activity feed">
619
+ <span class="ticker-item"><span class="ticker-agent">Sisko</span> standing by...</span>
620
+ </footer>
621
+ </div>
622
+
623
+ <script src="danger-room-prophecy.js"></script>
624
+ <script src="danger-room.js"></script>
625
+ </body>
626
+ </html>