Restyle the UI: instrument-panel palette, type system, and a signal accent

Replaces the default shadcn grayscale/Geist look with a deliberate
identity built around the product's own subject - a control panel for
running scripts and watching their output live:

- Type: Bricolage Grotesque for page/card titles (via the existing
  --font-heading token, used with restraint), IBM Plex Sans for UI body
  text, IBM Plex Mono for technical data (run IDs, commands, timestamps,
  status labels) - all self-hosted at build time via next/font/google,
  no runtime CDN dependency for a self-hosted tool.
- Color: a cool graphite ink/paper base with a warm brass signal accent
  in both themes. The brass tone doubles as the "running" status color,
  so an active run literally lights the UI up with the brand color.
  New --status-* tokens give queued/running/succeeded/failed/cancelled/
  warn a single source of truth instead of ad-hoc Tailwind color classes.
- Structural language: small tracked-out uppercase mono labels mark
  technical fields (Command, Variables, Triggered by...) consistently;
  the live-output terminal gets an instrument-bezel frame (header bar +
  panel) instead of floating loose above the xterm canvas.

Layout/IA is unchanged throughout - this is a token- and detail-level
pass, not a restructuring.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-16 11:44:30 +02:00
co-authored by Claude Sonnet 5
parent f102ace7e8
commit 7e1569b94c
12 changed files with 176 additions and 117 deletions
+16 -6
View File
@@ -1,18 +1,28 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import { Bricolage_Grotesque, IBM_Plex_Mono, IBM_Plex_Sans } from "next/font/google";
import { ThemeProvider } from "next-themes";
import { TooltipProvider } from "@/components/ui/tooltip";
import { Toaster } from "@/components/ui/sonner";
import "./globals.css";
const geistSans = Geist({
variable: "--font-geist-sans",
// Display face for page titles and card headings (wired via --font-heading in globals.css) - used
// with restraint, never for body copy. Body/UI text and technical data (run IDs, commands,
// timestamps) share the IBM Plex family so the two registers still read as one system.
const displayFont = Bricolage_Grotesque({
variable: "--font-display",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
const sansFont = IBM_Plex_Sans({
variable: "--font-sans",
subsets: ["latin"],
weight: ["400", "500", "600", "700"],
});
const monoFont = IBM_Plex_Mono({
variable: "--font-mono",
subsets: ["latin"],
weight: ["400", "500", "600"],
});
export const metadata: Metadata = {
@@ -31,7 +41,7 @@ export default function RootLayout({
return (
<html
lang="en"
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
className={`${displayFont.variable} ${sansFont.variable} ${monoFont.variable} h-full antialiased`}
suppressHydrationWarning
>
<body