@orchyn/mcp 1.9.0 β†’ 1.9.1

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.
@@ -1,11 +1,15 @@
1
1
  /**
2
- * Single unified HTML template for all Orchyn MCP tools.
2
+ * MCP Apps HTML UI template for Orchyn tools.
3
3
  *
4
- * The host renders this in a sandboxed iframe. After the MCP Apps handshake,
5
- * the host pushes the tool result via `ui/notifications/tool-result`.
6
- * The template auto-detects the data shape and renders the appropriate view.
7
- *
8
- * No external dependencies β€” pure HTML + CSS + JS, fully inline.
4
+ * Features:
5
+ * - Skeleton loading shimmer while tool executes
6
+ * - Smooth fade-in transitions when data arrives
7
+ * - Expandable analysis sections (click to expand/collapse)
8
+ * - Click-to-copy on hashtags, hooks, quotes
9
+ * - Hover micro-interactions on cards
10
+ * - Dark/light theme auto-detection
11
+ * - Progress indicator for multi-step tools
12
+ * - Responsive layout
9
13
  */
10
14
  export const ORCHYN_UI_TEMPLATE = `<!DOCTYPE html>
11
15
  <html lang="en">
@@ -14,193 +18,240 @@ export const ORCHYN_UI_TEMPLATE = `<!DOCTYPE html>
14
18
  <meta name="viewport" content="width=device-width,initial-scale=1"/>
15
19
  <title>Orchyn</title>
16
20
  <style>
17
- :root {
18
- --bg: #ffffff; --fg: #111827; --muted: #6b7280; --border: #e5e7eb;
19
- --card-bg: #ffffff; --tag-bg: #f3f4f6; --accent: #14151a;
20
- --tiktok: #000; --instagram: #E1306C; --youtube: #FF0000;
21
- --douyin: #000; --xiaohongshu: #FF2442; --twitter: #1DA1F2; --bilibili: #00A1D6;
22
- }
23
- @media(prefers-color-scheme:dark){
24
- :root {
25
- --bg: #1a1a2e; --fg: #f0f0f0; --muted: #9ca3af; --border: #374151;
26
- --card-bg: #16213e; --tag-bg: #1f2937; --accent: #e2e8f0;
27
- }
28
- }
29
- * { margin:0; padding:0; box-sizing:border-box; }
30
- body { font-family: system-ui,-apple-system,sans-serif; background:var(--bg); color:var(--fg); padding:12px; }
31
- .loading { color:var(--muted); font-size:14px; text-align:center; padding:40px 0; }
32
- .gallery { display:flex; flex-wrap:wrap; gap:10px; }
33
- .card {
34
- border:1px solid var(--border); border-radius:12px; overflow:hidden;
35
- width:300px; background:var(--card-bg); display:inline-block;
36
- vertical-align:top; box-shadow:0 1px 3px rgba(0,0,0,0.06);
37
- transition: box-shadow 0.2s;
38
- }
39
- .card:hover { box-shadow:0 4px 12px rgba(0,0,0,0.12); }
40
- .card-wide { max-width:520px; width:100%; }
41
- .card img { width:100%; height:200px; object-fit:cover; display:block; }
42
- .card-wide img { max-height:340px; }
43
- .card-body { padding:12px 14px; }
44
- .badge {
45
- display:inline-block; padding:2px 8px; border-radius:999px;
46
- font-size:11px; font-weight:700; text-transform:capitalize;
47
- }
48
- .handle { font-size:12px; color:var(--muted); }
49
- .title { font-size:14px; font-weight:600; line-height:1.3; margin:6px 0; }
50
- .card-wide .title { font-size:16px; font-weight:700; }
51
- .stats { display:flex; flex-wrap:wrap; gap:4px; align-items:center; }
52
- .stat {
53
- display:inline-flex; align-items:center; gap:3px;
54
- font-size:12px; color:var(--muted);
55
- }
56
- .stat-pill {
57
- font-size:13px; color:var(--fg); background:var(--tag-bg);
58
- padding:4px 10px; border-radius:999px;
59
- }
60
- .dot { color:var(--border); margin:0 2px; }
61
- .btn {
62
- display:inline-block; margin-top:10px; padding:6px 14px;
63
- color:#fff; border-radius:999px; text-decoration:none;
64
- font-size:12px; font-weight:600; transition:opacity 0.2s;
65
- }
66
- .btn:hover { opacity:0.85; }
67
- .section { margin-bottom:12px; }
68
- .section-label {
69
- font-size:11px; font-weight:700; color:var(--muted);
70
- text-transform:uppercase; letter-spacing:0.05em; margin-bottom:4px;
71
- }
72
- .section-text { font-size:13px; color:var(--fg); line-height:1.5; }
73
- .tag {
74
- display:inline-block; padding:3px 10px; border-radius:999px;
75
- font-size:12px; margin:2px;
76
- }
77
- .bar-track {
78
- height:8px; background:var(--tag-bg); border-radius:999px;
79
- overflow:hidden; flex:1;
80
- }
81
- .bar-fill { height:100%; border-radius:999px; transition:width 0.4s ease; }
82
- .quote-box {
83
- background:var(--tag-bg); padding:8px 12px; border-radius:8px;
84
- font-size:13px; font-weight:600; line-height:1.4; margin:4px 0;
85
- }
86
- .comment-row {
87
- padding:8px 0; border-bottom:1px solid var(--border);
88
- display:flex; justify-content:space-between; align-items:flex-start; gap:8px;
89
- }
90
- .comment-row:last-child { border-bottom:none; }
91
- .creator-card {
92
- border:1px solid var(--border); border-radius:12px; padding:14px;
93
- width:220px; background:var(--card-bg); display:inline-block;
94
- vertical-align:top; margin:4px; box-shadow:0 1px 3px rgba(0,0,0,0.05);
95
- }
96
- .avatar {
97
- width:48px; height:48px; border-radius:50%; object-fit:cover;
98
- }
99
- .avatar-placeholder {
100
- width:48px; height:48px; border-radius:50%;
101
- display:flex; align-items:center; justify-content:center; font-size:20px;
102
- }
103
- .verified {
104
- display:inline-block; width:16px; height:16px; border-radius:50%;
105
- color:#fff; font-size:10px; line-height:16px; text-align:center; margin-left:4px;
106
- }
107
- .sound-card {
108
- border:1px solid var(--border); border-radius:12px; padding:12px;
109
- width:260px; background:var(--card-bg); display:inline-block;
110
- vertical-align:top; margin:4px; box-shadow:0 1px 3px rgba(0,0,0,0.05);
111
- }
112
- .sound-cover {
113
- width:64px; height:64px; border-radius:8px; object-fit:cover;
114
- }
115
- .credits-card {
116
- border:1px solid var(--border); border-radius:14px; max-width:360px;
117
- background:var(--card-bg); margin:8px 0; padding:20px;
118
- box-shadow:0 2px 8px rgba(0,0,0,0.06);
119
- }
120
- .tier-badge {
121
- display:inline-block; padding:3px 10px; background:#eff6ff;
122
- border-radius:999px; font-size:11px; color:#1e40af; font-weight:600;
123
- }
124
- .free-tag {
125
- display:inline-block; padding:3px 8px; background:#d1fae5;
126
- border-radius:999px; font-size:11px; color:#065f46; margin:2px;
127
- }
128
- .json-block {
129
- background:var(--tag-bg); border:1px solid var(--border);
130
- border-radius:8px; padding:12px; font-size:12px;
131
- font-family:monospace; white-space:pre-wrap; word-break:break-all;
132
- max-height:300px; overflow-y:auto; margin-top:8px;
133
- }
21
+ :root{
22
+ --bg:#fafbfc;--fg:#111827;--muted:#6b7280;--border:#e5e7eb;
23
+ --card:#fff;--card-hover:#f9fafb;--tag:#f3f4f6;--accent:#14151a;
24
+ --shadow-sm:0 1px 2px rgba(0,0,0,.05);--shadow-md:0 4px 12px rgba(0,0,0,.08);
25
+ --shadow-lg:0 8px 24px rgba(0,0,0,.12);--radius:12px;--radius-sm:8px;
26
+ --transition:all .25s cubic-bezier(.4,0,.2,1);
27
+ --green:#10b981;--amber:#f59e0b;--red:#ef4444;--blue:#3b82f6;
28
+ }
29
+ @media(prefers-color-scheme:dark){:root{
30
+ --bg:#0f172a;--fg:#f1f5f9;--muted:#94a3b8;--border:#1e293b;
31
+ --card:#1e293b;--card-hover:#273548;--tag:#1e293b;--accent:#e2e8f0;
32
+ --shadow-sm:0 1px 2px rgba(0,0,0,.2);--shadow-md:0 4px 12px rgba(0,0,0,.3);
33
+ --shadow-lg:0 8px 24px rgba(0,0,0,.4);
34
+ }}
35
+ *{margin:0;padding:0;box-sizing:border-box;}
36
+ body{font-family:system-ui,-apple-system,'Segoe UI',sans-serif;background:var(--bg);color:var(--fg);padding:16px;line-height:1.5;}
37
+
38
+ /* ─── Loading / Skeleton ─── */
39
+ .loading-container{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:48px 24px;gap:16px;}
40
+ .loading-spinner{width:32px;height:32px;border:3px solid var(--border);border-top-color:var(--accent);border-radius:50%;animation:spin .8s linear infinite;}
41
+ @keyframes spin{to{transform:rotate(360deg)}}
42
+ .loading-text{font-size:14px;color:var(--muted);animation:pulse 1.5s ease-in-out infinite;}
43
+ @keyframes pulse{0%,100%{opacity:1}50%{opacity:.5}}
44
+
45
+ .skeleton{background:var(--tag);border-radius:var(--radius-sm);overflow:hidden;position:relative;}
46
+ .skeleton::after{content:'';position:absolute;inset:0;background:linear-gradient(90deg,transparent,rgba(255,255,255,.08),transparent);animation:shimmer 1.5s infinite;}
47
+ @keyframes shimmer{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}
48
+ .skeleton-thumb{width:100%;height:180px;border-radius:var(--radius) var(--radius) 0 0;}
49
+ .skeleton-line{height:14px;margin:8px 14px;border-radius:4px;}
50
+ .skeleton-line.short{width:60%;}
51
+ .skeleton-line.medium{width:80%;}
52
+ .skeleton-badge{width:80px;height:20px;border-radius:999px;margin:12px 14px 0;}
53
+ .skeleton-gallery{display:flex;flex-wrap:wrap;gap:10px;}
54
+ .skeleton-card{width:300px;border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;background:var(--card);}
55
+ .skeleton-creator{width:220px;border:1px solid var(--border);border-radius:var(--radius);padding:14px;background:var(--card);}
56
+ .skeleton-avatar{width:48px;height:48px;border-radius:50%;margin-bottom:8px;}
57
+
58
+ /* ─── Content entrance ─── */
59
+ .fade-in{animation:fadeIn .4s ease-out;}
60
+ @keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
61
+ .stagger>*{opacity:0;animation:fadeIn .4s ease-out forwards;}
62
+ .stagger>*:nth-child(1){animation-delay:.05s}
63
+ .stagger>*:nth-child(2){animation-delay:.1s}
64
+ .stagger>*:nth-child(3){animation-delay:.15s}
65
+ .stagger>*:nth-child(4){animation-delay:.2s}
66
+ .stagger>*:nth-child(5){animation-delay:.25s}
67
+ .stagger>*:nth-child(6){animation-delay:.3s}
68
+ .stagger>*:nth-child(7){animation-delay:.35s}
69
+ .stagger>*:nth-child(8){animation-delay:.4s}
70
+
71
+ /* ─── Cards ─── */
72
+ .gallery{display:flex;flex-wrap:wrap;gap:10px;}
73
+ .card{border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;width:300px;background:var(--card);display:inline-block;vertical-align:top;box-shadow:var(--shadow-sm);transition:var(--transition);cursor:default;}
74
+ .card:hover{box-shadow:var(--shadow-md);transform:translateY(-2px);border-color:var(--muted);}
75
+ .card-wide{max-width:520px;width:100%;}
76
+ .card img{width:100%;height:200px;object-fit:cover;display:block;transition:transform .3s ease;}
77
+ .card:hover img{transform:scale(1.02);}
78
+ .card-wide img{max-height:340px;}
79
+ .card-body{padding:14px 16px;}
80
+
81
+ /* ─── Badges & Tags ─── */
82
+ .badge{display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:999px;font-size:11px;font-weight:700;text-transform:capitalize;transition:var(--transition);}
83
+ .handle{font-size:12px;color:var(--muted);margin-left:auto;}
84
+ .tag{display:inline-flex;align-items:center;gap:3px;padding:4px 10px;border-radius:999px;font-size:12px;margin:2px;transition:var(--transition);cursor:default;}
85
+ .tag.clickable{cursor:pointer;user-select:none;}
86
+ .tag.clickable:hover{filter:brightness(.9);transform:scale(1.05);}
87
+ .tag.clickable:active{transform:scale(.97);}
88
+ .tag.copied{background:var(--green)!important;color:#fff!important;}
89
+
90
+ /* ─── Typography ─── */
91
+ .title{font-size:14px;font-weight:600;line-height:1.35;margin:6px 0;}
92
+ .card-wide .title{font-size:16px;font-weight:700;}
93
+ .caption{font-size:13px;color:var(--muted);line-height:1.5;margin:6px 0 0;}
94
+
95
+ /* ─── Stats ─── */
96
+ .stats{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-top:8px;}
97
+ .stat-pill{display:inline-flex;align-items:center;gap:4px;font-size:12px;color:var(--fg);background:var(--tag);padding:5px 12px;border-radius:999px;transition:var(--transition);}
98
+ .stat-pill:hover{background:var(--border);}
99
+
100
+ /* ─── Buttons ─── */
101
+ .btn{display:inline-flex;align-items:center;gap:6px;margin-top:12px;padding:8px 18px;color:#fff;border-radius:999px;text-decoration:none;font-size:13px;font-weight:600;transition:var(--transition);border:none;cursor:pointer;}
102
+ .btn:hover{filter:brightness(1.1);transform:translateY(-1px);box-shadow:var(--shadow-sm);}
103
+ .btn:active{transform:translateY(0);filter:brightness(.95);}
104
+ .btn-sm{padding:5px 12px;font-size:11px;margin-top:8px;}
105
+
106
+ /* ─── Sections (expandable) ─── */
107
+ .section{margin-bottom:14px;border-radius:var(--radius-sm);overflow:hidden;}
108
+ .section-header{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--tag);border-radius:var(--radius-sm);cursor:pointer;transition:var(--transition);user-select:none;}
109
+ .section-header:hover{background:var(--border);}
110
+ .section-label{font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;}
111
+ .section-chevron{font-size:12px;color:var(--muted);transition:transform .2s ease;}
112
+ .section-header.open .section-chevron{transform:rotate(180deg);}
113
+ .section-content{padding:10px 12px;max-height:0;overflow:hidden;transition:max-height .3s ease,padding .3s ease;}
114
+ .section-content.open{max-height:600px;padding:10px 12px;}
115
+ .section-text{font-size:13px;color:var(--fg);line-height:1.6;}
116
+
117
+ /* ─── Progress bar ─── */
118
+ .progress-bar{height:6px;background:var(--tag);border-radius:999px;overflow:hidden;margin:6px 0;}
119
+ .progress-fill{height:100%;border-radius:999px;transition:width .6s cubic-bezier(.4,0,.2,1);background:linear-gradient(90deg,var(--blue),var(--green));}
120
+
121
+ /* ─── Hook strength ─── */
122
+ .hook-bar-track{display:flex;align-items:center;gap:10px;margin-top:6px;}
123
+ .hook-bar{flex:1;height:10px;background:var(--tag);border-radius:999px;overflow:hidden;}
124
+ .hook-bar-fill{height:100%;border-radius:999px;transition:width .8s cubic-bezier(.4,0,.2,1);}
125
+ .hook-score{font-size:15px;font-weight:800;min-width:40px;text-align:right;}
126
+
127
+ /* ─── Quote box ─── */
128
+ .quote-box{background:var(--tag);padding:10px 14px;border-radius:var(--radius-sm);font-size:13px;font-weight:600;line-height:1.45;margin:6px 0;border-left:3px solid var(--blue);position:relative;}
129
+ .quote-box .copy-btn{position:absolute;top:8px;right:8px;background:var(--card);border:1px solid var(--border);border-radius:6px;padding:3px 8px;font-size:10px;color:var(--muted);cursor:pointer;transition:var(--transition);opacity:0;}
130
+ .quote-box:hover .copy-btn{opacity:1;}
131
+ .copy-btn:hover{background:var(--accent);color:#fff;}
132
+
133
+ /* ─── Comments ─── */
134
+ .comment-row{padding:10px 0;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:flex-start;gap:10px;transition:var(--transition);}
135
+ .comment-row:last-child{border-bottom:none;}
136
+ .comment-row:hover{background:var(--tag);margin:0 -6px;padding:10px 6px;border-radius:var(--radius-sm);}
137
+
138
+ /* ─── Creator cards ─── */
139
+ .creator-card{border:1px solid var(--border);border-radius:var(--radius);padding:16px;width:230px;background:var(--card);display:inline-block;vertical-align:top;margin:4px;box-shadow:var(--shadow-sm);transition:var(--transition);}
140
+ .creator-card:hover{box-shadow:var(--shadow-md);transform:translateY(-2px);}
141
+ .avatar{width:52px;height:52px;border-radius:50%;object-fit:cover;border:2px solid var(--border);}
142
+ .avatar-placeholder{width:52px;height:52px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:22px;}
143
+ .verified{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;color:#fff;font-size:10px;margin-left:4px;}
144
+
145
+ /* ─── Sound cards ─── */
146
+ .sound-card{border:1px solid var(--border);border-radius:var(--radius);padding:14px;width:270px;background:var(--card);display:inline-block;vertical-align:top;margin:4px;box-shadow:var(--shadow-sm);transition:var(--transition);}
147
+ .sound-card:hover{box-shadow:var(--shadow-md);transform:translateY(-2px);}
148
+ .sound-cover{width:68px;height:68px;border-radius:var(--radius-sm);object-fit:cover;}
149
+
150
+ /* ─── Credits ─── */
151
+ .credits-card{border:1px solid var(--border);border-radius:16px;max-width:380px;background:var(--card);margin:8px 0;padding:24px;box-shadow:var(--shadow-md);}
152
+ .tier-badge{display:inline-flex;align-items:center;padding:4px 12px;background:linear-gradient(135deg,#eff6ff,#dbeafe);border-radius:999px;font-size:12px;color:#1e40af;font-weight:700;}
153
+ .free-tag{display:inline-flex;align-items:center;gap:3px;padding:4px 10px;background:linear-gradient(135deg,#d1fae5,#a7f3d0);border-radius:999px;font-size:11px;color:#065f46;font-weight:600;margin:2px;transition:var(--transition);}
154
+ .free-tag:hover{transform:scale(1.05);}
155
+
156
+ /* ─── JSON fallback ─── */
157
+ .json-block{background:var(--tag);border:1px solid var(--border);border-radius:var(--radius-sm);padding:14px;font-size:12px;font-family:'SF Mono',Monaco,monospace;white-space:pre-wrap;word-break:break-all;max-height:320px;overflow-y:auto;margin-top:10px;}
158
+
159
+ /* ─── Empty state ─── */
160
+ .empty-state{text-align:center;padding:48px 24px;color:var(--muted);}
161
+ .empty-state .icon{font-size:48px;margin-bottom:12px;}
162
+ .empty-state .text{font-size:14px;}
134
163
  </style>
135
164
  </head>
136
165
  <body>
137
- <div id="app"><div class="loading">Loading…</div></div>
166
+ <div id="app">
167
+ <div class="loading-container">
168
+ <div class="loading-spinner"></div>
169
+ <div class="loading-text">Loading results…</div>
170
+ </div>
171
+ </div>
138
172
  <script>
139
173
  (function(){
140
- let nextId=1;
141
- const pending=new Map();
174
+ var nextId=1;var pending=new Map();
175
+ var loadingTimer=null;
142
176
 
143
177
  function send(method,params){
144
- const id=nextId++;
145
- return new Promise((resolve,reject)=>{
146
- pending.set(id,{resolve,reject});
147
- window.parent.postMessage({jsonrpc:"2.0",id,method,params},"*");
178
+ var id=nextId++;
179
+ return new Promise(function(resolve,reject){
180
+ pending.set(id,{resolve:resolve,reject:reject});
181
+ window.parent.postMessage({jsonrpc:"2.0",id:id,method:method,params:params},"*");
148
182
  });
149
183
  }
150
184
 
151
185
  window.addEventListener("message",function(ev){
152
- const d=ev.data;
153
- if(!d||typeof d!=="object")return;
186
+ var d=ev.data;if(!d||typeof d!=="object")return;
154
187
  if(d.id&&pending.has(d.id)){
155
- const p=pending.get(d.id);
156
- pending.delete(d.id);
188
+ var p=pending.get(d.id);pending.delete(d.id);
157
189
  if(d.error)p.reject(new Error(d.error.message||JSON.stringify(d.error)));
158
- else p.resolve(d.result);
159
- return;
190
+ else p.resolve(d.result);return;
160
191
  }
161
192
  if(d.method==="ui/notifications/tool-result"){
193
+ clearTimeout(loadingTimer);
162
194
  render(d.params);
163
195
  }
164
- if(d.method==="ui/notifications/tool-input"){
165
- // Tool input available β€” could show loading state
196
+ if(d.method==="ui/notifications/tool-input-partial"){
197
+ updateProgress(d.params);
166
198
  }
167
199
  });
168
200
 
201
+ // Show skeleton after 300ms of waiting (feels instant but shows loading for slow tools)
202
+ loadingTimer=setTimeout(function(){
203
+ var app=document.getElementById("app");
204
+ if(app)app.innerHTML=renderSkeleton();
205
+ },300);
206
+
169
207
  // MCP Apps handshake
170
208
  send("ui/initialize",{
171
209
  protocolVersion:"2026-01-26",
172
210
  capabilities:{},
173
- clientInfo:{name:"orchyn-view",version:"1.0.0"}
211
+ clientInfo:{name:"orchyn-view",version:"2.0.0"}
174
212
  }).then(function(){
175
213
  window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/initialized",params:{}},"*");
176
214
  }).catch(function(){});
177
215
 
216
+ // ─── Helpers ───
178
217
  function esc(s){return String(s||"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");}
179
218
  function fmtNum(n){n=Number(n)||0;return n>=1e6?(n/1e6).toFixed(1)+"M":n>=1e3?(n/1e3).toFixed(1)+"K":String(n);}
180
219
  function pColor(p){return{tiktok:"#000",instagram:"#E1306C",youtube:"#FF0000",douyin:"#000",xiaohongshu:"#FF2442",twitter:"#1DA1F2",x:"#1DA1F2",bilibili:"#00A1D6"}[p]||"#6B7280";}
181
220
  function pEmoji(p){return{tiktok:"🎡",instagram:"πŸ“Έ",youtube:"▢️",douyin:"🎢",xiaohongshu:"πŸ“•",twitter:"🐦",x:"🐦",bilibili:"πŸ“Ί"}[p]||"πŸ”—";}
182
221
 
222
+ function copyText(text){
223
+ navigator.clipboard.writeText(text).catch(function(){});
224
+ }
225
+
226
+ // ─── Skeleton ───
227
+ function renderSkeleton(){
228
+ return '<div class="skeleton-gallery stagger">'
229
+ +Array(3).fill(0).map(function(){
230
+ return '<div class="skeleton-card">'
231
+ +'<div class="skeleton skeleton-thumb"></div>'
232
+ +'<div class="skeleton skeleton-badge"></div>'
233
+ +'<div class="skeleton skeleton-line medium"></div>'
234
+ +'<div class="skeleton skeleton-line short"></div>'
235
+ +'</div>';
236
+ }).join("")+'</div>';
237
+ }
238
+
239
+ // ─── Post Card ───
183
240
  function postCard(p,wide){
184
- var platform=p.platform||"unknown";
185
- var color=pColor(platform);
186
- var emoji=pEmoji(platform);
187
- var title=p.title||p.caption||"";
188
- var handle=p.creatorHandle||"";
189
- var url=p.externalUrl||"";
190
- var thumb=p.thumbnailUrl||"";
191
- var ct=p.contentType||"post";
241
+ var platform=p.platform||"unknown",color=pColor(platform),emoji=pEmoji(platform);
242
+ var title=p.title||p.caption||"",handle=p.creatorHandle||"",url=p.externalUrl||"";
243
+ var thumb=p.thumbnailUrl||"",ct=p.contentType||"post";
192
244
  var views=p.views||0,likes=p.likes||0,comments=p.comments||0,shares=p.shares||0;
193
245
  var cls=wide?"card card-wide":"card";
194
- var statsHtml="";
195
- [[views,"πŸ‘οΈ"],[likes,"❀️"],[comments,"πŸ’¬"],[shares,"πŸ”„"]].forEach(function(s){
196
- if(s[0]>0)statsHtml+='<span class="stat">'+s[1]+" "+fmtNum(s[0])+"</span>";
197
- });
246
+ var statsHtml=[[views,"πŸ‘οΈ"],[likes,"❀️"],[comments,"πŸ’¬"],[shares,"πŸ”„"]]
247
+ .filter(function(s){return s[0]>0})
248
+ .map(function(s){return'<span class="stat-pill">'+s[1]+" "+fmtNum(s[0])+"</span>";}).join("");
198
249
  var handleHtml=handle?'<span class="handle">@'+esc(handle)+"</span>":"";
199
- var linkHtml=url?'<a href="'+esc(url)+'" target="_blank" class="btn" style="background:'+color+'">View on '+esc(platform)+" β†’</a>":"";
200
- var thumbHtml=thumb?'<img src="'+esc(thumb)+'" alt="thumbnail"/>':"";
250
+ var linkHtml=url?'<a href="'+esc(url)+'" target="_blank" class="btn" style="background:'+color+'">View on '+esc(platform)+' β†’</a>':"";
251
+ var thumbHtml=thumb?'<img src="'+esc(thumb)+'" alt="thumbnail" loading="lazy"/>':"";
201
252
  var ctTag=wide?'<span style="font-size:12px;color:var(--muted);text-transform:capitalize">'+esc(ct)+"</span>":"";
202
253
  return '<div class="'+cls+'">'+thumbHtml+'<div class="card-body">'
203
- +'<div style="display:flex;align-items:center;gap:6px;margin-bottom:6px">'
254
+ +'<div style="display:flex;align-items:center;gap:6px;margin-bottom:4px">'
204
255
  +'<span class="badge" style="background:'+color+'15;color:'+color+'">'+emoji+" "+esc(platform)+"</span>"
205
256
  +ctTag+handleHtml+"</div>"
206
257
  +'<div class="title">'+esc(title.length>160?title.slice(0,160)+"…":title)+"</div>"
@@ -208,146 +259,166 @@ export const ORCHYN_UI_TEMPLATE = `<!DOCTYPE html>
208
259
  +linkHtml+"</div></div>";
209
260
  }
210
261
 
262
+ // ─── Creator Card ───
211
263
  function creatorCard(c){
212
- var platform=c.platform||"tiktok";
213
- var color=pColor(platform);
214
- var emoji=pEmoji(platform);
215
- var username=c.username||c.uniqueId||"";
216
- var nickname=c.nickname||c.displayName||username;
217
- var followers=c.followers||c.followerCount||0;
218
- var sig=(c.signature||c.bio||"").slice(0,100);
219
- var verified=c.verified||false;
220
- var avatar=c.avatarUrl||c.avatar_thumb||"";
264
+ var platform=c.platform||"tiktok",color=pColor(platform),emoji=pEmoji(platform);
265
+ var username=c.username||c.uniqueId||"",nickname=c.nickname||c.displayName||username;
266
+ var followers=c.followers||c.followerCount||0,sig=(c.signature||c.bio||"").slice(0,100);
267
+ var verified=c.verified||false,avatar=c.avatarUrl||c.avatar_thumb||"";
221
268
  var avatarHtml=avatar
222
- ?'<img class="avatar" src="'+esc(avatar)+'" alt="avatar"/>'
269
+ ?'<img class="avatar" src="'+esc(avatar)+'" alt="avatar" loading="lazy"/>'
223
270
  :'<div class="avatar-placeholder" style="background:'+color+'20">'+emoji+"</div>";
224
271
  var vBadge=verified?'<span class="verified" style="background:'+color+'">βœ“</span>':"";
225
272
  return '<div class="creator-card">'
226
- +'<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px">'
273
+ +'<div style="display:flex;align-items:center;gap:12px;margin-bottom:10px">'
227
274
  +avatarHtml+"<div>"
228
275
  +'<div style="display:flex;align-items:center"><span style="font-size:14px;font-weight:700">'+esc(nickname)+"</span>"+vBadge+"</div>"
229
276
  +'<div class="handle">@'+esc(username)+"</div></div></div>"
230
- +'<div style="font-size:12px;color:var(--fg);font-weight:600;margin-bottom:4px">'+fmtNum(followers)+" followers</div>"
277
+ +'<div style="font-size:13px;color:var(--fg);font-weight:600;margin-bottom:6px">'+fmtNum(followers)+" followers</div>"
231
278
  +sig?'<div style="font-size:12px;color:var(--muted);line-height:1.4">'+esc(sig)+"</div>":""
232
279
  +"</div>";
233
280
  }
234
281
 
282
+ // ─── Expandable Section ───
283
+ function section(label,contentHtml,openByDefault){
284
+ var id="sec_"+Math.random().toString(36).slice(2,8);
285
+ return '<div class="section">'
286
+ +'<div class="section-header'+(openByDefault?" open":"")+'" onclick="toggleSection(this)">'
287
+ +'<span class="section-label">'+esc(label)+'</span>'
288
+ +'<span class="section-chevron">β–Ό</span></div>'
289
+ +'<div class="section-content'+(openByDefault?" open":"")+'">'+contentHtml+'</div></div>';
290
+ }
291
+
292
+ // ─── Analysis Card ───
235
293
  function analysisCard(d){
236
- var a=d.analysis||{};
237
- var postHtml=postCard(d.post||d,true);
238
- var sections="";
239
- if(a.summary)sections+='<div class="section"><div class="section-label">Summary</div><div class="section-text">'+esc(a.summary)+"</div></div>";
294
+ var a=d.analysis||{},postHtml=postCard(d.post||d,true);var sections="";
295
+ if(a.summary)sections+=section("Summary",'<div class="section-text">'+esc(a.summary)+"</div>",true);
240
296
  if(a.hookStrength!=null){
241
- var hs=Number(a.hookStrength);
242
- var pct=Math.min(hs/10*100,100);
243
- var bc=hs>=7?"#10b981":hs>=4?"#f59e0b":"#ef4444";
244
- sections+='<div class="section"><div class="section-label">Hook Strength</div>'
245
- +'<div style="display:flex;align-items:center;gap:8px"><div class="bar-track"><div class="bar-fill" style="width:'+pct+"%;background:"+bc+'"></div></div>'
246
- +'<span style="font-size:13px;font-weight:700">'+hs+"/10</span></div></div>";
297
+ var hs=Number(a.hookStrength),pct=Math.min(hs/10*100,100);
298
+ var bc=hs>=7?"var(--green)":hs>=4?"var(--amber)":"var(--red)";
299
+ sections+='<div class="section" style="margin-bottom:14px"><div style="padding:10px 12px">'
300
+ +'<div class="section-label" style="margin-bottom:8px">Hook Strength</div>'
301
+ +'<div class="hook-bar-track">'
302
+ +'<div class="hook-bar"><div class="hook-bar-fill" style="width:'+pct+"%;background:"+bc+'"></div></div>'
303
+ +'<span class="hook-score" style="color:'+bc+'">'+hs+"/10</span></div></div></div>";
247
304
  }
248
- if(a.niche)sections+='<div class="section"><span class="tag" style="background:var(--tag-bg);color:var(--fg)">πŸ“ '+esc(a.niche)+"</span></div>";
249
- if(a.whyItWorks)sections+='<div class="section"><div class="section-label">Why It Works</div><div class="section-text">'+esc((a.whyItWorks||"").slice(0,300))+"</div></div>";
250
- if(a.emotionalArc)sections+='<div class="section"><div class="section-label">Emotional Arc</div><div class="section-text">'+esc(a.emotionalArc)+"</div></div>";
305
+ if(a.niche||a.visualStyle){
306
+ var tags="";
307
+ if(a.niche)tags+='<span class="tag clickable" onclick="copyText(this.dataset.v)" data-v="'+esc(a.niche)+'">πŸ“ '+esc(a.niche)+"</span>";
308
+ if(a.visualStyle)tags+='<span class="tag">🎨 '+esc((a.visualStyle||"").slice(0,60))+"</span>";
309
+ sections+='<div style="margin-bottom:12px;display:flex;flex-wrap:wrap;gap:4px">'+tags+"</div>";
310
+ }
311
+ if(a.whyItWorks)sections+=section("Why It Works",'<div class="section-text">'+esc((a.whyItWorks||"").slice(0,400))+"</div>");
312
+ if(a.emotionalArc)sections+=section("Emotional Arc",'<div class="section-text">'+esc(a.emotionalArc)+"</div>");
251
313
  if(a.viralTriggers&&a.viralTriggers.length){
252
- var vt=a.viralTriggers.slice(0,6).map(function(t){return'<span class="tag" style="background:#fef3c7;color:#92400e">πŸ”₯ '+esc(t)+"</span>";}).join("");
253
- sections+='<div class="section"><div class="section-label">Viral Triggers</div>'+vt+"</div>";
314
+ var vt=a.viralTriggers.slice(0,8).map(function(t){return'<span class="tag clickable" onclick="copyText(this.dataset.v)" data-v="'+esc(t)+'">πŸ”₯ '+esc(t)+"</span>";}).join("");
315
+ sections+=section("Viral Triggers",vt);
254
316
  }
255
- if(a.suggestedHook)sections+='<div class="section"><div class="section-label">Suggested Hook</div><div class="quote-box">πŸ’‘ '+esc(a.suggestedHook)+"</div></div>";
317
+ if(a.suggestedHook)sections+=section("Suggested Hook",'<div class="quote-box">'+esc(a.suggestedHook)+'<button class="copy-btn" onclick="copyText(\\''+esc(a.suggestedHook).replace(/'/g,"\\\\'")+'\\')">Copy</button></div>',true);
256
318
  if(a.suggestedHashtags&&a.suggestedHashtags.length){
257
- var sh=a.suggestedHashtags.slice(0,8).map(function(t){return'<span class="tag" style="background:#ede9fe;color:#6d28d9">#'+esc(t.replace(/^#/,""))+"</span>";}).join("");
258
- sections+='<div class="section"><div class="section-label">Hashtags</div>'+sh+"</div>";
319
+ var sh=a.suggestedHashtags.slice(0,10).map(function(t){var clean=t.replace(/^#/,"");return'<span class="tag clickable" onclick="copyText(this.dataset.v)" data-v="#'+esc(clean)+'" style="background:#ede9fe;color:#6d28d9">#'+esc(clean)+"</span>";}).join("");
320
+ sections+=section("Hashtags",sh);
259
321
  }
260
- if(a.formatBreakdown)sections+='<div class="section"><div class="section-label">Format</div><div class="section-text">'+esc((a.formatBreakdown||"").slice(0,250))+"</div></div>";
322
+ if(a.formatBreakdown)sections+=section("Format Breakdown",'<div class="section-text">'+esc((a.formatBreakdown||"").slice(0,300))+"</div>");
261
323
  if(a.negativeSignals&&a.negativeSignals.length){
262
- var ns=a.negativeSignals.slice(0,5).map(function(n){return'<span class="tag" style="background:#fef2f2;color:#991b1b">⚠️ '+esc(n)+"</span>";}).join("");
263
- sections+='<div class="section"><div class="section-label">Weaknesses</div>'+ns+"</div>";
324
+ var ns=a.negativeSignals.slice(0,6).map(function(n){return'<span class="tag" style="background:#fef2f2;color:#991b1b">⚠️ '+esc(n)+"</span>";}).join("");
325
+ sections+=section("Weaknesses",ns);
264
326
  }
265
327
  if(a.variationIdeas&&a.variationIdeas.length){
266
- var vi=a.variationIdeas.slice(0,5).map(function(v){return"<li>"+esc(v)+"</li>";}).join("");
267
- sections+='<div class="section"><div class="section-label">Variation Ideas</div><ul style="margin:0;padding-left:18px">'+vi+"</ul></div>";
328
+ var vi=a.variationIdeas.slice(0,6).map(function(v){return'<li style="font-size:13px;color:var(--fg);margin:3px 0;padding-left:4px">'+esc(v)+"</li>";}).join("");
329
+ sections+=section("Variation Ideas",'<ul style="margin:0;padding-left:18px">'+vi+"</ul>");
268
330
  }
269
331
  if(!sections)return postHtml;
270
- return postHtml+'<div class="card card-wide" style="margin-top:8px"><div class="card-body">'
271
- +'<div style="font-size:15px;font-weight:700;margin-bottom:14px">πŸ“Š AI Analysis</div>'
332
+ return postHtml+'<div class="card card-wide fade-in" style="margin-top:10px"><div class="card-body">'
333
+ +'<div style="font-size:16px;font-weight:700;margin-bottom:14px;display:flex;align-items:center;gap:8px">πŸ“Š AI Analysis</div>'
272
334
  +sections+"</div></div>";
273
335
  }
274
336
 
337
+ // ─── Render ───
275
338
  function render(result){
276
- var app=document.getElementById("app");
277
- if(!app)return;
339
+ var app=document.getElementById("app");if(!app)return;
278
340
  var d=result&&result.structuredContent?result.structuredContent:result;
279
- if(!d||typeof d!=="object"){app.innerHTML='<div class="json-block">'+esc(JSON.stringify(d,null,2))+"</div>";return;}
341
+ if(!d||typeof d!=="object"){app.innerHTML='<div class="json-block fade-in">'+esc(JSON.stringify(d,null,2))+"</div>";return;}
280
342
 
281
- // Detect shape
282
- if(d.analysis&&(d.post||d.url))return void(app.innerHTML=analysisCard(d));
343
+ // Analysis
344
+ if(d.analysis&&(d.post||d.url)){app.innerHTML=analysisCard(d);return;}
345
+ // Posts gallery
283
346
  if(d.posts&&Array.isArray(d.posts)){
284
- var gallery=d.posts.map(function(p){return postCard(p,false);}).join("");
285
- return void(app.innerHTML='<div class="gallery">'+gallery+"</div>");
286
- }
347
+ if(!d.posts.length){app.innerHTML='<div class="empty-state fade-in"><div class="icon">πŸ”</div><div class="text">No posts found</div></div>';return;}
348
+ app.innerHTML='<div class="gallery stagger">'+d.posts.map(function(p){return postCard(p,false);}).join("")+"</div>";return;}
349
+ // Creators
287
350
  if(d.creators&&Array.isArray(d.creators)){
288
- var cg=d.creators.map(function(c){return creatorCard(c);}).join("");
289
- return void(app.innerHTML='<div class="gallery">'+cg+"</div>");
290
- }
351
+ if(!d.creators.length){app.innerHTML='<div class="empty-state fade-in"><div class="icon">πŸ‘€</div><div class="text">No creators found</div></div>';return;}
352
+ app.innerHTML='<div class="gallery stagger">'+d.creators.map(function(c){return creatorCard(c);}).join("")+"</div>";return;}
353
+ // Comments
291
354
  if(d.comments&&Array.isArray(d.comments)){
292
355
  var ch=d.comments.slice(0,15).map(function(c){
293
- var user=c.username||c.user||"";
294
- var text=(c.text||c.comment||"").slice(0,120);
295
- var likes=c.likes||c.likeCount||0;
356
+ var user=c.username||c.user||"",text=(c.text||c.comment||"").slice(0,140),likes=c.likes||c.likeCount||0;
296
357
  return '<div class="comment-row"><div style="flex:1"><span style="font-size:12px;font-weight:600">@'+esc(user)+"</span>"
297
- +'<div style="font-size:13px;color:var(--fg);line-height:1.4;margin-top:2px">'+esc(text)+"</div></div>"
358
+ +'<div style="font-size:13px;color:var(--fg);line-height:1.45;margin-top:3px">'+esc(text)+"</div></div>"
298
359
  +(likes>0?'<span style="font-size:11px;color:var(--muted);white-space:nowrap">❀️ '+fmtNum(likes)+"</span>":"")+"</div>";
299
360
  }).join("");
300
- return void(app.innerHTML='<div class="card card-wide"><div class="card-body">'
301
- +'<div style="font-size:15px;font-weight:700;margin-bottom:10px">πŸ’¬ Comments</div>'+ch+"</div></div>");
302
- }
361
+ app.innerHTML='<div class="card card-wide fade-in"><div class="card-body">'
362
+ +'<div style="font-size:16px;font-weight:700;margin-bottom:12px">πŸ’¬ Comments ('+d.comments.length+')</div>'+ch+"</div></div>";return;}
363
+ // Sounds
303
364
  if(d.sounds&&Array.isArray(d.sounds)){
304
- var snds=d.sounds.map(function(s){
365
+ app.innerHTML='<div class="gallery stagger">'+d.sounds.map(function(s){
305
366
  var color=pColor(s.platform||"tiktok");
306
- var cover=s.coverUrl?'<img class="sound-cover" src="'+esc(s.coverUrl)+'" alt="cover"/>'
307
- :'<div class="sound-cover" style="background:'+color+'15;display:flex;align-items:center;justify-content:center;font-size:24px">🎡</div>';
367
+ var cover=s.coverUrl?'<img class="sound-cover" src="'+esc(s.coverUrl)+'" alt="cover" loading="lazy"/>'
368
+ :'<div class="sound-cover" style="background:'+color+'15;display:flex;align-items:center;justify-content:center;font-size:26px">🎡</div>';
308
369
  var play=s.playUrl||s.url||"";
309
- var playBtn=play?'<a href="'+esc(play)+'" target="_blank" class="btn" style="background:'+color+';margin-top:6px;padding:4px 12px;font-size:11px">β–Ά Play</a>':"";
310
- return '<div class="sound-card"><div style="display:flex;gap:10px;align-items:center">'
370
+ var playBtn=play?'<a href="'+esc(play)+'" target="_blank" class="btn btn-sm" style="background:'+color+'">β–Ά Play</a>':"";
371
+ return '<div class="sound-card"><div style="display:flex;gap:12px;align-items:center">'
311
372
  +cover+'<div style="flex:1;min-width:0">'
312
- +'<div style="font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'+esc(s.title||"")+"</div>"
373
+ +'<div style="font-size:14px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'+esc(s.title||"")+"</div>"
313
374
  +'<div style="font-size:12px;color:var(--muted)">'+esc(s.artist||s.author||"")+(s.duration?" β€’ "+esc(s.duration):"")+"</div>"
314
375
  +playBtn+"</div></div></div>";
315
- }).join("");
316
- return void(app.innerHTML='<div class="gallery">'+snds+"</div>");
317
- }
376
+ }).join("")+"</div>";return;}
377
+ // Credits
318
378
  if(d.balance!=null||d.tier){
319
- var bal=Number(d.balance)||0;
320
- var tier=d.tier||"";
321
- var ff=d.firstFreeTools||[];
379
+ var bal=Number(d.balance)||0,tier=d.tier||"",ff=d.firstFreeTools||[];
322
380
  var freeHtml="";
323
- if(ff.length){
324
- var tags=ff.map(function(t){return'<span class="free-tag">✨ '+esc(t)+" free</span>";}).join("");
325
- freeHtml='<div style="margin-top:10px"><div class="section-label">Free first uses remaining</div><div style="display:flex;flex-wrap:wrap;gap:4px">'+tags+"</div></div>";
326
- }
327
- return void(app.innerHTML='<div class="credits-card">'
328
- +'<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px">'
329
- +'<div style="font-size:15px;font-weight:700">πŸ’° Your Credits</div>'
381
+ if(ff.length){var tags=ff.map(function(t){return'<span class="free-tag">✨ '+esc(t)+" free</span>";}).join("");
382
+ freeHtml='<div style="margin-top:12px"><div class="section-label" style="margin-bottom:6px">Free first uses remaining</div><div style="display:flex;flex-wrap:wrap;gap:4px">'+tags+"</div></div>";}
383
+ app.innerHTML='<div class="credits-card fade-in">'
384
+ +'<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px">'
385
+ +'<div style="font-size:16px;font-weight:700">πŸ’° Your Credits</div>'
330
386
  +(tier?'<span class="tier-badge">'+esc(tier)+"</span>":"")+"</div>"
331
- +'<div style="font-size:32px;font-weight:800;margin:8px 0">'+bal+"</div>"
332
- +'<div style="font-size:13px;color:var(--muted)">credits remaining</div>'
333
- +freeHtml+"</div>");
334
- }
387
+ +'<div style="font-size:36px;font-weight:800;margin:10px 0;letter-spacing:-1px">'+bal+"</div>"
388
+ +'<div style="font-size:13px;color:var(--muted)">credits remaining</div>'+freeHtml+"</div>";return;}
389
+ // Checkout
335
390
  if(d.checkoutUrl||d.packs){
336
- return void(app.innerHTML='<div class="card card-wide"><div class="card-body">'
337
- +'<div style="font-size:15px;font-weight:700;margin-bottom:12px">πŸ›’ Credit Packs</div>'
391
+ app.innerHTML='<div class="card card-wide fade-in"><div class="card-body">'
392
+ +'<div style="font-size:16px;font-weight:700;margin-bottom:14px">πŸ›’ Credit Packs</div>'
338
393
  +'<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:10px">'
339
- +'<div style="border:1px solid var(--border);border-radius:10px;padding:14px;text-align:center"><div style="font-size:13px;font-weight:600">Starter</div><div style="font-size:22px;font-weight:800;margin:4px 0">$12.50</div><div style="font-size:12px;color:var(--muted)">500 credits</div></div>'
340
- +'<div style="border:2px solid var(--accent);border-radius:10px;padding:14px;text-align:center;box-shadow:0 4px 12px rgba(0,0,0,0.08)"><div style="font-size:13px;font-weight:600">Pro</div><div style="font-size:22px;font-weight:800;margin:4px 0">$40</div><div style="font-size:12px;color:var(--muted)">2,000 credits</div></div>'
341
- +'<div style="border:1px solid var(--border);border-radius:10px;padding:14px;text-align:center"><div style="font-size:13px;font-weight:600">Scale</div><div style="font-size:22px;font-weight:800;margin:4px 0">$85</div><div style="font-size:12px;color:var(--muted)">5,000 credits</div></div>'
342
- +"</div></div></div>");
343
- }
344
- // Single post (get_social_media)
345
- if(d.post||d.platform){
346
- return void(app.innerHTML=postCard(d.post||d,true));
347
- }
348
- // Fallback: pretty-print JSON
349
- app.innerHTML='<div class="json-block">'+esc(JSON.stringify(d,null,2))+"</div>";
394
+ +'<div style="border:1px solid var(--border);border-radius:10px;padding:16px;text-align:center;transition:var(--transition);cursor:pointer" onmouseover="this.style.borderColor=var(--muted)" onmouseout="this.style.borderColor=var(--border)"><div style="font-size:13px;font-weight:600">Starter</div><div style="font-size:24px;font-weight:800;margin:6px 0">$12.50</div><div style="font-size:12px;color:var(--muted)">500 credits</div></div>'
395
+ +'<div style="border:2px solid var(--accent);border-radius:10px;padding:16px;text-align:center;box-shadow:var(--shadow-md)"><div style="font-size:13px;font-weight:600">Pro ⭐</div><div style="font-size:24px;font-weight:800;margin:6px 0">$40</div><div style="font-size:12px;color:var(--muted)">2,000 credits</div></div>'
396
+ +'<div style="border:1px solid var(--border);border-radius:10px;padding:16px;text-align:center;transition:var(--transition);cursor:pointer" onmouseover="this.style.borderColor=var(--muted)" onmouseout="this.style.borderColor=var(--border)"><div style="font-size:13px;font-weight:600">Scale</div><div style="font-size:24px;font-weight:800;margin:6px 0">$85</div><div style="font-size:12px;color:var(--muted)">5,000 credits</div></div>'
397
+ +"</div></div></div>";return;}
398
+ // Single post
399
+ if(d.post||d.platform){app.innerHTML=postCard(d.post||d,true);return;}
400
+ // Fallback
401
+ app.innerHTML='<div class="json-block fade-in">'+esc(JSON.stringify(d,null,2))+"</div>";
402
+ }
403
+
404
+ function updateProgress(params){
405
+ var app=document.getElementById("app");
406
+ if(!app)return;
407
+ var text=params&&params.arguments?JSON.stringify(params.arguments):"Processing…";
408
+ app.innerHTML='<div class="loading-container fade-in">'
409
+ +'<div class="loading-spinner"></div>'
410
+ +'<div class="loading-text">'+esc(text.length>80?text.slice(0,80)+"…":text)+'</div>'
411
+ +'<div class="progress-bar" style="width:200px"><div class="progress-fill" style="width:60%"></div></div>'
412
+ +'</div>';
350
413
  }
414
+
415
+ // Global helpers
416
+ window.copyText=copyText;
417
+ window.toggleSection=function(header){
418
+ header.classList.toggle("open");
419
+ var content=header.nextElementSibling;
420
+ if(content)content.classList.toggle("open");
421
+ };
351
422
  })();
352
423
  </script>
353
424
  </body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orchyn/mcp",
3
- "version": "1.9.0",
3
+ "version": "1.9.1",
4
4
  "description": "MCP server for orchyn - fetch, discover and understand TikTok/Instagram/YouTube/X posts with AI (media metadata, niche discovery, hook & viral analysis)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",