Polish Foundry desktop UI: billing redesign, sidebar hover menu, org switching fix

- Redesign billing page with task-hours pricing model (Free: 8h, Pro: 200h/seat)
- Add bulk hour purchase packages and Stripe payment management
- Remove Usage nav section, add upgrade CTA in Members for free plan
- Fix gear icon to open menu on hover with debounced timers
- Fix org switching in workspace flyout (portal outside-click detection)
- Fix tab strip padding when sidebar is collapsed
- Update website components and Tauri config

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nicholas Kissel 2026-03-11 19:34:25 -07:00
parent f6656a90af
commit ed6e6f6fa5
24 changed files with 1746 additions and 1028 deletions

View file

@ -105,7 +105,7 @@ export function DownloadFoundry() {
</button>
{showDropdown && (
<div className="absolute left-1/2 top-full mt-2 -translate-x-1/2 rounded-lg border border-white/10 bg-zinc-900 p-2 shadow-xl">
<div className="absolute left-1/2 top-full mt-2 -translate-x-1/2 rounded-lg border border-white/10 bg-[#0f0f11] p-2 shadow-xl">
{secondary.map((p) => (
<a
key={p.arch}

View file

@ -36,7 +36,7 @@ export function FeatureGrid() {
className="grid gap-4 md:grid-cols-2 lg:grid-cols-4"
>
{/* Universal Agent API - Span full width */}
<div className="group col-span-full flex flex-col gap-4 rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="group col-span-full flex flex-col gap-4 rounded-xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="flex items-center gap-3">
<div className="text-zinc-500 transition-colors group-hover:text-orange-400">
<Workflow className="h-4 w-4" />
@ -49,7 +49,7 @@ export function FeatureGrid() {
</div>
{/* Streaming Events */}
<div className="group flex flex-col gap-4 rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="group flex flex-col gap-4 rounded-xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="flex items-center gap-3">
<div className="text-zinc-500 transition-colors group-hover:text-green-400">
<Server className="h-4 w-4" />
@ -62,7 +62,7 @@ export function FeatureGrid() {
</div>
{/* Universal Schema */}
<div className="group flex flex-col gap-4 rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="group flex flex-col gap-4 rounded-xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="flex items-center gap-3">
<div className="text-zinc-500 transition-colors group-hover:text-purple-400">
<Database className="h-4 w-4" />
@ -75,7 +75,7 @@ export function FeatureGrid() {
</div>
{/* Runs Inside Any Sandbox */}
<div className="group lg:col-span-2 flex flex-col gap-4 rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="group lg:col-span-2 flex flex-col gap-4 rounded-xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="flex items-center gap-3">
<div className="text-zinc-500 transition-colors group-hover:text-blue-400">
<Globe className="h-4 w-4" />
@ -88,7 +88,7 @@ export function FeatureGrid() {
</div>
{/* Session Management */}
<div className="group lg:col-span-2 flex flex-col gap-4 rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="group lg:col-span-2 flex flex-col gap-4 rounded-xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="flex items-center gap-3">
<div className="text-zinc-500 transition-colors group-hover:text-amber-400">
<Download className="h-4 w-4" />
@ -101,7 +101,7 @@ export function FeatureGrid() {
</div>
{/* OpenCode SDK & UI Support */}
<div className="group lg:col-span-2 flex flex-col gap-4 rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="group lg:col-span-2 flex flex-col gap-4 rounded-xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="flex items-center gap-3">
<div className="text-zinc-500 transition-colors group-hover:text-pink-400">
<Plug className="h-4 w-4" />

View file

@ -50,7 +50,7 @@ const footer = {
export function Footer() {
return (
<footer className="border-t border-white/10 bg-black">
<footer className="border-t border-white/10 bg-[#09090b]">
<div className="mx-auto max-w-6xl px-6 py-16 lg:py-20">
<div className="xl:grid xl:grid-cols-12 xl:gap-16">
{/* Logo & Social */}

View file

@ -126,7 +126,7 @@ export function GetStarted() {
className="grid grid-cols-1 gap-4 md:grid-cols-3"
>
{/* Option 1: SDK */}
<div className="group flex flex-col rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="group flex flex-col rounded-xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="mb-4 flex items-center gap-3">
<div className="text-zinc-500">
<Code className="h-4 w-4" />
@ -142,7 +142,7 @@ export function GetStarted() {
</p>
<div className="flex-1 flex flex-col">
<div className="overflow-hidden rounded-lg border border-white/10 bg-black/50 flex-1 flex flex-col">
<div className="overflow-hidden rounded-lg border border-white/10 bg-[#0c0c0e] flex-1 flex flex-col">
<div className="flex items-center justify-between border-b border-white/10 bg-white/5 px-3 py-2">
<span className="text-[10px] font-medium text-zinc-500">example.ts</span>
<CopyButton text={sdkCodeRaw} />
@ -153,7 +153,7 @@ export function GetStarted() {
</div>
{/* Option 2: HTTP API */}
<div className="group flex flex-col rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="group flex flex-col rounded-xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="mb-4 flex items-center gap-3">
<div className="text-zinc-500">
<Server className="h-4 w-4" />
@ -169,7 +169,7 @@ export function GetStarted() {
</p>
<div className="flex-1 flex flex-col">
<div className="overflow-hidden rounded-lg border border-white/10 bg-black/50 flex-1 flex flex-col">
<div className="overflow-hidden rounded-lg border border-white/10 bg-[#0c0c0e] flex-1 flex flex-col">
<div className="flex items-center justify-between border-b border-white/10 bg-white/5 px-3 py-2">
<span className="text-[10px] font-medium text-zinc-500">terminal</span>
<CopyButton text={sandboxCommand} />
@ -190,7 +190,7 @@ export function GetStarted() {
</div>
{/* Option 3: Open Source */}
<div className="group flex flex-col rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="group flex flex-col rounded-xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="mb-4 flex items-center gap-3">
<div className="text-zinc-500">
<GitBranch className="h-4 w-4" />
@ -206,7 +206,7 @@ export function GetStarted() {
</p>
<div className="flex-1 flex flex-col">
<div className="overflow-hidden rounded-lg border border-white/10 bg-black/50 flex-1 flex flex-col">
<div className="overflow-hidden rounded-lg border border-white/10 bg-[#0c0c0e] flex-1 flex flex-col">
<div className="flex items-center justify-between border-b border-white/10 bg-white/5 px-3 py-2">
<span className="text-[10px] font-medium text-zinc-500">terminal</span>
<CopyButton text={sourceCommands} />

View file

@ -23,7 +23,7 @@ function UniversalAPIDiagram() {
}, []);
return (
<div className="relative w-full aspect-[4/3] sm:aspect-[16/9] bg-[#050505] rounded-2xl border border-white/10 overflow-hidden flex items-center justify-center shadow-2xl">
<div className="relative w-full aspect-[4/3] sm:aspect-[16/9] bg-[#0c0c0e] rounded-xl border border-white/10 overflow-hidden flex items-center justify-center shadow-2xl">
{/* Background Dots - color changes with active adapter */}
<div
className="absolute inset-0 opacity-[0.15] pointer-events-none transition-all duration-1000"
@ -46,7 +46,7 @@ function UniversalAPIDiagram() {
{/* YOUR APP NODE - Glass dark effect with backdrop blur */}
<foreignObject x="60" y="175" width="180" height="100">
<div className="w-full h-full rounded-2xl border border-white/10 bg-black/40 backdrop-blur-md flex items-center justify-center">
<div className="w-full h-full rounded-xl border border-white/10 bg-[#09090b]/60 backdrop-blur-md flex items-center justify-center">
<span className="text-white text-xl font-bold">Your App</span>
</div>
</foreignObject>
@ -69,7 +69,7 @@ function UniversalAPIDiagram() {
{/* SANDBOX BOUNDARY - Glass dark effect with backdrop blur */}
<foreignObject x="360" y="45" width="410" height="360">
<div className="w-full h-full rounded-3xl border border-white/10 bg-black/40 backdrop-blur-md">
<div className="w-full h-full rounded-xl border border-white/10 bg-[#09090b]/60 backdrop-blur-md">
<div className="text-white text-sm font-extrabold tracking-[0.2em] text-center pt-4">SANDBOX</div>
</div>
</foreignObject>
@ -228,7 +228,7 @@ export function Hero() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="mb-6 text-3xl font-medium leading-[1.1] tracking-tight text-white md:text-5xl"
className="mb-6 text-3xl font-semibold leading-[1.1] tracking-tight text-white md:text-5xl"
>
Run Coding Agents in Sandboxes.
<br />

View file

@ -32,7 +32,7 @@ export function Inspector() {
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.2 }}
className="overflow-hidden rounded-2xl border border-white/10"
className="overflow-hidden rounded-xl border border-white/10"
>
<img src="/images/inspector.png" alt="Sandbox Agent Inspector" className="w-full" />
</motion.div>

View file

@ -4,14 +4,14 @@ const integrations = ["Daytona", "E2B", "AI SDK", "Anthropic", "OpenAI", "Docker
export function Integrations() {
return (
<section id="integrations" className="py-24 bg-zinc-900/20 border-t border-white/5 relative overflow-hidden">
<section id="integrations" className="py-24 bg-[#0f0f11]/50 border-t border-white/5 relative overflow-hidden">
<div className="max-w-4xl mx-auto px-6 text-center">
<h2 className="text-3xl font-bold text-white mb-6">Works with your stack</h2>
<h2 className="text-3xl font-semibold text-white mb-6">Works with your stack</h2>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{integrations.map((item) => (
<div
key={item}
className="h-16 flex items-center justify-center rounded-xl border border-white/5 bg-zinc-900/50 text-zinc-300 font-mono text-sm hover:border-accent/40 hover:text-accent transition-all cursor-default"
className="h-16 flex items-center justify-center rounded-xl border border-white/5 bg-white/[0.02] text-zinc-300 font-mono text-sm hover:border-accent/40 hover:text-accent transition-all cursor-default"
>
{item}
</div>

View file

@ -6,7 +6,7 @@ import { GitHubStars } from "./GitHubStars";
function NavItem({ href, children }: { href: string; children: React.ReactNode }) {
return (
<a href={href} className="px-3 py-2 text-sm font-medium text-zinc-400 transition-colors duration-200 hover:text-white">
<a href={href} className="px-3 py-2 text-sm font-normal text-zinc-400 transition-colors duration-200 hover:text-white">
{children}
</a>
);
@ -28,19 +28,19 @@ export function Navigation() {
return (
<div className="fixed top-0 z-50 w-full max-w-[1200px] md:left-1/2 md:top-4 md:-translate-x-1/2 md:px-8">
<div
className={`relative before:pointer-events-none before:absolute before:inset-[-1px] before:z-20 before:hidden before:rounded-2xl before:border before:content-[''] before:transition-colors before:duration-300 before:ease-in-out md:before:block ${
className={`relative before:pointer-events-none before:absolute before:inset-[-1px] before:z-20 before:hidden before:rounded-xl before:border before:content-[''] before:transition-colors before:duration-300 before:ease-in-out md:before:block ${
isScrolled ? "before:border-white/10" : "before:border-transparent"
}`}
>
{/* Background with blur */}
<div
className={`absolute inset-0 -z-[1] hidden overflow-hidden rounded-2xl transition-all duration-300 ease-in-out md:block ${
isScrolled ? "bg-black/80 backdrop-blur-lg" : "bg-transparent backdrop-blur-none"
className={`absolute inset-0 -z-[1] hidden overflow-hidden rounded-xl transition-all duration-300 ease-in-out md:block ${
isScrolled ? "bg-[#09090b]/80 backdrop-blur-lg" : "bg-transparent backdrop-blur-none"
}`}
/>
<header
className={`bg-black/60 border-b-transparent sticky top-0 z-10 flex flex-col items-center border-b backdrop-blur-md pt-2 pb-2 md:static md:bg-transparent md:rounded-2xl md:max-w-[1200px] md:border-transparent md:backdrop-blur-none transition-all hover:opacity-100 ${
className={`bg-[#09090b]/60 border-b-transparent sticky top-0 z-10 flex flex-col items-center border-b backdrop-blur-md pt-2 pb-2 md:static md:bg-transparent md:rounded-xl md:max-w-[1200px] md:border-transparent md:backdrop-blur-none transition-all hover:opacity-100 ${
isScrolled ? "opacity-100" : "opacity-80"
}`}
>
@ -91,7 +91,7 @@ export function Navigation() {
{/* Mobile menu */}
{mobileMenuOpen && (
<div className="md:hidden border border-white/10 bg-black/95 backdrop-blur-lg rounded-2xl mt-2 mx-2 shadow-xl">
<div className="md:hidden border border-white/10 bg-[#09090b]/95 backdrop-blur-lg rounded-xl mt-2 mx-2 shadow-xl">
<div className="px-4 py-4 space-y-1">
<a
href="/docs"

View file

@ -26,18 +26,18 @@ const problems = [
export function ProblemsSolved() {
return (
<section id="features" className="py-24 bg-zinc-950 border-y border-white/5">
<section id="features" className="py-24 bg-[#0f0f11] border-y border-white/5">
<div className="max-w-7xl mx-auto px-6">
<div className="text-center mb-16">
<h2 className="text-3xl font-bold text-white mb-4">Why Coding Agent SDK?</h2>
<h2 className="text-3xl font-semibold text-white mb-4">Why Coding Agent SDK?</h2>
<p className="text-zinc-400 max-w-xl mx-auto">Solving the three fundamental friction points of agentic software development.</p>
</div>
<div className="grid md:grid-cols-3 gap-8">
{problems.map((item, idx) => (
<div key={idx} className="group p-8 rounded-2xl bg-zinc-900/40 border border-white/5 hover:border-accent/30 transition-all duration-300">
<div key={idx} className="group p-8 rounded-xl bg-white/[0.02] border border-white/5 hover:border-accent/30 transition-all duration-300">
<FeatureIcon icon={item.icon} color={item.color} />
<h3 className="text-xl font-bold text-white mb-3">{item.title}</h3>
<h3 className="text-xl font-semibold text-white mb-3">{item.title}</h3>
<p className="text-zinc-400 text-sm leading-relaxed">{item.desc}</p>
</div>
))}

View file

@ -10,11 +10,11 @@ interface ButtonProps {
}
export function Button({ children, variant = "primary", size = "md", href, onClick, className = "" }: ButtonProps) {
const baseStyles = "inline-flex items-center justify-center font-bold rounded-lg transition-all";
const baseStyles = "inline-flex items-center justify-center font-medium rounded-lg transition-all";
const variants = {
primary: "bg-white text-black hover:bg-zinc-200",
secondary: "bg-zinc-900 border border-white/10 text-white hover:bg-zinc-800",
secondary: "bg-[#0f0f11] border border-white/10 text-white hover:bg-white/[0.06]",
ghost: "text-zinc-400 hover:text-white",
};

View file

@ -40,7 +40,7 @@ const structuredData = {
<meta name="keywords" content="coding agents, AI SDK, Claude Code, Codex, OpenCode, Amp, Pi, sandbox, remote code execution, developer tools, AI coding assistant, code automation" />
<meta name="author" content="Rivet" />
<meta name="robots" content="index, follow" />
<meta name="theme-color" content="#000000" />
<meta name="theme-color" content="#09090b" />
<link rel="canonical" href={canonicalURL} />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
@ -48,8 +48,8 @@ const structuredData = {
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<!-- Manrope + JetBrains Mono (from Google Fonts) -->
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<!-- IBM Plex Sans + IBM Plex Mono (from Google Fonts) -->
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap" rel="stylesheet" />
<title>{title}</title>

View file

@ -7,14 +7,14 @@
--header-height: 3.5rem;
/* Theme colors (HSL for flexibility) */
--background: 20 14.3% 4.1%;
--foreground: 60 9.1% 97.8%;
--primary: 18.5 100% 50%;
--primary-foreground: 60 9.1% 97.8%;
--muted: 34 10% 10%;
--muted-foreground: 24 5.4% 63.9%;
--border: 12 6.5% 15.1%;
--card: 0 9.09% 6.47%;
--background: 240 10% 3.9%;
--foreground: 0 0% 100%;
--primary: 18 100% 50%;
--primary-foreground: 0 0% 100%;
--muted: 240 5% 7%;
--muted-foreground: 240 4% 66%;
--border: 0 0% 100% / 0.10;
--card: 240 6% 4%;
/* Shiki syntax highlighting */
--shiki-color-text: theme('colors.white');
@ -34,9 +34,9 @@
}
body {
@apply bg-black text-white antialiased;
font-family: 'Manrope', system-ui, sans-serif;
font-weight: 500;
@apply bg-[#09090b] text-white antialiased;
font-family: 'IBM Plex Sans', 'Segoe UI', system-ui, sans-serif;
font-weight: 400;
}
/* Text selection - matches rivet.dev */
@ -124,7 +124,7 @@
}
.glass-strong {
@apply bg-black/95 backdrop-blur-lg border border-white/10;
@apply bg-[#09090b]/95 backdrop-blur-lg border border-white/10;
}
/* Bento box card effects */
@ -179,11 +179,11 @@
/* Glow effect for buttons and interactive elements */
.glow-accent {
box-shadow: 0 0 20px rgba(255, 69, 0, 0.3);
box-shadow: 0 0 20px rgba(255, 79, 0, 0.3);
}
.glow-accent-hover:hover {
box-shadow: 0 0 30px rgba(255, 69, 0, 0.5);
box-shadow: 0 0 30px rgba(255, 79, 0, 0.5);
}
/* Code highlight styling */
@ -196,7 +196,7 @@
}
.code-highlight-ref.is-active {
background-color: rgba(255, 69, 0, 0.1);
background-color: rgba(255, 79, 0, 0.1);
}
.code-highlight-ref.is-active::before {
@ -206,7 +206,7 @@
top: 0;
bottom: 0;
width: 2px;
background-color: #ff4500;
background-color: #ff4f00;
}
/* Hide scrollbar */
@ -228,12 +228,12 @@
/* Backdrop with blur */
.backdrop-glow {
@apply backdrop-blur-lg bg-black/80;
@apply backdrop-blur-lg bg-[#09090b]/80;
}
/* Better focus ring */
.focus-ring {
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-black;
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-[#09090b];
}
}

View file

@ -4,23 +4,26 @@ export default {
theme: {
extend: {
colors: {
// Primary accent (OrangeRed)
accent: "#FF4500",
// Primary accent (Foundry orange)
accent: "#ff4f00",
// Extended color palette
background: "#000000",
"text-primary": "#FAFAFA",
"text-secondary": "#A0A0A0",
border: "#252525",
background: "#09090b",
"bg-secondary": "#0f0f11",
"bg-tertiary": "#0c0c0e",
"text-primary": "#ffffff",
"text-secondary": "#a1a1aa",
"text-tertiary": "#71717a",
border: "rgba(255, 255, 255, 0.10)",
// Code syntax highlighting
"code-keyword": "#c084fc",
"code-function": "#60a5fa",
"code-string": "#4ade80",
"code-comment": "#737373",
"code-comment": "#71717a",
},
fontFamily: {
sans: ["Manrope", "system-ui", "sans-serif"],
heading: ["Manrope", "system-ui", "sans-serif"],
mono: ["JetBrains Mono", "monospace"],
sans: ["IBM Plex Sans", "Segoe UI", "system-ui", "sans-serif"],
heading: ["IBM Plex Sans", "Segoe UI", "system-ui", "sans-serif"],
mono: ["IBM Plex Mono", "SFMono-Regular", "monospace"],
},
animation: {
"fade-in-up": "fade-in-up 0.8s ease-out forwards",