@dotit/core 1.0.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 (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +229 -0
  3. package/dist/aliases.d.ts +1 -0
  4. package/dist/aliases.js +8 -0
  5. package/dist/ask.d.ts +7 -0
  6. package/dist/ask.js +55 -0
  7. package/dist/browser.d.ts +12 -0
  8. package/dist/browser.js +32 -0
  9. package/dist/diff.d.ts +17 -0
  10. package/dist/diff.js +179 -0
  11. package/dist/document-css.d.ts +1 -0
  12. package/dist/document-css.js +290 -0
  13. package/dist/executor.d.ts +40 -0
  14. package/dist/executor.js +501 -0
  15. package/dist/history.d.ts +10 -0
  16. package/dist/history.js +297 -0
  17. package/dist/html-to-it.d.ts +1 -0
  18. package/dist/html-to-it.js +288 -0
  19. package/dist/index-builder.d.ts +62 -0
  20. package/dist/index-builder.js +228 -0
  21. package/dist/index.d.ts +39 -0
  22. package/dist/index.js +94 -0
  23. package/dist/language-registry.d.ts +39 -0
  24. package/dist/language-registry.js +530 -0
  25. package/dist/markdown.d.ts +1 -0
  26. package/dist/markdown.js +123 -0
  27. package/dist/merge.d.ts +6 -0
  28. package/dist/merge.js +255 -0
  29. package/dist/parser.d.ts +29 -0
  30. package/dist/parser.js +1562 -0
  31. package/dist/query.d.ts +32 -0
  32. package/dist/query.js +293 -0
  33. package/dist/renderer.d.ts +16 -0
  34. package/dist/renderer.js +1286 -0
  35. package/dist/schema.d.ts +47 -0
  36. package/dist/schema.js +574 -0
  37. package/dist/source.d.ts +3 -0
  38. package/dist/source.js +223 -0
  39. package/dist/theme.d.ts +49 -0
  40. package/dist/theme.js +113 -0
  41. package/dist/themes/corporate.json +86 -0
  42. package/dist/themes/dark.json +64 -0
  43. package/dist/themes/editorial.json +54 -0
  44. package/dist/themes/legal.json +57 -0
  45. package/dist/themes/minimal.json +50 -0
  46. package/dist/themes/print.json +54 -0
  47. package/dist/themes/technical.json +59 -0
  48. package/dist/themes/warm.json +53 -0
  49. package/dist/trust.d.ts +66 -0
  50. package/dist/trust.js +200 -0
  51. package/dist/types.d.ts +234 -0
  52. package/dist/types.js +19 -0
  53. package/dist/utils.d.ts +2 -0
  54. package/dist/utils.js +13 -0
  55. package/dist/validate.d.ts +13 -0
  56. package/dist/validate.js +711 -0
  57. package/dist/workflow.d.ts +18 -0
  58. package/dist/workflow.js +160 -0
  59. package/package.json +51 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 IntentText Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,229 @@
1
+ # @dotit/core
2
+
3
+ Parser, HTML renderer, and document generation engine for **IntentText** (`.it`) — a structured interchange format for AI agents and humans.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @dotit/core
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { parseIntentText, renderHTML } from "@dotit/core";
15
+
16
+ const doc = parseIntentText(`
17
+ title: Sprint Planning — Week 12
18
+ summary: Tasks and decisions for the week.
19
+
20
+ section: Action Items
21
+ task: Write migration script | owner: Sarah | due: Wednesday
22
+ task: Update CI pipeline | owner: Dev Team | due: Friday
23
+ done: Security audit complete
24
+
25
+ section: Notes
26
+ note: Next demo on Friday 3pm.
27
+ info: New staging environment is live.
28
+ `);
29
+
30
+ console.log(doc.version); // "1.4"
31
+ console.log(doc.blocks.length); // 8
32
+
33
+ const html = renderHTML(doc); // Styled HTML output
34
+ ```
35
+
36
+ > Pure TypeScript — no native or WASM dependency. Runs unchanged in Node and the
37
+ > browser. (The earlier Rust/WASM engine was removed in v4; the TS parser is the
38
+ > single canonical implementation. See [SPEC.md](./SPEC.md).)
39
+
40
+ ## API
41
+
42
+ ### Parsing
43
+
44
+ ```typescript
45
+ import { parseIntentText } from "@dotit/core";
46
+
47
+ const doc = parseIntentText(source);
48
+ // Returns: IntentDocument { version, metadata, blocks, diagnostics }
49
+ ```
50
+
51
+ ### Rendering
52
+
53
+ ```typescript
54
+ import { renderHTML, renderPrint } from "@dotit/core";
55
+
56
+ // Inline HTML fragment (for embedding in a page)
57
+ const html = renderHTML(doc);
58
+
59
+ // Full print-optimized HTML document with embedded CSS
60
+ // Reads font: and page: blocks for dynamic typography and layout
61
+ const printHtml = renderPrint(doc);
62
+ ```
63
+
64
+ ### Template Merge
65
+
66
+ Resolve `{{variable}}` placeholders in a parsed document using a JSON data object.
67
+
68
+ ```typescript
69
+ import { mergeData, parseAndMerge } from "@dotit/core";
70
+
71
+ const data = {
72
+ company: { name: "Acme Corp" },
73
+ invoice_number: "INV-2026-001",
74
+ total: "17,325 QAR",
75
+ };
76
+
77
+ // Merge after parsing
78
+ const merged = mergeData(doc, data);
79
+
80
+ // Parse + merge in one step
81
+ const result = parseAndMerge(templateString, data);
82
+ ```
83
+
84
+ - Dot notation: `{{company.name}}` → `data.company.name`
85
+ - Array indices: `{{items.0.description}}` → `data.items[0].description`
86
+ - System variables: `{{date}}`, `{{year}}` resolved automatically
87
+ - Runtime variables: `{{page}}`, `{{pages}}` become CSS page counters in `renderPrint`
88
+ - Missing fields: `parseAndMerge(src, data, { missing: "blank" })` renders an
89
+ unresolved `{{field}}` empty — use for finished documents so an invoice never
90
+ prints a literal `{{customer.phone}}` (default `"keep"` aids template authoring)
91
+
92
+ ### Server-side PDFs
93
+
94
+ For real PDF bytes on a server (email attachments, archiving, batch runs) use the
95
+ opt-in companion **[`@dotit/pdf`](https://www.npmjs.com/package/@dotit/pdf)** —
96
+ `issuePDF(template, data, { signer })` runs merge → **seal** (tamper-evident SHA-256) →
97
+ PDF in one call. Core itself stays zero-dependency.
98
+
99
+ ### Querying
100
+
101
+ ```typescript
102
+ import { queryBlocks } from "@dotit/core";
103
+
104
+ const result = queryBlocks(doc, "type:task owner:Ahmed sort:due:asc limit:5");
105
+ console.log(result.blocks); // Filtered & sorted blocks
106
+ ```
107
+
108
+ ### Trust — sign, seal, verify
109
+
110
+ `.it` documents are tamper-evident. `sealDocument` records a signer and freezes the
111
+ content with a SHA-256 hash; `verifyDocument` recomputes it and reports integrity.
112
+
113
+ ```typescript
114
+ import { sealDocument, verifyDocument } from "@dotit/core";
115
+
116
+ const sealed = sealDocument(source, { signer: "Sarah Chen", role: "Legal" });
117
+ const result = verifyDocument(sealed.source);
118
+ console.log(result.intact); // true — false if a single character changed
119
+ ```
120
+
121
+ The hashing rules are open and documented in [SPEC.md](./SPEC.md), so anyone with the
122
+ library can verify independently.
123
+
124
+ ### Converters
125
+
126
+ ```typescript
127
+ import { convertMarkdownToIntentText } from "@dotit/core";
128
+
129
+ const itSource = convertMarkdownToIntentText(markdownString);
130
+ ```
131
+
132
+ ## Syntax Overview
133
+
134
+ ### Structure & Content
135
+
136
+ ```
137
+ title: My Document
138
+ section: Chapter One
139
+ sub: Details
140
+ note: A standalone fact.
141
+ task: Do something | owner: Ahmed | due: Friday
142
+ done: Already finished | time: Monday
143
+ quote: Be concise. | by: Strunk
144
+ info: Informational callout.
145
+ ---
146
+ ```
147
+
148
+ ### Agentic Workflows (v2.0+)
149
+
150
+ ```
151
+ agent: deploy-agent | model: claude-sonnet-4
152
+ step: Run tests | tool: ci.test | timeout: 300000
153
+ decision: Pass? | if: tests == "pass" | then: step-2 | else: step-3
154
+ gate: Approve deploy | approver: ops-lead | timeout: 24h
155
+ handoff: Transfer | from: deploy-agent | to: monitor-agent
156
+ emit: Complete | phase: deploy | level: success
157
+ ```
158
+
159
+ ### Document Generation (v2.5)
160
+
161
+ ```
162
+ font: | family: Palatino Linotype | size: 12pt | leading: 1.8
163
+ page: | size: A5 | margins: 25mm | footer: Page {{page}} of {{pages}}
164
+
165
+ title: *Chapter One*
166
+ dedication: To the builders who write before they code.
167
+ byline: Ahmed Al-Rashid | role: Author
168
+ epigraph: The tools we build shape the thoughts we can think. | source: Kenneth Iverson
169
+ toc: | depth: 2 | title: Contents
170
+
171
+ section: Introduction
172
+ caption: Figure 1 — The parsing pipeline
173
+ footnote: 1 | See chapter 3 for details.
174
+ break:
175
+ ```
176
+
177
+ ### Inline Formatting
178
+
179
+ | Style | Syntax |
180
+ | ------------- | ------------ |
181
+ | Bold | `*text*` |
182
+ | Italic | `_text_` |
183
+ | Strikethrough | `~text~` |
184
+ | Code | `` `code` `` |
185
+ | Highlight | `^text^` |
186
+ | Inline note | `[[text]]` |
187
+ | Footnote ref | `{1}` |
188
+ | Styled span | `[text]{ color: #c00; weight: bold }` — style part of a line |
189
+
190
+ ### Styling (three layers)
191
+
192
+ 1. **Theme** — `renderHTML(doc, { theme: "corporate" })` (8 built-in document classes)
193
+ 2. **`style:` rules (v4.3)** — house styling per block type, declared once:
194
+ `style: section | color: #0a7 | weight: 600`
195
+ (targets: title, summary, section, sub, text, quote, callout/info, table,
196
+ table-header, metric, contact, divider; same constrained style keys — never
197
+ arbitrary CSS, content stays queryable)
198
+ 3. **Per-line props / inline spans** — exceptions: `text: hi | color: red`,
199
+ `[word]{ size: 1.2em }` (most-specific wins)
200
+
201
+ ## CLI
202
+
203
+ ```bash
204
+ node cli.js document.it # Parse to JSON
205
+ node cli.js document.it --html # Render HTML
206
+ node cli.js template.it --data data.json --html # Merge + render
207
+ node cli.js template.it --data data.json --print # Print-optimized HTML
208
+ node cli.js template.it --data data.json --pdf out.pdf # PDF via Puppeteer
209
+ ```
210
+
211
+ ## Test Suite
212
+
213
+ 869 tests covering parser, renderer, query engine, converters, agentic blocks,
214
+ document generation, trust/seal, and round-trip serialization.
215
+
216
+ ```bash
217
+ pnpm test
218
+ ```
219
+
220
+ ## Links
221
+
222
+ - [Full Specification](https://itdocs.vercel.app/docs/reference)
223
+ - [Usage Guide](https://itdocs.vercel.app/docs/guide)
224
+ - [Changelog](https://github.com/intenttext/IntentText/blob/main/CHANGELOG.md)
225
+ - [Example Templates](https://github.com/intenttext/IntentText/tree/main/examples/templates)
226
+
227
+ ## License
228
+
229
+ MIT
@@ -0,0 +1 @@
1
+ export declare const ALIASES: Record<string, string>;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ALIASES = void 0;
4
+ const language_registry_1 = require("./language-registry");
5
+ exports.ALIASES = {
6
+ ...language_registry_1.ALIAS_MAP,
7
+ ...language_registry_1.EXTENSION_LEGACY_ALIASES,
8
+ };
package/dist/ask.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { ComposedResult } from "./index-builder";
2
+ export interface AskOptions {
3
+ maxTokens?: number;
4
+ format?: "text" | "json";
5
+ }
6
+ export declare function serializeContext(results: ComposedResult[]): string;
7
+ export declare function askDocuments(results: ComposedResult[], question: string, options?: AskOptions): Promise<string>;
package/dist/ask.js ADDED
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serializeContext = serializeContext;
4
+ exports.askDocuments = askDocuments;
5
+ function serializeContext(results) {
6
+ const lines = [];
7
+ let currentFile = "";
8
+ for (const r of results) {
9
+ if (r.file !== currentFile) {
10
+ currentFile = r.file;
11
+ lines.push(`\n--- ${r.file} ---`);
12
+ }
13
+ const props = Object.entries(r.block.properties)
14
+ .map(([k, v]) => `${k}: ${v}`)
15
+ .join(" | ");
16
+ const section = r.block.section ? ` [${r.block.section}]` : "";
17
+ lines.push(`[${r.block.type}]${section} ${r.block.content}${props ? " | " + props : ""}`);
18
+ }
19
+ return lines.join("\n");
20
+ }
21
+ async function askDocuments(results, question, options = {}) {
22
+ const apiKey = process.env.ANTHROPIC_API_KEY;
23
+ if (!apiKey) {
24
+ return "Error: ANTHROPIC_API_KEY environment variable is not set.\nSet it with: export ANTHROPIC_API_KEY=your-key-here";
25
+ }
26
+ const context = serializeContext(results);
27
+ const maxTokens = options.maxTokens ?? 1024;
28
+ const formatHint = options.format === "json"
29
+ ? "\nReturn your answer as valid JSON when possible."
30
+ : "";
31
+ const systemPrompt = `You are a helpful assistant that answers questions about IntentText (.it) documents. You will be given a structured representation of document blocks from one or more .it files. Answer the user's question based only on the provided document data. Be concise and factual.${formatHint}`;
32
+ const userMessage = `Here are the document contents:\n${context}\n\nQuestion: ${question}`;
33
+ const body = JSON.stringify({
34
+ model: "claude-sonnet-4-20250514",
35
+ max_tokens: maxTokens,
36
+ system: systemPrompt,
37
+ messages: [{ role: "user", content: userMessage }],
38
+ });
39
+ const response = await fetch("https://api.anthropic.com/v1/messages", {
40
+ method: "POST",
41
+ headers: {
42
+ "Content-Type": "application/json",
43
+ "x-api-key": apiKey,
44
+ "anthropic-version": "2023-06-01",
45
+ },
46
+ body,
47
+ });
48
+ if (!response.ok) {
49
+ const errorText = await response.text();
50
+ return `Error: Anthropic API returned ${response.status}: ${errorText}`;
51
+ }
52
+ const data = (await response.json());
53
+ const textBlocks = data.content.filter((c) => c.type === "text");
54
+ return textBlocks.map((b) => b.text).join("\n");
55
+ }
@@ -0,0 +1,12 @@
1
+ export { parseIntentText, parseIntentTextSafe } from "./parser";
2
+ export { renderHTML, renderPrint } from "./renderer";
3
+ export { mergeData, parseAndMerge } from "./merge";
4
+ export { convertMarkdownToIntentText } from "./markdown";
5
+ export { queryBlocks, parseQuery, formatQueryResult, queryDocument, } from "./query";
6
+ export { validateDocument, createSchema, formatValidationResult, PREDEFINED_SCHEMAS, } from "./schema";
7
+ export { documentToSource } from "./source";
8
+ export { validateDocumentSemantic } from "./validate";
9
+ export { diffDocuments } from "./diff";
10
+ export { extractWorkflow } from "./workflow";
11
+ export type { WorkflowStep, WorkflowGraph } from "./workflow";
12
+ export type { IntentDocument, IntentBlock, BlockType, InlineNode, ParseOptions, Diagnostic, AgenticStatus, IntentDocumentMetadata, } from "./types";
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractWorkflow = exports.diffDocuments = exports.validateDocumentSemantic = exports.documentToSource = exports.PREDEFINED_SCHEMAS = exports.formatValidationResult = exports.createSchema = exports.validateDocument = exports.queryDocument = exports.formatQueryResult = exports.parseQuery = exports.queryBlocks = exports.convertMarkdownToIntentText = exports.parseAndMerge = exports.mergeData = exports.renderPrint = exports.renderHTML = exports.parseIntentTextSafe = exports.parseIntentText = void 0;
4
+ var parser_1 = require("./parser");
5
+ Object.defineProperty(exports, "parseIntentText", { enumerable: true, get: function () { return parser_1.parseIntentText; } });
6
+ Object.defineProperty(exports, "parseIntentTextSafe", { enumerable: true, get: function () { return parser_1.parseIntentTextSafe; } });
7
+ var renderer_1 = require("./renderer");
8
+ Object.defineProperty(exports, "renderHTML", { enumerable: true, get: function () { return renderer_1.renderHTML; } });
9
+ Object.defineProperty(exports, "renderPrint", { enumerable: true, get: function () { return renderer_1.renderPrint; } });
10
+ var merge_1 = require("./merge");
11
+ Object.defineProperty(exports, "mergeData", { enumerable: true, get: function () { return merge_1.mergeData; } });
12
+ Object.defineProperty(exports, "parseAndMerge", { enumerable: true, get: function () { return merge_1.parseAndMerge; } });
13
+ var markdown_1 = require("./markdown");
14
+ Object.defineProperty(exports, "convertMarkdownToIntentText", { enumerable: true, get: function () { return markdown_1.convertMarkdownToIntentText; } });
15
+ var query_1 = require("./query");
16
+ Object.defineProperty(exports, "queryBlocks", { enumerable: true, get: function () { return query_1.queryBlocks; } });
17
+ Object.defineProperty(exports, "parseQuery", { enumerable: true, get: function () { return query_1.parseQuery; } });
18
+ Object.defineProperty(exports, "formatQueryResult", { enumerable: true, get: function () { return query_1.formatQueryResult; } });
19
+ Object.defineProperty(exports, "queryDocument", { enumerable: true, get: function () { return query_1.queryDocument; } });
20
+ var schema_1 = require("./schema");
21
+ Object.defineProperty(exports, "validateDocument", { enumerable: true, get: function () { return schema_1.validateDocument; } });
22
+ Object.defineProperty(exports, "createSchema", { enumerable: true, get: function () { return schema_1.createSchema; } });
23
+ Object.defineProperty(exports, "formatValidationResult", { enumerable: true, get: function () { return schema_1.formatValidationResult; } });
24
+ Object.defineProperty(exports, "PREDEFINED_SCHEMAS", { enumerable: true, get: function () { return schema_1.PREDEFINED_SCHEMAS; } });
25
+ var source_1 = require("./source");
26
+ Object.defineProperty(exports, "documentToSource", { enumerable: true, get: function () { return source_1.documentToSource; } });
27
+ var validate_1 = require("./validate");
28
+ Object.defineProperty(exports, "validateDocumentSemantic", { enumerable: true, get: function () { return validate_1.validateDocumentSemantic; } });
29
+ var diff_1 = require("./diff");
30
+ Object.defineProperty(exports, "diffDocuments", { enumerable: true, get: function () { return diff_1.diffDocuments; } });
31
+ var workflow_1 = require("./workflow");
32
+ Object.defineProperty(exports, "extractWorkflow", { enumerable: true, get: function () { return workflow_1.extractWorkflow; } });
package/dist/diff.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { IntentDocument, IntentBlock } from "./types";
2
+ export interface BlockModification {
3
+ blockId: string;
4
+ before: IntentBlock;
5
+ after: IntentBlock;
6
+ contentChanged: boolean;
7
+ propertiesChanged: string[];
8
+ typeChanged: boolean;
9
+ }
10
+ export interface DocumentDiff {
11
+ added: IntentBlock[];
12
+ removed: IntentBlock[];
13
+ modified: BlockModification[];
14
+ unchanged: IntentBlock[];
15
+ summary: string;
16
+ }
17
+ export declare function diffDocuments(before: IntentDocument, after: IntentDocument): DocumentDiff;
package/dist/diff.js ADDED
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.diffDocuments = diffDocuments;
4
+ const utils_1 = require("./utils");
5
+ function diffDocuments(before, after) {
6
+ const beforeBlocks = before?.blocks ? (0, utils_1.flattenBlocks)(before.blocks) : [];
7
+ const afterBlocks = after?.blocks ? (0, utils_1.flattenBlocks)(after.blocks) : [];
8
+ const added = [];
9
+ const removed = [];
10
+ const modified = [];
11
+ const unchanged = [];
12
+ const matchedBefore = new Set();
13
+ const matchedAfter = new Set();
14
+ for (let i = 0; i < beforeBlocks.length; i++) {
15
+ if (matchedBefore.has(i))
16
+ continue;
17
+ for (let j = 0; j < afterBlocks.length; j++) {
18
+ if (matchedAfter.has(j))
19
+ continue;
20
+ if (beforeBlocks[i].type === afterBlocks[j].type &&
21
+ beforeBlocks[i].content === afterBlocks[j].content) {
22
+ const propChanges = diffProperties(beforeBlocks[i], afterBlocks[j]);
23
+ if (propChanges.length === 0) {
24
+ unchanged.push(beforeBlocks[i]);
25
+ }
26
+ else {
27
+ modified.push({
28
+ blockId: beforeBlocks[i].id,
29
+ before: beforeBlocks[i],
30
+ after: afterBlocks[j],
31
+ contentChanged: false,
32
+ propertiesChanged: propChanges,
33
+ typeChanged: false,
34
+ });
35
+ }
36
+ matchedBefore.add(i);
37
+ matchedAfter.add(j);
38
+ break;
39
+ }
40
+ }
41
+ }
42
+ for (let i = 0; i < beforeBlocks.length; i++) {
43
+ if (matchedBefore.has(i))
44
+ continue;
45
+ let bestJ = -1;
46
+ let bestSim = 0;
47
+ for (let j = 0; j < afterBlocks.length; j++) {
48
+ if (matchedAfter.has(j))
49
+ continue;
50
+ if (beforeBlocks[i].type !== afterBlocks[j].type)
51
+ continue;
52
+ const sim = similarity(beforeBlocks[i].content, afterBlocks[j].content);
53
+ if (sim > 0.8 && sim > bestSim) {
54
+ bestSim = sim;
55
+ bestJ = j;
56
+ }
57
+ }
58
+ if (bestJ >= 0) {
59
+ const propChanges = diffProperties(beforeBlocks[i], afterBlocks[bestJ]);
60
+ modified.push({
61
+ blockId: beforeBlocks[i].id,
62
+ before: beforeBlocks[i],
63
+ after: afterBlocks[bestJ],
64
+ contentChanged: beforeBlocks[i].content !== afterBlocks[bestJ].content,
65
+ propertiesChanged: propChanges,
66
+ typeChanged: false,
67
+ });
68
+ matchedBefore.add(i);
69
+ matchedAfter.add(bestJ);
70
+ }
71
+ }
72
+ for (let i = 0; i < beforeBlocks.length; i++) {
73
+ if (matchedBefore.has(i))
74
+ continue;
75
+ let bestJ = -1;
76
+ let bestSim = 0;
77
+ for (let j = 0; j < afterBlocks.length; j++) {
78
+ if (matchedAfter.has(j))
79
+ continue;
80
+ const sim = similarity(beforeBlocks[i].content, afterBlocks[j].content);
81
+ if (sim > 0.8 && sim > bestSim) {
82
+ bestSim = sim;
83
+ bestJ = j;
84
+ }
85
+ }
86
+ if (bestJ >= 0) {
87
+ const propChanges = diffProperties(beforeBlocks[i], afterBlocks[bestJ]);
88
+ modified.push({
89
+ blockId: beforeBlocks[i].id,
90
+ before: beforeBlocks[i],
91
+ after: afterBlocks[bestJ],
92
+ contentChanged: beforeBlocks[i].content !== afterBlocks[bestJ].content,
93
+ propertiesChanged: propChanges,
94
+ typeChanged: beforeBlocks[i].type !== afterBlocks[bestJ].type,
95
+ });
96
+ matchedBefore.add(i);
97
+ matchedAfter.add(bestJ);
98
+ }
99
+ }
100
+ for (let i = 0; i < beforeBlocks.length; i++) {
101
+ if (!matchedBefore.has(i))
102
+ removed.push(beforeBlocks[i]);
103
+ }
104
+ for (let j = 0; j < afterBlocks.length; j++) {
105
+ if (!matchedAfter.has(j))
106
+ added.push(afterBlocks[j]);
107
+ }
108
+ const parts = [];
109
+ if (added.length > 0)
110
+ parts.push(`${added.length} added`);
111
+ if (removed.length > 0)
112
+ parts.push(`${removed.length} removed`);
113
+ if (modified.length > 0)
114
+ parts.push(`${modified.length} modified`);
115
+ if (unchanged.length > 0)
116
+ parts.push(`${unchanged.length} unchanged`);
117
+ const summary = parts.join(", ") || "no changes";
118
+ return { added, removed, modified, unchanged, summary };
119
+ }
120
+ function diffProperties(a, b) {
121
+ const propsA = a.properties || {};
122
+ const propsB = b.properties || {};
123
+ const allKeys = new Set([...Object.keys(propsA), ...Object.keys(propsB)]);
124
+ const changed = [];
125
+ for (const key of allKeys) {
126
+ if (String(propsA[key] ?? "") !== String(propsB[key] ?? "")) {
127
+ changed.push(key);
128
+ }
129
+ }
130
+ return changed;
131
+ }
132
+ function similarity(a, b) {
133
+ if (a === b)
134
+ return 1;
135
+ if (a.length === 0 && b.length === 0)
136
+ return 1;
137
+ if (a.length === 0 || b.length === 0)
138
+ return 0;
139
+ const maxLen = Math.max(a.length, b.length);
140
+ if (maxLen > 1000) {
141
+ return quickSimilarity(a, b);
142
+ }
143
+ const dist = levenshtein(a, b);
144
+ return 1 - dist / maxLen;
145
+ }
146
+ function levenshtein(a, b) {
147
+ const m = a.length;
148
+ const n = b.length;
149
+ let prev = new Array(n + 1);
150
+ let curr = new Array(n + 1);
151
+ for (let j = 0; j <= n; j++)
152
+ prev[j] = j;
153
+ for (let i = 1; i <= m; i++) {
154
+ curr[0] = i;
155
+ for (let j = 1; j <= n; j++) {
156
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
157
+ curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
158
+ }
159
+ [prev, curr] = [curr, prev];
160
+ }
161
+ return prev[n];
162
+ }
163
+ function quickSimilarity(a, b) {
164
+ const triA = new Set();
165
+ const triB = new Set();
166
+ for (let i = 0; i <= a.length - 3; i++)
167
+ triA.add(a.slice(i, i + 3));
168
+ for (let i = 0; i <= b.length - 3; i++)
169
+ triB.add(b.slice(i, i + 3));
170
+ let shared = 0;
171
+ for (const t of triA) {
172
+ if (triB.has(t))
173
+ shared++;
174
+ }
175
+ const total = triA.size + triB.size;
176
+ if (total === 0)
177
+ return 1;
178
+ return (2 * shared) / total;
179
+ }
@@ -0,0 +1 @@
1
+ export declare const DOCUMENT_CSS = "\n/* \u2500\u2500 Base \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-document{font-family:Georgia,'Times New Roman',serif;line-height:1.7;color:#111;max-width:680px;margin:0 auto;padding:32px 24px;}\n/* \u2500\u2500 Typography \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-title{font-size:1.75rem;line-height:1.2;margin:0 0 12px;font-weight:700;letter-spacing:-0.01em;}\n.intent-summary{margin:8px 0 20px;padding:8px 0 8px 14px;border-left:2px solid #999;color:#333;font-style:italic;font-size:0.95rem;}\n.intent-section{margin:24px 0 8px;font-size:1.1rem;line-height:1.3;font-weight:600;padding-bottom:4px;border-bottom:1px solid #ccc;}\n.intent-sub{margin:16px 0 6px;font-size:1rem;line-height:1.3;font-weight:600;}\n.intent-note{margin:6px 0;color:#222;}\n.intent-prose{margin:0 0 1em;color:#222;font-size:1rem;line-height:1.8;max-width:65ch;text-wrap:pretty;}\n.intent-align-center{text-align:center;}\n.intent-align-right{text-align:right;}\n.intent-align-justify{text-align:justify;}\n/* \u2500\u2500 Divider \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-divider{margin:18px 0;text-align:center;}\n.intent-divider-line{border:none;border-top:1px solid #ccc;margin:0;}\n.intent-divider-label{display:inline-block;padding:0 10px;background:#fff;color:#888;font-size:0.78rem;position:relative;top:-9px;}\n/* \u2500\u2500 Tasks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-task{display:flex;align-items:flex-start;gap:8px;padding:7px 10px;border:1px solid #ddd;margin:5px 0;}\n.intent-task-checkbox{margin-top:3px;flex-shrink:0;}\n.intent-task-text{flex:1;}\n.intent-task-meta{display:flex;gap:6px;color:#888;font-size:0.78rem;white-space:nowrap;}\n.intent-task-owner::before{content:'@ ';opacity:0.6;}\n.intent-task-due::before{content:'due ';}\n.intent-task-time::before{content:'at ';}\n.intent-task-text-done{text-decoration:line-through;color:#999;}\n/* \u2500\u2500 Ask \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-ask{display:flex;gap:10px;margin:10px 0;padding:6px 0 6px 12px;border-left:2px solid #999;align-items:baseline;}\n.intent-ask-label{font-size:0.68rem;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:#555;flex-shrink:0;line-height:1.65;}\n.intent-ask-content{flex:1;color:#333;font-style:italic;}\n/* \u2500\u2500 Quote \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-quote{margin:14px 0;padding:2px 0 2px 16px;border-left:2px solid #999;font-style:italic;color:#333;}\n.intent-quote p{margin:0;line-height:1.7;}\n.intent-quote-cite{display:block;margin-top:5px;font-style:normal;color:#888;font-size:0.82rem;}\n/* \u2500\u2500 Code \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-code{margin:10px 0;padding:10px 12px;background:#f5f5f5;border:1px solid #ddd;overflow-x:auto;}\n.intent-code code{font-family:'SFMono-Regular',Consolas,'Liberation Mono',Menlo,monospace;font-size:0.85rem;color:#111;}\n/* \u2500\u2500 Table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-table{width:100%;border-collapse:collapse;margin:12px 0;font-size:0.9em;}\n.intent-table th,.intent-table-th{padding:6px 10px;text-align:left;font-weight:600;font-size:0.78rem;text-transform:uppercase;letter-spacing:0.04em;border-bottom:2px solid #333;}\n.intent-table td,.intent-table-td{padding:6px 10px;text-align:left;border-bottom:1px solid #ddd;vertical-align:top;}\n.intent-row:last-child .intent-table-td,.intent-row:last-child td{border-bottom:none;}\n/* \u2500\u2500 Image \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-image{margin:12px 0;}\n.intent-image-img{max-width:100%;height:auto;border:1px solid #ddd;}\n.intent-image-caption{margin-top:4px;color:#555;font-size:0.82rem;text-align:center;font-style:italic;}\n/* \u2500\u2500 Links / Refs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-link{margin:4px 0;}\n.intent-link a{color:#111;text-decoration:underline;}\n.intent-ref{margin:4px 0;}\n.intent-ref a{color:#111;text-decoration:underline;font-style:italic;}\n.intent-unknown{margin:6px 0;padding:6px 10px;border:1px dashed #ccc;color:#888;}\n/* \u2500\u2500 Embed \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-embed{margin:14px 0;}\n.intent-embed iframe,.intent-embed video,.intent-embed audio{display:block;width:100%;border:1px solid #ddd;}\n/* \u2500\u2500 Callouts \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-callout{display:flex;gap:10px;margin:10px 0;padding:6px 0 6px 12px;border-left:2px solid #888;align-items:baseline;}\n.intent-callout-label{font-size:0.68rem;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;flex-shrink:0;white-space:nowrap;line-height:1.65;color:#444;}\n.intent-callout-content{flex:1;color:#222;}\n.intent-info{border-color:#888;}\n.intent-info .intent-callout-label{color:#444;}\n.intent-warning{border-color:#888;}\n.intent-warning .intent-callout-label{color:#444;}\n.intent-tip{border-color:#888;}\n.intent-tip .intent-callout-label{color:#444;}\n.intent-success{border-color:#888;}\n.intent-success .intent-callout-label{color:#444;}\n/* \u2500\u2500 Inline formatting \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-inline-link{color:#111;text-decoration:underline;}\n.intent-inline-highlight{background:#eee;padding:0 .15em;}\n.intent-inline-note{display:inline-block;padding:0 .3em;border:1px solid #ddd;color:#333;font-size:.92em;}\n.intent-inline-quote{color:#333;font-style:italic;}\n.intent-inline-date{font-weight:600;font-family:'SFMono-Regular',Consolas,monospace;}\n.intent-inline-mention{font-weight:600;}\n.intent-inline-tag{font-weight:600;}\n/* \u2500\u2500 Lists \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nul,ol{margin:6px 0 6px 20px;padding:0;}\nli{margin:3px 0;color:#222;}\n/* \u2500\u2500 v2 Agentic Workflow Blocks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-step{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #ddd;margin:5px 0;}\n.intent-step-icon{font-size:0.85rem;flex-shrink:0;}\n.intent-step-content{flex:1;font-weight:500;}\n.intent-step-meta{display:flex;gap:5px;align-items:center;flex-wrap:wrap;}\n.intent-step-id{font-size:0.72rem;color:#888;font-family:monospace;}\n.intent-step-depends{font-size:0.75rem;color:#555;font-style:italic;}\n.intent-badge{font-size:0.7rem;padding:1px 6px;border:1px solid #bbb;font-weight:600;text-transform:uppercase;letter-spacing:0.04em;}\n.intent-badge-tool{border-color:#999;}\n.intent-status-pending{color:#666;}\n.intent-status-running{color:#333;animation:intent-pulse 1.5s ease-in-out infinite;}\n.intent-status-blocked{color:#666;}\n.intent-status-failed{color:#333;text-decoration:line-through;}\n.intent-status-done{color:#333;}\n.intent-status-skipped,.intent-status-cancelled{color:#999;text-decoration:line-through;}\n@keyframes intent-pulse{0%,100%{opacity:1;}50%{opacity:0.4;}}\n.intent-decision{display:flex;gap:10px;margin:8px 0;padding:8px 12px;border:1px solid #bbb;}\n.intent-decision-diamond{width:16px;height:16px;border:2px solid #333;transform:rotate(45deg);flex-shrink:0;margin-top:4px;}\n.intent-decision-body{flex:1;}\n.intent-decision-label{font-weight:600;margin-bottom:3px;}\n.intent-decision-condition{font-size:0.85rem;color:#444;font-family:monospace;margin-bottom:3px;}\n.intent-decision-branches{display:flex;gap:14px;font-size:0.82rem;}\n.intent-decision-then{color:#333;}\n.intent-decision-else{color:#333;}\n.intent-trigger{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #ddd;margin:5px 0;}\n.intent-trigger-icon{font-size:1rem;}\n.intent-trigger-content{flex:1;font-weight:500;}\n.intent-badge-event{border-color:#999;}\n.intent-loop{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #ddd;margin:5px 0;}\n.intent-loop-icon{font-size:1rem;}\n.intent-loop-content{flex:1;font-weight:500;}\n.intent-loop-over,.intent-loop-do{font-size:0.8rem;color:#555;font-family:monospace;}\n.intent-checkpoint{display:flex;align-items:center;gap:8px;margin:16px 0;color:#555;font-size:0.85rem;font-weight:600;text-transform:uppercase;letter-spacing:0.06em;}\n.intent-checkpoint-flag{font-size:1rem;}\n.intent-checkpoint-label{flex-shrink:0;}\n.intent-checkpoint-line{flex:1;border:none;border-top:1px dashed #bbb;margin:0;}\n.intent-audit{margin:4px 0;padding:4px 8px;font-family:'SFMono-Regular',Consolas,monospace;font-size:0.8rem;color:#555;border-left:2px solid #bbb;}\n.intent-audit-prefix{color:#888;font-weight:600;}\n.intent-error-block{border-color:#999;}\n.intent-error-block .intent-callout-label{color:#333;}\n.intent-error-fallback{font-size:0.8rem;color:#555;font-style:italic;margin-left:6px;}\n.intent-error-notify{font-size:0.8rem;color:#555;margin-left:6px;}\n.intent-context-table{width:auto;border-collapse:collapse;margin:6px 0;font-size:0.85rem;}\n.intent-context-key{padding:3px 10px 3px 8px;font-weight:600;color:#333;font-family:monospace;border-bottom:1px solid #ddd;}\n.intent-context-val{padding:3px 12px 3px 6px;color:#333;font-family:monospace;border-bottom:1px solid #ddd;}\n.intent-context{margin:4px 0;font-size:0.85rem;color:#333;}\n.intent-progress{display:flex;align-items:center;gap:8px;margin:6px 0;}\n.intent-progress-label{font-size:0.85rem;color:#222;flex-shrink:0;}\n.intent-progress-bar{flex:1;height:6px;background:#ddd;overflow:hidden;}\n.intent-progress-fill{height:100%;background:#555;}\n.intent-progress-pct{font-size:0.78rem;color:#555;font-weight:600;min-width:36px;text-align:right;}\n.intent-file-ref{display:flex;align-items:center;gap:6px;margin:4px 0;padding:4px 8px;border:1px dashed #ccc;font-size:0.82rem;color:#555;font-family:monospace;}\n.intent-file-ref-icon{font-size:0.9rem;}\n/* \u2500\u2500 v2.1 Agentic Workflow Blocks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-emit-block{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #bbb;margin:5px 0;}\n.intent-emit-icon{font-size:1rem;}\n.intent-emit-content{flex:1;font-weight:500;}\n.intent-emit-meta{display:flex;gap:5px;align-items:center;}\n.intent-emit-phase{font-size:0.78rem;color:#555;font-weight:600;}\n.intent-badge-level{border-color:#999;}\n.intent-result{display:flex;align-items:flex-start;gap:8px;padding:7px 10px;border:1px solid #bbb;margin:5px 0;flex-wrap:wrap;}\n.intent-result-success{border-color:#999;}\n.intent-result-error,.intent-result-failure{border-color:#999;}\n.intent-result-icon{font-size:1rem;flex-shrink:0;}\n.intent-result-content{flex:1;font-weight:500;}\n.intent-badge-code{border-color:#999;font-family:monospace;}\n.intent-result-data{width:100%;margin-top:3px;padding:4px 8px;font-size:0.82rem;overflow-x:auto;border-top:1px solid #ddd;}\n.intent-result-data code{font-family:'SFMono-Regular',Consolas,monospace;font-size:0.82rem;color:#333;}\n.intent-handoff{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #bbb;margin:5px 0;}\n.intent-handoff-icon{font-size:1rem;}\n.intent-handoff-content{flex:1;font-weight:500;}\n.intent-handoff-arrow{display:flex;align-items:center;gap:5px;font-size:0.82rem;color:#444;font-weight:600;}\n.intent-handoff-agent{padding:1px 5px;border:1px solid #bbb;font-family:monospace;font-size:0.78rem;}\n.intent-wait{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #ddd;margin:5px 0;border-left:2px solid #999;}\n.intent-wait-icon{font-size:1rem;animation:intent-pulse 2s ease-in-out infinite;}\n.intent-wait-content{flex:1;font-weight:500;color:#333;}\n.intent-wait-meta{display:flex;gap:5px;align-items:center;}\n.intent-badge-timeout{border-color:#999;font-family:monospace;}\n.intent-wait-fallback{font-size:0.8rem;color:#555;font-style:italic;}\n.intent-parallel{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #bbb;margin:5px 0;}\n.intent-parallel-icon{font-size:1rem;}\n.intent-parallel-content{flex:1;font-weight:500;}\n.intent-parallel-steps{display:flex;gap:4px;flex-wrap:wrap;}\n.intent-badge-parallel-step{border-color:#999;font-family:monospace;font-size:0.72rem;padding:1px 5px;}\n.intent-badge-join{border-color:#999;font-size:0.72rem;padding:1px 5px;}\n.intent-retry{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #bbb;margin:5px 0;}\n.intent-retry-icon{font-size:1rem;}\n.intent-retry-content{flex:1;font-weight:500;}\n.intent-retry-meta{display:flex;gap:5px;align-items:center;}\n.intent-badge-retry-max{border-color:#999;font-size:0.72rem;}\n.intent-badge-retry-delay{border-color:#999;font-size:0.72rem;font-family:monospace;}\n.intent-badge-retry-backoff{border-color:#999;font-size:0.72rem;font-style:italic;}\n/* \u2500\u2500 v2.2 Agentic Workflow Blocks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-gate{display:flex;gap:10px;margin:8px 0;padding:10px 12px;border:2px solid #888;}\n.intent-gate-icon{font-size:1.2rem;flex-shrink:0;margin-top:2px;}\n.intent-gate-body{flex:1;}\n.intent-gate-label{font-weight:600;margin-bottom:3px;}\n.intent-gate-meta{display:flex;gap:5px;align-items:center;flex-wrap:wrap;}\n.intent-badge-approver{border-color:#999;font-family:monospace;}\n.intent-gate-fallback{font-size:0.8rem;color:#555;font-style:italic;}\n.intent-call{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px dashed #999;margin:5px 0;}\n.intent-call-icon{font-size:1rem;}\n.intent-call-content{flex:1;font-weight:500;font-family:monospace;font-size:0.9rem;}\n.intent-call-meta{display:flex;gap:6px;align-items:center;}\n.intent-call-input{font-size:0.78rem;color:#555;font-family:monospace;}\n.intent-call-output{font-size:0.78rem;color:#555;font-family:monospace;}\n/* \u2500\u2500 v2.5 Document Generation Blocks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.it-page-break{page-break-after:always;break-after:page;height:0;}\n.it-byline{margin:0 0 16px;font-size:0.9em;color:#333;}\n.it-byline-author{display:block;font-weight:bold;}\n.it-byline-meta{display:block;font-size:0.85em;color:#666;margin-top:2px;}\n.it-epigraph{font-style:italic;text-align:center;margin:20px 3em;border:none;padding:0;}\n.it-epigraph p{margin:0;}\n.it-epigraph .it-epigraph-by{display:block;text-align:right;font-size:0.9em;margin-top:4px;font-style:normal;color:#666;}\n.it-caption{font-size:0.85em;font-style:italic;text-align:center;color:#444;margin-top:3px;margin-bottom:10px;}\n.it-dedication{font-style:italic;text-align:center;margin:3em auto;}\n.it-toc{margin:20px 0;}\n.it-toc-title{font-size:1.1rem;font-weight:600;margin-bottom:8px;border:none;}\n.it-toc ol{list-style:none;padding:0;margin:0;}\n.it-toc li{margin:3px 0;}\n.it-toc li a{color:#111;text-decoration:none;border-bottom:1px dotted #bbb;}\n.it-toc li a:hover{border-bottom-style:solid;}\n.it-toc .it-toc-sub{padding-left:20px;font-size:0.92em;}\n.it-footnotes{border-top:1px solid #ccc;margin-top:24px;padding-top:8px;font-size:0.85em;color:#444;}\n.it-footnotes ol{padding-left:1.5em;margin:0;}\n.it-footnotes li{margin:3px 0;}\nsup.it-fn-ref{font-size:0.7em;vertical-align:super;}\nsup.it-fn-ref a{color:#111;text-decoration:none;border-bottom:1px solid #999;}\n/* \u2500\u2500 v2.8 Document Trust \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.it-approval{display:flex;gap:10px;margin:10px 0;padding:10px 14px;border:1px solid #4caf50;background:#f8fdf8;}\n.it-approval__icon{font-size:1.2rem;color:#4caf50;flex-shrink:0;}\n.it-approval__body{display:flex;flex-direction:column;gap:2px;}\n.it-approval__label{font-size:0.72rem;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:#4caf50;}\n.it-approval__who{font-size:0.9rem;color:#222;}\n.it-approval__date{font-size:0.8rem;color:#666;}\n.it-signature{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:10px 0;padding:10px 14px;border:1px solid #daa520;background:#fffdf5;}\n.it-signature--valid{border-color:#4caf50;background:#f8fdf8;}\n.it-signature--invalid{border-color:#c62828;background:#fdf5f5;}\n.it-signature__name{font-weight:600;font-size:0.95rem;color:#111;}\n.it-signature__role{font-size:0.85rem;color:#555;}\n.it-signature__date{font-size:0.8rem;color:#666;}\n.it-signature__status{font-size:0.8rem;font-weight:600;margin-left:auto;}\n.it-sealed-banner{display:flex;gap:10px;align-items:center;margin:16px 0;padding:12px 16px;border:2px solid #c62828;background:#fdf5f5;font-weight:600;}\n.it-sealed-banner__icon{font-size:1.3rem;}\n.it-sealed-banner__text{font-size:1rem;color:#c62828;text-transform:uppercase;letter-spacing:0.04em;}\n.it-sealed-banner__date{font-size:0.8rem;color:#666;margin-left:auto;}\n.it-sealed-banner__hash{font-size:0.72rem;color:#888;font-family:monospace;}\n/* \u2500\u2500 v2.11 Keyword Expansion \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.it-ref-card{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #ddd;margin:5px 0;}\n.it-ref-icon{font-size:1rem;flex-shrink:0;}\n.it-ref-link{color:#111;text-decoration:underline;font-weight:500;}\n.it-ref-name{font-weight:500;}\n.it-ref-rel{font-size:0.7rem;padding:1px 6px;border:1px solid #bbb;font-weight:600;text-transform:uppercase;letter-spacing:0.04em;}\n.it-def{margin:6px 0;padding:4px 0;}\n.it-def-term{font-weight:700;font-size:0.95rem;color:#111;}\n.it-def-abbr{font-weight:400;color:#555;}\n.it-def-meaning{margin:2px 0 0 0;color:#333;font-size:0.92rem;padding-left:1em;}\n.it-metric{display:inline-block;padding:10px 14px;border:1px solid #ddd;margin:5px;min-width:140px;vertical-align:top;}\n.it-metric-name{font-size:0.78rem;font-weight:600;text-transform:uppercase;letter-spacing:0.04em;color:#555;}\n.it-metric-value{font-size:1.6rem;font-weight:700;line-height:1.2;color:#111;}\n.it-metric-unit{font-size:0.85rem;font-weight:400;color:#666;margin-left:2px;}\n.it-metric-target{font-size:0.78rem;color:#888;}\n.it-metric-trend{font-size:1rem;font-weight:700;margin-top:2px;}\n.it-metric-period{font-size:0.72rem;color:#888;}\n.it-metric-green{border-color:#4caf50;}\n.it-metric-green .it-metric-value{color:#2e7d32;}\n.it-metric-red{border-color:#c62828;}\n.it-metric-red .it-metric-value{color:#c62828;}\n.it-metric-neutral{border-color:#ddd;}\n/* Document total/line rows (invoice, receipt, statement) \u2014 matches the editor's\n itMetric node so editor-designed templates print identically. */\n.it-metric-row{display:flex;align-items:baseline;justify-content:space-between;gap:16px;padding:5px 0;border-bottom:1px solid var(--it-color-border,#e5e7eb);}\n.it-metric-row__label{color:var(--it-color-muted,#555);}\n.it-metric-row__value{font-variant-numeric:tabular-nums;font-weight:600;color:var(--it-color-text,#111);white-space:nowrap;}\n.it-metric-row--total{border-bottom:none;border-top:2px solid var(--it-color-text,#333);margin-top:2px;padding-top:8px;font-size:1.05em;}\n.it-metric-row--total .it-metric-row__label{color:var(--it-color-text,#111);font-weight:600;}\n.it-amendment{margin:10px 0;padding:10px 14px;border:2px solid #e65100;background:#fff8e1;}\n.it-amendment-header{display:flex;align-items:center;gap:8px;margin-bottom:6px;}\n.it-amendment-icon{font-size:1rem;}\n.it-amendment-ref{font-size:0.72rem;font-weight:700;padding:1px 6px;border:1px solid #e65100;color:#e65100;text-transform:uppercase;letter-spacing:0.04em;}\n.it-amendment-title{font-weight:600;color:#111;}\n.it-amendment-section{font-size:0.85rem;color:#555;font-style:italic;}\n.it-amendment-was{font-size:0.85rem;color:#c62828;text-decoration:line-through;}\n.it-amendment-now{font-size:0.85rem;color:#2e7d32;font-weight:500;}\n.it-amendment-meta{display:flex;gap:8px;margin-top:4px;font-size:0.8rem;color:#666;}\n.it-figure{margin:14px 0;}\n.it-figure img{display:block;margin:0 auto;border:1px solid #ddd;}\n.it-figure-caption{font-size:0.85em;font-style:italic;text-align:center;color:#444;margin-top:6px;}\n.it-signline{margin:20px 0;padding:0;}\n.it-signline-label{font-size:0.72rem;color:#888;text-transform:uppercase;letter-spacing:0.06em;margin-bottom:4px;}\n.it-signline-rule{border-bottom:1px solid #111;margin-bottom:4px;}\n.it-signline-name{font-size:0.9rem;font-weight:500;color:#111;}\n.it-signline-role{font-size:0.82rem;color:#555;}\n.it-signline-date{font-size:0.82rem;color:#555;margin-top:4px;}\n.it-contact{padding:8px 12px;border:1px solid #ddd;margin:5px 0;}\n.it-contact-name{font-weight:600;font-size:0.95rem;color:#111;}\n.it-contact-role{font-size:0.82rem;color:#555;}\n.it-contact-org{font-size:0.82rem;color:#555;}\n.it-contact-email a,.it-contact-phone a,.it-contact-url a{color:#111;text-decoration:underline;font-size:0.85rem;}\n.it-deadline{padding:8px 12px;border-left:3px solid #4caf50;margin:5px 0;}\n.it-deadline-name{font-weight:600;color:#111;}\n.it-deadline-date{font-size:0.9rem;font-weight:600;color:#111;}\n.it-deadline-consequence{font-size:0.85rem;color:#555;font-style:italic;}\n.it-deadline-owner{font-size:0.82rem;color:#555;}\n.it-deadline-authority{font-size:0.82rem;color:#555;}\n.it-deadline-green{border-color:#4caf50;}\n.it-deadline-amber{border-color:#f57c00;}\n.it-deadline-red{border-color:#c62828;}\n";