feat: lab-terminal theme + new logo

Adopt the Hangman Lab visual language (adapted from the Gitea
STYLE.md, Gitea-only mechanics excluded):

- New acid SVG mark as favicon (?v cache-bust) and navbar logo.
- Single acid accent (#d8ff3e); retune globals.css tokens to the
  ink/panel/line/text/dim/danger palette; drop the cyan/violet pair
  (secondary -> same acid so existing components stay on-brand).
- Fonts: IBM Plex Mono for body/UI/mono, Major Mono Display for the
  lowercase brand lockup; Tailwind fontFamily + content fonts updated.
- Site-wide fixed 48px blueprint-grid backdrop + one acid sheen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
h z
2026-05-17 14:05:16 +01:00
parent 117a1385ab
commit cbac2b0771
7 changed files with 115 additions and 56 deletions

View File

@@ -0,0 +1,44 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 733.000000 733.000000" role="img" aria-label="Hangman Lab">
<g transform="translate(0.000000,733.000000) scale(0.100000,-0.100000)"
fill="#d8ff3e" stroke="none">
<path d="M812 6860 c-66 -40 -73 -66 -70 -242 3 -141 5 -159 24 -185 43 -58
63 -63 262 -64 l182 -1 0 -2694 0 -2694 -290 0 c-314 0 -332 -3 -380 -54 -24
-27 -25 -32 -28 -199 -3 -195 4 -218 71 -250 32 -16 257 -17 3084 -17 2955 0
3049 1 3083 19 65 34 75 66 75 236 0 186 -16 224 -104 254 -25 8 -682 11
-2512 11 l-2479 0 0 1998 0 1997 698 697 697 697 670 -3 c369 -2 680 -4 693
-5 22 -1 22 -1 22 -269 l0 -268 84 -12 c47 -7 103 -19 125 -27 41 -14 41 -14
43 283 l3 297 631 1 c698 2 673 -1 714 67 18 28 20 51 20 187 0 173 -8 201
-72 240 -33 20 -56 20 -2623 20 -2567 0 -2590 0 -2623 -20z m1725 -500 c-1 -3
-183 -185 -404 -404 l-403 -399 0 405 0 406 405 -1 c223 -1 404 -4 402 -7z
M4283 5701 c-459 -125 -690 -624 -483 -1046 67 -138 196 -266 335 -335 281
-139 612 -93 837 118 235 219 297 575 152 870 -85 174 -235 306 -427 375 -111
40 -302 48 -414 18z m267 -211 c95 -15 201 -70 274 -144 273 -274 173 -723
-189 -851 -93 -33 -236 -35 -326 -5 -202 68 -340 249 -356 465 -18 242 153
471 394 529 71 18 119 19 203 6z M5945 4716 c-56 -25 -80 -61 -80 -122 0 -48
4 -57 36 -90 88 -88 219 -29 219 98 0 45 -34 96 -75 114 -42 17 -61 17 -100 0z
M5675 4466 c-60 -26 -73 -109 -26 -157 62 -61 161 -19 161 70 0 74 -68 118
-135 87z M3747 4397 c-10 -7 -226 -223 -479 -482 -307 -313 -467 -483 -479
-510 -35 -75 -17 -177 38 -227 39 -35 114 -61 160 -54 100 13 104 17 583 554
l145 162 3 -404 c3 -455 15 -342 -137 -1186 -76 -423 -101 -587 -101 -664 0
-190 182 -307 377 -242 62 21 136 95 152 152 6 22 29 188 52 369 57 466 109
839 118 848 4 4 52 6 106 5 l99 -3 67 -210 c38 -115 68 -220 69 -232 0 -12
-38 -152 -85 -311 -47 -159 -85 -302 -85 -317 0 -128 109 -225 255 -225 109 1
185 42 228 125 26 51 237 683 237 710 0 11 -54 182 -121 380 -121 360 -121
360 -134 605 -8 135 -14 292 -14 350 l0 105 152 -158 c84 -87 166 -167 182
-177 44 -29 98 -26 135 8 38 35 187 379 173 401 -5 8 -34 20 -64 26 -59 11
-38 -8 -393 362 -89 93 -100 97 -174 59 -59 -30 -161 -62 -229 -71 -52 -7 -53
-7 -53 -41 0 -44 -21 -84 -61 -118 -38 -32 -41 0 32 -455 l52 -325 -82 -78
c-45 -43 -85 -78 -89 -78 -4 0 -42 35 -84 78 l-77 77 34 215 c19 118 46 289
61 379 26 164 26 164 -5 188 -42 33 -54 58 -61 121 -5 54 -5 54 -92 87 -98 38
-184 89 -243 145 -76 70 -123 87 -168 57z M5504 4170 c-74 -30 -69 -170 6
-170 19 0 20 -7 20 -123 0 -122 0 -122 -54 -262 -30 -77 -97 -243 -150 -369
-106 -252 -113 -287 -73 -347 46 -70 38 -69 560 -69 327 0 475 3 490 11 69 35
107 109 88 172 -5 17 -62 142 -126 277 -225 470 -215 443 -215 586 0 114 2
124 18 124 57 0 72 101 23 151 -29 29 -29 29 -298 28 -147 0 -278 -4 -289 -9z
m376 -307 c1 -148 1 -148 81 -333 101 -231 98 -222 68 -216 -13 3 -116 22
-229 42 -112 19 -208 37 -212 40 -4 2 18 75 48 160 54 156 54 156 54 305 l0
149 95 0 95 0 0 -147z m-219 -593 c22 0 49 -42 49 -75 0 -46 -29 -75 -74 -75
-37 0 -76 36 -76 71 0 46 45 94 78 83 8 -2 18 -4 23 -4z m327 -126 c53 -59 -7
-144 -80 -113 -54 22 -65 83 -22 125 30 31 67 27 102 -12z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -5,11 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="dark"> <meta name="color-scheme" content="dark">
<title>Hangman Lab</title> <title>Hangman Lab</title>
<link rel="icon" type="image/png" href="./icons/logo.png"> <link rel="icon" type="image/svg+xml" href="./icons/hangman-lab-logo.svg?v=hl-20260517">
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link <link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap" href="https://fonts.googleapis.com/css2?family=Major+Mono+Display&family=IBM+Plex+Mono:ital,wght@0,400;0,500;0,600;1,400&display=swap"
rel="stylesheet" rel="stylesheet"
/> />
</head> </head>

View File

@@ -12,7 +12,7 @@
} }
code { code {
font-family: ui-monospace, "JetBrains Mono", "Courier New", Courier, monospace; font-family: ui-monospace, "IBM Plex Mono", "Courier New", Courier, monospace;
background-color: hsl(var(--muted)); background-color: hsl(var(--muted));
color: hsl(var(--foreground)); color: hsl(var(--foreground));
padding: 2px 6px; padding: 2px 6px;

View File

@@ -34,7 +34,7 @@
.markdown-preview h4, .markdown-preview h4,
.markdown-preview h5, .markdown-preview h5,
.markdown-preview h6 { .markdown-preview h6 {
font-family: "JetBrains Mono", ui-monospace, monospace; font-family: "IBM Plex Mono", ui-monospace, monospace;
font-weight: 600; font-weight: 600;
color: hsl(var(--foreground)); color: hsl(var(--foreground));
line-height: 1.3; line-height: 1.3;
@@ -108,7 +108,7 @@
/* Inline code */ /* Inline code */
.markdown-preview :not(pre) > code { .markdown-preview :not(pre) > code {
font-family: "JetBrains Mono", ui-monospace, monospace; font-family: "IBM Plex Mono", ui-monospace, monospace;
font-size: 0.85em; font-size: 0.85em;
background-color: hsl(var(--muted)); background-color: hsl(var(--muted));
color: hsl(var(--primary)); color: hsl(var(--primary));
@@ -128,7 +128,7 @@
box-shadow: inset 0 0 40px -20px hsl(var(--primary) / 0.25); box-shadow: inset 0 0 40px -20px hsl(var(--primary) / 0.25);
} }
.markdown-preview pre code { .markdown-preview pre code {
font-family: "JetBrains Mono", ui-monospace, monospace; font-family: "IBM Plex Mono", ui-monospace, monospace;
font-size: 0.85rem; font-size: 0.85rem;
background: transparent; background: transparent;
border: none; border: none;
@@ -150,7 +150,7 @@
} }
.markdown-preview th { .markdown-preview th {
background-color: hsl(var(--muted)); background-color: hsl(var(--muted));
font-family: "JetBrains Mono", ui-monospace, monospace; font-family: "IBM Plex Mono", ui-monospace, monospace;
font-size: 0.8rem; font-size: 0.8rem;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;

View File

@@ -124,13 +124,13 @@ const MainNavigation = () => {
className="group flex items-center gap-2.5 pr-3" className="group flex items-center gap-2.5 pr-3"
> >
<img <img
src="/icons/logo.png" src="/icons/hangman-lab-logo.svg"
alt="Logo" alt="Hangman Lab"
className="h-7 w-7 rounded" className="h-7 w-7"
/> />
<span className="font-mono text-sm font-semibold tracking-tight"> <span className="font-display text-base leading-none tracking-tight">
<span className="text-foreground">HANGMAN</span> <span className="text-foreground">hangman</span>
<span className="neon-text">//LAB</span> <span className="neon-text"> lab</span>
</span> </span>
</Link> </Link>

View File

@@ -2,37 +2,40 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
/* Dark-tech design tokens (single dark theme). HSL triplets so Tailwind /* Lab-terminal theme — adapted from the Gitea STYLE.md for this React app.
color utilities and shadcn-style primitives resolve via hsl(var(--x)). */ Single acid accent (#d8ff3e), dark blueprint surfaces, monospace UI.
HSL triplets so Tailwind / shadcn-style primitives resolve hsl(var(--x)). */
:root, :root,
.dark { .dark {
--background: 222 32% 6%; --background: 216 24% 4%; /* #080a0d ink */
--foreground: 210 22% 92%; --foreground: 217 35% 86%; /* #cdd8e8 text */
--surface: 222 28% 8.5%; --surface: 214 29% 8%; /* #0f141b panel */
--card: 222 26% 9.5%; --card: 214 29% 8%;
--card-foreground: 210 22% 92%; --card-foreground: 217 38% 95%; /* #e9f0fa strong text */
--muted: 222 20% 14%; --muted: 214 27% 12%; /* hovered panel */
--muted-foreground: 215 16% 60%; --muted-foreground: 216 18% 48%; /* #647691 dim / eyebrow */
--accent: 222 24% 13%; --accent: 214 27% 11%; /* row/element hover wash base */
--accent-foreground: 210 22% 92%; --accent-foreground: 217 35% 86%;
--border: 220 18% 18%; --border: 213 28% 16%; /* #1d2733 lines / dividers */
--input: 220 18% 16%; --input: 213 28% 14%;
--ring: 186 92% 56%; --ring: 72 100% 62%; /* acid focus ring */
/* cyan primary, violet secondary — the neon accents */ /* THE accent — one acid, used for links/primary/active/focus. */
--primary: 186 92% 56%; --primary: 72 100% 62%; /* #d8ff3e */
--primary-foreground: 222 47% 6%; --primary-foreground: 96 24% 5%; /* #0c0f08 text on acid */
--secondary: 258 90% 68%; /* No second hue (STYLE: "one acid"). Secondary == acid so any
--secondary-foreground: 0 0% 100%; component using it stays on-brand. */
--secondary: 72 100% 62%;
--secondary-foreground: 96 24% 5%;
--destructive: 0 72% 56%; --destructive: 3 100% 66%; /* #ff5a52 errors only */
--destructive-foreground: 0 0% 100%; --destructive-foreground: 0 0% 100%;
--radius: 0.5rem; --radius: 0.75rem;
} }
* { * {
@@ -45,25 +48,35 @@ body,
height: 100%; height: 100%;
} }
html {
background-color: hsl(var(--background));
}
body { body {
margin: 0; margin: 0;
background-color: hsl(var(--background)); background-color: transparent;
color: hsl(var(--foreground)); color: hsl(var(--foreground));
font-family: Inter, ui-sans-serif, system-ui, sans-serif; font-family: "IBM Plex Mono", ui-monospace, SFMono-Regular, monospace;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
} }
/* Ambient grid + glow backdrop for the app shell */ /* Site-wide blueprint grid backdrop (STYLE §11.2): fixed, behind content,
48px #1d2733 lines at low opacity, radial-masked, plus one acid sheen. */
body::before { body::before {
content: ""; content: "";
position: fixed; position: fixed;
inset: 0; inset: 0;
z-index: -1;
pointer-events: none; pointer-events: none;
z-index: 0; background-color: hsl(var(--background));
background: background-image:
radial-gradient(60rem 60rem at 110% -10%, hsl(258 90% 68% / 0.10), transparent 60%), radial-gradient(1000px 560px at 78% -8%, hsl(72 100% 62% / 0.10), transparent 60%),
radial-gradient(50rem 50rem at -10% 110%, hsl(186 92% 56% / 0.08), transparent 60%); linear-gradient(hsl(213 28% 16% / 0.16) 1px, transparent 1px),
linear-gradient(90deg, hsl(213 28% 16% / 0.16) 1px, transparent 1px);
background-size: 100% 100%, 48px 48px, 48px 48px;
-webkit-mask-image: radial-gradient(ellipse 90% 80% at 50% 30%, #000 55%, transparent 100%);
mask-image: radial-gradient(ellipse 90% 80% at 50% 30%, #000 55%, transparent 100%);
} }
::selection { ::selection {
@@ -71,7 +84,6 @@ body::before {
color: hsl(var(--foreground)); color: hsl(var(--foreground));
} }
/* Slim techy scrollbars */
* { * {
scrollbar-width: thin; scrollbar-width: thin;
scrollbar-color: hsl(var(--border)) transparent; scrollbar-color: hsl(var(--border)) transparent;
@@ -89,16 +101,24 @@ body::before {
} }
@layer utilities { @layer utilities {
/* Display lockup font — always lowercase per STYLE §3. */
.font-display {
font-family: "Major Mono Display", "IBM Plex Mono", monospace;
text-transform: lowercase;
}
.neon-text { .neon-text {
color: hsl(var(--primary)); color: hsl(var(--primary));
text-shadow: 0 0 12px hsl(var(--primary) / 0.55); text-shadow: 0 0 44px hsl(var(--primary) / 0.38);
} }
/* kept for compatibility with components that used the old violet
accent — now the same single acid. */
.neon-text-violet { .neon-text-violet {
color: hsl(var(--secondary)); color: hsl(var(--primary));
text-shadow: 0 0 12px hsl(var(--secondary) / 0.55); text-shadow: 0 0 44px hsl(var(--primary) / 0.38);
} }
.glass { .glass {
background: hsl(var(--surface) / 0.7); background: hsl(214 29% 8% / 0.55);
backdrop-filter: blur(10px); backdrop-filter: blur(16px) saturate(150%);
border: 1px solid hsl(var(--primary) / 0.16);
} }
} }

View File

@@ -42,15 +42,10 @@ module.exports = {
sm: "calc(var(--radius) - 4px)", sm: "calc(var(--radius) - 4px)",
}, },
fontFamily: { fontFamily: {
sans: ["Inter", "ui-sans-serif", "system-ui", "sans-serif"], // Lab-terminal: IBM Plex Mono is the body/UI/mono face.
mono: [ sans: ["IBM Plex Mono", "ui-monospace", "SFMono-Regular", "monospace"],
"JetBrains Mono", mono: ["IBM Plex Mono", "ui-monospace", "SFMono-Regular", "monospace"],
"Fira Code", display: ["Major Mono Display", "IBM Plex Mono", "monospace"],
"ui-monospace",
"SFMono-Regular",
"Menlo",
"monospace",
],
}, },
boxShadow: { boxShadow: {
glow: "0 0 0 1px hsl(var(--primary) / 0.25), 0 0 24px -6px hsl(var(--primary) / 0.45)", glow: "0 0 0 1px hsl(var(--primary) / 0.25), 0 0 24px -6px hsl(var(--primary) / 0.45)",