opencode-bioresearcher 1.6.0 → 1.7.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/connector-meta.json +1 -1
- package/package.json +1 -1
- package/skills/bioresearcher-deep-research/SKILL.md +22 -3
- package/skills/bioresearcher-deep-research/references/citations.md +3 -0
- package/skills/bioresearcher-deep-research/references/report-template.md +1 -0
- package/skills/bioresearcher-deep-research/scripts/markdown-to-html.py +1884 -35
- package/skills/bioresearcher-deep-research/scripts/vet-references.py +330 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Convert a markdown research report to a standalone HTML file.
|
|
2
|
+
"""Convert a markdown research report to a standalone, publication-grade HTML file.
|
|
3
3
|
|
|
4
4
|
Usage:
|
|
5
5
|
uv run --with markdown python scripts/markdown-to-html.py report.md -o report.html
|
|
@@ -7,11 +7,19 @@ Usage:
|
|
|
7
7
|
Dependencies:
|
|
8
8
|
- markdown (python-markdown), provided by `uv run --with markdown`
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
Features:
|
|
11
|
+
- 100% self-contained: zero external network assets (fonts, icons, CDN scripts).
|
|
12
|
+
- BioResearcher · Deep Research branding & metadata card.
|
|
13
|
+
- Responsive Table of Contents: sticky desktop sidebar and mobile slide-over drawer.
|
|
14
|
+
- Interactive in-text citations: superscript badges, floating boundary-aware
|
|
15
|
+
tooltips with tail flipping, auto-linkified DOIs, PMIDs, and NCT trial IDs.
|
|
16
|
+
- Print-ready typography and media queries.
|
|
12
17
|
"""
|
|
13
18
|
|
|
14
19
|
import argparse
|
|
20
|
+
import base64
|
|
21
|
+
import html
|
|
22
|
+
import re
|
|
15
23
|
import sys
|
|
16
24
|
from pathlib import Path
|
|
17
25
|
|
|
@@ -24,47 +32,1888 @@ except ImportError:
|
|
|
24
32
|
)
|
|
25
33
|
sys.exit(2)
|
|
26
34
|
|
|
35
|
+
DEFAULT_ICON_DATA_URI = "data:image/jpeg;base64,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"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_brand_icon_uri() -> str:
|
|
39
|
+
"""Retrieve brand icon data URI with local repository fallback."""
|
|
40
|
+
repo_icon = Path(__file__).resolve().parents[3] / "connector" / "workbuddy" / "icon.jpg"
|
|
41
|
+
if repo_icon.is_file():
|
|
42
|
+
try:
|
|
43
|
+
return f"data:image/jpeg;base64,{base64.b64encode(repo_icon.read_bytes()).decode('ascii')}"
|
|
44
|
+
except OSError:
|
|
45
|
+
pass
|
|
46
|
+
return DEFAULT_ICON_DATA_URI
|
|
47
|
+
|
|
48
|
+
|
|
27
49
|
CSS = """
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
font-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
:root {
|
|
51
|
+
--primary: #0284c7;
|
|
52
|
+
--primary-hover: #0369a1;
|
|
53
|
+
--primary-light: #f0f9ff;
|
|
54
|
+
--primary-border: #bae6fd;
|
|
55
|
+
--text-main: #0f172a;
|
|
56
|
+
--text-muted: #64748b;
|
|
57
|
+
--text-light: #94a3b8;
|
|
58
|
+
--bg-page: #f8fafc;
|
|
59
|
+
--bg-surface: #ffffff;
|
|
60
|
+
--border-color: #e2e8f0;
|
|
61
|
+
--border-subtle: #f1f5f9;
|
|
62
|
+
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
63
|
+
--font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
|
|
64
|
+
--sidebar-w: 270px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
68
|
+
|
|
69
|
+
html {
|
|
70
|
+
scroll-behavior: smooth;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
body {
|
|
74
|
+
margin: 0;
|
|
75
|
+
padding: 0;
|
|
76
|
+
font-family: var(--font-sans);
|
|
77
|
+
font-size: 16px;
|
|
78
|
+
line-height: 1.65;
|
|
79
|
+
color: var(--text-main);
|
|
80
|
+
background-color: var(--bg-page);
|
|
81
|
+
-webkit-font-smoothing: antialiased;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* ---------------- Layout ---------------- */
|
|
85
|
+
.report-wrapper {
|
|
86
|
+
display: flex;
|
|
87
|
+
max-width: 1280px;
|
|
88
|
+
margin: 0 auto;
|
|
89
|
+
padding: 24px 20px;
|
|
90
|
+
gap: 36px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.report-sidebar {
|
|
94
|
+
width: var(--sidebar-w);
|
|
95
|
+
flex-shrink: 0;
|
|
96
|
+
position: sticky;
|
|
97
|
+
top: 24px;
|
|
98
|
+
max-height: calc(100vh - 48px);
|
|
99
|
+
overflow-y: auto;
|
|
100
|
+
background: var(--bg-surface);
|
|
101
|
+
border: 1px solid var(--border-color);
|
|
102
|
+
border-radius: 12px;
|
|
103
|
+
padding: 20px 16px;
|
|
104
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.report-main {
|
|
108
|
+
flex: 1;
|
|
109
|
+
min-width: 0; /* Prevents flex child overflow from wide tables */
|
|
110
|
+
max-width: 900px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* ---------------- Header & Branding ---------------- */
|
|
114
|
+
.report-header-card {
|
|
115
|
+
background: var(--bg-surface);
|
|
116
|
+
border: 1px solid var(--border-color);
|
|
117
|
+
border-radius: 12px;
|
|
118
|
+
padding: 28px 32px;
|
|
119
|
+
margin-bottom: 28px;
|
|
120
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.brand-badge-bar {
|
|
124
|
+
display: flex;
|
|
125
|
+
align-items: center;
|
|
126
|
+
justify-content: space-between;
|
|
127
|
+
margin-bottom: 16px;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.brand-badge {
|
|
131
|
+
display: inline-flex;
|
|
132
|
+
align-items: center;
|
|
133
|
+
gap: 8px;
|
|
134
|
+
background: var(--primary-light);
|
|
135
|
+
border: 1px solid var(--primary-border);
|
|
136
|
+
color: var(--primary);
|
|
137
|
+
font-size: 13px;
|
|
138
|
+
font-weight: 600;
|
|
139
|
+
padding: 4px 10px;
|
|
140
|
+
border-radius: 20px;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.brand-logo-img {
|
|
144
|
+
width: 20px;
|
|
145
|
+
height: 20px;
|
|
146
|
+
border-radius: 5px;
|
|
147
|
+
object-fit: cover;
|
|
148
|
+
flex-shrink: 0;
|
|
149
|
+
border: 1px solid rgba(15, 23, 42, 0.08);
|
|
150
|
+
display: inline-block;
|
|
151
|
+
vertical-align: middle;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.sidebar-logo-img {
|
|
155
|
+
width: 22px;
|
|
156
|
+
height: 22px;
|
|
157
|
+
border-radius: 5px;
|
|
158
|
+
object-fit: cover;
|
|
159
|
+
flex-shrink: 0;
|
|
160
|
+
border: 1px solid rgba(15, 23, 42, 0.08);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.drawer-logo-img {
|
|
164
|
+
width: 22px;
|
|
165
|
+
height: 22px;
|
|
166
|
+
border-radius: 5px;
|
|
167
|
+
object-fit: cover;
|
|
168
|
+
flex-shrink: 0;
|
|
169
|
+
border: 1px solid rgba(15, 23, 42, 0.08);
|
|
170
|
+
vertical-align: middle;
|
|
171
|
+
margin-right: 8px;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.report-title {
|
|
175
|
+
margin: 0 0 16px 0;
|
|
176
|
+
font-size: 2rem;
|
|
177
|
+
font-weight: 700;
|
|
178
|
+
line-height: 1.25;
|
|
179
|
+
color: var(--text-main);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.meta-grid {
|
|
183
|
+
display: grid;
|
|
184
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
185
|
+
gap: 12px;
|
|
186
|
+
margin-top: 16px;
|
|
187
|
+
padding-top: 16px;
|
|
188
|
+
border-top: 1px solid var(--border-subtle);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.meta-item {
|
|
192
|
+
display: flex;
|
|
193
|
+
flex-direction: column;
|
|
194
|
+
font-size: 13px;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.meta-label {
|
|
198
|
+
font-weight: 600;
|
|
199
|
+
text-transform: uppercase;
|
|
200
|
+
letter-spacing: 0.05em;
|
|
201
|
+
font-size: 11px;
|
|
202
|
+
color: var(--text-muted);
|
|
203
|
+
margin-bottom: 2px;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.meta-value {
|
|
207
|
+
color: var(--text-main);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.meta-code {
|
|
211
|
+
font-family: var(--font-mono);
|
|
212
|
+
background: var(--border-subtle);
|
|
213
|
+
padding: 2px 6px;
|
|
214
|
+
border-radius: 4px;
|
|
215
|
+
font-size: 12px;
|
|
216
|
+
display: inline-block;
|
|
217
|
+
width: fit-content;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.meta-scope {
|
|
221
|
+
grid-column: 1 / -1;
|
|
222
|
+
line-height: 1.5;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/* ---------------- Main Content Body ---------------- */
|
|
226
|
+
.markdown-body {
|
|
227
|
+
background: var(--bg-surface);
|
|
228
|
+
border: 1px solid var(--border-color);
|
|
229
|
+
border-radius: 12px;
|
|
230
|
+
padding: 36px 40px;
|
|
231
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.markdown-body h1,
|
|
235
|
+
.markdown-body h2,
|
|
236
|
+
.markdown-body h3,
|
|
237
|
+
.markdown-body h4,
|
|
238
|
+
.markdown-body h5,
|
|
239
|
+
.markdown-body h6 {
|
|
240
|
+
font-weight: 600;
|
|
241
|
+
line-height: 1.3;
|
|
242
|
+
margin-top: 1.8em;
|
|
243
|
+
margin-bottom: 0.6em;
|
|
244
|
+
color: var(--text-main);
|
|
245
|
+
scroll-margin-top: 80px;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.markdown-body h1 {
|
|
249
|
+
font-size: 1.75rem;
|
|
250
|
+
border-bottom: 1px solid var(--border-color);
|
|
251
|
+
padding-bottom: 0.3em;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.markdown-body h2 {
|
|
255
|
+
font-size: 1.4rem;
|
|
256
|
+
border-bottom: 1px solid var(--border-color);
|
|
257
|
+
padding-bottom: 0.3em;
|
|
258
|
+
color: #1e293b;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.markdown-body h3 {
|
|
262
|
+
font-size: 1.15rem;
|
|
263
|
+
color: #334155;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.markdown-body p {
|
|
267
|
+
margin-top: 0;
|
|
268
|
+
margin-bottom: 1.1em;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.markdown-body a {
|
|
272
|
+
color: var(--primary);
|
|
273
|
+
text-decoration: none;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.markdown-body a:hover {
|
|
277
|
+
text-decoration: underline;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.markdown-body ul, .markdown-body ol {
|
|
281
|
+
margin-top: 0;
|
|
282
|
+
margin-bottom: 1.2em;
|
|
283
|
+
padding-left: 1.6em;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.markdown-body li {
|
|
287
|
+
margin-bottom: 0.35em;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.markdown-body hr {
|
|
291
|
+
height: 1px;
|
|
292
|
+
background: var(--border-color);
|
|
293
|
+
border: 0;
|
|
294
|
+
margin: 2.2em 0;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.markdown-body blockquote {
|
|
298
|
+
margin: 1.2em 0;
|
|
299
|
+
padding: 0.6em 1.2em;
|
|
300
|
+
border-left: 4px solid var(--primary-border);
|
|
301
|
+
background: var(--primary-light);
|
|
302
|
+
color: #334155;
|
|
303
|
+
border-radius: 0 8px 8px 0;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/* ---------------- Tables ---------------- */
|
|
307
|
+
.markdown-body table {
|
|
308
|
+
width: 100%;
|
|
309
|
+
border-collapse: collapse;
|
|
310
|
+
margin: 1.4em 0;
|
|
311
|
+
font-size: 14px;
|
|
312
|
+
display: block;
|
|
313
|
+
overflow-x: auto;
|
|
314
|
+
border: 1px solid var(--border-color);
|
|
315
|
+
border-radius: 8px;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.markdown-body th, .markdown-body td {
|
|
319
|
+
padding: 8px 14px;
|
|
320
|
+
border: 1px solid var(--border-color);
|
|
321
|
+
text-align: left;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.markdown-body th {
|
|
325
|
+
background: #f8fafc;
|
|
326
|
+
font-weight: 600;
|
|
327
|
+
color: #475569;
|
|
328
|
+
white-space: nowrap;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.markdown-body tr:nth-child(even) td {
|
|
332
|
+
background: #fbfcfd;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.markdown-body tr:hover td {
|
|
336
|
+
background: #f1f5f9;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/* ---------------- Code ---------------- */
|
|
340
|
+
.markdown-body code {
|
|
341
|
+
font-family: var(--font-mono);
|
|
342
|
+
font-size: 85%;
|
|
343
|
+
background: #f1f5f9;
|
|
344
|
+
padding: 0.2em 0.4em;
|
|
345
|
+
border-radius: 4px;
|
|
346
|
+
color: #0f172a;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.markdown-body pre {
|
|
350
|
+
background: #0f172a;
|
|
351
|
+
color: #f8fafc;
|
|
352
|
+
padding: 16px;
|
|
353
|
+
border-radius: 8px;
|
|
354
|
+
overflow-x: auto;
|
|
355
|
+
margin: 1.2em 0;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.markdown-body pre code {
|
|
359
|
+
background: transparent;
|
|
360
|
+
color: inherit;
|
|
361
|
+
padding: 0;
|
|
362
|
+
font-size: 90%;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/* ---------------- Table of Contents (Sidebar) ---------------- */
|
|
366
|
+
.sidebar-header {
|
|
367
|
+
display: flex;
|
|
368
|
+
align-items: center;
|
|
369
|
+
justify-content: space-between;
|
|
370
|
+
margin-bottom: 14px;
|
|
371
|
+
padding-bottom: 12px;
|
|
372
|
+
border-bottom: 1px solid var(--border-color);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.sidebar-brand {
|
|
376
|
+
display: flex;
|
|
377
|
+
align-items: center;
|
|
378
|
+
gap: 6px;
|
|
379
|
+
font-weight: 700;
|
|
380
|
+
font-size: 14px;
|
|
381
|
+
color: var(--text-main);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.sidebar-badge {
|
|
385
|
+
font-size: 11px;
|
|
386
|
+
color: var(--primary);
|
|
387
|
+
background: var(--primary-light);
|
|
388
|
+
border: 1px solid var(--primary-border);
|
|
389
|
+
padding: 2px 6px;
|
|
390
|
+
border-radius: 10px;
|
|
391
|
+
font-weight: 600;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.toc-title {
|
|
395
|
+
font-size: 12px;
|
|
396
|
+
font-weight: 700;
|
|
397
|
+
text-transform: uppercase;
|
|
398
|
+
letter-spacing: 0.05em;
|
|
399
|
+
color: var(--text-muted);
|
|
400
|
+
margin-bottom: 10px;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.toc-container .toc ul {
|
|
404
|
+
list-style: none;
|
|
405
|
+
padding-left: 0;
|
|
406
|
+
margin: 0;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.toc-container .toc ul ul {
|
|
410
|
+
padding-left: 14px;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.toc-container .toc li {
|
|
414
|
+
margin-bottom: 4px;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.toc-container .toc a {
|
|
418
|
+
display: block;
|
|
419
|
+
font-size: 13px;
|
|
420
|
+
color: var(--text-muted);
|
|
421
|
+
padding: 4px 8px;
|
|
422
|
+
border-radius: 6px;
|
|
423
|
+
line-height: 1.4;
|
|
424
|
+
text-decoration: none;
|
|
425
|
+
transition: all 0.15s ease;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.toc-container .toc a:hover {
|
|
429
|
+
color: var(--primary);
|
|
430
|
+
background: var(--primary-light);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.toc-container .toc a.active {
|
|
434
|
+
color: var(--primary);
|
|
435
|
+
background: var(--primary-light);
|
|
436
|
+
font-weight: 600;
|
|
437
|
+
border-left: 3px solid var(--primary);
|
|
438
|
+
border-radius: 0 6px 6px 0;
|
|
439
|
+
padding-left: 7px;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/* ---------------- Mobile TOC Drawer & Toggle ---------------- */
|
|
443
|
+
.mobile-toc-btn {
|
|
444
|
+
display: none;
|
|
445
|
+
position: fixed;
|
|
446
|
+
bottom: 24px;
|
|
447
|
+
right: 24px;
|
|
448
|
+
z-index: 999;
|
|
449
|
+
align-items: center;
|
|
450
|
+
gap: 8px;
|
|
451
|
+
background: var(--primary);
|
|
452
|
+
color: #ffffff;
|
|
453
|
+
border: none;
|
|
454
|
+
border-radius: 30px;
|
|
455
|
+
padding: 10px 18px;
|
|
456
|
+
font-size: 14px;
|
|
457
|
+
font-weight: 600;
|
|
458
|
+
box-shadow: 0 4px 14px rgba(2, 132, 199, 0.35);
|
|
459
|
+
cursor: pointer;
|
|
460
|
+
transition: transform 0.15s ease;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.mobile-toc-btn:active {
|
|
464
|
+
transform: scale(0.96);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.mobile-toc-backdrop {
|
|
468
|
+
display: none;
|
|
469
|
+
position: fixed;
|
|
470
|
+
inset: 0;
|
|
471
|
+
background: rgba(15, 23, 42, 0.45);
|
|
472
|
+
backdrop-filter: blur(2px);
|
|
473
|
+
z-index: 1000;
|
|
474
|
+
opacity: 0;
|
|
475
|
+
transition: opacity 0.2s ease;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.mobile-toc-drawer {
|
|
479
|
+
position: fixed;
|
|
480
|
+
top: 0;
|
|
481
|
+
right: 0;
|
|
482
|
+
bottom: 0;
|
|
483
|
+
width: 320px;
|
|
484
|
+
max-width: 85vw;
|
|
485
|
+
background: var(--bg-surface);
|
|
486
|
+
z-index: 1001;
|
|
487
|
+
box-shadow: -4px 0 20px rgba(0,0,0,0.15);
|
|
488
|
+
transform: translateX(100%);
|
|
489
|
+
transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
490
|
+
display: flex;
|
|
491
|
+
flex-direction: column;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.mobile-toc-drawer.open {
|
|
495
|
+
transform: translateX(0);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.mobile-toc-backdrop.open {
|
|
499
|
+
display: block;
|
|
500
|
+
opacity: 1;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.drawer-header {
|
|
504
|
+
display: flex;
|
|
505
|
+
align-items: center;
|
|
506
|
+
justify-content: space-between;
|
|
507
|
+
padding: 18px 20px;
|
|
508
|
+
border-bottom: 1px solid var(--border-color);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
.drawer-title {
|
|
512
|
+
font-weight: 700;
|
|
513
|
+
font-size: 16px;
|
|
514
|
+
color: var(--text-main);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
.drawer-close {
|
|
518
|
+
background: transparent;
|
|
519
|
+
border: none;
|
|
520
|
+
font-size: 24px;
|
|
521
|
+
color: var(--text-muted);
|
|
522
|
+
cursor: pointer;
|
|
523
|
+
padding: 4px 8px;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
.drawer-toc {
|
|
527
|
+
flex: 1;
|
|
528
|
+
overflow-y: auto;
|
|
529
|
+
padding: 16px 20px;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
.drawer-toc .toc ul {
|
|
533
|
+
list-style: none;
|
|
534
|
+
padding-left: 0;
|
|
535
|
+
margin: 0;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.drawer-toc .toc ul ul {
|
|
539
|
+
padding-left: 14px;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.drawer-toc .toc li {
|
|
543
|
+
margin-bottom: 6px;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.drawer-toc .toc a {
|
|
547
|
+
display: block;
|
|
548
|
+
font-size: 14px;
|
|
549
|
+
color: var(--text-muted);
|
|
550
|
+
padding: 6px 8px;
|
|
551
|
+
border-radius: 6px;
|
|
552
|
+
text-decoration: none;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.drawer-toc .toc a.active {
|
|
556
|
+
color: var(--primary);
|
|
557
|
+
background: var(--primary-light);
|
|
558
|
+
font-weight: 600;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/* ---------------- Citations & Tooltips ---------------- */
|
|
562
|
+
.cite-ref a {
|
|
563
|
+
scroll-margin-top: 120px;
|
|
564
|
+
outline: none;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.cite-ref a.cite-pulse {
|
|
568
|
+
animation: cite-return-pulse 2s cubic-bezier(0.2, 0, 0, 1) forwards;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
@keyframes cite-return-pulse {
|
|
572
|
+
0% {
|
|
573
|
+
background-color: #fef08a;
|
|
574
|
+
color: #854d0e;
|
|
575
|
+
box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.4), 0 0 12px rgba(245, 158, 11, 0.25);
|
|
576
|
+
border-color: #f59e0b;
|
|
577
|
+
}
|
|
578
|
+
60% {
|
|
579
|
+
background-color: #fef9c3;
|
|
580
|
+
box-shadow: 0 0 0 6px rgba(245, 158, 11, 0.15);
|
|
581
|
+
}
|
|
582
|
+
100% {
|
|
583
|
+
background-color: var(--primary-light);
|
|
584
|
+
color: var(--primary);
|
|
585
|
+
box-shadow: none;
|
|
586
|
+
border-color: var(--primary-border);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.cite-caller-block-highlight {
|
|
591
|
+
animation: cite-block-glow 1.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
@keyframes cite-block-glow {
|
|
595
|
+
0% {
|
|
596
|
+
background-color: rgba(254, 240, 138, 0.4);
|
|
597
|
+
box-shadow: 0 0 0 8px rgba(254, 240, 138, 0.4);
|
|
598
|
+
border-radius: 6px;
|
|
599
|
+
}
|
|
600
|
+
60% {
|
|
601
|
+
background-color: rgba(254, 240, 138, 0.15);
|
|
602
|
+
box-shadow: 0 0 0 8px rgba(254, 240, 138, 0.15);
|
|
603
|
+
}
|
|
604
|
+
100% {
|
|
605
|
+
background-color: transparent;
|
|
606
|
+
box-shadow: 0 0 0 0 transparent;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
@media (prefers-reduced-motion: reduce) {
|
|
611
|
+
html { scroll-behavior: auto !important; }
|
|
612
|
+
.cite-ref a.cite-pulse {
|
|
613
|
+
animation: none;
|
|
614
|
+
background-color: #fef08a;
|
|
615
|
+
transition: background-color 1s ease;
|
|
616
|
+
}
|
|
617
|
+
.cite-caller-block-highlight {
|
|
618
|
+
animation: none;
|
|
619
|
+
background-color: transparent;
|
|
620
|
+
}
|
|
621
|
+
.cite-return-chip {
|
|
622
|
+
transition: none;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/* ---------------- Floating Return Chip ---------------- */
|
|
627
|
+
.cite-return-chip {
|
|
628
|
+
position: fixed;
|
|
629
|
+
bottom: 28px;
|
|
630
|
+
left: 50%;
|
|
631
|
+
transform: translateX(-50%) translateY(100px);
|
|
632
|
+
z-index: 998;
|
|
633
|
+
display: flex;
|
|
634
|
+
align-items: center;
|
|
635
|
+
background: #0f172a;
|
|
636
|
+
color: #f8fafc;
|
|
637
|
+
padding: 4px 6px 4px 14px;
|
|
638
|
+
border-radius: 30px;
|
|
639
|
+
box-shadow: 0 10px 25px -5px rgba(15, 23, 42, 0.3), 0 8px 10px -6px rgba(15, 23, 42, 0.3);
|
|
640
|
+
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
641
|
+
opacity: 0;
|
|
642
|
+
pointer-events: none;
|
|
643
|
+
transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.2s ease;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
.cite-return-chip.visible {
|
|
647
|
+
transform: translateX(-50%) translateY(0);
|
|
648
|
+
opacity: 1;
|
|
649
|
+
pointer-events: auto;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
.cite-return-btn {
|
|
653
|
+
background: transparent;
|
|
654
|
+
border: none;
|
|
655
|
+
color: #ffffff;
|
|
656
|
+
font-family: var(--font-sans);
|
|
657
|
+
font-size: 13px;
|
|
658
|
+
font-weight: 600;
|
|
659
|
+
display: flex;
|
|
660
|
+
align-items: center;
|
|
661
|
+
gap: 8px;
|
|
662
|
+
cursor: pointer;
|
|
663
|
+
padding: 6px 4px;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
.cite-return-btn:hover .return-text {
|
|
667
|
+
text-decoration: underline;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
.return-arrow {
|
|
671
|
+
font-size: 14px;
|
|
672
|
+
color: #38bdf8;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
.return-badge {
|
|
676
|
+
font-family: var(--font-mono);
|
|
677
|
+
color: #38bdf8;
|
|
678
|
+
font-size: 12px;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
.cite-return-dismiss {
|
|
682
|
+
background: transparent;
|
|
683
|
+
border: none;
|
|
684
|
+
color: #94a3b8;
|
|
685
|
+
font-size: 18px;
|
|
686
|
+
line-height: 1;
|
|
687
|
+
cursor: pointer;
|
|
688
|
+
padding: 6px 10px;
|
|
689
|
+
margin-left: 4px;
|
|
690
|
+
border-radius: 50%;
|
|
691
|
+
display: flex;
|
|
692
|
+
align-items: center;
|
|
693
|
+
justify-content: center;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.cite-return-dismiss:hover {
|
|
697
|
+
color: #ffffff;
|
|
698
|
+
background: rgba(255, 255, 255, 0.1);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.ref-backlink, .ref-backlinks {
|
|
702
|
+
font-family: var(--font-sans);
|
|
703
|
+
font-size: 12px;
|
|
704
|
+
margin-left: 8px;
|
|
705
|
+
display: inline-flex;
|
|
706
|
+
align-items: center;
|
|
707
|
+
flex-wrap: wrap;
|
|
708
|
+
gap: 4px;
|
|
709
|
+
vertical-align: middle;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.ref-occ-prefix {
|
|
713
|
+
color: var(--text-light);
|
|
714
|
+
font-size: 13px;
|
|
715
|
+
margin-right: 2px;
|
|
716
|
+
user-select: none;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
.ref-occ-others {
|
|
720
|
+
display: inline-flex;
|
|
721
|
+
align-items: center;
|
|
722
|
+
flex-wrap: wrap;
|
|
723
|
+
gap: 4px;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
.ref-occ-pill {
|
|
727
|
+
display: inline-flex;
|
|
728
|
+
align-items: center;
|
|
729
|
+
justify-content: center;
|
|
730
|
+
gap: 4px;
|
|
731
|
+
min-width: 24px;
|
|
732
|
+
height: 24px;
|
|
733
|
+
padding: 0 6px;
|
|
734
|
+
background: var(--primary-light);
|
|
735
|
+
border: 1px solid var(--primary-border);
|
|
736
|
+
border-radius: 6px;
|
|
737
|
+
font-size: 11px;
|
|
738
|
+
font-weight: 500;
|
|
739
|
+
color: var(--primary);
|
|
740
|
+
text-decoration: none;
|
|
741
|
+
position: relative;
|
|
742
|
+
transition: all 0.15s ease;
|
|
743
|
+
vertical-align: middle;
|
|
744
|
+
outline: none;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
.ref-occ-pill:hover {
|
|
748
|
+
background: #e0f2fe;
|
|
749
|
+
border-color: #7dd3fc;
|
|
750
|
+
color: var(--primary-hover);
|
|
751
|
+
text-decoration: none;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
.ref-occ-pill:focus-visible {
|
|
755
|
+
box-shadow: 0 0 0 2px var(--primary);
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/* Touch target expansion (44x44px minimum for mobile compliance) */
|
|
759
|
+
.ref-occ-pill::before {
|
|
760
|
+
content: '';
|
|
761
|
+
position: absolute;
|
|
762
|
+
top: 50%;
|
|
763
|
+
left: 50%;
|
|
764
|
+
transform: translate(-50%, -50%);
|
|
765
|
+
min-width: 44px;
|
|
766
|
+
min-height: 44px;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/* Active Origin Pill (One-Click Return to calling text) */
|
|
770
|
+
.ref-occ-pill.ref-occ-active {
|
|
771
|
+
background: var(--primary);
|
|
772
|
+
color: #ffffff;
|
|
773
|
+
border-color: var(--primary-hover);
|
|
774
|
+
font-weight: 600;
|
|
775
|
+
padding: 0 8px;
|
|
776
|
+
box-shadow: 0 1px 4px rgba(2, 132, 199, 0.35);
|
|
777
|
+
animation: occ-active-bounce 0.4s cubic-bezier(0.16, 1, 0.3, 1);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
@keyframes occ-active-bounce {
|
|
781
|
+
0% { transform: scale(0.92); }
|
|
782
|
+
60% { transform: scale(1.04); }
|
|
783
|
+
100% { transform: scale(1); }
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.ref-occ-pill.ref-occ-active:hover {
|
|
787
|
+
background: var(--primary-hover);
|
|
788
|
+
color: #ffffff;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
.ref-occ-pill.ref-occ-active .pill-arrow {
|
|
792
|
+
font-size: 12px;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
.ref-occ-pill.ref-occ-active .pill-sec {
|
|
796
|
+
max-width: 150px;
|
|
797
|
+
overflow: hidden;
|
|
798
|
+
text-overflow: ellipsis;
|
|
799
|
+
white-space: nowrap;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
.ref-occ-pill.ref-occ-active .pill-occ {
|
|
803
|
+
opacity: 0.85;
|
|
804
|
+
font-size: 10px;
|
|
805
|
+
font-weight: normal;
|
|
806
|
+
}
|
|
807
|
+
.cite-ref {
|
|
808
|
+
font-size: 0.75em;
|
|
809
|
+
line-height: 0;
|
|
810
|
+
vertical-align: super;
|
|
811
|
+
margin: 0 1.5px;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
.cite-ref a {
|
|
815
|
+
display: inline-flex;
|
|
816
|
+
align-items: center;
|
|
817
|
+
justify-content: center;
|
|
818
|
+
min-width: 1.35em;
|
|
819
|
+
height: 1.35em;
|
|
820
|
+
padding: 0 4px;
|
|
821
|
+
background: var(--primary-light);
|
|
822
|
+
color: var(--primary);
|
|
823
|
+
border: 1px solid var(--primary-border);
|
|
824
|
+
border-radius: 4px;
|
|
825
|
+
font-weight: 600;
|
|
826
|
+
font-family: var(--font-mono);
|
|
827
|
+
font-size: 0.85em;
|
|
828
|
+
text-decoration: none;
|
|
829
|
+
cursor: pointer;
|
|
830
|
+
transition: all 0.15s ease;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
.cite-ref a:hover {
|
|
834
|
+
background: var(--primary);
|
|
835
|
+
color: #ffffff;
|
|
836
|
+
border-color: var(--primary);
|
|
837
|
+
box-shadow: 0 2px 4px rgba(2, 132, 199, 0.25);
|
|
838
|
+
text-decoration: none;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
.cite-tooltip {
|
|
842
|
+
position: absolute;
|
|
843
|
+
z-index: 9999;
|
|
844
|
+
max-width: 440px;
|
|
845
|
+
min-width: 260px;
|
|
846
|
+
width: max-content;
|
|
847
|
+
padding: 12px 16px;
|
|
848
|
+
background: var(--bg-surface);
|
|
849
|
+
border: 1px solid var(--border-color);
|
|
850
|
+
border-radius: 8px;
|
|
851
|
+
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
|
|
852
|
+
font-size: 13px;
|
|
853
|
+
line-height: 1.5;
|
|
854
|
+
color: var(--text-main);
|
|
855
|
+
display: none;
|
|
856
|
+
opacity: 0;
|
|
857
|
+
pointer-events: none;
|
|
858
|
+
transition: opacity 0.15s ease;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
.cite-tooltip.visible {
|
|
862
|
+
display: block;
|
|
863
|
+
pointer-events: auto;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
.cite-tooltip.fade-in {
|
|
867
|
+
opacity: 1;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
.cite-tooltip.fade-out {
|
|
871
|
+
opacity: 0;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
.cite-header {
|
|
875
|
+
display: flex;
|
|
876
|
+
align-items: center;
|
|
877
|
+
justify-content: space-between;
|
|
878
|
+
margin-bottom: 6px;
|
|
879
|
+
gap: 8px;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
.cite-tooltip .cite-label {
|
|
883
|
+
font-size: 11px;
|
|
884
|
+
font-weight: 700;
|
|
885
|
+
color: var(--text-muted);
|
|
886
|
+
text-transform: uppercase;
|
|
887
|
+
letter-spacing: 0.05em;
|
|
888
|
+
margin-bottom: 0;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
.cite-jump-link {
|
|
892
|
+
font-size: 11px;
|
|
893
|
+
color: var(--primary);
|
|
894
|
+
text-decoration: none;
|
|
895
|
+
font-weight: 500;
|
|
896
|
+
white-space: nowrap;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
.cite-jump-link:hover {
|
|
900
|
+
text-decoration: underline;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
.cite-tail {
|
|
904
|
+
position: absolute;
|
|
905
|
+
top: -6px;
|
|
906
|
+
left: 50%;
|
|
907
|
+
transform: translateX(-50%);
|
|
908
|
+
width: 0;
|
|
909
|
+
height: 0;
|
|
910
|
+
border-left: 6px solid transparent;
|
|
911
|
+
border-right: 6px solid transparent;
|
|
912
|
+
border-bottom: 6px solid var(--border-color);
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
.cite-tail::after {
|
|
916
|
+
content: '';
|
|
917
|
+
position: absolute;
|
|
918
|
+
top: 1px;
|
|
919
|
+
left: -5px;
|
|
920
|
+
width: 0;
|
|
921
|
+
height: 0;
|
|
922
|
+
border-left: 5px solid transparent;
|
|
923
|
+
border-right: 5px solid transparent;
|
|
924
|
+
border-bottom: 5px solid var(--bg-surface);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
.cite-tail.flip {
|
|
928
|
+
top: auto;
|
|
929
|
+
bottom: -6px;
|
|
930
|
+
border-bottom: none;
|
|
931
|
+
border-top: 6px solid var(--border-color);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
.cite-tail.flip::after {
|
|
935
|
+
top: auto;
|
|
936
|
+
bottom: 1px;
|
|
937
|
+
border-bottom: none;
|
|
938
|
+
border-top: 5px solid var(--bg-surface);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
.cite-tooltip a.ref-link {
|
|
942
|
+
color: var(--primary);
|
|
943
|
+
text-decoration: none;
|
|
944
|
+
font-weight: 500;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
.cite-tooltip a.ref-link:hover {
|
|
948
|
+
text-decoration: underline;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
/* ---------------- Bibliography / References Section ---------------- */
|
|
952
|
+
.references-container {
|
|
953
|
+
margin-top: 1.2em;
|
|
954
|
+
display: flex;
|
|
955
|
+
flex-direction: column;
|
|
956
|
+
gap: 12px;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
.ref-item {
|
|
960
|
+
display: flex;
|
|
961
|
+
align-items: flex-start;
|
|
962
|
+
gap: 10px;
|
|
963
|
+
font-size: 14px;
|
|
964
|
+
line-height: 1.55;
|
|
965
|
+
padding: 10px 14px;
|
|
966
|
+
border-radius: 8px;
|
|
967
|
+
background: #fbfcfd;
|
|
968
|
+
border: 1px solid var(--border-subtle);
|
|
969
|
+
scroll-margin-top: 80px;
|
|
970
|
+
transition: background-color 0.3s ease;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
.ref-item:hover {
|
|
974
|
+
border-color: var(--border-color);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
.ref-item:target {
|
|
978
|
+
animation: ref-target-pulse 2.2s ease-out;
|
|
979
|
+
border-color: var(--primary-border);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
@keyframes ref-target-pulse {
|
|
983
|
+
0% { background-color: #fef08a; }
|
|
984
|
+
60% { background-color: #fef9c3; }
|
|
985
|
+
100% { background-color: #fbfcfd; }
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
.ref-num {
|
|
989
|
+
font-family: var(--font-mono);
|
|
990
|
+
font-weight: 600;
|
|
991
|
+
color: var(--primary);
|
|
992
|
+
font-size: 13px;
|
|
993
|
+
flex-shrink: 0;
|
|
994
|
+
padding-top: 1px;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
.ref-body {
|
|
998
|
+
flex: 1;
|
|
999
|
+
color: #334155;
|
|
1000
|
+
word-break: break-word;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/* ---------------- Responsive Styles ---------------- */
|
|
1004
|
+
@media (max-width: 1024px) {
|
|
1005
|
+
.report-sidebar {
|
|
1006
|
+
display: none;
|
|
1007
|
+
}
|
|
1008
|
+
.report-wrapper {
|
|
1009
|
+
padding: 16px;
|
|
1010
|
+
}
|
|
1011
|
+
.report-header-card, .markdown-body {
|
|
1012
|
+
padding: 24px 20px;
|
|
1013
|
+
}
|
|
1014
|
+
.mobile-toc-btn {
|
|
1015
|
+
display: inline-flex;
|
|
1016
|
+
}
|
|
1017
|
+
.cite-return-chip {
|
|
1018
|
+
left: auto;
|
|
1019
|
+
transform: translateY(100px);
|
|
1020
|
+
right: 20px;
|
|
1021
|
+
bottom: calc(76px + env(safe-area-inset-bottom, 0px));
|
|
1022
|
+
max-width: calc(100vw - 40px);
|
|
1023
|
+
}
|
|
1024
|
+
.cite-return-chip.visible {
|
|
1025
|
+
transform: translateY(0);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
@media (max-width: 640px) {
|
|
1030
|
+
.report-title {
|
|
1031
|
+
font-size: 1.5rem;
|
|
1032
|
+
}
|
|
1033
|
+
.meta-grid {
|
|
1034
|
+
grid-template-columns: 1fr;
|
|
1035
|
+
}
|
|
1036
|
+
.cite-tooltip {
|
|
1037
|
+
max-width: calc(100vw - 32px);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/* ---------------- Print Styles ---------------- */
|
|
1042
|
+
@media print {
|
|
1043
|
+
@page { margin: 1.5cm; }
|
|
1044
|
+
body {
|
|
1045
|
+
background: #ffffff !important;
|
|
1046
|
+
color: #000000 !important;
|
|
1047
|
+
font-size: 11pt;
|
|
1048
|
+
}
|
|
1049
|
+
.report-sidebar,
|
|
1050
|
+
.mobile-toc-btn,
|
|
1051
|
+
.mobile-toc-backdrop,
|
|
1052
|
+
.mobile-toc-drawer,
|
|
1053
|
+
#cite-tooltip,
|
|
1054
|
+
#cite-return-chip,
|
|
1055
|
+
.ref-backlink,
|
|
1056
|
+
.ref-backlinks,
|
|
1057
|
+
.ref-occ-pill {
|
|
1058
|
+
display: none !important;
|
|
1059
|
+
}
|
|
1060
|
+
.report-wrapper {
|
|
1061
|
+
max-width: 100% !important;
|
|
1062
|
+
padding: 0 !important;
|
|
1063
|
+
}
|
|
1064
|
+
.report-header-card, .markdown-body {
|
|
1065
|
+
border: none !important;
|
|
1066
|
+
box-shadow: none !important;
|
|
1067
|
+
padding: 0 !important;
|
|
1068
|
+
margin-bottom: 24px !important;
|
|
1069
|
+
}
|
|
1070
|
+
a {
|
|
1071
|
+
color: #000000 !important;
|
|
1072
|
+
text-decoration: underline !important;
|
|
1073
|
+
}
|
|
1074
|
+
.ref-item {
|
|
1075
|
+
background: transparent !important;
|
|
1076
|
+
border: none !important;
|
|
1077
|
+
padding: 4px 0 !important;
|
|
1078
|
+
break-inside: avoid;
|
|
1079
|
+
page-break-inside: avoid;
|
|
1080
|
+
}
|
|
1081
|
+
table, pre, blockquote {
|
|
1082
|
+
break-inside: avoid;
|
|
1083
|
+
page-break-inside: avoid;
|
|
1084
|
+
}
|
|
1085
|
+
h1, h2, h3 {
|
|
1086
|
+
break-after: avoid;
|
|
1087
|
+
page-break-after: avoid;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
""".strip()
|
|
1091
|
+
|
|
1092
|
+
SVG_DNA_ICON = """<svg class="brand-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M4.5 3a1.5 1.5 0 0 0-1.5 1.5v.38c0 .4.16.78.44 1.06L7.38 10l-3.94 4.06a1.5 1.5 0 0 0-.44 1.06v.38a1.5 1.5 0 0 0 1.5 1.5h.38c.4 0 .78-.16 1.06-.44L10 12.62l3.94 4.06c.28.28.66.44 1.06.44h.38a1.5 1.5 0 0 0 1.5-1.5v-.38c0-.4-.16-.78-.44-1.06L12.5 10l4.06-3.94c.28-.28.44-.66.44-1.06V4.5A1.5 1.5 0 0 0 15.5 3h-.38c-.4 0-.78.16-1.06.44L10 7.38 6.06 3.44A1.5 1.5 0 0 0 5.02 3H4.5zM12 2a1 1 0 0 1 1 1v1.17l2.29-2.29A2.5 2.5 0 0 1 17.06 1H18.5A2.5 2.5 0 0 1 21 3.5v1.44c0 .66-.26 1.3-.73 1.77L16.41 10l3.86 3.86c.47.47.73 1.11.73 1.77v1.87a2.5 2.5 0 0 1-2.5 2.5h-1.44a2.5 2.5 0 0 1-1.77-.73L13 16.9V21a1 1 0 1 1-2 0v-4.1l-2.29 2.37a2.5 2.5 0 0 1-1.77.73H5.5A2.5 2.5 0 0 1 3 17.5v-1.87c0-.66.26-1.3.73-1.77L7.59 10 3.73 6.14A2.5 2.5 0 0 1 3 4.37V2.5A2.5 2.5 0 0 1 5.5 0h1.44c.66 0 1.3.26 1.77.73L11 3.03V2a1 1 0 0 1 1-1z"/></svg>"""
|
|
1093
|
+
SVG_LIST_ICON = """<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="21" y2="6"></line><line x1="8" y1="12" x2="21" y2="12"></line><line x1="8" y1="18" x2="21" y2="18"></line><line x1="3" y1="6" x2="3.01" y2="6"></line><line x1="3" y1="12" x2="3.01" y2="12"></line><line x1="3" y1="18" x2="3.01" y2="18"></line></svg>"""
|
|
1094
|
+
|
|
1095
|
+
CLIENT_SCRIPT = r"""
|
|
1096
|
+
(function() {
|
|
1097
|
+
var contentEl = document.getElementById('content');
|
|
1098
|
+
if (!contentEl) return;
|
|
1099
|
+
|
|
1100
|
+
function esc(s) {
|
|
1101
|
+
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
function formatReferenceHtml(str) {
|
|
1105
|
+
var placeholders = [];
|
|
1106
|
+
function pushPh(h) { var idx = placeholders.length; placeholders.push(h); return '%%%PH_' + idx + '%%%'; }
|
|
1107
|
+
|
|
1108
|
+
// 1. DOIs
|
|
1109
|
+
var s = str.replace(/\bdoi:\s*(10\.\d{4,9}\/[^\s;,]+)/gi, function(_, doi) {
|
|
1110
|
+
var cleanDoi = doi.replace(/[.,;:!?)\]]+$/, '');
|
|
1111
|
+
return pushPh('<a class="ref-link" href="https://doi.org/' + esc(cleanDoi) + '" target="_blank" rel="noopener noreferrer">doi:' + esc(cleanDoi) + '</a>');
|
|
1112
|
+
});
|
|
1113
|
+
|
|
1114
|
+
// 2. PMIDs
|
|
1115
|
+
s = s.replace(/\bPMID:\s*(\d+)/gi, function(_, id) {
|
|
1116
|
+
return pushPh('<a class="ref-link" href="https://pubmed.ncbi.nlm.nih.gov/' + id + '/" target="_blank" rel="noopener noreferrer">PMID: ' + id + '</a>');
|
|
1117
|
+
});
|
|
1118
|
+
|
|
1119
|
+
// 3. ClinicalTrials.gov NCT IDs
|
|
1120
|
+
s = s.replace(/\b(NCT\d{8})\b/gi, function(_, nct) {
|
|
1121
|
+
return pushPh('<a class="ref-link" href="https://clinicaltrials.gov/study/' + nct + '" target="_blank" rel="noopener noreferrer">' + nct + '</a>');
|
|
1122
|
+
});
|
|
1123
|
+
|
|
1124
|
+
// 4. URLs
|
|
1125
|
+
s = s.replace(/(https?:\/\/[^\s<>"]+)/g, function(url) {
|
|
1126
|
+
var cleanUrl = url.replace(/[.,;:!?)\]]+$/, '');
|
|
1127
|
+
var trailing = url.slice(cleanUrl.length);
|
|
1128
|
+
return pushPh('<a class="ref-link" href="' + esc(cleanUrl) + '" target="_blank" rel="noopener noreferrer">' + esc(cleanUrl) + '</a>') + esc(trailing);
|
|
1129
|
+
});
|
|
1130
|
+
|
|
1131
|
+
s = esc(s).replace(/%%%PH_(\d+)%%%/g, function(_, idx) {
|
|
1132
|
+
return placeholders[parseInt(idx, 10)];
|
|
1133
|
+
});
|
|
1134
|
+
return s;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// ---- 1. Process Bibliography ----
|
|
1138
|
+
var headings = contentEl.querySelectorAll('h1, h2, h3, h4, h5, h6');
|
|
1139
|
+
var refHeading = null;
|
|
1140
|
+
for (var i = 0; i < headings.length; i++) {
|
|
1141
|
+
if (/^(?:\d+[\.\s]+)?(?:references?|bibliography|literature cited|citations|参考文献)[\s:]*$/i.test(headings[i].textContent.trim())) {
|
|
1142
|
+
refHeading = headings[i];
|
|
1143
|
+
break;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
var refsMap = new Map();
|
|
1148
|
+
var refElements = [];
|
|
1149
|
+
|
|
1150
|
+
if (refHeading) {
|
|
1151
|
+
var refLevel = parseInt(refHeading.tagName.charAt(1), 10);
|
|
1152
|
+
var next = refHeading.nextElementSibling;
|
|
1153
|
+
while (next) {
|
|
1154
|
+
if (/^H[1-6]$/i.test(next.tagName)) {
|
|
1155
|
+
if (parseInt(next.tagName.charAt(1), 10) <= refLevel) break;
|
|
1156
|
+
}
|
|
1157
|
+
refElements.push(next);
|
|
1158
|
+
next = next.nextElementSibling;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
var rawEntries = [];
|
|
1162
|
+
refElements.forEach(function(el) {
|
|
1163
|
+
if (el.tagName === 'OL' || el.tagName === 'UL') {
|
|
1164
|
+
el.querySelectorAll('li').forEach(function(li, idx) {
|
|
1165
|
+
var text = li.textContent.trim();
|
|
1166
|
+
var m = text.match(/^\[(\d+)\]\s*([\s\S]*)/);
|
|
1167
|
+
if (m) {
|
|
1168
|
+
rawEntries.push({ num: parseInt(m[1], 10), body: m[2].trim() });
|
|
1169
|
+
} else {
|
|
1170
|
+
rawEntries.push({ num: idx + 1, body: text });
|
|
1171
|
+
}
|
|
1172
|
+
});
|
|
1173
|
+
} else {
|
|
1174
|
+
var text = el.textContent;
|
|
1175
|
+
var regex = /(?:^|\n)\s*\[(\d+)\]\s*([\s\S]*?)(?=(?:\n\s*\[\d+\]|$))/g;
|
|
1176
|
+
var match, found = false;
|
|
1177
|
+
while ((match = regex.exec(text)) !== null) {
|
|
1178
|
+
found = true;
|
|
1179
|
+
rawEntries.push({ num: parseInt(match[1], 10), body: match[2].trim() });
|
|
1180
|
+
}
|
|
1181
|
+
if (!found && text.trim()) {
|
|
1182
|
+
var m = text.trim().match(/^\[(\d+)\]\s*([\s\S]*)/);
|
|
1183
|
+
if (m) rawEntries.push({ num: parseInt(m[1], 10), body: m[2].trim() });
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
});
|
|
1187
|
+
|
|
1188
|
+
if (rawEntries.length > 0) {
|
|
1189
|
+
var container = document.createElement('div');
|
|
1190
|
+
container.className = 'references-container';
|
|
1191
|
+
rawEntries.forEach(function(item) {
|
|
1192
|
+
refsMap.set(item.num, item.body);
|
|
1193
|
+
var div = document.createElement('div');
|
|
1194
|
+
div.className = 'ref-item';
|
|
1195
|
+
div.id = 'ref-' + item.num;
|
|
1196
|
+
div.innerHTML = '<span class="ref-num">[' + item.num + ']</span><div class="ref-body">' + formatReferenceHtml(item.body) + '</div>';
|
|
1197
|
+
container.appendChild(div);
|
|
1198
|
+
});
|
|
1199
|
+
refElements[0].parentNode.insertBefore(container, refElements[0]);
|
|
1200
|
+
refElements.forEach(function(e) { e.remove(); });
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// ---- 2. In-Text Citation Replacement & Caller Identity Tracking ----
|
|
1205
|
+
var forbidden = new Set(['CODE', 'PRE', 'A', 'SCRIPT', 'STYLE', 'TEXTAREA', 'NAV', 'BUTTON']);
|
|
1206
|
+
function isForbidden(n) {
|
|
1207
|
+
var p = n.parentElement;
|
|
1208
|
+
while (p && p !== contentEl) {
|
|
1209
|
+
if (forbidden.has(p.tagName) || (p.classList && p.classList.contains('references-container'))) return true;
|
|
1210
|
+
p = p.parentElement;
|
|
1211
|
+
}
|
|
1212
|
+
return false;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
var walker = document.createTreeWalker(contentEl, NodeFilter.SHOW_TEXT);
|
|
1216
|
+
var textNodes = [];
|
|
1217
|
+
while (walker.nextNode()) {
|
|
1218
|
+
if (!isForbidden(walker.currentNode)) {
|
|
1219
|
+
textNodes.push(walker.currentNode);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
var citeRegex = /\[(\d+(?:\s*[-–—]\s*\d+)?(?:\s*[,,]\s*\d+(?:\s*[-–—]\s*\d+)?)*)\]/g;
|
|
1224
|
+
var refCallMap = new Map();
|
|
1225
|
+
|
|
1226
|
+
textNodes.forEach(function(node) {
|
|
1227
|
+
var text = node.textContent;
|
|
1228
|
+
if (!citeRegex.test(text)) return;
|
|
1229
|
+
citeRegex.lastIndex = 0;
|
|
1230
|
+
|
|
1231
|
+
var frag = document.createDocumentFragment();
|
|
1232
|
+
var lastIdx = 0, m;
|
|
1233
|
+
|
|
1234
|
+
while ((m = citeRegex.exec(text)) !== null) {
|
|
1235
|
+
var nums = [];
|
|
1236
|
+
m[1].split(/[,,]/).forEach(function(part) {
|
|
1237
|
+
part = part.trim();
|
|
1238
|
+
var rm = part.match(/^(\d+)\s*[-–—]\s*(\d+)$/);
|
|
1239
|
+
if (rm) {
|
|
1240
|
+
var start = parseInt(rm[1], 10);
|
|
1241
|
+
var end = parseInt(rm[2], 10);
|
|
1242
|
+
for (var k = start; k <= end; k++) nums.push(k);
|
|
1243
|
+
} else {
|
|
1244
|
+
var single = parseInt(part, 10);
|
|
1245
|
+
if (!isNaN(single)) nums.push(single);
|
|
1246
|
+
}
|
|
1247
|
+
});
|
|
1248
|
+
|
|
1249
|
+
if (refsMap.size > 0 && !nums.some(function(n) { return refsMap.has(n); })) {
|
|
1250
|
+
continue;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
if (m.index > lastIdx) {
|
|
1254
|
+
frag.appendChild(document.createTextNode(text.slice(lastIdx, m.index)));
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
var sup = document.createElement('sup');
|
|
1258
|
+
sup.className = 'cite-ref';
|
|
1259
|
+
nums.forEach(function(num, idx) {
|
|
1260
|
+
if (idx > 0) sup.appendChild(document.createTextNode(', '));
|
|
1261
|
+
var a = document.createElement('a');
|
|
1262
|
+
a.textContent = num;
|
|
1263
|
+
|
|
1264
|
+
var existingCalls = refCallMap.get(num) || [];
|
|
1265
|
+
var callId = 'cite-call-' + num + '-' + (existingCalls.length + 1);
|
|
1266
|
+
existingCalls.push(callId);
|
|
1267
|
+
refCallMap.set(num, existingCalls);
|
|
1268
|
+
|
|
1269
|
+
a.id = callId;
|
|
1270
|
+
a.setAttribute('data-call-id', callId);
|
|
1271
|
+
a.setAttribute('data-ref', num);
|
|
1272
|
+
a.href = '#ref-' + num;
|
|
1273
|
+
sup.appendChild(a);
|
|
1274
|
+
});
|
|
1275
|
+
frag.appendChild(sup);
|
|
1276
|
+
lastIdx = citeRegex.lastIndex;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
if (lastIdx === 0) return;
|
|
1280
|
+
|
|
1281
|
+
if (lastIdx < text.length) {
|
|
1282
|
+
frag.appendChild(document.createTextNode(text.slice(lastIdx)));
|
|
1283
|
+
}
|
|
1284
|
+
node.parentNode.replaceChild(frag, node);
|
|
1285
|
+
});
|
|
1286
|
+
|
|
1287
|
+
// ---- 3. Single-Pass Document Indexer: Map Citations to Headings & Excerpts ----
|
|
1288
|
+
var callMetaMap = new Map();
|
|
1289
|
+
var headings = Array.from(contentEl.querySelectorAll('h1, h2, h3, h4, h5, h6'));
|
|
1290
|
+
var mainHeadings = headings.filter(function(h) {
|
|
1291
|
+
return !h.closest('.references-container') && h !== refHeading;
|
|
1292
|
+
});
|
|
1293
|
+
var allCiteLinks = Array.from(contentEl.querySelectorAll('.cite-ref a'));
|
|
1294
|
+
|
|
1295
|
+
function extractSentenceSnippet(blockEl, targetLink) {
|
|
1296
|
+
if (!blockEl) return '';
|
|
1297
|
+
var fullText = blockEl.textContent.replace(/\s+/g, ' ').trim();
|
|
1298
|
+
var linkText = targetLink.textContent.trim();
|
|
1299
|
+
var linkIdx = fullText.indexOf('[' + linkText + ']');
|
|
1300
|
+
if (linkIdx === -1) linkIdx = fullText.indexOf(linkText);
|
|
1301
|
+
if (linkIdx === -1) return fullText.slice(0, 80) + '...';
|
|
1302
|
+
var start = Math.max(0, linkIdx - 40);
|
|
1303
|
+
var end = Math.min(fullText.length, linkIdx + 40);
|
|
1304
|
+
var snippet = fullText.slice(start, end).trim();
|
|
1305
|
+
if (start > 0) snippet = '…' + snippet;
|
|
1306
|
+
if (end < fullText.length) snippet = snippet + '…';
|
|
1307
|
+
return snippet;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
var hIdx = 0;
|
|
1311
|
+
var currentHeading = { id: '', text: 'Overview', cleanText: 'Overview', shortSec: 'Overview' };
|
|
1312
|
+
|
|
1313
|
+
allCiteLinks.forEach(function(link) {
|
|
1314
|
+
while (hIdx < mainHeadings.length &&
|
|
1315
|
+
(mainHeadings[hIdx].compareDocumentPosition(link) & Node.DOCUMENT_POSITION_FOLLOWING)) {
|
|
1316
|
+
var rawTitle = mainHeadings[hIdx].textContent.trim();
|
|
1317
|
+
var cleanTitle = rawTitle.replace(/^[#\d\.\s]+/, '') || rawTitle || 'Section';
|
|
1318
|
+
var numMatch = rawTitle.match(/^(\d+(?:\.\d+)*)/);
|
|
1319
|
+
var shortSec = numMatch ? ('§' + numMatch[1]) : (cleanTitle.length > 16 ? cleanTitle.slice(0, 14) + '…' : cleanTitle);
|
|
1320
|
+
currentHeading = {
|
|
1321
|
+
id: mainHeadings[hIdx].id,
|
|
1322
|
+
text: rawTitle,
|
|
1323
|
+
cleanText: cleanTitle,
|
|
1324
|
+
shortSec: shortSec
|
|
1325
|
+
};
|
|
1326
|
+
hIdx++;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
var block = link.closest('p, li, td, th, blockquote') || link.parentElement;
|
|
1330
|
+
var snippet = extractSentenceSnippet(block, link);
|
|
1331
|
+
|
|
1332
|
+
callMetaMap.set(link.id, {
|
|
1333
|
+
callId: link.id,
|
|
1334
|
+
refNum: parseInt(link.getAttribute('data-ref'), 10),
|
|
1335
|
+
headingId: currentHeading.id,
|
|
1336
|
+
headingText: currentHeading.text,
|
|
1337
|
+
shortSec: currentHeading.shortSec,
|
|
1338
|
+
snippet: snippet
|
|
1339
|
+
});
|
|
1340
|
+
});
|
|
1341
|
+
|
|
1342
|
+
// ---- 4. Intelligent In-Situ Reference Backlinks with Unified Active Origin Pill ----
|
|
1343
|
+
function renderReferenceBacklinks(num, activeCallId) {
|
|
1344
|
+
var item = document.getElementById('ref-' + num);
|
|
1345
|
+
if (!item) return;
|
|
1346
|
+
var bodyEl = item.querySelector('.ref-body');
|
|
1347
|
+
if (!bodyEl) return;
|
|
1348
|
+
var calls = refCallMap.get(num);
|
|
1349
|
+
if (!calls || calls.length === 0) return;
|
|
1350
|
+
|
|
1351
|
+
var existingBl = bodyEl.querySelector('.ref-backlinks');
|
|
1352
|
+
if (existingBl) existingBl.remove();
|
|
1353
|
+
|
|
1354
|
+
var span = document.createElement('span');
|
|
1355
|
+
span.className = 'ref-backlinks';
|
|
1356
|
+
|
|
1357
|
+
if (calls.length === 1) {
|
|
1358
|
+
var cid = calls[0];
|
|
1359
|
+
var meta = callMetaMap.get(cid) || { headingText: 'Section', shortSec: 'Section', snippet: '' };
|
|
1360
|
+
var isActive = (activeCallId === cid);
|
|
1361
|
+
var bl = document.createElement('a');
|
|
1362
|
+
bl.className = 'ref-occ-pill' + (isActive ? ' ref-occ-active' : '');
|
|
1363
|
+
bl.href = '#' + cid;
|
|
1364
|
+
bl.setAttribute('data-call-id', cid);
|
|
1365
|
+
bl.setAttribute('aria-label', (isActive ? 'Return to reading in ' : 'Jump to citation in ') + meta.headingText + (meta.snippet ? ': ' + meta.snippet : ''));
|
|
1366
|
+
bl.title = (isActive ? 'Return to text in ' : 'Citation in ') + meta.headingText + (meta.snippet ? ':\n"' + meta.snippet + '"' : '');
|
|
1367
|
+
if (isActive) bl.setAttribute('aria-current', 'location');
|
|
1368
|
+
bl.innerHTML = '<span class="pill-arrow" aria-hidden="true">↩</span> <span class="pill-sec">' + esc(meta.shortSec) + '</span>';
|
|
1369
|
+
span.appendChild(bl);
|
|
1370
|
+
} else {
|
|
1371
|
+
var activeIdx = calls.indexOf(activeCallId);
|
|
1372
|
+
if (activeIdx !== -1) {
|
|
1373
|
+
var activeMeta = callMetaMap.get(activeCallId) || { headingText: 'Section', shortSec: 'Section', snippet: '' };
|
|
1374
|
+
var actPill = document.createElement('a');
|
|
1375
|
+
actPill.className = 'ref-occ-pill ref-occ-active';
|
|
1376
|
+
actPill.href = '#' + activeCallId;
|
|
1377
|
+
actPill.setAttribute('data-call-id', activeCallId);
|
|
1378
|
+
actPill.setAttribute('aria-current', 'location');
|
|
1379
|
+
actPill.setAttribute('aria-label', 'Return to reading in ' + activeMeta.headingText + ' (occurrence ' + (activeIdx + 1) + ' of ' + calls.length + '): ' + activeMeta.snippet);
|
|
1380
|
+
actPill.title = 'Return to reading in ' + activeMeta.headingText + ' (occurrence ' + (activeIdx + 1) + '):\n"' + activeMeta.snippet + '"';
|
|
1381
|
+
actPill.innerHTML = '<span class="pill-arrow" aria-hidden="true">↩</span> <span class="pill-sec">' + esc(activeMeta.shortSec) + '</span> <span class="pill-occ">(' + (activeIdx + 1) + ')</span>';
|
|
1382
|
+
span.appendChild(actPill);
|
|
1383
|
+
|
|
1384
|
+
var othersWrap = document.createElement('span');
|
|
1385
|
+
othersWrap.className = 'ref-occ-others';
|
|
1386
|
+
othersWrap.setAttribute('aria-label', 'Other occurrences in report:');
|
|
1387
|
+
calls.forEach(function(cid, idx) {
|
|
1388
|
+
if (idx === activeIdx) return;
|
|
1389
|
+
var m = callMetaMap.get(cid) || { headingText: 'Section', shortSec: 'Section', snippet: '' };
|
|
1390
|
+
var link = document.createElement('a');
|
|
1391
|
+
link.className = 'ref-occ-pill';
|
|
1392
|
+
link.href = '#' + cid;
|
|
1393
|
+
link.setAttribute('data-call-id', cid);
|
|
1394
|
+
link.setAttribute('aria-label', 'Occurrence ' + (idx + 1) + ' in ' + m.headingText + ': ' + m.snippet);
|
|
1395
|
+
link.title = 'Occurrence ' + (idx + 1) + ' in ' + m.headingText + (m.snippet ? ':\n"' + m.snippet + '"' : '');
|
|
1396
|
+
link.textContent = (idx + 1);
|
|
1397
|
+
othersWrap.appendChild(link);
|
|
1398
|
+
});
|
|
1399
|
+
span.appendChild(othersWrap);
|
|
1400
|
+
} else {
|
|
1401
|
+
var prefix = document.createElement('span');
|
|
1402
|
+
prefix.className = 'ref-occ-prefix';
|
|
1403
|
+
prefix.innerHTML = '<span aria-hidden="true">↩</span>';
|
|
1404
|
+
span.appendChild(prefix);
|
|
1405
|
+
|
|
1406
|
+
calls.forEach(function(cid, idx) {
|
|
1407
|
+
var m = callMetaMap.get(cid) || { headingText: 'Section', shortSec: 'Section', snippet: '' };
|
|
1408
|
+
var link = document.createElement('a');
|
|
1409
|
+
link.className = 'ref-occ-pill';
|
|
1410
|
+
link.href = '#' + cid;
|
|
1411
|
+
link.setAttribute('data-call-id', cid);
|
|
1412
|
+
link.setAttribute('aria-label', 'Occurrence ' + (idx + 1) + ' in ' + m.headingText + ': ' + m.snippet);
|
|
1413
|
+
link.title = 'Occurrence ' + (idx + 1) + ' in ' + m.headingText + (m.snippet ? ':\n"' + m.snippet + '"' : '');
|
|
1414
|
+
link.textContent = (idx + 1);
|
|
1415
|
+
span.appendChild(link);
|
|
1416
|
+
});
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
bodyEl.appendChild(span);
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
refsMap.forEach(function(_, num) {
|
|
1423
|
+
renderReferenceBacklinks(num, null);
|
|
1424
|
+
});
|
|
1425
|
+
|
|
1426
|
+
// ---- 3. Interactive Singleton Tooltip Engine ----
|
|
1427
|
+
var tooltip = document.getElementById('cite-tooltip');
|
|
1428
|
+
var tooltipTail = tooltip ? tooltip.querySelector('.cite-tail') : null;
|
|
1429
|
+
var tooltipBody = tooltip ? tooltip.querySelector('.cite-body') : null;
|
|
1430
|
+
var tooltipLabel = tooltip ? tooltip.querySelector('.cite-label') : null;
|
|
1431
|
+
var tooltipJump = tooltip ? tooltip.querySelector('.cite-jump-link') : null;
|
|
1432
|
+
var activeTrigger = null;
|
|
1433
|
+
var showTimer = null, hideTimer = null;
|
|
1434
|
+
|
|
1435
|
+
function showTooltip(triggerEl) {
|
|
1436
|
+
if (!tooltip || !tooltipBody) return;
|
|
1437
|
+
clearTimeout(hideTimer); hideTimer = null;
|
|
1438
|
+
var num = triggerEl.getAttribute('data-ref');
|
|
1439
|
+
var refText = refsMap.get(parseInt(num, 10));
|
|
1440
|
+
if (!refText) return;
|
|
1441
|
+
|
|
1442
|
+
if (tooltipLabel) tooltipLabel.textContent = 'Reference [' + num + ']';
|
|
1443
|
+
if (tooltipJump) tooltipJump.href = '#ref-' + num;
|
|
1444
|
+
tooltipBody.innerHTML = formatReferenceHtml(refText);
|
|
1445
|
+
|
|
1446
|
+
tooltip.style.left = '0px';
|
|
1447
|
+
tooltip.style.top = '0px';
|
|
1448
|
+
tooltip.classList.add('visible');
|
|
1449
|
+
tooltip.classList.remove('fade-out');
|
|
1450
|
+
|
|
1451
|
+
var r = triggerEl.getBoundingClientRect();
|
|
1452
|
+
var tr = tooltip.getBoundingClientRect();
|
|
1453
|
+
var sy = window.scrollY || document.documentElement.scrollTop;
|
|
1454
|
+
var sx = window.scrollX || document.documentElement.scrollLeft;
|
|
1455
|
+
var clientW = document.documentElement.clientWidth;
|
|
1456
|
+
|
|
1457
|
+
var left = r.left + sx + (r.width / 2) - (tr.width / 2);
|
|
1458
|
+
if (left < sx + 12) left = sx + 12;
|
|
1459
|
+
if (left + tr.width > sx + clientW - 12) left = sx + clientW - tr.width - 12;
|
|
1460
|
+
|
|
1461
|
+
var top = r.bottom + sy + 6;
|
|
1462
|
+
var above = false;
|
|
1463
|
+
if (top + tr.height > window.innerHeight + sy - 12) {
|
|
1464
|
+
top = r.top + sy - tr.height - 6;
|
|
1465
|
+
above = true;
|
|
1466
|
+
}
|
|
1467
|
+
if (above && top < sy + 6) top = sy + 6;
|
|
1468
|
+
|
|
1469
|
+
if (tooltipTail) {
|
|
1470
|
+
var tailLeft = (r.left + sx + r.width / 2) - left;
|
|
1471
|
+
tailLeft = Math.max(14, Math.min(tr.width - 14, tailLeft));
|
|
1472
|
+
tooltipTail.style.left = tailLeft + 'px';
|
|
1473
|
+
tooltipTail.style.transform = 'none';
|
|
1474
|
+
if (above) tooltipTail.classList.add('flip');
|
|
1475
|
+
else tooltipTail.classList.remove('flip');
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
tooltip.style.left = left + 'px';
|
|
1479
|
+
tooltip.style.top = top + 'px';
|
|
1480
|
+
requestAnimationFrame(function() { tooltip.classList.add('fade-in'); });
|
|
1481
|
+
activeTrigger = triggerEl;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
function hideTooltip() {
|
|
1485
|
+
if (!tooltip) return;
|
|
1486
|
+
tooltip.classList.remove('fade-in');
|
|
1487
|
+
tooltip.classList.add('fade-out');
|
|
1488
|
+
setTimeout(function() {
|
|
1489
|
+
if (tooltip.classList.contains('fade-out')) {
|
|
1490
|
+
tooltip.classList.remove('visible', 'fade-out');
|
|
1491
|
+
activeTrigger = null;
|
|
1492
|
+
}
|
|
1493
|
+
}, 150);
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
document.addEventListener('mouseenter', function(e) {
|
|
1497
|
+
var a = e.target.closest('.cite-ref a');
|
|
1498
|
+
if (!a) return;
|
|
1499
|
+
clearTimeout(hideTimer);
|
|
1500
|
+
clearTimeout(showTimer);
|
|
1501
|
+
showTimer = setTimeout(function() { showTooltip(a); }, 200);
|
|
1502
|
+
}, true);
|
|
1503
|
+
|
|
1504
|
+
document.addEventListener('mouseleave', function(e) {
|
|
1505
|
+
var a = e.target.closest('.cite-ref a');
|
|
1506
|
+
if (!a) return;
|
|
1507
|
+
clearTimeout(showTimer);
|
|
1508
|
+
hideTimer = setTimeout(hideTooltip, 220);
|
|
1509
|
+
}, true);
|
|
1510
|
+
|
|
1511
|
+
if (tooltip) {
|
|
1512
|
+
tooltip.addEventListener('mouseenter', function() {
|
|
1513
|
+
clearTimeout(hideTimer);
|
|
1514
|
+
});
|
|
1515
|
+
tooltip.addEventListener('mouseleave', function() {
|
|
1516
|
+
hideTimer = setTimeout(hideTooltip, 220);
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
// ---- 5. Floating Return Chip & Reorientation Engine ----
|
|
1521
|
+
var chipEl = document.getElementById('cite-return-chip');
|
|
1522
|
+
var chipBtn = document.getElementById('cite-return-btn');
|
|
1523
|
+
var chipBadge = document.getElementById('cite-return-badge');
|
|
1524
|
+
var chipDismiss = document.getElementById('cite-return-dismiss');
|
|
1525
|
+
var activeReturnTarget = null;
|
|
1526
|
+
|
|
1527
|
+
function showReturnChip(callId, refNum) {
|
|
1528
|
+
if (!chipEl) return;
|
|
1529
|
+
activeReturnTarget = callId;
|
|
1530
|
+
var meta = callMetaMap.get(callId);
|
|
1531
|
+
var labelText = 'Return to text';
|
|
1532
|
+
if (meta && meta.shortSec) {
|
|
1533
|
+
labelText = 'Return to ' + meta.shortSec;
|
|
1534
|
+
}
|
|
1535
|
+
var returnTextEl = chipBtn ? chipBtn.querySelector('.return-text') : null;
|
|
1536
|
+
if (returnTextEl) returnTextEl.textContent = labelText;
|
|
1537
|
+
if (chipBadge) chipBadge.textContent = '[' + refNum + ']';
|
|
1538
|
+
chipEl.classList.add('visible');
|
|
1539
|
+
chipEl.setAttribute('aria-hidden', 'false');
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
function hideReturnChip() {
|
|
1543
|
+
if (!chipEl) return;
|
|
1544
|
+
chipEl.classList.remove('visible');
|
|
1545
|
+
chipEl.setAttribute('aria-hidden', 'true');
|
|
1546
|
+
activeReturnTarget = null;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
function triggerPulse(el) {
|
|
1550
|
+
el.classList.remove('cite-pulse');
|
|
1551
|
+
void el.offsetWidth;
|
|
1552
|
+
el.classList.add('cite-pulse');
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
function triggerBlockGlow(el) {
|
|
1556
|
+
el.classList.remove('cite-caller-block-highlight');
|
|
1557
|
+
void el.offsetWidth;
|
|
1558
|
+
el.classList.add('cite-caller-block-highlight');
|
|
1559
|
+
setTimeout(function() {
|
|
1560
|
+
el.classList.remove('cite-caller-block-highlight');
|
|
1561
|
+
}, 2000);
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
function jumpToCallingText(callId) {
|
|
1565
|
+
var el = document.getElementById(callId);
|
|
1566
|
+
if (!el) return;
|
|
1567
|
+
hideReturnChip();
|
|
1568
|
+
|
|
1569
|
+
var parentDetails = el.closest('details');
|
|
1570
|
+
if (parentDetails) parentDetails.open = true;
|
|
1571
|
+
|
|
1572
|
+
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
1573
|
+
triggerPulse(el);
|
|
1574
|
+
|
|
1575
|
+
var parentBlock = el.closest('p, li, td, th, blockquote') || el.parentElement;
|
|
1576
|
+
if (parentBlock) triggerBlockGlow(parentBlock);
|
|
1577
|
+
|
|
1578
|
+
el.setAttribute('tabindex', '-1');
|
|
1579
|
+
el.focus({ preventScroll: true });
|
|
1580
|
+
|
|
1581
|
+
var refNum = el.getAttribute('data-ref');
|
|
1582
|
+
if (refNum) {
|
|
1583
|
+
setTimeout(function() {
|
|
1584
|
+
renderReferenceBacklinks(parseInt(refNum, 10), null);
|
|
1585
|
+
}, 600);
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
if (history.state && history.state.citeOrigin === callId) {
|
|
1589
|
+
history.back();
|
|
1590
|
+
} else {
|
|
1591
|
+
history.replaceState(null, '', window.location.pathname + window.location.search);
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
document.addEventListener('click', function(e) {
|
|
1596
|
+
var a = e.target.closest('.cite-ref a');
|
|
1597
|
+
if (a) {
|
|
1598
|
+
if (e.pointerType === 'touch' && (!activeTrigger || activeTrigger !== a || !tooltip.classList.contains('fade-in'))) {
|
|
1599
|
+
e.preventDefault();
|
|
1600
|
+
showTooltip(a);
|
|
1601
|
+
} else {
|
|
1602
|
+
e.preventDefault();
|
|
1603
|
+
var callId = a.id;
|
|
1604
|
+
var refNum = a.getAttribute('data-ref');
|
|
1605
|
+
var meta = callMetaMap.get(callId);
|
|
1606
|
+
history.replaceState({ citeOrigin: callId }, '');
|
|
1607
|
+
history.pushState({ citeOrigin: callId, refId: 'ref-' + refNum, refNum: refNum, headingText: meta ? meta.headingText : '' }, '', '#ref-' + refNum);
|
|
1608
|
+
renderReferenceBacklinks(parseInt(refNum, 10), callId);
|
|
1609
|
+
var targetRef = document.getElementById('ref-' + refNum);
|
|
1610
|
+
if (targetRef) targetRef.scrollIntoView({ behavior: 'smooth' });
|
|
1611
|
+
showReturnChip(callId, refNum);
|
|
1612
|
+
hideTooltip();
|
|
1613
|
+
}
|
|
1614
|
+
return;
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
var jumpLink = e.target.closest('.cite-jump-link');
|
|
1618
|
+
if (jumpLink && activeTrigger) {
|
|
1619
|
+
e.preventDefault();
|
|
1620
|
+
var jCallId = activeTrigger.id;
|
|
1621
|
+
var jRefNum = activeTrigger.getAttribute('data-ref');
|
|
1622
|
+
var jMeta = callMetaMap.get(jCallId);
|
|
1623
|
+
history.replaceState({ citeOrigin: jCallId }, '');
|
|
1624
|
+
history.pushState({ citeOrigin: jCallId, refId: 'ref-' + jRefNum, refNum: jRefNum, headingText: jMeta ? jMeta.headingText : '' }, '', '#ref-' + jRefNum);
|
|
1625
|
+
renderReferenceBacklinks(parseInt(jRefNum, 10), jCallId);
|
|
1626
|
+
var targetRefJump = document.getElementById('ref-' + jRefNum);
|
|
1627
|
+
if (targetRefJump) targetRefJump.scrollIntoView({ behavior: 'smooth' });
|
|
1628
|
+
showReturnChip(jCallId, jRefNum);
|
|
1629
|
+
hideTooltip();
|
|
1630
|
+
return;
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
var backlink = e.target.closest('.ref-occ-pill, .ref-backlink');
|
|
1634
|
+
if (backlink) {
|
|
1635
|
+
e.preventDefault();
|
|
1636
|
+
var targetId = backlink.getAttribute('data-call-id');
|
|
1637
|
+
if (targetId) {
|
|
1638
|
+
jumpToCallingText(targetId);
|
|
1639
|
+
}
|
|
1640
|
+
return;
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
if (!e.target.closest('#cite-tooltip')) {
|
|
1644
|
+
hideTooltip();
|
|
1645
|
+
}
|
|
1646
|
+
});
|
|
1647
|
+
|
|
1648
|
+
if (chipBtn) {
|
|
1649
|
+
chipBtn.addEventListener('click', function() {
|
|
1650
|
+
if (activeReturnTarget) jumpToCallingText(activeReturnTarget);
|
|
1651
|
+
});
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
if (chipDismiss) {
|
|
1655
|
+
chipDismiss.addEventListener('click', hideReturnChip);
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
window.addEventListener('popstate', function(e) {
|
|
1659
|
+
if (e.state && e.state.citeOrigin) {
|
|
1660
|
+
if (e.state.refId && window.location.hash === '#' + e.state.refId) {
|
|
1661
|
+
renderReferenceBacklinks(parseInt(e.state.refNum, 10), e.state.citeOrigin);
|
|
1662
|
+
showReturnChip(e.state.citeOrigin, e.state.refNum || '');
|
|
1663
|
+
} else {
|
|
1664
|
+
var el = document.getElementById(e.state.citeOrigin);
|
|
1665
|
+
if (el) {
|
|
1666
|
+
var parentDetails = el.closest('details');
|
|
1667
|
+
if (parentDetails) parentDetails.open = true;
|
|
1668
|
+
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
1669
|
+
triggerPulse(el);
|
|
1670
|
+
var parentBlock = el.closest('p, li, td, th, blockquote') || el.parentElement;
|
|
1671
|
+
if (parentBlock) triggerBlockGlow(parentBlock);
|
|
1672
|
+
el.setAttribute('tabindex', '-1');
|
|
1673
|
+
el.focus({ preventScroll: true });
|
|
1674
|
+
}
|
|
1675
|
+
hideReturnChip();
|
|
1676
|
+
}
|
|
1677
|
+
} else {
|
|
1678
|
+
hideReturnChip();
|
|
1679
|
+
}
|
|
1680
|
+
});
|
|
1681
|
+
|
|
1682
|
+
// ---- 4. ScrollSpy Engine ----
|
|
1683
|
+
var headingsList = Array.from(contentEl.querySelectorAll('h1, h2, h3'));
|
|
1684
|
+
var tocLinks = Array.from(document.querySelectorAll('.report-sidebar .toc a, .drawer-toc .toc a'));
|
|
1685
|
+
|
|
1686
|
+
function updateScrollSpy() {
|
|
1687
|
+
if (!headingsList.length || !tocLinks.length) return;
|
|
1688
|
+
var scrollY = window.scrollY || document.documentElement.scrollTop;
|
|
1689
|
+
var isAtBottom = (window.innerHeight + scrollY) >= (document.documentElement.scrollHeight - 36);
|
|
1690
|
+
|
|
1691
|
+
var currentId = '';
|
|
1692
|
+
if (isAtBottom) {
|
|
1693
|
+
currentId = headingsList[headingsList.length - 1].id;
|
|
1694
|
+
} else {
|
|
1695
|
+
for (var i = headingsList.length - 1; i >= 0; i--) {
|
|
1696
|
+
if (headingsList[i].offsetTop <= scrollY + 95) {
|
|
1697
|
+
currentId = headingsList[i].id;
|
|
1698
|
+
break;
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
tocLinks.forEach(function(link) {
|
|
1704
|
+
var match = link.getAttribute('href') === '#' + currentId;
|
|
1705
|
+
link.classList.toggle('active', match);
|
|
1706
|
+
if (match && link.closest('.report-sidebar')) {
|
|
1707
|
+
link.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
|
1708
|
+
}
|
|
1709
|
+
});
|
|
1710
|
+
|
|
1711
|
+
if (refHeading && activeReturnTarget && scrollY < refHeading.offsetTop - 350) {
|
|
1712
|
+
hideReturnChip();
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
window.addEventListener('scroll', updateScrollSpy, { passive: true });
|
|
1716
|
+
updateScrollSpy();
|
|
1717
|
+
|
|
1718
|
+
// ---- 5. Mobile TOC Drawer Controls ----
|
|
1719
|
+
var drawerToggle = document.getElementById('mobile-toc-toggle');
|
|
1720
|
+
var drawer = document.getElementById('mobile-toc-drawer');
|
|
1721
|
+
var backdrop = document.getElementById('mobile-toc-backdrop');
|
|
1722
|
+
var drawerClose = document.getElementById('drawer-close-btn');
|
|
1723
|
+
|
|
1724
|
+
function openDrawer() {
|
|
1725
|
+
if (drawer) drawer.classList.add('open');
|
|
1726
|
+
if (backdrop) backdrop.classList.add('open');
|
|
1727
|
+
document.body.style.overflow = 'hidden';
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
function closeDrawer() {
|
|
1731
|
+
if (drawer) drawer.classList.remove('open');
|
|
1732
|
+
if (backdrop) backdrop.classList.remove('open');
|
|
1733
|
+
document.body.style.overflow = '';
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
if (drawerToggle) drawerToggle.addEventListener('click', openDrawer);
|
|
1737
|
+
if (drawerClose) drawerClose.addEventListener('click', closeDrawer);
|
|
1738
|
+
if (backdrop) backdrop.addEventListener('click', closeDrawer);
|
|
1739
|
+
|
|
1740
|
+
document.querySelectorAll('.drawer-toc a').forEach(function(link) {
|
|
1741
|
+
link.addEventListener('click', function() {
|
|
1742
|
+
closeDrawer();
|
|
1743
|
+
});
|
|
1744
|
+
});
|
|
1745
|
+
|
|
1746
|
+
document.addEventListener('keydown', function(e) {
|
|
1747
|
+
if (e.key === 'Escape') {
|
|
1748
|
+
closeDrawer();
|
|
1749
|
+
hideTooltip();
|
|
1750
|
+
hideReturnChip();
|
|
1751
|
+
}
|
|
1752
|
+
});
|
|
1753
|
+
})();
|
|
1754
|
+
""".strip()
|
|
1755
|
+
|
|
1756
|
+
|
|
1757
|
+
def parse_metadata(raw_text: str) -> tuple[str, dict[str, str], str]:
|
|
1758
|
+
"""Extract report title, metadata fields, and cleaned markdown text."""
|
|
1759
|
+
lines = raw_text.splitlines()
|
|
1760
|
+
title = ""
|
|
1761
|
+
metadata = {}
|
|
1762
|
+
cleaned_lines = []
|
|
1763
|
+
|
|
1764
|
+
# Check first few lines for # Title and Generated: line
|
|
1765
|
+
skip_indices = set()
|
|
1766
|
+
for idx, line in enumerate(lines[:6]):
|
|
1767
|
+
stripped = line.strip()
|
|
1768
|
+
if stripped.startswith("# ") and not title:
|
|
1769
|
+
title = stripped[2:].strip()
|
|
1770
|
+
skip_indices.add(idx)
|
|
1771
|
+
elif re.search(r"Generated:\s*", stripped, re.IGNORECASE) and "|" in stripped:
|
|
1772
|
+
skip_indices.add(idx)
|
|
1773
|
+
# Parse key-value tokens separated by pipe
|
|
1774
|
+
parts = [p.strip() for p in stripped.split("|")]
|
|
1775
|
+
for p in parts:
|
|
1776
|
+
if ":" in p:
|
|
1777
|
+
k, v = p.split(":", 1)
|
|
1778
|
+
metadata[k.strip().lower()] = v.strip()
|
|
1779
|
+
|
|
1780
|
+
for idx, line in enumerate(lines):
|
|
1781
|
+
if idx not in skip_indices:
|
|
1782
|
+
cleaned_lines.append(line)
|
|
1783
|
+
|
|
1784
|
+
return title, metadata, "\n".join(cleaned_lines)
|
|
1785
|
+
|
|
1786
|
+
|
|
1787
|
+
def build_header_card(title: str, metadata: dict[str, str], icon_uri: str) -> str:
|
|
1788
|
+
"""Construct publication-grade header hero card."""
|
|
1789
|
+
items = []
|
|
1790
|
+
if "topic" in metadata:
|
|
1791
|
+
items.append(f'<div class="meta-item"><span class="meta-label">Topic</span><span class="meta-code">{html.escape(metadata["topic"])}</span></div>')
|
|
1792
|
+
if "generated" in metadata:
|
|
1793
|
+
items.append(f'<div class="meta-item"><span class="meta-label">Generated</span><span class="meta-value">{html.escape(metadata["generated"])}</span></div>')
|
|
1794
|
+
if "scope" in metadata:
|
|
1795
|
+
items.append(f'<div class="meta-item meta-scope"><span class="meta-label">Research Scope</span><span class="meta-value">{html.escape(metadata["scope"])}</span></div>')
|
|
1796
|
+
|
|
1797
|
+
meta_html = f'<div class="meta-grid">{"".join(items)}</div>' if items else ""
|
|
1798
|
+
|
|
1799
|
+
return f"""
|
|
1800
|
+
<header class="report-header-card">
|
|
1801
|
+
<div class="brand-badge-bar">
|
|
1802
|
+
<div class="brand-badge">
|
|
1803
|
+
<img class="brand-logo-img" src="{icon_uri}" alt="" aria-hidden="true">
|
|
1804
|
+
<span>BioResearcher · Deep Research</span>
|
|
1805
|
+
</div>
|
|
1806
|
+
</div>
|
|
1807
|
+
<h1 class="report-title">{html.escape(title)}</h1>
|
|
1808
|
+
{meta_html}
|
|
1809
|
+
</header>
|
|
1810
|
+
""".strip()
|
|
52
1811
|
|
|
53
1812
|
|
|
54
1813
|
def convert(markdown_path: Path, title: str) -> str:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
1814
|
+
raw_text = markdown_path.read_text(encoding="utf-8")
|
|
1815
|
+
doc_title, metadata, cleaned_markdown = parse_metadata(raw_text)
|
|
1816
|
+
effective_title = doc_title or title
|
|
1817
|
+
|
|
1818
|
+
md = md_lib.Markdown(
|
|
1819
|
+
extensions=["tables", "fenced_code", "sane_lists", "toc"],
|
|
1820
|
+
extension_configs={
|
|
1821
|
+
"toc": {
|
|
1822
|
+
"toc_depth": "2-3",
|
|
1823
|
+
"title": "",
|
|
1824
|
+
"permalink": False,
|
|
1825
|
+
}
|
|
1826
|
+
},
|
|
62
1827
|
)
|
|
1828
|
+
body_html = md.convert(cleaned_markdown)
|
|
1829
|
+
toc_html = md.toc or ""
|
|
1830
|
+
|
|
1831
|
+
icon_uri = get_brand_icon_uri()
|
|
1832
|
+
header_card = build_header_card(effective_title, metadata, icon_uri)
|
|
1833
|
+
|
|
1834
|
+
return f"""<!DOCTYPE html>
|
|
1835
|
+
<html lang="en">
|
|
1836
|
+
<head>
|
|
1837
|
+
<meta charset="utf-8">
|
|
1838
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1839
|
+
<title>{html.escape(effective_title)}</title>
|
|
1840
|
+
<link rel="icon" type="image/jpeg" href="{icon_uri}">
|
|
1841
|
+
<style>{CSS}</style>
|
|
1842
|
+
</head>
|
|
1843
|
+
<body>
|
|
1844
|
+
|
|
1845
|
+
<div class="report-wrapper">
|
|
1846
|
+
<aside class="report-sidebar">
|
|
1847
|
+
<div class="sidebar-header">
|
|
1848
|
+
<div class="sidebar-brand">
|
|
1849
|
+
<img class="sidebar-logo-img" src="{icon_uri}" alt="" aria-hidden="true">
|
|
1850
|
+
<span>BioResearcher</span>
|
|
1851
|
+
</div>
|
|
1852
|
+
<span class="sidebar-badge">Deep Research</span>
|
|
1853
|
+
</div>
|
|
1854
|
+
<div class="toc-title">Table of Contents</div>
|
|
1855
|
+
<nav class="toc-container">
|
|
1856
|
+
{toc_html}
|
|
1857
|
+
</nav>
|
|
1858
|
+
</aside>
|
|
1859
|
+
|
|
1860
|
+
<main class="report-main">
|
|
1861
|
+
{header_card}
|
|
1862
|
+
<article id="content" class="markdown-body">
|
|
1863
|
+
{body_html}
|
|
1864
|
+
</article>
|
|
1865
|
+
</main>
|
|
1866
|
+
</div>
|
|
1867
|
+
|
|
1868
|
+
<button class="mobile-toc-btn" id="mobile-toc-toggle" aria-label="Toggle Table of Contents">
|
|
1869
|
+
{SVG_LIST_ICON}
|
|
1870
|
+
<span>Contents</span>
|
|
1871
|
+
</button>
|
|
1872
|
+
|
|
1873
|
+
<div class="mobile-toc-backdrop" id="mobile-toc-backdrop"></div>
|
|
1874
|
+
<div class="mobile-toc-drawer" id="mobile-toc-drawer">
|
|
1875
|
+
<div class="drawer-header">
|
|
1876
|
+
<div class="drawer-title">
|
|
1877
|
+
<img class="drawer-logo-img" src="{icon_uri}" alt="" aria-hidden="true">
|
|
1878
|
+
<span>Table of Contents</span>
|
|
1879
|
+
</div>
|
|
1880
|
+
<button class="drawer-close" id="drawer-close-btn" aria-label="Close Table of Contents">×</button>
|
|
1881
|
+
</div>
|
|
1882
|
+
<nav class="drawer-toc">
|
|
1883
|
+
{toc_html}
|
|
1884
|
+
</nav>
|
|
1885
|
+
</div>
|
|
1886
|
+
|
|
1887
|
+
<div id="cite-tooltip" class="cite-tooltip" role="tooltip" aria-hidden="true">
|
|
1888
|
+
<div class="cite-tail"></div>
|
|
1889
|
+
<div class="cite-header">
|
|
1890
|
+
<span class="cite-label">Reference</span>
|
|
1891
|
+
<a class="cite-jump-link" href="#">Jump to reference ↓</a>
|
|
1892
|
+
</div>
|
|
1893
|
+
<div class="cite-body"></div>
|
|
1894
|
+
</div>
|
|
1895
|
+
|
|
1896
|
+
<aside id="cite-return-chip" class="cite-return-chip" aria-live="polite" aria-hidden="true">
|
|
1897
|
+
<button type="button" class="cite-return-btn" id="cite-return-btn">
|
|
1898
|
+
<span aria-hidden="true" class="return-arrow">↩</span>
|
|
1899
|
+
<span class="return-text">Back to text</span>
|
|
1900
|
+
<span class="return-badge" id="cite-return-badge">[1]</span>
|
|
1901
|
+
</button>
|
|
1902
|
+
<button type="button" class="cite-return-dismiss" id="cite-return-dismiss" aria-label="Dismiss return prompt">×</button>
|
|
1903
|
+
</aside>
|
|
1904
|
+
|
|
1905
|
+
<script>
|
|
1906
|
+
{CLIENT_SCRIPT}
|
|
1907
|
+
</script>
|
|
1908
|
+
|
|
1909
|
+
</body>
|
|
1910
|
+
</html>
|
|
1911
|
+
"""
|
|
63
1912
|
|
|
64
1913
|
|
|
65
1914
|
def main() -> None:
|
|
66
1915
|
parser = argparse.ArgumentParser(
|
|
67
|
-
description="Convert a markdown file to standalone
|
|
1916
|
+
description="Convert a markdown file to standalone publication-grade HTML."
|
|
68
1917
|
)
|
|
69
1918
|
parser.add_argument("input", help="input markdown file")
|
|
70
1919
|
parser.add_argument("-o", "--output", help="output HTML file (default: input with .html)")
|