From db369f0fded5d51296d6ae1374a15b70f3bb6f1b Mon Sep 17 00:00:00 2001 From: RomeoCavazza Date: Sun, 7 Jun 2026 00:41:44 +0200 Subject: [PATCH 1/2] fix(build): restore Tailwind PostCSS pipeline --- postcss.config.mjs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 postcss.config.mjs diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000..61e3684 --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; From 2be3c1337b749d5389ab2f1c5af08039e89c4fec Mon Sep 17 00:00:00 2001 From: RomeoCavazza Date: Sun, 7 Jun 2026 00:41:53 +0200 Subject: [PATCH 2/2] feat(landing): refine hero composition and signal cards --- src/components/sections/FeatureGrid.tsx | 10 +--- src/components/sections/HeroSection.tsx | 58 ++++++++++---------- src/components/ui/display-cards.tsx | 70 +++++++++++++++---------- 3 files changed, 73 insertions(+), 65 deletions(-) diff --git a/src/components/sections/FeatureGrid.tsx b/src/components/sections/FeatureGrid.tsx index 3f7a50c..96a39c7 100644 --- a/src/components/sections/FeatureGrid.tsx +++ b/src/components/sections/FeatureGrid.tsx @@ -25,17 +25,9 @@ export function FeatureGrid() {
-

- About OpsWarden -

- The command room for incidents, releases, and shared operational context. + Coordinate faster under pressure.

-

- OpsWarden is built for teams that need one operational surface, not - five disconnected ones. The goal is simple: less context loss, less - handoff friction, and faster resolution under pressure. -

diff --git a/src/components/sections/HeroSection.tsx b/src/components/sections/HeroSection.tsx index 7ed54a5..fc7c57e 100644 --- a/src/components/sections/HeroSection.tsx +++ b/src/components/sections/HeroSection.tsx @@ -14,35 +14,42 @@ export function HeroSection() { className="pointer-events-none absolute left-1/2 top-10 -z-10 h-[480px] w-[820px] -translate-x-1/2 rounded-full bg-[radial-gradient(ellipse_at_center,rgba(251,192,45,0.10),transparent_60%)] blur-[70px]" /> - {/* Copy — on top */} -
-

- Ship fearlessly, resolve instantly. -

+
+
+
+

+ + Ship fearlessly, + + + resolve instantly. + +

-

- OpsWarden coordinates your incidents and releases in real time — with an - AI SRE{' '} -
- that proposes the root cause and the runbook, straight in the incident - timeline. -

+

+ OpsWarden coordinates your incidents and releases in real time — with an AI + SRE that proposes the root cause and the runbook, straight in the incident + timeline. +

-
- - Start now - +
+ + Start now + +
+
+ +
+ +
{/* Faux app window — below */} -
-
- -
+
-
- Incident timeline - Release-aware - AI runbooks -
); diff --git a/src/components/ui/display-cards.tsx b/src/components/ui/display-cards.tsx index d2aba2a..27de38e 100644 --- a/src/components/ui/display-cards.tsx +++ b/src/components/ui/display-cards.tsx @@ -1,5 +1,3 @@ -"use client"; - import React from "react"; import { cn } from "@/lib/utils"; import { Bot, GitBranch, ShieldAlert } from "lucide-react"; @@ -14,7 +12,6 @@ interface DisplayCardProps { } function DisplayCard({ - className, icon = , title = "Featured", description = "Discover amazing content", @@ -22,51 +19,43 @@ function DisplayCard({ titleClassName = "text-gold", }: DisplayCardProps) { return ( -
*]:flex [&>*]:items-center [&>*]:gap-2", - className - )} - > -
- +
+
+ {icon} -

{title}

+

{title}

+ {date}
-

{description}

-

{date}

+

+ {description} +

); } // Applied to the product: incidents, releases, AI SRE. +// Order matters — this reads top→bottom as the AI-SRE story. const PRODUCT_CARDS: DisplayCardProps[] = [ { icon: , title: "Incident opened", - description: "API latency spike detected on eu-west.", + description: "API latency spike on eu-west.", date: "2 min ago", titleClassName: "text-[#ff8c69]", - className: - "[grid-area:stack] -translate-x-8 -translate-y-6 rotate-[-6deg] hover:-translate-y-10", }, { icon: , title: "AI hypothesis", - description: "Likely root cause: database connection saturation.", + description: "Root cause: DB connection saturation.", date: "Now", - className: - "[grid-area:stack] translate-x-3 translate-y-8 rotate-[4deg] hover:-translate-y-1", }, { icon: , title: "Runbook attached", - description: "Rollback checkout-worker and drain stuck jobs.", + description: "Rollback checkout-worker, drain jobs.", date: "Suggested", titleClassName: "text-[#8ad5a3]", - className: - "[grid-area:stack] translate-x-16 translate-y-20 rotate-[10deg] hover:translate-y-12", }, ]; @@ -74,14 +63,39 @@ interface DisplayCardsProps { cards?: DisplayCardProps[]; } +// Stacked-deck cascade. Each card is OPAQUE so the one in front cleanly +// occludes the one behind (no text bleed). z grows with index so the deck +// reads top→bottom while every card's header + description stays visible; +// the front card only ever covers the bottom padding of the card behind it. +// Rear cards are nudged + scaled for depth, so it reads as a deck, not a list. +const LAYERS = [ + { top: "0rem", x: "1.25rem", scale: 0.955, z: 10, opacity: 0.9 }, + { top: "4.5rem", x: "0.625rem", scale: 0.978, z: 20, opacity: 0.96 }, + { top: "9rem", x: "0rem", scale: 1, z: 30, opacity: 1 }, +]; + export default function DisplayCards({ cards }: DisplayCardsProps) { - const displayCards = cards || PRODUCT_CARDS; + const baseCards = cards || PRODUCT_CARDS; return ( -
- {displayCards.map((cardProps, index) => ( - - ))} +
+ {baseCards.map((card, index) => { + const layer = LAYERS[index] ?? LAYERS[LAYERS.length - 1]; + return ( +
+ +
+ ); + })}
); }