- {o.d} -
-{o.claim}
+{o.tail}
+
@@ -169,7 +176,7 @@ export default async function SolutionPage({ params }: PageProps) {
{o.claim} {o.tail}
{solution.title}
@@ -188,11 +195,11 @@ export default async function SolutionPage({ params }: PageProps) {
-
Where agents earn their keep.
diff --git a/apps/website/src/components/solutions/SolutionCodeBlock.tsx b/apps/website/src/components/solutions/SolutionCodeBlock.tsx
index 9ab58ae04..8c53c0ee3 100644
--- a/apps/website/src/components/solutions/SolutionCodeBlock.tsx
+++ b/apps/website/src/components/solutions/SolutionCodeBlock.tsx
@@ -20,7 +20,7 @@ async function highlight(block: SolutionCode) {
return codeToHtml(block.source, { lang: block.language, theme: 'tokyo-night' });
}
-export async function SolutionCodeBlock({ code, accent }: { code: SolutionCodeBlocks; accent: string }) {
+export async function SolutionCodeBlock({ code }: { code: SolutionCodeBlocks }) {
// Highlight every block up front: an async map inside JSX would give React
// promises to render rather than markup.
const rendered = await Promise.all(
@@ -31,7 +31,7 @@ export async function SolutionCodeBlock({ code, accent }: { code: SolutionCodeBl
What it looks like in your codebase
diff --git a/apps/website/src/components/solutions/SolutionDemoBlock.tsx b/apps/website/src/components/solutions/SolutionDemoBlock.tsx
index 1714ca224..f1b0f2a73 100644
--- a/apps/website/src/components/solutions/SolutionDemoBlock.tsx
+++ b/apps/website/src/components/solutions/SolutionDemoBlock.tsx
@@ -18,12 +18,12 @@ import type { DemoClip } from '../../lib/demo-media';
* No client JS: `autoPlay muted loop playsInline` is the whole behaviour, so
* this stays a Server Component.
*/
-export function SolutionDemoBlock({ clip, accent }: { clip: DemoClip; accent: string }) {
+export function SolutionDemoBlock({ clip }: { clip: DemoClip }) {
return (
The approval gate, in the product
diff --git a/apps/website/src/lib/solutions-data.ts b/apps/website/src/lib/solutions-data.ts
index 3041dbd28..899a2e3fd 100644
--- a/apps/website/src/lib/solutions-data.ts
+++ b/apps/website/src/lib/solutions-data.ts
@@ -71,8 +71,6 @@ export type SolutionCodeBlocks = readonly SolutionCode[];
export interface SolutionConfig {
slug: string;
- color: string;
- rgb: string;
eyebrow: string;
title: string;
subtitle: string;
@@ -97,8 +95,6 @@ export interface SolutionConfig {
export const SOLUTIONS: SolutionConfig[] = [
{
slug: 'compliance',
- color: '#D4850F',
- rgb: '212,133,15',
eyebrow: 'Compliance & Audit',
title: 'AI agents your compliance\nteam will actually approve',
subtitle: 'Human-in-the-loop approvals, auditable thread history, and deterministic testing — built into the framework, not bolted on.',
@@ -190,8 +186,6 @@ export const SOLUTIONS: SolutionConfig[] = [
},
{
slug: 'analytics',
- color: '#0F7B8D',
- rgb: '15,123,141',
eyebrow: 'Analytics & BI',
title: 'Natural language queries.\nReal-time dashboards.',
subtitle: 'Your users ask questions in plain English. The agent queries, visualizes, and streams results — all inside your Angular app.',
@@ -268,8 +262,6 @@ export class DashboardComponent {
},
{
slug: 'customer-support',
- color: '#5B4FCF',
- rgb: '91,79,207',
eyebrow: 'Customer Support',
title: 'AI agents that know when\nto escalate to a human',
subtitle: 'Resolve routine tickets autonomously, surface context instantly, and hand off to humans seamlessly — with full conversation history.',
diff --git a/apps/website/src/styles/pages.css b/apps/website/src/styles/pages.css
index a0a4af39c..ed455a865 100644
--- a/apps/website/src/styles/pages.css
+++ b/apps/website/src/styles/pages.css
@@ -335,9 +335,18 @@
max-width: 640px;
}
.sol-index-grid-header {
- text-align: center;
margin-bottom: 48px;
}
+.sol-index-rail {
+ display: flex;
+ align-items: baseline;
+ gap: 14px;
+}
+.sol-index-rail-line {
+ flex: 1;
+ height: 1px;
+ background: var(--color-border);
+}
.sol-index-eyebrow-tight {
margin-bottom: 12px;
}
@@ -399,13 +408,22 @@
/* Solution detail page — app/solutions/[slug]/page.tsx */
.sol-page-section-header {
- text-align: center;
max-width: 720px;
- margin: 0 auto 48px;
+ margin-bottom: 48px;
}
.sol-page-eyebrow-tight {
margin-bottom: 12px;
}
+.sol-page-rail {
+ display: flex;
+ align-items: baseline;
+ gap: 14px;
+}
+.sol-page-rail-line {
+ flex: 1;
+ height: 1px;
+ background: var(--color-border);
+}
.sol-page-h2 {
font-family: var(--font-garamond);
font-size: var(--text-h2);
@@ -492,10 +510,11 @@
}
.sol-page-metric {
font-family: var(--font-garamond);
- font-style: italic;
- font-size: 32px;
+ font-size: 40px;
font-weight: 700;
- line-height: 1.1;
+ line-height: 0.9;
+ letter-spacing: -0.02em;
+ color: var(--color-text-primary);
margin: 0;
margin-bottom: 12px;
}
@@ -639,10 +658,18 @@
}
.pilot-section-header {
max-width: 720px;
- margin: 0 auto;
- text-align: center;
margin-bottom: 48px;
}
+.pilot-rail2 {
+ display: flex;
+ align-items: baseline;
+ gap: 14px;
+}
+.pilot-rail2-line {
+ flex: 1;
+ height: 1px;
+ background: var(--color-border);
+}
.pilot-h2 {
font-family: var(--font-garamond);
font-size: var(--text-h2);
@@ -655,29 +682,39 @@
.pilot-h2-spaced {
margin-bottom: 16px;
}
-.pilot-outcomes-grid {
+.pilot-outcome-rows {
+ margin-top: 22px;
+ border-top: 2px solid var(--color-text-primary);
+ max-width: 56ch;
+}
+.pilot-outcome-row {
display: grid;
- grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
+ grid-template-columns: 1fr auto;
gap: 16px;
- max-width: 1000px;
- margin: 0 auto;
+ align-items: baseline;
+ border-bottom: 1px solid var(--color-border);
+ padding: 10px 0;
}
-.pilot-outcome-h3 {
+.pilot-outcome-claim {
font-family: var(--font-inter);
- font-size: 17px;
- line-height: 1.3;
- font-weight: 600;
+ font-size: 15px;
+ line-height: 1.5;
color: var(--color-text-primary);
margin: 0;
- margin-bottom: 8px;
}
-.pilot-outcome-body {
- font-family: var(--font-inter);
- font-size: 14px;
- line-height: var(--text-body--line-height);
- color: var(--color-text-secondary);
+.pilot-outcome-tail {
+ font-family: var(--font-mono);
+ font-size: 11.5px;
+ color: var(--color-text-muted);
+ white-space: nowrap;
margin: 0;
}
+@media (max-width: 640px) {
+ .pilot-outcome-row {
+ grid-template-columns: 1fr;
+ gap: 2px;
+ }
+}
.pilot-contact-inner {
max-width: 720px;
margin: 0 auto;
@@ -1168,13 +1205,3 @@
gap: 12px;
flex-wrap: wrap;
}
-
-/* Per-page accent color, set inline as --accent (unbounded prop — the
- * lint-guard escape hatch). The compound selector matches the Eyebrow tone
- * rules' 0-2-0 specificity ([data-ui="eyebrow"][data-tone=…] in ui.css) and
- * wins the tie because pages.css imports after ui.css — the inline color it
- * replaces used to outrank everything. */
-[data-accent-text],
-[data-ui='eyebrow'][data-accent-text] {
- color: var(--accent);
-}
diff --git a/docs/superpowers/plans/2026-09-01-solutions-pilot.md b/docs/superpowers/plans/2026-09-01-solutions-pilot.md
new file mode 100644
index 000000000..608d0a984
--- /dev/null
+++ b/docs/superpowers/plans/2026-09-01-solutions-pilot.md
@@ -0,0 +1,196 @@
+# Solutions + Pilot Back Half Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** The ninth arc per `docs/superpowers/specs/2026-09-01-solutions-pilot-arc-design.md`: kill per-solution accent theming, rail the remaining centered headers, proof-cell the capability metrics, and ledger the pilot outcomes.
+
+**Architecture:** Next.js 16 / React 19; UNLAYERED CSS (`pages.css` holds sol-/pilot- rules). `solution.color` has exactly two consumers: `lib/solutions-data.ts` (definition, 5 values) and `app/solutions/[slug]/page.tsx` (threading) — the index page does not use it. No page specs exist for these routes yet.
+
+**Test command:** `cd apps/website && npx vitest run --config vite.config.mts` — baseline all green (53 files; count from a fresh run before starting).
+**Branch:** `blove/solutions-pilot` — create from `blove/final-review-fixes` (the fix batch, PR #922 pending): `git checkout -b blove/solutions-pilot blove/final-review-fixes`. If #922 has merged by start time, branch from origin/main instead and note it.
+
+---
+
+### Task 1: /solutions/[slug] — accent removal + rails + proof metrics
+
+**Files:**
+- Modify: `apps/website/src/app/solutions/[slug]/page.tsx`
+- Modify: `apps/website/src/lib/solutions-data.ts`
+- Create: `apps/website/src/app/solutions/[slug]/page.spec.tsx`
+- Modify: `apps/website/src/styles/pages.css`
+
+- [ ] **Step 1: Spec FIRST (failing).** New spec rendering ONE solution page (pick the first slug from `getAllSolutionSlugs()`):
+
+```tsx
+// apps/website/src/app/solutions/[slug]/page.spec.tsx
+import { render, screen } from '@testing-library/react';
+import { describe, it, expect, vi } from 'vitest';
+import SolutionPage from './page';
+import { getAllSolutionSlugs } from '../../../lib/solutions-data';
+
+vi.mock('../../../lib/analytics/client', () => ({
+ track: vi.fn(),
+ trackCtaClick: vi.fn(),
+ trackExternalLinkClick: vi.fn(),
+}));
+
+describe('SolutionPage', () => {
+ it('renders navy rails with no per-solution accent theming', async () => {
+ const slug = getAllSolutionSlugs()[0];
+ const ui = await SolutionPage({ params: Promise.resolve({ slug }) });
+ const { container } = render(ui);
+ expect(container.querySelectorAll('[data-accent-text]')).toHaveLength(0);
+ expect(container.querySelectorAll('.sol-page-rail').length).toBeGreaterThanOrEqual(3);
+ expect(container.querySelector('.sol-page-metric')).toBeTruthy();
+ expect(screen.getByRole('heading', { level: 1 })).toBeTruthy();
+ });
+});
+```
+
+Adapt mocks if children demand more (async CodeShowcase-style components: mock to `() => null` if present — check imports). Run → FAIL (no `.sol-page-rail` exists). Paste it.
+
+- [ ] **Step 2: Page changes.**
+ - Delete the `accent` prop from `PainPoints`, `Architecture`, `Capabilities` (signatures + call sites) and every `style={{ '--accent': … }}` + `data-accent-text` attribute in the file (hero Eyebrow included). All Eyebrows: `tone="accent"`, keep classNames.
+ - Each `sol-page-section-header` gains the railkick as its first child:
+```tsx
+