@drunkcoding/agents-and-skills 0.0.13 → 0.0.15

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 (83) hide show
  1. package/.claude-plugin/marketplace.json +9 -6
  2. package/README.md +1 -1
  3. package/package.json +1 -1
  4. package/plugins/html-effectiveness/.claude-plugin/plugin.json +1 -1
  5. package/plugins/html-effectiveness/README.md +9 -4
  6. package/plugins/html-effectiveness/agents/report-builder.md +4 -0
  7. package/plugins/html-effectiveness/assets/base.css +40 -20
  8. package/plugins/html-effectiveness/docs/template-gallery.md +28 -0
  9. package/plugins/html-effectiveness/scripts/_tmp.js +37 -0
  10. package/plugins/html-effectiveness/scripts/catalog.js +47 -0
  11. package/plugins/html-effectiveness/scripts/extract.js +104 -0
  12. package/plugins/html-effectiveness/scripts/render.js +2 -2
  13. package/plugins/html-effectiveness/skills/html-effectiveness/SKILL.md +4 -4
  14. package/plugins/html-effectiveness/templates/01-exploration-code-approaches.html.tmpl +400 -0
  15. package/plugins/html-effectiveness/templates/02-exploration-visual-designs.html.tmpl +456 -0
  16. package/plugins/html-effectiveness/templates/03-code-review-pr.html.tmpl +581 -0
  17. package/plugins/html-effectiveness/templates/04-code-understanding.html.tmpl +443 -0
  18. package/plugins/html-effectiveness/templates/05-design-system.html.tmpl +578 -0
  19. package/plugins/html-effectiveness/templates/06-component-variants.html.tmpl +557 -0
  20. package/plugins/html-effectiveness/templates/07-prototype-animation.html.tmpl +417 -0
  21. package/plugins/html-effectiveness/templates/08-prototype-interaction.html.tmpl +363 -0
  22. package/plugins/html-effectiveness/templates/09-slide-deck.html.tmpl +535 -0
  23. package/plugins/html-effectiveness/templates/10-svg-illustrations.html.tmpl +444 -0
  24. package/plugins/html-effectiveness/templates/11-status-report.html.tmpl +152 -0
  25. package/plugins/html-effectiveness/templates/12-incident-report.html.tmpl +547 -0
  26. package/plugins/html-effectiveness/templates/13-flowchart-diagram.html.tmpl +361 -0
  27. package/plugins/html-effectiveness/templates/14-research-feature-explainer.html.tmpl +348 -0
  28. package/plugins/html-effectiveness/templates/15-research-concept-explainer.html.tmpl +334 -0
  29. package/plugins/html-effectiveness/templates/16-implementation-plan.html.tmpl +657 -0
  30. package/plugins/html-effectiveness/templates/17-pr-writeup.html.tmpl +553 -0
  31. package/plugins/html-effectiveness/templates/18-editor-triage-board.html.tmpl +541 -0
  32. package/plugins/html-effectiveness/templates/19-editor-feature-flags.html.tmpl +627 -0
  33. package/plugins/html-effectiveness/templates/20-editor-prompt-tuner.html.tmpl +687 -0
  34. package/plugins/html-effectiveness/templates/manifest.json +436 -2
  35. package/plugins/html-effectiveness/tests/_tmp.test.js +58 -0
  36. package/plugins/html-effectiveness/tests/fixtures/01-exploration-code-approaches.data.json +3 -0
  37. package/plugins/html-effectiveness/tests/fixtures/02-exploration-visual-designs.data.json +3 -0
  38. package/plugins/html-effectiveness/tests/fixtures/03-code-review-pr.data.json +3 -0
  39. package/plugins/html-effectiveness/tests/fixtures/04-code-understanding.data.json +3 -0
  40. package/plugins/html-effectiveness/tests/fixtures/05-design-system.data.json +3 -0
  41. package/plugins/html-effectiveness/tests/fixtures/06-component-variants.data.json +3 -0
  42. package/plugins/html-effectiveness/tests/fixtures/07-prototype-animation.data.json +3 -0
  43. package/plugins/html-effectiveness/tests/fixtures/08-prototype-interaction.data.json +3 -0
  44. package/plugins/html-effectiveness/tests/fixtures/09-slide-deck.data.json +3 -0
  45. package/plugins/html-effectiveness/tests/fixtures/10-svg-illustrations.data.json +3 -0
  46. package/plugins/html-effectiveness/tests/fixtures/11-status-report.data.json +37 -0
  47. package/plugins/html-effectiveness/tests/fixtures/12-incident-report.data.json +3 -0
  48. package/plugins/html-effectiveness/tests/fixtures/13-flowchart-diagram.data.json +3 -0
  49. package/plugins/html-effectiveness/tests/fixtures/14-research-feature-explainer.data.json +3 -0
  50. package/plugins/html-effectiveness/tests/fixtures/15-research-concept-explainer.data.json +3 -0
  51. package/plugins/html-effectiveness/tests/fixtures/16-implementation-plan.data.json +3 -0
  52. package/plugins/html-effectiveness/tests/fixtures/17-pr-writeup.data.json +3 -0
  53. package/plugins/html-effectiveness/tests/fixtures/18-editor-triage-board.data.json +3 -0
  54. package/plugins/html-effectiveness/tests/fixtures/19-editor-feature-flags.data.json +3 -0
  55. package/plugins/html-effectiveness/tests/fixtures/20-editor-prompt-tuner.data.json +3 -0
  56. package/plugins/html-effectiveness/tests/manifest.test.js +61 -0
  57. package/plugins/plugin-validator/.claude-plugin/plugin.json +1 -1
  58. package/plugins/plugin-validator/skills/validate-agents/SKILL.md +2 -2
  59. package/plugins/plugin-validator/skills/validate-commands/SKILL.md +2 -2
  60. package/plugins/plugin-validator/skills/validate-hooks/SKILL.md +57 -18
  61. package/plugins/team-superpower/.claude-plugin/plugin.json +7 -39
  62. package/plugins/team-superpower/README.md +85 -24
  63. package/plugins/team-superpower/agents/backend-developer.md +82 -0
  64. package/plugins/team-superpower/agents/designer.md +5 -1
  65. package/plugins/team-superpower/agents/frontend-developer.md +96 -0
  66. package/plugins/team-superpower/agents/planner.md +144 -16
  67. package/plugins/team-superpower/agents/qa-engineer.md +30 -0
  68. package/plugins/team-superpower/agents/reviewer.md +68 -22
  69. package/plugins/team-superpower/agents/security-engineer.md +110 -0
  70. package/plugins/team-superpower/agents/software-architect.md +30 -0
  71. package/plugins/team-superpower/assets/CLAUDE.md.template +96 -0
  72. package/plugins/team-superpower/assets/ESCALATION.md +19 -5
  73. package/plugins/team-superpower/assets/SESSION_README.md +119 -11
  74. package/plugins/team-superpower/commands/team-feature-resume.md +72 -6
  75. package/plugins/team-superpower/commands/team-feature.md +329 -28
  76. package/plugins/team-superpower/hooks/hooks.json +0 -3
  77. package/plugins/team-superpower/hooks/task-completed.sh +54 -5
  78. package/plugins/team-superpower/hooks/task-created.sh +79 -4
  79. package/plugins/team-superpower/scripts/detect-stack.sh +434 -0
  80. package/plugins/team-superpower/scripts/parse-claudemd.sh +194 -0
  81. package/plugins/tech-graph/.claude-plugin/plugin.json +1 -1
  82. package/plugins/tech-graph/agents/tech-graph.md +8 -0
  83. package/plugins/team-superpower/agents/implementer.md +0 -46
@@ -0,0 +1,535 @@
1
+ <!--
2
+ template: 09-slide-deck
3
+ upstream: 09-slide-deck.html
4
+ slots:
5
+ title: string # replaces first <h1> innerHTML
6
+ -->
7
+ <!-- ============================================================
8
+ Slide 1 — Title
9
+ ============================================================ -->
10
+ <section class="slide title-slide" id="s1">
11
+ <div class="slide-inner">
12
+ <svg class="ornament" width="56" height="56" viewBox="0 0 56 56" aria-hidden="true">
13
+ <circle cx="28" cy="28" r="22" fill="none" stroke="#D1CFC5" stroke-width="1.5"/>
14
+ <path d="M16 28 H40 M28 16 V40" stroke="#D97757" stroke-width="1.5" stroke-linecap="round"/>
15
+ <circle cx="28" cy="28" r="3" fill="#141413"/>
16
+ </svg>
17
+ <h1>{{title}}</h1>
18
+ <p class="subtitle">
19
+ What shipped, what's moving, and one decision we need from the
20
+ room before the Acme 2.4 cut.
21
+ </p>
22
+ <div class="byline">
23
+ <span>Friday demo</span>
24
+ <span>6 slides</span>
25
+ <span>~4 min</span>
26
+ </div>
27
+ </div>
28
+ </section>
29
+
30
+ <!-- ============================================================
31
+ Slide 2 — Shipped
32
+ ============================================================ -->
33
+ <section class="slide" id="s2">
34
+ <div class="slide-inner">
35
+ <div class="eyebrow">Shipped this week</div>
36
+ <h2>Three things out the door</h2>
37
+ <ul class="ship-list">
38
+ <li class="ship-item">
39
+ <span class="ship-dot"></span>
40
+ <div>
41
+ <div class="ship-title">Bulk task import</div>
42
+ <div class="ship-desc">
43
+ CSV and JSON uploads now land straight into a board with
44
+ column mapping — no more paste-and-pray.
45
+ </div>
46
+ </div>
47
+ <span class="ship-ref">#4211</span>
48
+ </li>
49
+ <li class="ship-item">
50
+ <span class="ship-dot"></span>
51
+ <div>
52
+ <div class="ship-title">Webhook retries v2</div>
53
+ <div class="ship-desc">
54
+ Exponential backoff with jitter; dead-letter queue surfaces
55
+ in the workspace admin panel.
56
+ </div>
57
+ </div>
58
+ <span class="ship-ref">#4188 #4203</span>
59
+ </li>
60
+ <li class="ship-item">
61
+ <span class="ship-dot"></span>
62
+ <div>
63
+ <div class="ship-title">Postgres 16 migration</div>
64
+ <div class="ship-desc">
65
+ All read replicas cut over Tuesday night; zero customer-facing
66
+ downtime, ~9% faster aggregate queries.
67
+ </div>
68
+ </div>
69
+ <span class="ship-ref">#4179</span>
70
+ </li>
71
+ </ul>
72
+ </div>
73
+ </section>
74
+
75
+ <!-- ============================================================
76
+ Slide 3 — In progress
77
+ ============================================================ -->
78
+ <section class="slide" id="s3">
79
+ <div class="slide-inner">
80
+ <div class="eyebrow">In progress</div>
81
+ <h2>Carrying into next week</h2>
82
+ <ul class="prog-list">
83
+ <li class="prog-item">
84
+ <div class="prog-head">
85
+ <span class="prog-title">Recurring tasks engine</span>
86
+ <span class="prog-pct">~70%</span>
87
+ </div>
88
+ <div class="prog-track"><div class="prog-fill" style="width:70%"></div></div>
89
+ <p class="prog-note">
90
+ Scheduler and RRULE parsing are done; remaining work is the
91
+ timezone edge cases and the "skip holidays" toggle.
92
+ </p>
93
+ </li>
94
+ <li class="prog-item">
95
+ <div class="prog-head">
96
+ <span class="prog-title">Audit log export</span>
97
+ <span class="prog-pct">~35%</span>
98
+ </div>
99
+ <div class="prog-track"><div class="prog-fill" style="width:35%"></div></div>
100
+ <p class="prog-note">
101
+ Streaming NDJSON endpoint is up behind a flag; still wiring
102
+ the S3 destination picker and retention policy UI.
103
+ </p>
104
+ </li>
105
+ </ul>
106
+ </div>
107
+ </section>
108
+
109
+ <!-- ============================================================
110
+ Slide 4 — Metrics
111
+ ============================================================ -->
112
+ <section class="slide" id="s4">
113
+ <div class="slide-inner">
114
+ <div class="eyebrow">Metrics</div>
115
+ <h2>Numbers we watch</h2>
116
+
117
+ <div class="metrics">
118
+ <div class="metric">
119
+ <div class="metric-label">API p95 latency</div>
120
+ <div class="metric-value">184<span style="font-size:28px">ms</span></div>
121
+ <div class="metric-delta down">↓ 12% wk/wk</div>
122
+ </div>
123
+ <div class="metric">
124
+ <div class="metric-label">Background job error rate</div>
125
+ <div class="metric-value">0.21<span style="font-size:28px">%</span></div>
126
+ <div class="metric-delta down">↓ 0.08pp</div>
127
+ </div>
128
+ </div>
129
+
130
+ <div class="sparkline-wrap">
131
+ <svg width="100%" height="64" viewBox="0 0 780 64" preserveAspectRatio="none" aria-hidden="true">
132
+ <polyline
133
+ points="0,22 110,30 220,18 330,34 440,26 550,40 660,24 780,12"
134
+ fill="none"
135
+ stroke="#788C5D"
136
+ stroke-width="2"
137
+ stroke-linejoin="round"
138
+ stroke-linecap="round"/>
139
+ <circle cx="780" cy="12" r="3.5" fill="#788C5D"/>
140
+ <line x1="0" y1="63" x2="780" y2="63" stroke="#D1CFC5" stroke-width="1"/>
141
+ </svg>
142
+ <div class="sparkline-caption">
143
+ p95 latency, trailing 8 days — lower is better
144
+ </div>
145
+ </div>
146
+ </div>
147
+ </section>
148
+
149
+ <!-- ============================================================
150
+ Slide 5 — Decision needed (inverted)
151
+ ============================================================ -->
152
+ <section class="slide invert" id="s5">
153
+ <div class="slide-inner">
154
+ <div class="eyebrow">Decision needed</div>
155
+ <h2>One call to make</h2>
156
+
157
+ <div class="decision-card">
158
+ <p class="decision-q">
159
+ Do we ship recurring tasks behind a workspace flag in 2.4, or
160
+ hold one more week for the timezone fixes?
161
+ </p>
162
+ <p class="decision-context">
163
+ Flagged rollout gets it to design partners Friday but means two
164
+ code paths for ~2 weeks. Holding keeps a single path but slips
165
+ the partner promise.
166
+ </p>
167
+ </div>
168
+
169
+ <div class="options">
170
+ <span class="chip lean">A — Flag it, ship Friday</span>
171
+ <span class="chip">B — Hold for 2.5</span>
172
+ </div>
173
+ </div>
174
+ </section>
175
+
176
+ <!-- ============================================================
177
+ Slide 6 — Next week
178
+ ============================================================ -->
179
+ <section class="slide" id="s6">
180
+ <div class="slide-inner">
181
+ <div class="eyebrow">Next week</div>
182
+ <h2>On deck</h2>
183
+ <ul class="next-list">
184
+ <li>Finish recurring tasks — timezone matrix tests, then dogfood on the internal ops board.</li>
185
+ <li>Audit log export to private beta — three workspaces lined up.</li>
186
+ <li>Start scoping rate-limit headers for the public API; RFC draft by Thursday.</li>
187
+ </ul>
188
+ <div class="footnote">
189
+ Questions → drop them in the platform channel or grab anyone after standup.
190
+ </div>
191
+ </div>
192
+ </section>
193
+
194
+ <!-- ============================================================
195
+ Slide counter
196
+ ============================================================ -->
197
+ <div id="counter">1 / 6</div>
198
+
199
+ <style>
200
+ /* ------------------------------------------------------------------
201
+ Design tokens
202
+ ------------------------------------------------------------------ */
203
+ :root {
204
+ --ivory: #FAF9F5;
205
+ --slate: #141413;
206
+ --clay: #D97757;
207
+ --oat: #E3DACC;
208
+ --olive: #788C5D;
209
+ --gray-150:#F0EEE6;
210
+ --gray-300:#D1CFC5;
211
+ --gray-500:#87867F;
212
+ --gray-700:#3D3D3A;
213
+
214
+ --serif: ui-serif, Georgia, "Times New Roman", serif;
215
+ --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
216
+ --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
217
+ }
218
+ * { margin: 0; padding: 0; box-sizing: border-box; }
219
+ /* ------------------------------------------------------------------
220
+ Slide shell
221
+ ------------------------------------------------------------------ */
222
+ .slide {
223
+ width: 100vw;
224
+ height: 100vh;
225
+ scroll-snap-align: start;
226
+ scroll-snap-stop: always;
227
+ display: flex;
228
+ align-items: center;
229
+ justify-content: center;
230
+ padding: 8vh 6vw;
231
+ }
232
+ .slide-inner {
233
+ width: 100%;
234
+ max-width: 780px;
235
+ }
236
+ .slide.invert {
237
+ background: var(--slate);
238
+ color: var(--ivory);
239
+ }
240
+ /* ------------------------------------------------------------------
241
+ Typography
242
+ ------------------------------------------------------------------ */
243
+ .eyebrow {
244
+ font-family: var(--mono);
245
+ font-size: 12px;
246
+ letter-spacing: 0.12em;
247
+ text-transform: uppercase;
248
+ color: var(--gray-500);
249
+ margin-bottom: 28px;
250
+ }
251
+ .invert .eyebrow { color: var(--gray-300); }
252
+ h1 {
253
+ font-family: var(--serif);
254
+ font-weight: 500;
255
+ font-size: clamp(40px, 6vw, 64px);
256
+ line-height: 1.08;
257
+ letter-spacing: -0.01em;
258
+ margin-bottom: 20px;
259
+ }
260
+ h2 {
261
+ font-family: var(--serif);
262
+ font-weight: 500;
263
+ font-size: clamp(30px, 4vw, 42px);
264
+ line-height: 1.15;
265
+ letter-spacing: -0.005em;
266
+ margin-bottom: 44px;
267
+ }
268
+ .subtitle {
269
+ font-size: 17px;
270
+ line-height: 1.6;
271
+ color: var(--gray-700);
272
+ max-width: 520px;
273
+ }
274
+ .mono { font-family: var(--mono); }
275
+ /* ------------------------------------------------------------------
276
+ Slide 1 — title
277
+ ------------------------------------------------------------------ */
278
+ .title-slide .slide-inner { text-align: left; }
279
+ .ornament {
280
+ display: block;
281
+ margin: 0 0 40px 0;
282
+ }
283
+ .byline {
284
+ margin-top: 56px;
285
+ font-family: var(--mono);
286
+ font-size: 12px;
287
+ color: var(--gray-500);
288
+ display: flex;
289
+ gap: 24px;
290
+ }
291
+ /* ------------------------------------------------------------------
292
+ Slide 2 — shipped list
293
+ ------------------------------------------------------------------ */
294
+ .ship-list {
295
+ list-style: none;
296
+ display: flex;
297
+ flex-direction: column;
298
+ gap: 28px;
299
+ }
300
+ .ship-item {
301
+ display: grid;
302
+ grid-template-columns: 14px 1fr auto;
303
+ column-gap: 20px;
304
+ align-items: baseline;
305
+ padding-bottom: 24px;
306
+ border-bottom: 1px solid var(--gray-150);
307
+ }
308
+ .ship-item:last-child { border-bottom: none; }
309
+ .ship-dot {
310
+ width: 9px;
311
+ height: 9px;
312
+ border-radius: 50%;
313
+ background: var(--olive);
314
+ margin-top: 8px;
315
+ align-self: start;
316
+ }
317
+ .ship-title {
318
+ font-family: var(--serif);
319
+ font-size: 20px;
320
+ font-weight: 500;
321
+ margin-bottom: 6px;
322
+ }
323
+ .ship-desc {
324
+ font-size: 14px;
325
+ line-height: 1.55;
326
+ color: var(--gray-700);
327
+ }
328
+ .ship-ref {
329
+ font-family: var(--mono);
330
+ font-size: 11px;
331
+ color: var(--gray-500);
332
+ white-space: nowrap;
333
+ padding-top: 4px;
334
+ }
335
+ /* ------------------------------------------------------------------
336
+ Slide 3 — in progress
337
+ ------------------------------------------------------------------ */
338
+ .prog-list {
339
+ list-style: none;
340
+ display: flex;
341
+ flex-direction: column;
342
+ gap: 40px;
343
+ }
344
+ .prog-item .prog-head {
345
+ display: flex;
346
+ justify-content: space-between;
347
+ align-items: baseline;
348
+ margin-bottom: 10px;
349
+ }
350
+ .prog-title {
351
+ font-family: var(--serif);
352
+ font-size: 20px;
353
+ font-weight: 500;
354
+ }
355
+ .prog-pct {
356
+ font-family: var(--mono);
357
+ font-size: 12px;
358
+ color: var(--gray-500);
359
+ }
360
+ .prog-track {
361
+ width: 100%;
362
+ height: 5px;
363
+ background: var(--gray-150);
364
+ border-radius: 3px;
365
+ overflow: hidden;
366
+ margin-bottom: 10px;
367
+ }
368
+ .prog-fill {
369
+ height: 100%;
370
+ background: var(--clay);
371
+ border-radius: 3px;
372
+ }
373
+ .prog-note {
374
+ font-size: 13px;
375
+ line-height: 1.55;
376
+ color: var(--gray-700);
377
+ }
378
+ /* ------------------------------------------------------------------
379
+ Slide 4 — metrics
380
+ ------------------------------------------------------------------ */
381
+ .metrics {
382
+ display: grid;
383
+ grid-template-columns: 1fr 1fr;
384
+ gap: 56px;
385
+ margin-bottom: 48px;
386
+ }
387
+ .metric-label {
388
+ font-family: var(--mono);
389
+ font-size: 11px;
390
+ letter-spacing: 0.08em;
391
+ text-transform: uppercase;
392
+ color: var(--gray-500);
393
+ margin-bottom: 14px;
394
+ }
395
+ .metric-value {
396
+ font-family: var(--serif);
397
+ font-size: 52px;
398
+ font-weight: 500;
399
+ line-height: 1;
400
+ letter-spacing: -0.01em;
401
+ }
402
+ .metric-delta {
403
+ font-family: var(--mono);
404
+ font-size: 13px;
405
+ margin-top: 12px;
406
+ }
407
+ .metric-delta.down { color: var(--olive); }
408
+ .metric-delta.up { color: var(--clay); }
409
+ .sparkline-wrap {
410
+ border-top: 1px solid var(--gray-300);
411
+ padding-top: 28px;
412
+ }
413
+ .sparkline-caption {
414
+ font-size: 12px;
415
+ color: var(--gray-500);
416
+ margin-top: 10px;
417
+ }
418
+ /* ------------------------------------------------------------------
419
+ Slide 5 — decision (inverted)
420
+ ------------------------------------------------------------------ */
421
+ .decision-card {
422
+ border: 1.5px solid var(--clay);
423
+ border-radius: 14px;
424
+ padding: 36px 38px;
425
+ background: rgba(217, 119, 87, 0.06);
426
+ }
427
+ .decision-q {
428
+ font-family: var(--serif);
429
+ font-size: 24px;
430
+ line-height: 1.4;
431
+ margin-bottom: 12px;
432
+ }
433
+ .decision-context {
434
+ font-size: 14px;
435
+ line-height: 1.6;
436
+ color: var(--gray-300);
437
+ }
438
+ .options {
439
+ display: flex;
440
+ gap: 14px;
441
+ margin-top: 32px;
442
+ flex-wrap: wrap;
443
+ }
444
+ .chip {
445
+ font-family: var(--mono);
446
+ font-size: 12px;
447
+ padding: 10px 18px;
448
+ border-radius: 999px;
449
+ border: 1px solid var(--gray-700);
450
+ color: var(--ivory);
451
+ background: transparent;
452
+ }
453
+ .chip.lean {
454
+ border-color: var(--clay);
455
+ color: var(--clay);
456
+ }
457
+ /* ------------------------------------------------------------------
458
+ Slide 6 — next week
459
+ ------------------------------------------------------------------ */
460
+ .next-list {
461
+ list-style: none;
462
+ display: flex;
463
+ flex-direction: column;
464
+ gap: 22px;
465
+ }
466
+ .next-list li {
467
+ font-family: var(--serif);
468
+ font-size: 21px;
469
+ line-height: 1.45;
470
+ padding-left: 36px;
471
+ position: relative;
472
+ }
473
+ .next-list li::before {
474
+ content: "";
475
+ position: absolute;
476
+ left: 0;
477
+ top: 0.55em;
478
+ width: 18px;
479
+ height: 1.5px;
480
+ background: var(--clay);
481
+ }
482
+ .footnote {
483
+ margin-top: 56px;
484
+ font-family: var(--mono);
485
+ font-size: 11px;
486
+ color: var(--gray-500);
487
+ }
488
+ /* ------------------------------------------------------------------
489
+ Slide counter
490
+ ------------------------------------------------------------------ */
491
+ #counter {
492
+ position: fixed;
493
+ bottom: 22px;
494
+ right: 28px;
495
+ font-family: var(--mono);
496
+ font-size: 12px;
497
+ color: var(--gray-500);
498
+ user-select: none;
499
+ z-index: 10;
500
+ }
501
+ @media (max-width: 640px) {
502
+ .metrics { grid-template-columns: 1fr; gap: 36px; }
503
+ .ship-item { grid-template-columns: 14px 1fr; }
504
+ .ship-ref { grid-column: 2; padding-top: 8px; }
505
+ }
506
+ </style>
507
+
508
+ <script>
509
+ (function () {
510
+ const slides = Array.from(document.querySelectorAll('.slide'));
511
+ const counter = document.getElementById('counter');
512
+ let current = 0;
513
+
514
+ function go(i) {
515
+ current = Math.max(0, Math.min(slides.length - 1, i));
516
+ slides[current].scrollIntoView({ behavior: 'smooth' });
517
+ }
518
+
519
+ document.addEventListener('keydown', function (e) {
520
+ if (e.key === 'ArrowRight' || e.key === 'ArrowDown' || e.key === ' ') { e.preventDefault(); go(current + 1); }
521
+ if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') { e.preventDefault(); go(current - 1); }
522
+ });
523
+
524
+ const obs = new IntersectionObserver(function (entries) {
525
+ entries.forEach(function (en) {
526
+ if (en.isIntersecting) {
527
+ current = slides.indexOf(en.target);
528
+ counter.textContent = (current + 1) + ' / ' + slides.length;
529
+ }
530
+ });
531
+ }, { threshold: 0.6 });
532
+
533
+ slides.forEach(function (s) { obs.observe(s); });
534
+ })();
535
+ </script>