@echomem/mcp 1.4.44 → 1.4.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +28 -25
  2. package/dist/city/README.md +9 -0
  3. package/dist/city/echo-ai-city-only.html +2232 -0
  4. package/dist/city/echo-extraction-plate.html +330 -0
  5. package/dist/city/echo-face-cutout.png +0 -0
  6. package/dist/city/personality_stickers/bossy.png +0 -0
  7. package/dist/city/personality_stickers/ghosty.png +0 -0
  8. package/dist/city/personality_stickers/loopy.png +0 -0
  9. package/dist/city/personality_stickers/lusty.png +0 -0
  10. package/dist/city/personality_stickers/maxxy.png +0 -0
  11. package/dist/city/personality_stickers/tabby.png +0 -0
  12. package/dist/city/vendor/OrbitControls.js +1417 -0
  13. package/dist/city/vendor/RoundedBoxGeometry.js +155 -0
  14. package/dist/city/vendor/echo_general-file-21.riv +0 -0
  15. package/dist/city/vendor/rive.js +8139 -0
  16. package/dist/city/vendor/rive.wasm +0 -0
  17. package/dist/city/vendor/three.module.min.js +6 -0
  18. package/dist/context-analysis/claude-native-canonical.js +2 -2
  19. package/dist/context-analysis/vendored-canonical.js +2 -2
  20. package/dist/context-analysis/workspace-report.js +3 -3
  21. package/dist/forensics.js +1531 -0
  22. package/dist/hud/hooks.js +31 -43
  23. package/dist/index.js +79 -15
  24. package/dist/local-data-paths.js +38 -0
  25. package/dist/migrate.js +140 -70
  26. package/dist/report.js +721 -0
  27. package/dist/save-checkpoint-hook.js +1 -1
  28. package/dist/setup-page/client-core.js +372 -18
  29. package/dist/setup-page/client-extraction.js +204 -37
  30. package/dist/setup-page/client-lifecycle.js +101 -31
  31. package/dist/setup-page/client-report-audit.js +819 -0
  32. package/dist/setup-page/client-report-city.js +356 -0
  33. package/dist/setup-page/client-report.js +6 -0
  34. package/dist/setup-page/client.js +2 -0
  35. package/dist/setup-page/styles-city-report.js +880 -0
  36. package/dist/setup-page/styles-context-audit.js +470 -0
  37. package/dist/setup-page/styles-extraction.js +31 -1
  38. package/dist/setup-page/styles-foundation.js +89 -0
  39. package/dist/setup-page/styles-mvp.js +155 -10
  40. package/dist/setup-page/styles-website-alignment.js +204 -0
  41. package/dist/setup-page/styles.js +4 -0
  42. package/dist/setup-page.js +4 -4
  43. package/dist/setup-preview.js +212 -4
  44. package/dist/setup.js +702 -321
  45. package/dist/source-session.js +3 -9
  46. package/dist/v1-contract.js +8 -0
  47. package/package.json +7 -9
  48. package/dist/config-files.js +0 -63
  49. package/dist/local-jsonl.js +0 -87
  50. package/dist/onboarding-stats.js +0 -16
@@ -0,0 +1,880 @@
1
+ // Generated from the prior inline setup page. This content is emitted into one browser IIFE/style tag.
2
+ export const SETUP_PAGE_STYLES_CITY_REPORT = String.raw ` /* ---- forensic report (ContextDoctorTwo) ---- */
3
+ .cityHero {
4
+ --city-display-w: min(calc(100vw - 28px), calc((100vh - 28px) * 0.7797));
5
+ --city-display-h: min(calc(100vh - 28px), calc((100vw - 28px) * 1.2826));
6
+ position: relative;
7
+ width: min(880px, 100%);
8
+ margin: clamp(-36px, -2vw, -16px) auto 0;
9
+ padding: 4px 0 0;
10
+ background: transparent;
11
+ }
12
+ .cityFigureRow {
13
+ /* Mirror the body-text column geometry (.context-audit): same 880px column,
14
+ same inner padding, same half-gutter nudge — so cityNote's left edge sits
15
+ exactly on the body text's left line, and cityFig's column starts exactly
16
+ on the body text's right line, then bleeds to the viewport's right edge. */
17
+ --hero-pad: clamp(22px, 4.5vw, 64px);
18
+ --audit-gutter: calc(150px + clamp(16px, 2.5vw, 36px));
19
+ display: grid;
20
+ /* City column width is chosen so its CENTER sits on the pie-chart axis below
21
+ (pie column center = 100vw − (100vw − 880px)/2 − pad + gutter/2 − 75px) while its
22
+ right edge stays glued to the viewport edge. The camera centers the city in the
23
+ canvas, so the default view lands exactly on that shared vertical axis. */
24
+ grid-template-columns: minmax(0, 1fr) calc(100vw - min(880px, 100vw) + 2 * var(--hero-pad) - var(--audit-gutter) + 150px);
25
+ gap: 0;
26
+ align-items: center;
27
+ margin-left: calc(var(--hero-pad) - var(--audit-gutter) / 2);
28
+ width: calc(50vw + 50% - var(--hero-pad) + var(--audit-gutter) / 2);
29
+ }
30
+ .cityFig { margin: 0; order: 2; position: relative; }
31
+ .cityNote { order: 1; }
32
+ /* ---- fullscreen city modal (80% viewport): dirty/clean toggle + tool legend + forensic stats ---- */
33
+ .cityFullBtn {
34
+ position: absolute;
35
+ z-index: 6;
36
+ left: 50%;
37
+ transform: translateX(-50%);
38
+ bottom: clamp(16px, 2.5vh, 30px);
39
+ display: inline-flex;
40
+ align-items: center;
41
+ gap: 8px;
42
+ padding: 10px 15px;
43
+ border: 1px solid rgba(26, 58, 143, 0.22);
44
+ border-radius: 999px;
45
+ background: rgba(255, 255, 255, 0.94);
46
+ color: var(--echo-ink-primary);
47
+ font-family: var(--echo-font-brand);
48
+ font-size: 12.5px;
49
+ font-weight: 700;
50
+ line-height: 1;
51
+ cursor: pointer;
52
+ box-shadow: 0 10px 28px rgba(28, 38, 60, 0.12);
53
+ }
54
+ .cityFullBtn:hover { background: #ffffff; }
55
+ .cityFullBtn svg { width: 12px; height: 12px; display: block; }
56
+ body.cityFull .cityFullBtn { display: none; }
57
+ .cityFullBackdrop { position: fixed; inset: 0; z-index: 58; background: rgba(26, 26, 26, 0.45); }
58
+ body.cityFull .cityShell {
59
+ position: fixed;
60
+ inset: 10vh 10vw;
61
+ width: auto;
62
+ height: auto;
63
+ z-index: 59;
64
+ background: var(--echo-paper-canvas);
65
+ border: 1px solid var(--echo-line-soft);
66
+ border-radius: 18px;
67
+ box-shadow: 0 40px 120px rgba(20, 24, 40, 0.4);
68
+ -webkit-mask-image: none;
69
+ mask-image: none;
70
+ }
71
+ .cityFullChrome {
72
+ position: fixed;
73
+ inset: 10vh 10vw;
74
+ z-index: 60;
75
+ display: flex;
76
+ flex-direction: column;
77
+ justify-content: space-between;
78
+ pointer-events: none;
79
+ padding: 16px 18px;
80
+ box-sizing: border-box;
81
+ }
82
+ .cityFullChrome[hidden], .cityFullBackdrop[hidden] { display: none; }
83
+ .cfc-bar { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
84
+ .cfc-left { display: flex; align-items: center; gap: 10px; }
85
+ /* Quiet toggles — same language as the top-nav pill: white pill, hairline border,
86
+ the active chip gets only a thin ink ring. No saturated fills. */
87
+ .cfc-toggle {
88
+ pointer-events: auto;
89
+ display: inline-flex;
90
+ align-items: center;
91
+ gap: 2px;
92
+ padding: 5px;
93
+ background: var(--echo-paper-white);
94
+ border: 1px solid rgba(26, 26, 26, 0.06);
95
+ border-radius: 999px;
96
+ box-shadow: 0 12px 30px rgba(28, 38, 60, 0.10);
97
+ }
98
+ .cfc-toggle button {
99
+ appearance: none;
100
+ display: inline-flex;
101
+ align-items: center;
102
+ gap: 7px;
103
+ border: 1px solid transparent;
104
+ border-radius: 999px;
105
+ padding: 8px 14px;
106
+ background: transparent;
107
+ font-family: var(--echo-font-brand);
108
+ font-size: 12.5px;
109
+ font-weight: 600;
110
+ line-height: 1;
111
+ color: var(--echo-ink-mute);
112
+ cursor: pointer;
113
+ transition: color 120ms linear, border-color 120ms linear;
114
+ }
115
+ .cfc-toggle button:hover { color: #1a1a1a; }
116
+ .cfc-toggle button.on { color: #1a1a1a; font-weight: 700; border-color: rgba(26, 26, 26, 0.16); }
117
+ .cfc-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: #c7372f; }
118
+ .cfc-face { width: 18px; height: 18px; border-radius: 50%; object-fit: cover; flex: none; }
119
+ .cfc-legend {
120
+ pointer-events: auto;
121
+ display: inline-flex;
122
+ align-items: center;
123
+ gap: 20px;
124
+ padding: 10px 18px;
125
+ background: #ffffff;
126
+ border: 1px solid var(--echo-line-soft);
127
+ border-radius: 999px;
128
+ box-shadow: 0 10px 26px rgba(28, 38, 60, 0.12);
129
+ font-family: var(--echo-font-mono);
130
+ font-size: 12px;
131
+ color: var(--echo-ink-text);
132
+ white-space: nowrap;
133
+ }
134
+ .cfc-legend .cfc-side { display: inline-flex; align-items: center; gap: 8px; }
135
+ .cfc-legend .cfc-swatch { width: 11px; height: 11px; border-radius: 3px; flex: none; }
136
+ .cfc-legend img { width: 18px; height: 18px; object-fit: contain; }
137
+ .cfc-legend b { font-size: 14.5px; font-variant-numeric: tabular-nums; }
138
+ .cfc-close {
139
+ pointer-events: auto;
140
+ width: 42px;
141
+ height: 42px;
142
+ flex: none;
143
+ border: 1px solid var(--echo-line-soft);
144
+ border-radius: 999px;
145
+ background: #ffffff;
146
+ color: #1a1a1a;
147
+ font-size: 20px;
148
+ line-height: 1;
149
+ cursor: pointer;
150
+ box-shadow: 0 10px 26px rgba(28, 38, 60, 0.12);
151
+ }
152
+ .cfc-close:hover { background: var(--echo-paper-soft); }
153
+ .cfc-stats {
154
+ pointer-events: auto;
155
+ align-self: center;
156
+ display: flex;
157
+ flex-wrap: wrap;
158
+ justify-content: center;
159
+ gap: 10px 30px;
160
+ padding: 13px 26px;
161
+ background: rgba(255, 255, 255, 0.95);
162
+ border: 1px solid var(--echo-line-soft);
163
+ border-radius: 14px;
164
+ box-shadow: 0 14px 40px rgba(28, 38, 60, 0.14);
165
+ }
166
+ .cfc-stat { display: grid; gap: 5px; justify-items: center; }
167
+ .cfc-stat span { font-family: var(--echo-font-mono); font-size: 9px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--echo-ink-mute); }
168
+ .cfc-stat strong { font-family: var(--echo-font-mono); font-size: 15px; line-height: 1; color: var(--echo-ink-text); font-variant-numeric: tabular-nums; }
169
+ .cityShell {
170
+ position: relative;
171
+ width: 100%;
172
+ height: clamp(400px, 52vh, 560px);
173
+ border-radius: 0;
174
+ overflow: hidden;
175
+ /* Fade the LEFT edge (toward the text) and the BOTTOM edge (toward the report);
176
+ top and right run clean to the viewport edge. Two mask layers intersected. */
177
+ -webkit-mask-image:
178
+ linear-gradient(to right, rgba(0, 0, 0, 0) 0%, #000 16%, #000 100%),
179
+ linear-gradient(to top, rgba(0, 0, 0, 0) 0%, #000 16%, #000 100%);
180
+ -webkit-mask-composite: source-in;
181
+ mask-image:
182
+ linear-gradient(to right, rgba(0, 0, 0, 0) 0%, #000 16%, #000 100%),
183
+ linear-gradient(to top, rgba(0, 0, 0, 0) 0%, #000 16%, #000 100%);
184
+ mask-composite: intersect;
185
+ }
186
+ .reportTop {
187
+ position: sticky;
188
+ top: 0;
189
+ z-index: 40;
190
+ display: grid;
191
+ grid-template-columns: 1fr auto 1fr;
192
+ align-items: center;
193
+ gap: 16px;
194
+ width: 100%;
195
+ margin: 0 auto;
196
+ padding: 12px clamp(24px, 4vw, 56px);
197
+ box-sizing: border-box;
198
+ background: var(--echo-paper-canvas);
199
+ border-bottom: 0;
200
+ margin-bottom: 0;
201
+ }
202
+ /* Yeah! Echo wordmark — ported 1:1 from WebPageReactVersion YeahEchoMark.module.css
203
+ (default lockup: bubble left, tail points right toward "Echo"). */
204
+ .yeahLogo {
205
+ position: relative;
206
+ display: inline-flex;
207
+ align-items: center;
208
+ gap: 0.5em;
209
+ justify-self: start;
210
+ font-size: 27px;
211
+ line-height: 1;
212
+ color: var(--echo-ink-primary);
213
+ }
214
+ .yeahLogo i {
215
+ position: relative;
216
+ font-family: "Caveat", cursive;
217
+ font-style: normal;
218
+ font-weight: 700;
219
+ font-size: 0.55em;
220
+ line-height: 1;
221
+ color: var(--echo-ink-primary);
222
+ background: var(--echo-paper-white);
223
+ border: 0.05em solid var(--echo-ink-primary);
224
+ padding: 0.06em 0.55em 0.14em;
225
+ border-radius: 999px;
226
+ box-shadow: 0 0.1em 0.16em rgba(26, 58, 143, 0.10);
227
+ }
228
+ .yeahLogo i::before,
229
+ .yeahLogo i::after { content: ""; position: absolute; width: 0; height: 0; top: 50%; }
230
+ .yeahLogo i::before {
231
+ right: -0.25em;
232
+ transform: translateY(-50%);
233
+ border-top: 0.24em solid transparent;
234
+ border-bottom: 0.24em solid transparent;
235
+ border-left: 0.32em solid var(--echo-ink-primary);
236
+ }
237
+ .yeahLogo i::after {
238
+ right: -0.14em;
239
+ transform: translateY(-50%);
240
+ border-top: 0.2em solid transparent;
241
+ border-bottom: 0.2em solid transparent;
242
+ border-left: 0.28em solid var(--echo-paper-white);
243
+ }
244
+ .yeahLogo b { font-family: var(--echo-font-brand); font-weight: 700; letter-spacing: -0.02em; font-size: 1em; line-height: 1; color: var(--echo-ink-primary); }
245
+ /* Center nav — same pill language as the website header lockup. */
246
+ .navCenter { justify-self: center; display: inline-flex; align-items: center; gap: 10px; }
247
+ .navPill {
248
+ display: inline-flex;
249
+ align-items: center;
250
+ gap: 4px;
251
+ padding: 5px;
252
+ background: var(--echo-paper-white);
253
+ border: 1px solid rgba(26, 26, 26, 0.06);
254
+ border-radius: 999px;
255
+ box-shadow: 0 12px 30px rgba(28, 38, 60, 0.10);
256
+ }
257
+ .navTitle {
258
+ display: inline-flex;
259
+ align-items: center;
260
+ gap: 8px;
261
+ font-family: var(--echo-font-brand);
262
+ font-size: 13px;
263
+ font-weight: 700;
264
+ line-height: 1;
265
+ white-space: nowrap;
266
+ color: #1a1a1a;
267
+ padding: 6px 8px 6px 10px;
268
+ }
269
+ .navTitleFace { width: 20px; height: 20px; border-radius: 50%; object-fit: cover; flex: none; }
270
+ .navDates { display: inline-flex; align-items: center; gap: 8px; padding-right: 4px; }
271
+ .navDates:empty { display: none; }
272
+ /* Mini timeline axis between the two dates — same language as the story
273
+ timeline: thin slate line, round endpoints, NOW end in warm coral. */
274
+ .navAxis {
275
+ position: relative;
276
+ width: 72px;
277
+ height: 2px;
278
+ border-radius: 999px;
279
+ background: #a9aec9;
280
+ }
281
+ .navAxis::before,
282
+ .navAxis::after {
283
+ content: "";
284
+ position: absolute;
285
+ top: 50%;
286
+ transform: translateY(-50%);
287
+ width: 6px;
288
+ height: 6px;
289
+ border-radius: 50%;
290
+ }
291
+ .navAxis::before { left: -1px; background: #a9aec9; }
292
+ .navAxis::after { right: -1px; background: #e06b52; }
293
+ .navDates em.isNow { border-color: #e06b52; color: #b94a35; background: #fdf3f0; }
294
+ .navDates em {
295
+ font-style: normal;
296
+ font-family: var(--echo-font-mono);
297
+ font-size: 10.5px;
298
+ font-weight: 700;
299
+ letter-spacing: 0.04em;
300
+ text-transform: uppercase;
301
+ line-height: 1;
302
+ white-space: nowrap;
303
+ color: #3a3a36;
304
+ background: #f7f7f5;
305
+ border: 1px solid #9b9b97;
306
+ border-radius: 999px;
307
+ padding: 7px 11px;
308
+ }
309
+ .navDates i { font-style: normal; font-family: var(--echo-font-mono); font-size: 11px; font-weight: 700; color: var(--echo-ink-faint); }
310
+ .navDot { width: 7px; height: 7px; border-radius: 50%; background: var(--echo-ink-accent); flex-shrink: 0; animation: navDotPulse 1.6s ease-in-out infinite; }
311
+ @keyframes navDotPulse {
312
+ 0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(78, 205, 196, 0.55); }
313
+ 50% { opacity: 0.35; box-shadow: 0 0 0 5px rgba(78, 205, 196, 0); }
314
+ }
315
+ .navLocal {
316
+ display: inline-flex;
317
+ align-items: center;
318
+ gap: 7px;
319
+ font-family: var(--echo-font-brand);
320
+ font-size: 12px;
321
+ font-weight: 700;
322
+ line-height: 1;
323
+ white-space: nowrap;
324
+ color: #1a1a1a;
325
+ background: var(--echo-paper-white);
326
+ border: 1px solid rgba(26, 26, 26, 0.08);
327
+ border-radius: 999px;
328
+ padding: 9px 14px;
329
+ box-shadow: 0 8px 22px rgba(28, 38, 60, 0.08);
330
+ }
331
+ .navLocal svg { width: 12px; height: 12px; display: block; color: var(--echo-ink-mute); }
332
+ .navConnect {
333
+ justify-self: end;
334
+ display: inline-flex;
335
+ align-items: center;
336
+ gap: 8px;
337
+ font-family: var(--echo-font-brand);
338
+ font-size: 13px;
339
+ font-weight: 700;
340
+ line-height: 1;
341
+ white-space: nowrap;
342
+ color: var(--echo-ink-accent-deep);
343
+ background: rgba(78, 205, 196, 0.16);
344
+ border: 1px solid rgba(78, 205, 196, 0.5);
345
+ border-radius: 999px;
346
+ padding: 12px 16px;
347
+ cursor: pointer;
348
+ transition: background 140ms linear;
349
+ }
350
+ .navConnect:hover { background: rgba(78, 205, 196, 0.28); }
351
+ .navConnect svg { width: 11px; height: 11px; display: block; }
352
+ .cityNote { display: grid; gap: 8px; align-content: center; justify-items: start; color: #242424; }
353
+ /* Echo speaks the greeting: mascot on the left, manga speech bubble to his right
354
+ (same bubble language as the Yeah! Echo wordmark — paper white, navy ink, left tail). */
355
+ .cityNote .fn-speak { display: flex; align-items: center; gap: 16px; margin-bottom: 4px; }
356
+ .cityNote img { width: 108px; height: auto; margin-top: -24px; flex: none; }
357
+ .cityNote .fn-bubble {
358
+ position: relative;
359
+ margin-top: -52px;
360
+ background: var(--echo-paper-white);
361
+ border: 1.6px solid #1a3a8f;
362
+ border-radius: 18px;
363
+ padding: 12px 20px 14px;
364
+ box-shadow: 0 3px 6px rgba(26, 58, 143, 0.10);
365
+ }
366
+ .cityNote .fn-bubble::before,
367
+ .cityNote .fn-bubble::after { content: ""; position: absolute; top: 62%; width: 0; height: 0; transform: translateY(-50%); }
368
+ .cityNote .fn-bubble::before {
369
+ left: -12px;
370
+ border-top: 8px solid transparent;
371
+ border-bottom: 8px solid transparent;
372
+ border-right: 12px solid #1a3a8f;
373
+ }
374
+ .cityNote .fn-bubble::after {
375
+ left: -9px;
376
+ border-top: 6.5px solid transparent;
377
+ border-bottom: 6.5px solid transparent;
378
+ border-right: 10px solid var(--echo-paper-white);
379
+ }
380
+ .cityNote h2 { margin: 0; font-family: var(--echo-font-brand); font-size: clamp(24px, 2.6vw, 32px); font-weight: 900; letter-spacing: -0.02em; line-height: 1; color: #171717; text-transform: lowercase; }
381
+ .cityNote .fn-save { margin: 9px 0 2px; max-width: 34ch; font-family: var(--echo-font-brand); font-size: 16px; font-weight: 600; line-height: 1.5; color: #242424; }
382
+ .cityNote .fn-save .fn-num,
383
+ .cityNote .fn-save .fn-less { font-weight: 800; color: #c7372f; font-variant-numeric: tabular-nums; white-space: nowrap; }
384
+ .cityNote h2 b { color: #1a3a8f; }
385
+ .cityNote .fn-dot { color: #f4a83b; }
386
+ .cityNote .fn-rank { margin: 0; font-family: var(--echo-font-brand); font-size: 15px; color: #666666; }
387
+ .cityNote .fn-rank b { font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: #242424; }
388
+ .fn-info {
389
+ /* beat the global button { min-height:44px; padding:0 16px } rule */
390
+ min-height: 0;
391
+ width: 17px;
392
+ height: 17px;
393
+ margin-left: 8px;
394
+ padding: 0;
395
+ display: inline-grid;
396
+ place-items: center;
397
+ border: 1.2px solid rgba(26, 26, 26, 0.35);
398
+ border-radius: 50%;
399
+ background: transparent;
400
+ color: rgba(26, 26, 26, 0.55);
401
+ font-family: Georgia, "Times New Roman", serif;
402
+ font-size: 11px;
403
+ font-weight: 700;
404
+ font-style: italic;
405
+ line-height: 1;
406
+ vertical-align: 2px;
407
+ cursor: pointer;
408
+ transition: color 120ms linear, border-color 120ms linear;
409
+ }
410
+ .fn-info:hover { color: #1a1a1a; border-color: #1a1a1a; }
411
+ .fn-guide-sec { margin: 16px 0 7px; font-family: var(--echo-font-mono); font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--echo-ink-mute); }
412
+ .fn-guide-sec:first-child { margin-top: 0; }
413
+ .fn-guide-row { margin: 0 0 7px; font-size: 13px; line-height: 1.5; color: var(--echo-ink-text); }
414
+ .fn-guide-row b { color: var(--echo-ink-primary); }
415
+ .fn-guide-row span { color: var(--echo-ink-mute); }
416
+ .fn-guide-row.is-you { background: var(--echo-paper-soft); border-radius: 8px; padding: 6px 10px; margin-left: -10px; }
417
+ .fn-guide-row.is-you i { display: inline-block; margin-left: 7px; padding: 2px 7px 3px; border-radius: 999px; background: #1a3a8f; color: #fff; font-style: normal; font-family: var(--echo-font-mono); font-size: 9px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; vertical-align: 1px; }
418
+ .echo-note-dlg .nb { max-height: min(60vh, 620px); overflow-y: auto; }
419
+ .cityNote .fn-lede { margin: 6px 0 0; max-width: 46ch; font-family: var(--echo-font-brand); font-size: 18px; line-height: 1.6; color: #242424; }
420
+ .cityNote .fn-lede mark { background: linear-gradient(transparent 62%, rgba(244, 168, 59, 0.45) 0); color: inherit; font-weight: 700; }
421
+ .cityShell iframe {
422
+ width: 100%;
423
+ height: 100%;
424
+ border: 0;
425
+ display: block;
426
+ border-radius: 0;
427
+ background: transparent;
428
+ }
429
+ .cityArrow {
430
+ position: absolute;
431
+ z-index: 5;
432
+ right: clamp(22px, 3vw, 42px);
433
+ bottom: clamp(22px, 3.5vh, 42px);
434
+ width: 44px;
435
+ height: 44px;
436
+ min-height: 44px;
437
+ padding: 0;
438
+ border-radius: 999px;
439
+ border-color: rgba(26, 58, 143, 0.2);
440
+ background: rgba(255, 255, 255, 0.92);
441
+ color: var(--echo-ink-primary);
442
+ font-size: 24px;
443
+ line-height: 1;
444
+ box-shadow: 0 10px 28px rgba(28, 38, 60, 0.12);
445
+ }
446
+ .detailsWrap {
447
+ width: 100%;
448
+ margin: 0;
449
+ padding: clamp(28px, 4vw, 52px) clamp(20px, 5vw, 72px);
450
+ background: var(--echo-paper-canvas);
451
+ }
452
+ #setup-details { scroll-margin-top: 0; }
453
+ .hero { padding: 4px 0 24px; }
454
+ .privacy {
455
+ display: grid;
456
+ grid-template-columns: auto 1fr;
457
+ gap: 10px;
458
+ align-items: baseline;
459
+ margin-bottom: 24px;
460
+ padding: 10px 0;
461
+ border-bottom: 1px solid var(--echo-line-soft);
462
+ }
463
+ .privacy span,
464
+ .kicker-mono,
465
+ .sectionHead span {
466
+ font-family: var(--echo-font-mono);
467
+ font-size: 12px;
468
+ font-weight: 700;
469
+ letter-spacing: 0.08em;
470
+ text-transform: uppercase;
471
+ color: var(--echo-ink-primary);
472
+ }
473
+ .privacy p { margin: 0; color: var(--echo-ink-mute); font-size: 14px; line-height: 1.55; }
474
+ .heroGrid {
475
+ display: grid;
476
+ grid-template-columns: minmax(0, 1fr) 280px;
477
+ gap: clamp(20px, 3vw, 36px);
478
+ align-items: stretch;
479
+ }
480
+ .heroCopy { display: flex; flex-direction: column; justify-content: center; }
481
+ .heroCopy .kicker-mono { margin: 0 0 14px; color: var(--echo-ink-primary); }
482
+ .heroCopy h2 {
483
+ max-width: 720px;
484
+ margin: 0;
485
+ font-size: clamp(34px, 5vw, 58px);
486
+ line-height: 1.02;
487
+ }
488
+ .heroCopy p:not(.kicker-mono) {
489
+ margin: 18px 0 0;
490
+ font-size: clamp(15px, 1.25vw, 18px);
491
+ line-height: 1.62;
492
+ color: var(--echo-ink-text);
493
+ }
494
+ .scoreCard, .promiseCard, .panel {
495
+ border: 1px solid var(--echo-line-soft);
496
+ border-radius: 8px;
497
+ background: var(--echo-paper-white);
498
+ }
499
+ .scoreCard { display: grid; align-content: center; min-height: 282px; padding: 22px; }
500
+ .scoreCard span, .promiseCard span {
501
+ font-family: var(--echo-font-mono);
502
+ font-size: 12px;
503
+ font-weight: 700;
504
+ letter-spacing: 0.08em;
505
+ text-transform: uppercase;
506
+ color: var(--echo-ink-mute);
507
+ }
508
+ .scoreCard strong {
509
+ margin-top: 12px;
510
+ font-family: var(--echo-font-brand);
511
+ font-size: clamp(72px, 8vw, 96px);
512
+ font-weight: 900;
513
+ line-height: 0.9;
514
+ color: var(--echo-ink-seal);
515
+ font-variant-numeric: tabular-nums;
516
+ }
517
+ .scoreCard em {
518
+ margin-top: 4px;
519
+ font-style: normal;
520
+ font-weight: 900;
521
+ font-size: 22px;
522
+ color: var(--echo-ink-primary);
523
+ }
524
+ .scoreCard p, .promiseCard p { margin: 14px 0 0; color: var(--echo-ink-mute); font-size: 14px; line-height: 1.55; }
525
+ .statStrip {
526
+ display: grid;
527
+ grid-template-columns: repeat(4, minmax(0, 1fr));
528
+ gap: 10px;
529
+ margin-top: 22px;
530
+ }
531
+ .stat {
532
+ min-height: 92px;
533
+ padding: 14px;
534
+ border: 1px solid var(--echo-line-soft);
535
+ border-radius: 8px;
536
+ background: var(--echo-paper-white);
537
+ }
538
+ .stat strong {
539
+ display: block;
540
+ font-family: var(--echo-font-brand);
541
+ font-size: clamp(24px, 2.8vw, 34px);
542
+ font-weight: 900;
543
+ line-height: 1;
544
+ color: var(--echo-ink-primary);
545
+ font-variant-numeric: tabular-nums;
546
+ }
547
+ .stat.alert strong { color: var(--echo-ink-seal); }
548
+ .stat span {
549
+ display: block;
550
+ margin-top: 8px;
551
+ font-family: var(--echo-font-mono);
552
+ font-size: 10px;
553
+ font-weight: 700;
554
+ letter-spacing: 0.06em;
555
+ text-transform: uppercase;
556
+ color: var(--echo-ink-mute);
557
+ }
558
+ .sourceNote {
559
+ max-width: 980px;
560
+ margin: 16px 0 0;
561
+ font-family: var(--echo-font-mono);
562
+ font-size: 11px;
563
+ line-height: 1.55;
564
+ color: var(--echo-ink-faint);
565
+ }
566
+ .sourceNote code {
567
+ padding: 1px 5px;
568
+ border-radius: 4px;
569
+ background: var(--echo-paper-soft);
570
+ color: var(--echo-ink-primary);
571
+ }
572
+ .section { padding: 30px 0 0; margin-top: 30px; border-top: 1px solid var(--echo-line-soft); }
573
+ .sectionHead { display: flex; gap: 12px; align-items: baseline; margin-bottom: 18px; }
574
+ .sectionHead h2 { margin: 0; font-size: clamp(24px, 3.4vw, 38px); line-height: 1.05; }
575
+ .twoCol {
576
+ display: grid;
577
+ grid-template-columns: minmax(0, 1fr) minmax(340px, 0.8fr);
578
+ gap: clamp(20px, 3.5vw, 36px);
579
+ align-items: start;
580
+ }
581
+ .storyText p { margin: 0 0 18px; color: var(--echo-ink-text); font-size: clamp(15px, 1.25vw, 18px); line-height: 1.62; }
582
+ .storyText p:last-child { margin-bottom: 0; }
583
+ .storyText b { color: var(--echo-ink-primary); }
584
+ .panel { display: grid; gap: 12px; padding: 16px; }
585
+ .promiseCard { padding: 22px; }
586
+ .promiseCard strong {
587
+ display: block;
588
+ margin-top: 12px;
589
+ font-family: var(--echo-font-brand);
590
+ font-size: clamp(34px, 4vw, 48px);
591
+ font-weight: 900;
592
+ line-height: 1;
593
+ color: var(--echo-ink-primary);
594
+ }
595
+ .promiseActions { display: grid; gap: 10px; margin-top: 18px; }
596
+ .promiseCard button, .promiseCard .button {
597
+ width: 100%;
598
+ min-height: 48px;
599
+ border-radius: 6px;
600
+ font-family: var(--echo-font-mono);
601
+ font-size: 13px;
602
+ font-weight: 800;
603
+ letter-spacing: 0.08em;
604
+ text-transform: uppercase;
605
+ }
606
+ .promiseCard .primary { border-color: var(--echo-ink-primary); background: var(--echo-ink-primary); color: #fff; }
607
+ .promiseCard .secondary { background: #fff; color: var(--echo-ink-primary); border-color: var(--echo-ink-primary); }
608
+
609
+ /* histogram */
610
+ .histo { display: flex; align-items: flex-end; gap: 3px; height: 120px; padding-top: 8px; }
611
+ .histoBar { flex: 1; min-height: 2px; border-radius: 2px 2px 0 0; background: var(--echo-ink-primary); }
612
+ .histoBar.night { background: var(--echo-ink-seal); }
613
+ .histoAxis {
614
+ display: flex; justify-content: space-between; margin-top: 8px;
615
+ font-family: var(--echo-font-mono); font-size: 10px; letter-spacing: 0.06em; color: var(--echo-ink-faint);
616
+ }
617
+ .chips { display: flex; flex-wrap: wrap; gap: 8px; }
618
+ .chips span {
619
+ padding: 6px 8px; border: 1px solid var(--echo-line-soft); border-radius: 6px;
620
+ background: var(--echo-paper-soft); font-family: var(--echo-font-mono); font-size: 11px; color: var(--echo-ink-primary);
621
+ }
622
+
623
+ /* reread / repo rows */
624
+ .row2 {
625
+ display: grid; grid-template-columns: 1fr auto; gap: 12px; align-items: baseline;
626
+ padding: 11px 0; border-bottom: 1px solid var(--echo-line-soft);
627
+ }
628
+ .row2:last-child { border-bottom: 0; }
629
+ .row2 b { font-family: var(--echo-font-mono); font-size: 13px; color: var(--echo-ink-primary); }
630
+ .row2 small { display: block; margin-top: 3px; font-size: 12px; color: var(--echo-ink-mute); }
631
+ .row2 strong {
632
+ font-family: var(--echo-font-brand); font-size: 24px; font-weight: 900;
633
+ color: var(--echo-ink-seal); font-variant-numeric: tabular-nums; white-space: nowrap;
634
+ }
635
+ .repoRow strong { color: var(--echo-ink-primary); }
636
+ .tag {
637
+ display: inline-block; margin-left: 8px; padding: 2px 7px; border-radius: 999px;
638
+ background: var(--echo-paper-soft); font-family: var(--echo-font-mono); font-size: 10px;
639
+ font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--echo-ink-seal);
640
+ }
641
+
642
+ /* cost split + model rows */
643
+ .segBar { display: flex; width: 100%; height: 22px; overflow: hidden; border-radius: 5px; background: var(--echo-paper-soft); }
644
+ .segBar span { display: block; min-width: 2px; }
645
+ .seg-output { background: var(--echo-ink-primary); }
646
+ .seg-cold { background: var(--echo-ink-mute); }
647
+ .seg-cw { background: var(--echo-ink-accent); }
648
+ .seg-cr { background: var(--echo-ink-seal); }
649
+ .ctxFacts {
650
+ display: grid;
651
+ grid-template-columns: repeat(2, minmax(0, 1fr));
652
+ gap: 10px;
653
+ margin-top: 16px;
654
+ }
655
+ .ctxFacts div {
656
+ min-height: 58px;
657
+ padding: 10px 12px;
658
+ border: 1px solid var(--echo-line-soft);
659
+ border-radius: 6px;
660
+ background: var(--echo-paper-soft);
661
+ }
662
+ .ctxFacts span {
663
+ display: block;
664
+ font-family: var(--echo-font-mono);
665
+ font-size: 10px;
666
+ font-weight: 800;
667
+ letter-spacing: 0.06em;
668
+ text-transform: uppercase;
669
+ color: var(--echo-ink-mute);
670
+ }
671
+ .ctxFacts strong {
672
+ display: block;
673
+ margin-top: 5px;
674
+ font-family: var(--echo-font-mono);
675
+ font-size: 12px;
676
+ line-height: 1.35;
677
+ color: var(--echo-ink-primary);
678
+ }
679
+ .costLegend { display: grid; gap: 6px; font-family: var(--echo-font-mono); font-size: 11px; color: var(--echo-ink-mute); }
680
+ .modelRow {
681
+ display: grid; grid-template-columns: 1fr auto auto; gap: 12px; align-items: baseline;
682
+ padding: 9px 0; border-bottom: 1px solid var(--echo-line-soft);
683
+ font-family: var(--echo-font-mono); font-size: 12px; color: var(--echo-ink-mute);
684
+ }
685
+ .modelRow:last-child { border-bottom: 0; }
686
+ .modelRow b { font-size: 13px; color: var(--echo-ink-primary); }
687
+ .modelRow strong { font-family: var(--echo-font-brand); font-size: 18px; font-weight: 900; color: var(--echo-ink-seal); }
688
+
689
+ .nightCard {
690
+ margin-top: 18px; padding: 20px 22px; border: 1px solid var(--echo-ink-seal);
691
+ border-radius: 8px; background: var(--echo-paper-white);
692
+ }
693
+ .nightCard span {
694
+ font-family: var(--echo-font-mono); font-size: 11px; font-weight: 700; letter-spacing: 0.08em;
695
+ text-transform: uppercase; color: var(--echo-ink-seal);
696
+ }
697
+ .nightCard p { margin: 10px 0 0; font-size: 17px; line-height: 1.5; color: var(--echo-ink-text); }
698
+ .nightCard b { color: var(--echo-ink-primary); }
699
+
700
+ /* optional city explanation page */
701
+ .explainPage {
702
+ max-width: 1260px;
703
+ margin: 0 auto;
704
+ }
705
+ .explainHero {
706
+ display: grid;
707
+ grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
708
+ gap: clamp(28px, 5vw, 70px);
709
+ align-items: end;
710
+ padding-bottom: clamp(28px, 5vw, 58px);
711
+ border-bottom: 1px solid var(--echo-line-soft);
712
+ }
713
+ .explainCopy {
714
+ max-width: 760px;
715
+ }
716
+ .explainCopy h2 {
717
+ margin: 10px 0 0;
718
+ font-size: clamp(38px, 5.4vw, 74px);
719
+ line-height: 0.98;
720
+ color: var(--echo-ink-primary);
721
+ }
722
+ .explainCopy p:not(.kicker-mono) {
723
+ max-width: 680px;
724
+ margin: 20px 0 0;
725
+ font-size: clamp(16px, 1.35vw, 20px);
726
+ line-height: 1.55;
727
+ color: var(--echo-ink-text);
728
+ }
729
+ .cleanReadout {
730
+ border: 1px solid var(--echo-line-soft);
731
+ border-radius: 8px;
732
+ padding: 22px;
733
+ background: #fff;
734
+ }
735
+ .cleanReadout span {
736
+ display: block;
737
+ font-family: var(--echo-font-mono);
738
+ font-size: 11px;
739
+ font-weight: 800;
740
+ letter-spacing: 0.08em;
741
+ text-transform: uppercase;
742
+ color: var(--echo-ink-mute);
743
+ }
744
+ .cleanReadout strong {
745
+ display: block;
746
+ margin-top: 8px;
747
+ font-family: var(--echo-font-brand);
748
+ font-size: clamp(54px, 6vw, 88px);
749
+ font-weight: 900;
750
+ line-height: 0.9;
751
+ color: var(--echo-ink-seal);
752
+ font-variant-numeric: tabular-nums;
753
+ }
754
+ .cleanReadout p {
755
+ margin: 14px 0 0;
756
+ color: var(--echo-ink-mute);
757
+ font-size: 15px;
758
+ line-height: 1.55;
759
+ }
760
+ .insightPills {
761
+ display: grid;
762
+ grid-template-columns: repeat(3, minmax(0, 1fr));
763
+ gap: 10px;
764
+ margin-top: clamp(18px, 3vw, 32px);
765
+ }
766
+ .insightPill {
767
+ border: 1px solid var(--echo-line-soft);
768
+ border-radius: 8px;
769
+ padding: 14px 16px;
770
+ background: #fff;
771
+ }
772
+ .insightPill strong {
773
+ display: block;
774
+ font-family: var(--echo-font-brand);
775
+ font-size: clamp(24px, 2.2vw, 34px);
776
+ font-weight: 900;
777
+ line-height: 1;
778
+ color: var(--echo-ink-primary);
779
+ font-variant-numeric: tabular-nums;
780
+ }
781
+ .insightPill.alert strong { color: var(--echo-ink-seal); }
782
+ .insightPill span {
783
+ display: block;
784
+ margin-top: 8px;
785
+ font-family: var(--echo-font-mono);
786
+ font-size: 10px;
787
+ font-weight: 800;
788
+ letter-spacing: 0.07em;
789
+ text-transform: uppercase;
790
+ color: var(--echo-ink-mute);
791
+ }
792
+ .calcNote {
793
+ margin-top: 18px;
794
+ border-top: 1px solid var(--echo-line-soft);
795
+ padding-top: 14px;
796
+ color: var(--echo-ink-faint);
797
+ font-family: var(--echo-font-mono);
798
+ font-size: 11px;
799
+ line-height: 1.6;
800
+ }
801
+ .calcNote summary {
802
+ cursor: pointer;
803
+ color: var(--echo-ink-primary);
804
+ font-weight: 800;
805
+ text-transform: uppercase;
806
+ letter-spacing: 0.06em;
807
+ }
808
+ .calcNote p { margin: 10px 0 0; }
809
+ .explainSections {
810
+ display: grid;
811
+ grid-template-columns: repeat(3, minmax(0, 1fr));
812
+ gap: 14px;
813
+ margin-top: clamp(28px, 4vw, 52px);
814
+ }
815
+ .explainCard {
816
+ border: 1px solid var(--echo-line-soft);
817
+ border-radius: 8px;
818
+ background: #fff;
819
+ padding: 18px;
820
+ min-height: 230px;
821
+ display: grid;
822
+ gap: 14px;
823
+ align-content: start;
824
+ }
825
+ .explainCard .kicker-mono { margin: 0; color: var(--echo-ink-mute); }
826
+ .explainCard h3 {
827
+ margin: 0;
828
+ font-family: var(--echo-font-brand);
829
+ font-size: clamp(21px, 2vw, 28px);
830
+ line-height: 1.08;
831
+ color: var(--echo-ink-primary);
832
+ }
833
+ .explainCard p {
834
+ margin: 0;
835
+ color: var(--echo-ink-text);
836
+ font-size: 15px;
837
+ line-height: 1.55;
838
+ }
839
+ .explainCard .panel {
840
+ padding: 0;
841
+ border: 0;
842
+ background: transparent;
843
+ }
844
+ .explainCta {
845
+ display: grid;
846
+ grid-template-columns: minmax(0, 1fr) auto;
847
+ gap: 24px;
848
+ align-items: center;
849
+ margin-top: 16px;
850
+ padding: 22px;
851
+ border: 1px solid var(--echo-line-soft);
852
+ border-radius: 8px;
853
+ background: var(--echo-paper-canvas);
854
+ }
855
+ .explainCta h3 {
856
+ margin: 0;
857
+ font-family: var(--echo-font-brand);
858
+ font-size: clamp(24px, 2.5vw, 34px);
859
+ line-height: 1.08;
860
+ color: var(--echo-ink-primary);
861
+ }
862
+ .explainCta p {
863
+ margin: 8px 0 0;
864
+ max-width: 700px;
865
+ color: var(--echo-ink-mute);
866
+ font-size: 15px;
867
+ line-height: 1.5;
868
+ }
869
+ .explainCta .primary, .explainCta .secondary {
870
+ min-width: 180px;
871
+ min-height: 50px;
872
+ border-radius: 8px;
873
+ font-family: var(--echo-font-mono);
874
+ font-size: 13px;
875
+ font-weight: 800;
876
+ letter-spacing: 0.08em;
877
+ text-transform: uppercase;
878
+ }
879
+
880
+ `;