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.
@@ -170,7 +170,7 @@ import {
170
170
  resolveDeploymentProfile,
171
171
  resolveLocalSourcebookSchemaType,
172
172
  transcribeMediaUrl
173
- } from "./chunk-P32KEY3D.js";
173
+ } from "./chunk-AIA3MFT2.js";
174
174
  import {
175
175
  auditImageUrls,
176
176
  auditImages,
@@ -226,7 +226,7 @@ import {
226
226
  } from "./chunk-FG6LJGJ7.js";
227
227
  import {
228
228
  PACKAGE_VERSION
229
- } from "./chunk-EJ6KU4PC.js";
229
+ } from "./chunk-AQA2ZL4X.js";
230
230
  import {
231
231
  abandonExtractSettlement,
232
232
  countSuccessfulPages,
@@ -32752,9 +32752,7 @@ function socialMeta(input) {
32752
32752
  ];
32753
32753
  return tags.join("\n ");
32754
32754
  }
32755
- function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
32756
- const sourceBytes = input.articles.reduce((total, article) => total + Buffer.byteLength(article.markdown), 0);
32757
- if (sourceBytes > 2e6) throw new Error("Editorial reading-room Markdown must be 2,000,000 bytes or fewer in total.");
32755
+ function buildEditorialArticles(input) {
32758
32756
  const seenSlugs = /* @__PURE__ */ new Set();
32759
32757
  const seenOrders = /* @__PURE__ */ new Set();
32760
32758
  const parser = markdownRenderer();
@@ -32781,7 +32779,19 @@ function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
32781
32779
  html: rendered
32782
32780
  };
32783
32781
  });
32782
+ return { articles, warnings, totalWordCount };
32783
+ }
32784
+ function renderEditorialArticleModels(input) {
32785
+ return buildEditorialArticles(input).articles;
32786
+ }
32787
+ function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
32788
+ const sourceBytes = input.articles.reduce((total, article) => total + Buffer.byteLength(article.markdown), 0);
32789
+ if (sourceBytes > 2e6) throw new Error("Editorial reading-room Markdown must be 2,000,000 bytes or fewer in total.");
32784
32790
  const generatedAt = now.toISOString();
32791
+ const built = buildEditorialArticles(input);
32792
+ const articles = built.articles;
32793
+ const warnings = built.warnings;
32794
+ const totalWordCount = built.totalWordCount;
32785
32795
  const data = { ...input, generatedAt, articles };
32786
32796
  const template = readAsset("index.html");
32787
32797
  const html = template.replace("<title>Editorial Reading Room</title>", `<title>${escapeHtml5(input.site.title)}</title>`).replace('content="A mobile-first editorial reading room."', `content="${escapeHtml5(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"));
@@ -33230,6 +33240,134 @@ async function hostEntityImages(input) {
33230
33240
  return rewrite;
33231
33241
  }
33232
33242
 
33243
+ // src/api/commons-embeddings.ts
33244
+ import { neon } from "@neondatabase/serverless";
33245
+ var COMMONS_EMBED_PROVIDER = "jina";
33246
+ var _vectorSql = null;
33247
+ var vectorSchemaReady = false;
33248
+ function commonsEmbedModel() {
33249
+ return (process.env.JINA_EMBED_MODEL ?? "jina-embeddings-v5-omni-small").trim();
33250
+ }
33251
+ function commonsEmbedDim() {
33252
+ return Number((process.env.JINA_EMBED_DIM ?? "1024").trim());
33253
+ }
33254
+ function commonsSemanticSearchConfigured() {
33255
+ return Boolean(process.env.JINA_API_KEY?.trim() && process.env.MEMORY_DATABASE_URL?.trim());
33256
+ }
33257
+ function vectorSql() {
33258
+ if (_vectorSql) return _vectorSql;
33259
+ const url = process.env.MEMORY_DATABASE_URL?.trim();
33260
+ if (!url) throw new Error("MEMORY_DATABASE_URL is not set; Commons semantic search needs the shared Postgres.");
33261
+ _vectorSql = neon(url);
33262
+ return _vectorSql;
33263
+ }
33264
+ async function ensureCommonsVectorSchema() {
33265
+ if (vectorSchemaReady) return;
33266
+ const dimension = commonsEmbedDim();
33267
+ await vectorSql().query("CREATE EXTENSION IF NOT EXISTS vector");
33268
+ await vectorSql().query(`
33269
+ CREATE TABLE IF NOT EXISTS commons_index_vectors (
33270
+ document_id TEXT PRIMARY KEY,
33271
+ entity_id TEXT NOT NULL,
33272
+ document_type TEXT NOT NULL,
33273
+ title TEXT NOT NULL,
33274
+ embedding vector(${dimension}) NOT NULL,
33275
+ model TEXT NOT NULL,
33276
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
33277
+ )
33278
+ `);
33279
+ await vectorSql().query("CREATE INDEX IF NOT EXISTS commons_index_vectors_entity ON commons_index_vectors(entity_id)");
33280
+ vectorSchemaReady = true;
33281
+ }
33282
+ async function embedCommonsTexts(texts) {
33283
+ const apiKey = process.env.JINA_API_KEY?.trim();
33284
+ if (!apiKey) throw new Error("JINA_API_KEY is not set; Commons semantic search cannot embed.");
33285
+ if (!texts.length) return [];
33286
+ const response = await fetch("https://api.jina.ai/v1/embeddings", {
33287
+ method: "POST",
33288
+ headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
33289
+ body: JSON.stringify({
33290
+ model: commonsEmbedModel(),
33291
+ dimensions: commonsEmbedDim(),
33292
+ input: texts.map((text2) => ({ text: text2.slice(0, 8e3) }))
33293
+ }),
33294
+ signal: AbortSignal.timeout(6e4)
33295
+ });
33296
+ if (!response.ok) {
33297
+ throw new Error(`Jina embedding request failed with HTTP ${response.status}: ${(await response.text()).slice(0, 200)}`);
33298
+ }
33299
+ const payload = await response.json();
33300
+ const vectors = (payload.data ?? []).map((item) => item.embedding);
33301
+ if (vectors.length !== texts.length) {
33302
+ throw new Error(`Jina returned ${vectors.length} embeddings for ${texts.length} inputs.`);
33303
+ }
33304
+ return vectors;
33305
+ }
33306
+ async function embedQueuedCommonsDocuments(limit = 50) {
33307
+ if (!commonsSemanticSearchConfigured()) return { claimed: 0, embedded: 0, failed: 0, remaining: 0 };
33308
+ await ensureCommonsVectorSchema();
33309
+ const bounded = Math.max(1, Math.min(200, Math.floor(limit)));
33310
+ const queued = await getDb().execute({
33311
+ sql: `SELECT id, entity_id, document_type, title, text FROM commons_index_documents
33312
+ WHERE embedding_status IN ('queued', 'failed') ORDER BY updated_at ASC LIMIT ?`,
33313
+ args: [bounded]
33314
+ });
33315
+ const rows = queued.rows;
33316
+ if (!rows.length) return { claimed: 0, embedded: 0, failed: 0, remaining: await queuedCommonsDocumentCount() };
33317
+ let embedded = 0;
33318
+ let failed = 0;
33319
+ const model = commonsEmbedModel();
33320
+ try {
33321
+ const vectors = await embedCommonsTexts(rows.map((row) => `${row.title}
33322
+
33323
+ ${row.text}`));
33324
+ for (const [index, row] of rows.entries()) {
33325
+ const literal = `[${vectors[index].join(",")}]`;
33326
+ await vectorSql().query(
33327
+ `INSERT INTO commons_index_vectors (document_id, entity_id, document_type, title, embedding, model, updated_at)
33328
+ VALUES ($1, $2, $3, $4, $5::vector, $6, now())
33329
+ ON CONFLICT (document_id) DO UPDATE SET entity_id = EXCLUDED.entity_id, document_type = EXCLUDED.document_type,
33330
+ title = EXCLUDED.title, embedding = EXCLUDED.embedding, model = EXCLUDED.model, updated_at = now()`,
33331
+ [row.id, row.entity_id, row.document_type, row.title, literal, model]
33332
+ );
33333
+ await getDb().execute({
33334
+ sql: `UPDATE commons_index_documents SET embedding_status = 'indexed', embedding_provider = ?, embedding_model = ?,
33335
+ vector_ref = ?, indexed_at = ?, error = NULL WHERE id = ?`,
33336
+ args: [COMMONS_EMBED_PROVIDER, model, row.id, (/* @__PURE__ */ new Date()).toISOString(), row.id]
33337
+ });
33338
+ embedded += 1;
33339
+ }
33340
+ } catch (error) {
33341
+ failed = rows.length - embedded;
33342
+ const message = (error instanceof Error ? error.message : String(error)).slice(0, 500);
33343
+ for (const row of rows.slice(embedded)) {
33344
+ await getDb().execute({
33345
+ sql: `UPDATE commons_index_documents SET embedding_status = 'failed', error = ? WHERE id = ?`,
33346
+ args: [message, row.id]
33347
+ }).catch(() => void 0);
33348
+ }
33349
+ }
33350
+ return { claimed: rows.length, embedded, failed, remaining: await queuedCommonsDocumentCount() };
33351
+ }
33352
+ async function queuedCommonsDocumentCount() {
33353
+ const result = await getDb().execute(`SELECT COUNT(*) AS n FROM commons_index_documents WHERE embedding_status IN ('queued', 'failed')`);
33354
+ return Number(result.rows[0]?.n ?? 0);
33355
+ }
33356
+ async function semanticCommonsEntityScores(query, limit = 40) {
33357
+ const scores = /* @__PURE__ */ new Map();
33358
+ if (!commonsSemanticSearchConfigured() || !query.trim()) return scores;
33359
+ await ensureCommonsVectorSchema();
33360
+ const [vector] = await embedCommonsTexts([query]);
33361
+ if (!vector) return scores;
33362
+ const rows = await vectorSql().query(
33363
+ `SELECT entity_id, MAX(1 - (embedding <=> $1::vector)) AS score
33364
+ FROM commons_index_vectors GROUP BY entity_id ORDER BY score DESC LIMIT $2`,
33365
+ [`[${vector.join(",")}]`, Math.max(1, Math.min(100, limit))]
33366
+ );
33367
+ for (const row of rows) scores.set(String(row.entity_id), Number(row.score));
33368
+ return scores;
33369
+ }
33370
+
33233
33371
  // src/api/schema-presence.ts
33234
33372
  var cache = null;
33235
33373
  async function loadSchemaObjects() {
@@ -33884,17 +34022,35 @@ async function searchCommonsEntities(filters = {}, userId) {
33884
34022
  args.push(mergedFilters.updatedAfter);
33885
34023
  }
33886
34024
  const terms = tokenize(mergedFilters.query);
33887
- for (const term of terms) {
33888
- clauses.push(`(
33889
- search_text LIKE ?
33890
- OR EXISTS (
33891
- SELECT 1 FROM commons_claims
33892
- WHERE commons_claims.subject_entity_id = commons_entities.id
33893
- AND (commons_claims.predicate LIKE ? OR commons_claims.predicate_label LIKE ? OR commons_claims.title LIKE ? OR commons_claims.object_url LIKE ?)
33894
- )
33895
- )`);
33896
- const pattern = `%${escapeLike(term)}%`;
33897
- args.push(pattern, pattern, pattern, pattern, pattern);
34025
+ const searchMode = mergedFilters.mode === "lexical" || mergedFilters.mode === "semantic" ? mergedFilters.mode : "hybrid";
34026
+ const semanticScores = !terms.length || searchMode === "lexical" || !commonsSemanticSearchConfigured() ? /* @__PURE__ */ new Map() : await semanticCommonsEntityScores(String(mergedFilters.query ?? ""), SEARCH_CANDIDATE_LIMIT).catch(() => /* @__PURE__ */ new Map());
34027
+ const semanticIds = [...semanticScores.entries()].filter(([, score]) => score >= 0.6).sort((left, right) => right[1] - left[1]).slice(0, 60).map(([id]) => id);
34028
+ if (terms.length) {
34029
+ const termClauses = [];
34030
+ for (const term of terms) {
34031
+ termClauses.push(`(
34032
+ search_text LIKE ?
34033
+ OR EXISTS (
34034
+ SELECT 1 FROM commons_claims
34035
+ WHERE commons_claims.subject_entity_id = commons_entities.id
34036
+ AND (commons_claims.predicate LIKE ? OR commons_claims.predicate_label LIKE ? OR commons_claims.title LIKE ? OR commons_claims.object_url LIKE ?)
34037
+ )
34038
+ )`);
34039
+ const pattern = `%${escapeLike(term)}%`;
34040
+ args.push(pattern, pattern, pattern, pattern, pattern);
34041
+ }
34042
+ const lexicalClause = `(${termClauses.join(" AND ")})`;
34043
+ if (searchMode === "semantic") {
34044
+ if (!semanticIds.length) return { results: [], filters: mergedFilters, limit, offset };
34045
+ args.length -= terms.length * 5;
34046
+ clauses.push(`id IN (${semanticIds.map(() => "?").join(", ")})`);
34047
+ args.push(...semanticIds);
34048
+ } else if (semanticIds.length) {
34049
+ clauses.push(`(${lexicalClause} OR id IN (${semanticIds.map(() => "?").join(", ")}))`);
34050
+ args.push(...semanticIds);
34051
+ } else {
34052
+ clauses.push(lexicalClause);
34053
+ }
33898
34054
  }
33899
34055
  if (!terms.length) {
33900
34056
  args.push(limit, offset);
@@ -33931,6 +34087,7 @@ async function searchCommonsEntities(filters = {}, userId) {
33931
34087
  `,
33932
34088
  args
33933
34089
  });
34090
+ const mode = searchMode;
33934
34091
  const ranked = candidates.rows.map((row) => {
33935
34092
  const record = row;
33936
34093
  const score = relevanceScore(terms, {
@@ -33941,8 +34098,10 @@ async function searchCommonsEntities(filters = {}, userId) {
33941
34098
  searchText: String(record.search_text ?? ""),
33942
34099
  claimText: String(record.claim_text ?? "")
33943
34100
  });
33944
- return { id: String(record.id), updatedAt: String(record.updated_at ?? ""), title: String(record.title ?? ""), score };
33945
- }).filter((candidate) => candidate.score > 0).sort((left, right) => right.score - left.score || right.updatedAt.localeCompare(left.updatedAt) || left.title.localeCompare(right.title));
34101
+ const semantic = semanticScores.get(String(record.id)) ?? 0;
34102
+ const fused = mode === "semantic" ? semantic * 100 : score + semantic * 60;
34103
+ return { id: String(record.id), updatedAt: String(record.updated_at ?? ""), title: String(record.title ?? ""), score: fused, lexical: score, semantic };
34104
+ }).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));
33946
34105
  const pageIds = ranked.slice(offset, offset + limit).map((candidate) => candidate.id);
33947
34106
  if (!pageIds.length) return { results: [], filters: mergedFilters, limit, offset };
33948
34107
  const page = await getDb().execute({
@@ -35429,6 +35588,7 @@ function normalizeRelatedEntities(related) {
35429
35588
  }
35430
35589
  function sanitizeSearchFilters(filters) {
35431
35590
  return {
35591
+ mode: filters.mode === "lexical" || filters.mode === "semantic" ? filters.mode : "hybrid",
35432
35592
  query: optionalText2(filters.query, 300) ?? void 0,
35433
35593
  entityType: filters.entityType ? normalizeEntityType(filters.entityType) : void 0,
35434
35594
  tag: optionalText2(filters.tag, 80) ?? void 0,
@@ -35702,6 +35862,97 @@ var CommonsRepositoryError = class extends Error {
35702
35862
 
35703
35863
  // src/api/commons-publication-repository.ts
35704
35864
  import { createHash as createHash16, randomUUID as randomUUID18 } from "crypto";
35865
+
35866
+ // src/editorial-reading-room/article-page.ts
35867
+ function escapeHtml6(value) {
35868
+ return String(value ?? "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
35869
+ }
35870
+ function articlePath(origin, slug4) {
35871
+ return `${origin.replace(/\/+$/, "")}/${encodeURIComponent(slug4)}`;
35872
+ }
35873
+ function renderEditorialArticlePage(input) {
35874
+ const articles = renderEditorialArticleModels(input.edition);
35875
+ const index = articles.findIndex((article2) => article2.slug === input.articleSlug);
35876
+ if (index === -1) return null;
35877
+ const article = articles[index];
35878
+ const previous = index > 0 ? articles[index - 1] : null;
35879
+ const next = index < articles.length - 1 ? articles[index + 1] : null;
35880
+ const canonicalUrl = articlePath(input.origin, article.slug);
35881
+ const site = input.edition.site;
35882
+ const description = article.summary || input.edition.deck || site.title;
35883
+ const jsonLd = JSON.stringify({
35884
+ "@context": "https://schema.org",
35885
+ "@type": "Article",
35886
+ "@id": `${canonicalUrl}#article`,
35887
+ headline: article.title,
35888
+ description,
35889
+ articleSection: article.category,
35890
+ wordCount: article.wordCount,
35891
+ url: canonicalUrl,
35892
+ isPartOf: { "@type": "CollectionPage", "@id": `${input.editionUrl}#collection`, name: site.title, url: input.editionUrl },
35893
+ publisher: { "@type": "Organization", name: input.publicationTitle, url: input.origin }
35894
+ }).replace(/</g, "\\u003c");
35895
+ const jumps = article.toc.length ? `<nav class="article-jumps" aria-label="On this page">${article.toc.map((item) => `<a href="#${escapeHtml6(item.id)}">${escapeHtml6(item.title)}</a>`).join("")}</nav>` : "";
35896
+ const neighbour = (item, label) => item ? `<a class="neighbour" href="${escapeHtml6(articlePath(input.origin, item.slug))}"><span>${label}</span><strong>${escapeHtml6(item.title)}</strong></a>` : "";
35897
+ const html = `<!doctype html>
35898
+ <html lang="en">
35899
+ <head>
35900
+ <meta charset="utf-8">
35901
+ <meta name="viewport" content="width=device-width, initial-scale=1">
35902
+ <title>${escapeHtml6(article.title)} \u2014 ${escapeHtml6(input.publicationTitle)}</title>
35903
+ <meta name="description" content="${escapeHtml6(description)}">
35904
+ <link rel="canonical" href="${escapeHtml6(canonicalUrl)}">
35905
+ <meta property="og:type" content="article">
35906
+ <meta property="og:title" content="${escapeHtml6(article.title)}">
35907
+ <meta property="og:description" content="${escapeHtml6(description)}">
35908
+ <meta property="og:url" content="${escapeHtml6(canonicalUrl)}">
35909
+ <meta property="og:site_name" content="${escapeHtml6(input.publicationTitle)}">
35910
+ <meta name="twitter:card" content="summary_large_image">
35911
+ <meta name="twitter:title" content="${escapeHtml6(article.title)}">
35912
+ <meta name="twitter:description" content="${escapeHtml6(description)}">
35913
+ <script type="application/ld+json">${jsonLd}</script>
35914
+ <style>
35915
+ :root{color-scheme:light dark;--ink:#12171f;--muted:#5b6672;--rule:#dfe4ea;--bg:#fbfbfa;--accent:#8a6a2f}
35916
+ *{box-sizing:border-box}
35917
+ body{margin:0;background:var(--bg);color:var(--ink);font:17px/1.65 Georgia,"Times New Roman",serif}
35918
+ a{color:inherit}
35919
+ header.masthead{border-bottom:1px solid var(--rule);padding:18px 20px}
35920
+ 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)}
35921
+ main{max-width:44rem;margin:0 auto;padding:34px 20px 64px}
35922
+ .kicker{font:600 12px/1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.1em;text-transform:uppercase;color:var(--accent)}
35923
+ h1{font-size:2.1rem;line-height:1.18;margin:12px 0 10px}
35924
+ .summary{color:var(--muted);font-size:1.06rem;margin:0 0 18px}
35925
+ .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}
35926
+ .article-jumps{display:flex;flex-wrap:wrap;gap:10px;margin:0 0 26px}
35927
+ .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}
35928
+ article h2{font-size:1.4rem;margin:32px 0 10px}
35929
+ article h3{font-size:1.15rem;margin:24px 0 8px}
35930
+ article p{margin:0 0 17px}
35931
+ .neighbours{display:grid;gap:12px;margin-top:44px;padding-top:22px;border-top:1px solid var(--rule)}
35932
+ .neighbour{display:block;text-decoration:none;border:1px solid var(--rule);border-radius:10px;padding:13px 15px;background:#fff}
35933
+ .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}
35934
+ 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}
35935
+ @media (prefers-color-scheme:dark){:root{--ink:#eef1f5;--muted:#9aa4b1;--rule:#2b323b;--bg:#12151a}.neighbour{background:#171b21}}
35936
+ </style>
35937
+ </head>
35938
+ <body>
35939
+ <header class="masthead"><a href="${escapeHtml6(input.origin)}">${escapeHtml6(input.publicationTitle)}</a></header>
35940
+ <main>
35941
+ <p class="kicker">${escapeHtml6(article.kicker || article.category)}</p>
35942
+ <h1>${escapeHtml6(article.title)}</h1>
35943
+ <p class="summary">${escapeHtml6(article.summary)}</p>
35944
+ <p class="meta">${escapeHtml6(article.category)} \xB7 ${article.wordCount} words \xB7 ${article.readingMinutes} min \xB7 <a href="${escapeHtml6(input.editionUrl)}">${escapeHtml6(site.title)}</a></p>
35945
+ ${jumps}
35946
+ <article>${article.html}</article>
35947
+ <div class="neighbours">${neighbour(previous, "Previous")}${neighbour(next, "Next")}</div>
35948
+ </main>
35949
+ <footer>${escapeHtml6(input.publicationTitle)} \xB7 <a href="${escapeHtml6(input.editionUrl)}">All articles in ${escapeHtml6(site.title)}</a></footer>
35950
+ </body>
35951
+ </html>`;
35952
+ return { html, article, canonicalUrl };
35953
+ }
35954
+
35955
+ // src/api/commons-publication-repository.ts
35705
35956
  var PUBLICATION_ROOT_DOMAIN = process.env.COMMONS_PUBLICATION_ROOT_DOMAIN || "transparent-commons.cc";
35706
35957
  var RESERVED_SUBDOMAINS = /* @__PURE__ */ new Set([
35707
35958
  "admin",
@@ -36032,6 +36283,20 @@ async function listCommonsPublicationEditions(publicationId) {
36032
36283
  if (!publication) return [];
36033
36284
  return result.rows.map((row) => rowToEdition(row, publication.subdomain));
36034
36285
  }
36286
+ async function getCommonsPublicationArticleHtml(subdomainInput, articleSlug, editionSlugInput) {
36287
+ const found = await getCommonsPublicationEditionHtml(subdomainInput, editionSlugInput);
36288
+ if (!found) return null;
36289
+ const { publication, edition } = found;
36290
+ const page = renderEditorialArticlePage({
36291
+ edition: { site: edition.site, deck: edition.deck, articles: edition.articles },
36292
+ articleSlug,
36293
+ origin: publicationPublicUrl(publication.subdomain),
36294
+ editionUrl: editionPublicUrl(publication.subdomain, edition.editionSlug),
36295
+ publicationTitle: publication.title
36296
+ });
36297
+ if (!page) return null;
36298
+ return { publication, edition, html: page.html, canonicalUrl: page.canonicalUrl };
36299
+ }
36035
36300
  async function getCommonsPublicationEditionHtml(subdomainInput, editionSlugInput) {
36036
36301
  const publication = await getCommonsPublicationBySubdomain(subdomainInput);
36037
36302
  if (!publication) return null;
@@ -36177,6 +36442,7 @@ function addPublicMetadata(html, canonicalUrl, publicationTitle) {
36177
36442
  var commonsApp = new Hono31();
36178
36443
  var auth2 = createApiKeyAuth();
36179
36444
  var SearchBodySchema = z32.object({
36445
+ mode: z32.enum(["lexical", "semantic", "hybrid"]).optional(),
36180
36446
  query: z32.string().max(300).optional(),
36181
36447
  entityType: z32.string().max(120).optional(),
36182
36448
  tag: z32.string().max(80).optional(),
@@ -36340,6 +36606,14 @@ var ValidatePublicationSchema = z32.object(CommonsValidatePublicationInputSchema
36340
36606
  var ClaimPublicationSchema = z32.object(CommonsClaimPublicationInputSchema).strict();
36341
36607
  var PublishEditorialSchema = z32.object(CommonsPublishEditorialInputSchema).strict();
36342
36608
  var UpdateEditorialArticleSchema = z32.object(CommonsUpdateEditorialArticleInputSchema).strict();
36609
+ commonsApp.post("/index/embed", auth2, async (c) => {
36610
+ const body = await c.req.json().catch(() => ({}));
36611
+ const result = await embedQueuedCommonsDocuments(Number(body.limit) || 50);
36612
+ return c.json({ ok: true, data: result });
36613
+ });
36614
+ commonsApp.get("/index/status", auth2, async (c) => {
36615
+ return c.json({ ok: true, data: { queued: await queuedCommonsDocumentCount(), semanticSearchConfigured: commonsSemanticSearchConfigured() } });
36616
+ });
36343
36617
  commonsApp.get("/health", async (c) => {
36344
36618
  await ensureCommonsSchema();
36345
36619
  return c.json({ ok: true, data: commonsDatabaseReport() });
@@ -36398,6 +36672,28 @@ commonsApp.get("/publications/:subdomain/site", async (c) => {
36398
36672
  return publicationError(c, error);
36399
36673
  }
36400
36674
  });
36675
+ commonsApp.get("/publications/:subdomain/articles/:articleSlug/site", async (c) => {
36676
+ try {
36677
+ const result = await getCommonsPublicationArticleHtml(c.req.param("subdomain"), c.req.param("articleSlug"));
36678
+ if (!result) return c.json({ ok: false, error: "article_not_found", message: "No published article matched that publication and slug." }, 404);
36679
+ return c.html(result.html, 200, {
36680
+ "cache-control": "public, max-age=60, s-maxage=300",
36681
+ "x-robots-tag": "index, follow",
36682
+ link: `<${result.canonicalUrl}>; rel="canonical"`
36683
+ });
36684
+ } catch (error) {
36685
+ return publicationError(c, error);
36686
+ }
36687
+ });
36688
+ commonsApp.get("/publications/:subdomain/editions/:editionSlug/articles/:articleSlug/site", async (c) => {
36689
+ try {
36690
+ const result = await getCommonsPublicationArticleHtml(c.req.param("subdomain"), c.req.param("articleSlug"), c.req.param("editionSlug"));
36691
+ if (!result) return c.json({ ok: false, error: "article_not_found", message: "No published article matched that publication, edition, and slug." }, 404);
36692
+ return c.html(result.html, 200, { "cache-control": "public, max-age=60, s-maxage=300", "x-robots-tag": "index, follow" });
36693
+ } catch (error) {
36694
+ return publicationError(c, error);
36695
+ }
36696
+ });
36401
36697
  commonsApp.get("/publications/:subdomain/editions/:editionSlug/site", async (c) => {
36402
36698
  try {
36403
36699
  const result = await getCommonsPublicationEditionHtml(c.req.param("subdomain"), c.req.param("editionSlug"));
@@ -36600,6 +36896,7 @@ ${urls.join("\n")}
36600
36896
  });
36601
36897
  function filtersFromQuery(query) {
36602
36898
  return {
36899
+ mode: query.mode === "lexical" || query.mode === "semantic" ? query.mode : void 0,
36603
36900
  query: query.query || query.q,
36604
36901
  entityType: query.entityType,
36605
36902
  tag: query.tag,
@@ -37249,7 +37546,7 @@ function pixelSnippet(publicId) {
37249
37546
  function formSnippet(publicId) {
37250
37547
  return `<div data-mcp-form="${publicId}"></div><script async src="https://mcpscraper.dev/analytics/v1/form.js?form=${publicId}"></script>`;
37251
37548
  }
37252
- function escapeHtml6(value) {
37549
+ function escapeHtml7(value) {
37253
37550
  return String(value ?? "").replace(
37254
37551
  /[&<>"']/g,
37255
37552
  (character) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[character]
@@ -37261,13 +37558,13 @@ function renderPublicForm(form, placementUrl) {
37261
37558
  const fields = form.fields.map((field) => {
37262
37559
  const required = field.required ? " required" : "";
37263
37560
  const options = (field.options ?? []).map(
37264
- (option) => `<option value="${escapeHtml6(option)}">${escapeHtml6(option)}</option>`
37561
+ (option) => `<option value="${escapeHtml7(option)}">${escapeHtml7(option)}</option>`
37265
37562
  ).join("");
37266
- const control = field.type === "textarea" ? `<textarea id="${escapeHtml6(field.id)}" name="${escapeHtml6(field.id)}"${required}></textarea>` : field.type === "select" ? `<select id="${escapeHtml6(field.id)}" name="${escapeHtml6(field.id)}"${required}><option value="">Choose\u2026</option>${options}</select>` : field.type === "checkbox" ? `<input id="${escapeHtml6(field.id)}" name="${escapeHtml6(field.id)}" type="checkbox" value="true"${required}>` : `<input id="${escapeHtml6(field.id)}" name="${escapeHtml6(field.id)}" type="${escapeHtml6(field.type)}"${required}>`;
37267
- return `<label${field.type === "checkbox" ? ' class="check"' : ""}><span>${escapeHtml6(field.label)}${field.required ? " *" : ""}</span>${control}</label>`;
37563
+ 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}>`;
37564
+ return `<label${field.type === "checkbox" ? ' class="check"' : ""}><span>${escapeHtml7(field.label)}${field.required ? " *" : ""}</span>${control}</label>`;
37268
37565
  }).join("");
37269
37566
  const brand = form.brand;
37270
- 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:${escapeHtml6(brand.textColor)};background:${escapeHtml6(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:${escapeHtml6(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">${escapeHtml6(form.consent_text)}</p>` : ""}<button>${escapeHtml6(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/${escapeHtml6(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>`;
37567
+ 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>`;
37271
37568
  }
37272
37569
  analyticsApp.get(
37273
37570
  "/health/live",
@@ -38523,7 +38820,7 @@ async function revokeScheduledRunViewLink(ownerId, runId, shareId, now = /* @__P
38523
38820
 
38524
38821
  // src/personal-authority/render.ts
38525
38822
  import { createHash as createHash21 } from "crypto";
38526
- function escapeHtml7(value) {
38823
+ function escapeHtml8(value) {
38527
38824
  return value.replace(/[&<>"']/g, (character) => ({
38528
38825
  "&": "&amp;",
38529
38826
  "<": "&lt;",
@@ -38534,13 +38831,13 @@ function escapeHtml7(value) {
38534
38831
  }
38535
38832
  function safeHref(value) {
38536
38833
  const trimmed = value.trim();
38537
- return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml7(trimmed) : "#";
38834
+ return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml8(trimmed) : "#";
38538
38835
  }
38539
38836
  function initials(name) {
38540
38837
  return name.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]?.toUpperCase()).join("") || "PA";
38541
38838
  }
38542
38839
  function action(action3, secondary = false) {
38543
- return `<a class="button${secondary ? " button--secondary" : ""}" href="${safeHref(action3.href)}">${escapeHtml7(action3.label)} <span aria-hidden="true">\u2197</span></a>`;
38840
+ return `<a class="button${secondary ? " button--secondary" : ""}" href="${safeHref(action3.href)}">${escapeHtml8(action3.label)} <span aria-hidden="true">\u2197</span></a>`;
38544
38841
  }
38545
38842
  function section(enabled, html) {
38546
38843
  return enabled ? html : "";
@@ -38549,7 +38846,7 @@ function renderPersonalAuthorityV1(input, config, generatedAt) {
38549
38846
  const flags = config.featureFlags;
38550
38847
  const brand = config.brandName || input.name;
38551
38848
  const generatedAtIso = generatedAt.toISOString();
38552
- const social = flags.socialLinks && input.socialLinks.length > 0 ? `<nav class="social" aria-label="Professional profiles">${input.socialLinks.map((link) => `<a href="${safeHref(link.href)}">${escapeHtml7(link.label)}</a>`).join("")}</nav>` : "";
38849
+ const social = flags.socialLinks && input.socialLinks.length > 0 ? `<nav class="social" aria-label="Professional profiles">${input.socialLinks.map((link) => `<a href="${safeHref(link.href)}">${escapeHtml8(link.label)}</a>`).join("")}</nav>` : "";
38553
38850
  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>` : "";
38554
38851
  const authority = input.authority;
38555
38852
  const consultation = input.consultation;
@@ -38561,21 +38858,21 @@ function renderPersonalAuthorityV1(input, config, generatedAt) {
38561
38858
  <html lang="en" data-theme="${config.theme}">
38562
38859
  <head>
38563
38860
  <meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
38564
- <meta name="description" content="${escapeHtml7(input.summary)}"><title>${escapeHtml7(input.name)} \u2014 ${escapeHtml7(input.professionalTitle)}</title>
38861
+ <meta name="description" content="${escapeHtml8(input.summary)}"><title>${escapeHtml8(input.name)} \u2014 ${escapeHtml8(input.professionalTitle)}</title>
38565
38862
  <style>
38566
38863
  :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)}
38567
38864
  @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}}
38568
38865
  </style></head>
38569
38866
  <body><a class="skip" href="#main">Skip to main content</a>
38570
- <header class="header"><a class="brand" href="#top"><span class="mark">${escapeHtml7(initials(input.name).slice(0, 1))}</span><strong>${escapeHtml7(brand)}</strong></a>${navigation}</header>
38571
- <main id="main"><section class="hero" id="top"><div class="portrait" aria-label="Portrait placeholder"><div class="portrait-card" aria-hidden="true">${escapeHtml7(initials(input.name))}</div></div><div class="hero-copy"><h1>${escapeHtml7(input.name)}</h1><p class="role">${escapeHtml7(input.professionalTitle)}</p><p class="summary">${escapeHtml7(input.summary)}</p><div class="actions">${action(input.primaryAction)}${input.secondaryAction ? action(input.secondaryAction, true) : ""}</div>${social}</div></section>
38572
- ${section(flags.authority && Boolean(authority), `<section class="light" id="about"><h2>${escapeHtml7(authority?.heading ?? "")}</h2>${authority?.paragraphs.map((paragraph) => `<p>${escapeHtml7(paragraph)}</p>`).join("") ?? ""}</section>`)}
38573
- ${section(flags.consultation && Boolean(consultation), `<section class="section consult"><div><p class="eyebrow">${escapeHtml7(consultation?.eyebrow ?? "Start a conversation")}</p><h2>${escapeHtml7(consultation?.heading ?? "")}</h2><p class="summary">${escapeHtml7(consultation?.summary ?? "")}</p>${consultation ? action(consultation.action) : ""}</div><div class="accent-card" aria-label="Image placeholder">${escapeHtml7(initials(input.name))}</div></section>`)}
38574
- ${section(flags.learning && Boolean(learning), `<section class="section learning"><div class="section-head"><h2>${escapeHtml7(learning?.heading ?? "")}</h2><p class="summary">${escapeHtml7(learning?.summary ?? "")}</p></div><div class="topic-grid">${learning?.topics.map((topic) => `<article class="topic"><strong>${escapeHtml7(topic.title)}</strong><h3>${escapeHtml7(topic.headline)}</h3><p>${escapeHtml7(topic.summary)}</p>${topic.href ? `<a href="${safeHref(topic.href)}">Explore \u2192</a>` : ""}</article>`).join("") ?? ""}</div></section>`)}
38575
- ${section(flags.services && Boolean(services), `<section class="section" id="services"><div class="section-head"><h2>${escapeHtml7(services?.heading ?? "")}</h2><p class="summary">${escapeHtml7(services?.summary ?? "")}</p></div><div class="grid">${services?.offers.map((offer) => `<article class="card"><h3>${escapeHtml7(offer.title)}</h3><p>${escapeHtml7(offer.description)}</p>${offer.action ? action(offer.action, true) : ""}</article>`).join("") ?? ""}</div></section>`)}
38576
- ${section(flags.proof && Boolean(proof), `<section class="section proof" id="proof"><div class="section-head"><h2>${escapeHtml7(proof?.heading ?? "")}</h2><p class="summary">${escapeHtml7(proof?.summary ?? "")}</p></div><div class="quotes">${proof?.testimonials.map((item) => `<article class="quote"><q>${escapeHtml7(item.quote)}</q><span>${escapeHtml7(item.person)}${item.role ? ` / ${escapeHtml7(item.role)}` : ""}</span></article>`).join("") ?? ""}</div></section>`)}
38577
- ${section(flags.finalCta && Boolean(finalCta), `<section class="section cta" id="contact"><p class="eyebrow">${escapeHtml7(finalCta?.eyebrow ?? "Ready when you are")}</p><h2>${escapeHtml7(finalCta?.heading ?? "")}</h2><p class="summary">${escapeHtml7(finalCta?.summary ?? "")}</p>${finalCta ? action(finalCta.action) : ""}</section>`)}
38578
- </main><footer class="footer"><div><strong>${escapeHtml7(input.name)}</strong><div>${escapeHtml7(input.professionalTitle)}</div>${config.showGeneratedAt ? `<div class="generated">Generated ${escapeHtml7(generatedAtIso)}</div>` : ""}</div><div>${input.location ? `<div>${escapeHtml7(input.location)}</div>` : ""}${input.email ? `<a href="mailto:${escapeHtml7(input.email)}">${escapeHtml7(input.email)}</a>` : ""}${input.phone ? `<div>${escapeHtml7(input.phone)}</div>` : ""}</div></footer>
38867
+ <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>
38868
+ <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>
38869
+ ${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>`)}
38870
+ ${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>`)}
38871
+ ${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>`)}
38872
+ ${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>`)}
38873
+ ${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>`)}
38874
+ ${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>`)}
38875
+ </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>
38579
38876
  <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>`;
38580
38877
  const bytes = Buffer.byteLength(html, "utf8");
38581
38878
  return {
@@ -38594,7 +38891,7 @@ var FONT_STACKS = Object.freeze({
38594
38891
  "modern-sans": "Avenir Next, Avenir, Helvetica Neue, Arial, sans-serif",
38595
38892
  "humanist-sans": "Optima, Candara, Segoe UI, sans-serif"
38596
38893
  });
38597
- function escapeHtml8(value) {
38894
+ function escapeHtml9(value) {
38598
38895
  return value.replace(
38599
38896
  /[&<>"']/g,
38600
38897
  (character) => ({
@@ -38608,13 +38905,13 @@ function escapeHtml8(value) {
38608
38905
  }
38609
38906
  function safeHref2(value) {
38610
38907
  const trimmed = value.trim();
38611
- return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml8(trimmed) : "#";
38908
+ return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml9(trimmed) : "#";
38612
38909
  }
38613
38910
  function initials2(name) {
38614
38911
  return name.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]?.toUpperCase()).join("") || "PA";
38615
38912
  }
38616
38913
  function action2(action3, secondary = false) {
38617
- return `<a class="button${secondary ? " button--secondary" : ""}" href="${safeHref2(action3.href)}">${escapeHtml8(action3.label)} <span aria-hidden="true">\u2197</span></a>`;
38914
+ return `<a class="button${secondary ? " button--secondary" : ""}" href="${safeHref2(action3.href)}">${escapeHtml9(action3.label)} <span aria-hidden="true">\u2197</span></a>`;
38618
38915
  }
38619
38916
  function section2(enabled, html) {
38620
38917
  return enabled ? html : "";
@@ -38658,7 +38955,7 @@ function renderPersonalAuthorityV2(input, config, generatedAt) {
38658
38955
  const surfaceContrast = bestContrastTextColor(colors.surface);
38659
38956
  const accentChannels = hexChannels(colors.accent);
38660
38957
  const generatedAtIso = generatedAt.toISOString();
38661
- const social = flags.socialLinks && input.socialLinks.length > 0 ? `<nav class="social" aria-label="Professional profiles">${input.socialLinks.map((link) => `<a href="${safeHref2(link.href)}">${escapeHtml8(link.label)}</a>`).join("")}</nav>` : "";
38958
+ const social = flags.socialLinks && input.socialLinks.length > 0 ? `<nav class="social" aria-label="Professional profiles">${input.socialLinks.map((link) => `<a href="${safeHref2(link.href)}">${escapeHtml9(link.label)}</a>`).join("")}</nav>` : "";
38662
38959
  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>` : "";
38663
38960
  const authority = input.authority;
38664
38961
  const consultation = input.consultation;
@@ -38670,22 +38967,22 @@ function renderPersonalAuthorityV2(input, config, generatedAt) {
38670
38967
  <html lang="en" data-theme="${config.theme}">
38671
38968
  <head>
38672
38969
  <meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
38673
- <meta name="description" content="${escapeHtml8(input.summary)}"><title>${escapeHtml8(input.name)} - ${escapeHtml8(input.professionalTitle)}</title>
38970
+ <meta name="description" content="${escapeHtml9(input.summary)}"><title>${escapeHtml9(input.name)} - ${escapeHtml9(input.professionalTitle)}</title>
38674
38971
  <style>
38675
38972
  :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)}
38676
38973
  @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}}
38677
38974
  @media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}.button{transition:none}}
38678
38975
  </style></head>
38679
38976
  <body><a class="skip" href="#main">Skip to main content</a>
38680
- <header class="header"><a class="brand" href="#top"><span class="mark">${escapeHtml8(initials2(input.name).slice(0, 1))}</span><strong>${escapeHtml8(brand)}</strong></a>${navigation}</header>
38681
- <main id="main"><section class="hero" id="top"><div class="portrait" aria-label="Portrait placeholder"><div class="portrait-card" aria-hidden="true">${escapeHtml8(initials2(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">${action2(input.primaryAction)}${input.secondaryAction ? action2(input.secondaryAction, true) : ""}</div>${social}</div></section>
38682
- ${section2(flags.authority && Boolean(authority), `<section class="light" id="about"><h2>${escapeHtml8(authority?.heading ?? "")}</h2>${authority?.paragraphs.map((paragraph) => `<p>${escapeHtml8(paragraph)}</p>`).join("") ?? ""}</section>`)}
38683
- ${section2(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 ? action2(consultation.action) : ""}</div><div class="accent-card" aria-label="Image placeholder">${escapeHtml8(initials2(input.name))}</div></section>`)}
38684
- ${section2(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="${safeHref2(topic.href)}">Explore \u2192</a>` : ""}</article>`).join("") ?? ""}</div></section>`)}
38685
- ${section2(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 ? action2(offer.action, true) : ""}</article>`).join("") ?? ""}</div></section>`)}
38686
- ${section2(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>`)}
38687
- ${section2(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 ? action2(finalCta.action) : ""}</section>`)}
38688
- </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>
38977
+ <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>
38978
+ <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>
38979
+ ${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>`)}
38980
+ ${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>`)}
38981
+ ${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>`)}
38982
+ ${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>`)}
38983
+ ${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>`)}
38984
+ ${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>`)}
38985
+ </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>
38689
38986
  <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>`;
38690
38987
  const bytes = Buffer.byteLength(html, "utf8");
38691
38988
  return {
@@ -38699,7 +38996,7 @@ ${section2(flags.finalCta && Boolean(finalCta), `<section class="section cta" id
38699
38996
 
38700
38997
  // src/newsroom-publisher/render.ts
38701
38998
  import { createHash as createHash23 } from "crypto";
38702
- function escapeHtml9(value) {
38999
+ function escapeHtml10(value) {
38703
39000
  return value.replace(/[&<>"']/g, (character) => ({
38704
39001
  "&": "&amp;",
38705
39002
  "<": "&lt;",
@@ -38710,30 +39007,30 @@ function escapeHtml9(value) {
38710
39007
  }
38711
39008
  function safeHref3(value) {
38712
39009
  const trimmed = value.trim();
38713
- return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml9(trimmed) : "#";
39010
+ return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml10(trimmed) : "#";
38714
39011
  }
38715
39012
  function formatDate(value) {
38716
39013
  const date = new Date(value);
38717
- return Number.isNaN(date.getTime()) ? escapeHtml9(value) : new Intl.DateTimeFormat("en", { month: "short", day: "numeric", year: "numeric" }).format(date);
39014
+ return Number.isNaN(date.getTime()) ? escapeHtml10(value) : new Intl.DateTimeFormat("en", { month: "short", day: "numeric", year: "numeric" }).format(date);
38718
39015
  }
38719
39016
  function initials3(value) {
38720
39017
  return value.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]).join("").toUpperCase();
38721
39018
  }
38722
39019
  function storyMedia(story, className = "") {
38723
39020
  if (story.imageUrl) {
38724
- return `<div class="story-media ${className}"><img src="${safeHref3(story.imageUrl)}" alt="${escapeHtml9(story.imageAlt || story.title)}" loading="lazy"></div>`;
39021
+ return `<div class="story-media ${className}"><img src="${safeHref3(story.imageUrl)}" alt="${escapeHtml10(story.imageAlt || story.title)}" loading="lazy"></div>`;
38725
39022
  }
38726
39023
  const tone = [...story.title].reduce((total, character) => total + character.charCodeAt(0), 0) % 5;
38727
- return `<div class="story-media story-media--placeholder story-media--tone-${tone} ${className}" role="img" aria-label="Editorial image placeholder for ${escapeHtml9(story.title)}"><i></i><b></b><span>${escapeHtml9(story.category)}</span></div>`;
39024
+ return `<div class="story-media story-media--placeholder story-media--tone-${tone} ${className}" role="img" aria-label="Editorial image placeholder for ${escapeHtml10(story.title)}"><i></i><b></b><span>${escapeHtml10(story.category)}</span></div>`;
38728
39025
  }
38729
39026
  function byline(story, showBylines) {
38730
- const author = story.author.href ? `<a href="${safeHref3(story.author.href)}">${escapeHtml9(story.author.name)}</a>` : escapeHtml9(story.author.name);
38731
- return `<div class="byline">${showBylines ? `<span>By ${author}</span>` : ""}<time datetime="${escapeHtml9(story.publishedAt)}">${formatDate(story.publishedAt)}</time>${story.sponsored ? "<b>Sponsored</b>" : ""}</div>`;
39027
+ const author = story.author.href ? `<a href="${safeHref3(story.author.href)}">${escapeHtml10(story.author.name)}</a>` : escapeHtml10(story.author.name);
39028
+ return `<div class="byline">${showBylines ? `<span>By ${author}</span>` : ""}<time datetime="${escapeHtml10(story.publishedAt)}">${formatDate(story.publishedAt)}</time>${story.sponsored ? "<b>Sponsored</b>" : ""}</div>`;
38732
39029
  }
38733
39030
  function storyCard(story, showBylines, variant = "") {
38734
39031
  return `<article class="story-card ${variant}">
38735
39032
  <a class="story-card__media" href="${safeHref3(story.href)}">${storyMedia(story)}</a>
38736
- <div class="story-card__body"><a class="kicker" href="${safeHref3(story.href)}">${escapeHtml9(story.category)}</a><h3><a href="${safeHref3(story.href)}">${escapeHtml9(story.title)}</a></h3>${story.dek ? `<p>${escapeHtml9(story.dek)}</p>` : ""}${byline(story, showBylines)}</div>
39033
+ <div class="story-card__body"><a class="kicker" href="${safeHref3(story.href)}">${escapeHtml10(story.category)}</a><h3><a href="${safeHref3(story.href)}">${escapeHtml10(story.title)}</a></h3>${story.dek ? `<p>${escapeHtml10(story.dek)}</p>` : ""}${byline(story, showBylines)}</div>
38737
39034
  </article>`;
38738
39035
  }
38739
39036
  function renderNewsroomPublisherV1(input, config, generatedAt) {
@@ -38750,22 +39047,22 @@ function renderNewsroomPublisherV1(input, config, generatedAt) {
38750
39047
  input.primaryPages.contact
38751
39048
  ];
38752
39049
  const trustPages = Object.values(input.trustPages);
38753
- const ticker = flags.breakingTicker && input.ticker ? `<div class="ticker"><div><b>${escapeHtml9(input.ticker.label)}</b><a href="${safeHref3(input.ticker.href || "#latest")}">${escapeHtml9(input.ticker.headline)}</a><span>${formatDate(generatedAtIso)}</span></div></div>` : "";
38754
- const masthead = `<nav class="utility-nav" aria-label="Publication pages"><div><span>${escapeHtml9(input.publication.location || "Independent newsroom")}</span>${primaryPages.slice(1).map((link) => `<a href="${safeHref3(link.href)}">${escapeHtml9(link.label)}</a>`).join("")}</div></nav><header class="masthead">
38755
- <a class="wordmark" href="${safeHref3(input.publication.url)}"><span>${escapeHtml9(brand)}</span><small>${escapeHtml9(input.publication.tagline)}</small></a>
39050
+ 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>` : "";
39051
+ const masthead = `<nav class="utility-nav" aria-label="Publication pages"><div><span>${escapeHtml10(input.publication.location || "Independent newsroom")}</span>${primaryPages.slice(1).map((link) => `<a href="${safeHref3(link.href)}">${escapeHtml10(link.label)}</a>`).join("")}</div></nav><header class="masthead">
39052
+ <a class="wordmark" href="${safeHref3(input.publication.url)}"><span>${escapeHtml10(brand)}</span><small>${escapeHtml10(input.publication.tagline)}</small></a>
38756
39053
  <div class="masthead__date"><span>Independent journalism</span><time datetime="${generatedAtIso}">${formatDate(generatedAtIso)}</time></div>
38757
39054
  <div class="masthead__tools"><button type="button" aria-label="Search">Search</button><button type="button" aria-label="Open menu">Menu</button></div>
38758
39055
  </header>`;
38759
- 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)}">${escapeHtml9(category.label)}</a>`).join("")}<a class="desk-nav__latest" href="#latest">Latest</a></div></nav>` : "";
39056
+ 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>` : "";
38760
39057
  const leadGrid = flags.leadGrid ? `<section class="lead-grid" aria-label="Top stories">
38761
39058
  <div class="lead-grid__label"><span>Today\u2019s edition</span><b>Top stories</b></div>
38762
- <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)}">${escapeHtml9(lead.category)}</a><h1><a href="${safeHref3(lead.href)}">${escapeHtml9(lead.title)}</a></h1>${lead.dek ? `<p>${escapeHtml9(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>
39059
+ <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>
38763
39060
  <div class="lead-support">${supporting.slice(0, 4).map((story, index) => `<div class="lead-support__item"><span>${String(index + 1).padStart(2, "0")}</span>${storyCard(story, config.showBylines, "story-card--support")}</div>`).join("")}</div>
38764
39061
  </section>` : "";
38765
39062
  const latest = flags.latestNews && input.latest.length > 0 ? `<section class="latest" id="latest">
38766
39063
  <div class="section-title"><div><span>Live desk</span><h2>Latest news</h2></div><a href="#top">Back to top \u2191</a></div>
38767
- <div class="latest__layout"><div class="latest__feed">${input.latest.map((story, index) => `<article class="feed-story"><span>${String(index + 1).padStart(2, "0")}</span><div><a class="kicker" href="${safeHref3(story.href)}">${escapeHtml9(story.category)}</a><h3><a href="${safeHref3(story.href)}">${escapeHtml9(story.title)}</a></h3>${story.dek ? `<p>${escapeHtml9(story.dek)}</p>` : ""}${byline(story, config.showBylines)}</div>${storyMedia(story, "story-media--feed")}</article>`).join("")}</div>
38768
- <aside class="editor-note"><span>From the newsroom</span><h3>Reporting with context, sources, and accountable bylines.</h3><p>${escapeHtml9(input.editorial.disclosure)}</p>${trustPages.slice(0, 4).map((link) => `<a href="${safeHref3(link.href)}">${escapeHtml9(link.label)} \u2197</a>`).join("")}</aside></div>
39064
+ <div class="latest__layout"><div class="latest__feed">${input.latest.map((story, index) => `<article class="feed-story"><span>${String(index + 1).padStart(2, "0")}</span><div><a class="kicker" href="${safeHref3(story.href)}">${escapeHtml10(story.category)}</a><h3><a href="${safeHref3(story.href)}">${escapeHtml10(story.title)}</a></h3>${story.dek ? `<p>${escapeHtml10(story.dek)}</p>` : ""}${byline(story, config.showBylines)}</div>${storyMedia(story, "story-media--feed")}</article>`).join("")}</div>
39065
+ <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((link) => `<a href="${safeHref3(link.href)}">${escapeHtml10(link.label)} \u2197</a>`).join("")}</aside></div>
38769
39066
  </section>` : "";
38770
39067
  const sectionLayouts = ["panorama", "mosaic", "tiles"];
38771
39068
  const sections = flags.categorySections ? input.sections.map((section3, sectionIndex) => {
@@ -38776,16 +39073,16 @@ function renderNewsroomPublisherV1(input, config, generatedAt) {
38776
39073
  layout === "panorama" && index === 0 ? "story-card--panorama" : layout === "mosaic" && index === 0 ? "story-card--mosaic-lead" : ""
38777
39074
  )).join("");
38778
39075
  return `<section class="desk-section desk-section--${sectionIndex % 2 ? "tint" : "plain"} desk-section--layout-${layout}">
38779
- <div class="section-title"><div><span>Coverage desk \xB7 ${String(sectionIndex + 1).padStart(2, "0")}</span><h2>${escapeHtml9(section3.name)}</h2></div>${section3.href ? `<a href="${safeHref3(section3.href)}">View all ${escapeHtml9(section3.name)} \u2192</a>` : ""}</div>
39076
+ <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>
38780
39077
  <div class="desk-section__grid desk-section__grid--${layout}">${cards}</div>
38781
39078
  </section>`;
38782
39079
  }).join("") : "";
38783
- const newsletter = flags.newsletter && input.newsletter ? `<section class="newsletter"><div><span>${escapeHtml9(input.newsletter.eyebrow || "Reader briefing")}</span><h2>${escapeHtml9(input.newsletter.heading)}</h2><p>${escapeHtml9(input.newsletter.summary)}</p></div><a href="${safeHref3(input.newsletter.action.href)}">${escapeHtml9(input.newsletter.action.label)} \u2192</a></section>` : "";
38784
- 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>${escapeHtml9(input.pressRoom.heading)}</h2><p>${escapeHtml9(input.pressRoom.summary)}</p><a href="${safeHref3(input.pressRoom.action.href)}">${escapeHtml9(input.pressRoom.action.label)} \u2192</a></div><div class="release-list">${input.pressRoom.releases.map((release) => `<article><time datetime="${escapeHtml9(release.publishedAt)}">${formatDate(release.publishedAt)}</time><span>${escapeHtml9(release.originatingCity)}</span><h3><a href="${safeHref3(release.href)}">${escapeHtml9(release.headline)}</a></h3></article>`).join("") || "<p>No releases are currently published.</p>"}</div></section>` : "";
38785
- 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((link, index) => `<a href="${safeHref3(link.href)}"><span>${String(index + 1).padStart(2, "0")}</span><strong>${escapeHtml9(link.label)}</strong><small>Read \u2192</small></a>`).join("")}</div></section>`;
38786
- const trustFooter = flags.trustFooter ? `<footer class="site-footer"><div class="editor"><span class="editor__avatar">${escapeHtml9(initials3(input.editorial.managingEditor.name))}</span><div><small>${escapeHtml9(input.editorial.managingEditor.role)}</small><h2>${input.editorial.managingEditor.href ? `<a href="${safeHref3(input.editorial.managingEditor.href)}">${escapeHtml9(input.editorial.managingEditor.name)}</a>` : escapeHtml9(input.editorial.managingEditor.name)}</h2><p>${escapeHtml9(input.editorial.managingEditor.bio)}</p></div></div><div class="footer-links"><h3>${escapeHtml9(brand)}</h3><p>${escapeHtml9(input.publication.tagline)}</p><nav>${primaryPages.map((link) => `<a href="${safeHref3(link.href)}">${escapeHtml9(link.label)}</a>`).join("")}</nav>${config.showGeneratedAt ? `<time datetime="${generatedAtIso}">Updated ${formatDate(generatedAtIso)}</time>` : ""}</div></footer>` : "";
39080
+ 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>` : "";
39081
+ 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>` : "";
39082
+ 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((link, index) => `<a href="${safeHref3(link.href)}"><span>${String(index + 1).padStart(2, "0")}</span><strong>${escapeHtml10(link.label)}</strong><small>Read \u2192</small></a>`).join("")}</div></section>`;
39083
+ 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((link) => `<a href="${safeHref3(link.href)}">${escapeHtml10(link.label)}</a>`).join("")}</nav>${config.showGeneratedAt ? `<time datetime="${generatedAtIso}">Updated ${formatDate(generatedAtIso)}</time>` : ""}</div></footer>` : "";
38787
39084
  const html = `<!doctype html>
38788
- <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>${escapeHtml9(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">
39085
+ <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">
38789
39086
  <style>
38790
39087
  :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}}
38791
39088
  /* Tampa-inspired publication palette */
@@ -38802,7 +39099,7 @@ body{overflow-x:hidden}.lead-story__body,.lead-support__item,.story-card__body{m
38802
39099
  @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)}}
38803
39100
  @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)}}
38804
39101
  @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}}
38805
- </style></head><body data-theme="${escapeHtml9(config.theme)}" id="top" data-scheduled-renderer="newsroom_publisher_v1">${ticker}${masthead}${navigation}<main>${leadGrid}${latest}${sections}${newsletter}${pressRoom}${trustCenter}</main>${trustFooter}</body></html>`;
39102
+ </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>`;
38806
39103
  const bytes = Buffer.byteLength(html);
38807
39104
  const sha2563 = createHash23("sha256").update(html).digest("hex");
38808
39105
  const filename = `${brand.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "newsroom"}-news-site.html`;
@@ -38811,7 +39108,7 @@ body{overflow-x:hidden}.lead-story__body,.lead-support__item,.story-card__body{m
38811
39108
 
38812
39109
  // src/blog-article/render.ts
38813
39110
  import { createHash as createHash24 } from "crypto";
38814
- function escapeHtml10(value) {
39111
+ function escapeHtml11(value) {
38815
39112
  return value.replace(
38816
39113
  /[&<>"']/g,
38817
39114
  (character) => ({
@@ -38825,11 +39122,11 @@ function escapeHtml10(value) {
38825
39122
  }
38826
39123
  function safeHref4(value) {
38827
39124
  const trimmed = value.trim();
38828
- return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml10(trimmed) : "#";
39125
+ return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml11(trimmed) : "#";
38829
39126
  }
38830
39127
  function formatDate2(value) {
38831
39128
  const date = new Date(value);
38832
- return Number.isNaN(date.getTime()) ? escapeHtml10(value) : new Intl.DateTimeFormat("en", {
39129
+ return Number.isNaN(date.getTime()) ? escapeHtml11(value) : new Intl.DateTimeFormat("en", {
38833
39130
  month: "long",
38834
39131
  day: "numeric",
38835
39132
  year: "numeric"
@@ -38843,15 +39140,15 @@ function jsonForScript(value) {
38843
39140
  }
38844
39141
  function portrait(input) {
38845
39142
  if (input.author.portraitUrl) {
38846
- return `<img class="author-portrait" src="${safeHref4(input.author.portraitUrl)}" alt="${escapeHtml10(input.author.portraitAlt || input.author.name)}">`;
39143
+ return `<img class="author-portrait" src="${safeHref4(input.author.portraitUrl)}" alt="${escapeHtml11(input.author.portraitAlt || input.author.name)}">`;
38847
39144
  }
38848
- return `<span class="author-portrait author-initials" aria-label="${escapeHtml10(input.author.name)}">${escapeHtml10(initials4(input.author.name))}</span>`;
39145
+ return `<span class="author-portrait author-initials" aria-label="${escapeHtml11(input.author.name)}">${escapeHtml11(initials4(input.author.name))}</span>`;
38849
39146
  }
38850
39147
  function sidebarArt(input) {
38851
39148
  if (input.sidebarMedia?.imageUrl) {
38852
- return `<img src="${safeHref4(input.sidebarMedia.imageUrl)}" alt="${escapeHtml10(input.sidebarMedia.imageAlt)}">`;
39149
+ return `<img src="${safeHref4(input.sidebarMedia.imageUrl)}" alt="${escapeHtml11(input.sidebarMedia.imageAlt)}">`;
38853
39150
  }
38854
- return `<svg viewBox="0 0 560 330" role="img" aria-label="${escapeHtml10(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>`;
39151
+ 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>`;
38855
39152
  }
38856
39153
  function citations(input) {
38857
39154
  const published = new Date(input.publishedAt);
@@ -38880,23 +39177,23 @@ function renderBlogArticleV1(input, config, generatedAt) {
38880
39177
  ...flags.faq && input.faq.length ? [{ id: "faq", title: "Frequently asked questions" }] : []
38881
39178
  ];
38882
39179
  const contributorText = [
38883
- `Written by <a href="${safeHref4(input.author.href || "#author")}">${escapeHtml10(input.author.name)}</a>`,
38884
- input.editor ? `Edited by <a href="${safeHref4(input.editor.href || "#")}">${escapeHtml10(input.editor.name)}</a>` : "",
38885
- input.reviewer ? `Reviewed by <a href="${safeHref4(input.reviewer.href || "#")}">${escapeHtml10(input.reviewer.name)}${input.reviewer.credential ? `, ${escapeHtml10(input.reviewer.credential)}` : ""}</a>` : ""
39180
+ `Written by <a href="${safeHref4(input.author.href || "#author")}">${escapeHtml11(input.author.name)}</a>`,
39181
+ input.editor ? `Edited by <a href="${safeHref4(input.editor.href || "#")}">${escapeHtml11(input.editor.name)}</a>` : "",
39182
+ input.reviewer ? `Reviewed by <a href="${safeHref4(input.reviewer.href || "#")}">${escapeHtml11(input.reviewer.name)}${input.reviewer.credential ? `, ${escapeHtml11(input.reviewer.credential)}` : ""}</a>` : ""
38886
39183
  ].filter(Boolean).join(" \xB7 ");
38887
39184
  const sections = input.sections.map(
38888
- (section3) => `<section id="${escapeHtml10(section3.id)}" class="article-section"><header>${section3.eyebrow ? `<span class="eyebrow">${escapeHtml10(section3.eyebrow)}</span>` : ""}<h2>${escapeHtml10(section3.title)}</h2></header>${section3.paragraphs.map((paragraph) => `<p>${escapeHtml10(paragraph)}</p>`).join("")}${section3.bullets?.length ? `<ul>${section3.bullets.map((item) => `<li>${escapeHtml10(item)}</li>`).join("")}</ul>` : ""}${section3.callout ? `<aside class="callout"><span>Worth noting</span><h3>${escapeHtml10(section3.callout.heading)}</h3><p>${escapeHtml10(section3.callout.body)}</p></aside>` : ""}</section>`
39185
+ (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>`
38889
39186
  ).join("");
38890
- 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>${escapeHtml10(item.question)}</span><b aria-hidden="true">+</b></button></h3><p id="faq-${index}" hidden>${escapeHtml10(item.answer)}</p></article>`).join("")}</div></section>` : "";
38891
- const media = flags.sidebarMedia && input.sidebarMedia ? `<figure class="sidebar-media" data-article-media>${sidebarArt(input)}${input.sidebarMedia.caption ? `<figcaption>${escapeHtml10(input.sidebarMedia.caption)}</figcaption>` : ""}</figure>` : "";
38892
- const disclosure = flags.disclosure && input.disclosure ? `<section class="disclosure"><button type="button" aria-expanded="false" aria-controls="disclosure-details"><span>${escapeHtml10(input.disclosure.summary)}</span><b aria-hidden="true">\u2304</b></button><p id="disclosure-details" hidden>${escapeHtml10(input.disclosure.details)}</p></section>` : "";
38893
- 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="#${escapeHtml10(item.id)}"${index === 0 ? ' aria-current="location"' : ""}><i></i><span>${escapeHtml10(item.title)}</span></a>`).join("")}</nav><button class="back-top" type="button">Back to top \u2191</button></aside>` : "";
39187
+ 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>` : "";
39188
+ 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>` : "";
39189
+ 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>` : "";
39190
+ 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>` : "";
38894
39191
  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>` : "";
38895
- 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)}">${escapeHtml10(input.author.name)}</a>` : escapeHtml10(input.author.name)}</h2><p>${escapeHtml10(input.author.role)}</p>${input.author.socialLinks.length || input.author.email ? `<nav aria-label="Author links">${input.author.socialLinks.map((link) => `<a href="${safeHref4(link.href)}">${escapeHtml10(link.label)}</a>`).join("")}${input.author.email ? `<a href="mailto:${escapeHtml10(input.author.email)}">Email</a>` : ""}</nav>` : ""}</div>${input.author.href ? `<a class="author-more" href="${safeHref4(input.author.href)}">Read more from ${escapeHtml10(input.author.name.split(/\s+/)[0] || input.author.name)}</a>` : ""}</div><p class="author-bio">${escapeHtml10(input.author.bio)}</p></section>` : actions;
38896
- 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> ${escapeHtml10(citationValues[style])}</button>`).join("")}</section><p class="citation-status" aria-live="polite"></p></div></dialog>` : "";
38897
- 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="${escapeHtml10(input.dek || input.keyTakeaways[0])}"><title>${escapeHtml10(input.title)} \xB7 ${escapeHtml10(brand)}</title><style>
39192
+ 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((link) => `<a href="${safeHref4(link.href)}">${escapeHtml11(link.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;
39193
+ 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>` : "";
39194
+ 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>
38898
39195
  :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}}
38899
- </style></head><body data-theme="${escapeHtml10(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)}">${escapeHtml10(input.category)}</a><span>/</span><span>Article</span></nav><span class="eyebrow">${escapeHtml10(input.eyebrow)}</span><h1>${escapeHtml10(input.title)}</h1>${input.dek ? `<p class="dek">${escapeHtml10(input.dek)}</p>` : ""}<div class="contributors">${contributorText}<div class="meta"><time datetime="${escapeHtml10(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>${escapeHtml10(item)}</li>`).join("")}</ul></section><section class="intro">${input.introduction.map((paragraph) => `<p>${escapeHtml10(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>`;
39196
+ </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>`;
38900
39197
  const bytes = Buffer.byteLength(html);
38901
39198
  const sha2563 = createHash24("sha256").update(html).digest("hex");
38902
39199
  return {
@@ -41496,7 +41793,7 @@ async function getFreeCreditBreakdown(userId) {
41496
41793
  }
41497
41794
 
41498
41795
  // src/api/memory-db.ts
41499
- import { neon } from "@neondatabase/serverless";
41796
+ import { neon as neon2 } from "@neondatabase/serverless";
41500
41797
 
41501
41798
  // src/api/memory-universe.ts
41502
41799
  var SEP = "\n";
@@ -41593,7 +41890,7 @@ function sql() {
41593
41890
  if (_sql) return _sql;
41594
41891
  const url = process.env.MEMORY_DATABASE_URL?.trim();
41595
41892
  if (!url) throw new Error("MEMORY_DATABASE_URL is not set (paa-crawler needs mcp-memory Neon URL for reads)");
41596
- _sql = neon(url);
41893
+ _sql = neon2(url);
41597
41894
  return _sql;
41598
41895
  }
41599
41896
  function physicalVault(owner, vault) {
@@ -47296,7 +47593,7 @@ app.get("/cron/tick", async (c) => {
47296
47593
  const budget = { maxJobs: 10, deadlineMs: startedAt + CRON_TICK_DRAIN_BUDGET_MS };
47297
47594
  const origin = `${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`;
47298
47595
  const unfinished = [];
47299
- 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([
47596
+ 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([
47300
47597
  settleWithinTickBudget("drainQueue", unfinished, drainQueue(budget), []),
47301
47598
  settleWithinTickBudget("monthlyRefreshSweep", unfinished, runMonthlyRefreshSweep(), { status: "skipped_deadline" }),
47302
47599
  settleWithinTickBudget("reapBrowserSessions", unfinished, reapIdleBrowserSessions(120), { reaped: 0 }),
@@ -47313,6 +47610,7 @@ app.get("/cron/tick", async (c) => {
47313
47610
  settleWithinTickBudget("siteExtractReconcile", unfinished, reconcileSiteExtractSettlements(10), { checked: 0, settled: 0, failed: 0 }),
47314
47611
  settleWithinTickBudget("paaRedispatch", unfinished, redispatchPendingPaaHarvests(10), { checked: 0, dispatched: 0, failed: 0 }),
47315
47612
  settleWithinTickBudget("paaReconcile", unfinished, reconcilePaaHarvestSettlements(10), { checked: 0, staleFailed: 0, settled: 0, failed: 0 }),
47613
+ settleWithinTickBudget("commonsEmbeddingDrain", unfinished, embedQueuedCommonsDocuments(50), { claimed: 0, embedded: 0, failed: 0, remaining: 0 }),
47316
47614
  settleWithinTickBudget("localSourcebookRedispatch", unfinished, redispatchQueuedLocalSourcebookAcquisitions(5), { checked: 0, dispatched: 0, failed: 0 }),
47317
47615
  settleWithinTickBudget("analyticsRollup", unfinished, refreshAnalyticsDailyRollupsIfDue(), { status: "failed", rows: 0 }),
47318
47616
  settleWithinTickBudget("analyticsForms", unfinished, deliverPendingAnalyticsForms(10), { claimed: 0, delivered: 0, deferred: 0 }),
@@ -47343,6 +47641,7 @@ app.get("/cron/tick", async (c) => {
47343
47641
  siteExtractReconciliation,
47344
47642
  paaHarvestRedispatch,
47345
47643
  paaHarvestReconciliation,
47644
+ commonsEmbeddingDrain,
47346
47645
  localSourcebookRedispatch,
47347
47646
  analyticsRollup,
47348
47647
  analyticsFormDelivery,
@@ -47575,4 +47874,4 @@ app.get("/blog/:slug/", (c) => {
47575
47874
  export {
47576
47875
  app
47577
47876
  };
47578
- //# sourceMappingURL=server-J4YGBOTS.js.map
47877
+ //# sourceMappingURL=server-IRKNU6LO.js.map