@zigrivers/scaffold 3.29.0 → 3.31.0
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/content/guides/AUTHORING.md +146 -0
- package/content/guides/cli/index.html +1855 -0
- package/content/guides/cli/index.md +206 -0
- package/content/guides/concepts/index.html +1970 -0
- package/content/guides/concepts/index.md +347 -0
- package/content/guides/dashboard/index.html +1913 -0
- package/content/guides/dashboard/index.md +264 -0
- package/content/guides/index.html +368 -15
- package/content/guides/install/.diagrams/diagram-0.svg +1 -0
- package/content/guides/install/.diagrams/manifest.json +3 -0
- package/content/guides/install/index.html +1653 -0
- package/content/guides/install/index.md +186 -0
- package/content/guides/knowledge/.diagrams/diagram-0.svg +1 -0
- package/content/guides/knowledge/.diagrams/manifest.json +3 -0
- package/content/guides/knowledge/index.html +1765 -0
- package/content/guides/knowledge/index.md +209 -0
- package/content/guides/knowledge-freshness/.diagrams/diagram-0.svg +1 -0
- package/content/guides/knowledge-freshness/.diagrams/manifest.json +3 -0
- package/content/guides/knowledge-freshness/index.html +2795 -0
- package/content/guides/knowledge-freshness/index.md +893 -0
- package/content/guides/mmr/index.html +407 -36
- package/content/guides/mmr/index.md +39 -16
- package/content/guides/multi-agent/.diagrams/diagram-0.svg +1 -0
- package/content/guides/multi-agent/.diagrams/manifest.json +3 -0
- package/content/guides/multi-agent/index.html +1715 -0
- package/content/guides/multi-agent/index.md +243 -0
- package/content/guides/observability/.diagrams/diagram-0.svg +1 -0
- package/content/guides/observability/.diagrams/diagram-1.svg +1 -0
- package/content/guides/observability/.diagrams/diagram-2.svg +1 -0
- package/content/guides/observability/.diagrams/diagram-3.svg +1 -0
- package/content/guides/observability/.diagrams/manifest.json +6 -0
- package/content/guides/observability/index.html +3257 -0
- package/content/guides/observability/index.md +1097 -0
- package/content/guides/pipeline/.diagrams/diagram-0.svg +1 -0
- package/content/guides/pipeline/.diagrams/diagram-1.svg +1 -0
- package/content/guides/pipeline/.diagrams/manifest.json +4 -0
- package/content/guides/pipeline/index.html +1973 -0
- package/content/guides/pipeline/index.md +387 -0
- package/content/guides/review-workflow/.diagrams/diagram-0.svg +1 -0
- package/content/guides/review-workflow/.diagrams/diagram-1.svg +1 -0
- package/content/guides/review-workflow/.diagrams/manifest.json +4 -0
- package/content/guides/review-workflow/index.html +1790 -0
- package/content/guides/review-workflow/index.md +248 -0
- package/dist/guides/build.d.ts +1 -1
- package/dist/guides/build.d.ts.map +1 -1
- package/dist/guides/build.js +21 -9
- package/dist/guides/build.js.map +1 -1
- package/dist/guides/build.test.js +47 -0
- package/dist/guides/build.test.js.map +1 -1
- package/dist/guides/chrome.d.ts.map +1 -1
- package/dist/guides/chrome.js +83 -12
- package/dist/guides/chrome.js.map +1 -1
- package/dist/guides/dashboard-theme.css +8 -0
- package/dist/guides/directives-cite.test.d.ts +2 -0
- package/dist/guides/directives-cite.test.d.ts.map +1 -0
- package/dist/guides/directives-cite.test.js +26 -0
- package/dist/guides/directives-cite.test.js.map +1 -0
- package/dist/guides/directives-tabs.test.js +47 -0
- package/dist/guides/directives-tabs.test.js.map +1 -1
- package/dist/guides/directives.d.ts +1 -0
- package/dist/guides/directives.d.ts.map +1 -1
- package/dist/guides/directives.js +38 -0
- package/dist/guides/directives.js.map +1 -1
- package/dist/guides/guides.css +268 -0
- package/dist/guides/index-page.d.ts.map +1 -1
- package/dist/guides/index-page.js +41 -8
- package/dist/guides/index-page.js.map +1 -1
- package/dist/guides/links.d.ts +14 -0
- package/dist/guides/links.d.ts.map +1 -0
- package/dist/guides/links.js +56 -0
- package/dist/guides/links.js.map +1 -0
- package/dist/guides/links.test.d.ts +2 -0
- package/dist/guides/links.test.d.ts.map +1 -0
- package/dist/guides/links.test.js +72 -0
- package/dist/guides/links.test.js.map +1 -0
- package/dist/guides/render.d.ts +1 -0
- package/dist/guides/render.d.ts.map +1 -1
- package/dist/guides/render.js +1 -1
- package/dist/guides/render.js.map +1 -1
- package/dist/guides/sanitize.d.ts.map +1 -1
- package/dist/guides/sanitize.js +5 -0
- package/dist/guides/sanitize.js.map +1 -1
- package/dist/guides/template.d.ts.map +1 -1
- package/dist/guides/template.js +7 -2
- package/dist/guides/template.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,1970 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" data-chrome-version="1">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>Concepts & Glossary</title>
|
|
7
|
+
<!-- scaffold:chrome v1 -->
|
|
8
|
+
<style>/* Scaffold Dashboard Theme
|
|
9
|
+
* All CSS for the generated pipeline dashboard.
|
|
10
|
+
* Embedded into HTML by scripts/generate-dashboard.sh.
|
|
11
|
+
* Design system reference: docs/design-system.md
|
|
12
|
+
*
|
|
13
|
+
* Aesthetic: "Precision Industrial" — Swiss-typographic control room.
|
|
14
|
+
* Deep navy dark mode with indigo accents, clean cool-white light mode.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/* ─── Design Tokens (Light Mode) ──────────────── */
|
|
18
|
+
:root {
|
|
19
|
+
/* Surface */
|
|
20
|
+
--bg: #f5f6fa;
|
|
21
|
+
--bg-card: #ffffff;
|
|
22
|
+
--bg-hover: #eef0f6;
|
|
23
|
+
--bg-inset: #e8eaf2;
|
|
24
|
+
|
|
25
|
+
/* Text */
|
|
26
|
+
--text: #1a1d2e;
|
|
27
|
+
--text-muted: #6b7294;
|
|
28
|
+
--text-faint: #9ba1c0;
|
|
29
|
+
|
|
30
|
+
/* Borders & Structure */
|
|
31
|
+
--border: #dde0ed;
|
|
32
|
+
--border-light: #eceef5;
|
|
33
|
+
--radius: 10px;
|
|
34
|
+
--radius-sm: 6px;
|
|
35
|
+
|
|
36
|
+
/* Accent */
|
|
37
|
+
--accent: #4f46e5;
|
|
38
|
+
--accent-hover: #4338ca;
|
|
39
|
+
--accent-glow: rgba(79, 70, 229, 0.10);
|
|
40
|
+
|
|
41
|
+
/* Semantic: Status */
|
|
42
|
+
--green: #059669;
|
|
43
|
+
--green-bg: #ecfdf5;
|
|
44
|
+
--green-border: #a7f3d0;
|
|
45
|
+
--blue: #2563eb;
|
|
46
|
+
--blue-bg: #eff6ff;
|
|
47
|
+
--blue-border: #bfdbfe;
|
|
48
|
+
--yellow: #d97706;
|
|
49
|
+
--yellow-bg: #fffbeb;
|
|
50
|
+
--yellow-border:#fde68a;
|
|
51
|
+
--red: #dc2626;
|
|
52
|
+
--red-bg: #fef2f2;
|
|
53
|
+
--red-border: #fecaca;
|
|
54
|
+
--gray: #9ca3af;
|
|
55
|
+
--gray-bg: #f3f4f6;
|
|
56
|
+
--gray-border: #e5e7eb;
|
|
57
|
+
--scrim: rgba(15, 17, 23, 0.45);
|
|
58
|
+
|
|
59
|
+
/* Semantic: Next Banner */
|
|
60
|
+
--next-bg: #eef2ff;
|
|
61
|
+
--next-border: #4f46e5;
|
|
62
|
+
--next-glow: rgba(79, 70, 229, 0.06);
|
|
63
|
+
|
|
64
|
+
/* Semantic: Progress */
|
|
65
|
+
--progress-bg: #e5e7eb;
|
|
66
|
+
--progress-h: 10px;
|
|
67
|
+
|
|
68
|
+
/* Depth */
|
|
69
|
+
--shadow-sm: 0 1px 2px rgba(30, 34, 60, 0.04);
|
|
70
|
+
--shadow: 0 1px 3px rgba(30, 34, 60, 0.07), 0 1px 2px rgba(30, 34, 60, 0.04);
|
|
71
|
+
--shadow-md: 0 4px 12px rgba(30, 34, 60, 0.08), 0 1px 3px rgba(30, 34, 60, 0.05);
|
|
72
|
+
--shadow-lg: 0 8px 24px rgba(30, 34, 60, 0.10), 0 2px 6px rgba(30, 34, 60, 0.04);
|
|
73
|
+
|
|
74
|
+
/* Spacing scale (4px base) */
|
|
75
|
+
--sp-1: 4px;
|
|
76
|
+
--sp-2: 8px;
|
|
77
|
+
--sp-3: 12px;
|
|
78
|
+
--sp-4: 16px;
|
|
79
|
+
--sp-5: 20px;
|
|
80
|
+
--sp-6: 24px;
|
|
81
|
+
--sp-8: 32px;
|
|
82
|
+
--sp-10: 40px;
|
|
83
|
+
|
|
84
|
+
/* Typography */
|
|
85
|
+
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
86
|
+
--font-mono: "SF Mono", "Cascadia Code", "Fira Code", "JetBrains Mono", Menlo, Consolas, monospace;
|
|
87
|
+
--text-xs: 0.75rem;
|
|
88
|
+
--text-sm: 0.8125rem;
|
|
89
|
+
--text-base: 0.9375rem;
|
|
90
|
+
--text-lg: 1.125rem;
|
|
91
|
+
--text-xl: 1.375rem;
|
|
92
|
+
--text-2xl: 1.75rem;
|
|
93
|
+
--lh-tight: 1.25;
|
|
94
|
+
--lh-normal: 1.5;
|
|
95
|
+
--lh-relaxed: 1.625;
|
|
96
|
+
--ls-tight: -0.01em;
|
|
97
|
+
--ls-wide: 0.025em;
|
|
98
|
+
--fw-normal: 400;
|
|
99
|
+
--fw-medium: 500;
|
|
100
|
+
--fw-semi: 600;
|
|
101
|
+
--fw-bold: 700;
|
|
102
|
+
|
|
103
|
+
/* Layout */
|
|
104
|
+
--max-w: 960px;
|
|
105
|
+
--page-pad: 24px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* ─── Design Tokens (Dark Mode) ───────────────── */
|
|
109
|
+
[data-theme="dark"] {
|
|
110
|
+
/* Surface */
|
|
111
|
+
--bg: #0f1117;
|
|
112
|
+
--bg-card: #1a1d2e;
|
|
113
|
+
--bg-hover: #252940;
|
|
114
|
+
--bg-inset: #141724;
|
|
115
|
+
|
|
116
|
+
/* Text */
|
|
117
|
+
--text: #e2e5f0;
|
|
118
|
+
--text-muted: #7c82a8;
|
|
119
|
+
--text-faint: #555c80;
|
|
120
|
+
|
|
121
|
+
/* Borders & Structure */
|
|
122
|
+
--border: #2a2f45;
|
|
123
|
+
--border-light: #21253a;
|
|
124
|
+
|
|
125
|
+
/* Accent */
|
|
126
|
+
--accent: #818cf8;
|
|
127
|
+
--accent-hover: #a5b4fc;
|
|
128
|
+
--accent-glow: rgba(129, 140, 248, 0.12);
|
|
129
|
+
|
|
130
|
+
/* Semantic: Status */
|
|
131
|
+
--green: #34d399;
|
|
132
|
+
--green-bg: rgba(6, 78, 59, 0.25);
|
|
133
|
+
--green-border: rgba(52, 211, 153, 0.25);
|
|
134
|
+
--blue: #60a5fa;
|
|
135
|
+
--blue-bg: rgba(30, 58, 95, 0.30);
|
|
136
|
+
--blue-border: rgba(96, 165, 250, 0.25);
|
|
137
|
+
--yellow: #fbbf24;
|
|
138
|
+
--yellow-bg: rgba(120, 53, 15, 0.25);
|
|
139
|
+
--yellow-border:rgba(251, 191, 36, 0.20);
|
|
140
|
+
--red: #f87171;
|
|
141
|
+
--red-bg: rgba(127, 29, 29, 0.25);
|
|
142
|
+
--red-border: rgba(248, 113, 113, 0.22);
|
|
143
|
+
--gray: #6b7294;
|
|
144
|
+
--gray-bg: #252940;
|
|
145
|
+
--gray-border: #363c58;
|
|
146
|
+
--scrim: rgba(0, 0, 0, 0.6);
|
|
147
|
+
|
|
148
|
+
/* Semantic: Next Banner */
|
|
149
|
+
--next-bg: rgba(30, 27, 75, 0.50);
|
|
150
|
+
--next-border: #818cf8;
|
|
151
|
+
--next-glow: rgba(129, 140, 248, 0.08);
|
|
152
|
+
|
|
153
|
+
/* Semantic: Progress */
|
|
154
|
+
--progress-bg: #1f2337;
|
|
155
|
+
|
|
156
|
+
/* Depth */
|
|
157
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.20);
|
|
158
|
+
--shadow: 0 1px 3px rgba(0, 0, 0, 0.30), 0 1px 2px rgba(0, 0, 0, 0.15);
|
|
159
|
+
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35), 0 1px 3px rgba(0, 0, 0, 0.20);
|
|
160
|
+
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.40), 0 2px 6px rgba(0, 0, 0, 0.20);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* ─── Theme Toggle ───────────────────────────── */
|
|
164
|
+
.theme-toggle {
|
|
165
|
+
background: var(--bg-inset);
|
|
166
|
+
border: 1px solid var(--border);
|
|
167
|
+
border-radius: var(--radius-sm);
|
|
168
|
+
padding: var(--sp-1) var(--sp-2);
|
|
169
|
+
cursor: pointer;
|
|
170
|
+
font-size: var(--text-base);
|
|
171
|
+
line-height: 1;
|
|
172
|
+
color: var(--text-muted);
|
|
173
|
+
transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
|
|
174
|
+
display: flex;
|
|
175
|
+
align-items: center;
|
|
176
|
+
margin-left: auto;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.theme-toggle:hover {
|
|
180
|
+
border-color: var(--accent);
|
|
181
|
+
color: var(--accent);
|
|
182
|
+
background: var(--accent-glow);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* ─── Base ────────────────────────────────────── */
|
|
186
|
+
*, *::before, *::after {
|
|
187
|
+
margin: 0;
|
|
188
|
+
padding: 0;
|
|
189
|
+
box-sizing: border-box;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
body {
|
|
193
|
+
font-family: var(--font-sans);
|
|
194
|
+
font-size: var(--text-base);
|
|
195
|
+
line-height: var(--lh-normal);
|
|
196
|
+
color: var(--text);
|
|
197
|
+
background: var(--bg);
|
|
198
|
+
-webkit-font-smoothing: antialiased;
|
|
199
|
+
-moz-osx-font-smoothing: grayscale;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* ─── Layout ──────────────────────────────────── */
|
|
203
|
+
.wrap {
|
|
204
|
+
max-width: var(--max-w);
|
|
205
|
+
margin: 0 auto;
|
|
206
|
+
padding: var(--sp-8) var(--page-pad);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* ─── Header ──────────────────────────────────── */
|
|
210
|
+
.header {
|
|
211
|
+
display: flex;
|
|
212
|
+
align-items: baseline;
|
|
213
|
+
gap: var(--sp-3);
|
|
214
|
+
margin-bottom: var(--sp-2);
|
|
215
|
+
flex-wrap: wrap;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
h1 {
|
|
219
|
+
font-size: var(--text-2xl);
|
|
220
|
+
font-weight: var(--fw-bold);
|
|
221
|
+
letter-spacing: var(--ls-tight);
|
|
222
|
+
line-height: var(--lh-tight);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
h2 {
|
|
226
|
+
font-size: var(--text-lg);
|
|
227
|
+
font-weight: var(--fw-semi);
|
|
228
|
+
letter-spacing: var(--ls-tight);
|
|
229
|
+
line-height: var(--lh-tight);
|
|
230
|
+
margin-bottom: var(--sp-3);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.header-meta {
|
|
234
|
+
font-size: var(--text-xs);
|
|
235
|
+
color: var(--text-faint);
|
|
236
|
+
margin-bottom: var(--sp-6);
|
|
237
|
+
letter-spacing: var(--ls-wide);
|
|
238
|
+
text-transform: uppercase;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* ─── Badge ───────────────────────────────────── */
|
|
242
|
+
.badge {
|
|
243
|
+
display: inline-block;
|
|
244
|
+
padding: 2px var(--sp-2);
|
|
245
|
+
border-radius: 99px;
|
|
246
|
+
font-size: var(--text-xs);
|
|
247
|
+
font-weight: var(--fw-semi);
|
|
248
|
+
letter-spacing: var(--ls-wide);
|
|
249
|
+
background: var(--accent);
|
|
250
|
+
color: #fff;
|
|
251
|
+
text-transform: uppercase;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.badge-optional {
|
|
255
|
+
background: var(--yellow-bg);
|
|
256
|
+
color: var(--yellow);
|
|
257
|
+
border: 1px solid var(--yellow-border);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/* ─── Progress Bar ────────────────────────────── */
|
|
261
|
+
.progress-bar {
|
|
262
|
+
width: 100%;
|
|
263
|
+
height: var(--progress-h);
|
|
264
|
+
background: var(--progress-bg);
|
|
265
|
+
border-radius: 99px;
|
|
266
|
+
overflow: hidden;
|
|
267
|
+
margin-bottom: var(--sp-6);
|
|
268
|
+
display: flex;
|
|
269
|
+
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.progress-bar .seg-done {
|
|
273
|
+
background: linear-gradient(135deg, var(--green), #10b981);
|
|
274
|
+
box-shadow: 0 0 8px rgba(5, 150, 105, 0.3);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.progress-bar .seg-likely {
|
|
278
|
+
background: linear-gradient(135deg, var(--blue), #3b82f6);
|
|
279
|
+
box-shadow: 0 0 8px rgba(37, 99, 235, 0.25);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.progress-bar .seg-skip {
|
|
283
|
+
background: var(--gray);
|
|
284
|
+
opacity: 0.7;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* ─── Summary Cards ───────────────────────────── */
|
|
288
|
+
.cards {
|
|
289
|
+
display: grid;
|
|
290
|
+
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
|
|
291
|
+
gap: var(--sp-3);
|
|
292
|
+
margin-bottom: var(--sp-6);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.card {
|
|
296
|
+
background: var(--bg-card);
|
|
297
|
+
border: 1px solid var(--border);
|
|
298
|
+
border-radius: var(--radius);
|
|
299
|
+
padding: var(--sp-4) var(--sp-5);
|
|
300
|
+
box-shadow: var(--shadow);
|
|
301
|
+
transition: box-shadow 0.15s ease, transform 0.15s ease;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.card:hover {
|
|
305
|
+
box-shadow: var(--shadow-md);
|
|
306
|
+
transform: translateY(-1px);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.card-num {
|
|
310
|
+
font-size: var(--text-2xl);
|
|
311
|
+
font-weight: var(--fw-bold);
|
|
312
|
+
font-family: var(--font-mono);
|
|
313
|
+
letter-spacing: var(--ls-tight);
|
|
314
|
+
line-height: 1;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.card-lbl {
|
|
318
|
+
font-size: var(--text-xs);
|
|
319
|
+
color: var(--text-muted);
|
|
320
|
+
margin-top: var(--sp-1);
|
|
321
|
+
letter-spacing: var(--ls-wide);
|
|
322
|
+
text-transform: uppercase;
|
|
323
|
+
font-weight: var(--fw-medium);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/* ─── What's Next Banner ──────────────────────── */
|
|
327
|
+
.next-banner {
|
|
328
|
+
background: var(--next-bg);
|
|
329
|
+
border: 1px solid var(--next-border);
|
|
330
|
+
border-left: 4px solid var(--next-border);
|
|
331
|
+
border-radius: var(--radius);
|
|
332
|
+
padding: var(--sp-5) var(--sp-6);
|
|
333
|
+
margin-bottom: var(--sp-6);
|
|
334
|
+
box-shadow: 0 0 0 1px var(--next-glow), var(--shadow);
|
|
335
|
+
position: relative;
|
|
336
|
+
overflow: hidden;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.next-banner::before {
|
|
340
|
+
content: "";
|
|
341
|
+
position: absolute;
|
|
342
|
+
top: 0;
|
|
343
|
+
left: 0;
|
|
344
|
+
width: 4px;
|
|
345
|
+
height: 100%;
|
|
346
|
+
background: var(--next-border);
|
|
347
|
+
animation: pulse-border 2.5s ease-in-out infinite;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
@keyframes pulse-border {
|
|
351
|
+
0%, 100% { opacity: 1; }
|
|
352
|
+
50% { opacity: 0.5; }
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.next-banner h2 {
|
|
356
|
+
color: var(--accent);
|
|
357
|
+
margin-bottom: var(--sp-1);
|
|
358
|
+
font-size: var(--text-base);
|
|
359
|
+
font-weight: var(--fw-semi);
|
|
360
|
+
letter-spacing: var(--ls-wide);
|
|
361
|
+
text-transform: uppercase;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.next-banner p {
|
|
365
|
+
color: var(--text);
|
|
366
|
+
font-size: var(--text-base);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.next-cmd {
|
|
370
|
+
font-family: var(--font-mono);
|
|
371
|
+
background: var(--bg-card);
|
|
372
|
+
padding: var(--sp-1) var(--sp-3);
|
|
373
|
+
border-radius: var(--radius-sm);
|
|
374
|
+
font-size: var(--text-sm);
|
|
375
|
+
display: inline-flex;
|
|
376
|
+
align-items: center;
|
|
377
|
+
gap: var(--sp-2);
|
|
378
|
+
margin-top: var(--sp-3);
|
|
379
|
+
border: 1px solid var(--border);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/* ─── Phase Headers (Collapsible) ─────────────── */
|
|
383
|
+
.phase {
|
|
384
|
+
margin-bottom: var(--sp-6);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.phase-hdr {
|
|
388
|
+
display: flex;
|
|
389
|
+
align-items: center;
|
|
390
|
+
gap: var(--sp-2);
|
|
391
|
+
cursor: pointer;
|
|
392
|
+
padding: var(--sp-2) 0;
|
|
393
|
+
user-select: none;
|
|
394
|
+
border-bottom: 2px solid var(--border);
|
|
395
|
+
margin-bottom: var(--sp-3);
|
|
396
|
+
transition: border-color 0.15s ease;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.phase-hdr:hover {
|
|
400
|
+
border-bottom-color: var(--accent);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.phase-hdr:hover h2 {
|
|
404
|
+
color: var(--accent);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.phase-hdr h2 {
|
|
408
|
+
transition: color 0.15s ease;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.phase-hdr .arr {
|
|
412
|
+
transition: transform 0.2s ease;
|
|
413
|
+
font-size: var(--text-xs);
|
|
414
|
+
color: var(--text-muted);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.phase-hdr.closed .arr {
|
|
418
|
+
transform: rotate(-90deg);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.phase-cnt {
|
|
422
|
+
font-size: var(--text-xs);
|
|
423
|
+
font-family: var(--font-mono);
|
|
424
|
+
color: var(--text-faint);
|
|
425
|
+
margin-left: auto;
|
|
426
|
+
letter-spacing: var(--ls-wide);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/* ─── Prompt List ─────────────────────────────── */
|
|
430
|
+
.plist {
|
|
431
|
+
display: flex;
|
|
432
|
+
flex-direction: column;
|
|
433
|
+
gap: var(--sp-2);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/* ─── Prompt Cards ────────────────────────────── */
|
|
437
|
+
.pcard {
|
|
438
|
+
background: var(--bg-card);
|
|
439
|
+
border: 1px solid var(--border);
|
|
440
|
+
border-radius: var(--radius);
|
|
441
|
+
padding: var(--sp-3) var(--sp-4);
|
|
442
|
+
box-shadow: var(--shadow-sm);
|
|
443
|
+
display: grid;
|
|
444
|
+
grid-template-columns: auto 1fr auto;
|
|
445
|
+
gap: var(--sp-2) var(--sp-3);
|
|
446
|
+
align-items: start;
|
|
447
|
+
transition: box-shadow 0.15s ease, transform 0.15s ease, border-color 0.15s ease;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.pcard:hover {
|
|
451
|
+
box-shadow: var(--shadow);
|
|
452
|
+
transform: translateY(-1px);
|
|
453
|
+
border-color: var(--accent-glow);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/* ─── Status Badges ──────────────────────────── */
|
|
457
|
+
.status-badge {
|
|
458
|
+
display: inline-flex;
|
|
459
|
+
align-items: center;
|
|
460
|
+
gap: var(--sp-1);
|
|
461
|
+
font-size: var(--text-xs);
|
|
462
|
+
font-weight: var(--fw-medium);
|
|
463
|
+
padding: 2px var(--sp-2);
|
|
464
|
+
border-radius: 99px;
|
|
465
|
+
white-space: nowrap;
|
|
466
|
+
flex-shrink: 0;
|
|
467
|
+
letter-spacing: var(--ls-wide);
|
|
468
|
+
line-height: var(--lh-tight);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.st-completed {
|
|
472
|
+
background: var(--green-bg);
|
|
473
|
+
color: var(--green);
|
|
474
|
+
border: 1px solid var(--green-border);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.st-likely-completed {
|
|
478
|
+
background: var(--blue-bg);
|
|
479
|
+
color: var(--blue);
|
|
480
|
+
border: 1px solid var(--blue-border);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.st-skipped {
|
|
484
|
+
background: var(--gray-bg);
|
|
485
|
+
color: var(--gray);
|
|
486
|
+
border: 1px solid var(--gray-border);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.st-pending {
|
|
490
|
+
background: var(--bg-inset);
|
|
491
|
+
color: var(--text-faint);
|
|
492
|
+
border: 1px solid var(--border);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/* ─── Status Legend ──────────────────────────── */
|
|
496
|
+
.status-legend {
|
|
497
|
+
display: flex;
|
|
498
|
+
flex-wrap: wrap;
|
|
499
|
+
gap: var(--sp-2);
|
|
500
|
+
margin-bottom: var(--sp-4);
|
|
501
|
+
padding: var(--sp-2) 0;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.status-legend .status-badge {
|
|
505
|
+
cursor: default;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/* ─── Prompt Card Inner ───────────────────────── */
|
|
509
|
+
.pinfo {
|
|
510
|
+
min-width: 0;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.pname {
|
|
514
|
+
font-weight: var(--fw-semi);
|
|
515
|
+
font-size: var(--text-base);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.pstep {
|
|
519
|
+
font-size: var(--text-xs);
|
|
520
|
+
font-family: var(--font-mono);
|
|
521
|
+
color: var(--text-faint);
|
|
522
|
+
letter-spacing: var(--ls-wide);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.pdesc {
|
|
526
|
+
font-size: var(--text-sm);
|
|
527
|
+
color: var(--text-muted);
|
|
528
|
+
margin-top: 2px;
|
|
529
|
+
line-height: var(--lh-relaxed);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
.pdesc-long {
|
|
533
|
+
font-size: var(--text-xs);
|
|
534
|
+
color: var(--text-faint);
|
|
535
|
+
margin-top: 2px;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.pdeps {
|
|
539
|
+
font-size: var(--text-xs);
|
|
540
|
+
color: var(--yellow);
|
|
541
|
+
margin-top: var(--sp-1);
|
|
542
|
+
font-weight: var(--fw-medium);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/* ─── Copy Command Button ─────────────────────── */
|
|
546
|
+
.pcmd {
|
|
547
|
+
font-family: var(--font-mono);
|
|
548
|
+
font-size: var(--text-xs);
|
|
549
|
+
background: var(--bg-inset);
|
|
550
|
+
padding: 3px var(--sp-2);
|
|
551
|
+
border-radius: var(--radius-sm);
|
|
552
|
+
cursor: pointer;
|
|
553
|
+
border: 1px solid var(--border);
|
|
554
|
+
white-space: nowrap;
|
|
555
|
+
align-self: center;
|
|
556
|
+
color: var(--text-muted);
|
|
557
|
+
transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
|
|
558
|
+
letter-spacing: var(--ls-wide);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
.pcmd:hover {
|
|
562
|
+
border-color: var(--accent);
|
|
563
|
+
color: var(--accent);
|
|
564
|
+
background: var(--accent-glow);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.pcmd.copied {
|
|
568
|
+
border-color: var(--green);
|
|
569
|
+
color: var(--green);
|
|
570
|
+
background: var(--green-bg);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/* ─── Prompt Modal ────────────────────────────── */
|
|
574
|
+
.modal-overlay {
|
|
575
|
+
position: fixed;
|
|
576
|
+
inset: 0;
|
|
577
|
+
background: rgba(0, 0, 0, 0.6);
|
|
578
|
+
display: flex;
|
|
579
|
+
align-items: center;
|
|
580
|
+
justify-content: center;
|
|
581
|
+
z-index: 1000;
|
|
582
|
+
padding: var(--sp-4);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
.modal {
|
|
586
|
+
background: var(--bg-card);
|
|
587
|
+
border: 1px solid var(--border);
|
|
588
|
+
border-radius: var(--radius);
|
|
589
|
+
box-shadow: var(--shadow-lg);
|
|
590
|
+
max-width: 720px;
|
|
591
|
+
width: 100%;
|
|
592
|
+
max-height: 85vh;
|
|
593
|
+
display: flex;
|
|
594
|
+
flex-direction: column;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.modal-header {
|
|
598
|
+
display: flex;
|
|
599
|
+
align-items: center;
|
|
600
|
+
gap: var(--sp-3);
|
|
601
|
+
padding: var(--sp-4) var(--sp-5);
|
|
602
|
+
border-bottom: 1px solid var(--border);
|
|
603
|
+
flex-shrink: 0;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.modal-header h3 {
|
|
607
|
+
font-size: var(--text-lg);
|
|
608
|
+
font-weight: var(--fw-semi);
|
|
609
|
+
flex: 1;
|
|
610
|
+
min-width: 0;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
.modal-close {
|
|
614
|
+
background: var(--bg-inset);
|
|
615
|
+
border: 1px solid var(--border);
|
|
616
|
+
border-radius: var(--radius-sm);
|
|
617
|
+
padding: var(--sp-1) var(--sp-2);
|
|
618
|
+
cursor: pointer;
|
|
619
|
+
font-size: var(--text-base);
|
|
620
|
+
color: var(--text-muted);
|
|
621
|
+
line-height: 1;
|
|
622
|
+
transition: border-color 0.15s ease, color 0.15s ease;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
.modal-close:hover {
|
|
626
|
+
border-color: var(--accent);
|
|
627
|
+
color: var(--accent);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
.modal-body {
|
|
631
|
+
padding: var(--sp-5);
|
|
632
|
+
overflow-y: auto;
|
|
633
|
+
flex: 1;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
.modal-body pre {
|
|
637
|
+
font-family: var(--font-mono);
|
|
638
|
+
font-size: var(--text-sm);
|
|
639
|
+
line-height: var(--lh-relaxed);
|
|
640
|
+
white-space: pre-wrap;
|
|
641
|
+
word-break: break-word;
|
|
642
|
+
color: var(--text);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.modal-body pre .md-heading {
|
|
646
|
+
font-weight: var(--fw-bold);
|
|
647
|
+
color: var(--accent);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
.modal-body pre .md-code {
|
|
651
|
+
background: var(--bg-inset);
|
|
652
|
+
padding: 1px 4px;
|
|
653
|
+
border-radius: 3px;
|
|
654
|
+
font-size: var(--text-xs);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
.modal-footer {
|
|
658
|
+
display: flex;
|
|
659
|
+
gap: var(--sp-2);
|
|
660
|
+
padding: var(--sp-3) var(--sp-5);
|
|
661
|
+
border-top: 1px solid var(--border);
|
|
662
|
+
flex-shrink: 0;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
.modal-copy-btn {
|
|
666
|
+
background: var(--accent);
|
|
667
|
+
color: #fff;
|
|
668
|
+
border: none;
|
|
669
|
+
border-radius: var(--radius-sm);
|
|
670
|
+
padding: var(--sp-2) var(--sp-4);
|
|
671
|
+
font-size: var(--text-sm);
|
|
672
|
+
font-weight: var(--fw-medium);
|
|
673
|
+
cursor: pointer;
|
|
674
|
+
transition: background 0.15s ease;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
.modal-copy-btn:hover {
|
|
678
|
+
background: var(--accent-hover);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
.modal-copy-btn.copied {
|
|
682
|
+
background: var(--green);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/* ─── Beads Task Section ─────────────────────── */
|
|
686
|
+
.beads-section {
|
|
687
|
+
margin-top: var(--sp-8);
|
|
688
|
+
margin-bottom: var(--sp-6);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
.beads-filters {
|
|
692
|
+
display: flex;
|
|
693
|
+
gap: var(--sp-2);
|
|
694
|
+
margin-bottom: var(--sp-3);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
.beads-filter {
|
|
698
|
+
background: var(--bg-inset);
|
|
699
|
+
border: 1px solid var(--border);
|
|
700
|
+
border-radius: 99px;
|
|
701
|
+
padding: var(--sp-1) var(--sp-3);
|
|
702
|
+
font-size: var(--text-xs);
|
|
703
|
+
font-weight: var(--fw-medium);
|
|
704
|
+
color: var(--text-muted);
|
|
705
|
+
cursor: pointer;
|
|
706
|
+
transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
|
|
707
|
+
letter-spacing: var(--ls-wide);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.beads-filter:hover {
|
|
711
|
+
border-color: var(--accent);
|
|
712
|
+
color: var(--accent);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
.beads-filter.active {
|
|
716
|
+
background: var(--accent);
|
|
717
|
+
color: #fff;
|
|
718
|
+
border-color: var(--accent);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/* ─── Beads Status Badges ────────────────────── */
|
|
722
|
+
.st-bead-open {
|
|
723
|
+
background: var(--accent-glow);
|
|
724
|
+
color: var(--accent);
|
|
725
|
+
border: 1px solid var(--accent);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
.st-bead-progress {
|
|
729
|
+
background: var(--blue-bg);
|
|
730
|
+
color: var(--blue);
|
|
731
|
+
border: 1px solid var(--blue-border);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
.st-bead-blocked {
|
|
735
|
+
background: var(--yellow-bg);
|
|
736
|
+
color: var(--yellow);
|
|
737
|
+
border: 1px solid var(--yellow-border);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.st-bead-deferred {
|
|
741
|
+
background: var(--gray-bg);
|
|
742
|
+
color: var(--gray);
|
|
743
|
+
border: 1px solid var(--gray-border);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
.st-bead-closed {
|
|
747
|
+
background: var(--green-bg);
|
|
748
|
+
color: var(--green);
|
|
749
|
+
border: 1px solid var(--green-border);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/* ─── Beads Filter Separator ─────────────────── */
|
|
753
|
+
.beads-filter-sep {
|
|
754
|
+
width: 1px;
|
|
755
|
+
background: var(--border);
|
|
756
|
+
align-self: stretch;
|
|
757
|
+
margin: 0 var(--sp-1);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/* ─── Beads Priority Filter ──────────────────── */
|
|
761
|
+
.beads-prio-filter {
|
|
762
|
+
background: var(--bg-inset);
|
|
763
|
+
border: 1px solid var(--border);
|
|
764
|
+
border-radius: 99px;
|
|
765
|
+
padding: var(--sp-1) var(--sp-3);
|
|
766
|
+
font-size: var(--text-xs);
|
|
767
|
+
font-weight: var(--fw-medium);
|
|
768
|
+
color: var(--text-muted);
|
|
769
|
+
cursor: pointer;
|
|
770
|
+
transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
|
|
771
|
+
letter-spacing: var(--ls-wide);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.beads-prio-filter:hover {
|
|
775
|
+
border-color: var(--accent);
|
|
776
|
+
color: var(--accent);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
.beads-prio-filter.active {
|
|
780
|
+
background: var(--accent);
|
|
781
|
+
color: #fff;
|
|
782
|
+
border-color: var(--accent);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/* ─── Beads Task Detail Modal ────────────────── */
|
|
786
|
+
.bead-meta-grid {
|
|
787
|
+
display: grid;
|
|
788
|
+
grid-template-columns: 1fr 1fr;
|
|
789
|
+
gap: var(--sp-3);
|
|
790
|
+
padding: var(--sp-4) 0;
|
|
791
|
+
border-bottom: 1px solid var(--border-light);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
.bead-meta-item {
|
|
795
|
+
display: flex;
|
|
796
|
+
flex-direction: column;
|
|
797
|
+
gap: 2px;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
.bead-meta-label {
|
|
801
|
+
font-size: var(--text-xs);
|
|
802
|
+
color: var(--text-faint);
|
|
803
|
+
text-transform: uppercase;
|
|
804
|
+
letter-spacing: var(--ls-wide);
|
|
805
|
+
font-weight: var(--fw-medium);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
.bead-meta-value {
|
|
809
|
+
font-size: var(--text-sm);
|
|
810
|
+
font-weight: var(--fw-medium);
|
|
811
|
+
color: var(--text);
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
.bead-description {
|
|
815
|
+
padding: var(--sp-4) 0;
|
|
816
|
+
border-bottom: 1px solid var(--border-light);
|
|
817
|
+
white-space: pre-wrap;
|
|
818
|
+
font-size: var(--text-sm);
|
|
819
|
+
line-height: var(--lh-relaxed);
|
|
820
|
+
color: var(--text-muted);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
.bead-deps {
|
|
824
|
+
padding: var(--sp-4) 0;
|
|
825
|
+
border-bottom: 1px solid var(--border-light);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
.bead-dep-group {
|
|
829
|
+
display: flex;
|
|
830
|
+
flex-wrap: wrap;
|
|
831
|
+
align-items: center;
|
|
832
|
+
gap: var(--sp-2);
|
|
833
|
+
margin-bottom: var(--sp-2);
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
.bead-dep-group:last-child {
|
|
837
|
+
margin-bottom: 0;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
.bead-dep-label {
|
|
841
|
+
font-size: var(--text-xs);
|
|
842
|
+
color: var(--text-faint);
|
|
843
|
+
text-transform: uppercase;
|
|
844
|
+
letter-spacing: var(--ls-wide);
|
|
845
|
+
font-weight: var(--fw-medium);
|
|
846
|
+
min-width: 80px;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
.bead-dep-link {
|
|
850
|
+
display: inline-block;
|
|
851
|
+
font-family: var(--font-mono);
|
|
852
|
+
font-size: var(--text-xs);
|
|
853
|
+
padding: 2px var(--sp-2);
|
|
854
|
+
border-radius: 99px;
|
|
855
|
+
background: var(--accent-glow);
|
|
856
|
+
color: var(--accent);
|
|
857
|
+
border: 1px solid var(--accent);
|
|
858
|
+
cursor: pointer;
|
|
859
|
+
transition: background 0.15s ease, color 0.15s ease;
|
|
860
|
+
text-decoration: none;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
.bead-dep-link:hover {
|
|
864
|
+
background: var(--accent);
|
|
865
|
+
color: #fff;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
.bead-timestamps {
|
|
869
|
+
display: flex;
|
|
870
|
+
flex-wrap: wrap;
|
|
871
|
+
gap: var(--sp-4);
|
|
872
|
+
padding: var(--sp-4) 0;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
.bead-ts-item {
|
|
876
|
+
display: flex;
|
|
877
|
+
flex-direction: column;
|
|
878
|
+
gap: 2px;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
.bead-ts-label {
|
|
882
|
+
font-size: var(--text-xs);
|
|
883
|
+
color: var(--text-faint);
|
|
884
|
+
text-transform: uppercase;
|
|
885
|
+
letter-spacing: var(--ls-wide);
|
|
886
|
+
font-weight: var(--fw-medium);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
.bead-ts-value {
|
|
890
|
+
font-size: var(--text-sm);
|
|
891
|
+
color: var(--text-muted);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
.bead-ts-value[title] {
|
|
895
|
+
border-bottom: 1px dotted var(--text-faint);
|
|
896
|
+
cursor: help;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/* ─── Standalone Commands Section ─────────────── */
|
|
900
|
+
.ongoing {
|
|
901
|
+
margin-top: var(--sp-10);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
.ongoing h2 {
|
|
905
|
+
letter-spacing: var(--ls-wide);
|
|
906
|
+
text-transform: uppercase;
|
|
907
|
+
font-size: var(--text-sm);
|
|
908
|
+
color: var(--text-muted);
|
|
909
|
+
margin-bottom: var(--sp-4);
|
|
910
|
+
border-bottom: 2px solid var(--border);
|
|
911
|
+
padding-bottom: var(--sp-2);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/* ─── Footer ──────────────────────────────────── */
|
|
915
|
+
.footer {
|
|
916
|
+
text-align: center;
|
|
917
|
+
font-size: var(--text-xs);
|
|
918
|
+
color: var(--text-faint);
|
|
919
|
+
margin-top: var(--sp-10);
|
|
920
|
+
padding-top: var(--sp-4);
|
|
921
|
+
border-top: 1px solid var(--border-light);
|
|
922
|
+
letter-spacing: var(--ls-wide);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
/* ─── Utilities ───────────────────────────────── */
|
|
926
|
+
.hidden {
|
|
927
|
+
display: none;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/* Build-observability severity + verdict tokens (Plan 4) */
|
|
931
|
+
:root {
|
|
932
|
+
--sev-p0: #dc2626; /* red 600 */
|
|
933
|
+
--sev-p1: #ea580c; /* orange 600 */
|
|
934
|
+
--sev-p2: #ca8a04; /* yellow 600 */
|
|
935
|
+
--sev-p3: #2563eb; /* blue 600 */
|
|
936
|
+
--sev-pass: #16a34a; /* green 600 */
|
|
937
|
+
}
|
|
938
|
+
[data-theme="dark"] {
|
|
939
|
+
--sev-p0: #f87171;
|
|
940
|
+
--sev-p1: #fb923c;
|
|
941
|
+
--sev-p2: #facc15;
|
|
942
|
+
--sev-p3: #60a5fa;
|
|
943
|
+
--sev-pass: #4ade80;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
/* Build-observability panel layout */
|
|
947
|
+
.panel {
|
|
948
|
+
background: var(--bg-card);
|
|
949
|
+
border: 1px solid var(--border);
|
|
950
|
+
border-radius: var(--radius);
|
|
951
|
+
padding: var(--sp-4) var(--sp-6);
|
|
952
|
+
margin-bottom: var(--sp-6);
|
|
953
|
+
}
|
|
954
|
+
.panel > header {
|
|
955
|
+
display: flex;
|
|
956
|
+
align-items: center;
|
|
957
|
+
gap: var(--sp-3);
|
|
958
|
+
margin-bottom: var(--sp-4);
|
|
959
|
+
flex-wrap: wrap;
|
|
960
|
+
}
|
|
961
|
+
.panel > header h2 {
|
|
962
|
+
margin: 0;
|
|
963
|
+
font-size: var(--text-base);
|
|
964
|
+
font-weight: var(--fw-semi);
|
|
965
|
+
}
|
|
966
|
+
.panel .meta {
|
|
967
|
+
color: var(--text-muted);
|
|
968
|
+
font-size: var(--text-sm);
|
|
969
|
+
}
|
|
970
|
+
.grid { display: grid; gap: var(--sp-4); }
|
|
971
|
+
.grid-2 { grid-template-columns: repeat(2, 1fr); }
|
|
972
|
+
@media (max-width: 640px) { .grid-2 { grid-template-columns: 1fr; } }
|
|
973
|
+
|
|
974
|
+
/* Finding filters */
|
|
975
|
+
.finding-filters {
|
|
976
|
+
display: flex;
|
|
977
|
+
gap: var(--sp-2);
|
|
978
|
+
flex-wrap: wrap;
|
|
979
|
+
margin-bottom: var(--sp-4);
|
|
980
|
+
}
|
|
981
|
+
.finding-filters button {
|
|
982
|
+
padding: var(--sp-1) var(--sp-3);
|
|
983
|
+
border: 1px solid var(--border);
|
|
984
|
+
border-radius: var(--radius-sm);
|
|
985
|
+
background: var(--bg-inset);
|
|
986
|
+
color: var(--text);
|
|
987
|
+
font-size: var(--text-sm);
|
|
988
|
+
cursor: pointer;
|
|
989
|
+
}
|
|
990
|
+
.finding-filters button:hover,
|
|
991
|
+
.finding-filters button.active {
|
|
992
|
+
background: var(--accent);
|
|
993
|
+
border-color: var(--accent);
|
|
994
|
+
color: #fff;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
/* Findings list */
|
|
998
|
+
.findings {
|
|
999
|
+
list-style: none;
|
|
1000
|
+
padding: 0;
|
|
1001
|
+
margin: 0;
|
|
1002
|
+
display: flex;
|
|
1003
|
+
flex-direction: column;
|
|
1004
|
+
gap: var(--sp-3);
|
|
1005
|
+
}
|
|
1006
|
+
.finding {
|
|
1007
|
+
background: var(--bg-inset);
|
|
1008
|
+
border: 1px solid var(--border-light);
|
|
1009
|
+
border-radius: var(--radius-sm);
|
|
1010
|
+
padding: var(--sp-3) var(--sp-4);
|
|
1011
|
+
}
|
|
1012
|
+
.finding header {
|
|
1013
|
+
display: flex;
|
|
1014
|
+
align-items: center;
|
|
1015
|
+
gap: var(--sp-2);
|
|
1016
|
+
flex-wrap: wrap;
|
|
1017
|
+
margin-bottom: var(--sp-2);
|
|
1018
|
+
}
|
|
1019
|
+
.finding-id {
|
|
1020
|
+
font-family: var(--font-mono, monospace);
|
|
1021
|
+
font-size: var(--text-xs);
|
|
1022
|
+
color: var(--text-muted);
|
|
1023
|
+
background: var(--bg-card);
|
|
1024
|
+
border: 1px solid var(--border);
|
|
1025
|
+
border-radius: 4px;
|
|
1026
|
+
padding: 1px var(--sp-1);
|
|
1027
|
+
}
|
|
1028
|
+
.finding .lens {
|
|
1029
|
+
font-size: var(--text-xs);
|
|
1030
|
+
color: var(--text-muted);
|
|
1031
|
+
}
|
|
1032
|
+
.finding .title {
|
|
1033
|
+
font-size: var(--text-sm);
|
|
1034
|
+
font-weight: var(--fw-semi);
|
|
1035
|
+
flex: 1;
|
|
1036
|
+
}
|
|
1037
|
+
.finding p { margin: 0; font-size: var(--text-sm); color: var(--text-muted); }
|
|
1038
|
+
.empty { color: var(--text-muted); font-size: var(--text-sm); text-align: center; padding: var(--sp-4); }
|
|
1039
|
+
|
|
1040
|
+
/* ── Mermaid diagrams ─────────────────────────────────────────────────────────
|
|
1041
|
+
The build renders mermaid to inline SVG via mmdc, then sanitizeSvg() +
|
|
1042
|
+
rehype-sanitize strip the SVG's own <script>, <foreignObject>, AND <style>
|
|
1043
|
+
for security. Stripping <style> means the diagram arrives unstyled (nodes
|
|
1044
|
+
default to a black fill). These theme-token rules restyle the SVG so nodes,
|
|
1045
|
+
edges, arrowheads, and labels render correctly — and follow light/dark mode.
|
|
1046
|
+
Authors must render with htmlLabels:false (the generator forces this) so node
|
|
1047
|
+
labels are native <text>/<tspan> rather than stripped <foreignObject> HTML. */
|
|
1048
|
+
figure.mermaid { margin: var(--sp-5) 0; text-align: center; }
|
|
1049
|
+
figure.mermaid svg { max-width: 100%; height: auto; }
|
|
1050
|
+
/* Node shapes */
|
|
1051
|
+
figure.mermaid svg .node rect,
|
|
1052
|
+
figure.mermaid svg .node circle,
|
|
1053
|
+
figure.mermaid svg .node ellipse,
|
|
1054
|
+
figure.mermaid svg .node polygon,
|
|
1055
|
+
figure.mermaid svg .node path {
|
|
1056
|
+
fill: var(--bg-inset);
|
|
1057
|
+
stroke: var(--border);
|
|
1058
|
+
stroke-width: 1px;
|
|
1059
|
+
}
|
|
1060
|
+
/* Background helper rects mermaid emits behind labels */
|
|
1061
|
+
figure.mermaid svg .node .label-container { fill: var(--bg-inset); stroke: var(--border); }
|
|
1062
|
+
figure.mermaid svg rect.background { fill: none; stroke: none; }
|
|
1063
|
+
/* Labels (rendered as <text>/<tspan> when htmlLabels:false) */
|
|
1064
|
+
figure.mermaid svg .nodeLabel,
|
|
1065
|
+
figure.mermaid svg .node text,
|
|
1066
|
+
figure.mermaid svg text.nodeLabel,
|
|
1067
|
+
figure.mermaid svg .label text,
|
|
1068
|
+
figure.mermaid svg span.nodeLabel {
|
|
1069
|
+
fill: var(--text);
|
|
1070
|
+
color: var(--text);
|
|
1071
|
+
font-family: var(--font-sans);
|
|
1072
|
+
}
|
|
1073
|
+
/* Edges: thin strokes, not filled blobs */
|
|
1074
|
+
figure.mermaid svg .edgePath path,
|
|
1075
|
+
figure.mermaid svg path.flowchart-link,
|
|
1076
|
+
figure.mermaid svg .flowchart-link {
|
|
1077
|
+
fill: none;
|
|
1078
|
+
stroke: var(--text-faint);
|
|
1079
|
+
stroke-width: 1.5px;
|
|
1080
|
+
}
|
|
1081
|
+
/* Arrowheads */
|
|
1082
|
+
figure.mermaid svg marker path,
|
|
1083
|
+
figure.mermaid svg .marker {
|
|
1084
|
+
fill: var(--text-faint);
|
|
1085
|
+
stroke: var(--text-faint);
|
|
1086
|
+
}
|
|
1087
|
+
figure.mermaid svg .edgeLabel,
|
|
1088
|
+
figure.mermaid svg .edgeLabel text { fill: var(--text-muted); color: var(--text-muted); }
|
|
1089
|
+
|
|
1090
|
+
/* ============================================================================
|
|
1091
|
+
* guides.css — component + layout styles for `scaffold guides` reference pages.
|
|
1092
|
+
*
|
|
1093
|
+
* Pairs with lib/dashboard-theme.css (the token source) and src/guides/chrome.ts
|
|
1094
|
+
* (the behavior). Styles the guide CHROME (.topbar, .layout, .rail, nav.toc,
|
|
1095
|
+
* .content) and the markdown DIRECTIVES (callouts, sev chips, filter-tables,
|
|
1096
|
+
* charts, tabs, citations) plus base prose typography.
|
|
1097
|
+
*
|
|
1098
|
+
* DESIGN SYSTEM: all COLORS come from dashboard-theme.css tokens, and spacing
|
|
1099
|
+
* uses the --sp-* scale wherever it maps. The few structural layout constants
|
|
1100
|
+
* (topbar height, rail/drawer width, chart label column, card min) are declared
|
|
1101
|
+
* as local custom properties below; a handful of sub-scale UI values (chip/bar
|
|
1102
|
+
* sizing, em-based inline-code padding) and the responsive breakpoint are
|
|
1103
|
+
* literal because no token expresses them. Both themes are covered because every
|
|
1104
|
+
* color is a token.
|
|
1105
|
+
* ==========================================================================*/
|
|
1106
|
+
|
|
1107
|
+
:root {
|
|
1108
|
+
--topbar-h: 52px; /* sticky topbar height; rail sticky offset keys off it */
|
|
1109
|
+
--rail-w: 260px; /* desktop TOC sidebar column */
|
|
1110
|
+
--drawer-w: 280px; /* mobile off-canvas TOC drawer */
|
|
1111
|
+
--card-min: 260px; /* index card min track width */
|
|
1112
|
+
--chart-label-w: 90px; /* chart row label column min */
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
/* ── Base / reset on top of the token base in dashboard-theme.css ─────────── */
|
|
1116
|
+
.content a { color: var(--accent); text-decoration: none; }
|
|
1117
|
+
.content a:hover { text-decoration: underline; }
|
|
1118
|
+
.content strong { font-weight: var(--fw-semi); }
|
|
1119
|
+
.content hr { border: 0; border-top: 1px solid var(--border-light); margin: var(--sp-6) 0; }
|
|
1120
|
+
|
|
1121
|
+
/* Consistent keyboard focus for every interactive control (a11y). */
|
|
1122
|
+
.topbar button:focus-visible,
|
|
1123
|
+
.copy-btn:focus-visible,
|
|
1124
|
+
.tab-btn:focus-visible,
|
|
1125
|
+
.filter-input:focus-visible,
|
|
1126
|
+
nav.toc a:focus-visible,
|
|
1127
|
+
.guide-card:focus-visible,
|
|
1128
|
+
.content a:focus-visible {
|
|
1129
|
+
outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-sm);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
/* ── Topbar ────────────────────────────────────────────────────────────────*/
|
|
1133
|
+
.topbar {
|
|
1134
|
+
position: sticky; top: 0; z-index: 60; height: var(--topbar-h);
|
|
1135
|
+
display: flex; align-items: center; gap: var(--sp-3);
|
|
1136
|
+
padding: 0 var(--page-pad);
|
|
1137
|
+
background: var(--bg-card); border-bottom: 1px solid var(--border);
|
|
1138
|
+
}
|
|
1139
|
+
.topbar h1 {
|
|
1140
|
+
flex: 1; min-width: 0; margin: 0;
|
|
1141
|
+
font-size: var(--text-lg); font-weight: var(--fw-bold);
|
|
1142
|
+
letter-spacing: var(--ls-tight);
|
|
1143
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
1144
|
+
}
|
|
1145
|
+
.topbar button {
|
|
1146
|
+
background: var(--bg-card); border: 1px solid var(--border); color: var(--text);
|
|
1147
|
+
border-radius: var(--radius-sm); padding: var(--sp-1) var(--sp-3); font-size: var(--text-base);
|
|
1148
|
+
line-height: 1; cursor: pointer; font-family: inherit;
|
|
1149
|
+
}
|
|
1150
|
+
.topbar button:hover { background: var(--bg-hover); border-color: var(--accent); }
|
|
1151
|
+
.nav-toggle { display: none; }
|
|
1152
|
+
|
|
1153
|
+
/* ── Layout: sticky sidebar TOC + reading-width content ──────────────────── */
|
|
1154
|
+
.layout {
|
|
1155
|
+
max-width: var(--max-w); margin: 0 auto;
|
|
1156
|
+
display: grid; grid-template-columns: var(--rail-w) minmax(0, 1fr);
|
|
1157
|
+
gap: var(--sp-8); padding: 0 var(--page-pad);
|
|
1158
|
+
}
|
|
1159
|
+
.rail {
|
|
1160
|
+
position: sticky; top: var(--topbar-h); align-self: start;
|
|
1161
|
+
height: calc(100vh - var(--topbar-h)); overflow-y: auto;
|
|
1162
|
+
padding: var(--sp-5) 0; border-right: 1px solid var(--border-light);
|
|
1163
|
+
}
|
|
1164
|
+
.content { min-width: 0; padding: var(--sp-6) 0 var(--sp-10); }
|
|
1165
|
+
|
|
1166
|
+
/* Backdrop behind the mobile drawer (toggled with the rail via chrome.ts). */
|
|
1167
|
+
.rail-backdrop { display: none; }
|
|
1168
|
+
/* In-drawer close button — hidden on desktop (the rail is a static sidebar). */
|
|
1169
|
+
.rail-close { display: none; }
|
|
1170
|
+
|
|
1171
|
+
/* ── Table of contents (scrollspy marks a.active) ────────────────────────── */
|
|
1172
|
+
nav.toc ul { list-style: none; margin: 0; padding: 0; }
|
|
1173
|
+
nav.toc li { margin: 0; }
|
|
1174
|
+
nav.toc a {
|
|
1175
|
+
display: block; padding: var(--sp-1) var(--sp-3); line-height: 1.35;
|
|
1176
|
+
color: var(--text-muted); font-size: var(--text-sm);
|
|
1177
|
+
text-decoration: none; border-left: 2px solid transparent;
|
|
1178
|
+
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
|
|
1179
|
+
}
|
|
1180
|
+
nav.toc a:hover { color: var(--text); background: var(--bg-hover); }
|
|
1181
|
+
nav.toc a.active {
|
|
1182
|
+
color: var(--accent); border-left-color: var(--accent);
|
|
1183
|
+
background: var(--accent-glow); font-weight: var(--fw-medium);
|
|
1184
|
+
}
|
|
1185
|
+
nav.toc li.toc-3 a { padding-left: var(--sp-6); font-size: var(--text-xs); }
|
|
1186
|
+
|
|
1187
|
+
/* ── Prose typography ──────────────────────────────────────────────────────*/
|
|
1188
|
+
.content h2 {
|
|
1189
|
+
font-size: var(--text-xl); letter-spacing: var(--ls-tight);
|
|
1190
|
+
margin: var(--sp-8) 0 var(--sp-3); padding-bottom: var(--sp-2);
|
|
1191
|
+
border-bottom: 1px solid var(--border-light); scroll-margin-top: calc(var(--topbar-h) + var(--sp-3));
|
|
1192
|
+
}
|
|
1193
|
+
.content h3 {
|
|
1194
|
+
font-size: var(--text-lg); margin: var(--sp-5) 0 var(--sp-2);
|
|
1195
|
+
scroll-margin-top: calc(var(--topbar-h) + var(--sp-3));
|
|
1196
|
+
}
|
|
1197
|
+
.content p { margin: var(--sp-3) 0; line-height: var(--lh-relaxed); }
|
|
1198
|
+
.content ul, .content ol { margin: var(--sp-3) 0; padding-left: var(--sp-6); }
|
|
1199
|
+
.content li { margin: var(--sp-1) 0; line-height: var(--lh-relaxed); }
|
|
1200
|
+
.content blockquote {
|
|
1201
|
+
margin: var(--sp-3) 0; padding: var(--sp-1) var(--sp-4);
|
|
1202
|
+
border-left: 3px solid var(--border); color: var(--text-muted);
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
/* ── Inline code + code blocks (chrome.ts wraps <pre> in .code + .copy-btn) ──*/
|
|
1206
|
+
.content code {
|
|
1207
|
+
font-family: var(--font-mono); font-size: 0.85em;
|
|
1208
|
+
background: var(--bg-inset); padding: 0.12em 0.4em; border-radius: var(--radius-sm);
|
|
1209
|
+
}
|
|
1210
|
+
.content .code { position: relative; margin: var(--sp-3) 0; }
|
|
1211
|
+
.content .code pre {
|
|
1212
|
+
margin: 0; padding: var(--sp-3) var(--sp-4); overflow-x: auto;
|
|
1213
|
+
background: var(--bg-inset); border: 1px solid var(--border-light);
|
|
1214
|
+
border-radius: var(--radius-sm); font-family: var(--font-mono);
|
|
1215
|
+
font-size: var(--text-sm); line-height: var(--lh-relaxed);
|
|
1216
|
+
}
|
|
1217
|
+
.content .code pre code { background: none; padding: 0; font-size: inherit; }
|
|
1218
|
+
.copy-btn {
|
|
1219
|
+
position: absolute; top: var(--sp-1); right: var(--sp-1);
|
|
1220
|
+
background: var(--bg-card); border: 1px solid var(--border); color: var(--text-muted);
|
|
1221
|
+
border-radius: var(--radius-sm); font-size: var(--text-xs); padding: var(--sp-1) var(--sp-2);
|
|
1222
|
+
cursor: pointer; opacity: 0.85; font-family: inherit;
|
|
1223
|
+
}
|
|
1224
|
+
.copy-btn:hover { color: var(--accent); border-color: var(--accent); opacity: 1; }
|
|
1225
|
+
|
|
1226
|
+
/* ── Callouts ─ (border-color BEFORE border-left-color so the accent wins) ── */
|
|
1227
|
+
.callout {
|
|
1228
|
+
margin: var(--sp-4) 0; padding: var(--sp-3) var(--sp-4);
|
|
1229
|
+
border: 1px solid var(--border); border-left-width: 3px;
|
|
1230
|
+
border-radius: var(--radius-sm); background: var(--bg-card);
|
|
1231
|
+
}
|
|
1232
|
+
.callout > :first-child { margin-top: 0; }
|
|
1233
|
+
.callout > :last-child { margin-bottom: 0; }
|
|
1234
|
+
.callout-note, .callout-info { background: var(--blue-bg); border-color: var(--blue-border); border-left-color: var(--blue); }
|
|
1235
|
+
.callout-tip { background: var(--green-bg); border-color: var(--green-border); border-left-color: var(--green); }
|
|
1236
|
+
.callout-warning { background: var(--yellow-bg); border-color: var(--yellow-border); border-left-color: var(--yellow); }
|
|
1237
|
+
.callout-danger { background: var(--red-bg); border-color: var(--red-border); border-left-color: var(--red); }
|
|
1238
|
+
|
|
1239
|
+
/* ── Severity chips (:sev) — tight pill, sub-scale vertical padding ───────── */
|
|
1240
|
+
.sev {
|
|
1241
|
+
display: inline-block; font-size: var(--text-xs); font-weight: var(--fw-semi);
|
|
1242
|
+
padding: 1px var(--sp-2); border-radius: 999px; line-height: 1.5;
|
|
1243
|
+
border: 1px solid var(--border); background: var(--bg-inset); color: var(--text-muted);
|
|
1244
|
+
white-space: nowrap;
|
|
1245
|
+
}
|
|
1246
|
+
.sev-p0 { color: var(--sev-p0); border-color: var(--sev-p0); }
|
|
1247
|
+
.sev-p1 { color: var(--sev-p1); border-color: var(--sev-p1); }
|
|
1248
|
+
.sev-p2 { color: var(--sev-p2); border-color: var(--sev-p2); }
|
|
1249
|
+
.sev-p3 { color: var(--sev-p3); border-color: var(--sev-p3); }
|
|
1250
|
+
.sev-pass { color: var(--sev-pass); border-color: var(--sev-pass); }
|
|
1251
|
+
|
|
1252
|
+
/* ── Citations (:cite) — inline provenance refs ──────────────────────────── */
|
|
1253
|
+
.fp, .cite-advisory {
|
|
1254
|
+
font-family: var(--font-mono); font-size: 0.82em;
|
|
1255
|
+
padding: 0.05em 0.35em; border-radius: var(--radius-sm);
|
|
1256
|
+
background: var(--bg-inset); border: 1px solid var(--border-light);
|
|
1257
|
+
}
|
|
1258
|
+
.fp { color: var(--accent); }
|
|
1259
|
+
.cite-advisory { color: var(--text-faint); border-style: dashed; }
|
|
1260
|
+
|
|
1261
|
+
/* ── Tables + filter-tables ──────────────────────────────────────────────── */
|
|
1262
|
+
.content table { width: 100%; border-collapse: collapse; margin: var(--sp-3) 0; font-size: var(--text-sm); }
|
|
1263
|
+
.content th, .content td { text-align: left; padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--border-light); vertical-align: top; }
|
|
1264
|
+
.content th {
|
|
1265
|
+
color: var(--text-muted); font-weight: var(--fw-semi); font-size: var(--text-xs);
|
|
1266
|
+
text-transform: uppercase; letter-spacing: var(--ls-wide); border-bottom-color: var(--border);
|
|
1267
|
+
}
|
|
1268
|
+
.content tbody tr:hover { background: var(--bg-hover); }
|
|
1269
|
+
.content td code { white-space: nowrap; }
|
|
1270
|
+
.filter-table { margin: var(--sp-4) 0; }
|
|
1271
|
+
.filter-input {
|
|
1272
|
+
width: 100%; max-width: 320px; margin-bottom: var(--sp-2);
|
|
1273
|
+
padding: var(--sp-2) var(--sp-3); font-family: inherit; font-size: var(--text-sm);
|
|
1274
|
+
color: var(--text); background: var(--bg-card);
|
|
1275
|
+
border: 1px solid var(--border); border-radius: var(--radius-sm);
|
|
1276
|
+
}
|
|
1277
|
+
.filter-input:focus { border-color: var(--accent); }
|
|
1278
|
+
|
|
1279
|
+
/* ── Charts (:::chart) — label + proportional bar (fill carries inline width%) */
|
|
1280
|
+
.chart-block { margin: var(--sp-4) 0; }
|
|
1281
|
+
.chart-row {
|
|
1282
|
+
display: grid; grid-template-columns: minmax(var(--chart-label-w), 24%) 1fr;
|
|
1283
|
+
align-items: center; gap: var(--sp-3); margin: var(--sp-1) 0;
|
|
1284
|
+
}
|
|
1285
|
+
.chart-label {
|
|
1286
|
+
font-size: var(--text-sm); color: var(--text-muted); text-align: right;
|
|
1287
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
1288
|
+
}
|
|
1289
|
+
.chart-row .chart-bar {
|
|
1290
|
+
height: 0.9em; min-width: 2px; background: var(--accent);
|
|
1291
|
+
border-radius: var(--radius-sm);
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
/* ── Tabs (::::tabs / :::tab) ─────────────────────────────────────────────── */
|
|
1295
|
+
.tabs { margin: var(--sp-4) 0; }
|
|
1296
|
+
.tablist { display: flex; flex-wrap: wrap; gap: var(--sp-1); border-bottom: 1px solid var(--border); margin-bottom: var(--sp-3); }
|
|
1297
|
+
.tab-btn {
|
|
1298
|
+
background: none; border: none; border-bottom: 2px solid transparent; margin-bottom: -1px;
|
|
1299
|
+
padding: var(--sp-2) var(--sp-3); color: var(--text-muted);
|
|
1300
|
+
font-family: inherit; font-size: var(--text-sm); font-weight: var(--fw-medium); cursor: pointer;
|
|
1301
|
+
}
|
|
1302
|
+
.tab-btn:hover { color: var(--text); }
|
|
1303
|
+
.tab-btn.active { color: var(--accent); border-bottom-color: var(--accent); }
|
|
1304
|
+
.tabpane { display: none; }
|
|
1305
|
+
.tabpane.active { display: block; }
|
|
1306
|
+
|
|
1307
|
+
/* ── Mermaid diagrams ────────────────────────────────────────────────────── */
|
|
1308
|
+
.content figure { margin: var(--sp-4) 0; text-align: center; }
|
|
1309
|
+
.content figure svg, .content > svg, .content .mermaid svg { max-width: 100%; height: auto; }
|
|
1310
|
+
|
|
1311
|
+
/* ── Index page: category card grid ──────────────────────────────────────── */
|
|
1312
|
+
.content .lead { color: var(--text-muted); font-size: var(--text-base); max-width: 60ch; margin-top: var(--sp-2); }
|
|
1313
|
+
.guide-cards {
|
|
1314
|
+
display: grid; grid-template-columns: repeat(auto-fill, minmax(min(var(--card-min), 100%), 1fr));
|
|
1315
|
+
gap: var(--sp-4); margin: var(--sp-4) 0 var(--sp-6);
|
|
1316
|
+
}
|
|
1317
|
+
.guide-card {
|
|
1318
|
+
display: flex; flex-direction: column; gap: var(--sp-2);
|
|
1319
|
+
padding: var(--sp-4); background: var(--bg-card);
|
|
1320
|
+
border: 1px solid var(--border); border-radius: var(--radius);
|
|
1321
|
+
color: inherit; text-decoration: none;
|
|
1322
|
+
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
1323
|
+
}
|
|
1324
|
+
.guide-card:hover { border-color: var(--accent); box-shadow: var(--shadow-md); text-decoration: none; }
|
|
1325
|
+
.guide-card-title { font-weight: var(--fw-semi); color: var(--accent); font-size: var(--text-base); }
|
|
1326
|
+
.guide-card-desc { color: var(--text-muted); font-size: var(--text-sm); line-height: var(--lh-normal); }
|
|
1327
|
+
|
|
1328
|
+
/* ── Responsive: TOC becomes an off-canvas drawer (chrome.ts toggles .open) ──*/
|
|
1329
|
+
/* 860px is literal — media queries cannot read custom properties. Revisit it if
|
|
1330
|
+
--topbar-h / --rail-w / --drawer-w change (the drawer sticky offsets key off them). */
|
|
1331
|
+
@media (max-width: 860px) {
|
|
1332
|
+
.nav-toggle { display: inline-flex; align-items: center; }
|
|
1333
|
+
.layout { grid-template-columns: 1fr; gap: 0; }
|
|
1334
|
+
.rail {
|
|
1335
|
+
position: fixed; top: var(--topbar-h); left: 0; bottom: 0; width: var(--drawer-w); z-index: 50;
|
|
1336
|
+
height: auto; background: var(--bg-card); border-right: 1px solid var(--border);
|
|
1337
|
+
padding: var(--sp-4); box-shadow: var(--shadow-lg);
|
|
1338
|
+
transform: translateX(-100%); transition: transform 0.2s ease, visibility 0.2s ease;
|
|
1339
|
+
/* Closed drawer is off-screen AND removed from tab order / pointer events. */
|
|
1340
|
+
visibility: hidden; pointer-events: none;
|
|
1341
|
+
}
|
|
1342
|
+
.rail.open { transform: translateX(0); visibility: visible; pointer-events: auto; }
|
|
1343
|
+
.rail-close {
|
|
1344
|
+
display: block; margin-left: auto; margin-bottom: var(--sp-2);
|
|
1345
|
+
background: var(--bg-card); border: 1px solid var(--border); color: var(--text);
|
|
1346
|
+
border-radius: var(--radius-sm); padding: var(--sp-1) var(--sp-3); font-size: var(--text-base);
|
|
1347
|
+
line-height: 1; cursor: pointer; font-family: inherit;
|
|
1348
|
+
}
|
|
1349
|
+
.rail-close:hover { background: var(--bg-hover); border-color: var(--accent); }
|
|
1350
|
+
.rail-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
1351
|
+
.rail-backdrop {
|
|
1352
|
+
display: block; position: fixed; inset: var(--topbar-h) 0 0 0;
|
|
1353
|
+
background: var(--scrim); z-index: 49;
|
|
1354
|
+
opacity: 0; pointer-events: none; transition: opacity 0.2s ease;
|
|
1355
|
+
}
|
|
1356
|
+
.rail.open ~ .rail-backdrop { opacity: 1; pointer-events: auto; }
|
|
1357
|
+
}
|
|
1358
|
+
</style>
|
|
1359
|
+
<script>(function(){try{var t=localStorage.getItem('guide-theme');if(!t&&window.matchMedia&&matchMedia('(prefers-color-scheme: dark)').matches)t='dark';if(t)document.documentElement.setAttribute('data-theme',t);}catch(e){}})();</script>
|
|
1360
|
+
</head>
|
|
1361
|
+
<body>
|
|
1362
|
+
<header class="topbar">
|
|
1363
|
+
<button data-action="nav" class="nav-toggle" aria-label="Toggle navigation"
|
|
1364
|
+
aria-expanded="false" aria-controls="guide-toc">☰</button>
|
|
1365
|
+
<h1>Concepts & Glossary</h1>
|
|
1366
|
+
<button data-action="theme" class="theme-toggle" aria-label="Toggle theme">◐</button>
|
|
1367
|
+
</header>
|
|
1368
|
+
<div class="layout">
|
|
1369
|
+
<aside class="rail" id="guide-toc">
|
|
1370
|
+
<button class="rail-close" data-action="nav" aria-label="Close navigation">✕</button>
|
|
1371
|
+
<nav class="toc" aria-label="Table of contents"><ul><li class="toc-2"><a href="#how-to-read-this-guide">How to read this guide</a></li><li class="toc-2"><a href="#pipeline-concepts">Pipeline concepts</a></li><li class="toc-3"><a href="#phase">Phase</a></li><li class="toc-3"><a href="#planning-vs-build-regime">Planning vs. build regime</a></li><li class="toc-3"><a href="#dependencies-hard-gate">dependencies (hard gate)</a></li><li class="toc-3"><a href="#reads-soft-reference">reads (soft reference)</a></li><li class="toc-3"><a href="#conditional-if-needed">Conditional / if-needed</a></li><li class="toc-3"><a href="#stateless-step">Stateless step</a></li><li class="toc-3"><a href="#create-vs-update-mode">CREATE vs. UPDATE mode</a></li><li class="toc-3"><a href="#methodology-preset">Methodology preset</a></li><li class="toc-3"><a href="#depth-15">Depth (1–5)</a></li><li class="toc-3"><a href="#overlay">Overlay</a></li><li class="toc-2"><a href="#observability-concepts">Observability concepts</a></li><li class="toc-3"><a href="#ledger">Ledger</a></li><li class="toc-3"><a href="#event">Event</a></li><li class="toc-3"><a href="#adapter">Adapter</a></li><li class="toc-3"><a href="#lens-ai">Lens (A–I)</a></li><li class="toc-3"><a href="#finding">Finding</a></li><li class="toc-3"><a href="#audit-verdict">Audit verdict</a></li><li class="toc-3"><a href="#fix-threshold">fix_threshold</a></li><li class="toc-3"><a href="#--fix-flow">--fix flow</a></li><li class="toc-3"><a href="#stall-signal">Stall signal</a></li><li class="toc-3"><a href="#phase-boundary-audit">Phase-boundary audit</a></li><li class="toc-3"><a href="#doc-conformance-channel">doc-conformance channel</a></li><li class="toc-2"><a href="#knowledge-concepts">Knowledge concepts</a></li><li class="toc-3"><a href="#knowledge-entry">Knowledge entry</a></li><li class="toc-3"><a href="#volatility-tier">Volatility tier</a></li><li class="toc-3"><a href="#knowledge-gap-signal">Knowledge-gap signal</a></li><li class="toc-2"><a href="#review-concepts">Review concepts</a></li><li class="toc-3"><a href="#channel">Channel</a></li><li class="toc-3"><a href="#compensating-pass">Compensating pass</a></li><li class="toc-3"><a href="#reconcile">Reconcile</a></li><li class="toc-3"><a href="#finding-key">finding_key</a></li><li class="toc-3"><a href="#mmr-verdict">MMR verdict</a></li><li class="toc-2"><a href="#multi-agent-concepts">Multi-agent concepts</a></li><li class="toc-3"><a href="#worktree">Worktree</a></li><li class="toc-3"><a href="#worktree-identity">Worktree identity</a></li><li class="toc-3"><a href="#ledger-harvest">Ledger harvest</a></li><li class="toc-3"><a href="#teardown">Teardown</a></li><li class="toc-2"><a href="#see-also">See also</a></li></ul></nav>
|
|
1372
|
+
</aside>
|
|
1373
|
+
<main class="content"><h2 id="how-to-read-this-guide">How to read this guide</h2>
|
|
1374
|
+
<p>Scaffold's other guides each go deep on one system; this one is the <strong>map of the
|
|
1375
|
+
vocabulary</strong> they share. Every term below gets a short definition and a link to
|
|
1376
|
+
the guide that owns the full story. When two guides use the same word slightly
|
|
1377
|
+
differently (a "verdict" in MMR vs. in the audit engine; a "lens" that lives in
|
|
1378
|
+
the audit but reasons about the knowledge base), this guide is where the seam is
|
|
1379
|
+
named.</p>
|
|
1380
|
+
<p>Terms cluster into four families:</p>
|
|
1381
|
+
<ul>
|
|
1382
|
+
<li><strong>Pipeline</strong> — how an idea becomes a build-ready spec.</li>
|
|
1383
|
+
<li><strong>Observability</strong> — the durable record of what the build actually did.</li>
|
|
1384
|
+
<li><strong>Review</strong> — how independent models gate changes.</li>
|
|
1385
|
+
<li><strong>Multi-agent</strong> — how parallel worktrees coordinate without stepping on each other.</li>
|
|
1386
|
+
</ul>
|
|
1387
|
+
<div class="filter-table"><input type="text" class="filter-input" placeholder="Filter…" aria-label="Filter table rows" disabled>
|
|
1388
|
+
|
|
1389
|
+
|
|
1390
|
+
|
|
1391
|
+
|
|
1392
|
+
|
|
1393
|
+
|
|
1394
|
+
|
|
1395
|
+
|
|
1396
|
+
|
|
1397
|
+
|
|
1398
|
+
|
|
1399
|
+
|
|
1400
|
+
|
|
1401
|
+
|
|
1402
|
+
|
|
1403
|
+
|
|
1404
|
+
|
|
1405
|
+
|
|
1406
|
+
|
|
1407
|
+
|
|
1408
|
+
|
|
1409
|
+
|
|
1410
|
+
|
|
1411
|
+
|
|
1412
|
+
|
|
1413
|
+
|
|
1414
|
+
|
|
1415
|
+
|
|
1416
|
+
|
|
1417
|
+
|
|
1418
|
+
|
|
1419
|
+
|
|
1420
|
+
|
|
1421
|
+
|
|
1422
|
+
|
|
1423
|
+
|
|
1424
|
+
|
|
1425
|
+
|
|
1426
|
+
|
|
1427
|
+
|
|
1428
|
+
|
|
1429
|
+
|
|
1430
|
+
|
|
1431
|
+
|
|
1432
|
+
|
|
1433
|
+
|
|
1434
|
+
|
|
1435
|
+
|
|
1436
|
+
|
|
1437
|
+
|
|
1438
|
+
|
|
1439
|
+
|
|
1440
|
+
|
|
1441
|
+
|
|
1442
|
+
|
|
1443
|
+
|
|
1444
|
+
|
|
1445
|
+
|
|
1446
|
+
|
|
1447
|
+
|
|
1448
|
+
|
|
1449
|
+
|
|
1450
|
+
|
|
1451
|
+
|
|
1452
|
+
|
|
1453
|
+
|
|
1454
|
+
|
|
1455
|
+
|
|
1456
|
+
|
|
1457
|
+
|
|
1458
|
+
|
|
1459
|
+
|
|
1460
|
+
|
|
1461
|
+
|
|
1462
|
+
|
|
1463
|
+
|
|
1464
|
+
|
|
1465
|
+
|
|
1466
|
+
|
|
1467
|
+
|
|
1468
|
+
|
|
1469
|
+
|
|
1470
|
+
|
|
1471
|
+
|
|
1472
|
+
|
|
1473
|
+
|
|
1474
|
+
|
|
1475
|
+
|
|
1476
|
+
|
|
1477
|
+
|
|
1478
|
+
|
|
1479
|
+
|
|
1480
|
+
|
|
1481
|
+
|
|
1482
|
+
|
|
1483
|
+
|
|
1484
|
+
|
|
1485
|
+
|
|
1486
|
+
|
|
1487
|
+
|
|
1488
|
+
|
|
1489
|
+
|
|
1490
|
+
|
|
1491
|
+
|
|
1492
|
+
|
|
1493
|
+
|
|
1494
|
+
|
|
1495
|
+
|
|
1496
|
+
|
|
1497
|
+
|
|
1498
|
+
|
|
1499
|
+
|
|
1500
|
+
|
|
1501
|
+
|
|
1502
|
+
|
|
1503
|
+
|
|
1504
|
+
|
|
1505
|
+
|
|
1506
|
+
|
|
1507
|
+
|
|
1508
|
+
|
|
1509
|
+
|
|
1510
|
+
|
|
1511
|
+
|
|
1512
|
+
|
|
1513
|
+
|
|
1514
|
+
|
|
1515
|
+
|
|
1516
|
+
|
|
1517
|
+
|
|
1518
|
+
|
|
1519
|
+
|
|
1520
|
+
|
|
1521
|
+
|
|
1522
|
+
|
|
1523
|
+
|
|
1524
|
+
|
|
1525
|
+
|
|
1526
|
+
|
|
1527
|
+
|
|
1528
|
+
|
|
1529
|
+
|
|
1530
|
+
|
|
1531
|
+
|
|
1532
|
+
|
|
1533
|
+
|
|
1534
|
+
|
|
1535
|
+
|
|
1536
|
+
|
|
1537
|
+
|
|
1538
|
+
|
|
1539
|
+
|
|
1540
|
+
|
|
1541
|
+
|
|
1542
|
+
|
|
1543
|
+
|
|
1544
|
+
|
|
1545
|
+
|
|
1546
|
+
|
|
1547
|
+
|
|
1548
|
+
|
|
1549
|
+
|
|
1550
|
+
|
|
1551
|
+
|
|
1552
|
+
|
|
1553
|
+
|
|
1554
|
+
|
|
1555
|
+
|
|
1556
|
+
|
|
1557
|
+
|
|
1558
|
+
|
|
1559
|
+
|
|
1560
|
+
|
|
1561
|
+
|
|
1562
|
+
<table><thead><tr><th>Term</th><th>Cluster</th><th>See also</th></tr></thead><tbody><tr><td>Phase</td><td>Pipeline</td><td><a href="../pipeline/index.md">pipeline</a></td></tr><tr><td>Planning vs. build regime</td><td>Pipeline</td><td><a href="../pipeline/index.md">pipeline</a></td></tr><tr><td><code>dependencies</code> (hard gate)</td><td>Pipeline</td><td><a href="../pipeline/index.md">pipeline</a></td></tr><tr><td><code>reads</code> (soft reference)</td><td>Pipeline</td><td><a href="../pipeline/index.md">pipeline</a></td></tr><tr><td>Conditional / <code>if-needed</code></td><td>Pipeline</td><td><a href="../pipeline/index.md">pipeline</a></td></tr><tr><td>Stateless step</td><td>Pipeline</td><td><a href="../pipeline/index.md">pipeline</a></td></tr><tr><td>CREATE vs. UPDATE mode</td><td>Pipeline</td><td><a href="../pipeline/index.md">pipeline</a></td></tr><tr><td>Methodology preset</td><td>Pipeline</td><td><a href="../pipeline/index.md">pipeline</a></td></tr><tr><td>Depth (1–5)</td><td>Pipeline</td><td><a href="../pipeline/index.md">pipeline</a></td></tr><tr><td>Overlay</td><td>Pipeline</td><td><a href="../pipeline/index.md">pipeline</a></td></tr><tr><td>Ledger</td><td>Observability</td><td><a href="../observability/index.md">observability</a></td></tr><tr><td>Event</td><td>Observability</td><td><a href="../observability/index.md">observability</a></td></tr><tr><td>Adapter</td><td>Observability</td><td><a href="../observability/index.md">observability</a></td></tr><tr><td>Lens (A–I)</td><td>Observability</td><td><a href="../observability/index.md">observability</a> · <a href="../knowledge-freshness/index.md">knowledge-freshness</a></td></tr><tr><td>Finding</td><td>Observability</td><td><a href="../observability/index.md">observability</a></td></tr><tr><td>Audit verdict</td><td>Observability</td><td><a href="../observability/index.md">observability</a></td></tr><tr><td><code>fix_threshold</code></td><td>Observability · Review</td><td><a href="../observability/index.md">observability</a> · <a href="../mmr/index.md">mmr</a></td></tr><tr><td><code>--fix</code> flow</td><td>Observability</td><td><a href="../observability/index.md">observability</a></td></tr><tr><td>Stall signal</td><td>Observability</td><td><a href="../observability/index.md">observability</a></td></tr><tr><td>Phase-boundary audit</td><td>Observability · Pipeline</td><td><a href="../observability/index.md">observability</a> · <a href="../pipeline/index.md">pipeline</a></td></tr><tr><td><code>doc-conformance</code> channel</td><td>Observability · Review</td><td><a href="../observability/index.md">observability</a> · <a href="../mmr/index.md">mmr</a></td></tr><tr><td>Knowledge entry</td><td>Knowledge</td><td><a href="../knowledge-freshness/index.md">knowledge-freshness</a> · <a href="../knowledge/index.md">knowledge</a></td></tr><tr><td>Volatility tier</td><td>Knowledge</td><td><a href="../knowledge-freshness/index.md">knowledge-freshness</a></td></tr><tr><td>Knowledge-gap signal</td><td>Knowledge</td><td><a href="../knowledge-freshness/index.md">knowledge-freshness</a></td></tr><tr><td>Channel</td><td>Review</td><td><a href="../mmr/index.md">mmr</a> · <a href="../review-workflow/index.md">review-workflow</a></td></tr><tr><td>Compensating pass</td><td>Review</td><td><a href="../mmr/index.md">mmr</a></td></tr><tr><td>Reconcile</td><td>Review</td><td><a href="../mmr/index.md">mmr</a></td></tr><tr><td><code>finding_key</code></td><td>Review</td><td><a href="../mmr/index.md">mmr</a></td></tr><tr><td>MMR verdict</td><td>Review</td><td><a href="../mmr/index.md">mmr</a></td></tr><tr><td>Worktree</td><td>Multi-agent</td><td><a href="../multi-agent/index.md">multi-agent</a> · <a href="../observability/index.md">observability</a></td></tr><tr><td>Worktree identity</td><td>Multi-agent</td><td><a href="../observability/index.md">observability</a></td></tr><tr><td>Ledger harvest</td><td>Multi-agent</td><td><a href="../observability/index.md">observability</a></td></tr><tr><td>Teardown</td><td>Multi-agent</td><td><a href="../observability/index.md">observability</a></td></tr></tbody></table></div>
|
|
1563
|
+
<h2 id="pipeline-concepts">Pipeline concepts</h2>
|
|
1564
|
+
<p>These describe the meta-prompt pipeline that turns an idea into a frozen,
|
|
1565
|
+
build-ready spec. Full treatment: <a href="../pipeline/index.md">the pipeline guide</a>.</p>
|
|
1566
|
+
<h3 id="phase">Phase</h3>
|
|
1567
|
+
<p>One of the <strong>16 ordered stages</strong> the pipeline divides into, numbered 0 (vision)
|
|
1568
|
+
through 15 (build). The phase list, slugs, numbers, and display names are defined
|
|
1569
|
+
exactly once, in the <code>PHASES</code> constant
|
|
1570
|
+
<span class="fp" data-path="src/types/frontmatter.ts:6">src/types/frontmatter.ts:6</span>; every doc, skill, and command resolves
|
|
1571
|
+
against it. Steps within a phase run in <code>order</code> sequence (phase N occupies the
|
|
1572
|
+
N00–N99 band). See <a href="../pipeline/index.md#the-16-phases-at-a-glance">the pipeline guide</a>.</p>
|
|
1573
|
+
<h3 id="planning-vs-build-regime">Planning vs. build regime</h3>
|
|
1574
|
+
<p>The pipeline splits into two regimes. <strong>Planning</strong> (phases 0–14) is <em>stateful</em>
|
|
1575
|
+
and <em>sequential</em> — each step produces a durable artifact and is run roughly once,
|
|
1576
|
+
in dependency order, working toward a frozen spec. <strong>Build</strong> (phase 15) is
|
|
1577
|
+
<em>stateless</em> and <em>on-demand</em> — the execution loops you run repeatedly while
|
|
1578
|
+
actually writing code. See <a href="../pipeline/index.md#the-mental-model">the pipeline guide</a>.</p>
|
|
1579
|
+
<h3 id="dependencies-hard-gate"><code>dependencies</code> (hard gate)</h3>
|
|
1580
|
+
<p>A step's frontmatter <code>dependencies</code> <span class="fp" data-path="src/types/frontmatter.ts:114">src/types/frontmatter.ts:114</span> are
|
|
1581
|
+
<strong>hard gates</strong>: <code>scaffold run</code> refuses a step until each dependency is
|
|
1582
|
+
<code>completed</code>, <code>skipped</code>, or disabled by the resolved pipeline/overlay (a disabled
|
|
1583
|
+
dep counts as satisfied). Contrast <code>reads</code>. See
|
|
1584
|
+
<a href="../pipeline/index.md#why-a-step-is-blocked">Why a step is blocked</a>.</p>
|
|
1585
|
+
<h3 id="reads-soft-reference"><code>reads</code> (soft reference)</h3>
|
|
1586
|
+
<p>A step's <code>reads</code> <span class="fp" data-path="src/types/frontmatter.ts:122">src/types/frontmatter.ts:122</span> are <strong>soft references</strong> — a
|
|
1587
|
+
step uses an upstream artifact if it's present, but a missing read never blocks
|
|
1588
|
+
execution (the assembler silently skips it). The
|
|
1589
|
+
<a href="../pipeline/index.md#why-a-step-is-blocked">pipeline guide</a> explains why
|
|
1590
|
+
<code>reads ≠ dependencies</code> is a common trip-up.</p>
|
|
1591
|
+
<h3 id="conditional-if-needed">Conditional / <code>if-needed</code></h3>
|
|
1592
|
+
<p>A step marked <code>conditional: 'if-needed'</code> <span class="fp" data-path="src/types/frontmatter.ts:118">src/types/frontmatter.ts:118</span> is
|
|
1593
|
+
enabled but only <em>applies</em> to certain project shapes (e.g. <code>database-schema</code>
|
|
1594
|
+
runs only if your project has a database layer). Conditional steps that don't
|
|
1595
|
+
apply count as "satisfied" for dependency purposes. See
|
|
1596
|
+
<a href="../pipeline/index.md#conditional-if-needed-steps">Conditional steps</a>.</p>
|
|
1597
|
+
<h3 id="stateless-step">Stateless step</h3>
|
|
1598
|
+
<p>A phase-15 build step with <code>stateless: true</code> <span class="fp" data-path="src/types/frontmatter.ts:126">src/types/frontmatter.ts:126</span>
|
|
1599
|
+
— it carries no completion state and can be run over and over (the agent loops,
|
|
1600
|
+
resume commands, <code>quick-task</code>, <code>new-enhancement</code>). The pipeline never tracks or
|
|
1601
|
+
gates these. See <a href="../pipeline/index.md#the-mental-model">the pipeline guide</a>.</p>
|
|
1602
|
+
<h3 id="create-vs-update-mode">CREATE vs. UPDATE mode</h3>
|
|
1603
|
+
<p>Every document-creating prompt detects whether its output file already exists. On
|
|
1604
|
+
first run it's <strong>CREATE mode</strong>; on a re-run it's <strong>UPDATE mode</strong>, which preserves
|
|
1605
|
+
human/team customizations and changes only what genuinely needs to change. This
|
|
1606
|
+
is what makes planning phases safe to iterate. See
|
|
1607
|
+
<a href="../pipeline/index.md#create-vs-update-mode">CREATE vs UPDATE mode</a>.</p>
|
|
1608
|
+
<h3 id="methodology-preset">Methodology preset</h3>
|
|
1609
|
+
<p><em>Which</em> steps are enabled. Three presets ship — <code>mvp</code>, <code>custom</code> (balanced), and
|
|
1610
|
+
<code>deep</code> (the schema default and most thorough). Presets are layered with
|
|
1611
|
+
<strong>overlays</strong>. See <a href="../pipeline/index.md#methodology-depth">Methodology & depth</a>.</p>
|
|
1612
|
+
<h3 id="depth-15">Depth (1–5)</h3>
|
|
1613
|
+
<p><em>How thorough</em> each enabled step's output is, on a 1–5 scale from Minimal to
|
|
1614
|
+
Exhaustive (depth 3 is the recommended default). Orthogonal to the preset:
|
|
1615
|
+
the preset picks the steps, depth dials each one's detail. At depth 4–5 some
|
|
1616
|
+
review/validation steps add external- or multi-model dispatch. See
|
|
1617
|
+
<a href="../pipeline/index.md#depth-15">Depth</a>.</p>
|
|
1618
|
+
<h3 id="overlay">Overlay</h3>
|
|
1619
|
+
<p>A preset layer (<code>content/methodology/*-overlay.yml</code>) applied on top of a
|
|
1620
|
+
preset. Overlays are either <strong>project-type</strong> (keyed by <code>project-type</code>, e.g.
|
|
1621
|
+
web-app, mobile, CLI, library) or <strong>structural</strong> (e.g. <code>multi-service</code>, which
|
|
1622
|
+
has no <code>project-type</code> and is activated by the presence of <code>services[]</code> in
|
|
1623
|
+
config). Most overlays only <strong>inject domain knowledge</strong> into existing steps; a
|
|
1624
|
+
few <strong>enable whole step families</strong> (game, multi-service). See
|
|
1625
|
+
<a href="../pipeline/index.md#project-type-playbooks">Project-type playbooks</a>.</p>
|
|
1626
|
+
<h2 id="observability-concepts">Observability concepts</h2>
|
|
1627
|
+
<p>These describe Build Observability — the durable record of what the build did,
|
|
1628
|
+
and the audit that checks it against the planning docs. Full treatment:
|
|
1629
|
+
<a href="../observability/index.md">the build observability guide</a>.</p>
|
|
1630
|
+
<h3 id="ledger">Ledger</h3>
|
|
1631
|
+
<p>The append-only <code>.scaffold/activity.jsonl</code> file where every durable observation
|
|
1632
|
+
lands as one JSON object per line. Writes are lock-guarded so parallel worktrees
|
|
1633
|
+
never corrupt it, each event is capped at 4 KiB, and secrets and home paths are
|
|
1634
|
+
redacted on the way in and out. See <a href="../observability/index.md#the-ledger">The ledger</a>.</p>
|
|
1635
|
+
<h3 id="event">Event</h3>
|
|
1636
|
+
<p>One typed entry in the ledger, written via <code>scaffold observe event <type> …</code>.
|
|
1637
|
+
There are <strong>nine event types</strong> <span class="fp" data-path="src/observability/engine/types.ts:9">src/observability/engine/types.ts:9</span>
|
|
1638
|
+
(<code>task_claimed</code>, <code>task_completed</code>, <code>decision_recorded</code>, <code>blocker_hit</code>,
|
|
1639
|
+
<code>blocker_resolved</code>, <code>pr_opened</code>, <code>progress_heartbeat</code>, <code>finding_acknowledged</code>,
|
|
1640
|
+
<code>knowledge_gap_signal</code>), each with its own payload allow-list. See
|
|
1641
|
+
<a href="../observability/index.md#the-nine-event-types">The nine event types</a>.</p>
|
|
1642
|
+
<h3 id="adapter">Adapter</h3>
|
|
1643
|
+
<p>A component that <em>synthesizes</em> events from the surrounding tools (git, GitHub,
|
|
1644
|
+
MMR jobs, pipeline state, test runs) so the timeline reflects more than what
|
|
1645
|
+
agents chose to record. Eight adapters exist
|
|
1646
|
+
<span class="fp" data-path="src/observability/engine/types.ts:69">src/observability/engine/types.ts:69</span>; five emit replay events, three are
|
|
1647
|
+
availability probes. See <a href="../observability/index.md#adapters">Adapters</a>.</p>
|
|
1648
|
+
<h3 id="lens-ai">Lens (A–I)</h3>
|
|
1649
|
+
<p>An independent audit check function inside <code>scaffold observe audit</code>. The suite
|
|
1650
|
+
runs <strong>nine lenses, A through I</strong> — TDD coverage, AC coverage, coding-standards
|
|
1651
|
+
drift, tech-stack drift, design-system drift, scope, decisions, cross-doc
|
|
1652
|
+
consistency, and knowledge gaps. Lenses A–G run under <code>--scope code</code>, H and I
|
|
1653
|
+
under <code>--scope docs</code>. See
|
|
1654
|
+
<a href="../observability/index.md#the-nine-lens-audit">The nine-lens audit</a>. <strong>Lens I</strong>
|
|
1655
|
+
(<code>I-knowledge-gaps</code>) lives in the audit but reasons about the knowledge base —
|
|
1656
|
+
its full behavior is in <a href="../knowledge-freshness/index.md#lens-i-gap-detection-suppression">the knowledge-freshness guide</a>.</p>
|
|
1657
|
+
<h3 id="finding">Finding</h3>
|
|
1658
|
+
<p>A single issue a lens reports, carrying a severity (<code>P0</code>–<code>P3</code>), a title, a
|
|
1659
|
+
source doc, and an optional fix hint. Findings can be <code>open</code>, <code>acknowledged</code>
|
|
1660
|
+
(silenced via <code>scaffold observe ack</code>), or <code>skipped</code> (a lens whose required
|
|
1661
|
+
adapter was missing). See
|
|
1662
|
+
<a href="../observability/index.md#the-nine-lens-audit">The nine-lens audit</a>.</p>
|
|
1663
|
+
<h3 id="audit-verdict">Audit verdict</h3>
|
|
1664
|
+
<p>The overall result of an audit run. The engine computes exactly <strong>three</strong>
|
|
1665
|
+
verdicts <span class="fp" data-path="src/observability/engine/types.ts:6">src/observability/engine/types.ts:6</span>: <code>pass</code> (no blocking
|
|
1666
|
+
findings, no skipped lenses), <code>degraded-pass</code> (no blocking findings but ≥1 lens
|
|
1667
|
+
skipped), and <code>blocked</code> (≥1 open finding at or above <code>fix_threshold</code>). Note
|
|
1668
|
+
this is <strong>not</strong> the same set as MMR's four verdicts — see <a href="#mmr-verdict">MMR verdict</a>.
|
|
1669
|
+
See <a href="../observability/index.md#verdict-taxonomy">Verdict taxonomy</a>.</p>
|
|
1670
|
+
<h3 id="fix-threshold"><code>fix_threshold</code></h3>
|
|
1671
|
+
<p>The severity cutoff that decides which findings count as <em>blocking</em>. A finding
|
|
1672
|
+
blocks when its status is <code>open</code> and its severity is at or above the threshold
|
|
1673
|
+
(default <strong>P2</strong>). The threshold never hides findings — it only decides which
|
|
1674
|
+
ones drive a <code>blocked</code> verdict. The same name and default govern the MMR gate.
|
|
1675
|
+
See <a href="../observability/index.md#verdict-taxonomy"><code>fix_threshold</code></a> and the
|
|
1676
|
+
<a href="../mmr/index.md#the-gate-the-four-verdicts">MMR gate</a>.</p>
|
|
1677
|
+
<h3 id="--fix-flow"><code>--fix</code> flow</h3>
|
|
1678
|
+
<p><code>scaffold observe audit --fix</code> doesn't just report blocking findings — it
|
|
1679
|
+
dispatches an agent to fix each one, verifies the fix with a single-lens
|
|
1680
|
+
re-audit, and writes a post-fix report, all under abort-safe stashing. See
|
|
1681
|
+
<a href="../observability/index.md#the---fix-flow">The --fix flow</a>.</p>
|
|
1682
|
+
<h3 id="stall-signal">Stall signal</h3>
|
|
1683
|
+
<p>A staleness alert raised on the "Needs Attention" surface when
|
|
1684
|
+
<code>scaffold observe progress</code> runs — e.g. a claimed task with no recent activity,
|
|
1685
|
+
a PR that hasn't merged, an unaddressed blocker. Six signals are defined; five
|
|
1686
|
+
fire today. Thresholds are configurable under <code>stall:</code> in
|
|
1687
|
+
<code>.scaffold/observability.yaml</code>. See
|
|
1688
|
+
<a href="../observability/index.md#stall-detection-the-six-signals">Stall detection</a>.</p>
|
|
1689
|
+
<h3 id="phase-boundary-audit">Phase-boundary audit</h3>
|
|
1690
|
+
<p>A non-gating cross-document audit that fires automatically when a planning
|
|
1691
|
+
document at a phase boundary is marked complete. It runs only the <code>H-cross-doc</code>
|
|
1692
|
+
lens at <code>scope=docs</code>, prints a one-line summary, and never blocks the state
|
|
1693
|
+
transition. The six boundary steps are <code>user-stories</code>, <code>tech-stack</code>,
|
|
1694
|
+
<code>coding-standards</code>, <code>design-system</code>, <code>implementation-plan</code>, and
|
|
1695
|
+
<code>implementation-playbook</code>. See
|
|
1696
|
+
<a href="../observability/index.md#phase-boundary-triggers">Phase-boundary triggers</a> and
|
|
1697
|
+
the <a href="../pipeline/index.md#phase-boundary-audits">pipeline view</a>.</p>
|
|
1698
|
+
<h3 id="doc-conformance-channel"><code>doc-conformance</code> channel</h3>
|
|
1699
|
+
<p>The seam where the audit plugs into multi-model review: a built-in MMR channel
|
|
1700
|
+
that runs <code>scaffold observe audit --output-mode=mmr-findings</code> and emits findings
|
|
1701
|
+
in MMR's <code>Finding</code> shape. Disabled by default; enable with
|
|
1702
|
+
<code>--channels=doc-conformance</code>. See
|
|
1703
|
+
<a href="../observability/index.md#mmr-doc-conformance-channel">MMR doc-conformance channel</a>
|
|
1704
|
+
and the <a href="../mmr/index.md#channel-architecture">MMR channel architecture</a>.</p>
|
|
1705
|
+
<h2 id="knowledge-concepts">Knowledge concepts</h2>
|
|
1706
|
+
<p>These describe the knowledge base and how it stays current. Full treatment:
|
|
1707
|
+
<a href="../knowledge-freshness/index.md">the knowledge-freshness guide</a> and
|
|
1708
|
+
<a href="../knowledge/index.md">the knowledge guide</a>.</p>
|
|
1709
|
+
<h3 id="knowledge-entry">Knowledge entry</h3>
|
|
1710
|
+
<p>A domain-expertise document under <code>content/knowledge/<category>/<slug>.md</code>,
|
|
1711
|
+
injected into prompts during assembly. Each declares a <code>name</code>, <code>volatility</code>
|
|
1712
|
+
tier, and a list of <code>sources</code>. See
|
|
1713
|
+
<a href="../knowledge/index.md">the knowledge guide</a> and
|
|
1714
|
+
<a href="../knowledge-freshness/index.md#adding-a-new-entry-to-the-kb">Adding a new entry</a>.</p>
|
|
1715
|
+
<h3 id="volatility-tier">Volatility tier</h3>
|
|
1716
|
+
<p>How often an entry is expected to drift, on a three-tier scale — <code>fast-moving</code>,
|
|
1717
|
+
<code>evolving</code> (default), <code>stable</code> — which sets the daily cron's re-audit cadence
|
|
1718
|
+
(14 / 60 / 180 days). See
|
|
1719
|
+
<a href="../knowledge-freshness/index.md#cadence-model">the cadence model</a>.</p>
|
|
1720
|
+
<h3 id="knowledge-gap-signal">Knowledge-gap signal</h3>
|
|
1721
|
+
<p>A <code>knowledge_gap_signal</code> ledger event emitted when an agent hits a topic the KB
|
|
1722
|
+
doesn't cover. <strong>Lens I</strong> aggregates these over a rolling 90-day window into
|
|
1723
|
+
P1/P2 findings, suppressing any topic an entry already covers. This is where the
|
|
1724
|
+
observability and knowledge-freshness systems meet. See
|
|
1725
|
+
<a href="../knowledge-freshness/index.md#how-a-gap-closes">How a gap closes</a>.</p>
|
|
1726
|
+
<h2 id="review-concepts">Review concepts</h2>
|
|
1727
|
+
<p>These describe Multi-Model Review (MMR). Full treatment:
|
|
1728
|
+
<a href="../mmr/index.md">the MMR guide</a> and
|
|
1729
|
+
<a href="../review-workflow/index.md">the review-workflow guide</a>.</p>
|
|
1730
|
+
<h3 id="channel">Channel</h3>
|
|
1731
|
+
<p>One independent AI reviewer in an MMR run — a separate subprocess given the same
|
|
1732
|
+
prompt and run in isolation. The built-in channels are <code>codex</code>, <code>gemini</code>,
|
|
1733
|
+
<code>claude</code>, <code>grok</code>, and the opt-in <code>doc-conformance</code>; the <code>scaffold run</code> wrappers
|
|
1734
|
+
add a Superpowers code-reviewer <em>agent</em> channel. A channel is pure config data,
|
|
1735
|
+
not per-channel code. See <a href="../mmr/index.md#channel-architecture">Channel architecture</a>.</p>
|
|
1736
|
+
<h3 id="compensating-pass">Compensating pass</h3>
|
|
1737
|
+
<p>When a channel is degraded (not installed, auth-failed, timed out), MMR runs a
|
|
1738
|
+
<code>claude -p</code> pass focused on that channel's strength area, labeled e.g.
|
|
1739
|
+
<code>[compensating: Grok-equivalent]</code>. These findings are single-source and
|
|
1740
|
+
low-confidence. See <a href="../mmr/index.md#degraded-mode-compensation-auth">Degraded mode</a>.</p>
|
|
1741
|
+
<h3 id="reconcile">Reconcile</h3>
|
|
1742
|
+
<p>The step that groups every channel's findings by a stable key, de-duplicates
|
|
1743
|
+
them, and scores each group for agreement and confidence — producing the single
|
|
1744
|
+
list and verdict. Agreement <em>between</em> channels raises confidence; disagreement
|
|
1745
|
+
surfaces ambiguity. <code>mmr reconcile</code> also folds an external agent channel's
|
|
1746
|
+
findings into an existing job. See
|
|
1747
|
+
<a href="../mmr/index.md#findings-reconciliation-verdicts">Findings, reconciliation & verdicts</a>.</p>
|
|
1748
|
+
<h3 id="finding-key"><code>finding_key</code></h3>
|
|
1749
|
+
<p>The stable identity MMR computes for a finding so the same issue can be tracked
|
|
1750
|
+
across rounds and acknowledgments. Line numbers are stripped from the location
|
|
1751
|
+
and severity is excluded, so the same issue at P1 vs. P2 collapses to one key;
|
|
1752
|
+
a character-5-gram shingle backs a fuzzy match for re-worded findings. See
|
|
1753
|
+
<a href="../mmr/index.md#stable-identity-finding-key">Stable identity</a>.</p>
|
|
1754
|
+
<h3 id="mmr-verdict">MMR verdict</h3>
|
|
1755
|
+
<p>The gate result of a review. MMR computes <strong>four</strong> verdicts: <code>pass</code>,
|
|
1756
|
+
<code>degraded-pass</code>, <code>blocked</code>, and <code>needs-user-decision</code> (no channel completed).
|
|
1757
|
+
Proceed only on <code>pass</code> or <code>degraded-pass</code>.</p>
|
|
1758
|
+
<div class="callout callout-warning"><p><strong>Two verdict vocabularies — don't conflate them.</strong> The MMR review gate has
|
|
1759
|
+
<em>four</em> verdicts (the fourth, <code>needs-user-decision</code>, fires when no channel
|
|
1760
|
+
completes). The Build Observability audit engine emits only <em>three</em> —
|
|
1761
|
+
<code>needs-user-decision</code> is <strong>not</strong> an audit-engine verdict. See
|
|
1762
|
+
<a href="../mmr/index.md#the-gate-the-four-verdicts">the MMR gate</a> and
|
|
1763
|
+
<a href="../observability/index.md#verdict-taxonomy">the audit verdict taxonomy</a>.</p></div>
|
|
1764
|
+
<h2 id="multi-agent-concepts">Multi-agent concepts</h2>
|
|
1765
|
+
<p>These describe how parallel agents share a repo without colliding. Full
|
|
1766
|
+
treatment: <a href="../multi-agent/index.md">the multi-agent guide</a>, with the durable
|
|
1767
|
+
record covered in <a href="../observability/index.md">the observability guide</a>.</p>
|
|
1768
|
+
<h3 id="worktree">Worktree</h3>
|
|
1769
|
+
<p>An isolated git working tree used for parallel agent execution, so multiple
|
|
1770
|
+
agents (and humans) can build different parts of a project at once without
|
|
1771
|
+
sharing a checkout. Each worktree has its own ledger. See
|
|
1772
|
+
<a href="../multi-agent/index.md">the multi-agent guide</a>.</p>
|
|
1773
|
+
<h3 id="worktree-identity">Worktree identity</h3>
|
|
1774
|
+
<p>The stable per-worktree identity recorded in <code>.scaffold/identity.json</code> on first
|
|
1775
|
+
write — a <code>worktree_id</code> (UUID), a <code>worktree_label</code>, and <code>created_at</code>. It's what
|
|
1776
|
+
lets the harvester tell one worktree's events from another's, and what stamps
|
|
1777
|
+
every event's <code>worktree_id</code>. See
|
|
1778
|
+
<a href="../observability/index.md#worktree-identity">Worktree identity</a>.</p>
|
|
1779
|
+
<h3 id="ledger-harvest">Ledger harvest</h3>
|
|
1780
|
+
<p>Copying a worktree's local ledger into the primary repo's archive <em>before</em> the
|
|
1781
|
+
worktree is removed, so the build's reasoning survives teardown.
|
|
1782
|
+
<code>harvest --recover</code> separately rotates already-harvested stale entries from
|
|
1783
|
+
<code>.scaffold/activity-archive/active/</code> into the monthly <code>YYYY-MM.jsonl</code> archives
|
|
1784
|
+
when their worktree is no longer live — it does <strong>not</strong> rescue an unharvested
|
|
1785
|
+
ledger; that ledger is lost once the worktree is removed. See
|
|
1786
|
+
<a href="../observability/index.md#harvest-recover-teardown">Harvest, recover & teardown</a>.</p>
|
|
1787
|
+
<h3 id="teardown">Teardown</h3>
|
|
1788
|
+
<p>Removing a finished worktree the safe way — <code>scripts/teardown-agent-worktree.sh</code>
|
|
1789
|
+
harvests the ledger first, then runs <code>git worktree remove</code>, then deletes the
|
|
1790
|
+
workspace branch. Harvesting before removal is what closes the
|
|
1791
|
+
decisions-die-at-teardown gap. See
|
|
1792
|
+
<a href="../observability/index.md#harvest-recover-teardown">Harvest, recover & teardown</a>.</p>
|
|
1793
|
+
<h2 id="see-also">See also</h2>
|
|
1794
|
+
<ul>
|
|
1795
|
+
<li><a href="../pipeline/index.md">The Scaffold Pipeline</a> — phases, dependencies, presets, depth.</li>
|
|
1796
|
+
<li><a href="../observability/index.md">Build Observability</a> — ledger, events, the nine lenses, verdicts, <code>--fix</code>.</li>
|
|
1797
|
+
<li><a href="../knowledge-freshness/index.md">Knowledge Freshness</a> — volatility tiers, gap signals, Lens I.</li>
|
|
1798
|
+
<li><a href="../mmr/index.md">MMR Reference</a> — channels, reconciliation, the four verdicts.</li>
|
|
1799
|
+
<li><a href="../multi-agent/index.md">Multi-agent</a> — worktrees and parallel execution.</li>
|
|
1800
|
+
<li><a href="../review-workflow/index.md">Review workflow</a> — running reviews end to end.</li>
|
|
1801
|
+
<li><a href="../cli/index.md">CLI reference</a> — the full command surface.</li>
|
|
1802
|
+
</ul></main>
|
|
1803
|
+
<div class="rail-backdrop" data-action="nav" aria-hidden="true"></div>
|
|
1804
|
+
</div>
|
|
1805
|
+
<script>(function(){
|
|
1806
|
+
var LS_KEY = 'guide-theme';
|
|
1807
|
+
function applyTheme(t) {
|
|
1808
|
+
document.documentElement.setAttribute('data-theme', t);
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
1812
|
+
// ─── Theme toggle ────────────────────────────────────────────────────────
|
|
1813
|
+
document.querySelectorAll('[data-action="theme"]').forEach(function(btn) {
|
|
1814
|
+
btn.addEventListener('click', function() {
|
|
1815
|
+
var current = document.documentElement.getAttribute('data-theme');
|
|
1816
|
+
var next = current === 'dark' ? 'light' : 'dark';
|
|
1817
|
+
applyTheme(next);
|
|
1818
|
+
try { localStorage.setItem(LS_KEY, next); } catch(e) {}
|
|
1819
|
+
});
|
|
1820
|
+
});
|
|
1821
|
+
|
|
1822
|
+
// ─── Mobile nav (drawer + backdrop; aria-expanded + Escape-to-close) ──────
|
|
1823
|
+
function setNav(open) {
|
|
1824
|
+
var rail = document.querySelector('.rail');
|
|
1825
|
+
if (rail) rail.classList.toggle('open', open);
|
|
1826
|
+
var toggle = document.querySelector('.nav-toggle');
|
|
1827
|
+
if (toggle) toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
1828
|
+
// Modal-drawer focus containment: while open, make the page content inert
|
|
1829
|
+
// (out of tab order + a11y tree) and move focus into the drawer; on close,
|
|
1830
|
+
// restore content and return focus to the toggle.
|
|
1831
|
+
var main = document.querySelector('.content');
|
|
1832
|
+
if (main) main.inert = open;
|
|
1833
|
+
if (open) {
|
|
1834
|
+
var first = rail && rail.querySelector('a, button, [tabindex]:not([tabindex="-1"])');
|
|
1835
|
+
if (first) first.focus();
|
|
1836
|
+
else if (rail) { rail.setAttribute('tabindex', '-1'); rail.focus(); }
|
|
1837
|
+
} else if (toggle) {
|
|
1838
|
+
toggle.focus();
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
// If the viewport grows past the mobile breakpoint while the drawer is open,
|
|
1842
|
+
// the rail becomes the desktop sidebar and the toggle hides — clear the open
|
|
1843
|
+
// state so .content doesn't stay inert with no way to close it.
|
|
1844
|
+
if (window.matchMedia) {
|
|
1845
|
+
var mq = window.matchMedia('(max-width: 860px)');
|
|
1846
|
+
var onMq = function() {
|
|
1847
|
+
if (mq.matches) return;
|
|
1848
|
+
var rail = document.querySelector('.rail');
|
|
1849
|
+
if (rail) rail.classList.remove('open');
|
|
1850
|
+
var toggle = document.querySelector('.nav-toggle');
|
|
1851
|
+
if (toggle) toggle.setAttribute('aria-expanded', 'false');
|
|
1852
|
+
var main = document.querySelector('.content');
|
|
1853
|
+
if (main) main.inert = false;
|
|
1854
|
+
};
|
|
1855
|
+
if (mq.addEventListener) mq.addEventListener('change', onMq);
|
|
1856
|
+
else if (mq.addListener) mq.addListener(onMq);
|
|
1857
|
+
}
|
|
1858
|
+
document.querySelectorAll('[data-action="nav"]').forEach(function(btn) {
|
|
1859
|
+
btn.addEventListener('click', function() {
|
|
1860
|
+
var rail = document.querySelector('.rail');
|
|
1861
|
+
setNav(!(rail && rail.classList.contains('open')));
|
|
1862
|
+
});
|
|
1863
|
+
});
|
|
1864
|
+
// Selecting a TOC link closes the drawer (so the now-active content isn't
|
|
1865
|
+
// left inert behind the panel) before the anchor navigation scrolls.
|
|
1866
|
+
var drawerRail = document.querySelector('.rail');
|
|
1867
|
+
if (drawerRail) {
|
|
1868
|
+
drawerRail.querySelectorAll('a').forEach(function(a) {
|
|
1869
|
+
a.addEventListener('click', function() {
|
|
1870
|
+
if (drawerRail.classList.contains('open')) setNav(false);
|
|
1871
|
+
});
|
|
1872
|
+
});
|
|
1873
|
+
}
|
|
1874
|
+
document.addEventListener('keydown', function(e) {
|
|
1875
|
+
var rail = document.querySelector('.rail');
|
|
1876
|
+
if (!rail || !rail.classList.contains('open')) return;
|
|
1877
|
+
if (e.key === 'Escape') { setNav(false); return; } // setNav restores focus to the toggle
|
|
1878
|
+
// Trap Tab within the open drawer (modal pattern).
|
|
1879
|
+
if (e.key !== 'Tab') return;
|
|
1880
|
+
var f = rail.querySelectorAll('a[href], button, [tabindex]:not([tabindex="-1"])');
|
|
1881
|
+
if (!f.length) return;
|
|
1882
|
+
var first = f[0], last = f[f.length - 1];
|
|
1883
|
+
if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
|
|
1884
|
+
else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
|
|
1885
|
+
});
|
|
1886
|
+
|
|
1887
|
+
// ─── Copy buttons ─────────────────────────────────────────────────────────
|
|
1888
|
+
document.querySelectorAll('pre').forEach(function(pre) {
|
|
1889
|
+
if (!pre.parentNode) return;
|
|
1890
|
+
var wrapper = document.createElement('div');
|
|
1891
|
+
wrapper.className = 'code';
|
|
1892
|
+
pre.parentNode.insertBefore(wrapper, pre);
|
|
1893
|
+
wrapper.appendChild(pre);
|
|
1894
|
+
var btn = document.createElement('button');
|
|
1895
|
+
btn.className = 'copy-btn';
|
|
1896
|
+
btn.textContent = 'Copy';
|
|
1897
|
+
btn.addEventListener('click', function() {
|
|
1898
|
+
var text = pre.textContent || '';
|
|
1899
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
1900
|
+
navigator.clipboard.writeText(text).then(function() {
|
|
1901
|
+
btn.textContent = 'Copied';
|
|
1902
|
+
setTimeout(function() { btn.textContent = 'Copy'; }, 1200);
|
|
1903
|
+
}, function() {
|
|
1904
|
+
btn.textContent = 'Copy';
|
|
1905
|
+
});
|
|
1906
|
+
}
|
|
1907
|
+
});
|
|
1908
|
+
wrapper.insertBefore(btn, pre);
|
|
1909
|
+
});
|
|
1910
|
+
|
|
1911
|
+
// ─── Tabs (ARIA pattern: aria-selected + roving tabindex + arrow keys) ────
|
|
1912
|
+
function activateTab(group, btn, focus) {
|
|
1913
|
+
var idx = btn.getAttribute('data-tab');
|
|
1914
|
+
group.querySelectorAll('.tab-btn').forEach(function(b) {
|
|
1915
|
+
var on = b === btn;
|
|
1916
|
+
b.classList.toggle('active', on);
|
|
1917
|
+
b.setAttribute('aria-selected', on ? 'true' : 'false');
|
|
1918
|
+
b.setAttribute('tabindex', on ? '0' : '-1');
|
|
1919
|
+
});
|
|
1920
|
+
group.querySelectorAll('.tabpane').forEach(function(pane) {
|
|
1921
|
+
pane.classList.toggle('active', pane.getAttribute('data-tab') === idx);
|
|
1922
|
+
});
|
|
1923
|
+
if (focus) btn.focus();
|
|
1924
|
+
}
|
|
1925
|
+
document.querySelectorAll('.tabs').forEach(function(group) {
|
|
1926
|
+
var btns = [].slice.call(group.querySelectorAll('.tab-btn'));
|
|
1927
|
+
btns.forEach(function(btn, i) {
|
|
1928
|
+
btn.addEventListener('click', function() { activateTab(group, btn, false); });
|
|
1929
|
+
btn.addEventListener('keydown', function(e) {
|
|
1930
|
+
var ni = -1;
|
|
1931
|
+
if (e.key === 'ArrowRight' || e.key === 'ArrowDown') ni = (i + 1) % btns.length;
|
|
1932
|
+
else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') ni = (i - 1 + btns.length) % btns.length;
|
|
1933
|
+
else if (e.key === 'Home') ni = 0;
|
|
1934
|
+
else if (e.key === 'End') ni = btns.length - 1;
|
|
1935
|
+
if (ni >= 0) { e.preventDefault(); activateTab(group, btns[ni], true); }
|
|
1936
|
+
});
|
|
1937
|
+
});
|
|
1938
|
+
});
|
|
1939
|
+
|
|
1940
|
+
// ─── Filter tables ────────────────────────────────────────────────────────
|
|
1941
|
+
document.querySelectorAll('.filter-input').forEach(function(input) {
|
|
1942
|
+
input.addEventListener('input', function() {
|
|
1943
|
+
var q = input.value.toLowerCase();
|
|
1944
|
+
var container = input.closest('.filter-table');
|
|
1945
|
+
if (!container) return;
|
|
1946
|
+
container.querySelectorAll('tbody tr').forEach(function(row) {
|
|
1947
|
+
var text = (row.textContent || '').toLowerCase();
|
|
1948
|
+
row.style.display = text.includes(q) ? '' : 'none';
|
|
1949
|
+
});
|
|
1950
|
+
});
|
|
1951
|
+
});
|
|
1952
|
+
|
|
1953
|
+
// ─── Scrollspy ────────────────────────────────────────────────────────────
|
|
1954
|
+
if (typeof IntersectionObserver === 'undefined') return;
|
|
1955
|
+
var headings = document.querySelectorAll('h2[id],h3[id]');
|
|
1956
|
+
if (!headings.length) return;
|
|
1957
|
+
var observer = new IntersectionObserver(function(entries) {
|
|
1958
|
+
entries.forEach(function(entry) {
|
|
1959
|
+
if (!entry.isIntersecting) return;
|
|
1960
|
+
var id = entry.target.getAttribute('id');
|
|
1961
|
+
document.querySelectorAll('.toc a').forEach(function(a) {
|
|
1962
|
+
a.classList.toggle('active', a.getAttribute('href') === '#' + id);
|
|
1963
|
+
});
|
|
1964
|
+
});
|
|
1965
|
+
}, { rootMargin: '0px 0px -70% 0px', threshold: 0 });
|
|
1966
|
+
headings.forEach(function(h) { observer.observe(h); });
|
|
1967
|
+
});
|
|
1968
|
+
})();</script>
|
|
1969
|
+
</body>
|
|
1970
|
+
</html>
|