Rebuild landing design system on the adaline pebble/meadow palette
Foundation for the adaline-based landing rebuild: - globals.css: warm-cream light theme + Material-3 dark theme mapped onto the existing CSS-var names; CSS-keyframe entrance + IntersectionObserver reveal motion (to replace framer-motion incrementally) - layout.tsx: self-host Instrument Sans/Serif, Newsreader and JetBrains Mono via next/font/google; drop the external Google Fonts <link> - _headers: tighten CSP style/font-src to 'self' now that fonts are local - components/ui: Container, Reveal, Eyebrow, Badge, Button, SectionHeading - lib/landing-content.ts: feature-section copy for the six product screens - public/images: six product screenshots optimized to WebP - add reicon-react/reicon-brands (bundled, CSP-safe SVG icons) Business logic (D1 download counter, platform metadata, theme, SEO) unchanged.
This commit is contained in:
1 parent
8265612206
commit
b1e2374c7b
20 files changed
+433
-67
No files matched your search
+2
-1
@@ -7,4 +7,5 @@ coverage/
|
||||
*.tsbuildinfo
|
||||
design-source/
|
||||
.DS_Store
|
||||
cred.txt
|
||||
cred.txt
|
||||
ailine
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://static.cloudflareinsights.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data:; connect-src 'self' https://cloudflareinsights.com; base-uri 'self'; form-action 'self'; frame-ancestors 'none'
|
||||
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://static.cloudflareinsights.com; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' data:; connect-src 'self' https://cloudflareinsights.com; base-uri 'self'; form-action 'self'; frame-ancestors 'none'
|
||||
Permissions-Policy: camera=(), microphone=(), geolocation=()
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
X-Content-Type-Options: nosniff
|
||||
|
||||
+142
-55
@@ -1,63 +1,86 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
/*
|
||||
* AgentCompany landing — design system.
|
||||
* Light theme is a faithful rendering of the adaline pebble/meadow palette
|
||||
* (warm cream + dark green). Dark theme uses the matching Material-3 dark
|
||||
* surfaces + mint primary. Components consume the CSS variables below, so the
|
||||
* whole palette is defined once here.
|
||||
*/
|
||||
|
||||
@theme {
|
||||
--font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
--font-serif: "Space Grotesk", "Inter", ui-sans-serif, system-ui, sans-serif;
|
||||
--font-mono: "Space Mono", ui-monospace, SFMono-Regular, monospace;
|
||||
--font-sans: var(--font-instrument-sans), ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
|
||||
--font-serif: var(--font-newsreader), "Source Serif Pro", Georgia, "Times New Roman", serif;
|
||||
--font-mono: var(--font-jetbrains-mono), ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
|
||||
--font-display: var(--font-instrument-serif), "Cormorant Garamond", Georgia, serif;
|
||||
}
|
||||
|
||||
/* ── Light Theme (Cohere) ── */
|
||||
/* ── Light theme (pebble / meadow) ── */
|
||||
:root {
|
||||
--bg: #ffffff;
|
||||
--bg-subtle: #fafafa;
|
||||
--panel: #ffffff;
|
||||
--panel-soft: #fafafa;
|
||||
--text: #000000;
|
||||
--text-secondary: #212121;
|
||||
--muted: #93939f;
|
||||
--muted-strong: #565650;
|
||||
--accent: #1863dc;
|
||||
--accent-hover: #1352b8;
|
||||
--accent-soft: rgba(24, 99, 220, 0.06);
|
||||
--text-on-accent: #ffffff;
|
||||
--cta: #000000;
|
||||
--cta-hover: #212121;
|
||||
--cta-soft: rgba(0, 0, 0, 0.04);
|
||||
--text-on-cta: #ffffff;
|
||||
--text-on-cta-muted: rgba(255, 255, 255, 0.75);
|
||||
--text-on-cta-faint: rgba(255, 255, 255, 0.60);
|
||||
--border: rgba(0, 0, 0, 0.06);
|
||||
--border-cool: #d9d9dd;
|
||||
--glow-warm: rgba(24, 99, 220, 0.04);
|
||||
--glow-accent: rgba(24, 99, 220, 0.03);
|
||||
--section-alt: rgba(0, 0, 0, 0.015);
|
||||
--bg: #fbfdf6;
|
||||
--bg-subtle: #f8f9f5;
|
||||
--panel: #fdfefb;
|
||||
--panel-soft: #f1f3ef;
|
||||
--panel-illustration: #eff2e8;
|
||||
--text: #0a1d08;
|
||||
--text-secondary: #2e3b28;
|
||||
--muted: #6b7860;
|
||||
--muted-strong: #505c47;
|
||||
--accent: #203b14;
|
||||
--accent-hover: #13290e;
|
||||
--accent-soft: #ecf2df;
|
||||
--text-on-accent: #fbfdf6;
|
||||
--cta: #203b14;
|
||||
--cta-hover: #13290e;
|
||||
--cta-soft: rgba(32, 59, 20, 0.06);
|
||||
--text-on-cta: #fbfdf6;
|
||||
--text-on-cta-muted: rgba(251, 253, 246, 0.75);
|
||||
--text-on-cta-faint: rgba(251, 253, 246, 0.6);
|
||||
--border: #e1e6df;
|
||||
--border-strong: #c4cbc2;
|
||||
--border-cool: #c4cbc2;
|
||||
--band: #2a332a;
|
||||
--band-text: #fbfdf6;
|
||||
--band-border: rgba(253, 254, 251, 0.24);
|
||||
--footer-bg: #050e11;
|
||||
--footer-text: #fbfdf6;
|
||||
--glow-warm: rgba(32, 59, 20, 0.05);
|
||||
--glow-accent: rgba(99, 143, 61, 0.06);
|
||||
--section-alt: rgba(32, 59, 20, 0.02);
|
||||
}
|
||||
|
||||
/* ── Dark Theme (Cohere) ── */
|
||||
/* ── Dark theme (Material-3 dark surfaces + mint primary) ── */
|
||||
.dark {
|
||||
--bg: #17171c;
|
||||
--bg-subtle: #1e1e24;
|
||||
--panel: #212126;
|
||||
--panel-soft: #2a2a30;
|
||||
--text: #fafafa;
|
||||
--text-secondary: #d9d9dd;
|
||||
--muted: #93939f;
|
||||
--muted-strong: #b8b8b2;
|
||||
--accent: #1863dc;
|
||||
--accent-hover: #2070e8;
|
||||
--accent-soft: rgba(24, 99, 220, 0.12);
|
||||
--text-on-accent: #ffffff;
|
||||
--cta: #fafafa;
|
||||
--cta-hover: #e5e5e5;
|
||||
--cta-soft: rgba(250, 250, 250, 0.06);
|
||||
--text-on-cta: #17171c;
|
||||
--text-on-cta-muted: rgba(23, 23, 28, 0.75);
|
||||
--text-on-cta-faint: rgba(23, 23, 28, 0.60);
|
||||
--border: rgba(250, 250, 250, 0.08);
|
||||
--border-cool: #333338;
|
||||
--glow-warm: rgba(24, 99, 220, 0.06);
|
||||
--glow-accent: rgba(24, 99, 220, 0.04);
|
||||
--section-alt: rgba(24, 99, 220, 0.025);
|
||||
--bg: #131515;
|
||||
--bg-subtle: #171b1c;
|
||||
--panel: #1d2226;
|
||||
--panel-soft: #20262a;
|
||||
--panel-illustration: #1d2226;
|
||||
--text: #d8e3dd;
|
||||
--text-secondary: #b2c3bf;
|
||||
--muted: #93a49e;
|
||||
--muted-strong: #b2c3bf;
|
||||
--accent: #5eec97;
|
||||
--accent-hover: #4af58f;
|
||||
--accent-soft: #1c4534;
|
||||
--text-on-accent: #124627;
|
||||
--cta: #5eec97;
|
||||
--cta-hover: #4af58f;
|
||||
--cta-soft: rgba(94, 236, 151, 0.1);
|
||||
--text-on-cta: #124627;
|
||||
--text-on-cta-muted: rgba(18, 70, 39, 0.75);
|
||||
--text-on-cta-faint: rgba(18, 70, 39, 0.55);
|
||||
--border: #2c343b;
|
||||
--border-strong: #3b454f;
|
||||
--border-cool: #3b454f;
|
||||
--band: #0b1510;
|
||||
--band-text: #d8e3dd;
|
||||
--band-border: rgba(216, 227, 221, 0.2);
|
||||
--footer-bg: #05090b;
|
||||
--footer-text: #d8e3dd;
|
||||
--glow-warm: rgba(94, 236, 151, 0.05);
|
||||
--glow-accent: rgba(94, 236, 151, 0.04);
|
||||
--section-alt: rgba(94, 236, 151, 0.03);
|
||||
}
|
||||
|
||||
/* ── Base ── */
|
||||
@@ -68,10 +91,16 @@ html {
|
||||
body {
|
||||
background-color: var(--bg);
|
||||
color: var(--text);
|
||||
font-family: var(--font-sans);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-rendering: optimizeLegibility;
|
||||
line-height: 1.65;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.font-display {
|
||||
font-family: var(--font-display);
|
||||
font-variant-ligatures: common-ligatures discretionary-ligatures;
|
||||
}
|
||||
|
||||
::selection {
|
||||
@@ -88,6 +117,13 @@ body {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* ── Eyebrow / small-caps mono label ── */
|
||||
.eyebrow {
|
||||
font-family: var(--font-mono);
|
||||
font-variant-caps: all-small-caps;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
/* ── Scrollbar ── */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
@@ -99,7 +135,7 @@ body {
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--border);
|
||||
background: var(--border-strong);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
@@ -109,10 +145,56 @@ body {
|
||||
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--border) transparent;
|
||||
scrollbar-color: var(--border-strong) transparent;
|
||||
}
|
||||
|
||||
/* ── Reduced Motion ── */
|
||||
/* ── Entrance + reveal motion (faithful to adaline: ease-out-quint) ── */
|
||||
@keyframes nav-enter {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rise-enter {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(14px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.enter-nav {
|
||||
animation: nav-enter 0.52s cubic-bezier(0.22, 1, 0.36, 1) 0.1s both;
|
||||
}
|
||||
|
||||
.enter-rise {
|
||||
animation: rise-enter 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
|
||||
}
|
||||
|
||||
/* Scroll-reveal primitive: hidden until IntersectionObserver marks it in view. */
|
||||
.reveal {
|
||||
opacity: 0;
|
||||
transform: translateY(16px);
|
||||
transition:
|
||||
opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
transition-delay: var(--reveal-delay, 0ms);
|
||||
}
|
||||
|
||||
.reveal[data-in-view="true"] {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* ── Reduced motion ── */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
html {
|
||||
scroll-behavior: auto;
|
||||
@@ -125,4 +207,9 @@ body {
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
|
||||
.reveal {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
+32
-7
@@ -1,6 +1,37 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Instrument_Sans, Instrument_Serif, Newsreader, JetBrains_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import { ThemeProvider } from "../components/theme-provider";
|
||||
|
||||
const instrumentSans = Instrument_Sans({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-instrument-sans",
|
||||
display: "swap",
|
||||
weight: ["400", "500", "600", "700"],
|
||||
});
|
||||
|
||||
const instrumentSerif = Instrument_Serif({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-instrument-serif",
|
||||
display: "swap",
|
||||
weight: "400",
|
||||
});
|
||||
|
||||
const newsreader = Newsreader({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-newsreader",
|
||||
display: "swap",
|
||||
weight: ["300", "400", "500"],
|
||||
});
|
||||
|
||||
const jetbrainsMono = JetBrains_Mono({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-jetbrains-mono",
|
||||
display: "swap",
|
||||
weight: ["400", "500"],
|
||||
});
|
||||
|
||||
const fontVariables = `${instrumentSans.variable} ${instrumentSerif.variable} ${newsreader.variable} ${jetbrainsMono.variable}`;
|
||||
import {
|
||||
landingHowItWorksNarrative,
|
||||
landingStructuredDataNarrative,
|
||||
@@ -180,15 +211,9 @@ const faqJsonLd = {
|
||||
|
||||
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<html lang="en" className={fontVariables} suppressHydrationWarning>
|
||||
<head>
|
||||
<meta name="googlebot" content="index, follow, max-video-preview:-1, max-image-preview:large, max-snippet:-1" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500;600;700&family=Space+Mono:wght@400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<script dangerouslySetInnerHTML={{ __html: themeScript }} />
|
||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(softwareJsonLd) }} />
|
||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationJsonLd) }} />
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
/** Rounded meadow pill, optionally a link. */
|
||||
export function Badge({
|
||||
children,
|
||||
href,
|
||||
className = "",
|
||||
}: {
|
||||
children: ReactNode;
|
||||
href?: string;
|
||||
className?: string;
|
||||
}) {
|
||||
const classes = `eyebrow inline-flex items-center gap-1.5 self-start rounded-full px-3 py-1.5 text-sm bg-[var(--accent-soft)] text-[var(--accent)] transition-colors ${className}`;
|
||||
|
||||
if (href) {
|
||||
return (
|
||||
<a href={href} className={classes}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
return <span className={classes}>{children}</span>;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
type ButtonVariant = "primary" | "ghost";
|
||||
type ButtonSize = "md" | "sm";
|
||||
|
||||
const base =
|
||||
"eyebrow inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[20px] text-sm transition-colors";
|
||||
|
||||
const sizeClasses: Record<ButtonSize, string> = {
|
||||
md: "h-11 px-6",
|
||||
sm: "h-9 px-4",
|
||||
};
|
||||
|
||||
const variantClasses: Record<ButtonVariant, string> = {
|
||||
primary: "bg-[var(--cta)] text-[var(--text-on-cta)] hover:bg-[var(--cta-hover)]",
|
||||
ghost: "border border-[var(--border-strong)] text-[var(--text-secondary)] hover:border-[var(--muted)]",
|
||||
};
|
||||
|
||||
/** Link-styled call to action. Every landing CTA is an anchor. */
|
||||
export function Button({
|
||||
children,
|
||||
href,
|
||||
variant = "primary",
|
||||
size = "md",
|
||||
external = false,
|
||||
className = "",
|
||||
"aria-label": ariaLabel,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
href: string;
|
||||
variant?: ButtonVariant;
|
||||
size?: ButtonSize;
|
||||
external?: boolean;
|
||||
className?: string;
|
||||
"aria-label"?: string;
|
||||
}) {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
aria-label={ariaLabel}
|
||||
{...(external ? { target: "_blank", rel: "noopener noreferrer" } : {})}
|
||||
className={`${base} ${sizeClasses[size]} ${variantClasses[variant]} ${className}`}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
/** Page-width wrapper: 1280px max, adaline grid margins (16px → 48px). */
|
||||
export function Container({ children, className = "" }: { children: ReactNode; className?: string }) {
|
||||
return <div className={`mx-auto w-full max-w-[1280px] px-4 md:px-12 ${className}`}>{children}</div>;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
/** Small-caps mono label used above section headings. */
|
||||
export function Eyebrow({ children, className = "" }: { children: ReactNode; className?: string }) {
|
||||
return (
|
||||
<span className={`eyebrow inline-flex items-center gap-1.5 text-sm text-[var(--muted)] ${className}`}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useState, type CSSProperties, type ReactNode } from "react";
|
||||
|
||||
/**
|
||||
* Scroll-reveal wrapper. Starts hidden (via the `.reveal` class) and marks
|
||||
* itself in view the first time it intersects the viewport, letting CSS handle
|
||||
* the rise-and-fade. Honours reduced-motion through the stylesheet.
|
||||
*/
|
||||
export function Reveal({
|
||||
children,
|
||||
delay = 0,
|
||||
className = "",
|
||||
}: {
|
||||
children: ReactNode;
|
||||
delay?: number;
|
||||
className?: string;
|
||||
}) {
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
const [inView, setInView] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const node = ref.current;
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
if (typeof IntersectionObserver === "undefined") {
|
||||
setInView(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting) {
|
||||
setInView(true);
|
||||
observer.disconnect();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
{ threshold: 0.2, rootMargin: "0px 0px -10% 0px" },
|
||||
);
|
||||
|
||||
observer.observe(node);
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={`reveal ${className}`}
|
||||
data-in-view={inView}
|
||||
style={delay ? ({ "--reveal-delay": `${delay}ms` } as CSSProperties) : undefined}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { Eyebrow } from "./eyebrow";
|
||||
|
||||
/** Eyebrow + heading + subhead block shared by every section. */
|
||||
export function SectionHeading({
|
||||
eyebrow,
|
||||
title,
|
||||
description,
|
||||
align = "left",
|
||||
className = "",
|
||||
}: {
|
||||
eyebrow?: string;
|
||||
title: ReactNode;
|
||||
description?: ReactNode;
|
||||
align?: "left" | "center";
|
||||
className?: string;
|
||||
}) {
|
||||
const alignment =
|
||||
align === "center" ? "items-center text-center mx-auto" : "items-start text-left";
|
||||
|
||||
return (
|
||||
<div className={`flex max-w-[68ch] flex-col gap-3 md:gap-4 ${alignment} ${className}`}>
|
||||
{eyebrow ? <Eyebrow>{eyebrow}</Eyebrow> : null}
|
||||
<h2 className="text-balance text-[30px] font-medium leading-[1.12] tracking-[-0.02em] text-[var(--text)] md:text-[34px]">
|
||||
{title}
|
||||
</h2>
|
||||
{description ? (
|
||||
<p className="max-w-[62ch] text-pretty text-lg leading-relaxed text-[var(--muted)]">{description}</p>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
export type FeatureSection = {
|
||||
id: string;
|
||||
eyebrow: string;
|
||||
title: string;
|
||||
description: string;
|
||||
image: string;
|
||||
imageAlt: string;
|
||||
};
|
||||
|
||||
export const featureSections: FeatureSection[] = [
|
||||
{
|
||||
id: "org-chart",
|
||||
eyebrow: "Self-organizing",
|
||||
title: "Your org chart builds itself",
|
||||
description:
|
||||
"Set one goal. The AI CEO decides which roles the mission needs, hires specialist agents, and draws the reporting lines — from your board seat down to every department.",
|
||||
image: "/images/org-chart.webp",
|
||||
imageAlt: "AgentCompany org chart with a board chair, an AI CEO, and specialist agents reporting into departments",
|
||||
},
|
||||
{
|
||||
id: "office",
|
||||
eyebrow: "Presence",
|
||||
title: "A workplace you can watch",
|
||||
description:
|
||||
"Every agent has a desk. See who is heads-down at work, who is in the meeting room, and what the whole company is doing — at a single glance across the floor.",
|
||||
image: "/images/office.webp",
|
||||
imageAlt: "Top-down view of the AgentCompany virtual office with named agents at their desks",
|
||||
},
|
||||
{
|
||||
id: "messages",
|
||||
eyebrow: "Coordination",
|
||||
title: "Agents that talk to each other",
|
||||
description:
|
||||
"Direct messages and department channels keep the team aligned. Read the reasoning behind every hand-off and decision, written out in plain language.",
|
||||
image: "/images/messages.webp",
|
||||
imageAlt: "AgentCompany messaging view with direct conversations between the CEO and specialist agents",
|
||||
},
|
||||
{
|
||||
id: "connectors",
|
||||
eyebrow: "Integrations",
|
||||
title: "Plugged into your stack",
|
||||
description:
|
||||
"Connect GitHub, Slack, Notion, Google Workspace, Stripe, and dozens more. Your agents do the work inside the tools your company already runs on.",
|
||||
image: "/images/connectors.webp",
|
||||
imageAlt: "AgentCompany connector catalog with dozens of integrations ready to connect",
|
||||
},
|
||||
{
|
||||
id: "cost-controls",
|
||||
eyebrow: "Control",
|
||||
title: "Spend stays under your cap",
|
||||
description:
|
||||
"Set a monthly budget and per-agent allocations. Track requests, tokens, and cost by agent — and hold the whole company inside the limit you set.",
|
||||
image: "/images/cost-controls.webp",
|
||||
imageAlt: "AgentCompany advanced settings showing budget caps and cost broken down by agent",
|
||||
},
|
||||
];
|
||||
Generated
+18
-1
@@ -11,7 +11,9 @@
|
||||
"framer-motion": "12.38.0",
|
||||
"next": "16.2.6",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4"
|
||||
"react-dom": "19.2.4",
|
||||
"reicon-brands": "^1.0.2",
|
||||
"reicon-react": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.2.2",
|
||||
@@ -1614,6 +1616,21 @@
|
||||
"react": "^19.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/reicon-brands": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/reicon-brands/-/reicon-brands-1.0.2.tgz",
|
||||
"integrity": "sha512-m+J4Ooa9vU1+Kg73GKni3eJgrFsoRmesLEgjkzHq4b3hkoJZj7so5kk8rYnkS8WZGfgH+ACb1u5wcjBRFUX4tw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/reicon-react": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/reicon-react/-/reicon-react-1.1.2.tgz",
|
||||
"integrity": "sha512-dbp1CPEPKFjWfG41lGRMWi74YKfKJlb2JcB/TRBAUQF6jalZYW1dRZisRPCpze5TfQwRBD30p40qnoY+oYi7MQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
"framer-motion": "12.38.0",
|
||||
"next": "16.2.6",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4"
|
||||
"react-dom": "19.2.4",
|
||||
"reicon-brands": "^1.0.2",
|
||||
"reicon-react": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.2.2",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://static.cloudflareinsights.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data:; connect-src 'self' https://cloudflareinsights.com; base-uri 'self'; form-action 'self'; frame-ancestors 'none'
|
||||
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://static.cloudflareinsights.com; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' data:; connect-src 'self' https://cloudflareinsights.com; base-uri 'self'; form-action 'self'; frame-ancestors 'none'
|
||||
Permissions-Policy: camera=(), microphone=(), geolocation=()
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
X-Content-Type-Options: nosniff
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 123 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 205 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
Reference in new issue
Block a user