fraim 2.0.166 → 2.0.167

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 (42) hide show
  1. package/dist/src/ai-hub/catalog.js +20 -27
  2. package/dist/src/ai-hub/server.js +418 -2
  3. package/dist/src/config/ai-manager-hiring.js +121 -0
  4. package/dist/src/config/compat.js +16 -0
  5. package/dist/src/config/feature-flags.js +25 -0
  6. package/dist/src/config/persona-capability-bundles.js +273 -0
  7. package/dist/src/config/persona-hiring.js +270 -0
  8. package/dist/src/config/portfolio-slug-overrides.js +17 -0
  9. package/dist/src/config/pricing.js +37 -0
  10. package/dist/src/config/stripe.js +43 -0
  11. package/dist/src/core/config-loader.js +9 -5
  12. package/dist/src/core/fraim-config-schema.generated.js +0 -21
  13. package/dist/src/core/utils/local-registry-resolver.js +8 -1
  14. package/package.json +5 -1
  15. package/public/ai-hub/index.html +81 -0
  16. package/public/ai-hub/review.css +13 -0
  17. package/public/ai-hub/script.js +414 -4
  18. package/public/ai-hub/styles.css +56 -0
  19. package/public/portfolio/ashley.html +523 -0
  20. package/public/portfolio/auditya.html +83 -0
  21. package/public/portfolio/banke.html +83 -0
  22. package/public/portfolio/beza.html +659 -0
  23. package/public/portfolio/careena.html +632 -0
  24. package/public/portfolio/casey.html +568 -0
  25. package/public/portfolio/celia.html +490 -0
  26. package/public/portfolio/deidre.html +642 -0
  27. package/public/portfolio/gautam.html +597 -0
  28. package/public/portfolio/hari.html +469 -0
  29. package/public/portfolio/huxley.html +1354 -0
  30. package/public/portfolio/index.html +741 -0
  31. package/public/portfolio/maestro.html +518 -0
  32. package/public/portfolio/mandy.html +590 -0
  33. package/public/portfolio/mona.html +597 -0
  34. package/public/portfolio/pam.html +887 -0
  35. package/public/portfolio/procella.html +107 -0
  36. package/public/portfolio/qasm.html +569 -0
  37. package/public/portfolio/ricardo.html +489 -0
  38. package/public/portfolio/sade.html +560 -0
  39. package/public/portfolio/sam.html +654 -0
  40. package/public/portfolio/sechar.html +580 -0
  41. package/public/portfolio/sreya.html +599 -0
  42. package/public/portfolio/swen.html +601 -0
@@ -0,0 +1,568 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-theme="light">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>CaSey · AI Customer Success + Support · FRAIM Portfolio</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
10
+ <style>
11
+ :root {
12
+ --accent: #06b6d4;
13
+ --accent-2: #0891b2;
14
+ --accent-light: #cffafe;
15
+ --text: #0a2240;
16
+ --text-2: #334155;
17
+ --muted: #64748b;
18
+ --bg: #ecfeff;
19
+ --surface: #ffffff;
20
+ --surface-2: #f8fafc;
21
+ --border: #e2e8f0;
22
+ --shadow: 0 4px 24px rgba(10,34,64,.08);
23
+ --shadow-lg: 0 12px 40px rgba(10,34,64,.14);
24
+ --radius: 18px;
25
+ --radius-sm: 10px;
26
+ --green: #10b981;
27
+ --purple: #8b5cf6;
28
+ --amber: #f59e0b;
29
+ --red: #ef4444;
30
+ --code-bg: #0f172a;
31
+ --code-border: #1e293b;
32
+ }
33
+ [data-theme="dark"] {
34
+ --text: #e2e8f0; --text-2: #cbd5e1; --muted: #94a3b8;
35
+ --bg: #061318; --surface: #0a1f26; --surface-2: #0d2830;
36
+ --border: #1e3f4f; --shadow: 0 4px 24px rgba(0,0,0,.35);
37
+ --shadow-lg: 0 12px 40px rgba(0,0,0,.5); --accent-light: #164e63;
38
+ --code-bg: #020c10; --code-border: #0a1f26;
39
+ }
40
+ * { box-sizing: border-box; margin: 0; padding: 0; }
41
+ body { font-family: 'Inter', sans-serif; background: var(--bg); color: var(--text); min-height: 100vh; transition: background .3s, color .3s; }
42
+ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
43
+
44
+ .site-header { position: sticky; top: 0; z-index: 100; display: flex; align-items: center; justify-content: space-between; padding: 14px 32px; background: var(--surface); border-bottom: 1px solid var(--border); }
45
+ .brand { display: flex; align-items: center; gap: 10px; text-decoration: none; }
46
+ .brand-logo { width: 32px; height: 32px; border-radius: 8px; background: linear-gradient(135deg, #10b981, #059669); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px; color: #fff; }
47
+ .brand-name { font-weight: 700; font-size: 15px; color: var(--text); }
48
+ .header-actions { display: flex; align-items: center; gap: 12px; }
49
+ .theme-btn { background: var(--surface-2); border: 1px solid var(--border); color: var(--muted); cursor: pointer; border-radius: 8px; padding: 7px 10px; font-size: 16px; }
50
+
51
+ .hero { max-width: 900px; margin: 56px auto 0; padding: 0 24px; text-align: center; }
52
+ .avatar-ring { display: inline-flex; align-items: center; justify-content: center; width: 96px; height: 96px; border-radius: 50%; background: linear-gradient(135deg, #06b6d4, #10b981, #6366f1); margin-bottom: 24px; box-shadow: 0 0 0 6px var(--accent-light); overflow: hidden; }
53
+ .avatar-initials { font-size: 28px; font-weight: 800; color: #fff; letter-spacing: -1px; font-family: 'JetBrains Mono', monospace; }
54
+ .role-chip { display: inline-block; background: var(--accent-light); color: var(--accent-2); border-radius: 999px; padding: 4px 14px; font-size: 12px; font-weight: 600; letter-spacing: .04em; margin-bottom: 16px; }
55
+ .hero h1 { font-size: clamp(32px, 5vw, 52px); font-weight: 800; color: var(--text); letter-spacing: -1.5px; line-height: 1.1; margin-bottom: 16px; }
56
+ .hero h1 span { color: var(--accent); }
57
+ .hero p { font-size: 17px; color: var(--muted); max-width: 560px; margin: 0 auto 32px; line-height: 1.7; }
58
+
59
+ .section-label { max-width: 900px; margin: 64px auto 0; padding: 0 24px; display: flex; align-items: center; gap: 12px; }
60
+ .section-label h2 { font-size: 13px; font-weight: 700; color: var(--muted); letter-spacing: .08em; text-transform: uppercase; }
61
+ .section-divider { flex: 1; height: 1px; background: var(--border); }
62
+
63
+ .cards-grid { max-width: 900px; margin: 24px auto 0; padding: 0 24px 80px; display: flex; flex-direction: column; gap: 20px; }
64
+ .card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; transition: box-shadow .2s; }
65
+ .card:hover { box-shadow: var(--shadow-lg); }
66
+ .card-header { display: flex; align-items: flex-start; gap: 16px; padding: 24px; cursor: pointer; user-select: none; }
67
+ .card-icon { width: 48px; height: 48px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 22px; flex-shrink: 0; }
68
+ .card-meta { flex: 1; min-width: 0; }
69
+ .card-tag { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; margin-bottom: 6px; }
70
+ .card-title { font-size: 18px; font-weight: 700; color: var(--text); line-height: 1.25; margin-bottom: 6px; }
71
+ .card-subtitle { font-size: 13px; color: var(--muted); }
72
+ .card-toggle { font-size: 22px; color: var(--muted); transition: transform .3s; flex-shrink: 0; align-self: center; }
73
+ .card.open .card-toggle { transform: rotate(90deg); }
74
+ .card-body { display: none; border-top: 1px solid var(--border); padding: 28px; }
75
+ .card.open .card-body { display: block; }
76
+
77
+ .card-context { font-size: 13px; color: var(--muted); font-style: italic; margin-bottom: 20px; line-height: 1.65; padding: 14px 16px; background: var(--surface-2); border-radius: var(--radius-sm); border-left: 3px solid var(--accent); }
78
+
79
+ .narrative { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; margin-bottom: 28px; }
80
+ @media (max-width: 640px) { .narrative { grid-template-columns: 1fr; } }
81
+ .narrative-step { background: var(--surface-2); border-radius: var(--radius-sm); padding: 16px; }
82
+ .step-label { font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin-bottom: 6px; }
83
+ .step-text { font-size: 13px; color: var(--text-2); line-height: 1.6; }
84
+
85
+ .artifact-label { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
86
+ .artifact-label::before { content: ''; display: block; width: 20px; height: 2px; background: var(--accent); border-radius: 2px; }
87
+
88
+ .source-ref { margin-top: 16px; font-size: 12px; color: var(--muted); }
89
+ .source-ref a { color: var(--accent); text-decoration: none; }
90
+ .source-ref a:hover { text-decoration: underline; }
91
+
92
+ .card-hire-cta { margin-top: 20px; display: flex; justify-content: flex-end; }
93
+
94
+ /* ══ ARTIFACT 1 — Customer Health Dashboard ══ */
95
+ .health-dashboard {
96
+ background: #0f172a;
97
+ border-radius: 14px;
98
+ overflow: hidden;
99
+ border: 1px solid #1e293b;
100
+ }
101
+ .health-topbar {
102
+ background: #1e293b;
103
+ padding: 12px 18px;
104
+ display: flex; align-items: center; justify-content: space-between;
105
+ border-bottom: 1px solid #334155;
106
+ }
107
+ .health-topbar-title { font-size: 13px; font-weight: 700; color: #e2e8f0; font-family: 'JetBrains Mono', monospace; }
108
+ .health-stats-row {
109
+ display: flex; gap: 12px; padding: 14px 18px;
110
+ border-bottom: 1px solid #1e293b;
111
+ flex-wrap: wrap;
112
+ }
113
+ .health-badge {
114
+ display: inline-flex; align-items: center; gap: 6px;
115
+ border-radius: 999px; padding: 5px 14px;
116
+ font-size: 12px; font-weight: 700;
117
+ }
118
+ .health-badge.good { background: rgba(16,185,129,.15); color: #34d399; border: 1px solid rgba(16,185,129,.3); }
119
+ .health-badge.warn { background: rgba(245,158,11,.15); color: #fbbf24; border: 1px solid rgba(245,158,11,.3); }
120
+ .health-badge.risk { background: rgba(239,68,68,.15); color: #f87171; border: 1px solid rgba(239,68,68,.3); }
121
+ .health-table { width: 100%; border-collapse: collapse; }
122
+ .health-table th {
123
+ padding: 8px 18px; font-size: 10px; font-weight: 700; letter-spacing: .08em;
124
+ text-transform: uppercase; color: #475569; text-align: left;
125
+ border-bottom: 1px solid #1e293b;
126
+ }
127
+ .health-table td {
128
+ padding: 10px 18px; font-size: 12px; color: #94a3b8;
129
+ border-bottom: 1px solid #0f172a;
130
+ font-family: 'JetBrains Mono', monospace;
131
+ }
132
+ .health-table tr:last-child td { border-bottom: none; }
133
+ .health-table td:first-child { color: #e2e8f0; font-family: 'Inter', sans-serif; font-weight: 600; }
134
+ .score-badge {
135
+ display: inline-flex; align-items: center; justify-content: center;
136
+ width: 44px; height: 22px; border-radius: 6px;
137
+ font-size: 11px; font-weight: 800;
138
+ }
139
+ .score-green { background: rgba(16,185,129,.2); color: #4ade80; border: 1px solid rgba(16,185,129,.3); }
140
+ .score-amber { background: rgba(245,158,11,.2); color: #fbbf24; border: 1px solid rgba(245,158,11,.3); }
141
+ .score-red { background: rgba(239,68,68,.2); color: #f87171; border: 1px solid rgba(239,68,68,.3); }
142
+
143
+ /* ══ ARTIFACT 2 — Support Queue Dashboard ══ */
144
+ .queue-panel {
145
+ background: var(--surface-2);
146
+ border: 1px solid var(--border);
147
+ border-radius: 14px;
148
+ overflow: hidden;
149
+ }
150
+ .queue-header {
151
+ padding: 14px 20px;
152
+ background: var(--surface);
153
+ border-bottom: 1px solid var(--border);
154
+ display: flex; align-items: center; justify-content: space-between;
155
+ }
156
+ .queue-title { font-size: 13px; font-weight: 700; color: var(--text); }
157
+ .queue-meta { font-size: 11px; color: var(--muted); }
158
+ .ticket-row {
159
+ display: flex; align-items: center; gap: 12px;
160
+ padding: 12px 20px;
161
+ border-bottom: 1px solid var(--border);
162
+ }
163
+ .ticket-row:last-of-type { border-bottom: none; }
164
+ .ticket-priority {
165
+ font-size: 11px; font-weight: 800; letter-spacing: .04em;
166
+ width: 28px; flex-shrink: 0;
167
+ }
168
+ .ticket-dot { font-size: 10px; flex-shrink: 0; }
169
+ .ticket-subject { font-size: 13px; font-weight: 600; color: var(--text); flex: 1; min-width: 0; }
170
+ .ticket-company { font-size: 11px; color: var(--muted); flex-shrink: 0; white-space: nowrap; }
171
+ .ticket-age { font-size: 11px; color: var(--muted); font-family: 'JetBrains Mono', monospace; flex-shrink: 0; width: 52px; text-align: right; }
172
+ .ticket-status {
173
+ font-size: 10px; font-weight: 700; letter-spacing: .05em;
174
+ border-radius: 6px; padding: 3px 8px; flex-shrink: 0; white-space: nowrap;
175
+ }
176
+ .status-escalated { background: rgba(239,68,68,.12); color: #f87171; border: 1px solid rgba(239,68,68,.2); }
177
+ .status-assigned { background: rgba(245,158,11,.12); color: #fbbf24; border: 1px solid rgba(245,158,11,.2); }
178
+ .status-open { background: rgba(100,116,139,.12); color: #94a3b8; border: 1px solid rgba(100,116,139,.2); }
179
+ .status-auto { background: rgba(16,185,129,.12); color: #34d399; border: 1px solid rgba(16,185,129,.2); }
180
+ .sla-bar-section {
181
+ padding: 12px 20px; background: var(--surface);
182
+ border-top: 1px solid var(--border);
183
+ display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
184
+ }
185
+ .sla-label { font-size: 11px; font-weight: 700; color: var(--muted); white-space: nowrap; }
186
+ .sla-bar-wrap { flex: 1; min-width: 100px; height: 6px; background: var(--border); border-radius: 999px; overflow: hidden; }
187
+ .sla-bar-fill { height: 100%; background: linear-gradient(90deg, #06b6d4, #10b981); border-radius: 999px; }
188
+ .sla-remaining { font-size: 11px; font-weight: 700; color: #06b6d4; font-family: 'JetBrains Mono', monospace; white-space: nowrap; }
189
+
190
+ /* ══ ARTIFACT 3 — Survey Campaign Results ══ */
191
+ .survey-results-card {
192
+ background: var(--surface-2);
193
+ border: 1px solid var(--border);
194
+ border-radius: 14px;
195
+ overflow: hidden;
196
+ }
197
+ .survey-header {
198
+ padding: 16px 20px;
199
+ background: var(--surface);
200
+ border-bottom: 1px solid var(--border);
201
+ display: flex; align-items: center; justify-content: space-between;
202
+ }
203
+ .survey-title { font-size: 14px; font-weight: 700; color: var(--text); }
204
+ .survey-period { font-size: 11px; color: var(--muted); }
205
+ .survey-body { padding: 20px; }
206
+ .response-rate-block { text-align: center; margin-bottom: 24px; }
207
+ .response-rate-big { font-size: 56px; font-weight: 800; color: #06b6d4; line-height: 1; font-family: 'JetBrains Mono', monospace; }
208
+ .response-rate-label { font-size: 12px; color: var(--muted); margin-top: 4px; }
209
+ .response-rate-avg { font-size: 11px; color: var(--muted); margin-top: 2px; }
210
+ .nps-bars { display: flex; flex-direction: column; gap: 10px; margin-bottom: 20px; }
211
+ .nps-bar-row { display: flex; align-items: center; gap: 10px; }
212
+ .nps-bar-label { font-size: 12px; font-weight: 600; color: var(--text-2); width: 120px; flex-shrink: 0; }
213
+ .nps-bar-track { flex: 1; height: 10px; background: var(--border); border-radius: 999px; overflow: hidden; }
214
+ .nps-bar-fill-cyan { height: 100%; background: #06b6d4; border-radius: 999px; }
215
+ .nps-bar-fill-gray { height: 100%; background: #94a3b8; border-radius: 999px; }
216
+ .nps-bar-fill-red { height: 100%; background: #ef4444; border-radius: 999px; }
217
+ .nps-bar-pct { font-size: 12px; font-weight: 700; color: var(--text); width: 36px; text-align: right; flex-shrink: 0; }
218
+ .nps-score-block { text-align: center; padding: 14px; border-top: 1px solid var(--border); }
219
+ .nps-score-num { font-size: 40px; font-weight: 800; color: var(--text); font-family: 'JetBrains Mono', monospace; }
220
+ .nps-score-label { font-size: 11px; color: var(--muted); margin-top: 2px; }
221
+ .nps-footer-note { font-size: 12px; color: #10b981; font-weight: 600; text-align: center; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
222
+
223
+ /* Footer */
224
+ .portfolio-footer { background: var(--surface); border-top: 1px solid var(--border); padding: 40px 24px; text-align: center; }
225
+ .footer-sub { margin-top: 20px; font-size: 12px; color: var(--muted); }
226
+ .footer-sub a { color: var(--accent); text-decoration: none; }
227
+
228
+ @media (max-width: 640px) {
229
+ .site-header { padding: 12px 16px; }
230
+ .hero { margin-top: 36px; }
231
+ .cards-grid { padding: 0 16px 60px; }
232
+ .card-header { padding: 18px; }
233
+ .card-body { padding: 18px; }
234
+ .section-label { margin-top: 40px; padding: 0 16px; }
235
+ .health-stats-row { gap: 8px; }
236
+ .ticket-company { display: none; }
237
+ .ticket-age { display: none; }
238
+ }
239
+ </style>
240
+ </head>
241
+ <body>
242
+
243
+ <header class="site-header">
244
+ <a class="brand" href="/">
245
+ <div class="brand-logo">F</div>
246
+ <span class="brand-name">FRAIM</span>
247
+ </a>
248
+ <div class="header-actions">
249
+ <button class="theme-btn" onclick="toggleTheme()" title="Toggle dark mode">☾</button>
250
+ </div>
251
+ </header>
252
+
253
+ <section class="hero">
254
+ <div class="avatar-ring">
255
+ <img src="https://api.dicebear.com/9.x/notionists/svg?seed=CASEY-cx&backgroundColor=a5f3fc&radius=50" width="96" height="96" alt="CASEY-cx avatar" style="border-radius:50%;">
256
+ </div>
257
+ <div class="role-chip">AI Customer Success + Support</div>
258
+ <h1>Customers stay.<br><span>Issues close.</span> Health scores rise.</h1>
259
+ <p>CaSey monitors account health signals, triages support queues, and runs survey campaigns that customers actually respond to — so churn stays low and your team stays focused.</p>
260
+ </section>
261
+
262
+ <div class="section-label">
263
+ <h2>Selected Work</h2>
264
+ <div class="section-divider"></div>
265
+ </div>
266
+
267
+ <div class="cards-grid">
268
+
269
+ <!-- Card 1: Customer Health Scoring -->
270
+ <div class="card open" id="card1">
271
+ <div class="card-header" onclick="toggleCard(1)">
272
+ <div class="card-icon" style="background:#cffafe;">📊</div>
273
+ <div class="card-meta">
274
+ <div class="card-tag" style="color:#06b6d4;">Account Health</div>
275
+ <div class="card-title">Churn spotted 6 weeks before it would have happened</div>
276
+ <div class="card-subtitle">CustomerEQ · member-360 · get_member_360 API</div>
277
+ </div>
278
+ <div class="card-toggle">›</div>
279
+ </div>
280
+ <div class="card-body">
281
+ <div class="card-context">A B2B SaaS had 340 active accounts and no systematic way to identify which ones were at risk — until renewals came up and it was too late to save them.</div>
282
+
283
+ <div class="narrative">
284
+ <div class="narrative-step">
285
+ <div class="step-label">The hidden signals</div>
286
+ <div class="step-text">Customer health signals are always present. Login frequency drops 3 weeks before a customer disengages. A feature they loved gets abandoned 2 weeks before they tell you the product isn't working for them. A champion leaves the company 4 weeks before the renewal conversation changes tone. None of these signals were visible because they weren't being monitored.</div>
287
+ </div>
288
+ <div class="narrative-step">
289
+ <div class="step-label">What CaSey Did</div>
290
+ <div class="step-text">CaSey built the health scoring system on top of CustomerEQ's member-360 API: NPS responses (40% weight), product usage frequency (30%), support ticket sentiment — are tickets frustrated or curious? — (20%), and stakeholder engagement — has the main contact gone dark? — (10%). Scores update weekly. Accounts below 40 trigger an automated check-in workflow.</div>
291
+ </div>
292
+ <div class="narrative-step">
293
+ <div class="step-label">The Outcome</div>
294
+ <div class="step-text">23 at-risk accounts identified in the first scoring run. 18 received proactive outreach within 48 hours. 14 renewed (61% save rate). Without the system, all 23 would have gone through renewal unwarned. $840K ARR retained.</div>
295
+ </div>
296
+ </div>
297
+
298
+ <div class="artifact-label">Live Artifact — Customer Health Dashboard</div>
299
+
300
+ <div class="health-dashboard">
301
+ <div class="health-topbar">
302
+ <span class="health-topbar-title">Customer Health — May 2026</span>
303
+ <span style="font-size:11px;color:#475569;">340 accounts · updated weekly</span>
304
+ </div>
305
+ <div class="health-stats-row">
306
+ <span class="health-badge good">● 304 Healthy</span>
307
+ <span class="health-badge warn">● 13 Monitor</span>
308
+ <span class="health-badge risk">● 23 At Risk</span>
309
+ </div>
310
+ <table class="health-table">
311
+ <thead>
312
+ <tr>
313
+ <th>Company</th>
314
+ <th>NPS</th>
315
+ <th>Usage</th>
316
+ <th>Sentiment</th>
317
+ <th>Health Score</th>
318
+ </tr>
319
+ </thead>
320
+ <tbody>
321
+ <tr>
322
+ <td>Acme Corp</td>
323
+ <td>9</td>
324
+ <td>Daily</td>
325
+ <td>😊</td>
326
+ <td><span class="score-badge score-green">91</span></td>
327
+ </tr>
328
+ <tr>
329
+ <td>BluePeak</td>
330
+ <td>6</td>
331
+ <td>Weekly</td>
332
+ <td>😐</td>
333
+ <td><span class="score-badge score-amber">64</span></td>
334
+ </tr>
335
+ <tr>
336
+ <td>TechFlow</td>
337
+ <td>4</td>
338
+ <td>Rare</td>
339
+ <td>😟</td>
340
+ <td><span class="score-badge score-red">28</span></td>
341
+ </tr>
342
+ <tr>
343
+ <td>Meridian</td>
344
+ <td>8</td>
345
+ <td>Daily</td>
346
+ <td>😊</td>
347
+ <td><span class="score-badge score-green">88</span></td>
348
+ </tr>
349
+ <tr>
350
+ <td>Apex Co</td>
351
+ <td>3</td>
352
+ <td>None</td>
353
+ <td>😟</td>
354
+ <td><span class="score-badge score-red">18</span></td>
355
+ </tr>
356
+ </tbody>
357
+ </table>
358
+ </div>
359
+
360
+ <div class="source-ref">
361
+ 📎 Source: <a href="#">CustomerEQ · get_member_360 · CustomerEQ MCP API</a>
362
+ </div>
363
+ <div class="card-hire-cta">
364
+ </div>
365
+ </div>
366
+ </div>
367
+
368
+ <!-- Card 2: Support Queue Management -->
369
+ <div class="card" id="card2">
370
+ <div class="card-header" onclick="toggleCard(2)">
371
+ <div class="card-icon" style="background:#cffafe;">🎯</div>
372
+ <div class="card-meta">
373
+ <div class="card-tag" style="color:#06b6d4;">Support Velocity</div>
374
+ <div class="card-title">4-hour resolution. Was 3 days.</div>
375
+ <div class="card-subtitle">CustomerEQ · support-queue-management · list_support_conversations</div>
376
+ </div>
377
+ <div class="card-toggle">›</div>
378
+ </div>
379
+ <div class="card-body">
380
+ <div class="card-context">A 200-customer SaaS had a support queue with 47 open tickets, some 5 days old. The support team of 2 was triaging manually — no priority scoring, no escalation rules.</div>
381
+
382
+ <div class="narrative">
383
+ <div class="narrative-step">
384
+ <div class="step-label">The broken queue</div>
385
+ <div class="step-text">Support queues without triage rules age uniformly. A 5-minute question and a critical production blocker both sit in the same queue, prioritized by who happened to submit first. Customers with critical issues wait 2 days. Customers with simple questions wait 2 days. Nobody is happy, and the simple questions could have been resolved in 4 minutes.</div>
386
+ </div>
387
+ <div class="narrative-step">
388
+ <div class="step-label">What CaSey Did</div>
389
+ <div class="step-text">CaSey implemented a triage system via CustomerEQ's conversation API: severity detection from ticket content (keywords: "production," "blocking," "can't access" → P0 auto-escalate; "how to," "question," "feature request" → P3 queue), SLA timers with escalation to Slack at 1 hour / 4 hours / 1 day, and an auto-responder for the 40% of tickets matching solved KB articles.</div>
390
+ </div>
391
+ <div class="narrative-step">
392
+ <div class="step-label">The Outcome</div>
393
+ <div class="step-text">Median first-response time dropped from 18 hours to 47 minutes. P0 resolution time: 4 hours (was 3 days — no escalation existed). 38% of tickets auto-resolved by KB article matching. Support team headcount stayed at 2 despite 60% customer growth.</div>
394
+ </div>
395
+ </div>
396
+
397
+ <div class="artifact-label">Live Artifact — Support Queue Dashboard</div>
398
+
399
+ <div class="queue-panel">
400
+ <div class="queue-header">
401
+ <span class="queue-title">Support Queue — Live View</span>
402
+ <span class="queue-meta">47 open tickets · 2 agents</span>
403
+ </div>
404
+
405
+ <div class="ticket-row">
406
+ <span class="ticket-priority" style="color:#ef4444;">P0</span>
407
+ <span class="ticket-dot">🔴</span>
408
+ <span class="ticket-subject">Production: API returning 500s</span>
409
+ <span class="ticket-company">Acme Corp</span>
410
+ <span class="ticket-age">1h 12m</span>
411
+ <span class="ticket-status status-escalated">ESCALATED</span>
412
+ </div>
413
+ <div class="ticket-row">
414
+ <span class="ticket-priority" style="color:#f97316;">P1</span>
415
+ <span class="ticket-dot">🟠</span>
416
+ <span class="ticket-subject">Data sync not working since update</span>
417
+ <span class="ticket-company">BluePeak</span>
418
+ <span class="ticket-age">2h 45m</span>
419
+ <span class="ticket-status status-assigned">ASSIGNED</span>
420
+ </div>
421
+ <div class="ticket-row">
422
+ <span class="ticket-priority" style="color:#eab308;">P2</span>
423
+ <span class="ticket-dot">🟡</span>
424
+ <span class="ticket-subject">Report export missing columns</span>
425
+ <span class="ticket-company">Meridian</span>
426
+ <span class="ticket-age">4h 10m</span>
427
+ <span class="ticket-status status-open">OPEN</span>
428
+ </div>
429
+ <div class="ticket-row">
430
+ <span class="ticket-priority" style="color:#10b981;">P3</span>
431
+ <span class="ticket-dot">🟢</span>
432
+ <span class="ticket-subject">How to configure webhooks?</span>
433
+ <span class="ticket-company">TechFlow</span>
434
+ <span class="ticket-age">12m</span>
435
+ <span class="ticket-status status-auto">AUTO-RESOLVED (KB match)</span>
436
+ </div>
437
+ <div class="ticket-row" style="border-bottom:none;">
438
+ <span class="ticket-priority" style="color:#10b981;">P3</span>
439
+ <span class="ticket-dot">🟢</span>
440
+ <span class="ticket-subject">What's the rate limit?</span>
441
+ <span class="ticket-company">Apex Co</span>
442
+ <span class="ticket-age">8m</span>
443
+ <span class="ticket-status status-auto">AUTO-RESOLVED (KB match)</span>
444
+ </div>
445
+
446
+ <div class="sla-bar-section">
447
+ <span class="sla-label">P0 SLA: 4h</span>
448
+ <div class="sla-bar-wrap"><div class="sla-bar-fill" style="width:70%;"></div></div>
449
+ <span class="sla-remaining">Remaining: 2h 48m</span>
450
+ </div>
451
+ </div>
452
+
453
+ <div class="source-ref">
454
+ 📎 Source: <a href="#">CustomerEQ · support-queue-management · list_support_conversations</a>
455
+ </div>
456
+ <div class="card-hire-cta">
457
+ </div>
458
+ </div>
459
+ </div>
460
+
461
+ <!-- Card 3: Survey Campaign Management -->
462
+ <div class="card" id="card3">
463
+ <div class="card-header" onclick="toggleCard(3)">
464
+ <div class="card-icon" style="background:#cffafe;">📣</div>
465
+ <div class="card-meta">
466
+ <div class="card-tag" style="color:#06b6d4;">Voice of Customer</div>
467
+ <div class="card-title">74% response rate. Industry average: 22%.</div>
468
+ <div class="card-subtitle">CustomerEQ · survey-campaign-management · create_survey API</div>
469
+ </div>
470
+ <div class="card-toggle">›</div>
471
+ </div>
472
+ <div class="card-body">
473
+ <div class="card-context">A SaaS company was running quarterly NPS surveys with a 19% response rate — too low to be statistically meaningful for their 340-account base.</div>
474
+
475
+ <div class="narrative">
476
+ <div class="narrative-step">
477
+ <div class="step-label">The spiral</div>
478
+ <div class="step-text">Low survey response rates are a self-fulfilling spiral: low responses → low data quality → vague insights → no action → customers feel unheard → lower responses next time. The standard industry NPS survey is sent via bulk email at 9am Tuesday to everyone at once, with no personalization and no follow-up.</div>
479
+ </div>
480
+ <div class="narrative-step">
481
+ <div class="step-label">What CaSey Did</div>
482
+ <div class="step-text">CaSey rebuilt the survey campaign: segmented accounts by health score, sent from the assigned CSM's name, personalized the first sentence to reference each account's most-used feature, sent at the time each contact typically opens email (SendTime optimization via engagement history), and triggered a personal follow-up from CaSey for any detractor (score ≤ 6) within 6 hours.</div>
483
+ </div>
484
+ <div class="narrative-step">
485
+ <div class="step-label">The Outcome</div>
486
+ <div class="step-text">NPS survey response rate rose from 19% to 74%. Detractor follow-up converted 8 of 11 detractors into passives or promoters within 30 days. Net Promoter Score rose from +31 to +58. The VP of Customer Success used the campaign as the model for every subsequent survey.</div>
487
+ </div>
488
+ </div>
489
+
490
+ <div class="artifact-label">Live Artifact — NPS Campaign Results</div>
491
+
492
+ <div class="survey-results-card">
493
+ <div class="survey-header">
494
+ <span class="survey-title">NPS Campaign — Q2 2026</span>
495
+ <span class="survey-period">340 accounts · sent May 2026</span>
496
+ </div>
497
+ <div class="survey-body">
498
+ <div class="response-rate-block">
499
+ <div class="response-rate-big">74%</div>
500
+ <div class="response-rate-label">Response Rate</div>
501
+ <div class="response-rate-avg">Industry avg: 22%</div>
502
+ </div>
503
+
504
+ <div class="nps-bars">
505
+ <div class="nps-bar-row">
506
+ <span class="nps-bar-label">Promoters (9–10)</span>
507
+ <div class="nps-bar-track"><div class="nps-bar-fill-cyan" style="width:58%;"></div></div>
508
+ <span class="nps-bar-pct">58%</span>
509
+ </div>
510
+ <div class="nps-bar-row">
511
+ <span class="nps-bar-label">Passives (7–8)</span>
512
+ <div class="nps-bar-track"><div class="nps-bar-fill-gray" style="width:27%;"></div></div>
513
+ <span class="nps-bar-pct">27%</span>
514
+ </div>
515
+ <div class="nps-bar-row">
516
+ <span class="nps-bar-label">Detractors (0–6)</span>
517
+ <div class="nps-bar-track"><div class="nps-bar-fill-red" style="width:15%;"></div></div>
518
+ <span class="nps-bar-pct">15%</span>
519
+ </div>
520
+ </div>
521
+
522
+ <div class="nps-score-block">
523
+ <div class="nps-score-num">+43</div>
524
+ <div class="nps-score-label">Net Promoter Score</div>
525
+ </div>
526
+
527
+ <div class="nps-footer-note">8/11 detractors → passives within 30 days ✓</div>
528
+ </div>
529
+ </div>
530
+
531
+ <div class="source-ref">
532
+ 📎 Source: <a href="#">CustomerEQ · survey-campaign-management · create_survey</a>
533
+ </div>
534
+ <div class="card-hire-cta">
535
+ </div>
536
+ </div>
537
+ </div>
538
+
539
+ </div>
540
+
541
+ <footer class="portfolio-footer">
542
+ <div class="footer-sub">
543
+ Part of the <a href="/">FRAIM</a> · 18 AI employees available ·
544
+ <a href="/">Back to FRAIM</a>
545
+ </div>
546
+ </footer>
547
+
548
+ <script>
549
+ function toggleTheme() {
550
+ const html = document.documentElement;
551
+ const isDark = html.getAttribute('data-theme') === 'dark';
552
+ html.setAttribute('data-theme', isDark ? 'light' : 'dark');
553
+ document.querySelector('.theme-btn').textContent = isDark ? '☾' : '☀';
554
+ }
555
+ if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
556
+ document.documentElement.setAttribute('data-theme', 'dark');
557
+ document.querySelector('.theme-btn').textContent = '☀';
558
+ }
559
+ function toggleCard(num) {
560
+ const card = document.getElementById('card' + num);
561
+ const isOpen = card.classList.contains('open');
562
+ document.querySelectorAll('.card').forEach(c => c.classList.remove('open'));
563
+ if (!isOpen) { card.classList.add('open'); card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }
564
+ }
565
+ </script>
566
+
567
+ </body>
568
+ </html>