Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
393 changes: 373 additions & 20 deletions website/app/(home)/styles/home.css

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions website/app/(home)/styles/shell.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
inset: 0;
z-index: 60;
pointer-events: none;
opacity: 0.04;
opacity: 0.02;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
background-size: 180px 180px;
}
Expand Down Expand Up @@ -332,8 +332,8 @@
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--accent);
box-shadow: 0 0 10px var(--accent);
background: var(--pop);
box-shadow: 0 0 10px var(--pop);
}
.site-root .section-title {
font-size: clamp(1.7rem, 1.1rem + 1.8vw, 2.6rem);
Expand Down Expand Up @@ -411,7 +411,7 @@
/* ── Footer ──────────────────────────────────────────────────────────── */
.site-footer {
flex-shrink: 0;
margin-top: clamp(60px, 6vw, 110px);
margin-top: clamp(36px, 3.5vw, 64px);
border-top: 1px solid var(--border);
background: color-mix(in srgb, var(--surface) 50%, transparent);
}
Expand Down
263 changes: 151 additions & 112 deletions website/app/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
@source '../components';

/* ════════════════════════════════════════════════════════════════════════
"The Case File" — a detective/inspector identity for RepoLens.
Leads LIGHT (warm manila + ink), with an amber/brass lens-glint accent and a
detective red for risk. Dark survives as a warm "night stakeout" (.dark), not
a cold terminal. next-themes flips .dark; tokens drive marketing + docs.
RepoLens — "Inspector" identity, bright & alive.
Leads LIGHT on a clean cool near-white (no warmth — brown reads cheap), with
near-black ink, a VIVID blue lead, a cyan scanner glint, and a hot-coral pop
for life. Green = FIT, red = RISK. Dark is a cool slate complement, not a
warm noir and not an AI terminal. next-themes flips .dark; tokens drive all.
──────────────────────────────────────────────────────────────────────── */

:root {
Expand All @@ -25,120 +26,158 @@
/* the stamp's heavy "slam" */
--ease-stamp: cubic-bezier(0.5, 1.8, 0.4, 0.95);

/* Amber/brass lens-glint accent + detective red. One ramp tuned for paper;
.dark brightens it for the night-stakeout surfaces. */
--accent: #9e530e;
--accent-2: #934a0c;
--accent-3: #d9822b;
--grad: linear-gradient(120deg, #d9822b 0%, #9e530e 60%, #934a0c 120%);
--grad-soft: linear-gradient(120deg, #d9822b, #9e530e);
--accent-glow: rgba(179, 94, 16, 0.35);
--accent-weak: rgba(179, 94, 16, 0.1);
--accent-line: rgba(179, 94, 16, 0.28);
/* Vivid blue lead + cyan scanner glint + hot-coral pop. Green=FIT, red=RISK.
.dark recasts these brighter on cool slate. */
--accent: #2563ff;
--accent-2: #1d4ed8;
--accent-3: #06b6d4;
--glint: #06b6d4;
--grad: linear-gradient(120deg, #06b6d4 0%, #2563ff 58%, #1d4ed8 120%);
--grad-soft: linear-gradient(120deg, #3b82f6, #2563ff);
--accent-glow: rgba(37, 99, 255, 0.3);
--accent-weak: rgba(37, 99, 255, 0.08);
--accent-line: rgba(37, 99, 255, 0.22);

/* warm = the amber CTA; red = the RISKY stamp / red flags */
--warm: #c2691c;
--warm-2: #d9822b;
--warm-ink: #2a1605;
--warm-glow: rgba(194, 105, 28, 0.4);
--warm-weak: rgba(194, 105, 28, 0.12);
--warm-line: rgba(194, 105, 28, 0.34);
--red: #c0392b;
--red-weak: rgba(192, 57, 43, 0.12);
/* warm = the primary CTA (vivid→deep blue, white text); pop = hot-coral life */
--warm: #2563ff;
--warm-2: #1d4ed8;
--warm-ink: #ffffff;
--warm-glow: rgba(37, 99, 255, 0.38);
--warm-weak: rgba(37, 99, 255, 0.1);
--warm-line: rgba(37, 99, 255, 0.26);
--pop: #ff5a5f;
--pop-weak: rgba(255, 90, 95, 0.12);
--pop-line: rgba(255, 90, 95, 0.34);
--red: #e5484d;
--red-weak: rgba(229, 72, 77, 0.12);

/* Case Filewarm manila paper, sepia ink */
--bg: #f4ead4;
--bg-2: #ecdfc2;
--surface: #fbf5e7;
--surface-2: #f5ecd6;
--border: #ddccab;
--border-2: #c8b285;
--text: #2a2114;
--text-strong: #17110a;
--sub: #5d5034;
--muted: #756544;
--faint: #a89571;
--ok: #2c7631;
--info: #1d6fa3;
--warn: #b4690a;
--bad: #c0392b;
--shadow-lg: 0 26px 70px -34px rgba(60, 42, 16, 0.38);
--shadow-md: 0 16px 38px -22px rgba(60, 42, 16, 0.3);
--paper-grain: 0.5;
/* Clean papercool near-white, ink near-black */
--bg: #f7f9fd;
--bg-2: #eef2f9;
--surface: #ffffff;
--surface-2: #f9fbfe;
--border: #e3e8f2;
--border-2: #ccd6e6;
--text: #1b2230;
--text-strong: #0b0e14;
--sub: #495264;
--muted: #6b7384;
--faint: #97a0b2;
--ok: #16a34a;
--info: #2563ff;
--warn: #06b6d4;
--bad: #e5484d;
--shadow-lg: 0 28px 64px -30px rgba(15, 30, 70, 0.3);
--shadow-md: 0 16px 38px -22px rgba(15, 30, 70, 0.22);
--paper-grain: 0;

/* fumadocs remap → Case File light */
--color-fd-background: #f4ead4;
--color-fd-foreground: #2a2114;
--color-fd-muted: #ecdfc2;
--color-fd-muted-foreground: #6a5c3d;
--color-fd-popover: #fbf5e7;
--color-fd-popover-foreground: #17110a;
--color-fd-card: #fbf5e7;
--color-fd-card-foreground: #17110a;
--color-fd-border: #ddccab;
--color-fd-primary: #9e530e;
--color-fd-primary-foreground: #fbf5e7;
--color-fd-secondary: #efe3ca;
--color-fd-secondary-foreground: #2a2114;
--color-fd-accent: #ecdfc2;
--color-fd-accent-foreground: #17110a;
--color-fd-ring: #9e530e;
/* fumadocs remap → bright light */
--color-fd-background: #f7f9fd;
--color-fd-foreground: #1b2230;
--color-fd-muted: #eef2f9;
--color-fd-muted-foreground: #6b7384;
--color-fd-popover: #ffffff;
--color-fd-popover-foreground: #0b0e14;
--color-fd-card: #ffffff;
--color-fd-card-foreground: #0b0e14;
--color-fd-border: #e3e8f2;
--color-fd-primary: #2563ff;
--color-fd-primary-foreground: #ffffff;
--color-fd-secondary: #eef2f9;
--color-fd-secondary-foreground: #1b2230;
--color-fd-accent: #e8eeff;
--color-fd-accent-foreground: #0b0e14;
--color-fd-ring: #2563ff;
}

.dark {
/* Night Stakeout — warm noir, not a cold terminal */
--bg: #1b1610;
--bg-2: #221b12;
--surface: #2a2116;
--surface-2: #32281a;
--border: #43361f;
--border-2: #5e4b2c;
--text: #ece1cd;
--text-strong: #fff8ec;
--sub: #c3b094;
--muted: #9c8a6a;
--faint: #6f6045;
/* Cool slate complement — clean dark, not a warm noir, not an AI terminal */
--bg: #0b0f17;
--bg-2: #121826;
--surface: #151c2b;
--surface-2: #1b2336;
--border: #283146;
--border-2: #3a4358;
--text: #e6ebf3;
--text-strong: #ffffff;
--sub: #aeb6c4;
--muted: #7f8799;
--faint: #596173;

/* brighter amber + red read better on the warm-dark surfaces */
--accent: #e0934a;
--accent-2: #cf7a2a;
--accent-3: #f0aa63;
--grad: linear-gradient(120deg, #f0aa63 0%, #e0934a 60%, #cf7a2a 120%);
--grad-soft: linear-gradient(120deg, #f0aa63, #e0934a);
--accent-glow: rgba(224, 147, 74, 0.45);
--accent-weak: rgba(224, 147, 74, 0.14);
--accent-line: rgba(224, 147, 74, 0.32);
--warm: #e0934a;
--warm-2: #f0aa63;
--warm-ink: #2a1605;
--warm-glow: rgba(224, 147, 74, 0.45);
--warm-weak: rgba(224, 147, 74, 0.16);
--warm-line: rgba(224, 147, 74, 0.36);
--red: #e06a5c;
--red-weak: rgba(224, 106, 92, 0.16);
--ok: #5cc05f;
--info: #56b6e8;
--warn: #e0a341;
--bad: #e06a5c;
--shadow-lg: 0 26px 70px -34px rgba(0, 0, 0, 0.72);
--shadow-md: 0 16px 44px -26px rgba(0, 0, 0, 0.66);
--paper-grain: 0.7;
/* brighter blue + cyan + coral on the slate surfaces */
--accent: #5a8cff;
--accent-2: #3b6ef0;
--accent-3: #34d6e8;
--glint: #34d6e8;
--grad: linear-gradient(120deg, #34d6e8 0%, #5a8cff 58%, #3b6ef0 120%);
--grad-soft: linear-gradient(120deg, #6f9bff, #5a8cff);
--accent-glow: rgba(90, 140, 255, 0.45);
--accent-weak: rgba(90, 140, 255, 0.16);
--accent-line: rgba(90, 140, 255, 0.32);
--warm: #5a8cff;
--warm-2: #4f86ff;
--warm-ink: #06122a;
--warm-glow: rgba(90, 140, 255, 0.5);
--warm-weak: rgba(90, 140, 255, 0.18);
--warm-line: rgba(90, 140, 255, 0.36);
--pop: #ff6b70;
--pop-weak: rgba(255, 107, 112, 0.16);
--pop-line: rgba(255, 107, 112, 0.4);
--red: #ff6b6b;
--red-weak: rgba(255, 107, 107, 0.16);
--ok: #3ecf7e;
--info: #5a8cff;
--warn: #34d6e8;
--bad: #ff6b6b;
--shadow-lg: 0 28px 64px -30px rgba(0, 0, 0, 0.72);
--shadow-md: 0 16px 44px -26px rgba(0, 0, 0, 0.62);
--paper-grain: 0;

/* fumadocs remap → night stakeout */
--color-fd-background: #1b1610;
--color-fd-foreground: #ece1cd;
--color-fd-muted: #2a2116;
--color-fd-muted-foreground: #c3b094;
--color-fd-popover: #221b12;
--color-fd-popover-foreground: #ece1cd;
--color-fd-card: #2a2116;
--color-fd-card-foreground: #ece1cd;
--color-fd-border: #43361f;
--color-fd-primary: #e0934a;
--color-fd-primary-foreground: #1b1610;
--color-fd-secondary: #32281a;
--color-fd-secondary-foreground: #ece1cd;
--color-fd-accent: #322619;
--color-fd-accent-foreground: #fff8ec;
--color-fd-ring: #e0934a;
/* fumadocs remap → cool dark */
--color-fd-background: #0b0f17;
--color-fd-foreground: #e6ebf3;
--color-fd-muted: #151c2b;
--color-fd-muted-foreground: #aeb6c4;
--color-fd-popover: #121826;
--color-fd-popover-foreground: #e6ebf3;
--color-fd-card: #151c2b;
--color-fd-card-foreground: #e6ebf3;
--color-fd-border: #283146;
--color-fd-primary: #5a8cff;
--color-fd-primary-foreground: #06122a;
--color-fd-secondary: #1b2336;
--color-fd-secondary-foreground: #e6ebf3;
--color-fd-accent: #1c2740;
--color-fd-accent-foreground: #ffffff;
--color-fd-ring: #5a8cff;
}

/* ════════════════════════════════════════════════════════════════════════
Theme snap — toggling the theme fires a quick white "screenshot" flash that
masks an instant swap, like snapping a photo of the repo (see snapToTheme in
lib/themeSnap.ts). One fading overlay, GPU-cheap — no full-page snapshot, so
no lag. Reduced-motion skips the flash (snapToTheme does a plain instant flip).
──────────────────────────────────────────────────────────────────────── */
.theme-flash {
position: fixed;
inset: 0;
z-index: 9999;
pointer-events: none;
background: #ffffff;
opacity: 0;
will-change: opacity;
}
.theme-flash.is-on {
animation: theme-snap 440ms ease-out forwards;
}
@keyframes theme-snap {
0% {
opacity: 0;
}
16% {
opacity: 0.92;
}
100% {
opacity: 0;
}
}
8 changes: 4 additions & 4 deletions website/app/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions website/components/home/Hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ export function Hero() {
<div className="container hero-grid">
<div className="hero-copy">
<span className="kicker">
<span className="pulse" /> Chrome Extension · Manifest V3 · v3.0
<span className="pulse" /> Case No. RL-3.0 · Chrome · Manifest V3
</span>

<h1 id="hero-heading" className="hero-title">
Read code before
<br />
you <span className="grad-text">trust it.</span>
you <span className="hero-mark">trust it.</span>
</h1>

<p className="hero-sub">
Expand Down
14 changes: 9 additions & 5 deletions website/components/home/HeroMascot.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { useEffect, useState } from 'react';
import { useEffect, useRef, useState } from 'react';

// Static assets live in public/ and are NOT auto-prefixed with the GitHub
// Pages basePath the way next/link is — so we prefix the <video>/<img> src by hand.
Expand All @@ -15,18 +15,21 @@ const CAPTIONS = [
const ALT = 'Vee, the RepoLens mascot, peering through a lens';

/**
* The hero mascot: an autoplaying, muted, looping clip of Vee in a framed
* stage. Under reduced-motion we show the poster frame instead — no autoplay,
* no loop — and the caption stops rotating.
* The hero mascot: an autoplaying, muted clip of Vee in a framed stage. The clip
* is a boomerang (forward → reversed) so it loops with no seam, eased slightly
* for a smoother feel. Under reduced-motion we show the poster frame instead —
* no autoplay, no loop — and the caption stops rotating.
*/
export function HeroMascot() {
const [reduced, setReduced] = useState(false);
const [i, setI] = useState(0);
const videoRef = useRef<HTMLVideoElement>(null);

useEffect(() => {
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
setReduced(reduce);
if (reduce) return;
if (videoRef.current) videoRef.current.playbackRate = 0.85;
const id = setInterval(() => setI((n) => (n + 1) % CAPTIONS.length), 3400);
return () => clearInterval(id);
}, []);
Expand All @@ -39,6 +42,7 @@ export function HeroMascot() {
<img src={`${BASE}/mascot-poster.jpg`} alt={ALT} width={230} height={270} />
) : (
<video
ref={videoRef}
className="hero-mascot-vid"
autoPlay
muted
Expand All @@ -49,7 +53,7 @@ export function HeroMascot() {
width={230}
height={270}
>
<source src={`${BASE}/mascot.mp4`} type="video/mp4" />
<source src={`${BASE}/mascot-loop.mp4`} type="video/mp4" />
</video>
)}
</div>
Expand Down
Loading
Loading