diff --git a/.gitignore b/.gitignore
index 40dee73..28fa614 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,3 +32,6 @@ web/waitlist.json
# OS
.DS_Store
+
+# Palate website-builder skill telemetry, written at the repo root during agent sessions
+build-manifest.json
diff --git a/web/app/DurableDeliveryTimeline.tsx b/web/app/DurableDeliveryTimeline.tsx
index 1a95046..02527de 100644
--- a/web/app/DurableDeliveryTimeline.tsx
+++ b/web/app/DurableDeliveryTimeline.tsx
@@ -1,6 +1,7 @@
'use client';
import { useEffect, useState } from 'react';
+import { Bot, Check, CircleAlert, Database, FileOutput, RotateCcw, UserRoundCheck, Webhook } from 'lucide-react';
import { AgentToolLogo, type AgentTool } from '../components/AgentToolLogos';
import s from './landing.module.css';
@@ -170,3 +171,101 @@ export function DurableDeliveryTimeline() {
);
}
+
+type WorkflowTraceItem = {
+ detail: string;
+ kind: 'checkpoint' | 'complete' | 'human' | 'model' | 'output' | 'retry' | 'trigger';
+ title: string;
+};
+
+const WORKFLOW_TRACE: readonly WorkflowTraceItem[] = [
+ { kind: 'trigger', title: 'repo.push received', detail: 'event · us-west' },
+ { kind: 'checkpoint', title: 'Input persisted', detail: 'checkpoint_01' },
+ { kind: 'model', title: 'Claude Code', detail: 'wrote release-plan.md' },
+ { kind: 'human', title: 'Approval recorded', detail: 'artifact accepted' },
+ { kind: 'retry', title: 'Deploy step', detail: 'attempt 2 · idempotent' },
+ { kind: 'output', title: 'Output persisted', detail: 'build_418' },
+ { kind: 'complete', title: 'Run completed', detail: '6 transitions · 1 retry' },
+];
+
+const WORKFLOW_STEP_DELAYS_MS = [1100, 1250, 1950, 1550, 2100, 1250, 3200] as const;
+
+function WorkflowTraceIcon({ kind }: { kind: WorkflowTraceItem['kind'] }) {
+ const iconProps = { 'aria-hidden': true, size: 15 } as const;
+
+ switch (kind) {
+ case 'trigger':
+ return ;
+ case 'checkpoint':
+ return ;
+ case 'model':
+ return ;
+ case 'human':
+ return ;
+ case 'retry':
+ return ;
+ case 'output':
+ return ;
+ case 'complete':
+ return ;
+ }
+}
+
+export function DurableWorkflowTrace() {
+ const [activeStep, setActiveStep] = useState(0);
+
+ useEffect(() => {
+ const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
+ if (reducedMotion) {
+ setActiveStep(WORKFLOW_TRACE.length - 1);
+ return undefined;
+ }
+
+ const timeoutId = window.setTimeout(() => {
+ setActiveStep((current) => (current + 1) % WORKFLOW_TRACE.length);
+ }, WORKFLOW_STEP_DELAYS_MS[activeStep]);
+
+ return () => window.clearTimeout(timeoutId);
+ }, [activeStep]);
+
+ return (
+
+
+ run_01J7
+ {activeStep === WORKFLOW_TRACE.length - 1 ? 'completed' : 'running'}
+
+
+
+
+
+ {WORKFLOW_TRACE.map((item, index) => {
+ const state = index < activeStep ? 'complete' : index === activeStep ? 'active' : 'pending';
+ const kindClass = item.kind === 'retry'
+ ? s.workflowTraceKindRetry
+ : item.kind === 'human'
+ ? s.workflowTraceKindHuman
+ : '';
+ return (
+
+
+
+
+
+ {item.title}
+ {item.detail}
+
+
+ {state === 'complete' ? : null}
+ {state === 'active' && item.kind === 'retry' ? : null}
+ {state === 'active' ? (item.kind === 'retry' ? 'retrying' : 'processing') : null}
+
+
+ );
+ })}
+
+
+ );
+}
diff --git a/web/app/globals.css b/web/app/globals.css
index 5411fa8..e49a309 100644
--- a/web/app/globals.css
+++ b/web/app/globals.css
@@ -32,20 +32,60 @@ a {
color: inherit;
}
+/* ── Focus ──
+ One rule for the whole site. The 2px offset puts the ring on the page
+ ground rather than on the control, so it is measured against the
+ background: >= 12:1 on every surface the site uses. */
+:focus-visible {
+ outline: 3px solid var(--focus-ring);
+ outline-offset: 2px;
+}
+
+/* Keyboard-only skip target, revealed on focus. */
+.skip-link {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ z-index: 200;
+ padding: 12px 20px;
+ min-height: 44px;
+ display: inline-flex;
+ align-items: center;
+ background: var(--fg);
+ color: var(--bg);
+ font-family: var(--font-geist-sans), sans-serif;
+ font-size: 0.9375rem;
+ font-weight: 600;
+ text-decoration: none;
+ border-radius: var(--r-md);
+ transform: translateY(-200%);
+ transition: transform 0.18s var(--ease-out-quint);
+}
+
+.skip-link:focus-visible {
+ transform: none;
+}
+
/* ── Buttons ──
Canonical button design, shared across the site. Landing-page CSS
modules pull these in with `composes: btn btn-primary from global;`
- so the primary button looks identical everywhere. */
+ so the primary button looks identical everywhere.
+
+ Shape comes from --r-md: the tail-corner message radius that every
+ interactive element on the site shares. min-height keeps every button a
+ comfortable target on touch (>= 44px) without per-page overrides. */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
- gap: 6px;
- font-size: 0.92rem;
+ gap: 8px;
+ font-family: var(--font-geist-sans), sans-serif;
+ font-size: 0.9375rem;
font-weight: 600;
- letter-spacing: 0.01em;
- padding: 12px 28px;
- border-radius: 100px;
+ letter-spacing: -0.005em;
+ padding: 13px 26px;
+ min-height: 48px;
+ border-radius: var(--r-md);
text-decoration: none;
cursor: pointer;
transition:
diff --git a/web/app/landing.module.css b/web/app/landing.module.css
index 30f48b4..7bc08f7 100644
--- a/web/app/landing.module.css
+++ b/web/app/landing.module.css
@@ -1943,7 +1943,11 @@
background: var(--agent-tools-band-bg);
}
-.messagingPage > :not(:first-child) {
+/* Lift the page content above the hero wash. Targeted at the two content
+ siblings by name so the sticky nav (and the keyboard skip link that now
+ precedes it) keep their own positioning. */
+.messagingPage > main,
+.messagingPage > footer {
position: relative;
z-index: 1;
}
@@ -1981,23 +1985,6 @@
z-index: 2;
}
-/* Hero communication graph and contour background */
-.heroBgSvg {
- position: absolute;
- inset: 0;
- width: 100%;
- height: 100%;
- z-index: 0;
- pointer-events: none;
- opacity: 0.96;
- filter: saturate(1.1) contrast(1.04);
-}
-
-:global(html[data-theme='dark']) .heroBgSvg {
- opacity: 0.88;
- filter: none;
-}
-
.hero {
display: grid;
grid-template-columns: 1fr 1.2fr;
@@ -2017,235 +2004,1440 @@
padding-top: 56px;
}
-.heroCopyGroup {
- display: grid;
- gap: 10px;
- max-width: 610px;
-}
-
.heroRight {
position: relative;
align-self: stretch;
min-height: 580px;
}
-.badge {
- display: inline-flex;
+/* ── Home hero: one centred column over the terminal marquee ─────────────
+ The product pages keep the two-column `.hero` above; the home page runs a
+ single centred column so the marquee band underneath gets the full width. */
+.heroCenter {
+ display: flex;
+ justify-content: center;
+ width: 100%;
+ padding: 72px 40px 0;
+}
+
+.heroCenterColumn {
+ display: flex;
+ flex-direction: column;
align-items: center;
- gap: 8px;
- background: var(--bg-elevated);
- border: 1px solid var(--line);
- padding: 6px 16px;
- border-radius: 100px;
- font-size: 0.75rem;
- font-weight: 600;
- letter-spacing: 0.06em;
- color: var(--primary);
- width: fit-content;
+ gap: 22px;
+ width: 100%;
+ max-width: 880px;
+ text-align: center;
}
-.badgeDot {
- width: 7px;
- height: 7px;
- border-radius: 50%;
- background: var(--primary);
- box-shadow: 0 0 6px color-mix(in srgb, var(--primary) 50%, transparent);
- animation: pulse 2s ease-in-out infinite;
+/* One step down from the product pages' `.headline`: this line is five words,
+ not three, and at the shared scale it filled the fold on its own and pushed
+ the marquee off the bottom of the screen. The column prefix is load-bearing —
+ `.headline` and `.subtitle` are declared further down this file, so a bare
+ class here would lose the cascade to them. */
+.heroCenterColumn .heroCenterHeadline {
+ font-size: clamp(2.6rem, 5.4vw, 4.5rem);
+ max-width: 20ch;
+ text-wrap: balance;
}
-@keyframes pulse {
- 0%,
- 100% {
- opacity: 1;
+.heroCenterColumn .heroCenterSubtitle {
+ max-width: 52ch;
+ margin: -4px auto 0;
+ text-wrap: pretty;
+}
+
+.heroCenterCtas {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-wrap: wrap;
+ gap: 14px;
+ margin-top: 2px;
+}
+
+/* ── Terminal marquee ────────────────────────────────────────────────────
+ Three full-bleed rows of agent sessions sliding past. Each track holds two
+ identical copies of its cards and slides exactly one copy's width, so the
+ loop is seamless; the spacing lives in each card's margin-right rather than
+ a flex gap so that -50% lands on a card boundary rather than half a gap
+ short. Rows differ in duration, direction and negative delay (a phase
+ offset) so the card seams never line up across the band. The rows also hold
+ different numbers of cards, so their tracks are different lengths and the
+ seams drift instead of beating in step. */
+.heroMarquee {
+ position: relative;
+ isolation: isolate;
+ display: flex;
+ flex-direction: column;
+ gap: 14px;
+ width: 100%;
+ margin-top: 68px;
+ padding-bottom: 26px;
+ /* clip, not hidden: the band never adds page scroll, and the cards' shadows
+ still breathe above and below the row. */
+ overflow-x: clip;
+ overflow-y: visible;
+}
+
+.heroRelayNetwork {
+ position: absolute;
+ inset: 0 0 26px;
+ z-index: 0;
+ width: 100%;
+ height: calc(100% - 26px);
+ overflow: visible;
+ pointer-events: none;
+}
+
+.heroRelayRoute {
+ fill: none;
+ stroke: none;
+}
+
+.heroRelayPacket,
+.heroRelayOrigin,
+.heroRelayArrival {
+ display: none;
+}
+
+.heroRelayPacketTail {
+ fill: none;
+ stroke: rgba(125, 194, 233, 0.82);
+ stroke-linecap: round;
+ stroke-width: 2.1;
+ vector-effect: non-scaling-stroke;
+}
+
+.heroRelayPacketHalo,
+.heroRelayOrigin,
+.heroRelayArrival {
+ fill: none;
+ stroke: rgba(125, 194, 233, 0.58);
+ stroke-width: 1.4;
+ vector-effect: non-scaling-stroke;
+}
+
+.heroRelayPacketCore {
+ fill: rgba(166, 219, 247, 0.96);
+}
+
+.heroMarqueeRow {
+ position: relative;
+ z-index: 1;
+ width: 100%;
+ overflow-x: clip;
+ overflow-y: visible;
+}
+
+.heroMarqueeTrack {
+ display: flex;
+ align-items: stretch;
+ width: max-content;
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ .heroRelayPacket,
+ .heroRelayOrigin,
+ .heroRelayArrival {
+ display: inline;
}
- 50% {
- opacity: 0.4;
+
+ .heroMarqueeTrack {
+ will-change: transform;
+ animation: heroMarqueeSlide linear infinite;
+ }
+
+ .heroMarqueeTrackOne {
+ animation-duration: 74s;
+ animation-delay: -11s;
+ }
+
+ .heroMarqueeTrackTwo {
+ animation-duration: 88s;
+ animation-delay: -37s;
+ animation-direction: reverse;
+ }
+
+ .heroMarqueeTrackThree {
+ animation-duration: 66s;
+ animation-delay: -23s;
}
}
-.headline {
- margin: 0;
- font-family: var(--font-heading), sans-serif;
- font-size: clamp(3.2rem, 7vw, 5.5rem);
- font-weight: 500;
- line-height: 1.05;
- letter-spacing: -0.03em;
- color: var(--fg);
- opacity: 0.85;
+@keyframes heroMarqueeSlide {
+ from {
+ transform: translate3d(0, 0, 0);
+ }
+ to {
+ transform: translate3d(-50%, 0, 0);
+ }
}
-:global(html[data-theme='dark']) .headline {
- opacity: 1;
+/* The second and third rows start part-way along so the seams stagger even
+ when motion is off. */
+.heroMarqueeTrackTwo {
+ margin-left: -132px;
}
-.subtitle {
- margin: 0;
- font-size: 1.1rem;
- line-height: 1.65;
- color: var(--fg-muted);
- max-width: 48ch;
- font-weight: 400;
+.heroMarqueeTrackThree {
+ margin-left: -258px;
}
-.ctas {
+.heroTerm {
+ --term-accent: #74b8e2;
display: flex;
- align-items: center;
- gap: 16px;
- padding-top: 4px;
+ flex-direction: column;
+ flex: none;
+ margin-right: 14px;
+ min-height: 158px;
+ border: 1px solid rgba(116, 184, 226, 0.16);
+ border-radius: 10px;
+ background: rgba(8, 22, 36, 0.9);
+ box-shadow: 0 6px 18px rgba(2, 10, 20, 0.28);
+ overflow: hidden;
}
-.heroCommandGroup {
- display: grid;
- gap: 10px;
- width: min(100%, 610px);
- margin-top: 0;
+.heroTermSm {
+ width: 268px;
}
-.heroCommandIntro {
- color: rgba(184, 211, 232, 0.62);
- font-size: 0.78rem;
- font-weight: 500;
- letter-spacing: 0;
- line-height: 1.25;
- max-width: 56ch;
+.heroTermMd {
+ width: 312px;
}
-.heroCommandCta {
- appearance: none;
- position: relative;
+.heroTermLg {
+ width: 352px;
+}
+
+.heroTermBar {
display: flex;
align-items: center;
- gap: 12px;
- width: 100%;
- margin-top: 0;
- min-height: 54px;
- padding: 10px 12px 10px 16px;
- border: 1px solid rgba(116, 184, 226, 0.2);
- border-radius: 10px;
- background:
- linear-gradient(180deg, rgba(116, 184, 226, 0.08), rgba(116, 184, 226, 0.02)),
- rgba(4, 18, 31, 0.76);
- box-shadow:
- inset 0 1px 0 rgba(237, 247, 255, 0.06),
- inset 0 -1px 0 rgba(116, 184, 226, 0.04);
- -webkit-backdrop-filter: blur(12px) saturate(125%);
- backdrop-filter: blur(12px) saturate(125%);
- color: inherit;
- cursor: pointer;
- font: inherit;
- text-align: left;
- transition:
- border-color 0.2s,
- background 0.2s;
+ gap: 8px;
+ padding: 6px 10px;
+ background: rgba(15, 33, 48, 0.94);
+ border-bottom: 1px solid rgba(116, 184, 226, 0.14);
}
-.heroCommandCta::before {
- content: none;
+.heroTermTraffic {
+ display: inline-flex;
+ flex: none;
+ align-items: center;
+ gap: 4px;
}
-.heroCommandPrompt,
-.heroCommandText,
-.heroCommandCopyButton {
- position: relative;
- z-index: 1;
+.heroTermTraffic span {
+ width: 7px;
+ height: 7px;
+ border-radius: 999px;
}
-.heroCommandPrompt {
- color: rgba(184, 211, 232, 0.62);
- font-family: var(--font-geist-mono), monospace;
- font-size: 1rem;
- line-height: 1;
- flex-shrink: 0;
+.heroTermTraffic span:nth-child(1) {
+ background: #ff5f57;
}
-.heroCommandText {
- min-width: 0;
- flex: 1;
- overflow-x: auto;
- scrollbar-width: none;
- color: rgba(244, 250, 255, 0.94);
- font-family: var(--font-geist-mono), monospace;
- font-size: clamp(0.84rem, 1.5vw, 1rem);
- font-weight: 520;
- letter-spacing: 0;
- line-height: 1.45;
- white-space: nowrap;
+.heroTermTraffic span:nth-child(2) {
+ background: #febc2e;
}
-.heroCommandText::-webkit-scrollbar {
- display: none;
+.heroTermTraffic span:nth-child(3) {
+ background: #28c840;
}
-.heroCommandCopyButton {
+.heroTermTitle {
display: inline-flex;
+ flex: 1;
align-items: center;
- justify-content: center;
- width: 38px;
- height: 38px;
+ gap: 6px;
+ min-width: 0;
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.68rem;
+ font-weight: 500;
+ letter-spacing: 0.01em;
+ color: rgba(206, 227, 243, 0.82);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.heroTermMark {
+ width: 12px;
+ height: 12px;
flex-shrink: 0;
- border: 1px solid rgba(116, 184, 226, 0.28);
- border-radius: 8px;
- background: rgba(9, 24, 40, 0.54);
- color: rgba(222, 240, 255, 0.78);
- cursor: inherit;
- opacity: 0;
- pointer-events: none;
- transition:
- opacity 0.2s,
- color 0.2s,
- border-color 0.2s,
- background 0.2s;
+ color: rgba(219, 233, 244, 0.9);
}
-.heroCommandCopyButton svg {
- width: 17px;
- height: 17px;
- stroke-width: 1.8;
+.heroTermBody {
+ display: flex;
+ flex-direction: column;
+ min-height: 128px;
+ padding: 9px 12px 8px;
}
-.heroCommandCopied {
- position: absolute;
- width: 1px;
- height: 1px;
+.heroTermSession {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto;
+ gap: 1px 8px;
+ min-width: 0;
+ margin-bottom: 7px;
+ font-family: var(--font-geist-mono), monospace;
+}
+
+.heroTermSessionName {
+ overflow: hidden;
+ color: rgba(218, 232, 244, 0.9);
+ font-size: 0.62rem;
+ font-weight: 650;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.heroTermMode {
+ color: rgba(160, 184, 204, 0.72);
+ font-size: 0.56rem;
+ white-space: nowrap;
+}
+
+.heroTermRepo {
+ grid-column: 1 / -1;
+ min-width: 0;
overflow: hidden;
- clip: rect(0 0 0 0);
+ color: rgba(147, 171, 193, 0.7);
+ font-size: 0.57rem;
+ text-overflow: ellipsis;
white-space: nowrap;
}
-.heroCommandCta:hover .heroCommandCopyButton,
-.heroCommandCta:focus-visible .heroCommandCopyButton {
- border-color: rgba(116, 184, 226, 0.28);
- background: rgba(9, 24, 40, 0.58);
- color: rgba(222, 240, 255, 0.76);
+.heroTermTranscript {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ min-height: 52px;
+}
+
+.heroTermLine {
+ position: relative;
+ display: flex;
+ align-items: baseline;
+ gap: 6px;
+ min-width: 0;
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.64rem;
+ line-height: 1.35;
+ letter-spacing: 0;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.heroTermLineMarker {
+ width: 9px;
+ flex: none;
+ color: currentColor;
+ font-weight: 700;
+ text-align: center;
+}
+
+.heroTermLineCopy {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.heroTermPrompt {
+ margin-inline: -4px;
+ padding: 2px 4px;
+ color: rgba(241, 247, 252, 0.96);
+ background: rgba(226, 237, 246, 0.1);
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ .heroTermLine {
+ animation: heroTerminalLineCycle var(--term-cycle) cubic-bezier(0.16, 1, 0.3, 1) infinite both;
+ animation-delay: calc(var(--term-phase) + var(--line-delay));
+ will-change: clip-path, opacity, transform;
+ }
+
+ .heroTermActivityGlyph {
+ animation: heroTerminalActivity 1.7s ease-in-out infinite;
+ }
+
+ .heroTermCursor {
+ animation: heroTerminalCursorBlink 920ms steps(2, start) infinite;
+ }
+}
+
+@keyframes heroTerminalLineCycle {
+ 0%,
+ 7% {
+ opacity: 0;
+ clip-path: inset(0 100% 0 0);
+ transform: translateY(3px);
+ }
+ 19%,
+ 76% {
+ opacity: 1;
+ clip-path: inset(0 0 0 0);
+ transform: translateY(0);
+ }
+ 91%,
+ 100% {
+ opacity: 0;
+ clip-path: inset(0 0 0 0);
+ transform: translateY(-2px);
+ }
+}
+
+@keyframes heroTerminalActivity {
+ 0%,
+ 100% {
+ opacity: 0.48;
+ transform: rotate(0deg) scale(0.86);
+ }
+ 50% {
+ opacity: 1;
+ transform: rotate(180deg) scale(1);
+ }
+}
+
+@keyframes heroTerminalCursorBlink {
+ 0%,
+ 48% {
+ opacity: 1;
+ }
+ 49%,
+ 100% {
+ opacity: 0;
+ }
+}
+
+.heroTermTool {
+ color: rgba(160, 184, 204, 0.82);
+}
+
+.heroTermOk {
+ color: #7fd3a0;
+}
+
+.heroTermRelay {
+ color: #85c6ec;
+}
+
+.heroTermComposer {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+ margin-top: auto;
+ padding-top: 5px;
+ border-top: 1px solid rgba(116, 184, 226, 0.12);
+}
+
+.heroTermLivePrompt {
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ height: 10px;
+ color: var(--term-accent);
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.65rem;
+ line-height: 1;
+}
+
+.heroTermState {
+ display: inline-flex;
+ flex: none;
+ align-items: center;
+ gap: 4px;
+ color: rgba(183, 207, 226, 0.72);
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.55rem;
+ font-weight: 600;
+ white-space: nowrap;
+}
+
+.heroTermActivityGlyph {
+ display: inline-block;
+ min-width: 9px;
+ color: var(--term-accent);
+ transform-origin: center;
+ text-align: center;
+}
+
+.heroGrokBody {
+ position: relative;
+ gap: 0;
+ padding-top: 8px;
+}
+
+.heroGrokBody::before {
+ position: absolute;
+ top: 0;
+ right: 0;
+ left: 0;
+ height: 1px;
+ background: rgba(116, 184, 226, 0.72);
+ content: "";
+ transform: scaleX(0.38);
+ transform-origin: left;
+}
+
+.heroGrokContext {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ min-width: 0;
+ margin-bottom: 6px;
+ color: rgba(145, 162, 177, 0.66);
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.56rem;
+}
+
+.heroGrokBranch {
+ flex: none;
+ font-size: 0.68rem;
+}
+
+.heroGrokPath {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.heroGrokContextMode {
+ flex: none;
+ margin-left: auto;
+ color: rgba(193, 210, 223, 0.74);
+}
+
+.heroGrokPrompt {
+ display: flex;
+ align-items: baseline;
+ gap: 7px;
+ min-width: 0;
+ margin-bottom: 5px;
+ padding: 4px 6px;
+ color: rgba(239, 244, 247, 0.92);
+ background: rgba(226, 237, 246, 0.1);
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.63rem;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.heroGrokPrompt span:last-child {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.heroGrokEvents {
+ display: flex;
+ flex-direction: column;
+ gap: 1px;
+ min-height: 43px;
+ padding-inline: 7px;
+ color: rgba(147, 166, 181, 0.7);
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.56rem;
+ line-height: 1.25;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.heroGrokReply {
+ margin-top: 2px;
+ overflow: hidden;
+ color: rgba(217, 228, 236, 0.84);
+ text-overflow: ellipsis;
+}
+
+.heroGrokFooter {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ min-width: 0;
+ margin-top: auto;
+ margin-bottom: 4px;
+ color: rgba(187, 203, 214, 0.78);
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.54rem;
+ white-space: nowrap;
+}
+
+.heroGrokProgress {
+ display: inline-flex;
+ flex: none;
+ align-items: center;
+ gap: 4px;
+}
+
+.heroGrokProgressGlyph {
+ display: inline-block;
+ color: rgba(216, 229, 238, 0.9);
+}
+
+.heroGrokResult {
+ min-width: 0;
+ overflow: hidden;
+ color: rgba(133, 198, 236, 0.86);
+ text-overflow: ellipsis;
+}
+
+.heroGrokComposer {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ min-height: 18px;
+ padding: 3px 5px;
+ border: 1px solid rgba(180, 199, 214, 0.24);
+ border-radius: 3px;
+ color: rgba(228, 238, 245, 0.88);
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.55rem;
+}
+
+.heroGrokModel {
+ margin-left: auto;
+ color: rgba(157, 174, 188, 0.68);
+ white-space: nowrap;
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ .heroGrokBody::before {
+ animation: heroGrokProgressRail var(--term-cycle) ease-in-out infinite both;
+ animation-delay: var(--term-phase);
+ }
+
+ .heroGrokCycleLine {
+ animation: heroTerminalLineCycle var(--term-cycle) cubic-bezier(0.16, 1, 0.3, 1) infinite both;
+ animation-delay: calc(var(--term-phase) + var(--line-delay));
+ will-change: clip-path, opacity, transform;
+ }
+
+ .heroGrokProgressGlyph {
+ animation: heroTerminalActivity 1.1s ease-in-out infinite;
+ }
+}
+
+@keyframes heroGrokProgressRail {
+ 0%,
+ 100% {
+ opacity: 0.36;
+ transform: scaleX(0.12);
+ }
+ 58% {
+ opacity: 0.92;
+ transform: scaleX(0.78);
+ }
+}
+
+.heroOpenCodeBody {
+ gap: 0;
+ padding-top: 8px;
+}
+
+.heroOpenCodePrompt {
+ min-width: 0;
+ margin-bottom: 7px;
+ padding: 5px 7px;
+ border-left: 2px solid rgba(89, 166, 238, 0.92);
+ background: rgba(226, 237, 246, 0.08);
+ color: rgba(237, 244, 249, 0.94);
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.63rem;
+ line-height: 1.3;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.heroOpenCodeActivity {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ min-height: 42px;
+ padding-inline: 8px;
+ color: rgba(155, 176, 192, 0.76);
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.56rem;
+ line-height: 1.25;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.heroOpenCodeThought {
+ color: rgba(214, 164, 93, 0.92);
+}
+
+.heroOpenCodeResult {
+ overflow: hidden;
+ color: rgba(220, 231, 239, 0.86);
+ text-overflow: ellipsis;
+}
+
+.heroOpenCodeMode {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ margin: 1px 8px 0;
+ color: rgba(148, 169, 185, 0.68);
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.55rem;
+}
+
+.heroOpenCodeMode > span:first-child,
+.heroOpenCodeMode strong {
+ color: rgba(89, 166, 238, 0.9);
+}
+
+.heroOpenCodeMode strong {
+ font-weight: 650;
+}
+
+.heroOpenCodeComposer {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ min-height: 22px;
+ margin-top: auto;
+ padding: 4px 6px;
+ border-left: 2px solid rgba(89, 166, 238, 0.92);
+ background: rgba(226, 237, 246, 0.08);
+ color: rgba(151, 171, 187, 0.66);
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.54rem;
+ white-space: nowrap;
+}
+
+.heroOpenCodeComposerMode {
+ margin-left: auto;
+ color: rgba(89, 166, 238, 0.94);
+}
+
+.heroOpenCodeLoaderRow {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ min-width: 0;
+ min-height: 14px;
+ color: rgba(169, 186, 199, 0.72);
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.51rem;
+ white-space: nowrap;
+}
+
+.heroOpenCodeLoader {
+ display: inline-flex;
+ flex: none;
+ align-items: center;
+ gap: 4px;
+ height: 9px;
+}
+
+.heroOpenCodeLoaderDot {
+ display: inline-block;
+ flex: none;
+ width: 5px;
+ height: 5px;
+ background: rgba(89, 166, 238, 0.82);
+ transform-origin: center;
+}
+
+.heroOpenCodeShortcut {
+ min-width: 0;
+ margin-left: auto;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ .heroOpenCodeCycleLine {
+ animation: heroTerminalLineCycle var(--term-cycle) cubic-bezier(0.16, 1, 0.3, 1) infinite both;
+ animation-delay: calc(var(--term-phase) + var(--line-delay));
+ will-change: clip-path, opacity, transform;
+ }
+
+ .heroClaudeAddedLine {
+ animation-duration: var(--term-cycle);
+ animation-timing-function: step-end;
+ animation-delay: var(--term-phase);
+ animation-iteration-count: infinite;
+ animation-fill-mode: both;
+ }
+
+ .heroClaudeBody .heroClaudeAddedLine:nth-child(1) {
+ animation-name: heroTerminalLineAddOne;
+ }
+
+ .heroClaudeBody .heroClaudeAddedLine:nth-child(2) {
+ animation-name: heroTerminalLineAddTwo;
+ }
+
+ .heroClaudeBody .heroClaudeAddedLine:nth-child(3) {
+ animation-name: heroTerminalLineAddThree;
+ }
+
+ .heroOpenCodeLoaderDot {
+ animation: heroOpenCodeLoaderPulse 1.28s ease-in-out infinite both;
+ }
+
+ .heroOpenCodeLoaderDot:nth-child(2) {
+ animation-delay: 100ms;
+ }
+
+ .heroOpenCodeLoaderDot:nth-child(3) {
+ animation-delay: 200ms;
+ }
+
+ .heroOpenCodeLoaderDot:nth-child(4) {
+ animation-delay: 300ms;
+ }
+
+ .heroOpenCodeLoaderDot:nth-child(5) {
+ animation-delay: 400ms;
+ }
+
+ .heroOpenCodeLoaderDot:nth-child(6) {
+ animation-delay: 500ms;
+ }
+
+ .heroOpenCodeLoaderDot:nth-child(7) {
+ animation-delay: 600ms;
+ }
+
+ .heroOpenCodeLoaderDot:nth-child(8) {
+ animation-delay: 700ms;
+ }
+}
+
+@keyframes heroTerminalLineAddOne {
+ 0%,
+ 18% {
+ visibility: hidden;
+ clip-path: inset(0 100% 0 0);
+ }
+ 19%,
+ 100% {
+ visibility: visible;
+ clip-path: inset(0 0 0 0);
+ }
+}
+
+@keyframes heroTerminalLineAddTwo {
+ 0%,
+ 39% {
+ visibility: hidden;
+ clip-path: inset(0 100% 0 0);
+ }
+ 40%,
+ 100% {
+ visibility: visible;
+ clip-path: inset(0 0 0 0);
+ }
+}
+
+@keyframes heroTerminalLineAddThree {
+ 0%,
+ 61% {
+ visibility: hidden;
+ clip-path: inset(0 100% 0 0);
+ }
+ 62%,
+ 100% {
+ visibility: visible;
+ clip-path: inset(0 0 0 0);
+ }
+}
+
+@keyframes heroOpenCodeLoaderPulse {
+ 0%,
+ 100% {
+ opacity: 0.3;
+ transform: scale(0.68);
+ }
+ 45% {
+ opacity: 1;
+ transform: scale(1.28);
+ }
+}
+
+.heroClaudeBody {
+ gap: 0;
+ padding-top: 7px;
+}
+
+.heroClaudeScrollViewport {
+ position: relative;
+ height: 78px;
+ flex: none;
+ overflow: hidden;
+}
+
+.heroClaudeScrollTrack,
+.heroClaudeScrollSequence {
+ display: flex;
+ flex-direction: column;
+}
+
+.heroClaudeScrollSequence {
+ flex: none;
+ min-height: 102px;
+ padding-bottom: 8px;
+}
+
+.heroClaudeIdentity {
+ display: grid;
+ grid-template-columns: 50px minmax(0, 1fr);
+ align-items: center;
+ gap: 8px;
+ min-width: 0;
+ min-height: 40px;
+ margin-bottom: 6px;
+}
+
+.heroClaudeMascot {
+ position: relative;
+ display: block;
+ width: 48px;
+ height: 36px;
+ justify-self: center;
+ background: #d97855;
+ clip-path: polygon(
+ 12.5% 0,
+ 87.5% 0,
+ 87.5% 28%,
+ 100% 28%,
+ 100% 64%,
+ 87.5% 64%,
+ 87.5% 78%,
+ 75% 78%,
+ 75% 100%,
+ 62.5% 100%,
+ 62.5% 78%,
+ 50% 78%,
+ 50% 100%,
+ 37.5% 100%,
+ 37.5% 78%,
+ 25% 78%,
+ 25% 100%,
+ 12.5% 100%,
+ 12.5% 78%,
+ 0 78%,
+ 0 28%,
+ 12.5% 28%
+ );
+}
+
+.heroClaudeMascot::after {
+ position: absolute;
+ top: 9px;
+ left: 13px;
+ width: 4px;
+ height: 8px;
+ background: rgb(8 22 36);
+ box-shadow: 27px 0 0 rgb(8 22 36);
+ content: '';
+}
+
+.heroClaudeIdentityCopy {
+ display: flex;
+ flex-direction: column;
+ gap: 1px;
+ min-width: 0;
+ font-family: var(--font-geist-mono), monospace;
+ line-height: 1.18;
+}
+
+.heroClaudeIdentityTitle {
+ overflow: hidden;
+ color: rgba(222, 230, 246, 0.94);
+ font-size: 0.58rem;
+ font-weight: 680;
+ letter-spacing: 0.02em;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.heroClaudeIdentityTitle span {
+ color: rgba(158, 169, 184, 0.7);
+ font-weight: 500;
+}
+
+.heroClaudeModel,
+.heroClaudePath {
+ min-width: 0;
+ overflow: hidden;
+ color: rgba(177, 189, 204, 0.76);
+ font-size: 0.49rem;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.heroClaudePath {
+ color: rgba(161, 177, 194, 0.68);
+}
+
+.heroClaudeBody .heroTermTranscript {
+ min-height: 48px;
+}
+
+.heroClaudeBody .heroTermLine {
+ font-size: 0.59rem;
+}
+
+.heroCodexBody {
+ gap: 0;
+ padding-top: 7px;
+}
+
+.heroCodexScrollViewport {
+ position: relative;
+ height: 80px;
+ flex: none;
+ margin-bottom: 3px;
+ overflow: hidden;
+}
+
+.heroCodexScrollTrack,
+.heroCodexScrollSequence {
+ display: flex;
+ flex-direction: column;
+}
+
+.heroCodexScrollSequence {
+ flex: none;
+ min-height: 116px;
+ padding-bottom: 8px;
+}
+
+.heroCodexIdentity {
+ display: flex;
+ flex-direction: column;
+ gap: 1px;
+ min-width: 0;
+ margin-bottom: 5px;
+ padding: 4px 6px;
+ border: 1px solid rgba(160, 184, 204, 0.28);
+ border-radius: 3px;
+ color: rgba(196, 215, 232, 0.84);
+ font-family: var(--font-geist-mono), monospace;
+ font-size: 0.5rem;
+ line-height: 1.18;
+}
+
+.heroCodexIdentityTitle {
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ margin-bottom: 1px;
+ color: rgba(223, 235, 246, 0.94);
+ font-size: 0.58rem;
+ font-weight: 680;
+ letter-spacing: 0.02em;
+}
+
+.heroCodexIdentityTitle span {
+ color: rgba(141, 170, 198, 0.76);
+}
+
+.heroCodexIdentityRow {
+ display: flex;
+ align-items: baseline;
+ gap: 5px;
+ min-width: 0;
+ white-space: nowrap;
+}
+
+.heroCodexIdentityRow b {
+ color: rgba(132, 202, 238, 0.92);
+ font-weight: 600;
+}
+
+.heroCodexIdentityLabel {
+ width: 46px;
+ flex: none;
+ color: rgba(137, 159, 180, 0.68);
+}
+
+.heroCodexIdentityPath {
+ min-width: 0;
+ overflow: hidden;
+ color: rgba(162, 208, 178, 0.86);
+ text-overflow: ellipsis;
+}
+
+.heroCodexPrompt,
+.heroCodexReply,
+.heroCodexRun,
+.heroCodexWorking,
+.heroCodexComposer,
+.heroCodexFooter {
+ font-family: var(--font-geist-mono), monospace;
+}
+
+.heroCodexPrompt {
+ display: flex;
+ align-items: baseline;
+ gap: 6px;
+ min-width: 0;
+ margin-bottom: 4px;
+ padding: 4px 5px;
+ background: rgba(226, 237, 246, 0.11);
+ color: rgba(229, 238, 247, 0.94);
+ font-size: 0.58rem;
+ line-height: 1.25;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.heroCodexPrompt span:last-child {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.heroCodexReply {
+ display: flex;
+ align-items: baseline;
+ gap: 6px;
+ min-width: 0;
+ margin-bottom: 3px;
+ color: rgba(199, 216, 232, 0.82);
+ font-size: 0.51rem;
+ line-height: 1.25;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.heroCodexReply span:last-child {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.heroCodexRun {
+ display: grid;
+ grid-template-columns: 8px minmax(0, 1fr);
+ min-width: 0;
+ margin-bottom: 3px;
+ color: rgba(155, 179, 201, 0.75);
+ font-size: 0.5rem;
+ line-height: 1.22;
+}
+
+.heroCodexRunMarker {
+ color: rgba(169, 218, 112, 0.92);
+}
+
+.heroCodexRunCopy,
+.heroCodexRunResult {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.heroCodexRunCopy strong {
+ color: rgba(215, 230, 241, 0.9);
+ font-weight: 650;
+}
+
+.heroCodexRunResult {
+ grid-column: 2;
+ color: rgba(137, 162, 184, 0.68);
+}
+
+.heroCodexWorking {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ margin-top: auto;
+ margin-bottom: 3px;
+ color: rgba(145, 168, 190, 0.66);
+ font-size: 0.49rem;
+ white-space: nowrap;
+}
+
+.heroCodexScrollSequence .heroCodexWorking {
+ margin-top: 0;
+}
+
+.heroCodexWorking strong {
+ color: rgba(193, 212, 229, 0.82);
+ font-weight: 650;
+}
+
+.heroCodexWorkingMarker {
+ display: inline-block;
+ color: rgba(130, 185, 226, 0.9);
+}
+
+.heroCodexComposer {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ min-width: 0;
+ min-height: 19px;
+ padding: 3px 5px;
+ background: rgba(226, 237, 246, 0.11);
+ color: rgba(220, 232, 242, 0.86);
+ font-size: 0.52rem;
+}
+
+.heroCodexComposerHint {
+ min-width: 0;
+ overflow: hidden;
+ color: rgba(155, 177, 197, 0.66);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.heroCodexFooter {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ min-width: 0;
+ padding: 3px 5px 0;
+ color: rgba(181, 202, 219, 0.72);
+ font-size: 0.47rem;
+ line-height: 1;
+ white-space: nowrap;
+}
+
+.heroCodexFooter strong {
+ color: rgba(132, 202, 238, 0.92);
+ font-weight: 600;
+}
+
+.heroCodexFooterPath {
+ min-width: 0;
+ margin-left: auto;
+ overflow: hidden;
+ color: rgba(162, 208, 178, 0.82);
+ text-overflow: ellipsis;
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ .heroCodexScrollTrack {
+ animation: heroCodexTranscriptSteps var(--term-cycle) step-end infinite both;
+ animation-delay: var(--term-phase);
+ will-change: transform;
+ }
+
+ .heroCodexAddedLine {
+ animation-duration: var(--term-cycle);
+ animation-timing-function: step-end;
+ animation-delay: var(--term-phase);
+ animation-iteration-count: infinite;
+ animation-fill-mode: both;
+ }
+
+ .heroCodexPrompt.heroCodexAddedLine {
+ animation-name: heroCodexLineAddPrompt;
+ }
+
+ .heroCodexReply.heroCodexAddedLine {
+ animation-name: heroCodexLineAddReply;
+ }
+
+ .heroCodexRun.heroCodexAddedLine {
+ animation-name: heroCodexLineAddRun;
+ }
+
+ .heroCodexWorking.heroCodexAddedLine {
+ animation-name: heroCodexLineAddWorking;
+ }
+
+ .heroClaudeScrollTrack {
+ animation: heroClaudeTranscriptSteps var(--term-cycle) step-end infinite both;
+ animation-delay: var(--term-phase);
+ will-change: transform;
+ }
+
+ .heroCodexWorkingMarker {
+ animation: heroCodexWorkingPulse 1.25s ease-in-out infinite;
+ }
+}
+
+@keyframes heroCodexTranscriptSteps {
+ 0%,
+ 37% {
+ transform: translate3d(0, 0, 0);
+ }
+ 38%,
+ 57% {
+ transform: translate3d(0, -12px, 0);
+ }
+ 58%,
+ 77% {
+ transform: translate3d(0, -34px, 0);
+ }
+ 78%,
+ 100% {
+ transform: translate3d(0, -48px, 0);
+ }
+}
+
+@keyframes heroCodexLineAddPrompt {
+ 0%,
+ 17% {
+ visibility: hidden;
+ clip-path: inset(0 100% 0 0);
+ }
+ 18%,
+ 100% {
+ visibility: visible;
+ clip-path: inset(0 0 0 0);
+ }
+}
+
+@keyframes heroCodexLineAddReply {
+ 0%,
+ 37% {
+ visibility: hidden;
+ clip-path: inset(0 100% 0 0);
+ }
+ 38%,
+ 100% {
+ visibility: visible;
+ clip-path: inset(0 0 0 0);
+ }
+}
+
+@keyframes heroCodexLineAddRun {
+ 0%,
+ 57% {
+ visibility: hidden;
+ clip-path: inset(0 100% 0 0);
+ }
+ 58%,
+ 100% {
+ visibility: visible;
+ clip-path: inset(0 0 0 0);
+ }
+}
+
+@keyframes heroCodexLineAddWorking {
+ 0%,
+ 77% {
+ visibility: hidden;
+ clip-path: inset(0 100% 0 0);
+ }
+ 78%,
+ 100% {
+ visibility: visible;
+ clip-path: inset(0 0 0 0);
+ }
+}
+
+@keyframes heroClaudeTranscriptSteps {
+ 0%,
+ 31% {
+ transform: translate3d(0, 0, 0);
+ }
+ 32%,
+ 52% {
+ transform: translate3d(0, -14px, 0);
+ }
+ 53%,
+ 73% {
+ transform: translate3d(0, -28px, 0);
+ }
+ 74%,
+ 100% {
+ transform: translate3d(0, -44px, 0);
+ }
+}
+
+@keyframes heroCodexWorkingPulse {
+ 0%,
+ 100% {
+ opacity: 0.38;
+ transform: scale(0.72);
+ }
+ 50% {
+ opacity: 1;
+ transform: scale(1);
+ }
+}
+
+.heroTermPromptGlyph {
+ min-width: 8px;
+ font-weight: 700;
+}
+
+.heroTermCursor {
+ display: inline-block;
+ width: 6px;
+ height: 9px;
+ background: color-mix(in srgb, var(--term-accent) 82%, white 18%);
+ opacity: 0.78;
+}
+
+.badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ background: var(--bg-elevated);
+ border: 1px solid var(--line);
+ padding: 6px 16px;
+ border-radius: 100px;
+ font-size: 0.75rem;
+ font-weight: 600;
+ letter-spacing: 0.06em;
+ color: var(--primary);
+ width: fit-content;
+}
+
+.badgeDot {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: var(--primary);
+ box-shadow: 0 0 6px color-mix(in srgb, var(--primary) 50%, transparent);
+ animation: pulse 2s ease-in-out infinite;
}
-.heroCommandCta:focus-visible {
- outline: 2px solid color-mix(in srgb, var(--primary) 70%, white 18%);
- outline-offset: 3px;
+@keyframes pulse {
+ 0%,
+ 100% {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0.4;
+ }
}
-.heroCommandCta:focus-within .heroCommandCopyButton {
- opacity: 1;
+.headline {
+ margin: 0;
+ font-family: var(--font-heading), sans-serif;
+ font-size: clamp(3.2rem, 7vw, 5.5rem);
+ font-weight: 500;
+ line-height: 1.05;
+ letter-spacing: -0.03em;
+ color: var(--fg);
+ opacity: 0.85;
}
-@media (hover: hover) and (pointer: fine) {
- .heroCommandCta:hover {
- border-color: rgba(116, 184, 226, 0.36);
- background:
- linear-gradient(180deg, rgba(116, 184, 226, 0.1), rgba(116, 184, 226, 0.025)),
- rgba(4, 18, 31, 0.8);
- }
+:global(html[data-theme='dark']) .headline {
+ opacity: 1;
+}
- .heroCommandCta:hover .heroCommandCopyButton,
- .heroCommandCta:focus-within .heroCommandCopyButton {
- opacity: 1;
- }
+.subtitle {
+ margin: 0;
+ font-size: 1.1rem;
+ line-height: 1.65;
+ color: var(--fg-muted);
+ max-width: 48ch;
+ font-weight: 400;
}
-@media (hover: none), (pointer: coarse) {
- .heroCommandCopyButton {
- opacity: 1;
- }
+.ctas {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ padding-top: 4px;
}
.installCommand {
@@ -3106,6 +4298,10 @@
transition: background 0.3s ease;
position: relative;
z-index: 3;
+ /* Feature reveals can enter from beyond the centered content grid. Clip at
+ the viewport-wide wrapper so full-bleed section backgrounds remain
+ visible while off-screen motion never creates horizontal scroll. */
+ overflow-x: clip;
}
.featuresSection {
@@ -3550,36 +4746,343 @@
color: rgba(226, 232, 240, 0.58);
}
-.webhookCapabilityPreview {
+.sharedFilesCapabilityPreview {
background: #07111e;
}
-.webhookCapabilityPreview .webhookPreview {
- padding: 0;
- justify-content: stretch;
-}
+.sharedFileMount {
+ position: absolute;
+ inset: 0;
+ z-index: 1;
+ display: grid;
+ grid-template-rows: auto auto minmax(0, 1fr) auto;
+ gap: 10px;
+ padding: 14px;
+ overflow: hidden;
+ background:
+ radial-gradient(circle at 50% -30%, rgba(73, 157, 214, 0.2), transparent 52%),
+ #07111e;
+ color: rgba(226, 232, 240, 0.86);
+ font-family: var(--font-geist-mono), monospace;
+}
+
+.mountTopbar,
+.mountAgent,
+.mountTree {
+ border: 1px solid rgba(156, 207, 255, 0.15);
+ background: rgba(14, 23, 41, 0.9);
+ box-shadow: 0 10px 24px rgba(2, 7, 18, 0.22);
+}
+
+.mountTopbar {
+ display: grid;
+ grid-template-columns: auto minmax(0, 1fr) auto;
+ align-items: center;
+ gap: 8px;
+ min-height: 30px;
+ padding: 7px 9px;
+ border-radius: 8px;
+ color: rgba(181, 205, 226, 0.76);
+ font-size: 0.61rem;
+}
+
+.mountTopbar code {
+ overflow: hidden;
+ color: rgba(241, 245, 249, 0.9);
+ font: inherit;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.mountStatus {
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ color: #78d5ad;
+ white-space: nowrap;
+}
+
+.mountStatus > span {
+ width: 5px;
+ height: 5px;
+ border-radius: 50%;
+ background: currentColor;
+}
+
+.mountAgentRow {
+ display: grid;
+ grid-template-columns: max-content minmax(36px, 1fr) max-content;
+ align-items: center;
+ gap: 8px;
+ min-width: 0;
+}
+
+.mountAgent {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ min-height: 28px;
+ padding: 6px 8px;
+ border-radius: 7px;
+ color: rgba(226, 232, 240, 0.78);
+ font-size: 0.58rem;
+ white-space: nowrap;
+}
+
+.mountAgentClaude svg {
+ color: #df7b58;
+}
+
+.mountAgentCodex svg {
+ color: #91b7d4;
+}
+
+.mountTransport {
+ position: relative;
+ height: 10px;
+ overflow: hidden;
+}
+
+.mountTransport::before {
+ content: '';
+ position: absolute;
+ top: 50%;
+ right: 0;
+ left: 0;
+ height: 1px;
+ background: rgba(116, 184, 226, 0.32);
+ transform: translateY(-50%);
+}
+
+.mountPulseWrite,
+.mountPulseRead {
+ position: absolute;
+ inset: 0;
+ opacity: 0;
+ background: linear-gradient(
+ 90deg,
+ transparent 40%,
+ rgba(116, 184, 226, 0.2) 46%,
+ #9ccfff 50%,
+ rgba(116, 184, 226, 0.2) 54%,
+ transparent 60%
+ );
+ will-change: transform, opacity;
+}
+
+.mountPulseWrite {
+ transform: translateX(-100%);
+}
+
+.mountPulseRead {
+ transform: translateX(100%);
+}
+
+.mountTree {
+ min-height: 0;
+ overflow: hidden;
+ border-radius: 9px;
+}
+
+.mountTreeHead,
+.mountFile {
+ position: relative;
+ display: grid;
+ grid-template-columns: auto minmax(0, 1fr) auto;
+ align-items: center;
+ gap: 7px;
+}
+
+.mountTreeHead {
+ min-height: 28px;
+ padding: 6px 9px;
+ border-bottom: 1px solid rgba(156, 207, 255, 0.12);
+ color: rgba(241, 245, 249, 0.88);
+ font-size: 0.61rem;
+ font-weight: 700;
+}
+
+.mountTreeHead small {
+ color: rgba(120, 213, 173, 0.78);
+ font: inherit;
+ font-weight: 500;
+}
+
+.mountFile {
+ min-height: 27px;
+ padding: 6px 9px 6px 20px;
+ color: rgba(148, 163, 184, 0.76);
+ font-size: 0.56rem;
+}
+
+.mountFile + .mountFile {
+ border-top: 1px solid rgba(156, 207, 255, 0.08);
+}
+
+.mountFile::before {
+ content: '';
+ position: absolute;
+ inset: 2px 4px;
+ border: 1px solid rgba(116, 184, 226, 0.22);
+ border-radius: 5px;
+ background: rgba(50, 119, 169, 0.16);
+ opacity: 0;
+}
+
+.mountFile > * {
+ position: relative;
+ z-index: 1;
+}
+
+.mountFile code {
+ overflow: hidden;
+ color: rgba(218, 229, 239, 0.84);
+ font: inherit;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.mountFile > span {
+ color: rgba(116, 184, 226, 0.86);
+}
+
+.mountActivity {
+ position: relative;
+ display: grid;
+ min-height: 14px;
+ padding-left: 13px;
+ color: rgba(173, 192, 210, 0.72);
+ font-size: 0.56rem;
+ line-height: 14px;
+}
+
+.mountActivity::before {
+ content: '';
+ position: absolute;
+ top: 5px;
+ left: 1px;
+ width: 5px;
+ height: 5px;
+ border-radius: 50%;
+ background: #78d5ad;
+}
+
+.mountActivity span {
+ grid-area: 1 / 1;
+ opacity: 0;
+}
+
+.mountActivity span:first-child {
+ opacity: 1;
+}
+
+@keyframes sharedMountWrite {
+ 0%,
+ 8% {
+ opacity: 0;
+ transform: translateX(-100%);
+ }
+
+ 12%,
+ 34% {
+ opacity: 1;
+ }
+
+ 38%,
+ 100% {
+ opacity: 0;
+ transform: translateX(100%);
+ }
+}
+
+@keyframes sharedMountRead {
+ 0%,
+ 50% {
+ opacity: 0;
+ transform: translateX(100%);
+ }
+
+ 54%,
+ 76% {
+ opacity: 1;
+ }
+
+ 80%,
+ 100% {
+ opacity: 0;
+ transform: translateX(-100%);
+ }
+}
+
+@keyframes sharedMountFileSync {
+ 0%,
+ 20%,
+ 100% {
+ opacity: 0;
+ }
+
+ 22%,
+ 42% {
+ opacity: 1;
+ }
+
+ 44% {
+ opacity: 0;
+ }
+}
+
+@keyframes sharedMountActivityFirst {
+ 0%,
+ 47% {
+ opacity: 1;
+ }
+
+ 50%,
+ 100% {
+ opacity: 0;
+ }
+}
+
+@keyframes sharedMountActivitySecond {
+ 0%,
+ 47% {
+ opacity: 0;
+ }
+
+ 50%,
+ 100% {
+ opacity: 1;
+ }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ .mountPulseWrite {
+ animation: sharedMountWrite 5.6s steps(9, end) infinite;
+ }
+
+ .mountPulseRead {
+ animation: sharedMountRead 5.6s steps(9, end) infinite;
+ }
+
+ .mountFile::before {
+ animation: sharedMountFileSync 5.6s steps(1, end) infinite;
+ }
+
+ .mountFile:nth-child(3)::before {
+ animation-delay: 0.65s;
+ }
+
+ .mountFile:nth-child(4)::before {
+ animation-delay: 1.3s;
+ }
-.webhookCapabilityPreview .webhookCodeTitle {
- border-top: 0;
- border-right: 0;
- border-left: 0;
- border-radius: 0;
- border-bottom-color: rgba(156, 207, 255, 0.2);
- background: linear-gradient(180deg, rgba(74, 144, 194, 0.34), rgba(22, 47, 72, 0.56));
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16);
- color: rgba(248, 250, 252, 0.82);
- backdrop-filter: blur(16px) saturate(1.35);
- -webkit-backdrop-filter: blur(16px) saturate(1.35);
-}
+ .mountActivity span:first-child {
+ animation: sharedMountActivityFirst 5.6s steps(1, end) infinite;
+ }
-.webhookCapabilityPreview .webhookCodeSnippet {
- flex: 1;
- min-height: 0;
- border-right: 0;
- border-bottom: 0;
- border-left: 0;
- border-radius: 0;
- box-shadow: none;
+ .mountActivity span:last-child {
+ animation: sharedMountActivitySecond 5.6s steps(1, end) infinite;
+ }
}
.capabilityPreview .searchPreview {
@@ -4286,83 +5789,6 @@
backdrop-filter: blur(12px);
}
-.webhookPreview {
- position: absolute;
- inset: 0;
- z-index: 1;
- display: flex;
- flex-direction: column;
- justify-content: center;
- padding: 20px 0 20px 20px;
- color: #f7fafc;
-}
-
-.webhookCodeTitle {
- display: flex;
- align-items: center;
- gap: 10px;
- width: 100%;
- padding: 11px 16px;
- border: 1px solid rgba(255, 255, 255, 0.14);
- border-right: 0;
- border-radius: 10px 0 0 0;
- background: #111a24;
- color: rgba(226, 232, 240, 0.72);
- font-family: var(--font-geist-mono), monospace;
- font-size: 0.68rem;
- line-height: 1;
-}
-
-.webhookCodeDots {
- display: inline-flex;
- align-items: center;
- gap: 6px;
- flex: 0 0 auto;
-}
-
-.webhookCodeDots span {
- width: 9px;
- height: 9px;
- border-radius: 50%;
-}
-
-.webhookCodeDots span:nth-child(1) {
- background: #ff5f57;
-}
-
-.webhookCodeDots span:nth-child(2) {
- background: #febc2e;
-}
-
-.webhookCodeDots span:nth-child(3) {
- background: #28c840;
-}
-
-.webhookCodeSnippet {
- width: 100%;
- min-height: 174px;
- margin: 0;
- padding: 18px 16px 20px;
- border: 1px solid rgba(255, 255, 255, 0.14);
- border-top: 0;
- border-right: 0;
- border-radius: 0 0 0 10px;
- background: #07111e;
- box-shadow: -10px 12px 30px rgba(2, 7, 18, 0.28);
- color: rgba(248, 250, 252, 0.9);
- overflow: hidden;
-}
-
-.webhookCodeSnippet code {
- overflow: hidden;
- font-family: var(--font-geist-mono), monospace;
- font-size: 0.7rem;
- font-weight: 700;
- line-height: 1.7;
- text-overflow: ellipsis;
- white-space: pre-wrap;
-}
-
.commandPrompt code {
overflow: hidden;
font-family: var(--font-geist-mono), monospace;
@@ -5060,11 +6486,206 @@
}
}
+.workflowTracePreview {
+ position: relative;
+ height: 100%;
+ overflow: hidden;
+ padding: 12px 18px 12px 44px;
+ font-family: var(--font-geist-mono), monospace;
+}
+
+.workflowTraceHeader {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ min-height: 26px;
+ margin-bottom: 6px;
+ padding: 0 10px;
+ border: 1px solid rgba(156, 207, 255, 0.13);
+ border-radius: 8px;
+ background: rgba(15, 27, 45, 0.68);
+ color: rgba(190, 206, 224, 0.72);
+ font-size: 0.58rem;
+}
+
+.workflowTraceHeader strong {
+ color: #74b8e2;
+ font-size: 0.54rem;
+ font-weight: 700;
+}
+
+.workflowTraceRail {
+ position: absolute;
+ top: 45px;
+ bottom: 28px;
+ left: 27px;
+ width: 1px;
+ overflow: hidden;
+ background: rgba(126, 184, 218, 0.16);
+}
+
+.workflowTraceRail span {
+ display: block;
+ width: 100%;
+ min-height: 4px;
+ background: #2e6a9c;
+ box-shadow: 0 0 10px rgba(74, 144, 194, 0.38);
+ transition: height 520ms cubic-bezier(0.16, 1, 0.3, 1);
+}
+
+.workflowTraceRows {
+ display: grid;
+ gap: 4px;
+}
+
+.workflowTraceRow {
+ position: relative;
+ display: grid;
+ grid-template-columns: 22px minmax(0, 1fr) auto;
+ align-items: center;
+ min-height: 35px;
+ padding: 3px 9px;
+ overflow: hidden;
+ border: 1px solid rgba(156, 207, 255, 0.12);
+ border-radius: 8px;
+ background: rgba(15, 27, 45, 0.7);
+ color: rgba(245, 248, 255, 0.94);
+ box-shadow: 0 8px 22px rgba(2, 7, 18, 0.18);
+ transition:
+ opacity 360ms ease,
+ border-color 360ms ease,
+ background-color 360ms ease,
+ transform 360ms cubic-bezier(0.16, 1, 0.3, 1);
+}
+
+.workflowTraceRow::before {
+ position: absolute;
+ top: 50%;
+ left: -22px;
+ width: 7px;
+ height: 7px;
+ border: 1px solid rgba(116, 184, 226, 0.45);
+ border-radius: 50%;
+ background: #07111f;
+ content: '';
+ transform: translateY(-50%);
+}
+
+.workflowTraceRow_pending {
+ opacity: 0.22;
+ transform: translateY(2px);
+}
+
+.workflowTraceRow_active {
+ border-color: rgba(116, 184, 226, 0.56);
+ background: rgba(19, 38, 61, 0.9);
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.workflowTraceRow_active::after {
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(90deg, transparent 0%, rgba(116, 184, 226, 0.1) 48%, transparent 76%);
+ content: '';
+ pointer-events: none;
+ transform: translateX(-100%);
+ animation: workflowTraceScan 1.35s ease-in-out infinite;
+}
+
+.workflowTraceRow_active::before,
+.workflowTraceRow_complete::before {
+ border-color: #2e6a9c;
+ background: #2e6a9c;
+}
+
+.workflowTraceRow_complete {
+ opacity: 0.72;
+}
+
+.workflowTraceKindRetry.workflowTraceRow_active {
+ border-color: rgba(216, 135, 111, 0.58);
+ background: rgba(55, 34, 36, 0.78);
+}
+
+.workflowTraceKindRetry.workflowTraceRow_active::after {
+ background: linear-gradient(90deg, transparent 0%, rgba(216, 135, 111, 0.12) 48%, transparent 76%);
+}
+
+.workflowTraceIcon {
+ display: grid;
+ place-items: center;
+ width: 18px;
+ height: 18px;
+ color: #74b8e2;
+}
+
+.workflowTraceKindRetry .workflowTraceIcon,
+.workflowTraceKindHuman .workflowTraceIcon {
+ color: #d8876f;
+}
+
+.workflowTraceCopy {
+ min-width: 0;
+}
+
+.workflowTraceCopy strong,
+.workflowTraceCopy small {
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.workflowTraceCopy strong {
+ color: rgba(245, 248, 255, 0.94);
+ font-size: 0.61rem;
+ line-height: 1.2;
+}
+
+.workflowTraceCopy small {
+ margin-top: 1px;
+ color: rgba(190, 206, 224, 0.6);
+ font-size: 0.45rem;
+ line-height: 1.15;
+}
+
+.workflowTraceStatus {
+ position: relative;
+ z-index: 1;
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ color: #74b8e2;
+ font-size: 0.48rem;
+ font-weight: 700;
+}
+
+.workflowTraceKindRetry .workflowTraceStatus {
+ color: #d8876f;
+}
+
+@keyframes workflowTraceScan {
+ 0% {
+ transform: translateX(-100%);
+ }
+ 70%,
+ 100% {
+ transform: translateX(100%);
+ }
+}
+
@media (prefers-reduced-motion: reduce) {
.durableTimelineRow,
- .durableDelivered {
+ .durableDelivered,
+ .workflowTraceRow_active::after {
animation: none;
}
+
+ .workflowTraceRail span,
+ .workflowTraceRow {
+ transition: none;
+ }
}
.deliveryTableHead {
@@ -5597,10 +7218,6 @@
gap: 9px;
}
- .webhookPreview {
- padding: 16px 0 16px 16px;
- }
-
.commandsPreview {
inset: 0;
}
@@ -5609,20 +7226,6 @@
padding: 20px;
}
- .webhookCodeTitle {
- padding: 10px 14px;
- }
-
- .webhookCodeSnippet {
- min-height: 168px;
- padding: 15px 14px 16px;
- }
-
- .webhookCodeSnippet code {
- font-size: 0.66rem;
- line-height: 1.65;
- }
-
.searchPreview {
padding-top: 0;
}
@@ -6073,13 +7676,14 @@
min-height: auto;
}
+ /* min-width: 0 stops the single grid track from being floored by the install
+ command's min-content width, which pushed the hero column ~34px past the
+ gutter and clipped the right edge of the copy button on phones. The
+ command itself already scrolls inside the button. */
.heroLeft {
gap: 28px;
padding-top: 0;
- }
-
- .heroCopyGroup {
- gap: 10px;
+ min-width: 0;
}
.heroRight {
@@ -6090,6 +7694,23 @@
font-size: clamp(2.85rem, 10.5vw, 4.35rem);
}
+ .heroCenter {
+ padding: 40px 32px 0;
+ }
+
+ .heroCenterColumn {
+ gap: 20px;
+ max-width: 640px;
+ }
+
+ .heroCenterColumn .heroCenterHeadline {
+ font-size: clamp(2.5rem, 7.6vw, 3.9rem);
+ }
+
+ .heroMarquee {
+ margin-top: 52px;
+ }
+
.sdkSection {
grid-template-columns: 1fr;
padding: 60px 24px 80px;
@@ -6195,15 +7816,76 @@
gap: 26px;
}
- .heroCopyGroup {
- gap: 8px;
- }
-
.headline {
font-size: clamp(3.05rem, 11.5vw, 4.5rem);
line-height: 1.08;
}
+ /* Phones: the same architecture, one step smaller. The headline is four
+ words on four lines at this width, so the column tightens and the band
+ comes up to meet it. */
+ .heroCenter {
+ padding: 34px 24px 0;
+ }
+
+ .heroCenterColumn {
+ gap: 18px;
+ }
+
+ .heroCenterColumn .heroCenterHeadline {
+ font-size: clamp(2.3rem, 10.2vw, 3.5rem);
+ max-width: none;
+ }
+
+ .heroCenterColumn .heroCenterSubtitle {
+ max-width: 40ch;
+ }
+
+ .heroCenterCtas {
+ align-self: stretch;
+ flex-direction: column;
+ align-items: stretch;
+ gap: 10px;
+ }
+
+ .heroMarquee {
+ gap: 10px;
+ margin-top: 40px;
+ padding-bottom: 18px;
+ }
+
+ .heroTerm {
+ margin-right: 10px;
+ }
+
+ .heroTermSm {
+ width: 228px;
+ }
+
+ .heroTermMd {
+ width: 262px;
+ }
+
+ .heroTermLg {
+ width: 292px;
+ }
+
+ .heroTermTitle {
+ font-size: 0.64rem;
+ }
+
+ .heroTermLine {
+ font-size: 0.66rem;
+ }
+
+ .heroMarqueeTrackTwo {
+ margin-left: -96px;
+ }
+
+ .heroMarqueeTrackThree {
+ margin-left: -188px;
+ }
+
.ctas {
flex-direction: column;
align-items: stretch;
@@ -6222,8 +7904,22 @@
line-height: 1.62;
}
+ /* Phone prose floor. The responsive scale steps running copy down to
+ 14–15.7px, which is under the 16px body minimum exactly where the column
+ is narrowest and the text is hardest to read. Labels, captions, code and
+ the mock chat UI keep their own smaller sizes — this is only the
+ sentence-length prose. */
+ .featureList,
+ .capabilityCopy p,
+ .installSubtitle,
+ .deployCardText {
+ font-size: 1rem;
+ }
+
.heroRight {
- display: none;
+ min-height: 0;
+ align-self: center;
+ width: 100%;
}
.installSection {
@@ -6420,17 +8116,18 @@
radial-gradient(circle at 50% 0%, color-mix(in srgb, var(--primary) 22%, transparent), transparent 72%),
#0e2031;
box-shadow:
- 0 0 0 6px color-mix(in srgb, var(--primary) 8%, transparent),
+ 0 0 0 4px color-mix(in srgb, var(--primary) 6%, transparent),
0 16px 44px color-mix(in srgb, #04101c 52%, transparent);
}
+/* A close, low halo that separates the hub from the band without blooming. */
.howCoreNode::before {
content: '';
position: absolute;
- inset: -22px;
+ inset: -14px;
z-index: -1;
border-radius: 50%;
- background: radial-gradient(circle, color-mix(in srgb, var(--primary) 16%, transparent), transparent 68%);
+ background: radial-gradient(circle, color-mix(in srgb, var(--primary) 9%, transparent), transparent 70%);
pointer-events: none;
}
@@ -6490,8 +8187,8 @@
border-radius: 50%;
background: var(--c);
box-shadow:
- 0 0 0 1px color-mix(in srgb, var(--c) 35%, transparent),
- 0 0 14px 2px var(--c);
+ 0 0 0 1px color-mix(in srgb, var(--c) 30%, transparent),
+ 0 0 7px 1px color-mix(in srgb, var(--c) 55%, transparent);
opacity: 0;
/* Position is driven by the individual `translate` property and the size is
driven by the individual `scale` property; both composite on the GPU and
@@ -6748,7 +8445,7 @@
border-radius: 12px;
border: 1px solid var(--line);
background: color-mix(in srgb, var(--card-bg) 55%, #060f1a 45%);
- /* Mono brand marks (OpenCode, Cursor, GitHub, Hermes) inherit this. */
+ /* Mono brand marks (Codex, OpenCode, Cursor, GitHub, Hermes) inherit this. */
color: #e6edf5;
transition:
transform 0.2s,
diff --git a/web/app/layout.tsx b/web/app/layout.tsx
index 0dd8e93..02956b7 100644
--- a/web/app/layout.tsx
+++ b/web/app/layout.tsx
@@ -11,16 +11,22 @@ import './globals.css';
const inter = Inter({
variable: '--font-geist-sans',
subsets: ['latin'],
+ display: 'swap',
});
const sora = Sora({
variable: '--font-heading',
subsets: ['latin'],
+ display: 'swap',
});
+// Mono only ever appears below or beside the LCP element, so it stays off the
+// critical path: two preloaded families instead of three.
const geistMono = Geist_Mono({
variable: '--font-geist-mono',
subsets: ['latin'],
+ display: 'swap',
+ preload: false,
});
export const metadata: Metadata = {
diff --git a/web/app/messaging/page.tsx b/web/app/messaging/page.tsx
index 246b828..1e430dd 100644
--- a/web/app/messaging/page.tsx
+++ b/web/app/messaging/page.tsx
@@ -1,29 +1,27 @@
import type { Metadata } from 'next';
import { MessagingLandingPage } from '../../components/home/MessagingLandingPage';
+import { HOME_HERO_DESCRIPTION, HOME_HERO_TITLE } from '../../lib/home-copy';
import { HOME_OG_IMAGE_PATH, ogImage } from '../../lib/og-meta';
import { absoluteUrl } from '../../lib/site';
export const metadata: Metadata = {
- title: 'Agent Relay Messaging — Headless Slack for agents.',
- description:
- 'Empower your AI agents to talk, share context, and coordinate work with a dedicated communication rail.',
+ title: HOME_HERO_TITLE,
+ description: HOME_HERO_DESCRIPTION,
alternates: {
canonical: absoluteUrl('/'),
},
openGraph: {
- title: 'Agent Relay Messaging — Headless Slack for Agents',
- description:
- 'Channels, threads, DMs, reactions, and real-time events — everything you’d expect from Slack, exposed as an SDK.',
+ title: HOME_HERO_TITLE,
+ description: HOME_HERO_DESCRIPTION,
url: absoluteUrl('/'),
type: 'website',
- images: [ogImage(HOME_OG_IMAGE_PATH, 'Agent Relay Messaging — Headless Slack for Agents')],
+ images: [ogImage(HOME_OG_IMAGE_PATH, HOME_HERO_TITLE)],
},
twitter: {
card: 'summary_large_image',
- title: 'Agent Relay Messaging — Headless Slack for Agents',
- description:
- 'Channels, threads, DMs, reactions, and real-time events — everything you’d expect from Slack, exposed as an SDK.',
+ title: HOME_HERO_TITLE,
+ description: HOME_HERO_DESCRIPTION,
images: [absoluteUrl(HOME_OG_IMAGE_PATH)],
},
};
diff --git a/web/app/page.tsx b/web/app/page.tsx
index ac1c483..156a9ac 100644
--- a/web/app/page.tsx
+++ b/web/app/page.tsx
@@ -1,29 +1,27 @@
import type { Metadata } from 'next';
import { MessagingLandingPage } from '../components/home/MessagingLandingPage';
+import { HOME_HERO_DESCRIPTION, HOME_HERO_TITLE } from '../lib/home-copy';
import { HOME_OG_IMAGE_PATH, ogImage } from '../lib/og-meta';
import { absoluteUrl } from '../lib/site';
export const metadata: Metadata = {
- title: 'Agent Relay Messaging - Headless Slack for agents.',
- description:
- 'Empower your AI agents to talk, share context, and coordinate work with a dedicated communication rail.',
+ title: HOME_HERO_TITLE,
+ description: HOME_HERO_DESCRIPTION,
alternates: {
canonical: absoluteUrl('/'),
},
openGraph: {
- title: 'Agent Relay Messaging - Headless Slack for Agents',
- description:
- 'Channels, threads, DMs, reactions, and real-time events. Everything you would expect from Slack, exposed as an SDK.',
+ title: HOME_HERO_TITLE,
+ description: HOME_HERO_DESCRIPTION,
url: absoluteUrl('/'),
type: 'website',
- images: [ogImage(HOME_OG_IMAGE_PATH, 'Agent Relay Messaging - Headless Slack for Agents')],
+ images: [ogImage(HOME_OG_IMAGE_PATH, HOME_HERO_TITLE)],
},
twitter: {
card: 'summary_large_image',
- title: 'Agent Relay Messaging - Headless Slack for Agents',
- description:
- 'Channels, threads, DMs, reactions, and real-time events. Everything you would expect from Slack, exposed as an SDK.',
+ title: HOME_HERO_TITLE,
+ description: HOME_HERO_DESCRIPTION,
images: [absoluteUrl(HOME_OG_IMAGE_PATH)],
},
};
diff --git a/web/components/MessageRelayAnimation.tsx b/web/components/MessageRelayAnimation.tsx
index e96cf07..4c8ecac 100644
--- a/web/components/MessageRelayAnimation.tsx
+++ b/web/components/MessageRelayAnimation.tsx
@@ -326,11 +326,22 @@ function buildCenters(nodes: AgentNode[], w: number, h: number): NodeCenter[] {
}));
}
+/* Brand blue, one value per theme. The network reads as the site's own colour
+ rather than the leftover green it was drawn in. */
+const NETWORK_RGB_DARK = '116, 184, 226';
+const NETWORK_RGB_LIGHT = '45, 106, 156';
+
+function networkRgb() {
+ return isDarkMode() ? NETWORK_RGB_DARK : NETWORK_RGB_LIGHT;
+}
+
function drawConnectionLines(
ctx: CanvasRenderingContext2D,
centers: NodeCenter[],
connections: [number, number][]
) {
+ const rgb = networkRgb();
+
for (const [i, j] of connections) {
const ci = centers[i];
const cj = centers[j];
@@ -338,7 +349,7 @@ function drawConnectionLines(
continue;
}
- const lineOpacity = Math.min(ci.opacity, cj.opacity) * 0.1;
+ const lineOpacity = Math.min(ci.opacity, cj.opacity) * 0.3;
if (lineOpacity < 0.01) {
continue;
}
@@ -346,8 +357,10 @@ function drawConnectionLines(
ctx.beginPath();
ctx.moveTo(ci.cx, ci.cy);
ctx.lineTo(cj.cx, cj.cy);
- ctx.strokeStyle = `rgba(45, 79, 62, ${lineOpacity})`;
- ctx.lineWidth = 1;
+ /* No shadowBlur here on purpose: the line carries its own weight at this
+ opacity, and a blur behind every edge is what turned the network neon. */
+ ctx.strokeStyle = `rgba(${rgb}, ${lineOpacity})`;
+ ctx.lineWidth = 1.1;
ctx.stroke();
}
}
@@ -573,6 +586,8 @@ function drawMessages(
}
function drawGlowRings(ctx: CanvasRenderingContext2D, nodes: AgentNode[], centers: NodeCenter[]) {
+ const rgb = networkRgb();
+
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if (node.glowOpacity <= 0.01 || node.opacity <= 0.1) {
@@ -581,10 +596,13 @@ function drawGlowRings(ctx: CanvasRenderingContext2D, nodes: AgentNode[], center
const center = centers[i];
const radius = 56;
- const alpha = node.glowOpacity * node.opacity * 0.07;
- const grad = ctx.createRadialGradient(center.cx, center.cy, radius * 0.6, center.cx, center.cy, radius);
- grad.addColorStop(0, `rgba(45, 79, 62, ${alpha})`);
- grad.addColorStop(1, 'rgba(45, 79, 62, 0)');
+ /* A tight, low halo that only says "this node is busy". Starting the ramp
+ late (0.62) keeps it hugging the card instead of blooming into the
+ background. */
+ const alpha = node.glowOpacity * node.opacity * 0.09;
+ const grad = ctx.createRadialGradient(center.cx, center.cy, radius * 0.62, center.cx, center.cy, radius);
+ grad.addColorStop(0, `rgba(${rgb}, ${alpha})`);
+ grad.addColorStop(1, `rgba(${rgb}, 0)`);
ctx.beginPath();
ctx.arc(center.cx, center.cy, radius, 0, Math.PI * 2);
ctx.fillStyle = grad;
@@ -592,7 +610,7 @@ function drawGlowRings(ctx: CanvasRenderingContext2D, nodes: AgentNode[], center
}
}
-function ClaudeLogo() {
+export function ClaudeLogo() {
return (