@tienne/gestalt 0.102.0 → 0.104.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 (179) hide show
  1. package/README.ko.md +2 -1
  2. package/README.md +2 -1
  3. package/dist/package.json +1 -1
  4. package/dist/plugin/role-agents/video-summarizer/AGENT.md +208 -108
  5. package/dist/plugin/skills/_shared/proactive-routing.md +2 -1
  6. package/dist/plugin/skills/research/references/design.md +1 -1
  7. package/dist/plugin/skills/video-digest/SKILL.md +430 -0
  8. package/dist/plugin/skills/video-digest/templates/background.md +15 -0
  9. package/dist/plugin/skills/video-digest/templates/blog.md +16 -0
  10. package/dist/plugin/skills/video-digest/templates/comments.md +19 -0
  11. package/dist/plugin/skills/video-digest/templates/counterpoints.md +15 -0
  12. package/dist/plugin/skills/video-digest/templates/flashcards.md +15 -0
  13. package/dist/plugin/skills/video-digest/templates/interview.md +15 -0
  14. package/dist/plugin/skills/video-digest/templates/meeting.md +15 -0
  15. package/dist/plugin/skills/video-digest/templates/mindmap.md +16 -0
  16. package/dist/plugin/skills/video-digest/templates/quiz.md +16 -0
  17. package/dist/plugin/skills/video-digest/templates/quotes.md +16 -0
  18. package/dist/plugin/skills/video-digest/templates/resources.md +14 -0
  19. package/dist/plugin/skills/video-digest/templates/timestamps.md +14 -0
  20. package/dist/plugin/skills/video-digest/templates/visual.md +22 -0
  21. package/dist/src/cli/commands/digest.d.ts +60 -0
  22. package/dist/src/cli/commands/digest.d.ts.map +1 -0
  23. package/dist/src/cli/commands/digest.js +401 -0
  24. package/dist/src/cli/commands/digest.js.map +1 -0
  25. package/dist/src/cli/index.d.ts.map +1 -1
  26. package/dist/src/cli/index.js +81 -0
  27. package/dist/src/cli/index.js.map +1 -1
  28. package/dist/src/digest/blocks.d.ts +5224 -0
  29. package/dist/src/digest/blocks.d.ts.map +1 -0
  30. package/dist/src/digest/blocks.js +156 -0
  31. package/dist/src/digest/blocks.js.map +1 -0
  32. package/dist/src/digest/captions.d.ts +37 -0
  33. package/dist/src/digest/captions.d.ts.map +1 -0
  34. package/dist/src/digest/captions.js +138 -0
  35. package/dist/src/digest/captions.js.map +1 -0
  36. package/dist/src/digest/comments.d.ts +113 -0
  37. package/dist/src/digest/comments.d.ts.map +1 -0
  38. package/dist/src/digest/comments.js +153 -0
  39. package/dist/src/digest/comments.js.map +1 -0
  40. package/dist/src/digest/diagram-schema.d.ts +765 -0
  41. package/dist/src/digest/diagram-schema.d.ts.map +1 -0
  42. package/dist/src/digest/diagram-schema.js +72 -0
  43. package/dist/src/digest/diagram-schema.js.map +1 -0
  44. package/dist/src/digest/format.d.ts +9 -0
  45. package/dist/src/digest/format.d.ts.map +1 -0
  46. package/dist/src/digest/format.js +26 -0
  47. package/dist/src/digest/format.js.map +1 -0
  48. package/dist/src/digest/frames.d.ts +46 -0
  49. package/dist/src/digest/frames.d.ts.map +1 -0
  50. package/dist/src/digest/frames.js +206 -0
  51. package/dist/src/digest/frames.js.map +1 -0
  52. package/dist/src/digest/index.d.ts +26 -0
  53. package/dist/src/digest/index.d.ts.map +1 -0
  54. package/dist/src/digest/index.js +26 -0
  55. package/dist/src/digest/index.js.map +1 -0
  56. package/dist/src/digest/ingest.d.ts +65 -0
  57. package/dist/src/digest/ingest.d.ts.map +1 -0
  58. package/dist/src/digest/ingest.js +303 -0
  59. package/dist/src/digest/ingest.js.map +1 -0
  60. package/dist/src/digest/lint-extension.d.ts +71 -0
  61. package/dist/src/digest/lint-extension.d.ts.map +1 -0
  62. package/dist/src/digest/lint-extension.js +512 -0
  63. package/dist/src/digest/lint-extension.js.map +1 -0
  64. package/dist/src/digest/lint.d.ts +50 -0
  65. package/dist/src/digest/lint.d.ts.map +1 -0
  66. package/dist/src/digest/lint.js +560 -0
  67. package/dist/src/digest/lint.js.map +1 -0
  68. package/dist/src/digest/merge.d.ts +40 -0
  69. package/dist/src/digest/merge.d.ts.map +1 -0
  70. package/dist/src/digest/merge.js +107 -0
  71. package/dist/src/digest/merge.js.map +1 -0
  72. package/dist/src/digest/ocr.d.ts +100 -0
  73. package/dist/src/digest/ocr.d.ts.map +1 -0
  74. package/dist/src/digest/ocr.js +179 -0
  75. package/dist/src/digest/ocr.js.map +1 -0
  76. package/dist/src/digest/prose.d.ts +47 -0
  77. package/dist/src/digest/prose.d.ts.map +1 -0
  78. package/dist/src/digest/prose.js +171 -0
  79. package/dist/src/digest/prose.js.map +1 -0
  80. package/dist/src/digest/render-blocks.d.ts +38 -0
  81. package/dist/src/digest/render-blocks.d.ts.map +1 -0
  82. package/dist/src/digest/render-blocks.js +378 -0
  83. package/dist/src/digest/render-blocks.js.map +1 -0
  84. package/dist/src/digest/render-html.d.ts +22 -0
  85. package/dist/src/digest/render-html.d.ts.map +1 -0
  86. package/dist/src/digest/render-html.js +505 -0
  87. package/dist/src/digest/render-html.js.map +1 -0
  88. package/dist/src/digest/render-md.d.ts +18 -0
  89. package/dist/src/digest/render-md.d.ts.map +1 -0
  90. package/dist/src/digest/render-md.js +126 -0
  91. package/dist/src/digest/render-md.js.map +1 -0
  92. package/dist/src/digest/render.d.ts +47 -0
  93. package/dist/src/digest/render.d.ts.map +1 -0
  94. package/dist/src/digest/render.js +126 -0
  95. package/dist/src/digest/render.js.map +1 -0
  96. package/dist/src/digest/reports.d.ts +26 -0
  97. package/dist/src/digest/reports.d.ts.map +1 -0
  98. package/dist/src/digest/reports.js +70 -0
  99. package/dist/src/digest/reports.js.map +1 -0
  100. package/dist/src/digest/scenes.d.ts +92 -0
  101. package/dist/src/digest/scenes.d.ts.map +1 -0
  102. package/dist/src/digest/scenes.js +182 -0
  103. package/dist/src/digest/scenes.js.map +1 -0
  104. package/dist/src/digest/schema-base.d.ts +31 -0
  105. package/dist/src/digest/schema-base.d.ts.map +1 -0
  106. package/dist/src/digest/schema-base.js +19 -0
  107. package/dist/src/digest/schema-base.js.map +1 -0
  108. package/dist/src/digest/schema.d.ts +12886 -0
  109. package/dist/src/digest/schema.d.ts.map +1 -0
  110. package/dist/src/digest/schema.js +215 -0
  111. package/dist/src/digest/schema.js.map +1 -0
  112. package/dist/src/digest/server.d.ts +36 -0
  113. package/dist/src/digest/server.d.ts.map +1 -0
  114. package/dist/src/digest/server.js +278 -0
  115. package/dist/src/digest/server.js.map +1 -0
  116. package/dist/src/digest/slice.d.ts +20 -0
  117. package/dist/src/digest/slice.d.ts.map +1 -0
  118. package/dist/src/digest/slice.js +48 -0
  119. package/dist/src/digest/slice.js.map +1 -0
  120. package/dist/src/digest/store.d.ts +67 -0
  121. package/dist/src/digest/store.d.ts.map +1 -0
  122. package/dist/src/digest/store.js +152 -0
  123. package/dist/src/digest/store.js.map +1 -0
  124. package/dist/src/digest/svg.d.ts +74 -0
  125. package/dist/src/digest/svg.d.ts.map +1 -0
  126. package/dist/src/digest/svg.js +415 -0
  127. package/dist/src/digest/svg.js.map +1 -0
  128. package/dist/src/digest/templates.d.ts +38 -0
  129. package/dist/src/digest/templates.d.ts.map +1 -0
  130. package/dist/src/digest/templates.js +125 -0
  131. package/dist/src/digest/templates.js.map +1 -0
  132. package/dist/src/digest/translate.d.ts +46 -0
  133. package/dist/src/digest/translate.d.ts.map +1 -0
  134. package/dist/src/digest/translate.js +50 -0
  135. package/dist/src/digest/translate.js.map +1 -0
  136. package/dist/src/digest/viewer-js.d.ts +4 -0
  137. package/dist/src/digest/viewer-js.d.ts.map +1 -0
  138. package/dist/src/digest/viewer-js.js +735 -0
  139. package/dist/src/digest/viewer-js.js.map +1 -0
  140. package/dist/src/digest/viewer-logic.d.ts +46 -0
  141. package/dist/src/digest/viewer-logic.d.ts.map +1 -0
  142. package/dist/src/digest/viewer-logic.js +89 -0
  143. package/dist/src/digest/viewer-logic.js.map +1 -0
  144. package/dist/src/digest/ytdlp.d.ts +34 -0
  145. package/dist/src/digest/ytdlp.d.ts.map +1 -0
  146. package/dist/src/digest/ytdlp.js +64 -0
  147. package/dist/src/digest/ytdlp.js.map +1 -0
  148. package/dist/src/mcp/schemas.d.ts +48 -0
  149. package/dist/src/mcp/schemas.d.ts.map +1 -1
  150. package/dist/src/mcp/schemas.js +25 -0
  151. package/dist/src/mcp/schemas.js.map +1 -1
  152. package/dist/src/mcp/server.d.ts.map +1 -1
  153. package/dist/src/mcp/server.js +7 -1
  154. package/dist/src/mcp/server.js.map +1 -1
  155. package/dist/src/mcp/tools/digest-passthrough.d.ts +3 -0
  156. package/dist/src/mcp/tools/digest-passthrough.d.ts.map +1 -0
  157. package/dist/src/mcp/tools/digest-passthrough.js +151 -0
  158. package/dist/src/mcp/tools/digest-passthrough.js.map +1 -0
  159. package/package.json +1 -1
  160. package/plugin/.codex-plugin/plugin.json +1 -1
  161. package/plugin/.mcp.json +1 -1
  162. package/plugin/mcp.json +1 -1
  163. package/plugin/role-agents/video-summarizer/AGENT.md +208 -108
  164. package/plugin/skills/_shared/proactive-routing.md +2 -1
  165. package/plugin/skills/research/references/design.md +1 -1
  166. package/plugin/skills/video-digest/SKILL.md +430 -0
  167. package/plugin/skills/video-digest/templates/background.md +15 -0
  168. package/plugin/skills/video-digest/templates/blog.md +16 -0
  169. package/plugin/skills/video-digest/templates/comments.md +19 -0
  170. package/plugin/skills/video-digest/templates/counterpoints.md +15 -0
  171. package/plugin/skills/video-digest/templates/flashcards.md +15 -0
  172. package/plugin/skills/video-digest/templates/interview.md +15 -0
  173. package/plugin/skills/video-digest/templates/meeting.md +15 -0
  174. package/plugin/skills/video-digest/templates/mindmap.md +16 -0
  175. package/plugin/skills/video-digest/templates/quiz.md +16 -0
  176. package/plugin/skills/video-digest/templates/quotes.md +16 -0
  177. package/plugin/skills/video-digest/templates/resources.md +14 -0
  178. package/plugin/skills/video-digest/templates/timestamps.md +14 -0
  179. package/plugin/skills/video-digest/templates/visual.md +22 -0
@@ -0,0 +1,505 @@
1
+ import { extensionKey } from './blocks.js';
2
+ import { CAPTION_LABEL, formatTime, stripNumbering, watchUrlAt } from './format.js';
3
+ import { frameFileName, shotFileName } from './frames.js';
4
+ import { extensionHtml, extensionPanelId, sectionDiagramHtml, } from './render-blocks.js';
5
+ import { renderDigestMarkdown, renderExtensionMarkdown } from './render-md.js';
6
+ import { DIFFICULTY_LABEL, isPreset, LENGTH_LABEL, reportKey, reportLabel } from './reports.js';
7
+ import { VIEWER_JS } from './viewer-js.js';
8
+ import { boldPattern, keywordPattern, REPORT_DIFFICULTIES, REPORT_LENGTHS, youtubeWatchUrl, } from './schema.js';
9
+ const MAX_IMAGE_BYTES = 5 * 1024 * 1024;
10
+ const MAX_TOTAL_IMAGE_BYTES = 15 * 1024 * 1024;
11
+ const e = (s) => s
12
+ .replace(/&/g, '&')
13
+ .replace(/</g, '&lt;')
14
+ .replace(/>/g, '&gt;')
15
+ .replace(/"/g, '&quot;')
16
+ .replace(/'/g, '&#39;');
17
+ // 장면 파일(s<ms>.jpg)이 빠졌을 때 소섹션 프레임과 헷갈리지 않게 경고에 구분해 적는다
18
+ const frameKind = (fileName) => (/^s\d+\.jpg$/.test(fileName) ? '장면' : '프레임');
19
+ /** research 렌더러의 예산과 같다. 한 장 5MB, 합계 15MB를 넘으면 그 프레임은 뺀다 */
20
+ class FrameBudget {
21
+ warnings;
22
+ total = 0;
23
+ constructor(warnings) {
24
+ this.warnings = warnings;
25
+ }
26
+ dataUri(data, fileName) {
27
+ if (data.length > MAX_IMAGE_BYTES) {
28
+ this.warnings.push(`${frameKind(fileName)}이 5MB를 넘어 건너뛰었다: ${fileName}`);
29
+ return null;
30
+ }
31
+ if (!this.charge(data.length, fileName))
32
+ return null;
33
+ return `data:image/jpeg;base64,${data.toString('base64')}`;
34
+ }
35
+ /** 이미 만든 data URI를 다시 실을 때도 HTML 크기는 그만큼 늘어서 같은 합계에 센다 */
36
+ charge(bytes, fileName) {
37
+ if (this.total + bytes > MAX_TOTAL_IMAGE_BYTES) {
38
+ this.warnings.push(`프레임 합계가 15MB를 넘어 ${frameKind(fileName)}을 건너뛰었다: ${fileName}`);
39
+ return false;
40
+ }
41
+ this.total += bytes;
42
+ return true;
43
+ }
44
+ }
45
+ // 본문에 `</script>`가 들어 있어도 태그를 닫지 못하게 꺾쇠를 유니코드 이스케이프로 바꾼다
46
+ export function embedJson(value) {
47
+ return JSON.stringify(value)
48
+ .replace(/</g, '\\u003c')
49
+ .replace(/\u2028/g, '\\u2028')
50
+ .replace(/\u2029/g, '\\u2029');
51
+ }
52
+ /**
53
+ * digest.json을 뷰어 HTML 한 장으로 바꾼다. LLM을 부르지 않는다.
54
+ * 본문 글자는 escape한 뒤 굵게와 키워드 마커 두 가지만 태그로 바꾼다.
55
+ */
56
+ export function renderDigestHtml(digest, transcript, opts = {}) {
57
+ const warnings = [];
58
+ const { meta, segments } = transcript;
59
+ const long = meta.durationSec >= 3600;
60
+ const isYoutube = meta.source === 'youtube' && Boolean(meta.videoId);
61
+ const at = (i) => segments[i]?.startSec ?? 0;
62
+ const loadFrame = opts.inlineFrames ? opts.loadFrame : undefined;
63
+ const budget = loadFrame ? new FrameBudget(warnings) : null;
64
+ const inline = (text, keywordIds) => e(text)
65
+ .replace(boldPattern(), (_m, inner) => `<strong>${inner}</strong>`)
66
+ .replace(keywordPattern(), (_m, id, label) => {
67
+ if (!keywordIds.has(id)) {
68
+ warnings.push(`키워드 목록에 없는 마커: ${id}`);
69
+ return label;
70
+ }
71
+ return `<button type="button" class="kw" data-kw="${id}">${label}</button>`;
72
+ });
73
+ // 스크립트 줄마다 Tab이 멈추면 긴 영상에서 정지점이 수천 개라 줄 링크는 Tab 순서에서 뺀다
74
+ const timeLink = (sec, tabbable = true) => {
75
+ const label = formatTime(sec, long);
76
+ const url = watchUrlAt(meta, sec);
77
+ if (!url)
78
+ return `<span class="ts" data-sec="${sec}">${label}</span>`;
79
+ const tab = tabbable ? '' : ' tabindex="-1"';
80
+ return `<a class="ts" href="${e(url)}" target="_blank" rel="noopener" data-sec="${sec}"${tab}>${label}</a>`;
81
+ };
82
+ const cite = (c) => `<sup><button type="button" class="cite" data-key="${c.key}" data-from="${c.from}" data-to="${c.to}" aria-label="출처 ${c.key + 1}">[${c.key + 1}]</button></sup>`;
83
+ const sec = (c) => segments[c.key]?.startSec ?? 0;
84
+ const blockCtx = { escape: e, cite, time: (c) => timeLink(sec(c)), sec };
85
+ const missingFrame = (subId, file) => warnings.push(`프레임이 없어 자리를 비웠다: ${subId} (${file})`);
86
+ // 확인 수단이 없는 렌더에서는 프레임이 없다고 경고하지 않는다. 예산 초과는 FrameBudget이 따로 경고한다
87
+ // 리포트 여럿이 같은 프레임을 쓰면 파일은 한 번만 읽는다. 같은 data URI가 HTML에 한 번 더 실리므로 예산은 다시 센다
88
+ const inlined = new Map();
89
+ const frameSrc = (file, subId) => {
90
+ let src = null;
91
+ if (budget && inlined.has(file)) {
92
+ const hit = inlined.get(file);
93
+ if (hit && budget.charge(hit.bytes, file))
94
+ src = hit.src;
95
+ }
96
+ else if (budget && loadFrame) {
97
+ const data = loadFrame(file);
98
+ if (data)
99
+ src = budget.dataUri(data, file);
100
+ else
101
+ missingFrame(subId, file);
102
+ inlined.set(file, src && data ? { src, bytes: data.length } : null);
103
+ }
104
+ else if (opts.frameExists) {
105
+ if (opts.frameExists(file))
106
+ src = `frames/${file}`;
107
+ else
108
+ missingFrame(subId, file);
109
+ }
110
+ return src;
111
+ };
112
+ const frame = (sec, subId) => {
113
+ const src = frameSrc(frameFileName(sec), subId);
114
+ if (!src)
115
+ return '';
116
+ const url = watchUrlAt(meta, sec);
117
+ const img = `<img src="${e(src)}" alt="${formatTime(sec, long)} 장면" loading="lazy">`;
118
+ const body = url
119
+ ? `<a class="frame-link" href="${e(url)}" target="_blank" rel="noopener" data-sec="${sec}">${img}</a>`
120
+ : `<span class="frame-link" data-sec="${sec}">${img}</span>`;
121
+ return `<figure class="frame">${body}<figcaption>${timeLink(sec)}</figcaption></figure>`;
122
+ };
123
+ // 사진을 누르면 확대 창만 열린다. 영상 이동은 figcaption의 시각 링크가 맡아서 한 번 클릭에 두 동작이 겹치지 않는다.
124
+ // 파일이 없는 장면은 자리를 비운다
125
+ const shotsHtml = (shots, subId) => shots
126
+ .map((shot) => {
127
+ const src = frameSrc(shotFileName(shot.sec), subId);
128
+ if (!src)
129
+ return '';
130
+ const caption = e(shot.caption);
131
+ return `<figure class="shot"><img src="${e(src)}" alt="${caption}" loading="lazy"><figcaption>${caption}${cite(shot.cite)} ${timeLink(shot.sec)}</figcaption></figure>`;
132
+ })
133
+ .join('');
134
+ const reportsMeta = digest.reports.map((r) => ({ report: r, key: reportKey(r.options) }));
135
+ const base = digest.reports[0].options;
136
+ // 첫 리포트는 1차와 같은 id를 써서 이미 공유된 앵커가 그대로 열린다. 나머지는 id에 못 쓰는 ~로 접두를 붙여 겹치지 않게 한다
137
+ const renderReport = (report, ri, key) => {
138
+ const { lead, sections, skipped, keywords } = report;
139
+ const kwIds = new Set(keywords.map((k) => k.id));
140
+ const pfx = ri === 0 ? '' : `r${ri}~`;
141
+ const hidden = ri === 0 ? '' : ' hidden';
142
+ const bullets = (list) => `<ul>${list
143
+ .map((b) => `<li>${inline(b.text, kwIds)}${cite(b.cite)}${b.children?.length ? bullets(b.children) : ''}</li>`)
144
+ .join('')}</ul>`;
145
+ // 장면이 있으면 첫 문장 프레임 대신 장면을 본문 옆에 둔다. 장면이 같은 구간을 더 잘 보여 줘서 둘 다 싣지 않는다
146
+ const subBody = (sub) => {
147
+ const shots = sub.shots?.length ? shotsHtml(sub.shots, sub.id) : '';
148
+ if (!shots)
149
+ return `${frame(sub.frameSec, sub.id)}${bullets(sub.bullets)}`;
150
+ return `<div class="sub-body has-shots"><div class="sub-text">${bullets(sub.bullets)}</div><div class="shots">${shots}</div></div>`;
151
+ };
152
+ const sectionsHtml = sections
153
+ .map((s, si) => {
154
+ const subs = s.subsections
155
+ .map((sub, ui) => `<div class="sub" id="sub-${pfx}${e(sub.id)}" data-from="${sub.cite.from}" data-to="${sub.cite.to}"><h3><span class="num">${si + 1}.${ui + 1}.</span> ${e(stripNumbering(sub.title))} ${timeLink(at(sub.cite.key))}</h3>${subBody(sub)}</div>`)
156
+ .join('');
157
+ return `<section class="sec" id="sec-${pfx}${e(s.id)}"><h2><span class="num">${si + 1}.</span> ${e(stripNumbering(s.title))} ${timeLink(at(s.cite.key))}</h2><p class="conclusion">${inline(s.conclusion, kwIds)}${cite(s.cite)}</p>${s.diagram ? sectionDiagramHtml(s.diagram, stripNumbering(s.title), blockCtx) : ''}${subs}</section>`;
158
+ })
159
+ .join('');
160
+ const toc = `<nav class="toc" aria-label="목차"><h2>목차</h2><ol>${sections
161
+ .map((s, si) => `<li><a href="#sec-${pfx}${e(s.id)}" data-nav="sec-${pfx}${e(s.id)}">${si + 1}. ${e(stripNumbering(s.title))}</a><ol>${s.subsections
162
+ .map((sub, ui) => `<li><a href="#sub-${pfx}${e(sub.id)}">${si + 1}.${ui + 1}. ${e(stripNumbering(sub.title))}</a></li>`)
163
+ .join('')}</ol></li>`)
164
+ .join('')}</ol></nav>`;
165
+ const minimap = `<nav class="minimap" aria-label="섹션 이동" data-ri="${ri}"${hidden}>${sections
166
+ .map((s, si) => `<a href="#sec-${pfx}${e(s.id)}" data-nav="sec-${pfx}${e(s.id)}" title="${e(stripNumbering(s.title))}" aria-label="${si + 1}. ${e(stripNumbering(s.title))}"><span aria-hidden="true">${si + 1}</span></a>`)
167
+ .join('')}</nav>`;
168
+ const keywordsHtml = keywords.length
169
+ ? `<section class="extra" id="${pfx}keywords"><h2>키워드</h2><dl>${keywords
170
+ .map((k) => `<dt>${e(k.term)} ${timeLink(at(k.firstCite.key))}</dt><dd>${inline(k.explanation, kwIds)}</dd>`)
171
+ .join('')}</dl></section>`
172
+ : '';
173
+ const skippedHtml = skipped.length
174
+ ? `<section class="extra" id="${pfx}skipped"><h2>요약에서 뺀 구간</h2><ul>${skipped
175
+ .map((s) => `<li>${timeLink(at(s.from))} 문장 ${s.from + 1}-${s.to + 1}: ${inline(s.reason, kwIds)}</li>`)
176
+ .join('')}</ul></section>`
177
+ : '';
178
+ const scope = [
179
+ report.options.range
180
+ ? `<p class="report-scope">${formatTime(report.options.range[0], long)}~${formatTime(report.options.range[1], long)} 구간만 요약했어요.</p>`
181
+ : '',
182
+ report.options.prompt ? `<p class="report-scope">요청: ${e(report.options.prompt)}</p>` : '',
183
+ ].join('');
184
+ const body = `<div class="report" data-ri="${ri}" data-report="${e(key)}" lang="${e(report.options.lang)}"${hidden}>${scope}<section class="lead"><p class="q">${inline(lead.question, kwIds)}</p><p>${inline(lead.answer, kwIds)}</p><p class="takeaway">${inline(lead.takeaway, kwIds)}</p></section>
185
+ ${toc}
186
+ ${sectionsHtml}
187
+ ${keywordsHtml}
188
+ ${skippedHtml}</div>`;
189
+ return { body, minimap };
190
+ };
191
+ const rendered = reportsMeta.map(({ report, key }, ri) => renderReport(report, ri, key));
192
+ const pressed = (on) => `aria-pressed="${on ? 'true' : 'false'}"`;
193
+ const customs = reportsMeta.filter(({ report }) => !isPreset(report.options, base));
194
+ const reportBar = `<div class="report-bar" role="group" aria-label="리포트 고르기"><span class="bar-label">분량</span>${REPORT_LENGTHS.map((l) => `<button type="button" data-length="${l}" ${pressed(l === base.length)}>${LENGTH_LABEL[l]}</button>`).join('')}<span class="bar-label">난이도</span>${REPORT_DIFFICULTIES.map((d) => `<button type="button" data-difficulty="${d}" ${pressed(d === base.difficulty)}>${DIFFICULTY_LABEL[d]}</button>`).join('')}${customs.length
195
+ ? `<label class="bar-label">다른 리포트 <select id="report-select">${reportsMeta
196
+ .map(({ report, key }, ri) => `<option value="${ri}" data-report="${e(key)}">${e(reportLabel(report.options, long))}</option>`)
197
+ .join('')}</select></label>`
198
+ : ''}</div><div id="report-missing" class="report-missing" role="status" hidden><p>이 조합의 리포트는 아직 없어요. 아래 명령을 세션에 붙여 넣으면 만들어요.</p><code id="report-cmd"></code> <button type="button" id="copy-cmd">명령 복사</button></div>`;
199
+ const watchBase = isYoutube ? youtubeWatchUrl(meta.videoId) : null;
200
+ const player = isYoutube
201
+ ? `<div id="player-slot" class="player-slot"><div id="player" class="player"><div id="player-frame"></div><a class="player-fallback" href="${e(watchBase)}" target="_blank" rel="noopener"><img src="https://i.ytimg.com/vi/${meta.videoId}/hqdefault.jpg" alt=""><span>유튜브에서 열기</span></a><button type="button" id="player-dock" class="player-dock" aria-label="미니 플레이어 닫기">×</button></div></div>`
202
+ : `<div id="player-slot" class="player-slot"><div id="player" class="player player-local"><video id="player-video" controls playsinline preload="metadata" aria-label="영상 재생"></video><p class="player-note">로컬 영상은 <code>gestalt digest serve ${e(digest.slug)}</code>로 열어야 재생돼요. 원본 파일을 옮겼으면 ingest를 다시 돌려 주세요.</p><button type="button" id="player-dock" class="player-dock" aria-label="미니 플레이어 닫기">×</button></div></div>`;
203
+ const trLang = meta.translationLang;
204
+ const hasTr = trLang !== undefined && segments.some((s) => s.translation);
205
+ const trToggle = hasTr
206
+ ? ` <button type="button" id="tr-toggle" class="tr-toggle" aria-pressed="true" hidden>번역</button>`
207
+ : '';
208
+ const tr = (s) => hasTr && s.translation
209
+ ? `<span class="tr" lang="${e(trLang ?? '')}">${e(s.translation)}</span>`
210
+ : '';
211
+ const script = `<div class="script"><h2>스크립트 <small>${e(CAPTION_LABEL[meta.captionSource])}</small>${trToggle}</h2><div id="script-body" class="script-body" tabindex="0" role="region" aria-label="영상 스크립트"><ol id="script-list">${segments
212
+ .map((s) => `<li data-i="${s.i}">${timeLink(s.startSec, false)}<span class="txt"><span class="src">${e(s.text)}</span>${tr(s)}</span></li>`)
213
+ .join('')}</ol></div></div>`;
214
+ const facts = [meta.channel, meta.publishedAt, formatTime(meta.durationSec, long)]
215
+ .filter(Boolean)
216
+ .map((f) => `<span>${e(f)}</span>`)
217
+ .join('');
218
+ const data = {
219
+ videoId: isYoutube ? meta.videoId : null,
220
+ localVideo: meta.source === 'file',
221
+ watchBase,
222
+ long,
223
+ starts: segments.map((s) => s.startSec),
224
+ slug: digest.slug,
225
+ reports: reportsMeta.map(({ report, key }) => ({
226
+ key,
227
+ length: report.options.length,
228
+ difficulty: report.options.difficulty,
229
+ lang: report.options.lang,
230
+ preset: isPreset(report.options, base),
231
+ keywords: Object.fromEntries(report.keywords.map((k) => [
232
+ k.id,
233
+ {
234
+ term: k.term,
235
+ explanation: k.explanation.replace(keywordPattern(), '$2').replace(boldPattern(), '$1'),
236
+ sec: at(k.firstCite.key),
237
+ },
238
+ ])),
239
+ markdown: renderDigestMarkdown(digest, transcript, {
240
+ frameExists: opts.frameExists,
241
+ report,
242
+ }),
243
+ })),
244
+ extensions: digest.extensions.map((x) => ({
245
+ key: extensionKey(x),
246
+ panel: extensionPanelId(x),
247
+ markdown: renderExtensionMarkdown(x, transcript),
248
+ })),
249
+ };
250
+ const extensions = digest.extensions;
251
+ const made = new Set(extensions.map((x) => x.template));
252
+ const menuTemplates = (opts.templates ?? []).filter((t) => !made.has(t.id));
253
+ const hasTabs = extensions.length > 0 || menuTemplates.length > 0;
254
+ const tab = (id, label, on) => `<button type="button" role="tab" id="tab-${e(id)}" data-tab="${e(id)}" aria-controls="${e(id)}" aria-selected="${on ? 'true' : 'false'}"${on ? '' : ' tabindex="-1"'}>${e(label)}</button>`;
255
+ const moreMenu = menuTemplates.length
256
+ ? `<button type="button" id="more-btn" class="more-btn" aria-expanded="false" aria-controls="more-menu">+ 더 만들기</button></div><div id="more-menu" class="more-menu" hidden><p>템플릿을 고르면 세션에 붙여 넣을 명령을 복사해요.</p><ul>${menuTemplates
257
+ .map((t) => `<li><button type="button" data-template="${e(t.id)}"><b>${e(t.title)}</b><small>${e(t.description)}</small></button></li>`)
258
+ .join('')}</ul><div id="more-cmd-box" hidden><code id="more-cmd"></code> <button type="button" id="more-copy">명령 복사</button></div></div>`
259
+ : '</div>';
260
+ const tabRow = hasTabs
261
+ ? `<div class="tab-row"><div class="tabs" role="tablist" aria-label="리포트 종류">${tab('panel-summary', '요약', true)}${extensions
262
+ .map((x) => tab(extensionPanelId(x), x.title, false))
263
+ .join('')}</div>${moreMenu}`
264
+ : '';
265
+ const extPanels = extensions.map((x) => extensionHtml(x, blockCtx)).join('\n');
266
+ const summary = `${hasTabs ? reportBar : ''}${rendered.map((r) => r.body).join('\n')}`;
267
+ const summaryPanel = hasTabs
268
+ ? `<div id="panel-summary" role="tabpanel" aria-labelledby="tab-panel-summary" tabindex="0">${summary}</div>\n${extPanels}`
269
+ : summary;
270
+ const html = `<!doctype html>
271
+ <html lang="${e(base.lang)}">
272
+ <head>
273
+ <meta charset="utf-8">
274
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
275
+ <meta name="referrer" content="strict-origin-when-cross-origin">
276
+ <title>${e(meta.title)}</title>
277
+ <style>${CSS}</style>
278
+ ${hasTabs ? '<noscript><style>.ext{display:block!important}.tabs,.more-btn,.quiz-check,.zoom-btn{display:none}.quiz-exp{display:block!important}</style></noscript>' : ''}
279
+ </head>
280
+ <body>
281
+ <div class="layout">
282
+ <aside class="side">${player}${script}</aside>
283
+ <main class="main">
284
+ <header class="head"><h1>${e(meta.title)}</h1><p class="facts">${facts}</p><div class="tools"><button type="button" id="copy-md">마크다운 복사</button><label>글자 크기 <input id="font-range" type="range" min="85" max="145" step="5" value="100"> <output id="font-value">100%</output></label><p id="copy-status" class="sr-only" role="status" aria-live="polite"></p></div>
285
+ ${hasTabs ? '' : reportBar}
286
+ <noscript><p class="note">자바스크립트가 꺼져 있어 출처 툴팁과 키워드 팝업, 재생 따라가기, 리포트 전환이 동작하지 않아요.${isYoutube ? ' 시각 링크는 유튜브 새 탭으로 열려요.' : ''}</p></noscript></header>
287
+ ${tabRow}
288
+ ${summaryPanel}
289
+ </main>
290
+ </div>
291
+ ${rendered.map((r) => r.minimap).join('')}
292
+ <script type="application/json" id="digest-data">${embedJson(data)}</script>
293
+ <script>${VIEWER_JS}</script>
294
+ </body>
295
+ </html>
296
+ `;
297
+ return { html, warnings: [...new Set(warnings)] };
298
+ }
299
+ // 토큰은 research 렌더러와 같은 값을 쓴다
300
+ const CSS = `
301
+ :root{--bg:#fafaf9;--fg:#1c1917;--muted:#78716c;--line:#e7e5e4;--card:#fff;--accent:#2563eb;--warn:#b45309;--chip:#f5f5f4;--hl:#fef3c7;--on-accent:#fff;--scale:1;--float-w:min(360px,60vw,calc(40vh * 16 / 9))}
302
+ @media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--bg:#0c0a09;--fg:#f5f5f4;--muted:#a8a29e;--line:#292524;--card:#1c1917;--accent:#60a5fa;--warn:#fbbf24;--chip:#292524;--hl:#422006;--on-accent:#0c0a09}}
303
+ :root[data-theme="dark"]{--bg:#0c0a09;--fg:#f5f5f4;--muted:#a8a29e;--line:#292524;--card:#1c1917;--accent:#60a5fa;--warn:#fbbf24;--chip:#292524;--hl:#422006;--on-accent:#0c0a09}
304
+ *{box-sizing:border-box}
305
+ html{font-size:calc(100% * var(--scale))}
306
+ body{margin:0;background:var(--bg);color:var(--fg);font:1rem/1.7 -apple-system,BlinkMacSystemFont,"Apple SD Gothic Neo","Pretendard",sans-serif}
307
+ a{color:var(--accent)}
308
+ button{font:inherit;color:inherit}
309
+ .layout{display:grid;grid-template-columns:minmax(300px,420px) minmax(0,1fr);gap:32px;max-width:1360px;margin:0 auto;padding:0 56px 0 16px}
310
+ .side{position:sticky;top:0;height:100vh;display:flex;flex-direction:column;gap:12px;padding:16px 0}
311
+ .player{position:relative;background:#000;border-radius:8px;overflow:hidden;flex:none}
312
+ #player-frame{position:absolute;inset:0;width:100%;height:100%;border:0;opacity:0;pointer-events:none}
313
+ .player.is-live #player-frame{position:static;display:block;height:auto;aspect-ratio:16/9;opacity:1;pointer-events:auto}
314
+ .player.is-live .player-fallback{display:none}
315
+ .player-fallback{display:block;position:relative;color:#fff;text-decoration:none}
316
+ .player-fallback img{display:block;width:100%;aspect-ratio:16/9;object-fit:cover;opacity:.7}
317
+ .player-fallback span{position:absolute;inset:auto 0 0 0;padding:10px 14px;background:rgba(0,0,0,.6);font-weight:600}
318
+ .player-note{background:var(--chip);color:var(--muted);padding:12px 14px;font-size:.9em;margin:0}
319
+ .player-local video{display:none;width:100%;aspect-ratio:16/9;background:#000}
320
+ .player-local.is-live video{display:block}
321
+ .player-local.is-live .player-note{display:none}
322
+ .player-slot{flex:none}
323
+ .player-slot.is-floating{aspect-ratio:16/9}
324
+ .player.is-floating{position:fixed;right:calc(16px + env(safe-area-inset-right, 0px));bottom:calc(16px + env(safe-area-inset-bottom, 0px));width:var(--float-w);z-index:15;box-shadow:0 8px 24px rgba(0,0,0,.35)}
325
+ .player-dock{display:none;position:absolute;top:6px;right:6px;width:40px;height:40px;border:0;border-radius:50%;background:rgba(0,0,0,.6);color:#fff;cursor:pointer;align-items:center;justify-content:center;font-size:18px;line-height:1}
326
+ .player.is-floating .player-dock{display:flex}
327
+ .script{display:flex;flex-direction:column;min-height:0;flex:1;border:1px solid var(--line);border-radius:8px;background:var(--card)}
328
+ .script h2{margin:0;padding:8px 12px;font-size:.95em;border-bottom:1px solid var(--line)}
329
+ .script h2 small{color:var(--muted);font-weight:400}
330
+ .script-body{overflow:auto;flex:1;position:relative}
331
+ #script-list{list-style:none;margin:0;padding:4px 0}
332
+ #script-list li{display:flex;gap:10px;padding:4px 12px;font-size:.9em;line-height:1.55}
333
+ #script-list li.is-playing{background:var(--hl)}
334
+ .tr{display:block;color:var(--muted);font-size:.95em}
335
+ .script.hide-tr .tr{display:none}
336
+ .tr-toggle{float:right;border:1px solid var(--line);background:var(--card);border-radius:6px;padding:0 8px;font-size:.85em;font-weight:400;cursor:pointer}
337
+ .tr-toggle[aria-pressed="true"]{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
338
+ .ts{font-variant-numeric:tabular-nums;color:var(--accent);text-decoration:none;font-size:.85em;white-space:nowrap;cursor:pointer}
339
+ a.ts:hover{text-decoration:underline}
340
+ .main{padding:24px 0 96px;min-width:0}
341
+ .head h1{margin:0 0 4px;font-size:1.6em;line-height:1.35}
342
+ .facts{margin:0;color:var(--muted);display:flex;flex-wrap:wrap;gap:12px;font-size:.9em}
343
+ .tools{display:flex;flex-wrap:wrap;gap:16px;align-items:center;margin:12px 0;font-size:.85em;color:var(--muted)}
344
+ .tools button{border:1px solid var(--line);background:var(--card);border-radius:6px;padding:4px 10px;cursor:pointer}
345
+ .note{color:var(--warn);font-size:.9em}
346
+ .report-bar{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin:8px 0;font-size:.85em}
347
+ .report-bar .bar-label{color:var(--muted);margin-left:6px}
348
+ .report-bar .bar-label:first-child{margin-left:0}
349
+ .report-bar button{border:1px solid var(--line);background:var(--card);border-radius:999px;padding:3px 12px;cursor:pointer}
350
+ .report-bar button[aria-pressed="true"]{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
351
+ .report-bar select{font:inherit;color:inherit;background:var(--card);border:1px solid var(--line);border-radius:6px;padding:2px 6px}
352
+ .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
353
+ .report-missing{border:1px dashed var(--line);border-radius:8px;padding:8px 12px;margin:8px 0;font-size:.88em;background:var(--card)}
354
+ .report-missing p{margin:0 0 6px}
355
+ .report-missing code{display:block;white-space:nowrap;overflow-x:auto;background:var(--chip);padding:4px 8px;border-radius:4px;margin:0 0 6px}
356
+ #report-cmd{user-select:all}
357
+ .report-missing button{border:1px solid var(--line);background:var(--card);border-radius:6px;padding:2px 10px;cursor:pointer}
358
+ .report-scope{color:var(--muted);font-size:.9em;margin:12px 0 0}
359
+ .tab-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:8px;border-bottom:1px solid var(--line);margin:12px 0 8px}
360
+ .tabs{display:flex;flex-wrap:wrap;gap:2px}
361
+ .tabs [role="tab"]{border:0;border-bottom:2px solid transparent;background:none;color:var(--muted);padding:6px 12px;font:inherit;font-size:.92em;cursor:pointer}
362
+ .tabs [role="tab"][aria-selected="true"]{color:var(--fg);border-bottom-color:var(--accent);font-weight:600}
363
+ .more-btn{margin-left:auto;margin-bottom:4px;border:1px dashed var(--line);background:var(--card);border-radius:999px;padding:3px 12px;font-size:.85em;cursor:pointer}
364
+ .more-menu{border:1px solid var(--line);border-radius:8px;padding:8px 12px;margin:0 0 8px;background:var(--card);font-size:.88em}
365
+ .more-menu p{margin:0 0 6px;color:var(--muted)}
366
+ .more-menu ul{list-style:none;margin:0 0 6px;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:6px}
367
+ .more-menu li button{width:100%;text-align:left;border:1px solid var(--line);background:var(--bg);border-radius:6px;padding:6px 8px;cursor:pointer;color:inherit;font:inherit}
368
+ .more-menu li small{display:block;color:var(--muted);font-size:.85em}
369
+ .more-menu code{display:block;white-space:nowrap;overflow-x:auto;background:var(--chip);padding:4px 8px;border-radius:4px;margin:0 0 6px}
370
+ #more-copy{border:1px solid var(--line);background:var(--card);border-radius:6px;padding:2px 10px;cursor:pointer}
371
+ .ext h2{font-size:1.35em;border-bottom:1px solid var(--line);padding-bottom:6px}
372
+ .ext h3{font-size:1.1em;margin:20px 0 6px}
373
+ .ext h4{font-size:1em;margin:12px 0 4px}
374
+ .quote{margin:16px 0;padding:10px 16px;border-left:3px solid var(--accent);background:var(--chip);border-radius:0 8px 8px 0}
375
+ .quote blockquote{margin:0;font-size:1.05em}
376
+ .quote-tr{margin:6px 0 0;color:var(--muted)}
377
+ .quote figcaption{margin-top:6px;font-size:.9em;color:var(--muted);display:flex;flex-wrap:wrap;gap:8px}
378
+ .ext-toc{list-style:none;padding:0;margin:8px 0}
379
+ .ext-toc li{display:flex;gap:12px;padding:6px 0;border-bottom:1px solid var(--line)}
380
+ .ext-toc li .ts{flex:none;padding-top:2px}
381
+ .ext-toc p{margin:2px 0 0;color:var(--muted);font-size:.95em}
382
+ .actions{list-style:none;padding:0;margin:8px 0}
383
+ .actions li{display:flex;gap:10px;padding:4px 0}
384
+ .actions .box{flex:none;width:14px;height:14px;margin-top:6px;border:1.5px solid var(--muted);border-radius:3px}
385
+ .actions small{display:flex;gap:10px;color:var(--muted)}
386
+ .qa dt{font-weight:600;margin-top:12px}
387
+ .qa dt::before{content:"Q. ";color:var(--accent)}
388
+ .qa dd{margin:4px 0 0}
389
+ .cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:10px;margin:12px 0}
390
+ .card{border:1px solid var(--line);border-radius:10px;background:var(--card);padding:12px 14px}
391
+ .card summary{cursor:pointer;font-weight:600;list-style:none;display:flex;justify-content:space-between;gap:10px}
392
+ .card summary::-webkit-details-marker{display:none}
393
+ .card summary::after{content:"";flex:none;width:7px;height:7px;margin-top:.4em;border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);transform:rotate(45deg)}
394
+ .card[open] summary{color:var(--muted);font-weight:400;font-size:.9em}
395
+ .card[open] summary::after{transform:rotate(-135deg);margin-top:.6em}
396
+ .card-back{margin-top:8px}
397
+ .quiz{padding-left:20px}
398
+ .quiz-q{border:1px solid var(--line);border-radius:10px;background:var(--card);padding:10px 14px;margin:0 0 12px}
399
+ .quiz-q legend{font-weight:600;padding:0 4px}
400
+ .quiz-choice{display:block;padding:3px 0;cursor:pointer}
401
+ .quiz-check{margin-top:6px;border:1px solid var(--line);background:var(--bg);border-radius:6px;padding:2px 10px;cursor:pointer;color:inherit;font:inherit}
402
+ .quiz-exp{margin-top:8px;border-top:1px solid var(--line)}
403
+ .quiz-exp p{margin:6px 0}
404
+ .quiz-result{margin:6px 0}.quiz-result:empty{margin:0}
405
+ .quiz-q.is-right .quiz-result{color:var(--accent);font-weight:600}
406
+ .quiz-q.is-wrong .quiz-result{color:var(--warn);font-weight:600}
407
+ .quiz-choice.is-answer>span:not(.quiz-mark){background:var(--hl);font-weight:600}
408
+ .quiz-choice.is-picked>span:not(.quiz-mark){outline:2px dashed var(--warn);outline-offset:1px;border-radius:3px}
409
+ .diagram{margin:16px 0}
410
+ .fig-card{margin:24px 0}
411
+ .fig-card .diagram{margin:8px 0}
412
+ .fig-exp{margin:6px 0 0}
413
+ .dg-scroll{overflow-x:auto;border:1px solid var(--line);border-radius:10px;background:var(--card);padding:8px}
414
+ .dg-svg{display:block;max-width:none}
415
+ .dg-svg text{fill:var(--fg);font-size:13px;font-family:inherit}
416
+ .dg-svg rect{fill:var(--bg);stroke:var(--line)}
417
+ .dg-svg path,.dg-svg line{stroke:var(--muted);fill:none;stroke-width:1.2}
418
+ .dg-svg .mm-d0 rect,.dg-svg .dg-head rect{fill:var(--accent);stroke:var(--accent)}
419
+ .dg-svg .mm-d0 text,.dg-svg .dg-head text{fill:var(--on-accent);font-size:14px;font-weight:600}
420
+ .dg-svg .mm-d1 rect,.dg-flow rect,.dg-cycle rect,.dg-timeline rect{stroke:var(--accent)}
421
+ .dg-svg rect.dg-cell{fill:var(--card);stroke:var(--line);stroke-dasharray:4 3}
422
+ .dg-svg .dg-dot{fill:var(--accent);stroke:none}
423
+ .dg-svg .dg-when text{fill:var(--accent);font-weight:600}
424
+ .dg-svg .dg-axis text{fill:var(--muted)}
425
+ .dg-svg .dg-arrow{fill:var(--muted);stroke:none}
426
+ .dg-svg .mm-cite,.dg-svg .dg-cite{cursor:pointer}
427
+ .dg-svg .mm-cite:hover rect,.dg-svg .dg-cite:hover rect{fill:var(--hl)}
428
+ .dg-svg .mm-cite:focus{outline:none}.dg-svg .dg-cite:focus{outline:none}
429
+ .dg-svg .mm-cite:focus-visible rect,.dg-svg .dg-cite:focus-visible rect{stroke:var(--accent);stroke-width:2}
430
+ .dg-bar{display:flex;justify-content:flex-end;align-items:center;gap:8px;margin-top:4px;font-size:.9em;color:var(--muted)}
431
+ .dg-bar span{margin-right:auto}
432
+ .zoom-btn{border:1px solid var(--line);background:var(--card);border-radius:6px;padding:2px 10px;cursor:pointer;color:inherit;font:inherit}
433
+ .dg-outline{margin-top:4px;font-size:.92em}
434
+ .dg-outline summary{cursor:pointer;color:var(--muted)}
435
+ #zoom-dialog{width:min(96vw,1400px);max-height:92vh;border:1px solid var(--line);border-radius:12px;background:var(--card);color:var(--fg);padding:12px}
436
+ #zoom-dialog::backdrop{background:rgba(0,0,0,.5)}
437
+ #zoom-dialog .zoom-body{overflow:auto;max-height:calc(92vh - 64px)}
438
+ #zoom-dialog .zoom-body svg{width:100%;height:auto;min-width:600px}
439
+ #zoom-dialog .zoom-close{float:right}
440
+ .cm-overview{font-size:1.05em}
441
+ .cm-meta{color:var(--muted);font-size:.9em}
442
+ .cm-groups{list-style:none;padding:0}
443
+ .cm-group{border:1px solid var(--line);border-radius:10px;background:var(--card);padding:10px 14px;margin:0 0 10px}
444
+ .cm-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px}
445
+ .cm-tone{font-size:.8em;border-radius:999px;padding:0 8px;background:var(--chip);color:var(--muted)}
446
+ .cm-positive .cm-tone{color:var(--accent)}
447
+ .cm-negative .cm-tone{color:var(--warn)}
448
+ .cm-count{margin-left:auto;color:var(--muted);font-size:.9em}
449
+ .cm-bar{height:4px;background:var(--chip);border-radius:2px;margin:6px 0}
450
+ .cm-bar i{display:block;height:100%;background:currentColor;border-radius:2px;color:var(--muted)}
451
+ .cm-positive .cm-bar i{color:var(--accent)}
452
+ .cm-negative .cm-bar i{color:var(--warn)}
453
+ .cm-ex{padding-left:18px;color:var(--muted);font-size:.95em}
454
+ .cm-ex q{white-space:pre-line}
455
+ body[data-tab="ext"] .minimap{display:none}
456
+ .lead{border-left:3px solid var(--accent);padding:4px 16px;margin:20px 0}
457
+ .lead .q{font-weight:700;font-size:1.1em}
458
+ .lead .takeaway{color:var(--muted)}
459
+ .toc{border:1px solid var(--line);border-radius:8px;padding:8px 20px;background:var(--card);margin:20px 0}
460
+ .toc h2{font-size:1em;margin:8px 0}
461
+ .toc ol{list-style:none;padding-left:0;margin:4px 0}
462
+ .toc ol ol{padding-left:16px;font-size:.92em}
463
+ .toc a{text-decoration:none;color:var(--fg)}
464
+ .toc a.is-current{color:var(--accent);font-weight:600}
465
+ .sec{scroll-margin-top:16px;padding-top:12px}
466
+ .sec h2{font-size:1.35em;border-bottom:1px solid var(--line);padding-bottom:6px}
467
+ .sub{scroll-margin-top:16px;container-type:inline-size}
468
+ .sub h3{font-size:1.1em;margin:24px 0 8px}
469
+ .num{color:var(--muted)}
470
+ .conclusion{font-weight:500}
471
+ .frame{margin:8px 0 12px}
472
+ .frame img{display:block;width:100%;max-width:640px;height:auto;max-height:360px;aspect-ratio:auto 16/9;object-fit:contain;border-radius:6px;border:1px solid var(--line);cursor:pointer}
473
+ .frame figcaption{margin-top:2px}
474
+ .sub-body.has-shots{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);gap:16px;align-items:start}
475
+ .shots{display:flex;flex-direction:column;gap:12px;margin:8px 0}
476
+ .shot{margin:0}
477
+ .shot-btn{display:block;width:100%;padding:0;border:0;border-radius:8px;background:none;cursor:zoom-in}
478
+ .shot img{display:block;width:100%;height:auto;aspect-ratio:auto 16/9;object-fit:contain;border:1px solid var(--line);border-radius:8px;background:var(--card)}
479
+ .sub-body.has-shots .shot img{max-height:50vh}
480
+ .shot figcaption{margin-top:4px;font-size:.92em;color:var(--muted)}
481
+ #zoom-dialog .zoom-body img{display:block;max-width:100%;width:auto;height:auto;max-height:calc(92vh - 64px);object-fit:contain;margin:0 auto}
482
+ .cite{border:0;background:none;padding:0 1px;color:var(--accent);cursor:pointer;font-size:.8em}
483
+ .kw{border:0;background:none;padding:0;border-bottom:1px dashed var(--accent);cursor:pointer}
484
+ .extra dt{font-weight:600;margin-top:8px}
485
+ .extra dd{margin:0 0 4px 0;color:var(--muted)}
486
+ .pop{position:absolute;z-index:20;max-width:min(420px,calc(100vw - 16px));background:var(--card);border:1px solid var(--line);border-radius:8px;box-shadow:0 6px 24px rgba(0,0,0,.18);padding:10px 12px;font-size:.88em}
487
+ .pop-head{display:flex;gap:6px;align-items:baseline;margin-bottom:4px}
488
+ .pop-range,.pop-more{color:var(--muted)}
489
+ .pop-lines{margin:0;padding-left:18px}
490
+ .pop-lines li.is-key{font-weight:600}
491
+ .pop p{margin:4px 0 0}
492
+ .minimap{position:fixed;right:12px;top:50%;transform:translateY(-50%);display:flex;flex-direction:column;gap:6px;z-index:10}
493
+ .minimap a{display:flex;width:28px;height:28px;border-radius:50%;align-items:center;justify-content:center;background:var(--card);border:1px solid var(--line);color:var(--muted);text-decoration:none;font-size:12px}
494
+ .minimap a.is-current{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
495
+ .minimap[hidden]{display:none}
496
+ @container (max-width:640px){.sub-body.has-shots{grid-template-columns:minmax(0,1fr)}}
497
+ @media (max-width:900px){
498
+ .layout{grid-template-columns:minmax(0,1fr);padding:0 16px;gap:0}
499
+ .side{position:static;height:auto}
500
+ .script-body{max-height:40vh}
501
+ .minimap{display:none}
502
+ .main{padding-bottom:calc(var(--float-w) * 9 / 16 + 32px + env(safe-area-inset-bottom, 0px))}
503
+ }
504
+ `;
505
+ //# sourceMappingURL=render-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-html.js","sourceRoot":"","sources":["../../../src/digest/render-html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { Extension } from './blocks.js';
2
+ import { type Digest, type Report, type Transcript } from './schema.js';
3
+ export interface RenderMdOptions {
4
+ /** 이 이름의 프레임이 있으면 소섹션에 `<framesHref>/...` 상대 경로로 싣는다 */
5
+ frameExists?: (fileName: string) => boolean;
6
+ /** 마크다운 파일에서 frames 폴더까지의 상대 경로. 슬러그 폴더 밖에 쓸 때만 바꾼다 */
7
+ framesHref?: string;
8
+ /** 내보낼 리포트. 없으면 첫 리포트다 */
9
+ report?: Report;
10
+ }
11
+ /**
12
+ * digest.json을 마크다운 한 파일로 바꾼다. LLM을 부르지 않는다.
13
+ * 기존 video-summarizer가 직접 쓰던 마크다운을 이 출력이 대신한다.
14
+ */
15
+ export declare function renderDigestMarkdown(digest: Digest, transcript: Transcript, opts?: RenderMdOptions): string;
16
+ /** 확장 리포트 한 벌을 마크다운으로. 머리말은 요약 마크다운과 같다 */
17
+ export declare function renderExtensionMarkdown(ext: Extension, transcript: Transcript): string;
18
+ //# sourceMappingURL=render-md.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-md.d.ts","sourceRoot":"","sources":["../../../src/digest/render-md.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAK7C,OAAO,EAIL,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5C,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,IAAI,GAAE,eAAoB,GACzB,MAAM,CAyER;AAED,2CAA2C;AAC3C,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,GAAG,MAAM,CAOtF"}