@rizom/site-rizom-foundation 0.2.0-alpha.142

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 ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@rizom/site-rizom-foundation",
3
+ "version": "0.2.0-alpha.142",
4
+ "description": "Rizom Foundation site package for hosted Rover deployments",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./src/index.ts"
8
+ },
9
+ "files": [
10
+ "src"
11
+ ],
12
+ "scripts": {
13
+ "typecheck": "tsc --noEmit",
14
+ "test": "bun test",
15
+ "lint": "eslint . --max-warnings 0",
16
+ "lint:fix": "eslint . --max-warnings 0 --fix",
17
+ "postpack": "publish-manifest restore",
18
+ "prepack": "publish-manifest prepare"
19
+ },
20
+ "dependencies": {
21
+ "@rizom/site": "0.2.0-alpha.142",
22
+ "@rizom/site-rizom": "0.2.0-alpha.142",
23
+ "preact": "^10.27.2"
24
+ },
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/rizom-ai/brains.git",
31
+ "directory": "sites/rizom-foundation"
32
+ },
33
+ "license": "Apache-2.0",
34
+ "author": "Yeehaa <yeehaa@rizom.ai> (https://rizom.ai)",
35
+ "homepage": "https://github.com/rizom-ai/brains/tree/main/sites/rizom-foundation#readme",
36
+ "bugs": {
37
+ "url": "https://github.com/rizom-ai/brains/issues"
38
+ },
39
+ "engines": {
40
+ "bun": ">=1.3.3"
41
+ }
42
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { rizomFoundationSite, rizomFoundationSite as default } from "./site";
2
+ export { foundationRoutes } from "./routes";
3
+ export { default as foundationSiteContent } from "./site-content";
package/src/layout.tsx ADDED
@@ -0,0 +1,89 @@
1
+ /** @jsxImportSource preact */
2
+ import type { ComponentChildren, JSX } from "preact";
3
+ import type { SiteLayoutInfo } from "@rizom/site";
4
+ import {
5
+ Footer,
6
+ Header,
7
+ RizomFrame,
8
+ SideNav,
9
+ socialLinksToRizomLinks,
10
+ } from "@rizom/site-rizom";
11
+
12
+ interface FoundationSiteInfo extends Pick<SiteLayoutInfo, "socialLinks"> {
13
+ cta?: {
14
+ buttonLink: string;
15
+ buttonText: string;
16
+ };
17
+ copyright: string;
18
+ }
19
+
20
+ interface FoundationLayoutProps {
21
+ sections: ComponentChildren[];
22
+ title: string;
23
+ description: string;
24
+ path: string;
25
+ siteInfo: FoundationSiteInfo;
26
+ }
27
+
28
+ const NAV_LINKS = [
29
+ { href: "#research", label: "Research" },
30
+ { href: "#events", label: "Events" },
31
+ { href: "#ecosystem", label: "Ecosystem" },
32
+ ];
33
+
34
+ const PRIMARY_CTA = {
35
+ href: "#mission",
36
+ label: "Read Manifesto",
37
+ };
38
+
39
+ const FOOTER_LINKS = [
40
+ { href: "#mission", label: "Newsletter" },
41
+ { href: "#ecosystem", label: "Ecosystem" },
42
+ { href: "#support", label: "Contact" },
43
+ ];
44
+
45
+ const FOOTER_TAGLINE = {
46
+ prefix: "",
47
+ link: { href: "https://rizom.work", label: "Rizom.work" },
48
+ suffix: " runs the TMS workshops and tools that fund this research.",
49
+ };
50
+
51
+ const SIDE_NAV_ITEMS = [
52
+ { href: "#hero", label: "Intro" },
53
+ { href: "#research", label: "Research" },
54
+ { href: "#events", label: "Events" },
55
+ { href: "#ownership", label: "About" },
56
+ { href: "#mission", label: "Follow" },
57
+ { href: "#ecosystem", label: "Network" },
58
+ ];
59
+
60
+ export const FoundationLayout = ({
61
+ sections,
62
+ siteInfo,
63
+ }: FoundationLayoutProps): JSX.Element => (
64
+ <RizomFrame>
65
+ <Header
66
+ brandSuffix="foundation"
67
+ navLinks={NAV_LINKS}
68
+ primaryCta={
69
+ siteInfo.cta
70
+ ? {
71
+ href: siteInfo.cta.buttonLink,
72
+ label: siteInfo.cta.buttonText,
73
+ }
74
+ : PRIMARY_CTA
75
+ }
76
+ />
77
+ <SideNav items={SIDE_NAV_ITEMS} />
78
+ <main>{sections}</main>
79
+ <Footer
80
+ brandSuffix="foundation"
81
+ metaLabel={siteInfo.copyright}
82
+ tagline={FOOTER_TAGLINE}
83
+ links={[
84
+ ...FOOTER_LINKS,
85
+ ...socialLinksToRizomLinks(siteInfo, ["linkedin"]),
86
+ ]}
87
+ />
88
+ </RizomFrame>
89
+ );
package/src/routes.ts ADDED
@@ -0,0 +1,55 @@
1
+ import type { RouteDefinitionInput } from "@rizom/site";
2
+
3
+ export const foundationRoutes: RouteDefinitionInput[] = [
4
+ {
5
+ id: "home",
6
+ path: "/",
7
+ layout: "default",
8
+ navigation: {
9
+ show: false,
10
+ slot: "secondary",
11
+ priority: 10,
12
+ },
13
+ sections: [
14
+ {
15
+ id: "hero",
16
+ template: "landing-page:hero",
17
+ content: {},
18
+ },
19
+ {
20
+ id: "pull-quote",
21
+ template: "landing-page:pull-quote",
22
+ content: {},
23
+ },
24
+ {
25
+ id: "research",
26
+ template: "landing-page:research",
27
+ content: {},
28
+ },
29
+ {
30
+ id: "events",
31
+ template: "landing-page:events",
32
+ content: {},
33
+ },
34
+ {
35
+ id: "support",
36
+ template: "landing-page:support",
37
+ content: {},
38
+ },
39
+ {
40
+ id: "ownership",
41
+ template: "landing-page:ownership",
42
+ content: {},
43
+ },
44
+ {
45
+ id: "mission",
46
+ template: "landing-page:mission",
47
+ content: {},
48
+ },
49
+ {
50
+ id: "ecosystem",
51
+ template: "landing-page:ecosystem",
52
+ },
53
+ ],
54
+ },
55
+ ];
@@ -0,0 +1,95 @@
1
+ /** @jsxImportSource preact */
2
+ import type { JSX } from "preact";
3
+ import { Badge, Divider, Section } from "@rizom/site-rizom";
4
+
5
+ export const ECOSYSTEM_SUFFIXES = ["ai", "foundation", "work"] as const;
6
+ type EcosystemSuffix = (typeof ECOSYSTEM_SUFFIXES)[number];
7
+
8
+ interface EcosystemCard {
9
+ suffix: EcosystemSuffix;
10
+ title: string;
11
+ body: string;
12
+ linkLabel: string;
13
+ linkHref: string;
14
+ }
15
+
16
+ interface EcosystemContent {
17
+ eyebrow: string;
18
+ headline: string;
19
+ cards: EcosystemCard[];
20
+ }
21
+
22
+ const BASE_CARD_CLASS =
23
+ "reveal relative overflow-hidden flex flex-col gap-2 p-6 md:p-8 rounded-[12px] md:rounded-[16px] border transition-all duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] hover:-translate-y-[3px] hover:border-white/12 [border-color:var(--rizom-ecosystem-card-border)] [background-image:var(--rizom-ecosystem-card-bg)] hover:[box-shadow:var(--rizom-ecosystem-card-hover-shadow)] before:content-[''] before:absolute before:top-0 before:left-0 before:right-0 before:h-[var(--rizom-ecosystem-card-bar-height)] before:opacity-[var(--rizom-ecosystem-card-bar-opacity)] hover:before:opacity-100 before:transition-opacity before:[background-image:var(--rizom-ecosystem-card-bar)]";
24
+
25
+ const ACTIVE_THEME =
26
+ "[--rizom-ecosystem-card-border:var(--color-card-panel-current-border)] [--rizom-ecosystem-card-bg:var(--color-card-panel-current-bg)] [--rizom-ecosystem-card-hover-shadow:0_16px_40px_-16px_var(--color-glow-panel-current)] [--rizom-ecosystem-card-bar-height:3px] [--rizom-ecosystem-card-bar-opacity:1] [--rizom-ecosystem-card-bar:linear-gradient(90deg,transparent,var(--color-accent)_30%,var(--color-accent)_70%,transparent)]";
27
+
28
+ const STANDARD_THEME =
29
+ "[--rizom-ecosystem-card-border:var(--color-card-panel-border)] [--rizom-ecosystem-card-bg:var(--color-card-panel-bg)] [--rizom-ecosystem-card-bar-height:2px] [--rizom-ecosystem-card-bar-opacity:0.6]";
30
+
31
+ const SUFFIX_THEME: Record<EcosystemSuffix, string> = {
32
+ ai: "[--rizom-ecosystem-card-hover-shadow:0_16px_40px_-16px_var(--color-glow-panel-ai)] [--rizom-ecosystem-card-bar:linear-gradient(90deg,transparent,var(--color-accent)_30%,var(--color-accent)_70%,transparent)]",
33
+ foundation:
34
+ "[--rizom-ecosystem-card-hover-shadow:0_16px_40px_-16px_var(--color-glow-panel-foundation)] [--rizom-ecosystem-card-bar:linear-gradient(90deg,transparent,var(--color-secondary)_30%,var(--color-secondary)_70%,transparent)]",
35
+ work: "[--rizom-ecosystem-card-hover-shadow:0_16px_40px_-16px_var(--color-glow-panel-work)] [--rizom-ecosystem-card-bar:linear-gradient(90deg,transparent,var(--palette-amber-light)_30%,var(--color-secondary)_70%,transparent)]",
36
+ };
37
+
38
+ const ACCENT_LINK: Record<EcosystemSuffix, string> = {
39
+ ai: "text-accent",
40
+ foundation: "text-secondary",
41
+ work: "text-secondary",
42
+ };
43
+
44
+ export const EcosystemLayout = ({
45
+ eyebrow,
46
+ headline,
47
+ cards,
48
+ }: EcosystemContent): JSX.Element => {
49
+ return (
50
+ <Section id="ecosystem" className="reveal pt-section pb-16 md:pb-24">
51
+ <Divider className="mb-10 md:mb-14" />
52
+ <div className="text-center mb-10 md:mb-14">
53
+ <Badge className="mb-6">{eyebrow}</Badge>
54
+ <h2 className="font-display text-display-md max-w-[880px] mx-auto">
55
+ {headline}
56
+ </h2>
57
+ </div>
58
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-6">
59
+ {cards.map((card, i) => {
60
+ const isActive = card.linkLabel === "You are here";
61
+ const isDisabled = card.linkHref.trim().length === 0;
62
+ const themeClass = isActive
63
+ ? ACTIVE_THEME
64
+ : `${STANDARD_THEME} ${SUFFIX_THEME[card.suffix]}`;
65
+ const linkClass = `mt-2 font-body text-[13px] md:text-[14px] font-medium ${isDisabled ? "text-theme-light opacity-70 cursor-default" : `transition-opacity hover:opacity-70 ${ACCENT_LINK[card.suffix]}`}`;
66
+ return (
67
+ <div
68
+ key={card.suffix}
69
+ className={`${BASE_CARD_CLASS} reveal-delay-${i + 1} ${themeClass}`}
70
+ >
71
+ <div className="mb-2 flex items-center gap-1 font-nav text-[16px]">
72
+ <span className="font-bold">rizom</span>
73
+ <span className="font-bold text-accent">.</span>
74
+ <span className="text-theme-muted">{card.suffix}</span>
75
+ </div>
76
+ <div className="font-nav text-[18px] md:text-[22px] font-bold">
77
+ {card.title}
78
+ </div>
79
+ <p className="text-[13px] md:text-[14px] leading-[1.7] text-theme-muted">
80
+ {card.body}
81
+ </p>
82
+ {isDisabled ? (
83
+ <span className={linkClass}>{card.linkLabel}</span>
84
+ ) : (
85
+ <a href={card.linkHref} className={linkClass}>
86
+ {card.linkLabel}
87
+ </a>
88
+ )}
89
+ </div>
90
+ );
91
+ })}
92
+ </div>
93
+ </Section>
94
+ );
95
+ };
@@ -0,0 +1,102 @@
1
+ /** @jsxImportSource preact */
2
+ import type { JSX } from "preact";
3
+ import { Button, Section } from "@rizom/site-rizom";
4
+ import {
5
+ FOUNDATION_OUTLINED_INDEX,
6
+ FOUNDATION_SECTION_EYEBROW_ROW,
7
+ FOUNDATION_SECTION_EYEBROW_RULE,
8
+ FOUNDATION_SECTION_EYEBROW_TEXT,
9
+ FOUNDATION_SECTION_HEADER,
10
+ FOUNDATION_SECTION_HEADLINE,
11
+ FOUNDATION_SECTION_SUBHEAD,
12
+ } from "../styles";
13
+ interface EventItem {
14
+ num: string;
15
+ city: string;
16
+ description: string;
17
+ date: string;
18
+ anchor: string;
19
+ actionLabel: string;
20
+ href: string;
21
+ }
22
+
23
+ interface EventsContent {
24
+ kicker: string;
25
+ headline: string;
26
+ subhead: string;
27
+ events: EventItem[];
28
+ primaryCtaLabel: string;
29
+ primaryCtaHref: string;
30
+ secondaryCtaLabel: string;
31
+ secondaryCtaHref: string;
32
+ }
33
+
34
+ export const EventsLayout = ({
35
+ kicker,
36
+ headline,
37
+ subhead,
38
+ events,
39
+ primaryCtaLabel,
40
+ primaryCtaHref,
41
+ secondaryCtaLabel,
42
+ secondaryCtaHref,
43
+ }: EventsContent): JSX.Element => {
44
+ return (
45
+ <Section id="events" className="reveal py-section">
46
+ <div className="mx-auto max-w-[960px]">
47
+ <div className={FOUNDATION_SECTION_HEADER}>
48
+ <div className={FOUNDATION_SECTION_EYEBROW_ROW}>
49
+ <span className={FOUNDATION_SECTION_EYEBROW_RULE} />
50
+ <span className={FOUNDATION_SECTION_EYEBROW_TEXT}>{kicker}</span>
51
+ </div>
52
+ <h2 className={`${FOUNDATION_SECTION_HEADLINE} max-w-[14ch]`}>
53
+ {headline}
54
+ </h2>
55
+ <p className={`${FOUNDATION_SECTION_SUBHEAD} max-w-[700px]`}>
56
+ {subhead}
57
+ </p>
58
+ </div>
59
+
60
+ <div className="flex flex-col">
61
+ {events.map((event, i) => (
62
+ <a
63
+ key={event.num + event.city}
64
+ href={event.href}
65
+ className={`reveal reveal-delay-${Math.min(i + 1, 3)} group grid grid-cols-[80px_1fr] items-start gap-6 border-t border-[var(--color-foundation-divider-soft)] py-8 transition-all hover:border-accent/40 hover:pl-3 md:grid-cols-[110px_1fr_220px] md:gap-8 md:py-11 md:hover:pl-4 max-[900px]:grid-cols-[80px_1fr] max-[900px]:gap-6 max-[900px]:py-8`}
66
+ >
67
+ <div className={FOUNDATION_OUTLINED_INDEX}>{event.num}</div>
68
+ <div>
69
+ <h3 className="font-display text-[28px] md:text-[42px] tracking-[-1.4px] leading-none text-theme transition-colors group-hover:text-accent">
70
+ {event.city}
71
+ </h3>
72
+ <p className="mt-3 text-body-xs md:text-body-sm text-theme-muted max-w-[560px] italic">
73
+ {event.description}
74
+ </p>
75
+ </div>
76
+ <div className="flex flex-col gap-2 pt-1 text-body-xs md:pt-3 md:text-body-sm md:text-right max-[900px]:col-span-full max-[900px]:flex-row max-[900px]:flex-wrap max-[900px]:items-baseline max-[900px]:gap-[14px] max-[900px]:pt-0 max-[900px]:text-left">
77
+ <span className="font-display text-[18px] md:text-[20px] text-accent tracking-[-0.3px]">
78
+ {event.date}
79
+ </span>
80
+ <span className="font-mono text-[10px] uppercase tracking-[0.15em] text-theme-light">
81
+ {event.anchor}
82
+ </span>
83
+ <span className="font-body text-theme-muted transition-all group-hover:text-accent md:group-hover:translate-x-1">
84
+ {event.actionLabel}
85
+ </span>
86
+ </div>
87
+ </a>
88
+ ))}
89
+ </div>
90
+
91
+ <div className="border-t border-white/8 pt-8 md:pt-10 flex flex-col md:flex-row gap-3 md:gap-5">
92
+ <Button href={primaryCtaHref} variant="primary">
93
+ {primaryCtaLabel}
94
+ </Button>
95
+ <Button href={secondaryCtaHref} variant="secondary">
96
+ {secondaryCtaLabel}
97
+ </Button>
98
+ </div>
99
+ </div>
100
+ </Section>
101
+ );
102
+ };
@@ -0,0 +1,84 @@
1
+ /** @jsxImportSource preact */
2
+ import type { JSX } from "preact";
3
+ import { Button, Section } from "@rizom/site-rizom";
4
+
5
+ interface HeroContent {
6
+ volumeLabel: string;
7
+ yearLabel: string;
8
+ metaLabel: string;
9
+ headline: string;
10
+ headlineTail: string;
11
+ tagline: string;
12
+ subtitle: string;
13
+ primaryCtaLabel: string;
14
+ primaryCtaHref: string;
15
+ secondaryCtaLabel: string;
16
+ secondaryCtaHref: string;
17
+ scrollLabel: string;
18
+ scrollHref: string;
19
+ colophon: string[];
20
+ }
21
+
22
+ export const HeroLayout = ({
23
+ volumeLabel,
24
+ yearLabel,
25
+ metaLabel,
26
+ headline,
27
+ headlineTail,
28
+ tagline,
29
+ subtitle,
30
+ primaryCtaLabel,
31
+ primaryCtaHref,
32
+ secondaryCtaLabel,
33
+ secondaryCtaHref,
34
+ scrollLabel,
35
+ scrollHref,
36
+ colophon,
37
+ }: HeroContent): JSX.Element => {
38
+ return (
39
+ <Section
40
+ id="hero"
41
+ className="flex min-h-[100dvh] items-center overflow-hidden text-center"
42
+ >
43
+ <div className="relative z-[2] mx-auto max-w-[1040px] pt-[52px] md:pt-[60px]">
44
+ <div className="mx-auto mb-8 inline-flex flex-wrap items-center justify-center gap-[10px] border-y border-[var(--color-foundation-meta-rule)] px-[18px] py-[10px] font-label text-label-sm font-semibold uppercase tracking-[0.18em] text-theme-light opacity-0 animate-hero-rise [animation-delay:0.1s] md:mb-14 md:gap-3 md:px-6 md:py-[11px]">
45
+ <span>{volumeLabel}</span>
46
+ <span className="text-accent">·</span>
47
+ <span>{yearLabel}</span>
48
+ <span className="text-accent">·</span>
49
+ <span>{metaLabel}</span>
50
+ <span className="inline-block h-2.5 w-2.5 rounded-full bg-accent shadow-[0_0_12px_var(--color-glow-cta)]" />
51
+ </div>
52
+ <h1 className="mb-6 font-display text-[clamp(56px,10.5vw,148px)] font-normal leading-[0.88] tracking-[-2.5px] opacity-0 animate-hero-rise [animation-delay:0.2s] md:tracking-[-5px]">
53
+ {headline}
54
+ <span className="mt-4 block text-[0.42em] leading-[1.2] tracking-[-1.5px] text-theme-muted italic md:mt-6 md:leading-[1.15]">
55
+ {headlineTail}
56
+ </span>
57
+ </h1>
58
+ <p className="mx-auto mb-7 max-w-[780px] font-display text-[clamp(20px,2.4vw,28px)] tracking-[-0.3px] text-theme italic leading-[1.4] opacity-0 animate-hero-rise [animation-delay:0.35s] md:mb-10">
59
+ {tagline}
60
+ </p>
61
+ <p className="mx-auto mb-11 max-w-[560px] font-body text-[16px] leading-[1.7] text-theme-muted italic opacity-0 animate-hero-rise [animation-delay:0.45s]">
62
+ {subtitle}
63
+ </p>
64
+ <div className="flex flex-col items-center gap-6 opacity-0 animate-hero-rise [animation-delay:0.6s] md:flex-row md:flex-wrap md:justify-center md:gap-9">
65
+ <Button href={primaryCtaHref} variant="primary" block>
66
+ {primaryCtaLabel}
67
+ </Button>
68
+ <Button href={secondaryCtaHref} variant="secondary" block>
69
+ {secondaryCtaLabel}
70
+ </Button>
71
+ </div>
72
+ <div className="mx-auto mt-10 flex max-w-[680px] flex-col items-center justify-center gap-[14px] border-t border-[var(--color-foundation-divider-soft)] pt-[18px] font-label text-label-sm font-medium uppercase tracking-[0.14em] text-theme-light opacity-0 animate-hero-rise [animation-delay:0.75s] md:mt-16 md:flex-row md:gap-8 md:pt-6">
73
+ {colophon.map((line) => (
74
+ <span key={line}>{line}</span>
75
+ ))}
76
+ </div>
77
+ </div>
78
+ <a className="scroll-cue" href={scrollHref} aria-label={scrollLabel}>
79
+ <span>{scrollLabel}</span>
80
+ <span className="scroll-cue-line"></span>
81
+ </a>
82
+ </Section>
83
+ );
84
+ };
@@ -0,0 +1,49 @@
1
+ /** @jsxImportSource preact */
2
+ import type { JSX } from "preact";
3
+ import { Button, Divider, Section } from "@rizom/site-rizom";
4
+
5
+ interface MissionContent {
6
+ preamble: string;
7
+ headlineStart: string;
8
+ headlineHighlight: string;
9
+ post: string;
10
+ primaryCtaLabel: string;
11
+ primaryCtaHref: string;
12
+ secondaryCtaLabel: string;
13
+ secondaryCtaHref: string;
14
+ }
15
+
16
+ export const MissionLayout = ({
17
+ preamble,
18
+ headlineStart,
19
+ headlineHighlight,
20
+ post,
21
+ primaryCtaLabel,
22
+ primaryCtaHref,
23
+ secondaryCtaLabel,
24
+ secondaryCtaHref,
25
+ }: MissionContent): JSX.Element => {
26
+ return (
27
+ <Section id="mission" className="reveal py-section text-center">
28
+ <Divider className="mb-10 md:mb-12" />
29
+ <p className="font-body text-body-sm md:text-body-lg text-theme-light max-w-[620px] mx-auto mb-8 md:mb-10">
30
+ {preamble}
31
+ </p>
32
+ <h2 className="font-display font-normal text-display-lg md:text-display-xl">
33
+ {headlineStart}{" "}
34
+ <span className="italic text-accent">{headlineHighlight}</span>
35
+ </h2>
36
+ <p className="font-body text-body-sm md:text-body-lg text-theme-light max-w-[560px] mx-auto mt-8">
37
+ {post}
38
+ </p>
39
+ <div className="flex flex-col md:flex-row gap-3 md:gap-5 md:justify-center items-stretch md:items-center mt-9 md:mt-16">
40
+ <Button href={primaryCtaHref} variant="primary-strong" size="lg" block>
41
+ {primaryCtaLabel}
42
+ </Button>
43
+ <Button href={secondaryCtaHref} variant="secondary" size="lg" block>
44
+ {secondaryCtaLabel}
45
+ </Button>
46
+ </div>
47
+ </Section>
48
+ );
49
+ };
@@ -0,0 +1,54 @@
1
+ /** @jsxImportSource preact */
2
+ import type { JSX } from "preact";
3
+ import { Badge, Section } from "@rizom/site-rizom";
4
+
5
+ interface OwnershipFeature {
6
+ icon: string;
7
+ title: string;
8
+ body: string;
9
+ }
10
+
11
+ interface OwnershipContent {
12
+ badge: string;
13
+ headline: string;
14
+ features: OwnershipFeature[];
15
+ }
16
+
17
+ export const OwnershipLayout = ({
18
+ badge,
19
+ headline,
20
+ features,
21
+ }: OwnershipContent): JSX.Element => {
22
+ return (
23
+ <Section id="ownership" className="reveal py-section">
24
+ <div className="flex flex-col items-start gap-9 md:flex-row md:gap-20">
25
+ <div className="w-full md:w-[45%]">
26
+ <Badge>{badge}</Badge>
27
+ <h2 className="font-display text-[28px] tracking-[-1px] leading-[1.1] md:text-display-md mt-4 md:mt-6">
28
+ {headline}
29
+ </h2>
30
+ </div>
31
+ <div className="flex w-full flex-col gap-8 md:w-[55%] md:pt-[60px]">
32
+ {features.map((row, i) => (
33
+ <div
34
+ key={row.icon + row.title}
35
+ className={`reveal reveal-delay-${i + 1} flex items-start gap-4 md:gap-5`}
36
+ >
37
+ <div className="shrink-0 min-w-[44px] md:min-w-[48px] h-11 md:h-12 flex items-center justify-center border border-accent rounded-lg font-nav text-[18px] md:text-heading-md font-bold text-accent">
38
+ {row.icon}
39
+ </div>
40
+ <div>
41
+ <div className="font-nav text-heading-sm md:text-heading-md font-bold mb-1.5">
42
+ {row.title}
43
+ </div>
44
+ <p className="text-body-xs md:text-body-sm text-theme-muted">
45
+ {row.body}
46
+ </p>
47
+ </div>
48
+ </div>
49
+ ))}
50
+ </div>
51
+ </div>
52
+ </Section>
53
+ );
54
+ };
@@ -0,0 +1,28 @@
1
+ /** @jsxImportSource preact */
2
+ import type { JSX } from "preact";
3
+ import { Section } from "@rizom/site-rizom";
4
+
5
+ interface PullQuoteContent {
6
+ quote: string;
7
+ attribution: string;
8
+ }
9
+
10
+ export const PullQuoteLayout = ({
11
+ quote,
12
+ attribution,
13
+ }: PullQuoteContent): JSX.Element => {
14
+ return (
15
+ <Section id="pull-quote" className="reveal pt-20 pb-10 md:pt-20 md:pb-10">
16
+ <div className="max-w-[880px] mx-auto px-4 md:px-10 text-center">
17
+ <div className="mx-auto mb-8 h-px w-12 bg-[var(--color-divider)]" />
18
+ <blockquote className="font-display font-light text-[26px] tracking-[-0.8px] leading-[1.25] md:text-[42px] text-theme">
19
+ {quote}
20
+ </blockquote>
21
+ <div className="mt-6 font-label text-label-sm font-medium uppercase tracking-[0.16em] text-theme-light">
22
+ {attribution}
23
+ </div>
24
+ <div className="mx-auto mt-8 h-px w-12 bg-[var(--color-divider)]" />
25
+ </div>
26
+ </Section>
27
+ );
28
+ };
@@ -0,0 +1,90 @@
1
+ /** @jsxImportSource preact */
2
+ import type { JSX } from "preact";
3
+ import { Button, Section } from "@rizom/site-rizom";
4
+ import {
5
+ FOUNDATION_OUTLINED_INDEX,
6
+ FOUNDATION_SECTION_EYEBROW_ROW,
7
+ FOUNDATION_SECTION_EYEBROW_RULE,
8
+ FOUNDATION_SECTION_EYEBROW_TEXT,
9
+ FOUNDATION_SECTION_HEADER,
10
+ FOUNDATION_SECTION_HEADLINE,
11
+ FOUNDATION_SECTION_SUBHEAD,
12
+ } from "../styles";
13
+ interface ResearchEssay {
14
+ num: string;
15
+ series: string;
16
+ title: string;
17
+ teaser: string;
18
+ href: string;
19
+ }
20
+
21
+ interface ResearchContent {
22
+ kicker: string;
23
+ headline: string;
24
+ subhead: string;
25
+ essays: ResearchEssay[];
26
+ ctaLabel: string;
27
+ ctaHref: string;
28
+ }
29
+
30
+ export const ResearchLayout = ({
31
+ kicker,
32
+ headline,
33
+ subhead,
34
+ essays,
35
+ ctaLabel,
36
+ ctaHref,
37
+ }: ResearchContent): JSX.Element => {
38
+ return (
39
+ <Section
40
+ id="research"
41
+ className="reveal px-0 py-[88px] md:pt-20 md:pb-[120px]"
42
+ >
43
+ <div className="mx-auto max-w-[960px]">
44
+ <div className={FOUNDATION_SECTION_HEADER}>
45
+ <div className={FOUNDATION_SECTION_EYEBROW_ROW}>
46
+ <span className={FOUNDATION_SECTION_EYEBROW_RULE} />
47
+ <span className={FOUNDATION_SECTION_EYEBROW_TEXT}>{kicker}</span>
48
+ </div>
49
+ <h2 className={`${FOUNDATION_SECTION_HEADLINE} max-w-[12ch]`}>
50
+ {headline}
51
+ </h2>
52
+ <p className={`${FOUNDATION_SECTION_SUBHEAD} max-w-[620px]`}>
53
+ {subhead}
54
+ </p>
55
+ </div>
56
+
57
+ <div className="flex flex-col">
58
+ {essays.map((essay, i) => (
59
+ <a
60
+ key={essay.num + essay.title}
61
+ href={essay.href}
62
+ className={`reveal reveal-delay-${Math.min(i + 1, 3)} group grid grid-cols-[80px_1fr_auto] items-start gap-6 border-t border-[var(--color-foundation-divider-soft)] py-8 transition-all hover:border-accent/40 hover:pl-3 md:grid-cols-[110px_1fr_36px] md:gap-8 md:py-11 md:hover:pl-4`}
63
+ >
64
+ <div className={FOUNDATION_OUTLINED_INDEX}>{essay.num}</div>
65
+ <div>
66
+ <div className="font-label text-label-sm font-semibold tracking-[0.12em] uppercase text-theme-light mb-2">
67
+ {essay.series}
68
+ </div>
69
+ <h3 className="font-display text-[24px] md:text-[34px] tracking-[-1px] leading-[1.05] text-theme">
70
+ {essay.title}
71
+ </h3>
72
+ <p className="mt-3 text-body-xs md:text-body-sm text-theme-muted max-w-[620px]">
73
+ {essay.teaser}
74
+ </p>
75
+ </div>
76
+ <div className="pt-1 md:pt-3 font-display text-[28px] md:text-[34px] text-accent transition-transform group-hover:translate-x-1">
77
+
78
+ </div>
79
+ </a>
80
+ ))}
81
+ <div className="border-t border-white/8 pt-8 md:pt-10">
82
+ <Button href={ctaHref} variant="secondary">
83
+ {ctaLabel}
84
+ </Button>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ </Section>
89
+ );
90
+ };
@@ -0,0 +1,13 @@
1
+ export const FOUNDATION_SECTION_HEADER = "mb-10 md:mb-12";
2
+ export const FOUNDATION_SECTION_EYEBROW_ROW =
3
+ "mb-4 flex items-center gap-3 text-accent";
4
+ export const FOUNDATION_SECTION_EYEBROW_RULE = "block h-px w-8 bg-accent/80";
5
+ export const FOUNDATION_SECTION_EYEBROW_TEXT =
6
+ "font-label text-label-md font-semibold uppercase tracking-[0.16em]";
7
+ export const FOUNDATION_SECTION_HEADLINE =
8
+ "font-display text-[32px] text-theme tracking-[-1px] leading-[1.08] md:text-display-md";
9
+ export const FOUNDATION_SECTION_SUBHEAD =
10
+ "mt-4 text-body-sm text-theme-muted md:text-body-md";
11
+
12
+ export const FOUNDATION_OUTLINED_INDEX =
13
+ "font-display text-[38px] leading-none tracking-[-1.5px] text-transparent md:text-[54px] [-webkit-text-stroke:1.2px_var(--color-accent)]";
@@ -0,0 +1,86 @@
1
+ /** @jsxImportSource preact */
2
+ import type { JSX } from "preact";
3
+ import { Section } from "@rizom/site-rizom";
4
+ import {
5
+ FOUNDATION_SECTION_EYEBROW_ROW,
6
+ FOUNDATION_SECTION_EYEBROW_RULE,
7
+ FOUNDATION_SECTION_EYEBROW_TEXT,
8
+ FOUNDATION_SECTION_HEADER,
9
+ FOUNDATION_SECTION_HEADLINE,
10
+ } from "../styles";
11
+ interface SupportCard {
12
+ tone: "amber" | "purple";
13
+ label: string;
14
+ headline: string;
15
+ body: string;
16
+ linkLabel: string;
17
+ linkHref: string;
18
+ }
19
+
20
+ interface SupportContent {
21
+ kicker: string;
22
+ headline: string;
23
+ cards: SupportCard[];
24
+ }
25
+
26
+ const CARD_BASE =
27
+ "flex flex-col items-start gap-5 rounded-2xl border px-6 py-8 md:p-10 transition-[transform,border-color,box-shadow] duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] hover:-translate-y-1";
28
+
29
+ const CARD_BY_TONE = {
30
+ amber: `${CARD_BASE} bg-[image:var(--color-card-rover-bg)] border-[var(--color-card-rover-border)] hover:border-[var(--color-foundation-support-amber-hover-border)] hover:shadow-[0_20px_60px_-20px_var(--color-foundation-support-amber-hover-shadow)]`,
31
+ purple: `${CARD_BASE} bg-[image:var(--color-card-relay-bg)] border-[var(--color-card-relay-border)] hover:border-[var(--color-foundation-support-purple-hover-border)] hover:shadow-[0_20px_60px_-20px_var(--color-foundation-support-purple-hover-shadow)]`,
32
+ };
33
+
34
+ const TEXT_BY_TONE = {
35
+ amber: "text-accent",
36
+ purple: "text-secondary",
37
+ };
38
+
39
+ export const SupportLayout = ({
40
+ kicker,
41
+ headline,
42
+ cards,
43
+ }: SupportContent): JSX.Element => {
44
+ return (
45
+ <Section id="support" className="reveal py-section">
46
+ <div className="mx-auto max-w-[1120px]">
47
+ <div className={FOUNDATION_SECTION_HEADER}>
48
+ <div className={FOUNDATION_SECTION_EYEBROW_ROW}>
49
+ <span className={FOUNDATION_SECTION_EYEBROW_RULE} />
50
+ <span className={FOUNDATION_SECTION_EYEBROW_TEXT}>{kicker}</span>
51
+ </div>
52
+ <h2 className={`${FOUNDATION_SECTION_HEADLINE} max-w-[14ch]`}>
53
+ {headline}
54
+ </h2>
55
+ </div>
56
+
57
+ <div className="mt-12 grid grid-cols-1 gap-4 md:grid-cols-2 md:gap-6">
58
+ {cards.map((card, i) => (
59
+ <div
60
+ key={card.label + card.headline}
61
+ className={`reveal reveal-delay-${i + 1} ${CARD_BY_TONE[card.tone]}`}
62
+ >
63
+ <span
64
+ className={`font-nav text-[18px] font-bold ${TEXT_BY_TONE[card.tone]}`}
65
+ >
66
+ {card.label}
67
+ </span>
68
+ <h3 className="font-display text-[clamp(26px,3vw,36px)] leading-[1.2] tracking-[-0.5px] text-theme">
69
+ {card.headline}
70
+ </h3>
71
+ <p className="text-body-xs md:text-body-sm text-theme-muted">
72
+ {card.body}
73
+ </p>
74
+ <a
75
+ href={card.linkHref}
76
+ className={`mt-2 font-body text-body-sm font-medium ${TEXT_BY_TONE[card.tone]} hover:opacity-75`}
77
+ >
78
+ {card.linkLabel}
79
+ </a>
80
+ </div>
81
+ ))}
82
+ </div>
83
+ </div>
84
+ </Section>
85
+ );
86
+ };
@@ -0,0 +1,209 @@
1
+ import type { SiteContentDefinition } from "@rizom/site";
2
+ import { HeroLayout } from "./sections/hero/layout";
3
+ import { PullQuoteLayout } from "./sections/pull-quote/layout";
4
+ import { ResearchLayout } from "./sections/research/layout";
5
+ import { EventsLayout } from "./sections/events/layout";
6
+ import { SupportLayout } from "./sections/support/layout";
7
+ import { OwnershipLayout } from "./sections/ownership/layout";
8
+ import { MissionLayout } from "./sections/mission/layout";
9
+ import { EcosystemLayout } from "./sections/ecosystem";
10
+
11
+ const foundationSiteContent: SiteContentDefinition = {
12
+ namespace: "landing-page",
13
+ sections: {
14
+ hero: {
15
+ description: "Rizom foundation hero — centered editorial manifesto intro",
16
+ title: "Hero Section",
17
+ layout: HeroLayout,
18
+ fields: {
19
+ volumeLabel: { label: "Volume label", type: "string" },
20
+ yearLabel: { label: "Year label", type: "string" },
21
+ metaLabel: { label: "Meta label", type: "string" },
22
+ headline: { label: "Headline", type: "string" },
23
+ headlineTail: { label: "Headline tail", type: "string" },
24
+ tagline: { label: "Tagline", type: "string" },
25
+ subtitle: { label: "Subtitle", type: "string" },
26
+ primaryCtaLabel: { label: "Primary CTA label", type: "string" },
27
+ primaryCtaHref: { label: "Primary CTA href", type: "string" },
28
+ secondaryCtaLabel: { label: "Secondary CTA label", type: "string" },
29
+ secondaryCtaHref: { label: "Secondary CTA href", type: "string" },
30
+ scrollLabel: { label: "Scroll label", type: "string" },
31
+ scrollHref: { label: "Scroll href", type: "string" },
32
+ colophon: {
33
+ label: "Colophon lines",
34
+ type: "array",
35
+ minItems: 1,
36
+ items: { label: "Colophon line", type: "string" },
37
+ },
38
+ },
39
+ },
40
+ "pull-quote": {
41
+ description: "Rizom pull-quote section — centered editorial quote block",
42
+ title: "Pull Quote Section",
43
+ layout: PullQuoteLayout,
44
+ fields: {
45
+ quote: { label: "Quote", type: "string" },
46
+ attribution: { label: "Attribution", type: "string" },
47
+ },
48
+ },
49
+ research: {
50
+ description: "Rizom research section — editorial essay index",
51
+ title: "Research Section",
52
+ layout: ResearchLayout,
53
+ fields: {
54
+ kicker: { label: "Kicker", type: "string" },
55
+ headline: { label: "Headline", type: "string" },
56
+ subhead: { label: "Subhead", type: "string" },
57
+ essays: {
58
+ label: "Essays",
59
+ type: "array",
60
+ minItems: 1,
61
+ items: {
62
+ label: "Essay",
63
+ type: "object",
64
+ fields: {
65
+ num: { label: "Number", type: "string" },
66
+ series: { label: "Series", type: "string" },
67
+ title: { label: "Title", type: "string" },
68
+ teaser: { label: "Teaser", type: "string" },
69
+ href: { label: "Href", type: "string" },
70
+ },
71
+ },
72
+ },
73
+ ctaLabel: { label: "CTA label", type: "string" },
74
+ ctaHref: { label: "CTA href", type: "string" },
75
+ },
76
+ },
77
+ events: {
78
+ description: "Rizom events section — editorial event index",
79
+ title: "Events Section",
80
+ layout: EventsLayout,
81
+ fields: {
82
+ kicker: { label: "Kicker", type: "string" },
83
+ headline: { label: "Headline", type: "string" },
84
+ subhead: { label: "Subhead", type: "string" },
85
+ events: {
86
+ label: "Events",
87
+ type: "array",
88
+ minItems: 1,
89
+ items: {
90
+ label: "Event",
91
+ type: "object",
92
+ fields: {
93
+ num: { label: "Number", type: "string" },
94
+ city: { label: "City", type: "string" },
95
+ description: { label: "Description", type: "string" },
96
+ date: { label: "Date", type: "string" },
97
+ anchor: { label: "Anchor", type: "string" },
98
+ actionLabel: { label: "Action label", type: "string" },
99
+ href: { label: "Href", type: "string" },
100
+ },
101
+ },
102
+ },
103
+ primaryCtaLabel: { label: "Primary CTA label", type: "string" },
104
+ primaryCtaHref: { label: "Primary CTA href", type: "string" },
105
+ secondaryCtaLabel: { label: "Secondary CTA label", type: "string" },
106
+ secondaryCtaHref: { label: "Secondary CTA href", type: "string" },
107
+ },
108
+ },
109
+ support: {
110
+ description: "Rizom support section — two-card funding/support grid",
111
+ title: "Support Section",
112
+ layout: SupportLayout,
113
+ fields: {
114
+ kicker: { label: "Kicker", type: "string" },
115
+ headline: { label: "Headline", type: "string" },
116
+ cards: {
117
+ label: "Cards",
118
+ type: "array",
119
+ length: 2,
120
+ items: {
121
+ label: "Card",
122
+ type: "object",
123
+ fields: {
124
+ tone: {
125
+ label: "Tone",
126
+ type: "enum",
127
+ options: ["amber", "purple"],
128
+ },
129
+ label: { label: "Label", type: "string" },
130
+ headline: { label: "Headline", type: "string" },
131
+ body: { label: "Body", type: "string" },
132
+ linkLabel: { label: "Link label", type: "string" },
133
+ linkHref: { label: "Link href", type: "string" },
134
+ },
135
+ },
136
+ },
137
+ },
138
+ },
139
+ ownership: {
140
+ description: "Rizom ownership section — people and community cards",
141
+ title: "Ownership Section",
142
+ layout: OwnershipLayout,
143
+ fields: {
144
+ badge: { label: "Badge", type: "string" },
145
+ headline: { label: "Headline", type: "string" },
146
+ features: {
147
+ label: "Features",
148
+ type: "array",
149
+ minItems: 1,
150
+ items: {
151
+ label: "Feature",
152
+ type: "object",
153
+ fields: {
154
+ icon: { label: "Icon", type: "string" },
155
+ title: { label: "Title", type: "string" },
156
+ body: { label: "Body", type: "string" },
157
+ },
158
+ },
159
+ },
160
+ },
161
+ },
162
+ mission: {
163
+ description: "Rizom mission section — newsletter and follow CTA",
164
+ title: "Mission Section",
165
+ layout: MissionLayout,
166
+ fields: {
167
+ preamble: { label: "Preamble", type: "string" },
168
+ headlineStart: { label: "Headline start", type: "string" },
169
+ headlineHighlight: { label: "Headline highlight", type: "string" },
170
+ post: { label: "Post", type: "string" },
171
+ primaryCtaLabel: { label: "Primary CTA label", type: "string" },
172
+ primaryCtaHref: { label: "Primary CTA href", type: "string" },
173
+ secondaryCtaLabel: { label: "Secondary CTA label", type: "string" },
174
+ secondaryCtaHref: { label: "Secondary CTA href", type: "string" },
175
+ },
176
+ },
177
+ ecosystem: {
178
+ description: "Rizom ecosystem section — sibling site cards",
179
+ title: "Ecosystem Section",
180
+ layout: EcosystemLayout,
181
+ fields: {
182
+ eyebrow: { label: "Eyebrow", type: "string" },
183
+ headline: { label: "Headline", type: "string" },
184
+ cards: {
185
+ label: "Cards",
186
+ type: "array",
187
+ minItems: 1,
188
+ items: {
189
+ label: "Card",
190
+ type: "object",
191
+ fields: {
192
+ suffix: {
193
+ label: "Suffix",
194
+ type: "enum",
195
+ options: ["ai", "foundation", "work"],
196
+ },
197
+ title: { label: "Title", type: "string" },
198
+ body: { label: "Body", type: "string" },
199
+ linkLabel: { label: "Link label", type: "string" },
200
+ linkHref: { label: "Link href", type: "string" },
201
+ },
202
+ },
203
+ },
204
+ },
205
+ },
206
+ },
207
+ };
208
+
209
+ export default foundationSiteContent;
package/src/site.ts ADDED
@@ -0,0 +1,17 @@
1
+ import type { SiteDefinition } from "@rizom/site";
2
+ import { createRizomSite } from "@rizom/site-rizom";
3
+ import { FoundationLayout } from "./layout";
4
+ import { foundationRoutes } from "./routes";
5
+ import foundationSiteContent from "./site-content";
6
+ import themeOverride from "./theme.css" with { type: "text" };
7
+
8
+ export const rizomFoundationSite: SiteDefinition = createRizomSite({
9
+ packageName: "@rizom/site-rizom-foundation",
10
+ themeProfile: "editorial",
11
+ layout: FoundationLayout,
12
+ routes: foundationRoutes,
13
+ content: foundationSiteContent,
14
+ themeOverride,
15
+ });
16
+
17
+ export default rizomFoundationSite;
package/src/theme.css ADDED
@@ -0,0 +1,28 @@
1
+ @layer theme {
2
+ :root {
3
+ --color-foundation-meta-rule: rgb(from var(--color-accent) r g b / 0.4);
4
+ --color-foundation-divider-soft: rgb(from var(--color-text) r g b / 0.06);
5
+ --color-foundation-support-amber-hover-border: rgb(
6
+ from var(--color-accent) r g b / 0.5
7
+ );
8
+ --color-foundation-support-amber-hover-shadow: rgb(
9
+ from var(--color-accent) r g b / 0.25
10
+ );
11
+ --color-foundation-support-purple-hover-border: rgb(
12
+ from var(--color-secondary) r g b / 0.5
13
+ );
14
+ --color-foundation-support-purple-hover-shadow: rgb(
15
+ from var(--color-secondary) r g b / 0.25
16
+ );
17
+ }
18
+
19
+ [data-theme="light"] {
20
+ --color-bg: #f5efe3;
21
+ --color-bg-subtle: #eee7d6;
22
+ --color-bg-card: #f0e9d8;
23
+ }
24
+ }
25
+
26
+ @layer theme-override {
27
+ /* Foundation editorial polish */
28
+ }
package/src/types.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ declare module "*.css" {
2
+ const content: string;
3
+ export default content;
4
+ }