create-pmos 0.124.0 → 0.126.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/package.json +1 -1
  2. package/payload/KIT-VERSION +2 -2
  3. package/payload/planning/evals/eval-calibration.md +1 -1
  4. package/payload/planning/okrs/health-budgets.md +1 -1
  5. package/payload/scripts/nine-stages.js +81 -0
  6. package/payload/scripts/workflow-state.js +2 -0
  7. package/payload/state/discoveries.md +1 -1
  8. package/payload/state/log.md +1 -1
  9. package/workspace/c3-one-home-test.js +131 -0
  10. package/workspace/fixtures/initiatives-api/list.json +171 -3
  11. package/workspace/fixtures/initiatives-api/roadmap.json +228 -4
  12. package/workspace/fixtures/initiatives-api/sheet.json +57 -1
  13. package/workspace/fixtures/one-home-baseline.json +83 -0
  14. package/workspace/guide/briefing-cards.md +40 -0
  15. package/workspace/guide/index.md +1 -0
  16. package/workspace/guide/layout.md +2 -0
  17. package/workspace/lib/engine/nine-stages.js +81 -0
  18. package/workspace/lib/engine/workflow-state.js +2 -0
  19. package/workspace/lib/facts-async.js +51 -0
  20. package/workspace/lib/item-steps.js +52 -0
  21. package/workspace/lib/jira-status.js +8 -3
  22. package/workspace/lib/jobs-to-be-done.js +52 -0
  23. package/workspace/lib/needs-overdue.js +41 -0
  24. package/workspace/lib/outbox-store.js +87 -0
  25. package/workspace/lib/pm-items.js +115 -0
  26. package/workspace/lib/route-modules.js +21 -0
  27. package/workspace/lib/routes-briefing.js +109 -0
  28. package/workspace/lib/routes-c3-init.js +53 -0
  29. package/workspace/lib/routes-c3-life.js +119 -0
  30. package/workspace/lib/routes-c3-strategy.js +169 -0
  31. package/workspace/lib/routes-c3-timeline.js +191 -0
  32. package/workspace/lib/routes-calendar-import.js +60 -0
  33. package/workspace/lib/routes-calendar-views.js +61 -0
  34. package/workspace/lib/routes-doc-health.js +79 -0
  35. package/workspace/lib/routes-doc-sheet.js +169 -0
  36. package/workspace/lib/routes-forecast.js +85 -0
  37. package/workspace/lib/routes-hooks.js +121 -0
  38. package/workspace/lib/routes-initiatives.js +3 -0
  39. package/workspace/lib/routes-intake.js +24 -0
  40. package/workspace/lib/routes-outbox.js +97 -0
  41. package/workspace/lib/routes-pm-items.js +216 -0
  42. package/workspace/lib/routes-records.js +61 -0
  43. package/workspace/lib/routes-releases.js +129 -0
  44. package/workspace/lib/routes-report-facts.js +84 -0
  45. package/workspace/lib/routes-report-families.js +32 -0
  46. package/workspace/lib/routes-roadmap-ops.js +141 -0
  47. package/workspace/lib/routes-runs.js +119 -0
  48. package/workspace/lib/routes-signals.js +50 -0
  49. package/workspace/lib/run-answers.js +69 -0
  50. package/workspace/package-lock.json +2 -2
  51. package/workspace/package.json +1 -1
  52. package/workspace/public/c3.html +26 -0
  53. package/workspace/public/pm/briefing-deck.js +413 -0
  54. package/workspace/public/pm/briefing-model.js +211 -0
  55. package/workspace/public/pm/c3-breakdown.js +240 -0
  56. package/workspace/public/pm/c3-brief.js +278 -0
  57. package/workspace/public/pm/c3-cal-strategy.js +528 -0
  58. package/workspace/public/pm/c3-case.js +185 -0
  59. package/workspace/public/pm/c3-daypart.js +176 -0
  60. package/workspace/public/pm/c3-demo-brief-ix.js +350 -0
  61. package/workspace/public/pm/c3-demo-cal-ix.js +74 -0
  62. package/workspace/public/pm/c3-demo-cal2.js +66 -0
  63. package/workspace/public/pm/c3-demo-cal3.js +173 -0
  64. package/workspace/public/pm/c3-demo-data.js +560 -0
  65. package/workspace/public/pm/c3-demo-init.js +373 -0
  66. package/workspace/public/pm/c3-demo-life.js +77 -0
  67. package/workspace/public/pm/c3-demo-misc2.js +46 -0
  68. package/workspace/public/pm/c3-demo-plan2.js +30 -0
  69. package/workspace/public/pm/c3-demo-rep-ix.js +126 -0
  70. package/workspace/public/pm/c3-demo-rep2.js +92 -0
  71. package/workspace/public/pm/c3-demo-term.js +153 -0
  72. package/workspace/public/pm/c3-demo-time.js +49 -0
  73. package/workspace/public/pm/c3-demo-work-ix.js +80 -0
  74. package/workspace/public/pm/c3-demo-work2.js +13 -0
  75. package/workspace/public/pm/c3-demo.js +113 -0
  76. package/workspace/public/pm/c3-doc-sheet.js +314 -0
  77. package/workspace/public/pm/c3-dock.js +180 -0
  78. package/workspace/public/pm/c3-docs.js +290 -0
  79. package/workspace/public/pm/c3-expand.js +96 -0
  80. package/workspace/public/pm/c3-init-extras.js +170 -0
  81. package/workspace/public/pm/c3-lifecycle-panels.js +476 -0
  82. package/workspace/public/pm/c3-misc-panels.js +89 -0
  83. package/workspace/public/pm/c3-plan-panels.js +163 -0
  84. package/workspace/public/pm/c3-plan.js +192 -0
  85. package/workspace/public/pm/c3-roadmap.js +249 -0
  86. package/workspace/public/pm/c3-sheet.js +107 -0
  87. package/workspace/public/pm/c3-shell.js +674 -0
  88. package/workspace/public/pm/c3-signals.js +196 -0
  89. package/workspace/public/pm/c3-strategy-panels.js +45 -0
  90. package/workspace/public/pm/c3-swipe.js +230 -0
  91. package/workspace/public/pm/c3-terminal-data.js +26 -0
  92. package/workspace/public/pm/c3-terminal-edge.js +91 -0
  93. package/workspace/public/pm/c3-terminal-icons.js +41 -0
  94. package/workspace/public/pm/c3-terminal-results.js +141 -0
  95. package/workspace/public/pm/c3-terminal.js +52 -0
  96. package/workspace/public/pm/c3-tickets.js +163 -0
  97. package/workspace/public/pm/c3-timeline.js +201 -0
  98. package/workspace/public/pm/c3-toast.js +16 -0
  99. package/workspace/public/pm/calendar-views.js +1014 -0
  100. package/workspace/public/pm/console3-lift.md +220 -0
  101. package/workspace/public/pm/console3.css +1547 -0
  102. package/workspace/public/pm/dest-initiatives.js +16 -3
  103. package/workspace/public/pm/dest-mywork.js +8 -1
  104. package/workspace/public/pm/dest-reports.js +47 -1
  105. package/workspace/public/pm/dest-today.js +55 -1
  106. package/workspace/public/pm/doc-health-panel.js +110 -0
  107. package/workspace/public/pm/doc-rail.js +9 -3
  108. package/workspace/public/pm/lifecycle-lens-model.js +228 -0
  109. package/workspace/public/pm/lifecycle-lens.js +261 -0
  110. package/workspace/public/pm/new-initiative-sheet.js +116 -21
  111. package/workspace/public/pm/outbox-panel.js +125 -0
  112. package/workspace/public/pm/pm-work-view.js +895 -0
  113. package/workspace/public/pm/releases-view.js +248 -0
  114. package/workspace/public/pm/report-families-view.js +503 -0
  115. package/workspace/public/pm/run-card.js +244 -0
  116. package/workspace/public/pm/sessions-panel.js +149 -0
  117. package/workspace/public/pm/shell-bell.js +162 -0
  118. package/workspace/public/pm/shell-model.js +83 -0
  119. package/workspace/public/pm/shell-phone.js +124 -0
  120. package/workspace/public/pm/shell-readaloud.js +53 -0
  121. package/workspace/public/pm/shell-recording.js +110 -0
  122. package/workspace/public/pm/shell-ticker.js +90 -0
  123. package/workspace/public/pm/slide-confirm.js +163 -0
  124. package/workspace/public/pm/timeline-forecast-view.js +164 -0
  125. package/workspace/public/pm/today-day.js +8 -2
  126. package/workspace/public/pm/tokens.css +1 -0
  127. package/workspace/server.js +5 -2
  128. package/workspace/test-files.json +21 -3
  129. package/workspace/test-lists/browser-suites-green.json +5 -0
@@ -0,0 +1,173 @@
1
+ /* pm/c3-demo-cal3.js — DEMO fixtures for the Calendar's Quarter and Year panes on /c3.html?demo=1 (c3-cal-strategy.js reads them).
2
+ * The content is the console3 mockup's own (console3.html: NSA/nsPlan line 2824, KRS 2857, SIGS 2861 and 3713, SIGC 2872 and 3714, SYNM 2887,
3
+ * MATP 2892, BETS 2910, stratCase 2919, CALC 2999 to 3015, calCards 3143, commits 2706). It answers GET /api/c3-strategy in the shape of
4
+ * workspace/lib/routes-c3-strategy.js, plus the demo-only extras the real route has no source for: `head` (the lens line), `deck` (the six cards of each
5
+ * zoom), `delivery` (the commitments of progSVG, initiatives and tasks), `direction` (the case file of the direction card) and `maturity`.
6
+ *
7
+ * Wiring: c3-demo.js imports this file for its side effect (one line). The import runs before c3-demo.js reads window.fetch, so the fetch wrapper
8
+ * installed here sits UNDER c3-demo.js's own: a path this file does not answer falls through to whatever was there. Real mode never loads it. */
9
+
10
+ const MNS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
11
+ const mlab = (i) => MNS[(i + 9) % 12] + " '" + (25 + Math.floor((i + 9) / 12));
12
+ const key = (i) => { const t = 2025 * 12 + 9 + i; return Math.floor(t / 12) + '-' + String((t % 12) + 1).padStart(2, '0'); };
13
+ const NSA = [9.4, 9.8, 10.2, 10.5, 10.9, 11.2, 11.5, 11.7, 11.9, 12.1, 12.15, 12.28, 12.4];
14
+ const plan = (i) => (i <= 12 ? 9.4 + (12.9 - 9.4) * (i / 12) : 12.9 + (18 - 12.9) * ((i - 12) / 11));
15
+ const slope = (NSA[12] - NSA[9]) / 3;
16
+ const proj = (i) => NSA[12] + slope * (i - 12);
17
+ const cross = (f) => { for (let i = 13; i <= 23; i++) if (proj(i) < plan(i) * f) return i; return -1; };
18
+ const nsVar = () => Math.round((NSA[12] / plan(12) - 1) * 100);
19
+ const LEAVE = mlab(cross(0.92)); const PIVOT = mlab(cross(0.85)); const VAR = Math.abs(nsVar());
20
+
21
+ const NORTH = { label: 'Weekly active accounts', unit: 'k', now: key(12), by: '2027-09-30',
22
+ axis: { quarter: { min: 11, max: 16, ticks: [12, 14, 16] }, year: { min: 8, max: 19, ticks: [10, 14, 18] } },
23
+ points: Array.from({ length: 24 }, (_, i) => ({ at: key(i), actual: i <= 12 ? NSA[i] : null, plan: Math.round(plan(i) * 100) / 100, proj: i >= 12 ? Math.round(proj(i) * 100) / 100 : null })) };
24
+
25
+ const OUTCOMES = [
26
+ { id: 'kr-conv', name: 'Conversion', pillar: 'Convert', unit: '%', start: 3.5, target: 4.0, now: 3.1, expected: 3.75, forecast: 2.9, status: 'off', lead: 'Down 6 weeks in a row. The address step loses 45%.', by: '2026-12-31', pivot: false, n_readings: 7 },
27
+ { id: 'kr-ent', name: 'Enterprise design partners', pillar: 'Enterprise', unit: '', start: 0, target: 5, now: 3, expected: 3, forecast: 5, status: 'ok', lead: 'Two more are asking for SCIM early.', by: '2026-12-31', pivot: false, n_readings: 7 },
28
+ { id: 'kr-ret', name: 'Retention, day 30', pillar: 'Retain', unit: '%', start: 40, target: 45, now: 41.5, expected: 42.9, forecast: 43, status: 'drift', lead: 'Flat. Label printing is the top pain.', by: '2026-12-31', pivot: false, n_readings: 7 },
29
+ { id: 'kr-disc', name: 'Returns discovery decided', pillar: 'Retain', unit: ' of 5', start: 0, target: 5, now: 2, expected: 2.5, forecast: 5, status: 'ok', lead: 'Interview 5 on 13 Oct decides park or continue.', by: '2026-12-31', pivot: false, n_readings: 3 },
30
+ ];
31
+
32
+ /* ── cases: the mockup's SIGC, stratCase and CALC, in the shape c3-case.js reads ── */
33
+ const O = (id, l, rec, msg, fx) => ({ id, l, rec: rec ? 1 : 0, msg, fx: fx || [] });
34
+ const CASE = {
35
+ conv: { sit: 'At this slope conversion ends the quarter at 2.9% against 4.0%. The pivot line is 3.0% for two weeks.', conf: 71, cta: 'Slide to confirm',
36
+ chg: [['clock', 'Down 6 weeks in a row', 'Analytics', 'bad'], ['alert', 'Cart to address loses 45%', 'funnel', 'bad'], ['scale', 'Scope change may be the cause', 'Jira', 'warn']],
37
+ opts: [O('x', 'Run the address-step experiment, freeze scope', 1, "Experiment brief is drafting. Scope freeze goes into today's decision.", [['check', 'Tests the cause before pivoting', 'ok'], ['clock', 'Result in 2 weeks']]),
38
+ O('w', 'Wait two more weeks', 0, 'Watching. The agent re-checks in 2 weeks.', [['alert', 'Reaches the pivot line unprepared', 'warn']]),
39
+ O('p', 'Pivot the checkout bet now', 0, 'Pivot review requested for the Quarterly review.', [['alert', 'Trigger not crossed yet', 'bad']])], unsure: 'One quarter of data. A seasonal dip is not ruled out.' },
40
+ ret: { sit: 'Retention has not moved all quarter, while the clearest customer pain sits in returns.', conf: 66, cta: 'Slide to confirm',
41
+ chg: [['clock', 'Day 30 at 41.5% against 45%', 'Analytics', 'warn'], ['notes', '3 of 3 calls name label printing', 'Notes', 'ok'], ['cal', 'Interview 5 on 13 Oct', 'Calendar']],
42
+ opts: [O('f', 'Pull Returns forward a quarter if interview 5 agrees', 1, 'Conditional change drafted for the Q1 plan.', [['check', 'Moves effort to the strongest signal', 'ok']]), O('k', 'Keep the plan', 0, 'Plan unchanged.', [['clock', 'Returns waits until Q1', 'warn']])] },
43
+ slip: { sit: 'The sandbox keys and the accessibility slot sit on the critical path. Cutting scope pulls the slot to 21 Oct and holds the date.', conf: 78, cta: 'Slide to confirm',
44
+ chg: [['clock', 'Keys 2 days late, slot not before 28 Oct', 'Jira', 'bad'], ['scale', 'Cut to 3 flows frees the 21 Oct slot', 'Calendar', 'ok'], ['out', 'Leadership was told 24 Oct', 'Slack', 'warn']],
45
+ opts: [O('c', 'Cut to 3 flows and hold 24 Oct', 1, 'Scenario set to the cut. The timeline and the Calendar follow.', [['check', 'Holds 24 Oct', 'ok']]), O('w', 'Warn leadership now with a new date', 0, 'Draft to Priya is in Review.', [['out', '31 Oct, with the cause', 'ok']]), O('h', 'Hold and watch', 0, 'No change.', [['alert', 'Crosses the 5-day line', 'warn']])], unsure: 'The vendor may deliver the keys sooner.' },
46
+ churn: { sit: 'Three scope changes in four weeks make any date a guess.', conf: 74, cta: 'Slide to confirm', chg: [['scale', '3 changes in 4 weeks', 'Jira', 'warn'], ['doc', 'PRD at v5', 'Confluence']],
47
+ opts: [O('z', "Freeze scope after today's decision", 1, 'Scope freeze added to the decision follow-ups.', [['check', 'Makes the date believable', 'ok']]), O('o', 'Stay flexible', 0, 'No freeze.', [['alert', 'Date stays a guess', 'warn']])] },
48
+ dep: { sit: 'The same vendor delay holds up two bets, so it is a portfolio risk and not a task risk.', conf: 82, cta: 'Slide to confirm', chg: [['alert', 'Sandbox keys 2 days overdue', 'Jira', 'bad'], ['init', 'Blocks Checkout v2 and SSO billing', 'Initiatives', 'warn']],
49
+ opts: [O('e', 'Escalate to the vendor lead today', 1, 'Escalation drafted for you to send.', [['check', 'Unblocks both bets', 'ok']]), O('w', 'Wait until Friday', 0, 'Waiting.', [['clock', 'Crosses 5 days', 'bad']])] },
50
+ rel: { sit: 'Dates have lost trust. Ranges tell leadership the truth about uncertainty.', conf: 69, cta: 'Slide to confirm', chg: [['report', '62% of dated promises kept', 'Reports', 'warn'], ['out', 'Next update to leadership: Fri 16 Oct', 'Calendar']],
51
+ opts: [O('r', 'Switch to ranges for estimates', 1, 'Ranges will be used in the next update.', [['check', 'Rebuilds trust', 'ok']]), O('d', 'Keep dates', 0, 'No change.', [['alert', 'Risks another miss', 'warn']])] },
52
+ gate: { sit: 'Build is far ahead of the evidence. A rubric draft exists but has no weights from you.', conf: 80, cta: 'Slide to confirm', chg: [['shield', 'Spec and rubric exist as drafts', 'gates', 'warn'], ['alert', 'No quality evidence yet', 'CI', 'warn']],
53
+ opts: [O('w', 'Set the rubric weights today', 1, 'Weights opened in Review.', [['check', 'Review can score the build', 'ok']]), O('l', 'Let the agent propose weights', 0, 'Agent proposal drafted.', [['clock', 'You still confirm them']])] },
54
+ ent: { sit: 'Customers are pulling Enterprise forward faster than the plan assumes.', conf: 77, cta: 'Slide to confirm', chg: [['user', '3 design partners live', 'Jira', 'ok'], ['mail', '2 asked for SCIM early', 'Gmail', 'ok'], ['target', '5 partners by Dec is the goal', 'OKR']],
55
+ opts: [O('q', 'Add Enterprise as a Q1 bet', 1, 'Q1 bet drafted for the Quarterly review.', [['check', 'Follows the pull', 'ok'], ['alert', 'Needs capacity from Retain', 'warn']]), O('h', 'Hold the plan', 0, 'No change.', [['alert', 'May lose the window', 'warn']])] },
56
+ };
57
+ const SIGNALS = [
58
+ { id: 'conv', sev: 'drift', t: 'Conversion has fallen six weeks in a row', ev: '3.5% to 3.1%. The address step loses 45% of carts.', thr: 'Below 3.0% for 2 weeks: pivot the checkout bet', ttt: 'about 2 weeks', sp: [3.5, 3.4, 3.4, 3.3, 3.3, 3.2, 3.1] },
59
+ { id: 'ret', sev: 'drift', t: 'Retention is flat while the top pain is returns', ev: 'Day 30 at 41.5% against 45%. 3 of 3 calls name label printing.', thr: 'No lift after interview 5: pull Returns forward', ttt: '5 days', sp: [41, 41.2, 41.4, 41.3, 41.5, 41.4, 41.5] },
60
+ { id: 'slip', sev: 'drift', t: 'Checkout v2 critical path is 7 days late', ev: 'Sandbox keys and the a11y slot move the ship date from 24 to 31 Oct.', thr: 'More than 5 days late: warn leadership', ttt: 'tripped', sp: [0, 0, 2, 4, 7, 7] },
61
+ { id: 'churn', sev: 'watch', t: 'Scope keeps changing on Checkout v2', ev: 'Scope changed 3 times in 4 weeks.', thr: 'A fourth change: re-baseline the plan', ttt: 'next change', sp: [1, 1, 2, 2, 3, 3, 3] },
62
+ { id: 'dep', sev: 'watch', t: 'One vendor blocks two bets', ev: 'Sandbox keys hold up Checkout v2 and SSO billing.', thr: 'More than 5 days overdue: escalate to the sponsor', ttt: '3 days', sp: [0, 0, 0, 1, 1, 2, 2] },
63
+ { id: 'rel', sev: 'watch', t: 'Dated promises are slipping more often', ev: '62% of dated promises kept this quarter against 80%.', thr: 'Below 55%: give ranges, not dates', ttt: '2 to 3 weeks', sp: [85, 80, 78, 72, 68, 65, 62] },
64
+ { id: 'gate', sev: 'watch', t: 'Search relevance has no quality evidence yet', ev: 'Build is 70% done. Quality, review and acceptance are all open.', thr: 'Build without a rubric: block the merge', ttt: '3 days', sp: [0, 0, 0, 1, 1, 2] },
65
+ { id: 'ent', sev: 'up', t: 'Enterprise pull is stronger than planned', ev: '3 design partners live. 2 more asked for SCIM early.', thr: '5 partners by Dec: make Enterprise a Q1 bet', ttt: 'on course', sp: [0, 0, 1, 1, 2, 3, 3] },
66
+ ].map((s) => ({ ...s, case: CASE[s.id], source: 'demo' }));
67
+
68
+ const SYNERGY = { unit: 'pillars',
69
+ columns: [{ id: 'convert', n: 'Convert', icon: 'target' }, { id: 'retain', n: 'Retain', icon: 'repo' }, { id: 'onboard', n: 'Onboard', icon: 'user' }, { id: 'enterprise', n: 'Enterprise', icon: 'shield' }],
70
+ rows: [{ id: 'checkout', title: 'Checkout v2', weights: [3, 0, 1, 0], parked: false, initiative: 'checkout' }, { id: 'returns', title: 'Returns experience', weights: [1, 3, 0, 0], parked: false, initiative: 'returns' },
71
+ { id: 'sso', title: 'SSO', weights: [1, 0, 0, 3], parked: false, initiative: 'sso' }, { id: 'search', title: 'Search relevance', weights: [1, 2, 0, 0], parked: false, initiative: 'search' },
72
+ { id: 'onb', title: 'Self-serve onboarding', weights: [0, 0, 3, 0], parked: true, initiative: 'onb' }],
73
+ notes: [{ icon: 'plus', tone: 'ok', text: 'SSO and Checkout v2 share billing code. Build them together and save about 2 weeks.' }, { icon: 'alert', tone: 'bad', text: 'Returns and Search relevance both need the platform team in November. Capacity clash.' },
74
+ { icon: 'out', tone: '', text: 'Returns findings feed the Q1 onboarding design.' }, { icon: 'user', tone: 'warn', text: 'Dara carries 4 items across 3 bets.' }] };
75
+
76
+ const MATURITY = { stages: ['Discover', 'Prove', 'Repeat', 'Scale', 'Lead'], target_label: "Sep '27", pillars: [
77
+ { n: 'Convert', now: 2, tgt: 4, proj: 3, ev: '3 of 7 criteria met', nx: 'Conversion at 3.8% or more for 4 weeks' }, { n: 'Retain', now: 2, tgt: 3, proj: 3, ev: '2 of 6 criteria met', nx: 'Returns contact rate at 0.5' },
78
+ { n: 'Onboard', now: 1, tgt: 2, proj: 1, ev: '0 of 5 criteria met', nx: 'a revived onboarding bet' }, { n: 'Enterprise', now: 2, tgt: 3, proj: 3, ev: '4 of 6 criteria met', nx: '5 design partners live' }] };
79
+
80
+ const TIMELINE = { quarters: ["Q4 '26", "Q1 '27", "Q2 '27", "Q3 '27"],
81
+ rows: [{ id: 'checkout', title: 'Checkout v2', sub: 'Convert', cells: ['c', 'c', '', ''], st: 'late', initiative: 'checkout' }, { id: 'search', title: 'Search relevance', sub: 'Convert', cells: ['c', '', '', ''], st: 'risk', initiative: 'search' },
82
+ { id: 'returns', title: 'Returns experience', sub: 'Retain', cells: ['c', 'c', '', ''], st: 'ok', initiative: 'returns' }, { id: 'sso', title: 'SSO and SCIM', sub: 'Enterprise', cells: ['c', 'c', 'c', ''], st: 'ok', initiative: 'sso' },
83
+ { id: 'onb', title: 'Self-serve onboarding', sub: 'Onboard', cells: ['', 'p', '', ''], st: 'park', initiative: 'onb' }, { id: 'audit', title: 'Enterprise audit logs', sub: 'Enterprise', cells: ['', 'a', '', ''], st: 'prop', initiative: null }],
84
+ checkpoints: [{ q: 0, f: 0.62, label: 'Returns on 13 Oct' }, { q: 0, f: 0.95, label: 'Quarterly review on 20 Dec' }, { q: 1, f: 0.7, label: 'Mid-quarter check in Feb' }] };
85
+
86
+ /* the commitments of the mockup's progSVG: initiatives (promised and forecast) and the PM's own tasks, as days of the quarter from 1 Oct */
87
+ const dn = (n) => new Date(Date.UTC(2026, 9, n)).toISOString().slice(0, 10);
88
+ const INIT = (id, n, start, due, fc, pct, st, why) => ({ id, n, kind: 'init', start: dn(start), due: dn(due), fc: dn(fc), pct, st, why, go: id });
89
+ const TASK = (id, n, due, st, why, late) => ({ id, n, kind: 'task', due: dn(due), st, why, late: late || 0 });
90
+ const DELIVERY = { rows: [
91
+ INIT('checkout', 'Checkout v2', 1, 24, 31, 0.5, 'late', 'Sandbox keys and the a11y slot move the ship date.'), INIT('returns', 'Returns experience', 1, 20, 20, 0.4, 'ok', 'Discovery, interview 3 of 5.'),
92
+ INIT('sso', 'SSO', 1, 14, 14, 0.75, 'risk', 'Three release gates still open.'), INIT('onb', 'Self-serve onboarding', 1, -1, -1, 0.2, 'park', 'No movement in 9 days. Continue or park?'), INIT('search', 'Search relevance', 1, 37, 37, 0.38, 'risk', 'EN-418 blocked on platform, no reply since Tue.'),
93
+ TASK('t-keys', 'Sandbox keys from the vendor', 6, 'over', 'Asked Tue. No reply in 2 days. Blocks 24 Oct.', 2), TASK('t-num', '1 Oct numbers to Priya', 8, 'ok', 'Priya asked at 07:58. Due 10:30.'), TASK('t-wk', 'Weekly status to leadership', 9, 'risk', 'The draft waits for the 14:00 decision.'),
94
+ TASK('t-sso', 'SSO date to Marta', 12, 'ok', "Promised after Monday's freeze."), TASK('t-int5', 'Interview 5: review the stop rule', 13, 'ok', 'Decides whether returns discovery continues.'), TASK('t-a11y', 'A11y audit slot', 21, 'risk', 'No slot before 28 Oct unless scope is cut.'),
95
+ TASK('t-prd', 'PRD v5 sent to Dara', 7, 'done', 'Sent Wed.'), TASK('t-ssob', 'SSO beta live', 6, 'done', '3 customers, 0 incidents.'), TASK('t-srch', 'Search fix merged', 6, 'done', 'p95 420 to 300 ms.')] };
96
+
97
+ /* ── the direction card's case files (stratCase) and the other deck cards' ── */
98
+ const DIR_Q = { tc: 'var(--warning)', sit: 'Conversion is off course and retention is flat, but the pivot line is not crossed. Fix the cause before changing the bet.', conf: 76, cta: 'Slide to adjust course',
99
+ chg: [['clock', 'Conversion lands at 2.9% against 4.0%', 'forecast', 'bad'], ['up', 'Enterprise is ahead: 3 of 5 partners', 'OKR', 'ok'], ['alert', '2 signals drifting, 3 on watch', 'signals', 'warn']],
100
+ opts: [O('adjust', 'Adjust: freeze scope, run the experiment, prepare Returns', 1, 'Course adjusted. Three follow-ups are in Review.', [['check', 'Tests the cause before pivoting', 'ok'], ['clock', 'Pivot review stays on 20 Dec']]),
101
+ O('persevere', 'Persevere: hold course', 0, 'Holding course. Signals stay on watch.', [['alert', 'Conversion keeps sliding', 'bad']]), O('pivot', 'Pivot the Convert bet', 0, 'Pivot review requested.', [['alert', 'Trigger is about 2 weeks away', 'bad']])],
102
+ unsure: 'One quarter of data.', ign: 'The slope reaches the pivot line in March.' };
103
+ const DIR_Y = { tc: 'var(--warning)', sit: 'The north star is ' + VAR + '% behind plan and the gap is widening. At this slope it leaves tolerance in ' + LEAVE + ' and reaches the pivot line in ' + PIVOT + '.', conf: 72, cta: 'Slide to rebalance',
104
+ chg: [['clock', 'Growth slowed to 0.8% a month, plan needs 3%', 'Analytics', 'bad'], ['up', 'Enterprise pull is the strongest upside', 'Signals', 'ok'], ['flag', 'Convert is one stage short of target', 'Maturity', 'warn']],
105
+ opts: [O('adjust', 'Adjust: shift effort to Enterprise and Retain', 1, 'Rebalance drafted for the Quarterly review.', [['check', 'Follows the strongest evidence', 'ok'], ['alert', 'Convert slows', 'warn']]),
106
+ O('persevere', 'Persevere: hold the plan', 0, 'Holding the plan.', [['alert', 'Leaves tolerance in ' + LEAVE, 'bad']]), O('pivot', 'Pivot: Enterprise-first strategy', 0, 'Pivot study requested.', [['alert', 'Too little evidence yet', 'warn']])],
107
+ unsure: 'Two quarters of Enterprise data.', ign: 'Pivot line reached in ' + PIVOT + '.' };
108
+ const K = (sit, conf, chg, opts, cta) => ({ sit, conf, cta: cta || 'Slide to confirm', chg, opts });
109
+ const CALC = {
110
+ qkr: K('Two outcomes are on course. Conversion is off course and retention is drifting, so the quarter needs a recovery plan, not a new target.', 74,
111
+ [['clock', 'Conversion lands at 2.9% against 4.0%', 'forecast', 'bad'], ['alert', 'Retention lands at 43% against 45%', 'forecast', 'warn'], ['check', 'Enterprise partners and discovery on course', 'OKR', 'ok']],
112
+ [O('rec', 'Keep the targets and add a recovery plan', 1, 'Recovery plan drafted for Conversion and Retention.', [['check', 'Keeps the ambition honest', 'ok']]), O('rb', 'Re-baseline Conversion to 3.4%', 0, 'Re-baseline requested.', [['alert', 'Hides the problem', 'bad']]), O('drop', 'Drop the Retention outcome', 0, 'Drop requested.', [['alert', 'Loses a pillar', 'bad']])], 'Slide to plan recovery'),
113
+ qsyn: K('Two bets share billing code and two others both need the platform team in November. Sequence them to save time and avoid a clash.', 73,
114
+ [['plus', 'SSO and Checkout v2 share billing code', 'Synergy', 'ok'], ['alert', 'Returns and Search relevance both need the platform team in Nov', 'Capacity', 'bad']],
115
+ [O('seq', 'Build the billing code once and move Search to December', 1, 'Sequence proposed for the Quarterly review.', [['check', 'Saves about 2 weeks', 'ok'], ['clock', 'Search slips a month', 'warn']]), O('as', 'Keep the plan', 0, 'No change.', [['alert', 'Clash in November', 'bad']])], 'Slide to sequence'),
116
+ qns: K('The north star is ' + VAR + '% behind plan and grows about 0.8% a month. Plan needs 3%.', 72,
117
+ [['clock', 'Leaves the tolerance band in ' + LEAVE, 'projection', 'warn'], ['alert', 'Reaches the pivot line in ' + PIVOT, 'projection', 'bad']],
118
+ [O('path', 'Draft a recovery path that closes half the gap by March', 1, 'Recovery path drafted.', [['check', 'Gives the review something to decide', 'ok']]), O('tgt', 'Revisit the plan target', 0, 'Review requested.', [['alert', 'Moves the goal, not the work', 'warn']]), O('hold', 'Hold', 0, 'Holding.', [['alert', 'Gap keeps widening', 'bad']])], 'Slide to draft'),
119
+ ymat: K('Two pillars are on course for September and two are one stage short. Convert and Onboard decide whether the year lands.', 70,
120
+ [['flag', 'Convert is one stage short', 'Maturity', 'warn'], ['moon', 'Onboard has no active bet', 'Maturity', 'bad'], ['check', 'Retain and Enterprise are on course', 'Maturity', 'ok']],
121
+ [O('b', 'Revive an Onboard bet in Q2 and focus Convert on the checkout fix', 1, 'Plan change drafted for the Quarterly review.', [['check', 'Closes both gaps', 'ok']]), O('k', 'Keep the plan', 0, 'No change.', [['alert', 'Two pillars stay short', 'warn']])], 'Slide to plan'),
122
+ ybets: K('Every bet has a date to persevere or pivot. The next one is Returns on 13 Oct, then the Quarterly review on 20 Dec.', 78,
123
+ [['flag', 'Returns review on 13 Oct', 'Checkpoint'], ['flag', 'Quarterly review on 20 Dec', 'Checkpoint'], ['spark', 'An agent-proposed Enterprise audit logs bet for Q1', 'Proposal', 'ok']],
124
+ [O('p', 'Add the proposed Enterprise audit logs bet to Q1', 1, 'Bet added to the Q1 draft.', [['check', 'Follows the strongest pull', 'ok']]), O('n', 'Decline the proposal', 0, 'Declined.', [['moon', 'Stays in the log']])], 'Slide to add'),
125
+ yopp: K('Customer pull for Enterprise is stronger than any other signal. An Enterprise-first strategy is worth a short study before the pivot line.', 62,
126
+ [['user', '3 design partners live, 2 asking early', 'Signals', 'ok'], ['flag', 'Enterprise is on course for September', 'Maturity', 'ok'], ['alert', 'Needs capacity from Retain and Convert', 'Capacity', 'warn']],
127
+ [O('st', 'Run a 6-week Enterprise-first study', 1, 'Study scoped as a draft brief.', [['check', 'Tests the pivot cheaply', 'ok']]), O('no', 'Stay with the four pillars', 0, 'No change.', [['clock', 'May miss the window', 'warn']])], 'Slide to scope the study'),
128
+ };
129
+
130
+ const FACTS_SIG = [['clock', '3 drifting'], ['eye', '4 on watch'], ['up', '1 upside']];
131
+ const CONV_NUM = { kind: 'num', big: '2.9', unit: '%', delta: 'lands here at this slope', tone: 'var(--destructive)', arr: [3.5, 3.4, 3.4, 3.3, 3.3, 3.2, 3.1], target: 4 };
132
+ const DECK = {
133
+ quarter: [
134
+ { k: 'qdir', ei: 'target', el: 'Quarter direction', h: 'Adjust course early', sub: '2 of 4 outcomes on course. Conversion is drifting. Enterprise is ahead.', hero: { kind: 'ns' }, facts: FACTS_SIG, case: DIR_Q, dir: true },
135
+ { k: 'qkr', ei: 'target', el: 'Outcomes', h: '2 of 4 outcomes on course', sub: 'Conversion is off course. Retention is drifting.', hero: { kind: 'krs' }, facts: [['flag', 'Quarterly review 20 Dec']], case: CALC.qkr },
136
+ { k: 'qsig', tag: 'critical', h: 'Conversion has fallen six weeks in a row', sub: 'Below 3.0% for 2 weeks is the pivot trigger.', hero: CONV_NUM, facts: [['clock', 'About 2 weeks to the trigger'], ['alert', 'Cart to address loses 45%']], case: CASE.conv },
137
+ { k: 'qsyn', tag: 'opp', h: 'Build SSO and Checkout billing together', sub: 'Saves about 2 weeks. Returns and Search clash on the platform team.', hero: { kind: 'rows', rows: [['plus', 'SSO and Checkout share billing code', 'ok', '+2 wk'], ['alert', 'Returns and Search need the platform team', 'bad', 'clash']] }, facts: [['user', 'Dara carries 4 items']], case: CALC.qsyn },
138
+ { k: 'qwin', tag: 'big', h: 'Enterprise is ahead: 3 of 5 partners', sub: 'Two more asked for SCIM early.', hero: { kind: 'ring', done: 3, total: 5, cap: '3 of 5 partners', sub: '2 more asking' }, facts: [['flag', 'First year-one milestone']], case: CASE.ent },
139
+ { k: 'qns', ei: 'up', el: 'North star', h: 'North star is ' + VAR + '% behind plan', sub: 'Leaves tolerance in ' + LEAVE + ', pivot line in ' + PIVOT + '.', hero: { kind: 'ns' }, facts: [['clock', '0.8% a month, plan needs 3%']], case: CALC.qns },
140
+ ],
141
+ year: [
142
+ { k: 'ydir', ei: 'target', el: 'Year direction', h: 'North star is ' + VAR + '% behind and widening', sub: 'It leaves tolerance in ' + LEAVE + ' and reaches the pivot line in ' + PIVOT + '.', hero: { kind: 'ns' }, facts: FACTS_SIG, case: DIR_Y, dir: true },
143
+ { k: 'ymat', ei: 'flag', el: 'Maturity', h: 'Two pillars one stage short', sub: 'Convert and Onboard decide whether the year lands.', hero: { kind: 'ladder' }, facts: [['flag', 'Target: September 2027']], case: CALC.ymat },
144
+ { k: 'yns', ei: 'up', el: 'North star', h: 'The gap is widening: ' + nsVar() + '% against plan', sub: 'Plan needs 3% a month. We are at 0.8%.', hero: { kind: 'ns' }, facts: [['alert', 'Pivot line in ' + PIVOT]], case: CALC.qns },
145
+ { k: 'ybets', ei: 'flag', el: 'Bets and checkpoints', h: 'Every bet has a date to persevere or pivot', sub: 'Next: Returns on 13 Oct, then the Quarterly review on 20 Dec.', hero: { kind: 'rows', rows: [['flag', 'Returns review', '', '13 Oct'], ['flag', 'Quarterly review', '', '20 Dec'], ['spark', 'Enterprise audit logs proposed', 'ok', 'agent']] }, facts: [['target', '6 bets, 4 pillars']], case: CALC.ybets },
146
+ { k: 'ysig', tag: 'critical', h: 'Conversion is the earliest warning', sub: 'Six weeks down. The pivot trigger is 2 weeks below 3.0%.', hero: { ...CONV_NUM, big: '3.1', delta: 'falling six weeks' }, facts: [['clock', '2 weeks to trigger']], case: CASE.conv },
147
+ { k: 'yopp', tag: 'opp', h: 'An Enterprise-first strategy deserves a study', sub: 'Customer pull is the strongest signal we have.', hero: { kind: 'rows', rows: [['user', '3 design partners live', 'ok'], ['mail', '2 asking for SCIM early', 'ok'], ['alert', 'Needs capacity from Retain', 'warn']] }, facts: [['spark', '6-week study']], case: CALC.yopp },
148
+ ],
149
+ };
150
+
151
+ export const STRATEGY = {
152
+ ok: true, today: '2026-10-08', demo: true, north: NORTH, outcomes: OUTCOMES, signals: SIGNALS, synergy: SYNERGY, timeline: TIMELINE, maturity: MATURITY, delivery: DELIVERY, deck: DECK,
153
+ head: { quarter: { i: 'target', h: 'Q4 is drifting: adjust early, before the pivot line', s: '2 of 4 outcomes on course. Conversion is off course and retention is flat. Enterprise is ahead.', ring: [2, 4] },
154
+ year: { i: 'flag', h: 'North star ' + VAR + '% behind plan, gap widening', s: 'Leaves tolerance in ' + LEAVE + ', reaches the pivot line in ' + PIVOT + ". 2 of 4 pillars on course for Sep '27.", ring: [2, 4] } },
155
+ direction: { state: 'adjust', next: 'Quarterly review, 20 Dec' },
156
+ sources: { kr_metrics: 4, bets: 6, hypotheses: 3, signal_rules: 8 },
157
+ };
158
+
159
+ /* the answer for GET /api/c3-strategy; chained under c3-demo.js's fetch wrapper (see the header) */
160
+ const realFetch = typeof window !== 'undefined' && window.fetch ? window.fetch.bind(window) : null;
161
+ if (realFetch) {
162
+ window.fetch = (input, init) => {
163
+ try {
164
+ const raw = typeof input === 'string' ? input : input instanceof URL ? input.href : input && input.url;
165
+ const method = String((init && init.method) || (input && input.method) || 'GET').toUpperCase();
166
+ const u = new URL(raw, location.origin);
167
+ if (method === 'GET' && u.origin === location.origin && u.pathname === '/api/c3-strategy') {
168
+ return Promise.resolve(new Response(JSON.stringify(STRATEGY), { status: 200, headers: { 'content-type': 'application/json' } }));
169
+ }
170
+ } catch { /* an unreadable request goes on as it is */ }
171
+ return realFetch(input, init);
172
+ };
173
+ }