mcp-scraper 0.58.0 → 0.60.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.
@@ -44650,7 +44650,7 @@ var PACKAGE_VERSION;
44650
44650
  var init_version = __esm({
44651
44651
  "src/version.ts"() {
44652
44652
  "use strict";
44653
- PACKAGE_VERSION = "0.58.0";
44653
+ PACKAGE_VERSION = "0.60.0";
44654
44654
  }
44655
44655
  });
44656
44656
 
@@ -46776,6 +46776,7 @@ var init_mcp_tool_schemas = __esm({
46776
46776
  includeZipGroups: import_zod43.z.boolean().default(true).describe("Include ZIP and county groups from the active hosted ZIP dataset.")
46777
46777
  };
46778
46778
  CommonsSearchEntitiesInputSchema = {
46779
+ mode: import_zod43.z.enum(["lexical", "semantic", "hybrid"]).optional().describe("Retrieval mode. hybrid (default) fuses meaning-based candidates with exact term matching; lexical matches terms only, which is what you want when the caller quoted an exact name or phrase; semantic ignores term matching entirely."),
46779
46780
  query: import_zod43.z.string().trim().max(300).optional().describe("Search text matched against title, description, tags, keywords, JSON-LD, source metadata, citations, media, and article body."),
46780
46781
  entityType: import_zod43.z.string().trim().max(120).optional().describe('Optional entity type filter. "Public Article", "PublicArticle", "Article", and "item" normalize to PublicArticle.'),
46781
46782
  tag: import_zod43.z.string().trim().max(80).optional().describe("Single canonical tag filter. Use tags for multiple tags."),
@@ -50422,7 +50423,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
50422
50423
  }, async (input) => formatG2Reviews(await executor.g2Reviews(input), input));
50423
50424
  server.registerTool("commons_search_entities", {
50424
50425
  title: "Transparent Commons Entity Search",
50425
- description: "Search the Transparent Commons public wiki graph using the same fields the public /wiki/ frontend uses: title, description, tags, keywords, JSON-LD, article body, citations, media, source metadata, related entities, trails, and saved account filters. This reads published Commons entities only.",
50426
+ description: "Search the Transparent Commons public wiki graph. Hybrid by default: meaning-based candidates fused with exact matching over title, description, tags, keywords, JSON-LD, body, citations, media, source metadata, related entities, trails, and saved filters, ranked title-first. Set mode:lexical for a quoted exact name or phrase. Reads published Commons entities only; never a personal Memory vault.",
50426
50427
  inputSchema: CommonsSearchEntitiesInputSchema,
50427
50428
  outputSchema: recordOutputSchema("commons_search_entities", CommonsGenericOutputSchema),
50428
50429
  annotations: {
@@ -50500,7 +50501,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
50500
50501
  }, async (input) => executor.commonsValidateEntity(input));
50501
50502
  server.registerTool("commons_submit_entity", {
50502
50503
  title: "Transparent Commons Governed Entity Write",
50503
- description: "Create or propose an edit to a Transparent Commons public wiki entity through the governed MCP Scraper write plane. A new entity costs 10 Credits; an edit to an existing entity costs 2 Credits. Preparation and validation are free, and idempotent retries are not charged twice. This never edits rendered HTML directly. Normal workflow is commons_prepare_entity, compose, commons_validate_entity, then submit. Choose a precise entityType and write a neutral encyclopedia projection with the matching entity structure, not a blog article or raw scrape dump. Use H2 sections and H3/H4/H5 subitems; every heading appears in the public page menu. Omit unsupported sections instead of publishing empty/filler headings. Transparent Commons is an open wiki: any account may edit any entity, and every edit publishes and is recorded on the public contribution ledger. Publishing requires a featured image and body/source evidence. Pass baseRevision when editing so the ledger can show whether the edit was written on top of a newer revision. Requires idempotencyKey.",
50504
+ description: "Create or propose an edit to a Transparent Commons public wiki entity through the governed MCP Scraper write plane. A new entity costs 10 Credits; an edit to an existing entity costs 2 Credits. Preparation and validation are free, and idempotent retries are not charged twice. This never edits rendered HTML directly. Normal workflow is commons_prepare_entity, compose, commons_validate_entity, then submit. commons_prepare_entity returns the entity profile contract and section guidance to compose against. Transparent Commons is an open wiki: any account may edit any entity, and every edit publishes and is recorded on the public contribution ledger. Publishing requires a featured image and body/source evidence. Pass baseRevision when editing so the ledger can show whether the edit was written on top of a newer revision. Requires idempotencyKey.",
50504
50505
  inputSchema: CommonsSubmitEntityInputSchema,
50505
50506
  outputSchema: recordOutputSchema("commons_submit_entity", CommonsGenericOutputSchema),
50506
50507
  annotations: {
@@ -50526,7 +50527,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
50526
50527
  }, async (input) => executor.commonsGetEntityLedger(input));
50527
50528
  server.registerTool("commons_host_image", {
50528
50529
  title: "Host a Transparent Commons Image",
50529
- description: "Download an image from a public https URL, or accept base64 bytes, and store it as a permanent Commons-hosted image. Returns the hosted URL to use on an entity. Commons never serves a third-party image URL: submitting an entity with an external image hosts it automatically, and this tool exists for hosting an image before or independently of a write. JPEG, PNG, GIF, and WebP up to 10 MB; SVG is rejected because the wiki serves images to the public web. Identical bytes are stored once and reused.",
50530
+ description: "Host an image from a public https URL or base64 bytes, returning a permanent Commons URL. Commons never serves a third-party image URL \u2014 commons_submit_entity hosts external images automatically, so use this only to host one before or independently of a write. JPEG, PNG, GIF, WebP up to 10 MB; SVG rejected. Identical bytes are stored once.",
50530
50531
  inputSchema: CommonsHostImageInputSchema,
50531
50532
  outputSchema: recordOutputSchema("commons_host_image", CommonsGenericOutputSchema),
50532
50533
  annotations: {
@@ -50606,7 +50607,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
50606
50607
  }, async (input) => executor.commonsPublishEditorial(input));
50607
50608
  server.registerTool("commons_update_editorial_article", {
50608
50609
  title: "Edit One Transparent Commons Article",
50609
- description: "Replace the Markdown of a single article in a published edition without resupplying the others. The edition already stores every article\u2019s source, so this reads them, swaps the one you name, re-renders, and publishes the next revision with the rest byte-identical. Use commons_get_publication with includeArticles to read current sources and the revision first; commons_publish_editorial remains the full-replace path for a wholesale rewrite. Requires baseRevision and idempotencyKey.",
50610
+ description: "Replace the Markdown of one article in a published edition without resupplying the others: it reads the stored sources, swaps the article you name, and publishes the next revision with the rest byte-identical. Read commons_get_publication with includeArticles first for the current source and revision. commons_publish_editorial is the full-replace path. Requires baseRevision and idempotencyKey.",
50610
50611
  inputSchema: CommonsUpdateEditorialArticleInputSchema,
50611
50612
  outputSchema: recordOutputSchema("commons_update_editorial_article", CommonsGenericOutputSchema),
50612
50613
  annotations: { title: "Edit One Transparent Commons Article", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true }
@@ -50680,7 +50681,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
50680
50681
  }, async (input) => executor.localSourcebookCapture(input));
50681
50682
  server.registerTool("local_sourcebook_submission_status", {
50682
50683
  title: "Local Sourcebook Submission Status",
50683
- description: "Read the authenticated caller\u2019s listing draft, enrichment coverage, immutable revision number, publication state, and exact live LocalSourcebook.com profile and reviews URLs. When status is failed, acquisitionError states why in plain language \u2014 read it before retrying, because a refresh repeats the same acquisition and will fail the same way until the cause is fixed. Coverage counters are written only when acquisition succeeds, so a failed listing still shows the pre-run crawl block; zeroed counters do not mean the crawl never ran.",
50684
+ description: "Read the caller\u2019s listing draft, enrichment coverage, revision number, publication state, and live LocalSourcebook.com profile and reviews URLs. When status is failed, acquisitionError says why \u2014 read it before retrying, since a refresh repeats the same acquisition. Coverage counters are written only on success, so zeroed counters on a failed listing do not mean the crawl never ran.",
50684
50685
  inputSchema: LocalSourcebookSubmissionStatusInputSchema,
50685
50686
  outputSchema: recordOutputSchema("local_sourcebook_submission_status", LocalSourcebookOutputSchema),
50686
50687
  annotations: localPlanningToolAnnotations("Local Sourcebook Submission Status")
@@ -64079,9 +64080,7 @@ function socialMeta(input) {
64079
64080
  ];
64080
64081
  return tags.join("\n ");
64081
64082
  }
64082
- function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
64083
- const sourceBytes = input.articles.reduce((total, article) => total + Buffer.byteLength(article.markdown), 0);
64084
- if (sourceBytes > 2e6) throw new Error("Editorial reading-room Markdown must be 2,000,000 bytes or fewer in total.");
64083
+ function buildEditorialArticles(input) {
64085
64084
  const seenSlugs = /* @__PURE__ */ new Set();
64086
64085
  const seenOrders = /* @__PURE__ */ new Set();
64087
64086
  const parser = markdownRenderer();
@@ -64108,7 +64107,19 @@ function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
64108
64107
  html: rendered
64109
64108
  };
64110
64109
  });
64110
+ return { articles, warnings, totalWordCount };
64111
+ }
64112
+ function renderEditorialArticleModels(input) {
64113
+ return buildEditorialArticles(input).articles;
64114
+ }
64115
+ function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
64116
+ const sourceBytes = input.articles.reduce((total, article) => total + Buffer.byteLength(article.markdown), 0);
64117
+ if (sourceBytes > 2e6) throw new Error("Editorial reading-room Markdown must be 2,000,000 bytes or fewer in total.");
64111
64118
  const generatedAt = now.toISOString();
64119
+ const built = buildEditorialArticles(input);
64120
+ const articles = built.articles;
64121
+ const warnings = built.warnings;
64122
+ const totalWordCount = built.totalWordCount;
64112
64123
  const data = { ...input, generatedAt, articles };
64113
64124
  const template = readAsset("index.html");
64114
64125
  const html = template.replace("<title>Editorial Reading Room</title>", `<title>${escapeHtml6(input.site.title)}</title>`).replace('content="A mobile-first editorial reading room."', `content="${escapeHtml6(input.deck || input.site.heroTitle)}"`).replace("<!--__READING_ROOM_SOCIAL_META__-->", socialMeta(input)).replace("/*__READING_ROOM_STYLES__*/", readAsset("styles.css")).replace("/*__READING_ROOM_DATA__*/", escapedJsonForHtml(data)).replace("/*__READING_ROOM_SCRIPT__*/", readAsset("app.js"));
@@ -64589,6 +64600,141 @@ var init_commons_image_store = __esm({
64589
64600
  }
64590
64601
  });
64591
64602
 
64603
+ // src/api/commons-embeddings.ts
64604
+ function commonsEmbedModel() {
64605
+ return (process.env.JINA_EMBED_MODEL ?? "jina-embeddings-v5-omni-small").trim();
64606
+ }
64607
+ function commonsEmbedDim() {
64608
+ return Number((process.env.JINA_EMBED_DIM ?? "1024").trim());
64609
+ }
64610
+ function commonsSemanticSearchConfigured() {
64611
+ return Boolean(process.env.JINA_API_KEY?.trim() && process.env.MEMORY_DATABASE_URL?.trim());
64612
+ }
64613
+ function vectorSql() {
64614
+ if (_vectorSql) return _vectorSql;
64615
+ const url = process.env.MEMORY_DATABASE_URL?.trim();
64616
+ if (!url) throw new Error("MEMORY_DATABASE_URL is not set; Commons semantic search needs the shared Postgres.");
64617
+ _vectorSql = (0, import_serverless.neon)(url);
64618
+ return _vectorSql;
64619
+ }
64620
+ async function ensureCommonsVectorSchema() {
64621
+ if (vectorSchemaReady) return;
64622
+ const dimension = commonsEmbedDim();
64623
+ await vectorSql().query("CREATE EXTENSION IF NOT EXISTS vector");
64624
+ await vectorSql().query(`
64625
+ CREATE TABLE IF NOT EXISTS commons_index_vectors (
64626
+ document_id TEXT PRIMARY KEY,
64627
+ entity_id TEXT NOT NULL,
64628
+ document_type TEXT NOT NULL,
64629
+ title TEXT NOT NULL,
64630
+ embedding vector(${dimension}) NOT NULL,
64631
+ model TEXT NOT NULL,
64632
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
64633
+ )
64634
+ `);
64635
+ await vectorSql().query("CREATE INDEX IF NOT EXISTS commons_index_vectors_entity ON commons_index_vectors(entity_id)");
64636
+ vectorSchemaReady = true;
64637
+ }
64638
+ async function embedCommonsTexts(texts) {
64639
+ const apiKey = process.env.JINA_API_KEY?.trim();
64640
+ if (!apiKey) throw new Error("JINA_API_KEY is not set; Commons semantic search cannot embed.");
64641
+ if (!texts.length) return [];
64642
+ const response = await fetch("https://api.jina.ai/v1/embeddings", {
64643
+ method: "POST",
64644
+ headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
64645
+ body: JSON.stringify({
64646
+ model: commonsEmbedModel(),
64647
+ dimensions: commonsEmbedDim(),
64648
+ input: texts.map((text2) => ({ text: text2.slice(0, 8e3) }))
64649
+ }),
64650
+ signal: AbortSignal.timeout(6e4)
64651
+ });
64652
+ if (!response.ok) {
64653
+ throw new Error(`Jina embedding request failed with HTTP ${response.status}: ${(await response.text()).slice(0, 200)}`);
64654
+ }
64655
+ const payload = await response.json();
64656
+ const vectors = (payload.data ?? []).map((item) => item.embedding);
64657
+ if (vectors.length !== texts.length) {
64658
+ throw new Error(`Jina returned ${vectors.length} embeddings for ${texts.length} inputs.`);
64659
+ }
64660
+ return vectors;
64661
+ }
64662
+ async function embedQueuedCommonsDocuments(limit = 50) {
64663
+ if (!commonsSemanticSearchConfigured()) return { claimed: 0, embedded: 0, failed: 0, remaining: 0 };
64664
+ await ensureCommonsVectorSchema();
64665
+ const bounded = Math.max(1, Math.min(200, Math.floor(limit)));
64666
+ const queued = await getDb().execute({
64667
+ sql: `SELECT id, entity_id, document_type, title, text FROM commons_index_documents
64668
+ WHERE embedding_status IN ('queued', 'failed') ORDER BY updated_at ASC LIMIT ?`,
64669
+ args: [bounded]
64670
+ });
64671
+ const rows = queued.rows;
64672
+ if (!rows.length) return { claimed: 0, embedded: 0, failed: 0, remaining: await queuedCommonsDocumentCount() };
64673
+ let embedded = 0;
64674
+ let failed = 0;
64675
+ const model = commonsEmbedModel();
64676
+ try {
64677
+ const vectors = await embedCommonsTexts(rows.map((row) => `${row.title}
64678
+
64679
+ ${row.text}`));
64680
+ for (const [index, row] of rows.entries()) {
64681
+ const literal = `[${vectors[index].join(",")}]`;
64682
+ await vectorSql().query(
64683
+ `INSERT INTO commons_index_vectors (document_id, entity_id, document_type, title, embedding, model, updated_at)
64684
+ VALUES ($1, $2, $3, $4, $5::vector, $6, now())
64685
+ ON CONFLICT (document_id) DO UPDATE SET entity_id = EXCLUDED.entity_id, document_type = EXCLUDED.document_type,
64686
+ title = EXCLUDED.title, embedding = EXCLUDED.embedding, model = EXCLUDED.model, updated_at = now()`,
64687
+ [row.id, row.entity_id, row.document_type, row.title, literal, model]
64688
+ );
64689
+ await getDb().execute({
64690
+ sql: `UPDATE commons_index_documents SET embedding_status = 'indexed', embedding_provider = ?, embedding_model = ?,
64691
+ vector_ref = ?, indexed_at = ?, error = NULL WHERE id = ?`,
64692
+ args: [COMMONS_EMBED_PROVIDER, model, row.id, (/* @__PURE__ */ new Date()).toISOString(), row.id]
64693
+ });
64694
+ embedded += 1;
64695
+ }
64696
+ } catch (error) {
64697
+ failed = rows.length - embedded;
64698
+ const message = (error instanceof Error ? error.message : String(error)).slice(0, 500);
64699
+ for (const row of rows.slice(embedded)) {
64700
+ await getDb().execute({
64701
+ sql: `UPDATE commons_index_documents SET embedding_status = 'failed', error = ? WHERE id = ?`,
64702
+ args: [message, row.id]
64703
+ }).catch(() => void 0);
64704
+ }
64705
+ }
64706
+ return { claimed: rows.length, embedded, failed, remaining: await queuedCommonsDocumentCount() };
64707
+ }
64708
+ async function queuedCommonsDocumentCount() {
64709
+ const result = await getDb().execute(`SELECT COUNT(*) AS n FROM commons_index_documents WHERE embedding_status IN ('queued', 'failed')`);
64710
+ return Number(result.rows[0]?.n ?? 0);
64711
+ }
64712
+ async function semanticCommonsEntityScores(query, limit = 40) {
64713
+ const scores = /* @__PURE__ */ new Map();
64714
+ if (!commonsSemanticSearchConfigured() || !query.trim()) return scores;
64715
+ await ensureCommonsVectorSchema();
64716
+ const [vector] = await embedCommonsTexts([query]);
64717
+ if (!vector) return scores;
64718
+ const rows = await vectorSql().query(
64719
+ `SELECT entity_id, MAX(1 - (embedding <=> $1::vector)) AS score
64720
+ FROM commons_index_vectors GROUP BY entity_id ORDER BY score DESC LIMIT $2`,
64721
+ [`[${vector.join(",")}]`, Math.max(1, Math.min(100, limit))]
64722
+ );
64723
+ for (const row of rows) scores.set(String(row.entity_id), Number(row.score));
64724
+ return scores;
64725
+ }
64726
+ var import_serverless, COMMONS_EMBED_PROVIDER, _vectorSql, vectorSchemaReady;
64727
+ var init_commons_embeddings = __esm({
64728
+ "src/api/commons-embeddings.ts"() {
64729
+ "use strict";
64730
+ import_serverless = require("@neondatabase/serverless");
64731
+ init_db();
64732
+ COMMONS_EMBED_PROVIDER = "jina";
64733
+ _vectorSql = null;
64734
+ vectorSchemaReady = false;
64735
+ }
64736
+ });
64737
+
64592
64738
  // src/api/schema-presence.ts
64593
64739
  async function loadSchemaObjects() {
64594
64740
  const res = await getDb().execute(
@@ -65082,17 +65228,35 @@ async function searchCommonsEntities(filters = {}, userId) {
65082
65228
  args.push(mergedFilters.updatedAfter);
65083
65229
  }
65084
65230
  const terms = tokenize(mergedFilters.query);
65085
- for (const term of terms) {
65086
- clauses.push(`(
65087
- search_text LIKE ?
65088
- OR EXISTS (
65089
- SELECT 1 FROM commons_claims
65090
- WHERE commons_claims.subject_entity_id = commons_entities.id
65091
- AND (commons_claims.predicate LIKE ? OR commons_claims.predicate_label LIKE ? OR commons_claims.title LIKE ? OR commons_claims.object_url LIKE ?)
65092
- )
65093
- )`);
65094
- const pattern = `%${escapeLike(term)}%`;
65095
- args.push(pattern, pattern, pattern, pattern, pattern);
65231
+ const searchMode = mergedFilters.mode === "lexical" || mergedFilters.mode === "semantic" ? mergedFilters.mode : "hybrid";
65232
+ const semanticScores = !terms.length || searchMode === "lexical" || !commonsSemanticSearchConfigured() ? /* @__PURE__ */ new Map() : await semanticCommonsEntityScores(String(mergedFilters.query ?? ""), SEARCH_CANDIDATE_LIMIT).catch(() => /* @__PURE__ */ new Map());
65233
+ const semanticIds = [...semanticScores.entries()].filter(([, score]) => score >= 0.6).sort((left, right) => right[1] - left[1]).slice(0, 60).map(([id]) => id);
65234
+ if (terms.length) {
65235
+ const termClauses = [];
65236
+ for (const term of terms) {
65237
+ termClauses.push(`(
65238
+ search_text LIKE ?
65239
+ OR EXISTS (
65240
+ SELECT 1 FROM commons_claims
65241
+ WHERE commons_claims.subject_entity_id = commons_entities.id
65242
+ AND (commons_claims.predicate LIKE ? OR commons_claims.predicate_label LIKE ? OR commons_claims.title LIKE ? OR commons_claims.object_url LIKE ?)
65243
+ )
65244
+ )`);
65245
+ const pattern = `%${escapeLike(term)}%`;
65246
+ args.push(pattern, pattern, pattern, pattern, pattern);
65247
+ }
65248
+ const lexicalClause = `(${termClauses.join(" AND ")})`;
65249
+ if (searchMode === "semantic") {
65250
+ if (!semanticIds.length) return { results: [], filters: mergedFilters, limit, offset };
65251
+ args.length -= terms.length * 5;
65252
+ clauses.push(`id IN (${semanticIds.map(() => "?").join(", ")})`);
65253
+ args.push(...semanticIds);
65254
+ } else if (semanticIds.length) {
65255
+ clauses.push(`(${lexicalClause} OR id IN (${semanticIds.map(() => "?").join(", ")}))`);
65256
+ args.push(...semanticIds);
65257
+ } else {
65258
+ clauses.push(lexicalClause);
65259
+ }
65096
65260
  }
65097
65261
  if (!terms.length) {
65098
65262
  args.push(limit, offset);
@@ -65129,6 +65293,7 @@ async function searchCommonsEntities(filters = {}, userId) {
65129
65293
  `,
65130
65294
  args
65131
65295
  });
65296
+ const mode = searchMode;
65132
65297
  const ranked = candidates.rows.map((row) => {
65133
65298
  const record = row;
65134
65299
  const score = relevanceScore(terms, {
@@ -65139,8 +65304,10 @@ async function searchCommonsEntities(filters = {}, userId) {
65139
65304
  searchText: String(record.search_text ?? ""),
65140
65305
  claimText: String(record.claim_text ?? "")
65141
65306
  });
65142
- return { id: String(record.id), updatedAt: String(record.updated_at ?? ""), title: String(record.title ?? ""), score };
65143
- }).filter((candidate) => candidate.score > 0).sort((left, right) => right.score - left.score || right.updatedAt.localeCompare(left.updatedAt) || left.title.localeCompare(right.title));
65307
+ const semantic = semanticScores.get(String(record.id)) ?? 0;
65308
+ const fused = mode === "semantic" ? semantic * 100 : score + semantic * 60;
65309
+ return { id: String(record.id), updatedAt: String(record.updated_at ?? ""), title: String(record.title ?? ""), score: fused, lexical: score, semantic };
65310
+ }).filter((candidate) => mode === "semantic" ? candidate.semantic > 0 : candidate.lexical > 0 || candidate.semantic >= 0.62).sort((left, right) => right.score - left.score || right.updatedAt.localeCompare(left.updatedAt) || left.title.localeCompare(right.title));
65144
65311
  const pageIds = ranked.slice(offset, offset + limit).map((candidate) => candidate.id);
65145
65312
  if (!pageIds.length) return { results: [], filters: mergedFilters, limit, offset };
65146
65313
  const page = await getDb().execute({
@@ -66626,6 +66793,7 @@ function normalizeRelatedEntities(related) {
66626
66793
  }
66627
66794
  function sanitizeSearchFilters(filters) {
66628
66795
  return {
66796
+ mode: filters.mode === "lexical" || filters.mode === "semantic" ? filters.mode : "hybrid",
66629
66797
  query: optionalText2(filters.query, 300) ?? void 0,
66630
66798
  entityType: filters.entityType ? normalizeEntityType(filters.entityType) : void 0,
66631
66799
  tag: optionalText2(filters.tag, 80) ?? void 0,
@@ -66893,6 +67061,7 @@ var init_commons_repository = __esm({
66893
67061
  import_node_crypto39 = require("crypto");
66894
67062
  init_db();
66895
67063
  init_commons_image_store();
67064
+ init_commons_embeddings();
66896
67065
  init_schema_presence();
66897
67066
  init_rates();
66898
67067
  init_commons_linksets();
@@ -67084,6 +67253,101 @@ var init_commons_repository = __esm({
67084
67253
  }
67085
67254
  });
67086
67255
 
67256
+ // src/editorial-reading-room/article-page.ts
67257
+ function escapeHtml7(value) {
67258
+ return String(value ?? "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
67259
+ }
67260
+ function articlePath(origin, slug4) {
67261
+ return `${origin.replace(/\/+$/, "")}/${encodeURIComponent(slug4)}`;
67262
+ }
67263
+ function renderEditorialArticlePage(input) {
67264
+ const articles = renderEditorialArticleModels(input.edition);
67265
+ const index = articles.findIndex((article2) => article2.slug === input.articleSlug);
67266
+ if (index === -1) return null;
67267
+ const article = articles[index];
67268
+ const previous = index > 0 ? articles[index - 1] : null;
67269
+ const next = index < articles.length - 1 ? articles[index + 1] : null;
67270
+ const canonicalUrl = articlePath(input.origin, article.slug);
67271
+ const site = input.edition.site;
67272
+ const description = article.summary || input.edition.deck || site.title;
67273
+ const jsonLd = JSON.stringify({
67274
+ "@context": "https://schema.org",
67275
+ "@type": "Article",
67276
+ "@id": `${canonicalUrl}#article`,
67277
+ headline: article.title,
67278
+ description,
67279
+ articleSection: article.category,
67280
+ wordCount: article.wordCount,
67281
+ url: canonicalUrl,
67282
+ isPartOf: { "@type": "CollectionPage", "@id": `${input.editionUrl}#collection`, name: site.title, url: input.editionUrl },
67283
+ publisher: { "@type": "Organization", name: input.publicationTitle, url: input.origin }
67284
+ }).replace(/</g, "\\u003c");
67285
+ const jumps = article.toc.length ? `<nav class="article-jumps" aria-label="On this page">${article.toc.map((item) => `<a href="#${escapeHtml7(item.id)}">${escapeHtml7(item.title)}</a>`).join("")}</nav>` : "";
67286
+ const neighbour = (item, label) => item ? `<a class="neighbour" href="${escapeHtml7(articlePath(input.origin, item.slug))}"><span>${label}</span><strong>${escapeHtml7(item.title)}</strong></a>` : "";
67287
+ const html = `<!doctype html>
67288
+ <html lang="en">
67289
+ <head>
67290
+ <meta charset="utf-8">
67291
+ <meta name="viewport" content="width=device-width, initial-scale=1">
67292
+ <title>${escapeHtml7(article.title)} \u2014 ${escapeHtml7(input.publicationTitle)}</title>
67293
+ <meta name="description" content="${escapeHtml7(description)}">
67294
+ <link rel="canonical" href="${escapeHtml7(canonicalUrl)}">
67295
+ <meta property="og:type" content="article">
67296
+ <meta property="og:title" content="${escapeHtml7(article.title)}">
67297
+ <meta property="og:description" content="${escapeHtml7(description)}">
67298
+ <meta property="og:url" content="${escapeHtml7(canonicalUrl)}">
67299
+ <meta property="og:site_name" content="${escapeHtml7(input.publicationTitle)}">
67300
+ <meta name="twitter:card" content="summary_large_image">
67301
+ <meta name="twitter:title" content="${escapeHtml7(article.title)}">
67302
+ <meta name="twitter:description" content="${escapeHtml7(description)}">
67303
+ <script type="application/ld+json">${jsonLd}</script>
67304
+ <style>
67305
+ :root{color-scheme:light dark;--ink:#12171f;--muted:#5b6672;--rule:#dfe4ea;--bg:#fbfbfa;--accent:#8a6a2f}
67306
+ *{box-sizing:border-box}
67307
+ body{margin:0;background:var(--bg);color:var(--ink);font:17px/1.65 Georgia,"Times New Roman",serif}
67308
+ a{color:inherit}
67309
+ header.masthead{border-bottom:1px solid var(--rule);padding:18px 20px}
67310
+ header.masthead a{font:600 13px/1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.08em;text-transform:uppercase;text-decoration:none;color:var(--muted)}
67311
+ main{max-width:44rem;margin:0 auto;padding:34px 20px 64px}
67312
+ .kicker{font:600 12px/1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.1em;text-transform:uppercase;color:var(--accent)}
67313
+ h1{font-size:2.1rem;line-height:1.18;margin:12px 0 10px}
67314
+ .summary{color:var(--muted);font-size:1.06rem;margin:0 0 18px}
67315
+ .meta{font:12px/1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:11px 0;margin-bottom:26px}
67316
+ .article-jumps{display:flex;flex-wrap:wrap;gap:10px;margin:0 0 26px}
67317
+ .article-jumps a{font:13px/1 ui-sans-serif,system-ui,sans-serif;color:var(--muted);text-decoration:none;border:1px solid var(--rule);border-radius:999px;padding:6px 11px}
67318
+ article h2{font-size:1.4rem;margin:32px 0 10px}
67319
+ article h3{font-size:1.15rem;margin:24px 0 8px}
67320
+ article p{margin:0 0 17px}
67321
+ .neighbours{display:grid;gap:12px;margin-top:44px;padding-top:22px;border-top:1px solid var(--rule)}
67322
+ .neighbour{display:block;text-decoration:none;border:1px solid var(--rule);border-radius:10px;padding:13px 15px;background:#fff}
67323
+ .neighbour span{display:block;font:11px/1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);margin-bottom:5px}
67324
+ footer{border-top:1px solid var(--rule);padding:20px;text-align:center;color:var(--muted);font:13px/1.5 ui-sans-serif,system-ui,sans-serif}
67325
+ @media (prefers-color-scheme:dark){:root{--ink:#eef1f5;--muted:#9aa4b1;--rule:#2b323b;--bg:#12151a}.neighbour{background:#171b21}}
67326
+ </style>
67327
+ </head>
67328
+ <body>
67329
+ <header class="masthead"><a href="${escapeHtml7(input.origin)}">${escapeHtml7(input.publicationTitle)}</a></header>
67330
+ <main>
67331
+ <p class="kicker">${escapeHtml7(article.kicker || article.category)}</p>
67332
+ <h1>${escapeHtml7(article.title)}</h1>
67333
+ <p class="summary">${escapeHtml7(article.summary)}</p>
67334
+ <p class="meta">${escapeHtml7(article.category)} \xB7 ${article.wordCount} words \xB7 ${article.readingMinutes} min \xB7 <a href="${escapeHtml7(input.editionUrl)}">${escapeHtml7(site.title)}</a></p>
67335
+ ${jumps}
67336
+ <article>${article.html}</article>
67337
+ <div class="neighbours">${neighbour(previous, "Previous")}${neighbour(next, "Next")}</div>
67338
+ </main>
67339
+ <footer>${escapeHtml7(input.publicationTitle)} \xB7 <a href="${escapeHtml7(input.editionUrl)}">All articles in ${escapeHtml7(site.title)}</a></footer>
67340
+ </body>
67341
+ </html>`;
67342
+ return { html, article, canonicalUrl };
67343
+ }
67344
+ var init_article_page = __esm({
67345
+ "src/editorial-reading-room/article-page.ts"() {
67346
+ "use strict";
67347
+ init_render();
67348
+ }
67349
+ });
67350
+
67087
67351
  // src/api/commons-publication-repository.ts
67088
67352
  async function prepareCommonsPublication(input, user) {
67089
67353
  await ensureCommonsSchema();
@@ -67382,6 +67646,20 @@ async function listCommonsPublicationEditions(publicationId) {
67382
67646
  if (!publication) return [];
67383
67647
  return result.rows.map((row) => rowToEdition(row, publication.subdomain));
67384
67648
  }
67649
+ async function getCommonsPublicationArticleHtml(subdomainInput, articleSlug, editionSlugInput) {
67650
+ const found = await getCommonsPublicationEditionHtml(subdomainInput, editionSlugInput);
67651
+ if (!found) return null;
67652
+ const { publication, edition } = found;
67653
+ const page = renderEditorialArticlePage({
67654
+ edition: { site: edition.site, deck: edition.deck, articles: edition.articles },
67655
+ articleSlug,
67656
+ origin: publicationPublicUrl(publication.subdomain),
67657
+ editionUrl: editionPublicUrl(publication.subdomain, edition.editionSlug),
67658
+ publicationTitle: publication.title
67659
+ });
67660
+ if (!page) return null;
67661
+ return { publication, edition, html: page.html, canonicalUrl: page.canonicalUrl };
67662
+ }
67385
67663
  async function getCommonsPublicationEditionHtml(subdomainInput, editionSlugInput) {
67386
67664
  const publication = await getCommonsPublicationBySubdomain(subdomainInput);
67387
67665
  if (!publication) return null;
@@ -67530,6 +67808,7 @@ var init_commons_publication_repository = __esm({
67530
67808
  init_db();
67531
67809
  init_commons_repository();
67532
67810
  init_render();
67811
+ init_article_page();
67533
67812
  PUBLICATION_ROOT_DOMAIN = process.env.COMMONS_PUBLICATION_ROOT_DOMAIN || "transparent-commons.cc";
67534
67813
  RESERVED_SUBDOMAINS = /* @__PURE__ */ new Set([
67535
67814
  "admin",
@@ -67569,6 +67848,7 @@ var init_commons_publication_repository = __esm({
67569
67848
  // src/api/commons-routes.ts
67570
67849
  function filtersFromQuery(query) {
67571
67850
  return {
67851
+ mode: query.mode === "lexical" || query.mode === "semantic" ? query.mode : void 0,
67572
67852
  query: query.query || query.q,
67573
67853
  entityType: query.entityType,
67574
67854
  tag: query.tag,
@@ -67643,6 +67923,7 @@ var init_commons_routes = __esm({
67643
67923
  init_api_auth();
67644
67924
  init_commons_repository();
67645
67925
  init_commons_image_store();
67926
+ init_commons_embeddings();
67646
67927
  init_commons_linksets();
67647
67928
  init_listing_write_billing();
67648
67929
  init_commons_publication_repository();
@@ -67650,6 +67931,7 @@ var init_commons_routes = __esm({
67650
67931
  commonsApp = new import_hono31.Hono();
67651
67932
  auth2 = createApiKeyAuth();
67652
67933
  SearchBodySchema = import_zod52.z.object({
67934
+ mode: import_zod52.z.enum(["lexical", "semantic", "hybrid"]).optional(),
67653
67935
  query: import_zod52.z.string().max(300).optional(),
67654
67936
  entityType: import_zod52.z.string().max(120).optional(),
67655
67937
  tag: import_zod52.z.string().max(80).optional(),
@@ -67813,6 +68095,14 @@ var init_commons_routes = __esm({
67813
68095
  ClaimPublicationSchema = import_zod52.z.object(CommonsClaimPublicationInputSchema).strict();
67814
68096
  PublishEditorialSchema = import_zod52.z.object(CommonsPublishEditorialInputSchema).strict();
67815
68097
  UpdateEditorialArticleSchema = import_zod52.z.object(CommonsUpdateEditorialArticleInputSchema).strict();
68098
+ commonsApp.post("/index/embed", auth2, async (c) => {
68099
+ const body = await c.req.json().catch(() => ({}));
68100
+ const result = await embedQueuedCommonsDocuments(Number(body.limit) || 50);
68101
+ return c.json({ ok: true, data: result });
68102
+ });
68103
+ commonsApp.get("/index/status", auth2, async (c) => {
68104
+ return c.json({ ok: true, data: { queued: await queuedCommonsDocumentCount(), semanticSearchConfigured: commonsSemanticSearchConfigured() } });
68105
+ });
67816
68106
  commonsApp.get("/health", async (c) => {
67817
68107
  await ensureCommonsSchema();
67818
68108
  return c.json({ ok: true, data: commonsDatabaseReport() });
@@ -67871,6 +68161,28 @@ var init_commons_routes = __esm({
67871
68161
  return publicationError(c, error);
67872
68162
  }
67873
68163
  });
68164
+ commonsApp.get("/publications/:subdomain/articles/:articleSlug/site", async (c) => {
68165
+ try {
68166
+ const result = await getCommonsPublicationArticleHtml(c.req.param("subdomain"), c.req.param("articleSlug"));
68167
+ if (!result) return c.json({ ok: false, error: "article_not_found", message: "No published article matched that publication and slug." }, 404);
68168
+ return c.html(result.html, 200, {
68169
+ "cache-control": "public, max-age=60, s-maxage=300",
68170
+ "x-robots-tag": "index, follow",
68171
+ link: `<${result.canonicalUrl}>; rel="canonical"`
68172
+ });
68173
+ } catch (error) {
68174
+ return publicationError(c, error);
68175
+ }
68176
+ });
68177
+ commonsApp.get("/publications/:subdomain/editions/:editionSlug/articles/:articleSlug/site", async (c) => {
68178
+ try {
68179
+ const result = await getCommonsPublicationArticleHtml(c.req.param("subdomain"), c.req.param("articleSlug"), c.req.param("editionSlug"));
68180
+ if (!result) return c.json({ ok: false, error: "article_not_found", message: "No published article matched that publication, edition, and slug." }, 404);
68181
+ return c.html(result.html, 200, { "cache-control": "public, max-age=60, s-maxage=300", "x-robots-tag": "index, follow" });
68182
+ } catch (error) {
68183
+ return publicationError(c, error);
68184
+ }
68185
+ });
67874
68186
  commonsApp.get("/publications/:subdomain/editions/:editionSlug/site", async (c) => {
67875
68187
  try {
67876
68188
  const result = await getCommonsPublicationEditionHtml(c.req.param("subdomain"), c.req.param("editionSlug"));
@@ -71439,7 +71751,7 @@ function pixelSnippet(publicId) {
71439
71751
  function formSnippet(publicId) {
71440
71752
  return `<div data-mcp-form="${publicId}"></div><script async src="https://mcpscraper.dev/analytics/v1/form.js?form=${publicId}"></script>`;
71441
71753
  }
71442
- function escapeHtml7(value) {
71754
+ function escapeHtml8(value) {
71443
71755
  return String(value ?? "").replace(
71444
71756
  /[&<>"']/g,
71445
71757
  (character) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[character]
@@ -71451,13 +71763,13 @@ function renderPublicForm(form, placementUrl) {
71451
71763
  const fields = form.fields.map((field) => {
71452
71764
  const required = field.required ? " required" : "";
71453
71765
  const options = (field.options ?? []).map(
71454
- (option) => `<option value="${escapeHtml7(option)}">${escapeHtml7(option)}</option>`
71766
+ (option) => `<option value="${escapeHtml8(option)}">${escapeHtml8(option)}</option>`
71455
71767
  ).join("");
71456
- const control = field.type === "textarea" ? `<textarea id="${escapeHtml7(field.id)}" name="${escapeHtml7(field.id)}"${required}></textarea>` : field.type === "select" ? `<select id="${escapeHtml7(field.id)}" name="${escapeHtml7(field.id)}"${required}><option value="">Choose\u2026</option>${options}</select>` : field.type === "checkbox" ? `<input id="${escapeHtml7(field.id)}" name="${escapeHtml7(field.id)}" type="checkbox" value="true"${required}>` : `<input id="${escapeHtml7(field.id)}" name="${escapeHtml7(field.id)}" type="${escapeHtml7(field.type)}"${required}>`;
71457
- return `<label${field.type === "checkbox" ? ' class="check"' : ""}><span>${escapeHtml7(field.label)}${field.required ? " *" : ""}</span>${control}</label>`;
71768
+ const control = field.type === "textarea" ? `<textarea id="${escapeHtml8(field.id)}" name="${escapeHtml8(field.id)}"${required}></textarea>` : field.type === "select" ? `<select id="${escapeHtml8(field.id)}" name="${escapeHtml8(field.id)}"${required}><option value="">Choose\u2026</option>${options}</select>` : field.type === "checkbox" ? `<input id="${escapeHtml8(field.id)}" name="${escapeHtml8(field.id)}" type="checkbox" value="true"${required}>` : `<input id="${escapeHtml8(field.id)}" name="${escapeHtml8(field.id)}" type="${escapeHtml8(field.type)}"${required}>`;
71769
+ return `<label${field.type === "checkbox" ? ' class="check"' : ""}><span>${escapeHtml8(field.label)}${field.required ? " *" : ""}</span>${control}</label>`;
71458
71770
  }).join("");
71459
71771
  const brand = form.brand;
71460
- return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>:root{font-family:ui-sans-serif,system-ui;color:${escapeHtml7(brand.textColor)};background:${escapeHtml7(brand.backgroundColor)}}*{box-sizing:border-box}body{margin:0;padding:18px}form{display:grid;gap:14px}label{display:grid;gap:6px;font-size:13px;font-weight:650}.check{grid-template-columns:auto 1fr;align-items:center}.check span{grid-column:2}.check input{grid-column:1;grid-row:1}input,textarea,select{width:100%;min-height:44px;padding:10px 12px;border:1px solid #ccd3df;border-radius:${brand.radius}px;background:white;color:inherit;font:inherit}textarea{min-height:110px;resize:vertical}button{min-height:46px;border:0;border-radius:${brand.radius}px;color:white;background:${escapeHtml7(brand.primaryColor)};font:inherit;font-weight:750;cursor:pointer}.consent{margin:0;color:#667085;font-size:11px;line-height:1.45}.notice{display:none;padding:12px;border-radius:${brand.radius}px;background:#edf8f2;color:#17613c}.hp{position:absolute!important;left:-9999px!important}</style></head><body><form id="mcp-form">${fields}<label class="hp">Website<input name="website" autocomplete="off" tabindex="-1"></label>${form.consent_text ? `<p class="consent">${escapeHtml7(form.consent_text)}</p>` : ""}<button>${escapeHtml7(form.submit_label)}</button><div class="notice" role="status"></div></form><script>(()=>{const form=document.querySelector('#mcp-form'),notice=form.querySelector('.notice'),q=new URLSearchParams(location.search);form.addEventListener('submit',async event=>{event.preventDefault();const button=form.querySelector('button');button.disabled=true;const raw=Object.fromEntries(new FormData(form).entries()),website=String(raw.website||''),clickIds={};delete raw.website;for(const k of ['fbclid','gclid','gbraid','wbraid','ttclid','rdt_cid','msclkid']){const v=q.get(k);if(v)clickIds[k]=v}try{const response=await fetch('/analytics/forms/${escapeHtml7(form.public_id)}/submissions',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({data:raw,website,placementUrl:${JSON.stringify(placementUrl)},visitorId:q.get('visitor')||undefined,sessionId:q.get('session')||undefined,source:q.get('source')||undefined,medium:q.get('medium')||undefined,campaign:q.get('campaign')||undefined,clickIds})});if(!response.ok)throw new Error('submit');notice.textContent=${JSON.stringify(form.success_message)};notice.style.display='block';form.reset();${form.redirect_url ? `setTimeout(()=>{top.location.href=${JSON.stringify(form.redirect_url)}},700);` : ""}}catch{notice.textContent='Your response could not be submitted. Please try again.';notice.style.display='block'}finally{button.disabled=false}})})()</script></body></html>`;
71772
+ return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>:root{font-family:ui-sans-serif,system-ui;color:${escapeHtml8(brand.textColor)};background:${escapeHtml8(brand.backgroundColor)}}*{box-sizing:border-box}body{margin:0;padding:18px}form{display:grid;gap:14px}label{display:grid;gap:6px;font-size:13px;font-weight:650}.check{grid-template-columns:auto 1fr;align-items:center}.check span{grid-column:2}.check input{grid-column:1;grid-row:1}input,textarea,select{width:100%;min-height:44px;padding:10px 12px;border:1px solid #ccd3df;border-radius:${brand.radius}px;background:white;color:inherit;font:inherit}textarea{min-height:110px;resize:vertical}button{min-height:46px;border:0;border-radius:${brand.radius}px;color:white;background:${escapeHtml8(brand.primaryColor)};font:inherit;font-weight:750;cursor:pointer}.consent{margin:0;color:#667085;font-size:11px;line-height:1.45}.notice{display:none;padding:12px;border-radius:${brand.radius}px;background:#edf8f2;color:#17613c}.hp{position:absolute!important;left:-9999px!important}</style></head><body><form id="mcp-form">${fields}<label class="hp">Website<input name="website" autocomplete="off" tabindex="-1"></label>${form.consent_text ? `<p class="consent">${escapeHtml8(form.consent_text)}</p>` : ""}<button>${escapeHtml8(form.submit_label)}</button><div class="notice" role="status"></div></form><script>(()=>{const form=document.querySelector('#mcp-form'),notice=form.querySelector('.notice'),q=new URLSearchParams(location.search);form.addEventListener('submit',async event=>{event.preventDefault();const button=form.querySelector('button');button.disabled=true;const raw=Object.fromEntries(new FormData(form).entries()),website=String(raw.website||''),clickIds={};delete raw.website;for(const k of ['fbclid','gclid','gbraid','wbraid','ttclid','rdt_cid','msclkid']){const v=q.get(k);if(v)clickIds[k]=v}try{const response=await fetch('/analytics/forms/${escapeHtml8(form.public_id)}/submissions',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({data:raw,website,placementUrl:${JSON.stringify(placementUrl)},visitorId:q.get('visitor')||undefined,sessionId:q.get('session')||undefined,source:q.get('source')||undefined,medium:q.get('medium')||undefined,campaign:q.get('campaign')||undefined,clickIds})});if(!response.ok)throw new Error('submit');notice.textContent=${JSON.stringify(form.success_message)};notice.style.display='block';form.reset();${form.redirect_url ? `setTimeout(()=>{top.location.href=${JSON.stringify(form.redirect_url)}},700);` : ""}}catch{notice.textContent='Your response could not be submitted. Please try again.';notice.style.display='block'}finally{button.disabled=false}})})()</script></body></html>`;
71461
71773
  }
71462
71774
  var import_hono32, import_factory6, import_zod54, import_node_crypto43, import_papaparse4, analyticsApp, auth3, entitlementGuard, ThorbitApiKeySchema, ThorbitCallbackSchema, SiteInputSchema, PixelInputSchema, PixelUpdateSchema, EventSchema, IngestionSchema, ConversionSchema, ExportSchema2, CampaignLinkSchema, FormFieldSchema, FormInputSchema, FormSubmissionSchema, CrmImportSchema, ActivationDestinationSchema, BusinessModelSchema, AdSpendSchema;
71463
71775
  var init_analytics_routes = __esm({
@@ -72943,7 +73255,7 @@ var init_scheduled_run_view_links = __esm({
72943
73255
  });
72944
73256
 
72945
73257
  // src/personal-authority/render.ts
72946
- function escapeHtml8(value) {
73258
+ function escapeHtml9(value) {
72947
73259
  return value.replace(/[&<>"']/g, (character) => ({
72948
73260
  "&": "&amp;",
72949
73261
  "<": "&lt;",
@@ -72954,13 +73266,13 @@ function escapeHtml8(value) {
72954
73266
  }
72955
73267
  function safeHref(value) {
72956
73268
  const trimmed = value.trim();
72957
- return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml8(trimmed) : "#";
73269
+ return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml9(trimmed) : "#";
72958
73270
  }
72959
73271
  function initials(name) {
72960
73272
  return name.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]?.toUpperCase()).join("") || "PA";
72961
73273
  }
72962
73274
  function action(action3, secondary = false) {
72963
- return `<a class="button${secondary ? " button--secondary" : ""}" href="${safeHref(action3.href)}">${escapeHtml8(action3.label)} <span aria-hidden="true">\u2197</span></a>`;
73275
+ return `<a class="button${secondary ? " button--secondary" : ""}" href="${safeHref(action3.href)}">${escapeHtml9(action3.label)} <span aria-hidden="true">\u2197</span></a>`;
72964
73276
  }
72965
73277
  function section(enabled, html) {
72966
73278
  return enabled ? html : "";
@@ -72969,7 +73281,7 @@ function renderPersonalAuthorityV1(input, config, generatedAt) {
72969
73281
  const flags = config.featureFlags;
72970
73282
  const brand = config.brandName || input.name;
72971
73283
  const generatedAtIso = generatedAt.toISOString();
72972
- const social = flags.socialLinks && input.socialLinks.length > 0 ? `<nav class="social" aria-label="Professional profiles">${input.socialLinks.map((link2) => `<a href="${safeHref(link2.href)}">${escapeHtml8(link2.label)}</a>`).join("")}</nav>` : "";
73284
+ const social = flags.socialLinks && input.socialLinks.length > 0 ? `<nav class="social" aria-label="Professional profiles">${input.socialLinks.map((link2) => `<a href="${safeHref(link2.href)}">${escapeHtml9(link2.label)}</a>`).join("")}</nav>` : "";
72973
73285
  const navigation = flags.navigation ? `<button class="menu" type="button" aria-expanded="false" aria-controls="nav">Menu</button><nav id="nav" class="nav" aria-label="Primary navigation"><a href="#about">About</a><a href="#services">Work</a><a href="#proof">Proof</a><a href="#contact">Contact</a></nav>` : "";
72974
73286
  const authority = input.authority;
72975
73287
  const consultation = input.consultation;
@@ -72981,21 +73293,21 @@ function renderPersonalAuthorityV1(input, config, generatedAt) {
72981
73293
  <html lang="en" data-theme="${config.theme}">
72982
73294
  <head>
72983
73295
  <meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
72984
- <meta name="description" content="${escapeHtml8(input.summary)}"><title>${escapeHtml8(input.name)} \u2014 ${escapeHtml8(input.professionalTitle)}</title>
73296
+ <meta name="description" content="${escapeHtml9(input.summary)}"><title>${escapeHtml9(input.name)} \u2014 ${escapeHtml9(input.professionalTitle)}</title>
72985
73297
  <style>
72986
73298
  :root{--blue:#2f66eb;--blue-soft:#dbe6ff;--ink:#050708;--paper:#f7f8fb;--white:#fff;--gray:#9ca5b5;--line:#27303b;--serif:Georgia,'Times New Roman',serif;--sans:Arial,Helvetica,sans-serif}*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--ink);color:var(--white);font-family:var(--sans);line-height:1.55}a{color:inherit}.skip{position:absolute;left:-9999px}.skip:focus{left:16px;top:16px;z-index:9;background:#fff;color:#000;padding:10px}.header{height:88px;display:flex;align-items:center;justify-content:space-between;padding:0 clamp(20px,4vw,72px);border-bottom:1px solid var(--line);position:relative;z-index:3;background:rgba(5,7,8,.96)}.brand{display:flex;align-items:center;gap:12px;text-decoration:none;font-family:var(--serif);font-size:24px}.mark{width:40px;height:40px;border-radius:50%;display:grid;place-items:center;background:var(--blue);font-family:var(--sans);font-weight:700}.nav{display:flex;align-items:center;gap:28px}.nav a{text-decoration:none;color:#c8ced8;font-size:14px}.nav a:hover{color:#fff}.menu{display:none;background:transparent;color:#fff;border:1px solid #5b6471;padding:10px 14px}.hero{display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.25fr);min-height:760px;border-bottom:3px solid var(--blue)}.portrait{display:grid;place-items:end center;background:radial-gradient(circle at 50% 38%,#273243 0,#11161d 38%,#060708 70%);overflow:hidden}.portrait-card{width:min(82%,560px);aspect-ratio:4/5;display:grid;place-items:center;align-self:end;border:1px solid #263142;border-bottom:0;background:linear-gradient(145deg,#252d38,#0b0d10 58%);font-family:var(--serif);font-size:clamp(80px,13vw,180px);color:#d9e4ff;text-shadow:0 0 42px rgba(47,102,235,.5)}.hero-copy{padding:clamp(44px,7vw,110px) clamp(24px,6vw,100px);display:flex;flex-direction:column;justify-content:center;background:linear-gradient(135deg,#080a0d,#101318)}h1,h2,h3,p{margin-top:0}.hero h1{font-family:var(--serif);font-size:clamp(58px,8vw,116px);line-height:.92;font-weight:400;color:var(--blue);margin-bottom:24px}.role{font-family:var(--serif);font-size:clamp(28px,3.8vw,52px);line-height:1.05;border-left:5px solid var(--blue);padding-left:22px;max-width:820px}.summary{color:#c6cbd3;font-size:clamp(17px,1.5vw,22px);max-width:760px}.actions{display:flex;gap:12px;flex-wrap:wrap;margin:24px 0}.button{display:inline-flex;align-items:center;justify-content:space-between;gap:28px;min-height:58px;padding:0 26px;background:var(--blue);border:1px solid var(--blue);text-decoration:none;font-weight:700}.button--secondary{background:transparent;border-color:#5c6572}.social{display:flex;gap:10px;flex-wrap:wrap}.social a{border:1px solid #39414d;border-radius:999px;padding:8px 13px;text-decoration:none;color:#d8dce4;font-size:13px}.light{background:var(--paper);color:#111722;padding:clamp(70px,10vw,150px) clamp(20px,6vw,90px)}.light h2,.section h2{font-family:var(--serif);font-size:clamp(42px,6vw,82px);line-height:1.02;font-weight:400;max-width:1080px}.light p{max-width:920px;color:#4e596a;font-size:18px}.section{padding:clamp(70px,9vw,130px) clamp(20px,6vw,90px);border-bottom:1px solid var(--line)}.section-head{max-width:920px;margin-bottom:46px}.eyebrow{text-transform:uppercase;letter-spacing:.18em;font-size:12px;color:#aab2bf}.consult{display:grid;grid-template-columns:1.3fr .7fr;gap:50px;background:linear-gradient(130deg,#060708,#111721)}.accent-card{min-height:360px;border:1px solid #2a3545;background:linear-gradient(145deg,rgba(47,102,235,.22),transparent 55%);display:grid;place-items:center;font-family:var(--serif);font-size:96px;color:var(--blue)}.grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}.card{border:1px solid #323a46;padding:26px;min-height:220px;background:#0b0e12}.card h3{font-family:var(--serif);font-size:30px}.card p{color:#b9c0ca}.learning{background:#020303}.topic-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px;background:#29313c;border:1px solid #29313c}.topic{background:#050708;padding:30px}.topic strong{display:block;color:var(--blue);text-transform:uppercase;font-size:11px;letter-spacing:.15em}.topic h3{font-family:var(--serif);font-size:30px;margin:8px 0}.topic p{color:#aeb6c1}.proof{background:linear-gradient(180deg,#0a0d11,#050607)}.quotes{display:flex;gap:14px;overflow:auto;scroll-snap-type:x mandatory;padding-bottom:12px}.quote{min-width:min(420px,86vw);scroll-snap-align:start;border:1px solid #343d49;padding:30px;background:#0c1015}.quote q{font-family:var(--serif);font-size:30px;line-height:1.25}.quote span{display:block;margin-top:24px;color:#aeb5c0;font-size:12px;text-transform:uppercase;letter-spacing:.12em}.cta{text-align:center;border-top:3px solid var(--blue);background:radial-gradient(circle at 50% 0,rgba(47,102,235,.25),transparent 50%)}.cta h2{margin-left:auto;margin-right:auto}.footer{display:grid;grid-template-columns:1fr auto;gap:40px;padding:46px clamp(20px,6vw,90px);color:#abb3bf}.footer strong{color:#fff;font-family:var(--serif);font-size:26px}.generated{font-size:11px;color:#737d8b;margin-top:10px}html[data-theme='slate']{--blue:#7f95b8;--blue-soft:#dfe6ef}html[data-theme='monochrome']{--blue:#fff;--blue-soft:#e7e7e7}.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0)}
72987
73299
  @media(max-width:760px){.header{height:78px}.menu{display:block}.nav{display:none;position:absolute;left:0;right:0;top:77px;padding:18px 20px;background:#090b0e;border-bottom:1px solid #303844;flex-direction:column;align-items:stretch}.nav.open{display:flex}.hero{grid-template-columns:1fr;min-height:0}.portrait{min-height:390px}.portrait-card{width:72%;max-height:360px}.hero-copy{padding:48px 20px 66px}.hero h1{font-size:64px}.role{font-size:34px}.actions{display:grid}.button{width:100%}.consult{grid-template-columns:1fr}.accent-card{min-height:220px}.grid,.topic-grid{grid-template-columns:1fr}.light,.section{padding:64px 20px}.light h2,.section h2{font-size:46px}.footer{grid-template-columns:1fr}}
72988
73300
  </style></head>
72989
73301
  <body><a class="skip" href="#main">Skip to main content</a>
72990
- <header class="header"><a class="brand" href="#top"><span class="mark">${escapeHtml8(initials(input.name).slice(0, 1))}</span><strong>${escapeHtml8(brand)}</strong></a>${navigation}</header>
72991
- <main id="main"><section class="hero" id="top"><div class="portrait" aria-label="Portrait placeholder"><div class="portrait-card" aria-hidden="true">${escapeHtml8(initials(input.name))}</div></div><div class="hero-copy"><h1>${escapeHtml8(input.name)}</h1><p class="role">${escapeHtml8(input.professionalTitle)}</p><p class="summary">${escapeHtml8(input.summary)}</p><div class="actions">${action(input.primaryAction)}${input.secondaryAction ? action(input.secondaryAction, true) : ""}</div>${social}</div></section>
72992
- ${section(flags.authority && Boolean(authority), `<section class="light" id="about"><h2>${escapeHtml8(authority?.heading ?? "")}</h2>${authority?.paragraphs.map((paragraph) => `<p>${escapeHtml8(paragraph)}</p>`).join("") ?? ""}</section>`)}
72993
- ${section(flags.consultation && Boolean(consultation), `<section class="section consult"><div><p class="eyebrow">${escapeHtml8(consultation?.eyebrow ?? "Start a conversation")}</p><h2>${escapeHtml8(consultation?.heading ?? "")}</h2><p class="summary">${escapeHtml8(consultation?.summary ?? "")}</p>${consultation ? action(consultation.action) : ""}</div><div class="accent-card" aria-label="Image placeholder">${escapeHtml8(initials(input.name))}</div></section>`)}
72994
- ${section(flags.learning && Boolean(learning), `<section class="section learning"><div class="section-head"><h2>${escapeHtml8(learning?.heading ?? "")}</h2><p class="summary">${escapeHtml8(learning?.summary ?? "")}</p></div><div class="topic-grid">${learning?.topics.map((topic) => `<article class="topic"><strong>${escapeHtml8(topic.title)}</strong><h3>${escapeHtml8(topic.headline)}</h3><p>${escapeHtml8(topic.summary)}</p>${topic.href ? `<a href="${safeHref(topic.href)}">Explore \u2192</a>` : ""}</article>`).join("") ?? ""}</div></section>`)}
72995
- ${section(flags.services && Boolean(services), `<section class="section" id="services"><div class="section-head"><h2>${escapeHtml8(services?.heading ?? "")}</h2><p class="summary">${escapeHtml8(services?.summary ?? "")}</p></div><div class="grid">${services?.offers.map((offer) => `<article class="card"><h3>${escapeHtml8(offer.title)}</h3><p>${escapeHtml8(offer.description)}</p>${offer.action ? action(offer.action, true) : ""}</article>`).join("") ?? ""}</div></section>`)}
72996
- ${section(flags.proof && Boolean(proof), `<section class="section proof" id="proof"><div class="section-head"><h2>${escapeHtml8(proof?.heading ?? "")}</h2><p class="summary">${escapeHtml8(proof?.summary ?? "")}</p></div><div class="quotes">${proof?.testimonials.map((item) => `<article class="quote"><q>${escapeHtml8(item.quote)}</q><span>${escapeHtml8(item.person)}${item.role ? ` / ${escapeHtml8(item.role)}` : ""}</span></article>`).join("") ?? ""}</div></section>`)}
72997
- ${section(flags.finalCta && Boolean(finalCta), `<section class="section cta" id="contact"><p class="eyebrow">${escapeHtml8(finalCta?.eyebrow ?? "Ready when you are")}</p><h2>${escapeHtml8(finalCta?.heading ?? "")}</h2><p class="summary">${escapeHtml8(finalCta?.summary ?? "")}</p>${finalCta ? action(finalCta.action) : ""}</section>`)}
72998
- </main><footer class="footer"><div><strong>${escapeHtml8(input.name)}</strong><div>${escapeHtml8(input.professionalTitle)}</div>${config.showGeneratedAt ? `<div class="generated">Generated ${escapeHtml8(generatedAtIso)}</div>` : ""}</div><div>${input.location ? `<div>${escapeHtml8(input.location)}</div>` : ""}${input.email ? `<a href="mailto:${escapeHtml8(input.email)}">${escapeHtml8(input.email)}</a>` : ""}${input.phone ? `<div>${escapeHtml8(input.phone)}</div>` : ""}</div></footer>
73302
+ <header class="header"><a class="brand" href="#top"><span class="mark">${escapeHtml9(initials(input.name).slice(0, 1))}</span><strong>${escapeHtml9(brand)}</strong></a>${navigation}</header>
73303
+ <main id="main"><section class="hero" id="top"><div class="portrait" aria-label="Portrait placeholder"><div class="portrait-card" aria-hidden="true">${escapeHtml9(initials(input.name))}</div></div><div class="hero-copy"><h1>${escapeHtml9(input.name)}</h1><p class="role">${escapeHtml9(input.professionalTitle)}</p><p class="summary">${escapeHtml9(input.summary)}</p><div class="actions">${action(input.primaryAction)}${input.secondaryAction ? action(input.secondaryAction, true) : ""}</div>${social}</div></section>
73304
+ ${section(flags.authority && Boolean(authority), `<section class="light" id="about"><h2>${escapeHtml9(authority?.heading ?? "")}</h2>${authority?.paragraphs.map((paragraph) => `<p>${escapeHtml9(paragraph)}</p>`).join("") ?? ""}</section>`)}
73305
+ ${section(flags.consultation && Boolean(consultation), `<section class="section consult"><div><p class="eyebrow">${escapeHtml9(consultation?.eyebrow ?? "Start a conversation")}</p><h2>${escapeHtml9(consultation?.heading ?? "")}</h2><p class="summary">${escapeHtml9(consultation?.summary ?? "")}</p>${consultation ? action(consultation.action) : ""}</div><div class="accent-card" aria-label="Image placeholder">${escapeHtml9(initials(input.name))}</div></section>`)}
73306
+ ${section(flags.learning && Boolean(learning), `<section class="section learning"><div class="section-head"><h2>${escapeHtml9(learning?.heading ?? "")}</h2><p class="summary">${escapeHtml9(learning?.summary ?? "")}</p></div><div class="topic-grid">${learning?.topics.map((topic) => `<article class="topic"><strong>${escapeHtml9(topic.title)}</strong><h3>${escapeHtml9(topic.headline)}</h3><p>${escapeHtml9(topic.summary)}</p>${topic.href ? `<a href="${safeHref(topic.href)}">Explore \u2192</a>` : ""}</article>`).join("") ?? ""}</div></section>`)}
73307
+ ${section(flags.services && Boolean(services), `<section class="section" id="services"><div class="section-head"><h2>${escapeHtml9(services?.heading ?? "")}</h2><p class="summary">${escapeHtml9(services?.summary ?? "")}</p></div><div class="grid">${services?.offers.map((offer) => `<article class="card"><h3>${escapeHtml9(offer.title)}</h3><p>${escapeHtml9(offer.description)}</p>${offer.action ? action(offer.action, true) : ""}</article>`).join("") ?? ""}</div></section>`)}
73308
+ ${section(flags.proof && Boolean(proof), `<section class="section proof" id="proof"><div class="section-head"><h2>${escapeHtml9(proof?.heading ?? "")}</h2><p class="summary">${escapeHtml9(proof?.summary ?? "")}</p></div><div class="quotes">${proof?.testimonials.map((item) => `<article class="quote"><q>${escapeHtml9(item.quote)}</q><span>${escapeHtml9(item.person)}${item.role ? ` / ${escapeHtml9(item.role)}` : ""}</span></article>`).join("") ?? ""}</div></section>`)}
73309
+ ${section(flags.finalCta && Boolean(finalCta), `<section class="section cta" id="contact"><p class="eyebrow">${escapeHtml9(finalCta?.eyebrow ?? "Ready when you are")}</p><h2>${escapeHtml9(finalCta?.heading ?? "")}</h2><p class="summary">${escapeHtml9(finalCta?.summary ?? "")}</p>${finalCta ? action(finalCta.action) : ""}</section>`)}
73310
+ </main><footer class="footer"><div><strong>${escapeHtml9(input.name)}</strong><div>${escapeHtml9(input.professionalTitle)}</div>${config.showGeneratedAt ? `<div class="generated">Generated ${escapeHtml9(generatedAtIso)}</div>` : ""}</div><div>${input.location ? `<div>${escapeHtml9(input.location)}</div>` : ""}${input.email ? `<a href="mailto:${escapeHtml9(input.email)}">${escapeHtml9(input.email)}</a>` : ""}${input.phone ? `<div>${escapeHtml9(input.phone)}</div>` : ""}</div></footer>
72999
73311
  <script>document.querySelector('.menu')?.addEventListener('click',function(){var nav=document.querySelector('.nav');var open=this.getAttribute('aria-expanded')!=='true';this.setAttribute('aria-expanded',String(open));nav?.classList.toggle('open',open)});document.querySelectorAll('.nav a').forEach(function(link){link.addEventListener('click',function(){document.querySelector('.nav')?.classList.remove('open');document.querySelector('.menu')?.setAttribute('aria-expanded','false')})});</script></body></html>`;
73000
73312
  const bytes = Buffer.byteLength(html, "utf8");
73001
73313
  return {
@@ -73015,7 +73327,7 @@ var init_render2 = __esm({
73015
73327
  });
73016
73328
 
73017
73329
  // src/personal-authority/render-v2.ts
73018
- function escapeHtml9(value) {
73330
+ function escapeHtml10(value) {
73019
73331
  return value.replace(
73020
73332
  /[&<>"']/g,
73021
73333
  (character) => ({
@@ -73029,13 +73341,13 @@ function escapeHtml9(value) {
73029
73341
  }
73030
73342
  function safeHref2(value) {
73031
73343
  const trimmed = value.trim();
73032
- return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml9(trimmed) : "#";
73344
+ return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml10(trimmed) : "#";
73033
73345
  }
73034
73346
  function initials2(name) {
73035
73347
  return name.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]?.toUpperCase()).join("") || "PA";
73036
73348
  }
73037
73349
  function action2(action3, secondary = false) {
73038
- return `<a class="button${secondary ? " button--secondary" : ""}" href="${safeHref2(action3.href)}">${escapeHtml9(action3.label)} <span aria-hidden="true">\u2197</span></a>`;
73350
+ return `<a class="button${secondary ? " button--secondary" : ""}" href="${safeHref2(action3.href)}">${escapeHtml10(action3.label)} <span aria-hidden="true">\u2197</span></a>`;
73039
73351
  }
73040
73352
  function section2(enabled, html) {
73041
73353
  return enabled ? html : "";
@@ -73079,7 +73391,7 @@ function renderPersonalAuthorityV2(input, config, generatedAt) {
73079
73391
  const surfaceContrast = bestContrastTextColor(colors.surface);
73080
73392
  const accentChannels = hexChannels(colors.accent);
73081
73393
  const generatedAtIso = generatedAt.toISOString();
73082
- const social = flags.socialLinks && input.socialLinks.length > 0 ? `<nav class="social" aria-label="Professional profiles">${input.socialLinks.map((link2) => `<a href="${safeHref2(link2.href)}">${escapeHtml9(link2.label)}</a>`).join("")}</nav>` : "";
73394
+ const social = flags.socialLinks && input.socialLinks.length > 0 ? `<nav class="social" aria-label="Professional profiles">${input.socialLinks.map((link2) => `<a href="${safeHref2(link2.href)}">${escapeHtml10(link2.label)}</a>`).join("")}</nav>` : "";
73083
73395
  const navigation = flags.navigation ? `<button class="menu" type="button" aria-expanded="false" aria-controls="nav">Menu</button><nav id="nav" class="nav" aria-label="Primary navigation"><a href="#about">About</a><a href="#services">Work</a><a href="#proof">Proof</a><a href="#contact">Contact</a></nav>` : "";
73084
73396
  const authority = input.authority;
73085
73397
  const consultation = input.consultation;
@@ -73091,22 +73403,22 @@ function renderPersonalAuthorityV2(input, config, generatedAt) {
73091
73403
  <html lang="en" data-theme="${config.theme}">
73092
73404
  <head>
73093
73405
  <meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
73094
- <meta name="description" content="${escapeHtml9(input.summary)}"><title>${escapeHtml9(input.name)} - ${escapeHtml9(input.professionalTitle)}</title>
73406
+ <meta name="description" content="${escapeHtml10(input.summary)}"><title>${escapeHtml10(input.name)} - ${escapeHtml10(input.professionalTitle)}</title>
73095
73407
  <style>
73096
73408
  :root{--accent:${colors.accent};--accent-rgb:${accentChannels};--accent-contrast:${accentContrast};--background:${colors.background};--surface:${colors.surface};--surface-contrast:${surfaceContrast};--text:${colors.text};--muted:color-mix(in srgb,var(--text) 68%,var(--background));--surface-muted:color-mix(in srgb,var(--surface-contrast) 72%,var(--surface));--line:color-mix(in srgb,var(--text) 16%,var(--background));--display:${displayFont};--body:${bodyFont}}*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--background);color:var(--text);font-family:var(--body);line-height:1.55}a{color:inherit}.skip{position:absolute;left:-9999px}.skip:focus{left:16px;top:16px;z-index:9;background:var(--accent);color:var(--accent-contrast);padding:10px 14px;border-radius:999px}.header{height:80px;display:flex;align-items:center;justify-content:space-between;padding:0 clamp(20px,4vw,72px);position:relative;z-index:3;background:var(--surface);color:var(--surface-contrast);border-radius:0 0 24px 24px}.brand{display:flex;align-items:center;gap:12px;text-decoration:none;font-family:var(--display);font-size:24px}.mark{width:40px;height:40px;border-radius:12px;display:grid;place-items:center;background:var(--accent);color:var(--accent-contrast);font-family:var(--body);font-weight:700}.nav{display:flex;align-items:center;gap:28px}.nav a{text-decoration:none;color:var(--surface-muted);font-size:14px}.nav a:hover{color:var(--surface-contrast)}.nav a:focus-visible,.button:focus-visible,.social a:focus-visible,.menu:focus-visible{outline:3px solid var(--accent);outline-offset:4px}.menu{display:none;background:transparent;color:var(--surface-contrast);border:1px solid color-mix(in srgb,var(--surface-contrast) 28%,var(--surface));border-radius:999px;padding:10px 14px}.hero{display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.25fr);min-height:min(760px,calc(100dvh - 80px));border-bottom:1px solid var(--line);background:var(--background)}.portrait{margin:clamp(16px,3vw,36px) clamp(12px,2vw,24px) clamp(16px,3vw,36px) clamp(16px,3vw,36px);display:grid;place-items:end center;background:var(--surface);border-radius:28px;overflow:hidden}.portrait-card{width:min(82%,560px);aspect-ratio:4/5;display:grid;place-items:center;align-self:end;border:1px solid color-mix(in srgb,var(--surface-contrast) 18%,var(--surface));border-bottom:0;background:linear-gradient(145deg,color-mix(in srgb,var(--surface-contrast) 12%,var(--surface)),var(--surface) 66%);font-family:var(--display);font-size:clamp(80px,13vw,180px);color:var(--surface-contrast)}.hero-copy{padding:clamp(44px,7vw,110px) clamp(24px,6vw,100px);display:flex;flex-direction:column;justify-content:center;background:var(--background)}h1,h2,h3,p{margin-top:0}.hero h1{font-family:var(--display);font-size:clamp(58px,8vw,116px);line-height:.96;font-weight:500;letter-spacing:-.04em;color:var(--text);margin-bottom:24px;text-wrap:balance}.role{font-family:var(--display);font-size:clamp(28px,3.8vw,52px);line-height:1.08;border-left:5px solid var(--accent);padding-left:22px;max-width:820px;text-wrap:balance}.summary{color:var(--muted);font-size:clamp(17px,1.5vw,22px);max-width:65ch}.actions{display:flex;gap:12px;flex-wrap:wrap;margin:24px 0}.button{display:inline-flex;align-items:center;justify-content:space-between;gap:28px;min-height:58px;padding:0 26px;background:var(--accent);color:var(--accent-contrast);border:1px solid var(--accent);border-radius:999px;text-decoration:none;font-weight:700;transition:transform .2s ease,filter .2s ease}.button:hover{filter:brightness(1.06)}.button:active{transform:translateY(1px)}.button--secondary{background:transparent;color:var(--text);border-color:var(--line)}.social{display:flex;gap:10px;flex-wrap:wrap}.social a{border:1px solid var(--line);border-radius:999px;padding:8px 13px;text-decoration:none;color:var(--muted);font-size:13px}.light{background:var(--background);color:var(--text);padding:clamp(70px,10vw,150px) clamp(20px,6vw,90px)}.light h2,.section h2{font-family:var(--display);font-size:clamp(42px,6vw,82px);line-height:1.05;font-weight:500;letter-spacing:-.035em;max-width:1080px;text-wrap:balance}.light p{max-width:65ch;color:var(--muted);font-size:18px}.section{padding:clamp(70px,9vw,130px) clamp(20px,6vw,90px);border-bottom:1px solid var(--line)}.section-head{max-width:920px;margin-bottom:46px}.eyebrow{text-transform:uppercase;letter-spacing:.18em;font-size:12px;color:var(--accent);font-weight:700}.consult{margin:clamp(20px,4vw,64px);display:grid;grid-template-columns:1.3fr .7fr;gap:50px;background:var(--surface);color:var(--surface-contrast);border:0;border-radius:28px}.consult .summary{color:var(--surface-muted)}.accent-card{min-height:360px;border:1px solid color-mix(in srgb,var(--surface-contrast) 18%,var(--surface));border-radius:24px;background:color-mix(in srgb,var(--accent) 14%,var(--surface));display:grid;place-items:center;font-family:var(--display);font-size:96px;color:var(--surface-contrast)}.grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px}.card{padding:30px;min-height:240px;border-radius:28px;background:var(--surface);color:var(--surface-contrast)}.card h3{font-family:var(--display);font-size:30px}.card p{color:var(--surface-muted)}.card .button--secondary{color:var(--surface-contrast);border-color:color-mix(in srgb,var(--surface-contrast) 28%,var(--surface))}.learning{background:var(--background)}.topic-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px}.topic{background:color-mix(in srgb,var(--text) 5%,var(--background));color:var(--text);border:1px solid var(--line);border-radius:28px;padding:30px}.topic strong{display:block;color:var(--accent);text-transform:uppercase;font-size:11px;letter-spacing:.15em}.topic h3{font-family:var(--display);font-size:30px;margin:8px 0}.topic p{color:var(--muted)}.topic a{color:var(--text);font-weight:700}.proof{background:color-mix(in srgb,var(--text) 5%,var(--background))}.quotes{display:flex;gap:14px;overflow:auto;scroll-snap-type:x mandatory;padding-bottom:12px}.quote{min-width:min(420px,86vw);scroll-snap-align:start;border:1px solid var(--line);border-radius:24px;padding:30px;background:var(--background)}.quote q{font-family:var(--display);font-size:30px;line-height:1.25}.quote span{display:block;margin-top:24px;color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.12em}.cta{margin:clamp(20px,4vw,64px);text-align:center;border:0;border-radius:28px;background:var(--surface);color:var(--surface-contrast)}.cta .summary{color:var(--surface-muted);margin-left:auto;margin-right:auto}.cta h2{margin-left:auto;margin-right:auto}.footer{display:grid;grid-template-columns:1fr auto;gap:40px;padding:46px clamp(20px,6vw,90px);color:var(--muted);background:var(--background)}.footer strong{color:var(--text);font-family:var(--display);font-size:26px}.generated{font-size:11px;color:var(--muted);margin-top:10px}.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0)}
73097
73409
  @media(max-width:760px){.header{height:78px;border-radius:0 0 18px 18px}.menu{display:block}.nav{display:none;position:absolute;left:0;right:0;top:77px;padding:18px 20px;background:var(--surface);border-radius:0 0 18px 18px;flex-direction:column;align-items:stretch}.nav.open{display:flex}.hero{grid-template-columns:1fr;min-height:0}.portrait{min-height:390px;margin:16px;border-radius:22px}.portrait-card{width:72%;max-height:360px}.hero-copy{padding:36px 20px 66px}.hero h1{font-size:58px}.role{font-size:34px}.actions{display:grid}.button{width:100%}.consult{grid-template-columns:1fr;margin:16px;border-radius:22px}.cta{margin:16px;border-radius:22px}.accent-card{min-height:220px}.grid,.topic-grid{grid-template-columns:1fr}.card,.topic{border-radius:22px}.light,.section{padding:64px 20px}.consult,.cta{padding:52px 20px}.light h2,.section h2{font-size:46px}.footer{grid-template-columns:1fr}}
73098
73410
  @media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}.button{transition:none}}
73099
73411
  </style></head>
73100
73412
  <body><a class="skip" href="#main">Skip to main content</a>
73101
- <header class="header"><a class="brand" href="#top"><span class="mark">${escapeHtml9(initials2(input.name).slice(0, 1))}</span><strong>${escapeHtml9(brand)}</strong></a>${navigation}</header>
73102
- <main id="main"><section class="hero" id="top"><div class="portrait" aria-label="Portrait placeholder"><div class="portrait-card" aria-hidden="true">${escapeHtml9(initials2(input.name))}</div></div><div class="hero-copy"><h1>${escapeHtml9(input.name)}</h1><p class="role">${escapeHtml9(input.professionalTitle)}</p><p class="summary">${escapeHtml9(input.summary)}</p><div class="actions">${action2(input.primaryAction)}${input.secondaryAction ? action2(input.secondaryAction, true) : ""}</div>${social}</div></section>
73103
- ${section2(flags.authority && Boolean(authority), `<section class="light" id="about"><h2>${escapeHtml9(authority?.heading ?? "")}</h2>${authority?.paragraphs.map((paragraph) => `<p>${escapeHtml9(paragraph)}</p>`).join("") ?? ""}</section>`)}
73104
- ${section2(flags.consultation && Boolean(consultation), `<section class="section consult"><div><p class="eyebrow">${escapeHtml9(consultation?.eyebrow ?? "Start a conversation")}</p><h2>${escapeHtml9(consultation?.heading ?? "")}</h2><p class="summary">${escapeHtml9(consultation?.summary ?? "")}</p>${consultation ? action2(consultation.action) : ""}</div><div class="accent-card" aria-label="Image placeholder">${escapeHtml9(initials2(input.name))}</div></section>`)}
73105
- ${section2(flags.learning && Boolean(learning), `<section class="section learning"><div class="section-head"><h2>${escapeHtml9(learning?.heading ?? "")}</h2><p class="summary">${escapeHtml9(learning?.summary ?? "")}</p></div><div class="topic-grid">${learning?.topics.map((topic) => `<article class="topic"><strong>${escapeHtml9(topic.title)}</strong><h3>${escapeHtml9(topic.headline)}</h3><p>${escapeHtml9(topic.summary)}</p>${topic.href ? `<a href="${safeHref2(topic.href)}">Explore \u2192</a>` : ""}</article>`).join("") ?? ""}</div></section>`)}
73106
- ${section2(flags.services && Boolean(services), `<section class="section" id="services"><div class="section-head"><h2>${escapeHtml9(services?.heading ?? "")}</h2><p class="summary">${escapeHtml9(services?.summary ?? "")}</p></div><div class="grid">${services?.offers.map((offer) => `<article class="card"><h3>${escapeHtml9(offer.title)}</h3><p>${escapeHtml9(offer.description)}</p>${offer.action ? action2(offer.action, true) : ""}</article>`).join("") ?? ""}</div></section>`)}
73107
- ${section2(flags.proof && Boolean(proof), `<section class="section proof" id="proof"><div class="section-head"><h2>${escapeHtml9(proof?.heading ?? "")}</h2><p class="summary">${escapeHtml9(proof?.summary ?? "")}</p></div><div class="quotes">${proof?.testimonials.map((item) => `<article class="quote"><q>${escapeHtml9(item.quote)}</q><span>${escapeHtml9(item.person)}${item.role ? ` / ${escapeHtml9(item.role)}` : ""}</span></article>`).join("") ?? ""}</div></section>`)}
73108
- ${section2(flags.finalCta && Boolean(finalCta), `<section class="section cta" id="contact"><p class="eyebrow">${escapeHtml9(finalCta?.eyebrow ?? "Ready when you are")}</p><h2>${escapeHtml9(finalCta?.heading ?? "")}</h2><p class="summary">${escapeHtml9(finalCta?.summary ?? "")}</p>${finalCta ? action2(finalCta.action) : ""}</section>`)}
73109
- </main><footer class="footer"><div><strong>${escapeHtml9(input.name)}</strong><div>${escapeHtml9(input.professionalTitle)}</div>${config.showGeneratedAt ? `<div class="generated">Generated ${escapeHtml9(generatedAtIso)}</div>` : ""}</div><div>${input.location ? `<div>${escapeHtml9(input.location)}</div>` : ""}${input.email ? `<a href="mailto:${escapeHtml9(input.email)}">${escapeHtml9(input.email)}</a>` : ""}${input.phone ? `<div>${escapeHtml9(input.phone)}</div>` : ""}</div></footer>
73413
+ <header class="header"><a class="brand" href="#top"><span class="mark">${escapeHtml10(initials2(input.name).slice(0, 1))}</span><strong>${escapeHtml10(brand)}</strong></a>${navigation}</header>
73414
+ <main id="main"><section class="hero" id="top"><div class="portrait" aria-label="Portrait placeholder"><div class="portrait-card" aria-hidden="true">${escapeHtml10(initials2(input.name))}</div></div><div class="hero-copy"><h1>${escapeHtml10(input.name)}</h1><p class="role">${escapeHtml10(input.professionalTitle)}</p><p class="summary">${escapeHtml10(input.summary)}</p><div class="actions">${action2(input.primaryAction)}${input.secondaryAction ? action2(input.secondaryAction, true) : ""}</div>${social}</div></section>
73415
+ ${section2(flags.authority && Boolean(authority), `<section class="light" id="about"><h2>${escapeHtml10(authority?.heading ?? "")}</h2>${authority?.paragraphs.map((paragraph) => `<p>${escapeHtml10(paragraph)}</p>`).join("") ?? ""}</section>`)}
73416
+ ${section2(flags.consultation && Boolean(consultation), `<section class="section consult"><div><p class="eyebrow">${escapeHtml10(consultation?.eyebrow ?? "Start a conversation")}</p><h2>${escapeHtml10(consultation?.heading ?? "")}</h2><p class="summary">${escapeHtml10(consultation?.summary ?? "")}</p>${consultation ? action2(consultation.action) : ""}</div><div class="accent-card" aria-label="Image placeholder">${escapeHtml10(initials2(input.name))}</div></section>`)}
73417
+ ${section2(flags.learning && Boolean(learning), `<section class="section learning"><div class="section-head"><h2>${escapeHtml10(learning?.heading ?? "")}</h2><p class="summary">${escapeHtml10(learning?.summary ?? "")}</p></div><div class="topic-grid">${learning?.topics.map((topic) => `<article class="topic"><strong>${escapeHtml10(topic.title)}</strong><h3>${escapeHtml10(topic.headline)}</h3><p>${escapeHtml10(topic.summary)}</p>${topic.href ? `<a href="${safeHref2(topic.href)}">Explore \u2192</a>` : ""}</article>`).join("") ?? ""}</div></section>`)}
73418
+ ${section2(flags.services && Boolean(services), `<section class="section" id="services"><div class="section-head"><h2>${escapeHtml10(services?.heading ?? "")}</h2><p class="summary">${escapeHtml10(services?.summary ?? "")}</p></div><div class="grid">${services?.offers.map((offer) => `<article class="card"><h3>${escapeHtml10(offer.title)}</h3><p>${escapeHtml10(offer.description)}</p>${offer.action ? action2(offer.action, true) : ""}</article>`).join("") ?? ""}</div></section>`)}
73419
+ ${section2(flags.proof && Boolean(proof), `<section class="section proof" id="proof"><div class="section-head"><h2>${escapeHtml10(proof?.heading ?? "")}</h2><p class="summary">${escapeHtml10(proof?.summary ?? "")}</p></div><div class="quotes">${proof?.testimonials.map((item) => `<article class="quote"><q>${escapeHtml10(item.quote)}</q><span>${escapeHtml10(item.person)}${item.role ? ` / ${escapeHtml10(item.role)}` : ""}</span></article>`).join("") ?? ""}</div></section>`)}
73420
+ ${section2(flags.finalCta && Boolean(finalCta), `<section class="section cta" id="contact"><p class="eyebrow">${escapeHtml10(finalCta?.eyebrow ?? "Ready when you are")}</p><h2>${escapeHtml10(finalCta?.heading ?? "")}</h2><p class="summary">${escapeHtml10(finalCta?.summary ?? "")}</p>${finalCta ? action2(finalCta.action) : ""}</section>`)}
73421
+ </main><footer class="footer"><div><strong>${escapeHtml10(input.name)}</strong><div>${escapeHtml10(input.professionalTitle)}</div>${config.showGeneratedAt ? `<div class="generated">Generated ${escapeHtml10(generatedAtIso)}</div>` : ""}</div><div>${input.location ? `<div>${escapeHtml10(input.location)}</div>` : ""}${input.email ? `<a href="mailto:${escapeHtml10(input.email)}">${escapeHtml10(input.email)}</a>` : ""}${input.phone ? `<div>${escapeHtml10(input.phone)}</div>` : ""}</div></footer>
73110
73422
  <script>document.querySelector('.menu')?.addEventListener('click',function(){var nav=document.querySelector('.nav');var open=this.getAttribute('aria-expanded')!=='true';this.setAttribute('aria-expanded',String(open));nav?.classList.toggle('open',open)});document.querySelectorAll('.nav a').forEach(function(link){link.addEventListener('click',function(){document.querySelector('.nav')?.classList.remove('open');document.querySelector('.menu')?.setAttribute('aria-expanded','false')})});</script></body></html>`;
73111
73423
  const bytes = Buffer.byteLength(html, "utf8");
73112
73424
  return {
@@ -73132,7 +73444,7 @@ var init_render_v2 = __esm({
73132
73444
  });
73133
73445
 
73134
73446
  // src/newsroom-publisher/render.ts
73135
- function escapeHtml10(value) {
73447
+ function escapeHtml11(value) {
73136
73448
  return value.replace(/[&<>"']/g, (character) => ({
73137
73449
  "&": "&amp;",
73138
73450
  "<": "&lt;",
@@ -73143,30 +73455,30 @@ function escapeHtml10(value) {
73143
73455
  }
73144
73456
  function safeHref3(value) {
73145
73457
  const trimmed = value.trim();
73146
- return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml10(trimmed) : "#";
73458
+ return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml11(trimmed) : "#";
73147
73459
  }
73148
73460
  function formatDate(value) {
73149
73461
  const date = new Date(value);
73150
- return Number.isNaN(date.getTime()) ? escapeHtml10(value) : new Intl.DateTimeFormat("en", { month: "short", day: "numeric", year: "numeric" }).format(date);
73462
+ return Number.isNaN(date.getTime()) ? escapeHtml11(value) : new Intl.DateTimeFormat("en", { month: "short", day: "numeric", year: "numeric" }).format(date);
73151
73463
  }
73152
73464
  function initials3(value) {
73153
73465
  return value.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]).join("").toUpperCase();
73154
73466
  }
73155
73467
  function storyMedia(story2, className = "") {
73156
73468
  if (story2.imageUrl) {
73157
- return `<div class="story-media ${className}"><img src="${safeHref3(story2.imageUrl)}" alt="${escapeHtml10(story2.imageAlt || story2.title)}" loading="lazy"></div>`;
73469
+ return `<div class="story-media ${className}"><img src="${safeHref3(story2.imageUrl)}" alt="${escapeHtml11(story2.imageAlt || story2.title)}" loading="lazy"></div>`;
73158
73470
  }
73159
73471
  const tone = [...story2.title].reduce((total, character) => total + character.charCodeAt(0), 0) % 5;
73160
- return `<div class="story-media story-media--placeholder story-media--tone-${tone} ${className}" role="img" aria-label="Editorial image placeholder for ${escapeHtml10(story2.title)}"><i></i><b></b><span>${escapeHtml10(story2.category)}</span></div>`;
73472
+ return `<div class="story-media story-media--placeholder story-media--tone-${tone} ${className}" role="img" aria-label="Editorial image placeholder for ${escapeHtml11(story2.title)}"><i></i><b></b><span>${escapeHtml11(story2.category)}</span></div>`;
73161
73473
  }
73162
73474
  function byline(story2, showBylines) {
73163
- const author = story2.author.href ? `<a href="${safeHref3(story2.author.href)}">${escapeHtml10(story2.author.name)}</a>` : escapeHtml10(story2.author.name);
73164
- return `<div class="byline">${showBylines ? `<span>By ${author}</span>` : ""}<time datetime="${escapeHtml10(story2.publishedAt)}">${formatDate(story2.publishedAt)}</time>${story2.sponsored ? "<b>Sponsored</b>" : ""}</div>`;
73475
+ const author = story2.author.href ? `<a href="${safeHref3(story2.author.href)}">${escapeHtml11(story2.author.name)}</a>` : escapeHtml11(story2.author.name);
73476
+ return `<div class="byline">${showBylines ? `<span>By ${author}</span>` : ""}<time datetime="${escapeHtml11(story2.publishedAt)}">${formatDate(story2.publishedAt)}</time>${story2.sponsored ? "<b>Sponsored</b>" : ""}</div>`;
73165
73477
  }
73166
73478
  function storyCard(story2, showBylines, variant = "") {
73167
73479
  return `<article class="story-card ${variant}">
73168
73480
  <a class="story-card__media" href="${safeHref3(story2.href)}">${storyMedia(story2)}</a>
73169
- <div class="story-card__body"><a class="kicker" href="${safeHref3(story2.href)}">${escapeHtml10(story2.category)}</a><h3><a href="${safeHref3(story2.href)}">${escapeHtml10(story2.title)}</a></h3>${story2.dek ? `<p>${escapeHtml10(story2.dek)}</p>` : ""}${byline(story2, showBylines)}</div>
73481
+ <div class="story-card__body"><a class="kicker" href="${safeHref3(story2.href)}">${escapeHtml11(story2.category)}</a><h3><a href="${safeHref3(story2.href)}">${escapeHtml11(story2.title)}</a></h3>${story2.dek ? `<p>${escapeHtml11(story2.dek)}</p>` : ""}${byline(story2, showBylines)}</div>
73170
73482
  </article>`;
73171
73483
  }
73172
73484
  function renderNewsroomPublisherV1(input, config, generatedAt) {
@@ -73183,22 +73495,22 @@ function renderNewsroomPublisherV1(input, config, generatedAt) {
73183
73495
  input.primaryPages.contact
73184
73496
  ];
73185
73497
  const trustPages = Object.values(input.trustPages);
73186
- const ticker = flags.breakingTicker && input.ticker ? `<div class="ticker"><div><b>${escapeHtml10(input.ticker.label)}</b><a href="${safeHref3(input.ticker.href || "#latest")}">${escapeHtml10(input.ticker.headline)}</a><span>${formatDate(generatedAtIso)}</span></div></div>` : "";
73187
- const masthead = `<nav class="utility-nav" aria-label="Publication pages"><div><span>${escapeHtml10(input.publication.location || "Independent newsroom")}</span>${primaryPages.slice(1).map((link2) => `<a href="${safeHref3(link2.href)}">${escapeHtml10(link2.label)}</a>`).join("")}</div></nav><header class="masthead">
73188
- <a class="wordmark" href="${safeHref3(input.publication.url)}"><span>${escapeHtml10(brand)}</span><small>${escapeHtml10(input.publication.tagline)}</small></a>
73498
+ const ticker = flags.breakingTicker && input.ticker ? `<div class="ticker"><div><b>${escapeHtml11(input.ticker.label)}</b><a href="${safeHref3(input.ticker.href || "#latest")}">${escapeHtml11(input.ticker.headline)}</a><span>${formatDate(generatedAtIso)}</span></div></div>` : "";
73499
+ const masthead = `<nav class="utility-nav" aria-label="Publication pages"><div><span>${escapeHtml11(input.publication.location || "Independent newsroom")}</span>${primaryPages.slice(1).map((link2) => `<a href="${safeHref3(link2.href)}">${escapeHtml11(link2.label)}</a>`).join("")}</div></nav><header class="masthead">
73500
+ <a class="wordmark" href="${safeHref3(input.publication.url)}"><span>${escapeHtml11(brand)}</span><small>${escapeHtml11(input.publication.tagline)}</small></a>
73189
73501
  <div class="masthead__date"><span>Independent journalism</span><time datetime="${generatedAtIso}">${formatDate(generatedAtIso)}</time></div>
73190
73502
  <div class="masthead__tools"><button type="button" aria-label="Search">Search</button><button type="button" aria-label="Open menu">Menu</button></div>
73191
73503
  </header>`;
73192
- const navigation = flags.navigation ? `<nav class="desk-nav" aria-label="Publication categories"><div><a class="desk-nav__home" href="#top">Home</a>${input.categories.map((category) => `<a href="${safeHref3(category.href)}">${escapeHtml10(category.label)}</a>`).join("")}<a class="desk-nav__latest" href="#latest">Latest</a></div></nav>` : "";
73504
+ const navigation = flags.navigation ? `<nav class="desk-nav" aria-label="Publication categories"><div><a class="desk-nav__home" href="#top">Home</a>${input.categories.map((category) => `<a href="${safeHref3(category.href)}">${escapeHtml11(category.label)}</a>`).join("")}<a class="desk-nav__latest" href="#latest">Latest</a></div></nav>` : "";
73193
73505
  const leadGrid = flags.leadGrid ? `<section class="lead-grid" aria-label="Top stories">
73194
73506
  <div class="lead-grid__label"><span>Today\u2019s edition</span><b>Top stories</b></div>
73195
- <article class="lead-story"><a class="lead-story__media" href="${safeHref3(lead.href)}">${storyMedia(lead, "story-media--lead")}</a><div class="lead-story__body"><a class="kicker" href="${safeHref3(lead.href)}">${escapeHtml10(lead.category)}</a><h1><a href="${safeHref3(lead.href)}">${escapeHtml10(lead.title)}</a></h1>${lead.dek ? `<p>${escapeHtml10(lead.dek)}</p>` : ""}${byline(lead, config.showBylines)}<a class="read-story" href="${safeHref3(lead.href)}">Read the full report <span>\u2197</span></a></div></article>
73507
+ <article class="lead-story"><a class="lead-story__media" href="${safeHref3(lead.href)}">${storyMedia(lead, "story-media--lead")}</a><div class="lead-story__body"><a class="kicker" href="${safeHref3(lead.href)}">${escapeHtml11(lead.category)}</a><h1><a href="${safeHref3(lead.href)}">${escapeHtml11(lead.title)}</a></h1>${lead.dek ? `<p>${escapeHtml11(lead.dek)}</p>` : ""}${byline(lead, config.showBylines)}<a class="read-story" href="${safeHref3(lead.href)}">Read the full report <span>\u2197</span></a></div></article>
73196
73508
  <div class="lead-support">${supporting.slice(0, 4).map((story2, index) => `<div class="lead-support__item"><span>${String(index + 1).padStart(2, "0")}</span>${storyCard(story2, config.showBylines, "story-card--support")}</div>`).join("")}</div>
73197
73509
  </section>` : "";
73198
73510
  const latest = flags.latestNews && input.latest.length > 0 ? `<section class="latest" id="latest">
73199
73511
  <div class="section-title"><div><span>Live desk</span><h2>Latest news</h2></div><a href="#top">Back to top \u2191</a></div>
73200
- <div class="latest__layout"><div class="latest__feed">${input.latest.map((story2, index) => `<article class="feed-story"><span>${String(index + 1).padStart(2, "0")}</span><div><a class="kicker" href="${safeHref3(story2.href)}">${escapeHtml10(story2.category)}</a><h3><a href="${safeHref3(story2.href)}">${escapeHtml10(story2.title)}</a></h3>${story2.dek ? `<p>${escapeHtml10(story2.dek)}</p>` : ""}${byline(story2, config.showBylines)}</div>${storyMedia(story2, "story-media--feed")}</article>`).join("")}</div>
73201
- <aside class="editor-note"><span>From the newsroom</span><h3>Reporting with context, sources, and accountable bylines.</h3><p>${escapeHtml10(input.editorial.disclosure)}</p>${trustPages.slice(0, 4).map((link2) => `<a href="${safeHref3(link2.href)}">${escapeHtml10(link2.label)} \u2197</a>`).join("")}</aside></div>
73512
+ <div class="latest__layout"><div class="latest__feed">${input.latest.map((story2, index) => `<article class="feed-story"><span>${String(index + 1).padStart(2, "0")}</span><div><a class="kicker" href="${safeHref3(story2.href)}">${escapeHtml11(story2.category)}</a><h3><a href="${safeHref3(story2.href)}">${escapeHtml11(story2.title)}</a></h3>${story2.dek ? `<p>${escapeHtml11(story2.dek)}</p>` : ""}${byline(story2, config.showBylines)}</div>${storyMedia(story2, "story-media--feed")}</article>`).join("")}</div>
73513
+ <aside class="editor-note"><span>From the newsroom</span><h3>Reporting with context, sources, and accountable bylines.</h3><p>${escapeHtml11(input.editorial.disclosure)}</p>${trustPages.slice(0, 4).map((link2) => `<a href="${safeHref3(link2.href)}">${escapeHtml11(link2.label)} \u2197</a>`).join("")}</aside></div>
73202
73514
  </section>` : "";
73203
73515
  const sectionLayouts = ["panorama", "mosaic", "tiles"];
73204
73516
  const sections = flags.categorySections ? input.sections.map((section3, sectionIndex) => {
@@ -73209,16 +73521,16 @@ function renderNewsroomPublisherV1(input, config, generatedAt) {
73209
73521
  layout === "panorama" && index === 0 ? "story-card--panorama" : layout === "mosaic" && index === 0 ? "story-card--mosaic-lead" : ""
73210
73522
  )).join("");
73211
73523
  return `<section class="desk-section desk-section--${sectionIndex % 2 ? "tint" : "plain"} desk-section--layout-${layout}">
73212
- <div class="section-title"><div><span>Coverage desk \xB7 ${String(sectionIndex + 1).padStart(2, "0")}</span><h2>${escapeHtml10(section3.name)}</h2></div>${section3.href ? `<a href="${safeHref3(section3.href)}">View all ${escapeHtml10(section3.name)} \u2192</a>` : ""}</div>
73524
+ <div class="section-title"><div><span>Coverage desk \xB7 ${String(sectionIndex + 1).padStart(2, "0")}</span><h2>${escapeHtml11(section3.name)}</h2></div>${section3.href ? `<a href="${safeHref3(section3.href)}">View all ${escapeHtml11(section3.name)} \u2192</a>` : ""}</div>
73213
73525
  <div class="desk-section__grid desk-section__grid--${layout}">${cards}</div>
73214
73526
  </section>`;
73215
73527
  }).join("") : "";
73216
- const newsletter = flags.newsletter && input.newsletter ? `<section class="newsletter"><div><span>${escapeHtml10(input.newsletter.eyebrow || "Reader briefing")}</span><h2>${escapeHtml10(input.newsletter.heading)}</h2><p>${escapeHtml10(input.newsletter.summary)}</p></div><a href="${safeHref3(input.newsletter.action.href)}">${escapeHtml10(input.newsletter.action.label)} \u2192</a></section>` : "";
73217
- const pressRoom = flags.pressRoom && input.pressRoom ? `<section class="press-room" id="press-room"><div class="press-room__intro"><span>Separate from editorial coverage</span><h2>${escapeHtml10(input.pressRoom.heading)}</h2><p>${escapeHtml10(input.pressRoom.summary)}</p><a href="${safeHref3(input.pressRoom.action.href)}">${escapeHtml10(input.pressRoom.action.label)} \u2192</a></div><div class="release-list">${input.pressRoom.releases.map((release) => `<article><time datetime="${escapeHtml10(release.publishedAt)}">${formatDate(release.publishedAt)}</time><span>${escapeHtml10(release.originatingCity)}</span><h3><a href="${safeHref3(release.href)}">${escapeHtml10(release.headline)}</a></h3></article>`).join("") || "<p>No releases are currently published.</p>"}</div></section>` : "";
73218
- const trustCenter = `<section class="trust-center" id="trust"><div class="trust-center__intro"><span>Public record</span><h2>How this newsroom works.</h2><p>Ownership, editorial practice, technology use, commercial relationships, and reader rights should be easy to find\u2014and written to be understood.</p></div><div class="trust-center__grid">${trustPages.map((link2, index) => `<a href="${safeHref3(link2.href)}"><span>${String(index + 1).padStart(2, "0")}</span><strong>${escapeHtml10(link2.label)}</strong><small>Read \u2192</small></a>`).join("")}</div></section>`;
73219
- const trustFooter = flags.trustFooter ? `<footer class="site-footer"><div class="editor"><span class="editor__avatar">${escapeHtml10(initials3(input.editorial.managingEditor.name))}</span><div><small>${escapeHtml10(input.editorial.managingEditor.role)}</small><h2>${input.editorial.managingEditor.href ? `<a href="${safeHref3(input.editorial.managingEditor.href)}">${escapeHtml10(input.editorial.managingEditor.name)}</a>` : escapeHtml10(input.editorial.managingEditor.name)}</h2><p>${escapeHtml10(input.editorial.managingEditor.bio)}</p></div></div><div class="footer-links"><h3>${escapeHtml10(brand)}</h3><p>${escapeHtml10(input.publication.tagline)}</p><nav>${primaryPages.map((link2) => `<a href="${safeHref3(link2.href)}">${escapeHtml10(link2.label)}</a>`).join("")}</nav>${config.showGeneratedAt ? `<time datetime="${generatedAtIso}">Updated ${formatDate(generatedAtIso)}</time>` : ""}</div></footer>` : "";
73528
+ const newsletter = flags.newsletter && input.newsletter ? `<section class="newsletter"><div><span>${escapeHtml11(input.newsletter.eyebrow || "Reader briefing")}</span><h2>${escapeHtml11(input.newsletter.heading)}</h2><p>${escapeHtml11(input.newsletter.summary)}</p></div><a href="${safeHref3(input.newsletter.action.href)}">${escapeHtml11(input.newsletter.action.label)} \u2192</a></section>` : "";
73529
+ const pressRoom = flags.pressRoom && input.pressRoom ? `<section class="press-room" id="press-room"><div class="press-room__intro"><span>Separate from editorial coverage</span><h2>${escapeHtml11(input.pressRoom.heading)}</h2><p>${escapeHtml11(input.pressRoom.summary)}</p><a href="${safeHref3(input.pressRoom.action.href)}">${escapeHtml11(input.pressRoom.action.label)} \u2192</a></div><div class="release-list">${input.pressRoom.releases.map((release) => `<article><time datetime="${escapeHtml11(release.publishedAt)}">${formatDate(release.publishedAt)}</time><span>${escapeHtml11(release.originatingCity)}</span><h3><a href="${safeHref3(release.href)}">${escapeHtml11(release.headline)}</a></h3></article>`).join("") || "<p>No releases are currently published.</p>"}</div></section>` : "";
73530
+ const trustCenter = `<section class="trust-center" id="trust"><div class="trust-center__intro"><span>Public record</span><h2>How this newsroom works.</h2><p>Ownership, editorial practice, technology use, commercial relationships, and reader rights should be easy to find\u2014and written to be understood.</p></div><div class="trust-center__grid">${trustPages.map((link2, index) => `<a href="${safeHref3(link2.href)}"><span>${String(index + 1).padStart(2, "0")}</span><strong>${escapeHtml11(link2.label)}</strong><small>Read \u2192</small></a>`).join("")}</div></section>`;
73531
+ const trustFooter = flags.trustFooter ? `<footer class="site-footer"><div class="editor"><span class="editor__avatar">${escapeHtml11(initials3(input.editorial.managingEditor.name))}</span><div><small>${escapeHtml11(input.editorial.managingEditor.role)}</small><h2>${input.editorial.managingEditor.href ? `<a href="${safeHref3(input.editorial.managingEditor.href)}">${escapeHtml11(input.editorial.managingEditor.name)}</a>` : escapeHtml11(input.editorial.managingEditor.name)}</h2><p>${escapeHtml11(input.editorial.managingEditor.bio)}</p></div></div><div class="footer-links"><h3>${escapeHtml11(brand)}</h3><p>${escapeHtml11(input.publication.tagline)}</p><nav>${primaryPages.map((link2) => `<a href="${safeHref3(link2.href)}">${escapeHtml11(link2.label)}</a>`).join("")}</nav>${config.showGeneratedAt ? `<time datetime="${generatedAtIso}">Updated ${formatDate(generatedAtIso)}</time>` : ""}</div></footer>` : "";
73220
73532
  const html = `<!doctype html>
73221
- <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex,nofollow"><title>${escapeHtml10(brand)} \xB7 News Publisher</title><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Archivo:wdth,wght@75..125,300..900&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
73533
+ <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex,nofollow"><title>${escapeHtml11(brand)} \xB7 News Publisher</title><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Archivo:wdth,wght@75..125,300..900&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
73222
73534
  <style>
73223
73535
  :root{--ink:#0b0b0c;--soft-ink:#222326;--muted:#696b70;--paper:#fff;--cream:#f4f0e8;--wash:#f5f5f3;--line:#d8d8d4;--signal:#275cf3;--acid:#d9ff43;--dark:#0b0b0c;--serif:"Instrument Serif",Georgia,serif;--sans:"Archivo",Arial,sans-serif;--mono:"JetBrains Mono",monospace;font-family:var(--sans);color:var(--ink);background:var(--paper)}*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--paper);line-height:1.45}body[data-theme=journal]{--cream:#eee7da;--signal:#9d2d25;--acid:#f0c84f}body[data-theme=midnight]{--paper:#e8e9ec;--cream:#dfe1e6;--wash:#d8dae0;--line:#b9bdc6;--signal:#224bcc}a{color:inherit;text-decoration:none}a,button{transition:color .18s ease,background .18s ease,opacity .18s ease,transform .18s ease}button{font:inherit}.utility-nav{color:#d2d2d2;background:var(--dark);border-bottom:1px solid #292929}.utility-nav>div{max-width:1180px;height:35px;margin:auto;display:flex;align-items:center;justify-content:flex-end;gap:20px;padding:0 18px;overflow:auto}.utility-nav span{margin-right:auto;color:#8d8d8d}.utility-nav a,.utility-nav span{font:600 8px/1 var(--mono);letter-spacing:.08em;text-transform:uppercase;white-space:nowrap}.utility-nav a:hover{color:#fff}.ticker{color:var(--ink);background:var(--acid);padding:0 18px}.ticker>div{max-width:1180px;height:36px;margin:auto;display:flex;align-items:center;gap:16px;font:600 10px/1 var(--mono)}.ticker b{padding:5px 7px;color:#fff;background:var(--ink);font-size:8px;letter-spacing:.1em;text-transform:uppercase}.ticker a{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ticker a:hover{text-decoration:underline}.ticker span{margin-left:auto;opacity:.58;font-size:8px;text-transform:uppercase}.masthead{max-width:1180px;height:126px;margin:auto;display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:center;gap:42px;padding:0 18px}.wordmark{display:grid;justify-self:start}.wordmark span{font:400 clamp(40px,5vw,68px)/.82 var(--serif);letter-spacing:-.055em}.wordmark small{max-width:430px;margin-top:11px;color:var(--muted);font:600 8px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase}.masthead__date{display:grid;gap:3px;text-align:right}.masthead__date span,.masthead__date time{font:600 8px/1.4 var(--mono);letter-spacing:.08em;text-transform:uppercase}.masthead__date span{color:var(--signal)}.masthead__date time{color:var(--muted)}.masthead__tools{display:flex;border:1px solid var(--ink)}.masthead__tools button{height:38px;padding:0 13px;border:0;background:transparent;font:700 9px/1 var(--mono);text-transform:uppercase;cursor:pointer}.masthead__tools button+button{border-left:1px solid var(--ink)}.masthead__tools button:hover{color:#fff;background:var(--ink)}.desk-nav{position:sticky;top:0;z-index:20;color:var(--ink);background:rgba(255,255,255,.96);border-top:1px solid var(--ink);border-bottom:1px solid var(--ink);backdrop-filter:blur(10px)}.desk-nav>div{max-width:1180px;height:43px;margin:auto;display:flex;align-items:center;overflow-x:auto;padding:0 18px}.desk-nav a{height:42px;display:grid;place-items:center;padding:0 17px;border-right:1px solid var(--line);font:650 9px/1 var(--mono);letter-spacing:.04em;text-transform:uppercase;white-space:nowrap}.desk-nav a:first-child{border-left:1px solid var(--line)}.desk-nav a:hover,.desk-nav__home{color:#fff!important;background:var(--ink)}.desk-nav__latest{margin-left:auto;color:var(--signal);border-left:1px solid var(--line)}main{max-width:1180px;margin:auto;padding:30px 18px 90px}.lead-grid{margin:0 -18px;padding:0 18px 42px;color:#fff;background:var(--dark);border-bottom:1px solid var(--ink)}.lead-grid__label{height:50px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #303030}.lead-grid__label span,.lead-grid__label b{font:600 8px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase}.lead-grid__label span{color:var(--acid)}.lead-grid__label b{color:#8f8f8f}.lead-story{display:grid;grid-template-columns:minmax(0,1.28fr) minmax(340px,.72fr);min-height:500px;border-bottom:1px solid #303030}.lead-story__media{display:block;margin-left:calc((1180px - 100vw)/2);min-width:0}.story-media{position:relative;aspect-ratio:16/10;overflow:hidden;background:#e2e2df}.story-media img{width:100%;height:100%;display:block;object-fit:cover;filter:saturate(.88) contrast(1.03);transition:transform .55s cubic-bezier(.2,.7,.2,1)}a:hover .story-media img{transform:scale(1.025)}.story-media--lead{height:100%;min-height:500px;aspect-ratio:auto}.story-media--placeholder{isolation:isolate;display:block;background:#d9d7d1}.story-media--placeholder:after{position:absolute;z-index:1;inset:0;background:linear-gradient(145deg,transparent 35%,rgba(0,0,0,.14));content:""}.story-media--placeholder i,.story-media--placeholder b{position:absolute;display:block}.story-media--placeholder i{width:72%;aspect-ratio:1;right:-20%;top:-32%;border:clamp(22px,5vw,72px) solid currentColor;border-radius:50%;opacity:.78}.story-media--placeholder b{width:42%;height:115%;left:15%;bottom:-45%;background:currentColor;transform:rotate(32deg);opacity:.88}.story-media--placeholder span{position:absolute;z-index:2;left:18px;bottom:15px;padding:6px 8px;color:#fff;background:var(--ink);font:600 8px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase}.story-media--tone-0{color:#123fce;background:#a5c8ff}.story-media--tone-1{color:#ef4d25;background:#ffd9bd}.story-media--tone-2{color:#907000;background:#f3df36}.story-media--tone-3{color:#1a7857;background:#b8e8cc}.story-media--tone-4{color:#7d3de0;background:#dfc5ff}.lead-story__body{display:flex;flex-direction:column;justify-content:center;padding:45px 0 45px 40px}.kicker{display:inline-flex;width:max-content;color:var(--signal);font:700 8px/1 var(--mono);letter-spacing:.11em;text-transform:uppercase}.lead-grid .kicker{color:var(--acid)}.lead-story h1{max-width:540px;margin:13px 0 18px;font:400 clamp(48px,5vw,76px)/.92 var(--serif);letter-spacing:-.052em}.lead-story p{max-width:490px;margin:0;color:#bdbdbd;font-size:15px;line-height:1.55}.byline{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:16px;color:var(--muted);font:600 8px/1.4 var(--mono);letter-spacing:.05em;text-transform:uppercase}.byline span{color:var(--ink);font-weight:700}.lead-grid .byline{color:#848484}.lead-grid .byline span{color:#e7e7e7}.byline b{padding:4px 6px;color:var(--ink);background:var(--acid)}.read-story{width:max-content;margin-top:34px;padding-bottom:6px;border-bottom:1px solid #777;font:650 10px/1 var(--mono);text-transform:uppercase}.read-story span{color:var(--acid)}.read-story:hover{border-color:#fff}.lead-support{display:grid;grid-template-columns:repeat(4,1fr);gap:0}.lead-support__item{display:grid;grid-template-columns:25px minmax(0,1fr);gap:12px;padding:22px 18px 0 0;border-right:1px solid #303030}.lead-support__item+.lead-support__item{padding-left:18px}.lead-support__item:last-child{border-right:0}.lead-support__item>span{color:#666;font:600 9px/1 var(--mono)}.story-card{min-width:0}.story-card h3{margin:7px 0;font:400 26px/1.02 var(--serif);letter-spacing:-.025em}.story-card p{margin:9px 0;color:var(--muted);font-size:12px}.story-card__body{padding-top:11px}.story-card--support .story-card__media{display:none}.story-card--support .story-card__body{padding:0}.story-card--support h3{margin-top:8px;color:#fff;font-size:21px}.story-card--support p,.story-card--support .byline span{display:none}.story-card--support .byline{color:#777}.section-title{display:flex;align-items:end;justify-content:space-between;gap:30px;margin-bottom:24px;padding-bottom:11px;border-bottom:2px solid var(--ink)}.section-title span,.newsletter span,.press-room__intro>span,.trust-center__intro>span{display:block;color:var(--signal);font:700 8px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase}.section-title h2,.newsletter h2,.press-room h2,.trust-center h2,.site-footer h2{margin:7px 0 0;font:400 clamp(38px,5vw,58px)/.95 var(--serif);letter-spacing:-.04em}.section-title>a{padding-bottom:4px;border-bottom:1px solid var(--ink);font:650 9px/1 var(--mono);text-transform:uppercase}.latest{padding:64px 0}.latest__layout{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:55px}.latest__feed{border-top:1px solid var(--ink)}.feed-story{display:grid;grid-template-columns:34px minmax(0,1fr) 180px;gap:18px;align-items:start;padding:19px 0;border-bottom:1px solid var(--line)}.feed-story>span{color:#a0a0a0;font:600 9px/1 var(--mono)}.feed-story h3{margin:7px 0;font:400 29px/1.02 var(--serif);letter-spacing:-.025em}.feed-story p{margin:8px 0;color:var(--muted);font-size:12px}.story-media--feed{aspect-ratio:4/3}.editor-note{position:sticky;top:68px;align-self:start;padding:25px;color:#fff;background:var(--dark);border-top:5px solid var(--acid)}.editor-note>span{color:var(--acid);font:600 8px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase}.editor-note h3{margin:13px 0;font:400 31px/.98 var(--serif)}.editor-note p{color:#aaa;font-size:12px}.editor-note a{display:block;padding:11px 0;border-top:1px solid #333;font:600 9px/1 var(--mono);text-transform:uppercase}.editor-note a:hover{color:var(--acid)}.desk-section{margin:0 -18px;padding:58px 18px;border-top:1px solid var(--ink)}.desk-section--tint{background:var(--cream)}.desk-section__grid{display:grid;grid-template-columns:repeat(4,1fr);gap:26px 14px}.story-card--wide{grid-column:span 2;grid-row:span 2}.story-card--wide h3{max-width:530px;font-size:40px}.story-card--wide p{max-width:540px;font-size:13px}.desk-section__grid>.story-card:not(.story-card--wide) .story-media{aspect-ratio:1}.newsletter{position:relative;margin:64px 0;display:grid;grid-template-columns:1fr auto;align-items:end;gap:50px;overflow:hidden;padding:clamp(38px,6vw,72px);color:var(--ink);background:var(--acid)}.newsletter:after{position:absolute;width:260px;height:260px;right:18%;top:-160px;border:55px solid var(--ink);border-radius:50%;content:"";opacity:.08}.newsletter span{color:var(--ink)}.newsletter h2{max-width:760px;font-size:clamp(44px,6vw,72px)}.newsletter p{max-width:680px;margin-bottom:0;color:#303030}.newsletter>a,.press-room__intro>a{position:relative;z-index:1;display:inline-flex;padding:14px 18px;color:#fff;background:var(--ink);border:1px solid var(--ink);font:700 9px/1 var(--mono);text-transform:uppercase}.newsletter>a:hover,.press-room__intro>a:hover{color:var(--ink);background:transparent}.press-room{display:grid;grid-template-columns:.7fr 1.3fr;gap:56px;padding:62px 0;border-top:6px solid var(--ink)}.press-room__intro p{max-width:390px;color:var(--muted)}.release-list{border-top:1px solid var(--ink)}.release-list article{display:grid;grid-template-columns:105px 105px 1fr;gap:15px;align-items:start;padding:20px 0;border-bottom:1px solid var(--line)}.release-list time,.release-list span{color:var(--muted);font:500 8px/1.4 var(--mono);text-transform:uppercase}.release-list h3{margin:0;font:400 22px/1.04 var(--serif)}.trust-center{margin:20px -18px -90px;padding:70px max(18px,calc((100vw - 1144px)/2)) 82px;color:#fff;background:var(--dark)}.trust-center__intro{max-width:810px;margin-bottom:38px}.trust-center__intro>span{color:var(--acid)}.trust-center__intro p{max-width:670px;color:#aaa}.trust-center__grid{display:grid;grid-template-columns:repeat(2,1fr);border-top:1px solid #444}.trust-center__grid a{display:grid;grid-template-columns:32px minmax(0,1fr) auto;align-items:center;gap:15px;min-height:70px;padding:0 18px 0 0;border-bottom:1px solid #333}.trust-center__grid a:nth-child(odd){margin-right:28px}.trust-center__grid a:hover{color:var(--acid)}.trust-center__grid span,.trust-center__grid small{color:#696969;font:600 8px/1 var(--mono)}.trust-center__grid strong{font:400 20px/1 var(--serif)}.site-footer{display:grid;grid-template-columns:1.15fr .85fr;gap:80px;padding:70px max(24px,calc((100vw - 1144px)/2));color:var(--ink);background:var(--cream);border-top:1px solid var(--ink)}.editor{display:grid;grid-template-columns:78px 1fr;gap:22px}.editor__avatar{width:78px;height:78px;display:grid;place-items:center;color:#fff;background:var(--signal);font:400 27px/1 var(--serif)}.editor small{color:var(--signal);font:700 8px/1 var(--mono);letter-spacing:.08em;text-transform:uppercase}.editor h2{font-size:38px}.editor p,.footer-links p{max-width:620px;color:var(--muted)}.footer-links h3{margin-top:0;font:400 29px/1 var(--serif)}.footer-links nav{display:grid;grid-template-columns:1fr 1fr;border-top:1px solid var(--ink)}.footer-links nav a{padding:9px 0;border-bottom:1px solid var(--line);font:600 8px/1 var(--mono);text-transform:uppercase}.footer-links time{display:block;margin-top:24px;color:var(--muted);font:500 8px/1 var(--mono)}@media(max-width:900px){.masthead{grid-template-columns:1fr auto;height:110px}.masthead__date{display:none}.lead-story{grid-template-columns:1fr}.lead-story__media{margin:0}.lead-story__body{padding:35px 0}.lead-support{grid-template-columns:1fr 1fr}.lead-support__item:nth-child(2){border-right:0}.lead-support__item:nth-child(n+3){border-top:1px solid #303030}.latest__layout,.press-room,.site-footer{grid-template-columns:1fr}.editor-note{position:static}.desk-section__grid{grid-template-columns:1fr 1fr}.story-card--wide{grid-column:1/-1}.site-footer{gap:40px}.feed-story{grid-template-columns:30px 1fr 150px}}@media(max-width:620px){.utility-nav span,.utility-nav a:nth-of-type(-n+2),.ticker span{display:none}.ticker>div{height:34px}.masthead{height:92px;gap:14px}.wordmark span{font-size:38px}.wordmark small{max-width:220px;font-size:6px}.masthead__tools button:first-child{display:none}.desk-nav>div{padding:0}.desk-nav a{padding:0 13px}.lead-grid{padding-bottom:20px}.lead-grid__label{height:40px}.story-media--lead{min-height:320px}.lead-story{min-height:0}.lead-story h1{font-size:48px}.lead-story__body{padding:27px 0 34px}.lead-support{grid-template-columns:1fr}.lead-support__item,.lead-support__item+.lead-support__item{padding:17px 0;border-right:0;border-top:1px solid #303030}.story-card--support h3{font-size:24px}.section-title{align-items:start}.section-title>a{display:none}.latest{padding:48px 0}.feed-story{grid-template-columns:25px 1fr}.story-media--feed{grid-column:2}.feed-story h3{font-size:26px}.desk-section__grid{grid-template-columns:1fr}.story-card--wide{grid-column:auto;grid-row:auto}.story-card--wide h3{font-size:34px}.newsletter{grid-template-columns:1fr}.newsletter h2{font-size:48px}.release-list article{grid-template-columns:1fr}.trust-center__grid{grid-template-columns:1fr}.trust-center__grid a:nth-child(odd){margin-right:0}.site-footer{padding:50px 20px}.editor{grid-template-columns:1fr}.footer-links nav{grid-template-columns:1fr}}
73224
73536
  /* Tampa-inspired publication palette */
@@ -73235,7 +73547,7 @@ body{overflow-x:hidden}.lead-story__body,.lead-support__item,.story-card__body{m
73235
73547
  @media(max-width:620px){main{width:100%}.story-media--lead{height:360px;min-height:0}.lead-story__body,.lead-support,.latest,.feed-story{width:100%;max-width:calc(100vw - 36px)}.feed-story>div{min-width:0}.lead-story h1,.story-card h3,.feed-story h3,.story-card h3 a,.feed-story h3 a{white-space:normal;word-break:break-word;overflow-wrap:anywhere}.lead-story h1{max-width:100%;font-size:40px;line-height:.94}.lead-support__item{width:100%;max-width:100%;grid-template-columns:24px minmax(0,1fr);overflow:hidden}.story-card--support,.story-card--support .story-card__body,.story-card--support h3{width:100%;max-width:calc(100vw - 92px)}.feed-story>div,.feed-story h3,.feed-story p{max-width:calc(100vw - 100px)}}
73236
73548
  @media(max-width:900px){.story-card--panorama{grid-template-columns:1fr}.desk-section__grid--mosaic{grid-template-columns:repeat(2,1fr)}.desk-section__grid--tiles{grid-template-columns:repeat(2,1fr)}}
73237
73549
  @media(max-width:620px){.desk-section__grid--panorama,.desk-section__grid--mosaic,.desk-section__grid--tiles{grid-template-columns:1fr}.story-card--panorama{display:block}.story-card--panorama h3,.story-card--mosaic-lead h3{font-size:34px}.story-card--mosaic-lead{grid-column:auto;grid-row:auto}.desk-section__grid--tiles>.story-card:nth-child(3n+2){margin-top:0}}
73238
- </style></head><body data-theme="${escapeHtml10(config.theme)}" id="top" data-scheduled-renderer="newsroom_publisher_v1">${ticker}${masthead}${navigation}<main>${leadGrid}${latest}${sections}${newsletter}${pressRoom}${trustCenter}</main>${trustFooter}</body></html>`;
73550
+ </style></head><body data-theme="${escapeHtml11(config.theme)}" id="top" data-scheduled-renderer="newsroom_publisher_v1">${ticker}${masthead}${navigation}<main>${leadGrid}${latest}${sections}${newsletter}${pressRoom}${trustCenter}</main>${trustFooter}</body></html>`;
73239
73551
  const bytes = Buffer.byteLength(html);
73240
73552
  const sha2563 = (0, import_node_crypto48.createHash)("sha256").update(html).digest("hex");
73241
73553
  const filename = `${brand.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "newsroom"}-news-site.html`;
@@ -73250,7 +73562,7 @@ var init_render3 = __esm({
73250
73562
  });
73251
73563
 
73252
73564
  // src/blog-article/render.ts
73253
- function escapeHtml11(value) {
73565
+ function escapeHtml12(value) {
73254
73566
  return value.replace(
73255
73567
  /[&<>"']/g,
73256
73568
  (character) => ({
@@ -73264,11 +73576,11 @@ function escapeHtml11(value) {
73264
73576
  }
73265
73577
  function safeHref4(value) {
73266
73578
  const trimmed = value.trim();
73267
- return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml11(trimmed) : "#";
73579
+ return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml12(trimmed) : "#";
73268
73580
  }
73269
73581
  function formatDate2(value) {
73270
73582
  const date = new Date(value);
73271
- return Number.isNaN(date.getTime()) ? escapeHtml11(value) : new Intl.DateTimeFormat("en", {
73583
+ return Number.isNaN(date.getTime()) ? escapeHtml12(value) : new Intl.DateTimeFormat("en", {
73272
73584
  month: "long",
73273
73585
  day: "numeric",
73274
73586
  year: "numeric"
@@ -73282,15 +73594,15 @@ function jsonForScript(value) {
73282
73594
  }
73283
73595
  function portrait(input) {
73284
73596
  if (input.author.portraitUrl) {
73285
- return `<img class="author-portrait" src="${safeHref4(input.author.portraitUrl)}" alt="${escapeHtml11(input.author.portraitAlt || input.author.name)}">`;
73597
+ return `<img class="author-portrait" src="${safeHref4(input.author.portraitUrl)}" alt="${escapeHtml12(input.author.portraitAlt || input.author.name)}">`;
73286
73598
  }
73287
- return `<span class="author-portrait author-initials" aria-label="${escapeHtml11(input.author.name)}">${escapeHtml11(initials4(input.author.name))}</span>`;
73599
+ return `<span class="author-portrait author-initials" aria-label="${escapeHtml12(input.author.name)}">${escapeHtml12(initials4(input.author.name))}</span>`;
73288
73600
  }
73289
73601
  function sidebarArt(input) {
73290
73602
  if (input.sidebarMedia?.imageUrl) {
73291
- return `<img src="${safeHref4(input.sidebarMedia.imageUrl)}" alt="${escapeHtml11(input.sidebarMedia.imageAlt)}">`;
73603
+ return `<img src="${safeHref4(input.sidebarMedia.imageUrl)}" alt="${escapeHtml12(input.sidebarMedia.imageAlt)}">`;
73292
73604
  }
73293
- return `<svg viewBox="0 0 560 330" role="img" aria-label="${escapeHtml11(input.sidebarMedia?.imageAlt || "Editorial article illustration")}"><defs><linearGradient id="ba-sky" x1="0" x2="1"><stop stop-color="#dbeafe"/><stop offset="1" stop-color="#d1fae5"/></linearGradient></defs><rect width="560" height="330" fill="url(#ba-sky)"/><circle cx="455" cy="72" r="88" fill="#93c5fd" opacity=".35"/><path d="M76 180 280 42l204 138v118H76Z" fill="#fff"/><path d="M52 185 280 28l228 157" fill="none" stroke="#10213d" stroke-width="18" stroke-linecap="round" stroke-linejoin="round"/><rect x="232" y="180" width="96" height="118" rx="8" fill="#bfdbfe"/><circle cx="385" cy="178" r="40" fill="#f8d5b8"/><path d="M335 330v-70c0-39 22-68 50-68s50 29 50 68v70" fill="#2563eb"/><circle cx="458" cy="196" r="34" fill="#8b5e3c"/><path d="M418 330v-64c0-34 18-60 40-60s40 26 40 60v64" fill="#45d5aa"/></svg>`;
73605
+ return `<svg viewBox="0 0 560 330" role="img" aria-label="${escapeHtml12(input.sidebarMedia?.imageAlt || "Editorial article illustration")}"><defs><linearGradient id="ba-sky" x1="0" x2="1"><stop stop-color="#dbeafe"/><stop offset="1" stop-color="#d1fae5"/></linearGradient></defs><rect width="560" height="330" fill="url(#ba-sky)"/><circle cx="455" cy="72" r="88" fill="#93c5fd" opacity=".35"/><path d="M76 180 280 42l204 138v118H76Z" fill="#fff"/><path d="M52 185 280 28l228 157" fill="none" stroke="#10213d" stroke-width="18" stroke-linecap="round" stroke-linejoin="round"/><rect x="232" y="180" width="96" height="118" rx="8" fill="#bfdbfe"/><circle cx="385" cy="178" r="40" fill="#f8d5b8"/><path d="M335 330v-70c0-39 22-68 50-68s50 29 50 68v70" fill="#2563eb"/><circle cx="458" cy="196" r="34" fill="#8b5e3c"/><path d="M418 330v-64c0-34 18-60 40-60s40 26 40 60v64" fill="#45d5aa"/></svg>`;
73294
73606
  }
73295
73607
  function citations(input) {
73296
73608
  const published = new Date(input.publishedAt);
@@ -73319,23 +73631,23 @@ function renderBlogArticleV1(input, config, generatedAt) {
73319
73631
  ...flags.faq && input.faq.length ? [{ id: "faq", title: "Frequently asked questions" }] : []
73320
73632
  ];
73321
73633
  const contributorText = [
73322
- `Written by <a href="${safeHref4(input.author.href || "#author")}">${escapeHtml11(input.author.name)}</a>`,
73323
- input.editor ? `Edited by <a href="${safeHref4(input.editor.href || "#")}">${escapeHtml11(input.editor.name)}</a>` : "",
73324
- input.reviewer ? `Reviewed by <a href="${safeHref4(input.reviewer.href || "#")}">${escapeHtml11(input.reviewer.name)}${input.reviewer.credential ? `, ${escapeHtml11(input.reviewer.credential)}` : ""}</a>` : ""
73634
+ `Written by <a href="${safeHref4(input.author.href || "#author")}">${escapeHtml12(input.author.name)}</a>`,
73635
+ input.editor ? `Edited by <a href="${safeHref4(input.editor.href || "#")}">${escapeHtml12(input.editor.name)}</a>` : "",
73636
+ input.reviewer ? `Reviewed by <a href="${safeHref4(input.reviewer.href || "#")}">${escapeHtml12(input.reviewer.name)}${input.reviewer.credential ? `, ${escapeHtml12(input.reviewer.credential)}` : ""}</a>` : ""
73325
73637
  ].filter(Boolean).join(" \xB7 ");
73326
73638
  const sections = input.sections.map(
73327
- (section3) => `<section id="${escapeHtml11(section3.id)}" class="article-section"><header>${section3.eyebrow ? `<span class="eyebrow">${escapeHtml11(section3.eyebrow)}</span>` : ""}<h2>${escapeHtml11(section3.title)}</h2></header>${section3.paragraphs.map((paragraph) => `<p>${escapeHtml11(paragraph)}</p>`).join("")}${section3.bullets?.length ? `<ul>${section3.bullets.map((item) => `<li>${escapeHtml11(item)}</li>`).join("")}</ul>` : ""}${section3.callout ? `<aside class="callout"><span>Worth noting</span><h3>${escapeHtml11(section3.callout.heading)}</h3><p>${escapeHtml11(section3.callout.body)}</p></aside>` : ""}</section>`
73639
+ (section3) => `<section id="${escapeHtml12(section3.id)}" class="article-section"><header>${section3.eyebrow ? `<span class="eyebrow">${escapeHtml12(section3.eyebrow)}</span>` : ""}<h2>${escapeHtml12(section3.title)}</h2></header>${section3.paragraphs.map((paragraph) => `<p>${escapeHtml12(paragraph)}</p>`).join("")}${section3.bullets?.length ? `<ul>${section3.bullets.map((item) => `<li>${escapeHtml12(item)}</li>`).join("")}</ul>` : ""}${section3.callout ? `<aside class="callout"><span>Worth noting</span><h3>${escapeHtml12(section3.callout.heading)}</h3><p>${escapeHtml12(section3.callout.body)}</p></aside>` : ""}</section>`
73328
73640
  ).join("");
73329
- const faq = flags.faq && input.faq.length ? `<section id="faq" class="faq"><span class="eyebrow">Common questions</span><h2>Frequently asked questions</h2><div>${input.faq.map((item, index) => `<article><h3><button type="button" aria-expanded="false" aria-controls="faq-${index}"><span>${escapeHtml11(item.question)}</span><b aria-hidden="true">+</b></button></h3><p id="faq-${index}" hidden>${escapeHtml11(item.answer)}</p></article>`).join("")}</div></section>` : "";
73330
- const media = flags.sidebarMedia && input.sidebarMedia ? `<figure class="sidebar-media" data-article-media>${sidebarArt(input)}${input.sidebarMedia.caption ? `<figcaption>${escapeHtml11(input.sidebarMedia.caption)}</figcaption>` : ""}</figure>` : "";
73331
- const disclosure = flags.disclosure && input.disclosure ? `<section class="disclosure"><button type="button" aria-expanded="false" aria-controls="disclosure-details"><span>${escapeHtml11(input.disclosure.summary)}</span><b aria-hidden="true">\u2304</b></button><p id="disclosure-details" hidden>${escapeHtml11(input.disclosure.details)}</p></section>` : "";
73332
- const toc = flags.stickyToc ? `<aside class="toc" data-sticky-toc><header><strong>Table of contents</strong><button type="button" aria-expanded="true" aria-controls="toc-links" aria-label="Collapse table of contents">\u2303</button></header><nav id="toc-links" aria-label="Table of contents">${tocItems.map((item, index) => `<a href="#${escapeHtml11(item.id)}"${index === 0 ? ' aria-current="location"' : ""}><i></i><span>${escapeHtml11(item.title)}</span></a>`).join("")}</nav><button class="back-top" type="button">Back to top \u2191</button></aside>` : "";
73641
+ const faq = flags.faq && input.faq.length ? `<section id="faq" class="faq"><span class="eyebrow">Common questions</span><h2>Frequently asked questions</h2><div>${input.faq.map((item, index) => `<article><h3><button type="button" aria-expanded="false" aria-controls="faq-${index}"><span>${escapeHtml12(item.question)}</span><b aria-hidden="true">+</b></button></h3><p id="faq-${index}" hidden>${escapeHtml12(item.answer)}</p></article>`).join("")}</div></section>` : "";
73642
+ const media = flags.sidebarMedia && input.sidebarMedia ? `<figure class="sidebar-media" data-article-media>${sidebarArt(input)}${input.sidebarMedia.caption ? `<figcaption>${escapeHtml12(input.sidebarMedia.caption)}</figcaption>` : ""}</figure>` : "";
73643
+ const disclosure = flags.disclosure && input.disclosure ? `<section class="disclosure"><button type="button" aria-expanded="false" aria-controls="disclosure-details"><span>${escapeHtml12(input.disclosure.summary)}</span><b aria-hidden="true">\u2304</b></button><p id="disclosure-details" hidden>${escapeHtml12(input.disclosure.details)}</p></section>` : "";
73644
+ const toc = flags.stickyToc ? `<aside class="toc" data-sticky-toc><header><strong>Table of contents</strong><button type="button" aria-expanded="true" aria-controls="toc-links" aria-label="Collapse table of contents">\u2303</button></header><nav id="toc-links" aria-label="Table of contents">${tocItems.map((item, index) => `<a href="#${escapeHtml12(item.id)}"${index === 0 ? ' aria-current="location"' : ""}><i></i><span>${escapeHtml12(item.title)}</span></a>`).join("")}</nav><button class="back-top" type="button">Back to top \u2191</button></aside>` : "";
73333
73645
  const actions = flags.citation || flags.share ? `<div class="article-actions">${flags.citation ? '<button type="button" data-cite aria-haspopup="dialog">\u270E <span>Cite us</span></button>' : ""}${flags.share ? '<button type="button" data-share>\u21E7 <span>Share this article</span></button>' : ""}</div><p class="action-status" aria-live="polite"></p>` : "";
73334
- const author = flags.authorCard ? `<section id="author" class="author-card">${actions}<div class="author-grid">${portrait(input)}<div><span>Written by</span><h2>${input.author.href ? `<a href="${safeHref4(input.author.href)}">${escapeHtml11(input.author.name)}</a>` : escapeHtml11(input.author.name)}</h2><p>${escapeHtml11(input.author.role)}</p>${input.author.socialLinks.length || input.author.email ? `<nav aria-label="Author links">${input.author.socialLinks.map((link2) => `<a href="${safeHref4(link2.href)}">${escapeHtml11(link2.label)}</a>`).join("")}${input.author.email ? `<a href="mailto:${escapeHtml11(input.author.email)}">Email</a>` : ""}</nav>` : ""}</div>${input.author.href ? `<a class="author-more" href="${safeHref4(input.author.href)}">Read more from ${escapeHtml11(input.author.name.split(/\s+/)[0] || input.author.name)}</a>` : ""}</div><p class="author-bio">${escapeHtml11(input.author.bio)}</p></section>` : actions;
73335
- const citationDialog = flags.citation ? `<dialog id="citation-dialog"><div><button class="dialog-close" type="button" aria-label="Close citation guide">\xD7</button><h2>Quick citation guide</h2><p>Select a citation to automatically copy it to your clipboard.</p><section>${Object.keys(citationValues).map((style) => `<button type="button" data-citation="${style}"><strong>${style}:</strong> ${escapeHtml11(citationValues[style])}</button>`).join("")}</section><p class="citation-status" aria-live="polite"></p></div></dialog>` : "";
73336
- const html = `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex,nofollow"><meta name="description" content="${escapeHtml11(input.dek || input.keyTakeaways[0])}"><title>${escapeHtml11(input.title)} \xB7 ${escapeHtml11(brand)}</title><style>
73646
+ const author = flags.authorCard ? `<section id="author" class="author-card">${actions}<div class="author-grid">${portrait(input)}<div><span>Written by</span><h2>${input.author.href ? `<a href="${safeHref4(input.author.href)}">${escapeHtml12(input.author.name)}</a>` : escapeHtml12(input.author.name)}</h2><p>${escapeHtml12(input.author.role)}</p>${input.author.socialLinks.length || input.author.email ? `<nav aria-label="Author links">${input.author.socialLinks.map((link2) => `<a href="${safeHref4(link2.href)}">${escapeHtml12(link2.label)}</a>`).join("")}${input.author.email ? `<a href="mailto:${escapeHtml12(input.author.email)}">Email</a>` : ""}</nav>` : ""}</div>${input.author.href ? `<a class="author-more" href="${safeHref4(input.author.href)}">Read more from ${escapeHtml12(input.author.name.split(/\s+/)[0] || input.author.name)}</a>` : ""}</div><p class="author-bio">${escapeHtml12(input.author.bio)}</p></section>` : actions;
73647
+ const citationDialog = flags.citation ? `<dialog id="citation-dialog"><div><button class="dialog-close" type="button" aria-label="Close citation guide">\xD7</button><h2>Quick citation guide</h2><p>Select a citation to automatically copy it to your clipboard.</p><section>${Object.keys(citationValues).map((style) => `<button type="button" data-citation="${style}"><strong>${style}:</strong> ${escapeHtml12(citationValues[style])}</button>`).join("")}</section><p class="citation-status" aria-live="polite"></p></div></dialog>` : "";
73648
+ const html = `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex,nofollow"><meta name="description" content="${escapeHtml12(input.dek || input.keyTakeaways[0])}"><title>${escapeHtml12(input.title)} \xB7 ${escapeHtml12(brand)}</title><style>
73337
73649
  :root{--ink:#10213d;--ink2:#1c355a;--blue:#2563eb;--blue2:#1749b6;--mint:#45d5aa;--paper:#f7f5f0;--line:#dce4ef;--card:#fff;--body:#475569;--serif:Iowan Old Style,Palatino Linotype,Palatino,Georgia,serif;--sans:Inter,Avenir Next,ui-sans-serif,system-ui,sans-serif}body[data-theme="slate"]{--ink:#1e293b;--ink2:#334155;--blue:#475569;--blue2:#1e293b;--mint:#94a3b8;--paper:#f8fafc}body[data-theme="forest"]{--ink:#12352e;--ink2:#23584c;--blue:#147d64;--blue2:#0c5b48;--mint:#79d8bd;--paper:#f4f8f3}*{box-sizing:border-box}html{scroll-behavior:smooth;background:var(--paper)}body{margin:0;color:#252a33;background:var(--paper);font-family:var(--sans);line-height:1.6}a{color:inherit}button{font:inherit}button:focus-visible,a:focus-visible{outline:3px solid var(--mint);outline-offset:3px}.progress{position:fixed;z-index:50;top:0;left:0;height:4px;width:0;background:var(--mint)}.hero{position:relative;overflow:hidden;color:#fff;background:var(--ink)}.hero:after{position:absolute;right:-110px;top:-150px;width:420px;height:420px;border:1px solid #ffffff1a;border-radius:50%;content:""}.hero-inner{position:relative;z-index:1;max-width:1240px;margin:auto;padding:58px 42px 126px}.breadcrumb{display:flex;gap:8px;margin-bottom:34px;color:#dbeafecc;font-size:14px}.eyebrow{display:block;color:var(--blue);font-size:12px;font-weight:800;letter-spacing:.16em;text-transform:uppercase}.hero .eyebrow{color:var(--mint)}h1,h2,h3,p{margin-top:0}.hero h1{max-width:1000px;margin:14px 0 24px;font:700 clamp(44px,6vw,78px)/.98 var(--serif);letter-spacing:-.035em}.hero .dek{max-width:780px;color:#dbeafe;font-size:20px}.contributors{margin-top:30px;color:#eff6ff;font-size:14px}.contributors a{font-weight:800}.meta{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:#dbeafecc}.layout{position:relative;z-index:2;display:grid;grid-template-columns:minmax(0,760px) 290px;gap:64px;max-width:1240px;margin:-78px auto 0;padding:0 42px 80px}.main{min-width:0}.takeaways{padding:38px 44px;border-radius:24px;background:#fff;box-shadow:0 24px 70px #10213d24}.takeaways h2{margin:5px 0 20px;font:700 32px/1.1 var(--serif);color:var(--ink)}.takeaways ul{display:grid;gap:16px;margin:0;padding:0;list-style:none}.takeaways li{position:relative;padding-left:26px;color:var(--body);font-size:17px}.takeaways li:before{position:absolute;left:2px;top:.7em;width:8px;height:8px;border-radius:50%;background:var(--blue);content:""}.intro{padding:40px 0 4px}.intro p,.article-section>p{margin-bottom:22px;color:var(--body);font:400 18px/1.75 var(--sans)}.article-section{scroll-margin-top:28px;padding-top:45px}.article-section h2,.faq h2{margin:6px 0 20px;color:var(--ink);font:700 38px/1.08 var(--serif);letter-spacing:-.02em}.article-section ul{display:grid;gap:10px;margin:22px 0;padding-left:24px;color:var(--body);font-size:17px}.article-section li::marker{color:var(--blue)}.callout{margin:34px 0;padding:24px 28px;border-left:4px solid var(--blue);border-radius:0 16px 16px 0;background:#fff}.callout span{color:var(--blue);font-size:11px;font-weight:800;letter-spacing:.13em;text-transform:uppercase}.callout h3{margin:5px 0 8px;color:var(--ink);font:700 24px/1.15 var(--serif)}.callout p{margin:0;color:var(--body)}.rail{padding-top:0}.sidebar-media{overflow:hidden;margin:0 0 18px;border:1px solid #dbeafe;border-radius:16px;background:#fff}.sidebar-media img,.sidebar-media svg{display:block;width:100%;aspect-ratio:16/9;object-fit:cover}.sidebar-media figcaption{padding:10px 13px;color:#64748b;font-size:11px}.disclosure{margin-bottom:28px;border-top:1px solid #dbeafe;border-bottom:1px solid #dbeafe}.disclosure button{display:flex;width:100%;align-items:center;justify-content:space-between;gap:14px;padding:15px 0;border:0;color:#64748b;background:transparent;text-align:left;font-size:12px;cursor:pointer}.disclosure button b{color:var(--blue);font-size:18px;transition:transform .2s}.disclosure button[aria-expanded="true"] b{transform:rotate(180deg)}.disclosure p{padding:0 0 16px;margin:0;color:#64748b;font-size:12px}.toc{position:sticky;top:30px;padding:22px;border:1px solid var(--line);border-radius:16px;background:#fff;box-shadow:0 2px 5px #10213d12}.toc header{display:flex;align-items:center;justify-content:space-between}.toc header strong{color:var(--ink);font:700 21px/1 var(--serif)}.toc header button{width:34px;height:34px;border:0;border-radius:50%;color:var(--blue);background:transparent;cursor:pointer}.toc nav{display:grid;margin-top:14px}.toc nav a{display:flex;align-items:flex-start;gap:11px;padding:8px 0;color:#64748b;text-decoration:none;font-size:13px;line-height:1.35}.toc nav i{width:8px;height:8px;margin-top:5px;border:2px solid #bfdbfe;border-radius:50%}.toc nav a[aria-current="location"]{color:var(--ink);font-weight:800}.toc nav a[aria-current="location"] i{border-color:var(--blue);background:var(--blue)}.back-top{width:100%;margin-top:18px;padding:16px 0 0;border:0;border-top:1px solid var(--line);color:var(--blue);background:transparent;text-align:right;font-size:13px;font-weight:800;cursor:pointer}.faq{scroll-margin-top:28px;padding-top:64px}.faq>div{border-top:1px solid var(--line);border-bottom:1px solid var(--line)}.faq article+article{border-top:1px solid var(--line)}.faq h3{margin:0}.faq h3 button{display:flex;width:100%;align-items:center;justify-content:space-between;gap:18px;padding:19px 0;border:0;color:var(--ink);background:transparent;text-align:left;font-weight:800;cursor:pointer}.faq h3 b{color:var(--blue);font-size:22px}.faq article>p{padding:0 0 20px;margin:0;color:var(--body);font-size:16px}.author-card{margin-top:64px;padding:32px 36px;border-radius:18px;background:#fff}.article-actions{display:flex;flex-wrap:wrap;justify-content:space-between;gap:14px}.article-actions button{display:inline-flex;min-height:46px;align-items:center;justify-content:center;gap:8px;padding:8px 18px;border:2px solid var(--blue);border-radius:999px;color:var(--ink);background:#fff;font-weight:800;cursor:pointer}.article-actions button:hover{color:#fff;background:var(--blue)}.action-status{min-height:20px;margin:8px 0 0;color:var(--blue);text-align:right;font-size:13px;font-weight:700}.author-grid{display:grid;grid-template-columns:auto 1fr auto;gap:22px;align-items:center;margin-top:24px}.author-portrait{width:88px;height:88px;border-radius:50%;object-fit:cover}.author-initials{display:grid;place-items:center;color:var(--ink);background:#fecdd3;font-size:22px;font-weight:900}.author-grid span{color:#64748b;font-size:13px}.author-grid h2{margin:2px 0;color:var(--ink);font:700 27px/1 var(--serif)}.author-grid h2 a{text-decoration:none}.author-grid p{margin:8px 0;color:#64748b;font-size:14px}.author-grid nav{display:flex;flex-wrap:wrap;gap:14px}.author-grid nav a{color:#64748b;font-size:12px}.author-more{display:inline-flex;min-height:48px;align-items:center;justify-content:center;padding:10px 24px;border:2px solid var(--blue);color:var(--blue);text-align:center;text-decoration:none;font-size:13px;font-weight:800}.author-bio{margin:24px 0 0!important;padding-top:20px;border-top:1px solid var(--line);color:var(--body);font-size:16px}dialog{width:min(720px,calc(100% - 30px));max-height:calc(100dvh - 30px);padding:0;border:0;border-radius:18px;color:var(--ink);background:#fff;box-shadow:0 24px 70px #10213d38}dialog::backdrop{background:#0f172a7a;backdrop-filter:blur(2px)}dialog>div{position:relative;padding:30px}dialog h2{margin:0 50px 2px 0;font:700 30px/1.1 var(--serif)}dialog>div>p{color:#64748b}.dialog-close{position:absolute;top:13px;right:13px;width:44px;height:44px;border:0;border-radius:50%;color:var(--blue);background:transparent;font-size:29px;cursor:pointer}dialog section{border-top:1px solid var(--line)}dialog section button{display:block;width:100%;padding:17px 5px;border:0;border-bottom:1px solid var(--line);color:var(--body);background:#fff;text-align:left;line-height:1.65;cursor:pointer}.citation-status{min-height:22px;margin:14px 0 0!important;color:var(--blue)!important;font-size:13px;font-weight:800}.generated{max-width:1156px;margin:-52px auto 50px;padding:0 42px;color:#94a3b8;font-size:11px}@media(max-width:900px){.layout{display:block}.rail{display:none}.hero-inner{padding-bottom:116px}}@media(max-width:620px){.hero-inner{padding:36px 20px 104px}.hero h1{font-size:46px}.hero .dek{font-size:17px}.layout{margin-top:-70px;padding:0 16px 54px}.takeaways{padding:28px 24px}.article-section h2,.faq h2{font-size:32px}.author-card{padding:24px}.article-actions{display:grid;justify-content:start}.author-grid{grid-template-columns:1fr;gap:12px}.author-more{width:100%}dialog>div{padding:24px}.generated{padding:0 20px}}
73338
- </style></head><body data-theme="${escapeHtml11(config.theme)}" data-scheduled-renderer="blog_article_v1"><div class="progress" aria-hidden="true"></div><header class="hero"><div class="hero-inner"><nav class="breadcrumb" aria-label="Breadcrumb"><a href="${safeHref4(input.canonicalUrl)}">${escapeHtml11(input.category)}</a><span>/</span><span>Article</span></nav><span class="eyebrow">${escapeHtml11(input.eyebrow)}</span><h1>${escapeHtml11(input.title)}</h1>${input.dek ? `<p class="dek">${escapeHtml11(input.dek)}</p>` : ""}<div class="contributors">${contributorText}<div class="meta"><time datetime="${escapeHtml11(articleDate)}">Updated ${formatDate2(articleDate)}</time><span>\u2022</span><span>${input.readTimeMinutes} min read</span>${input.reviewer ? "<span>\u2022</span><strong>Expert reviewed</strong>" : ""}</div></div></div></header><main class="layout"><article class="main"><section class="takeaways"><span class="eyebrow">The short answer</span><h2>Key takeaways</h2><ul>${input.keyTakeaways.map((item) => `<li>${escapeHtml11(item)}</li>`).join("")}</ul></section><section class="intro">${input.introduction.map((paragraph) => `<p>${escapeHtml11(paragraph)}</p>`).join("")}</section>${sections}${faq}${author}</article><div class="rail">${media}${disclosure}${toc}</div></main>${config.showGeneratedAt ? `<p class="generated">Rendered ${formatDate2(generatedAtIso)} by MCP Scraper.</p>` : ""}${citationDialog}<script>(()=>{const citations=${jsonForScript(citationValues)};const canonical=${jsonForScript(input.canonicalUrl)};const title=${jsonForScript(input.title)};const progress=document.querySelector('.progress');const tocLinks=[...document.querySelectorAll('.toc nav a')];const targets=tocLinks.map(link=>document.querySelector(link.hash)).filter(Boolean);const update=()=>{const max=document.documentElement.scrollHeight-innerHeight;if(progress)progress.style.width=(max>0?scrollY/max*100:0)+'%';let active=targets[0]?.id;for(const target of targets){if(target.getBoundingClientRect().top<=innerHeight*.55)active=target.id}tocLinks.forEach(link=>link.toggleAttribute('aria-current',link.hash==='#'+active));tocLinks.forEach(link=>{if(link.hash==='#'+active)link.setAttribute('aria-current','location');else link.removeAttribute('aria-current')})};addEventListener('scroll',update,{passive:true});addEventListener('resize',update);update();document.querySelectorAll('.faq h3 button').forEach(button=>button.addEventListener('click',()=>{const panel=document.getElementById(button.getAttribute('aria-controls'));const open=button.getAttribute('aria-expanded')==='true';button.setAttribute('aria-expanded',String(!open));panel.hidden=open;button.querySelector('b').textContent=open?'+':'\u2212'}));const disclosure=document.querySelector('.disclosure button');disclosure?.addEventListener('click',()=>{const panel=document.getElementById(disclosure.getAttribute('aria-controls'));const open=disclosure.getAttribute('aria-expanded')==='true';disclosure.setAttribute('aria-expanded',String(!open));panel.hidden=open});const tocToggle=document.querySelector('.toc header button');tocToggle?.addEventListener('click',()=>{const nav=document.getElementById('toc-links');const open=tocToggle.getAttribute('aria-expanded')==='true';tocToggle.setAttribute('aria-expanded',String(!open));nav.hidden=open;tocToggle.textContent=open?'\u2304':'\u2303'});document.querySelector('.back-top')?.addEventListener('click',()=>scrollTo({top:0,behavior:'smooth'}));const copy=async text=>{try{await navigator.clipboard.writeText(text)}catch{const area=document.createElement('textarea');area.value=text;area.style.position='fixed';area.style.opacity='0';document.body.append(area);area.select();document.execCommand('copy');area.remove()}};const dialog=document.getElementById('citation-dialog');document.querySelector('[data-cite]')?.addEventListener('click',()=>dialog.showModal());document.querySelector('.dialog-close')?.addEventListener('click',()=>dialog.close());dialog?.addEventListener('click',event=>{if(event.target===dialog)dialog.close()});document.querySelectorAll('[data-citation]').forEach(button=>button.addEventListener('click',async()=>{const style=button.dataset.citation;await copy(citations[style]);document.querySelector('.citation-status').textContent=style+' citation copied to clipboard.'}));document.querySelector('[data-share]')?.addEventListener('click',async()=>{const status=document.querySelector('.action-status');if(navigator.share){try{await navigator.share({title,url:canonical});status.textContent='Sharing options opened.';return}catch(error){if(error.name==='AbortError')return}}await copy(canonical);status.textContent='Article link copied to clipboard.'})})()</script></body></html>`;
73650
+ </style></head><body data-theme="${escapeHtml12(config.theme)}" data-scheduled-renderer="blog_article_v1"><div class="progress" aria-hidden="true"></div><header class="hero"><div class="hero-inner"><nav class="breadcrumb" aria-label="Breadcrumb"><a href="${safeHref4(input.canonicalUrl)}">${escapeHtml12(input.category)}</a><span>/</span><span>Article</span></nav><span class="eyebrow">${escapeHtml12(input.eyebrow)}</span><h1>${escapeHtml12(input.title)}</h1>${input.dek ? `<p class="dek">${escapeHtml12(input.dek)}</p>` : ""}<div class="contributors">${contributorText}<div class="meta"><time datetime="${escapeHtml12(articleDate)}">Updated ${formatDate2(articleDate)}</time><span>\u2022</span><span>${input.readTimeMinutes} min read</span>${input.reviewer ? "<span>\u2022</span><strong>Expert reviewed</strong>" : ""}</div></div></div></header><main class="layout"><article class="main"><section class="takeaways"><span class="eyebrow">The short answer</span><h2>Key takeaways</h2><ul>${input.keyTakeaways.map((item) => `<li>${escapeHtml12(item)}</li>`).join("")}</ul></section><section class="intro">${input.introduction.map((paragraph) => `<p>${escapeHtml12(paragraph)}</p>`).join("")}</section>${sections}${faq}${author}</article><div class="rail">${media}${disclosure}${toc}</div></main>${config.showGeneratedAt ? `<p class="generated">Rendered ${formatDate2(generatedAtIso)} by MCP Scraper.</p>` : ""}${citationDialog}<script>(()=>{const citations=${jsonForScript(citationValues)};const canonical=${jsonForScript(input.canonicalUrl)};const title=${jsonForScript(input.title)};const progress=document.querySelector('.progress');const tocLinks=[...document.querySelectorAll('.toc nav a')];const targets=tocLinks.map(link=>document.querySelector(link.hash)).filter(Boolean);const update=()=>{const max=document.documentElement.scrollHeight-innerHeight;if(progress)progress.style.width=(max>0?scrollY/max*100:0)+'%';let active=targets[0]?.id;for(const target of targets){if(target.getBoundingClientRect().top<=innerHeight*.55)active=target.id}tocLinks.forEach(link=>link.toggleAttribute('aria-current',link.hash==='#'+active));tocLinks.forEach(link=>{if(link.hash==='#'+active)link.setAttribute('aria-current','location');else link.removeAttribute('aria-current')})};addEventListener('scroll',update,{passive:true});addEventListener('resize',update);update();document.querySelectorAll('.faq h3 button').forEach(button=>button.addEventListener('click',()=>{const panel=document.getElementById(button.getAttribute('aria-controls'));const open=button.getAttribute('aria-expanded')==='true';button.setAttribute('aria-expanded',String(!open));panel.hidden=open;button.querySelector('b').textContent=open?'+':'\u2212'}));const disclosure=document.querySelector('.disclosure button');disclosure?.addEventListener('click',()=>{const panel=document.getElementById(disclosure.getAttribute('aria-controls'));const open=disclosure.getAttribute('aria-expanded')==='true';disclosure.setAttribute('aria-expanded',String(!open));panel.hidden=open});const tocToggle=document.querySelector('.toc header button');tocToggle?.addEventListener('click',()=>{const nav=document.getElementById('toc-links');const open=tocToggle.getAttribute('aria-expanded')==='true';tocToggle.setAttribute('aria-expanded',String(!open));nav.hidden=open;tocToggle.textContent=open?'\u2304':'\u2303'});document.querySelector('.back-top')?.addEventListener('click',()=>scrollTo({top:0,behavior:'smooth'}));const copy=async text=>{try{await navigator.clipboard.writeText(text)}catch{const area=document.createElement('textarea');area.value=text;area.style.position='fixed';area.style.opacity='0';document.body.append(area);area.select();document.execCommand('copy');area.remove()}};const dialog=document.getElementById('citation-dialog');document.querySelector('[data-cite]')?.addEventListener('click',()=>dialog.showModal());document.querySelector('.dialog-close')?.addEventListener('click',()=>dialog.close());dialog?.addEventListener('click',event=>{if(event.target===dialog)dialog.close()});document.querySelectorAll('[data-citation]').forEach(button=>button.addEventListener('click',async()=>{const style=button.dataset.citation;await copy(citations[style]);document.querySelector('.citation-status').textContent=style+' citation copied to clipboard.'}));document.querySelector('[data-share]')?.addEventListener('click',async()=>{const status=document.querySelector('.action-status');if(navigator.share){try{await navigator.share({title,url:canonical});status.textContent='Sharing options opened.';return}catch(error){if(error.name==='AbortError')return}}await copy(canonical);status.textContent='Article link copied to clipboard.'})})()</script></body></html>`;
73339
73651
  const bytes = Buffer.byteLength(html);
73340
73652
  const sha2563 = (0, import_node_crypto49.createHash)("sha256").update(html).digest("hex");
73341
73653
  return {
@@ -76235,7 +76547,7 @@ function sql() {
76235
76547
  if (_sql) return _sql;
76236
76548
  const url = process.env.MEMORY_DATABASE_URL?.trim();
76237
76549
  if (!url) throw new Error("MEMORY_DATABASE_URL is not set (paa-crawler needs mcp-memory Neon URL for reads)");
76238
- _sql = (0, import_serverless.neon)(url);
76550
+ _sql = (0, import_serverless2.neon)(url);
76239
76551
  return _sql;
76240
76552
  }
76241
76553
  function physicalVault(owner, vault) {
@@ -76428,11 +76740,11 @@ async function dbUsage(identity, plan) {
76428
76740
  unlimited: isUnlimited(plan)
76429
76741
  };
76430
76742
  }
76431
- var import_serverless, _sql, EMBED_BYTES_PER_CHUNK, FREE_COST_CAP_USD;
76743
+ var import_serverless2, _sql, EMBED_BYTES_PER_CHUNK, FREE_COST_CAP_USD;
76432
76744
  var init_memory_db = __esm({
76433
76745
  "src/api/memory-db.ts"() {
76434
76746
  "use strict";
76435
- import_serverless = require("@neondatabase/serverless");
76747
+ import_serverless2 = require("@neondatabase/serverless");
76436
76748
  init_rates();
76437
76749
  init_memory_universe();
76438
76750
  _sql = null;
@@ -79453,6 +79765,7 @@ var init_server = __esm({
79453
79765
  init_scheduled_artifact_internal_routes();
79454
79766
  init_site_audit_worker();
79455
79767
  init_local_sourcebook_worker();
79768
+ init_commons_embeddings();
79456
79769
  init_local_sourcebook_dispatch();
79457
79770
  import_factory8 = require("hono/factory");
79458
79771
  import_cookie2 = require("hono/cookie");
@@ -82236,7 +82549,7 @@ var init_server = __esm({
82236
82549
  const budget = { maxJobs: 10, deadlineMs: startedAt + CRON_TICK_DRAIN_BUDGET_MS };
82237
82550
  const origin = `${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`;
82238
82551
  const unfinished = [];
82239
- const [results, sweepResult, reapResult, expiredResult, blobCleanup, connectedDataArtifactCleanup, connectedAccountBilling, directoryWorkflowDispatch, directoryWorkflowReconciliation, directoryArtifactCleanup, siteExtractArtifactCleanup, siteExtractRedispatch, siteExtractReconciliation, paaHarvestRedispatch, paaHarvestReconciliation, localSourcebookRedispatch, analyticsRollup, analyticsFormDelivery, workflowDispatchResult, scheduledRunReconciliation, retentionSweep] = await Promise.all([
82552
+ const [results, sweepResult, reapResult, expiredResult, blobCleanup, connectedDataArtifactCleanup, connectedAccountBilling, directoryWorkflowDispatch, directoryWorkflowReconciliation, directoryArtifactCleanup, siteExtractArtifactCleanup, siteExtractRedispatch, siteExtractReconciliation, paaHarvestRedispatch, paaHarvestReconciliation, commonsEmbeddingDrain, localSourcebookRedispatch, analyticsRollup, analyticsFormDelivery, workflowDispatchResult, scheduledRunReconciliation, retentionSweep] = await Promise.all([
82240
82553
  settleWithinTickBudget("drainQueue", unfinished, drainQueue2(budget), []),
82241
82554
  settleWithinTickBudget("monthlyRefreshSweep", unfinished, runMonthlyRefreshSweep(), { status: "skipped_deadline" }),
82242
82555
  settleWithinTickBudget("reapBrowserSessions", unfinished, reapIdleBrowserSessions(120), { reaped: 0 }),
@@ -82253,6 +82566,7 @@ var init_server = __esm({
82253
82566
  settleWithinTickBudget("siteExtractReconcile", unfinished, reconcileSiteExtractSettlements(10), { checked: 0, settled: 0, failed: 0 }),
82254
82567
  settleWithinTickBudget("paaRedispatch", unfinished, redispatchPendingPaaHarvests(10), { checked: 0, dispatched: 0, failed: 0 }),
82255
82568
  settleWithinTickBudget("paaReconcile", unfinished, reconcilePaaHarvestSettlements(10), { checked: 0, staleFailed: 0, settled: 0, failed: 0 }),
82569
+ settleWithinTickBudget("commonsEmbeddingDrain", unfinished, embedQueuedCommonsDocuments(50), { claimed: 0, embedded: 0, failed: 0, remaining: 0 }),
82256
82570
  settleWithinTickBudget("localSourcebookRedispatch", unfinished, redispatchQueuedLocalSourcebookAcquisitions(5), { checked: 0, dispatched: 0, failed: 0 }),
82257
82571
  settleWithinTickBudget("analyticsRollup", unfinished, refreshAnalyticsDailyRollupsIfDue(), { status: "failed", rows: 0 }),
82258
82572
  settleWithinTickBudget("analyticsForms", unfinished, deliverPendingAnalyticsForms(10), { claimed: 0, delivered: 0, deferred: 0 }),
@@ -82283,6 +82597,7 @@ var init_server = __esm({
82283
82597
  siteExtractReconciliation,
82284
82598
  paaHarvestRedispatch,
82285
82599
  paaHarvestReconciliation,
82600
+ commonsEmbeddingDrain,
82286
82601
  localSourcebookRedispatch,
82287
82602
  analyticsRollup,
82288
82603
  analyticsFormDelivery,