diff --git a/app/globals.css b/app/globals.css index 44371d21..e2362483 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,6 +1,10 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import "tailwindcss"; + +/* Explicit source roots for Tailwind v4. Auto-detection misses files when + Turbopack's workspace root is ambiguous (e.g. shell cwd differs from the + web project root), so we pin the scan paths here. */ +@source "../components/**/*.{ts,tsx}"; +@source "../app/**/*.{ts,tsx}"; :root { --surface-0: #09090b; @@ -17,11 +21,11 @@ --code-border: #27272a; } -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} +/* Note: no `* { margin: 0; padding: 0; box-sizing: border-box; }` here. + Tailwind v4's Preflight (included by `@import "tailwindcss"`) already + resets margins on block elements and sets border-box globally. An + unlayered `*` selector would beat Tailwind's `@layer utilities` and + silently break every margin utility (mb-*, mt-*, mx-*, etc.). */ html { font-size: 16px; @@ -37,14 +41,19 @@ body { overflow-x: hidden; } -a { - color: var(--brand); - text-decoration: none; - transition: color 150ms cubic-bezier(0.16, 1, 0.3, 1); -} +/* Default link color. Wrapped in @layer base so Tailwind utilities + (text-white, text-zinc-*, etc.) in @layer utilities still win. An + unlayered `a { color: ... }` would silently override utilities. */ +@layer base { + a { + color: var(--brand); + text-decoration: none; + transition: color 150ms cubic-bezier(0.16, 1, 0.3, 1); + } -a:hover { - color: var(--text-primary); + a:hover { + color: var(--text-primary); + } } code { diff --git a/components/Hero.tsx b/components/Hero.tsx index d5281e3f..039f091c 100644 --- a/components/Hero.tsx +++ b/components/Hero.tsx @@ -1,16 +1,65 @@ +"use client"; + +import { useEffect, useState } from "react"; + +// Rotating taglines — Slot 3 above the hero sub (ELF-457, brief ELF-456). +// Order matters: index 0 is the default and the initial server-rendered string. +const TAGLINES = [ + "Inspect any request. Mock any response.", + "Your HTTP bin, on your machine.", + "Send. Capture. Mock. No signup.", +] as const; + +// Per-tagline dwell. 3.5s gives ~2.8s solid visibility after the 700ms crossfade. +const ROTATE_MS = 3500; + export default function Hero() { + const [index, setIndex] = useState(0); + + useEffect(() => { + // Respect prefers-reduced-motion at the JS layer too: don't start a timer + // for users who opt out. The fade is independently suppressed via the + // motion-reduce: variant on the
class below.
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
+ const id = window.setInterval(() => {
+ setIndex((i) => (i + 1) % TAGLINES.length);
+ }, ROTATE_MS);
+ return () => window.clearInterval(id);
+ }, []);
+
return (
+ {t}
+
One Go binary. SQLite under the hood.
Self-hostable HTTP request
-
+
+ {/* Slot 3: rotating tagline. Fixed-height container prevents CLS; subtle
+ opacity crossfade so it doesn't compete with the terminal CTA below.
+ a11y: aria-live polite + aria-hidden on inactive items. */}
+
inspector + mocker
diff --git a/next.config.ts b/next.config.ts
index 1f6f6ced..519c8e35 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -1,9 +1,17 @@
import type { NextConfig } from "next";
+import path from "node:path";
const nextConfig: NextConfig = {
images: {
unoptimized: true,
},
+ // Pin the Turbopack workspace root to this directory. Without this, Turbopack
+ // infers it from the shell's cwd, which during Paperclip agent runs is the
+ // paperclip project root — that misroutes CSS/source scanning and silently
+ // strips Tailwind utility classes from the production bundle.
+ turbopack: {
+ root: path.resolve(import.meta.dirname),
+ },
};
export default nextConfig;