smlflg commited on
Commit
0ef38b4
·
verified ·
1 Parent(s): a2dbca5

Initial public upload from Projekte/CodexMaxHarnessHowTo

Browse files
Files changed (5) hide show
  1. .codex/config.toml +31 -0
  2. README.md +26 -0
  3. app.js +352 -0
  4. index.html +433 -0
  5. styles.css +911 -0
.codex/config.toml ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Coding MCPs: project-local registration (2026-09-07).
2
+
3
+ [mcp_servers.serena]
4
+ command = "/home/smlflg/.local/share/coding-mcp/serena/.venv/bin/serena"
5
+ args = ["start-mcp-server", "--context=codex", "--project", "/home/smlflg/Projekte/CodexMaxHarnessHowTo", "--enable-web-dashboard", "false", "--open-web-dashboard", "false", "--enable-gui-log-window", "false"]
6
+ cwd = "/home/smlflg/Projekte/CodexMaxHarnessHowTo"
7
+ enabled = true
8
+ startup_timeout_sec = 120
9
+ tool_timeout_sec = 180
10
+
11
+ [mcp_servers.serena.env]
12
+ "SERENA_HOME" = "/home/smlflg/.local/share/coding-mcp/serena/state"
13
+
14
+ [mcp_servers.gitnexus]
15
+ command = "/home/smlflg/.nvm/versions/node/v24.13.0/bin/node"
16
+ args = ["/home/smlflg/.local/share/coding-mcp/gitnexus/node_modules/gitnexus/dist/cli/index.js", "mcp"]
17
+ cwd = "/home/smlflg/Projekte/CodexMaxHarnessHowTo"
18
+ enabled = true
19
+ startup_timeout_sec = 120
20
+ tool_timeout_sec = 180
21
+
22
+ [mcp_servers.gitnexus.env]
23
+ "GITNEXUS_HOME" = "/home/smlflg/.local/share/coding-mcp/gitnexus/runtime"
24
+
25
+ [mcp_servers.context7]
26
+ command = "/home/smlflg/.nvm/versions/node/v24.13.0/bin/node"
27
+ args = ["/home/smlflg/.local/share/coding-mcp/context7/node_modules/@upstash/context7-mcp/dist/index.js"]
28
+ cwd = "/home/smlflg/Projekte/CodexMaxHarnessHowTo"
29
+ enabled = true
30
+ startup_timeout_sec = 120
31
+ tool_timeout_sec = 180
README.md ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Codex Max Harness How-To
2
+
3
+ Private lokale Static-Site fuer ein 8-Tage-Codex-Runbook.
4
+
5
+ ## Oeffnen
6
+
7
+ `index.html` direkt im Browser oeffnen. Die Seite nutzt keine externen Runtime-Abhaengigkeiten.
8
+
9
+ ## Inhalte
10
+
11
+ - 8-Tage-Plan fuer produktive Codex-Nutzung
12
+ - Burn-down-Rechner fuer Credit- oder Credit-Aequivalent-Planung
13
+ - Task-Kosten-Schaetzung anhand der OpenAI Codex Rate Card
14
+ - lokales Harness-Backlog per `localStorage`
15
+ - Prompt-Vorlagen fuer Codex CLI und Review-Runs
16
+ - Praxis-Log: Claude-Code-Setup, Codex-Subagent-Profil und Harness-Ausnahme
17
+
18
+ ## Quellen
19
+
20
+ Die Zahlen und Aussagen wurden am 21. April 2026 gegen offizielle OpenAI-Help/Docs-Seiten geprueft:
21
+
22
+ - Using Codex with your ChatGPT plan: https://help.openai.com/en/articles/11369540-codex-in-chatgpt-faq
23
+ - Codex rate card: https://help-lb.openai.com/en/articles/20001106-codex-rate-card
24
+ - About ChatGPT Pro tiers: https://help.openai.com/en/articles/9793128-what-is-c
25
+ - Using Credits for Flexible Usage: https://help.openai.com/en/articles/12642688-using-credits-for-flexible-usage-in-chatgpt-free-go-plus-pro-sora
26
+ - Docs MCP: https://developers.openai.com/learn/docs-mcp
app.js ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const rateCard = {
2
+ "GPT-5.4": { input: 62.5, cached: 6.25, output: 375 },
3
+ "GPT-5.4-Mini": { input: 18.75, cached: 1.875, output: 113 },
4
+ "GPT-5.3-Codex": { input: 43.75, cached: 4.375, output: 350 },
5
+ "GPT-5.2-Codex": { input: 43.75, cached: 4.375, output: 350 },
6
+ };
7
+
8
+ const days = [
9
+ {
10
+ title: "Inventar und Ziele",
11
+ mode: "Scout",
12
+ output: "Repo-Liste, Top-20 Task-Kandidaten, Risiko-Matrix",
13
+ items: ["Codex Usage Panel pruefen", "beste Repos nach Impact sortieren", "keine Endlosjobs starten"],
14
+ },
15
+ {
16
+ title: "Harness-Benchmark",
17
+ mode: "Scout",
18
+ output: "Messbare Eval-Suite fuer Codex, Hermes, OpenCode",
19
+ items: ["identische Tasksheets", "Zeit, Kosten, Fehlerklasse erfassen", "ein Scoreboard schreiben"],
20
+ },
21
+ {
22
+ title: "Testgenerator-Welle",
23
+ mode: "Build",
24
+ output: "Tests fuer riskante Module und fehlende Regressionen",
25
+ items: ["erst failing tests", "dann Fixes", "Coverage-Luecken dokumentieren"],
26
+ },
27
+ {
28
+ title: "Refactor-Welle",
29
+ mode: "Build",
30
+ output: "kleinere APIs, weniger Duplication, bessere Grenzen",
31
+ items: ["keine Big-Bang-Refactors", "jede Aenderung testbar", "Diffs nach Modul trennen"],
32
+ },
33
+ {
34
+ title: "Frontend-Finish",
35
+ mode: "Ship",
36
+ output: "visuell fertige lokale Tools mit Screenshot-Check",
37
+ items: ["mobile und desktop pruefen", "Textueberlauf fixen", "leere States bauen"],
38
+ },
39
+ {
40
+ title: "Doku und Runbooks",
41
+ mode: "Ship",
42
+ output: "README, Setup, Troubleshooting, Agent-Prompts",
43
+ items: ["nur operative Doku", "keine Markdown-Flut", "Prompts als wiederverwendbare Vorlagen"],
44
+ },
45
+ {
46
+ title: "Review-Tag",
47
+ mode: "Verify",
48
+ output: "Codex-Reviews, Security-Checks, CI-Fixes",
49
+ items: ["codex review nutzen", "Findings zuerst", "nur echte Risiken fixen"],
50
+ },
51
+ {
52
+ title: "Final Sweep",
53
+ mode: "Verify",
54
+ output: "Archiv, offene Risiken, naechster Monatsplan",
55
+ items: ["Zombie-Sessions schliessen", "Artefakte verlinken", "Lessons in Harness-Guide uebernehmen"],
56
+ },
57
+ ];
58
+
59
+ const prompts = [
60
+ {
61
+ title: "Deep Repo Audit",
62
+ command: `codex exec --full-auto -m gpt-5.4 -C /home/smlflg/Projekte/DEIN_REPO \\
63
+ "Lies das Repo, finde die 10 hoechsten Hebel fuer Tests, Sicherheit und Wartbarkeit. Aendere noch nichts. Gib eine priorisierte, belegte Liste mit Dateien und konkreten naechsten Commands aus."`,
64
+ },
65
+ {
66
+ title: "Harness Eval Run",
67
+ command: `codex exec --full-auto -m gpt-5.4 -C /home/smlflg/Projekte/HarnessEcosystem \\
68
+ "Baue eine kleine reproduzierbare Eval fuer Codex-Harness-Verhalten: Tasksheet, Messkriterien, Beispieltask, Ergebnis-Tabelle. Halte die Aenderung eng und teste lokal."`,
69
+ },
70
+ {
71
+ title: "Test-First Fix",
72
+ command: `codex exec --full-auto -m gpt-5.4 -c model_reasoning_effort="high" -C /home/smlflg/Projekte/DEIN_REPO \\
73
+ "Finde eine reale, riskante Bugklasse. Schreibe zuerst einen failing Test, implementiere den kleinsten Fix, fuehre relevante Tests aus und erklaere den Diff."`,
74
+ },
75
+ {
76
+ title: "Codex Review",
77
+ command: `codex review --base main "Priorisiere Bugs, Regressionen, Security-Risiken und fehlende Tests. Keine Stil-Nitpicks ohne Risiko."`,
78
+ },
79
+ {
80
+ title: "OpenAI Docs MCP Check",
81
+ command: `codex exec --search -C /home/smlflg/Projekte/DEIN_REPO \\
82
+ "Nutze openaiDeveloperDocs, pruefe ob unsere OpenAI-API-Nutzung aktuell ist, und schlage gezielte Code-Aenderungen vor. Nur offizielle OpenAI-Doku verwenden."`,
83
+ },
84
+ {
85
+ title: "Finish Pass",
86
+ command: `codex exec --full-auto -m gpt-5.4 -C /home/smlflg/Projekte/DEIN_REPO \\
87
+ "Mache aus diesem lokalen Tool ein fertiges Artefakt: README, Startanleitung, leere States, Fehlertexte, kleine UI-Politur und abschliessende Verifikation."`,
88
+ },
89
+ ];
90
+
91
+ const lanes = ["Scout", "Build", "Verify", "Ship"];
92
+ const defaultTasks = [
93
+ { id: "seed-mcp-docs", title: "Codex MCP Docs in bestehende OpenAI-Projekte einbauen", lane: "Scout", model: "GPT-5.4" },
94
+ { id: "seed-promptgarage-eval", title: "PromptGarage: Eval-DB pruefen und Judge-Runs automatisieren", lane: "Build", model: "GPT-5.3-Codex" },
95
+ { id: "seed-token-diaet", title: "HarnessEcosystem: TOKEN_DIAET mit neuen Codex-Rate-Card-Daten aktualisieren", lane: "Ship", model: "GPT-5.4" },
96
+ { id: "seed-static-sites", title: "Alle privaten Static-Sites auf mobile Textueberlaeufe pruefen", lane: "Verify", model: "GPT-5.4-Mini" },
97
+ ];
98
+
99
+ const formatter = new Intl.NumberFormat("de-DE", { maximumFractionDigits: 0 });
100
+ const preciseFormatter = new Intl.NumberFormat("de-DE", { maximumFractionDigits: 2 });
101
+ let taskState = loadTasks();
102
+
103
+ function escapeHtml(value) {
104
+ return String(value)
105
+ .replaceAll("&", "&")
106
+ .replaceAll("<", "&lt;")
107
+ .replaceAll(">", "&gt;")
108
+ .replaceAll('"', "&quot;")
109
+ .replaceAll("'", "&#039;");
110
+ }
111
+
112
+ function createId() {
113
+ if (globalThis.crypto?.randomUUID) return crypto.randomUUID();
114
+ return `task-${Date.now()}-${Math.random().toString(16).slice(2)}`;
115
+ }
116
+
117
+ function normalizeTask(task) {
118
+ const lane = lanes.includes(task?.lane) ? task.lane : "Scout";
119
+ const model = Object.hasOwn(rateCard, task?.model) ? task.model : "GPT-5.4";
120
+ return {
121
+ id: String(task?.id || createId()),
122
+ title: String(task?.title || "Unbenannter Task").slice(0, 240),
123
+ lane,
124
+ model,
125
+ };
126
+ }
127
+
128
+ function loadTasks() {
129
+ try {
130
+ const saved = localStorage.getItem("codex-max-harness-tasks");
131
+ if (!saved) return defaultTasks.map(normalizeTask);
132
+ const parsed = JSON.parse(saved);
133
+ return Array.isArray(parsed) ? parsed.map(normalizeTask) : defaultTasks.map(normalizeTask);
134
+ } catch {
135
+ return defaultTasks.map(normalizeTask);
136
+ }
137
+ }
138
+
139
+ function numberFrom(id) {
140
+ return Number(document.getElementById(id).value || 0);
141
+ }
142
+
143
+ function renderTimeline() {
144
+ document.getElementById("timeline").innerHTML = days
145
+ .map(
146
+ (day, index) => `
147
+ <article class="day-card">
148
+ <div class="day-kicker"><span class="dot"></span>Tag ${index + 1} · ${escapeHtml(day.mode)}</div>
149
+ <h3>${escapeHtml(day.title)}</h3>
150
+ <p><strong>Output:</strong> ${escapeHtml(day.output)}</p>
151
+ <ul>${day.items.map((item) => `<li>${escapeHtml(item)}</li>`).join("")}</ul>
152
+ </article>
153
+ `,
154
+ )
155
+ .join("");
156
+ }
157
+
158
+ function renderModels() {
159
+ const select = document.getElementById("modelSelect");
160
+ select.innerHTML = Object.keys(rateCard)
161
+ .map((model) => `<option value="${model}">${model}</option>`)
162
+ .join("");
163
+ }
164
+
165
+ function updateBudget() {
166
+ const remaining = numberFrom("remainingCredits");
167
+ const daysLeft = Math.max(1, numberFrom("remainingDays"));
168
+ const buffer = Math.min(40, Math.max(0, numberFrom("bufferPercent"))) / 100;
169
+ const blocks = Math.max(1, numberFrom("blocksPerDay"));
170
+ const usable = remaining * (1 - buffer);
171
+ const daily = usable / daysLeft;
172
+ const block = daily / blocks;
173
+
174
+ document.getElementById("usableCredits").textContent = formatter.format(usable);
175
+ document.getElementById("dailyCredits").textContent = formatter.format(daily);
176
+ document.getElementById("blockCredits").textContent = formatter.format(block);
177
+ }
178
+
179
+ function updateEstimate() {
180
+ const selected = document.getElementById("modelSelect").value;
181
+ const rate = rateCard[selected];
182
+ const input = numberFrom("inputTokens") * rate.input;
183
+ const cached = numberFrom("cachedTokens") * rate.cached;
184
+ const output = numberFrom("outputTokens") * rate.output;
185
+ const multiplier = document.getElementById("fastMode").checked ? 2 : 1;
186
+ const total = (input + cached + output) * multiplier;
187
+
188
+ document.getElementById("estimatedCredits").textContent = preciseFormatter.format(total);
189
+ document.getElementById("estimateDetail").textContent =
190
+ `${selected}: Input ${rate.input}, Cached ${rate.cached}, Output ${rate.output} Credits pro 1M Tokens`;
191
+ }
192
+
193
+ function getTasks() {
194
+ return taskState;
195
+ }
196
+
197
+ function saveTasks(tasks) {
198
+ taskState = tasks.map(normalizeTask);
199
+ try {
200
+ localStorage.setItem("codex-max-harness-tasks", JSON.stringify(taskState));
201
+ } catch {
202
+ // Keep the in-memory board working when file:// or private mode blocks storage.
203
+ }
204
+ }
205
+
206
+ function moveTask(id, direction) {
207
+ const tasks = getTasks();
208
+ const task = tasks.find((item) => item.id === id);
209
+ if (!task) return;
210
+ const index = lanes.indexOf(task.lane);
211
+ const nextIndex = Math.min(lanes.length - 1, Math.max(0, index + direction));
212
+ task.lane = lanes[nextIndex];
213
+ saveTasks(tasks);
214
+ renderKanban();
215
+ }
216
+
217
+ function deleteTask(id) {
218
+ saveTasks(getTasks().filter((task) => task.id !== id));
219
+ renderKanban();
220
+ }
221
+
222
+ function renderKanban() {
223
+ const tasks = getTasks();
224
+ document.getElementById("kanban").innerHTML = lanes
225
+ .map((lane) => {
226
+ const laneTasks = tasks.filter((task) => task.lane === lane);
227
+ return `
228
+ <section class="lane" aria-label="${escapeHtml(lane)}">
229
+ <h3>${escapeHtml(lane)}<span class="lane-count">${laneTasks.length}</span></h3>
230
+ ${laneTasks
231
+ .map(
232
+ (task) => `
233
+ <article class="task-card">
234
+ <strong>${escapeHtml(task.title)}</strong>
235
+ <div class="task-meta">
236
+ <span class="tag">${escapeHtml(task.model)}</span>
237
+ <span class="tag alt">${escapeHtml(task.lane)}</span>
238
+ </div>
239
+ <div class="task-actions">
240
+ <button type="button" data-task-move="${escapeHtml(task.id)}" data-direction="-1">Zurueck</button>
241
+ <button type="button" data-task-move="${escapeHtml(task.id)}" data-direction="1">Weiter</button>
242
+ <button type="button" data-task-delete="${escapeHtml(task.id)}">Loeschen</button>
243
+ </div>
244
+ </article>
245
+ `,
246
+ )
247
+ .join("")}
248
+ </section>
249
+ `;
250
+ })
251
+ .join("");
252
+ }
253
+
254
+ function renderPrompts() {
255
+ document.getElementById("promptGrid").innerHTML = prompts
256
+ .map(
257
+ (prompt, index) => `
258
+ <article class="prompt-card">
259
+ <h3>${escapeHtml(prompt.title)}</h3>
260
+ <pre><code>${escapeHtml(prompt.command)}</code></pre>
261
+ <button class="button ghost small" type="button" data-copy="${index}">Kopieren</button>
262
+ </article>
263
+ `,
264
+ )
265
+ .join("");
266
+ }
267
+
268
+ function fallbackCopy(text) {
269
+ const area = document.createElement("textarea");
270
+ area.value = text;
271
+ area.setAttribute("readonly", "");
272
+ area.style.position = "fixed";
273
+ area.style.left = "-9999px";
274
+ document.body.append(area);
275
+ area.select();
276
+ try {
277
+ return document.execCommand("copy");
278
+ } finally {
279
+ area.remove();
280
+ }
281
+ }
282
+
283
+ async function copyText(text) {
284
+ try {
285
+ if (navigator.clipboard?.writeText) {
286
+ await navigator.clipboard.writeText(text);
287
+ return true;
288
+ }
289
+ } catch {
290
+ // Fall through to the textarea fallback for file:// contexts.
291
+ }
292
+ return fallbackCopy(text);
293
+ }
294
+
295
+ function attachEvents() {
296
+ document.querySelectorAll("#budgetForm input").forEach((input) => {
297
+ input.addEventListener("input", updateBudget);
298
+ });
299
+
300
+ document.querySelectorAll("#costForm input, #costForm select").forEach((input) => {
301
+ input.addEventListener("input", updateEstimate);
302
+ input.addEventListener("change", updateEstimate);
303
+ });
304
+
305
+ document.getElementById("taskForm").addEventListener("submit", (event) => {
306
+ event.preventDefault();
307
+ const title = document.getElementById("taskTitle").value.trim();
308
+ if (!title) return;
309
+ const tasks = getTasks();
310
+ tasks.push({
311
+ id: createId(),
312
+ title,
313
+ lane: document.getElementById("taskLane").value,
314
+ model: document.getElementById("taskModel").value,
315
+ });
316
+ saveTasks(tasks);
317
+ event.currentTarget.reset();
318
+ renderKanban();
319
+ });
320
+
321
+ document.getElementById("kanban").addEventListener("click", (event) => {
322
+ const moveButton = event.target.closest("[data-task-move]");
323
+ if (moveButton) {
324
+ moveTask(moveButton.dataset.taskMove, Number(moveButton.dataset.direction));
325
+ return;
326
+ }
327
+
328
+ const deleteButton = event.target.closest("[data-task-delete]");
329
+ if (deleteButton) {
330
+ deleteTask(deleteButton.dataset.taskDelete);
331
+ }
332
+ });
333
+
334
+ document.getElementById("promptGrid").addEventListener("click", async (event) => {
335
+ const button = event.target.closest("[data-copy]");
336
+ if (!button) return;
337
+ const prompt = prompts[Number(button.dataset.copy)];
338
+ const copied = await copyText(prompt.command);
339
+ button.textContent = copied ? "Kopiert" : "Nicht kopiert";
340
+ window.setTimeout(() => {
341
+ button.textContent = "Kopieren";
342
+ }, 1200);
343
+ });
344
+ }
345
+
346
+ renderTimeline();
347
+ renderModels();
348
+ renderKanban();
349
+ renderPrompts();
350
+ attachEvents();
351
+ updateBudget();
352
+ updateEstimate();
index.html ADDED
@@ -0,0 +1,433 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="de">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Codex Max Harness | Privates 8-Tage-Runbook</title>
7
+ <meta
8
+ name="description"
9
+ content="Private lokale How-to-Seite fuer produktive Codex-Max-Nutzung ueber acht Tage."
10
+ />
11
+ <link rel="stylesheet" href="./styles.css" />
12
+ </head>
13
+ <body>
14
+ <header class="topbar">
15
+ <a class="brand" href="#top" aria-label="Codex Max Harness Start">
16
+ <span class="brand-mark" aria-hidden="true">CM</span>
17
+ <span>
18
+ <strong>Codex Max Harness</strong>
19
+ <small>Privates 8-Tage-Runbook</small>
20
+ </span>
21
+ </a>
22
+ <nav aria-label="Seitennavigation">
23
+ <a href="#plan">Plan</a>
24
+ <a href="#wellen">Wellen</a>
25
+ <a href="#setup-log">Setup</a>
26
+ <a href="#rechner">Rechner</a>
27
+ <a href="#backlog">Backlog</a>
28
+ <a href="#prompts">Prompts</a>
29
+ </nav>
30
+ </header>
31
+
32
+ <main id="top">
33
+ <section class="hero">
34
+ <div class="hero-copy">
35
+ <p class="eyebrow">Stand: 21. April 2026 · lokal · nicht deployt</p>
36
+ <h1>Nutze dein Codex-Pro-Fenster fuer echte Artefakte.</h1>
37
+ <p>
38
+ Acht intensive Codex-Tage: Evals, Refactors, Tests, Reviews, Dokumentation
39
+ und Produktisierung. Der Fokus liegt auf hoher Auslastung durch wertvolle
40
+ Arbeit, nicht auf Limit-Umgehung oder Token-Spam.
41
+ </p>
42
+ <div class="hero-actions">
43
+ <a class="button primary" href="#plan">8-Tage-Plan starten</a>
44
+ <a class="button ghost" href="#rechner">Budget schaetzen</a>
45
+ </div>
46
+ </div>
47
+ <aside class="signal-panel" aria-label="Status">
48
+ <div class="pulse-grid" aria-hidden="true">
49
+ <span></span><span></span><span></span><span></span>
50
+ <span></span><span></span><span></span><span></span>
51
+ <span></span><span></span><span></span><span></span>
52
+ </div>
53
+ <div class="signal-stats">
54
+ <div>
55
+ <strong>8</strong>
56
+ <span>Tage</span>
57
+ </div>
58
+ <div>
59
+ <strong>2</strong>
60
+ <span>aktive Sessions max.</span>
61
+ </div>
62
+ <div>
63
+ <strong>4</strong>
64
+ <span>Harness-Wellen</span>
65
+ </div>
66
+ </div>
67
+ </aside>
68
+ </section>
69
+
70
+ <section class="notice">
71
+ <strong>Korrekte Annahme:</strong>
72
+ <span>
73
+ Dein Pro-Tier oder Monatsbudget ist nicht automatisch ein linearer Token-Eimer.
74
+ Die plan-inkludierte Nutzung wird zuerst verbraucht; separat gekaufte Credits
75
+ greifen danach. Fuer Codex zaehlen Task-Komplexitaet, Ausfuehrungsort, Modell,
76
+ Fast Mode sowie Input-/Cached-/Output-Tokens. Pruefe dein echtes Limit im
77
+ Codex Usage Panel.
78
+ </span>
79
+ </section>
80
+
81
+ <section id="wellen" class="section">
82
+ <div class="section-head">
83
+ <p class="eyebrow">Subagents</p>
84
+ <h2>Mehr Agenten, aber in Wellen</h2>
85
+ <p>
86
+ Parallelitaet lohnt sich, wenn die Aufgaben entkoppelt sind. Jede Welle bekommt
87
+ ein klares Tasksheet, eigene Dateien und einen Konvergenzpunkt, bevor die naechste
88
+ Welle startet.
89
+ </p>
90
+ </div>
91
+ <div class="wave-grid">
92
+ <article class="wave-card">
93
+ <span>1</span>
94
+ <h3>Scout</h3>
95
+ <p>2-3 Read-only-Agenten lesen verschiedene Repos oder Problemfelder.</p>
96
+ <strong>Output: Befundliste mit Datei-/Risiko-Referenzen.</strong>
97
+ </article>
98
+ <article class="wave-card">
99
+ <span>2</span>
100
+ <h3>Plan</h3>
101
+ <p>Ein Hauptagent verdichtet die Scouts zu Tasksheets und Write-Scopes.</p>
102
+ <strong>Output: kleine, konfliktarme Arbeitspakete.</strong>
103
+ </article>
104
+ <article class="wave-card">
105
+ <span>3</span>
106
+ <h3>Build</h3>
107
+ <p>Mehrere Worker bearbeiten disjunkte Dateien oder Module parallel.</p>
108
+ <strong>Output: integrierbare Patches plus Testbefehle.</strong>
109
+ </article>
110
+ <article class="wave-card">
111
+ <span>4</span>
112
+ <h3>Verify</h3>
113
+ <p>Review-Agenten pruefen Verhalten, Tests, UI und Doku gegen den Scope.</p>
114
+ <strong>Output: Findings zuerst, dann Ship-Entscheidung.</strong>
115
+ </article>
116
+ </div>
117
+ <div class="guardrail">
118
+ <strong>Guardrail:</strong>
119
+ <span>
120
+ Keine Multi-Account-Tricks, kein Rate-Limit-Bypass, keine Endlosschleifen.
121
+ Viel Codex nutzen heisst hier: grosse legitime Aufgaben, klare Scopes,
122
+ Tests und Reviews.
123
+ </span>
124
+ </div>
125
+ </section>
126
+
127
+ <section id="setup-log" class="section">
128
+ <div class="section-head">
129
+ <p class="eyebrow">Praxis-Log</p>
130
+ <h2>Claude-Code-Setup als Vorlage fuer Codex</h2>
131
+ <p>
132
+ Dieser Inhalt ist ein dokumentierter Terminal-Snapshot, kein auszufuehrender Prompt.
133
+ Er zeigt, welche Muster aus deinem Claude-Code-Setup sinnvoll nach Codex wandern und
134
+ wo der Harness bewusst konservativ bleiben muss.
135
+ </p>
136
+ </div>
137
+
138
+ <div class="case-grid">
139
+ <article class="case-card">
140
+ <h3>Ausgangslage</h3>
141
+ <p>
142
+ Codex wurde in <code>~/.claude</code> gestartet und hat dein Claude-Code-Setup
143
+ read-only bewertet: <code>CLAUDE.md</code>, <code>settings.json</code>, Hooks,
144
+ Slash-Commands, GSD-Workflow, Agenten, Event-Logging und Tests.
145
+ </p>
146
+ <ul>
147
+ <li><code>settings.json</code> war syntaktisch valide.</li>
148
+ <li>Background-Agent-Gate: <code>5/5 tests passed</code>.</li>
149
+ <li>Event-Logger-Threshold: <code>4/4 tests passed</code>.</li>
150
+ <li>Worktree war dirty; Submodule <code>commands</code> war nicht initialisiert.</li>
151
+ </ul>
152
+ </article>
153
+
154
+ <article class="case-card">
155
+ <h3>Starke Muster</h3>
156
+ <p>
157
+ Das Setup ist mehr als Dotfiles: portable Config, Backup-Strategie, kompaktere
158
+ Kernregeln, Hook-Gates, Sidecar-/OpenCode-Anbindung und testbare Schutzlogik.
159
+ </p>
160
+ <ul>
161
+ <li>Explore-first statt blindem Bauen.</li>
162
+ <li>Background-Agent-Denke: Hauptsession bleibt Orchestrator.</li>
163
+ <li>Verification-Gate mit konkretem Test- oder Smoke-Beleg.</li>
164
+ <li>Mode-Trennung: Planning, Build, Review, Debug, Verify.</li>
165
+ </ul>
166
+ </article>
167
+
168
+ <article class="case-card warning-card">
169
+ <h3>Scharfe Kanten</h3>
170
+ <p>
171
+ Nicht alles gehoert nach Codex. Besonders riskant sind bequeme Permission-Defaults,
172
+ Hook-Kaskaden und zu viel unsichtbare Kontext-Injektion.
173
+ </p>
174
+ <ul>
175
+ <li><code>Bash(*)</code> plus Permission-Skip ist kein hartes Sicherheitsmodell.</li>
176
+ <li>Event-Logging kann sensible Tool-Payloads mitschneiden.</li>
177
+ <li>Absolute Sidecar-Pfade brechen Restore-Portabilitaet.</li>
178
+ <li>Zu viele Hooks koennen Latenz und schwer sichtbare Fehler erzeugen.</li>
179
+ </ul>
180
+ </article>
181
+ </div>
182
+
183
+ <div class="transfer-panel">
184
+ <div>
185
+ <p class="eyebrow">Transfer</p>
186
+ <h3>Nach Codex uebernehmen</h3>
187
+ <ul>
188
+ <li>Agent-first-Orchestrierung fuer nicht-triviale Aufgaben.</li>
189
+ <li>Explorer fuer unabhängige Codebase-Fragen, Risiken und Testkarten.</li>
190
+ <li>Worker nur mit disjunktem Datei- oder Modulbesitz.</li>
191
+ <li>Main Session als Integrator, Konfliktloeser und finaler Reviewer.</li>
192
+ <li>Config-Validation: Dateien komplett lesen, Syntax pruefen, keine Keys erfinden.</li>
193
+ </ul>
194
+ </div>
195
+ <div>
196
+ <p class="eyebrow">Nicht 1:1 uebernehmen</p>
197
+ <h3>Harness bleibt messbar</h3>
198
+ <ul>
199
+ <li>Keine Claude-Hook-Kaskade in Codex nachbauen.</li>
200
+ <li>Keine massive Slash-Command-Matrix ohne echten Nutzen.</li>
201
+ <li>Keine Permission-Lockerung als Produktivitaetsersatz.</li>
202
+ <li>Keine maximalen Subagent-Waves bei Evals, Benchmarks oder Ablations.</li>
203
+ <li>Keine parallelen Implementierer am selben bewerteten Artefakt.</li>
204
+ </ul>
205
+ </div>
206
+ </div>
207
+
208
+ <div class="implementation-note">
209
+ <strong>Implementierter Codex-Umbau:</strong>
210
+ <span>
211
+ <code>~/.codex/instructions.md</code> wurde global auf agent-first gestellt.
212
+ <code>build.md</code>, <code>planning.md</code> und <code>review.md</code>
213
+ nutzen parallele Lanes, wenn sie unabhaengig sind. Neu dazu kam
214
+ <code>~/.codex/runbooks/parallel-build.md</code>. Fuer
215
+ <code>HarnessEcosystem</code>, <code>.hermes</code>, <code>judge</code>,
216
+ <code>eval</code>, <code>benchmark</code>, <code>matrix</code> und
217
+ <code>ablation</code> gilt konservativer Eval-Modus.
218
+ </span>
219
+ </div>
220
+
221
+ <details class="terminal-log">
222
+ <summary>Terminal-Auszug anzeigen</summary>
223
+ <pre><code>smlflg@pop-os:~$ cd .claude/
224
+ smlflg@pop-os:~/.claude$ codex
225
+ OpenAI Codex v0.122.0
226
+ model: gpt-5.4 xhigh
227
+ directory: ~/.claude
228
+
229
+ Frage:
230
+ was sagst du zu meinem claude code setup
231
+
232
+ Read-only Checks:
233
+ - CLAUDE.md, settings.json, README.md, package.json
234
+ - hooks/coaching, event_logger.py, enforce-background-agents.py
235
+ - settings.json valid
236
+ - Background-Agent-Gate: 5/5 tests passed
237
+ - Event-Logger-Threshold: 4/4 tests passed
238
+ - Worktree dirty: CLAUDE.md, settings.json, coaching_log.md
239
+ - commands submodule nicht initialisiert
240
+
241
+ Einschaetzung:
242
+ Sehr gutes Power-User-Setup fuer schnelle agentische Arbeit, aber mit scharfen Kanten.
243
+ Staerken: kompakte Kernregeln, valide Settings, Hook-Gates, Tests, portable Backup-Story.
244
+ Risiken: Bash(*)/Permission-Skip, volle Hook-Payload-Logs, viele Hooks pro Prompt/Tool,
245
+ absolute Sidecar-Pfade, unsauberer Git/Submodule-Zustand.
246
+
247
+ Folgefrage:
248
+ codex profil so umbauen, dass codex immer maximal viele subagents verwendet;
249
+ welche Features aus Claude Code nach Codex/Hermes uebertragen?
250
+
251
+ Entscheidung:
252
+ Global aggressiv, aber Harness/Eval konservativ.
253
+
254
+ Umgesetzt:
255
+ - ~/.codex/instructions.md: agent-first orchestration
256
+ - ~/.codex/runbooks/build.md: parallele Explorer/Worker mit disjunkten Scopes
257
+ - ~/.codex/runbooks/planning.md: Explorer fuer unabhaengige Unbekannte
258
+ - ~/.codex/runbooks/review.md: Behavior/Test/Architektur-Lanes
259
+ - ~/.codex/runbooks/parallel-build.md: neues Runbook fuer maximale sinnvolle Subagent-Waves
260
+
261
+ Harness-Ausnahme:
262
+ Bei HarnessEcosystem, FirstRealHarnessEvaluation_KarpathiesMD, .hermes, harness-*,
263
+ judge, eval, benchmark, matrix, ablation oder Prompt-/Rule-Experimenten:
264
+ keine spekulativen Subagent-Waves, keine parallelen Implementierer am selben Artefakt,
265
+ Reproduzierbarkeit und Attribution vor Durchsatz.</code></pre>
266
+ </details>
267
+ </section>
268
+
269
+ <section id="plan" class="section">
270
+ <div class="section-head">
271
+ <p class="eyebrow">Runbook</p>
272
+ <h2>8 Tage, acht Outputs</h2>
273
+ <p>
274
+ Jeder Tag endet mit einem greifbaren Ergebnis. Wenn ein Tag schneller fertig ist,
275
+ wird nicht blind fan-out erzeugt, sondern die naechste Review- oder Testwelle gestartet.
276
+ </p>
277
+ </div>
278
+ <div class="timeline" id="timeline"></div>
279
+ </section>
280
+
281
+ <section id="rechner" class="section split">
282
+ <div class="panel">
283
+ <div class="panel-head">
284
+ <p class="eyebrow">Burn-down</p>
285
+ <h2>Tagesziel berechnen</h2>
286
+ </div>
287
+ <form class="controls" id="budgetForm">
288
+ <label>
289
+ Zusatz-Credits oder eigenes Planungsziel
290
+ <input id="remainingCredits" type="number" min="0" step="10" value="10000" />
291
+ </label>
292
+ <label>
293
+ Resttage
294
+ <input id="remainingDays" type="number" min="1" max="31" value="8" />
295
+ </label>
296
+ <label>
297
+ Sicherheitspuffer in %
298
+ <input id="bufferPercent" type="number" min="0" max="40" value="8" />
299
+ </label>
300
+ <label>
301
+ Geplante Arbeitsbloecke pro Tag
302
+ <input id="blocksPerDay" type="number" min="1" max="8" value="3" />
303
+ </label>
304
+ </form>
305
+ <div class="metrics">
306
+ <div>
307
+ <span>Nutzbar</span>
308
+ <strong id="usableCredits">9.200</strong>
309
+ </div>
310
+ <div>
311
+ <span>Pro Tag</span>
312
+ <strong id="dailyCredits">1.150</strong>
313
+ </div>
314
+ <div>
315
+ <span>Pro Block</span>
316
+ <strong id="blockCredits">383</strong>
317
+ </div>
318
+ </div>
319
+ </div>
320
+
321
+ <div class="panel">
322
+ <div class="panel-head">
323
+ <p class="eyebrow">Rate Card</p>
324
+ <h2>Task-Kosten schaetzen</h2>
325
+ </div>
326
+ <form class="controls" id="costForm">
327
+ <label>
328
+ Modell
329
+ <select id="modelSelect"></select>
330
+ </label>
331
+ <label>
332
+ Input Tokens in Mio.
333
+ <input id="inputTokens" type="number" min="0" step="0.01" value="0.25" />
334
+ </label>
335
+ <label>
336
+ Cached Input Tokens in Mio.
337
+ <input id="cachedTokens" type="number" min="0" step="0.01" value="0.4" />
338
+ </label>
339
+ <label>
340
+ Output Tokens in Mio.
341
+ <input id="outputTokens" type="number" min="0" step="0.01" value="0.06" />
342
+ </label>
343
+ <label class="check">
344
+ <input id="fastMode" type="checkbox" />
345
+ <span>Fast Mode einrechnen (2x Credits)</span>
346
+ </label>
347
+ </form>
348
+ <div class="estimate">
349
+ <span>Geschaetzte Task-Kosten</span>
350
+ <strong id="estimatedCredits">0</strong>
351
+ <small id="estimateDetail">Credits</small>
352
+ </div>
353
+ </div>
354
+ </section>
355
+
356
+ <section id="backlog" class="section">
357
+ <div class="section-head">
358
+ <p class="eyebrow">Harness-Backlog</p>
359
+ <h2>Aufgaben, die Tokens verdienen</h2>
360
+ <p>
361
+ Speichere High-Value-Aufgaben lokal im Browser. Gute Kandidaten sind grosse
362
+ Codebase-Reviews, Testgenerierung, UI-Finishing, Migrationspläne und Eval-Runs.
363
+ </p>
364
+ </div>
365
+ <form class="task-form" id="taskForm">
366
+ <label class="visually-hidden" for="taskTitle">Backlog-Task</label>
367
+ <input id="taskTitle" name="taskTitle" placeholder="Task, z. B. PromptGarage Eval-Harness haerten" required />
368
+ <select id="taskLane" name="taskLane" aria-label="Lane">
369
+ <option value="Scout">Scout</option>
370
+ <option value="Build">Build</option>
371
+ <option value="Verify">Verify</option>
372
+ <option value="Ship">Ship</option>
373
+ </select>
374
+ <select id="taskModel" name="taskModel" aria-label="Modell">
375
+ <option>GPT-5.4</option>
376
+ <option>GPT-5.3-Codex</option>
377
+ <option>GPT-5.4-Mini</option>
378
+ </select>
379
+ <button class="button primary" type="submit">Hinzufuegen</button>
380
+ </form>
381
+ <div class="kanban" id="kanban"></div>
382
+ </section>
383
+
384
+ <section id="prompts" class="section">
385
+ <div class="section-head">
386
+ <p class="eyebrow">Prompt-Bibliothek</p>
387
+ <h2>Codex-Kommandos fuer lange, wertvolle Runs</h2>
388
+ <p>
389
+ Die Vorlagen sind fuer lokale Arbeit gedacht. Passe Pfade und Repositories an,
390
+ bevor du sie ausfuehrst.
391
+ </p>
392
+ </div>
393
+ <div class="prompt-grid" id="promptGrid"></div>
394
+ </section>
395
+
396
+ <section class="section sources">
397
+ <div class="section-head">
398
+ <p class="eyebrow">Quellen</p>
399
+ <h2>Offizielle Grundlage</h2>
400
+ </div>
401
+ <ul>
402
+ <li>
403
+ <a href="https://help.openai.com/en/articles/11369540-codex-in-chatgpt-faq">
404
+ OpenAI Help: Using Codex with your ChatGPT plan
405
+ </a>
406
+ </li>
407
+ <li>
408
+ <a href="https://help-lb.openai.com/en/articles/20001106-codex-rate-card">
409
+ OpenAI Help: Codex rate card
410
+ </a>
411
+ </li>
412
+ <li>
413
+ <a href="https://help.openai.com/en/articles/9793128-what-is-c">
414
+ OpenAI Help: About ChatGPT Pro tiers
415
+ </a>
416
+ </li>
417
+ <li>
418
+ <a href="https://help.openai.com/en/articles/12642688-using-credits-for-flexible-usage-in-chatgpt-free-go-plus-pro-sora">
419
+ OpenAI Help: Using Credits for Flexible Usage
420
+ </a>
421
+ </li>
422
+ <li>
423
+ <a href="https://developers.openai.com/learn/docs-mcp">
424
+ OpenAI Developers: Docs MCP
425
+ </a>
426
+ </li>
427
+ </ul>
428
+ </section>
429
+ </main>
430
+
431
+ <script src="./app.js"></script>
432
+ </body>
433
+ </html>
styles.css ADDED
@@ -0,0 +1,911 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root {
2
+ --bg: #f7f8fb;
3
+ --surface: #ffffff;
4
+ --ink: #16202a;
5
+ --muted: #667380;
6
+ --line: #dfe5ec;
7
+ --teal: #0f9f8f;
8
+ --teal-dark: #087568;
9
+ --coral: #df5a45;
10
+ --gold: #bd8d24;
11
+ --blue: #316fd0;
12
+ --green-soft: #dff5ef;
13
+ --coral-soft: #fde6df;
14
+ --gold-soft: #fff2c9;
15
+ --blue-soft: #e4edff;
16
+ --shadow: 0 18px 55px rgba(25, 39, 52, 0.12);
17
+ color-scheme: light;
18
+ font-family:
19
+ Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
20
+ }
21
+
22
+ * {
23
+ box-sizing: border-box;
24
+ }
25
+
26
+ .visually-hidden {
27
+ position: absolute;
28
+ width: 1px;
29
+ height: 1px;
30
+ padding: 0;
31
+ margin: -1px;
32
+ overflow: hidden;
33
+ clip: rect(0, 0, 0, 0);
34
+ white-space: nowrap;
35
+ border: 0;
36
+ }
37
+
38
+ html {
39
+ scroll-behavior: smooth;
40
+ overflow-x: hidden;
41
+ }
42
+
43
+ body {
44
+ margin: 0;
45
+ background:
46
+ linear-gradient(120deg, rgba(15, 159, 143, 0.08), transparent 34%),
47
+ linear-gradient(260deg, rgba(223, 90, 69, 0.08), transparent 30%),
48
+ var(--bg);
49
+ color: var(--ink);
50
+ overflow-x: hidden;
51
+ }
52
+
53
+ a {
54
+ color: inherit;
55
+ }
56
+
57
+ .topbar {
58
+ position: sticky;
59
+ top: 0;
60
+ z-index: 10;
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: space-between;
64
+ gap: 20px;
65
+ min-height: 70px;
66
+ padding: 12px clamp(18px, 4vw, 54px);
67
+ border-bottom: 1px solid rgba(223, 229, 236, 0.8);
68
+ background: rgba(247, 248, 251, 0.88);
69
+ backdrop-filter: blur(18px);
70
+ }
71
+
72
+ .brand {
73
+ display: inline-flex;
74
+ align-items: center;
75
+ gap: 12px;
76
+ text-decoration: none;
77
+ min-width: 220px;
78
+ }
79
+
80
+ .brand-mark {
81
+ display: grid;
82
+ place-items: center;
83
+ width: 42px;
84
+ height: 42px;
85
+ border-radius: 8px;
86
+ background: var(--ink);
87
+ color: white;
88
+ font-size: 13px;
89
+ font-weight: 800;
90
+ }
91
+
92
+ .brand strong,
93
+ .brand small {
94
+ display: block;
95
+ }
96
+
97
+ .brand small {
98
+ margin-top: 2px;
99
+ color: var(--muted);
100
+ font-size: 12px;
101
+ }
102
+
103
+ nav {
104
+ display: flex;
105
+ align-items: center;
106
+ gap: 6px;
107
+ flex-wrap: wrap;
108
+ justify-content: flex-end;
109
+ }
110
+
111
+ nav a {
112
+ padding: 9px 12px;
113
+ border-radius: 8px;
114
+ color: var(--muted);
115
+ font-size: 14px;
116
+ font-weight: 700;
117
+ text-decoration: none;
118
+ }
119
+
120
+ nav a:hover,
121
+ nav a:focus-visible {
122
+ background: var(--surface);
123
+ color: var(--ink);
124
+ outline: none;
125
+ }
126
+
127
+ main {
128
+ width: min(1180px, calc(100% - 32px));
129
+ margin: 0 auto;
130
+ }
131
+
132
+ .hero {
133
+ min-height: calc(100vh - 70px);
134
+ display: grid;
135
+ grid-template-columns: minmax(0, 1.15fr) minmax(320px, 0.85fr);
136
+ gap: clamp(24px, 5vw, 70px);
137
+ align-items: center;
138
+ padding: 48px 0 36px;
139
+ }
140
+
141
+ .hero-copy {
142
+ max-width: 760px;
143
+ min-width: 0;
144
+ }
145
+
146
+ .eyebrow {
147
+ margin: 0 0 12px;
148
+ color: var(--teal-dark);
149
+ font-size: 12px;
150
+ font-weight: 900;
151
+ letter-spacing: 0.08em;
152
+ text-transform: uppercase;
153
+ }
154
+
155
+ h1,
156
+ h2,
157
+ h3,
158
+ p {
159
+ margin-top: 0;
160
+ }
161
+
162
+ h1 {
163
+ margin-bottom: 22px;
164
+ max-width: 920px;
165
+ font-size: clamp(44px, 7vw, 86px);
166
+ line-height: 0.96;
167
+ letter-spacing: 0;
168
+ overflow-wrap: break-word;
169
+ hyphens: auto;
170
+ }
171
+
172
+ h2,
173
+ h3,
174
+ p,
175
+ li,
176
+ a,
177
+ button {
178
+ overflow-wrap: break-word;
179
+ }
180
+
181
+ h2 {
182
+ margin-bottom: 12px;
183
+ font-size: clamp(28px, 4vw, 44px);
184
+ line-height: 1.05;
185
+ letter-spacing: 0;
186
+ }
187
+
188
+ h3 {
189
+ margin-bottom: 8px;
190
+ font-size: 19px;
191
+ }
192
+
193
+ .hero-copy > p:not(.eyebrow),
194
+ .section-head p {
195
+ max-width: 760px;
196
+ color: var(--muted);
197
+ font-size: 18px;
198
+ line-height: 1.65;
199
+ }
200
+
201
+ .hero-actions {
202
+ display: flex;
203
+ flex-wrap: wrap;
204
+ gap: 12px;
205
+ margin-top: 30px;
206
+ }
207
+
208
+ .button {
209
+ appearance: none;
210
+ border: 1px solid transparent;
211
+ border-radius: 8px;
212
+ padding: 12px 16px;
213
+ font: inherit;
214
+ font-size: 14px;
215
+ font-weight: 850;
216
+ cursor: pointer;
217
+ text-decoration: none;
218
+ transition:
219
+ transform 160ms ease,
220
+ box-shadow 160ms ease,
221
+ background 160ms ease;
222
+ }
223
+
224
+ .button:hover {
225
+ transform: translateY(-1px);
226
+ }
227
+
228
+ .button.primary {
229
+ background: var(--ink);
230
+ color: #fff;
231
+ box-shadow: 0 10px 26px rgba(22, 32, 42, 0.18);
232
+ }
233
+
234
+ .button.ghost {
235
+ border-color: var(--line);
236
+ background: rgba(255, 255, 255, 0.72);
237
+ color: var(--ink);
238
+ }
239
+
240
+ .button.small {
241
+ padding: 8px 10px;
242
+ font-size: 12px;
243
+ }
244
+
245
+ .signal-panel {
246
+ position: relative;
247
+ min-width: 0;
248
+ min-height: 520px;
249
+ overflow: hidden;
250
+ border: 1px solid var(--line);
251
+ border-radius: 8px;
252
+ background:
253
+ linear-gradient(135deg, rgba(255, 255, 255, 0.94), rgba(255, 255, 255, 0.72)),
254
+ repeating-linear-gradient(0deg, rgba(22, 32, 42, 0.04), rgba(22, 32, 42, 0.04) 1px, transparent 1px, transparent 28px);
255
+ box-shadow: var(--shadow);
256
+ }
257
+
258
+ .pulse-grid {
259
+ position: absolute;
260
+ inset: 38px;
261
+ display: grid;
262
+ grid-template-columns: repeat(4, 1fr);
263
+ gap: 14px;
264
+ }
265
+
266
+ .pulse-grid span {
267
+ min-height: 78px;
268
+ border-radius: 8px;
269
+ background: linear-gradient(160deg, rgba(15, 159, 143, 0.18), rgba(49, 111, 208, 0.12));
270
+ border: 1px solid rgba(15, 159, 143, 0.22);
271
+ }
272
+
273
+ .pulse-grid span:nth-child(3n) {
274
+ background: linear-gradient(160deg, rgba(223, 90, 69, 0.16), rgba(189, 141, 36, 0.12));
275
+ border-color: rgba(223, 90, 69, 0.22);
276
+ }
277
+
278
+ .pulse-grid span:nth-child(4n) {
279
+ background: linear-gradient(160deg, rgba(49, 111, 208, 0.17), rgba(15, 159, 143, 0.12));
280
+ border-color: rgba(49, 111, 208, 0.22);
281
+ }
282
+
283
+ .signal-stats {
284
+ position: absolute;
285
+ right: 24px;
286
+ bottom: 24px;
287
+ left: 24px;
288
+ display: grid;
289
+ grid-template-columns: repeat(3, 1fr);
290
+ gap: 12px;
291
+ }
292
+
293
+ .signal-stats div {
294
+ min-height: 118px;
295
+ padding: 18px;
296
+ border: 1px solid rgba(223, 229, 236, 0.88);
297
+ border-radius: 8px;
298
+ background: rgba(255, 255, 255, 0.86);
299
+ }
300
+
301
+ .signal-stats strong {
302
+ display: block;
303
+ font-size: 42px;
304
+ line-height: 1;
305
+ }
306
+
307
+ .signal-stats span {
308
+ display: block;
309
+ margin-top: 8px;
310
+ color: var(--muted);
311
+ font-size: 13px;
312
+ font-weight: 700;
313
+ }
314
+
315
+ .notice {
316
+ display: flex;
317
+ gap: 16px;
318
+ align-items: flex-start;
319
+ margin: 0 0 72px;
320
+ padding: 18px 20px;
321
+ border: 1px solid rgba(189, 141, 36, 0.34);
322
+ border-radius: 8px;
323
+ background: var(--gold-soft);
324
+ color: #4b3b0b;
325
+ line-height: 1.55;
326
+ }
327
+
328
+ .notice strong {
329
+ white-space: nowrap;
330
+ }
331
+
332
+ .notice span,
333
+ .guardrail span {
334
+ min-width: 0;
335
+ }
336
+
337
+ .section {
338
+ padding: 68px 0;
339
+ }
340
+
341
+ .section-head {
342
+ margin-bottom: 26px;
343
+ }
344
+
345
+ .timeline {
346
+ display: grid;
347
+ grid-template-columns: repeat(4, 1fr);
348
+ gap: 14px;
349
+ }
350
+
351
+ .wave-grid {
352
+ display: grid;
353
+ grid-template-columns: repeat(4, 1fr);
354
+ gap: 14px;
355
+ }
356
+
357
+ .wave-card {
358
+ min-height: 250px;
359
+ padding: 20px;
360
+ border: 1px solid var(--line);
361
+ border-radius: 8px;
362
+ background: rgba(255, 255, 255, 0.92);
363
+ box-shadow: 0 12px 34px rgba(25, 39, 52, 0.08);
364
+ }
365
+
366
+ .wave-card span {
367
+ display: grid;
368
+ place-items: center;
369
+ width: 38px;
370
+ height: 38px;
371
+ margin-bottom: 18px;
372
+ border-radius: 8px;
373
+ background: var(--ink);
374
+ color: #fff;
375
+ font-weight: 900;
376
+ }
377
+
378
+ .wave-card:nth-child(2) span {
379
+ background: var(--teal-dark);
380
+ }
381
+
382
+ .wave-card:nth-child(3) span {
383
+ background: var(--blue);
384
+ }
385
+
386
+ .wave-card:nth-child(4) span {
387
+ background: var(--coral);
388
+ }
389
+
390
+ .wave-card p {
391
+ color: var(--muted);
392
+ line-height: 1.55;
393
+ }
394
+
395
+ .wave-card strong {
396
+ display: block;
397
+ line-height: 1.45;
398
+ }
399
+
400
+ .guardrail {
401
+ display: flex;
402
+ align-items: flex-start;
403
+ gap: 14px;
404
+ margin-top: 16px;
405
+ padding: 18px 20px;
406
+ border: 1px solid rgba(223, 90, 69, 0.28);
407
+ border-radius: 8px;
408
+ background: var(--coral-soft);
409
+ color: #6d2a1f;
410
+ line-height: 1.55;
411
+ }
412
+
413
+ .case-grid {
414
+ display: grid;
415
+ grid-template-columns: repeat(3, 1fr);
416
+ gap: 14px;
417
+ }
418
+
419
+ .case-card,
420
+ .transfer-panel,
421
+ .implementation-note,
422
+ .terminal-log {
423
+ border: 1px solid var(--line);
424
+ border-radius: 8px;
425
+ background: rgba(255, 255, 255, 0.92);
426
+ box-shadow: 0 12px 34px rgba(25, 39, 52, 0.08);
427
+ }
428
+
429
+ .case-card {
430
+ min-height: 310px;
431
+ padding: 20px;
432
+ }
433
+
434
+ .case-card p,
435
+ .case-card li,
436
+ .transfer-panel li,
437
+ .implementation-note {
438
+ color: var(--muted);
439
+ line-height: 1.55;
440
+ }
441
+
442
+ .case-card ul,
443
+ .transfer-panel ul {
444
+ margin: 14px 0 0;
445
+ padding-left: 18px;
446
+ }
447
+
448
+ .warning-card {
449
+ border-color: rgba(223, 90, 69, 0.26);
450
+ background: linear-gradient(145deg, rgba(253, 230, 223, 0.88), rgba(255, 255, 255, 0.92));
451
+ }
452
+
453
+ .transfer-panel {
454
+ display: grid;
455
+ grid-template-columns: repeat(2, 1fr);
456
+ gap: 18px;
457
+ margin-top: 14px;
458
+ padding: 22px;
459
+ }
460
+
461
+ .implementation-note {
462
+ display: flex;
463
+ gap: 14px;
464
+ margin-top: 14px;
465
+ padding: 18px 20px;
466
+ border-color: rgba(15, 159, 143, 0.28);
467
+ background: linear-gradient(145deg, var(--green-soft), rgba(255, 255, 255, 0.94));
468
+ }
469
+
470
+ .implementation-note strong {
471
+ color: var(--ink);
472
+ white-space: nowrap;
473
+ }
474
+
475
+ code {
476
+ border-radius: 6px;
477
+ background: rgba(22, 32, 42, 0.07);
478
+ color: var(--ink);
479
+ padding: 1px 4px;
480
+ }
481
+
482
+ .terminal-log {
483
+ margin-top: 14px;
484
+ overflow: hidden;
485
+ }
486
+
487
+ .terminal-log summary {
488
+ cursor: pointer;
489
+ padding: 16px 18px;
490
+ font-weight: 850;
491
+ }
492
+
493
+ .terminal-log pre {
494
+ border-radius: 0;
495
+ border-top: 1px solid rgba(255, 255, 255, 0.12);
496
+ }
497
+
498
+ .day-card,
499
+ .panel,
500
+ .prompt-card,
501
+ .source-card,
502
+ .task-card {
503
+ min-width: 0;
504
+ border: 1px solid var(--line);
505
+ border-radius: 8px;
506
+ background: rgba(255, 255, 255, 0.92);
507
+ box-shadow: 0 12px 34px rgba(25, 39, 52, 0.08);
508
+ }
509
+
510
+ .day-card {
511
+ min-height: 260px;
512
+ padding: 20px;
513
+ }
514
+
515
+ .day-kicker {
516
+ display: inline-flex;
517
+ align-items: center;
518
+ gap: 8px;
519
+ margin-bottom: 14px;
520
+ color: var(--muted);
521
+ font-size: 12px;
522
+ font-weight: 900;
523
+ text-transform: uppercase;
524
+ }
525
+
526
+ .dot {
527
+ width: 10px;
528
+ height: 10px;
529
+ border-radius: 999px;
530
+ background: var(--teal);
531
+ }
532
+
533
+ .day-card:nth-child(2n) .dot {
534
+ background: var(--blue);
535
+ }
536
+
537
+ .day-card:nth-child(3n) .dot {
538
+ background: var(--coral);
539
+ }
540
+
541
+ .day-card:nth-child(4n) .dot {
542
+ background: var(--gold);
543
+ }
544
+
545
+ .day-card ul,
546
+ .sources ul {
547
+ margin: 14px 0 0;
548
+ padding-left: 18px;
549
+ color: var(--muted);
550
+ line-height: 1.55;
551
+ }
552
+
553
+ .split {
554
+ display: grid;
555
+ grid-template-columns: repeat(2, 1fr);
556
+ gap: 18px;
557
+ }
558
+
559
+ .panel {
560
+ padding: 22px;
561
+ }
562
+
563
+ .panel-head {
564
+ margin-bottom: 18px;
565
+ }
566
+
567
+ .controls {
568
+ display: grid;
569
+ grid-template-columns: repeat(2, 1fr);
570
+ gap: 14px;
571
+ }
572
+
573
+ label {
574
+ display: grid;
575
+ gap: 8px;
576
+ color: var(--muted);
577
+ font-size: 13px;
578
+ font-weight: 800;
579
+ }
580
+
581
+ input,
582
+ select,
583
+ textarea {
584
+ width: 100%;
585
+ min-height: 44px;
586
+ border: 1px solid var(--line);
587
+ border-radius: 8px;
588
+ background: #fff;
589
+ color: var(--ink);
590
+ font: inherit;
591
+ font-size: 14px;
592
+ padding: 10px 12px;
593
+ }
594
+
595
+ input:focus,
596
+ select:focus,
597
+ textarea:focus {
598
+ border-color: var(--teal);
599
+ outline: 3px solid rgba(15, 159, 143, 0.14);
600
+ }
601
+
602
+ .check {
603
+ grid-template-columns: auto 1fr;
604
+ align-items: center;
605
+ grid-column: 1 / -1;
606
+ }
607
+
608
+ .check input {
609
+ width: 18px;
610
+ min-height: 18px;
611
+ }
612
+
613
+ .metrics {
614
+ display: grid;
615
+ grid-template-columns: repeat(3, 1fr);
616
+ gap: 10px;
617
+ margin-top: 18px;
618
+ }
619
+
620
+ .metrics div,
621
+ .estimate {
622
+ padding: 16px;
623
+ border-radius: 8px;
624
+ background: linear-gradient(145deg, var(--green-soft), #fff);
625
+ border: 1px solid rgba(15, 159, 143, 0.22);
626
+ }
627
+
628
+ .metrics span,
629
+ .estimate span,
630
+ .estimate small {
631
+ display: block;
632
+ color: var(--muted);
633
+ font-size: 12px;
634
+ font-weight: 850;
635
+ }
636
+
637
+ .metrics strong,
638
+ .estimate strong {
639
+ display: block;
640
+ margin-top: 8px;
641
+ font-size: 32px;
642
+ line-height: 1;
643
+ }
644
+
645
+ .estimate {
646
+ margin-top: 18px;
647
+ background: linear-gradient(145deg, var(--blue-soft), #fff);
648
+ border-color: rgba(49, 111, 208, 0.22);
649
+ }
650
+
651
+ .estimate small {
652
+ margin-top: 8px;
653
+ }
654
+
655
+ .task-form {
656
+ display: grid;
657
+ grid-template-columns: minmax(240px, 1fr) 150px 170px auto;
658
+ gap: 10px;
659
+ margin-bottom: 16px;
660
+ }
661
+
662
+ .kanban {
663
+ display: grid;
664
+ grid-template-columns: repeat(4, 1fr);
665
+ gap: 14px;
666
+ }
667
+
668
+ .lane {
669
+ min-height: 280px;
670
+ padding: 14px;
671
+ border: 1px dashed rgba(102, 115, 128, 0.38);
672
+ border-radius: 8px;
673
+ background: rgba(255, 255, 255, 0.52);
674
+ }
675
+
676
+ .lane h3 {
677
+ display: flex;
678
+ align-items: center;
679
+ justify-content: space-between;
680
+ margin: 0 0 12px;
681
+ font-size: 15px;
682
+ }
683
+
684
+ .lane-count {
685
+ display: inline-grid;
686
+ place-items: center;
687
+ min-width: 24px;
688
+ height: 24px;
689
+ border-radius: 8px;
690
+ background: var(--ink);
691
+ color: #fff;
692
+ font-size: 12px;
693
+ }
694
+
695
+ .task-card {
696
+ padding: 13px;
697
+ margin-bottom: 10px;
698
+ }
699
+
700
+ .task-card strong {
701
+ display: block;
702
+ margin-bottom: 8px;
703
+ overflow-wrap: anywhere;
704
+ }
705
+
706
+ .task-meta {
707
+ display: flex;
708
+ flex-wrap: wrap;
709
+ gap: 6px;
710
+ margin-bottom: 10px;
711
+ }
712
+
713
+ .tag {
714
+ display: inline-flex;
715
+ align-items: center;
716
+ min-height: 24px;
717
+ padding: 4px 8px;
718
+ border-radius: 8px;
719
+ background: var(--blue-soft);
720
+ color: #21446e;
721
+ font-size: 11px;
722
+ font-weight: 850;
723
+ }
724
+
725
+ .tag.alt {
726
+ background: var(--coral-soft);
727
+ color: #7b2e20;
728
+ }
729
+
730
+ .task-actions {
731
+ display: flex;
732
+ gap: 8px;
733
+ flex-wrap: wrap;
734
+ }
735
+
736
+ .task-actions button {
737
+ border: 1px solid var(--line);
738
+ border-radius: 8px;
739
+ background: #fff;
740
+ color: var(--muted);
741
+ cursor: pointer;
742
+ font: inherit;
743
+ font-size: 12px;
744
+ font-weight: 850;
745
+ padding: 7px 9px;
746
+ }
747
+
748
+ .prompt-grid {
749
+ display: grid;
750
+ grid-template-columns: repeat(2, 1fr);
751
+ gap: 14px;
752
+ }
753
+
754
+ .prompt-card {
755
+ display: grid;
756
+ gap: 14px;
757
+ padding: 18px;
758
+ }
759
+
760
+ pre {
761
+ margin: 0;
762
+ overflow: auto;
763
+ border-radius: 8px;
764
+ background: #111820;
765
+ color: #f4f8fb;
766
+ padding: 16px;
767
+ font-size: 13px;
768
+ line-height: 1.5;
769
+ }
770
+
771
+ code {
772
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
773
+ }
774
+
775
+ pre code {
776
+ background: transparent;
777
+ color: inherit;
778
+ padding: 0;
779
+ }
780
+
781
+ .sources {
782
+ padding-bottom: 96px;
783
+ }
784
+
785
+ .sources ul {
786
+ display: grid;
787
+ grid-template-columns: repeat(2, 1fr);
788
+ gap: 12px;
789
+ list-style: none;
790
+ padding: 0;
791
+ }
792
+
793
+ .sources li {
794
+ min-height: 76px;
795
+ padding: 18px;
796
+ border: 1px solid var(--line);
797
+ border-radius: 8px;
798
+ background: rgba(255, 255, 255, 0.9);
799
+ }
800
+
801
+ .sources a {
802
+ color: var(--blue);
803
+ font-weight: 850;
804
+ }
805
+
806
+ @media (max-width: 980px) {
807
+ .hero,
808
+ .split,
809
+ .timeline,
810
+ .wave-grid,
811
+ .case-grid,
812
+ .transfer-panel,
813
+ .kanban,
814
+ .prompt-grid,
815
+ .sources ul {
816
+ grid-template-columns: 1fr;
817
+ }
818
+
819
+ .hero {
820
+ min-height: auto;
821
+ }
822
+
823
+ .signal-panel {
824
+ min-height: 420px;
825
+ }
826
+
827
+ .task-form {
828
+ grid-template-columns: 1fr 1fr;
829
+ }
830
+
831
+ .task-form input {
832
+ grid-column: 1 / -1;
833
+ }
834
+ }
835
+
836
+ @media (max-width: 680px) {
837
+ .topbar {
838
+ align-items: flex-start;
839
+ flex-direction: column;
840
+ gap: 10px;
841
+ padding: 12px;
842
+ }
843
+
844
+ nav {
845
+ justify-content: flex-start;
846
+ gap: 2px;
847
+ width: 100%;
848
+ }
849
+
850
+ nav a {
851
+ padding: 8px 7px;
852
+ font-size: 13px;
853
+ }
854
+
855
+ main {
856
+ width: calc(100vw - 36px);
857
+ }
858
+
859
+ h1 {
860
+ max-width: min(100%, 330px);
861
+ font-size: 34px;
862
+ line-height: 1.02;
863
+ word-break: normal;
864
+ }
865
+
866
+ .hero-copy > p:not(.eyebrow),
867
+ .section-head p {
868
+ max-width: min(100%, 330px);
869
+ font-size: 17px;
870
+ }
871
+
872
+ .notice,
873
+ .guardrail,
874
+ .implementation-note,
875
+ .hero-actions {
876
+ flex-direction: column;
877
+ }
878
+
879
+ .notice span,
880
+ .guardrail span,
881
+ .implementation-note span {
882
+ max-width: min(100%, 330px);
883
+ }
884
+
885
+ .implementation-note strong {
886
+ white-space: normal;
887
+ }
888
+
889
+ .button {
890
+ width: 100%;
891
+ text-align: center;
892
+ }
893
+
894
+ .signal-stats,
895
+ .controls,
896
+ .metrics,
897
+ .task-form {
898
+ grid-template-columns: 1fr;
899
+ }
900
+
901
+ .pulse-grid {
902
+ inset: 24px;
903
+ grid-template-columns: repeat(3, 1fr);
904
+ }
905
+
906
+ .signal-stats {
907
+ right: 12px;
908
+ left: 12px;
909
+ bottom: 12px;
910
+ }
911
+ }