From 7409aec953ad5591916c0e4676e6cc1d8d8323b4 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sat, 29 Aug 2026 14:35:45 -0700 Subject: [PATCH 1/3] refactor(website): move hero and feature landing blocks to landing.css --- .../src/components/landing/Differentiator.tsx | 123 +---- .../src/components/landing/FeatureBlock.tsx | 139 +----- apps/website/src/components/landing/Hero.tsx | 114 +---- .../components/landing/WhitePaperBlock.tsx | 169 +------ apps/website/src/styles/landing.css | 459 ++++++++++++++++++ 5 files changed, 520 insertions(+), 484 deletions(-) diff --git a/apps/website/src/components/landing/Differentiator.tsx b/apps/website/src/components/landing/Differentiator.tsx index 4404e7267..fc5c12b13 100644 --- a/apps/website/src/components/landing/Differentiator.tsx +++ b/apps/website/src/components/landing/Differentiator.tsx @@ -77,7 +77,7 @@ function CheckIcon() { strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" - style={{ flexShrink: 0, marginTop: 4 }} + className="differentiator-check-icon" > @@ -89,107 +89,33 @@ export function Differentiator() {
-
- Why this exists -

+
+ Why this exists +

Everything an Angular agent needs once the demo works.

-

+

A streaming chat tutorial takes an hour. Shipping a real agent — durable, interruptible, observable, on your design system — takes most teams six months. Threadplane gives the Angular surface that the rest of the stack assumes you've already built.

-
    +
      {PRODUCTION_ROWS.map((row) => ( -
    • +
    • -
      -
      - +
      +
      + {row.need} - + {row.description}
      - + {row.primitive}
      @@ -197,17 +123,7 @@ export function Differentiator() { ))}
    -

    +

    Want help walking these on your codebase?{' '} Pilot to Prod →

    - -

); diff --git a/apps/website/src/components/landing/FeatureBlock.tsx b/apps/website/src/components/landing/FeatureBlock.tsx index 271e4c884..b913053ed 100644 --- a/apps/website/src/components/landing/FeatureBlock.tsx +++ b/apps/website/src/components/landing/FeatureBlock.tsx @@ -1,6 +1,5 @@ import type { ReactNode } from 'react'; import Link from 'next/link'; -import { tokens } from '@threadplane/design-tokens'; import { Container } from '../ui/Container'; import { Section } from '../ui/Section'; import { Eyebrow } from '../ui/Eyebrow'; @@ -38,86 +37,20 @@ export function FeatureBlock({ return (
-
+
{/* Text column */} -
- {eyebrow} -

+
+ {eyebrow} +

{headline}

-

+

{body}

-
    +
      {bullets.map((b) => ( -
    • -
    • + {b} @@ -126,73 +59,27 @@ export function FeatureBlock({
    {/* Supporting card row */} -
    +
    {supportingCards.map((sc) => ( -
    +
    {sc.title}
    -
    +
    {sc.description}
    ))}
    - + {cta.label} →
    {/* Visual column */} -
    {visual}
    +
    {visual}
    - -

); diff --git a/apps/website/src/components/landing/Hero.tsx b/apps/website/src/components/landing/Hero.tsx index 2d21342a3..da769a751 100644 --- a/apps/website/src/components/landing/Hero.tsx +++ b/apps/website/src/components/landing/Hero.tsx @@ -1,7 +1,6 @@ 'use client'; import React, { useCallback, useState } from 'react'; -import { tokens } from '@threadplane/design-tokens'; import { Container } from '../ui/Container'; import { Section } from '../ui/Section'; import { Eyebrow } from '../ui/Eyebrow'; @@ -65,61 +64,23 @@ export function Hero() { return (
-
+
{/* Left column */}
- + Threadplane · Angular agent UI -

+

Ship production agent UIs in Angular.

-

+

{HERO_SUBHEAD}

-
+
-
+
{POSITIONING_PROOF_POINTS.map((proofPoint, index) => ( {proofPoint.label} @@ -139,17 +100,7 @@ export function Hero() { ))}
-

+

Not another backend agent runtime. Keep LangGraph, Genkit, Mastra, CrewAI, or your own service. Threadplane solves the Angular UI layer.

@@ -167,33 +118,25 @@ export function Hero() { surface: 'home', }) } - style={{ display: 'block', textDecoration: 'none' }} + className="hero-demo-link" aria-label="Open the generative UI example running in cockpit" > Canonical demo — agent renders a live airline operations dashboard with KPI cards, charts, and a disruptions table -

+

Open in cockpit →

- -
); diff --git a/apps/website/src/components/landing/WhitePaperBlock.tsx b/apps/website/src/components/landing/WhitePaperBlock.tsx index a7425dbf9..5c7fd73c3 100644 --- a/apps/website/src/components/landing/WhitePaperBlock.tsx +++ b/apps/website/src/components/landing/WhitePaperBlock.tsx @@ -1,6 +1,5 @@ 'use client'; import { useState } from 'react'; -import { tokens } from '@threadplane/design-tokens'; import { Container } from '../ui/Container'; import { Section } from '../ui/Section'; import { Eyebrow } from '../ui/Eyebrow'; @@ -70,79 +69,23 @@ export function WhitePaperBlock({ paper = 'overview' }: WhitePaperBlockProps = { return (
-
+
- Field report -

+ Field report +

The last-mile gap in Angular AI.

-
    +
      {BULLETS.map((b) => ( -
    • -
    • +
    • ))}
    {state === 'done' ? ( -
    +
    ✓ Check your inbox — the guide is on its way.{' '} Or download directly.
    ) : ( -
    + setEmail(e.target.value)} required disabled={state === 'submitting'} - style={{ - flex: '1 1 240px', - background: tokens.surfaces.surface, - border: `1px solid ${tokens.surfaces.border}`, - borderRadius: tokens.radius.md, - padding: '12px 14px', - fontFamily: tokens.typography.body.family, - fontSize: tokens.typography.body.size, - color: tokens.colors.textPrimary, - outline: 'none', - }} + className="wp-email-input" />
    {/* Tilted whitepaper cover */} -
    +
    -
    +
    -
    +
    Field report · 18 pages
    -
    +
    From Prototype to Production
    -
    +
    Six production-readiness dimensions for Angular AI teams.
    -
    +
    Threadplane
    - -
); diff --git a/apps/website/src/styles/landing.css b/apps/website/src/styles/landing.css index 599cc6f63..0e9a50f31 100644 --- a/apps/website/src/styles/landing.css +++ b/apps/website/src/styles/landing.css @@ -8,3 +8,462 @@ * * Migration: docs/superpowers/plans/2026-08-29-inline-style-substrate-migration.md */ + +/* Hero — components/landing/Hero.tsx */ +.hero-grid { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: 64px; + align-items: center; +} +.hero-eyebrow { + margin-bottom: 16px; +} +.hero-heading { + font-family: var(--font-garamond); + font-size: var(--text-h1); + line-height: var(--text-h1--line-height); + font-weight: 700; + color: var(--color-text-primary); + margin: 0; + margin-bottom: 24px; + letter-spacing: -0.02em; +} +.hero-subhead { + font-family: var(--font-inter); + font-size: var(--text-body-lg); + line-height: var(--text-body-lg--line-height); + color: var(--color-text-secondary); + margin: 0; + margin-bottom: 32px; + max-width: 54ch; +} +.hero-cta-row { + display: flex; + gap: 12px; + margin-bottom: 24px; + flex-wrap: wrap; +} +.hero-proof-row { + display: flex; + gap: 8px; + align-items: center; + flex-wrap: wrap; + margin-bottom: 12px; +} +.hero-proof-link { + text-decoration: none; +} +.hero-caption { + margin: 0; + font-family: var(--font-inter); + font-size: var(--text-body); + line-height: var(--text-body--line-height); + color: var(--color-text-muted); + font-style: italic; + max-width: 60ch; +} +.hero-demo-link { + display: block; + text-decoration: none; +} +.hero-demo-frame { + width: 100%; +} +.hero-demo-img { + display: block; + width: 100%; + height: auto; +} +.hero-demo-caption { + margin: 12px 0 0; + text-align: center; + font-family: var(--font-inter); + font-size: 13px; + color: var(--color-text-muted); +} +.hero-demo-caption-link { + color: var(--color-accent); + text-decoration: none; + font-weight: 600; +} +@keyframes blink { to { visibility: hidden; } } +@media (max-width: 900px) { + .hero-grid { + grid-template-columns: 1fr !important; + gap: 40px !important; + } +} +.hero-proof-pill { + transition: transform 160ms ease, background 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease; + will-change: transform; +} +.hero-proof-link:hover > .hero-proof-pill, +.hero-proof-link:focus-visible > .hero-proof-pill { + transform: translateY(-1px); + background: var(--color-accent-surface) !important; + border-color: var(--color-accent-border) !important; + color: var(--color-accent) !important; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); +} +.hero-proof-link:active > .hero-proof-pill { + transform: translateY(0); + box-shadow: none; +} +@media (prefers-reduced-motion: reduce) { + .hero-proof-pill { transition: none; } + .hero-proof-link:hover > .hero-proof-pill, + .hero-proof-link:focus-visible > .hero-proof-pill { transform: none; } +} + +/* FeatureBlock — components/landing/FeatureBlock.tsx */ +.feature-block-grid { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: 64px; + align-items: center; +} +.feature-block-text { + order: 1; +} +.feature-block-visual { + order: 2; +} +.feature-block-grid[data-visual-left] .feature-block-text { + order: 2; +} +.feature-block-grid[data-visual-left] .feature-block-visual { + order: 1; +} +.feature-block-eyebrow { + margin-bottom: 16px; +} +.feature-block-heading { + font-family: var(--font-garamond); + font-size: var(--text-h2); + line-height: var(--text-h2--line-height); + font-weight: 700; + color: var(--color-text-primary); + margin: 0; + margin-bottom: 20px; + letter-spacing: -0.015em; +} +.feature-block-body { + font-family: var(--font-inter); + font-size: var(--text-body-lg); + line-height: var(--text-body-lg--line-height); + color: var(--color-text-secondary); + margin: 0; + margin-bottom: 24px; +} +.feature-block-bullets { + list-style: none; + padding: 0; + margin: 0 0 32px 0; + display: flex; + flex-direction: column; + gap: 12px; +} +.feature-block-bullet { + display: flex; + align-items: flex-start; + gap: 10px; + font-family: var(--font-inter); + font-size: var(--text-body); + line-height: var(--text-body--line-height); + color: var(--color-text-primary); +} +.feature-block-bullet-check { + flex: 0 0 18px; + height: 18px; + margin-top: 4px; + border-radius: var(--radius-full); + background: var(--color-accent-surface); + border: 1px solid var(--color-accent-border); + color: var(--color-accent); + font-size: 11px; + font-weight: 700; + display: inline-flex; + align-items: center; + justify-content: center; + line-height: 1; +} +.feature-block-card-row { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); + gap: 8px; + margin-bottom: 24px; +} +.feature-block-card-title { + font-family: "JetBrains Mono", monospace; + font-size: 12px; + font-weight: 700; + color: var(--color-accent); + margin-bottom: 4px; +} +.feature-block-card-desc { + font-family: var(--font-inter); + font-size: var(--text-caption); + line-height: var(--text-caption--line-height); + color: var(--color-text-secondary); +} +.feature-block-cta { + font-family: Inter, system-ui, sans-serif; + font-size: 15px; + font-weight: 600; + color: var(--color-accent); + text-decoration: none; + display: inline-flex; + align-items: center; + gap: 6px; +} +@media (max-width: 900px) { + .feature-block-grid { + grid-template-columns: 1fr !important; + gap: 32px !important; + } + .feature-block-grid > div { + order: unset !important; + } +} + +/* Differentiator — components/landing/Differentiator.tsx */ +.differentiator-check-icon { + flex-shrink: 0; + margin-top: 4px; +} +.differentiator-section { + padding-top: 72px; +} +.differentiator-intro { + max-width: 1020px; + margin: 0 auto 44px; + text-align: center; +} +.differentiator-eyebrow { + margin-bottom: 16px; +} +.differentiator-heading { + font-family: var(--font-garamond); + font-size: var(--text-h2); + line-height: var(--text-h2--line-height); + font-weight: 700; + color: var(--color-text-primary); + margin: 0; + margin-bottom: 20px; + letter-spacing: -0.015em; +} +.differentiator-subhead { + font-family: var(--font-inter); + font-size: var(--text-body-lg); + line-height: var(--text-body-lg--line-height); + color: var(--color-text-secondary); + margin: 0 auto; + max-width: 760px; +} +.differentiator-list { + list-style: none; + padding: 0; + margin: 0 auto; + max-width: 980px; + border-top: 1px solid var(--color-border); +} +.why-row { + display: flex; + align-items: flex-start; + gap: 16px; + padding: 18px 8px; + border-bottom: 1px solid var(--color-border); +} +.why-row__body { + flex: 1; + display: flex; + gap: 16px; + align-items: baseline; + flex-wrap: wrap; +} +.why-row__text { + flex: 1 1 200px; + min-width: 0; +} +.why-row__need { + font-family: var(--font-inter); + font-size: var(--text-body); + line-height: var(--text-body--line-height); + font-weight: 600; + color: var(--color-text-primary); + margin-right: 8px; +} +.why-row__description { + font-family: var(--font-inter); + font-size: var(--text-body); + line-height: var(--text-body--line-height); + color: var(--color-text-secondary); +} +.why-row__primitive { + font-family: "JetBrains Mono", monospace; + font-size: 13px; + color: var(--color-text-muted); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; +} +.differentiator-footer { + margin: 24px auto 0; + max-width: 980px; + text-align: center; + font-family: var(--font-inter); + font-size: var(--text-body); + line-height: var(--text-body--line-height); + color: var(--color-text-muted); +} +.differentiator-footer-link { + color: var(--color-accent); + text-decoration: none; + font-weight: 600; +} +@media (max-width: 640px) { + .why-row__body { + flex-direction: column !important; + gap: 6px !important; + } +} + +/* WhitePaperBlock — components/landing/WhitePaperBlock.tsx */ +.wp-grid { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: 64px; + align-items: center; +} +.wp-eyebrow { + margin-bottom: 16px; +} +.wp-heading { + font-family: var(--font-garamond); + font-size: var(--text-h2); + line-height: var(--text-h2--line-height); + font-weight: 700; + color: var(--color-text-primary); + margin: 0; + margin-bottom: 20px; + letter-spacing: -0.015em; +} +.wp-bullets { + list-style: none; + padding: 0; + margin: 0 0 24px 0; + display: flex; + flex-direction: column; + gap: 10px; +} +.wp-bullet { + display: flex; + align-items: flex-start; + gap: 10px; + font-family: var(--font-inter); + font-size: var(--text-body-lg); + line-height: var(--text-body-lg--line-height); + color: var(--color-text-secondary); +} +.wp-bullet-dot { + flex: 0 0 6px; + height: 6px; + margin-top: 12px; + border-radius: var(--radius-full); + background: var(--color-accent); +} +.wp-success { + font-family: var(--font-inter); + font-size: var(--text-body); + color: #1a7a40; + margin-bottom: 16px; +} +.wp-success-link { + color: var(--color-accent); +} +.wp-form { + display: flex; + gap: 8px; + flex-wrap: wrap; + max-width: 480px; +} +.wp-email-input { + flex: 1 1 240px; + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + padding: 12px 14px; + font-family: var(--font-inter); + font-size: var(--text-body); + color: var(--color-text-primary); + outline: none; +} +.wp-error { + margin-top: 12px; + color: var(--color-angular-red); + font-size: 14px; +} +.wp-error-link { + color: var(--color-accent); +} +.wp-already { + margin-top: 12px; + font-size: 13px; + color: var(--color-text-muted); + font-family: var(--font-inter); +} +.wp-already-link { + color: var(--color-accent); + text-decoration: underline; +} +.wp-cover-wrap { + display: flex; + justify-content: center; +} +.wp-cover { + aspect-ratio: 8.5 / 11; + background: linear-gradient(135deg, #fafbfc 0%, #eaf3ff 100%); + padding: 48px 36px; + display: flex; + flex-direction: column; + justify-content: space-between; +} +.wp-cover-badge { + font-family: "JetBrains Mono", monospace; + font-size: 11px; + text-transform: uppercase; + letter-spacing: 0.15em; + color: var(--color-accent); + margin-bottom: 14px; +} +.wp-cover-title { + font-family: "EB Garamond", Georgia, serif; + font-size: 28px; + line-height: 1.15; + font-weight: 700; + color: var(--color-text-primary); + margin-bottom: 12px; + font-style: italic; +} +.wp-cover-desc { + font-family: Inter, system-ui, sans-serif; + font-size: 14px; + line-height: 1.5; + color: var(--color-text-secondary); +} +.wp-cover-footer { + font-family: "JetBrains Mono", monospace; + font-size: 11px; + color: var(--color-text-muted); + text-transform: uppercase; + letter-spacing: 0.1em; +} +@media (max-width: 900px) { + .wp-grid { + grid-template-columns: 1fr !important; + gap: 40px !important; + } +} + From fbb2579821782e1fc676dc968425e922b4e08ac9 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sat, 29 Aug 2026 14:35:52 -0700 Subject: [PATCH 2/3] refactor(website): move landing section strip to landing.css --- .../src/components/landing/EcosystemStrip.tsx | 142 +------ .../src/components/landing/FinalCTA.tsx | 40 +- .../src/components/landing/HomeFAQ.tsx | 20 +- .../src/components/landing/PilotBlock.tsx | 130 +----- .../src/components/landing/Promises.tsx | 61 +-- .../src/components/landing/RecentArticles.tsx | 37 +- .../components/landing/ag-ui/BackendsGrid.tsx | 44 +- apps/website/src/styles/landing.css | 390 ++++++++++++++++++ 8 files changed, 442 insertions(+), 422 deletions(-) diff --git a/apps/website/src/components/landing/EcosystemStrip.tsx b/apps/website/src/components/landing/EcosystemStrip.tsx index a58d64140..3171a681b 100644 --- a/apps/website/src/components/landing/EcosystemStrip.tsx +++ b/apps/website/src/components/landing/EcosystemStrip.tsx @@ -1,4 +1,3 @@ -import { tokens } from '@threadplane/design-tokens'; import { Container } from '../ui/Container'; import { Section } from '../ui/Section'; import { Eyebrow } from '../ui/Eyebrow'; @@ -51,22 +50,7 @@ const ECOSYSTEM_GROUPS: EcosystemGroup[] = [ function EcosystemTile({ item }: { item: EcosystemItem }) { return ( -
+
{item.logoSrc ? ( ) : null} -
-
+
+
{item.name}
-
+
{item.note}
@@ -116,78 +77,25 @@ export function EcosystemStrip() { return (
-
- +
+ Works with your agent stack -

+

Bring the model, runtime, and UI protocol you already use.

-

+

Threadplane gives Angular teams production-ready chat, durable threads, interrupts, subagents, planning, memory, and generative UI without locking the backend to one provider.

-
+
{ECOSYSTEM_GROUPS.map((group) => ( -
-
+
+
{group.title}
-
+
{group.items.map((item) => ( ))} @@ -195,30 +103,6 @@ export function EcosystemStrip() {
))}
- -
); diff --git a/apps/website/src/components/landing/FinalCTA.tsx b/apps/website/src/components/landing/FinalCTA.tsx index d99cc7773..2a36f3415 100644 --- a/apps/website/src/components/landing/FinalCTA.tsx +++ b/apps/website/src/components/landing/FinalCTA.tsx @@ -1,4 +1,3 @@ -import { tokens } from '@threadplane/design-tokens'; import { Container } from '../ui/Container'; import { Section } from '../ui/Section'; import { Button } from '../ui/Button'; @@ -29,36 +28,14 @@ export function FinalCTA({ return (
-
-

+
+

{headline}

-

+

{subtext}

-
+
{primary ? (
{/* Timeline */} -
+
{TIMELINE.map((t) => ( -
-
+
+
{t.phase}
-
+
{t.title}
-
+
{t.body}
@@ -163,15 +68,6 @@ export function PilotBlock() { ))}
- -

); diff --git a/apps/website/src/components/landing/Promises.tsx b/apps/website/src/components/landing/Promises.tsx index 1a2d289aa..140f05837 100644 --- a/apps/website/src/components/landing/Promises.tsx +++ b/apps/website/src/components/landing/Promises.tsx @@ -1,4 +1,3 @@ -import { tokens } from '@threadplane/design-tokens'; import { Container } from '../ui/Container'; import { Section } from '../ui/Section'; import { Eyebrow } from '../ui/Eyebrow'; @@ -31,70 +30,24 @@ export function Promises() { return (
-
- +
+ Built on principles -

+

What we won't do.

-

+

Honest commitments, not aspirations.

-
+
{PROMISES.map((p) => ( -

+

{p.title}

-

+

{p.body}

diff --git a/apps/website/src/components/landing/RecentArticles.tsx b/apps/website/src/components/landing/RecentArticles.tsx index fca9b3ab3..eaaf54e35 100644 --- a/apps/website/src/components/landing/RecentArticles.tsx +++ b/apps/website/src/components/landing/RecentArticles.tsx @@ -1,5 +1,4 @@ import Link from 'next/link'; -import { tokens } from '@threadplane/design-tokens'; import { Section } from '../ui/Section'; import { Container } from '../ui/Container'; import { Eyebrow } from '../ui/Eyebrow'; @@ -18,47 +17,23 @@ export function RecentArticles() { return (
-
- +
+ Blog -

+

Recent articles

-
+
{posts.map((p) => ( ))}
-
- +
+ View all articles →
diff --git a/apps/website/src/components/landing/ag-ui/BackendsGrid.tsx b/apps/website/src/components/landing/ag-ui/BackendsGrid.tsx index ee8515c77..358c604ef 100644 --- a/apps/website/src/components/landing/ag-ui/BackendsGrid.tsx +++ b/apps/website/src/components/landing/ag-ui/BackendsGrid.tsx @@ -1,5 +1,3 @@ -import { tokens } from '@threadplane/design-tokens'; - interface Backend { readonly name: string; readonly note: string; @@ -18,47 +16,13 @@ const BACKENDS: readonly Backend[] = [ export function BackendsGrid() { return ( -
+
{BACKENDS.map((b) => ( -
-
+
+
{b.name}
-
+
{b.note}
diff --git a/apps/website/src/styles/landing.css b/apps/website/src/styles/landing.css index 0e9a50f31..300de6d0a 100644 --- a/apps/website/src/styles/landing.css +++ b/apps/website/src/styles/landing.css @@ -467,3 +467,393 @@ } } +/* PilotBlock — components/landing/PilotBlock.tsx */ +.pilot-block-grid { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: 64px; + align-items: center; +} +.pilot-eyebrow { + margin-bottom: 16px; +} +.pilot-heading { + font-family: var(--font-garamond); + font-size: var(--text-h2); + line-height: var(--text-h2--line-height); + font-weight: 700; + color: var(--color-text-primary); + margin: 0; + margin-bottom: 20px; + letter-spacing: -0.015em; +} +.pilot-subhead { + font-family: var(--font-inter); + font-size: var(--text-body-lg); + line-height: var(--text-body-lg--line-height); + color: var(--color-text-secondary); + margin: 0; + margin-bottom: 24px; +} +.pilot-outcomes { + list-style: none; + padding: 0; + margin: 0 0 32px 0; + display: flex; + flex-direction: column; + gap: 10px; +} +.pilot-outcome { + display: flex; + align-items: flex-start; + gap: 10px; + font-family: var(--font-inter); + font-size: var(--text-body); + line-height: var(--text-body--line-height); + color: var(--color-text-primary); +} +.pilot-outcome-check { + flex: 0 0 18px; + height: 18px; + margin-top: 4px; + border-radius: var(--radius-full); + background: var(--color-accent); + color: var(--color-text-inverted); + font-size: 11px; + font-weight: 700; + display: inline-flex; + align-items: center; + justify-content: center; + line-height: 1; +} +.pilot-cta-row { + display: flex; + gap: 12px; + flex-wrap: wrap; +} +.pilot-timeline { + display: flex; + flex-direction: column; + gap: 12px; +} +.pilot-timeline-row { + display: flex; + align-items: flex-start; + gap: 16px; +} +.pilot-timeline-phase { + flex: 0 0 36px; + height: 36px; + border-radius: var(--radius-full); + background: var(--color-accent); + color: var(--color-text-inverted); + font-family: "JetBrains Mono", monospace; + font-size: 14px; + font-weight: 700; + display: inline-flex; + align-items: center; + justify-content: center; +} +.pilot-timeline-title { + font-family: Inter, system-ui, sans-serif; + font-size: 17px; + font-weight: 600; + color: var(--color-text-primary); + margin-bottom: 4px; +} +.pilot-timeline-body { + font-family: var(--font-inter); + font-size: var(--text-body); + line-height: var(--text-body--line-height); + color: var(--color-text-secondary); +} +@media (max-width: 900px) { + .pilot-block-grid { + grid-template-columns: 1fr !important; + gap: 40px !important; + } +} + +/* EcosystemStrip — components/landing/EcosystemStrip.tsx */ +[data-ui="ecosystem-tile"] { + min-height: 76px; + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); + background: var(--color-surface); + box-shadow: var(--shadow-sm); + padding: 14px 16px; + display: flex; + align-items: center; + justify-content: flex-start; + gap: 5px; + transition: border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease; +} +.ecosystem-tile-logo { + width: 24px; + height: 24px; + object-fit: contain; + flex: 0 0 auto; + margin-right: 8px; +} +.ecosystem-tile-body { + min-width: 0; +} +.ecosystem-tile-name { + font-family: Inter, system-ui, sans-serif; + font-size: 15px; + line-height: 1.25; + font-weight: 700; + color: var(--color-text-primary); +} +.ecosystem-tile-note { + font-family: "JetBrains Mono", monospace; + font-size: 10px; + line-height: 1.4; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--color-text-muted); +} +.ecosystem-intro { + max-width: 780px; + margin: 0 auto 28px; + text-align: center; +} +.ecosystem-eyebrow { + margin-bottom: 12px; +} +.ecosystem-heading { + font-family: var(--font-garamond); + font-size: var(--text-h2); + line-height: var(--text-h2--line-height); + font-weight: 700; + color: var(--color-text-primary); + margin: 0; + margin-bottom: 14px; + letter-spacing: 0; +} +.ecosystem-subhead { + font-family: var(--font-inter); + font-size: var(--text-body-lg); + line-height: var(--text-body-lg--line-height); + color: var(--color-text-secondary); + margin: 0; +} +.ecosystem-groups { + display: grid; + gap: 18px; + max-width: 1080px; + margin: 0 auto; +} +.ecosystem-row { + display: grid; + grid-template-columns: 170px minmax(0, 1fr); + gap: 14px; + align-items: start; +} +.ecosystem-row-title { + font-family: "JetBrains Mono", monospace; + font-size: 11px; + line-height: 1.5; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--color-accent); + padding-top: 16px; +} +.ecosystem-row-tiles { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 10px; +} +[data-ui="ecosystem-tile"]:hover { + border-color: var(--color-accent-border-hover); + box-shadow: var(--shadow-md); + transform: translateY(-1px); +} +@media (max-width: 760px) { + .ecosystem-row { + grid-template-columns: 1fr !important; + gap: 8px !important; + } + .ecosystem-row > div:first-child { + padding-top: 0 !important; + } +} +@media (prefers-reduced-motion: reduce) { + [data-ui="ecosystem-tile"]:hover { + transform: none; + } +} + +/* Promises — components/landing/Promises.tsx */ +.promises-intro { + text-align: center; + margin-bottom: 56px; +} +.promises-eyebrow { + margin-bottom: 16px; +} +.promises-heading { + font-family: var(--font-garamond); + font-size: var(--text-h2); + line-height: var(--text-h2--line-height); + font-weight: 700; + color: var(--color-text-primary); + margin: 0; + margin-bottom: 12px; + letter-spacing: -0.015em; +} +.promises-subhead { + font-family: var(--font-inter); + font-size: var(--text-body-lg); + line-height: var(--text-body-lg--line-height); + color: var(--color-text-secondary); + margin: 0; +} +.promises-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 16px; + max-width: 1100px; + margin: 0 auto; +} +.promises-card-title { + font-family: var(--font-inter); + font-size: 17px; + line-height: 1.3; + font-weight: 600; + color: var(--color-text-primary); + margin: 0; + margin-bottom: 8px; +} +.promises-card-body { + font-family: var(--font-inter); + font-size: 14px; + line-height: var(--text-body--line-height); + color: var(--color-text-secondary); + margin: 0; +} + +/* RecentArticles — components/landing/RecentArticles.tsx */ +.recent-articles-header { + margin-bottom: 32px; +} +.recent-articles-eyebrow { + margin-bottom: 16px; +} +.recent-articles-heading { + font-family: var(--font-garamond); + font-size: var(--text-h2); + line-height: var(--text-h2--line-height); + font-weight: 700; + letter-spacing: -0.015em; + color: var(--color-text-primary); + margin: 0; +} +.recent-articles-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 16px; +} +.recent-articles-footer { + margin-top: 32px; + text-align: center; +} +.recent-articles-link { + color: var(--color-accent); + font-weight: 500; + text-decoration: none; +} + +/* FinalCTA — components/landing/FinalCTA.tsx */ +.final-cta-inner { + max-width: 720px; + margin: 0 auto; + text-align: center; +} +.final-cta-heading { + font-family: var(--font-garamond); + font-size: var(--text-h2); + line-height: var(--text-h2--line-height); + font-weight: 700; + color: var(--color-text-primary); + margin: 0; + margin-bottom: 16px; + letter-spacing: -0.015em; + font-style: italic; +} +.final-cta-subtext { + font-family: var(--font-inter); + font-size: var(--text-body-lg); + line-height: var(--text-body-lg--line-height); + color: var(--color-text-secondary); + margin: 0; + margin-bottom: 32px; +} +.final-cta-row { + display: flex; + justify-content: center; + gap: 12px; + flex-wrap: wrap; + margin-bottom: 16px; +} +.final-cta-caption { + font-family: var(--font-inter); + font-size: var(--text-caption); + color: var(--color-text-muted); + margin: 0; +} + +/* HomeFAQ — components/landing/HomeFAQ.tsx */ +.home-faq-intro { + text-align: center; + margin-bottom: 48px; +} +.home-faq-eyebrow { + margin-bottom: 16px; +} +.home-faq-heading { + font-family: var(--font-garamond); + font-size: var(--text-h2); + line-height: var(--text-h2--line-height); + font-weight: 700; + color: var(--color-text-primary); + margin: 0; + letter-spacing: -0.015em; +} +.home-faq-body { + max-width: 800px; + margin: 0 auto; +} + +/* BackendsGrid — components/landing/ag-ui/BackendsGrid.tsx */ +.backends-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); + gap: 10px; + padding: 16px; + background: var(--color-surface-tinted); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); +} +.backends-grid-item { + padding: 14px 14px; + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + display: flex; + flex-direction: column; + gap: 4px; +} +.backends-grid-name { + font-family: Inter, system-ui, sans-serif; + font-size: 14px; + font-weight: 600; + color: var(--color-text-primary); +} +.backends-grid-note { + font-family: "JetBrains Mono", monospace; + font-size: 11px; + color: var(--color-text-muted); +} + From e58d278c6c77dbc667364b4274a996f28c57d64b Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sat, 29 Aug 2026 14:36:00 -0700 Subject: [PATCH 3/3] refactor(website): move demo and code-showcase landing styles to landing.css --- .../src/components/landing/DemoModal.tsx | 53 +-- .../src/components/landing/DemoShowcase.tsx | 20 +- .../components/landing/HighlightedCode.tsx | 2 +- .../chat-landing/ChatLandingCodeShowcase.tsx | 38 +- .../langgraph/LangGraphCodeShowcase.tsx | 38 +- .../landing/render/RenderCodeShowcase.tsx | 38 +- apps/website/src/styles/landing.css | 358 ++++++++++++++++++ 7 files changed, 404 insertions(+), 143 deletions(-) diff --git a/apps/website/src/components/landing/DemoModal.tsx b/apps/website/src/components/landing/DemoModal.tsx index c45311cec..ef53861d1 100644 --- a/apps/website/src/components/landing/DemoModal.tsx +++ b/apps/website/src/components/landing/DemoModal.tsx @@ -1,7 +1,6 @@ // apps/website/src/components/landing/DemoModal.tsx 'use client'; import { useEffect, useRef } from 'react'; -import { tokens } from '@threadplane/design-tokens'; import { trackExternalLinkClick } from '../../lib/analytics/client'; type TabKey = 'langgraph' | 'ag-ui'; @@ -62,67 +61,39 @@ export function DemoModal({ open, onClose, tabs, active, onActive }: DemoModalPr aria-modal="true" aria-label="Live demo" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }} - style={{ - position: 'fixed', inset: 0, zIndex: 100, - display: 'flex', alignItems: 'center', justifyContent: 'center', - background: 'rgba(16,18,32,.55)', - animation: 'demoModalBackdrop .16s ease-out', - }} + className="demo-modal" > - -
-
-