answerlint 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +558 -0
- package/assets/overview.png +0 -0
- package/assets/report-hero.png +0 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +89065 -0
- package/package.json +74 -0
- package/templates/report.hbs +929 -0
|
@@ -0,0 +1,929 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>answerlint Report — {{report.url}}</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--bg: #f8f9fa;
|
|
10
|
+
--surface: #ffffff;
|
|
11
|
+
--border: #e0e0e0;
|
|
12
|
+
--text: #1a1a1a;
|
|
13
|
+
--text-secondary: #5f6368;
|
|
14
|
+
--pass: #0cce6b;
|
|
15
|
+
--fail: #ff4e42;
|
|
16
|
+
--warn: #ffa400;
|
|
17
|
+
--poor: #ff4e42;
|
|
18
|
+
--needs-improvement: #ffa400;
|
|
19
|
+
--good: #0cce6b;
|
|
20
|
+
--excellent: #0cce6b;
|
|
21
|
+
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
22
|
+
--mono: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
|
|
23
|
+
--radius: 8px;
|
|
24
|
+
--shadow: 0 1px 3px rgba(0,0,0,.12), 0 1px 2px rgba(0,0,0,.08);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
28
|
+
|
|
29
|
+
body {
|
|
30
|
+
font-family: var(--font);
|
|
31
|
+
background: var(--bg);
|
|
32
|
+
color: var(--text);
|
|
33
|
+
line-height: 1.6;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* ── HEADER ── */
|
|
37
|
+
.header {
|
|
38
|
+
background: #1a1a2e;
|
|
39
|
+
color: #fff;
|
|
40
|
+
padding: 20px 0;
|
|
41
|
+
}
|
|
42
|
+
.header-inner {
|
|
43
|
+
max-width: 1080px;
|
|
44
|
+
margin: 0 auto;
|
|
45
|
+
padding: 0 24px;
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
gap: 16px;
|
|
49
|
+
}
|
|
50
|
+
.logo { font-size: 1.4rem; font-weight: 700; letter-spacing: -0.5px; }
|
|
51
|
+
.logo span { color: #7c3aed; }
|
|
52
|
+
.header-url {
|
|
53
|
+
font-size: .85rem;
|
|
54
|
+
color: rgba(255,255,255,.6);
|
|
55
|
+
word-break: break-all;
|
|
56
|
+
}
|
|
57
|
+
.header-meta {
|
|
58
|
+
margin-left: auto;
|
|
59
|
+
text-align: right;
|
|
60
|
+
font-size: .8rem;
|
|
61
|
+
color: rgba(255,255,255,.5);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* ── LAYOUT ── */
|
|
65
|
+
.container { max-width: 1080px; margin: 0 auto; padding: 32px 24px; }
|
|
66
|
+
|
|
67
|
+
/* ── SCORE SUMMARY ── */
|
|
68
|
+
.score-summary {
|
|
69
|
+
background: var(--surface);
|
|
70
|
+
border-radius: var(--radius);
|
|
71
|
+
box-shadow: var(--shadow);
|
|
72
|
+
padding: 32px;
|
|
73
|
+
margin-bottom: 32px;
|
|
74
|
+
display: grid;
|
|
75
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
76
|
+
gap: 32px;
|
|
77
|
+
align-items: center;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.gauge-wrap {
|
|
81
|
+
display: flex;
|
|
82
|
+
flex-direction: column;
|
|
83
|
+
align-items: center;
|
|
84
|
+
gap: 8px;
|
|
85
|
+
}
|
|
86
|
+
.gauge-wrap.composite { grid-column: 1; }
|
|
87
|
+
|
|
88
|
+
.gauge-label {
|
|
89
|
+
font-size: .75rem;
|
|
90
|
+
font-weight: 600;
|
|
91
|
+
text-transform: uppercase;
|
|
92
|
+
letter-spacing: .08em;
|
|
93
|
+
color: var(--text-secondary);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.gauge {
|
|
97
|
+
position: relative;
|
|
98
|
+
width: 140px;
|
|
99
|
+
height: 140px;
|
|
100
|
+
}
|
|
101
|
+
.gauge svg { transform: rotate(-90deg); }
|
|
102
|
+
.gauge-track { fill: none; stroke: #e8eaed; stroke-width: 8; }
|
|
103
|
+
.gauge-fill { fill: none; stroke-width: 8; stroke-linecap: round; transition: stroke-dashoffset .6s ease; }
|
|
104
|
+
.gauge-score {
|
|
105
|
+
position: absolute;
|
|
106
|
+
inset: 0;
|
|
107
|
+
display: flex;
|
|
108
|
+
flex-direction: column;
|
|
109
|
+
align-items: center;
|
|
110
|
+
justify-content: center;
|
|
111
|
+
}
|
|
112
|
+
.gauge-number {
|
|
113
|
+
font-size: 2.2rem;
|
|
114
|
+
font-weight: 700;
|
|
115
|
+
line-height: 1;
|
|
116
|
+
}
|
|
117
|
+
.gauge-band {
|
|
118
|
+
font-size: .7rem;
|
|
119
|
+
font-weight: 600;
|
|
120
|
+
text-transform: uppercase;
|
|
121
|
+
letter-spacing: .06em;
|
|
122
|
+
margin-top: 2px;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.gauge.small { width: 100px; height: 100px; }
|
|
126
|
+
.gauge.small .gauge-number { font-size: 1.6rem; }
|
|
127
|
+
.gauge.small .gauge-band { font-size: .6rem; }
|
|
128
|
+
|
|
129
|
+
.sub-scores {
|
|
130
|
+
display: flex;
|
|
131
|
+
flex-direction: column;
|
|
132
|
+
gap: 24px;
|
|
133
|
+
grid-column: 2 / 4;
|
|
134
|
+
}
|
|
135
|
+
.sub-score-row {
|
|
136
|
+
display: flex;
|
|
137
|
+
align-items: center;
|
|
138
|
+
gap: 16px;
|
|
139
|
+
}
|
|
140
|
+
.sub-score-info { flex: 1; }
|
|
141
|
+
.sub-score-name { font-size: .9rem; font-weight: 600; }
|
|
142
|
+
.sub-score-desc { font-size: .78rem; color: var(--text-secondary); }
|
|
143
|
+
.progress-bar-wrap { width: 220px; }
|
|
144
|
+
.progress-bar {
|
|
145
|
+
height: 8px;
|
|
146
|
+
background: #e8eaed;
|
|
147
|
+
border-radius: 4px;
|
|
148
|
+
overflow: hidden;
|
|
149
|
+
}
|
|
150
|
+
.progress-bar-fill {
|
|
151
|
+
height: 100%;
|
|
152
|
+
border-radius: 4px;
|
|
153
|
+
transition: width .6s ease;
|
|
154
|
+
}
|
|
155
|
+
.progress-label {
|
|
156
|
+
font-size: .8rem;
|
|
157
|
+
font-weight: 600;
|
|
158
|
+
margin-top: 4px;
|
|
159
|
+
text-align: right;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* COMPARISON */
|
|
163
|
+
.comparison-brief {
|
|
164
|
+
display: grid;
|
|
165
|
+
grid-template-columns: minmax(220px, .8fr) 1.2fr;
|
|
166
|
+
gap: 20px;
|
|
167
|
+
padding: 24px;
|
|
168
|
+
border-bottom: 1px solid var(--border);
|
|
169
|
+
background: #fbfcff;
|
|
170
|
+
}
|
|
171
|
+
.comparison-leader {
|
|
172
|
+
border: 1px solid var(--border);
|
|
173
|
+
border-radius: var(--radius);
|
|
174
|
+
padding: 18px;
|
|
175
|
+
background: #fff;
|
|
176
|
+
}
|
|
177
|
+
.comparison-kicker {
|
|
178
|
+
font-size: .7rem;
|
|
179
|
+
font-weight: 800;
|
|
180
|
+
letter-spacing: .08em;
|
|
181
|
+
text-transform: uppercase;
|
|
182
|
+
color: var(--text-secondary);
|
|
183
|
+
margin-bottom: 8px;
|
|
184
|
+
}
|
|
185
|
+
.comparison-leader-title {
|
|
186
|
+
font-size: 1.45rem;
|
|
187
|
+
font-weight: 800;
|
|
188
|
+
line-height: 1.1;
|
|
189
|
+
margin-bottom: 8px;
|
|
190
|
+
}
|
|
191
|
+
.comparison-gap {
|
|
192
|
+
display: inline-flex;
|
|
193
|
+
align-items: baseline;
|
|
194
|
+
gap: 4px;
|
|
195
|
+
padding: 5px 9px;
|
|
196
|
+
border-radius: 999px;
|
|
197
|
+
background: #f1f3f4;
|
|
198
|
+
font-weight: 800;
|
|
199
|
+
margin-bottom: 12px;
|
|
200
|
+
}
|
|
201
|
+
.comparison-gap strong { font-size: 1.35rem; line-height: 1; }
|
|
202
|
+
.comparison-summary {
|
|
203
|
+
font-size: .86rem;
|
|
204
|
+
color: var(--text-secondary);
|
|
205
|
+
line-height: 1.45;
|
|
206
|
+
}
|
|
207
|
+
.comparison-now {
|
|
208
|
+
display: grid;
|
|
209
|
+
grid-template-columns: 1fr 1fr;
|
|
210
|
+
gap: 14px;
|
|
211
|
+
}
|
|
212
|
+
.comparison-now-panel {
|
|
213
|
+
border: 1px solid var(--border);
|
|
214
|
+
border-radius: var(--radius);
|
|
215
|
+
background: #fff;
|
|
216
|
+
padding: 16px;
|
|
217
|
+
min-width: 0;
|
|
218
|
+
}
|
|
219
|
+
.comparison-panel-title {
|
|
220
|
+
font-size: .82rem;
|
|
221
|
+
font-weight: 800;
|
|
222
|
+
margin-bottom: 10px;
|
|
223
|
+
}
|
|
224
|
+
.comparison-action-list {
|
|
225
|
+
list-style: none;
|
|
226
|
+
display: flex;
|
|
227
|
+
flex-direction: column;
|
|
228
|
+
gap: 9px;
|
|
229
|
+
font-size: .84rem;
|
|
230
|
+
color: var(--text);
|
|
231
|
+
}
|
|
232
|
+
.comparison-action-list li {
|
|
233
|
+
display: grid;
|
|
234
|
+
grid-template-columns: auto 1fr;
|
|
235
|
+
gap: 8px;
|
|
236
|
+
align-items: start;
|
|
237
|
+
}
|
|
238
|
+
.comparison-rank {
|
|
239
|
+
display: inline-flex;
|
|
240
|
+
align-items: center;
|
|
241
|
+
justify-content: center;
|
|
242
|
+
width: 20px;
|
|
243
|
+
height: 20px;
|
|
244
|
+
border-radius: 50%;
|
|
245
|
+
background: #fef7e0;
|
|
246
|
+
color: #b06000;
|
|
247
|
+
font-size: .72rem;
|
|
248
|
+
font-weight: 800;
|
|
249
|
+
line-height: 1;
|
|
250
|
+
}
|
|
251
|
+
.comparison-action-meta {
|
|
252
|
+
display: block;
|
|
253
|
+
margin-top: 2px;
|
|
254
|
+
color: var(--text-secondary);
|
|
255
|
+
font-size: .74rem;
|
|
256
|
+
line-height: 1.35;
|
|
257
|
+
}
|
|
258
|
+
.comparison-grid {
|
|
259
|
+
display: grid;
|
|
260
|
+
grid-template-columns: repeat(3, 1fr);
|
|
261
|
+
gap: 16px;
|
|
262
|
+
padding: 24px;
|
|
263
|
+
border-bottom: 1px solid var(--border);
|
|
264
|
+
}
|
|
265
|
+
.comparison-metric {
|
|
266
|
+
border: 1px solid var(--border);
|
|
267
|
+
border-radius: var(--radius);
|
|
268
|
+
padding: 16px;
|
|
269
|
+
background: #fff;
|
|
270
|
+
}
|
|
271
|
+
.comparison-label {
|
|
272
|
+
font-size: .72rem;
|
|
273
|
+
font-weight: 700;
|
|
274
|
+
color: var(--text-secondary);
|
|
275
|
+
letter-spacing: .08em;
|
|
276
|
+
text-transform: uppercase;
|
|
277
|
+
margin-bottom: 8px;
|
|
278
|
+
}
|
|
279
|
+
.comparison-values {
|
|
280
|
+
display: flex;
|
|
281
|
+
align-items: baseline;
|
|
282
|
+
gap: 8px;
|
|
283
|
+
font-size: .9rem;
|
|
284
|
+
color: var(--text-secondary);
|
|
285
|
+
}
|
|
286
|
+
.comparison-values strong {
|
|
287
|
+
font-size: 1.8rem;
|
|
288
|
+
color: var(--text);
|
|
289
|
+
line-height: 1;
|
|
290
|
+
}
|
|
291
|
+
.comparison-bar {
|
|
292
|
+
margin-top: 14px;
|
|
293
|
+
display: flex;
|
|
294
|
+
flex-direction: column;
|
|
295
|
+
gap: 7px;
|
|
296
|
+
}
|
|
297
|
+
.comparison-bar-row {
|
|
298
|
+
display: grid;
|
|
299
|
+
grid-template-columns: 74px 1fr 32px;
|
|
300
|
+
gap: 8px;
|
|
301
|
+
align-items: center;
|
|
302
|
+
font-size: .73rem;
|
|
303
|
+
color: var(--text-secondary);
|
|
304
|
+
}
|
|
305
|
+
.comparison-bar-track {
|
|
306
|
+
height: 7px;
|
|
307
|
+
border-radius: 999px;
|
|
308
|
+
background: #e8eaed;
|
|
309
|
+
overflow: hidden;
|
|
310
|
+
}
|
|
311
|
+
.comparison-bar-fill {
|
|
312
|
+
height: 100%;
|
|
313
|
+
border-radius: 999px;
|
|
314
|
+
background: #1a73e8;
|
|
315
|
+
}
|
|
316
|
+
.comparison-bar-fill.competitor { background: #c2185b; }
|
|
317
|
+
.delta-positive { color: var(--pass); font-weight: 700; }
|
|
318
|
+
.delta-negative { color: var(--fail); font-weight: 700; }
|
|
319
|
+
.delta-neutral { color: var(--text-secondary); font-weight: 700; }
|
|
320
|
+
.comparison-columns {
|
|
321
|
+
display: grid;
|
|
322
|
+
grid-template-columns: 1fr 1fr;
|
|
323
|
+
gap: 24px;
|
|
324
|
+
padding: 24px;
|
|
325
|
+
}
|
|
326
|
+
.comparison-column-title {
|
|
327
|
+
font-size: .85rem;
|
|
328
|
+
font-weight: 700;
|
|
329
|
+
margin-bottom: 12px;
|
|
330
|
+
}
|
|
331
|
+
.comparison-column-subtitle {
|
|
332
|
+
font-size: .76rem;
|
|
333
|
+
color: var(--text-secondary);
|
|
334
|
+
margin: -6px 0 12px;
|
|
335
|
+
line-height: 1.45;
|
|
336
|
+
}
|
|
337
|
+
.comparison-list {
|
|
338
|
+
list-style: none;
|
|
339
|
+
display: flex;
|
|
340
|
+
flex-direction: column;
|
|
341
|
+
gap: 8px;
|
|
342
|
+
font-size: .84rem;
|
|
343
|
+
color: var(--text);
|
|
344
|
+
}
|
|
345
|
+
.comparison-list li {
|
|
346
|
+
padding: 10px 12px;
|
|
347
|
+
background: #f8f9fa;
|
|
348
|
+
border-radius: 4px;
|
|
349
|
+
border-left: 3px solid var(--border);
|
|
350
|
+
}
|
|
351
|
+
.comparison-list-title {
|
|
352
|
+
display: flex;
|
|
353
|
+
align-items: center;
|
|
354
|
+
gap: 8px;
|
|
355
|
+
font-weight: 700;
|
|
356
|
+
margin-bottom: 4px;
|
|
357
|
+
}
|
|
358
|
+
.comparison-list-body {
|
|
359
|
+
color: var(--text-secondary);
|
|
360
|
+
line-height: 1.45;
|
|
361
|
+
}
|
|
362
|
+
.comparison-pill {
|
|
363
|
+
display: inline-flex;
|
|
364
|
+
align-items: center;
|
|
365
|
+
padding: 1px 7px;
|
|
366
|
+
border-radius: 999px;
|
|
367
|
+
background: #e8f0fe;
|
|
368
|
+
color: #1a73e8;
|
|
369
|
+
font-size: .68rem;
|
|
370
|
+
font-weight: 800;
|
|
371
|
+
text-transform: uppercase;
|
|
372
|
+
letter-spacing: .04em;
|
|
373
|
+
}
|
|
374
|
+
.comparison-pill.high { background: #fce8e6; color: #c5221f; }
|
|
375
|
+
.comparison-pill.medium { background: #fef7e0; color: #b06000; }
|
|
376
|
+
.comparison-pill.low { background: #e8f0fe; color: #1a73e8; }
|
|
377
|
+
|
|
378
|
+
/* ── SECTION CARDS ── */
|
|
379
|
+
.section {
|
|
380
|
+
background: var(--surface);
|
|
381
|
+
border-radius: var(--radius);
|
|
382
|
+
box-shadow: var(--shadow);
|
|
383
|
+
margin-bottom: 24px;
|
|
384
|
+
overflow: hidden;
|
|
385
|
+
}
|
|
386
|
+
.section-header {
|
|
387
|
+
display: flex;
|
|
388
|
+
align-items: center;
|
|
389
|
+
gap: 12px;
|
|
390
|
+
padding: 16px 24px;
|
|
391
|
+
cursor: pointer;
|
|
392
|
+
user-select: none;
|
|
393
|
+
border-bottom: 1px solid var(--border);
|
|
394
|
+
}
|
|
395
|
+
.section-header:hover { background: #f5f5f5; }
|
|
396
|
+
.section-title { font-size: 1rem; font-weight: 600; }
|
|
397
|
+
.section-count {
|
|
398
|
+
font-size: .75rem;
|
|
399
|
+
font-weight: 600;
|
|
400
|
+
padding: 2px 8px;
|
|
401
|
+
border-radius: 12px;
|
|
402
|
+
background: #e8eaed;
|
|
403
|
+
color: var(--text-secondary);
|
|
404
|
+
}
|
|
405
|
+
.section-count.fail-count { background: #fce8e6; color: var(--fail); }
|
|
406
|
+
.section-count.pass-count { background: #e6f4ea; color: var(--pass); }
|
|
407
|
+
.chevron {
|
|
408
|
+
margin-left: auto;
|
|
409
|
+
font-size: 1rem;
|
|
410
|
+
color: var(--text-secondary);
|
|
411
|
+
transition: transform .2s;
|
|
412
|
+
}
|
|
413
|
+
.section-body { padding: 0; }
|
|
414
|
+
.section-body.collapsed { display: none; }
|
|
415
|
+
|
|
416
|
+
/* ── AUDIT ROWS ── */
|
|
417
|
+
.audit-item {
|
|
418
|
+
padding: 20px 24px;
|
|
419
|
+
border-bottom: 1px solid var(--border);
|
|
420
|
+
}
|
|
421
|
+
.audit-item:last-child { border-bottom: none; }
|
|
422
|
+
|
|
423
|
+
.audit-header {
|
|
424
|
+
display: flex;
|
|
425
|
+
align-items: flex-start;
|
|
426
|
+
gap: 12px;
|
|
427
|
+
margin-bottom: 8px;
|
|
428
|
+
}
|
|
429
|
+
.audit-status-badge {
|
|
430
|
+
flex-shrink: 0;
|
|
431
|
+
font-size: .7rem;
|
|
432
|
+
font-weight: 700;
|
|
433
|
+
padding: 3px 8px;
|
|
434
|
+
border-radius: 4px;
|
|
435
|
+
text-transform: uppercase;
|
|
436
|
+
letter-spacing: .06em;
|
|
437
|
+
margin-top: 2px;
|
|
438
|
+
}
|
|
439
|
+
.badge-pass { background: #e6f4ea; color: #137333; }
|
|
440
|
+
.badge-fail { background: #fce8e6; color: #c5221f; }
|
|
441
|
+
.badge-warn { background: #fef7e0; color: #b06000; }
|
|
442
|
+
|
|
443
|
+
.audit-title { font-size: .95rem; font-weight: 600; flex: 1; }
|
|
444
|
+
.audit-category-tag {
|
|
445
|
+
font-size: .68rem;
|
|
446
|
+
font-weight: 700;
|
|
447
|
+
padding: 2px 7px;
|
|
448
|
+
border-radius: 10px;
|
|
449
|
+
text-transform: uppercase;
|
|
450
|
+
letter-spacing: .06em;
|
|
451
|
+
flex-shrink: 0;
|
|
452
|
+
}
|
|
453
|
+
.tag-aeo { background: #e8f0fe; color: #1a73e8; }
|
|
454
|
+
.tag-geo { background: #fce4ec; color: #c2185b; }
|
|
455
|
+
|
|
456
|
+
.audit-evidence {
|
|
457
|
+
font-size: .82rem;
|
|
458
|
+
color: var(--text-secondary);
|
|
459
|
+
padding: 8px 12px;
|
|
460
|
+
background: #f8f9fa;
|
|
461
|
+
border-radius: 4px;
|
|
462
|
+
border-left: 3px solid var(--border);
|
|
463
|
+
margin: 8px 0;
|
|
464
|
+
font-family: var(--mono);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/* ── RECOMMENDATION BLOCK ── */
|
|
468
|
+
.recommendation {
|
|
469
|
+
margin-top: 16px;
|
|
470
|
+
border: 1px solid var(--border);
|
|
471
|
+
border-radius: var(--radius);
|
|
472
|
+
overflow: hidden;
|
|
473
|
+
}
|
|
474
|
+
.rec-header {
|
|
475
|
+
display: flex;
|
|
476
|
+
align-items: center;
|
|
477
|
+
gap: 10px;
|
|
478
|
+
padding: 10px 16px;
|
|
479
|
+
background: #f8f9fa;
|
|
480
|
+
border-bottom: 1px solid var(--border);
|
|
481
|
+
}
|
|
482
|
+
.rec-header-title { font-size: .8rem; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--text-secondary); }
|
|
483
|
+
.priority-badge {
|
|
484
|
+
font-size: .68rem;
|
|
485
|
+
font-weight: 700;
|
|
486
|
+
padding: 2px 8px;
|
|
487
|
+
border-radius: 10px;
|
|
488
|
+
text-transform: uppercase;
|
|
489
|
+
letter-spacing: .06em;
|
|
490
|
+
}
|
|
491
|
+
.priority-high { background: #fce8e6; color: #c5221f; }
|
|
492
|
+
.priority-medium { background: #fef7e0; color: #b06000; }
|
|
493
|
+
.priority-low { background: #e8f0fe; color: #1a73e8; }
|
|
494
|
+
|
|
495
|
+
.score-impact {
|
|
496
|
+
margin-left: auto;
|
|
497
|
+
font-size: .78rem;
|
|
498
|
+
font-weight: 600;
|
|
499
|
+
color: var(--pass);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
.rec-body { padding: 14px 16px; }
|
|
503
|
+
.rec-instruction {
|
|
504
|
+
font-size: .88rem;
|
|
505
|
+
color: var(--text);
|
|
506
|
+
margin-bottom: 12px;
|
|
507
|
+
line-height: 1.6;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.code-block {
|
|
511
|
+
background: #1a1a2e;
|
|
512
|
+
color: #e8e8e8;
|
|
513
|
+
border-radius: 6px;
|
|
514
|
+
overflow: hidden;
|
|
515
|
+
}
|
|
516
|
+
.code-block-header {
|
|
517
|
+
display: flex;
|
|
518
|
+
align-items: center;
|
|
519
|
+
padding: 8px 14px;
|
|
520
|
+
background: rgba(255,255,255,.05);
|
|
521
|
+
border-bottom: 1px solid rgba(255,255,255,.1);
|
|
522
|
+
font-size: .72rem;
|
|
523
|
+
color: rgba(255,255,255,.5);
|
|
524
|
+
font-family: var(--mono);
|
|
525
|
+
}
|
|
526
|
+
.copy-btn {
|
|
527
|
+
margin-left: auto;
|
|
528
|
+
background: rgba(255,255,255,.1);
|
|
529
|
+
border: none;
|
|
530
|
+
color: rgba(255,255,255,.7);
|
|
531
|
+
font-size: .72rem;
|
|
532
|
+
padding: 3px 8px;
|
|
533
|
+
border-radius: 4px;
|
|
534
|
+
cursor: pointer;
|
|
535
|
+
font-family: var(--font);
|
|
536
|
+
}
|
|
537
|
+
.copy-btn:hover { background: rgba(255,255,255,.2); }
|
|
538
|
+
.code-block pre {
|
|
539
|
+
padding: 14px;
|
|
540
|
+
font-size: .82rem;
|
|
541
|
+
font-family: var(--mono);
|
|
542
|
+
white-space: pre;
|
|
543
|
+
overflow-x: auto;
|
|
544
|
+
line-height: 1.5;
|
|
545
|
+
color: #e8e8e8;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/* ── PASSED SECTION ── */
|
|
549
|
+
.passed-section .section-header { cursor: pointer; }
|
|
550
|
+
.audit-item.passed .audit-title { color: var(--text-secondary); }
|
|
551
|
+
|
|
552
|
+
/* ── FOOTER ── */
|
|
553
|
+
.footer {
|
|
554
|
+
text-align: center;
|
|
555
|
+
padding: 32px 24px;
|
|
556
|
+
color: var(--text-secondary);
|
|
557
|
+
font-size: .8rem;
|
|
558
|
+
border-top: 1px solid var(--border);
|
|
559
|
+
margin-top: 40px;
|
|
560
|
+
}
|
|
561
|
+
.footer a { color: #7c3aed; text-decoration: none; }
|
|
562
|
+
|
|
563
|
+
/* ── RESPONSIVE ── */
|
|
564
|
+
@media (max-width: 720px) {
|
|
565
|
+
.score-summary { grid-template-columns: 1fr; }
|
|
566
|
+
.sub-scores { grid-column: 1; }
|
|
567
|
+
.progress-bar-wrap { width: 140px; }
|
|
568
|
+
.comparison-brief,
|
|
569
|
+
.comparison-now,
|
|
570
|
+
.comparison-grid,
|
|
571
|
+
.comparison-columns { grid-template-columns: 1fr; }
|
|
572
|
+
}
|
|
573
|
+
</style>
|
|
574
|
+
</head>
|
|
575
|
+
<body>
|
|
576
|
+
|
|
577
|
+
<div class="header">
|
|
578
|
+
<div class="header-inner">
|
|
579
|
+
<div>
|
|
580
|
+
<div class="logo">cite<span>ops</span></div>
|
|
581
|
+
<div class="header-url">{{report.url}}</div>
|
|
582
|
+
</div>
|
|
583
|
+
<div class="header-meta">
|
|
584
|
+
Generated {{generatedAt}}<br />
|
|
585
|
+
answerlint v1.0
|
|
586
|
+
</div>
|
|
587
|
+
</div>
|
|
588
|
+
</div>
|
|
589
|
+
|
|
590
|
+
<div class="container">
|
|
591
|
+
|
|
592
|
+
<!-- SCORE SUMMARY -->
|
|
593
|
+
<div class="score-summary">
|
|
594
|
+
<div class="gauge-wrap composite">
|
|
595
|
+
<div class="gauge-label">Composite Score</div>
|
|
596
|
+
<div class="gauge">
|
|
597
|
+
<svg viewBox="0 0 120 120" width="140" height="140">
|
|
598
|
+
<circle class="gauge-track" cx="60" cy="60" r="54" />
|
|
599
|
+
<circle
|
|
600
|
+
class="gauge-fill"
|
|
601
|
+
cx="60" cy="60" r="54"
|
|
602
|
+
stroke="{{scoreColor}}"
|
|
603
|
+
stroke-dasharray="339.3"
|
|
604
|
+
stroke-dashoffset="{{gaugeOffset report.scores.composite}}"
|
|
605
|
+
/>
|
|
606
|
+
</svg>
|
|
607
|
+
<div class="gauge-score">
|
|
608
|
+
<span class="gauge-number" style="color: {{scoreColor}}">{{report.scores.composite}}</span>
|
|
609
|
+
<span class="gauge-band" style="color: {{scoreColor}}">{{bandLabel}}</span>
|
|
610
|
+
</div>
|
|
611
|
+
</div>
|
|
612
|
+
</div>
|
|
613
|
+
|
|
614
|
+
<div class="sub-scores">
|
|
615
|
+
<div class="sub-score-row">
|
|
616
|
+
<div class="gauge small">
|
|
617
|
+
<svg viewBox="0 0 120 120" width="100" height="100">
|
|
618
|
+
<circle class="gauge-track" cx="60" cy="60" r="54" />
|
|
619
|
+
<circle
|
|
620
|
+
class="gauge-fill"
|
|
621
|
+
cx="60" cy="60" r="54"
|
|
622
|
+
stroke="#1a73e8"
|
|
623
|
+
stroke-dasharray="339.3"
|
|
624
|
+
stroke-dashoffset="{{gaugeOffset report.scores.aeo}}"
|
|
625
|
+
/>
|
|
626
|
+
</svg>
|
|
627
|
+
<div class="gauge-score">
|
|
628
|
+
<span class="gauge-number" style="color: #1a73e8">{{report.scores.aeo}}</span>
|
|
629
|
+
</div>
|
|
630
|
+
</div>
|
|
631
|
+
<div class="sub-score-info">
|
|
632
|
+
<div class="sub-score-name">AEO Score</div>
|
|
633
|
+
<div class="sub-score-desc">Answer Engine Optimization — FAQ schema, direct answers, Q&A density, readability, entities, author</div>
|
|
634
|
+
</div>
|
|
635
|
+
</div>
|
|
636
|
+
|
|
637
|
+
<div class="sub-score-row">
|
|
638
|
+
<div class="gauge small">
|
|
639
|
+
<svg viewBox="0 0 120 120" width="100" height="100">
|
|
640
|
+
<circle class="gauge-track" cx="60" cy="60" r="54" />
|
|
641
|
+
<circle
|
|
642
|
+
class="gauge-fill"
|
|
643
|
+
cx="60" cy="60" r="54"
|
|
644
|
+
stroke="#c2185b"
|
|
645
|
+
stroke-dasharray="339.3"
|
|
646
|
+
stroke-dashoffset="{{gaugeOffset report.scores.geo}}"
|
|
647
|
+
/>
|
|
648
|
+
</svg>
|
|
649
|
+
<div class="gauge-score">
|
|
650
|
+
<span class="gauge-number" style="color: #c2185b">{{report.scores.geo}}</span>
|
|
651
|
+
</div>
|
|
652
|
+
</div>
|
|
653
|
+
<div class="sub-score-info">
|
|
654
|
+
<div class="sub-score-name">GEO Score</div>
|
|
655
|
+
<div class="sub-score-desc">Generative Engine Optimization — topical depth, EEAT, freshness, citations, comparisons, citation likelihood</div>
|
|
656
|
+
</div>
|
|
657
|
+
</div>
|
|
658
|
+
</div>
|
|
659
|
+
</div>
|
|
660
|
+
|
|
661
|
+
{{#if comparisonReport}}
|
|
662
|
+
<div class="section comparison-section">
|
|
663
|
+
<div class="section-header">
|
|
664
|
+
<span class="section-title">Competitor Comparison</span>
|
|
665
|
+
<span class="section-count">target vs competitor</span>
|
|
666
|
+
</div>
|
|
667
|
+
|
|
668
|
+
<div class="comparison-brief">
|
|
669
|
+
<div class="comparison-leader">
|
|
670
|
+
<div class="comparison-kicker">Winner signal</div>
|
|
671
|
+
<div class="comparison-leader-title">{{comparisonReport.comparison.leader.label}}</div>
|
|
672
|
+
<div class="comparison-gap">
|
|
673
|
+
<strong>{{comparisonReport.comparison.leader.score_gap}}</strong>
|
|
674
|
+
<span>point gap</span>
|
|
675
|
+
</div>
|
|
676
|
+
<p class="comparison-summary">{{comparisonReport.comparison.leader.summary}}</p>
|
|
677
|
+
</div>
|
|
678
|
+
|
|
679
|
+
<div class="comparison-now">
|
|
680
|
+
<div class="comparison-now-panel">
|
|
681
|
+
<div class="comparison-panel-title">Improve first</div>
|
|
682
|
+
{{#if comparisonReport.comparison.improve_first.length}}
|
|
683
|
+
<ul class="comparison-action-list">
|
|
684
|
+
{{#each (take comparisonReport.comparison.improve_first 3)}}
|
|
685
|
+
<li>
|
|
686
|
+
<span class="comparison-rank">{{inc @index}}</span>
|
|
687
|
+
<span>{{title}}<span class="comparison-action-meta">{{priority}} priority · +{{score_impact}} pts · {{reason}}</span></span>
|
|
688
|
+
</li>
|
|
689
|
+
{{/each}}
|
|
690
|
+
</ul>
|
|
691
|
+
{{else}}
|
|
692
|
+
<ul class="comparison-action-list"><li><span class="comparison-rank">1</span><span>No urgent target gaps found.</span></li></ul>
|
|
693
|
+
{{/if}}
|
|
694
|
+
</div>
|
|
695
|
+
|
|
696
|
+
<div class="comparison-now-panel">
|
|
697
|
+
<div class="comparison-panel-title">Competitor edge</div>
|
|
698
|
+
{{#if comparisonReport.comparison.competitor_edges.length}}
|
|
699
|
+
<ul class="comparison-action-list">
|
|
700
|
+
{{#each (take comparisonReport.comparison.competitor_edges 3)}}
|
|
701
|
+
<li>
|
|
702
|
+
<span class="comparison-rank">{{inc @index}}</span>
|
|
703
|
+
<span>{{title}}<span class="comparison-action-meta">{{reason}}</span></span>
|
|
704
|
+
</li>
|
|
705
|
+
{{/each}}
|
|
706
|
+
</ul>
|
|
707
|
+
{{else}}
|
|
708
|
+
<ul class="comparison-action-list"><li><span class="comparison-rank">1</span><span>No competitor-only passing checks.</span></li></ul>
|
|
709
|
+
{{/if}}
|
|
710
|
+
</div>
|
|
711
|
+
</div>
|
|
712
|
+
</div>
|
|
713
|
+
|
|
714
|
+
<div class="comparison-grid">
|
|
715
|
+
<div class="comparison-metric">
|
|
716
|
+
<div class="comparison-label">Composite</div>
|
|
717
|
+
<div class="comparison-values">
|
|
718
|
+
<strong>{{comparisonReport.comparison.scores.composite.target}}</strong>
|
|
719
|
+
<span>vs {{comparisonReport.comparison.scores.composite.competitor}}</span>
|
|
720
|
+
<span class="{{deltaClass comparisonReport.comparison.scores.composite.delta}}">
|
|
721
|
+
{{signedNumber comparisonReport.comparison.scores.composite.delta}}
|
|
722
|
+
</span>
|
|
723
|
+
</div>
|
|
724
|
+
<div class="comparison-bar">
|
|
725
|
+
<div class="comparison-bar-row">
|
|
726
|
+
<span>Target</span>
|
|
727
|
+
<span class="comparison-bar-track"><span class="comparison-bar-fill" style="width: {{comparisonReport.comparison.scores.composite.target}}%"></span></span>
|
|
728
|
+
<strong>{{comparisonReport.comparison.scores.composite.target}}</strong>
|
|
729
|
+
</div>
|
|
730
|
+
<div class="comparison-bar-row">
|
|
731
|
+
<span>Competitor</span>
|
|
732
|
+
<span class="comparison-bar-track"><span class="comparison-bar-fill competitor" style="width: {{comparisonReport.comparison.scores.composite.competitor}}%"></span></span>
|
|
733
|
+
<strong>{{comparisonReport.comparison.scores.composite.competitor}}</strong>
|
|
734
|
+
</div>
|
|
735
|
+
</div>
|
|
736
|
+
</div>
|
|
737
|
+
<div class="comparison-metric">
|
|
738
|
+
<div class="comparison-label">AEO</div>
|
|
739
|
+
<div class="comparison-values">
|
|
740
|
+
<strong>{{comparisonReport.comparison.scores.aeo.target}}</strong>
|
|
741
|
+
<span>vs {{comparisonReport.comparison.scores.aeo.competitor}}</span>
|
|
742
|
+
<span class="{{deltaClass comparisonReport.comparison.scores.aeo.delta}}">
|
|
743
|
+
{{signedNumber comparisonReport.comparison.scores.aeo.delta}}
|
|
744
|
+
</span>
|
|
745
|
+
</div>
|
|
746
|
+
<div class="comparison-bar">
|
|
747
|
+
<div class="comparison-bar-row">
|
|
748
|
+
<span>Target</span>
|
|
749
|
+
<span class="comparison-bar-track"><span class="comparison-bar-fill" style="width: {{comparisonReport.comparison.scores.aeo.target}}%"></span></span>
|
|
750
|
+
<strong>{{comparisonReport.comparison.scores.aeo.target}}</strong>
|
|
751
|
+
</div>
|
|
752
|
+
<div class="comparison-bar-row">
|
|
753
|
+
<span>Competitor</span>
|
|
754
|
+
<span class="comparison-bar-track"><span class="comparison-bar-fill competitor" style="width: {{comparisonReport.comparison.scores.aeo.competitor}}%"></span></span>
|
|
755
|
+
<strong>{{comparisonReport.comparison.scores.aeo.competitor}}</strong>
|
|
756
|
+
</div>
|
|
757
|
+
</div>
|
|
758
|
+
</div>
|
|
759
|
+
<div class="comparison-metric">
|
|
760
|
+
<div class="comparison-label">GEO</div>
|
|
761
|
+
<div class="comparison-values">
|
|
762
|
+
<strong>{{comparisonReport.comparison.scores.geo.target}}</strong>
|
|
763
|
+
<span>vs {{comparisonReport.comparison.scores.geo.competitor}}</span>
|
|
764
|
+
<span class="{{deltaClass comparisonReport.comparison.scores.geo.delta}}">
|
|
765
|
+
{{signedNumber comparisonReport.comparison.scores.geo.delta}}
|
|
766
|
+
</span>
|
|
767
|
+
</div>
|
|
768
|
+
<div class="comparison-bar">
|
|
769
|
+
<div class="comparison-bar-row">
|
|
770
|
+
<span>Target</span>
|
|
771
|
+
<span class="comparison-bar-track"><span class="comparison-bar-fill" style="width: {{comparisonReport.comparison.scores.geo.target}}%"></span></span>
|
|
772
|
+
<strong>{{comparisonReport.comparison.scores.geo.target}}</strong>
|
|
773
|
+
</div>
|
|
774
|
+
<div class="comparison-bar-row">
|
|
775
|
+
<span>Competitor</span>
|
|
776
|
+
<span class="comparison-bar-track"><span class="comparison-bar-fill competitor" style="width: {{comparisonReport.comparison.scores.geo.competitor}}%"></span></span>
|
|
777
|
+
<strong>{{comparisonReport.comparison.scores.geo.competitor}}</strong>
|
|
778
|
+
</div>
|
|
779
|
+
</div>
|
|
780
|
+
</div>
|
|
781
|
+
</div>
|
|
782
|
+
|
|
783
|
+
<div class="comparison-columns">
|
|
784
|
+
<div>
|
|
785
|
+
<div class="comparison-column-title">What to copy from the competitor</div>
|
|
786
|
+
<div class="comparison-column-subtitle">Checks where the competitor already has the stronger citation-readiness signal.</div>
|
|
787
|
+
{{#if comparisonReport.comparison.competitor_edges.length}}
|
|
788
|
+
<ul class="comparison-list">
|
|
789
|
+
{{#each comparisonReport.comparison.competitor_edges}}
|
|
790
|
+
<li>
|
|
791
|
+
<div class="comparison-list-title">
|
|
792
|
+
<span>{{title}}</span>
|
|
793
|
+
<span class="comparison-pill {{priority}}">{{priority}}</span>
|
|
794
|
+
</div>
|
|
795
|
+
<div class="comparison-list-body">{{action}}</div>
|
|
796
|
+
</li>
|
|
797
|
+
{{/each}}
|
|
798
|
+
</ul>
|
|
799
|
+
{{else}}
|
|
800
|
+
<ul class="comparison-list"><li>No competitor-only passing checks.</li></ul>
|
|
801
|
+
{{/if}}
|
|
802
|
+
</div>
|
|
803
|
+
<div>
|
|
804
|
+
<div class="comparison-column-title">Improve first</div>
|
|
805
|
+
<div class="comparison-column-subtitle">Prioritized target gaps, with competitor parity gaps boosted to the top.</div>
|
|
806
|
+
{{#if comparisonReport.comparison.improve_first.length}}
|
|
807
|
+
<ul class="comparison-list">
|
|
808
|
+
{{#each comparisonReport.comparison.improve_first}}
|
|
809
|
+
<li>
|
|
810
|
+
<div class="comparison-list-title">
|
|
811
|
+
<span>{{title}}</span>
|
|
812
|
+
<span class="comparison-pill {{priority}}">+{{score_impact}} pts</span>
|
|
813
|
+
</div>
|
|
814
|
+
<div class="comparison-list-body">{{action}}</div>
|
|
815
|
+
</li>
|
|
816
|
+
{{/each}}
|
|
817
|
+
</ul>
|
|
818
|
+
{{else}}
|
|
819
|
+
<ul class="comparison-list"><li>No priority improvements found.</li></ul>
|
|
820
|
+
{{/if}}
|
|
821
|
+
</div>
|
|
822
|
+
</div>
|
|
823
|
+
</div>
|
|
824
|
+
{{/if}}
|
|
825
|
+
|
|
826
|
+
<!-- FAILING AUDITS / RECOMMENDATIONS -->
|
|
827
|
+
{{#with (sortByImpact report.audits) as |failures|}}
|
|
828
|
+
{{#if failures.length}}
|
|
829
|
+
<div class="section">
|
|
830
|
+
<div class="section-header" onclick="toggleSection(this)">
|
|
831
|
+
<span class="section-title">Recommendations</span>
|
|
832
|
+
<span class="section-count fail-count">{{failures.length}} issues</span>
|
|
833
|
+
<span class="chevron">▾</span>
|
|
834
|
+
</div>
|
|
835
|
+
<div class="section-body">
|
|
836
|
+
{{#each failures}}
|
|
837
|
+
<div class="audit-item">
|
|
838
|
+
<div class="audit-header">
|
|
839
|
+
<span class="audit-status-badge {{#if (eq status 'fail')}}badge-fail{{else}}badge-warn{{/if}}">
|
|
840
|
+
{{upper status}}
|
|
841
|
+
</span>
|
|
842
|
+
<span class="audit-title">{{title}}</span>
|
|
843
|
+
<span class="audit-category-tag tag-{{category}}">{{upper category}}</span>
|
|
844
|
+
</div>
|
|
845
|
+
|
|
846
|
+
<div class="audit-evidence">{{evidence}}</div>
|
|
847
|
+
|
|
848
|
+
{{#if recommendation}}
|
|
849
|
+
<div class="recommendation">
|
|
850
|
+
<div class="rec-header">
|
|
851
|
+
<span class="rec-header-title">How to fix</span>
|
|
852
|
+
<span class="priority-badge {{priorityClass recommendation.priority}}">
|
|
853
|
+
{{capitalize recommendation.priority}} priority
|
|
854
|
+
</span>
|
|
855
|
+
<span class="score-impact">+{{recommendation.score_impact}} pts</span>
|
|
856
|
+
</div>
|
|
857
|
+
<div class="rec-body">
|
|
858
|
+
<p class="rec-instruction">{{recommendation.instruction}}</p>
|
|
859
|
+
{{#if recommendation.code_snippet}}
|
|
860
|
+
<div class="code-block">
|
|
861
|
+
<div class="code-block-header">
|
|
862
|
+
<span>Suggested code</span>
|
|
863
|
+
<button class="copy-btn" onclick="copyCode(this)">Copy</button>
|
|
864
|
+
</div>
|
|
865
|
+
<pre>{{preEscape recommendation.code_snippet}}</pre>
|
|
866
|
+
</div>
|
|
867
|
+
{{/if}}
|
|
868
|
+
</div>
|
|
869
|
+
</div>
|
|
870
|
+
{{/if}}
|
|
871
|
+
</div>
|
|
872
|
+
{{/each}}
|
|
873
|
+
</div>
|
|
874
|
+
</div>
|
|
875
|
+
{{/if}}
|
|
876
|
+
{{/with}}
|
|
877
|
+
|
|
878
|
+
<!-- PASSED AUDITS -->
|
|
879
|
+
{{#with (passedAudits report.audits) as |passed|}}
|
|
880
|
+
{{#if passed.length}}
|
|
881
|
+
<div class="section passed-section">
|
|
882
|
+
<div class="section-header" onclick="toggleSection(this)">
|
|
883
|
+
<span class="section-title">Passed Audits</span>
|
|
884
|
+
<span class="section-count pass-count">{{passed.length}} passed</span>
|
|
885
|
+
<span class="chevron" style="transform: rotate(-90deg)">▾</span>
|
|
886
|
+
</div>
|
|
887
|
+
<div class="section-body collapsed">
|
|
888
|
+
{{#each passed}}
|
|
889
|
+
<div class="audit-item passed">
|
|
890
|
+
<div class="audit-header">
|
|
891
|
+
<span class="audit-status-badge badge-pass">PASS</span>
|
|
892
|
+
<span class="audit-title">{{title}}</span>
|
|
893
|
+
<span class="audit-category-tag tag-{{category}}">{{upper category}}</span>
|
|
894
|
+
</div>
|
|
895
|
+
<div class="audit-evidence">{{evidence}}</div>
|
|
896
|
+
</div>
|
|
897
|
+
{{/each}}
|
|
898
|
+
</div>
|
|
899
|
+
</div>
|
|
900
|
+
{{/if}}
|
|
901
|
+
{{/with}}
|
|
902
|
+
|
|
903
|
+
</div>
|
|
904
|
+
|
|
905
|
+
<div class="footer">
|
|
906
|
+
Generated by <a href="https://github.com/yourusername/answerlint" target="_blank">answerlint</a> · {{generatedAt}}
|
|
907
|
+
</div>
|
|
908
|
+
|
|
909
|
+
<script>
|
|
910
|
+
function toggleSection(header) {
|
|
911
|
+
const body = header.nextElementSibling;
|
|
912
|
+
const chevron = header.querySelector('.chevron');
|
|
913
|
+
const isCollapsed = body.classList.contains('collapsed');
|
|
914
|
+
body.classList.toggle('collapsed');
|
|
915
|
+
chevron.style.transform = isCollapsed ? 'rotate(0deg)' : 'rotate(-90deg)';
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
function copyCode(btn) {
|
|
919
|
+
const pre = btn.closest('.code-block').querySelector('pre');
|
|
920
|
+
const text = pre.innerText;
|
|
921
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
922
|
+
btn.textContent = 'Copied!';
|
|
923
|
+
setTimeout(() => { btn.textContent = 'Copy'; }, 2000);
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
</script>
|
|
927
|
+
|
|
928
|
+
</body>
|
|
929
|
+
</html>
|