@amityco/social-plus-vise 1.4.5 → 1.5.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.
@@ -0,0 +1,2187 @@
1
+ <!doctype html>
2
+ <meta charset="utf-8">
3
+ <meta name="viewport" content="width=device-width, initial-scale=1">
4
+ <title>Vise — How It Helps</title>
5
+ <style>
6
+ :root{
7
+ color-scheme:light;
8
+ --paper:#F6F7F9;
9
+ --paper-raised:#FFFFFF;
10
+ --paper-elevated:#EEF2F7;
11
+ --ink:#172033;
12
+ --ink-soft:#4B5565;
13
+ --ink-faint:#7B8797;
14
+ --verified:#A04B12;
15
+ --bad:#B42318;
16
+ --bad-soft:#FDE9E7;
17
+ --bad-line:#F2B8B5;
18
+ --good:#166B45;
19
+ --good-soft:#E6F4EC;
20
+ --good-line:#A7D7BC;
21
+ --line:#D8DEE8;
22
+ --brand:#176B57;
23
+ --brand-dark:#0D3F34;
24
+ --brand-soft:#E1F1EC;
25
+ --focus:#2563EB;
26
+ --shadow:0 22px 60px rgba(32,47,75,.13);
27
+ --mono:ui-monospace,"SF Mono","Cascadia Code","JetBrains Mono",Menlo,Consolas,monospace;
28
+ --sans:"IBM Plex Sans",ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
29
+ }
30
+ *{box-sizing:border-box;}
31
+ html{scroll-behavior:smooth;}
32
+ body{margin:0;background:var(--paper);}
33
+ .doc{background:linear-gradient(180deg,#FFFFFF 0%,#F6F8FB 36%,#F2F5F8 100%);color:var(--ink);font-family:var(--sans);line-height:1.55;min-height:100%;overflow-x:hidden;}
34
+ .wrap{max-width:1160px;margin:0 auto;padding:0 28px 110px;}
35
+ ::selection{background:#CCEBD9;}
36
+ a{color:inherit;}
37
+ code{font-family:var(--mono);font-size:.92em;color:#8B3A0B;background:#FFF7ED;padding:2px 6px;border-radius:5px;border:1px solid #FED7AA;}
38
+
39
+ .reveal{opacity:0;transform:translateY(12px);transition:opacity .42s ease,transform .42s ease;}
40
+ .reveal.in{opacity:1;transform:none;}
41
+ @media (prefers-reduced-motion:reduce){
42
+ html{scroll-behavior:auto;}
43
+ .reveal{opacity:1;transform:none;transition:none;}
44
+ .spin,.skel::after{animation:none !important;}
45
+ }
46
+
47
+ .masthead{padding:24px 0 16px;border-bottom:1px solid var(--line);display:flex;justify-content:space-between;align-items:flex-end;gap:16px;flex-wrap:wrap;}
48
+ .masthead .tag{font-family:var(--mono);font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-soft);}
49
+ .masthead .tag b{color:var(--ink);font-weight:800;}
50
+ .masthead .meta{font-family:var(--mono);font-size:11px;color:var(--ink-faint);text-align:right;line-height:1.6;}
51
+
52
+ .hero{display:grid;grid-template-columns:minmax(0,1fr) 360px;gap:32px;align-items:start;padding:34px 0 24px;}
53
+ .hero-copy{min-width:0;}
54
+ .eyebrow{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--verified);margin:0 0 14px;}
55
+ .hero h1{font-size:clamp(40px,6.4vw,68px);line-height:.96;letter-spacing:0;margin:0 0 22px;max-width:14ch;text-wrap:balance;}
56
+ .hero p.sub{font-size:18px;color:var(--ink-soft);max-width:63ch;margin:0 0 14px;}
57
+ .hero p.note{color:var(--ink-faint);font-size:14px;max-width:66ch;margin:0;}
58
+ .hero-actions{display:flex;gap:12px;flex-wrap:wrap;margin-top:26px;}
59
+ .hero-action{min-height:44px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);border-radius:8px;padding:10px 14px;font-family:var(--mono);font-size:12px;font-weight:800;text-decoration:none;color:var(--ink-soft);background:#FFFFFF;box-shadow:0 1px 2px rgba(32,47,75,.05);transition:background .2s ease,border-color .2s ease,color .2s ease,transform .2s ease,box-shadow .2s ease;}
60
+ .hero-action.primary{background:var(--brand);border-color:var(--brand);color:#FFFFFF;}
61
+ .hero-action:hover{background:#F8FAFC;border-color:#AAB4C3;color:var(--ink);transform:translateY(-1px);box-shadow:0 8px 20px rgba(32,47,75,.09);}
62
+ .hero-action.primary:hover{background:#0F5D4C;border-color:#0F5D4C;color:#FFFFFF;}
63
+ .hero-action:focus-visible,.toc a:focus-visible,.gallery-tab:focus-visible,.fitbtn:focus-visible,.tabbtn:focus-visible{outline:3px solid var(--focus);outline-offset:3px;}
64
+
65
+ .hero-panel{background:linear-gradient(180deg,#FFFFFF,#F8FAFC);border:1px solid var(--line);border-radius:14px;padding:16px;box-shadow:var(--shadow);}
66
+ .panel-label{font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-faint);margin:0 0 12px;}
67
+ .loop{display:grid;gap:10px;margin:0;padding:0;list-style:none;}
68
+ .loop li{display:grid;grid-template-columns:26px 1fr;gap:9px;align-items:start;border:1px solid #E2E8F0;background:#FFFFFF;border-radius:9px;padding:9px;}
69
+ .loop b{display:block;font-size:13px;color:var(--ink);line-height:1.25;}
70
+ .loop span{font-size:12px;color:var(--ink-soft);}
71
+ .loop .num{width:26px;height:26px;border-radius:7px;background:var(--brand-soft);color:var(--brand-dark);display:inline-flex;align-items:center;justify-content:center;font-family:var(--mono);font-size:11px;font-weight:900;}
72
+ .panel-stat{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px;}
73
+ .panel-stat div{border:1px solid #E2E8F0;background:#F8FAFC;border-radius:9px;padding:11px;}
74
+ .panel-stat b{display:block;font-family:var(--mono);font-size:20px;color:var(--good);}
75
+ .panel-stat span{display:block;font-size:11px;color:var(--ink-faint);}
76
+
77
+ .toc{grid-column:1 / -1;display:flex;gap:10px;flex-wrap:wrap;padding:16px 0 0;border-top:1px solid var(--line);}
78
+ .toc a{
79
+ min-height:38px;display:inline-flex;align-items:center;font-family:var(--mono);font-size:12px;color:var(--ink-soft);text-decoration:none;
80
+ border:1px solid var(--line);border-radius:999px;padding:8px 14px;background:#FFFFFF;
81
+ transition:border-color .2s ease,color .2s ease,background .2s ease;
82
+ }
83
+ .toc a:hover{border-color:var(--brand);color:var(--brand-dark);background:var(--brand-soft);}
84
+
85
+ .capabilities,.benchmark{padding:42px 0 14px;border-top:1px solid var(--line);}
86
+ .section-kicker{font-family:var(--mono);font-size:11px;letter-spacing:.13em;text-transform:uppercase;color:var(--verified);margin:0 0 10px;}
87
+ .capabilities h2,.benchmark h2,.demo-section h2,.closer h2{font-size:clamp(28px,4vw,44px);line-height:1.05;margin:0 0 12px;max-width:13ch;text-wrap:balance;}
88
+ .benchmark h2{max-width:17ch;}
89
+ .capabilities .intro,.benchmark .intro{font-size:16px;color:var(--ink-soft);max-width:74ch;margin:0 0 24px;}
90
+ .capgrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;}
91
+ .capcard{background:var(--paper-raised);border:1px solid var(--line);border-radius:10px;padding:18px;min-height:100%;}
92
+ .capcard h3{font-size:16px;margin:0 0 10px;}
93
+ .capcard p{margin:0;color:var(--ink-soft);font-size:13.5px;}
94
+ .capcard ul{margin:0;padding-left:18px;color:var(--ink-soft);font-size:13.5px;}
95
+ .capcard li{margin:6px 0;}
96
+ .capcard.layer{background:#FFFFFF;}
97
+ .capcard.boundary{background:#FFF7ED;border-color:#FED7AA;}
98
+ .capcard .chipline{display:flex;flex-wrap:wrap;gap:6px;margin-top:14px;}
99
+ .capcard .chipline span{font-family:var(--mono);font-size:10.5px;color:var(--brand-dark);background:var(--brand-soft);border:1px solid #B9DBCF;border-radius:999px;padding:5px 8px;}
100
+
101
+ /* ============ ONE-GLANCE RECONCILIATION ============ */
102
+ .bx-recon{border:1px solid var(--line);border-radius:16px;background:var(--paper-raised);padding:16px 18px 18px;display:flex;flex-direction:column;gap:12px;box-shadow:0 16px 42px rgba(32,47,75,.08);}
103
+ .bx-recon-tag{font-family:var(--mono);font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-soft);}
104
+ .bx-recon-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;}
105
+ .bx-recon-cell{display:flex;flex-direction:column;gap:5px;border:1px solid var(--line);border-radius:12px;background:var(--paper-elevated);padding:13px 15px;min-width:0;}
106
+ .bx-recon-cell-key{border:2px solid var(--brand);background:var(--brand-soft);box-shadow:0 10px 30px rgba(23,107,87,.12);}
107
+ .bx-recon-num{font-family:var(--mono);font-size:30px;line-height:1;color:var(--ink-soft);letter-spacing:-.01em;font-variant-numeric:tabular-nums;}
108
+ .bx-recon-num-key{color:var(--brand-dark);}
109
+ .bx-recon-lab{font-size:12.5px;font-weight:700;color:var(--ink);letter-spacing:-.005em;}
110
+ .bx-recon-cell-key .bx-recon-lab{color:var(--brand-dark);}
111
+ .bx-recon-note{font-size:12px;line-height:1.45;color:var(--ink-soft);}
112
+ .bx-recon-note b{color:var(--ink);}
113
+ .bx-recon-note em{color:var(--verified);font-style:normal;}
114
+
115
+ /* ============ CROSS-MODEL BAND ============ */
116
+ .bx-xm{display:flex;flex-direction:column;gap:16px;border:1px solid var(--line);border-radius:18px;background:var(--paper-elevated);padding:18px 18px 20px;}
117
+ .bx-xm-head{display:flex;flex-direction:column;gap:7px;}
118
+ .bx-xm-copy{margin:0;font-size:13px;line-height:1.5;color:var(--ink-soft);max-width:92ch;}
119
+ .bx-xm-copy b{color:var(--ink);}
120
+ .bx-xm-copy em{color:var(--brand-dark);font-style:normal;}
121
+
122
+ .bx-xm-cards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;align-items:stretch;}
123
+ .bx-xm-card{border:1px solid var(--line);border-radius:16px;background:var(--paper-raised);padding:18px 20px;display:flex;flex-direction:column;gap:14px;min-width:0;box-shadow:0 16px 42px rgba(32,47,75,.08);}
124
+ .bx-xm-anchor{border:2px solid var(--brand);box-shadow:0 20px 50px rgba(23,107,87,.14);}
125
+ .bx-xm-caveated{border-color:var(--line);background:linear-gradient(180deg,var(--paper-elevated),var(--paper-raised));}
126
+ .bx-xm-card-head{display:flex;flex-direction:column;gap:6px;}
127
+ .bx-xm-model{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;}
128
+ .bx-xm-name{font-size:17px;font-weight:700;color:var(--ink);letter-spacing:-.01em;}
129
+ .bx-xm-badge{font-family:var(--mono);font-size:10px;letter-spacing:.06em;text-transform:uppercase;padding:3px 9px;border-radius:999px;white-space:nowrap;display:inline-flex;align-items:center;gap:6px;}
130
+ .bx-xm-badge-anchor{color:var(--brand-dark);background:var(--brand-soft);border:1px solid var(--good-line);font-weight:600;}
131
+ .bx-xm-badge-dot{width:7px;height:7px;border-radius:50%;background:var(--brand);flex:0 0 auto;}
132
+ .bx-xm-badge-earlier{color:var(--ink-soft);background:var(--paper-elevated);border:1px solid var(--line);}
133
+ .bx-xm-proto{margin:0;font-size:11.5px;line-height:1.4;color:var(--ink-soft);font-family:var(--mono);letter-spacing:.01em;}
134
+ .bx-xm-nums{display:flex;align-items:flex-end;gap:22px;flex-wrap:wrap;}
135
+ .bx-xm-stat{display:flex;flex-direction:column;gap:5px;}
136
+ .bx-xm-stat b{font-family:var(--mono);font-size:32px;line-height:1;color:var(--ink);letter-spacing:-.01em;font-variant-numeric:tabular-nums;}
137
+ .bx-xm-stat span{font-size:11px;color:var(--ink-soft);font-family:var(--mono);letter-spacing:.03em;}
138
+ .bx-xm-lift b{color:var(--good);}
139
+ .bx-xm-lift-soft b{color:var(--ink-soft);display:inline-flex;align-items:baseline;gap:3px;}
140
+ .bx-xm-lift-soft .bx-strike{color:var(--ink-soft);}
141
+ .bx-xm-lift-soft .bx-capmark{font-size:11px;}
142
+ .bx-xm-foot{margin:0;font-size:12.5px;line-height:1.5;color:var(--ink-soft);display:flex;gap:8px;align-items:flex-start;}
143
+ .bx-xm-foot b{color:var(--ink);}
144
+ .bx-xm-foot-clean{color:var(--brand-dark);}
145
+ .bx-xm-foot-mark{color:var(--good);font-weight:700;flex:0 0 auto;}
146
+ .bx-xm-chip{display:flex;gap:9px;align-items:flex-start;border:1px solid var(--line);border-left:3px solid var(--verified);border-radius:10px;background:var(--paper-elevated);padding:11px 13px;margin-top:auto;}
147
+ .bx-xm-chip-mark{color:var(--verified);font-size:9px;flex:0 0 auto;margin-top:3px;}
148
+ .bx-xm-chip-text{font-size:12px;line-height:1.5;color:var(--ink-soft);}
149
+ .bx-xm-chip-text b{color:var(--ink);}
150
+ .bx-xm-chip-text code{font-family:var(--mono);font-size:11px;background:var(--paper-raised);border:1px solid var(--line);border-radius:4px;padding:0 4px;color:var(--verified);}
151
+
152
+ /* CONVERGENCE STRIP */
153
+ .bx-conv{border:1px solid var(--good-line);border-radius:14px;background:linear-gradient(180deg,var(--good-soft),var(--paper-raised));padding:16px 18px;display:flex;flex-direction:column;gap:14px;}
154
+ .bx-conv-head{display:flex;flex-direction:column;gap:6px;}
155
+ .bx-conv-tag{align-self:flex-start;font-family:var(--mono);font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:var(--good);font-weight:600;}
156
+ .bx-conv-lead{margin:0;font-size:13px;line-height:1.5;color:var(--ink-soft);max-width:92ch;}
157
+ .bx-conv-lead b{color:var(--brand-dark);}
158
+ .bx-conv-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;}
159
+ .bx-conv-plat{border:1px solid var(--good-line);border-radius:12px;background:var(--paper-raised);padding:13px 16px;display:flex;flex-direction:column;gap:10px;min-width:0;}
160
+ .bx-conv-plat-name{font-size:14px;font-weight:700;color:var(--ink);}
161
+ .bx-conv-pair{display:flex;align-items:stretch;gap:12px;}
162
+ .bx-conv-cell{flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:4px;}
163
+ .bx-conv-agent{font-family:var(--mono);font-size:10.5px;letter-spacing:.03em;color:var(--ink-soft);white-space:nowrap;}
164
+ .bx-conv-num{font-family:var(--mono);font-size:24px;font-weight:700;color:var(--good);font-variant-numeric:tabular-nums;letter-spacing:-.01em;line-height:1;}
165
+ .bx-conv-vs{align-self:center;font-family:var(--mono);font-size:18px;color:var(--ink-faint);flex:0 0 auto;}
166
+ .bx-conv-spread{font-family:var(--mono);font-size:10.5px;letter-spacing:.03em;color:var(--good);align-self:flex-start;padding:2px 8px;border-radius:999px;background:var(--good-soft);border:1px solid var(--good-line);}
167
+ .bx-conv-note{margin:0;font-size:12px;line-height:1.5;color:var(--ink-soft);}
168
+ .bx-conv-note b{color:var(--ink);}
169
+ .bx-conv-note em{color:var(--verified);font-style:normal;}
170
+
171
+ /* deep-dive header divider */
172
+ .bx-deep{display:flex;flex-direction:column;gap:0;border-top:1px dashed var(--line);padding-top:20px;margin-top:4px;}
173
+ .bx-deep-head{display:flex;flex-direction:column;gap:7px;}
174
+
175
+ /* ============ existing rules below (reused) ============ */
176
+ .bx-shell{display:flex;flex-direction:column;gap:20px;margin-top:6px;}
177
+ .bx-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;}
178
+
179
+ /* legend */
180
+ .bx-legend{display:flex;flex-wrap:wrap;align-items:center;gap:8px 18px;font-family:var(--mono);font-size:11px;letter-spacing:.02em;color:var(--ink-soft);}
181
+ .bx-key{display:inline-flex;align-items:center;gap:7px;}
182
+ .bx-swatch{width:12px;height:12px;border-radius:3px;flex:0 0 auto;}
183
+ .bx-swatch-vise{background:var(--brand);}
184
+ .bx-swatch-ctrl{background:#AAB4C3;}
185
+ .bx-key-note{color:var(--ink-soft);letter-spacing:.05em;}
186
+
187
+ /* ============ HEADLINE: two composites ============ */
188
+ .bx-headline{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;}
189
+ .bx-head-primary,.bx-head-secondary{border:1px solid var(--line);border-radius:16px;padding:18px 20px;box-shadow:0 16px 42px rgba(32,47,75,.08);display:flex;flex-direction:column;gap:12px;min-width:0;}
190
+ .bx-head-primary{background:var(--paper-raised);}
191
+ .bx-head-secondary{background:linear-gradient(180deg,var(--good-soft),var(--paper-raised));border-color:var(--good-line);}
192
+ .bx-head-tag{font-family:var(--mono);font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-soft);}
193
+ .bx-head-tag-alt{color:var(--good);font-weight:600;}
194
+ .bx-head-nums{display:flex;align-items:flex-end;gap:22px;flex-wrap:wrap;}
195
+ .bx-head-stat{display:flex;flex-direction:column;gap:5px;}
196
+ .bx-head-stat b{font-family:var(--mono);font-size:30px;line-height:1;color:var(--ink);letter-spacing:-.01em;font-variant-numeric:tabular-nums;}
197
+ .bx-ctrl-num{color:var(--ink-soft)!important;}
198
+ .bx-head-stat span{font-size:11px;color:var(--ink-soft);font-family:var(--mono);letter-spacing:.03em;}
199
+ .bx-head-lift b{color:var(--good);}
200
+ .bx-head-copy{margin:0;font-size:12.5px;line-height:1.5;color:var(--ink-soft);}
201
+ .bx-head-copy b{color:var(--ink);}
202
+ .bx-head-secondary .bx-head-copy b{color:var(--brand-dark);}
203
+ .bx-head-round{display:block;margin-top:6px;font-family:var(--mono);font-size:10.5px;line-height:1.5;letter-spacing:.01em;color:var(--ink-soft);}
204
+ .bx-head-secondary .bx-head-copy .bx-head-round b{color:var(--ink-soft);}
205
+
206
+ /* ============ DIMENSION LEDGER ============ */
207
+ .bx-dims{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;}
208
+ .bx-dims-lead{grid-column:1 / -1;margin:2px 0 0;font-size:13.5px;line-height:1.5;color:var(--ink-soft);}
209
+ .bx-dims-lead b{color:var(--ink);}
210
+ .bx-dim{border:1px solid var(--line);border-radius:14px;background:var(--paper-raised);padding:16px 18px;box-shadow:0 16px 42px rgba(32,47,75,.08);display:flex;flex-direction:column;min-width:0;}
211
+ .bx-dim-win{border-left:3px solid var(--good);}
212
+ .bx-dim-tie{border-left:3px solid var(--ink-faint);}
213
+ .bx-dim-struct{grid-column:1 / -1;background:var(--paper-elevated);border-style:dashed;border-color:var(--line);border-left:3px dashed var(--line);box-shadow:none;}
214
+ .bx-dim-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;flex-wrap:wrap;}
215
+ .bx-dim-name{font-size:17px;font-weight:700;color:var(--ink);letter-spacing:-.01em;}
216
+ .bx-dim-kind{font-family:var(--mono);font-size:10px;letter-spacing:.06em;text-transform:uppercase;padding:3px 8px;border-radius:999px;white-space:nowrap;}
217
+ .bx-kind-win{color:var(--good);background:var(--good-soft);border:1px solid var(--good-line);}
218
+ .bx-kind-tie{color:var(--ink-soft);background:var(--paper-elevated);border:1px solid var(--line);}
219
+ .bx-kind-budget{color:var(--verified);background:var(--paper-elevated);border:1px solid var(--line);text-transform:none;letter-spacing:.02em;}
220
+ .bx-kind-struct{color:var(--ink-soft);background:repeating-linear-gradient(-45deg,var(--paper-elevated),var(--paper-elevated) 4px,var(--paper-raised) 4px,var(--paper-raised) 8px);border:1px solid var(--line);}
221
+ .bx-dim-sub{margin:7px 0 14px;font-size:12.5px;line-height:1.45;color:var(--ink-soft);}
222
+ .bx-dim-sub b{color:var(--ink);}
223
+ .bx-dim-weight{display:inline-block;font-family:var(--mono);font-size:10.5px;color:var(--ink-soft);letter-spacing:.03em;white-space:nowrap;}
224
+ .bx-body{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:16px;}
225
+ .bx-plot{display:flex;flex-direction:column;gap:8px;min-width:0;}
226
+ .bx-row{display:grid;grid-template-columns:52px minmax(0,1fr) 46px;align-items:center;gap:10px;}
227
+ .bx-arm{font-family:var(--mono);font-size:11px;color:var(--ink-soft);letter-spacing:.02em;}
228
+ .bx-track{position:relative;height:9px;border-radius:999px;background:#E7ECF3;overflow:hidden;}
229
+ .bx-fill{height:100%;border-radius:999px;}
230
+ .bx-fill-vise{background:var(--brand);}
231
+ .bx-fill-ctrl{background:#AAB4C3;}
232
+ .bx-fill-struct{background:repeating-linear-gradient(-45deg,var(--ink-faint),var(--ink-faint) 5px,#AAB4C3 5px,#AAB4C3 10px);}
233
+ .bx-track-zero{overflow:visible;background:#E7ECF3;}
234
+ .bx-zero-label{position:absolute;left:8px;top:50%;transform:translateY(-50%);font-family:var(--mono);font-size:10px;color:var(--ink-soft);letter-spacing:.02em;white-space:nowrap;}
235
+ .bx-val{font-family:var(--mono);font-size:13px;font-weight:600;color:var(--ink);text-align:right;font-variant-numeric:tabular-nums;}
236
+ .bx-val-ctrl{color:var(--ink-soft);font-weight:500;}
237
+ .bx-val-struct{color:var(--ink-soft);}
238
+ .bx-delta{display:flex;flex-direction:column;align-items:flex-end;line-height:1;padding-left:14px;border-left:1px solid var(--line);min-width:82px;}
239
+ .bx-delta-lead{font-family:var(--mono);font-size:9px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-soft);margin-bottom:6px;}
240
+ .bx-delta-num{font-family:var(--mono);font-size:26px;font-weight:700;letter-spacing:-.01em;font-variant-numeric:tabular-nums;}
241
+ .bx-delta-cap{font-family:var(--mono);font-size:9px;letter-spacing:.09em;text-transform:uppercase;margin-top:5px;color:var(--ink-soft);}
242
+ .bx-delta-win .bx-delta-num{color:var(--good);}
243
+ .bx-delta-tie .bx-delta-num{color:var(--ink-soft);}
244
+ .bx-delta-struct .bx-delta-num{color:var(--ink-soft);font-weight:600;font-size:22px;}
245
+
246
+ /* tie note */
247
+ .bx-tie-note{border:1px solid var(--line);border-left:3px solid var(--verified);border-radius:12px;background:var(--paper-raised);padding:13px 16px;font-size:13.5px;line-height:1.5;color:var(--ink-soft);}
248
+ .bx-tie-note b{color:var(--ink);}
249
+ .bx-tie-note em{color:var(--verified);font-style:normal;}
250
+
251
+ /* ============ PER-PLATFORM DUMBBELL LADDER ============ */
252
+ .bx-platforms{display:flex;flex-direction:column;gap:14px;}
253
+ .bx-plat-head{display:flex;flex-direction:column;gap:7px;}
254
+ /* rust reserved for genuine caveats; neutral section kickers use ink-soft */
255
+ .bx-tag,.bx-note-tag{align-self:flex-start;font-family:var(--mono);font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:var(--verified);}
256
+ .bx-tag-neutral{color:var(--ink-soft);}
257
+ .bx-plat-copy{margin:0;font-size:13px;line-height:1.5;color:var(--ink-soft);max-width:92ch;}
258
+ .bx-plat-copy b{color:var(--ink);}
259
+ .bx-plat-copy em{color:var(--brand-dark);font-style:normal;}
260
+ .bx-plat-list{display:flex;flex-direction:column;gap:2px;border:1px solid var(--line);border-radius:14px;background:var(--paper-raised);box-shadow:0 10px 30px rgba(32,47,75,.06);padding:6px;}
261
+ .bx-plat{padding:13px 16px 15px;border-radius:10px;}
262
+ .bx-plat + .bx-plat{border-top:1px solid var(--line);border-top-left-radius:0;border-top-right-radius:0;}
263
+ .bx-plat-avg{background:var(--brand-soft);border:1px solid var(--good-line);margin-bottom:4px;}
264
+ .bx-plat-top{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:16px;flex-wrap:wrap;}
265
+ .bx-plat-name{font-size:14px;font-weight:700;color:var(--ink);white-space:nowrap;}
266
+ .bx-plat-fix{display:inline;font-weight:400;font-size:12px;color:var(--ink-soft);white-space:normal;margin-left:8px;}
267
+ .bx-plat-meta{display:inline-flex;align-items:center;gap:10px;flex-shrink:0;}
268
+ .bx-plat-delta{font-family:var(--mono);font-size:15px;font-weight:700;color:var(--good);font-variant-numeric:tabular-nums;}
269
+ .bx-plat-avg .bx-plat-delta{font-size:18px;}
270
+ .bx-sig{display:inline-block;padding:1px 8px;border-radius:999px;font-family:var(--mono);font-size:10.5px;background:var(--good-soft);color:var(--good);border:1px solid var(--good-line);white-space:nowrap;}
271
+ .bx-sig-full{background:var(--good-soft);color:var(--good);border:1px solid var(--good-line);}
272
+ .bx-sig-low{background:var(--paper-elevated);color:var(--verified);border-color:var(--line);}
273
+
274
+ /* the axis / dumbbell */
275
+ .bx-axis{position:relative;height:22px;}
276
+ .bx-gridlines{position:absolute;inset:0;}
277
+ .bx-gridlines i{position:absolute;top:-2px;bottom:-2px;width:1px;background:var(--line);}
278
+ .bx-gridlines i:first-child,.bx-gridlines i:last-child{background:var(--ink-faint);opacity:.5;}
279
+ .bx-connector{position:absolute;top:50%;height:4px;transform:translateY(-50%);border-radius:999px;background:linear-gradient(90deg,#AAB4C3,var(--brand));}
280
+ .bx-plat-avg .bx-connector{height:5px;}
281
+ .bx-dot{position:absolute;top:50%;width:14px;height:14px;border-radius:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 3px var(--paper-raised);}
282
+ .bx-plat-avg .bx-dot{box-shadow:0 0 0 3px var(--brand-soft);width:16px;height:16px;}
283
+ .bx-dot-ctrl{background:#AAB4C3;z-index:1;}
284
+ .bx-dot-vise{background:var(--brand);z-index:2;}
285
+ .bx-dot-capped{background:var(--brand);}
286
+ .bx-dot-lab{position:absolute;left:50%;top:-2px;transform:translate(-50%,-100%);font-family:var(--mono);font-size:11px;font-weight:600;color:var(--brand-dark);white-space:nowrap;font-variant-numeric:tabular-nums;}
287
+ .bx-dot-ctrl .bx-dot-lab{color:var(--ink-soft);font-weight:500;}
288
+ .bx-dot-lab-below{top:auto;bottom:-2px;transform:translate(-50%,100%);}
289
+ /* edge-aware labels: a dot sitting near the axis right edge (Web 88.3, RN 89.7)
290
+ right-aligns its nowrap label to the dot center so it never overhangs the
291
+ axis padding-box, independent of the host page's outer padding. */
292
+ .bx-dot-edge .bx-dot-lab{left:auto;right:50%;transform:translate(50%,-100%);}
293
+ .bx-capmark{color:var(--verified);font-size:8px;vertical-align:super;margin-left:1px;}
294
+ .bx-axis-scale{position:relative;height:16px;margin:0 6px;font-family:var(--mono);font-size:10.5px;color:var(--ink-soft);font-variant-numeric:tabular-nums;}
295
+ .bx-axis-scale span{position:absolute;transform:translateX(-50%);}
296
+ .bx-axis-scale span:first-child{transform:translateX(0);}
297
+ .bx-axis-scale span:last-child{transform:translateX(-100%);}
298
+
299
+ /* notes */
300
+ .bx-notes{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;}
301
+ .bx-note{border:1px solid var(--line);border-radius:12px;padding:14px 16px;background:var(--paper-raised);}
302
+ .bx-note-cost{border-left:3px solid var(--verified);}
303
+ .bx-note-super{border-left:3px solid var(--ink-faint);}
304
+ .bx-note-tag{display:block;margin-bottom:6px;}
305
+ .bx-note-cost .bx-note-tag{color:var(--verified);}
306
+ .bx-note-super .bx-note-tag{color:var(--ink-soft);}
307
+ .bx-note p{margin:0;font-size:13px;line-height:1.5;color:var(--ink-soft);}
308
+ .bx-note b{color:var(--ink);}
309
+ .bx-note em{font-style:italic;}
310
+ .bx-strike{text-decoration:line-through;color:var(--ink-soft);text-decoration-color:var(--verified);}
311
+ .bx-footnote{margin:0;font-size:12px;line-height:1.55;color:var(--ink-soft);max-width:100%;border-top:1px dashed var(--line);padding-top:14px;}
312
+ .bx-footnote b{color:var(--ink);}
313
+
314
+ @media (max-width:860px){
315
+ .bx-recon-grid{grid-template-columns:1fr;}
316
+ .bx-xm-cards{grid-template-columns:1fr;}
317
+ .bx-conv-grid{grid-template-columns:1fr;}
318
+ .bx-headline{grid-template-columns:1fr;}
319
+ .bx-dims{grid-template-columns:1fr;}
320
+ .bx-dim-struct{grid-column:auto;}
321
+ .bx-notes{grid-template-columns:1fr;}
322
+ }
323
+ @media (max-width:520px){
324
+ .bx-xm{padding:14px;}
325
+ .bx-xm-card{padding:15px 16px;}
326
+ .bx-xm-stat b{font-size:26px;}
327
+ .bx-xm-nums{gap:16px;}
328
+ .bx-recon{padding:14px;}
329
+ .bx-conv-num{font-size:20px;}
330
+ .bx-dim{padding:14px;}
331
+ .bx-body{grid-template-columns:1fr;gap:12px;}
332
+ .bx-delta{flex-direction:row;align-items:baseline;gap:8px;padding-left:0;border-left:0;border-top:1px solid var(--line);padding-top:10px;width:100%;justify-content:space-between;}
333
+ .bx-delta-lead{margin-bottom:0;order:1;}
334
+ .bx-delta-num{order:2;font-size:22px;}
335
+ .bx-delta-cap{order:3;margin-top:0;}
336
+ .bx-head-nums{gap:16px;}
337
+ .bx-head-stat b{font-size:24px;}
338
+ .bx-row{grid-template-columns:46px minmax(0,1fr) 42px;gap:8px;}
339
+ .bx-plat-name{white-space:normal;}
340
+ .bx-plat-fix{display:block;margin-left:0;margin-top:3px;}
341
+ .bx-plat-top{margin-bottom:22px;}
342
+ }
343
+ /* tightest stop: force the triple mono stats to a stable 3-col grid instead of ad-hoc wrap */
344
+ @media (max-width:390px){
345
+ .bx-xm-nums,.bx-head-nums{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;align-items:end;}
346
+ .bx-xm-stat b,.bx-head-stat b{font-size:21px;}
347
+ .bx-xm-stat span,.bx-head-stat span{font-size:10px;}
348
+ .bx-recon-num{font-size:26px;}
349
+ .bx-conv-pair{gap:8px;}
350
+ .bx-conv-num{font-size:18px;}
351
+ .bx-conv-vs{font-size:14px;}
352
+ /* inset the dumbbell axis at the narrowest width so no dot label leans on
353
+ the host page's outer padding to stay inside; the edge-aligned rightmost
354
+ labels then sit comfortably within the padded axis parent. */
355
+ .bx-axis{margin:0 8px;}
356
+ .bx-axis-scale{margin:0 14px;}
357
+ }
358
+
359
+ .catgroup{padding-top:22px;}
360
+ .cathead{display:grid;grid-template-columns:72px minmax(0,1fr);gap:20px;align-items:flex-start;padding:62px 0 18px;scroll-margin-top:16px;}
361
+ .cathead .catletter{font-family:var(--mono);font-size:52px;font-weight:900;color:var(--brand);line-height:1;flex:none;}
362
+ .cathead h2{font-size:clamp(28px,4vw,42px);line-height:1.08;margin:0 0 8px;text-wrap:balance;}
363
+ .cathead p{font-size:16px;color:var(--ink-soft);margin:0;max-width:62ch;}
364
+
365
+ section.problem{padding:24px;margin:18px 0;border:1px solid var(--line);border-radius:14px;background:rgba(255,255,255,.88);box-shadow:0 14px 38px rgba(32,47,75,.08);}
366
+ .ftag{font-family:var(--mono);font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-faint);margin:0 0 10px;}
367
+ .problem h3{font-size:clamp(22px,2.4vw,30px);line-height:1.15;font-weight:800;margin:0 0 10px;text-wrap:balance;max-width:38ch;}
368
+ .pdesc{font-size:15.5px;color:var(--ink-soft);max-width:72ch;margin:0 0 22px;}
369
+
370
+ .diffrow{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;align-items:stretch;}
371
+ .pane{min-width:0;border-radius:10px;padding:16px;position:relative;}
372
+ .pane.bad{background:linear-gradient(180deg,#FFF7F6,#FDE9E7);border:1px solid var(--bad-line);}
373
+ .pane.good{background:linear-gradient(180deg,#F7FCF9,#E6F4EC);border:1px solid var(--good-line);}
374
+ .panelabel{font-family:var(--mono);font-size:11px;letter-spacing:.08em;margin:0 0 12px;display:flex;align-items:center;gap:6px;}
375
+ .pane.bad .panelabel{color:var(--bad);}
376
+ .pane.good .panelabel{color:var(--good);}
377
+ .panelabel .marker{font-weight:700;}
378
+
379
+ .phone{background:#F8FAFC;border-radius:14px;border:1px solid #E2E8F0;overflow:hidden;box-shadow:0 10px 24px rgba(32,47,75,.12);}
380
+ .phone .ptop{padding:10px 12px;font-size:11.5px;font-weight:800;border-bottom:1px solid rgba(15,23,42,.1);color:#111827;background:#F1F5F9;}
381
+ .phone .pbody{padding:14px;min-height:150px;font-size:12.5px;color:#111827;}
382
+
383
+ .mech{font-family:var(--mono);font-size:12.5px;line-height:1.7;color:var(--ink-soft);margin:18px 0 0;padding:14px 16px;border:1px solid var(--line);border-radius:10px;background:#F8FAFC;}
384
+ .mech b,.mech span{color:var(--ink);font-weight:700;}
385
+
386
+ /* --- mock content bits --- */
387
+ .row{display:flex;justify-content:space-between;align-items:center;padding:7px 0;border-bottom:1px dashed rgba(15,23,42,.12);}
388
+ .row:last-child{border-bottom:none;}
389
+ .muted{color:#697386;}
390
+ .redtxt{color:#B42318;font-family:var(--mono);font-size:11.5px;font-weight:700;}
391
+ .greentxt{color:#136B3A;font-family:var(--mono);font-size:11.5px;font-weight:700;}
392
+ .idblob{font-family:var(--mono);font-size:11px;background:#f5f0ea;border:1px solid #e6ddcf;padding:6px 8px;border-radius:4px;color:#7a6f5f;word-break:break-all;}
393
+ .namecard{font-weight:700;font-size:14px;margin-bottom:3px;}
394
+ .tagpill{display:inline-block;font-family:var(--mono);font-size:10px;padding:2px 7px;border-radius:10px;margin-top:6px;}
395
+ .tagpill.bad{background:var(--bad-soft);color:var(--bad);border:1px solid var(--bad-line);}
396
+ .tagpill.good{background:var(--good-soft);color:var(--good);border:1px solid var(--good-line);}
397
+ .spin{width:16px;height:16px;border-radius:50%;border:2px solid #e4ded2;border-top-color:var(--bad);display:inline-block;animation:spin 1s linear infinite;vertical-align:middle;margin-right:8px;}
398
+ @keyframes spin{to{transform:rotate(360deg);}}
399
+ .avatar{width:22px;height:22px;border-radius:50%;background:#9aa6a1;display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;margin-right:8px;color:#fff;font-size:9px;font-weight:700;font-family:var(--sans);}
400
+ .postline{height:7px;background:#e9e6de;border-radius:3px;margin:5px 0;}
401
+ .skel{height:34px;background:#eeece5;border-radius:6px;margin:8px 0;position:relative;overflow:hidden;}
402
+ .skel::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,transparent,rgba(255,255,255,.6),transparent);animation:shine 1.6s ease-in-out infinite;}
403
+ @keyframes shine{from{transform:translateX(-100%);}to{transform:translateX(100%);}}
404
+ .btn{display:inline-block;font-size:11.5px;font-weight:600;padding:6px 12px;border-radius:5px;margin-top:8px;}
405
+ .btn.disabled{background:#e7e4dc;color:#a9a49a;}
406
+ .btn.brand-generic{background:#3b6ef2;color:#fff;font-family:Arial,sans-serif;border-radius:14px;}
407
+ .btn.brand-native{background:#8a3b2e;color:#fff2ea;font-family:var(--mono);letter-spacing:.03em;border-radius:3px;}
408
+ .field{display:flex;justify-content:space-between;font-family:var(--mono);font-size:11px;padding:4px 0;}
409
+ .permline{display:flex;align-items:center;gap:6px;font-family:var(--mono);font-size:11px;padding:3px 0;}
410
+ .dot{width:7px;height:7px;border-radius:50%;flex:none;}
411
+ .dot.on{background:var(--good);}
412
+ .dot.off{background:var(--bad);}
413
+ .bubble{font-size:11.5px;padding:7px 10px;border-radius:10px;margin:5px 0;max-width:88%;}
414
+ .bubble.user{background:#E2E8F0;color:#111827;margin-left:auto;border-bottom-right-radius:3px;}
415
+ .bubble.bot{background:#EEF2F7;color:#334155;border-bottom-left-radius:3px;}
416
+ .optrow{border:1px solid rgba(0,0,0,.08);border-radius:6px;padding:6px 9px;margin:6px 0;font-size:11px;background:#fff;}
417
+ .optrow.picked{border-color:#86EFAC;background:#ECFDF5;}
418
+ .optrow b{display:block;font-size:11.5px;margin-bottom:1px;}
419
+ .optrow .d{color:#8a8a83;}
420
+ .optrow.picked .d{color:#277044;}
421
+
422
+ .demo-section{padding:70px 0 72px;border-top:1px solid var(--line);}
423
+ .demo-shell{display:flex;flex-direction:column;align-items:center;gap:18px;}
424
+ .demo-toggle{display:inline-flex;flex-wrap:wrap;justify-content:center;max-width:100%;border:1px solid var(--line);border-radius:999px;padding:4px;background:var(--paper-raised);}
425
+ .fitbtn{font-family:var(--mono);font-size:12px;letter-spacing:.02em;padding:9px 16px;border-radius:20px;border:none;background:transparent;color:var(--ink-soft);cursor:pointer;transition:background .2s ease,color .2s ease;}
426
+ .fitbtn.active[data-fmode="without"]{background:var(--bad);color:#fff;}
427
+ .fitbtn.active[data-fmode="vise"]{background:var(--good);color:#fff;}
428
+
429
+ /* ---------- realistic integration output gallery ---------- */
430
+ .showcase-gallery{margin:30px 0 34px;border:1px solid var(--line);border-radius:18px;background:linear-gradient(135deg,#FFFFFF 0%,#F7FAFC 62%,#EEF5F2 100%);padding:18px;box-shadow:0 18px 48px rgba(32,47,75,.1);}
431
+ .gallery-tabs{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 18px;}
432
+ .gallery-tab{min-height:44px;border:1px solid var(--line);background:#FFFFFF;color:var(--ink-soft);border-radius:999px;padding:10px 15px;font-weight:900;font-size:12.5px;cursor:pointer;box-shadow:0 1px 2px rgba(32,47,75,.05);transition:background .2s ease,border-color .2s ease,color .2s ease,transform .2s ease,box-shadow .2s ease;}
433
+ .gallery-tab.active{background:var(--brand);border-color:var(--brand);color:#FFFFFF;box-shadow:0 10px 24px rgba(23,107,87,.18);}
434
+ .gallery-tab:hover{border-color:var(--brand);color:var(--brand-dark);transform:translateY(-1px);}
435
+ .gallery-tab.active:hover{color:#FFFFFF;}
436
+ .gallery-stage{display:grid;grid-template-columns:minmax(280px,1fr) minmax(320px,420px);gap:24px;align-items:start;}
437
+ .gallery-copy{background:rgba(255,255,255,.94);border:1px solid var(--line);border-radius:14px;padding:22px;box-shadow:0 12px 30px rgba(32,47,75,.08);}
438
+ .gallery-copy .eyebrow{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-faint);margin:0 0 8px;}
439
+ .gallery-copy h3{font-size:28px;line-height:1.1;margin:0 0 12px;text-wrap:balance;}
440
+ .gallery-copy p{font-size:15px;color:var(--ink-soft);margin:0 0 16px;max-width:54ch;}
441
+ .gallery-brief{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:18px 0;}
442
+ .brief-card{border:1px solid var(--line);background:#F8FAFC;border-radius:10px;padding:10px;}
443
+ .brief-card b{display:block;font-size:12px;color:var(--ink);line-height:1.3;margin-bottom:3px;}
444
+ .brief-card span{display:block;font-size:11.5px;color:var(--ink-soft);line-height:1.35;}
445
+ .brief-label{font-family:var(--mono);font-size:9px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-faint);margin-bottom:5px;}
446
+ .gallery-proof{display:grid;gap:8px;margin:16px 0;}
447
+ .gallery-proof div{border:1px solid var(--line);background:#F8FAFC;border-radius:9px;padding:11px 12px;}
448
+ .gallery-proof b{display:block;font-size:12px;color:var(--ink);}
449
+ .gallery-proof span{font-size:12px;color:var(--ink-soft);}
450
+ .gallery-features{display:flex;flex-wrap:wrap;gap:7px;margin-top:16px;}
451
+ .gallery-features span{font-family:var(--mono);font-size:10.5px;color:var(--brand-dark);background:var(--brand-soft);border:1px solid #B9DBCF;border-radius:999px;padding:5px 8px;}
452
+ .showcase-device{display:grid;gap:12px;justify-items:center;}
453
+ .gallery-evidence{width:100%;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;}
454
+ .gallery-evidence div{border:1px solid var(--line);border-radius:10px;background:#FFFFFF;padding:10px;box-shadow:0 1px 2px rgba(32,47,75,.04);}
455
+ .gallery-evidence b{display:block;font-size:11px;color:var(--ink);line-height:1.25;}
456
+ .gallery-evidence span{display:block;font-size:10.5px;color:var(--ink-soft);line-height:1.35;margin-top:3px;}
457
+ .device-frame{width:380px;max-width:100%;background:#070A0F;border-radius:38px;padding:9px;box-shadow:var(--shadow);}
458
+ .device-screen{height:720px;border-radius:29px;overflow:hidden;background:#fff;display:flex;flex-direction:column;}
459
+ .phone-status{display:flex;justify-content:space-between;align-items:center;padding:10px 18px 2px;font-size:12px;font-weight:800;color:#111814;}
460
+ .phone-status .icons{display:flex;gap:5px;align-items:center;}
461
+ .phone-status .bar{display:inline-block;width:15px;height:9px;border-radius:2px;background:#111814;opacity:.82;}
462
+ .phone-app{display:flex;justify-content:space-between;align-items:center;padding:11px 16px 8px;}
463
+ .phone-brand{font-size:18px;font-weight:900;color:var(--brand-dark);}
464
+ .phone-avatar{width:38px;height:38px;border-radius:50%;background:var(--brand);color:#fff;display:inline-flex;align-items:center;justify-content:center;font-weight:900;font-size:13px;}
465
+ .phone-tabs{display:flex;gap:7px;padding:0 16px 12px;overflow-x:auto;}
466
+ .phone-tabs span{font-size:11px;font-weight:800;color:#70786f;border:1px solid #ece5d9;border-radius:999px;padding:6px 10px;white-space:nowrap;}
467
+ .phone-tabs .active{background:var(--brand);border-color:var(--brand);color:#fff;}
468
+ .phone-scroll{padding:0 16px 18px;overflow-y:auto;min-height:0;flex:1;}
469
+ .phone-hero{border-radius:16px;color:#fff;padding:16px;margin-bottom:14px;background:linear-gradient(135deg,var(--brand-dark),var(--brand));}
470
+ .phone-hero .kicker{font-family:var(--mono);font-size:10px;text-transform:uppercase;letter-spacing:.08em;opacity:.76;margin:0 0 8px;}
471
+ .phone-hero h4{font-size:28px;line-height:1.05;margin:0;letter-spacing:0;}
472
+ .phone-hero p{font-size:12.5px;line-height:1.45;opacity:.86;margin:10px 0 0;}
473
+ .phone-hero .subrow{display:flex;gap:7px;flex-wrap:wrap;margin-top:12px;}
474
+ .phone-hero .subrow span{font-family:var(--mono);font-size:10px;color:#fff;background:rgba(255,255,255,.15);border:1px solid rgba(255,255,255,.24);border-radius:999px;padding:5px 8px;}
475
+ .phone-metrics{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:14px;}
476
+ .phone-metric{border:1px solid #eee8dc;border-radius:10px;padding:10px;background:#fcfbf8;}
477
+ .phone-metric b{display:block;font-size:20px;color:#16201b;}
478
+ .phone-metric span{font-size:10px;color:#7d837a;}
479
+ .phone-context{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-bottom:14px;}
480
+ .phone-context-card{border:1px solid #E5E9F0;border-radius:12px;background:#F8FAFC;padding:10px;}
481
+ .phone-context-card b{display:block;font-size:12px;color:#172033;margin-bottom:3px;}
482
+ .phone-context-card span{display:block;font-size:10.5px;color:#657184;line-height:1.35;}
483
+ .phone-section-title{font-family:var(--mono);font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:#8d8a80;margin:18px 0 8px;}
484
+ .phone-community{border-radius:12px;padding:13px 14px;margin-bottom:12px;color:#fff;background:var(--brand);}
485
+ .phone-community b{display:block;font-size:15px;margin-bottom:3px;}
486
+ .phone-community span{font-size:11.5px;opacity:.88;}
487
+ .phone-feed-header{display:flex;justify-content:space-between;align-items:center;gap:10px;margin:12px 0 8px;}
488
+ .phone-feed-header b{font-size:13px;color:#1a211d;}
489
+ .phone-feed-header span{font-family:var(--mono);font-size:10px;color:var(--brand-dark);background:#EEF7F2;border:1px solid #CDE8DC;border-radius:999px;padding:5px 7px;white-space:nowrap;}
490
+ .phone-card{border:1px solid #eee8dc;border-radius:12px;background:#fff;padding:12px;margin-bottom:10px;}
491
+ .phone-author{display:flex;align-items:center;gap:9px;margin-bottom:9px;}
492
+ .mini-avatar{width:28px;height:28px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;color:#fff;font-weight:800;font-size:11px;flex:none;}
493
+ .phone-author b{display:block;font-size:12.5px;color:#1a211d;}
494
+ .phone-author span{font-size:10.5px;color:#8d8a80;}
495
+ .phone-post-title{font-size:13.5px;font-weight:900;color:#172033;margin:0 0 4px;line-height:1.25;}
496
+ .phone-card p{font-size:12.5px;line-height:1.45;color:#343b36;margin:0 0 10px;}
497
+ .phone-media{height:74px;border-radius:12px;margin:9px 0 10px;background:linear-gradient(135deg,rgba(23,107,87,.14),rgba(37,99,235,.12));border:1px solid #E4EBF3;display:grid;place-items:center;font-family:var(--mono);font-size:10.5px;color:#53606F;}
498
+ .phone-poll{border:1px solid #E5E9F0;border-radius:10px;background:#F8FAFC;padding:8px;margin:9px 0;}
499
+ .phone-poll b{display:block;font-size:11px;color:#172033;margin-bottom:6px;}
500
+ .phone-poll-row{height:20px;border-radius:999px;background:#E9EEF5;overflow:hidden;position:relative;margin-top:5px;}
501
+ .phone-poll-row span{position:relative;z-index:1;display:block;padding:3px 8px;font-size:10px;color:#172033;}
502
+ .phone-poll-row i{position:absolute;inset:0 auto 0 0;background:rgba(23,107,87,.22);}
503
+ .phone-actions{display:flex;gap:12px;font-size:11px;color:#777f75;font-weight:800;}
504
+ .phone-comment{display:flex;gap:8px;align-items:flex-start;border-radius:10px;background:#f5f1e9;padding:8px;margin-top:9px;font-size:11.5px;color:#4f574f;}
505
+ .phone-notice{border:1px solid #E5E9F0;background:#F8FAFC;border-radius:12px;padding:10px 11px;margin:10px 0;font-size:11.5px;line-height:1.4;color:#4B5565;}
506
+ .phone-notice b{color:#172033;}
507
+ .phone-composer{border:1px solid #eadfcf;border-radius:12px;background:#fff9ec;padding:10px;margin:12px 0;}
508
+ .phone-composer b{display:block;font-size:12px;color:#5c4630;margin-bottom:7px;}
509
+ .phone-field{border-radius:9px;background:#fff;padding:9px;color:#7b756a;font-size:11.5px;margin-bottom:9px;}
510
+ .phone-button{display:block;text-align:center;border-radius:999px;background:var(--brand);color:#fff;font-weight:900;font-size:12px;padding:9px;}
511
+ .phone-surface-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:12px 0;}
512
+ .phone-surface-pill{border:1px solid #E5E9F0;border-radius:12px;background:#FFFFFF;padding:9px;}
513
+ .phone-surface-pill b{display:block;font-size:11.5px;color:#172033;margin-bottom:2px;}
514
+ .phone-surface-pill span{font-size:10.5px;color:#657184;line-height:1.3;}
515
+ .phone-mod{border:1px solid #F2D0B5;background:#FFF7ED;color:#8B3A0B;border-radius:10px;padding:8px 10px;font-size:10.5px;line-height:1.35;margin:10px 0;}
516
+ .phone-side{display:grid;gap:9px;}
517
+ .phone-side-card{border:1px solid #eee8dc;background:#fff;border-radius:12px;padding:11px;}
518
+ .phone-side-card b{display:block;font-size:12.5px;color:#1c241f;margin-bottom:3px;}
519
+ .phone-side-card span{font-size:11.5px;color:#747b72;}
520
+ .phone-chat{display:flex;align-items:center;gap:8px;padding:8px 0;border-top:1px solid #f0ebe0;}
521
+ .phone-chat:first-of-type{border-top:none;}
522
+ .unread-dot{margin-left:auto;min-width:18px;height:18px;border-radius:9px;background:var(--brand);color:#fff;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;}
523
+ .phone-footer-proof{border-top:1px solid #EEF2F7;margin-top:12px;padding-top:10px;font-family:var(--mono);font-size:10px;color:#7B8797;line-height:1.45;}
524
+ .device-screen{--screen-bg:#fff;--card-bg:#fff;--card-line:#E5E9F0;--text-main:#172033;--text-muted:#657184;--soft:#F8FAFC;--hero-fg:#fff;background:var(--screen-bg);color:var(--text-main);}
525
+ .device-screen.theme-training{--screen-bg:#F6F1E8;--card-bg:#FFFDF8;--card-line:#E8DCC8;--text-main:#19231D;--text-muted:#756F63;--soft:#ECE4D6;--hero-fg:#FDFBF4;--brand:#1F7C68;--brand-dark:#12362D;--accent-soft:#DDEEE7;}
526
+ .device-screen.theme-market{--screen-bg:#F5F7FB;--card-bg:#FFFFFF;--card-line:#DCE4EE;--text-main:#111827;--text-muted:#627084;--soft:#EEF3F8;--hero-fg:#FFFFFF;--brand:#255F8E;--brand-dark:#122E47;--accent-soft:#DCEAF6;}
527
+ .device-screen.theme-audio{--screen-bg:#F7F2FA;--card-bg:#FFFEFC;--card-line:#E7DAEF;--text-main:#221B32;--text-muted:#766B83;--soft:#EFE8F5;--hero-fg:#FFFFFF;--brand:#6B55B6;--brand-dark:#2B214C;--accent-soft:#E8DFFD;}
528
+ .device-screen .phone-status{color:var(--text-main);}
529
+ .device-screen .phone-status .bar{background:var(--text-main);}
530
+ .device-screen .phone-brand{color:var(--text-main);}
531
+ .device-screen .phone-avatar{background:var(--brand);}
532
+ .device-screen .phone-tabs span{background:rgba(255,255,255,.55);border-color:var(--card-line);color:var(--text-muted);}
533
+ .device-screen .phone-tabs .active{background:var(--brand);border-color:var(--brand);color:#fff;}
534
+ .phone-native-hero{border-radius:18px;color:var(--hero-fg);padding:14px;margin-bottom:10px;background:linear-gradient(135deg,var(--brand-dark),var(--brand));box-shadow:0 14px 28px rgba(17,24,39,.12);}
535
+ .phone-native-hero .kicker{font-family:var(--mono);font-size:10px;text-transform:uppercase;letter-spacing:.08em;opacity:.76;margin:0 0 8px;}
536
+ .phone-native-hero h4{font-size:23px;line-height:1.05;margin:0;letter-spacing:0;}
537
+ .phone-native-hero p{font-size:12px;line-height:1.38;opacity:.88;margin:8px 0 0;}
538
+ .native-visual{height:58px;border-radius:14px;margin-top:10px;background:rgba(255,255,255,.15);border:1px solid rgba(255,255,255,.24);position:relative;overflow:hidden;}
539
+ .visual-route::before{content:"";position:absolute;left:24px;right:24px;top:48px;height:3px;background:#fff;border-radius:99px;transform:rotate(-9deg);box-shadow:54px -19px 0 -1px rgba(255,255,255,.85),112px 12px 0 -1px rgba(255,255,255,.75),178px -13px 0 -1px rgba(255,255,255,.65);}
540
+ .visual-route::after{content:"7.4 km Marina loop";position:absolute;left:14px;bottom:12px;font-family:var(--mono);font-size:10px;color:rgba(255,255,255,.88);}
541
+ .visual-chart{display:flex;align-items:flex-end;gap:8px;padding:16px 16px 26px;}
542
+ .visual-chart span{flex:1;border-radius:5px 5px 0 0;background:rgba(255,255,255,.78);min-height:18px;}
543
+ .visual-chart::after{content:"watchlist +3.2%";position:absolute;left:16px;bottom:10px;font-family:var(--mono);font-size:10px;color:rgba(255,255,255,.88);}
544
+ .visual-wave{display:flex;align-items:center;gap:5px;padding:12px 16px;}
545
+ .visual-wave span{width:6px;border-radius:999px;background:rgba(255,255,255,.82);}
546
+ .visual-wave::after{content:"episode waveform · 21:40";position:absolute;left:16px;bottom:10px;font-family:var(--mono);font-size:10px;color:rgba(255,255,255,.88);}
547
+ .native-tiles{display:grid;grid-template-columns:repeat(3,1fr);gap:7px;margin:0 0 10px;}
548
+ .native-tile{border:1px solid var(--card-line);border-radius:13px;background:var(--card-bg);padding:8px;box-shadow:0 6px 16px rgba(17,24,39,.05);}
549
+ .native-tile b{display:block;font-size:16px;line-height:1;color:var(--text-main);}
550
+ .native-tile span{display:block;font-size:10px;color:var(--text-muted);margin-top:5px;line-height:1.25;}
551
+ .native-list{display:grid;gap:7px;margin-bottom:10px;}
552
+ .native-row{display:flex;align-items:center;gap:8px;border:1px solid var(--card-line);border-radius:13px;background:var(--card-bg);padding:8px;}
553
+ .native-icon{width:30px;height:30px;border-radius:10px;background:var(--accent-soft);display:inline-flex;align-items:center;justify-content:center;color:var(--brand-dark);font-weight:900;font-size:10px;flex:none;}
554
+ .native-row b{display:block;font-size:12px;color:var(--text-main);}
555
+ .native-row span{font-size:10.5px;color:var(--text-muted);}
556
+ .social-anchor{border:1px solid color-mix(in srgb,var(--brand) 35%,white);border-radius:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--brand) 9%,white),var(--card-bg));padding:11px;margin:10px 0;}
557
+ .social-anchor .label{font-family:var(--mono);font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--brand-dark);margin:0 0 6px;}
558
+ .social-anchor b{display:block;font-size:14px;color:var(--text-main);}
559
+ .social-anchor span{display:block;font-size:11.5px;color:var(--text-muted);line-height:1.35;margin-top:3px;}
560
+ .device-screen .phone-card,.device-screen .phone-composer,.device-screen .phone-surface-pill,.device-screen .phone-notice{background:var(--card-bg);border-color:var(--card-line);}
561
+ .device-screen .phone-section-title{color:var(--text-muted);}
562
+ .device-screen .phone-feed-header b,.device-screen .phone-post-title,.device-screen .phone-author b,.device-screen .phone-surface-pill b,.device-screen .phone-notice b{color:var(--text-main);}
563
+ .device-screen .phone-card p,.device-screen .phone-author span,.device-screen .phone-surface-pill span,.device-screen .phone-notice,.device-screen .phone-comment{color:var(--text-muted);}
564
+ .device-screen .phone-media{background:var(--soft);border-color:var(--card-line);color:var(--text-muted);}
565
+ .phone-media .media-label{font-family:var(--mono);font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);}
566
+ .phone-media .media-bars{display:flex;align-items:end;gap:5px;width:78%;height:34px;margin-top:8px;}
567
+ .phone-media .media-bars i{display:block;flex:1;border-radius:3px 3px 0 0;background:var(--brand);opacity:.5;}
568
+ .theme-audio .phone-media .media-bars{align-items:center;}
569
+ .theme-audio .phone-media .media-bars i{width:5px;flex:none;border-radius:999px;opacity:.68;}
570
+ .phone-bottom-nav{display:flex;flex:none;border-top:1px solid var(--card-line);background:rgba(255,255,255,.76);padding:7px 8px 11px;backdrop-filter:blur(10px);}
571
+ .phone-bottom-nav span{flex:1;text-align:center;font-size:10px;font-weight:800;color:var(--text-muted);}
572
+ .phone-bottom-nav .active{color:var(--brand-dark);}
573
+
574
+ /* ---------- production-grade demo phone ---------- */
575
+ .demo-phone{width:330px;max-width:100%;aspect-ratio:9/19.5;background:#fff;border-radius:34px;border:8px solid #070A0F;box-shadow:var(--shadow);}
576
+ .demo-phone .screenclip{border-radius:24px;overflow:hidden;background:#fff;height:100%;display:flex;flex-direction:column;}
577
+ .statusbar{display:flex;flex:none;justify-content:space-between;align-items:center;padding:10px 18px 2px;font-size:12px;font-weight:700;color:#0d1210;font-family:var(--sans);}
578
+ .statusbar .icons{display:flex;align-items:center;gap:5px;}
579
+ .sig{display:flex;align-items:flex-end;gap:2px;height:8px;}
580
+ .sig i{width:2.5px;background:#0d1210;border-radius:1px;display:block;}
581
+ .sig i:nth-child(1){height:35%;} .sig i:nth-child(2){height:55%;} .sig i:nth-child(3){height:78%;} .sig i:nth-child(4){height:100%;}
582
+ .wifi{width:13px;height:9px;border:1.6px solid #0d1210;border-top:none;border-radius:0 0 9px 9px;}
583
+ .batt{width:21px;height:10px;border:1.4px solid #0d1210;border-radius:2px;padding:1.5px;position:relative;}
584
+ .batt i{display:block;width:75%;height:100%;background:#0d1210;border-radius:1px;}
585
+ .batt::after{content:"";position:absolute;right:-3px;top:3px;width:2px;height:4px;background:#0d1210;border-radius:0 1px 1px 0;}
586
+ .appbar{display:flex;flex:none;align-items:center;justify-content:space-between;padding:10px 16px 12px;}
587
+ .appbar .wordmark{font-family:var(--sans);font-weight:800;font-size:16px;letter-spacing:-.01em;color:var(--brand-dark);}
588
+ .appbar .wordmark::before{content:"◆";color:var(--brand);font-size:11px;margin-right:6px;}
589
+ .style-ref{font-size:10px;color:#a29d8f;font-style:italic;align-self:center;}
590
+ .screenclip.dark .style-ref{color:#6b7075;}
591
+ .statrow{display:flex;justify-content:space-between;margin:8px 0 20px;text-align:center;}
592
+ .statnum{font-size:25px;font-weight:800;color:#141a16;}
593
+ .screenclip.dark .statnum{color:#fff;}
594
+ .statlabel{font-size:11px;color:#8c897d;margin-top:2px;}
595
+ .listing-thumb{width:44px;height:44px;border-radius:8px;flex:none;background:linear-gradient(135deg,#e9e6de,#d3cfc2);}
596
+ .progress-track{height:5px;background:#eee;border-radius:3px;margin-top:6px;overflow:hidden;}
597
+ .screenclip.dark .progress-track{background:#2a2e31;}
598
+ .progress-fill{height:100%;background:var(--brand);}
599
+ .social-pulse{display:flex;align-items:flex-start;gap:8px;margin-top:16px;padding:10px 12px;border-radius:8px;background:#f6f4ee;border-left:3px solid var(--brand);font-size:11.5px;line-height:1.4;color:#5c6259;}
600
+ .social-pulse .ic{width:15px;height:15px;color:var(--brand);flex:none;margin-top:1px;}
601
+ .social-pulse b{color:#2a2f2a;}
602
+ .screenclip.dark .social-pulse{background:#1c2023;color:#a6ada8;}
603
+ .screenclip.dark .social-pulse b{color:#e4e7e3;}
604
+ .activity-label{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:#a29d8f;margin:20px 0 6px;}
605
+ .screenclip.dark .activity-label{color:#6b7075;}
606
+ .trend{display:flex;align-items:flex-end;gap:4px;height:34px;margin:16px 0 4px;}
607
+ .trend i{flex:1;display:block;background:var(--brand);opacity:.32;border-radius:2px 2px 0 0;}
608
+ .coach-tip{margin-top:14px;padding:10px 12px;border-radius:8px;background:#f0eee6;font-size:11.5px;line-height:1.4;color:#5c6259;}
609
+ .screenclip.dark .coach-tip{background:#1e2225;color:#a6ada8;}
610
+ .groups-strip{display:flex;gap:12px;overflow-x:auto;padding:2px 0 6px;margin-bottom:2px;}
611
+ .group-chip{display:flex;flex-direction:column;align-items:center;gap:6px;width:66px;flex:none;}
612
+ .group-chip .p-avatar{width:46px;height:46px;font-size:14px;}
613
+ .group-name{font-size:10px;line-height:1.25;text-align:center;color:#8c897d;}
614
+ .screenclip.dark .group-name{color:#9199a1;}
615
+ .acct-list{margin-top:8px;}
616
+ .acct-row{display:flex;justify-content:space-between;align-items:center;padding:11px 0;border-bottom:1px solid #f0ede4;font-size:13px;color:#141a16;}
617
+ .acct-row:last-child{border-bottom:none;}
618
+ .acct-val{color:#8c897d;}
619
+ .screenclip.dark .acct-row{border-bottom-color:#262a2d;color:#e4e7e3;}
620
+ .screenclip.dark .acct-val{color:#9199a1;}
621
+
622
+ /* ---------- curated 15-point example demo ---------- */
623
+ .pin{display:inline-flex;align-items:center;justify-content:center;min-width:16px;height:16px;padding:0 4px;border-radius:8px;font-size:9px;font-weight:700;font-family:var(--mono);margin-left:6px;vertical-align:middle;color:#fff;}
624
+ .pin.bad{background:var(--bad);}
625
+ .pin.good{background:var(--good);}
626
+ .pin-holder{margin:5px 0 2px;}
627
+ .cx-head{margin-bottom:8px;}
628
+ .cx-title{font-size:15px;font-weight:800;color:#141a16;}
629
+ .cx-sub{font-size:11px;color:#8c897d;}
630
+ .screenclip.dark .cx-title{color:#fff;}
631
+ .p-empty{border:1px dashed var(--bad-line);border-radius:5px;margin:8px 0;padding:5px 8px;font-size:10.5px;color:#c97f6e;}
632
+ .cx-err{font-size:11.5px;color:#c97f6e;margin:8px 0;}
633
+ .cx-missing,.cx-empty,.p-nocomment{font-size:11.5px;color:#8c897d;margin:8px 0;}
634
+ .screenclip.dark .cx-missing,.screenclip.dark .cx-empty,.screenclip.dark .p-nocomment{color:#7d838a;}
635
+ .cx-ok{font-size:11.5px;color:#3F6B45;margin:8px 0;}
636
+ .screenclip.dark .cx-ok{color:#7FA986;}
637
+ .cx-blank{border:1px dashed #3a3f43;border-radius:6px;margin-top:14px;padding:8px 10px;font-size:10.5px;color:#6b7075;}
638
+ .fit-legend{font-family:var(--mono);font-size:11px;color:var(--ink-faint);text-align:center;margin:16px 0 6px;max-width:60ch;}
639
+ .fit-counter{font-family:var(--mono);font-size:12px;text-align:center;margin-top:14px;padding:8px 16px;border-radius:20px;}
640
+ .fit-counter.bad{color:var(--bad);background:var(--bad-soft);border:1px solid var(--bad-line);}
641
+ .fit-counter.good{color:var(--good);background:var(--good-soft);border:1px solid var(--good-line);}
642
+ .uth{display:grid;grid-template-columns:1fr 1fr;gap:8px;width:320px;max-width:100%;margin:16px auto 0;}
643
+ .uth-lbl{grid-column:1 / -1;font-family:var(--mono);font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-faint);text-align:center;}
644
+ .uth-item{border:1px solid var(--line);border-radius:8px;padding:9px 11px;font-family:var(--mono);font-size:10.5px;background:var(--paper-raised);}
645
+ .uth-item .uth-k{color:var(--ink-soft);display:flex;align-items:center;justify-content:space-between;}
646
+ .uth-item .uth-v{font-weight:700;margin-top:3px;}
647
+ .uth-item.bad .uth-v{color:var(--bad);}
648
+ .uth-item.good .uth-v{color:var(--good);}
649
+ .demo-content{padding:2px 16px 18px;flex:1;min-height:0;overflow-y:auto;font-family:var(--sans);}
650
+ .ic{width:20px;height:20px;display:inline-block;vertical-align:middle;}
651
+ @media (max-width:720px){.capgrid{grid-template-columns:1fr;}}
652
+
653
+ .p-avatar{width:34px;height:34px;border-radius:50%;flex:none;display:inline-flex;align-items:center;justify-content:center;color:#fff;font-size:12px;font-weight:700;font-family:var(--sans);}
654
+ .p-card{padding:14px 0;border-bottom:1px solid #f0ede4;}
655
+ .p-card:last-child{border-bottom:none;}
656
+ .p-head{display:flex;align-items:center;gap:10px;}
657
+ .p-name{font-size:13.5px;font-weight:700;color:#141a16;}
658
+ .p-time{font-size:11.5px;color:#9a978c;font-weight:500;}
659
+ .p-body{font-size:13px;line-height:1.5;color:#262d28;margin:10px 0 12px;}
660
+ .p-actions{display:flex;align-items:center;gap:18px;}
661
+ .p-action{display:flex;align-items:center;gap:5px;font-size:12px;color:#8c897d;font-weight:600;}
662
+ .p-action .ic{width:18px;height:18px;}
663
+ .p-action.liked{color:var(--bad);}
664
+ .p-reply{display:flex;gap:8px;margin-top:6px;padding-left:2px;}
665
+ .p-reply .p-avatar{width:22px;height:22px;font-size:9px;}
666
+ .p-reply .txt{font-size:12px;color:#4e534d;background:#f5f2ea;border-radius:12px;padding:6px 11px;}
667
+
668
+ .cover{height:76px;border-radius:14px;background:linear-gradient(135deg,var(--brand) 0%,var(--brand-dark) 100%);position:relative;margin-bottom:34px;}
669
+ .cover .p-avatar{position:absolute;left:14px;bottom:-22px;width:52px;height:52px;font-size:16px;border:3px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,.15);}
670
+ .cgroup-name{font-size:16px;font-weight:800;color:#141a16;margin:0 0 2px;}
671
+ .cgroup-meta{font-size:12px;color:#8c897d;display:flex;align-items:center;gap:5px;}
672
+ .pill-btn{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:700;padding:9px 18px;border-radius:20px;border:none;margin-top:12px;font-family:var(--sans);}
673
+ .pill-btn.primary{background:var(--brand);color:#fff;}
674
+ .pill-btn.ghost{background:#eef1ee;color:#141a16;}
675
+
676
+ .chat-row{display:flex;align-items:center;gap:11px;padding:11px 0;border-bottom:1px solid #f0ede4;}
677
+ .chat-row:last-child{border-bottom:none;}
678
+ .chat-name{font-size:13.5px;font-weight:700;color:#141a16;}
679
+ .chat-preview{font-size:12px;color:#8c897d;margin-top:1px;}
680
+ .chat-meta{margin-left:auto;text-align:right;flex:none;}
681
+ .chat-time{font-size:10.5px;color:#b0ac9f;}
682
+ .unread{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;border-radius:9px;background:var(--brand);color:#fff;font-size:10px;font-weight:700;margin-top:4px;}
683
+
684
+ .prof-head{display:flex;align-items:center;gap:14px;padding-top:6px;}
685
+ .prof-head .p-avatar{width:58px;height:58px;font-size:18px;}
686
+ .prof-stats{display:flex;gap:18px;margin:14px 0 4px;}
687
+ .prof-stat b{display:block;font-size:15px;color:#141a16;}
688
+ .prof-stat span{font-size:11px;color:#8c897d;}
689
+
690
+ .errscreen{display:flex;flex-direction:column;align-items:center;text-align:center;padding-top:56px;color:#8c897d;}
691
+ .errscreen .glyph{width:38px;height:38px;border-radius:50%;background:#f6e6e1;color:var(--bad);display:flex;align-items:center;justify-content:center;font-family:var(--mono);font-weight:700;margin-bottom:12px;}
692
+ .errscreen .err-title{font-size:13px;font-weight:700;color:#3a3a34;}
693
+ .errscreen .code{font-family:var(--mono);font-size:10.5px;color:#a89f8e;background:#f5f2ea;border-radius:6px;padding:8px 12px;margin-top:12px;max-width:230px;}
694
+
695
+ .tabbar2{display:flex;flex:none;border-top:1px solid #f0ede4;padding:6px 4px 10px;}
696
+ .tabbtn{flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;background:none;border:none;padding:6px 2px;font-family:var(--sans);font-size:10px;color:#b0ac9f;cursor:pointer;}
697
+ .tabbtn .ic{width:22px;height:22px;}
698
+ .tabbtn.active{color:var(--brand-dark);}
699
+
700
+ /* ---------- per-vertical dark skin (e.g. betting) ---------- */
701
+ .screenclip.dark{background:#14171a;}
702
+ .screenclip.dark .statusbar{color:#fff;}
703
+ .screenclip.dark .sig i{background:#fff;}
704
+ .screenclip.dark .wifi{border-color:#fff;}
705
+ .screenclip.dark .batt{border-color:#fff;}
706
+ .screenclip.dark .batt i{background:#fff;}
707
+ .screenclip.dark .batt::after{background:#fff;}
708
+ .screenclip.dark .demo-content{color:#dfe1e0;}
709
+ .screenclip.dark .p-card,.screenclip.dark .chat-row{border-bottom-color:#262a2d;}
710
+ .screenclip.dark .p-name,.screenclip.dark .chat-name,.screenclip.dark .cgroup-name,.screenclip.dark .prof-stat b{color:#fff;}
711
+ .screenclip.dark .p-time,.screenclip.dark .chat-preview,.screenclip.dark .muted,.screenclip.dark .prof-stat span,.screenclip.dark .cgroup-meta,.screenclip.dark .errscreen,.screenclip.dark .statlabel{color:#9199a1;}
712
+ .screenclip.dark .p-body{color:#d3d6d5;}
713
+ .screenclip.dark .p-reply .txt{background:#202427;color:#c7cace;}
714
+ .screenclip.dark .tabbtn{color:#8f959b;}
715
+ .screenclip.dark .tabbtn.active{color:var(--brand);}
716
+ .screenclip.dark .appbar .wordmark{color:#fff;}
717
+ .screenclip.dark .pill-btn.primary{color:#0e1210;}
718
+ .screenclip.dark .unread{color:#0e1210;}
719
+ .screenclip.dark .pill-btn.ghost{background:#222629;color:#fff;}
720
+ .screenclip.dark .errscreen .code{background:#1d2124;color:#a7abaf;border-color:#2a2e31;}
721
+ .screenclip.dark .errscreen .glyph{background:#3a2325;color:#e28a7d;}
722
+ .screenclip.dark .errscreen .err-title{color:#fff;}
723
+ @media (max-width:860px){
724
+ .hero{grid-template-columns:1fr;padding-top:42px;}
725
+ .hero h1{max-width:14ch;}
726
+ .panel-stat{grid-template-columns:1fr 1fr;}
727
+ .capgrid{grid-template-columns:1fr;}
728
+ .cathead{grid-template-columns:52px 1fr;}
729
+ .cathead .catletter{font-size:42px;}
730
+ .diffrow{grid-template-columns:1fr;}
731
+ .gallery-stage{grid-template-columns:minmax(0,1fr);}
732
+ .device-frame{width:100%;max-width:380px;margin:0 auto;}
733
+ .device-screen{height:680px;}
734
+ }
735
+ @media (max-width:520px){
736
+ .wrap{padding:0 16px 88px;}
737
+ .masthead .meta{text-align:left;}
738
+ .hero h1{font-size:40px;}
739
+ .loop li div span{display:none;}
740
+ .hero-actions{display:grid;}
741
+ section.problem{padding:18px;border-radius:12px;}
742
+ .phone .pbody{min-height:128px;}
743
+ .panel-stat{grid-template-columns:1fr 1fr;}
744
+ .uth{grid-template-columns:1fr;}
745
+ .phone-hero h4{font-size:24px;}
746
+ .phone-metrics{grid-template-columns:1fr;}
747
+ .gallery-brief,.gallery-evidence,.phone-context,.phone-surface-grid{grid-template-columns:1fr;}
748
+ .showcase-gallery{padding:14px;border-radius:14px;}
749
+ .gallery-copy{padding:18px;}
750
+ }
751
+
752
+ .closer{padding:60px 0 0;border-top:1px solid var(--line);}
753
+ .closer p{font-size:15.5px;color:var(--ink-soft);max-width:66ch;}
754
+ .closer a{color:var(--verified);}
755
+ .colophon{padding:32px 0 0;font-family:var(--mono);font-size:11px;color:var(--ink-faint);line-height:1.8;}
756
+ </style>
757
+
758
+ <svg aria-hidden="true" style="position:absolute;width:0;height:0;overflow:hidden;">
759
+ <defs>
760
+ <symbol id="ic-heart" viewBox="0 0 24 24"><path d="M12 20.3c-.3 0-.6-.1-.8-.3C7.5 17.3 4 14 4 10.1 4 7.2 6.2 5 9 5c1.4 0 2.7.7 3 1.8.3-1.1 1.6-1.8 3-1.8 2.8 0 5 2.2 5 5.1 0 3.9-3.5 7.2-7.2 10-.2.1-.5.2-.8.2z" fill="currentColor"/></symbol>
761
+ <symbol id="ic-comment" viewBox="0 0 24 24"><path d="M4 5.5h16a1 1 0 0 1 1 1V16a1 1 0 0 1-1 1H9.2L5 20.5V17H4a1 1 0 0 1-1-1V6.5a1 1 0 0 1 1-1z" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/></symbol>
762
+ <symbol id="ic-share" viewBox="0 0 24 24"><circle cx="6" cy="12" r="2.2" fill="none" stroke="currentColor" stroke-width="1.6"/><circle cx="17.5" cy="6" r="2.2" fill="none" stroke="currentColor" stroke-width="1.6"/><circle cx="17.5" cy="18" r="2.2" fill="none" stroke="currentColor" stroke-width="1.6"/><line x1="8" y1="11" x2="15.5" y2="7.2" stroke="currentColor" stroke-width="1.5"/><line x1="8" y1="13" x2="15.5" y2="16.8" stroke="currentColor" stroke-width="1.5"/></symbol>
763
+ <symbol id="tab-feed" viewBox="0 0 24 24"><rect x="3" y="3" width="7.5" height="7.5" rx="2" fill="currentColor"/><rect x="13.5" y="3" width="7.5" height="7.5" rx="2" fill="currentColor" opacity=".5"/><rect x="3" y="13.5" width="7.5" height="7.5" rx="2" fill="currentColor" opacity=".5"/><rect x="13.5" y="13.5" width="7.5" height="7.5" rx="2" fill="currentColor"/></symbol>
764
+ <symbol id="tab-community" viewBox="0 0 24 24"><circle cx="9" cy="7.5" r="3.4" fill="currentColor"/><circle cx="17" cy="9" r="2.6" fill="currentColor" opacity=".5"/><path d="M3 20c0-3.6 2.7-6.2 6-6.2s6 2.6 6 6.2" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/><path d="M14.5 20c0-2.7 1.6-4.6 3.7-4.6 1.7 0 3.2 1.3 3.6 3.2" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" opacity=".5"/></symbol>
765
+ <symbol id="tab-chat" viewBox="0 0 24 24"><path d="M4 5h16a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1H10l-4.6 3.7V16H4a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1z" fill="currentColor"/><circle cx="9" cy="10.4" r="1.1" fill="#fff"/><circle cx="13" cy="10.4" r="1.1" fill="#fff"/><circle cx="17" cy="10.4" r="1.1" fill="#fff"/></symbol>
766
+ <symbol id="tab-profile" viewBox="0 0 24 24"><circle cx="12" cy="8" r="4" fill="currentColor"/><path d="M4 20c0-4.4 3.6-7 8-7s8 2.6 8 7" fill="currentColor"/></symbol>
767
+ <symbol id="tab-native" viewBox="0 0 24 24"><polygon points="13,2 4,14 11,14 10,22 20,10 13,10" fill="currentColor"/></symbol>
768
+ <symbol id="ic-pulse" viewBox="0 0 24 24"><path d="M2 12h4l2.5-7 5 14 2.5-7H22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></symbol>
769
+ <symbol id="ic-chart" viewBox="0 0 24 24"><rect x="4" y="12" width="3.4" height="8" rx="1" fill="currentColor"/><rect x="10.3" y="7" width="3.4" height="13" rx="1" fill="currentColor"/><rect x="16.6" y="4" width="3.4" height="16" rx="1" fill="currentColor"/></symbol>
770
+ <symbol id="ic-bag" viewBox="0 0 24 24"><path d="M6 8h12l-1 12H7L6 8z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="M9 8V6.5a3 3 0 0 1 6 0V8" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></symbol>
771
+ <symbol id="ic-wallet" viewBox="0 0 24 24"><rect x="3.5" y="6" width="17" height="13" rx="2.5" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M3.5 10h17" stroke="currentColor" stroke-width="1.8"/><circle cx="16.5" cy="14.5" r="1.4" fill="currentColor"/></symbol>
772
+ <symbol id="ic-calendar" viewBox="0 0 24 24"><rect x="4" y="5.5" width="16" height="15" rx="2.5" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M4 10h16M8 3.5v4M16 3.5v4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></symbol>
773
+ <symbol id="ic-clipboard" viewBox="0 0 24 24"><rect x="5.5" y="5" width="13" height="16" rx="2.2" fill="none" stroke="currentColor" stroke-width="1.8"/><rect x="9" y="3" width="6" height="4" rx="1.4" fill="currentColor"/><path d="M9 12h6M9 16h4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></symbol>
774
+ </defs>
775
+ </svg>
776
+
777
+ <div class="doc">
778
+ <div class="wrap">
779
+
780
+ <div class="masthead">
781
+ <div class="tag"><b>VISE</b> — HOW IT HELPS</div>
782
+ <div class="meta">Vise capability explainer<br>Updated 2026-07-02</div>
783
+ </div>
784
+
785
+ <section class="hero reveal">
786
+ <div class="hero-copy">
787
+ <p class="eyebrow">Agentic workflow governance for social.plus</p>
788
+ <h1>From plausible code to proven integration.</h1>
789
+ <p class="sub">Vise helps an AI coding agent move from a broad social.plus request to a scoped, SDK-grounded, evidence-backed implementation. It does not replace the agent or the human reviewer; it gives both a better operating system.</p>
790
+ <p class="note">Every screen below is a simplified, redrawn mock built to make each mechanism legible at a glance. The current benchmark scorecard and calculation method live in the public README.</p>
791
+ <div class="hero-actions">
792
+ <a class="hero-action primary" href="#live-demo">View realistic output</a>
793
+ <a class="hero-action" href="#cat-a">Browse example checks</a>
794
+ </div>
795
+ </div>
796
+ <aside class="hero-panel" aria-label="Vise workflow summary">
797
+ <p class="panel-label">Current workflow shape</p>
798
+ <ol class="loop">
799
+ <li><span class="num">01</span><div><b>Clarify</b><span>Resolve scope, platform, region, and social target.</span></div></li>
800
+ <li><span class="num">02</span><div><b>Offer EI experiences</b><span>Turn broad asks into concrete product directions.</span></div></li>
801
+ <li><span class="num">03</span><div><b>Blueprint sign-off</b><span>Lock selected surfaces before build work starts.</span></div></li>
802
+ <li><span class="num">04</span><div><b>Build and check</b><span>Use SDK facts, sensors, completeness, and runtime proof.</span></div></li>
803
+ </ol>
804
+ <div class="panel-stat">
805
+ <div><b>400+</b><span>platform-specific checks</span></div>
806
+ <div><b>15</b><span>illustrated examples</span></div>
807
+ </div>
808
+ </aside>
809
+ <nav class="toc" aria-label="Page sections">
810
+ <a href="#capabilities">What Vise does</a>
811
+ <a href="#benchmark">Benchmark evidence</a>
812
+ <a href="#cat-a">A · Right thing</a>
813
+ <a href="#cat-b">B · Runtime</a>
814
+ <a href="#cat-c">C · Wiring</a>
815
+ <a href="#cat-d">D · Completeness</a>
816
+ <a href="#cat-e">E · Polish &amp; safety</a>
817
+ </nav>
818
+ </section>
819
+
820
+ <section class="capabilities reveal" id="capabilities">
821
+ <p class="section-kicker">Capability model</p>
822
+ <h2>What Vise can and cannot do</h2>
823
+ <p class="intro">Vise is workflow governance for AI coding agents implementing social.plus. It gives the agent a local, evidence-backed path from product intent to SDK-correct implementation, while keeping the human in control of scope and runtime proof.</p>
824
+ <div class="capgrid">
825
+ <div class="capcard layer">
826
+ <h3>1. Alignment layer</h3>
827
+ <p>Clarifies the product ask, proposes EI directions when the request is broad, and holds blueprint sign-off before the agent commits to a multi-surface build.</p>
828
+ <div class="chipline"><span>inspect</span><span>creative</span><span>plan</span></div>
829
+ </div>
830
+ <div class="capcard layer">
831
+ <h3>2. Implementation layer</h3>
832
+ <p>Grounds the agent in SDK facts, dependency expectations, target-discovery rules, source scanners, per-surface completeness checks, and 400+ platform-specific validation checks.</p>
833
+ <div class="chipline"><span>sdk facts</span><span>sensors</span><span>workplan</span></div>
834
+ </div>
835
+ <div class="capcard layer">
836
+ <h3>3. Evidence layer</h3>
837
+ <p>Separates build success from runtime proof. When runtime proof is requested or claimed, the agent needs screenshots, simulator/browser checks, or an explicit boundary.</p>
838
+ <div class="chipline"><span>check</span><span>smoke</span><span>report</span></div>
839
+ </div>
840
+ <div class="capcard">
841
+ <h3>Vise can help</h3>
842
+ <ul>
843
+ <li>Inspect app surfaces and platform signals before code changes.</li>
844
+ <li>Preserve decision and validation evidence under local `sp-vise/` artifacts.</li>
845
+ <li>Guide natural target discovery instead of raw object IDs.</li>
846
+ </ul>
847
+ </div>
848
+ <div class="capcard">
849
+ <h3>Vise cannot replace</h3>
850
+ <ul>
851
+ <li>The host AI agent that edits customer code.</li>
852
+ <li>A human product decision when multiple social experiences are valid.</li>
853
+ <li>Actual runtime evidence when the app was never launched.</li>
854
+ </ul>
855
+ </div>
856
+ <div class="capcard boundary">
857
+ <h3>Practical expectation</h3>
858
+ <p>Vise raises the floor. It does not make every run perfect. The useful promise is fewer silent guesses, clearer boundaries, and better evidence when a reviewer asks, "How do we know it worked?"</p>
859
+ </div>
860
+ </div>
861
+ </section>
862
+
863
+ <section class="benchmark reveal" id="benchmark">
864
+ <p class="section-kicker">Real E2E benchmark evidence &middot; two coding agents</p>
865
+ <h2>Two popular agents. Same brownfield integration. Vise won on every platform &mdash; and where both baselines actually ran, the lift agrees.</h2>
866
+ <p class="intro">We ran the governed Vise workflow against a Vise-off checklist baseline on the same brownfield social.plus integration &mdash; first with <b>OpenAI&nbsp;Codex&nbsp;GPT-5.4</b>, then with <b>Claude&nbsp;Sonnet&nbsp;5</b> on a hardened protocol. Vise led on all five platform families with both. But the two headline gaps are <b>not</b> equally solid, and neither raw average is the number to stand behind. Read the direction, not the decimals &mdash; <b>n&nbsp;=&nbsp;1 per arm</b>.</p>
867
+
868
+ <div class="bx-shell">
869
+
870
+ <div class="bx-legend" role="note">
871
+ <span class="bx-key"><span class="bx-swatch bx-swatch-vise"></span>Vise&nbsp;(governed)</span>
872
+ <span class="bx-key"><span class="bx-swatch bx-swatch-ctrl"></span>No&nbsp;Vise&nbsp;(checklist baseline)</span>
873
+ <span class="bx-key bx-key-note">Shared 0&ndash;100 composite &middot; both arms always shown &middot; averaged across 5 platforms &middot; deltas computed on unrounded scores</span>
874
+ </div>
875
+
876
+ <!-- ============ ONE-GLANCE RECONCILIATION ============ -->
877
+ <div class="bx-recon" role="note">
878
+ <span class="bx-recon-tag">Three honest numbers on this page &mdash; they measure different things</span>
879
+ <div class="bx-recon-grid">
880
+ <div class="bx-recon-cell">
881
+ <b class="bx-recon-num">+29.1</b>
882
+ <span class="bx-recon-lab">Sonnet&nbsp;5 clean anchor</span>
883
+ <span class="bx-recon-note">Full weighted composite. <b>Includes</b> the +90 definitional capability axis, so it is <em>not</em> the earned real-world number.</span>
884
+ </div>
885
+ <div class="bx-recon-cell bx-recon-cell-key">
886
+ <b class="bx-recon-num bx-recon-num-key">+12.1</b>
887
+ <span class="bx-recon-lab">The number we stand behind</span>
888
+ <span class="bx-recon-note">Sonnet&nbsp;5 <b>credible-only</b>: definitional axis removed, four fair dimensions re-weighted to 100%. The honest apples-to-apples lift.</span>
889
+ </div>
890
+ <div class="bx-recon-cell">
891
+ <b class="bx-recon-num">+23&ndash;31</b>
892
+ <span class="bx-recon-lab">Cross-model convergence</span>
893
+ <span class="bx-recon-note"><b>Raw composites</b> (still capability-inflated) on the two platforms where both baselines launched. Proves the lift&rsquo;s <b>direction</b> holds across agents &mdash; not its magnitude.</span>
894
+ </div>
895
+ </div>
896
+ </div>
897
+
898
+ <!-- ============ CROSS-MODEL BAND ============ -->
899
+ <div class="bx-xm">
900
+ <div class="bx-xm-head">
901
+ <span class="bx-tag bx-tag-neutral">Cross-model band &middot; average composite per agent</span>
902
+ <p class="bx-xm-copy">Same benchmark, two agents. The <b>anchor is Claude&nbsp;Sonnet&nbsp;5</b> &mdash; the hardened protocol where every no-Vise control built and launched, so its gap is earned. Codex&rsquo;s larger gap is shown <em>only</em> with its control-failure caveat attached. Both averages below are full composites; the honest apples-to-apples lift is the <b>+12.1</b> credible-only figure above.</p>
903
+ </div>
904
+
905
+ <div class="bx-xm-cards">
906
+
907
+ <div class="bx-xm-card bx-xm-anchor">
908
+ <div class="bx-xm-card-head">
909
+ <div class="bx-xm-model">
910
+ <span class="bx-xm-name">Claude&nbsp;Sonnet&nbsp;5</span>
911
+ <span class="bx-xm-badge bx-xm-badge-anchor"><span class="bx-xm-badge-dot" aria-hidden="true"></span>Anchor result</span>
912
+ </div>
913
+ <p class="bx-xm-proto">Hardened protocol &middot; all 5 controls built &amp; launched</p>
914
+ </div>
915
+ <div class="bx-xm-nums">
916
+ <div class="bx-xm-stat"><b>82.2</b><span>Vise</span></div>
917
+ <div class="bx-xm-stat"><b class="bx-ctrl-num">53.1</b><span>no&nbsp;Vise</span></div>
918
+ <div class="bx-xm-stat bx-xm-lift"><b>+29.1</b><span>full composite</span></div>
919
+ </div>
920
+ <p class="bx-xm-foot bx-xm-foot-clean"><span class="bx-xm-foot-mark" aria-hidden="true">&#10003;</span>Clean, conservative: all 5 controls launched. This +29.1 still carries the +90 definitional axis &mdash; the earned lift is +12.1 credible-only.</p>
921
+ </div>
922
+
923
+ <div class="bx-xm-card bx-xm-caveated">
924
+ <div class="bx-xm-card-head">
925
+ <div class="bx-xm-model">
926
+ <span class="bx-xm-name">OpenAI&nbsp;Codex&nbsp;GPT-5.4</span>
927
+ <span class="bx-xm-badge bx-xm-badge-earlier">Earlier protocol</span>
928
+ </div>
929
+ <p class="bx-xm-proto">First benchmark &middot; less-hardened harness</p>
930
+ </div>
931
+ <div class="bx-xm-nums">
932
+ <div class="bx-xm-stat"><b>91.8</b><span>Vise</span></div>
933
+ <div class="bx-xm-stat"><b class="bx-ctrl-num">48.0</b><span>no&nbsp;Vise</span></div>
934
+ <div class="bx-xm-stat bx-xm-lift bx-xm-lift-soft"><b><span class="bx-strike">+43.8</span><span class="bx-capmark" aria-hidden="true">&#9650;</span></b><span>inflated gap</span></div>
935
+ </div>
936
+ <div class="bx-xm-chip" role="note">
937
+ <span class="bx-xm-chip-mark" aria-hidden="true">&#9650;</span>
938
+ <span class="bx-xm-chip-text"><b>Earlier protocol inflates this.</b> 2 of 5 no-Vise controls failed before launch &mdash; Flutter deleted <code>lib/main.dart</code> (watchdog-killed &rarr; 33.0) and Android was depressed by an instrument failure (31.2). A third, iOS (43.0), ran low. All three <b>deflated the control and inflated this gap.</b></span>
939
+ </div>
940
+ </div>
941
+
942
+ </div>
943
+
944
+ <!-- CONVERGENCE STRIP -->
945
+ <div class="bx-conv" role="note">
946
+ <div class="bx-conv-head">
947
+ <span class="bx-conv-tag">Where both controls actually launched, the agents agree</span>
948
+ <p class="bx-conv-lead">Isolate the two platforms where the Codex control <b>built and launched</b> &mdash; Web and React&nbsp;Native &mdash; and the two agents&rsquo; deltas <b>agree within ~5 points</b>, both clearly positive. The inflation is confined to the failed-control platforms.</p>
949
+ </div>
950
+ <div class="bx-conv-grid">
951
+ <div class="bx-conv-plat">
952
+ <span class="bx-conv-plat-name">Web</span>
953
+ <div class="bx-conv-pair">
954
+ <div class="bx-conv-cell"><span class="bx-conv-agent">Codex</span><b class="bx-conv-num">+25.8</b></div>
955
+ <span class="bx-conv-vs" aria-hidden="true">&#8776;</span>
956
+ <div class="bx-conv-cell"><span class="bx-conv-agent">Sonnet&nbsp;5</span><b class="bx-conv-num">+31.5</b></div>
957
+ </div>
958
+ <span class="bx-conv-spread">agree within 5.7 pts</span>
959
+ </div>
960
+ <div class="bx-conv-plat">
961
+ <span class="bx-conv-plat-name">React&nbsp;Native</span>
962
+ <div class="bx-conv-pair">
963
+ <div class="bx-conv-cell"><span class="bx-conv-agent">Codex</span><b class="bx-conv-num">+23.0</b></div>
964
+ <span class="bx-conv-vs" aria-hidden="true">&#8776;</span>
965
+ <div class="bx-conv-cell"><span class="bx-conv-agent">Sonnet&nbsp;5</span><b class="bx-conv-num">+27.6</b></div>
966
+ </div>
967
+ <span class="bx-conv-spread">agree within 4.6 pts</span>
968
+ </div>
969
+ </div>
970
+ <p class="bx-conv-note"><b>Read these as raw composites, not the real-world lift.</b> Each Vise delta here still embeds the +90 definitional axis &mdash; the same inflation this section quarantines everywhere else &mdash; so these figures prove the lift points the <b>same direction</b> across two agents, not that the earned magnitude is +23&ndash;31. For the earned magnitude, use the <b>+12.1</b> credible-only number. iOS is left out of this window because the Codex iOS control launched but <em>ran low</em> (43.0) &mdash; the same reason its +43.8 average is caveated.</p>
971
+ </div>
972
+ </div>
973
+
974
+ <!-- ============ SONNET-5 CLEAN-RUN DEEP DIVE ============ -->
975
+ <div class="bx-deep">
976
+ <div class="bx-deep-head">
977
+ <span class="bx-tag bx-tag-neutral">The clean run, read honestly &middot; Claude Sonnet 5</span>
978
+ <p class="bx-plat-copy">The rest of this section is the Sonnet-5 run in full &mdash; the one where every control launched. The two composites below are the <em>same</em> anchor and credible-only numbers from the top, now broken down: the story isn&rsquo;t the definitional axis, it&rsquo;s that the credible, product-facing dimensions move while correctness stays a near-tie.</p>
979
+ </div>
980
+ </div>
981
+
982
+ <div class="bx-headline">
983
+ <div class="bx-head-primary">
984
+ <span class="bx-head-tag">Full weighted composite &middot; all five dimensions</span>
985
+ <div class="bx-head-nums">
986
+ <div class="bx-head-stat"><b>82.2</b><span>Vise</span></div>
987
+ <div class="bx-head-stat"><b class="bx-ctrl-num">53.1</b><span>no&nbsp;Vise</span></div>
988
+ <div class="bx-head-stat bx-head-lift"><b>+29.1</b><span>full composite</span></div>
989
+ </div>
990
+ <p class="bx-head-copy">The same <b>+29.1</b> as the anchor card above &mdash; averaged across the five platforms, shown here for context, not as the headline. It <b>includes</b> the capability-activation axis (25% of the score), where the control is <b>0 by construction</b>, so most of this gap is definitional.</p>
991
+ </div>
992
+ <div class="bx-head-secondary">
993
+ <span class="bx-head-tag bx-head-tag-alt">Credible-only composite &middot; capability axis removed</span>
994
+ <div class="bx-head-nums">
995
+ <div class="bx-head-stat"><b>83.0</b><span>Vise</span></div>
996
+ <div class="bx-head-stat"><b class="bx-ctrl-num">70.8</b><span>no&nbsp;Vise</span></div>
997
+ <div class="bx-head-stat bx-head-lift"><b>+12.1</b><span>earned lift</span></div>
998
+ </div>
999
+ <p class="bx-head-copy"><b>This is the real-world lift &mdash; the same +12.1 flagged at the top.</b> Drop the definitional axis, re-weight the remaining four dimensions to 100%, and the honest head-to-head gap is <b>+12.1</b>. Directional: <b>n&nbsp;=&nbsp;1 per arm</b>. <span class="bx-head-round">Scores are rounded for display; the delta is computed on the unrounded composites (83.0&nbsp;&minus;&nbsp;70.8 reads as ~12.2 by hand, 12.1 exact).</span></p>
1000
+ </div>
1001
+ </div>
1002
+
1003
+ <div class="bx-dims">
1004
+ <p class="bx-dims-lead">That <b>+12.1</b> credible lift breaks down across four fair dimensions. The fifth &mdash; capability activation &mdash; is quarantined at the bottom because it is a definition, not a contest.</p>
1005
+
1006
+ <div class="bx-dim bx-dim-win">
1007
+ <div class="bx-dim-head">
1008
+ <span class="bx-dim-name">Product outcome</span>
1009
+ <span class="bx-dim-kind bx-kind-win">Credible win</span>
1010
+ </div>
1011
+ <p class="bx-dim-sub">Governed arm ships more of the requested surfaces. <span class="bx-dim-weight">25% weight</span></p>
1012
+ <div class="bx-body">
1013
+ <div class="bx-plot">
1014
+ <div class="bx-row"><span class="bx-arm">Vise</span><div class="bx-track"><div class="bx-fill bx-fill-vise" style="width:77.1%"></div></div><b class="bx-val">77.1</b></div>
1015
+ <div class="bx-row"><span class="bx-arm">No&nbsp;Vise</span><div class="bx-track"><div class="bx-fill bx-fill-ctrl" style="width:59.5%"></div></div><b class="bx-val bx-val-ctrl">59.5</b></div>
1016
+ </div>
1017
+ <div class="bx-delta bx-delta-win"><span class="bx-delta-lead">delta</span><span class="bx-delta-num">+17.6</span></div>
1018
+ </div>
1019
+ </div>
1020
+
1021
+ <div class="bx-dim bx-dim-win">
1022
+ <div class="bx-dim-head">
1023
+ <span class="bx-dim-name">Design integration</span>
1024
+ <span class="bx-dim-kind bx-kind-win">Credible win</span>
1025
+ </div>
1026
+ <p class="bx-dim-sub">Surfaces fit the host product better. <span class="bx-dim-weight">20% weight</span></p>
1027
+ <div class="bx-body">
1028
+ <div class="bx-plot">
1029
+ <div class="bx-row"><span class="bx-arm">Vise</span><div class="bx-track"><div class="bx-fill bx-fill-vise" style="width:87.1%"></div></div><b class="bx-val">87.1</b></div>
1030
+ <div class="bx-row"><span class="bx-arm">No&nbsp;Vise</span><div class="bx-track"><div class="bx-fill bx-fill-ctrl" style="width:71.3%"></div></div><b class="bx-val bx-val-ctrl">71.3</b></div>
1031
+ </div>
1032
+ <div class="bx-delta bx-delta-win"><span class="bx-delta-lead">delta</span><span class="bx-delta-num">+15.8</span></div>
1033
+ </div>
1034
+ </div>
1035
+
1036
+ <div class="bx-dim bx-dim-tie">
1037
+ <div class="bx-dim-head">
1038
+ <span class="bx-dim-name">Correctness</span>
1039
+ <span class="bx-dim-kind bx-kind-tie">Near-parity</span>
1040
+ </div>
1041
+ <p class="bx-dim-sub">Build / runtime hygiene, SDK-backed source &mdash; on Android the checklist control built cleaner. <span class="bx-dim-weight">20% weight</span></p>
1042
+ <div class="bx-body">
1043
+ <div class="bx-plot">
1044
+ <div class="bx-row"><span class="bx-arm">Vise</span><div class="bx-track"><div class="bx-fill bx-fill-vise" style="width:96.2%"></div></div><b class="bx-val">96.2</b></div>
1045
+ <div class="bx-row"><span class="bx-arm">No&nbsp;Vise</span><div class="bx-track"><div class="bx-fill bx-fill-ctrl" style="width:94.3%"></div></div><b class="bx-val bx-val-ctrl">94.3</b></div>
1046
+ </div>
1047
+ <div class="bx-delta bx-delta-tie"><span class="bx-delta-lead">delta</span><span class="bx-delta-num">+1.9</span></div>
1048
+ </div>
1049
+ </div>
1050
+
1051
+ <div class="bx-dim bx-dim-tie">
1052
+ <div class="bx-dim-head">
1053
+ <span class="bx-dim-name">Efficiency</span>
1054
+ <span class="bx-dim-kind bx-kind-budget">Budget metric &middot; slower in wall-clock</span>
1055
+ </div>
1056
+ <p class="bx-dim-sub">Scorer token / step budget only. Real elapsed time is <b>worse</b> &mdash; web ran ~2.7&times; the control. <span class="bx-dim-weight">10% weight</span></p>
1057
+ <div class="bx-body">
1058
+ <div class="bx-plot">
1059
+ <div class="bx-row"><span class="bx-arm">Vise</span><div class="bx-track"><div class="bx-fill bx-fill-vise" style="width:63%"></div></div><b class="bx-val">63.0</b></div>
1060
+ <div class="bx-row"><span class="bx-arm">No&nbsp;Vise</span><div class="bx-track"><div class="bx-fill bx-fill-ctrl" style="width:51.3%"></div></div><b class="bx-val bx-val-ctrl">51.3</b></div>
1061
+ </div>
1062
+ <div class="bx-delta bx-delta-tie"><span class="bx-delta-lead">budget &Delta;</span><span class="bx-delta-num">+11.7</span></div>
1063
+ </div>
1064
+ </div>
1065
+
1066
+ <div class="bx-dim bx-dim-struct">
1067
+ <div class="bx-dim-head">
1068
+ <span class="bx-dim-name">Capability activation</span>
1069
+ <span class="bx-dim-kind bx-kind-struct">Structural &middot; Vise-definitional</span>
1070
+ </div>
1071
+ <p class="bx-dim-sub">The control scores <b>0 by construction</b> &mdash; it must not run the governed workflow. Context, not proof of value. <span class="bx-dim-weight">25% weight</span></p>
1072
+ <div class="bx-body">
1073
+ <div class="bx-plot">
1074
+ <div class="bx-row"><span class="bx-arm">Vise</span><div class="bx-track"><div class="bx-fill bx-fill-struct" style="width:90%"></div></div><b class="bx-val bx-val-struct">90</b></div>
1075
+ <div class="bx-row"><span class="bx-arm">No&nbsp;Vise</span><div class="bx-track bx-track-zero"><span class="bx-zero-label">0 &mdash; by construction</span></div><b class="bx-val bx-val-ctrl">0</b></div>
1076
+ </div>
1077
+ <div class="bx-delta bx-delta-struct"><span class="bx-delta-lead">delta</span><span class="bx-delta-num">+90</span><span class="bx-delta-cap">definitional</span></div>
1078
+ </div>
1079
+ </div>
1080
+ </div>
1081
+
1082
+ <div class="bx-tie-note">
1083
+ <b>Read it straight:</b> correctness is essentially a tie &mdash; on Android the checklist control was actually the cleaner build. Vise doesn&rsquo;t make code dramatically more crash-free than a disciplined checklist; it ships more of the right product, better integrated. The <b>+90</b> capability axis is a definition, not a result, and efficiency is a scorer <em>budget</em> figure &mdash; the governed arm is slower in real time. Keep both out of the headline.
1084
+ </div>
1085
+
1086
+ <div class="bx-platforms">
1087
+ <div class="bx-plat-head">
1088
+ <span class="bx-tag">Every platform, head-to-head &middot; Sonnet 5</span>
1089
+ <p class="bx-plat-copy">The same direction held on all five platform families; every control built and launched. Bars share one 0&ndash;100 axis, so each connector length <em>is</em> that platform&rsquo;s full-composite lift (still capability-inclusive). Scores marked <span class="bx-capmark" aria-hidden="true">&#9650;</span> were held <b>below</b> their raw weighted score by runtime-signal coverage (the <b>signals</b> chip), <b>not</b> by any correctness failure.</p>
1090
+ </div>
1091
+
1092
+ <div class="bx-plat-list">
1093
+
1094
+ <div class="bx-plat bx-plat-avg">
1095
+ <div class="bx-plat-top">
1096
+ <span class="bx-plat-name">Average <span class="bx-plat-fix">5 brownfield fixtures &middot; live tenant &middot; no mocking</span></span>
1097
+ <span class="bx-plat-meta"><span class="bx-plat-delta">+29.1</span></span>
1098
+ </div>
1099
+ <div class="bx-axis" role="img" aria-label="Average: Vise 82.2, no Vise 53.1, on a 0 to 100 scale.">
1100
+ <div class="bx-gridlines"><i style="left:0"></i><i style="left:25%"></i><i style="left:50%"></i><i style="left:75%"></i><i style="left:100%"></i></div>
1101
+ <div class="bx-connector" style="left:53.1%;width:29.1%"></div>
1102
+ <span class="bx-dot bx-dot-ctrl" style="left:53.1%"><span class="bx-dot-lab bx-dot-lab-below">53.1</span></span>
1103
+ <span class="bx-dot bx-dot-vise" style="left:82.2%"><span class="bx-dot-lab">82.2</span></span>
1104
+ </div>
1105
+ </div>
1106
+
1107
+ <div class="bx-plat">
1108
+ <div class="bx-plat-top">
1109
+ <span class="bx-plat-name">React&nbsp;Native <span class="bx-plat-fix">Arena Fit &mdash; athlete training app with clubhouse feed</span></span>
1110
+ <span class="bx-plat-meta"><span class="bx-sig bx-sig-full">8/9 signals</span><span class="bx-plat-delta">+27.6</span></span>
1111
+ </div>
1112
+ <div class="bx-axis" role="img" aria-label="React Native: Vise 89.7, no Vise 62.1, on a 0 to 100 scale.">
1113
+ <div class="bx-gridlines"><i style="left:0"></i><i style="left:25%"></i><i style="left:50%"></i><i style="left:75%"></i><i style="left:100%"></i></div>
1114
+ <div class="bx-connector" style="left:62.1%;width:27.6%"></div>
1115
+ <span class="bx-dot bx-dot-ctrl" style="left:62.1%"><span class="bx-dot-lab bx-dot-lab-below">62.1</span></span>
1116
+ <span class="bx-dot bx-dot-vise bx-dot-edge" style="left:89.7%"><span class="bx-dot-lab">89.7</span></span>
1117
+ </div>
1118
+ </div>
1119
+
1120
+ <div class="bx-plat">
1121
+ <div class="bx-plat-top">
1122
+ <span class="bx-plat-name">Web <span class="bx-plat-fix">PULSE &mdash; fitness media app with program communities</span></span>
1123
+ <span class="bx-plat-meta"><span class="bx-sig">6/9 signals</span><span class="bx-plat-delta">+31.5</span></span>
1124
+ </div>
1125
+ <div class="bx-axis" role="img" aria-label="Web: Vise 88.3, no Vise 56.8, on a 0 to 100 scale.">
1126
+ <div class="bx-gridlines"><i style="left:0"></i><i style="left:25%"></i><i style="left:50%"></i><i style="left:75%"></i><i style="left:100%"></i></div>
1127
+ <div class="bx-connector" style="left:56.8%;width:31.5%"></div>
1128
+ <span class="bx-dot bx-dot-ctrl" style="left:56.8%"><span class="bx-dot-lab bx-dot-lab-below">56.8</span></span>
1129
+ <span class="bx-dot bx-dot-vise bx-dot-edge" style="left:88.3%"><span class="bx-dot-lab">88.3</span></span>
1130
+ </div>
1131
+ </div>
1132
+
1133
+ <div class="bx-plat">
1134
+ <div class="bx-plat-top">
1135
+ <span class="bx-plat-name">Flutter <span class="bx-plat-fix">Fieldhouse &mdash; training clubhouse with squad discussions</span></span>
1136
+ <span class="bx-plat-meta"><span class="bx-sig bx-sig-low">4/9 signals</span><span class="bx-plat-delta">+29.5</span></span>
1137
+ </div>
1138
+ <div class="bx-axis" role="img" aria-label="Flutter: Vise 78.0, held below its raw score by 4 of 9 runtime signals; no Vise 48.5, on a 0 to 100 scale.">
1139
+ <div class="bx-gridlines"><i style="left:0"></i><i style="left:25%"></i><i style="left:50%"></i><i style="left:75%"></i><i style="left:100%"></i></div>
1140
+ <div class="bx-connector" style="left:48.5%;width:29.5%"></div>
1141
+ <span class="bx-dot bx-dot-ctrl" style="left:48.5%"><span class="bx-dot-lab bx-dot-lab-below">48.5</span></span>
1142
+ <span class="bx-dot bx-dot-vise bx-dot-capped" style="left:78%"><span class="bx-dot-lab">78.0<span class="bx-capmark" aria-hidden="true">&#9650;</span><span class="bx-sr">held below raw weighted score by 4 of 9 runtime-signal coverage, not a correctness failure</span></span></span>
1143
+ </div>
1144
+ </div>
1145
+
1146
+ <div class="bx-plat">
1147
+ <div class="bx-plat-top">
1148
+ <span class="bx-plat-name">iOS <span class="bx-plat-fix">Luminary Club &mdash; editorial audio / reading-club app</span></span>
1149
+ <span class="bx-plat-meta"><span class="bx-sig bx-sig-low">5/9 signals</span><span class="bx-plat-delta">+29.5</span></span>
1150
+ </div>
1151
+ <div class="bx-axis" role="img" aria-label="iOS: Vise 77.5, held below its raw score by 5 of 9 runtime signals; no Vise 48.0, on a 0 to 100 scale.">
1152
+ <div class="bx-gridlines"><i style="left:0"></i><i style="left:25%"></i><i style="left:50%"></i><i style="left:75%"></i><i style="left:100%"></i></div>
1153
+ <div class="bx-connector" style="left:48%;width:29.5%"></div>
1154
+ <span class="bx-dot bx-dot-ctrl" style="left:48%"><span class="bx-dot-lab bx-dot-lab-below">48.0</span></span>
1155
+ <span class="bx-dot bx-dot-vise bx-dot-capped" style="left:77.5%"><span class="bx-dot-lab">77.5<span class="bx-capmark" aria-hidden="true">&#9650;</span><span class="bx-sr">held below raw weighted score by 5 of 9 runtime-signal coverage, not a correctness failure</span></span></span>
1156
+ </div>
1157
+ </div>
1158
+
1159
+ <div class="bx-plat">
1160
+ <div class="bx-plat-top">
1161
+ <span class="bx-plat-name">Android <span class="bx-plat-fix">MarketPulse &mdash; investor watchlist app with social circles</span></span>
1162
+ <span class="bx-plat-meta"><span class="bx-sig bx-sig-low">5/9 signals</span><span class="bx-plat-delta">+27.4</span></span>
1163
+ </div>
1164
+ <div class="bx-axis" role="img" aria-label="Android: Vise 77.5, held below its raw score by 5 of 9 runtime signals; no Vise 50.1, on a 0 to 100 scale. On this platform the control built cleaner on correctness.">
1165
+ <div class="bx-gridlines"><i style="left:0"></i><i style="left:25%"></i><i style="left:50%"></i><i style="left:75%"></i><i style="left:100%"></i></div>
1166
+ <div class="bx-connector" style="left:50.1%;width:27.4%"></div>
1167
+ <span class="bx-dot bx-dot-ctrl" style="left:50.1%"><span class="bx-dot-lab bx-dot-lab-below">50.1</span></span>
1168
+ <span class="bx-dot bx-dot-vise bx-dot-capped" style="left:77.5%"><span class="bx-dot-lab">77.5<span class="bx-capmark" aria-hidden="true">&#9650;</span><span class="bx-sr">held below raw weighted score by 5 of 9 runtime-signal coverage, not a correctness failure</span></span></span>
1169
+ </div>
1170
+ </div>
1171
+
1172
+ </div>
1173
+
1174
+ <div class="bx-axis-scale" aria-hidden="true">
1175
+ <span style="left:0">0</span><span style="left:25%">25</span><span style="left:50%">50</span><span style="left:75%">75</span><span style="left:100%">100</span>
1176
+ </div>
1177
+ </div>
1178
+
1179
+ <div class="bx-notes">
1180
+ <div class="bx-note bx-note-cost">
1181
+ <span class="bx-note-tag">Tradeoff</span>
1182
+ <p><b>Governance is more thorough but slower.</b> The Vise arm delivers more surfaces at a higher wall-clock cost &mdash; on web it ran roughly <b>2.7&times;</b> the control&rsquo;s elapsed time. The efficiency dimension above is a scorer <em>budget</em> metric, not real time.</p>
1183
+ </div>
1184
+ <div class="bx-note bx-note-super">
1185
+ <span class="bx-note-tag">Why Sonnet 5 is the anchor, not Codex</span>
1186
+ <p>The earlier Codex GPT-5.4 average (91.8 / 48.0 / <span class="bx-strike">+43.8</span>) is inflated: two no-Vise controls were watchdog-killed <em>before launch</em> and iOS ran low, deflating the control. The Sonnet-5 controls all built and launched (React&nbsp;Native no-Vise reached 62.1), so <b>+29.1</b> &mdash; and the earned <b>+12.1</b> credible-only lift &mdash; are the honest numbers to headline.</p>
1187
+ </div>
1188
+ </div>
1189
+
1190
+ <p class="bx-footnote">Both agents run each arm on the same brownfield fixture with a live tenant and no mocking; <b>Vise is the deterministic CLI under test, not an AI model.</b> Scoring weights: capability activation 25% (definitional), product outcome 25%, design integration 20%, correctness 20%, efficiency 10%. The credible-only composite drops the capability axis and re-weights the remaining four to 100%. All deltas are computed on unrounded composites, so a hand-subtraction of the rounded scores can differ by 0.1. Codex GPT-5.4 (Medium) ran late&nbsp;June&nbsp;2026 on the first, less-hardened harness; Claude&nbsp;Sonnet&nbsp;5 ran early&nbsp;July&nbsp;2026 on the current hardened protocol &mdash; the protocol was hardened between the two runs, which is why their controls are not directly comparable and the convergence view is limited to the two platforms where both launched. July&nbsp;2026 directional product-evidence runs on representative fixtures, <b>n&nbsp;=&nbsp;1 per arm</b> &mdash; not a third-party audit. For a formal comparison, keep each Vise / no-Vise pair on the same model and reasoning setting.</p>
1191
+
1192
+ </div>
1193
+ </section>
1194
+
1195
+ <!-- ============ CATEGORY A — was EI ============ -->
1196
+ <div class="catgroup">
1197
+ <div class="cathead reveal" id="cat-a">
1198
+ <p class="catletter">A</p>
1199
+ <div><h2>Did it build the right thing?</h2><p>The first decision Vise helps govern, before any code exists. Get this one wrong and nothing below is worth checking.</p></div>
1200
+ </div>
1201
+
1202
+ <section class="problem reveal">
1203
+ <p class="ftag">Example 1 of 15</p>
1204
+ <h3>"Add social features" became something. Nobody chose what.</h3>
1205
+ <p class="pdesc">A broad request has more than one valid shape — a feed-first community, a live-class chat hub, an events-and-challenges hangout. Left alone, an agent silently picks one interpretation and starts building. The first time anyone finds out it guessed wrong is after the surfaces already exist.</p>
1206
+ <div class="diffrow">
1207
+ <div class="pane bad">
1208
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1209
+ <div class="phone"><div class="ptop">New request</div><div class="pbody">
1210
+ <div class="bubble user">Add social features to my running app</div>
1211
+ <div class="bubble bot">Sure — adding a community feed.</div>
1212
+ <span class="tagpill bad">1 unnamed assumption</span>
1213
+ </div></div>
1214
+ </div>
1215
+ <div class="pane good">
1216
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1217
+ <div class="phone"><div class="ptop">New request</div><div class="pbody">
1218
+ <div class="bubble user">Add social features to my running app</div>
1219
+ <div class="optrow picked"><b>Community First</b><span class="d">feed + groups</span></div>
1220
+ <div class="optrow"><b>Live Class Hub</b><span class="d">chat-first, schedule-driven</span></div>
1221
+ <div class="optrow"><b>Challenges &amp; Events</b><span class="d">leaderboards, RSVPs</span></div>
1222
+ <p class="muted" style="font-size:10.5px;margin-top:6px;">rationale: fits existing "Clubs" nav; no live-class infra yet</p>
1223
+ <span class="tagpill good">experience selected, rationale recorded</span>
1224
+ </div></div>
1225
+ </div>
1226
+ </div>
1227
+ <p class="mech">→ Vise mechanism: <span>the Engagement Intelligence step</span> (<code>vise creative</code>) — a broad request surfaces named, concrete experience candidates instead of one silent guess, and the blueprint gate records a grounded rationale before a choice locks in and drives what gets built.</p>
1228
+ </section>
1229
+ </div>
1230
+
1231
+ <!-- ============ CATEGORY B — was A ============ -->
1232
+ <div class="catgroup">
1233
+ <div class="cathead reveal" id="cat-b">
1234
+ <p class="catletter">B</p>
1235
+ <div><h2>Does it run?</h2><p>The build succeeded. That was never the hard part — the hard part is surviving contact with a real device.</p></div>
1236
+ </div>
1237
+
1238
+ <section class="problem reveal">
1239
+ <p class="ftag">Example 2 of 15</p>
1240
+ <h3>It compiled. Then it crashed on the phone.</h3>
1241
+ <p class="pdesc">A build can succeed and a screen can still crash the instant a real user opens it — because the code asked the SDK for data before the SDK had finished starting up. No compiler catches that.</p>
1242
+ <div class="diffrow">
1243
+ <div class="pane bad">
1244
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1245
+ <div class="phone"><div class="ptop">Fieldhouse Club</div><div class="pbody">
1246
+ <p class="redtxt">State: error</p>
1247
+ <p class="muted" style="margin-top:6px;">"Bad state: MessageDbAdapter is not ready yet"</p>
1248
+ <p class="muted" style="margin-top:10px;">Visible communities: 0</p>
1249
+ </div></div>
1250
+ </div>
1251
+ <div class="pane good">
1252
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1253
+ <div class="phone"><div class="ptop">Fieldhouse Club</div><div class="pbody">
1254
+ <p class="greentxt">State: loaded</p>
1255
+ <div class="row" style="margin-top:8px;"><span>Trailhead Club</span></div>
1256
+ <div class="row"><span>Downtown Riders</span></div>
1257
+ <p class="muted" style="margin-top:6px;">10 communities</p>
1258
+ </div></div>
1259
+ </div>
1260
+ </div>
1261
+ <p class="mech">→ Vise mechanism: <span>runtime readiness review + smoke evidence</span> — Vise asks for browser, simulator, emulator, or device proof when runtime proof is requested or declared; if that proof is declined, the agent must say runtime behavior is unproven. The skill also documents the SDK init order that avoids this race.</p>
1262
+ </section>
1263
+
1264
+ <section class="problem reveal">
1265
+ <p class="ftag">Example 3 of 15</p>
1266
+ <h3>It pinned to "latest." Latest changed overnight.</h3>
1267
+ <p class="pdesc">A dependency left unpinned can resolve to a newer SDK build between one install and the next — quietly changing behavior nobody asked to change, on a schedule nobody controls.</p>
1268
+ <div class="diffrow">
1269
+ <div class="pane bad">
1270
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1271
+ <div class="phone"><div class="ptop">pubspec.yaml</div><div class="pbody">
1272
+ <div class="idblob">amity_sdk: any</div>
1273
+ <p class="redtxt" style="margin-top:10px;">resolved 6.42.0 → 6.44.0 overnight</p>
1274
+ <span class="tagpill bad">unpinned</span>
1275
+ </div></div>
1276
+ </div>
1277
+ <div class="pane good">
1278
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1279
+ <div class="phone"><div class="ptop">pubspec.yaml</div><div class="pbody">
1280
+ <div class="idblob" style="color:#3f6b45;border-color:#bcd0bd;background:#eef3ec;">amity_sdk: 6.42.0</div>
1281
+ <p class="greentxt" style="margin-top:10px;">version pinned</p>
1282
+ <span class="tagpill good">stable build</span>
1283
+ </div></div>
1284
+ </div>
1285
+ </div>
1286
+ <p class="mech">→ Vise mechanism: <span>dependency-manifest validation</span> — the SDK dependency is checked for a pinned version, not a floating wildcard or "latest" tag.</p>
1287
+ </section>
1288
+
1289
+ <section class="problem reveal">
1290
+ <p class="ftag">Example 4 of 15</p>
1291
+ <h3>The manifest was missing one line. Nothing else said why.</h3>
1292
+ <p class="pdesc">A missing Android network permission can leave a screen silently unable to reach the network — with no error pointing at the real cause.</p>
1293
+ <div class="diffrow">
1294
+ <div class="pane bad">
1295
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1296
+ <div class="phone"><div class="ptop">AndroidManifest.xml</div><div class="pbody">
1297
+ <div class="permline"><span class="dot on"></span>ACCESS_NETWORK_STATE</div>
1298
+ <div class="permline"><span class="dot off"></span>INTERNET</div>
1299
+ <p class="redtxt" style="margin-top:10px;">network calls silently fail</p>
1300
+ </div></div>
1301
+ </div>
1302
+ <div class="pane good">
1303
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1304
+ <div class="phone"><div class="ptop">AndroidManifest.xml</div><div class="pbody">
1305
+ <div class="permline"><span class="dot on"></span>ACCESS_NETWORK_STATE</div>
1306
+ <div class="permline"><span class="dot on"></span>INTERNET</div>
1307
+ <p class="greentxt" style="margin-top:10px;">setup validated</p>
1308
+ </div></div>
1309
+ </div>
1310
+ </div>
1311
+ <p class="mech">→ Vise mechanism: <span>platform setup validation</span> — manifest, permission, and SDK-manager setup calls are checked per platform before a build counts as wired up.</p>
1312
+ </section>
1313
+ </div>
1314
+
1315
+ <!-- ============ CATEGORY C — was B ============ -->
1316
+ <div class="catgroup">
1317
+ <div class="cathead reveal" id="cat-c">
1318
+ <p class="catletter">C</p>
1319
+ <div><h2>Is it really wired?</h2><p>The app can look connected without being connected. This is the gap between a convincing demo and a real integration.</p></div>
1320
+ </div>
1321
+
1322
+ <section class="problem reveal">
1323
+ <p class="ftag">Example 5 of 15</p>
1324
+ <h3>It looked connected. It was actually hardcoded.</h3>
1325
+ <p class="pdesc">A demo can "work" by pasting one real community's ID straight into the source. It looks alive in the room where it was built — point it at a different tenant and it shows nothing.</p>
1326
+ <div class="diffrow">
1327
+ <div class="pane bad">
1328
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1329
+ <div class="phone"><div class="ptop">ClubApp</div><div class="pbody">
1330
+ <div class="idblob">communityId =<br>"6788a1c9f2e0d..."</div>
1331
+ <p class="redtxt" style="margin-top:10px;">⨯ not found in this environment</p>
1332
+ <span class="tagpill bad">hardcoded literal</span>
1333
+ </div></div>
1334
+ </div>
1335
+ <div class="pane good">
1336
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1337
+ <div class="phone"><div class="ptop">ArenaFit</div><div class="pbody">
1338
+ <div class="namecard">Tempo Morning Run Club</div>
1339
+ <p class="muted" style="font-size:11px;">discovered via SDK query</p>
1340
+ <span class="tagpill good">✓ live from SDK</span>
1341
+ </div></div>
1342
+ </div>
1343
+ </div>
1344
+ <p class="mech">→ Vise mechanism: <span>the source scanner + natural-target discovery rule</span> — hardcoded <code>communityId</code>/<code>postId</code>/<code>channelId</code> literals are flagged; targets must come from a live SDK query, a create flow, or user selection.</p>
1345
+ </section>
1346
+
1347
+ <section class="problem reveal">
1348
+ <p class="ftag">Example 6 of 15</p>
1349
+ <h3>It was in package.json. It was never in the app.</h3>
1350
+ <p class="pdesc">A dependency can sit in the project without a single runtime call ever using it — the SDK is present on disk, absent from the product.</p>
1351
+ <div class="diffrow">
1352
+ <div class="pane bad">
1353
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1354
+ <div class="phone"><div class="ptop">package.json ✓ installed</div><div class="pbody">
1355
+ <div class="idblob">"@amityco/ts-sdk": "^6.1.0"</div>
1356
+ <p class="redtxt" style="margin-top:10px;">0 SDK calls found in source</p>
1357
+ <span class="tagpill bad">installed, unused</span>
1358
+ </div></div>
1359
+ </div>
1360
+ <div class="pane good">
1361
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1362
+ <div class="phone"><div class="ptop">package.json ✓ installed</div><div class="pbody">
1363
+ <div class="idblob">client.community.getCommunities()</div>
1364
+ <p class="greentxt" style="margin-top:10px;">6 SDK calls found in source</p>
1365
+ <span class="tagpill good">actively wired</span>
1366
+ </div></div>
1367
+ </div>
1368
+ </div>
1369
+ <p class="mech">→ Vise mechanism: <span>SDK-usage detection</span> — a dependency being installed isn't treated as evidence the integration exists; Vise checks for actual runtime calls.</p>
1370
+ </section>
1371
+
1372
+ <section class="problem reveal">
1373
+ <p class="ftag">Example 7 of 15</p>
1374
+ <h3>It read the field. Just not the shape the SDK returns.</h3>
1375
+ <p class="pdesc">A reaction count or a follow status doesn't always come back as a plain number or boolean — sometimes it's a structured object. Code that assumes the simple shape shows the wrong thing instead of failing loudly.</p>
1376
+ <div class="diffrow">
1377
+ <div class="pane bad">
1378
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1379
+ <div class="phone"><div class="ptop">Post</div><div class="pbody">
1380
+ <div class="postline" style="width:88%"></div>
1381
+ <div class="postline" style="width:60%"></div>
1382
+ <p class="redtxt" style="margin-top:10px;">Reactions: [object Object]</p>
1383
+ <span class="btn disabled">Follow</span>
1384
+ </div></div>
1385
+ </div>
1386
+ <div class="pane good">
1387
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1388
+ <div class="phone"><div class="ptop">Post</div><div class="pbody">
1389
+ <div class="postline" style="width:88%"></div>
1390
+ <div class="postline" style="width:60%"></div>
1391
+ <p class="greentxt" style="margin-top:10px;">♥ 24 reactions</p>
1392
+ <span class="btn brand-generic">Following ✓</span>
1393
+ </div></div>
1394
+ </div>
1395
+ </div>
1396
+ <p class="mech">→ Vise mechanism: <span>shape-correctness sensors</span> — reaction-count and follow-status fields are checked against the structure the SDK actually returns, not the shape a template guessed.</p>
1397
+ </section>
1398
+ </div>
1399
+
1400
+ <!-- ============ CATEGORY D — was C ============ -->
1401
+ <div class="catgroup">
1402
+ <div class="cathead reveal" id="cat-d">
1403
+ <p class="catletter">D</p>
1404
+ <div><h2>Is it actually complete?</h2><p>Individually working pieces can still add up to an unfinished feature — the gap between "a surface" and "the surface that was asked for."</p></div>
1405
+ </div>
1406
+
1407
+ <section class="problem reveal">
1408
+ <p class="ftag">Example 8 of 15</p>
1409
+ <h3>It stopped after the first screen.</h3>
1410
+ <p class="pdesc">Left alone, an agent will often build the one surface you asked about first, declare the job done, and quietly leave the rest of the request unbuilt.</p>
1411
+ <div class="diffrow">
1412
+ <div class="pane bad">
1413
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1414
+ <div class="phone"><div class="ptop">Build plan</div><div class="pbody">
1415
+ <div class="row"><span>Feed</span><span class="greentxt">✓ done</span></div>
1416
+ <div class="row"><span class="muted">Community</span><span class="muted">pending</span></div>
1417
+ <div class="row"><span class="muted">Chat</span><span class="muted">pending</span></div>
1418
+ <div class="row"><span class="muted">Profile</span><span class="muted">pending</span></div>
1419
+ <p class="redtxt" style="margin-top:12px;">agent: "All done!"</p>
1420
+ </div></div>
1421
+ </div>
1422
+ <div class="pane good">
1423
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1424
+ <div class="phone"><div class="ptop">Build plan</div><div class="pbody">
1425
+ <div class="row"><span>Feed</span><span class="greentxt">✓ done</span></div>
1426
+ <div class="row"><span>Community</span><span class="greentxt">✓ done</span></div>
1427
+ <div class="row"><span>Chat</span><span class="greentxt">✓ done</span></div>
1428
+ <div class="row"><span>Profile</span><span class="greentxt">✓ done</span></div>
1429
+ <p class="greentxt" style="margin-top:12px;">workplan status: complete</p>
1430
+ </div></div>
1431
+ </div>
1432
+ </div>
1433
+ <p class="mech">→ Vise mechanism: <span><code>vise workplan status</code> + completeness gates</span> — completion is tracked per requested surface, and <code>vise check</code> can hold the build at a completeness gap until required baseline items are built or explicitly scoped out.</p>
1434
+ </section>
1435
+
1436
+ <section class="problem reveal">
1437
+ <p class="ftag">Example 9 of 15</p>
1438
+ <h3>It said "loaded." The screen was empty.</h3>
1439
+ <p class="pdesc">A feed can technically finish loading and still show nothing — zero posts, a spinner that never resolves, a button that's disabled by default — and still get shipped as the finished feature.</p>
1440
+ <div class="diffrow">
1441
+ <div class="pane bad">
1442
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1443
+ <div class="phone"><div class="ptop">Community feed</div><div class="pbody">
1444
+ <p><span class="spin"></span>Loading…</p>
1445
+ <p class="muted" style="margin-top:10px;">0 posts</p>
1446
+ <span class="btn disabled">New post</span>
1447
+ </div></div>
1448
+ </div>
1449
+ <div class="pane good">
1450
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1451
+ <div class="phone"><div class="ptop">Community feed</div><div class="pbody">
1452
+ <div><span class="avatar" style="background:#C1613F;">JA</span><b style="font-size:12px;">Jordan Ames</b></div>
1453
+ <div class="postline" style="width:92%"></div>
1454
+ <div class="postline" style="width:70%"></div>
1455
+ <p class="muted" style="font-size:11px;margin-top:8px;">💬 3 comments · ♥ 12</p>
1456
+ <span class="btn brand-generic" style="margin-top:10px;">New post</span>
1457
+ </div></div>
1458
+ </div>
1459
+ </div>
1460
+ <p class="mech">→ Vise mechanism: <span>populated runtime evidence + completeness baseline</span> — feed proof should show real content, not just a resolved loading state; declared smoke surfaces can require populated evidence, and the feed baseline checks for practical interaction affordances.</p>
1461
+ </section>
1462
+
1463
+ <section class="problem reveal">
1464
+ <p class="ftag">Example 10 of 15</p>
1465
+ <h3>It rendered the post. It skipped the conversation.</h3>
1466
+ <p class="pdesc">A feed that shows posts but never surfaces even a hint of their comments quietly drops one of the clearest signals that a community is actually alive.</p>
1467
+ <div class="diffrow">
1468
+ <div class="pane bad">
1469
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1470
+ <div class="phone"><div class="ptop">Post</div><div class="pbody">
1471
+ <div class="postline" style="width:90%"></div>
1472
+ <div class="postline" style="width:55%"></div>
1473
+ <p class="muted" style="margin-top:12px;font-size:11px;">no replies shown</p>
1474
+ </div></div>
1475
+ </div>
1476
+ <div class="pane good">
1477
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1478
+ <div class="phone"><div class="ptop">Post</div><div class="pbody">
1479
+ <div class="postline" style="width:90%"></div>
1480
+ <div class="postline" style="width:55%"></div>
1481
+ <p class="muted" style="margin-top:10px;font-size:11.5px;">↳ Priya: can't wait for this 🎉</p>
1482
+ <p class="greentxt" style="font-size:11px;">2 more replies</p>
1483
+ </div></div>
1484
+ </div>
1485
+ </div>
1486
+ <p class="mech">→ Vise mechanism: <span>the comment-preview baseline gate</span> — any surface that renders posts is required to show a comment preview, not just the post itself.</p>
1487
+ </section>
1488
+
1489
+ <section class="problem reveal">
1490
+ <p class="ftag">Example 11 of 15</p>
1491
+ <h3>The post loaded. The words didn't.</h3>
1492
+ <p class="pdesc">It's possible to render a post card — avatar, name, timestamp, reaction bar — and never actually put the post's own text on screen.</p>
1493
+ <div class="diffrow">
1494
+ <div class="pane bad">
1495
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1496
+ <div class="phone"><div class="ptop">Post</div><div class="pbody">
1497
+ <div><span class="avatar" style="background:#4A5A6B;">SO</span><b style="font-size:12px;">Sam Okafor</b></div>
1498
+ <div style="height:38px;border:1px dashed var(--bad-line);border-radius:6px;margin:8px 0;"></div>
1499
+ <p class="muted" style="font-size:11px;">♥ 4 · 💬 0</p>
1500
+ </div></div>
1501
+ </div>
1502
+ <div class="pane good">
1503
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1504
+ <div class="phone"><div class="ptop">Post</div><div class="pbody">
1505
+ <div><span class="avatar" style="background:#4A5A6B;">SO</span><b style="font-size:12px;">Sam Okafor</b></div>
1506
+ <p style="margin:8px 0 4px;font-size:12px;">"Back-to-back PRs this week, group run Saturday 7am 🏃"</p>
1507
+ <p class="muted" style="font-size:11px;">♥ 4 · 💬 2</p>
1508
+ </div></div>
1509
+ </div>
1510
+ </div>
1511
+ <p class="mech">→ Vise mechanism: <span>the post-body rendering requirement</span> — a post surface isn't complete until the post's own text content is confirmed on screen, not just its metadata chrome.</p>
1512
+ </section>
1513
+ </div>
1514
+
1515
+ <!-- ============ CATEGORY E — was D ============ -->
1516
+ <div class="catgroup">
1517
+ <div class="cathead reveal" id="cat-e">
1518
+ <p class="catletter">E</p>
1519
+ <div><h2>Does it look, feel, and stay safe?</h2><p>The last mile — where a correct, complete integration either earns trust or quietly loses it.</p></div>
1520
+ </div>
1521
+
1522
+ <section class="problem reveal">
1523
+ <p class="ftag">Example 12 of 15</p>
1524
+ <h3>It worked. It just looked like someone else's app.</h3>
1525
+ <p class="pdesc">A technically correct integration can still feel bolted on — default buttons and system fonts dropped into a product that otherwise has a strong visual identity of its own.</p>
1526
+ <div class="diffrow">
1527
+ <div class="pane bad">
1528
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1529
+ <div class="phone">
1530
+ <div class="ptop" style="font-family:Arial,sans-serif;">Community</div>
1531
+ <div class="pbody" style="font-family:Arial,sans-serif;">
1532
+ <div class="namecard" style="font-family:Arial,sans-serif;">Trailhead Club</div>
1533
+ <p class="muted" style="font-size:11.5px;">1,204 members</p>
1534
+ <span class="btn brand-generic">Join</span>
1535
+ </div>
1536
+ </div>
1537
+ </div>
1538
+ <div class="pane good">
1539
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1540
+ <div class="phone">
1541
+ <div class="ptop" style="background:#f3ece4;color:#5c2c1e;">Community</div>
1542
+ <div class="pbody">
1543
+ <div class="namecard">Trailhead Club</div>
1544
+ <p class="muted" style="font-size:11.5px;">1,204 members</p>
1545
+ <span class="btn brand-native">JOIN CLUB</span>
1546
+ </div>
1547
+ </div>
1548
+ </div>
1549
+ </div>
1550
+ <p class="mech">→ Vise mechanism: <span>the advisory design review loop</span> — the host app's palette, type, spacing, and contrast signals can be extracted into a design contract and previewed against the new surface. It guides the build, but it is not a hard build gate.</p>
1551
+ </section>
1552
+
1553
+ <section class="problem reveal">
1554
+ <p class="ftag">Example 13 of 15</p>
1555
+ <h3>For half a second, it looked broken.</h3>
1556
+ <p class="pdesc">A screen that flashes fully blank between "nothing yet" and "here's your feed" reads as broken even when it resolves a moment later — especially the first time a new user ever sees it.</p>
1557
+ <div class="diffrow">
1558
+ <div class="pane bad">
1559
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1560
+ <div class="phone"><div class="ptop">Feed</div><div class="pbody">
1561
+ <p class="muted" style="padding-top:40px;text-align:center;">— nothing rendered —</p>
1562
+ </div></div>
1563
+ </div>
1564
+ <div class="pane good">
1565
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1566
+ <div class="phone"><div class="ptop">Feed</div><div class="pbody">
1567
+ <div class="skel" style="width:100%"></div>
1568
+ <div class="skel" style="width:70%"></div>
1569
+ </div></div>
1570
+ </div>
1571
+ </div>
1572
+ <p class="mech">→ Vise mechanism: <span>the loading-state advisory</span> — a surface needs a visible loading state, not a blank frame, between navigation and data arriving.</p>
1573
+ </section>
1574
+
1575
+ <section class="problem reveal">
1576
+ <p class="ftag">Example 14 of 15</p>
1577
+ <h3>The API key was one Git push away from public.</h3>
1578
+ <p class="pdesc">A key hardcoded as a source fallback — "use the env var, or if that's missing, use this literal" — survives long after whoever wrote it forgets it's there.</p>
1579
+ <div class="diffrow">
1580
+ <div class="pane bad">
1581
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1582
+ <div class="phone"><div class="ptop">client.ts</div><div class="pbody">
1583
+ <div class="idblob">apiKey: process.env.KEY<br>|| "sk_live_82fa91..."</div>
1584
+ <span class="tagpill bad">secret in source</span>
1585
+ </div></div>
1586
+ </div>
1587
+ <div class="pane good">
1588
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1589
+ <div class="phone"><div class="ptop">client.ts</div><div class="pbody">
1590
+ <div class="idblob" style="color:#3f6b45;border-color:#bcd0bd;background:#eef3ec;">apiKey: process.env.KEY</div>
1591
+ <span class="tagpill good">no literal fallback</span>
1592
+ </div></div>
1593
+ </div>
1594
+ </div>
1595
+ <p class="mech">→ Vise mechanism: <span>the secret scanner</span> — literal API keys used as a fallback value are flagged even when an env var is also present.</p>
1596
+ </section>
1597
+
1598
+ <section class="problem reveal">
1599
+ <p class="ftag">Example 15 of 15</p>
1600
+ <h3>One checkbox nobody meant to ship.</h3>
1601
+ <p class="pdesc">A create/update payload can quietly include an admin-only field like "official" status — setting it to <code>false</code> still counts as configuring it, and it isn't a decision a normal user flow should make.</p>
1602
+ <div class="diffrow">
1603
+ <div class="pane bad">
1604
+ <p class="panelabel"><span class="marker">−</span> WITHOUT VISE</p>
1605
+ <div class="phone"><div class="ptop">Create community</div><div class="pbody">
1606
+ <div class="field"><span>displayName</span><span>"Trailhead Club"</span></div>
1607
+ <div class="field" style="color:var(--bad);"><span>isOfficial</span><span>false</span></div>
1608
+ <span class="tagpill bad">privileged field set</span>
1609
+ </div></div>
1610
+ </div>
1611
+ <div class="pane good">
1612
+ <p class="panelabel"><span class="marker">+</span> WITH VISE</p>
1613
+ <div class="phone"><div class="ptop">Create community</div><div class="pbody">
1614
+ <div class="field"><span>displayName</span><span>"Trailhead Club"</span></div>
1615
+ <p class="muted" style="font-size:11px;margin-top:4px;">no admin-only fields set</p>
1616
+ <span class="tagpill good">privileged fields excluded</span>
1617
+ </div></div>
1618
+ </div>
1619
+ </div>
1620
+ <p class="mech">→ Vise mechanism: <span>the privileged-field check</span> — admin-only fields such as <code>isOfficial</code> are flagged in create/update payloads regardless of the value assigned.</p>
1621
+ </section>
1622
+ </div>
1623
+
1624
+ <section class="demo-section reveal" id="fit-demo">
1625
+ <p class="ftag">15 examples from the larger ruleset, in one product-shaped app</p>
1626
+ <h2>A curated slice of the checks, inside a realistic fitness app.</h2>
1627
+ <p class="pdesc">The examples above, made concrete in one illustrated product — Recoup, a recovery-tracking app. Vise has 400+ platform-specific checks; this section turns 15 representative gaps into an easy-to-scan product story. Flip to <b>Without Vise</b> and tap through: each numbered pin marks where one example bites, in context. Flip to <b>With Vise</b> and every pin turns green as the surface is planned, checked, or verified through the Vise workflow. Same product concept — different integration discipline.</p>
1628
+ <p class="fit-legend">Each pin maps to one example check above · <span style="color:var(--bad);">red = present</span> · <span style="color:var(--good);">green = caught</span></p>
1629
+
1630
+ <div class="demo-shell">
1631
+ <div class="demo-toggle" role="tablist" aria-label="Integration state">
1632
+ <button class="fitbtn active" role="tab" aria-selected="true" data-fmode="without">Without Vise</button>
1633
+ <button class="fitbtn" role="tab" aria-selected="false" data-fmode="vise">With Vise</button>
1634
+ </div>
1635
+
1636
+ <div class="demo-phone">
1637
+ <div class="screenclip dark" id="fitScreen">
1638
+ <div class="statusbar">
1639
+ <span>9:41</span>
1640
+ <span class="icons">
1641
+ <span class="sig"><i></i><i></i><i></i><i></i></span>
1642
+ <span class="wifi"></span>
1643
+ <span class="batt"><i></i></span>
1644
+ </span>
1645
+ </div>
1646
+ <div class="appbar"><span class="wordmark">Recoup</span><span class="style-ref">performance recovery style</span></div>
1647
+ <div class="demo-content" id="fitContent"></div>
1648
+ <div class="tabbar2" id="fitTabbar"></div>
1649
+ </div>
1650
+ </div>
1651
+
1652
+ <div class="fit-counter bad" id="fitCounter">15 representative gaps flagged across the app</div>
1653
+
1654
+ <div class="uth" id="fitUth"></div>
1655
+ </div>
1656
+ </section>
1657
+
1658
+ <section class="demo-section reveal" id="live-demo">
1659
+ <p class="ftag">The full picture</p>
1660
+ <h2>What a realistic Vise integration output should look like.</h2>
1661
+ <p class="pdesc">The finished app should still feel like the customer's product. Vise should add social.plus where it naturally belongs: product-derived communities, SDK-backed feeds, post creation, reactions, comment previews, chat, profile/follow graph, and lightweight notifications — without raw object IDs or a detached "social demo" tab. The mock phones below intentionally use different product themes so the social layer feels adapted, not pasted.</p>
1662
+
1663
+ <div class="showcase-gallery" id="realOutputGallery">
1664
+ <div class="gallery-tabs" role="tablist" aria-label="Realistic integration examples">
1665
+ <button class="gallery-tab active" type="button" role="tab" aria-selected="true" data-output="arena">Training</button>
1666
+ <button class="gallery-tab" type="button" role="tab" aria-selected="false" data-output="market">Markets</button>
1667
+ <button class="gallery-tab" type="button" role="tab" aria-selected="false" data-output="audio">Audio</button>
1668
+ </div>
1669
+ <div class="gallery-stage">
1670
+ <div class="gallery-copy" id="galleryCopy"></div>
1671
+ <div class="showcase-device">
1672
+ <div class="device-frame" aria-live="polite">
1673
+ <div class="device-screen" id="galleryPhone"></div>
1674
+ </div>
1675
+ <div class="gallery-evidence" id="galleryEvidence"></div>
1676
+ </div>
1677
+ </div>
1678
+ </div>
1679
+
1680
+ </section>
1681
+
1682
+ <div class="closer reveal">
1683
+ <h2>Grounded in real benchmark work.</h2>
1684
+ <p>The examples above are grounded in recent Vise dogfood and real end-to-end benchmark work across web, Android, iOS, Flutter, and React Native. They are a readable slice of a larger 400+ check system; the public README carries the current scorecard and calculation method.</p>
1685
+ </div>
1686
+
1687
+ <div class="colophon">
1688
+ Grounded in: current Vise README evidence model · architecture workflow · runtime-smoke guidance · Engagement Intelligence · compliance, completeness, and advisory design validation layers.<br>
1689
+ Capability explainer for marketing enablement. Prepared 2026-07-02.
1690
+ </div>
1691
+
1692
+ </div>
1693
+ </div>
1694
+
1695
+ <script>
1696
+ (function(){
1697
+ var els = document.querySelectorAll('.reveal');
1698
+ if(!('IntersectionObserver' in window)){ els.forEach(function(e){e.classList.add('in');}); return; }
1699
+ var io = new IntersectionObserver(function(entries){
1700
+ entries.forEach(function(en){ if(en.isIntersecting){ en.target.classList.add('in'); io.unobserve(en.target); } });
1701
+ }, {threshold:0.1});
1702
+ els.forEach(function(e){ io.observe(e); });
1703
+ })();
1704
+ </script>
1705
+
1706
+ <script>
1707
+ (function(){
1708
+ var root = document.getElementById('realOutputGallery');
1709
+ if(!root) return;
1710
+ var copyEl = document.getElementById('galleryCopy');
1711
+ var phoneEl = document.getElementById('galleryPhone');
1712
+ var evidenceEl = document.getElementById('galleryEvidence');
1713
+ var buttons = root.querySelectorAll('.gallery-tab');
1714
+ var active = 'arena';
1715
+
1716
+ var examples = {
1717
+ arena: {
1718
+ eyebrow: 'React Native · fitness training',
1719
+ title: 'A training app keeps its coaching workflow, then gains a crew layer.',
1720
+ body: 'The social target comes from the selected program, coach, and readiness state. The finished screen still feels like a training product first, with social.plus woven into the moment where the user already expects peer context.',
1721
+ brief: [
1722
+ ['Prompt', 'Add social features', 'Broad ask against an existing training dashboard.'],
1723
+ ['Vise offered', 'Community-first, live coaching hub, challenge crew', 'Each option mapped to current navigation and data.'],
1724
+ ['Chosen', 'Community-first crews', 'Program-derived communities plus feed, composer, chat, and profile/follow.']
1725
+ ],
1726
+ brand: 'Arena Fit',
1727
+ initials: 'NR',
1728
+ color: '#1F7C68',
1729
+ colorDark: '#13261F',
1730
+ theme: 'training',
1731
+ tabs: ['Today', 'Program', 'Crew', 'Chat', 'Profile'],
1732
+ activeTab: 'Crew',
1733
+ bottomNav: ['Today', 'Plan', 'Crew', 'Inbox', 'You'],
1734
+ nativeHero: ['Training plan', 'Threshold Engine · Week 4', 'Coach view keeps readiness, route, and session intent above the new crew layer.', 'route'],
1735
+ nativeTiles: [['82%', 'readiness'], ['6 × 4:00', 'tempo set'], ['7.4 km', 'route loaded']],
1736
+ nativeRows: [
1737
+ ['PLAN', 'Threshold intervals', 'Warmup · 6 reps · cooldown'],
1738
+ ['REC', 'Recovery constraint', 'Keep strain below 46 today'],
1739
+ ['CAL', 'Coach check-in', 'Mika reviews cooldown notes at 6pm']
1740
+ ],
1741
+ heroKicker: 'Today',
1742
+ heroTitle: 'Hold pace, keep the finish controlled.',
1743
+ heroCopy: 'Readiness, coach notes, and the current program point to a steady threshold session.',
1744
+ heroChips: ['82% readiness', 'Threshold Engine', 'Coach Mika'],
1745
+ metrics: [['82%', 'readiness'], ['46', 'load'], ['7:12', 'target pace']],
1746
+ context: [
1747
+ ['Native product state', 'Threshold block · week 4 · run scheduled today.'],
1748
+ ['Target discovery', 'Crew selected from active program, not a pasted community id.']
1749
+ ],
1750
+ community: ['Threshold Engine Crew', 'Program-derived community · 1,248 members · Singapore endurance block'],
1751
+ author: ['MT', 'Mika Tan', 'Coach · 12 min'],
1752
+ postTitle: 'Threshold cue for today',
1753
+ post: 'Coach cue: settle into threshold rhythm, stay relaxed through the final push, and share your cooldown note.',
1754
+ media: 'training split image attachment',
1755
+ poll: ['How did the last interval feel?', [['Controlled', '64%'], ['Too hot', '24%'], ['Held back', '12%']]],
1756
+ actions: ['24 reactions', '8 comments', 'Share'],
1757
+ comment: ['NR', 'Nora Reed: hit 7:10 on interval four and felt strong.'],
1758
+ composer: ['Post to crew', 'Threshold check-in · visible to Threshold Engine Crew', 'Share with crew'],
1759
+ surfaces: [
1760
+ ['Profile/follow', 'Nora Reed · 7 following · Follow button active.'],
1761
+ ['Chat', 'Threshold Crew · 3 unread · Coach Mika synced.'],
1762
+ ['Notifications', 'Crew reaction digest appears inside Today.'],
1763
+ ['Moderation', 'Report action available from post menu.']
1764
+ ],
1765
+ proof: [
1766
+ ['Brownfield fit', 'The coaching dashboard remains the primary app.'],
1767
+ ['Runtime-visible social', 'Feed, post composer, reactions, comment preview, chat, and profile are visible inside the product.'],
1768
+ ['No arbitrary ids', 'User-facing labels are product-native; raw object ids stay in evidence.']
1769
+ ],
1770
+ evidence: [
1771
+ ['Before screenshot', 'Training dashboard, program detail, no peer layer.'],
1772
+ ['After screenshot', 'Crew tab with SDK-backed feed and composer.'],
1773
+ ['Runtime proof', 'Device path opens loaded data, not only build success.'],
1774
+ ['Data policy', 'Community/post/channel targets discovered naturally.']
1775
+ ],
1776
+ features: ['community discovery', 'feed', 'post composer', 'multi post type rendering', 'reactions', 'comment preview', 'profile/follow', 'chat']
1777
+ },
1778
+ market: {
1779
+ eyebrow: 'Web · investor watchlist',
1780
+ title: 'A portfolio product turns holdings into investor circles.',
1781
+ body: 'The social layer is derived from watchlist and holding context, so the user joins discussions that match the product state already on screen instead of landing in an unrelated global feed.',
1782
+ brief: [
1783
+ ['Prompt', 'Add community around holdings', 'Existing app had portfolio, alerts, and market research.'],
1784
+ ['Vise offered', 'Watchlist circles, analyst Q&A, alert-room chat', 'The options separated feed, chat, and notification emphasis.'],
1785
+ ['Chosen', 'Watchlist circles', 'Holdings-derived communities with feed, comments, follow graph, notifications, and report affordances.']
1786
+ ],
1787
+ brand: 'MarketPulse',
1788
+ initials: 'DC',
1789
+ color: '#245D87',
1790
+ colorDark: '#143654',
1791
+ theme: 'market',
1792
+ tabs: ['Portfolio', 'Markets', 'Circle', 'Alerts', 'Profile'],
1793
+ activeTab: 'Circle',
1794
+ bottomNav: ['Home', 'Watch', 'Circle', 'Alerts', 'You'],
1795
+ nativeHero: ['Portfolio', '$24,318 under watch', 'Holdings, alerts, and market context stay visible before the investor circle appears.', 'chart'],
1796
+ nativeTiles: [['+3.2%', 'this week'], ['18', 'watchlist'], ['4', 'alerts']],
1797
+ nativeRows: [
1798
+ ['AI', 'AInfra Corp', '+2.8% · earnings beat'],
1799
+ ['GG', 'GreenGrid Energy', '+1.4% · dividend watch'],
1800
+ ['NT', 'Novaterra', '-0.6% · risk alert']
1801
+ ],
1802
+ heroKicker: 'Portfolio',
1803
+ heroTitle: '$24,318 under watch.',
1804
+ heroCopy: 'AInfra Corp, GreenGrid Energy, and Novaterra drive the user’s active watchlist.',
1805
+ heroChips: ['18 symbols', '4 alerts', 'income strategy'],
1806
+ metrics: [['+3.2%', 'this week'], ['18', 'watchlist'], ['4', 'alerts']],
1807
+ context: [
1808
+ ['Native product state', 'Portfolio and watchlist stay in front of the experience.'],
1809
+ ['Target discovery', 'Investor circle selected from holdings and followed analysts.']
1810
+ ],
1811
+ community: ['Dividend Growth Investors', 'Matched from holdings · 18 active today · followed by Priya Anand'],
1812
+ author: ['PA', 'Priya Anand', '1h · circle post'],
1813
+ postTitle: 'Q3 income basket adjustment',
1814
+ post: 'Q3 earnings beat estimates across the portfolio. I am trimming the growth sleeve and adding to dividend stability.',
1815
+ media: 'watchlist performance card',
1816
+ poll: ['What should anchor the next rebalance?', [['Payout safety', '52%'], ['Growth', '31%'], ['Cash', '17%']]],
1817
+ actions: ['41 reactions', '8 comments', 'Follow'],
1818
+ comment: ['DK', 'Devin Cole: solid read, especially on payout coverage.'],
1819
+ composer: ['Share market note', 'Visible to Dividend Growth Investors · linked to AInfra watchlist', 'Post insight'],
1820
+ surfaces: [
1821
+ ['Profile/follow', 'Priya Anand profile opens with verified investing interests.'],
1822
+ ['Chat', 'Dividend Watchlist · 5 unread · Earnings alerts synced.'],
1823
+ ['Notifications', '4 investors you follow added AInfra Corp this week.'],
1824
+ ['Moderation', 'Report action scoped to the circle discussion card.']
1825
+ ],
1826
+ proof: [
1827
+ ['Brownfield fit', 'Portfolio and market workflows stay in front.'],
1828
+ ['Contextual social', 'Community discovery is derived from holdings and watchlist signals.'],
1829
+ ['Governed output', 'Notifications, report affordance, and profile/follow are included.']
1830
+ ],
1831
+ evidence: [
1832
+ ['Before screenshot', 'Portfolio, market movers, and alert center only.'],
1833
+ ['After screenshot', 'Circle tab with feed, poll, comments, and moderation.'],
1834
+ ['Runtime proof', 'Browser route loads seeded watchlist-derived community.'],
1835
+ ['Data policy', 'No hardcoded postId, channelId, targetId, or communityId in UI.']
1836
+ ],
1837
+ features: ['community discovery', 'feed', 'post composer', 'reactions', 'comment preview', 'profile/follow', 'chat', 'notifications', 'moderation affordance']
1838
+ },
1839
+ audio: {
1840
+ eyebrow: 'iOS · editorial audio',
1841
+ title: 'An editorial audio app adds listener clubs around episodes.',
1842
+ body: 'The integration follows the listening journey: current episode, saved show, curator profile, then club discussion. The social surfaces amplify the audio product rather than competing with it.',
1843
+ brief: [
1844
+ ['Prompt', 'Make listening more social', 'Existing app had episode pages, saved shows, and curator notes.'],
1845
+ ['Vise offered', 'Episode club, curator follow graph, listening-room chat', 'Each direction preserved the listening flow as the main job.'],
1846
+ ['Chosen', 'Episode club', 'Episode-derived community with discussion feed, composer, profile/follow, chat, and notification cues.']
1847
+ ],
1848
+ brand: 'Northstar Audio',
1849
+ initials: 'AL',
1850
+ color: '#5A4EA1',
1851
+ colorDark: '#29294A',
1852
+ theme: 'audio',
1853
+ tabs: ['Listen', 'Episode', 'Club', 'Chat', 'Profile'],
1854
+ activeTab: 'Club',
1855
+ bottomNav: ['Home', 'Listen', 'Club', 'Chat', 'Library'],
1856
+ nativeHero: ['Now playing', 'Cities After Dark', 'Playback, host notes, saved status, and episode progress remain the center of the screen.', 'wave'],
1857
+ nativeTiles: [['32m', 'episode'], ['86%', 'finished'], ['12', 'saved']],
1858
+ nativeRows: [
1859
+ ['EP', 'Field Notes episode', 'Cities After Dark · editorial pick'],
1860
+ ['HOST', 'Ari Leong notes', 'Sound design timestamps attached'],
1861
+ ['QUEUE', 'Quiet Listening Room', '128 live listeners nearby']
1862
+ ],
1863
+ heroKicker: 'Now playing',
1864
+ heroTitle: 'Field Notes: Cities After Dark.',
1865
+ heroCopy: 'A curated show page with saved episodes, host notes, and listening history.',
1866
+ heroChips: ['32m episode', '86% finished', 'saved show'],
1867
+ metrics: [['32m', 'episode'], ['86%', 'finished'], ['12', 'saved']],
1868
+ context: [
1869
+ ['Native product state', 'Current episode and host notes remain the entry point.'],
1870
+ ['Target discovery', 'Club selected from the active episode and show collection.']
1871
+ ],
1872
+ community: ['Cities After Dark Club', 'Episode-derived club · 6,420 listeners · 128 live now'],
1873
+ author: ['AL', 'Ari Leong', 'Curator · just now'],
1874
+ postTitle: 'Sound design note',
1875
+ post: 'The last third of this episode is a great example of sound design carrying the narrative without narration.',
1876
+ media: 'episode waveform highlight',
1877
+ poll: ['Best segment?', [['Metro transition', '49%'], ['Rooftop scene', '34%'], ['Outro', '17%']]],
1878
+ actions: ['89 reactions', '21 comments', 'Save'],
1879
+ comment: ['KM', 'Kai Moon: the metro transition at 21:40 is incredible.'],
1880
+ composer: ['Join the episode thread', 'Reply as listener · attached to current episode', 'Post comment'],
1881
+ surfaces: [
1882
+ ['Profile/follow', 'Ari Leong · 12.4k followers · Follow synced.'],
1883
+ ['Chat', 'After Dark Club · 9 unread · Quiet Listening Room available.'],
1884
+ ['Notifications', 'New replies from listeners you follow.'],
1885
+ ['Moderation', 'Report and mute actions stay inside the episode club.']
1886
+ ],
1887
+ proof: [
1888
+ ['Brownfield fit', 'The listening flow and episode surface remain the app center.'],
1889
+ ['Multi-surface journey', 'Discussion feed, post composer, reactions, comment preview, follow, chat, and profile connect around the show.'],
1890
+ ['Natural target', 'The current episode selects the club target.']
1891
+ ],
1892
+ evidence: [
1893
+ ['Before screenshot', 'Episode detail, playback controls, and curator notes.'],
1894
+ ['After screenshot', 'Club tab with episode feed and companion chat.'],
1895
+ ['Runtime proof', 'Simulator path shows populated listener data and comments.'],
1896
+ ['Data policy', 'Runtime-safe labels replace raw object identifiers.']
1897
+ ],
1898
+ features: ['community discovery', 'feed', 'post composer', 'reactions', 'comment preview', 'profile/follow', 'chat', 'notifications', 'runtime-safe labels']
1899
+ }
1900
+ };
1901
+
1902
+ function avatar(initials, color){
1903
+ return '<span class="mini-avatar" style="background:' + color + ';">' + initials + '</span>';
1904
+ }
1905
+ function renderBrief(cards){
1906
+ return '<div class="gallery-brief">' + cards.map(function(item){
1907
+ return '<div class="brief-card"><div class="brief-label">' + item[0] + '</div><b>' + item[1] + '</b><span>' + item[2] + '</span></div>';
1908
+ }).join('') + '</div>';
1909
+ }
1910
+ function renderPoll(poll){
1911
+ return '<div class="phone-poll"><b>' + poll[0] + '</b>' + poll[1].map(function(row){
1912
+ return '<div class="phone-poll-row"><i style="width:' + row[1] + ';"></i><span>' + row[0] + ' · ' + row[1] + '</span></div>';
1913
+ }).join('') + '</div>';
1914
+ }
1915
+ function renderNativeHero(data){
1916
+ var visual = '';
1917
+ if(data.nativeHero[3] === 'chart'){
1918
+ visual = '<div class="native-visual visual-chart"><span style="height:36%"></span><span style="height:62%"></span><span style="height:48%"></span><span style="height:78%"></span><span style="height:56%"></span><span style="height:88%"></span></div>';
1919
+ } else if(data.nativeHero[3] === 'wave'){
1920
+ visual = '<div class="native-visual visual-wave"><span style="height:22px"></span><span style="height:48px"></span><span style="height:31px"></span><span style="height:62px"></span><span style="height:40px"></span><span style="height:70px"></span><span style="height:28px"></span><span style="height:54px"></span><span style="height:35px"></span><span style="height:46px"></span></div>';
1921
+ } else {
1922
+ visual = '<div class="native-visual visual-route"></div>';
1923
+ }
1924
+ return '<section class="phone-native-hero"><p class="kicker">' + data.nativeHero[0] + '</p><h4>' + data.nativeHero[1] + '</h4><p>' + data.nativeHero[2] + '</p>' + visual + '</section>';
1925
+ }
1926
+ function renderNativeTiles(data){
1927
+ return '<div class="native-tiles">' + data.nativeTiles.map(function(tile){
1928
+ return '<div class="native-tile"><b>' + tile[0] + '</b><span>' + tile[1] + '</span></div>';
1929
+ }).join('') + '</div>';
1930
+ }
1931
+ function renderNativeRows(data){
1932
+ return '<div class="native-list">' + data.nativeRows.slice(0, 2).map(function(row){
1933
+ return '<div class="native-row"><span class="native-icon">' + row[0] + '</span><div><b>' + row[1] + '</b><span>' + row[2] + '</span></div></div>';
1934
+ }).join('') + '</div>';
1935
+ }
1936
+ function renderMedia(data){
1937
+ var bars = data.poll[1].map(function(row, index){
1938
+ var height = data.theme === 'audio' ? (22 + index * 15) : (30 + index * 18);
1939
+ return '<i style="height:' + height + 'px"></i>';
1940
+ }).join('');
1941
+ return '<div class="phone-media"><div><div class="media-label">' + data.media + '</div><div class="media-bars">' + bars + '</div></div></div>';
1942
+ }
1943
+ function renderBottomNav(data){
1944
+ return '<div class="phone-bottom-nav">' + data.bottomNav.map(function(item){
1945
+ return '<span class="' + (item === data.activeTab || item === 'Crew' || item === 'Circle' || item === 'Club' ? 'active' : '') + '">' + item + '</span>';
1946
+ }).join('') + '</div>';
1947
+ }
1948
+ function render(){
1949
+ var data = examples[active];
1950
+ copyEl.innerHTML = '<p class="eyebrow">' + data.eyebrow + '</p>' +
1951
+ '<h3>' + data.title + '</h3>' +
1952
+ '<p>' + data.body + '</p>' +
1953
+ renderBrief(data.brief) +
1954
+ '<div class="gallery-proof">' + data.proof.map(function(item){
1955
+ return '<div><b>' + item[0] + '</b><span>' + item[1] + '</span></div>';
1956
+ }).join('') + '</div>' +
1957
+ '<div class="gallery-features">' + data.features.map(function(item){ return '<span>' + item + '</span>'; }).join('') + '</div>';
1958
+
1959
+ evidenceEl.innerHTML = data.evidence.map(function(item){
1960
+ return '<div><b>' + item[0] + '</b><span>' + item[1] + '</span></div>';
1961
+ }).join('');
1962
+
1963
+ phoneEl.className = 'device-screen theme-' + data.theme;
1964
+ phoneEl.style.setProperty('--brand', data.color);
1965
+ phoneEl.style.setProperty('--brand-dark', data.colorDark);
1966
+ phoneEl.innerHTML = '<div class="phone-status"><span>9:41</span><span class="icons"><span class="bar"></span><span class="bar"></span></span></div>' +
1967
+ '<div class="phone-app"><span class="phone-brand">' + data.brand + '</span><span class="phone-avatar">' + data.initials + '</span></div>' +
1968
+ '<div class="phone-tabs">' + data.tabs.map(function(tab){
1969
+ return '<span class="' + (tab === data.activeTab ? 'active' : '') + '">' + tab + '</span>';
1970
+ }).join('') + '</div>' +
1971
+ '<div class="phone-scroll">' +
1972
+ renderNativeHero(data) +
1973
+ renderNativeTiles(data) +
1974
+ renderNativeRows(data) +
1975
+ '<div class="social-anchor"><p class="label">Vise-added social.plus layer</p><b>' + data.community[0] + '</b><span>' + data.community[1] + '</span></div>' +
1976
+ '<div class="phone-feed-header"><b>Community feed</b><span>text · image · poll</span></div>' +
1977
+ '<article class="phone-card"><div class="phone-author">' + avatar(data.author[0], data.color) + '<div><b>' + data.author[1] + '</b><span>' + data.author[2] + '</span></div></div>' +
1978
+ '<div class="phone-post-title">' + data.postTitle + '</div><p>' + data.post + '</p>' + renderMedia(data) + renderPoll(data.poll) + '<div class="phone-actions">' + data.actions.map(function(action){ return '<span>' + action + '</span>'; }).join('') + '</div>' +
1979
+ '<div class="phone-comment">' + avatar(data.comment[0], data.colorDark) + '<span>' + data.comment[1] + '</span></div></article>' +
1980
+ '<div class="phone-composer"><b>' + data.composer[0] + '</b><div class="phone-field">' + data.composer[1] + '</div><span class="phone-button">' + data.composer[2] + '</span></div>' +
1981
+ '<div class="phone-context">' + data.context.map(function(item){ return '<div class="phone-context-card"><b>' + item[0] + '</b><span>' + item[1] + '</span></div>'; }).join('') + '</div>' +
1982
+ '<p class="phone-section-title">Companion surfaces</p>' +
1983
+ '<div class="phone-surface-grid">' + data.surfaces.map(function(item){ return '<div class="phone-surface-pill"><b>' + item[0] + '</b><span>' + item[1] + '</span></div>'; }).join('') + '</div>' +
1984
+ '<div class="phone-notice"><b>Notification preview</b><br>' + data.surfaces[2][1] + '</div>' +
1985
+ '<div class="phone-mod">Moderation affordance: report, mute, and remove-from-view actions remain visible without exposing privileged SDK fields.</div>' +
1986
+ '<div class="phone-footer-proof">Runtime-safe labels only · community discovery via SDK query · no hardcoded communityId, postId, channelId, or targetId in the user interface</div>' +
1987
+ '</div>' + renderBottomNav(data);
1988
+
1989
+ buttons.forEach(function(button){
1990
+ var isActive = button.getAttribute('data-output') === active;
1991
+ button.classList.toggle('active', isActive);
1992
+ button.setAttribute('aria-selected', isActive ? 'true' : 'false');
1993
+ });
1994
+ }
1995
+
1996
+ buttons.forEach(function(button){
1997
+ button.addEventListener('click', function(){
1998
+ active = button.getAttribute('data-output');
1999
+ render();
2000
+ });
2001
+ });
2002
+ render();
2003
+ })();
2004
+ </script>
2005
+
2006
+ <script>
2007
+ (function(){
2008
+ function chatRow(c, i, name, preview, time, unread){
2009
+ return '<div class="chat-row"><span class="p-avatar" style="background:' + c + '">' + i + '</span>' +
2010
+ '<div><div class="chat-name">' + name + '</div><div class="chat-preview">' + preview + '</div></div>' +
2011
+ '<div class="chat-meta"><div class="chat-time">' + time + '</div>' + (unread ? '<span class="unread">' + unread + '</span>' : '') + '</div></div>';
2012
+ }
2013
+ function socialPulse(text){
2014
+ return '<div class="social-pulse"><svg class="ic"><use href="#tab-community"></use></svg><span>' + text + '</span></div>';
2015
+ }
2016
+ function profStat(value,label){
2017
+ return '<div class="prof-stat"><b>' + value + '</b><span>' + label + '</span></div>';
2018
+ }
2019
+ function sparkline(values, todayIndex){
2020
+ var bars = values.map(function(v,idx){
2021
+ return '<i style="height:' + v + '%;' + (idx === todayIndex ? 'opacity:1;' : '') + '"></i>';
2022
+ }).join('');
2023
+ return '<div class="trend">' + bars + '</div>';
2024
+ }
2025
+ function coachTip(text){
2026
+ return '<div class="coach-tip">' + text + '</div>';
2027
+ }
2028
+
2029
+ function statTrio(a,al,b,bl,c,cl,accent){
2030
+ return '<div class="statrow"><div><div class="statnum" style="' + (accent?('color:'+accent+';'):'') + '">' + a + '</div><div class="statlabel">' + al + '</div></div>' +
2031
+ '<div><div class="statnum">' + b + '</div><div class="statlabel">' + bl + '</div></div>' +
2032
+ '<div><div class="statnum">' + c + '</div><div class="statlabel">' + cl + '</div></div></div>';
2033
+ }
2034
+ function holdingRow(c,i,name,sub,change,good){
2035
+ return '<div class="chat-row"><span class="p-avatar" style="background:' + c + '">' + i + '</span><div><div class="chat-name">' + name + '</div><div class="chat-preview">' + sub + '</div></div>' +
2036
+ '<div class="chat-meta"><div class="chat-time" style="color:' + (good ? '#3F6B45' : '#A23B2E') + ';font-weight:700;">' + change + '</div></div></div>';
2037
+ }
2038
+ function courseRow(name, pct){
2039
+ return '<div class="chat-row"><div style="flex:1;"><div class="chat-name">' + name + '</div><div class="progress-track"><div class="progress-fill" style="width:' + pct + '%"></div></div></div>' +
2040
+ '<div class="chat-meta"><div class="chat-time">' + pct + '%</div></div></div>';
2041
+ }
2042
+ // Generic renderer for the second native screen: composes a few block types into real product UI.
2043
+ function blockRows(items){
2044
+ return items.map(function(it){
2045
+ var lead = it.thumb
2046
+ ? '<span class="listing-thumb"></span>'
2047
+ : '<span class="p-avatar" style="background:' + (it.color || '#9aa6a1') + '">' + (it.initials || '') + '</span>';
2048
+ var sub = it.sub ? '<div class="chat-preview">' + it.sub + '</div>' : '';
2049
+ var right = it.right
2050
+ ? '<div class="chat-meta"><div class="chat-time"' + (typeof it.good === 'boolean' ? ' style="color:' + (it.good ? '#3F6B45' : '#A23B2E') + ';font-weight:700;"' : '') + '>' + it.right + '</div></div>'
2051
+ : '';
2052
+ return '<div class="chat-row">' + lead + '<div><div class="chat-name">' + it.title + '</div>' + sub + '</div>' + right + '</div>';
2053
+ }).join('');
2054
+ }
2055
+ function renderBlocks(blocks){
2056
+ return blocks.map(function(b){
2057
+ if(b.type === 'statTrio') return statTrio(b.a, b.al, b.b, b.bl, b.c, b.cl);
2058
+ if(b.type === 'rows') return blockRows(b.items);
2059
+ if(b.type === 'progress') return b.items.map(function(it){ return courseRow(it.label, it.pct); }).join('');
2060
+ if(b.type === 'note') return coachTip(b.text);
2061
+ return '';
2062
+ }).join('');
2063
+ }
2064
+ function groupsStrip(groups){
2065
+ return '<div class="groups-strip">' + groups.map(function(g){
2066
+ return '<div class="group-chip"><span class="p-avatar" style="background:' + g.color + '">' + g.initials + '</span><span class="group-name">' + g.name + '</span></div>';
2067
+ }).join('') + '</div>';
2068
+ }
2069
+ function profileFull(a){
2070
+ var stats = a.stats.map(function(s){ return profStat(s.value, s.label); }).join('');
2071
+ var rows = a.rows.map(function(r){ return '<div class="acct-row"><span>' + r.title + '</span><span class="acct-val">' + r.right + '</span></div>'; }).join('');
2072
+ return '<div class="prof-head"><span class="p-avatar" style="background:' + a.c + '">' + a.i + '</span>' +
2073
+ '<div><div class="p-name" style="font-size:15px;">' + a.name + '</div><div class="p-time">' + a.sub + '</div></div></div>' +
2074
+ '<div class="prof-stats">' + stats + '</div><div class="acct-list">' + rows + '</div>';
2075
+ }
2076
+
2077
+ // ---- curated 15-point example demo (reuses the component helpers above) ----
2078
+ var fitContentEl = document.getElementById('fitContent');
2079
+ if(fitContentEl){
2080
+ var fitTabbarEl = document.getElementById('fitTabbar');
2081
+ var fitCounterEl = document.getElementById('fitCounter');
2082
+ var fitUthEl = document.getElementById('fitUth');
2083
+ var fitButtons = document.querySelectorAll('.fitbtn');
2084
+ var fmode = 'without';
2085
+ var ftab = 'community';
2086
+ var FIT_TABS = [
2087
+ {id:'home', icon:'tab-native', label:'Recovery'},
2088
+ {id:'trends', icon:'ic-pulse', label:'Trends'},
2089
+ {id:'community', icon:'tab-community', label:'Community'},
2090
+ {id:'profile', icon:'tab-profile', label:'Profile'}
2091
+ ];
2092
+ var FIT_UTH = [
2093
+ {n:3, k:'SDK version', bad:'^6.x floating', good:'6.42.0 pinned'},
2094
+ {n:4, k:'Network permission', bad:'INTERNET missing', good:'granted'},
2095
+ {n:14, k:'API key', bad:'in source bundle', good:'server-side only'},
2096
+ {n:15, k:'Create payload', bad:'isOfficial: false set', good:'admin fields excluded'}
2097
+ ];
2098
+ var pin = function(n, fixed){ return '<span class="pin ' + (fixed ? 'good' : 'bad') + '">' + n + '</span>'; };
2099
+
2100
+ var fitHomeBase = statTrio('82%','Recovery','9.2','Strain','7h 42m','Sleep','#12C48B') +
2101
+ sparkline([55,70,40,85,60,75,82], 6) +
2102
+ holdingRow('#B5901F','❤','Resting heart rate','52 bpm','-3 bpm',true) +
2103
+ coachTip('Recovery is trending up — a moderate-to-high strain day fits well today.');
2104
+ var fitTrendsBase = renderBlocks([
2105
+ {type:'statTrio',a:'68%',al:'Recovery',b:'-4 ms',bl:'HRV Δ',c:'51 ms',cl:'HRV avg'},
2106
+ {type:'rows',items:[
2107
+ {initials:'RC',color:'#12C48B',title:'Recovery',sub:'30-day avg',right:'71%'},
2108
+ {initials:'ST',color:'#2A3140',title:'Day Strain',sub:'30-day avg',right:'13.4'},
2109
+ {initials:'SL',color:'#2A3140',title:'Sleep performance',sub:'30-day avg',right:'84%'}
2110
+ ]},
2111
+ {type:'progress',items:[{label:'Sleep consistency',pct:78},{label:'Recovery in the green',pct:62}]}
2112
+ ]);
2113
+
2114
+ function fitContent(mode, tab){
2115
+ var fixed = mode === 'vise';
2116
+ if(tab === 'home'){
2117
+ return fitHomeBase + (fixed
2118
+ ? socialPulse('<b>Dawn Patrol Run Club</b> — 4 members recovered green this morning') + '<div class="pin-holder">' + pin(13,true) + ' social pulse renders</div>'
2119
+ : '<div class="cx-blank">Squad activity — stuck on a blank frame' + pin(13,false) + '</div>');
2120
+ }
2121
+ if(tab === 'trends'){
2122
+ return fitTrendsBase + (fixed
2123
+ ? socialPulse('<b>2 squadmates</b> logged a strain above 15 today') + '<div class="pin-holder">' + pin(6,true) + ' SDK data wired in</div>'
2124
+ : '<div class="cx-missing">Squad comparison — SDK added, never called' + pin(6,false) + '</div>');
2125
+ }
2126
+ if(tab === 'community'){
2127
+ if(fixed){
2128
+ return '<div class="cx-head"><div class="cx-title">Run Clubs</div><div class="cx-sub">your squads &amp; challenges' + pin(1,true) + '</div></div>' +
2129
+ '<div class="p-card"><div class="p-head"><span class="p-avatar" style="background:#C1613F">JA</span><div><div class="p-name">Jordan Ames</div><div class="p-time">2h · Dawn Patrol Run Club</div></div></div>' +
2130
+ '<p class="p-body">Back-to-back PRs this week 🏃 — group run Saturday 7am.' + pin(11,true) + '</p>' +
2131
+ '<div class="p-actions"><span class="p-action liked"><svg class="ic"><use href="#ic-heart"></use></svg>24' + pin(7,true) + '</span><span class="p-action"><svg class="ic"><use href="#ic-comment"></use></svg>3</span><span class="p-action"><svg class="ic"><use href="#ic-share"></use></svg></span></div>' +
2132
+ '<div class="p-reply"><span class="p-avatar" style="background:#B5901F">PR</span><span class="txt">Let\'s go 🎉' + pin(10,true) + '</span></div></div>' +
2133
+ '<div class="cx-ok">12 posts in your clubs today' + pin(9,true) + '</div>' +
2134
+ '<p class="activity-label">Squads</p>' + groupsStrip([{initials:'DP',color:'#12C48B',name:'Dawn Patrol Run Club'},{initials:'TS',color:'#2A3140',name:'Threshold Squad'},{initials:'MM',color:'#5C3A1B',name:'Marathon Block'}]) + '<div class="pin-holder">' + pin(5,true) + ' discovered live</div>' +
2135
+ '<p class="activity-label">Messages</p>' + chatRow('#12C48B','MR','Morning Run Crew','Sam: see you at the trailhead!','9:02',3) + '<div class="pin-holder">' + pin(2,true) + ' chat connected</div>' +
2136
+ '<p class="activity-label">Challenges</p><div class="cx-ok">3 active — Summer Streak, 100mi' + pin(8,true) + '</div>' +
2137
+ '<button class="pill-btn primary" style="margin-top:12px;">Join Club' + pin(12,true) + '</button>';
2138
+ }
2139
+ return '<div class="cx-head"><div class="cx-title">Feed</div><div class="cx-sub">generic global feed' + pin(1,false) + '</div></div>' +
2140
+ '<div class="p-card"><div class="p-head"><span class="p-avatar" style="background:#C1613F">JA</span><div><div class="p-name">Jordan Ames</div><div class="p-time">2h</div></div></div>' +
2141
+ '<div class="p-empty">no post text' + pin(11,false) + '</div>' +
2142
+ '<div class="p-actions"><span class="p-action">♥ [object Object]' + pin(7,false) + '</span></div>' +
2143
+ '<div class="p-nocomment">no comments' + pin(10,false) + '</div></div>' +
2144
+ '<div class="cx-empty">0 more posts loaded' + pin(9,false) + '</div>' +
2145
+ '<p class="activity-label">Squads</p><div class="cx-err">Squad unavailable — networkId undefined' + pin(5,false) + '</div>' +
2146
+ '<p class="activity-label">Messages</p><div class="cx-err">Chat crashed — MessageDbAdapter not ready' + pin(2,false) + '</div>' +
2147
+ '<p class="activity-label">Challenges</p><div class="cx-missing">Not built' + pin(8,false) + '</div>' +
2148
+ '<button class="btn brand-generic" style="margin-top:12px;">Join' + pin(12,false) + '</button>';
2149
+ }
2150
+ var prof = profileFull({c:'#C1613F',i:'SO',name:'Sam Okafor',sub:'Recoup Band 4.0 · Connected',
2151
+ stats:[{value:'63',label:'Day streak'},{value:'212',label:'Workouts'},{value:'99%',label:'Best recovery'}],
2152
+ rows:[{title:'Device',right:'Recoup Band 4.0'},{title:'Membership',right:'Annual · Active'}]});
2153
+ return prof + (fixed
2154
+ ? '<p class="activity-label">Social</p><div class="prof-stats">' + profStat('1,204','Followers') + profStat('318','Following') + '</div><button class="pill-btn primary">Following ✓</button>'
2155
+ : '<p class="activity-label">Social</p><div class="cx-err">Followers didn\'t load — surface never finished</div>');
2156
+ }
2157
+
2158
+ function fitRenderTabbar(){
2159
+ fitTabbarEl.innerHTML = FIT_TABS.map(function(t){
2160
+ var on = t.id === ftab;
2161
+ return '<button class="tabbtn' + (on ? ' active' : '') + '" role="tab" aria-selected="' + (on ? 'true' : 'false') + '" data-ftab="' + t.id + '"><svg class="ic"><use href="#' + t.icon + '"></use></svg>' + t.label + '</button>';
2162
+ }).join('');
2163
+ }
2164
+ function fitRender(){
2165
+ var fixed = fmode === 'vise';
2166
+ fitRenderTabbar();
2167
+ fitContentEl.innerHTML = fitContent(fmode, ftab);
2168
+ fitCounterEl.textContent = fixed ? '15 representative gaps caught — every showcased surface works' : '15 representative gaps flagged across the app';
2169
+ fitCounterEl.className = 'fit-counter ' + (fixed ? 'good' : 'bad');
2170
+ fitUthEl.innerHTML = '<div class="uth-lbl">Under the hood — build &amp; security</div>' + FIT_UTH.map(function(u){
2171
+ return '<div class="uth-item ' + (fixed ? 'good' : 'bad') + '"><div class="uth-k">' + u.k + pin(u.n, fixed) + '</div><div class="uth-v">' + (fixed ? u.good : u.bad) + '</div></div>';
2172
+ }).join('');
2173
+ fitButtons.forEach(function(b){
2174
+ var on = b.getAttribute('data-fmode') === fmode;
2175
+ b.classList.toggle('active', on);
2176
+ b.setAttribute('aria-selected', on ? 'true' : 'false');
2177
+ });
2178
+ }
2179
+ fitButtons.forEach(function(b){ b.addEventListener('click', function(){ fmode = b.getAttribute('data-fmode'); fitRender(); }); });
2180
+ fitTabbarEl.addEventListener('click', function(e){ var b = e.target.closest('.tabbtn'); if(!b) return; ftab = b.getAttribute('data-ftab'); fitRender(); });
2181
+ var fitScreen = document.getElementById('fitScreen');
2182
+ fitScreen.style.setProperty('--brand', '#12C48B');
2183
+ fitScreen.style.setProperty('--brand-dark', '#0C8C64');
2184
+ fitRender();
2185
+ }
2186
+ })();
2187
+ </script>