@rizom/site-rizom-ai 0.2.0-alpha.166 → 0.2.0-alpha.167
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/package.json +4 -4
- package/src/brain-screens.tsx +465 -0
- package/src/brain.tsx +418 -0
- package/src/home.tsx +17 -192
- package/src/layout.tsx +52 -18
- package/src/routes.ts +32 -4
- package/src/shared.tsx +56 -0
- package/src/site.ts +4 -2
package/src/brain.tsx
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
/** @jsxImportSource preact */
|
|
2
|
+
import type { JSX } from "preact";
|
|
3
|
+
import type { SiteSectionGroup } from "@rizom/site";
|
|
4
|
+
import { defineSection, sectionGroup, z } from "@rizom/site-sections";
|
|
5
|
+
import { Section, renderHighlightedText } from "@rizom/site-rizom";
|
|
6
|
+
import {
|
|
7
|
+
Band,
|
|
8
|
+
CtaRow,
|
|
9
|
+
SectCap,
|
|
10
|
+
Trio,
|
|
11
|
+
trioSchema,
|
|
12
|
+
ctaSchema,
|
|
13
|
+
ROOM_HIGHLIGHT_CLS,
|
|
14
|
+
} from "./shared";
|
|
15
|
+
import {
|
|
16
|
+
BrainScreenStyles,
|
|
17
|
+
StudioScreen,
|
|
18
|
+
ChatScreen,
|
|
19
|
+
IntegrationsScreen,
|
|
20
|
+
DashboardScreen,
|
|
21
|
+
} from "./brain-screens";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The /brain room — the product's own page. The consolidated homepage grew
|
|
25
|
+
* two pages long because it told the umbrella story and the product story at
|
|
26
|
+
* once; the product story lives here, told as the brain's life with its owner
|
|
27
|
+
* in four chapters — capture, ask, see it run, connect — each illustrated by a
|
|
28
|
+
* real interface screen, then the data principles and the quickstart.
|
|
29
|
+
*
|
|
30
|
+
* The namespace ("brain") matches the route id, so each section stores as
|
|
31
|
+
* site-content/brain/<section>.md and resolves as "brain:<section>".
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/* ============ chapter heading ============ */
|
|
35
|
+
|
|
36
|
+
/* The shared chapter head: a numbered cap, a display headline with an accent
|
|
37
|
+
em, and a standfirst. Used by every chapter so the copy stays authored. */
|
|
38
|
+
function ChapterHead({
|
|
39
|
+
cap,
|
|
40
|
+
capNote,
|
|
41
|
+
headline,
|
|
42
|
+
intro,
|
|
43
|
+
}: {
|
|
44
|
+
cap: string;
|
|
45
|
+
capNote?: string | undefined;
|
|
46
|
+
headline: string;
|
|
47
|
+
intro: string;
|
|
48
|
+
}): JSX.Element {
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
<SectCap lead={cap} trail={capNote} />
|
|
52
|
+
<h2 className="reveal reveal-delay-1 mt-3.5 max-w-[20em] font-display text-[clamp(28px,3vw,40px)] font-[465] leading-[1.1] tracking-[-0.014em] text-theme [font-variation-settings:'SOFT'_78,'opsz'_84]">
|
|
53
|
+
{renderHighlightedText(headline, ROOM_HIGHLIGHT_CLS)}
|
|
54
|
+
</h2>
|
|
55
|
+
<p className="reveal reveal-delay-2 mt-4 max-w-[62ch] font-body text-[17px] leading-[1.7] text-theme-muted">
|
|
56
|
+
{intro}
|
|
57
|
+
</p>
|
|
58
|
+
</>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* ============ hero ============ */
|
|
63
|
+
|
|
64
|
+
const heroSchema = z.object({
|
|
65
|
+
eyebrow: z.string(),
|
|
66
|
+
provenance: z.string(),
|
|
67
|
+
headline: z.string(),
|
|
68
|
+
standfirst: z.string(),
|
|
69
|
+
primaryCta: ctaSchema,
|
|
70
|
+
secondaryCta: ctaSchema,
|
|
71
|
+
chips: z.array(z.string()),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
function BrainHeroSection({
|
|
75
|
+
eyebrow,
|
|
76
|
+
provenance,
|
|
77
|
+
headline,
|
|
78
|
+
standfirst,
|
|
79
|
+
primaryCta,
|
|
80
|
+
secondaryCta,
|
|
81
|
+
chips,
|
|
82
|
+
}: z.infer<typeof heroSchema>): JSX.Element {
|
|
83
|
+
return (
|
|
84
|
+
<Section
|
|
85
|
+
id="brain-hero"
|
|
86
|
+
className="relative overflow-hidden pt-16 pb-8 md:pt-20"
|
|
87
|
+
>
|
|
88
|
+
<div
|
|
89
|
+
aria-hidden="true"
|
|
90
|
+
className="pointer-events-none absolute -inset-x-[10%] -inset-y-[30%] bg-[radial-gradient(680px_360px_at_14%_8%,rgb(from_var(--color-accent)_r_g_b_/_0.14),transparent_66%)]"
|
|
91
|
+
/>
|
|
92
|
+
<div className="relative">
|
|
93
|
+
<SectCap lead={eyebrow} trail={provenance} />
|
|
94
|
+
<h1 className="mt-[18px] max-w-[15.5em] font-display text-[clamp(36px,4.8vw,64px)] font-[448] leading-[1.04] tracking-[-0.02em] text-theme [font-variation-settings:'SOFT'_88,'opsz'_110]">
|
|
95
|
+
{renderHighlightedText(headline, ROOM_HIGHLIGHT_CLS)}
|
|
96
|
+
</h1>
|
|
97
|
+
<p className="mt-4 max-w-[52ch] font-body text-[20px] leading-[1.7] text-theme-muted">
|
|
98
|
+
{standfirst}
|
|
99
|
+
</p>
|
|
100
|
+
<CtaRow
|
|
101
|
+
primaryCta={primaryCta}
|
|
102
|
+
secondaryCta={secondaryCta}
|
|
103
|
+
className="mt-[26px]"
|
|
104
|
+
/>
|
|
105
|
+
<div className="mt-9 flex flex-wrap gap-2.5">
|
|
106
|
+
{chips.map((chip) => (
|
|
107
|
+
<span
|
|
108
|
+
key={chip}
|
|
109
|
+
className="rounded-full border border-theme px-[13px] py-1.5 font-label text-[10.5px] tracking-[0.06em] text-theme-light"
|
|
110
|
+
>
|
|
111
|
+
{chip}
|
|
112
|
+
</span>
|
|
113
|
+
))}
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</Section>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* ============ shared authored checklist ============ */
|
|
121
|
+
|
|
122
|
+
function Checks({ items }: { items: string[] }): JSX.Element {
|
|
123
|
+
return (
|
|
124
|
+
<ul className="mt-[18px] max-w-[40ch] font-body text-[15.5px] text-theme-light">
|
|
125
|
+
{items.map((item) => (
|
|
126
|
+
<li
|
|
127
|
+
key={item}
|
|
128
|
+
className="flex gap-2.5 border-b border-theme-light py-[7px]"
|
|
129
|
+
>
|
|
130
|
+
<span aria-hidden="true" className="font-label text-secondary">
|
|
131
|
+
✓
|
|
132
|
+
</span>
|
|
133
|
+
{item}
|
|
134
|
+
</li>
|
|
135
|
+
))}
|
|
136
|
+
</ul>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* ============ 01 · capture — the studio ============ */
|
|
141
|
+
|
|
142
|
+
const captureSchema = z.object({
|
|
143
|
+
cap: z.string(),
|
|
144
|
+
capNote: z.string().optional(),
|
|
145
|
+
headline: z.string(),
|
|
146
|
+
intro: z.string(),
|
|
147
|
+
checks: z.array(z.string()),
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
function BrainCaptureSection({
|
|
151
|
+
cap,
|
|
152
|
+
capNote,
|
|
153
|
+
headline,
|
|
154
|
+
intro,
|
|
155
|
+
checks,
|
|
156
|
+
}: z.infer<typeof captureSchema>): JSX.Element {
|
|
157
|
+
return (
|
|
158
|
+
<Section id="capture" className="py-14">
|
|
159
|
+
{/* Screen styles are global; emitted once here, the first screen chapter. */}
|
|
160
|
+
<BrainScreenStyles />
|
|
161
|
+
<SectCap lead={cap} trail={capNote} />
|
|
162
|
+
<div className="mt-4 grid items-center gap-11 lg:grid-cols-[4fr_8fr]">
|
|
163
|
+
<div>
|
|
164
|
+
<h2 className="reveal reveal-delay-1 font-display text-[clamp(26px,2.6vw,34px)] font-[465] leading-[1.12] tracking-[-0.012em] text-theme [font-variation-settings:'SOFT'_78,'opsz'_84]">
|
|
165
|
+
{renderHighlightedText(headline, ROOM_HIGHLIGHT_CLS)}
|
|
166
|
+
</h2>
|
|
167
|
+
<p className="reveal reveal-delay-2 mt-4 font-body text-[16.5px] leading-[1.7] text-theme-muted">
|
|
168
|
+
{intro}
|
|
169
|
+
</p>
|
|
170
|
+
<Checks items={checks} />
|
|
171
|
+
</div>
|
|
172
|
+
<div className="reveal reveal-delay-2">
|
|
173
|
+
<StudioScreen />
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
</Section>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* ============ 02 · ask — the chat and its integrations ============ */
|
|
181
|
+
|
|
182
|
+
const askSchema = z.object({
|
|
183
|
+
cap: z.string(),
|
|
184
|
+
capNote: z.string().optional(),
|
|
185
|
+
headline: z.string(),
|
|
186
|
+
intro: z.string(),
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
function BrainAskSection({
|
|
190
|
+
cap,
|
|
191
|
+
capNote,
|
|
192
|
+
headline,
|
|
193
|
+
intro,
|
|
194
|
+
}: z.infer<typeof askSchema>): JSX.Element {
|
|
195
|
+
return (
|
|
196
|
+
<Section id="ask" className="py-14">
|
|
197
|
+
<ChapterHead
|
|
198
|
+
cap={cap}
|
|
199
|
+
capNote={capNote}
|
|
200
|
+
headline={headline}
|
|
201
|
+
intro={intro}
|
|
202
|
+
/>
|
|
203
|
+
<div className="mt-7 grid items-start gap-6 lg:grid-cols-[1.12fr_1fr]">
|
|
204
|
+
<div className="reveal reveal-delay-1">
|
|
205
|
+
<ChatScreen />
|
|
206
|
+
</div>
|
|
207
|
+
<div className="reveal reveal-delay-2">
|
|
208
|
+
<IntegrationsScreen />
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
</Section>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* ============ 03 · see it run — the dashboard ============ */
|
|
216
|
+
|
|
217
|
+
const runSchema = z.object({
|
|
218
|
+
cap: z.string(),
|
|
219
|
+
capNote: z.string().optional(),
|
|
220
|
+
headline: z.string(),
|
|
221
|
+
intro: z.string(),
|
|
222
|
+
note: z.string(),
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
function BrainRunSection({
|
|
226
|
+
cap,
|
|
227
|
+
capNote,
|
|
228
|
+
headline,
|
|
229
|
+
intro,
|
|
230
|
+
note,
|
|
231
|
+
}: z.infer<typeof runSchema>): JSX.Element {
|
|
232
|
+
return (
|
|
233
|
+
<Section id="run" className="py-14">
|
|
234
|
+
<ChapterHead
|
|
235
|
+
cap={cap}
|
|
236
|
+
capNote={capNote}
|
|
237
|
+
headline={headline}
|
|
238
|
+
intro={intro}
|
|
239
|
+
/>
|
|
240
|
+
<div className="reveal reveal-delay-1 mt-7 max-w-[1120px]">
|
|
241
|
+
<DashboardScreen />
|
|
242
|
+
</div>
|
|
243
|
+
<p className="reveal reveal-delay-2 mt-5 max-w-[52em] font-display text-[17px] font-normal italic text-theme-light [font-variation-settings:'SOFT'_85]">
|
|
244
|
+
{renderHighlightedText(note, "font-medium not-italic text-theme-muted")}
|
|
245
|
+
</p>
|
|
246
|
+
</Section>
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* ============ 04 · connect — back to the map ============ */
|
|
251
|
+
|
|
252
|
+
const connectSchema = z.object({
|
|
253
|
+
cap: z.string(),
|
|
254
|
+
capNote: z.string().optional(),
|
|
255
|
+
headline: z.string(),
|
|
256
|
+
intro: z.string(),
|
|
257
|
+
cta: ctaSchema,
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
function BrainConnectSection({
|
|
261
|
+
cap,
|
|
262
|
+
capNote,
|
|
263
|
+
headline,
|
|
264
|
+
intro,
|
|
265
|
+
cta,
|
|
266
|
+
}: z.infer<typeof connectSchema>): JSX.Element {
|
|
267
|
+
return (
|
|
268
|
+
<Section id="connect" className="py-14">
|
|
269
|
+
<ChapterHead
|
|
270
|
+
cap={cap}
|
|
271
|
+
capNote={capNote}
|
|
272
|
+
headline={headline}
|
|
273
|
+
intro={intro}
|
|
274
|
+
/>
|
|
275
|
+
<div className="reveal reveal-delay-2 mt-6">
|
|
276
|
+
<a
|
|
277
|
+
href={cta.href}
|
|
278
|
+
className="font-body text-[15.5px] text-theme-light no-underline transition-colors hover:text-accent"
|
|
279
|
+
>
|
|
280
|
+
{cta.label}
|
|
281
|
+
</a>
|
|
282
|
+
</div>
|
|
283
|
+
</Section>
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* ============ your data, your rules ============ */
|
|
288
|
+
|
|
289
|
+
function BrainYourDataSection({
|
|
290
|
+
cap,
|
|
291
|
+
items,
|
|
292
|
+
}: z.infer<typeof trioSchema>): JSX.Element {
|
|
293
|
+
return (
|
|
294
|
+
<Section id="your-data" className="py-14">
|
|
295
|
+
<SectCap lead={cap} />
|
|
296
|
+
<Trio items={items} mono={true} />
|
|
297
|
+
</Section>
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/* ============ quickstart ============ */
|
|
302
|
+
|
|
303
|
+
const termLineSchema = z.object({
|
|
304
|
+
kind: z.enum(["comment", "command", "ok"]),
|
|
305
|
+
text: z.string(),
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
const quickstartSchema = z.object({
|
|
309
|
+
cap: z.string(),
|
|
310
|
+
capNote: z.string(),
|
|
311
|
+
lines: z.array(termLineSchema),
|
|
312
|
+
checks: z.array(z.string()),
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
type TermLine = z.infer<typeof termLineSchema>;
|
|
316
|
+
|
|
317
|
+
function termLineClass(kind: TermLine["kind"]): string {
|
|
318
|
+
switch (kind) {
|
|
319
|
+
case "comment":
|
|
320
|
+
return "text-theme-light opacity-70";
|
|
321
|
+
case "ok":
|
|
322
|
+
return "text-secondary";
|
|
323
|
+
case "command":
|
|
324
|
+
return "text-theme";
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function BrainQuickstartSection({
|
|
329
|
+
cap,
|
|
330
|
+
capNote,
|
|
331
|
+
lines,
|
|
332
|
+
checks,
|
|
333
|
+
}: z.infer<typeof quickstartSchema>): JSX.Element {
|
|
334
|
+
return (
|
|
335
|
+
<Section id="quickstart" className="py-14">
|
|
336
|
+
<SectCap lead={cap} trail={capNote} />
|
|
337
|
+
<div className="mt-7 grid max-w-[1000px] items-start gap-12 md:grid-cols-[1.15fr_1fr]">
|
|
338
|
+
<div className="reveal reveal-delay-1 border border-theme bg-theme-subtle/60 px-6 py-5 font-label text-[14px] leading-[1.9]">
|
|
339
|
+
{lines.map((line, i) => (
|
|
340
|
+
<div key={i} className={termLineClass(line.kind)}>
|
|
341
|
+
{line.kind === "command" && (
|
|
342
|
+
<span className="select-none text-accent">$ </span>
|
|
343
|
+
)}
|
|
344
|
+
{line.text}
|
|
345
|
+
</div>
|
|
346
|
+
))}
|
|
347
|
+
</div>
|
|
348
|
+
<Checks items={checks} />
|
|
349
|
+
</div>
|
|
350
|
+
</Section>
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/* ============ closing band ============ */
|
|
355
|
+
|
|
356
|
+
const closeSchema = z.object({
|
|
357
|
+
quote: z.string(),
|
|
358
|
+
sub: z.string(),
|
|
359
|
+
primaryCta: ctaSchema,
|
|
360
|
+
secondaryCta: ctaSchema,
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
function BrainCloseSection({
|
|
364
|
+
quote,
|
|
365
|
+
sub,
|
|
366
|
+
primaryCta,
|
|
367
|
+
secondaryCta,
|
|
368
|
+
}: z.infer<typeof closeSchema>): JSX.Element {
|
|
369
|
+
return (
|
|
370
|
+
<Band quote={quote}>
|
|
371
|
+
<p className="reveal reveal-delay-1 mt-[18px] max-w-[52ch] font-body text-[17px] text-theme-light">
|
|
372
|
+
{sub}
|
|
373
|
+
</p>
|
|
374
|
+
<CtaRow
|
|
375
|
+
primaryCta={primaryCta}
|
|
376
|
+
secondaryCta={secondaryCta}
|
|
377
|
+
className="reveal reveal-delay-2 mt-[26px]"
|
|
378
|
+
/>
|
|
379
|
+
</Band>
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/* ============ the brain section group ============ */
|
|
384
|
+
|
|
385
|
+
export const brainSections: SiteSectionGroup = sectionGroup("brain", {
|
|
386
|
+
hero: defineSection(heroSchema, BrainHeroSection, {
|
|
387
|
+
title: "Hero",
|
|
388
|
+
description: "Product hero — build the agent that represents you",
|
|
389
|
+
}),
|
|
390
|
+
capture: defineSection(captureSchema, BrainCaptureSection, {
|
|
391
|
+
title: "Capture",
|
|
392
|
+
description: "01 · Capture — markdown corpus, illustrated by the studio",
|
|
393
|
+
}),
|
|
394
|
+
ask: defineSection(askSchema, BrainAskSection, {
|
|
395
|
+
title: "Ask",
|
|
396
|
+
description: "02 · Ask — chat + Discord, Claude/MCP, terminal",
|
|
397
|
+
}),
|
|
398
|
+
run: defineSection(runSchema, BrainRunSection, {
|
|
399
|
+
title: "See It Run",
|
|
400
|
+
description: "03 · See it run — the dashboard overview",
|
|
401
|
+
}),
|
|
402
|
+
connect: defineSection(connectSchema, BrainConnectSection, {
|
|
403
|
+
title: "Connect",
|
|
404
|
+
description: "04 · Connect — takes your seat in the network (the map)",
|
|
405
|
+
}),
|
|
406
|
+
"your-data": defineSection(trioSchema, BrainYourDataSection, {
|
|
407
|
+
title: "Your Data",
|
|
408
|
+
description: "Your data, your rules — ownership trio (mono markers)",
|
|
409
|
+
}),
|
|
410
|
+
quickstart: defineSection(quickstartSchema, BrainQuickstartSection, {
|
|
411
|
+
title: "Quickstart",
|
|
412
|
+
description: "Three-command quickstart terminal with a checklist",
|
|
413
|
+
}),
|
|
414
|
+
close: defineSection(closeSchema, BrainCloseSection, {
|
|
415
|
+
title: "Close",
|
|
416
|
+
description: "Closing band — own the intelligence you already have",
|
|
417
|
+
}),
|
|
418
|
+
});
|
package/src/home.tsx
CHANGED
|
@@ -9,67 +9,23 @@ import {
|
|
|
9
9
|
CtaRow,
|
|
10
10
|
AliveLine,
|
|
11
11
|
SectCap,
|
|
12
|
+
Trio,
|
|
13
|
+
trioSchema,
|
|
12
14
|
ctaSchema,
|
|
13
15
|
delayClass,
|
|
14
|
-
HIGHLIGHT_CLS,
|
|
15
16
|
} from "./shared";
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
|
-
* The
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
19
|
+
* The umbrella home page. The hero is the live agent proximity map (wired in
|
|
20
|
+
* routes.ts as agent-discovery:proximity-map); the sections here tell the
|
|
21
|
+
* story the map opens — the dark it fights (problem), how the network grows
|
|
22
|
+
* (growth), the mission band, the three faces, and the living-proof colophon.
|
|
23
|
+
* Each section is authored from one zod schema (its component's props are
|
|
24
|
+
* `z.infer` of that schema); copy is content-driven, stored as markdown in
|
|
25
|
+
* site-content/home/<section>.md. Only the assembled section group is
|
|
26
|
+
* exported — the schemas and components are module-local.
|
|
24
27
|
*/
|
|
25
28
|
|
|
26
|
-
/* ============ hero ============ */
|
|
27
|
-
|
|
28
|
-
const heroSchema = z.object({
|
|
29
|
-
kicker: z.string(),
|
|
30
|
-
headline: z.string(),
|
|
31
|
-
standfirst: z.string(),
|
|
32
|
-
primaryCta: ctaSchema,
|
|
33
|
-
secondaryCta: ctaSchema,
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
function HomeHeroSection({
|
|
37
|
-
kicker,
|
|
38
|
-
headline,
|
|
39
|
-
standfirst,
|
|
40
|
-
primaryCta,
|
|
41
|
-
secondaryCta,
|
|
42
|
-
}: z.infer<typeof heroSchema>): JSX.Element {
|
|
43
|
-
return (
|
|
44
|
-
<Section
|
|
45
|
-
id="hero"
|
|
46
|
-
className="relative overflow-hidden pt-[84px] pb-[72px] md:pt-[110px]"
|
|
47
|
-
>
|
|
48
|
-
<div
|
|
49
|
-
aria-hidden="true"
|
|
50
|
-
className="pointer-events-none absolute -inset-x-[15%] -inset-y-[35%] bg-[radial-gradient(760px_400px_at_16%_4%,var(--color-wash-a),transparent_64%),radial-gradient(560px_340px_at_92%_90%,var(--color-wash-b),transparent_70%)]"
|
|
51
|
-
/>
|
|
52
|
-
<div className="relative">
|
|
53
|
-
<p className="animate-hero-rise font-label text-label-sm uppercase tracking-[0.22em] text-accent opacity-0">
|
|
54
|
-
{kicker}
|
|
55
|
-
</p>
|
|
56
|
-
<h1 className="mt-5 max-w-[10.5em] animate-hero-rise font-display text-[clamp(50px,6.4vw,96px)] font-[435] leading-[0.99] tracking-[-0.022em] text-theme opacity-0 [animation-delay:0.12s] [font-variation-settings:'SOFT'_92,'opsz'_130]">
|
|
57
|
-
{renderHighlightedText(headline, HIGHLIGHT_CLS)}
|
|
58
|
-
</h1>
|
|
59
|
-
<div className="mt-9 flex animate-hero-rise flex-col items-start gap-[22px] opacity-0 [animation-delay:0.26s] lg:flex-row lg:items-baseline lg:gap-[60px]">
|
|
60
|
-
<p className="max-w-[42ch] font-body text-[21px] leading-[1.7] text-theme-muted">
|
|
61
|
-
{renderHighlightedText(
|
|
62
|
-
standfirst,
|
|
63
|
-
"font-medium not-italic text-theme",
|
|
64
|
-
)}
|
|
65
|
-
</p>
|
|
66
|
-
<CtaRow primaryCta={primaryCta} secondaryCta={secondaryCta} />
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
</Section>
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
29
|
/* ============ growth diagram ============ */
|
|
74
30
|
|
|
75
31
|
const growthSchema = z.object({
|
|
@@ -94,52 +50,7 @@ function HomeGrowthSection({
|
|
|
94
50
|
);
|
|
95
51
|
}
|
|
96
52
|
|
|
97
|
-
/* ============
|
|
98
|
-
|
|
99
|
-
const trioItemSchema = z.object({
|
|
100
|
-
marker: z.string(),
|
|
101
|
-
title: z.string(),
|
|
102
|
-
text: z.string(),
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
const trioSchema = z.object({
|
|
106
|
-
cap: z.string(),
|
|
107
|
-
items: z.array(trioItemSchema),
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
type TrioItem = z.infer<typeof trioItemSchema>;
|
|
111
|
-
|
|
112
|
-
function Trio({
|
|
113
|
-
items,
|
|
114
|
-
mono,
|
|
115
|
-
}: {
|
|
116
|
-
items: TrioItem[];
|
|
117
|
-
mono: boolean;
|
|
118
|
-
}): JSX.Element {
|
|
119
|
-
return (
|
|
120
|
-
<div className="mt-[30px] grid max-w-[1040px] gap-11 md:grid-cols-3">
|
|
121
|
-
{items.map((item, i) => (
|
|
122
|
-
<div key={item.title} className={`reveal ${delayClass(i)}`}>
|
|
123
|
-
{mono ? (
|
|
124
|
-
<span className="inline-block pt-3 pb-[15px] font-label text-[14px] font-medium tracking-[0.1em] text-accent">
|
|
125
|
-
{item.marker}
|
|
126
|
-
</span>
|
|
127
|
-
) : (
|
|
128
|
-
<span className="block font-display text-[44px] font-light leading-none text-theme-light [font-variation-settings:'SOFT'_30,'opsz'_100]">
|
|
129
|
-
{item.marker}
|
|
130
|
-
</span>
|
|
131
|
-
)}
|
|
132
|
-
<b className="mt-2.5 block font-display text-[21px] font-[520] tracking-[-0.006em] text-theme [font-variation-settings:'SOFT'_55]">
|
|
133
|
-
{item.title}
|
|
134
|
-
</b>
|
|
135
|
-
<p className="mt-2 font-body text-[15.5px] text-theme-light">
|
|
136
|
-
{item.text}
|
|
137
|
-
</p>
|
|
138
|
-
</div>
|
|
139
|
-
))}
|
|
140
|
-
</div>
|
|
141
|
-
);
|
|
142
|
-
}
|
|
53
|
+
/* ============ problem trio ============ */
|
|
143
54
|
|
|
144
55
|
function HomeProblemSection({
|
|
145
56
|
cap,
|
|
@@ -153,83 +64,6 @@ function HomeProblemSection({
|
|
|
153
64
|
);
|
|
154
65
|
}
|
|
155
66
|
|
|
156
|
-
function HomeYourDataSection({
|
|
157
|
-
cap,
|
|
158
|
-
items,
|
|
159
|
-
}: z.infer<typeof trioSchema>): JSX.Element {
|
|
160
|
-
return (
|
|
161
|
-
<Section id="your-data" className="py-14">
|
|
162
|
-
<SectCap lead={cap} />
|
|
163
|
-
<Trio items={items} mono={true} />
|
|
164
|
-
</Section>
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/* ============ quickstart ============ */
|
|
169
|
-
|
|
170
|
-
const termLineSchema = z.object({
|
|
171
|
-
kind: z.enum(["comment", "command", "ok"]),
|
|
172
|
-
text: z.string(),
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
const quickstartSchema = z.object({
|
|
176
|
-
cap: z.string(),
|
|
177
|
-
capNote: z.string(),
|
|
178
|
-
lines: z.array(termLineSchema),
|
|
179
|
-
checks: z.array(z.string()),
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
type TermLine = z.infer<typeof termLineSchema>;
|
|
183
|
-
|
|
184
|
-
function termLineClass(kind: TermLine["kind"]): string {
|
|
185
|
-
switch (kind) {
|
|
186
|
-
case "comment":
|
|
187
|
-
return "text-theme-light opacity-70";
|
|
188
|
-
case "ok":
|
|
189
|
-
return "text-secondary";
|
|
190
|
-
case "command":
|
|
191
|
-
return "text-theme";
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function HomeQuickstartSection({
|
|
196
|
-
cap,
|
|
197
|
-
capNote,
|
|
198
|
-
lines,
|
|
199
|
-
checks,
|
|
200
|
-
}: z.infer<typeof quickstartSchema>): JSX.Element {
|
|
201
|
-
return (
|
|
202
|
-
<Section id="quickstart" className="py-14">
|
|
203
|
-
<SectCap lead={cap} trail={capNote} />
|
|
204
|
-
<div className="mt-7 grid max-w-[1000px] items-start gap-12 md:grid-cols-[1.15fr_1fr]">
|
|
205
|
-
<div className="reveal reveal-delay-1 border border-theme bg-theme-subtle/60 px-6 py-5 font-label text-[14px] leading-[1.9]">
|
|
206
|
-
{lines.map((line, i) => (
|
|
207
|
-
<div key={i} className={termLineClass(line.kind)}>
|
|
208
|
-
{line.kind === "command" && (
|
|
209
|
-
<span className="select-none text-accent">$ </span>
|
|
210
|
-
)}
|
|
211
|
-
{line.text}
|
|
212
|
-
</div>
|
|
213
|
-
))}
|
|
214
|
-
</div>
|
|
215
|
-
<ul className="reveal reveal-delay-2 font-body text-[15.5px] text-theme-light">
|
|
216
|
-
{checks.map((check) => (
|
|
217
|
-
<li
|
|
218
|
-
key={check}
|
|
219
|
-
className="flex gap-2.5 border-b border-theme-light py-[7px]"
|
|
220
|
-
>
|
|
221
|
-
<span aria-hidden="true" className="font-label text-secondary">
|
|
222
|
-
✓
|
|
223
|
-
</span>
|
|
224
|
-
{check}
|
|
225
|
-
</li>
|
|
226
|
-
))}
|
|
227
|
-
</ul>
|
|
228
|
-
</div>
|
|
229
|
-
</Section>
|
|
230
|
-
);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
67
|
/* ============ mission band ============ */
|
|
234
68
|
|
|
235
69
|
const missionSchema = z.object({
|
|
@@ -329,15 +163,14 @@ const aliveSchema = z.object({
|
|
|
329
163
|
/* ============ the home section group ============ */
|
|
330
164
|
|
|
331
165
|
/**
|
|
332
|
-
* The
|
|
333
|
-
* id, so each
|
|
334
|
-
*
|
|
166
|
+
* The umbrella home page's authored sections. The namespace ("home") matches
|
|
167
|
+
* the route id, so each stores as site-content/home/<section>.md and resolves
|
|
168
|
+
* as "home:<section>". The hero is not here — it is the live agent proximity
|
|
169
|
+
* map (agent-discovery:proximity-map), whose authored copy lives at
|
|
170
|
+
* site-content/home/network.md and merges over the live data via the content
|
|
171
|
+
* overlay.
|
|
335
172
|
*/
|
|
336
173
|
export const homeSections: SiteSectionGroup = sectionGroup("home", {
|
|
337
|
-
hero: defineSection(heroSchema, HomeHeroSection, {
|
|
338
|
-
title: "Hero",
|
|
339
|
-
description: "Platform homepage hero: kicker, headline, standfirst, CTAs",
|
|
340
|
-
}),
|
|
341
174
|
growth: defineSection(growthSchema, HomeGrowthSection, {
|
|
342
175
|
title: "Growth",
|
|
343
176
|
description: "You → Team → Network growth diagram with caption and note",
|
|
@@ -346,14 +179,6 @@ export const homeSections: SiteSectionGroup = sectionGroup("home", {
|
|
|
346
179
|
title: "Problem",
|
|
347
180
|
description: "Why it has to exist — problem trio (large numerals)",
|
|
348
181
|
}),
|
|
349
|
-
"your-data": defineSection(trioSchema, HomeYourDataSection, {
|
|
350
|
-
title: "Your Data",
|
|
351
|
-
description: "Your data, your rules — ownership trio (mono markers)",
|
|
352
|
-
}),
|
|
353
|
-
quickstart: defineSection(quickstartSchema, HomeQuickstartSection, {
|
|
354
|
-
title: "Quickstart",
|
|
355
|
-
description: "Three-command quickstart terminal with a checklist",
|
|
356
|
-
}),
|
|
357
182
|
mission: defineSection(missionSchema, HomeMissionSection, {
|
|
358
183
|
title: "Mission",
|
|
359
184
|
description: "Mission band — display-italic statement, sub line, CTAs",
|