History

marketing: blog on the rail layout; one shared shell for home, pricing, and blog (#2019)

Rhys Sullivan committed 1 month ago

Commit 37f91a21 parent 6bd57756 files · +233 −415Browse files

Unified · Split

6 files
  1. apps/marketing/src/layouts/BlogPostLayout.astro +27 −153
  2. apps/marketing/src/layouts/RailLayout.astro +49 −0
  3. apps/marketing/src/pages/blog/index.astro +27 −126
  4. apps/marketing/src/pages/index.astro +7 −50
  5. apps/marketing/src/pages/pricing.astro +57 −86
  6. apps/marketing/src/styles/variants/doc.css +66 −0
apps/marketing/src/layouts/BlogPostLayout.astro+27−153
@@ -1,5 +1,5 @@
1---1---
2import Layout from "./Layout.astro";2import RailLayout from "./RailLayout.astro";
3 3
4interface Props {4interface Props {
5 title: string;5 title: string;
@@ -11,17 +11,9 @@ interface Props { · 5 unmodified lines
11 authorAvatar: string;11 authorAvatar: string;
12}12}
13 13
14const {14const { title, description, date, author, authorHandle, authorRole, authorAvatar } =
15 title,15 Astro.props;
16 description,
17 date,
18 author,
19 authorHandle,
20 authorRole,
21 authorAvatar,
22} = Astro.props;
23 16
24const GH = "https://github.com/UsefulSoftwareCo/executor";
25const authorX = `https://x.com/${authorHandle}`;17const authorX = `https://x.com/${authorHandle}`;
26 18
27const formattedDate = date.toLocaleDateString("en-US", {19const formattedDate = date.toLocaleDateString("en-US", {
@@ -36,147 +28,29 @@ const formattedDate = date.toLocaleDateString("en-US", { · 8 unmodified lines
36const isoDate = date.toISOString();28const isoDate = date.toISOString();
37---29---
38 30
39<Layout title={`${title} — Executor`} description={description}>31<RailLayout title={`${title} — Executor`} description={description} current="blog">
40 <main class="bg-soft relative min-h-dvh antialiased">32 <article class="doc">
41 {/* Graph-paper pattern + fade behind the header, matching the homepage */}33 <header class="doc__intro doc__intro--post">
42 <div34 <a href="/blog" class="doc__crumb">← Writing</a>
43 class="pattern-bg pattern-graph"35 <h1 class="doc__title">{title}</h1>
44 style="position:absolute;top:0;left:0;right:0;height:60vh;z-index:1;pointer-events:none;"36 <p class="doc__lede">{description}</p>
45 >37 <a href={authorX} target="_blank" rel="noopener noreferrer" class="doc__sig doc__sig--post">
38 <img src={authorAvatar} alt="" width="40" height="40" loading="lazy" />
39 <span class="doc__sig-b">
40 <strong>{author}</strong>
41 <span>{authorRole} · <time datetime={isoDate}>{formattedDate}</time></span>
42 </span>
43 </a>
44 </header>
45
46 <div class="blog-prose doc__prose">
47 <slot />
46 </div>48 </div>
47 <div
48 style="position:absolute;top:0;left:0;right:0;height:60vh;z-index:2;pointer-events:none;background:linear-gradient(180deg,transparent 0%,transparent 55%,var(--color-surface) 100%);"
49 >
50 </div>
51
52 <div class="relative z-10">
53 {/* ─── NAV ─── */}
54 <nav>
55 <div
56 class="mx-auto flex h-14 max-w-[1200px] items-center justify-between px-6 sm:px-10"
57 >
58 <a href="/" class="flex items-center gap-2.5">
59 <img src="/favicon-192.png" alt="" class="h-5 w-5" />
60 <span class="text-[15px] font-semibold tracking-[-0.01em] text-ink"
61 >executor</span
62 >
63 </a>
64 <div class="flex items-center gap-5">
65 <a
66 href="/blog"
67 class="text-[14px] font-medium text-ink-2 transition-colors hover:text-ink"
68 >Blog</a
69 >
70 <a
71 href="https://executor.sh/docs"
72 class="hidden text-[14px] font-medium text-ink-2 transition-colors hover:text-ink sm:inline"
73 >Docs</a
74 >
75 <a
76 href={GH}
77 class="text-[14px] font-medium text-ink-2 transition-colors hover:text-ink"
78 >GitHub</a
79 >
80 <a href="/#install" class="btn-primary">Get started →</a>
81 </div>
82 </div>
83 </nav>
84
85 {/* ─── HEADER ─── */}
86 <section class="px-6 pt-16 pb-10 sm:px-10 sm:pt-24 sm:pb-14">
87 <div class="mx-auto max-w-[720px]">
88 <a
89 href="/blog"
90 class="eyebrow inline-flex items-center gap-1.5 transition-colors hover:text-ink-2"
91 >← Blog</a
92 >
93 <h1
94 class="mt-5 text-[clamp(2.2rem,5vw,3.6rem)] font-semibold leading-[1.05] tracking-[-0.025em] text-ink text-balance"
95 >
96 {title}
97 </h1>
98 <p class="mt-5 text-[17px] leading-[1.6] text-ink-2 text-pretty">
99 {description}
100 </p>
101 <div class="mt-8 flex items-center gap-3">
102 <a
103 href={authorX}
104 target="_blank"
105 rel="noopener noreferrer"
106 class="shrink-0"
107 aria-label={`${author} on X`}
108 >
109 <img
110 src={authorAvatar}
111 alt={author}
112 width="44"
113 height="44"
114 loading="lazy"
115 class="h-11 w-11 rounded-full object-cover ring-1 ring-rule"
116 />
117 </a>
118 <div class="min-w-0">
119 <a
120 href={authorX}
121 target="_blank"
122 rel="noopener noreferrer"
123 class="text-[15px] font-semibold text-ink transition-colors hover:text-accent"
124 >{author}</a
125 >
126 <div class="mt-0.5 text-[13px] leading-snug text-ink-3">
127 {authorRole} · <time datetime={isoDate}>{formattedDate}</time>
128 </div>
129 </div>
130 </div>
131 </div>
132 </section>
133 49
134 {/* ─── ARTICLE ─── */}50 <section class="doc__section">
135 <section class="px-6 pt-2 pb-20 sm:px-10 sm:pb-28">51 <p class="doc__quiet-p">
136 <article class="blog-prose mx-auto max-w-[720px]">52 <a href="/blog">More writing</a> · <a href="/">Back to Executor</a>
137 <slot />53 </p>
138 </article>54 </section>
139 </section>55 </article>
140 56</RailLayout>
141 {/* ─── BOTTOM CTA ─── */}
142 <section class="border-t border-rule py-16 sm:py-20">
143 <div class="mx-auto max-w-[720px] px-6 text-center sm:px-10">
144 <h2 class="section-title mx-auto mb-7 max-w-[20ch]">
145 Connect any agent to <span class="serif-italic">everything</span>.
146 </h2>
147 <div class="flex flex-wrap items-center justify-center gap-3">
148 <a href="/#install" class="btn-primary btn-primary--hero"
149 >Get started →</a
150 >
151 <a href={GH} class="btn-secondary">Star on GitHub</a>
152 </div>
153 </div>
154 </section>
155
156 {/* ─── FOOTER ─── */}
157 <footer class="border-t border-rule py-10">
158 <div
159 class="mx-auto flex max-w-[1200px] flex-col items-start justify-between gap-6 px-6 sm:flex-row sm:items-center sm:px-10"
160 >
161 <div class="flex items-center gap-2.5">
162 <img src="/favicon-192.png" alt="" class="h-4 w-4 opacity-80" />
163 <span class="text-[13px] font-medium text-ink-2">executor</span>
164 <span class="ml-2 text-[12px] text-ink-3"
165 >© {new Date().getFullYear()}</span
166 >
167 </div>
168 <div class="flex items-center gap-6 text-[13px] text-ink-2">
169 <a href="/blog" class="transition-colors hover:text-ink">Blog</a>
170 <a
171 href="https://executor.sh/docs"
172 class="transition-colors hover:text-ink">Docs</a
173 >
174 <a href={GH} class="transition-colors hover:text-ink">GitHub</a>
175 <a href="/privacy" class="transition-colors hover:text-ink">Privacy</a>
176 <a href="/terms" class="transition-colors hover:text-ink">Terms</a>
177 </div>
178 </div>
179 </footer>
180 </div>
181 </main>
182</Layout>
apps/marketing/src/layouts/RailLayout.astro+49−0
@@ -0,0 +1,49 @@
1---
2// The site shell: sticky rail on the left, one centred frame, footer at the
3// bottom of the body column. The homepage, pricing, and blog all use it.
4// Prerendered pages resolve the star count once at build time.
5import Layout from "./Layout.astro";
6import RailB from "../components/variants/rail-b.astro";
7import { getStars, formatStars } from "../lib/github";
8import "../styles/variants/doc.css";
9
10interface Props {
11 title: string;
12 description: string;
13 current?: "home" | "pricing" | "blog";
14}
15const { title, description, current = "home" } = Astro.props;
16
17const GH = "https://github.com/UsefulSoftwareCo/executor";
18const stars = await getStars();
19---
20
21<Layout title={title} description={description}>
22 <main class="bg-soft min-h-dvh relative antialiased">
23 <div class="relative z-10 page">
24 <div class="page__rail page__rail--b">
25 <RailB stars={stars != null ? formatStars(stars) : null} current={current} />
26 </div>
27 <div class="page__body">
28 <slot />
29
30 <footer class="border-t border-rule py-10">
31 <div class="max-w-[1200px] mx-auto px-6 sm:px-10 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6">
32 <div class="flex items-center gap-2.5">
33 <img src="/favicon-192.png" alt="" class="w-4 h-4 opacity-80" />
34 <span class="text-[13px] font-medium text-ink-2">executor</span>
35 <span class="text-[12px] text-ink-3 ml-2">© {new Date().getFullYear()}</span>
36 </div>
37 <div class="flex items-center gap-6 text-[13px] text-ink-2">
38 <a href="https://executor.sh/docs" class="hover:text-ink transition-colors">Docs</a>
39 <a href="/blog" class="hover:text-ink transition-colors">Blog</a>
40 <a href={GH} class="hover:text-ink transition-colors">GitHub</a>
41 <a href="/privacy" class="hover:text-ink transition-colors">Privacy</a>
42 <a href="/terms" class="hover:text-ink transition-colors">Terms</a>
43 </div>
44 </div>
45 </footer>
46 </div>
47 </div>
48 </main>
49</Layout>
apps/marketing/src/pages/blog/index.astro+27−126
@@ -1,10 +1,8 @@
1---1---
2export const prerender = true;2export const prerender = true;
3import Layout from "../../layouts/Layout.astro";3import RailLayout from "../../layouts/RailLayout.astro";
4import { getCollection } from "astro:content";4import { getCollection } from "astro:content";
5 5
6const GH = "https://github.com/UsefulSoftwareCo/executor";
7
8const posts = (await getCollection("blog", ({ data }) => !data.draft)).sort(6const posts = (await getCollection("blog", ({ data }) => !data.draft)).sort(
9 (a, b) => b.data.date.getTime() - a.data.date.getTime(),7 (a, b) => b.data.date.getTime() - a.data.date.getTime(),
10);8);
@@ -20,126 +18,29 @@ const fmt = (date: Date) => · 9 unmodified lines
20 });18 });
21---19---
22 20
23<Layout21<RailLayout title="Blog — Executor" description="Latest news and updates from Executor." current="blog">
24 title="Blog — Executor"22 <article class="doc">
25 description="Latest news and updates from Executor."23 <header class="doc__intro">
26>24 <h1 class="doc__title">Writing</h1>
27 <main class="bg-soft relative min-h-dvh antialiased">25 <p class="doc__lede">Notes from building Executor.</p>
28 <div26 </header>
29 class="pattern-bg pattern-graph"27
30 style="position:absolute;top:0;left:0;right:0;height:60vh;z-index:1;pointer-events:none;"28 {
31 >29 posts.length === 0 ? (
32 </div>30 <p class="text-[15px] text-ink-3">No posts yet. Check back soon.</p>
33 <div31 ) : (
34 style="position:absolute;top:0;left:0;right:0;height:60vh;z-index:2;pointer-events:none;background:linear-gradient(180deg,transparent 0%,transparent 55%,var(--color-surface) 100%);"32 <ul class="doc__posts">
35 >33 {posts.map((post) => (
36 </div>34 <li>
37 35 <a href={`/blog/${post.id}`} class="doc__post">
38 <div class="relative z-10">36 <span class="doc__post-date">{fmt(post.data.date)}</span>
39 {/* ─── NAV ─── */}37 <span class="doc__post-title">{post.data.title}</span>
40 <nav>38 <span class="doc__post-desc">{post.data.description}</span>
41 <div39 </a>
42 class="mx-auto flex h-14 max-w-[1200px] items-center justify-between px-6 sm:px-10"40 </li>
43 >41 ))}
44 <a href="/" class="flex items-center gap-2.5">42 </ul>
45 <img src="/favicon-192.png" alt="" class="h-5 w-5" />43 )
46 <span class="text-[15px] font-semibold tracking-[-0.01em] text-ink"44 }
47 >executor</span45 </article>
48 >46</RailLayout>
49 </a>
50 <div class="flex items-center gap-5">
51 <a
52 href="/blog"
53 class="text-[14px] font-medium text-ink transition-colors">Blog</a
54 >
55 <a
56 href="https://executor.sh/docs"
57 class="hidden text-[14px] font-medium text-ink-2 transition-colors hover:text-ink sm:inline"
58 >Docs</a
59 >
60 <a
61 href={GH}
62 class="text-[14px] font-medium text-ink-2 transition-colors hover:text-ink"
63 >GitHub</a
64 >
65 <a href="/#install" class="btn-primary">Get started →</a>
66 </div>
67 </div>
68 </nav>
69
70 {/* ─── HEADER ─── */}
71 <section class="px-6 pt-16 pb-10 sm:px-10 sm:pt-24 sm:pb-12">
72 <div class="mx-auto max-w-[760px]">
73 <h1
74 class="text-[clamp(2.4rem,5.6vw,4rem)] font-semibold leading-[1.02] tracking-[-0.025em] text-ink"
75 >
76 Blog
77 </h1>
78 <p class="mt-5 max-w-[54ch] text-[17px] leading-[1.6] text-ink-2 text-pretty">
79 Latest news and updates from Executor
80 </p>
81 </div>
82 </section>
83
84 {/* ─── POST LIST ─── */}
85 <section class="px-6 pb-24 sm:px-10 sm:pb-32">
86 <div class="mx-auto max-w-[760px]">
87 {
88 posts.length === 0 ? (
89 <p class="text-[15px] text-ink-3">No posts yet. Check back soon.</p>
90 ) : (
91 <ul class="flex flex-col gap-4">
92 {posts.map((post) => (
93 <li>
94 <a
95 href={`/blog/${post.id}`}
96 class="surface-card group block p-6 transition-colors sm:p-7"
97 >
98 <div class="mb-2 font-mono text-[12px] uppercase tracking-[0.14em] text-ink-3">
99 {fmt(post.data.date)}
100 </div>
101 <h2 class="text-[20px] font-semibold tracking-[-0.01em] text-ink sm:text-[22px]">
102 {post.data.title}
103 </h2>
104 <p class="mt-2 text-[14.5px] leading-[1.55] text-ink-2 text-pretty">
105 {post.data.description}
106 </p>
107 <span class="mt-4 inline-flex items-center gap-1 text-[13.5px] font-medium text-ink-2 transition-colors group-hover:text-ink">
108 Read post →
109 </span>
110 </a>
111 </li>
112 ))}
113 </ul>
114 )
115 }
116 </div>
117 </section>
118
119 {/* ─── FOOTER ─── */}
120 <footer class="border-t border-rule py-10">
121 <div
122 class="mx-auto flex max-w-[1200px] flex-col items-start justify-between gap-6 px-6 sm:flex-row sm:items-center sm:px-10"
123 >
124 <div class="flex items-center gap-2.5">
125 <img src="/favicon-192.png" alt="" class="h-4 w-4 opacity-80" />
126 <span class="text-[13px] font-medium text-ink-2">executor</span>
127 <span class="ml-2 text-[12px] text-ink-3"
128 >© {new Date().getFullYear()}</span
129 >
130 </div>
131 <div class="flex items-center gap-6 text-[13px] text-ink-2">
132 <a href="/blog" class="transition-colors hover:text-ink">Blog</a>
133 <a
134 href="https://executor.sh/docs"
135 class="transition-colors hover:text-ink">Docs</a
136 >
137 <a href={GH} class="transition-colors hover:text-ink">GitHub</a>
138 <a href="/privacy" class="transition-colors hover:text-ink">Privacy</a>
139 <a href="/terms" class="transition-colors hover:text-ink">Terms</a>
140 </div>
141 </div>
142 </footer>
143 </div>
144 </main>
145</Layout>
apps/marketing/src/pages/index.astro+7−50
@@ -1,10 +1,8 @@
1---1---
2import Layout from "../layouts/Layout.astro";2import RailLayout from "../layouts/RailLayout.astro";
3// Imported so Vite emits it as a hashed build asset (served from /_astro/...);3// Imported so Vite emits it as a hashed build asset (served from /_astro/...);
4// the deploy pipeline does not pick up newly added /public files.4// the deploy pipeline does not pick up newly added /public files.
5import { getStars, formatStars } from "../lib/github";
6import { setupPrompt } from "../content/site-copy";5import { setupPrompt } from "../content/site-copy";
7import RailB from "../components/variants/rail-b.astro";
8import DocBody from "../components/variants/doc-body.astro";6import DocBody from "../components/variants/doc-body.astro";
9 7
10const GH = "https://github.com/UsefulSoftwareCo/executor";8const GH = "https://github.com/UsefulSoftwareCo/executor";
@@ -12,57 +10,16 @@ const GH = "https://github.com/UsefulSoftwareCo/executor"; · 1 unmodified line
12// /api/* is app-owned (apps/cloud/src/app-paths.ts), so this hits the WorkOS10// /api/* is app-owned (apps/cloud/src/app-paths.ts), so this hits the WorkOS
13// login flow directly. Returning users land here; new users use Get started.11// login flow directly. Returning users land here; new users use Get started.
14const SIGN_IN = "/api/auth/login";12const SIGN_IN = "/api/auth/login";
15const stars = await getStars();
16 13
17---14---
18 15
19<Layout>16<RailLayout
20 <main class="bg-soft min-h-dvh relative antialiased">17 title="Executor — The gateway to connect your agent to everything"
21 {/* Graph-paper hero texture: grayscale (ink-masked), faded into the surface18 description="One place every agent plugs into every tool you already use. Wire it up once, bring the whole team."
22 at the bottom. Part of the registry-grade language, not a colored effect. */}19>
23 <div20 <DocBody gh={GH} />
24 class="pattern-bg pattern-graph"21</RailLayout>
25 style="position: absolute; top: 0; left: 0; right: 0; height: 100vh; z-index: 1; pointer-events: none;"
26 >
27 </div>
28 <div
29 style="position: absolute; top: 0; left: 0; right: 0; height: 100vh; z-index: 2; pointer-events: none; background: linear-gradient(180deg, transparent 0%, transparent 65%, var(--color-surface) 100%);"
30 >
31 </div>
32 22
33 <div class="relative z-10 page">
34 <div class="page__rail page__rail--b"><RailB stars={stars != null ? formatStars(stars) : null} /></div>
35 <div class="page__body">
36
37 <DocBody gh={GH} />
38
39 {/* ─── FOOTER ─── */}
40 <footer class="border-t border-rule py-10">
41 <div
42 class="max-w-[1200px] mx-auto px-6 sm:px-10 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6"
43 >
44 <div class="flex items-center gap-2.5">
45 <img src="/favicon-192.png" alt="" class="w-4 h-4 opacity-80" />
46 <span class="text-[13px] font-medium text-ink-2">executor</span>
47 <span class="text-[12px] text-ink-3 ml-2"
48 >© {new Date().getFullYear()}</span
49 >
50 </div>
51 <div class="flex items-center gap-6 text-[13px] text-ink-2">
52 <a href="https://executor.sh/docs" class="hover:text-ink transition-colors"
53 >Docs</a
54 >
55 <a href="/blog" class="hover:text-ink transition-colors">Blog</a>
56 <a href={GH} class="hover:text-ink transition-colors">GitHub</a>
57 <a href="/privacy" class="hover:text-ink transition-colors">Privacy</a>
58 <a href="/terms" class="hover:text-ink transition-colors">Terms</a>
59 </div>
60 </div>
61 </footer>
62 </div>
63 </div>
64 </main>
65</Layout>
66 23
67<script>24<script>
68 // Copy buttons. Use the async Clipboard API in secure contexts and fall back25 // Copy buttons. Use the async Clipboard API in secure contexts and fall back
apps/marketing/src/pages/pricing.astro+57−86
@@ -1,13 +1,9 @@
1---1---
2import Layout from "../layouts/Layout.astro";2import RailLayout from "../layouts/RailLayout.astro";
3import { getStars, formatStars } from "../lib/github";
4import { pricingTiers } from "../content/site-copy";3import { pricingTiers } from "../content/site-copy";
5import RailB from "../components/variants/rail-b.astro";
6import "../styles/variants/doc.css";
7import "../styles/variants/pricing.css";4import "../styles/variants/pricing.css";
8 5
9const GH = "https://github.com/UsefulSoftwareCo/executor";6const GH = "https://github.com/UsefulSoftwareCo/executor";
10const stars = await getStars();
11 7
12// Same tiers the Markdown route serves; the card layout only needs a split8// Same tiers the Markdown route serves; the card layout only needs a split
13// between the number and its unit, and a real href for each call to action.9// between the number and its unit, and a real href for each call to action.
@@ -39,91 +35,66 @@ const cards = [ · 25 unmodified lines
39];35];
40---36---
41 37
42<Layout38<RailLayout
43 title="Pricing — Executor"39 title="Pricing — Executor"
44 description="Start free, pay per member. Executor Cloud pricing for teams and enterprises."40 description="Start free, pay per member. Executor Cloud pricing for teams and enterprises."
41 current="pricing"
45>42>
46 <main class="bg-soft min-h-dvh relative antialiased">43 <article class="doc">
47 <div class="relative z-10 page">44 <header class="doc__intro">
48 <div class="page__rail page__rail--b">45 <h1 class="doc__title">Start free, pay per member.</h1>
49 <RailB stars={stars != null ? formatStars(stars) : null} current="pricing" />46 <p class="doc__lede">
50 </div>47 Cloud is free for small teams. Team is one flat price per person. Enterprise is
51 <div class="page__body">48 for orgs that need it on their own infrastructure with their own controls.
52 <article class="doc">49 </p>
53 <header class="doc__intro">50 </header>
54 <h1 class="doc__title">Start free, pay per member.</h1>
55 <p class="doc__lede">
56 Cloud is free for small teams. Team is one flat price per person. Enterprise is
57 for orgs that need it on their own infrastructure with their own controls.
58 </p>
59 </header>
60
61 <div class="pricing">
62 {
63 cards.map(({ tier, amount, unit, href, label, recommended }) => (
64 <section class:list={["pricing__card", recommended && "pricing__card--rec"]}>
65 <span class="pricing__eyebrow">{recommended ? "Recommended" : tier.name === "Free" ? "Get started" : "Custom needs"}</span>
66 <h2 class="pricing__name">{tier.name}</h2>
67 <p class="pricing__aud">{tier.audience.replace(" (recommended)", "")}</p>
68 <p class="pricing__price">
69 <span class="pricing__amount">{amount}</span>
70 {unit ? <span class="pricing__unit">{unit}</span> : null}
71 </p>
72 <a href={href} class={recommended ? "btn-primary" : "btn-secondary"}>{label}</a>
73 {tier.featuresLabel ? <p class="pricing__flabel">{tier.featuresLabel}</p> : null}
74 <ul class="check-list">
75 {tier.features.map((f) => (
76 <li>
77 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5" /></svg>
78 {f}
79 </li>
80 ))}
81 </ul>
82 </section>
83 ))
84 }
85 </div>
86
87 51
88 <section class="doc__section">52 <div class="pricing">
89 <h2 class="doc__h">Questions</h2>53 {
90 <dl class="doc__beats">54 cards.map(({ tier, amount, unit, href, label, recommended }) => (
91 <div>55 <section class:list={["pricing__card", recommended && "pricing__card--rec"]}>
92 <dt>What counts as an execution?</dt>56 <span class="pricing__eyebrow">{recommended ? "Recommended" : tier.name === "Free" ? "Get started" : "Custom needs"}</span>
93 <dd>One call to the Executor tool from your agent. A single execution can make many tool calls inside it.</dd>57 <h2 class="pricing__name">{tier.name}</h2>
94 </div>58 <p class="pricing__aud">{tier.audience.replace(" (recommended)", "")}</p>
95 <div>59 <p class="pricing__price">
96 <dt>What happens when the free tier runs out?</dt>60 <span class="pricing__amount">{amount}</span>
97 <dd>Calls pause until the month resets or you move to Team. Nothing is deleted.</dd>61 {unit ? <span class="pricing__unit">{unit}</span> : null}
98 </div>
99 <div>
100 <dt>Can I mix Cloud and self-hosted?</dt>
101 <dd>Yes. They are the same code, and an agent can point at more than one Executor.</dd>
102 </div>
103 </dl>
104 <p class="doc__quiet-p">
105 Something else? <a href="mailto:rhys@executor.sh?subject=Executor%20pricing">Email Rhys</a>.
106 </p>62 </p>
63 <a href={href} class={recommended ? "btn-primary" : "btn-secondary"}>{label}</a>
64 {tier.featuresLabel ? <p class="pricing__flabel">{tier.featuresLabel}</p> : null}
65 <ul class="check-list">
66 {tier.features.map((f) => (
67 <li>
68 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5" /></svg>
69 {f}
70 </li>
71 ))}
72 </ul>
107 </section>73 </section>
108 </article>74 ))
109 75 }
110 <footer class="border-t border-rule py-10">
111 <div class="max-w-[1200px] mx-auto px-6 sm:px-10 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6">
112 <div class="flex items-center gap-2.5">
113 <img src="/favicon-192.png" alt="" class="w-4 h-4 opacity-80" />
114 <span class="text-[13px] font-medium text-ink-2">executor</span>
115 <span class="text-[12px] text-ink-3 ml-2">© {new Date().getFullYear()}</span>
116 </div>
117 <div class="flex items-center gap-6 text-[13px] text-ink-2">
118 <a href="https://executor.sh/docs" class="hover:text-ink transition-colors">Docs</a>
119 <a href="/blog" class="hover:text-ink transition-colors">Blog</a>
120 <a href={GH} class="hover:text-ink transition-colors">GitHub</a>
121 <a href="/privacy" class="hover:text-ink transition-colors">Privacy</a>
122 <a href="/terms" class="hover:text-ink transition-colors">Terms</a>
123 </div>
124 </div>
125 </footer>
126 </div>
127 </div>76 </div>
128 </main>77
129</Layout>78
79 <section class="doc__section">
80 <h2 class="doc__h">Questions</h2>
81 <dl class="doc__beats">
82 <div>
83 <dt>What counts as an execution?</dt>
84 <dd>One call to the Executor tool from your agent. A single execution can make many tool calls inside it.</dd>
85 </div>
86 <div>
87 <dt>What happens when the free tier runs out?</dt>
88 <dd>Calls pause until the month resets or you move to Team. Nothing is deleted.</dd>
89 </div>
90 <div>
91 <dt>Can I mix Cloud and self-hosted?</dt>
92 <dd>Yes. They are the same code, and an agent can point at more than one Executor.</dd>
93 </div>
94 </dl>
95 <p class="doc__quiet-p">
96 Something else? <a href="mailto:rhys@executor.sh?subject=Executor%20pricing">Email Rhys</a>.
97 </p>
98 </section>
99 </article>
100</RailLayout>
apps/marketing/src/styles/variants/doc.css+66−0
@@ -949,3 +949,69 @@ a.doc__term-v:hover { · 948 unmodified lines
949 text-align: left;949 text-align: left;
950 }950 }
951}951}
952
953/* ── Blog ── */
954.doc__posts {
955 display: grid;
956 margin-top: 0.5rem;
957 border-top: 1px solid var(--color-rule);
958}
959.doc__post {
960 display: grid;
961 gap: 0.3rem;
962 padding: 1.15rem 0 1.25rem;
963 border-bottom: 1px solid var(--color-rule);
964 text-decoration: none;
965 color: var(--color-ink-2);
966}
967.doc__post-date {
968 font-family: var(--font-mono);
969 font-size: 11px;
970 text-transform: uppercase;
971 letter-spacing: 0.14em;
972 color: var(--color-ink-3);
973}
974.doc__post-title {
975 font-size: 19px;
976 font-weight: 600;
977 letter-spacing: -0.01em;
978 color: var(--color-ink);
979 text-decoration: underline;
980 text-underline-offset: 4px;
981 text-decoration-color: transparent;
982 transition: text-decoration-color 0.15s ease;
983}
984.doc__post:hover .doc__post-title {
985 text-decoration-color: var(--color-rule-strong);
986}
987.doc__post-desc {
988 font-size: 15px;
989 line-height: 1.55;
990 text-wrap: pretty;
991}
992.doc__crumb {
993 display: inline-block;
994 font-family: var(--font-mono);
995 font-size: 11px;
996 text-transform: uppercase;
997 letter-spacing: 0.14em;
998 color: var(--color-ink-3);
999 margin-bottom: 1rem;
1000}
1001.doc__crumb:hover {
1002 color: var(--color-ink);
1003}
1004.doc__sig--post {
1005 margin-top: 0.5rem;
1006}
1007.doc__intro--post {
1008 padding-bottom: 2rem;
1009 border-bottom: 1px solid var(--color-rule);
1010 margin-bottom: 2rem;
1011}
1012@media (min-width: 1024px) {
1013 .doc__prose,
1014 .doc__posts {
1015 max-width: 720px;
1016 }
1017}