@fasl-work/caos-app-shell 0.11.2 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
- import { useThemeStore, useShellLang, useLangStore, SHELL_TOKENS, pick, useStageSize, NOT_AVAILABLE, formatTicks, formatNumber, NBSP } from './chunk-DX36XRD5.js';
2
- export { NBSP, NOT_AVAILABLE, SCIENTIFIC_BELOW, SHELL_TOKENS, Stage, applyTheme, formatNumber, formatTicks, pick, readTheme, resolveToken, useFormat, useLangStore, useShellLang, useStageSize, useThemeStore, useThemeTokens } from './chunk-DX36XRD5.js';
3
- export { LANG_STORAGE_KEY, STANDARD_ROUTES, THEME_BOOT_SCRIPT, THEME_STORAGE_KEY } from './chunk-X6Y5CDUD.js';
1
+ import { useThemeStore, useShellLang, useLangStore, SHELL_TOKENS, pick, useStageSize, NOT_AVAILABLE, formatTicks, formatNumber, NBSP } from './chunk-3QYQCWSZ.js';
2
+ export { NBSP, NOT_AVAILABLE, SCIENTIFIC_BELOW, SHELL_TOKENS, Stage, applyTheme, formatNumber, formatTicks, pick, readTheme, resolveToken, useFormat, useLangStore, useShellLang, useStageSize, useThemeStore, useThemeTokens } from './chunk-3QYQCWSZ.js';
3
+ import { APP_ROUTE, LANDING_ROUTE } from './chunk-YVVDBSAC.js';
4
+ export { APP_ROUTE, LANDING_ROUTE, LANG_STORAGE_KEY, STANDARD_ROUTES, THEME_BOOT_SCRIPT, THEME_STORAGE_KEY } from './chunk-YVVDBSAC.js';
4
5
  import { createContext, Component, useState, useRef, useId, useEffect, useCallback, useContext, useMemo, useLayoutEffect, Children } from 'react';
5
- import { useInRouterContext, NavLink, useLocation } from 'react-router';
6
+ import { useInRouterContext, NavLink, useLocation, Navigate, Link } from 'react-router';
6
7
  import { Sun, Moon, Languages, Boxes, CodeXml, Globe, Briefcase, Info } from 'lucide-react';
7
8
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
9
  import katex from 'katex';
@@ -123,21 +124,21 @@ function validateArchitectureConfig(config) {
123
124
  const out = [];
124
125
  if (config.tabs.length < 5) out.push(`the architecture modal has ${config.tabs.length} tabs; ADR-0058 requires at least 5`);
125
126
  const known = new Set(SHELL_TOKENS);
126
- for (const t of config.tabs) {
127
- if (!t.en?.trim() || !t.es?.trim() || !t.body_en?.trim() || !t.body_es?.trim()) {
128
- out.push(`architecture tab "${t.id}" lacks a label or a body in one language`);
127
+ for (const t2 of config.tabs) {
128
+ if (!t2.en?.trim() || !t2.es?.trim() || !t2.body_en?.trim() || !t2.body_es?.trim()) {
129
+ out.push(`architecture tab "${t2.id}" lacks a label or a body in one language`);
129
130
  }
130
- const svg = t.svg.trim();
131
+ const svg = t2.svg.trim();
131
132
  if (!svg.startsWith("<svg")) {
132
- out.push(`architecture tab "${t.id}": the diagram must be an inline SVG string (import it with ?raw), not a URL`);
133
+ out.push(`architecture tab "${t2.id}": the diagram must be an inline SVG string (import it with ?raw), not a URL`);
133
134
  continue;
134
135
  }
135
136
  for (const name of new Set([...svg.matchAll(/var\((--[a-z0-9-]+)/gi)].map((x) => x[1]))) {
136
- if (!known.has(name)) out.push(`architecture tab "${t.id}" uses ${name}, which the shell does not define`);
137
+ if (!known.has(name)) out.push(`architecture tab "${t2.id}" uses ${name}, which the shell does not define`);
137
138
  }
138
139
  const hex = svg.replace(/url\(\s*#[^)]*\)/gi, "").replace(/href\s*=\s*["']#[^"']*["']/gi, "").match(/#[0-9a-f]{3,8}\b/gi);
139
140
  if (hex) {
140
- out.push(`architecture tab "${t.id}" uses hex colours (${[...new Set(hex)].slice(0, 3).join(", ")}); use shell tokens so it follows the theme`);
141
+ out.push(`architecture tab "${t2.id}" uses hex colours (${[...new Set(hex)].slice(0, 3).join(", ")}); use shell tokens so it follows the theme`);
141
142
  }
142
143
  }
143
144
  return out;
@@ -191,7 +192,7 @@ function ArchitectureModal({ config, onClose }) {
191
192
  if (opener?.isConnected) opener.focus();
192
193
  };
193
194
  }, []);
194
- const tab = tabs.find((t) => t.id === active) ?? tabs[0];
195
+ const tab = tabs.find((t2) => t2.id === active) ?? tabs[0];
195
196
  useEffect(() => {
196
197
  if (!tab) return;
197
198
  setErr(null);
@@ -245,19 +246,19 @@ function ArchitectureModal({ config, onClose }) {
245
246
  }
246
247
  )
247
248
  ] }),
248
- /* @__PURE__ */ jsx("div", { role: "tablist", "aria-label": title, style: { display: "flex", flexWrap: "wrap", gap: 4, padding: "8px 14px 0", borderBottom: "1px solid var(--color-border)" }, children: tabs.map((t) => {
249
- const sel = t.id === active;
249
+ /* @__PURE__ */ jsx("div", { role: "tablist", "aria-label": title, style: { display: "flex", flexWrap: "wrap", gap: 4, padding: "8px 14px 0", borderBottom: "1px solid var(--color-border)" }, children: tabs.map((t2) => {
250
+ const sel = t2.id === active;
250
251
  return /* @__PURE__ */ jsx(
251
252
  "button",
252
253
  {
253
- id: `${id}-${t.id}`,
254
+ id: `${id}-${t2.id}`,
254
255
  role: "tab",
255
256
  "aria-selected": sel,
256
257
  "aria-controls": `${id}-panel`,
257
258
  tabIndex: sel ? 0 : -1,
258
- onClick: () => setActive(t.id),
259
+ onClick: () => setActive(t2.id),
259
260
  onKeyDown: (event) => {
260
- const index = tabs.indexOf(t);
261
+ const index = tabs.indexOf(t2);
261
262
  const next = event.key === "Home" ? 0 : event.key === "End" ? tabs.length - 1 : event.key === "ArrowRight" ? (index + 1) % tabs.length : event.key === "ArrowLeft" ? (index - 1 + tabs.length) % tabs.length : -1;
262
263
  if (next < 0) return;
263
264
  event.preventDefault();
@@ -275,9 +276,9 @@ function ArchitectureModal({ config, onClose }) {
275
276
  color: sel ? "var(--color-accent-fg, #fff)" : "var(--color-fg-subtle)",
276
277
  fontWeight: sel ? 600 : 400
277
278
  },
278
- children: es ? t.es : t.en
279
+ children: es ? t2.es : t2.en
279
280
  },
280
- t.id
281
+ t2.id
281
282
  );
282
283
  }) }),
283
284
  /* @__PURE__ */ jsxs("div", { id: `${id}-panel`, role: "tabpanel", "aria-labelledby": `${id}-${tab.id}`, "data-arch-lang": es ? "es" : "en", "data-tab": tab.id, "data-state": err ? "missing" : svg === null ? "loading" : "ready", style: { overflowY: "auto", minHeight: 0, padding: "14px 16px 18px" }, children: [
@@ -428,6 +429,11 @@ function Frame({ config, pathname, routed, children }) {
428
429
  ] }) }) })
429
430
  ] });
430
431
  }
432
+ function Landing() {
433
+ const { pathname, search, hash } = useLocation();
434
+ const oldAppLink = pathname === "/" && (search !== "" || hash !== "");
435
+ return /* @__PURE__ */ jsx(Navigate, { to: `${oldAppLink ? APP_ROUTE : LANDING_ROUTE}${search}${hash}`, replace: true });
436
+ }
431
437
  function WorkbenchShell({
432
438
  brand,
433
439
  routes,
@@ -522,14 +528,14 @@ function createVizLoop(frame, options, deps) {
522
528
  handle = null;
523
529
  }
524
530
  };
525
- function tick(t) {
531
+ function tick(t2) {
526
532
  handle = null;
527
533
  if (baseline) {
528
- last = t;
534
+ last = t2;
529
535
  baseline = false;
530
536
  }
531
- const dt = t - last;
532
- last = t;
537
+ const dt = t2 - last;
538
+ last = t2;
533
539
  elapsed += dt;
534
540
  let e = elapsed;
535
541
  const capped = durationMs != null && e >= durationMs;
@@ -712,7 +718,7 @@ function CaseSelector(props) {
712
718
  className,
713
719
  layout = "chips"
714
720
  } = props;
715
- const t = { ...TEXT[lang], ...text };
721
+ const t2 = { ...TEXT[lang], ...text };
716
722
  const baseId = useId();
717
723
  const param = typeof deepLink === "string" ? deepLink : "case";
718
724
  const linkPending = useRef(Boolean(deepLink));
@@ -735,8 +741,8 @@ function CaseSelector(props) {
735
741
  const modified = cases.find((c) => c.id === modifiedFromId) ?? null;
736
742
  return /* @__PURE__ */ jsxs("div", { className: `cs${className ? ` ${className}` : ""}`, role: "group", "aria-label": ariaLabel ?? "Case selector", children: [
737
743
  source && lanes.length > 1 && /* @__PURE__ */ jsxs("div", { className: "cs-source", children: [
738
- /* @__PURE__ */ jsx("span", { className: "cs-source-label", children: t.source }),
739
- /* @__PURE__ */ jsx("div", { className: "cs-source-tabs", role: "tablist", "aria-label": t.source, children: lanes.map((k) => /* @__PURE__ */ jsx(
744
+ /* @__PURE__ */ jsx("span", { className: "cs-source-label", children: t2.source }),
745
+ /* @__PURE__ */ jsx("div", { className: "cs-source-tabs", role: "tablist", "aria-label": t2.source, children: lanes.map((k) => /* @__PURE__ */ jsx(
740
746
  "button",
741
747
  {
742
748
  type: "button",
@@ -744,12 +750,12 @@ function CaseSelector(props) {
744
750
  "aria-selected": source === k,
745
751
  className: source === k ? "subtab active" : "subtab",
746
752
  onClick: () => onSourceChange?.(k),
747
- children: k === "synthetic" ? t.synthetic : k === "real" ? t.real : t.uploaded
753
+ children: k === "synthetic" ? t2.synthetic : k === "real" ? t2.real : t2.uploaded
748
754
  },
749
755
  k
750
756
  )) })
751
757
  ] }),
752
- source && source !== "synthetic" && /* @__PURE__ */ jsx("p", { className: "cs-locked banner", children: lockedNote ?? t.lockedNote }),
758
+ source && source !== "synthetic" && /* @__PURE__ */ jsx("p", { className: "cs-locked banner", children: lockedNote ?? t2.lockedNote }),
753
759
  layout === "select" && /* @__PURE__ */ jsx(
754
760
  "select",
755
761
  {
@@ -788,11 +794,11 @@ function CaseSelector(props) {
788
794
  ] }, g.category || "_")),
789
795
  modified && /* @__PURE__ */ jsxs("div", { className: "cs-modified", children: [
790
796
  /* @__PURE__ */ jsxs("span", { className: "badge accent", children: [
791
- t.modifiedPrefix,
797
+ t2.modifiedPrefix,
792
798
  " ",
793
799
  /* @__PURE__ */ jsx("strong", { children: modified.name })
794
800
  ] }),
795
- onResetToCanonical && /* @__PURE__ */ jsx("button", { type: "button", className: "cs-reset", onClick: onResetToCanonical, children: t.reset })
801
+ onResetToCanonical && /* @__PURE__ */ jsx("button", { type: "button", className: "cs-reset", onClick: onResetToCanonical, children: t2.reset })
796
802
  ] })
797
803
  ] });
798
804
  }
@@ -957,7 +963,7 @@ function Tabs({ tabs, initial, value, onChange, ariaLabel }) {
957
963
  document.getElementById(`${baseId}-tab-${target.id}`)?.focus();
958
964
  }
959
965
  }
960
- const current = tabs.find((t) => t.id === active) ?? tabs[0];
966
+ const current = tabs.find((t2) => t2.id === active) ?? tabs[0];
961
967
  return /* @__PURE__ */ jsxs("div", { className: "tabs", children: [
962
968
  /* @__PURE__ */ jsx("div", { className: "tablist", role: "tablist", "aria-label": ariaLabel, ref: rowRef, children: tabs.map((tab, idx) => {
963
969
  const selected = tab.id === current?.id;
@@ -1025,7 +1031,7 @@ function SubTabs({ tabs, initial, value, onChange, ariaLabel, orientation = "hor
1025
1031
  document.getElementById(`${baseId}-subtab-${target.id}`)?.focus();
1026
1032
  }
1027
1033
  }
1028
- const current = tabs.find((t) => t.id === active) ?? tabs[0];
1034
+ const current = tabs.find((t2) => t2.id === active) ?? tabs[0];
1029
1035
  return /* @__PURE__ */ jsxs("div", { className: vertical ? "subtabs subtabs-vertical" : "subtabs", children: [
1030
1036
  /* @__PURE__ */ jsx(
1031
1037
  "div",
@@ -1076,7 +1082,7 @@ function TabGroups({ groups, value, onChange, ariaLabel }) {
1076
1082
  const [own, setOwn] = useState({ group: groups[0]?.id ?? "" });
1077
1083
  const sel = value ?? own;
1078
1084
  const group = groups.find((g) => g.id === sel.group) ?? groups[0];
1079
- const tabOf = (g, wanted) => g.tabs.find((t) => t.id === wanted)?.id ?? g.tabs[0]?.id ?? "";
1085
+ const tabOf = (g, wanted) => g.tabs.find((t2) => t2.id === wanted)?.id ?? g.tabs[0]?.id ?? "";
1080
1086
  function set(next) {
1081
1087
  if (value === void 0) setOwn(next);
1082
1088
  onChange?.(next);
@@ -1137,7 +1143,7 @@ function Figure({ caption, children }) {
1137
1143
  ] });
1138
1144
  }
1139
1145
  var DOC_AREAS = {
1140
- "/introduction": ["initiative", "outcomes", "positioning", "credibility", "problem", "principles", "math", "pipeline", "honesty"],
1146
+ "/introduction": ["problem", "principles", "math", "pipeline", "honesty"],
1141
1147
  "/methodology": ["method"],
1142
1148
  "/implementation": ["architecture", "reproducibility", "engine", "lanes", "contract", "deployment"],
1143
1149
  "/experiments": ["question", "metrics", "protocol", "datasets"],
@@ -1206,6 +1212,1306 @@ function Stat({ value, unit, source }) {
1206
1212
  ] })
1207
1213
  ] });
1208
1214
  }
1215
+
1216
+ // src/content/executive.schema.json
1217
+ var executive_schema_default = {
1218
+ $schema: "https://json-schema.org/draft/2020-12/schema",
1219
+ $id: "https://github.com/fsantibanezleal/CAOS_APP_SHELL/blob/main/src/content/executive.schema.json",
1220
+ title: "CAOS executive view data, version 2.0.0",
1221
+ description: "The one data file a CAOS product fills for the executive view of its Introduction (content/executive.json): the industry's problem framed for a decision maker, general and never tied to a client or written as a pitch. Every text is { en, es }; nothing outside these fields is allowed. The floors are minimum and maximum counts of rows (minItems, maxItems). The writing limits (30 words per sentence, one sentence for key messages, captions, actions and the like, two for the key statement, at least 25 words in a paragraph, no equation, no inline citation, no promotional or client-bound wording), the 4 C's rule (exactly the 4 C's of FOUR_CS, in order, each c equal to its name), the owners that are roles of the current situation, the weights of the causes and the sources-by-id rules (every citation names a source, every source is cited, a source is an https link whose title and note cite no file) are checked by validateExecutive in executive.ts, on top of this structure.",
1222
+ type: "object",
1223
+ additionalProperties: false,
1224
+ required: [
1225
+ "title",
1226
+ "key_statement",
1227
+ "headline_figures",
1228
+ "pain",
1229
+ "context",
1230
+ "situation",
1231
+ "trends",
1232
+ "proposal",
1233
+ "illustrations",
1234
+ "sources"
1235
+ ],
1236
+ properties: {
1237
+ title: {
1238
+ $ref: "#/$defs/text",
1239
+ description: "The problem's title: the industry's problem, not a product name."
1240
+ },
1241
+ key_statement: {
1242
+ $ref: "#/$defs/text",
1243
+ description: "One or two sentences naming the pain and the direction proposed."
1244
+ },
1245
+ headline_figures: {
1246
+ type: "array",
1247
+ minItems: 2,
1248
+ maxItems: 3,
1249
+ description: "Two or three headline figures, each a short heading, one figure and its linked source.",
1250
+ items: {
1251
+ $ref: "#/$defs/figure"
1252
+ }
1253
+ },
1254
+ pain: {
1255
+ type: "object",
1256
+ additionalProperties: false,
1257
+ required: [
1258
+ "key_message",
1259
+ "paragraphs",
1260
+ "bearers",
1261
+ "figures",
1262
+ "causes"
1263
+ ],
1264
+ properties: {
1265
+ key_message: {
1266
+ $ref: "#/$defs/text",
1267
+ description: "One line: what a reader who stops here takes away."
1268
+ },
1269
+ paragraphs: {
1270
+ type: "array",
1271
+ minItems: 2,
1272
+ maxItems: 3,
1273
+ description: "Two paragraphs (at least 25 words each): what goes wrong, for whom, how big.",
1274
+ items: {
1275
+ $ref: "#/$defs/text"
1276
+ }
1277
+ },
1278
+ bearers: {
1279
+ type: "array",
1280
+ minItems: 3,
1281
+ maxItems: 5,
1282
+ items: {
1283
+ type: "object",
1284
+ additionalProperties: false,
1285
+ required: [
1286
+ "who",
1287
+ "cost",
1288
+ "measure"
1289
+ ],
1290
+ properties: {
1291
+ who: {
1292
+ $ref: "#/$defs/text",
1293
+ description: "Who bears it."
1294
+ },
1295
+ cost: {
1296
+ $ref: "#/$defs/text",
1297
+ description: "The cost in money, time, risk or harm."
1298
+ },
1299
+ measure: {
1300
+ $ref: "#/$defs/text",
1301
+ description: "How it is measured."
1302
+ }
1303
+ }
1304
+ }
1305
+ },
1306
+ figures: {
1307
+ type: "array",
1308
+ minItems: 2,
1309
+ maxItems: 4,
1310
+ description: "At least two sourced industry figures.",
1311
+ items: {
1312
+ $ref: "#/$defs/figure"
1313
+ }
1314
+ },
1315
+ causes: {
1316
+ type: "array",
1317
+ minItems: 3,
1318
+ maxItems: 5,
1319
+ description: "Three to five non-overlapping branches, weighted by size.",
1320
+ items: {
1321
+ type: "object",
1322
+ additionalProperties: false,
1323
+ required: [
1324
+ "cause",
1325
+ "weight"
1326
+ ],
1327
+ properties: {
1328
+ cause: {
1329
+ $ref: "#/$defs/text",
1330
+ description: "One branch of the problem; branches do not overlap."
1331
+ },
1332
+ weight: {
1333
+ type: "integer",
1334
+ minimum: 1,
1335
+ maximum: 100,
1336
+ description: "The size of the branch as a percent of the whole; the weights add to at most 100."
1337
+ }
1338
+ }
1339
+ }
1340
+ }
1341
+ }
1342
+ },
1343
+ context: {
1344
+ type: "object",
1345
+ additionalProperties: false,
1346
+ required: [
1347
+ "key_message",
1348
+ "paragraphs",
1349
+ "setting",
1350
+ "forces",
1351
+ "evidence"
1352
+ ],
1353
+ properties: {
1354
+ key_message: {
1355
+ $ref: "#/$defs/text",
1356
+ description: "One line: what a reader who stops here takes away."
1357
+ },
1358
+ paragraphs: {
1359
+ type: "array",
1360
+ minItems: 1,
1361
+ maxItems: 2,
1362
+ description: "One or two paragraphs (at least 25 words each).",
1363
+ items: {
1364
+ $ref: "#/$defs/text"
1365
+ }
1366
+ },
1367
+ setting: {
1368
+ $ref: "#/$defs/text",
1369
+ description: "The class of organisations, rules, data and technology the problem lives in."
1370
+ },
1371
+ forces: {
1372
+ type: "array",
1373
+ minItems: 3,
1374
+ maxItems: 4,
1375
+ items: {
1376
+ type: "object",
1377
+ additionalProperties: false,
1378
+ required: [
1379
+ "force",
1380
+ "direction"
1381
+ ],
1382
+ properties: {
1383
+ force: {
1384
+ $ref: "#/$defs/text",
1385
+ description: "A force that keeps the pain going."
1386
+ },
1387
+ direction: {
1388
+ $ref: "#/$defs/direction"
1389
+ }
1390
+ }
1391
+ }
1392
+ },
1393
+ evidence: {
1394
+ type: "array",
1395
+ minItems: 1,
1396
+ maxItems: 4,
1397
+ description: "At least one sourced rule or figure.",
1398
+ items: {
1399
+ type: "object",
1400
+ additionalProperties: false,
1401
+ required: [
1402
+ "statement",
1403
+ "source"
1404
+ ],
1405
+ properties: {
1406
+ statement: {
1407
+ $ref: "#/$defs/text",
1408
+ description: "One sourced rule or figure."
1409
+ },
1410
+ source: {
1411
+ $ref: "#/$defs/sourceId"
1412
+ }
1413
+ }
1414
+ }
1415
+ }
1416
+ }
1417
+ },
1418
+ situation: {
1419
+ type: "object",
1420
+ additionalProperties: false,
1421
+ required: [
1422
+ "key_message",
1423
+ "roles",
1424
+ "interaction",
1425
+ "state_of_the_art",
1426
+ "status"
1427
+ ],
1428
+ properties: {
1429
+ key_message: {
1430
+ $ref: "#/$defs/text",
1431
+ description: "One line: what a reader who stops here takes away."
1432
+ },
1433
+ roles: {
1434
+ type: "array",
1435
+ minItems: 3,
1436
+ maxItems: 5,
1437
+ items: {
1438
+ type: "object",
1439
+ additionalProperties: false,
1440
+ required: [
1441
+ "role",
1442
+ "decides",
1443
+ "needs"
1444
+ ],
1445
+ properties: {
1446
+ role: {
1447
+ $ref: "#/$defs/text",
1448
+ description: "A role involved; a family of roles, never a person or an organisation."
1449
+ },
1450
+ decides: {
1451
+ $ref: "#/$defs/text",
1452
+ description: "What it decides."
1453
+ },
1454
+ needs: {
1455
+ $ref: "#/$defs/text",
1456
+ description: "What it needs."
1457
+ }
1458
+ }
1459
+ }
1460
+ },
1461
+ interaction: {
1462
+ $ref: "#/$defs/text",
1463
+ description: "One sentence on how the roles interact."
1464
+ },
1465
+ state_of_the_art: {
1466
+ type: "array",
1467
+ minItems: 3,
1468
+ maxItems: 5,
1469
+ items: {
1470
+ type: "object",
1471
+ additionalProperties: false,
1472
+ required: [
1473
+ "approach",
1474
+ "achieves",
1475
+ "falls_short",
1476
+ "source"
1477
+ ],
1478
+ properties: {
1479
+ approach: {
1480
+ $ref: "#/$defs/text",
1481
+ description: "An approach in use, described fairly."
1482
+ },
1483
+ achieves: {
1484
+ $ref: "#/$defs/text",
1485
+ description: "What it achieves."
1486
+ },
1487
+ falls_short: {
1488
+ $ref: "#/$defs/text",
1489
+ description: "Where it falls short."
1490
+ },
1491
+ source: {
1492
+ $ref: "#/$defs/sourceId"
1493
+ }
1494
+ }
1495
+ }
1496
+ },
1497
+ status: {
1498
+ type: "object",
1499
+ additionalProperties: false,
1500
+ required: [
1501
+ "heading",
1502
+ "value",
1503
+ "unit",
1504
+ "date",
1505
+ "source"
1506
+ ],
1507
+ properties: {
1508
+ heading: {
1509
+ $ref: "#/$defs/text"
1510
+ },
1511
+ value: {
1512
+ $ref: "#/$defs/text"
1513
+ },
1514
+ unit: {
1515
+ $ref: "#/$defs/text"
1516
+ },
1517
+ date: {
1518
+ $ref: "#/$defs/text",
1519
+ description: "The date of the figure."
1520
+ },
1521
+ source: {
1522
+ $ref: "#/$defs/sourceId"
1523
+ }
1524
+ },
1525
+ description: "One sourced status figure with its date."
1526
+ }
1527
+ }
1528
+ },
1529
+ trends: {
1530
+ type: "object",
1531
+ additionalProperties: false,
1532
+ required: [
1533
+ "key_message",
1534
+ "items"
1535
+ ],
1536
+ properties: {
1537
+ key_message: {
1538
+ $ref: "#/$defs/text",
1539
+ description: "One line: what a reader who stops here takes away."
1540
+ },
1541
+ items: {
1542
+ type: "array",
1543
+ minItems: 3,
1544
+ maxItems: 5,
1545
+ items: {
1546
+ type: "object",
1547
+ additionalProperties: false,
1548
+ required: [
1549
+ "trend",
1550
+ "kind",
1551
+ "direction",
1552
+ "horizon",
1553
+ "signal",
1554
+ "effect",
1555
+ "confidence"
1556
+ ],
1557
+ properties: {
1558
+ trend: {
1559
+ $ref: "#/$defs/text"
1560
+ },
1561
+ kind: {
1562
+ type: "string",
1563
+ enum: [
1564
+ "regulatory",
1565
+ "technological",
1566
+ "market",
1567
+ "practice"
1568
+ ]
1569
+ },
1570
+ direction: {
1571
+ $ref: "#/$defs/direction"
1572
+ },
1573
+ horizon: {
1574
+ type: "string",
1575
+ enum: [
1576
+ "now",
1577
+ "two_years",
1578
+ "ten_years"
1579
+ ]
1580
+ },
1581
+ signal: {
1582
+ type: "object",
1583
+ additionalProperties: false,
1584
+ required: [
1585
+ "statement",
1586
+ "source"
1587
+ ],
1588
+ properties: {
1589
+ statement: {
1590
+ $ref: "#/$defs/text",
1591
+ description: "The sourced signal."
1592
+ },
1593
+ source: {
1594
+ $ref: "#/$defs/sourceId"
1595
+ }
1596
+ }
1597
+ },
1598
+ effect: {
1599
+ $ref: "#/$defs/text",
1600
+ description: "Its effect on the roles of the current situation."
1601
+ },
1602
+ confidence: {
1603
+ type: "string",
1604
+ enum: [
1605
+ "low",
1606
+ "medium",
1607
+ "high"
1608
+ ]
1609
+ }
1610
+ }
1611
+ }
1612
+ }
1613
+ }
1614
+ },
1615
+ proposal: {
1616
+ type: "object",
1617
+ additionalProperties: false,
1618
+ required: [
1619
+ "key_message",
1620
+ "paragraphs",
1621
+ "four_cs",
1622
+ "actions",
1623
+ "risks",
1624
+ "unknowns"
1625
+ ],
1626
+ properties: {
1627
+ key_message: {
1628
+ $ref: "#/$defs/text",
1629
+ description: "One line: what a reader who stops here takes away."
1630
+ },
1631
+ paragraphs: {
1632
+ type: "array",
1633
+ minItems: 1,
1634
+ maxItems: 2,
1635
+ description: "The approach at the level of the problem, tied to its causes (at least 25 words each).",
1636
+ items: {
1637
+ $ref: "#/$defs/text"
1638
+ }
1639
+ },
1640
+ four_cs: {
1641
+ type: "array",
1642
+ minItems: 4,
1643
+ maxItems: 4,
1644
+ description: "Required: exactly 4 rows, the 4 C's of FOUR_CS in order (Choice, Context, Cost, Control), each c equal to the name in both languages.",
1645
+ items: {
1646
+ type: "object",
1647
+ additionalProperties: false,
1648
+ required: [
1649
+ "c",
1650
+ "applies"
1651
+ ],
1652
+ properties: {
1653
+ c: {
1654
+ $ref: "#/$defs/text",
1655
+ description: "The C's name."
1656
+ },
1657
+ applies: {
1658
+ $ref: "#/$defs/text",
1659
+ description: "One sentence: what this C means for the proposal."
1660
+ }
1661
+ }
1662
+ }
1663
+ },
1664
+ actions: {
1665
+ type: "array",
1666
+ minItems: 3,
1667
+ maxItems: 6,
1668
+ items: {
1669
+ type: "object",
1670
+ additionalProperties: false,
1671
+ required: [
1672
+ "action",
1673
+ "owner",
1674
+ "horizon",
1675
+ "check"
1676
+ ],
1677
+ properties: {
1678
+ action: {
1679
+ $ref: "#/$defs/text"
1680
+ },
1681
+ owner: {
1682
+ $ref: "#/$defs/text",
1683
+ description: "A role of the current situation, written as there."
1684
+ },
1685
+ horizon: {
1686
+ $ref: "#/$defs/text"
1687
+ },
1688
+ check: {
1689
+ $ref: "#/$defs/text",
1690
+ description: "How success is checked."
1691
+ }
1692
+ }
1693
+ }
1694
+ },
1695
+ risks: {
1696
+ type: "array",
1697
+ minItems: 1,
1698
+ maxItems: 4,
1699
+ items: {
1700
+ $ref: "#/$defs/text"
1701
+ }
1702
+ },
1703
+ unknowns: {
1704
+ type: "array",
1705
+ minItems: 1,
1706
+ maxItems: 4,
1707
+ items: {
1708
+ $ref: "#/$defs/text"
1709
+ }
1710
+ },
1711
+ handoff: {
1712
+ $ref: "#/$defs/text",
1713
+ description: "Optional: one closing line on the part of the problem the work explores."
1714
+ }
1715
+ }
1716
+ },
1717
+ illustrations: {
1718
+ type: "object",
1719
+ additionalProperties: false,
1720
+ required: [
1721
+ "pain",
1722
+ "situation",
1723
+ "proposal"
1724
+ ],
1725
+ properties: {
1726
+ pain: {
1727
+ $ref: "#/$defs/illustration"
1728
+ },
1729
+ situation: {
1730
+ $ref: "#/$defs/illustration"
1731
+ },
1732
+ proposal: {
1733
+ $ref: "#/$defs/illustration"
1734
+ }
1735
+ }
1736
+ },
1737
+ sources: {
1738
+ type: "array",
1739
+ minItems: 1,
1740
+ description: "The sources, each a link; the notes are numbered in the order of first use. Every figure and every state-of-the-art or trend claim names one by id.",
1741
+ items: {
1742
+ type: "object",
1743
+ additionalProperties: false,
1744
+ required: [
1745
+ "id",
1746
+ "title",
1747
+ "url"
1748
+ ],
1749
+ properties: {
1750
+ id: {
1751
+ type: "string",
1752
+ pattern: "^[a-z0-9][a-z0-9-]*$",
1753
+ "x-pattern-message": "must be lower case letters, digits and hyphens",
1754
+ description: "The id the figures and claims cite."
1755
+ },
1756
+ title: {
1757
+ $ref: "#/$defs/text",
1758
+ description: "The publication, in plain words."
1759
+ },
1760
+ url: {
1761
+ type: "string",
1762
+ minLength: 1,
1763
+ pattern: "^https://[^\\s]+$",
1764
+ "x-pattern-message": "must be an https:// link (the page or document itself, no other scheme, no spaces)",
1765
+ description: "The https link to the page or document."
1766
+ },
1767
+ note: {
1768
+ $ref: "#/$defs/text",
1769
+ description: "Optional, at most one sentence, for example a page number. Never a file name or number."
1770
+ }
1771
+ }
1772
+ }
1773
+ }
1774
+ },
1775
+ $defs: {
1776
+ text: {
1777
+ type: "object",
1778
+ additionalProperties: false,
1779
+ required: [
1780
+ "en",
1781
+ "es"
1782
+ ],
1783
+ properties: {
1784
+ en: {
1785
+ type: "string",
1786
+ minLength: 1
1787
+ },
1788
+ es: {
1789
+ type: "string",
1790
+ minLength: 1
1791
+ }
1792
+ }
1793
+ },
1794
+ sourceId: {
1795
+ type: "string",
1796
+ minLength: 1,
1797
+ description: "The id of an entry of sources."
1798
+ },
1799
+ direction: {
1800
+ type: "string",
1801
+ enum: [
1802
+ "rising",
1803
+ "easing",
1804
+ "steady"
1805
+ ],
1806
+ description: "Where the force or the trend is heading."
1807
+ },
1808
+ figure: {
1809
+ type: "object",
1810
+ additionalProperties: false,
1811
+ required: [
1812
+ "heading",
1813
+ "value",
1814
+ "unit",
1815
+ "source"
1816
+ ],
1817
+ properties: {
1818
+ heading: {
1819
+ $ref: "#/$defs/text",
1820
+ description: "A short heading."
1821
+ },
1822
+ value: {
1823
+ $ref: "#/$defs/text"
1824
+ },
1825
+ unit: {
1826
+ $ref: "#/$defs/text"
1827
+ },
1828
+ source: {
1829
+ $ref: "#/$defs/sourceId"
1830
+ }
1831
+ }
1832
+ },
1833
+ illustration: {
1834
+ type: "object",
1835
+ additionalProperties: false,
1836
+ required: [
1837
+ "file",
1838
+ "caption"
1839
+ ],
1840
+ properties: {
1841
+ file: {
1842
+ description: "The inline SVG: one path, or one path per language.",
1843
+ anyOf: [
1844
+ {
1845
+ type: "string",
1846
+ minLength: 1
1847
+ },
1848
+ {
1849
+ type: "object",
1850
+ additionalProperties: false,
1851
+ required: [
1852
+ "en",
1853
+ "es"
1854
+ ],
1855
+ properties: {
1856
+ en: {
1857
+ type: "string",
1858
+ minLength: 1
1859
+ },
1860
+ es: {
1861
+ type: "string",
1862
+ minLength: 1
1863
+ }
1864
+ }
1865
+ }
1866
+ ]
1867
+ },
1868
+ caption: {
1869
+ $ref: "#/$defs/text",
1870
+ description: "One sentence saying what the reader should take from the illustration."
1871
+ }
1872
+ }
1873
+ }
1874
+ }
1875
+ };
1876
+
1877
+ // src/content/executive.ts
1878
+ var EXECUTIVE_SCHEMA_VERSION = "2.0.0";
1879
+ var FOUR_CS = [
1880
+ { name: { en: "Choice", es: "Elecci\xF3n" }, definition: { en: "flexibility across proprietary and open models.", es: "flexibilidad entre modelos propietarios y abiertos." } },
1881
+ { name: { en: "Context", es: "Contexto" }, definition: { en: "AI grounded in business meaning, so decisions are accurate.", es: "IA anclada en el significado del negocio, para que las decisiones sean exactas." } },
1882
+ { name: { en: "Cost", es: "Costo" }, definition: { en: "visibility of what the AI spends.", es: "visibilidad de lo que gasta la IA." } },
1883
+ { name: { en: "Control", es: "Control" }, definition: { en: "one governance over data, models and agents.", es: "una sola gobernanza sobre datos, modelos y agentes." } }
1884
+ ];
1885
+ var EXEC_LIMITS = {
1886
+ maxWords: 30,
1887
+ /** The fewest words of a paragraph: no one-line sections, no restating the title. */
1888
+ minParagraphWords: 25,
1889
+ /** An equation or a TeX marker: a dollar sign, `\(`, `\[` or a backslash command. */
1890
+ equation: /\$|\\\(|\\\[|\\[a-zA-Z]+/,
1891
+ /** An inline citation: `(Source`, `[1]`, `(ECB`, or a parenthesised author-year such as `(Smith et al., 2019)`. */
1892
+ citations: [/\(\s*Source/i, /\[\d+\]/, /\(\s*ECB/, /\(\w[^()]*\d{4}\)/],
1893
+ /** A source that cites a file name or number in place of its link (a `.pdf` is allowed only beside a written-out https link). */
1894
+ fileCitations: [/\bfile\s*\d/i, /\barchivo\s*\d/i, /\.pdf\b/i, /\bPublished on\b/i],
1895
+ /** Promotional or client-bound wording (the view is general: never a client, never a pitch; Felipe 2026-10-13). Whole words, either case. */
1896
+ promotional: [/\bour\s+clients?\b/i, /\bnuestros?\s+clientes?\b/i, /\bcontact\s+us\b/i, /\bcontáctenos\b/i, /\bbuy\b/i, /\bcomprar\b/i, /\bprices?\b/i, /\bprecios?\b/i, /\boffers?\b/i, /\bofertas?\b/i]
1897
+ };
1898
+ function sentencesOf(text) {
1899
+ return text.split(/(?<=[.?!])\s+/).map((s) => s.trim()).filter(Boolean);
1900
+ }
1901
+ function wordsIn(text) {
1902
+ return text.split(/\s+/).filter((w) => /[\p{L}\p{N}]/u.test(w)).length;
1903
+ }
1904
+ var ROOT = executive_schema_default;
1905
+ var typeOf = (v) => v === null ? "null" : Array.isArray(v) ? "array" : typeof v;
1906
+ var join = (base, key) => base ? `${base}.${key}` : key;
1907
+ function resolve(node) {
1908
+ if (typeof node.$ref !== "string") return node;
1909
+ const name = node.$ref.replace("#/$defs/", "");
1910
+ return { ...ROOT.$defs[name], ...node.description ? { description: node.description } : {} };
1911
+ }
1912
+ function check(value, rawNode, path, out) {
1913
+ const node = resolve(rawNode);
1914
+ if (node.anyOf) {
1915
+ const ok = node.anyOf.some((alt) => {
1916
+ const sub = [];
1917
+ check(value, alt, path, sub);
1918
+ return sub.length === 0;
1919
+ });
1920
+ if (!ok) out.push({ path, message: `matches none of the allowed forms (${node.anyOf.map((a) => resolve(a).type).join(" or ")})` });
1921
+ return;
1922
+ }
1923
+ const t2 = typeOf(value);
1924
+ const wanted = node.type === "integer" ? "number" : node.type;
1925
+ if (node.type && t2 !== wanted) {
1926
+ out.push({ path, message: `must be ${node.type === "object" ? "an object" : node.type === "array" ? "an array" : `a ${node.type}`}, not ${t2 === "undefined" ? "missing" : t2 === "array" ? "an array" : t2 === "object" ? "an object" : `a ${t2}`}` });
1927
+ return;
1928
+ }
1929
+ if (node.type === "integer" && !Number.isInteger(value)) out.push({ path, message: "must be a whole number" });
1930
+ if (typeof value === "number") {
1931
+ if (node.minimum !== void 0 && value < node.minimum) out.push({ path, message: `must be at least ${node.minimum}` });
1932
+ if (node.maximum !== void 0 && value > node.maximum) out.push({ path, message: `must be at most ${node.maximum}` });
1933
+ }
1934
+ if (node.enum && !node.enum.includes(value)) out.push({ path, message: `must be one of ${node.enum.join(", ")}` });
1935
+ if (node.type === "string" && typeof value === "string" && node.minLength && value.trim().length < node.minLength) {
1936
+ out.push({ path, message: "must not be empty" });
1937
+ } else if (node.type === "string" && typeof value === "string" && node.pattern && !new RegExp(node.pattern).test(value)) {
1938
+ out.push({ path, message: node["x-pattern-message"] ?? `must match ${node.pattern}` });
1939
+ }
1940
+ if (node.type === "array") {
1941
+ const list = value;
1942
+ if (node.minItems !== void 0 && list.length < node.minItems) out.push({ path, message: `needs at least ${node.minItems} item(s), has ${list.length}` });
1943
+ if (node.maxItems !== void 0 && list.length > node.maxItems) out.push({ path, message: `allows at most ${node.maxItems} item(s), has ${list.length}` });
1944
+ if (node.items) list.forEach((item, i) => check(item, node.items, `${path}[${i}]`, out));
1945
+ }
1946
+ if (node.type === "object") {
1947
+ const obj = value;
1948
+ for (const key of node.required ?? []) {
1949
+ if (!(key in obj) || obj[key] === void 0) out.push({ path: join(path, key), message: "is required and missing" });
1950
+ }
1951
+ const props = node.properties ?? {};
1952
+ for (const key of Object.keys(obj)) {
1953
+ if (props[key]) check(obj[key], props[key], join(path, key), out);
1954
+ else if (node.additionalProperties === false) out.push({ path: join(path, key), message: "is not a field of the executive view (nothing else is allowed)" });
1955
+ }
1956
+ }
1957
+ }
1958
+ function executiveTextFields(d) {
1959
+ const out = [];
1960
+ const add = (path, text, sentences, minWords) => out.push({ path, text, sentences, minWords });
1961
+ const figure = (base, f) => {
1962
+ add(`${base}.heading`, f.heading);
1963
+ add(`${base}.value`, f.value);
1964
+ add(`${base}.unit`, f.unit);
1965
+ };
1966
+ add("title", d.title, 1);
1967
+ add("key_statement", d.key_statement, 2);
1968
+ d.headline_figures.forEach((f, i) => figure(`headline_figures[${i}]`, f));
1969
+ const { pain, context: context2, situation, trends, proposal } = d;
1970
+ add("pain.key_message", pain.key_message, 1);
1971
+ pain.paragraphs.forEach((p, i) => add(`pain.paragraphs[${i}]`, p, void 0, EXEC_LIMITS.minParagraphWords));
1972
+ pain.bearers.forEach((b, i) => {
1973
+ add(`pain.bearers[${i}].who`, b.who);
1974
+ add(`pain.bearers[${i}].cost`, b.cost);
1975
+ add(`pain.bearers[${i}].measure`, b.measure);
1976
+ });
1977
+ pain.figures.forEach((f, i) => figure(`pain.figures[${i}]`, f));
1978
+ pain.causes.forEach((c, i) => add(`pain.causes[${i}].cause`, c.cause));
1979
+ add("context.key_message", context2.key_message, 1);
1980
+ context2.paragraphs.forEach((p, i) => add(`context.paragraphs[${i}]`, p, void 0, EXEC_LIMITS.minParagraphWords));
1981
+ add("context.setting", context2.setting);
1982
+ context2.forces.forEach((f, i) => add(`context.forces[${i}].force`, f.force));
1983
+ context2.evidence.forEach((e, i) => add(`context.evidence[${i}].statement`, e.statement, 1));
1984
+ add("situation.key_message", situation.key_message, 1);
1985
+ situation.roles.forEach((r, i) => {
1986
+ add(`situation.roles[${i}].role`, r.role);
1987
+ add(`situation.roles[${i}].decides`, r.decides);
1988
+ add(`situation.roles[${i}].needs`, r.needs);
1989
+ });
1990
+ add("situation.interaction", situation.interaction, 1);
1991
+ situation.state_of_the_art.forEach((a, i) => {
1992
+ add(`situation.state_of_the_art[${i}].approach`, a.approach);
1993
+ add(`situation.state_of_the_art[${i}].achieves`, a.achieves);
1994
+ add(`situation.state_of_the_art[${i}].falls_short`, a.falls_short);
1995
+ });
1996
+ figure("situation.status", situation.status);
1997
+ add("situation.status.date", situation.status.date);
1998
+ add("trends.key_message", trends.key_message, 1);
1999
+ trends.items.forEach((t2, i) => {
2000
+ add(`trends.items[${i}].trend`, t2.trend);
2001
+ add(`trends.items[${i}].signal.statement`, t2.signal.statement, 1);
2002
+ add(`trends.items[${i}].effect`, t2.effect);
2003
+ });
2004
+ add("proposal.key_message", proposal.key_message, 1);
2005
+ proposal.paragraphs.forEach((p, i) => add(`proposal.paragraphs[${i}]`, p, void 0, EXEC_LIMITS.minParagraphWords));
2006
+ proposal.four_cs.forEach((c, i) => {
2007
+ add(`proposal.four_cs[${i}].c`, c.c);
2008
+ add(`proposal.four_cs[${i}].applies`, c.applies, 1);
2009
+ });
2010
+ proposal.actions.forEach((a, i) => {
2011
+ add(`proposal.actions[${i}].action`, a.action, 1);
2012
+ add(`proposal.actions[${i}].owner`, a.owner);
2013
+ add(`proposal.actions[${i}].horizon`, a.horizon);
2014
+ add(`proposal.actions[${i}].check`, a.check, 1);
2015
+ });
2016
+ proposal.risks.forEach((r, i) => add(`proposal.risks[${i}]`, r, 1));
2017
+ proposal.unknowns.forEach((u, i) => add(`proposal.unknowns[${i}]`, u, 1));
2018
+ if (proposal.handoff) add("proposal.handoff", proposal.handoff, 1);
2019
+ for (const name of ["pain", "situation", "proposal"]) add(`illustrations.${name}.caption`, d.illustrations[name].caption, 1);
2020
+ return out;
2021
+ }
2022
+ function executiveCitations(d) {
2023
+ const out = [];
2024
+ d.headline_figures.forEach((f, i) => out.push({ path: `headline_figures[${i}].source`, source: f.source, tab: 0 }));
2025
+ d.pain.figures.forEach((f, i) => out.push({ path: `pain.figures[${i}].source`, source: f.source, tab: 1 }));
2026
+ d.context.evidence.forEach((e, i) => out.push({ path: `context.evidence[${i}].source`, source: e.source, tab: 2 }));
2027
+ d.situation.state_of_the_art.forEach((a, i) => out.push({ path: `situation.state_of_the_art[${i}].source`, source: a.source, tab: 3 }));
2028
+ out.push({ path: "situation.status.source", source: d.situation.status.source, tab: 3 });
2029
+ d.trends.items.forEach((t2, i) => out.push({ path: `trends.items[${i}].signal.source`, source: t2.signal.source, tab: 4 }));
2030
+ return out;
2031
+ }
2032
+ function sourceOrder(d) {
2033
+ return [...new Set(executiveCitations(d).map((c) => c.source))];
2034
+ }
2035
+ function writingProblems(text, maxSentences, minWords) {
2036
+ const out = [];
2037
+ const sentences = sentencesOf(text);
2038
+ for (const s of sentences) {
2039
+ const n = wordsIn(s);
2040
+ if (n > EXEC_LIMITS.maxWords) out.push(`a sentence of ${n} words; the limit is ${EXEC_LIMITS.maxWords}`);
2041
+ }
2042
+ if (maxSentences !== void 0 && sentences.length > maxSentences) {
2043
+ out.push(maxSentences === 1 ? `must be one sentence, has ${sentences.length}` : `has ${sentences.length} sentences; the limit is ${maxSentences}`);
2044
+ }
2045
+ if (minWords !== void 0 && wordsIn(text) < minWords) out.push(`has ${wordsIn(text)} words; a paragraph needs at least ${minWords} (no one-line sections)`);
2046
+ if (EXEC_LIMITS.equation.test(text)) out.push("holds an equation or a TeX marker; the executive view holds none");
2047
+ if (EXEC_LIMITS.citations.some((re) => re.test(text))) out.push('holds an inline citation; give the source in "sources"');
2048
+ for (const re of EXEC_LIMITS.promotional) {
2049
+ const m = re.exec(text);
2050
+ if (m) out.push(`holds promotional or client-bound wording ("${m[0]}"); the executive view is general, never a client, never a pitch`);
2051
+ }
2052
+ return out;
2053
+ }
2054
+ function sourceTextProblems(text, maxSentences) {
2055
+ const out = [];
2056
+ const sentences = sentencesOf(text);
2057
+ for (const sentence of sentences) {
2058
+ const n = wordsIn(sentence);
2059
+ if (n > EXEC_LIMITS.maxWords) out.push(`a sentence of ${n} words; the limit is ${EXEC_LIMITS.maxWords}`);
2060
+ }
2061
+ if (maxSentences !== void 0 && sentences.length > maxSentences) out.push(maxSentences === 1 ? `must be one sentence, has ${sentences.length}` : `has ${sentences.length} sentences; the limit is ${maxSentences}`);
2062
+ const written = /https?:\/\//i.test(text);
2063
+ for (const re of EXEC_LIMITS.fileCitations) {
2064
+ if (re.source.includes("pdf") && written) continue;
2065
+ const m = re.exec(text);
2066
+ if (m) out.push(`cites a file name or number in place of the link ("${m[0]}"); give the publication as the title and its https link as the url`);
2067
+ }
2068
+ return out;
2069
+ }
2070
+ var sameText = (a, b) => Boolean(a && b && a.en === b.en && a.es === b.es);
2071
+ function validateExecutive(data) {
2072
+ const out = [];
2073
+ check(data, ROOT, "", out);
2074
+ if (out.length > 0) return out;
2075
+ const d = data;
2076
+ d.proposal.four_cs.forEach((r, i) => {
2077
+ const want = FOUR_CS[i].name;
2078
+ if (!sameText(r.c, want)) {
2079
+ out.push({ path: `proposal.four_cs[${i}].c`, message: `must be "${want.en}" in English and "${want.es}" in Spanish (the ${i + 1}${["st", "nd", "rd", "th"][i]} of the 4 C's, in Felipe's order); found "${r.c.en}" and "${r.c.es}"` });
2080
+ }
2081
+ });
2082
+ const total = d.pain.causes.reduce((sum, c) => sum + c.weight, 0);
2083
+ if (total > 100) out.push({ path: "pain.causes", message: `the weights add to ${total} percent; non-overlapping causes add to at most 100` });
2084
+ d.proposal.actions.forEach((a, i) => {
2085
+ if (!d.situation.roles.some((r) => sameText(r.role, a.owner))) {
2086
+ out.push({ path: `proposal.actions[${i}].owner`, message: `must be one of the roles of the current situation (${d.situation.roles.map((r) => `"${r.role.en}"`).join(", ")}), written the same in both languages` });
2087
+ }
2088
+ });
2089
+ for (const f of executiveTextFields(d)) {
2090
+ for (const lang of ["en", "es"]) {
2091
+ for (const m of writingProblems(f.text[lang], f.sentences, f.minWords)) out.push({ path: `${f.path}.${lang}`, message: m });
2092
+ }
2093
+ }
2094
+ const ids = /* @__PURE__ */ new Map();
2095
+ d.sources.forEach((s, i) => {
2096
+ if (ids.has(s.id)) out.push({ path: `sources[${i}].id`, message: `"${s.id}" is already the id of sources[${ids.get(s.id)}]` });
2097
+ else ids.set(s.id, i);
2098
+ for (const lang of ["en", "es"]) {
2099
+ for (const m of sourceTextProblems(s.title[lang])) out.push({ path: `sources[${i}].title.${lang}`, message: m });
2100
+ if (s.note) for (const m of sourceTextProblems(s.note[lang], 1)) out.push({ path: `sources[${i}].note.${lang}`, message: m });
2101
+ }
2102
+ });
2103
+ const cited = /* @__PURE__ */ new Set();
2104
+ for (const c of executiveCitations(d)) {
2105
+ if (!ids.has(c.source)) {
2106
+ out.push({ path: c.path, message: `"${c.source}" is not the id of any source (the ids are ${[...ids.keys()].join(", ")})` });
2107
+ continue;
2108
+ }
2109
+ cited.add(c.source);
2110
+ }
2111
+ d.sources.forEach((s, i) => {
2112
+ if (!cited.has(s.id)) out.push({ path: `sources[${i}].id`, message: `"${s.id}" is cited by no figure or claim; every source backs a figure or a claim` });
2113
+ });
2114
+ return out;
2115
+ }
2116
+ var EXEC_SECTION_DEFS = [
2117
+ { id: "pain", key: "pain", title: { en: "The pain", es: "El problema" } },
2118
+ { id: "context", key: "context", title: { en: "The context", es: "El contexto" } },
2119
+ { id: "situation", key: "situation", title: { en: "The current situation", es: "La situaci\xF3n actual" } },
2120
+ { id: "trends", key: "trends", title: { en: "The trends", es: "Las tendencias" } },
2121
+ { id: "proposal", key: "proposal", title: { en: "The proposal", es: "La propuesta" } }
2122
+ ];
2123
+ var SECTION_TITLES = EXEC_SECTION_DEFS.map((d) => d.title);
2124
+ var ONWARD_LINKS = {
2125
+ technical: { en: "How the work explores this problem", es: "C\xF3mo explora el trabajo este problema" },
2126
+ app: { en: "Open the App", es: "Abrir la App" }
2127
+ };
2128
+ var UI = {
2129
+ bearers: { en: "Who bears it", es: "Qui\xE9n lo soporta" },
2130
+ cost: { en: "Cost", es: "Costo" },
2131
+ measure: { en: "Measured by", es: "Se mide por" },
2132
+ causes: { en: "Where it comes from", es: "De d\xF3nde viene" },
2133
+ setting: { en: "Setting", es: "Entorno" },
2134
+ forces: { en: "What keeps it going", es: "Qu\xE9 lo mantiene" },
2135
+ evidence: { en: "Rules and figures", es: "Reglas y cifras" },
2136
+ roles: { en: "The roles involved", es: "Los roles involucrados" },
2137
+ decides: { en: "Decides", es: "Decide" },
2138
+ needs: { en: "Needs", es: "Necesita" },
2139
+ sota: { en: "How it is handled today", es: "C\xF3mo se maneja hoy" },
2140
+ achieves: { en: "Achieves", es: "Logra" },
2141
+ fallsShort: { en: "Falls short", es: "Se queda corto" },
2142
+ signal: { en: "Signal", es: "Se\xF1al" },
2143
+ effect: { en: "Effect on the roles", es: "Efecto en los roles" },
2144
+ confidence: { en: "Confidence", es: "Confianza" },
2145
+ fourCs: { en: "The 4 C's applied", es: "Las 4 C aplicadas" },
2146
+ actions: { en: "Actions", es: "Acciones" },
2147
+ owner: { en: "Owner", es: "Responsable" },
2148
+ horizon: { en: "When", es: "Cu\xE1ndo" },
2149
+ check: { en: "How we would know", es: "C\xF3mo lo sabremos" },
2150
+ risks: { en: "Risks", es: "Riesgos" },
2151
+ unknowns: { en: "What is still unknown", es: "Lo que a\xFAn se desconoce" },
2152
+ sources: { en: "Sources", es: "Fuentes" },
2153
+ onward: { en: "Onward", es: "Continuar" },
2154
+ sections: { en: "The sections of the executive view", es: "Las secciones de la vista ejecutiva" },
2155
+ source: { en: "Source", es: "Fuente" },
2156
+ errorTitle: { en: "The executive view data is not valid", es: "Los datos de la vista ejecutiva no son v\xE1lidos" },
2157
+ errorLead: {
2158
+ en: "Fix content/executive.json against executive.schema.json; the view shows nothing until it is valid.",
2159
+ es: "Corrija content/executive.json seg\xFAn executive.schema.json; la vista no muestra nada hasta que sea v\xE1lido."
2160
+ },
2161
+ loading: { en: "Loading the illustration", es: "Cargando la ilustraci\xF3n" },
2162
+ missing: { en: "The illustration file did not load", es: "No carg\xF3 el archivo de la ilustraci\xF3n" }
2163
+ };
2164
+ var DIRECTION = {
2165
+ rising: { en: "Rising", es: "En aumento" },
2166
+ easing: { en: "Easing", es: "Cediendo" },
2167
+ steady: { en: "Steady", es: "Estable" }
2168
+ };
2169
+ var KIND = {
2170
+ regulatory: { en: "Regulatory", es: "Regulatoria" },
2171
+ technological: { en: "Technological", es: "Tecnol\xF3gica" },
2172
+ market: { en: "Market", es: "De mercado" },
2173
+ practice: { en: "Practice", es: "De pr\xE1ctica" }
2174
+ };
2175
+ var HORIZON = {
2176
+ now: { en: "Now", es: "Ahora" },
2177
+ two_years: { en: "In two years", es: "En dos a\xF1os" },
2178
+ ten_years: { en: "In ten years", es: "En diez a\xF1os" }
2179
+ };
2180
+ var CONFIDENCE = {
2181
+ low: { en: "Low", es: "Baja" },
2182
+ medium: { en: "Medium", es: "Media" },
2183
+ high: { en: "High", es: "Alta" }
2184
+ };
2185
+ var t = (text, lang) => text[lang];
2186
+ function cleanSvg(text) {
2187
+ const doc = new DOMParser().parseFromString(text, "image/svg+xml");
2188
+ const root = doc.documentElement;
2189
+ if (!root || root.localName !== "svg" || doc.querySelector("parsererror")) return null;
2190
+ for (const bad of Array.from(doc.querySelectorAll("script, foreignObject"))) bad.remove();
2191
+ for (const el of Array.from(doc.querySelectorAll("*"))) {
2192
+ for (const attr of Array.from(el.attributes)) {
2193
+ if (/^on/i.test(attr.name) || /^(xlink:)?href$/i.test(attr.name) && /^\s*javascript:/i.test(attr.value)) el.removeAttribute(attr.name);
2194
+ }
2195
+ }
2196
+ root.removeAttribute("width");
2197
+ root.removeAttribute("height");
2198
+ if (!root.getAttribute("viewBox")) return null;
2199
+ if (!root.getAttribute("role")) root.setAttribute("role", "img");
2200
+ return new XMLSerializer().serializeToString(root);
2201
+ }
2202
+ function Illustration({ name, spec, base, lang }) {
2203
+ const file = typeof spec.file === "string" ? spec.file : spec.file[lang];
2204
+ const url = /^([a-z]+:)?\/\//i.test(file) || file.startsWith("/") ? file : `${base}${file}`;
2205
+ const [loaded, setLoaded] = useState({ status: "loading" });
2206
+ useEffect(() => {
2207
+ let live = true;
2208
+ setLoaded({ status: "loading" });
2209
+ fetch(url).then((r) => {
2210
+ if (!r.ok) throw new Error(`HTTP ${r.status}`);
2211
+ return r.text();
2212
+ }).then((text) => {
2213
+ const svg = cleanSvg(text);
2214
+ if (!svg) throw new Error("not an SVG document with a viewBox");
2215
+ if (live) setLoaded({ status: "ready", svg });
2216
+ }).catch((e) => {
2217
+ if (live) setLoaded({ status: "error", why: e.message });
2218
+ });
2219
+ return () => {
2220
+ live = false;
2221
+ };
2222
+ }, [url]);
2223
+ return /* @__PURE__ */ jsxs(
2224
+ "figure",
2225
+ {
2226
+ className: "figure caos-exec-fig",
2227
+ "data-exec-illustration": name,
2228
+ "data-lang": lang,
2229
+ "data-exec-file": file,
2230
+ "data-state": loaded.status === "ready" ? void 0 : loaded.status,
2231
+ children: [
2232
+ loaded.status === "ready" ? /* @__PURE__ */ jsx("div", { className: "caos-exec-art", dangerouslySetInnerHTML: { __html: loaded.svg } }) : loaded.status === "error" ? /* @__PURE__ */ jsxs("p", { className: "caos-exec-fig-error", role: "alert", children: [
2233
+ t(UI.missing, lang),
2234
+ ": ",
2235
+ /* @__PURE__ */ jsx("code", { children: file }),
2236
+ " (",
2237
+ loaded.why,
2238
+ ")"
2239
+ ] }) : /* @__PURE__ */ jsx("div", { className: "caos-exec-art caos-exec-art-wait", "aria-busy": "true", "aria-label": t(UI.loading, lang) }),
2240
+ /* @__PURE__ */ jsx("figcaption", { className: "figure-caption", "data-exec-field": `illustrations.${name}.caption`, children: t(spec.caption, lang) })
2241
+ ]
2242
+ }
2243
+ );
2244
+ }
2245
+ var Label = ({ children }) => /* @__PURE__ */ jsx("span", { className: "caos-exec-label", children });
2246
+ function Section({ n, lang, keyMessage, keyPath, children }) {
2247
+ return /* @__PURE__ */ jsxs("section", { className: "caos-exec-section", "data-exec-section": n, "aria-label": t(SECTION_TITLES[n - 1], lang), children: [
2248
+ /* @__PURE__ */ jsx("p", { className: "caos-exec-key", "data-exec-key-message": "", "data-exec-field": keyPath, children: t(keyMessage, lang) }),
2249
+ children
2250
+ ] });
2251
+ }
2252
+ function openSiblingTechnical(from) {
2253
+ const panel2 = from.closest('[role="tabpanel"]');
2254
+ const own = panel2?.getAttribute("aria-labelledby");
2255
+ const tab = own ? document.getElementById(own) : null;
2256
+ const target = tab?.closest('[role="tablist"]')?.querySelector('[role="tab"][data-tab="technical"]');
2257
+ target?.click();
2258
+ target?.focus();
2259
+ }
2260
+ function ExecutiveView({ data, base, onOpenTechnical }) {
2261
+ return /* @__PURE__ */ jsx(ExecutiveViewBody, { data, base, onOpenTechnical });
2262
+ }
2263
+ function ExecutiveViewBody({ data, base = "/", lang: forced, open = 1, onOpenTechnical }) {
2264
+ const stored = useShellLang();
2265
+ const lang = forced ?? stored;
2266
+ const routed = useInRouterContext();
2267
+ const problems = validateExecutive(data);
2268
+ if (problems.length > 0) {
2269
+ return /* @__PURE__ */ jsxs(
2270
+ "div",
2271
+ {
2272
+ className: "caos-exec caos-exec-error",
2273
+ "data-executive-view": "",
2274
+ "data-executive-schema": EXECUTIVE_SCHEMA_VERSION,
2275
+ "data-executive-valid": "false",
2276
+ "data-executive-errors": problems.map((p) => `${p.path || "(file)"}: ${p.message}`).join(" | "),
2277
+ "data-state": "error",
2278
+ role: "alert",
2279
+ children: [
2280
+ /* @__PURE__ */ jsx("h2", { children: t(UI.errorTitle, lang) }),
2281
+ /* @__PURE__ */ jsx("p", { children: t(UI.errorLead, lang) }),
2282
+ /* @__PURE__ */ jsx("ul", { children: problems.map((p, i) => /* @__PURE__ */ jsxs("li", { children: [
2283
+ /* @__PURE__ */ jsx("code", { children: p.path || "(file)" }),
2284
+ ": ",
2285
+ p.message
2286
+ ] }, i)) })
2287
+ ]
2288
+ }
2289
+ );
2290
+ }
2291
+ const d = data;
2292
+ const order = sourceOrder(d);
2293
+ const sourceOf = (id) => d.sources.find((s) => s.id === id);
2294
+ const note = (id) => order.indexOf(id) + 1;
2295
+ const Cite2 = ({ id }) => /* @__PURE__ */ jsx("sup", { className: "caos-exec-cite", children: /* @__PURE__ */ jsx("a", { href: `#exec-note-${note(id)}`, "aria-label": `${t(UI.source, lang)} ${note(id)}`, children: note(id) }) });
2296
+ const field = (path, text) => /* @__PURE__ */ jsx("span", { "data-exec-field": path, children: t(text, lang) });
2297
+ const Figure2 = ({ f, path, kind }) => /* @__PURE__ */ jsxs("li", { className: "caos-exec-figure", "data-exec-item": kind, children: [
2298
+ /* @__PURE__ */ jsx(Label, { children: field(`${path}.heading`, f.heading) }),
2299
+ /* @__PURE__ */ jsx("strong", { className: "caos-exec-value", "data-exec-field": `${path}.value`, children: t(f.value, lang) }),
2300
+ " ",
2301
+ field(`${path}.unit`, f.unit),
2302
+ /* @__PURE__ */ jsx(Cite2, { id: f.source })
2303
+ ] });
2304
+ const Paragraphs = ({ list, path }) => /* @__PURE__ */ jsx(Fragment, { children: list.map((p, i) => /* @__PURE__ */ jsx("p", { className: "caos-exec-paragraph", "data-exec-item": path, children: field(`${path}[${i}]`, p) }, i)) });
2305
+ const art = (name) => /* @__PURE__ */ jsx(Illustration, { name, spec: d.illustrations[name], base, lang });
2306
+ const enumLabel = (map, key) => t(map[key], lang);
2307
+ const bodies = [
2308
+ // 1. the pain
2309
+ /* @__PURE__ */ jsxs(Section, { n: 1, lang, keyMessage: d.pain.key_message, keyPath: "pain.key_message", children: [
2310
+ /* @__PURE__ */ jsx(Paragraphs, { list: d.pain.paragraphs, path: "pain.paragraphs" }),
2311
+ art("pain"),
2312
+ /* @__PURE__ */ jsx("ul", { className: "caos-exec-figures", children: d.pain.figures.map((f, i) => /* @__PURE__ */ jsx(Figure2, { f, path: `pain.figures[${i}]`, kind: "pain.figures" }, i)) }),
2313
+ /* @__PURE__ */ jsx("h3", { className: "caos-exec-sub", children: t(UI.bearers, lang) }),
2314
+ /* @__PURE__ */ jsx("ul", { className: "caos-exec-cards", children: d.pain.bearers.map((b, i) => /* @__PURE__ */ jsxs("li", { className: "caos-exec-card", "data-exec-item": "pain.bearers", children: [
2315
+ /* @__PURE__ */ jsx("strong", { children: field(`pain.bearers[${i}].who`, b.who) }),
2316
+ /* @__PURE__ */ jsxs("div", { children: [
2317
+ /* @__PURE__ */ jsx(Label, { children: t(UI.cost, lang) }),
2318
+ " ",
2319
+ field(`pain.bearers[${i}].cost`, b.cost)
2320
+ ] }),
2321
+ /* @__PURE__ */ jsxs("div", { children: [
2322
+ /* @__PURE__ */ jsx(Label, { children: t(UI.measure, lang) }),
2323
+ " ",
2324
+ field(`pain.bearers[${i}].measure`, b.measure)
2325
+ ] })
2326
+ ] }, i)) }),
2327
+ /* @__PURE__ */ jsx("h3", { className: "caos-exec-sub", children: t(UI.causes, lang) }),
2328
+ /* @__PURE__ */ jsx("ul", { className: "caos-exec-causes", children: d.pain.causes.map((c, i) => /* @__PURE__ */ jsxs("li", { className: "caos-exec-cause", "data-exec-item": "pain.causes", "data-exec-weight": c.weight, children: [
2329
+ /* @__PURE__ */ jsxs("div", { className: "caos-exec-cause-head", children: [
2330
+ field(`pain.causes[${i}].cause`, c.cause),
2331
+ " ",
2332
+ /* @__PURE__ */ jsxs("strong", { className: "caos-exec-value", children: [
2333
+ c.weight,
2334
+ "%"
2335
+ ] })
2336
+ ] }),
2337
+ /* @__PURE__ */ jsx("div", { className: "caos-exec-bar", "aria-hidden": "true", children: /* @__PURE__ */ jsx("span", { style: { width: `${c.weight}%` } }) })
2338
+ ] }, i)) })
2339
+ ] }, "pain"),
2340
+ // 2. the context
2341
+ /* @__PURE__ */ jsxs(Section, { n: 2, lang, keyMessage: d.context.key_message, keyPath: "context.key_message", children: [
2342
+ /* @__PURE__ */ jsx(Paragraphs, { list: d.context.paragraphs, path: "context.paragraphs" }),
2343
+ /* @__PURE__ */ jsxs("p", { className: "caos-exec-setting", children: [
2344
+ /* @__PURE__ */ jsx(Label, { children: t(UI.setting, lang) }),
2345
+ " ",
2346
+ field("context.setting", d.context.setting)
2347
+ ] }),
2348
+ /* @__PURE__ */ jsx("h3", { className: "caos-exec-sub", children: t(UI.forces, lang) }),
2349
+ /* @__PURE__ */ jsx("ul", { className: "caos-exec-cards", children: d.context.forces.map((f, i) => /* @__PURE__ */ jsxs("li", { className: "caos-exec-card", "data-exec-item": "context.forces", "data-exec-direction": f.direction, children: [
2350
+ field(`context.forces[${i}].force`, f.force),
2351
+ /* @__PURE__ */ jsx("span", { className: "caos-exec-badge", children: enumLabel(DIRECTION, f.direction) })
2352
+ ] }, i)) }),
2353
+ /* @__PURE__ */ jsx("h3", { className: "caos-exec-sub", children: t(UI.evidence, lang) }),
2354
+ /* @__PURE__ */ jsx("ul", { className: "caos-exec-evidence", children: d.context.evidence.map((e, i) => /* @__PURE__ */ jsxs("li", { "data-exec-item": "context.evidence", children: [
2355
+ field(`context.evidence[${i}].statement`, e.statement),
2356
+ /* @__PURE__ */ jsx(Cite2, { id: e.source })
2357
+ ] }, i)) })
2358
+ ] }, "context"),
2359
+ // 3. the current situation
2360
+ /* @__PURE__ */ jsxs(Section, { n: 3, lang, keyMessage: d.situation.key_message, keyPath: "situation.key_message", children: [
2361
+ /* @__PURE__ */ jsx("h3", { className: "caos-exec-sub", children: t(UI.roles, lang) }),
2362
+ /* @__PURE__ */ jsx("ul", { className: "caos-exec-cards", children: d.situation.roles.map((r, i) => /* @__PURE__ */ jsxs("li", { className: "caos-exec-card", "data-exec-item": "situation.roles", children: [
2363
+ /* @__PURE__ */ jsx("strong", { children: field(`situation.roles[${i}].role`, r.role) }),
2364
+ /* @__PURE__ */ jsxs("div", { children: [
2365
+ /* @__PURE__ */ jsx(Label, { children: t(UI.decides, lang) }),
2366
+ " ",
2367
+ field(`situation.roles[${i}].decides`, r.decides)
2368
+ ] }),
2369
+ /* @__PURE__ */ jsxs("div", { children: [
2370
+ /* @__PURE__ */ jsx(Label, { children: t(UI.needs, lang) }),
2371
+ " ",
2372
+ field(`situation.roles[${i}].needs`, r.needs)
2373
+ ] })
2374
+ ] }, i)) }),
2375
+ /* @__PURE__ */ jsx("p", { className: "caos-exec-interaction", children: field("situation.interaction", d.situation.interaction) }),
2376
+ art("situation"),
2377
+ /* @__PURE__ */ jsx("h3", { className: "caos-exec-sub", children: t(UI.sota, lang) }),
2378
+ /* @__PURE__ */ jsx("ul", { className: "caos-exec-cards", children: d.situation.state_of_the_art.map((a, i) => /* @__PURE__ */ jsxs("li", { className: "caos-exec-card", "data-exec-item": "situation.state_of_the_art", children: [
2379
+ /* @__PURE__ */ jsxs("strong", { children: [
2380
+ field(`situation.state_of_the_art[${i}].approach`, a.approach),
2381
+ /* @__PURE__ */ jsx(Cite2, { id: a.source })
2382
+ ] }),
2383
+ /* @__PURE__ */ jsxs("div", { children: [
2384
+ /* @__PURE__ */ jsx(Label, { children: t(UI.achieves, lang) }),
2385
+ " ",
2386
+ field(`situation.state_of_the_art[${i}].achieves`, a.achieves)
2387
+ ] }),
2388
+ /* @__PURE__ */ jsxs("div", { children: [
2389
+ /* @__PURE__ */ jsx(Label, { children: t(UI.fallsShort, lang) }),
2390
+ " ",
2391
+ field(`situation.state_of_the_art[${i}].falls_short`, a.falls_short)
2392
+ ] })
2393
+ ] }, i)) }),
2394
+ /* @__PURE__ */ jsxs("p", { className: "caos-exec-status", "data-exec-item": "situation.status", children: [
2395
+ /* @__PURE__ */ jsx(Label, { children: field("situation.status.heading", d.situation.status.heading) }),
2396
+ " ",
2397
+ /* @__PURE__ */ jsx("strong", { className: "caos-exec-value", "data-exec-field": "situation.status.value", children: t(d.situation.status.value, lang) }),
2398
+ " ",
2399
+ field("situation.status.unit", d.situation.status.unit),
2400
+ " ",
2401
+ /* @__PURE__ */ jsx("span", { className: "caos-exec-sep", children: "\xB7" }),
2402
+ " ",
2403
+ field("situation.status.date", d.situation.status.date),
2404
+ /* @__PURE__ */ jsx(Cite2, { id: d.situation.status.source })
2405
+ ] })
2406
+ ] }, "situation"),
2407
+ // 4. the trends
2408
+ /* @__PURE__ */ jsx(Section, { n: 4, lang, keyMessage: d.trends.key_message, keyPath: "trends.key_message", children: /* @__PURE__ */ jsx("ul", { className: "caos-exec-cards", children: d.trends.items.map((it, i) => /* @__PURE__ */ jsxs("li", { className: "caos-exec-card", "data-exec-item": "trends.items", "data-exec-horizon": it.horizon, children: [
2409
+ /* @__PURE__ */ jsx("strong", { children: field(`trends.items[${i}].trend`, it.trend) }),
2410
+ /* @__PURE__ */ jsxs("div", { className: "caos-exec-badges", children: [
2411
+ /* @__PURE__ */ jsx("span", { className: "caos-exec-badge", children: enumLabel(KIND, it.kind) }),
2412
+ /* @__PURE__ */ jsx("span", { className: "caos-exec-badge", children: enumLabel(DIRECTION, it.direction) }),
2413
+ /* @__PURE__ */ jsx("span", { className: "caos-exec-badge", children: enumLabel(HORIZON, it.horizon) }),
2414
+ /* @__PURE__ */ jsxs("span", { className: "caos-exec-badge", children: [
2415
+ t(UI.confidence, lang),
2416
+ ": ",
2417
+ enumLabel(CONFIDENCE, it.confidence)
2418
+ ] })
2419
+ ] }),
2420
+ /* @__PURE__ */ jsxs("div", { children: [
2421
+ /* @__PURE__ */ jsx(Label, { children: t(UI.signal, lang) }),
2422
+ " ",
2423
+ field(`trends.items[${i}].signal.statement`, it.signal.statement),
2424
+ /* @__PURE__ */ jsx(Cite2, { id: it.signal.source })
2425
+ ] }),
2426
+ /* @__PURE__ */ jsxs("div", { children: [
2427
+ /* @__PURE__ */ jsx(Label, { children: t(UI.effect, lang) }),
2428
+ " ",
2429
+ field(`trends.items[${i}].effect`, it.effect)
2430
+ ] })
2431
+ ] }, i)) }) }, "trends"),
2432
+ // 5. the proposal
2433
+ /* @__PURE__ */ jsxs(Section, { n: 5, lang, keyMessage: d.proposal.key_message, keyPath: "proposal.key_message", children: [
2434
+ /* @__PURE__ */ jsx(Paragraphs, { list: d.proposal.paragraphs, path: "proposal.paragraphs" }),
2435
+ art("proposal"),
2436
+ /* @__PURE__ */ jsx("h3", { className: "caos-exec-sub", children: t(UI.fourCs, lang) }),
2437
+ /* @__PURE__ */ jsx("ul", { className: "caos-exec-cs", children: d.proposal.four_cs.map((r, i) => /* @__PURE__ */ jsxs("li", { className: "caos-exec-card", "data-exec-c": i, "data-exec-item": "proposal.four_cs", children: [
2438
+ /* @__PURE__ */ jsx("strong", { "data-exec-field": `proposal.four_cs[${i}].c`, "data-exec-cname": "", children: t(FOUR_CS[i].name, lang) }),
2439
+ /* @__PURE__ */ jsx("small", { className: "caos-exec-cdef", "data-exec-cdef": "", children: t(FOUR_CS[i].definition, lang) }),
2440
+ /* @__PURE__ */ jsx("span", { children: field(`proposal.four_cs[${i}].applies`, r.applies) })
2441
+ ] }, i)) }),
2442
+ /* @__PURE__ */ jsx("h3", { className: "caos-exec-sub", children: t(UI.actions, lang) }),
2443
+ /* @__PURE__ */ jsx("ol", { className: "caos-exec-actions", children: d.proposal.actions.map((a, i) => /* @__PURE__ */ jsxs("li", { className: "caos-exec-card", "data-exec-item": "proposal.actions", children: [
2444
+ /* @__PURE__ */ jsx("strong", { children: field(`proposal.actions[${i}].action`, a.action) }),
2445
+ /* @__PURE__ */ jsxs("div", { children: [
2446
+ /* @__PURE__ */ jsx(Label, { children: t(UI.owner, lang) }),
2447
+ " ",
2448
+ field(`proposal.actions[${i}].owner`, a.owner),
2449
+ " ",
2450
+ /* @__PURE__ */ jsx("span", { className: "caos-exec-sep", children: "\xB7" }),
2451
+ " ",
2452
+ /* @__PURE__ */ jsx(Label, { children: t(UI.horizon, lang) }),
2453
+ " ",
2454
+ field(`proposal.actions[${i}].horizon`, a.horizon)
2455
+ ] }),
2456
+ /* @__PURE__ */ jsxs("div", { children: [
2457
+ /* @__PURE__ */ jsx(Label, { children: t(UI.check, lang) }),
2458
+ " ",
2459
+ field(`proposal.actions[${i}].check`, a.check)
2460
+ ] })
2461
+ ] }, i)) }),
2462
+ /* @__PURE__ */ jsx("h3", { className: "caos-exec-sub", children: t(UI.risks, lang) }),
2463
+ /* @__PURE__ */ jsx("ul", { className: "caos-exec-list", children: d.proposal.risks.map((r, i) => /* @__PURE__ */ jsx("li", { "data-exec-item": "proposal.risks", children: field(`proposal.risks[${i}]`, r) }, i)) }),
2464
+ /* @__PURE__ */ jsx("h3", { className: "caos-exec-sub", children: t(UI.unknowns, lang) }),
2465
+ /* @__PURE__ */ jsx("ul", { className: "caos-exec-list", children: d.proposal.unknowns.map((u, i) => /* @__PURE__ */ jsx("li", { "data-exec-item": "proposal.unknowns", children: field(`proposal.unknowns[${i}]`, u) }, i)) }),
2466
+ d.proposal.handoff && /* @__PURE__ */ jsx("p", { className: "caos-exec-handoff", children: field("proposal.handoff", d.proposal.handoff) })
2467
+ ] }, "proposal")
2468
+ ];
2469
+ return /* @__PURE__ */ jsxs("div", { className: "caos-exec", "data-executive-view": "", "data-executive-schema": EXECUTIVE_SCHEMA_VERSION, "data-executive-valid": "true", children: [
2470
+ /* @__PURE__ */ jsxs("header", { className: "caos-exec-landing", "data-exec-landing": "", children: [
2471
+ /* @__PURE__ */ jsx("h2", { className: "caos-exec-title", "data-exec-field": "title", children: t(d.title, lang) }),
2472
+ /* @__PURE__ */ jsx("p", { className: "caos-exec-statement", "data-exec-field": "key_statement", children: t(d.key_statement, lang) }),
2473
+ /* @__PURE__ */ jsx("ul", { className: "caos-exec-headline", children: d.headline_figures.map((f, i) => /* @__PURE__ */ jsx(Figure2, { f, path: `headline_figures[${i}]`, kind: "headline_figures" }, i)) })
2474
+ ] }),
2475
+ /* @__PURE__ */ jsx("div", { className: "caos-exec-tabs", "data-exec-tabs": "", children: /* @__PURE__ */ jsx(
2476
+ SubTabs,
2477
+ {
2478
+ ariaLabel: t(UI.sections, lang),
2479
+ initial: EXEC_SECTION_DEFS[open - 1]?.id,
2480
+ tabs: EXEC_SECTION_DEFS.map((def, i) => ({ id: def.id, label: t(def.title, lang), content: bodies[i] }))
2481
+ }
2482
+ ) }),
2483
+ /* @__PURE__ */ jsxs("aside", { className: "caos-exec-notes-wrap", "aria-label": t(UI.sources, lang), children: [
2484
+ /* @__PURE__ */ jsx("h3", { className: "caos-exec-notes-title", children: t(UI.sources, lang) }),
2485
+ /* @__PURE__ */ jsx("ol", { className: "caos-exec-notes", "data-exec-notes": "", children: order.map((id, i) => {
2486
+ const src = sourceOf(id);
2487
+ return /* @__PURE__ */ jsxs("li", { id: `exec-note-${i + 1}`, "data-exec-source": id, children: [
2488
+ /* @__PURE__ */ jsx("a", { href: src.url, target: "_blank", rel: "noopener noreferrer", "data-exec-source-title": "", children: t(src.title, lang) }),
2489
+ src.note && /* @__PURE__ */ jsxs(Fragment, { children: [
2490
+ " ",
2491
+ /* @__PURE__ */ jsx("span", { className: "caos-exec-note-text", "data-exec-source-note": "", children: t(src.note, lang) })
2492
+ ] })
2493
+ ] }, id);
2494
+ }) })
2495
+ ] }),
2496
+ /* @__PURE__ */ jsxs("nav", { className: "caos-exec-links", "data-exec-links": "", "aria-label": t(UI.onward, lang), children: [
2497
+ /* @__PURE__ */ jsx(
2498
+ "a",
2499
+ {
2500
+ href: "#technical",
2501
+ className: "caos-exec-link",
2502
+ "data-exec-link": "technical",
2503
+ onClick: (e) => {
2504
+ e.preventDefault();
2505
+ if (onOpenTechnical) onOpenTechnical();
2506
+ else openSiblingTechnical(e.currentTarget);
2507
+ },
2508
+ children: t(ONWARD_LINKS.technical, lang)
2509
+ }
2510
+ ),
2511
+ routed ? /* @__PURE__ */ jsx(Link, { to: APP_ROUTE, className: "caos-exec-link", "data-exec-link": "app", children: t(ONWARD_LINKS.app, lang) }) : /* @__PURE__ */ jsx("a", { href: `${base}${APP_ROUTE.slice(1)}`, className: "caos-exec-link", "data-exec-link": "app", children: t(ONWARD_LINKS.app, lang) })
2512
+ ] })
2513
+ ] });
2514
+ }
1209
2515
  function Question({ question, answer }) {
1210
2516
  return /* @__PURE__ */ jsxs("div", { className: "caos-qa", "data-qa": "", children: [
1211
2517
  /* @__PURE__ */ jsx("p", { className: "caos-qa-question", "data-question": "", children: question }),
@@ -1236,7 +2542,7 @@ function viewParamOf(option) {
1236
2542
  }
1237
2543
  function SurfacePage({ title, lede, actions, tabs, value, onChange, deepLinkView = true, ariaLabel, instrument, children }) {
1238
2544
  const lang = useShellLang();
1239
- const [open, select] = useUrlView((tabs ?? []).map((t) => t.id), tabs ? viewParamOf(deepLinkView) : null, value, onChange);
2545
+ const [open, select] = useUrlView((tabs ?? []).map((t2) => t2.id), tabs ? viewParamOf(deepLinkView) : null, value, onChange);
1240
2546
  const head = title !== void 0 || lede !== void 0 || actions !== void 0;
1241
2547
  return /* @__PURE__ */ jsxs("div", { className: "page-body wide caos-surface", "data-surface": "", children: [
1242
2548
  head && /* @__PURE__ */ jsxs("div", { className: "caos-surface-head", children: [
@@ -1388,9 +2694,9 @@ function BarChart({ title, data, axis, orientation = "horizontal", values = true
1388
2694
  const barH = Math.min(rowH * 0.5, 40);
1389
2695
  drawing = /* @__PURE__ */ jsxs("svg", { width, height: drawnHeight, role: "img", "aria-label": name, "data-chart": "", "data-chart-kind": "bars", children: [
1390
2696
  /* @__PURE__ */ jsx("title", { children: name }),
1391
- ticks.map((t, i) => /* @__PURE__ */ jsxs("g", { children: [
1392
- /* @__PURE__ */ jsx("line", { x1: sx(t), x2: sx(t), y1: top, y2: plotBottom, stroke: "var(--color-border)", strokeWidth: t === 0 ? 1.4 : 1 }),
1393
- /* @__PURE__ */ jsx("text", { x: sx(t), y: plotBottom + 6 + LINE - 2, textAnchor: i === 0 && sx(t) - textWidth(tickLabels[i], PX) / 2 < 0 ? "start" : i === ticks.length - 1 && sx(t) + textWidth(tickLabels[i], PX) / 2 > width ? "end" : "middle", fontSize: PX, fill: "var(--color-fg-subtle)", style: { fontFamily: "var(--font-sans)" }, children: tickLabels[i] })
2697
+ ticks.map((t2, i) => /* @__PURE__ */ jsxs("g", { children: [
2698
+ /* @__PURE__ */ jsx("line", { x1: sx(t2), x2: sx(t2), y1: top, y2: plotBottom, stroke: "var(--color-border)", strokeWidth: t2 === 0 ? 1.4 : 1 }),
2699
+ /* @__PURE__ */ jsx("text", { x: sx(t2), y: plotBottom + 6 + LINE - 2, textAnchor: i === 0 && sx(t2) - textWidth(tickLabels[i], PX) / 2 < 0 ? "start" : i === ticks.length - 1 && sx(t2) + textWidth(tickLabels[i], PX) / 2 > width ? "end" : "middle", fontSize: PX, fill: "var(--color-fg-subtle)", style: { fontFamily: "var(--font-sans)" }, children: tickLabels[i] })
1394
2700
  ] }, `t${i}`)),
1395
2701
  /* @__PURE__ */ jsx("text", { x: x0 + (x1 - x0) / 2, y: plotBottom + 6 + LINE + 4 + LINE - 2, textAnchor: "middle", fontSize: PX, fill: "var(--color-fg-subtle)", style: { fontFamily: "var(--font-sans)" }, children: axisTitle }),
1396
2702
  data.map((d, i) => {
@@ -1444,9 +2750,9 @@ function BarChart({ title, data, axis, orientation = "horizontal", values = true
1444
2750
  drawing = /* @__PURE__ */ jsxs("svg", { width, height: h, role: "img", "aria-label": name, "data-chart": "", "data-chart-kind": "bars", children: [
1445
2751
  /* @__PURE__ */ jsx("title", { children: name }),
1446
2752
  /* @__PURE__ */ jsx("text", { x: 0, y: LINE - 2, textAnchor: "start", fontSize: PX, fill: "var(--color-fg-subtle)", style: { fontFamily: "var(--font-sans)" }, children: axisTitle }),
1447
- ticks.map((t, i) => /* @__PURE__ */ jsxs("g", { children: [
1448
- /* @__PURE__ */ jsx("line", { x1: left, x2: width - right, y1: sy(t), y2: sy(t), stroke: "var(--color-border)", strokeWidth: t === 0 ? 1.4 : 1 }),
1449
- /* @__PURE__ */ jsx("text", { x: left - 6, y: sy(t) + 4, textAnchor: "end", fontSize: PX, fill: "var(--color-fg-subtle)", style: { fontFamily: "var(--font-sans)" }, children: tickLabels[i] })
2753
+ ticks.map((t2, i) => /* @__PURE__ */ jsxs("g", { children: [
2754
+ /* @__PURE__ */ jsx("line", { x1: left, x2: width - right, y1: sy(t2), y2: sy(t2), stroke: "var(--color-border)", strokeWidth: t2 === 0 ? 1.4 : 1 }),
2755
+ /* @__PURE__ */ jsx("text", { x: left - 6, y: sy(t2) + 4, textAnchor: "end", fontSize: PX, fill: "var(--color-fg-subtle)", style: { fontFamily: "var(--font-sans)" }, children: tickLabels[i] })
1450
2756
  ] }, `t${i}`)),
1451
2757
  data.map((d, i) => {
1452
2758
  const cx = left + band * i + band / 2;
@@ -1637,7 +2943,7 @@ function CaseWorkbench(props) {
1637
2943
  `CaseWorkbench: ${tabs.length} groups; at most ${MAX_WORKBENCH_GROUPS} peers, then group by question (ADR-0071 rule 5)`
1638
2944
  );
1639
2945
  }
1640
- const [openGroup, selectGroup] = useUrlView(tabs.map((t) => t.id), viewParamOf(deepLinkView), group, onGroupChange);
2946
+ const [openGroup, selectGroup] = useUrlView(tabs.map((t2) => t2.id), viewParamOf(deepLinkView), group, onGroupChange);
1641
2947
  const railHead = cases || variants ? /* @__PURE__ */ jsxs(Fragment, { children: [
1642
2948
  cases && /* @__PURE__ */ jsx(CaseSelector, { lang, ...cases }),
1643
2949
  variants && /* @__PURE__ */ jsx(VariantBar, { ...variants })
@@ -1865,4 +3171,4 @@ function ViewsRow({ children, shares }) {
1865
3171
  }) });
1866
3172
  }
1867
3173
 
1868
- export { AppShell, ArchitectureModal, BREAKPOINTS, BarChart, Callout, CaseSelector, CaseWorkbench, ChipGroup, CitationsProvider, Cite, DOC_AREAS, DocPage, DocReferences, DocRefsScope, DocSection, Equation, Figure, FocusShell, Gauge, Glossary, InlineMath, Knob, LaneBadge, LanguageToggle, MAX_PEER_TABS, MAX_WORKBENCH_GROUPS, PanelBoundary, PlotCard, Question, Readout, ReferenceList, Refs, Stat, SubTabs, SurfacePage, TabGroups, Tabs, ThemeToggle, VariantBar, Verdict, ViewsRow, WorkbenchLayout, WorkbenchShell, WorkbenchStateContext, caseKind, caseTooltip, casesInSource, createVizLoop, firstAppearance, fitLabel, fontFamily, groupByCategory, isStale, makeStateKey, niceStep, niceTicks, readCaseParam, replaceQueryParam, sourcesPresent, textWidth, usePausedViz, useUrlView, useWorkbenchState, validateArchitectureConfig, viewParamOf, widestLabel, withCaseParam };
3174
+ export { AppShell, ArchitectureModal, BREAKPOINTS, BarChart, Callout, CaseSelector, CaseWorkbench, ChipGroup, CitationsProvider, Cite, DOC_AREAS, DocPage, DocReferences, DocRefsScope, DocSection, EXECUTIVE_SCHEMA_VERSION, Equation, ExecutiveView, FOUR_CS, Figure, FocusShell, Gauge, Glossary, InlineMath, Knob, Landing, LaneBadge, LanguageToggle, MAX_PEER_TABS, MAX_WORKBENCH_GROUPS, PanelBoundary, PlotCard, Question, Readout, ReferenceList, Refs, Stat, SubTabs, SurfacePage, TabGroups, Tabs, ThemeToggle, VariantBar, Verdict, ViewsRow, WorkbenchLayout, WorkbenchShell, WorkbenchStateContext, caseKind, caseTooltip, casesInSource, createVizLoop, firstAppearance, fitLabel, fontFamily, groupByCategory, isStale, makeStateKey, niceStep, niceTicks, readCaseParam, replaceQueryParam, sourcesPresent, textWidth, usePausedViz, useUrlView, useWorkbenchState, validateArchitectureConfig, validateExecutive, viewParamOf, widestLabel, withCaseParam };