Align the platform look and feel with the devplace.net terminal design

Retheme every token in variables.css to the terminal design language:
near-black surfaces (#0a0a0f/#111118/#1a1a24), terminal green accent
(#22c55e) with dark on-accent text, gray text ramp, #222233 borders,
sharp 4-8px radii, neutral depth shadows, and JetBrains Mono as the
primary UI font (vendored latin woff2, no CDN).

Follow-through outside the token file: white-on-accent buttons/tabs now
use the new --on-accent token for contrast, three var() fallback
violations shipping the old palette are gone, the dead --bg-hover token
is replaced with --bg-card-hover, avatar fallback SVG, statistics chart
palette, chat light-theme overrides, offline page, PWA manifest,
theme-color meta, OG image + app icons regenerated in the new palette,
and the /docs/styles-colors style guide now documents the new values.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
blindxfish 2026-08-09 20:55:46 +02:00
parent 1a5fc9428a
commit c19ff19de2
36 changed files with 189 additions and 140 deletions

View File

@ -28,6 +28,6 @@ def generate_avatar_svg(seed: str) -> str:
initial = seed[:1].upper() if seed else "?"
return (
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">'
f'<rect width="100" height="100" rx="50" fill="#ff6b35"/>'
f'<text x="50" y="65" text-anchor="middle" fill="white" font-size="40" font-weight="700" font-family="sans-serif">{initial}</text></svg>'
f'<rect width="100" height="100" rx="50" fill="#22c55e"/>'
f'<text x="50" y="65" text-anchor="middle" fill="#052e16" font-size="40" font-weight="700" font-family="sans-serif">{initial}</text></svg>'
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -205,14 +205,14 @@
}
.admin-btn-primary {
background: var(--accent, var(--info));
color: var(--white);
background: var(--accent);
color: var(--on-accent);
border-color: transparent;
}
.admin-btn-primary:hover {
background: var(--accent-hover, var(--accent));
color: var(--white);
background: var(--accent-hover);
color: var(--on-accent);
}
.admin-btn-danger {
@ -399,7 +399,7 @@
.pagination-btn:hover {
background: var(--accent);
color: var(--white);
color: var(--on-accent);
border-color: var(--accent);
text-decoration: none;
}
@ -443,12 +443,12 @@
.pagination-page-active {
background: var(--accent);
color: var(--white);
color: var(--on-accent);
}
.pagination-page-active:hover {
background: var(--accent-hover);
color: var(--white);
color: var(--on-accent);
}
.pagination-ellipsis {

View File

@ -117,7 +117,7 @@
font-size: 1rem;
font-weight: 700;
background: var(--accent);
color: var(--white);
color: var(--on-accent);
border-radius: var(--radius);
}

View File

@ -445,8 +445,8 @@ img {
.btn-primary {
background: var(--accent-gradient);
color: var(--white);
box-shadow: 0 2px 12px rgba(255, 95, 70, 0.3);
color: var(--on-accent);
box-shadow: 0 0 0 1px rgba(var(--accent-rgb), 0.35);
}
.btn-primary:hover {
@ -554,7 +554,7 @@ img {
justify-content: center;
font-weight: 700;
font-size: 1rem;
color: var(--white);
color: var(--on-accent);
flex-shrink: 0;
overflow: hidden;
}
@ -589,7 +589,7 @@ img {
pointer-events: none;
}
.presence-dot.online { background: var(--success, #2f9e44); }
.presence-dot.online { background: var(--success); }
.award-badge {
position: absolute;
@ -650,7 +650,7 @@ img {
.nav-bell { position: relative; display: inline-flex; align-items: center; justify-content: center; line-height: 1; }
.nav-badge {
position: absolute; top: -6px; right: -8px; z-index: 1; min-width: 16px; height: 16px;
padding: 0 0.25rem; border-radius: 8px; background: var(--accent); color: var(--white);
padding: 0 0.25rem; border-radius: 8px; background: var(--accent); color: var(--on-accent);
font-size: 0.6875rem; font-weight: 700;
display: flex; align-items: center; justify-content: center;
}
@ -884,7 +884,7 @@ img {
button.comment-form-submit {
padding: 0.375rem 0.5rem;
background: var(--accent);
color: var(--white);
color: var(--on-accent);
font-weight: 600;
font-size: 0.8125rem;
line-height: 1.4;

View File

@ -232,7 +232,7 @@ dp-chat[mode="embed"] {
.message-bubble.mine {
align-self: flex-end;
background: var(--accent);
color: var(--white);
color: var(--on-accent);
border-bottom-right-radius: 4px;
}
@ -429,7 +429,7 @@ dp-chat[mode="embed"] {
height: 36px;
padding: 0;
background: var(--accent);
color: var(--white);
color: var(--on-accent);
border-radius: 50%;
display: flex;
align-items: center;

View File

@ -209,7 +209,7 @@
.cm-suggest li:hover,
.cm-suggest li.cm-suggest-active {
background: var(--bg-hover, var(--border));
background: var(--bg-card-hover);
}
.cm-suggest li.cm-suggest-active {

View File

@ -241,7 +241,7 @@
.ds-phase.is-done .ds-phase-dot {
background: var(--accent);
border-color: var(--accent);
color: var(--white);
color: var(--on-accent);
}
.ds-phase.is-done .ds-phase-name {
@ -546,7 +546,7 @@ dp-deepsearch-chat {
.ds-chat-msg.user .ds-chat-bubble {
background: var(--accent);
color: var(--white);
color: var(--on-accent);
}
.ds-chat-msg.agent .ds-chat-bubble {
@ -597,7 +597,7 @@ dp-deepsearch-chat {
.ds-chat-send {
background: var(--accent);
color: var(--white);
color: var(--on-accent);
border: none;
border-radius: var(--radius-input);
padding: 0 var(--space-md);

View File

@ -292,7 +292,7 @@ dp-docs-chat {
.docs-chat-send {
background: var(--accent);
color: var(--white);
color: var(--on-accent);
border: none;
border-radius: var(--radius);
padding: 0.625rem 1.25rem;

View File

@ -431,7 +431,7 @@ textarea.param-input {
.format-option.active {
background: var(--accent);
color: var(--white);
color: var(--on-accent);
}
.format-fixed {
@ -621,7 +621,7 @@ pre.code-pre > .code-gutter {
.docs-search-snippet mark {
background: var(--accent);
color: var(--white);
color: var(--on-accent);
padding: 0 0.125rem;
border-radius: 3px;
}

View File

@ -39,7 +39,7 @@
.feed-nav-btn.active {
background: var(--accent-gradient);
color: var(--white);
color: var(--on-accent);
box-shadow: var(--glow-accent);
}
@ -285,7 +285,7 @@
min-width: 1.25rem;
padding: 0 0.375rem;
border-radius: 999px;
background: var(--success, #2f9e44);
background: var(--success);
color: var(--white);
font-size: 0.6875rem;
text-align: center;
@ -369,7 +369,7 @@
height: 64px;
border-radius: 50%;
background: var(--accent-gradient);
color: var(--white);
color: var(--on-accent);
font-size: 2rem;
line-height: 1;
display: flex;

View File

@ -35,11 +35,11 @@
text-decoration: none;
}
.issues-filter:hover {
background: var(--bg-hover);
background: var(--bg-card-hover);
}
.issues-filter.active {
background: var(--accent);
color: var(--white);
color: var(--on-accent);
border-color: var(--accent);
}
.issues-modal-hint {

View File

@ -70,7 +70,7 @@
.dashboard-btn-primary {
background: var(--accent);
color: var(--white);
color: var(--on-accent);
border-color: var(--accent);
font-weight: 700;
padding: 0.55rem 1.5rem;
@ -123,7 +123,7 @@
.dashboard-xp-fill {
height: 100%;
background: var(--accent-gradient, linear-gradient(90deg, var(--accent), #f0932b));
background: var(--accent-gradient);
border-radius: 3px;
transition: width 0.4s ease;
}
@ -466,7 +466,7 @@
font-size: 1.125rem;
border-radius: var(--radius-lg);
background: var(--accent);
color: var(--white);
color: var(--on-accent);
font-weight: 700;
}
@ -567,7 +567,7 @@
padding: 0.7rem 2rem;
border-radius: var(--radius-lg);
background: var(--accent);
color: var(--white);
color: var(--on-accent);
font-size: 0.9375rem;
font-weight: 700;
}
@ -637,7 +637,7 @@
.landing-xp-fill {
height: 100%;
background: var(--accent-gradient, linear-gradient(90deg, var(--accent), #f0932b));
background: var(--accent-gradient);
border-radius: 3px;
transition: width 0.4s ease;
}
@ -970,7 +970,7 @@
margin-top: auto;
align-self: flex-start;
background: var(--accent);
color: var(--white);
color: var(--on-accent);
border: none;
border-radius: var(--radius-lg);
padding: 0.6rem 1.1rem;
@ -1105,7 +1105,7 @@
font-size: 1.05rem;
border-radius: var(--radius-lg);
background: var(--accent);
color: var(--white);
color: var(--on-accent);
font-weight: 700;
text-decoration: none;
transition: filter 0.15s ease, transform 0.15s ease;

View File

@ -257,7 +257,7 @@
font-size: 0.875rem;
font-weight: 600;
background: var(--accent);
color: var(--white);
color: var(--on-accent);
border-radius: var(--radius);
}

View File

@ -49,7 +49,7 @@
}
.profile-presence.online {
color: var(--success, #2f9e44);
color: var(--success);
}
.profile-presence::before {
@ -64,7 +64,7 @@
}
.profile-presence.online::before {
background: var(--success, #2f9e44);
background: var(--success);
}
.profile-stats {
@ -231,7 +231,7 @@ a.profile-stat-value:hover {
.profile-tab.active {
background: var(--accent);
color: var(--white);
color: var(--on-accent);
}
.profile-posts {
@ -464,7 +464,7 @@ a.profile-stat-value:hover {
}
.ai-correction-status[data-state="success"] {
color: var(--success, #2f9e44);
color: var(--success);
}
.ai-correction-status[data-state="error"] {

View File

@ -100,7 +100,7 @@
.pf-node-row.active {
background: var(--accent);
color: var(--white);
color: var(--on-accent);
}
.pf-node-row.pf-selected {
@ -110,7 +110,7 @@
.pf-node-row.pf-selected.active {
background: var(--accent);
color: var(--white);
color: var(--on-accent);
}
.pf-node-row.pf-dragging {

View File

@ -28,7 +28,7 @@
.projects-tab.active {
background: var(--accent-gradient);
color: var(--white);
color: var(--on-accent);
box-shadow: var(--glow-accent);
}

View File

@ -77,7 +77,7 @@
.sidebar-link.active,
.sidebar-link.active:hover {
background: var(--accent-gradient);
color: var(--white);
color: var(--on-accent);
font-weight: 600;
box-shadow: var(--glow-accent);
}

View File

@ -1,41 +1,42 @@
/* retoor <retoor@molodetz.nl> */
:root {
--bg-primary: #080413;
--bg-secondary: #120821;
--bg-card: #1a1030;
--bg-card-hover: #241640;
--bg-input: #140b26;
--bg-modal: #1a1030;
--bg-primary: #0a0a0f;
--bg-secondary: #111118;
--bg-card: #111118;
--bg-card-hover: #1a1a24;
--bg-input: #0a0a0f;
--bg-modal: #111118;
--accent: #ff6b35;
--accent-rgb: 255, 107, 53;
--accent-hover: #ff7d4d;
--accent-light: rgba(255, 107, 53, 0.12);
--accent-2: #ff4f8b;
--accent-gradient: linear-gradient(135deg, #ff6b3d, #ff4f6d);
--accent: #22c55e;
--accent-rgb: 34, 197, 94;
--accent-hover: #16a34a;
--accent-light: rgba(34, 197, 94, 0.12);
--accent-2: #4ade80;
--accent-gradient: linear-gradient(135deg, #22c55e, #16a34a);
--on-accent: #052e16;
--text-primary: #f4eefb;
--text-secondary: #b8a8d0;
--text-muted: #7a6a90;
--text-primary: #c8c8d0;
--text-secondary: #8b8b9e;
--text-muted: #6b6b80;
--border: rgba(255, 255, 255, 0.08);
--border-light: rgba(255, 255, 255, 0.14);
--border: #222233;
--border-light: #2e2e40;
--success: #4caf50;
--warning: #ff9800;
--danger: #e53935;
--info: #42a5f5;
--success: #22c55e;
--warning: #eab308;
--danger: #ef4444;
--info: #60a5fa;
--radius: 12px;
--radius-input: 14px;
--radius-lg: 18px;
--radius-xl: 24px;
--radius: 4px;
--radius-input: 4px;
--radius-lg: 6px;
--radius-xl: 8px;
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.25);
--shadow: 0 4px 20px rgba(0, 0, 0, 0.28);
--shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.45);
--glow-accent: 0 6px 24px rgba(255, 95, 70, 0.45);
--shadow-sm: 0 0 0 1px rgba(34, 34, 51, 0.8);
--shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
--shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.6);
--glow-accent: 0 0 0 1px rgba(var(--accent-rgb), 0.35);
--white: #fff;
--overlay-dark: rgba(0, 0, 0, 0.7);
@ -48,8 +49,8 @@
--space-xl: 1.5rem;
--space-2xl: 2rem;
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--font-mono: "SF Mono", Monaco, "Cascadia Code", monospace;
--font-sans: "JetBrains Mono", "SF Mono", ui-monospace, Menlo, Consolas, monospace;
--font-mono: "JetBrains Mono", "SF Mono", Monaco, "Cascadia Code", monospace;
--nav-height: 56px;
--sidebar-width: 240px;
@ -76,5 +77,5 @@
--topic-fun: #ffab00;
--topic-politics: #00bcd4;
--bg-gradient: linear-gradient(135deg, #080413 0%, #160a28 50%, #080413 100%);
--bg-gradient: linear-gradient(135deg, #0a0a0f 0%, #111118 50%, #0a0a0f 100%);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -1,14 +1,14 @@
// retoor <retoor@molodetz.nl>
const CHART_COLORS = [
"#ff6b35",
"#22c55e",
"#7c4dff",
"#00bfa5",
"#448aff",
"#ffab00",
"#ff5252",
"#42a5f5",
"#ff4f8b",
"#4ade80",
];
export class StatisticsCharts {

View File

@ -24,15 +24,15 @@ const SEARCH_DEBOUNCE_MS = 200;
const AUTO_GROW_MAX_HEIGHT_PX = 160;
const LIGHT_THEME_OVERRIDES = {
"--bg-primary": "#f5f3fa",
"--bg-primary": "#f1f5f9",
"--bg-secondary": "#ffffff",
"--bg-card": "#ffffff",
"--bg-card-hover": "#f0edf7",
"--text-primary": "#1a1030",
"--text-secondary": "#4a3f5c",
"--text-muted": "#8b7fa0",
"--border": "rgba(0, 0, 0, 0.1)",
"--border-light": "rgba(0, 0, 0, 0.16)",
"--bg-card-hover": "#e2e8f0",
"--text-primary": "#0f172a",
"--text-secondary": "#475569",
"--text-muted": "#64748b",
"--border": "#cbd5e1",
"--border-light": "#e2e8f0",
};
export class AppChat extends Component {

View File

@ -9,8 +9,8 @@
"orientation": "any",
"lang": "en",
"dir": "ltr",
"background_color": "#0f0a1a",
"theme_color": "#0f0a1a",
"background_color": "#0a0a0f",
"theme_color": "#0a0a0f",
"icons": [
{
"src": "/static/icon-192.png",

View File

@ -7,11 +7,11 @@
<title>Offline - DevPlace</title>
<style>
:root {
--bg-primary: #0f0a1a;
--bg-card: #221436;
--accent: #ff6b35;
--text-primary: #f0e8f8;
--text-muted: #9a8db0;
--bg-primary: #0a0a0f;
--bg-card: #111118;
--accent: #22c55e;
--text-primary: #c8c8d0;
--text-muted: #6b6b80;
}
* { box-sizing: border-box; }
body {
@ -22,21 +22,21 @@
justify-content: center;
background: var(--bg-primary);
color: var(--text-primary);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
font-family: "JetBrains Mono", "SF Mono", ui-monospace, Menlo, Consolas, monospace;
padding: 1.5rem;
}
.offline-card {
max-width: 360px;
text-align: center;
background: var(--bg-card);
border-radius: 16px;
border-radius: 6px;
padding: 2.5rem 2rem;
}
.offline-mark {
width: 72px;
height: 72px;
margin: 0 auto 1.25rem;
border-radius: 16px;
border-radius: 6px;
background: var(--accent);
color: var(--bg-primary);
font-size: 2.75rem;
@ -49,7 +49,7 @@
background: var(--accent);
color: var(--bg-primary);
border: none;
border-radius: 8px;
border-radius: 4px;
padding: 0.75rem 1.5rem;
font-size: 1rem;
font-weight: 600;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -1,13 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630" viewBox="0 0 1200 630">
<rect width="1200" height="630" fill="#0f0a1a"/>
<rect width="1200" height="630" fill="#0a0a0f"/>
<rect x="0" y="0" width="1200" height="630" fill="url(#g)"/>
<defs>
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#ff6b35" stop-opacity="0.15"/>
<stop offset="100%" stop-color="#1a1028" stop-opacity="0"/>
<stop offset="0%" stop-color="#22c55e" stop-opacity="0.12"/>
<stop offset="100%" stop-color="#111118" stop-opacity="0"/>
</linearGradient>
</defs>
<text x="600" y="280" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="96" font-weight="800" fill="#f0e8f8">DevPlace</text>
<text x="600" y="370" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="36" fill="#b8a8d0">The Developer Social Network</text>
<circle cx="600" cy="480" r="8" fill="#ff6b35"/>
<text x="600" y="300" text-anchor="middle" font-family="'JetBrains Mono', 'SF Mono', Menlo, monospace" font-size="104" font-weight="800" fill="#22c55e">DevPlace</text>
<rect x="440" y="334" width="320" height="8" fill="#22c55e"/>
<text x="600" y="412" text-anchor="middle" font-family="'JetBrains Mono', 'SF Mono', Menlo, monospace" font-size="34" fill="#8b8b9e">The Developer Social Network</text>
<circle cx="600" cy="484" r="8" fill="#22c55e"/>
</svg>

Before

Width:  |  Height:  |  Size: 832 B

After

Width:  |  Height:  |  Size: 897 B

View File

@ -0,0 +1,46 @@
/* JetBrains Mono (latin) - vendored from @fontsource/jetbrains-mono 5.2.5 (SIL OFL 1.1) */
@font-face {
font-family: "JetBrains Mono";
font-style: normal;
font-display: swap;
font-weight: 400;
src: url(./jetbrains-mono-latin-400-normal.woff2) format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: "JetBrains Mono";
font-style: italic;
font-display: swap;
font-weight: 400;
src: url(./jetbrains-mono-latin-400-italic.woff2) format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: "JetBrains Mono";
font-style: normal;
font-display: swap;
font-weight: 500;
src: url(./jetbrains-mono-latin-500-normal.woff2) format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: "JetBrains Mono";
font-style: normal;
font-display: swap;
font-weight: 600;
src: url(./jetbrains-mono-latin-600-normal.woff2) format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: "JetBrains Mono";
font-style: normal;
font-display: swap;
font-weight: 700;
src: url(./jetbrains-mono-latin-700-normal.woff2) format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View File

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta name="theme-color" content="#0f0a1a">
<meta name="theme-color" content="#0a0a0f">
<meta name="asset-version" content="{{ static_version }}">
<title>{% if page_title %}{{ page_title }}{% else %}DevPlace - The Developer Social Network{% endif %}</title>
<meta name="description" content="{% if meta_description %}{{ meta_description }}{% else %}Track industry shifts. Discover bold releases. Share what you're building in an open environment built by developers, for developers.{% endif %}">
@ -42,6 +42,7 @@
<link rel="modulepreload" href="{{ static_url('/static/js/Application.js') }}">
<link rel="modulepreload" href="{{ static_url('/static/js/components/index.js') }}">
<link rel="stylesheet" href="{{ static_url('/static/vendor/fonts/jetbrains-mono.css') }}">
<link rel="stylesheet" href="{{ static_url('/static/css/variables.css') }}">
<link rel="stylesheet" href="{{ static_url('/static/css/base.css') }}">
<link rel="stylesheet" href="{{ static_url('/static/css/components.css') }}">

View File

@ -8,7 +8,7 @@ The palette is defined once, as CSS custom properties on `:root` in `static/css/
DevPlace is kept open for hours, often at night. The theme is therefore **dark, low-glare, and deliberately quiet**: deep violet-black backgrounds, soft lavender text, and a *single* warm accent.
- **One accent, used sparingly.** A single orange (`--accent`, `#ff6b35`) marks what matters: the primary action, the active navigation item, links, and the current vote. Because nothing else competes for it, the accent always means "act on this". A second strong colour used decoratively breaks it.
- **One accent, used sparingly.** A single terminal green (`--accent`, `#22c55e`) marks what matters: the primary action, the active navigation item, links, and the current vote. Because nothing else competes for it, the accent always means "act on this". A second strong colour used decoratively breaks it.
- **Backgrounds layer by elevation.** A near-black page sits behind slightly lighter cards, behind a lighter hover state. Depth comes from these few background steps plus a soft shadow, not from borders alone.
- **Text is a three-step hierarchy.** Primary for content, secondary for supporting text, muted for metadata. There is no fourth shade.
- **Colour with meaning is reserved.** Status colours (success, warning, danger, info) and topic colours carry semantics. They never "brighten up" a layout.
@ -19,20 +19,20 @@ Layered from the page backdrop up to interactive surfaces.
| Token | Value | Use it for | Do not |
|-------|-------|-----------|--------|
| `--bg-primary` | `#080413` | The page backdrop (`body`). | Put cards or inputs directly on it without a surface token. |
| `--bg-secondary` | `#120821` | The top nav, dropdowns, the mobile panel, demo frames. | Use as a card body in the content area. |
| `--bg-card` | `#1a1030` | Cards, panels, the standard content surface. | Use for the page backdrop. |
| `--bg-card-hover` | `#241640` | Hover state of cards, list rows, and ghost buttons. | Use as a resting background. |
| `--bg-input` | `#140b26` | Inputs, textareas, selects. | Use as a content card surface. |
| `--bg-modal` | `#1a1030` | Modal card body. | Use outside modals. |
| `--bg-primary` | `#0a0a0f` | The page backdrop (`body`). | Put cards or inputs directly on it without a surface token. |
| `--bg-secondary` | `#111118` | The top nav, dropdowns, the mobile panel, demo frames. | Use as a card body in the content area. |
| `--bg-card` | `#111118` | Cards, panels, the standard content surface. | Use for the page backdrop. |
| `--bg-card-hover` | `#1a1a24` | Hover state of cards, list rows, and ghost buttons. | Use as a resting background. |
| `--bg-input` | `#0a0a0f` | Inputs, textareas, selects. | Use as a content card surface. |
| `--bg-modal` | `#111118` | Modal card body. | Use outside modals. |
| `--bg-gradient` | violet gradient | Large hero / landing surfaces only. | Apply to small components. |
## Accent
| Token | Value | Use it for | Do not |
|-------|-------|-----------|--------|
| `--accent` | `#ff6b35` | The single primary action, active nav link, links, the voted star, focus border. | A second decorative colour, large fills, or more than one primary action per view. |
| `--accent-hover` | `#ff7d4d` | Hover state of accent surfaces and links. | Resting state. |
| `--accent` | `#22c55e` | The single primary action, active nav link, links, the voted star, focus border. | A second decorative colour, large fills, or more than one primary action per view. |
| `--accent-hover` | `#16a34a` | Hover state of accent surfaces and links. | Resting state. |
| `--accent-light` | `rgba(255,107,53,.12)` | The tinted background behind an *active* nav item or self-highlight row. | Body text (too low contrast). |
| `--accent-rgb` | `255, 107, 53` | Composing any other accent tint: `rgba(var(--accent-rgb), 0.3)`. | Writing `rgba(255, 107, 53, ...)` literally anywhere. |
@ -42,19 +42,19 @@ A strict three-step hierarchy. Never introduce a fourth text shade.
| Token | Value | Use it for |
|-------|-------|-----------|
| `--text-primary` | `#f4eefb` | Headings and body content. |
| `--text-secondary` | `#b8a8d0` | Supporting copy, labels, secondary buttons. |
| `--text-muted` | `#7a6a90` | Timestamps, counts, hints, metadata. |
| `--text-primary` | `#c8c8d0` | Headings and body content. |
| `--text-secondary` | `#8b8b9e` | Supporting copy, labels, secondary buttons. |
| `--text-muted` | `#6b6b80` | Timestamps, counts, hints, metadata. |
## Borders, radius, and shadow
| Token | Value | Use it for |
|-------|-------|-----------|
| `--border` | `rgba(255,255,255,.08)` | The default hairline on cards, inputs, dividers. |
| `--border-light` | `rgba(255,255,255,.14)` | Hover/emphasis borders. |
| `--radius` | `12px` | Buttons, inputs, small controls. |
| `--radius-lg` | `18px` | Cards and panels. |
| `--radius-xl` | `24px` | Large feature surfaces. |
| `--border` | `#222233` | The default hairline on cards, inputs, dividers. |
| `--border-light` | `#2e2e40` | Hover/emphasis borders. |
| `--radius` | `4px` | Buttons, inputs, small controls. |
| `--radius-lg` | `6px` | Cards and panels. |
| `--radius-xl` | `8px` | Large feature surfaces. |
| `--shadow-sm` / `--shadow` / `--shadow-lg` | (shadows) | Card hover, raised panels, modals respectively. |
## Status colours (semantic only)
@ -63,10 +63,10 @@ These encode meaning and must only be used to convey it.
| Token | Value | Means |
|-------|-------|-------|
| `--success` | `#4caf50` | Success, healthy, online. |
| `--warning` | `#ff9800` | Caution; also the colour of a cast vote star. |
| `--danger` | `#e53935` | Errors, destructive actions, the create-post button. |
| `--info` | `#42a5f5` | Neutral information. |
| `--success` | `#22c55e` | Success, healthy, online. |
| `--warning` | `#eab308` | Caution; also the colour of a cast vote star. |
| `--danger` | `#ef4444` | Errors, destructive actions, the create-post button. |
| `--info` | `#60a5fa` | Neutral information. |
## Topic colours (badges only)
@ -83,7 +83,7 @@ Used exclusively for topic badges (`.badge-devlog`, `.badge-showcase`, …) and
## Rules
1. **Never hardcode a colour.** Use the token: `color: var(--text-secondary)`, never `color: #b8a8d0`. If a value is missing, add a token to `variables.css` rather than inlining a hex. Accent tints at other alphas compose the channel token: `rgba(var(--accent-rgb), 0.3)`.
1. **Never hardcode a colour.** Use the token: `color: var(--text-secondary)`, never `color: #8b8b9e`. If a value is missing, add a token to `variables.css` rather than inlining a hex. Accent tints at other alphas compose the channel token: `rgba(var(--accent-rgb), 0.3)`.
2. **Never give a global token a fallback.** Write `var(--accent)`, never `var(--accent, #hex)`. A fallback silently masks a dead or misspelled token: the page keeps rendering, but from a value nobody maintains.
3. **Feature palettes are file-scoped token blocks.** A page with its own semantic palette (the Devii terminal, the AI-usage grades) defines it once as custom properties at the top of its own stylesheet (`devii.css` scopes `--devii-*` on `devii-terminal`; `isslop.css` scopes `--isslop-*` on `:root`) and references only those below. Raw hex values may exist in exactly two places: `variables.css` and these file-scoped blocks.
4. **One accent per view.** Exactly one primary action should carry `--accent`. Everything else is `--btn-secondary`/ghost.
@ -124,20 +124,20 @@ The reference below is rendered live from the tokens, so it always reflects the
<div class="component-demo">
<div class="component-demo-title">Live palette</div>
<div class="sg-swatch-grid">
<div class="sg-swatch"><span class="sg-chip sg-chip-bg-primary"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--bg-primary</span><span class="sg-swatch-hex">#080413</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-bg-secondary"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--bg-secondary</span><span class="sg-swatch-hex">#120821</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-bg-card"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--bg-card</span><span class="sg-swatch-hex">#1a1030</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-bg-card-hover"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--bg-card-hover</span><span class="sg-swatch-hex">#241640</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-accent"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--accent</span><span class="sg-swatch-hex">#ff6b35</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-accent-hover"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--accent-hover</span><span class="sg-swatch-hex">#ff7d4d</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-text-primary"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--text-primary</span><span class="sg-swatch-hex">#f4eefb</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-text-secondary"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--text-secondary</span><span class="sg-swatch-hex">#b8a8d0</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-text-muted"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--text-muted</span><span class="sg-swatch-hex">#7a6a90</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-bg-primary"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--bg-primary</span><span class="sg-swatch-hex">#0a0a0f</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-bg-secondary"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--bg-secondary</span><span class="sg-swatch-hex">#111118</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-bg-card"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--bg-card</span><span class="sg-swatch-hex">#111118</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-bg-card-hover"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--bg-card-hover</span><span class="sg-swatch-hex">#1a1a24</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-accent"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--accent</span><span class="sg-swatch-hex">#22c55e</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-accent-hover"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--accent-hover</span><span class="sg-swatch-hex">#16a34a</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-text-primary"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--text-primary</span><span class="sg-swatch-hex">#c8c8d0</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-text-secondary"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--text-secondary</span><span class="sg-swatch-hex">#8b8b9e</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-text-muted"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--text-muted</span><span class="sg-swatch-hex">#6b6b80</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-border"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--border</span><span class="sg-swatch-hex">rgba(255,255,255,.08)</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-success"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--success</span><span class="sg-swatch-hex">#4caf50</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-warning"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--warning</span><span class="sg-swatch-hex">#ff9800</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-danger"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--danger</span><span class="sg-swatch-hex">#e53935</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-info"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--info</span><span class="sg-swatch-hex">#42a5f5</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-success"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--success</span><span class="sg-swatch-hex">#22c55e</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-warning"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--warning</span><span class="sg-swatch-hex">#eab308</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-danger"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--danger</span><span class="sg-swatch-hex">#ef4444</span></span></div>
<div class="sg-swatch"><span class="sg-chip sg-chip-info"></span><span class="sg-swatch-info"><span class="sg-swatch-name">--info</span><span class="sg-swatch-hex">#60a5fa</span></span></div>
</div>
</div>