@cyanmycelium/mcp-broker 0.4.0 → 1.2.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.
Files changed (151) hide show
  1. package/.mcp-broker.example/CONFIGURATION-EN.md +861 -0
  2. package/.mcp-broker.example/CONFIGURATION-FR.md +871 -0
  3. package/.mcp-broker.example/README.md +8 -3
  4. package/.mcp-broker.example/config.json +86 -0
  5. package/README.md +122 -3
  6. package/dist/bin.d.ts +0 -1
  7. package/dist/bin.js +180 -208
  8. package/dist/bin.js.map +1 -1
  9. package/dist/chunk-FTDKH2C4.js +3670 -0
  10. package/dist/chunk-FTDKH2C4.js.map +1 -0
  11. package/dist/{broker/grammars → grammars}/claude/en.json +1 -1
  12. package/dist/{broker/grammars → grammars}/claude/fr.json +1 -1
  13. package/dist/index.d.ts +1790 -18
  14. package/dist/index.js +2 -14
  15. package/dist/index.js.map +1 -1
  16. package/package.json +14 -8
  17. package/scripts/copy-assets.mjs +16 -10
  18. package/scripts/gen-cert.mjs +5 -5
  19. package/scripts/pack-mcpb.mjs +5 -5
  20. package/scripts/sign-bundle.mjs +6 -6
  21. package/src/auth/auth.config.ts +98 -0
  22. package/src/auth/auth.types.ts +120 -0
  23. package/src/auth/http.auth.ts +128 -0
  24. package/src/auth/index.ts +34 -0
  25. package/src/auth/jwt.validator.ts +63 -0
  26. package/src/auth/provider.auth.ts +114 -0
  27. package/src/auth/resource.metadata.ts +34 -0
  28. package/src/authorization/audit.ts +35 -0
  29. package/src/authorization/capability.classifier.ts +114 -0
  30. package/src/authorization/index.ts +37 -0
  31. package/src/authorization/policy.engine.ts +212 -0
  32. package/src/authorization/policy.types.ts +105 -0
  33. package/src/authorization/resource.path.ts +126 -0
  34. package/src/authorization/runtime.ts +56 -0
  35. package/src/authorization/slot.resource.ts +50 -0
  36. package/src/authorization/subject.mapper.ts +81 -0
  37. package/src/bin.ts +90 -7
  38. package/src/broker/adapters/broker.adapter.info.ts +3 -3
  39. package/src/broker/adapters/broker.adapter.providers.ts +3 -3
  40. package/src/broker/aggregate/aggregate.catalog.ts +49 -21
  41. package/src/broker/aggregate/aggregate.server.ts +149 -19
  42. package/src/broker/aggregate/provider.client.session.ts +22 -22
  43. package/src/broker/behaviors/broker.behavior.info.ts +4 -4
  44. package/src/broker/behaviors/broker.behavior.providers.ts +6 -6
  45. package/src/broker/broker.context.ts +10 -4
  46. package/src/broker/broker.grammars.ts +16 -13
  47. package/src/broker/broker.server.ts +12 -9
  48. package/src/broker/grammars/claude/en.json +1 -1
  49. package/src/broker/grammars/claude/fr.json +1 -1
  50. package/src/broker/index.ts +9 -9
  51. package/src/config.ts +81 -8
  52. package/src/index.ts +121 -20
  53. package/src/{mcpb.loader.ts → mcpb/mcpb.loader.ts} +24 -21
  54. package/src/{mcpb.unzip.ts → mcpb/mcpb.unzip.ts} +2 -2
  55. package/src/remote.transports.ts +11 -8
  56. package/src/remote.upstream.ts +11 -8
  57. package/src/stdio.upstream.ts +9 -6
  58. package/src/upstream.ts +6 -3
  59. package/src/ws/ws.interfaces.ts +357 -0
  60. package/src/{ws.tunnel.builder.ts → ws/ws.tunnel.builder.ts} +112 -9
  61. package/src/{ws.tunnel.ts → ws/ws.tunnel.ts} +646 -457
  62. package/web/README.md +94 -0
  63. package/web/assets/logo.png +0 -0
  64. package/web/broker-self-mcp.html +338 -0
  65. package/web/css/styles.css +580 -0
  66. package/web/demos/DemoPlaceholder.html +258 -0
  67. package/web/demos/broker-explorer/css/app.css +393 -0
  68. package/web/demos/broker-explorer/index.html +94 -0
  69. package/web/demos/broker-explorer/js/app.js +271 -0
  70. package/web/demos/broker-explorer/js/mcp-ws-client.js +132 -0
  71. package/web/demos/oauth-lab/README.md +94 -0
  72. package/web/demos/oauth-lab/config.json +117 -0
  73. package/web/demos/oauth-lab/css/app.css +1097 -0
  74. package/web/demos/oauth-lab/index.html +323 -0
  75. package/web/demos/oauth-lab/js/app.js +654 -0
  76. package/web/demos/oauth-lab/server/auth-server.mjs +426 -0
  77. package/web/demos/oauth-lab/server/factory-provider.mjs +269 -0
  78. package/web/demos/oauth-lab/server/smoke-test.mjs +308 -0
  79. package/web/demos/oauth-lab/server/start.mjs +106 -0
  80. package/web/demos/provider-tunnel/css/app.css +384 -0
  81. package/web/demos/provider-tunnel/index.html +99 -0
  82. package/web/demos/provider-tunnel/js/app.js +226 -0
  83. package/web/demos/provider-tunnel/js/toolbox-server.js +186 -0
  84. package/web/index.html +558 -0
  85. package/web/js/lib/broker-tunnel.js +173 -0
  86. package/dist/broker/adapters/broker.adapter.info.d.ts +0 -16
  87. package/dist/broker/adapters/broker.adapter.info.js +0 -43
  88. package/dist/broker/adapters/broker.adapter.info.js.map +0 -1
  89. package/dist/broker/adapters/broker.adapter.providers.d.ts +0 -18
  90. package/dist/broker/adapters/broker.adapter.providers.js +0 -61
  91. package/dist/broker/adapters/broker.adapter.providers.js.map +0 -1
  92. package/dist/broker/aggregate/aggregate.catalog.d.ts +0 -54
  93. package/dist/broker/aggregate/aggregate.catalog.js +0 -105
  94. package/dist/broker/aggregate/aggregate.catalog.js.map +0 -1
  95. package/dist/broker/aggregate/aggregate.server.d.ts +0 -47
  96. package/dist/broker/aggregate/aggregate.server.js +0 -151
  97. package/dist/broker/aggregate/aggregate.server.js.map +0 -1
  98. package/dist/broker/aggregate/provider.client.session.d.ts +0 -52
  99. package/dist/broker/aggregate/provider.client.session.js +0 -140
  100. package/dist/broker/aggregate/provider.client.session.js.map +0 -1
  101. package/dist/broker/behaviors/broker.behavior.info.d.ts +0 -15
  102. package/dist/broker/behaviors/broker.behavior.info.js +0 -41
  103. package/dist/broker/behaviors/broker.behavior.info.js.map +0 -1
  104. package/dist/broker/behaviors/broker.behavior.providers.d.ts +0 -19
  105. package/dist/broker/behaviors/broker.behavior.providers.js +0 -69
  106. package/dist/broker/behaviors/broker.behavior.providers.js.map +0 -1
  107. package/dist/broker/broker.context.d.ts +0 -59
  108. package/dist/broker/broker.context.js +0 -2
  109. package/dist/broker/broker.context.js.map +0 -1
  110. package/dist/broker/broker.grammars.d.ts +0 -130
  111. package/dist/broker/broker.grammars.js +0 -229
  112. package/dist/broker/broker.grammars.js.map +0 -1
  113. package/dist/broker/broker.server.d.ts +0 -66
  114. package/dist/broker/broker.server.js +0 -73
  115. package/dist/broker/broker.server.js.map +0 -1
  116. package/dist/broker/index.d.ts +0 -9
  117. package/dist/broker/index.js +0 -7
  118. package/dist/broker/index.js.map +0 -1
  119. package/dist/config.d.ts +0 -136
  120. package/dist/config.js +0 -61
  121. package/dist/config.js.map +0 -1
  122. package/dist/mcpb.loader.d.ts +0 -24
  123. package/dist/mcpb.loader.js +0 -161
  124. package/dist/mcpb.loader.js.map +0 -1
  125. package/dist/mcpb.unzip.d.ts +0 -6
  126. package/dist/mcpb.unzip.js +0 -95
  127. package/dist/mcpb.unzip.js.map +0 -1
  128. package/dist/remote.transports.d.ts +0 -16
  129. package/dist/remote.transports.js +0 -297
  130. package/dist/remote.transports.js.map +0 -1
  131. package/dist/remote.upstream.d.ts +0 -36
  132. package/dist/remote.upstream.js +0 -52
  133. package/dist/remote.upstream.js.map +0 -1
  134. package/dist/stdio.upstream.d.ts +0 -45
  135. package/dist/stdio.upstream.js +0 -85
  136. package/dist/stdio.upstream.js.map +0 -1
  137. package/dist/upstream.d.ts +0 -33
  138. package/dist/upstream.js +0 -2
  139. package/dist/upstream.js.map +0 -1
  140. package/dist/version.d.ts +0 -2
  141. package/dist/version.js +0 -9
  142. package/dist/version.js.map +0 -1
  143. package/dist/ws.tunnel.builder.d.ts +0 -139
  144. package/dist/ws.tunnel.builder.js +0 -205
  145. package/dist/ws.tunnel.builder.js.map +0 -1
  146. package/dist/ws.tunnel.d.ts +0 -373
  147. package/dist/ws.tunnel.js +0 -1090
  148. package/dist/ws.tunnel.js.map +0 -1
  149. /package/dist/{broker/grammars → grammars}/default/en.json +0 -0
  150. /package/dist/{broker/grammars → grammars}/default/fr.json +0 -0
  151. /package/dist/{broker/grammars → grammars}/default/zh.json +0 -0
@@ -0,0 +1,580 @@
1
+ /* =============================================================
2
+ @cyanmycelium/mcp-broker, site styles
3
+ Same charte as mcp-core, blue accent instead of green-cyan.
4
+ ============================================================= */
5
+
6
+ :root {
7
+ /* Surfaces */
8
+ --bg: #0b0f14;
9
+ --bg-elev-1: #11161d;
10
+ --bg-elev-2: #161c25;
11
+ --bg-inline: #1a212c;
12
+ --rule: #1f2731;
13
+ --rule-strong: #2a3340;
14
+
15
+ /* Foreground */
16
+ --fg: #e6edf3;
17
+ --fg-muted: #9aa7b5;
18
+ --fg-dim: #6b7785;
19
+
20
+ /* Accents (blue) */
21
+ --blue: #3b82f6;
22
+ --blue-dim: #2563eb;
23
+ --blue-bright: #60a5fa;
24
+ --blue-deep: #001a3d;
25
+ --blue-fog: rgba(59, 130, 246, 0.10);
26
+ --blue-fog-2: rgba(59, 130, 246, 0.18);
27
+ --lime: #b8e060;
28
+
29
+ /* Syntax (Tokyo-Night-ish, tuned to the blue accent) */
30
+ --syn-fg: #c9d3df;
31
+ --syn-comment: #5c6776;
32
+ --syn-keyword: #c792ea;
33
+ --syn-type: #82d8ff;
34
+ --syn-string: #b8e060;
35
+ --syn-number: #ffb86b;
36
+ --syn-fn: #3b82f6;
37
+ --syn-prop: #e6edf3;
38
+ --syn-punct: #6b7785;
39
+ --syn-builtin: #f78c6c;
40
+ --syn-decorator:#ffcb6b;
41
+
42
+ /* Type */
43
+ --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
44
+ --font-mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', Menlo, Consolas, monospace;
45
+
46
+ /* Layout */
47
+ --col: 860px;
48
+ --gutter: 32px;
49
+ }
50
+
51
+ * { box-sizing: border-box; }
52
+
53
+ html, body {
54
+ margin: 0;
55
+ background: var(--bg);
56
+ color: var(--fg);
57
+ font-family: var(--font-sans);
58
+ font-size: 16px;
59
+ line-height: 1.6;
60
+ -webkit-font-smoothing: antialiased;
61
+ -moz-osx-font-smoothing: grayscale;
62
+ font-feature-settings: 'cv11', 'ss01', 'ss03';
63
+ }
64
+
65
+ ::selection { background: var(--blue-fog-2); color: var(--fg); }
66
+
67
+ a { color: var(--blue); text-decoration: none; }
68
+ a:hover { text-decoration: underline; text-underline-offset: 3px; }
69
+
70
+ /* ---------------- Layout shell ---------------- */
71
+
72
+ .shell {
73
+ max-width: var(--col);
74
+ margin: 0 auto;
75
+ padding: 0 var(--gutter);
76
+ }
77
+
78
+ .topbar {
79
+ position: sticky;
80
+ top: 0;
81
+ z-index: 10;
82
+ backdrop-filter: blur(10px);
83
+ background: rgba(11, 15, 20, 0.72);
84
+ border-bottom: 1px solid var(--rule);
85
+ }
86
+ .topbar-inner {
87
+ display: flex;
88
+ align-items: center;
89
+ justify-content: space-between;
90
+ height: 56px;
91
+ }
92
+ .brand {
93
+ display: inline-flex;
94
+ align-items: center;
95
+ gap: 10px;
96
+ font-family: var(--font-mono);
97
+ font-size: 13px;
98
+ color: var(--fg);
99
+ letter-spacing: -0.01em;
100
+ }
101
+ .brand-mark {
102
+ width: 24px;
103
+ height: 24px;
104
+ display: inline-block;
105
+ image-rendering: pixelated;
106
+ image-rendering: crisp-edges;
107
+ }
108
+ .topbar-links {
109
+ display: flex;
110
+ gap: 22px;
111
+ font-size: 13px;
112
+ }
113
+ .topbar-links a { color: var(--fg-muted); }
114
+ .topbar-links a:hover { color: var(--fg); text-decoration: none; }
115
+
116
+ /* ---------------- Hero ---------------- */
117
+
118
+ .hero {
119
+ padding: 96px 0 72px;
120
+ border-bottom: 1px solid var(--rule);
121
+ }
122
+ .hero-mark {
123
+ margin: 0 0 24px;
124
+ }
125
+ .hero-mark img {
126
+ width: 96px;
127
+ height: 96px;
128
+ image-rendering: pixelated;
129
+ image-rendering: crisp-edges;
130
+ }
131
+ .eyebrow {
132
+ display: inline-flex;
133
+ align-items: center;
134
+ gap: 8px;
135
+ font-family: var(--font-mono);
136
+ font-size: 12px;
137
+ color: var(--blue);
138
+ letter-spacing: 0.04em;
139
+ text-transform: uppercase;
140
+ margin-bottom: 18px;
141
+ }
142
+ .eyebrow .dot {
143
+ width: 6px;
144
+ height: 6px;
145
+ border-radius: 50%;
146
+ background: var(--blue);
147
+ box-shadow: 0 0 12px var(--blue);
148
+ }
149
+ h1.hero-title {
150
+ font-family: var(--font-mono);
151
+ font-size: clamp(28px, 4.5vw, 44px);
152
+ font-weight: 500;
153
+ letter-spacing: -0.02em;
154
+ margin: 0 0 18px;
155
+ line-height: 1.15;
156
+ color: var(--fg);
157
+ }
158
+ h1.hero-title .at { color: var(--blue); }
159
+ h1.hero-title .sl { color: var(--fg-dim); }
160
+
161
+ .hero-sub {
162
+ font-size: 20px;
163
+ line-height: 1.5;
164
+ color: var(--fg-muted);
165
+ max-width: 620px;
166
+ margin: 0 0 28px;
167
+ text-wrap: pretty;
168
+ }
169
+
170
+ .badges {
171
+ display: flex;
172
+ flex-wrap: wrap;
173
+ gap: 8px;
174
+ margin: 0 0 36px;
175
+ }
176
+ .badge {
177
+ display: inline-flex;
178
+ align-items: center;
179
+ gap: 6px;
180
+ height: 24px;
181
+ padding: 0 10px;
182
+ font-family: var(--font-mono);
183
+ font-size: 11px;
184
+ letter-spacing: 0.02em;
185
+ border-radius: 4px;
186
+ background: var(--bg-elev-1);
187
+ border: 1px solid var(--rule);
188
+ color: var(--fg-muted);
189
+ }
190
+ .badge .k { color: var(--fg-dim); }
191
+ .badge .v { color: var(--fg); }
192
+ .badge.accent .v { color: var(--blue); }
193
+
194
+ .hero-cta {
195
+ display: flex;
196
+ flex-wrap: wrap;
197
+ gap: 12px;
198
+ align-items: center;
199
+ }
200
+
201
+ .btn {
202
+ display: inline-flex;
203
+ align-items: center;
204
+ gap: 10px;
205
+ height: 44px;
206
+ padding: 0 18px;
207
+ border-radius: 6px;
208
+ font-family: var(--font-mono);
209
+ font-size: 13px;
210
+ font-weight: 500;
211
+ cursor: pointer;
212
+ border: 1px solid transparent;
213
+ transition: background 120ms, border-color 120ms, color 120ms, transform 120ms;
214
+ text-decoration: none;
215
+ white-space: nowrap;
216
+ }
217
+ .btn:hover { text-decoration: none; }
218
+ .btn:active { transform: translateY(1px); }
219
+
220
+ .btn-primary {
221
+ background: var(--blue);
222
+ color: #ffffff;
223
+ border-color: var(--blue);
224
+ }
225
+ .btn-primary:hover { background: var(--blue-bright); border-color: var(--blue-bright); color: var(--blue-deep); }
226
+ .btn-primary .cmd-dollar { color: #ffffff; opacity: 0.7; }
227
+ .btn-primary .copy-state { color: #ffffff; opacity: 0.7; font-size: 11px; }
228
+ .btn-primary:hover .cmd-dollar,
229
+ .btn-primary:hover .copy-state { color: var(--blue-deep); opacity: 0.7; }
230
+
231
+ .btn-secondary {
232
+ background: transparent;
233
+ color: var(--fg);
234
+ border-color: var(--rule-strong);
235
+ }
236
+ .btn-secondary:hover { border-color: var(--fg-muted); background: var(--bg-elev-1); }
237
+ .btn-secondary svg { opacity: 0.8; }
238
+
239
+ /* ---------------- Sections ---------------- */
240
+
241
+ section {
242
+ padding: 72px 0;
243
+ border-bottom: 1px solid var(--rule);
244
+ }
245
+ section:last-of-type { border-bottom: none; }
246
+
247
+ .section-num {
248
+ font-family: var(--font-mono);
249
+ font-size: 11px;
250
+ letter-spacing: 0.16em;
251
+ color: var(--fg-dim);
252
+ text-transform: uppercase;
253
+ margin-bottom: 14px;
254
+ }
255
+ h2 {
256
+ font-family: var(--font-sans);
257
+ font-size: 28px;
258
+ line-height: 1.25;
259
+ font-weight: 600;
260
+ letter-spacing: -0.02em;
261
+ margin: 0 0 20px;
262
+ color: var(--fg);
263
+ text-wrap: balance;
264
+ }
265
+ h3 {
266
+ font-family: var(--font-sans);
267
+ font-size: 17px;
268
+ font-weight: 600;
269
+ margin: 36px 0 12px;
270
+ color: var(--fg);
271
+ letter-spacing: -0.01em;
272
+ }
273
+ h3 .h3-num {
274
+ font-family: var(--font-mono);
275
+ font-size: 11px;
276
+ color: var(--blue);
277
+ margin-right: 10px;
278
+ font-weight: 400;
279
+ }
280
+
281
+ p.intro {
282
+ font-size: 17px;
283
+ color: var(--fg-muted);
284
+ max-width: 720px;
285
+ margin: 0 0 24px;
286
+ line-height: 1.6;
287
+ text-wrap: pretty;
288
+ }
289
+ p {
290
+ color: var(--fg-muted);
291
+ margin: 0 0 16px;
292
+ }
293
+ p.caption {
294
+ font-size: 14px;
295
+ color: var(--fg-dim);
296
+ margin: 12px 0 0;
297
+ }
298
+ p strong { color: var(--fg); font-weight: 600; }
299
+
300
+ /* Inline code */
301
+ code.inline,
302
+ p code, li code, td code, th code {
303
+ font-family: var(--font-mono);
304
+ font-size: 0.86em;
305
+ color: var(--blue);
306
+ background: var(--bg-inline);
307
+ border: 1px solid var(--rule);
308
+ padding: 1px 6px;
309
+ border-radius: 4px;
310
+ white-space: nowrap;
311
+ }
312
+ td code, th code { white-space: normal; }
313
+
314
+ /* ---------------- Why list ---------------- */
315
+
316
+ ol.why {
317
+ list-style: none;
318
+ padding: 0;
319
+ margin: 0 0 24px;
320
+ counter-reset: why;
321
+ display: grid;
322
+ gap: 18px;
323
+ }
324
+ ol.why li {
325
+ counter-increment: why;
326
+ display: grid;
327
+ grid-template-columns: 36px 1fr;
328
+ gap: 16px;
329
+ align-items: start;
330
+ }
331
+ ol.why li .why-icon {
332
+ width: 32px;
333
+ height: 32px;
334
+ border: 1px solid var(--rule-strong);
335
+ border-radius: 6px;
336
+ display: grid;
337
+ place-items: center;
338
+ color: var(--blue);
339
+ background: var(--bg-elev-1);
340
+ flex-shrink: 0;
341
+ }
342
+ ol.why li .why-body {
343
+ color: var(--fg-muted);
344
+ line-height: 1.55;
345
+ }
346
+ ol.why li .why-body b { color: var(--fg); font-weight: 500; }
347
+
348
+ .conclusion {
349
+ margin-top: 28px;
350
+ padding: 18px 20px;
351
+ background: var(--blue-fog);
352
+ border-left: 2px solid var(--blue);
353
+ border-radius: 0 6px 6px 0;
354
+ color: var(--fg);
355
+ font-size: 15px;
356
+ line-height: 1.6;
357
+ }
358
+ .conclusion code { background: rgba(0,0,0,0.25); }
359
+
360
+ /* ---------------- Layer cards (architecture roles) ---------------- */
361
+
362
+ .stack {
363
+ margin: 32px 0 40px;
364
+ display: grid;
365
+ gap: 0;
366
+ position: relative;
367
+ }
368
+ .stack-layer {
369
+ background: var(--bg-elev-1);
370
+ border: 1px solid var(--rule-strong);
371
+ border-radius: 8px;
372
+ padding: 18px 22px;
373
+ position: relative;
374
+ transition: border-color 160ms, background 160ms;
375
+ }
376
+ .stack-layer:hover {
377
+ border-color: var(--blue-dim);
378
+ background: var(--bg-elev-2);
379
+ }
380
+ .stack-layer + .stack-arrow {
381
+ height: 28px;
382
+ display: grid;
383
+ place-items: center;
384
+ color: var(--fg-dim);
385
+ }
386
+ .stack-layer-head {
387
+ display: flex;
388
+ align-items: baseline;
389
+ gap: 14px;
390
+ margin-bottom: 6px;
391
+ }
392
+ .stack-layer-name {
393
+ font-family: var(--font-mono);
394
+ font-size: 12px;
395
+ letter-spacing: 0.16em;
396
+ color: var(--blue);
397
+ font-weight: 500;
398
+ }
399
+ .stack-layer-idx {
400
+ font-family: var(--font-mono);
401
+ font-size: 11px;
402
+ color: var(--fg-dim);
403
+ }
404
+ .stack-layer-body {
405
+ color: var(--fg-muted);
406
+ font-size: 15px;
407
+ line-height: 1.5;
408
+ }
409
+
410
+ /* ---------------- Tables ---------------- */
411
+
412
+ .table-wrap {
413
+ margin: 28px 0;
414
+ border: 1px solid var(--rule);
415
+ border-radius: 8px;
416
+ overflow: hidden;
417
+ background: var(--bg-elev-1);
418
+ }
419
+ table {
420
+ width: 100%;
421
+ border-collapse: collapse;
422
+ font-size: 14px;
423
+ }
424
+ thead th {
425
+ background: var(--bg-elev-2);
426
+ color: var(--fg);
427
+ font-weight: 600;
428
+ text-align: left;
429
+ padding: 12px 16px;
430
+ font-size: 12px;
431
+ letter-spacing: 0.04em;
432
+ text-transform: uppercase;
433
+ border-bottom: 1px solid var(--rule-strong);
434
+ }
435
+ tbody td {
436
+ padding: 12px 16px;
437
+ border-bottom: 1px solid var(--rule);
438
+ color: var(--fg-muted);
439
+ vertical-align: top;
440
+ line-height: 1.5;
441
+ }
442
+ tbody tr:last-child td { border-bottom: none; }
443
+ tbody tr:hover td { background: rgba(255,255,255,0.015); }
444
+
445
+ th.col-this, td.col-this {
446
+ background: var(--blue-fog);
447
+ color: var(--fg);
448
+ }
449
+ td.col-this { font-weight: 500; }
450
+ td.col-this code { background: rgba(0,0,0,0.3); color: var(--blue); border-color: rgba(59, 130, 246, 0.25); }
451
+ th.col-this { color: var(--blue); }
452
+
453
+ td.no { color: var(--fg-dim); font-family: var(--font-mono); font-size: 13px; }
454
+
455
+ /* ---------------- Code blocks ---------------- */
456
+
457
+ .code-wrap {
458
+ margin: 20px 0 24px;
459
+ background: #0a0e13;
460
+ border: 1px solid var(--rule);
461
+ border-radius: 8px;
462
+ overflow: hidden;
463
+ position: relative;
464
+ }
465
+ .code-head {
466
+ display: flex;
467
+ align-items: center;
468
+ justify-content: space-between;
469
+ padding: 9px 14px 9px 16px;
470
+ background: var(--bg-elev-1);
471
+ border-bottom: 1px solid var(--rule);
472
+ font-family: var(--font-mono);
473
+ font-size: 11px;
474
+ color: var(--fg-dim);
475
+ letter-spacing: 0.04em;
476
+ }
477
+ .code-head .lang { color: var(--blue); text-transform: uppercase; letter-spacing: 0.16em; }
478
+ .code-head .copy-btn {
479
+ background: transparent;
480
+ border: 1px solid var(--rule-strong);
481
+ color: var(--fg-muted);
482
+ border-radius: 4px;
483
+ padding: 3px 8px;
484
+ font-family: var(--font-mono);
485
+ font-size: 10px;
486
+ cursor: pointer;
487
+ letter-spacing: 0.06em;
488
+ text-transform: uppercase;
489
+ transition: all 120ms;
490
+ }
491
+ .code-head .copy-btn:hover { color: var(--blue); border-color: var(--blue-dim); }
492
+ .code-head .copy-btn.copied { color: var(--blue); border-color: var(--blue); }
493
+
494
+ pre {
495
+ margin: 0;
496
+ padding: 18px 0;
497
+ overflow-x: auto;
498
+ font-family: var(--font-mono);
499
+ font-size: 13px;
500
+ line-height: 1.65;
501
+ color: var(--syn-fg);
502
+ tab-size: 2;
503
+ }
504
+ pre.scroll-y { max-height: 540px; overflow-y: auto; }
505
+ pre code { display: block; padding: 0 18px; min-width: max-content; }
506
+
507
+ .tk-c { color: var(--syn-comment); font-style: italic; }
508
+ .tk-k { color: var(--syn-keyword); }
509
+ .tk-t { color: var(--syn-type); }
510
+ .tk-s { color: var(--syn-string); }
511
+ .tk-n { color: var(--syn-number); }
512
+ .tk-f { color: var(--syn-fn); }
513
+ .tk-p { color: var(--syn-prop); }
514
+ .tk-pu { color: var(--syn-punct); }
515
+ .tk-b { color: var(--syn-builtin); }
516
+ .tk-d { color: var(--syn-decorator); }
517
+ .tk-step{ color: var(--blue); font-weight: 600; }
518
+
519
+ /* ---------------- Footer ---------------- */
520
+
521
+ footer {
522
+ padding: 48px 0 64px;
523
+ border-top: 1px solid var(--rule);
524
+ color: var(--fg-dim);
525
+ font-size: 13px;
526
+ }
527
+ .footer-inner {
528
+ display: flex;
529
+ flex-wrap: wrap;
530
+ gap: 24px;
531
+ justify-content: space-between;
532
+ align-items: baseline;
533
+ }
534
+ .footer-links {
535
+ display: flex;
536
+ gap: 22px;
537
+ font-family: var(--font-mono);
538
+ }
539
+ .footer-links a { color: var(--fg-muted); }
540
+
541
+ /* ---------------- Toast (copy) ---------------- */
542
+
543
+ .toast {
544
+ position: fixed;
545
+ bottom: 24px;
546
+ left: 50%;
547
+ transform: translateX(-50%) translateY(20px);
548
+ background: var(--blue);
549
+ color: #ffffff;
550
+ font-family: var(--font-mono);
551
+ font-size: 12px;
552
+ padding: 10px 16px;
553
+ border-radius: 6px;
554
+ font-weight: 600;
555
+ opacity: 0;
556
+ transition: opacity 160ms, transform 160ms;
557
+ pointer-events: none;
558
+ z-index: 50;
559
+ box-shadow: 0 8px 32px rgba(59, 130, 246, 0.3);
560
+ }
561
+ .toast.show {
562
+ opacity: 1;
563
+ transform: translateX(-50%) translateY(0);
564
+ }
565
+
566
+ /* ---------------- Responsive ---------------- */
567
+
568
+ @media (max-width: 640px) {
569
+ :root { --gutter: 20px; }
570
+ .hero { padding: 64px 0 48px; }
571
+ .hero-mark img { width: 72px; height: 72px; }
572
+ section { padding: 48px 0; }
573
+ h1.hero-title { font-size: 28px; }
574
+ .hero-sub { font-size: 17px; }
575
+ h2 { font-size: 22px; }
576
+ .btn { width: 100%; justify-content: center; }
577
+ .table-wrap { font-size: 13px; }
578
+ thead th, tbody td { padding: 10px 12px; }
579
+ .topbar-links { gap: 14px; }
580
+ }