@capagents/forgeqe 1.1.2 → 1.1.3

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.
@@ -15,6 +15,9 @@ import { describeRequirement } from "./status.ts"
15
15
  const root = path.resolve(import.meta.dir, "..", "..")
16
16
  export const GUIDE_FILE = path.join(root, "docs", "user-guide.html")
17
17
  const THEME_SOURCE = path.join(root, "docs", "security-data-flow.html")
18
+ const GUIDE_LOGO_LIGHT_FILE = "/Users/oldguard/Documents/GitHub/test-agent-nexus/public/forge-qe-ai-logo.png"
19
+ const GUIDE_LOGO_DARK_FILE = "/Users/oldguard/Documents/GitHub/test-agent-nexus/public/forge-qe-ai-logo-white.png"
20
+ const PARTNER_LOGO_FILE = "/Users/oldguard/Documents/GitHub/test-agent-nexus/public/assets/capgemini-logo.svg"
18
21
 
19
22
  /** Chapters that are not a capability area: which HOW_TO_USE sections they hold, in order. */
20
23
  const START: DocRef[] = ["What you need to run", "Quick start", "1. Install", "2. Scaffold config"].map((heading) => ({ doc: "HOW_TO_USE.md", heading }))
@@ -44,9 +47,11 @@ function sharedLook() {
44
47
  const page = readFileSync(THEME_SOURCE, "utf8")
45
48
  const tokens = page.match(/\/\* =+ tokens =+ \*\/[\s\S]*?(?=\/\* =+ base =+ \*\/)/)?.[0]
46
49
  const favicon = page.match(/<link rel="icon"[^>]*>/)?.[0]
47
- const logo = page.match(/const MARK = h\("img", \{ src: "(data:image\/png;base64,[A-Za-z0-9+/=]+)"/)?.[1]
48
- if (!tokens || !favicon || !logo) throw new Error(`${THEME_SOURCE} no longer has its tokens block, favicon, or MARK logo where the guide reads them.`)
49
- return { tokens: tokens.trim(), favicon, logo }
50
+ const logo = `data:image/png;base64,${readFileSync(GUIDE_LOGO_LIGHT_FILE).toString("base64")}`
51
+ const logoDark = `data:image/png;base64,${readFileSync(GUIDE_LOGO_DARK_FILE).toString("base64")}`
52
+ const partnerLogo = `data:image/svg+xml;base64,${Buffer.from(readFileSync(PARTNER_LOGO_FILE, "utf8")).toString("base64")}`
53
+ if (!tokens || !favicon) throw new Error(`${THEME_SOURCE} no longer has its tokens block or favicon where the guide reads them.`)
54
+ return { tokens: tokens.trim(), favicon, logo, logoDark, partnerLogo }
50
55
  }
51
56
 
52
57
  /** Which section renders where: the first place that names it; later places link to it. */
@@ -175,8 +180,25 @@ export function renderGuide(): string {
175
180
  { id: "reference", title: "Reference", note: "MCP, tuning, logs, environment variables, and every command", body: ids(REFERENCE).map((id) => docBlock(id, sections, placement, 3)).join("\n") },
176
181
  ]
177
182
 
178
- const rail = chapters
179
- .map((c, i) => `<li><a href="#${c.id}"><span class="n">${String(i + 1).padStart(2, "0")}</span><span class="t">${esc(c.title)}</span><span class="d">${esc(c.note)}</span></a></li>`)
183
+ const railGroups = [
184
+ { label: "Guide", items: chapters.filter((c) => ["overview", "get-started", "using"].includes(c.id)) },
185
+ { label: "Capability areas", items: chapters.filter((c) => c.id.startsWith("area-")) },
186
+ { label: "Reference", items: chapters.filter((c) => c.id === "reference") },
187
+ ]
188
+ .filter((g) => g.items.length > 0)
189
+ .map((g) => [
190
+ `<section class="rail-group">`,
191
+ `<h2 class="rail-title mono">${esc(g.label)}</h2>`,
192
+ `<ol class="chapters">`,
193
+ g.items
194
+ .map((c) => {
195
+ const n = String(chapters.indexOf(c) + 1).padStart(2, "0")
196
+ return `<li><a href="#${c.id}"><span class="n">${n}</span><span class="t">${esc(c.title)}</span><span class="d">${esc(c.note)}</span></a></li>`
197
+ })
198
+ .join("\n"),
199
+ `</ol>`,
200
+ `</section>`,
201
+ ].join("\n"))
180
202
  .join("\n")
181
203
 
182
204
  return `<!DOCTYPE html>
@@ -191,7 +213,7 @@ export function renderGuide(): string {
191
213
  ${look.favicon}
192
214
  <link rel="preconnect" href="https://fonts.googleapis.com">
193
215
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
194
- <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&family=Montserrat:ital,wght@0,400;0,500;0,600;0,700;0,800;1,700;1,800&display=swap" rel="stylesheet">
216
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
195
217
  <style>
196
218
  ${look.tokens}
197
219
  ${GUIDE_CSS}
@@ -200,23 +222,39 @@ ${GUIDE_CSS}
200
222
  <body>
201
223
  <a class="skip" href="#panel">Skip to the guide</a>
202
224
  <div id="app">
203
- <header class="mast">
204
- <div class="mark"><img src="${look.logo}" alt=""><b>ForgeQE</b></div>
205
- <span class="sep" aria-hidden="true"></span>
206
- <div class="ttl"><h1>User guide</h1><span class="sub">How to use ForgeQE, and every feature in detail</span></div>
207
- <div class="right"><button class="theme" type="button" aria-label="Switch theme" title="Switch theme">${SUN}${MOON}</button></div>
208
- </header>
225
+ <div class="shell">
209
226
  <nav class="rail" aria-label="Chapters">
210
- <div class="cap mono">Contents</div>
211
- <ol class="chapters">
212
- ${rail}
213
- </ol>
227
+ <div class="rail-inner">
228
+ <div class="side-brand">
229
+ <div class="mark"><img class="logo light" src="${look.logo}" alt="ForgeQE AI"><img class="logo dark" src="${look.logoDark}" alt="" aria-hidden="true"></div>
230
+ <label class="search-wrap" for="rail-search"><span class="search-icon" aria-hidden="true">⌕</span><input id="rail-search" class="rail-search" type="search" placeholder="Search sections" aria-label="Search sections"></label>
231
+ </div>
232
+ ${railGroups}
233
+ </div>
214
234
  </nav>
235
+ <header class="mast">
236
+ <nav class="tabs" aria-label="Guide views"><span class="tab is-active" aria-current="page">Docs</span><button class="tab" type="button" disabled>Changelog</button></nav>
237
+ <div class="right"><img class="partner-logo" src="${look.partnerLogo}" alt="Capgemini"><button class="theme" type="button" aria-label="Switch theme" title="Switch theme">${SUN}${MOON}</button></div>
238
+ </header>
215
239
  <main class="panel" id="panel" tabindex="-1">
216
240
  <div class="page">
241
+ <header class="pagehead">
242
+ <nav class="crumbs" aria-label="Breadcrumb"><a href="#overview">Docs</a><span aria-hidden="true">/</span><span aria-current="page">User guide</span></nav>
243
+ <span class="kicker mono">ForgeQE guide</span>
244
+ <h1>User guide</h1>
245
+ <p>Install ForgeQE, learn the shell, and find every capability with its requirements, prompts, and limits in one place.</p>
246
+ </header>
217
247
  ${chapters.map((c, i) => chapter(i + 1, c)).join("\n")}
218
248
  </div>
219
249
  </main>
250
+ <aside class="toc" aria-label="On this page">
251
+ <div class="toc-box">
252
+ <span class="toc-kicker mono">On this page</span>
253
+ <p class="toc-current" id="toc-current">Overview</p>
254
+ <ol class="toc-links" id="toc-links"></ol>
255
+ </div>
256
+ </aside>
257
+ </div>
220
258
  </div>
221
259
  <script>
222
260
  ${GUIDE_JS}
@@ -229,175 +267,248 @@ ${GUIDE_JS}
229
267
  const SUN = `<svg class="sun" viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="3" fill="none" stroke="currentColor" stroke-width="1.4"/><path d="M8 1v2M8 13v2M1 8h2M13 8h2M3 3l1.4 1.4M11.6 11.6 13 13M3 13l1.4-1.4M11.6 4.4 13 3" stroke="currentColor" stroke-width="1.4"/></svg>`
230
268
  const MOON = `<svg class="moon" viewBox="0 0 16 16" aria-hidden="true"><path d="M13 10.2A5.5 5.5 0 0 1 5.8 3a5.5 5.5 0 1 0 7.2 7.2Z" fill="none" stroke="currentColor" stroke-width="1.4"/></svg>`
231
269
 
232
- /** The shared shell (masthead, rail, panel, chapter head, card) as docs/security-data-flow.html writes it, plus the guide's reading styles. */
270
+ /** A docs-style shell for the generated guide, using the shared documentation tokens and logo. */
233
271
  const GUIDE_CSS = `
234
272
  /* ============ base ============ */
235
273
  *{box-sizing:border-box}
236
274
  html,body{height:100%}
237
275
  html{-webkit-text-size-adjust:100%}
238
- body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--sans);font-size:12.75px;line-height:1.5;-webkit-font-smoothing:antialiased}
276
+ :root{
277
+ --sans:'Plus Jakarta Sans',ui-sans-serif,'Segoe UI',Arial,sans-serif;
278
+ --display:'Plus Jakarta Sans',ui-sans-serif,'Segoe UI',Arial,sans-serif;
279
+ --mono:'Plus Jakarta Sans',ui-sans-serif,'Segoe UI',Arial,sans-serif;
280
+ --guide-bg:#F8FAFC;
281
+ --guide-panel:#FFFFFF;
282
+ --guide-panel-2:#FCFDFE;
283
+ --guide-line:#E2E8F0;
284
+ --guide-text:#020617;
285
+ --guide-muted:#475569;
286
+ --guide-soft:#F1F5F9;
287
+ --guide-accent:#0369A1;
288
+ }
289
+ :root[data-theme="dark"]{
290
+ --guide-bg:#08111F;
291
+ --guide-panel:#0E1726;
292
+ --guide-panel-2:#101B2C;
293
+ --guide-line:#22324A;
294
+ --guide-text:#E8EEF8;
295
+ --guide-muted:#9FB0C7;
296
+ --guide-soft:#132034;
297
+ --guide-accent:#60A5FA;
298
+ }
299
+ @media (prefers-color-scheme:dark){
300
+ :root:not([data-theme="light"]){
301
+ --guide-bg:#08111F;
302
+ --guide-panel:#0E1726;
303
+ --guide-panel-2:#101B2C;
304
+ --guide-line:#22324A;
305
+ --guide-text:#E8EEF8;
306
+ --guide-muted:#9FB0C7;
307
+ --guide-soft:#132034;
308
+ --guide-accent:#60A5FA;
309
+ }
310
+ }
311
+ body{margin:0;background:var(--guide-bg);color:var(--guide-text);font-family:var(--sans);font-size:13.5px;line-height:1.65;-webkit-font-smoothing:antialiased}
239
312
  button{font:inherit;color:inherit}
240
- :focus-visible{outline:2px solid var(--focus);outline-offset:2px}
241
- code{font-family:var(--codefont);font-size:.88em;background:var(--code);padding:0 4px;border:1px solid var(--hair);border-radius:2px;white-space:nowrap}
313
+ :focus-visible{outline:2px solid var(--guide-accent);outline-offset:2px}
314
+ code{font-family:var(--codefont);font-size:.92em;font-weight:500;background:var(--guide-panel);color:var(--guide-text);padding:2px 7px;border:1px solid var(--guide-line);border-radius:8px;white-space:nowrap}
242
315
  p{margin:0}
243
- h2,h3{margin:0}
244
- a{color:var(--ink);text-decoration:underline;text-decoration-color:var(--rule);text-underline-offset:2px}
245
- a:hover{text-decoration-color:var(--ink)}
246
- .muted{color:var(--muted)}
247
- .mono{font-family:var(--mono);font-size:10px;letter-spacing:.09em;text-transform:uppercase;font-weight:500}
248
- .skip{position:absolute;left:-9999px;top:8px;z-index:20;background:var(--card);color:var(--ink);padding:6px 10px;border:1px solid var(--ink)}
316
+ h1,h2,h3{margin:0}
317
+ a{color:var(--guide-accent);text-decoration:underline;text-decoration-color:color-mix(in srgb,var(--guide-accent) 35%,transparent);text-underline-offset:2px}
318
+ a:hover{text-decoration-color:var(--guide-accent)}
319
+ .muted{color:var(--guide-muted)}
320
+ .mono{font-family:var(--mono);font-size:10px;letter-spacing:.09em;text-transform:uppercase;font-weight:700}
321
+ .skip{position:absolute;left:-9999px;top:8px;z-index:20;background:var(--guide-panel);color:var(--guide-text);padding:6px 10px;border:1px solid var(--guide-line)}
249
322
  .skip:focus{left:8px}
250
323
 
251
324
  /* ============ shell ============ */
252
- #app{height:100vh;height:100dvh;display:grid;grid-template-columns:216px minmax(0,1fr);grid-template-rows:auto minmax(0,1fr)}
253
- .mast{grid-column:1/-1;display:flex;align-items:center;gap:16px;height:52px;padding:0 20px;background:var(--brand);color:var(--brand-ink)}
254
- .mark{display:flex;align-items:center;gap:9px;flex:none}
255
- .mark img{display:block;width:30px;height:30px;padding:2px;background:var(--brand-ink);border-radius:7px}
256
- .mark b{font-family:var(--sans);font-weight:700;font-size:14px;letter-spacing:-.01em}
257
- .mast .sep{width:1px;height:22px;background:color-mix(in srgb,var(--brand-ink) 40%,transparent);flex:none}
258
- .mast .ttl{display:flex;align-items:baseline;gap:12px;min-width:0}
259
- .mast h1{font-family:var(--display);font-weight:700;font-size:16px;line-height:1;margin:0;white-space:nowrap;letter-spacing:-.005em}
260
- .mast .sub{color:var(--brand-soft);font-size:11.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
325
+ #app{height:100vh;height:100dvh}
326
+ .mast{grid-column:2 / 4;grid-row:1;display:flex;align-items:center;justify-content:space-between;gap:18px;height:52px;padding:0 24px;background:var(--guide-panel);border-bottom:1px solid var(--guide-line)}
327
+ .mark{display:flex;align-items:center;flex:none}
328
+ .mark .logo{display:block;height:36px;width:auto;max-width:196px}
329
+ .mark .logo.dark{display:none}
330
+ .tabs{display:flex;align-items:center;gap:16px}
331
+ .tab{border:0;background:transparent;color:var(--guide-muted);padding:0 0 12px;border-radius:0;font-size:12px;font-weight:600;line-height:1;cursor:default;border-bottom:1px solid transparent}
332
+ .tab.is-active{color:var(--guide-text);box-shadow:none;border-bottom-color:var(--guide-accent)}
333
+ .tab:disabled{opacity:.7}
261
334
  .mast .right{margin-left:auto;display:flex;align-items:center;gap:14px;flex:none}
262
- .theme{display:grid;place-items:center;width:30px;height:30px;border:1px solid color-mix(in srgb,var(--brand-ink) 50%,transparent);background:transparent;cursor:pointer;border-radius:0;color:var(--brand-ink)}
263
- .theme:hover{background:var(--brand-ink);color:var(--brand);border-color:var(--brand-ink)}
264
- .mast :focus-visible{outline-color:var(--brand-ink)}
335
+ .partner-logo{display:block;height:20px;width:auto;opacity:.98}
336
+ .theme{display:grid;place-items:center;width:34px;height:34px;border:1px solid var(--guide-line);background:var(--guide-panel);cursor:pointer;border-radius:12px;color:var(--guide-text)}
337
+ .theme:hover{border-color:color-mix(in srgb,var(--guide-accent) 35%,var(--guide-line));background:var(--guide-soft)}
265
338
  .theme svg{width:14px;height:14px}
266
339
  .theme .sun{display:none}
340
+ :root[data-theme="dark"] .mark .logo.light{display:none}
341
+ :root[data-theme="dark"] .mark .logo.dark{display:block}
267
342
  :root[data-theme="dark"] .theme .sun{display:block}
268
343
  :root[data-theme="dark"] .theme .moon{display:none}
269
344
  @media (prefers-color-scheme:dark){
345
+ :root:not([data-theme="light"]) .mark .logo.light{display:none}
346
+ :root:not([data-theme="light"]) .mark .logo.dark{display:block}
270
347
  :root:not([data-theme="light"]) .theme .sun{display:block}
271
348
  :root:not([data-theme="light"]) .theme .moon{display:none}
272
349
  }
273
-
274
- /* chapter rail */
275
- .rail{grid-row:2;border-right:1px solid var(--hair);background:var(--band);display:flex;flex-direction:column;min-height:0;overflow:auto}
276
- .rail .cap{padding:16px 18px 8px;color:var(--muted)}
277
- .chapters{list-style:none;margin:0;display:flex;flex-direction:column;padding:0 0 12px}
278
- .chapters a{position:relative;display:grid;grid-template-columns:28px minmax(0,1fr);gap:0 6px;text-decoration:none;border-top:1px solid var(--hair);padding:11px 16px 11px 18px;color:var(--muted)}
279
- .chapters li:last-child a{border-bottom:1px solid var(--hair)}
280
- .chapters .n{font-family:var(--mono);font-size:10.5px;font-weight:600;padding-top:2px;color:var(--muted)}
281
- .chapters .t{font-weight:600;font-size:12.5px;color:var(--ink2);line-height:1.3}
282
- .chapters .d{grid-column:2;font-size:11px;line-height:1.4;margin-top:2px}
283
- .chapters a::before{content:"";position:absolute;left:0;top:-1px;bottom:-1px;width:3px;background:var(--ink);transform:scaleY(0);transform-origin:top;transition:transform .25s ease}
284
- .chapters a:hover{background:var(--card)}
285
- .chapters a:hover .t{color:var(--ink)}
286
- .chapters a[aria-current]{background:var(--card);color:var(--ink2)}
287
- .chapters a[aria-current] .t,.chapters a[aria-current] .n{color:var(--ink)}
350
+ .shell{height:100%;min-height:0;display:grid;grid-template-columns:214px minmax(0,1fr) 188px;grid-template-rows:auto minmax(0,1fr);gap:0}
351
+
352
+ /* left rail */
353
+ .rail,.toc{min-height:0;overflow:auto}
354
+ .rail{grid-column:1;grid-row:1 / 3;background:var(--guide-panel);border-right:1px solid var(--guide-line)}
355
+ .rail-inner{padding:14px 14px 28px}
356
+ .side-brand{display:flex;flex-direction:column;gap:18px;margin-bottom:18px;padding:8px 6px 4px}
357
+ .side-brand-copy .eyebrow{color:var(--guide-accent)}
358
+ .search-wrap{display:flex;align-items:center;gap:8px;height:36px;padding:0 10px;background:var(--guide-panel);border:1px solid var(--guide-line);border-radius:10px}
359
+ .search-icon{font-size:14px;line-height:1;color:#94A3B8}
360
+ .rail-search{width:100%;border:0;background:transparent;padding:0;font:inherit;color:var(--guide-text)}
361
+ .rail-search::placeholder{color:#94A3B8}
362
+ .rail-search:focus{outline:0}
363
+ .rail-group+.rail-group{margin-top:20px}
364
+ .rail-title{margin:0 0 10px;color:var(--guide-muted);font-size:9.5px}
365
+ .chapters{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
366
+ .chapters li+li{margin-top:2px}
367
+ .chapters a{position:relative;display:grid;grid-template-columns:22px minmax(0,1fr);gap:0 8px;padding:6px 8px 6px 12px;border-radius:8px;text-decoration:none;color:var(--guide-muted);transition:background-color .18s ease}
368
+ .chapters .n{font-family:var(--mono);font-size:10px;padding-top:2px;color:#94A3B8}
369
+ .chapters .t{font-weight:500;font-size:12px;line-height:1.35;color:var(--guide-muted)}
370
+ .chapters .d{display:none}
371
+ .chapters a::before{content:"";position:absolute;left:0;top:7px;bottom:7px;width:2px;border-radius:999px;background:var(--guide-accent);transform:scaleY(0);transform-origin:top;transition:transform .18s ease}
372
+ .chapters a:hover{background:var(--guide-panel-2)}
373
+ .chapters a:hover .t{color:var(--guide-text)}
374
+ .chapters a[aria-current]{background:transparent;box-shadow:none}
375
+ .chapters a[aria-current] .t,.chapters a[aria-current] .n{color:var(--guide-text);font-weight:600}
288
376
  .chapters a[aria-current]::before{transform:scaleY(1)}
289
- .chapters a:focus-visible{outline-offset:-2px}
377
+
378
+ /* right toc */
379
+ .toc{grid-column:3;grid-row:2;padding:14px 16px 20px;background:transparent;border-left:1px solid var(--guide-line)}
380
+ .toc-box{position:sticky;top:0;display:flex;flex-direction:column;gap:10px;padding:6px 0 0;background:transparent;border:0;border-radius:0;box-shadow:none}
381
+ .toc-kicker{color:var(--guide-muted)}
382
+ .toc-current{font-weight:700;font-size:13px;line-height:1.35;color:var(--guide-text)}
383
+ .toc-links{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}
384
+ .toc-links a{display:block;padding:4px 0 4px 10px;border-left:2px solid transparent;font-size:11.5px;line-height:1.45;color:var(--guide-muted);text-decoration:none}
385
+ .toc-links a:hover{color:var(--guide-text)}
386
+ .toc-links a[aria-current]{border-left-color:var(--guide-accent);color:var(--guide-text);font-weight:600}
290
387
 
291
388
  /* content */
292
- .panel{grid-row:2;min-width:0;min-height:0;overflow:auto;padding:14px 22px 18px;scroll-behavior:smooth}
293
- .page{max-width:920px;margin:0 auto;display:flex;flex-direction:column;gap:36px;padding-bottom:40vh}
294
- .chapter{display:flex;flex-direction:column;gap:16px;scroll-margin-top:8px}
295
- .chead{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;padding-bottom:9px;border-bottom:1px solid var(--hair)}
296
- .chead .mono{color:var(--muted)}
297
- .chead h2{font-family:var(--display);font-weight:700;font-size:20px;line-height:1.1;letter-spacing:-.01em}
298
- .chead p{color:var(--muted);font-size:12px;flex:1 1 280px}
389
+ .panel{grid-column:2;grid-row:2;min-width:0;min-height:0;overflow:auto;padding:0 16px 40px;scroll-behavior:smooth}
390
+ .page{max-width:980px;margin:0 auto;display:flex;flex-direction:column;gap:56px;padding:28px 24px 28vh;background:transparent;border:0;border-radius:0;box-shadow:none}
391
+ .pagehead{display:flex;flex-direction:column;gap:12px;padding:2px 0 4px}
392
+ .crumbs{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--guide-muted)}
393
+ .crumbs a{text-decoration:none;color:var(--guide-accent);font-weight:600}
394
+ .crumbs span[aria-current="page"]{color:var(--guide-muted)}
395
+ .pagehead .kicker{color:var(--guide-accent)}
396
+ .pagehead h1{font-family:var(--display);font-weight:800;font-size:clamp(34px,3.2vw,46px);line-height:1;letter-spacing:-.035em;color:var(--guide-text)}
397
+ .pagehead p{max-width:60ch;color:var(--guide-muted);font-size:15px;line-height:1.72}
398
+ .chapter{display:flex;flex-direction:column;gap:28px;scroll-margin-top:20px}
399
+ .chead{display:flex;flex-direction:column;gap:7px;padding-bottom:16px;border-bottom:1px solid var(--guide-line)}
400
+ .chead .mono{color:var(--guide-accent)}
401
+ .chead h2{font-family:var(--display);font-weight:750;font-size:30px;line-height:1.06;letter-spacing:-.03em;color:var(--guide-text)}
402
+ .chead p{color:var(--guide-muted);font-size:14.5px;max-width:58ch}
299
403
 
300
404
  /* overview */
301
- .lead{font-size:13.5px;line-height:1.6;color:var(--ink2)}
302
- .band-title{font-family:var(--display);font-weight:700;font-size:15.5px;line-height:1.15;margin-top:6px}
303
- .area{display:grid;grid-template-columns:140px minmax(0,1fr);gap:8px 16px;border-top:1px solid var(--hair);padding-top:10px}
304
- .area-name{text-decoration:none;color:var(--org);padding-top:2px}
405
+ .lead{font-size:14.75px;line-height:1.78;color:var(--guide-muted)}
406
+ .band-title{font-family:var(--display);font-weight:700;font-size:19px;line-height:1.15;margin-top:12px;color:var(--guide-text)}
407
+ .area{display:grid;grid-template-columns:150px minmax(0,1fr);gap:12px 18px;border-top:1px solid var(--guide-line);padding-top:16px}
408
+ .area-name{text-decoration:none;color:#0F766E;padding-top:4px}
305
409
  .area-name:hover{text-decoration:underline;text-underline-offset:3px}
306
- .tiles{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px}
307
- .tile{display:flex;flex-direction:column;gap:2px;height:100%;background:var(--card);border:1px solid var(--hair);padding:8px 10px;text-decoration:none;color:var(--ink)}
308
- .tile b{font-size:12.5px;font-weight:600}
309
- .tile span{color:var(--muted);font-size:11.5px}
310
- .tile:hover{border-color:var(--ink)}
311
-
312
- /* feature card */
313
- .spec{background:var(--card);border:1px solid var(--hair);display:flex;flex-direction:column;scroll-margin-top:8px}
314
- .spec>.hd{display:flex;align-items:baseline;gap:10px;padding:10px 14px 8px;border-bottom:1px solid var(--hair)}
315
- .spec>.hd .mono{color:var(--org)}
316
- .spec>.hd h3{font-family:var(--display);font-weight:700;font-size:15.5px;line-height:1.15}
317
- .spec>.ds{padding:8px 14px 10px;color:var(--muted);font-size:12px}
318
- .facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 22px;padding:10px 14px 12px;border-top:1px solid var(--hair);background:var(--canvas)}
410
+ .tiles{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:10px}
411
+ .tile{display:flex;flex-direction:column;gap:4px;height:100%;background:var(--guide-panel);border:1px solid var(--guide-line);border-radius:16px;padding:14px 15px;text-decoration:none;color:var(--guide-text);box-shadow:0 10px 26px rgba(15,23,42,.04)}
412
+ .tile b{font-size:13px;font-weight:700}
413
+ .tile span{color:var(--guide-muted);font-size:12px;line-height:1.45}
414
+ .tile:hover{border-color:color-mix(in srgb,var(--guide-accent) 22%,var(--guide-line));background:var(--guide-panel-2)}
415
+
416
+ /* feature cards */
417
+ .spec{background:var(--guide-panel);border:1px solid var(--guide-line);border-radius:18px;display:flex;flex-direction:column;scroll-margin-top:16px;overflow:hidden;box-shadow:0 12px 32px rgba(15,23,42,.05)}
418
+ .spec>.hd{display:flex;align-items:center;gap:10px;padding:16px 20px 12px;border-bottom:1px solid var(--guide-line)}
419
+ .spec>.hd .mono{color:#0F766E}
420
+ .spec>.hd h3{font-family:var(--display);font-weight:700;font-size:18px;line-height:1.15;color:var(--guide-text)}
421
+ .spec>.ds{padding:12px 22px 16px;color:var(--guide-muted);font-size:14px;line-height:1.7}
422
+ .facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 28px;padding:18px 22px 20px;border-top:1px solid var(--guide-line);background:var(--guide-panel-2)}
319
423
  .fact{display:flex;flex-direction:column;gap:6px;min-width:0}
320
- .fact>.mono{color:var(--muted)}
424
+ .fact>.mono{color:var(--guide-muted);font-size:9.5px}
321
425
  .asks,.needs,.plainlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
322
- .asks li{border-left:3px solid var(--ink);padding:2px 0 2px 8px;font-size:12.5px;color:var(--ink)}
323
- .needs li{display:grid;grid-template-columns:86px minmax(0,1fr);gap:8px;align-items:baseline;font-size:12.25px}
324
- .need{justify-self:start;display:inline-flex;align-items:center;gap:5px;font-family:var(--mono);font-size:9.5px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;padding:1px 6px 1px 5px;border:1px solid currentColor;border-radius:2px;line-height:1.5;white-space:nowrap;color:var(--ink2);background:var(--card)}
426
+ .asks li{border-left:2px solid var(--guide-accent);padding:4px 0 4px 10px;font-size:13px;color:var(--guide-text);line-height:1.6}
427
+ .needs li{display:grid;grid-template-columns:92px minmax(0,1fr);gap:10px;align-items:baseline;font-size:12.75px;line-height:1.6}
428
+ .need{justify-self:start;display:inline-flex;align-items:center;gap:5px;font-family:var(--mono);font-size:9.5px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;padding:1px 7px 1px 6px;border:1px solid currentColor;border-radius:999px;line-height:1.5;white-space:nowrap;color:var(--guide-muted);background:var(--guide-panel)}
325
429
  .need::before{content:"";width:5px;height:5px;background:currentColor;flex:none}
326
- .need.opt{border-style:dashed;color:var(--muted)}
430
+ .need.opt{border-style:dashed;color:var(--guide-muted)}
327
431
  .need.opt::before{background:none;border:1px solid currentColor;width:4px;height:4px}
328
- .need.input{color:var(--muted);background:var(--band)}
329
- .plainlist li{font-size:12.25px}
432
+ .need.input{color:var(--guide-muted);background:var(--guide-soft)}
433
+ .plainlist li{font-size:12.4px}
330
434
  .tools{display:flex;flex-wrap:wrap;gap:6px}
331
- .detail{padding:12px 14px 14px;border-top:1px solid var(--hair);display:flex;flex-direction:column;gap:14px}
332
- .detail>.mono{color:var(--muted)}
333
-
334
- /* documentation text */
335
- .doc{display:flex;flex-direction:column;gap:8px;scroll-margin-top:8px}
336
- .doc>:is(h3,h4){font-family:var(--display);font-weight:700;font-size:15.5px;line-height:1.15;margin:0}
337
- .doc.sub{margin-top:8px;padding-top:10px;border-top:1px dashed var(--hair)}
338
- .doc.sub>:is(h4,h5){font-family:var(--display);font-weight:700;font-size:13.5px;margin:0}
339
- .chapter>.doc+.doc{padding-top:18px;border-top:1px solid var(--hair)}
340
- .see{color:var(--muted);font-size:12.25px}
341
- .prose{font-size:13.5px;line-height:1.6;color:var(--ink2)}
435
+ .detail{padding:20px 22px 22px;border-top:1px solid var(--guide-line);display:flex;flex-direction:column;gap:20px}
436
+ .detail>.mono{color:var(--guide-muted)}
437
+
438
+ /* prose */
439
+ .doc{display:flex;flex-direction:column;gap:12px;scroll-margin-top:16px}
440
+ .doc>:is(h3,h4){font-family:var(--display);font-weight:700;font-size:21px;line-height:1.15;margin:0;letter-spacing:-.02em;color:var(--guide-text)}
441
+ .doc.sub{margin-top:8px;padding-top:12px;border-top:1px dashed var(--guide-line)}
442
+ .doc.sub>:is(h4,h5){font-family:var(--display);font-weight:700;font-size:16px;margin:0;color:var(--guide-text)}
443
+ .chapter>.doc+.doc{padding-top:28px;border-top:1px solid var(--guide-line)}
444
+ .see{color:var(--guide-muted);font-size:12.25px}
445
+ .prose{font-size:15px;line-height:1.9;color:var(--guide-muted)}
342
446
  .prose :where(p,ul,ol,pre,blockquote){margin:0}
343
- .prose>*+*{margin-top:10px}
344
- .prose ul,.prose ol{padding-left:20px}
345
- .prose li+li{margin-top:4px}
346
- .prose strong{color:var(--ink)}
347
- .prose h5,.prose h6{font-family:var(--display);font-weight:700;font-size:13.5px;color:var(--ink);margin:16px 0 0}
447
+ .prose>*+*{margin-top:16px}
448
+ .prose ul,.prose ol{padding-left:22px}
449
+ .prose li+li{margin-top:8px}
450
+ .prose strong{color:var(--guide-text)}
451
+ .prose h5,.prose h6{font-family:var(--display);font-weight:700;font-size:15px;color:var(--guide-text);margin:18px 0 0}
348
452
  .prose code{white-space:normal;overflow-wrap:anywhere}
349
- .prose pre{margin:0;padding:10px 12px;overflow-x:auto;background:var(--code);border:1px solid var(--hair);font-family:var(--codefont);font-size:11.5px;line-height:1.6}
350
- .prose pre code{background:none;border:0;padding:0;font-size:inherit;white-space:pre;overflow-wrap:normal}
351
- .prose hr{border:0;border-top:1px solid var(--hair)}
352
- .prose blockquote{margin:0;padding-left:12px;border-left:3px solid var(--rule);color:var(--muted)}
353
- .tbl{overflow-x:auto;border:1px solid var(--hair)}
354
- .tbl table{border-collapse:collapse;width:100%;font-size:12.25px;line-height:1.5}
355
- .tbl th,.tbl td{text-align:left;vertical-align:top;padding:6px 10px;border-bottom:1px solid var(--hair)}
356
- .tbl th{background:var(--band);color:var(--ink);font-weight:600}
357
- .tbl tr:last-child td{border-bottom:0}
358
-
359
- /* ============ responsive shell ============ */
360
- @media (max-width:1023px){
361
- #app{grid-template-columns:minmax(0,1fr);grid-template-rows:auto auto minmax(0,1fr)}
362
- .rail{grid-row:2;border-right:0;border-bottom:1px solid var(--hair);overflow:visible}
363
- .rail .cap{display:none}
453
+ .prose pre{margin:0;padding:16px 18px;overflow-x:auto;background:linear-gradient(180deg,#152033,#0C1422);color:#F8FBFF;border:1px solid #22314A;border-radius:16px;font-family:var(--codefont);font-size:13px;line-height:1.75;box-shadow:inset 0 1px 0 color-mix(in srgb,#fff 10%,transparent),0 1px 0 rgba(15,23,42,.12);tab-size:2}
454
+ .prose pre code{display:block;background:none;border:0;padding:0;font-size:inherit;white-space:pre;overflow-wrap:normal;color:inherit}
455
+ .prose hr{border:0;border-top:1px solid var(--guide-line)}
456
+ .prose blockquote{margin:0;padding-left:14px;border-left:3px solid var(--guide-accent);color:var(--guide-muted)}
457
+ .tbl{overflow-x:auto;border:1px solid var(--guide-line);border-radius:16px;background:var(--guide-panel);box-shadow:0 10px 28px rgba(15,23,42,.04)}
458
+ .tbl table{border-collapse:separate;border-spacing:0;width:100%;font-size:13px;line-height:1.65}
459
+ .tbl th,.tbl td{text-align:left;vertical-align:top;padding:12px 16px;border-bottom:1px solid var(--guide-line)}
460
+ .tbl th{background:var(--guide-soft);color:var(--guide-muted);font-weight:700;font-size:10px;letter-spacing:.08em;text-transform:uppercase}
461
+ .tbl tbody tr:nth-child(even) td{background:var(--guide-panel-2)}
462
+ .tbl tbody tr:hover td{background:color-mix(in srgb,var(--guide-panel-2) 78%,var(--guide-soft))}
463
+ .tbl td code{font-size:.85em}
464
+
465
+ /* responsive */
466
+ @media (max-width:1180px){
467
+ .shell{grid-template-columns:214px minmax(0,1fr);grid-template-rows:auto minmax(0,1fr)}
468
+ .mast{grid-column:2;grid-row:1}
469
+ .toc{display:none}
470
+ }
471
+ @media (max-width:900px){
472
+ .shell{grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:14px;padding:0}
473
+ .rail{grid-column:1;grid-row:1;overflow:visible;border-right:0;border-bottom:1px solid var(--guide-line)}
474
+ .mast{grid-column:1;grid-row:2}
475
+ .rail-inner{padding:12px 14px}
476
+ .rail-group+.rail-group{margin-top:14px}
364
477
  .chapters{flex-direction:row;overflow-x:auto;scrollbar-width:none;padding:0}
365
478
  .chapters::-webkit-scrollbar{display:none}
366
479
  .chapters li{flex:none}
367
- .chapters a{grid-template-columns:auto auto;gap:6px;border-top:0;border-right:1px solid var(--hair);padding:10px 14px}
368
- .chapters li:last-child a{border-bottom:0}
369
- .chapters .d{display:none}
370
- .chapters a::before{left:0;right:0;top:auto;bottom:0;width:auto;height:3px;transform:scaleX(0);transform-origin:left}
480
+ .chapters a{grid-template-columns:auto auto;gap:6px;padding:9px 12px}
481
+ .chapters .n{padding-top:1px}
482
+ .chapters a::before{left:10px;right:10px;top:auto;bottom:0;width:auto;height:2px;transform:scaleX(0);transform-origin:left}
371
483
  .chapters a[aria-current]::before{transform:scaleX(1)}
372
- .panel{grid-row:3;padding:12px 16px 18px}
373
- .mast .sub{display:none}
484
+ .panel{grid-column:1;grid-row:3;padding:0 14px 32px}
485
+ .page{padding:24px 10px 24vh;border-radius:0}
486
+ .tabs{margin-left:auto}
374
487
  .facts{grid-template-columns:minmax(0,1fr)}
375
488
  .area{grid-template-columns:minmax(0,1fr)}
376
489
  }
377
490
  @media (max-width:640px){
378
- .mast{padding:0 12px;gap:10px;height:48px}
379
- .mast .sep,.mark b{display:none}
380
- .mast h1{font-size:18px}
381
- .panel{padding:12px 16px 18px}
382
- .chead h2{font-size:21px}
491
+ .mast{padding:12px 14px;height:auto;flex-wrap:wrap}
492
+ .tabs{order:3;margin-left:0}
493
+ .page{padding:22px 4px 22vh;border-radius:0}
494
+ .pagehead h1,.chead h2{font-size:24px}
383
495
  }
384
496
  @media (prefers-reduced-motion:reduce){.panel{scroll-behavior:auto}.chapters a::before{transition:none}}
385
497
 
386
- /* ============ print ============ */
498
+ /* print */
387
499
  @media print{
388
500
  #app{display:block;height:auto}
389
- .rail,.theme,.skip{display:none}
501
+ .rail,.toc,.theme,.tabs,.skip{display:none}
390
502
  .panel{overflow:visible;padding:0}
391
- .page{max-width:none;padding-bottom:0}
392
- .mast{background:none;color:var(--ink);border-bottom:1px solid var(--ink)}
393
- .mast .sub{color:var(--muted)}
503
+ .page{max-width:none;padding:0;border:0;box-shadow:none;background:none}
504
+ .mast{padding:0 0 12px;background:none;color:var(--guide-text);border-bottom:1px solid var(--guide-text);backdrop-filter:none}
394
505
  .spec,.doc{break-inside:auto}
395
506
  .chapter{break-before:page}
396
507
  .chapter:first-child{break-before:auto}
397
508
  }
398
509
  `
399
510
 
400
- /** The theme switch (stored as the other documentation pages store it) and the rail following the chapter in view. */
511
+ /** Theme switching, active left rail, and a docs-style "On this page" outline for the current chapter. */
401
512
  const GUIDE_JS = `(function () {
402
513
  var root = document.documentElement;
403
514
  var dark = function () {
@@ -417,26 +528,91 @@ const GUIDE_JS = `(function () {
417
528
 
418
529
  var panel = document.getElementById("panel");
419
530
  var links = Array.prototype.slice.call(document.querySelectorAll(".chapters a"));
531
+ var railSearch = document.getElementById("rail-search");
532
+ var railGroups = Array.prototype.slice.call(document.querySelectorAll(".rail-group"));
533
+ var tocCurrent = document.getElementById("toc-current");
534
+ var tocLinks = document.getElementById("toc-links");
420
535
  var byId = {};
421
536
  links.forEach(function (a) { byId[a.getAttribute("href").slice(1)] = a; });
422
- var mark = function (id) {
423
- links.forEach(function (a) { if (a === byId[id]) a.setAttribute("aria-current", "location"); else a.removeAttribute("aria-current"); });
424
- var a = byId[id];
425
- if (a && a.scrollIntoView && window.matchMedia("(max-width:1023px)").matches) a.scrollIntoView({ block: "nearest", inline: "nearest" });
537
+ var filterRail = function (term) {
538
+ railGroups.forEach(function (group) {
539
+ var items = Array.prototype.slice.call(group.querySelectorAll(".chapters li"));
540
+ var shown = 0;
541
+ items.forEach(function (item) {
542
+ var a = item.querySelector("a");
543
+ var label = a ? a.textContent.toLowerCase() : "";
544
+ var on = !term || label.indexOf(term) !== -1;
545
+ item.style.display = on ? "" : "none";
546
+ if (on) shown += 1;
547
+ });
548
+ group.style.display = shown ? "" : "none";
549
+ });
426
550
  };
427
551
  var chapters = Array.prototype.slice.call(document.querySelectorAll(".chapter"));
552
+ var itemText = function (node) {
553
+ var heading = node.querySelector("h3,h4,h5");
554
+ return heading ? heading.textContent.trim() : "";
555
+ };
556
+ var tocItems = function (chapter) {
557
+ return Array.prototype.slice.call(chapter.querySelectorAll("[id^='cap-'],[id^='doc-']")).filter(function (node) { return !!itemText(node); });
558
+ };
428
559
  var current = function () {
429
- var top = panel.getBoundingClientRect().top + 24, id = chapters[0].id;
560
+ var top = panel.getBoundingClientRect().top + 72, id = chapters[0].id;
430
561
  chapters.forEach(function (c) { if (c.getBoundingClientRect().top <= top) id = c.id; });
431
562
  return id;
432
563
  };
564
+ var currentItem = function (nodes) {
565
+ if (!nodes.length) return null;
566
+ var top = panel.getBoundingClientRect().top + 116, id = nodes[0].id;
567
+ nodes.forEach(function (node) { if (node.getBoundingClientRect().top <= top) id = node.id; });
568
+ return id;
569
+ };
570
+ var renderToc = function (chapterId) {
571
+ var chapter = document.getElementById(chapterId);
572
+ if (!chapter || !tocLinks || !tocCurrent) return;
573
+ var title = chapter.querySelector(".chead h2");
574
+ tocCurrent.textContent = title ? title.textContent.trim() : "On this page";
575
+ var nodes = tocItems(chapter);
576
+ tocLinks.innerHTML = "";
577
+ nodes.forEach(function (node) {
578
+ var li = document.createElement("li");
579
+ var a = document.createElement("a");
580
+ a.setAttribute("href", "#" + node.id);
581
+ a.textContent = itemText(node);
582
+ li.appendChild(a);
583
+ tocLinks.appendChild(li);
584
+ });
585
+ var itemId = currentItem(nodes);
586
+ Array.prototype.forEach.call(tocLinks.querySelectorAll("a"), function (a) {
587
+ if (itemId && a.getAttribute("href") === "#" + itemId) a.setAttribute("aria-current", "location");
588
+ else a.removeAttribute("aria-current");
589
+ });
590
+ };
591
+ var mark = function (id) {
592
+ links.forEach(function (a) { if (a === byId[id]) a.setAttribute("aria-current", "location"); else a.removeAttribute("aria-current"); });
593
+ var a = byId[id];
594
+ if (a && a.scrollIntoView && window.matchMedia("(max-width:900px)").matches) a.scrollIntoView({ block: "nearest", inline: "nearest" });
595
+ renderToc(id);
596
+ };
597
+ var locateChapter = function (id) {
598
+ for (var i = 0; i < chapters.length; i++) {
599
+ var chapter = chapters[i];
600
+ if (chapter.id === id) return chapter.id;
601
+ var safe = window.CSS && CSS.escape ? CSS.escape(id) : id.replace(/[^a-zA-Z0-9_-]/g, "\\$&");
602
+ if (chapter.querySelector("#" + safe)) return chapter.id;
603
+ }
604
+ return current();
605
+ };
433
606
  var ticking = false;
434
607
  panel.addEventListener("scroll", function () {
435
608
  if (ticking) return;
436
609
  ticking = true;
437
610
  requestAnimationFrame(function () { ticking = false; mark(current()); });
438
611
  }, { passive: true });
439
- mark(location.hash && byId[location.hash.slice(1)] ? location.hash.slice(1) : current());
612
+ if (railSearch) railSearch.addEventListener("input", function () { filterRail(railSearch.value.trim().toLowerCase()); });
613
+ filterRail("");
614
+ mark(location.hash && document.getElementById(location.hash.slice(1)) ? locateChapter(location.hash.slice(1)) : current());
615
+
440
616
  // The browser jumps to a link's section before the fonts arrive, and the text reflows when they do: jump again
441
617
  // after each font loads and once the page has, until the reader scrolls themselves.
442
618
  var target = location.hash && document.getElementById(location.hash.slice(1));
@@ -447,9 +623,15 @@ const GUIDE_JS = `(function () {
447
623
  var settle = function () {
448
624
  if (moved) return;
449
625
  target.scrollIntoView({ block: "start", behavior: "instant" });
450
- mark(current());
626
+ mark(locateChapter(target.id));
451
627
  };
452
628
  window.addEventListener("load", settle);
453
629
  if (document.fonts) document.fonts.addEventListener("loadingdone", settle);
454
630
  }
631
+ window.addEventListener("hashchange", function () {
632
+ var id = location.hash.slice(1);
633
+ if (!id) return mark(current());
634
+ mark(locateChapter(id));
635
+ });
455
636
  })();`
637
+