forgedock 1.0.17 → 1.0.18

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 (131) hide show
  1. package/README.md +34 -1
  2. package/bin/cross-publish.mjs +344 -0
  3. package/bin/forgedock.mjs +229 -17
  4. package/commands/autopilot.md +77 -0
  5. package/commands/design-bench.md +176 -0
  6. package/commands/design-render-critique-loop.md +103 -0
  7. package/commands/design.md +259 -0
  8. package/commands/issue.md +7 -3
  9. package/commands/orchestrate.md +121 -0
  10. package/commands/qa-sweep.md +37 -2
  11. package/commands/quality-gate.md +30 -0
  12. package/commands/review-pr-staging.md +158 -2
  13. package/commands/test-gate.md +929 -0
  14. package/commands/work-on/build/implement.md +5 -3
  15. package/commands/work-on.md +53 -3
  16. package/docs/CI.md +177 -0
  17. package/docs/FORGE-PROTOCOL.md +324 -0
  18. package/docs/articles/b-vs-c-baseline.md +210 -0
  19. package/docs/articles/full-abc-benchmark.md +205 -0
  20. package/docs/articles/selective-spec-loading-token-savings.md +140 -0
  21. package/docs/design/abc-benchmark.md +195 -0
  22. package/docs/design/design-architect-rationale.md +123 -0
  23. package/docs/design/design-memory.md +61 -0
  24. package/docs/design/design-spec-schema.md +248 -0
  25. package/docs/design/design-system-lint.md +150 -0
  26. package/docs/design/divergent-generation.md +106 -0
  27. package/docs/design/effects-appropriateness.md +133 -0
  28. package/docs/design/fixtures/briefs/README.md +47 -0
  29. package/docs/design/fixtures/briefs/cadence.md +39 -0
  30. package/docs/design/fixtures/briefs/plume.md +39 -0
  31. package/docs/design/fixtures/briefs/slipstream.md +39 -0
  32. package/docs/design/fixtures/briefs/tender.md +39 -0
  33. package/docs/design/fixtures/briefs/voltage.md +39 -0
  34. package/docs/design/fixtures/runs/b-vs-c-baseline/cadence/arm-b/run-1.html +364 -0
  35. package/docs/design/fixtures/runs/b-vs-c-baseline/cadence/arm-b/run-2.html +420 -0
  36. package/docs/design/fixtures/runs/b-vs-c-baseline/cadence/arm-b/run-3.html +506 -0
  37. package/docs/design/fixtures/runs/b-vs-c-baseline/plume/arm-b/run-1.html +611 -0
  38. package/docs/design/fixtures/runs/b-vs-c-baseline/plume/arm-b/run-2.html +594 -0
  39. package/docs/design/fixtures/runs/b-vs-c-baseline/plume/arm-b/run-3.html +817 -0
  40. package/docs/design/fixtures/runs/b-vs-c-baseline/runs.json +175 -0
  41. package/docs/design/fixtures/runs/b-vs-c-baseline/scorecard.json +138 -0
  42. package/docs/design/fixtures/runs/b-vs-c-baseline/slipstream/arm-b/run-1.html +373 -0
  43. package/docs/design/fixtures/runs/b-vs-c-baseline/slipstream/arm-b/run-2.html +398 -0
  44. package/docs/design/fixtures/runs/b-vs-c-baseline/slipstream/arm-b/run-3.html +595 -0
  45. package/docs/design/fixtures/runs/b-vs-c-baseline/tender/arm-b/run-1.html +531 -0
  46. package/docs/design/fixtures/runs/b-vs-c-baseline/tender/arm-b/run-2.html +565 -0
  47. package/docs/design/fixtures/runs/b-vs-c-baseline/tender/arm-b/run-3.html +674 -0
  48. package/docs/design/fixtures/runs/b-vs-c-baseline/voltage/arm-b/run-1.html +388 -0
  49. package/docs/design/fixtures/runs/b-vs-c-baseline/voltage/arm-b/run-2.html +463 -0
  50. package/docs/design/fixtures/runs/b-vs-c-baseline/voltage/arm-b/run-3.html +568 -0
  51. package/docs/design/fixtures/runs/full-abc/cadence/arm-a/run-1.html +562 -0
  52. package/docs/design/fixtures/runs/full-abc/cadence/arm-a/run-2.html +618 -0
  53. package/docs/design/fixtures/runs/full-abc/cadence/arm-a/run-3.html +618 -0
  54. package/docs/design/fixtures/runs/full-abc/cadence/arm-b/run-1.html +364 -0
  55. package/docs/design/fixtures/runs/full-abc/cadence/arm-b/run-2.html +420 -0
  56. package/docs/design/fixtures/runs/full-abc/cadence/arm-b/run-3.html +506 -0
  57. package/docs/design/fixtures/runs/full-abc/plume/arm-a/run-1.html +527 -0
  58. package/docs/design/fixtures/runs/full-abc/plume/arm-a/run-2.html +445 -0
  59. package/docs/design/fixtures/runs/full-abc/plume/arm-a/run-3.html +483 -0
  60. package/docs/design/fixtures/runs/full-abc/plume/arm-b/run-1.html +611 -0
  61. package/docs/design/fixtures/runs/full-abc/plume/arm-b/run-2.html +594 -0
  62. package/docs/design/fixtures/runs/full-abc/plume/arm-b/run-3.html +817 -0
  63. package/docs/design/fixtures/runs/full-abc/runs.json +190 -0
  64. package/docs/design/fixtures/runs/full-abc/scorecard.json +144 -0
  65. package/docs/design/fixtures/runs/full-abc/slipstream/arm-a/run-1.html +496 -0
  66. package/docs/design/fixtures/runs/full-abc/slipstream/arm-a/run-2.html +447 -0
  67. package/docs/design/fixtures/runs/full-abc/slipstream/arm-a/run-3.html +564 -0
  68. package/docs/design/fixtures/runs/full-abc/slipstream/arm-b/run-1.html +373 -0
  69. package/docs/design/fixtures/runs/full-abc/slipstream/arm-b/run-2.html +398 -0
  70. package/docs/design/fixtures/runs/full-abc/slipstream/arm-b/run-3.html +595 -0
  71. package/docs/design/fixtures/runs/full-abc/tender/arm-a/run-1.html +622 -0
  72. package/docs/design/fixtures/runs/full-abc/tender/arm-a/run-2.html +475 -0
  73. package/docs/design/fixtures/runs/full-abc/tender/arm-a/run-3.html +660 -0
  74. package/docs/design/fixtures/runs/full-abc/tender/arm-b/run-1.html +531 -0
  75. package/docs/design/fixtures/runs/full-abc/tender/arm-b/run-2.html +565 -0
  76. package/docs/design/fixtures/runs/full-abc/tender/arm-b/run-3.html +674 -0
  77. package/docs/design/fixtures/runs/full-abc/voltage/arm-a/run-1.html +525 -0
  78. package/docs/design/fixtures/runs/full-abc/voltage/arm-a/run-2.html +446 -0
  79. package/docs/design/fixtures/runs/full-abc/voltage/arm-a/run-3.html +463 -0
  80. package/docs/design/fixtures/runs/full-abc/voltage/arm-b/run-1.html +388 -0
  81. package/docs/design/fixtures/runs/full-abc/voltage/arm-b/run-2.html +463 -0
  82. package/docs/design/fixtures/runs/full-abc/voltage/arm-b/run-3.html +568 -0
  83. package/docs/design/fixtures/runs/full-abc-opus/cadence/arm-a/run-1.html +1068 -0
  84. package/docs/design/fixtures/runs/full-abc-opus/cadence/arm-a/run-2.html +1423 -0
  85. package/docs/design/fixtures/runs/full-abc-opus/cadence/arm-a/run-3.html +1245 -0
  86. package/docs/design/fixtures/runs/full-abc-opus/cadence/arm-b/run-1.html +305 -0
  87. package/docs/design/fixtures/runs/full-abc-opus/cadence/arm-b/run-2.html +327 -0
  88. package/docs/design/fixtures/runs/full-abc-opus/cadence/arm-b/run-3.html +428 -0
  89. package/docs/design/fixtures/runs/full-abc-opus/plume/arm-a/run-1.html +1270 -0
  90. package/docs/design/fixtures/runs/full-abc-opus/plume/arm-a/run-2.html +1172 -0
  91. package/docs/design/fixtures/runs/full-abc-opus/plume/arm-a/run-3.html +1532 -0
  92. package/docs/design/fixtures/runs/full-abc-opus/plume/arm-b/run-1.html +315 -0
  93. package/docs/design/fixtures/runs/full-abc-opus/plume/arm-b/run-2.html +342 -0
  94. package/docs/design/fixtures/runs/full-abc-opus/plume/arm-b/run-3.html +353 -0
  95. package/docs/design/fixtures/runs/full-abc-opus/runs.json +190 -0
  96. package/docs/design/fixtures/runs/full-abc-opus/scorecard.json +144 -0
  97. package/docs/design/fixtures/runs/full-abc-opus/slipstream/arm-a/run-1.html +345 -0
  98. package/docs/design/fixtures/runs/full-abc-opus/slipstream/arm-a/run-2.html +396 -0
  99. package/docs/design/fixtures/runs/full-abc-opus/slipstream/arm-a/run-3.html +502 -0
  100. package/docs/design/fixtures/runs/full-abc-opus/slipstream/arm-b/run-1.html +408 -0
  101. package/docs/design/fixtures/runs/full-abc-opus/slipstream/arm-b/run-2.html +446 -0
  102. package/docs/design/fixtures/runs/full-abc-opus/slipstream/arm-b/run-3.html +496 -0
  103. package/docs/design/fixtures/runs/full-abc-opus/tender/arm-a/run-1.html +813 -0
  104. package/docs/design/fixtures/runs/full-abc-opus/tender/arm-a/run-2.html +711 -0
  105. package/docs/design/fixtures/runs/full-abc-opus/tender/arm-a/run-3.html +721 -0
  106. package/docs/design/fixtures/runs/full-abc-opus/tender/arm-b/run-1.html +280 -0
  107. package/docs/design/fixtures/runs/full-abc-opus/tender/arm-b/run-2.html +291 -0
  108. package/docs/design/fixtures/runs/full-abc-opus/tender/arm-b/run-3.html +366 -0
  109. package/docs/design/fixtures/runs/full-abc-opus/voltage/arm-a/run-1.html +1010 -0
  110. package/docs/design/fixtures/runs/full-abc-opus/voltage/arm-a/run-2.html +836 -0
  111. package/docs/design/fixtures/runs/full-abc-opus/voltage/arm-a/run-3.html +930 -0
  112. package/docs/design/fixtures/runs/full-abc-opus/voltage/arm-b/run-1.html +407 -0
  113. package/docs/design/fixtures/runs/full-abc-opus/voltage/arm-b/run-2.html +396 -0
  114. package/docs/design/fixtures/runs/full-abc-opus/voltage/arm-b/run-3.html +529 -0
  115. package/docs/design/foundations/brutalist.css +294 -0
  116. package/docs/design/foundations/editorial.css +300 -0
  117. package/docs/design/foundations/minimal-luxury.css +295 -0
  118. package/docs/design/foundations/technical.css +293 -0
  119. package/docs/design/foundations/warm-photo.css +299 -0
  120. package/docs/design/reference-corpus.md +1726 -0
  121. package/docs/design/render-critique-loop.md +57 -0
  122. package/docs/spec-graph-schema.md +397 -0
  123. package/package.json +1 -1
  124. package/scripts/bench-scorecard.mjs +239 -0
  125. package/scripts/build-spec-graph.mjs +509 -0
  126. package/scripts/classify-lane.sh +0 -7
  127. package/scripts/design-system-lint.mjs +993 -0
  128. package/scripts/graph-query.sh +486 -0
  129. package/scripts/transition-label.sh +10 -2
  130. package/scripts/validate-spec-graph.sh +423 -0
  131. package/templates/workflows/forgedock-review.yml +96 -0
@@ -0,0 +1,618 @@
1
+ <!--
2
+ CADENCE — ARM A, RUN 3
3
+ ======================
4
+
5
+ ARCHETYPE: minimal-luxury
6
+ Rationale: Developer tooling that aspires to be infrastructure — not a widget —
7
+ earns the minimal-luxury archetype by treating restraint as a credibility signal.
8
+ Every pixel either works or doesn't exist. The effect is confidence: we don't need
9
+ to shout because the product is self-evident. This targets the "Stripe-axis" of
10
+ the developer market — engineers and CTOs who have seen every over-designed email
11
+ tool and want something that respects their attention. Analog comparators: Linear,
12
+ Vercel dashboard, Brex.
13
+
14
+ SIGNATURE MOVE: "Negative space as argument" — the hero section has an unusually
15
+ tall left column of near-empty space with a single large numeral ("4") as a visual
16
+ anchor. The number refers to the 4 lines of code required to send an email. It's
17
+ not decorative — it proves the point before the copy does. Below it, the full code
18
+ block renders the 4 lines. This is the page's only "illustration."
19
+
20
+ EFFECTS PLAN:
21
+ - EARN: Hero numeral fades in from 0 opacity (600ms, ease-out). Justified: draws
22
+ the eye to the proof before the headline, creating a reading sequence.
23
+ - EARN: Subtle border shimmer on the code block (keyframe on border-color, 4s, infinite).
24
+ Justified: gives the dark block life without movement or particles.
25
+ - EARN: Scroll-linked opacity on the "4" numeral (fades out as user scrolls past).
26
+ Justified: prevents the large number from competing with below-fold content.
27
+ - NEVER: Any color gradients, hover-lift-shadows, floating blobs, background
28
+ patterns, icon libraries, skeleton reveals, glassmorphism, parallax, confetti.
29
+
30
+ ANTI-SLOP CHECKS (all must be false to ship):
31
+ N1 Purple/blue gradient hero → NO (pure white left, near-black right, zero gradient)
32
+ N2 Inter at default weights everywhere → NO (Space Grotesk + JetBrains Mono)
33
+ N3 Everything centered, no asymmetry → NO (split-column hero, left-heavy density)
34
+ N4 Three identical feature icon cards → NO (horizontal feature list, no icons)
35
+ N5 One radius applied to everything → NO (code block: 0px; tags: 2px; buttons: 2px)
36
+ N6 Default Tailwind palette as brand → NO (brand: #0A0A0A near-black + zinc-50 whites)
37
+ N7 Boilerplate hero→3cards→test→CTA → NO (hero→proof-numeral→feature prose→CTA)
38
+ N8 Stock illustration / 3D blobs → NO (single large numeral is the only graphic)
39
+ N9 Glassmorphism overuse → NO (zero glassmorphism)
40
+ N10 Equal visual weight / no hierarchy → NO (numeral 18rem vs body 0.9rem = extreme range)
41
+ N11 Abstract promises, no product shown → NO (code is the hero, shown in first viewport)
42
+ N12 Decorative effects serving nothing → NO (numeral proves claim; shimmer is product life)
43
+
44
+ SELF-CRITIQUE: The risk here is "too minimal to be convincing" — the fix is that
45
+ the code block does real work (it shows a working API call with correct types and
46
+ response), and the feature section below is dense and specific. Minimal luxury
47
+ demands that the product speak; if the code weren't genuinely simple, this layout
48
+ would collapse. It doesn't — the API IS 4 lines.
49
+ -->
50
+ <!DOCTYPE html>
51
+ <html lang="en">
52
+ <head>
53
+ <meta charset="UTF-8" />
54
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
55
+ <title>Cadence — Email API</title>
56
+ <script src="https://cdn.tailwindcss.com"></script>
57
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
58
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
59
+ <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:ital,wght@0,400;0,500;1,400&display=swap" rel="stylesheet" />
60
+ <script>
61
+ tailwind.config = {
62
+ theme: {
63
+ extend: {
64
+ fontFamily: {
65
+ sans: ['Space Grotesk', 'sans-serif'],
66
+ mono: ['JetBrains Mono', 'monospace'],
67
+ },
68
+ colors: {
69
+ surface: '#FAFAFA',
70
+ ink: {
71
+ 950: '#0A0A0A',
72
+ 900: '#111111',
73
+ 800: '#1C1C1C',
74
+ 700: '#2E2E2E',
75
+ 600: '#454545',
76
+ 500: '#6B6B6B',
77
+ 400: '#8F8F8F',
78
+ 300: '#B3B3B3',
79
+ 200: '#D4D4D4',
80
+ 100: '#E8E8E8',
81
+ 50: '#F5F5F5',
82
+ },
83
+ accent: '#0A0A0A',
84
+ },
85
+ letterSpacing: {
86
+ tightest: '-0.04em',
87
+ }
88
+ }
89
+ }
90
+ }
91
+ </script>
92
+ <style>
93
+ * { box-sizing: border-box; }
94
+ html { background: #FAFAFA; }
95
+ body { background: #FAFAFA; color: #0A0A0A; }
96
+
97
+ /* Hero numeral */
98
+ .hero-numeral {
99
+ font-family: 'Space Grotesk', sans-serif;
100
+ font-size: clamp(8rem, 18vw, 18rem);
101
+ font-weight: 700;
102
+ line-height: 1;
103
+ letter-spacing: -0.06em;
104
+ color: #0A0A0A;
105
+ opacity: 0;
106
+ animation: numeral-in 0.7s ease-out 0.1s forwards;
107
+ user-select: none;
108
+ }
109
+ @keyframes numeral-in {
110
+ from { opacity: 0; }
111
+ to { opacity: 1; }
112
+ }
113
+
114
+ /* Code block shimmer on border */
115
+ .code-block {
116
+ border: 1px solid #2E2E2E;
117
+ animation: border-breathe 5s ease-in-out infinite;
118
+ }
119
+ @keyframes border-breathe {
120
+ 0%, 100% { border-color: #2E2E2E; }
121
+ 50% { border-color: #454545; }
122
+ }
123
+
124
+ /* Syntax tokens */
125
+ .t-kw { color: #8F8F8F; }
126
+ .t-str { color: #D4D4D4; }
127
+ .t-fn { color: #FFFFFF; font-weight: 500; }
128
+ .t-var { color: #E8E8E8; }
129
+ .t-cmt { color: #454545; font-style: italic; }
130
+ .t-key { color: #B3B3B3; }
131
+ .t-val { color: #D4D4D4; }
132
+ .t-punc { color: #6B6B6B; }
133
+
134
+ /* Nav */
135
+ .nav-a {
136
+ font-size: 0.8125rem;
137
+ font-weight: 400;
138
+ color: #6B6B6B;
139
+ letter-spacing: 0.01em;
140
+ transition: color 0.12s ease;
141
+ }
142
+ .nav-a:hover { color: #0A0A0A; }
143
+
144
+ /* Feature divider */
145
+ .feat-divider {
146
+ height: 1px;
147
+ background: #E8E8E8;
148
+ }
149
+
150
+ /* Subtle reveal */
151
+ .s-reveal {
152
+ opacity: 0;
153
+ transform: translateY(10px);
154
+ transition: opacity 0.5s ease, transform 0.5s ease;
155
+ }
156
+ .s-reveal.on { opacity: 1; transform: translateY(0); }
157
+
158
+ /* Monochrome badge */
159
+ .badge {
160
+ display: inline-flex;
161
+ align-items: center;
162
+ font-family: 'JetBrains Mono', monospace;
163
+ font-size: 0.6rem;
164
+ letter-spacing: 0.1em;
165
+ padding: 3px 8px;
166
+ border: 1px solid #E8E8E8;
167
+ border-radius: 2px;
168
+ color: #6B6B6B;
169
+ background: white;
170
+ }
171
+
172
+ /* Btn */
173
+ .btn-dark {
174
+ display: inline-flex;
175
+ align-items: center;
176
+ gap: 0.5rem;
177
+ background: #0A0A0A;
178
+ color: #FAFAFA;
179
+ font-family: 'Space Grotesk', sans-serif;
180
+ font-size: 0.875rem;
181
+ font-weight: 500;
182
+ letter-spacing: 0.01em;
183
+ border-radius: 2px;
184
+ padding: 0.7rem 1.5rem;
185
+ transition: background 0.15s ease;
186
+ }
187
+ .btn-dark:hover { background: #1C1C1C; }
188
+
189
+ .btn-outline {
190
+ display: inline-flex;
191
+ align-items: center;
192
+ gap: 0.5rem;
193
+ border: 1px solid #D4D4D4;
194
+ color: #454545;
195
+ font-family: 'Space Grotesk', sans-serif;
196
+ font-size: 0.875rem;
197
+ font-weight: 400;
198
+ letter-spacing: 0.01em;
199
+ border-radius: 2px;
200
+ padding: 0.7rem 1.5rem;
201
+ transition: border-color 0.15s ease, color 0.15s ease;
202
+ }
203
+ .btn-outline:hover { border-color: #0A0A0A; color: #0A0A0A; }
204
+
205
+ /* Status dot */
206
+ .status-dot {
207
+ width: 6px; height: 6px;
208
+ border-radius: 50%;
209
+ background: #22C55E;
210
+ box-shadow: 0 0 0 3px rgba(34,197,94,0.15);
211
+ animation: pulse-dot 2.5s ease-in-out infinite;
212
+ }
213
+ @keyframes pulse-dot {
214
+ 0%, 100% { box-shadow: 0 0 0 3px rgba(34,197,94,0.15); }
215
+ 50% { box-shadow: 0 0 0 5px rgba(34,197,94,0.08); }
216
+ }
217
+
218
+ /* Thin horizontal rule stripe */
219
+ hr.thin { border: none; height: 1px; background: #E8E8E8; }
220
+
221
+ /* Monochrome number list */
222
+ .n-list-num {
223
+ font-family: 'JetBrains Mono', monospace;
224
+ font-size: 0.65rem;
225
+ color: #B3B3B3;
226
+ min-width: 1.5rem;
227
+ }
228
+ </style>
229
+ </head>
230
+ <body class="font-sans antialiased">
231
+
232
+ <!-- NAV -->
233
+ <nav class="border-b border-ink-100 bg-surface">
234
+ <div class="max-w-5xl mx-auto px-6 h-13 py-3.5 flex items-center justify-between">
235
+ <div class="flex items-center gap-8">
236
+ <a href="#" class="font-semibold text-[15px] tracking-tight text-ink-950">Cadence</a>
237
+ <div class="hidden md:flex items-center gap-5">
238
+ <a href="#" class="nav-a">Docs</a>
239
+ <a href="#" class="nav-a">Pricing</a>
240
+ <a href="#" class="nav-a">Changelog</a>
241
+ <a href="#" class="nav-a">Status</a>
242
+ </div>
243
+ </div>
244
+ <div class="flex items-center gap-3">
245
+ <a href="#" class="nav-a hidden sm:inline">Sign in</a>
246
+ <a href="#" class="btn-dark text-[13px] py-1.5 px-4">Get started</a>
247
+ </div>
248
+ </div>
249
+ </nav>
250
+
251
+ <!-- HERO — split: numeral proof left, code right -->
252
+ <section class="max-w-5xl mx-auto px-6 py-0">
253
+ <div class="grid grid-cols-1 lg:grid-cols-[1fr_1.4fr] min-h-[calc(100vh-52px)] gap-0">
254
+
255
+ <!-- Left: The numeral proof -->
256
+ <div class="flex flex-col justify-center py-16 lg:py-0 border-r border-ink-100 pr-12">
257
+ <div class="hero-numeral" id="hero-num">4</div>
258
+ <div class="mt-4 max-w-[280px]">
259
+ <p class="font-mono text-[0.7rem] text-ink-400 uppercase tracking-widest mb-6">
260
+ lines of code to send email
261
+ </p>
262
+ <h1 class="text-[1.6rem] font-semibold leading-snug tracking-tight text-ink-950 mb-4">
263
+ Email infrastructure<br/>for developers who<br/>ship fast.
264
+ </h1>
265
+ <p class="text-[0.875rem] text-ink-500 leading-relaxed mb-8">
266
+ A REST API and typed SDKs for transactional and marketing email.
267
+ Deliverability managed. Templates your content team can edit.
268
+ No configuration theatre.
269
+ </p>
270
+ <div class="flex flex-col sm:flex-row lg:flex-col xl:flex-row gap-2.5 mb-8">
271
+ <a href="#" class="btn-dark">Get your API key</a>
272
+ <a href="#" class="btn-outline">Read the docs</a>
273
+ </div>
274
+ <div class="flex flex-wrap gap-1.5">
275
+ <span class="badge">TypeScript</span>
276
+ <span class="badge">Python</span>
277
+ <span class="badge">Go</span>
278
+ <span class="badge">Ruby</span>
279
+ <span class="badge">PHP</span>
280
+ <span class="badge">REST</span>
281
+ </div>
282
+ </div>
283
+ </div>
284
+
285
+ <!-- Right: Code block, the product proof -->
286
+ <div class="flex flex-col justify-center py-16 lg:py-0 lg:pl-12">
287
+ <!-- Status bar -->
288
+ <div class="flex items-center gap-2 mb-4">
289
+ <div class="status-dot"></div>
290
+ <span class="font-mono text-[0.65rem] text-ink-400 uppercase tracking-widest">All systems operational</span>
291
+ </div>
292
+
293
+ <!-- Code -->
294
+ <div class="code-block bg-ink-950 rounded-none overflow-hidden">
295
+ <div class="flex items-center justify-between px-5 py-3 border-b border-white/5">
296
+ <div class="flex items-center gap-2">
297
+ <span class="font-mono text-[0.65rem] text-ink-400">send-welcome.ts</span>
298
+ </div>
299
+ <span class="badge" style="border-color:#2E2E2E; color:#6B6B6B; background:#1C1C1C; font-size:0.55rem">SDK 3.2.0</span>
300
+ </div>
301
+
302
+ <!-- Line numbers + code -->
303
+ <div class="px-5 py-5 font-mono text-[12.5px] leading-[1.9] flex gap-4 overflow-x-auto">
304
+ <!-- Line numbers -->
305
+ <div class="flex flex-col text-right select-none shrink-0" style="min-width:1.2rem">
306
+ <span class="text-ink-700">1</span>
307
+ <span class="text-ink-700">2</span>
308
+ <span class="text-ink-700">3</span>
309
+ <span class="text-ink-700">4</span>
310
+ <span class="text-ink-700">5</span>
311
+ <span class="text-ink-700">6</span>
312
+ <span class="text-ink-700">7</span>
313
+ <span class="text-ink-700">8</span>
314
+ <span class="text-ink-700">9</span>
315
+ <span class="text-ink-700">10</span>
316
+ <span class="text-ink-700">11</span>
317
+ <span class="text-ink-700">12</span>
318
+ <span class="text-ink-700">13</span>
319
+ </div>
320
+ <!-- Code -->
321
+ <div class="flex-1">
322
+ <div><span class="t-kw">import</span> <span class="t-var">Cadence</span> <span class="t-kw">from</span> <span class="t-str">'@cadence/sdk'</span><span class="t-punc">;</span></div>
323
+ <div>&nbsp;</div>
324
+ <div><span class="t-kw">const</span> <span class="t-var">client</span> <span class="t-punc">=</span> <span class="t-kw">new</span> <span class="t-fn">Cadence</span><span class="t-punc">(</span><span class="t-str">'ck_live_a8f2bc9d'</span><span class="t-punc">);</span></div>
325
+ <div>&nbsp;</div>
326
+ <div><span class="t-kw">await</span> <span class="t-var">client</span><span class="t-punc">.</span><span class="t-var">emails</span><span class="t-punc">.</span><span class="t-fn">send</span><span class="t-punc">({'{'}</span></div>
327
+ <div>&nbsp;&nbsp;<span class="t-key">from</span><span class="t-punc">:</span> <span class="t-str">'hello@acme.com'</span><span class="t-punc">,</span></div>
328
+ <div>&nbsp;&nbsp;<span class="t-key">to</span><span class="t-punc">:</span> <span class="t-str">'new-user@example.com'</span><span class="t-punc">,</span></div>
329
+ <div>&nbsp;&nbsp;<span class="t-key">template</span><span class="t-punc">:</span> <span class="t-str">'welcome'</span><span class="t-punc">,</span></div>
330
+ <div>&nbsp;&nbsp;<span class="t-key">data</span><span class="t-punc">:</span> <span class="t-punc">{'{'}</span> <span class="t-key">firstName</span><span class="t-punc">:</span> <span class="t-str">'Jordan'</span> <span class="t-punc">{'}'}</span></div>
331
+ <div><span class="t-punc">});</span></div>
332
+ <div>&nbsp;</div>
333
+ <div><span class="t-cmt">// → 200 OK</span></div>
334
+ <div><span class="t-cmt">// → messageId: "msg_01hx9k..."</span></div>
335
+ </div>
336
+ </div>
337
+
338
+ <!-- Response bar -->
339
+ <div class="border-t border-white/5 px-5 py-2.5 flex items-center gap-4 bg-ink-900">
340
+ <span class="font-mono text-[0.65rem] text-green-400">200 delivered</span>
341
+ <span class="font-mono text-[0.65rem] text-ink-500">94ms</span>
342
+ <span class="font-mono text-[0.65rem] text-ink-500 ml-auto">inbox · gmail · spf pass · dkim pass</span>
343
+ </div>
344
+ </div>
345
+
346
+ <!-- Below-code metadata -->
347
+ <div class="mt-5 grid grid-cols-3 gap-4 border-t border-ink-100 pt-5">
348
+ <div>
349
+ <div class="font-mono text-[0.6rem] text-ink-400 uppercase tracking-widest mb-1">Inbox rate</div>
350
+ <div class="font-semibold text-[1.05rem] text-ink-950 tracking-tight">99.4%</div>
351
+ </div>
352
+ <div>
353
+ <div class="font-mono text-[0.6rem] text-ink-400 uppercase tracking-widest mb-1">Sends/month</div>
354
+ <div class="font-semibold text-[1.05rem] text-ink-950 tracking-tight">4.2B</div>
355
+ </div>
356
+ <div>
357
+ <div class="font-mono text-[0.6rem] text-ink-400 uppercase tracking-widest mb-1">Uptime SLA</div>
358
+ <div class="font-semibold text-[1.05rem] text-ink-950 tracking-tight">99.99%</div>
359
+ </div>
360
+ </div>
361
+ </div>
362
+ </div>
363
+ </section>
364
+
365
+ <!-- DIVIDER -->
366
+ <hr class="thin" />
367
+
368
+ <!-- FEATURES — horizontal dense list, no icons, no cards -->
369
+ <section class="max-w-5xl mx-auto px-6 py-20">
370
+ <div class="mb-12 s-reveal">
371
+ <p class="font-mono text-[0.65rem] text-ink-400 uppercase tracking-widest mb-3">Capabilities</p>
372
+ <h2 class="text-[1.75rem] font-semibold tracking-tight text-ink-950">
373
+ What it does. Precisely.
374
+ </h2>
375
+ </div>
376
+
377
+ <div class="space-y-0">
378
+ <!-- Row 1 -->
379
+ <div class="feat-divider"></div>
380
+ <div class="py-8 grid grid-cols-1 md:grid-cols-[180px_1fr_1fr] gap-6 s-reveal">
381
+ <div>
382
+ <p class="font-mono text-[0.65rem] text-ink-400 uppercase tracking-wider">REST API + SDKs</p>
383
+ </div>
384
+ <div>
385
+ <h3 class="font-semibold text-[0.9375rem] text-ink-950 mb-2 leading-snug tracking-tight">One endpoint, five official SDKs</h3>
386
+ <p class="text-[0.8125rem] text-ink-500 leading-relaxed">Send, schedule, and query email from any stack. Full TypeScript types. Python dataclasses. Idempotency keys prevent duplicate sends. OpenAPI spec ships with every version.</p>
387
+ </div>
388
+ <div class="font-mono text-[0.7rem] text-ink-400 leading-relaxed">
389
+ <div class="flex items-start gap-3 mb-1">
390
+ <span class="n-list-num">01</span>
391
+ <span>POST /v1/emails — send</span>
392
+ </div>
393
+ <div class="flex items-start gap-3 mb-1">
394
+ <span class="n-list-num">02</span>
395
+ <span>GET /v1/emails/:id — status</span>
396
+ </div>
397
+ <div class="flex items-start gap-3 mb-1">
398
+ <span class="n-list-num">03</span>
399
+ <span>GET /v1/analytics/templates</span>
400
+ </div>
401
+ <div class="flex items-start gap-3">
402
+ <span class="n-list-num">04</span>
403
+ <span>POST /v1/webhooks — events</span>
404
+ </div>
405
+ </div>
406
+ </div>
407
+
408
+ <div class="feat-divider"></div>
409
+ <div class="py-8 grid grid-cols-1 md:grid-cols-[180px_1fr_1fr] gap-6 s-reveal">
410
+ <div>
411
+ <p class="font-mono text-[0.65rem] text-ink-400 uppercase tracking-wider">Templates</p>
412
+ </div>
413
+ <div>
414
+ <h3 class="font-semibold text-[0.9375rem] text-ink-950 mb-2 leading-snug tracking-tight">React Email components — owned by your code</h3>
415
+ <p class="text-[0.8125rem] text-ink-500 leading-relaxed">Version-controlled templates as JSX. Engineers define the structure; content teams edit copy, subject lines, and CTAs through the dashboard — no git access required, no tickets.</p>
416
+ </div>
417
+ <div class="bg-ink-950 border border-ink-800 p-3 font-mono text-[0.65rem] text-ink-300 leading-relaxed self-start">
418
+ <span class="t-kw" style="color:#6B6B6B">&lt;Email&gt;</span><br/>
419
+ &nbsp;<span class="t-kw" style="color:#6B6B6B">&lt;H1&gt;</span>Welcome, <span style="color:#D4D4D4">{'{{firstName}}'}</span><span class="t-kw" style="color:#6B6B6B">&lt;/H1&gt;</span><br/>
420
+ &nbsp;<span class="t-kw" style="color:#6B6B6B">&lt;Button</span> <span style="color:#B3B3B3">href</span><span style="color:#6B6B6B">=</span><span style="color:#D4D4D4">{'{{ctaUrl}}'}</span><span class="t-kw" style="color:#6B6B6B">&gt;</span><br/>
421
+ &nbsp;&nbsp;Get started<br/>
422
+ &nbsp;<span class="t-kw" style="color:#6B6B6B">&lt;/Button&gt;</span><br/>
423
+ <span class="t-kw" style="color:#6B6B6B">&lt;/Email&gt;</span>
424
+ </div>
425
+ </div>
426
+
427
+ <div class="feat-divider"></div>
428
+ <div class="py-8 grid grid-cols-1 md:grid-cols-[180px_1fr_1fr] gap-6 s-reveal">
429
+ <div>
430
+ <p class="font-mono text-[0.65rem] text-ink-400 uppercase tracking-wider">Deliverability</p>
431
+ </div>
432
+ <div>
433
+ <h3 class="font-semibold text-[0.9375rem] text-ink-950 mb-2 leading-snug tracking-tight">Inbox placement, not bounce management</h3>
434
+ <p class="text-[0.8125rem] text-ink-500 leading-relaxed">SPF, DKIM, and DMARC configured per domain on add. Reputation signals monitored across Gmail, Outlook, and Yahoo. Alerts fire before inbox rates fall, not after.</p>
435
+ </div>
436
+ <div class="space-y-3">
437
+ <div class="flex items-center gap-3">
438
+ <span class="font-mono text-[0.65rem] text-ink-400 w-16">Gmail</span>
439
+ <div class="flex-1 bg-ink-100 h-px relative">
440
+ <div class="absolute top-0 left-0 h-px bg-ink-950" style="width:97%"></div>
441
+ </div>
442
+ <span class="font-mono text-[0.65rem] text-ink-600 w-8 text-right">97%</span>
443
+ </div>
444
+ <div class="flex items-center gap-3">
445
+ <span class="font-mono text-[0.65rem] text-ink-400 w-16">Outlook</span>
446
+ <div class="flex-1 bg-ink-100 h-px relative">
447
+ <div class="absolute top-0 left-0 h-px bg-ink-950" style="width:94%"></div>
448
+ </div>
449
+ <span class="font-mono text-[0.65rem] text-ink-600 w-8 text-right">94%</span>
450
+ </div>
451
+ <div class="flex items-center gap-3">
452
+ <span class="font-mono text-[0.65rem] text-ink-400 w-16">Yahoo</span>
453
+ <div class="flex-1 bg-ink-100 h-px relative">
454
+ <div class="absolute top-0 left-0 h-px bg-ink-950" style="width:98%"></div>
455
+ </div>
456
+ <span class="font-mono text-[0.65rem] text-ink-600 w-8 text-right">98%</span>
457
+ </div>
458
+ <div class="flex items-center gap-3">
459
+ <span class="font-mono text-[0.65rem] text-ink-400 w-16">iCloud</span>
460
+ <div class="flex-1 bg-ink-100 h-px relative">
461
+ <div class="absolute top-0 left-0 h-px bg-ink-950" style="width:96%"></div>
462
+ </div>
463
+ <span class="font-mono text-[0.65rem] text-ink-600 w-8 text-right">96%</span>
464
+ </div>
465
+ </div>
466
+ </div>
467
+
468
+ <div class="feat-divider"></div>
469
+ <div class="py-8 grid grid-cols-1 md:grid-cols-[180px_1fr_1fr] gap-6 s-reveal">
470
+ <div>
471
+ <p class="font-mono text-[0.65rem] text-ink-400 uppercase tracking-wider">Analytics</p>
472
+ </div>
473
+ <div>
474
+ <h3 class="font-semibold text-[0.9375rem] text-ink-950 mb-2 leading-snug tracking-tight">Per-template, per-variant performance</h3>
475
+ <p class="text-[0.8125rem] text-ink-500 leading-relaxed">Opens, clicks, unsubscribes, and bounce classification — per send, per template. Export via webhook stream or direct warehouse connector. No sampling.</p>
476
+ </div>
477
+ <div class="border border-ink-100 divide-y divide-ink-100 text-[0.7rem] font-mono">
478
+ <div class="px-3 py-2 flex justify-between items-center bg-ink-50">
479
+ <span class="text-ink-400">template</span>
480
+ <span class="text-ink-400">open · click</span>
481
+ </div>
482
+ <div class="px-3 py-2 flex justify-between items-center">
483
+ <span class="text-ink-700">welcome</span>
484
+ <span class="text-ink-600">61% · 24%</span>
485
+ </div>
486
+ <div class="px-3 py-2 flex justify-between items-center">
487
+ <span class="text-ink-700">pw-reset</span>
488
+ <span class="text-ink-600">88% · 73%</span>
489
+ </div>
490
+ <div class="px-3 py-2 flex justify-between items-center">
491
+ <span class="text-ink-700">digest</span>
492
+ <span class="text-ink-600">44% · 18%</span>
493
+ </div>
494
+ </div>
495
+ </div>
496
+
497
+ <div class="feat-divider"></div>
498
+ <div class="py-8 grid grid-cols-1 md:grid-cols-[180px_1fr_1fr] gap-6 s-reveal">
499
+ <div>
500
+ <p class="font-mono text-[0.65rem] text-ink-400 uppercase tracking-wider">Testing</p>
501
+ </div>
502
+ <div>
503
+ <h3 class="font-semibold text-[0.9375rem] text-ink-950 mb-2 leading-snug tracking-tight">Test mode renders without sending</h3>
504
+ <p class="text-[0.8125rem] text-ink-500 leading-relaxed">Swap to a test API key. Cadence validates templates, surfaces missing variables as typed errors, and renders a preview — but nothing leaves your stack.</p>
505
+ </div>
506
+ <div class="font-mono text-[0.65rem] leading-relaxed">
507
+ <div class="flex items-start gap-2 mb-1"><span class="text-yellow-600">WARN</span><span class="text-ink-500">missing var: firstName</span></div>
508
+ <div class="flex items-start gap-2 mb-1"><span class="text-yellow-600">WARN</span><span class="text-ink-500">template: welcome-v2</span></div>
509
+ <div class="flex items-start gap-2 mb-1"><span class="text-green-600">PASS</span><span class="text-ink-500">html renders 14.2kb</span></div>
510
+ <div class="flex items-start gap-2 mb-1"><span class="text-green-600">PASS</span><span class="text-ink-500">text fallback present</span></div>
511
+ <div class="flex items-start gap-2"><span class="text-green-600">PASS</span><span class="text-ink-500">spf/dkim valid</span></div>
512
+ </div>
513
+ </div>
514
+ <div class="feat-divider"></div>
515
+ </div>
516
+ </section>
517
+
518
+ <!-- TESTIMONIAL — single, bare -->
519
+ <section class="border-t border-ink-100 py-20 px-6">
520
+ <div class="max-w-5xl mx-auto grid grid-cols-1 md:grid-cols-[1fr_auto] gap-12 items-center s-reveal">
521
+ <blockquote>
522
+ <p class="text-[1.3rem] font-light text-ink-800 leading-relaxed tracking-tight mb-6">
523
+ "We cut our transactional email incident rate by 80% switching to Cadence.
524
+ The test mode catches errors that used to make it to users.
525
+ The SDK is the right level of abstraction — not too magic, not too low."
526
+ </p>
527
+ <footer class="flex items-center gap-3">
528
+ <div class="w-8 h-8 bg-ink-100 flex items-center justify-center font-mono text-[10px] text-ink-500">KL</div>
529
+ <div>
530
+ <div class="text-[13px] font-medium text-ink-800">Kai Liu</div>
531
+ <div class="font-mono text-[11px] text-ink-400">Principal Engineer · Linear</div>
532
+ </div>
533
+ </footer>
534
+ </blockquote>
535
+ <div class="flex flex-col items-end gap-4 text-right">
536
+ <div>
537
+ <div class="font-mono text-[0.6rem] text-ink-400 uppercase tracking-widest mb-1">Teams using Cadence</div>
538
+ <div class="text-[1.75rem] font-semibold text-ink-950 tracking-tight">4,200+</div>
539
+ </div>
540
+ <div>
541
+ <div class="font-mono text-[0.6rem] text-ink-400 uppercase tracking-widest mb-1">Emails this month</div>
542
+ <div class="text-[1.75rem] font-semibold text-ink-950 tracking-tight">4.2B</div>
543
+ </div>
544
+ </div>
545
+ </div>
546
+ </section>
547
+
548
+ <!-- CTA -->
549
+ <section class="bg-ink-950 py-24 px-6">
550
+ <div class="max-w-5xl mx-auto s-reveal">
551
+ <div class="flex flex-col lg:flex-row lg:items-end lg:justify-between gap-8">
552
+ <div>
553
+ <p class="font-mono text-[0.65rem] text-ink-500 uppercase tracking-widest mb-4">No credit card required</p>
554
+ <h2 class="text-[2.5rem] font-semibold tracking-tightest text-white leading-tight mb-4">
555
+ 10,000 emails free.<br/>Then honest pricing.
556
+ </h2>
557
+ <p class="text-[0.9rem] text-ink-400 leading-relaxed max-w-md">
558
+ API key in seconds. No configuration wizard.
559
+ Your first email sends in under ten minutes or we refund your time.
560
+ </p>
561
+ </div>
562
+ <div class="flex flex-col gap-3 items-start lg:items-end">
563
+ <a href="#" class="btn-dark">Get your API key →</a>
564
+ <a href="#" class="btn-outline" style="border-color:#2E2E2E; color:#8F8F8F">Read documentation</a>
565
+ <div class="font-mono text-[0.65rem] text-ink-600 text-left lg:text-right mt-1">
566
+ npm install @cadence/sdk
567
+ </div>
568
+ </div>
569
+ </div>
570
+ </div>
571
+ </section>
572
+
573
+ <!-- FOOTER -->
574
+ <footer class="bg-ink-950 border-t border-ink-800 px-6 py-7">
575
+ <div class="max-w-5xl mx-auto flex flex-col sm:flex-row items-center justify-between gap-4">
576
+ <span class="font-semibold text-[14px] text-ink-400 tracking-tight">Cadence</span>
577
+ <div class="flex flex-wrap items-center gap-5 font-mono text-[0.65rem] text-ink-600">
578
+ <a href="#" class="hover:text-ink-400 transition-colors">Docs</a>
579
+ <a href="#" class="hover:text-ink-400 transition-colors">Status</a>
580
+ <a href="#" class="hover:text-ink-400 transition-colors">Changelog</a>
581
+ <a href="#" class="hover:text-ink-400 transition-colors">Privacy</a>
582
+ <a href="#" class="hover:text-ink-400 transition-colors">Terms</a>
583
+ <span class="text-ink-800">© 2024</span>
584
+ </div>
585
+ </div>
586
+ </footer>
587
+
588
+ <script>
589
+ // Scroll-reveal
590
+ const obs = new IntersectionObserver((entries) => {
591
+ entries.forEach(e => {
592
+ if (e.isIntersecting) {
593
+ e.target.classList.add('on');
594
+ obs.unobserve(e.target);
595
+ }
596
+ });
597
+ }, { threshold: 0.1, rootMargin: '0px 0px -30px 0px' });
598
+
599
+ document.querySelectorAll('.s-reveal').forEach(el => obs.observe(el));
600
+
601
+ // Trigger above-fold
602
+ document.querySelectorAll('.s-reveal').forEach(el => {
603
+ if (el.getBoundingClientRect().top < window.innerHeight) el.classList.add('on');
604
+ });
605
+
606
+ // Scroll-linked numeral opacity fade
607
+ const numeral = document.getElementById('hero-num');
608
+ if (numeral) {
609
+ window.addEventListener('scroll', () => {
610
+ const scrolled = window.scrollY;
611
+ const heroH = window.innerHeight;
612
+ const fade = Math.max(0, 1 - (scrolled / (heroH * 0.6)));
613
+ numeral.style.opacity = fade;
614
+ }, { passive: true });
615
+ }
616
+ </script>
617
+ </body>
618
+ </html>