Design pass: visual alignment with the Ghost blog

Fixed-dark theme matching blog.c0smere.net (Source theme + injections):
bg #0b0d12, white/64%-white text, accent green #218107 (links lifted to
#2fa50f for contrast). Self-hosted JetBrains Mono + Libre Baskerville —
the same woff2 files the blog serves. Site header with logo + nav
mirroring gh-head; serif-italic quotes; blog-style borderless tables;
single dark shiki/mermaid theme; homepage styled as a typographic feed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wes
2026-07-21 21:38:04 -04:00
co-authored by Claude Fable 5
parent 0a57aa9db1
commit 601922e607
10 changed files with 413 additions and 166 deletions
+2 -3
View File
@@ -13,8 +13,7 @@ export default defineConfig({
markdown: {
remarkPlugins: [[remarkObsidian, { slugMap }], remarkMath],
rehypePlugins: [rehypeKatex],
shikiConfig: {
themes: { light: 'github-light', dark: 'github-dark' },
},
// single dark theme — the site is fixed-dark to match blog.c0smere.net
shikiConfig: { theme: 'github-dark' },
},
});
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+409 -161
View File
@@ -22,17 +22,41 @@ const showToc = headings.filter((h) => h.depth <= 3).length >= 2;
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{title}{isHome ? '' : ' // Wesley Ray'}</title>
<meta name="theme-color" content="#0b0d12" />
{description && <meta name="description" content={description} />}
<link
rel="preload"
href="/fonts/jetbrains-mono-v13-latin-regular.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<link
rel="preload"
href="/fonts/jetbrains-mono-v13-latin-700.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<script
defer
data-domain="garden.c0smere.net"
src="https://plausible.io/js/script.js"></script>
</head>
<body>
<body class={isHome ? 'home' : undefined}>
<div class="layout">
<div class="content-col">
<header>
{!isHome && <nav><a href="/">← home</a></nav>}
<div class="site-head">
<a class="site-logo" href="/">Wesley Ray</a>
<nav class="site-nav">
<a href="https://blog.c0smere.net">blog</a>
<a href="https://git.c0smere.net/wes">git</a>
<a href="https://resume.c0smere.net/raywes88/wesley-ray-default"
>resume</a
>
</nav>
</div>
<div id="hq" class="header-quote" hidden>
<span id="hq-text"></span>
<span id="hq-attr" class="hq-attr"></span>
@@ -153,35 +177,94 @@ const showToc = headings.filter((h) => h.depth <= 3).length >= 2;
pre.textContent = code.textContent ?? '';
code.parentElement?.replaceWith(pre);
});
mermaid.initialize({
startOnLoad: false,
theme: matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'default',
});
mermaid.initialize({ startOnLoad: false, theme: 'dark' });
await mermaid.run();
}
</script>
<style is:global>
:root {
--bg: #faf8f8;
--fg: #2b2b2b;
--muted: #4e4e4e;
--faint: #e5e5e5;
--accent: #284b63;
--accent2: #84a59d;
color-scheme: light dark;
/* Same font files the Ghost blog (Source theme) serves — one property,
one set of faces: JetBrains Mono everywhere, Libre Baskerville for
quoted matter. */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/jetbrains-mono-v13-latin-regular.woff2') format('woff2');
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #161618;
--fg: #ebebec;
--muted: #d4d4d4;
--faint: #393639;
--accent: #7b97aa;
--accent2: #84a59d;
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/fonts/jetbrains-mono-v13-latin-700.woff2') format('woff2');
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 800;
font-display: swap;
src: url('/fonts/jetbrains-mono-v13-latin-800.woff2') format('woff2');
}
@font-face {
font-family: 'JetBrains Mono';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('/fonts/jetbrains-mono-v13-latin-italic.woff2') format('woff2');
}
@font-face {
font-family: 'JetBrains Mono';
font-style: italic;
font-weight: 700;
font-display: swap;
src: url('/fonts/jetbrains-mono-v13-latin-700italic.woff2')
format('woff2');
}
@font-face {
font-family: 'Libre Baskerville';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/libre-baskerville-v14-latin-regular.woff2')
format('woff2');
}
@font-face {
font-family: 'Libre Baskerville';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('/fonts/libre-baskerville-v14-latin-italic.woff2')
format('woff2');
}
@font-face {
font-family: 'Libre Baskerville';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/fonts/libre-baskerville-v14-latin-700.woff2') format('woff2');
}
/* Tokens lifted from blog.c0smere.net (Ghost Source theme + code
injection): bg #0b0d12, white text, 64%-white secondary, accent
#218107. --link is the same green lifted for AA contrast on the
dark ground; --accent stays the blog's exact brand green for
borders and fills. Fixed dark — the blog has no light mode. */
:root {
--bg: #0b0d12;
--fg: #ffffff;
--muted: hsla(0, 0%, 100%, 0.64);
--faint: hsla(0, 0%, 100%, 0.16);
--hair: hsla(0, 0%, 100%, 0.08);
--accent: #218107;
--link: #2fa50f;
--link-bright: #46c421;
--mono:
'JetBrains Mono', ui-monospace, 'Cascadia Mono', Menlo, Consolas,
monospace;
--serif: 'Libre Baskerville', Georgia, serif;
color-scheme: dark;
}
* {
box-sizing: border-box;
@@ -190,8 +273,11 @@ const showToc = headings.filter((h) => h.depth <= 3).length >= 2;
margin: 0;
background: var(--bg);
color: var(--fg);
font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
line-height: 1.6;
font-family: var(--mono);
line-height: 1.7;
}
::selection {
background: rgba(33, 129, 7, 0.45);
}
.layout {
margin: 0 auto;
@@ -202,7 +288,7 @@ const showToc = headings.filter((h) => h.depth <= 3).length >= 2;
.sidebar {
margin-top: 2.5rem;
padding-top: 1rem;
border-top: 1px solid var(--faint);
border-top: 1px solid var(--hair);
}
/* TOC only exists as a right column on wide screens */
.toc-col {
@@ -243,17 +329,159 @@ const showToc = headings.filter((h) => h.depth <= 3).length >= 2;
padding: 1.5rem 0 1.5rem 0.5rem;
}
}
/* ---- links ---- */
a {
color: var(--link);
text-decoration: underline;
text-decoration-color: color-mix(in srgb, var(--link) 40%, transparent);
text-underline-offset: 3px;
}
a:hover {
color: var(--link-bright);
text-decoration-color: currentColor;
}
/* ---- site header (mirrors the blog's gh-head) ---- */
.site-head {
display: flex;
flex-wrap: wrap;
align-items: baseline;
justify-content: space-between;
gap: 0.5rem 1.5rem;
margin-bottom: 1.25rem;
}
.site-logo {
font-size: 1.05rem;
font-weight: 800;
letter-spacing: -0.02em;
color: var(--fg);
text-decoration: none;
}
.site-logo:hover {
color: var(--link-bright);
}
.site-nav {
display: flex;
gap: 1.2rem;
font-size: 0.85rem;
}
.site-nav a {
color: var(--muted);
text-decoration: none;
}
.site-nav a:hover {
color: var(--fg);
}
.header-quote {
margin-bottom: 1.75rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--hair);
font-family: var(--serif);
font-style: italic;
font-size: 0.9rem;
line-height: 1.7;
color: var(--muted);
}
.header-quote .hq-attr {
font-family: var(--mono);
font-style: normal;
white-space: nowrap;
margin-left: 0.4rem;
font-size: 0.75rem;
}
/* ---- headings ---- */
h1, h2, h3, h4, h5, h6 {
line-height: 1.3;
letter-spacing: -0.02em;
scroll-margin-top: 1rem;
}
h1 {
font-size: 1.7rem;
font-weight: 800;
}
h2 {
font-size: 1.3rem;
font-weight: 700;
margin-top: 2.4em;
}
h3 {
font-size: 1.1rem;
font-weight: 700;
}
h4, h5, h6 {
font-size: 1rem;
font-weight: 700;
}
/* ---- sidebar ---- */
.sidebar-title {
margin: 0 0 0.5rem;
font-weight: 800;
letter-spacing: -0.01em;
}
.sidebar-title a {
color: var(--fg);
text-decoration: none;
}
.sidebar ul {
list-style: none;
margin: 0;
padding-left: 0.85rem;
font-size: 0.8rem;
}
.sidebar > ul,
.sidebar-title + ul {
padding-left: 0;
}
.sidebar li {
margin: 0.15rem 0;
}
.sidebar a {
color: var(--muted);
text-decoration: none;
}
.sidebar a:hover {
color: var(--fg);
text-decoration: underline;
}
.sidebar a[aria-current='page'] {
color: var(--link);
font-weight: 700;
}
.sidebar summary {
cursor: pointer;
list-style: none;
}
.sidebar summary::before {
content: '▸';
display: inline-block;
width: 0.9em;
color: var(--muted);
font-size: 0.8em;
transition: transform 0.15s;
}
.sidebar details[open] > summary::before {
transform: rotate(90deg);
}
.sidebar summary a {
font-weight: 700;
color: var(--fg);
}
/* ---- table of contents ---- */
.toc-title {
margin: 0 0 0.5rem;
font-weight: 600;
font-size: 0.85rem;
font-weight: 700;
font-size: 0.8rem;
}
.toc ul {
list-style: none;
margin: 0;
padding: 0;
font-size: 0.8rem;
border-left: 1px solid var(--faint);
font-size: 0.75rem;
border-left: 1px solid var(--hair);
}
.toc li {
margin: 0.2rem 0;
@@ -273,100 +501,111 @@ const showToc = headings.filter((h) => h.depth <= 3).length >= 2;
padding-left: 2.25rem;
}
.toc li a:hover {
color: var(--accent);
color: var(--fg);
}
.toc li a.toc-active {
color: var(--accent);
border-left-color: var(--accent);
color: var(--link);
border-left-color: var(--link);
}
h1, h2, h3, h4, h5, h6 {
scroll-margin-top: 1rem;
/* ---- content ---- */
img {
max-width: 100%;
height: auto;
border-radius: 4px;
}
.sidebar-title {
margin: 0 0 0.5rem;
font-weight: 600;
pre {
padding: 1rem 1.1rem;
border-radius: 6px;
border: 1px solid var(--hair);
overflow-x: auto;
font-size: 0.82rem;
line-height: 1.55;
}
.sidebar-title a {
color: var(--fg);
text-decoration: none;
:not(pre) > code {
background: var(--hair);
padding: 0.1em 0.35em;
border-radius: 4px;
font-size: 0.92em;
}
.sidebar ul {
list-style: none;
margin: 0;
padding-left: 0.85rem;
font-size: 0.85rem;
}
.sidebar > ul,
.sidebar-title + ul {
padding-left: 0;
}
.sidebar li {
margin: 0.15rem 0;
}
.sidebar a {
color: var(--muted);
text-decoration: none;
}
.sidebar a:hover {
color: var(--accent);
text-decoration: underline;
}
.sidebar a[aria-current='page'] {
color: var(--accent);
font-weight: 600;
}
.sidebar summary {
cursor: pointer;
list-style: none;
}
.sidebar summary::before {
content: '▸';
display: inline-block;
width: 0.9em;
color: var(--muted);
font-size: 0.8em;
transition: transform 0.15s;
}
.sidebar details[open] > summary::before {
transform: rotate(90deg);
}
.sidebar summary a {
font-weight: 550;
color: var(--fg);
}
a {
color: var(--accent);
}
h1, h2, h3, h4 {
line-height: 1.25;
}
header nav {
margin-bottom: 1rem;
/* tables: transparent with hairline row borders, matching the blog's
table code injection */
table {
border-collapse: collapse;
display: block;
overflow-x: auto;
max-width: 100%;
font-size: 0.9rem;
}
.header-quote {
margin-bottom: 1.75rem;
padding-bottom: 0.75rem;
th, td {
border: 0;
border-bottom: 1px solid var(--faint);
font-size: 0.85rem;
font-style: italic;
color: var(--muted);
padding: 0.5em 0.85em;
text-align: left;
}
.header-quote .hq-attr {
font-style: normal;
white-space: nowrap;
margin-left: 0.4rem;
font-size: 0.8rem;
}
footer {
margin-top: 3rem;
padding-top: 1rem;
hr {
border: 0;
border-top: 1px solid var(--faint);
font-size: 0.85rem;
margin: 2.5rem 0;
}
.katex-display {
overflow-x: auto;
overflow-y: hidden;
}
/* quoted matter goes serif-italic, like the blog's serif accents */
blockquote {
margin: 1.5rem 0;
padding: 0.1rem 0 0.1rem 1.25rem;
border-left: 3px solid var(--accent);
font-family: var(--serif);
font-style: italic;
font-size: 0.95rem;
line-height: 1.8;
color: var(--muted);
}
/* Obsidian callouts are blockquotes too — keep them mono/upright */
.callout {
font-family: var(--mono);
font-style: normal;
font-size: 1rem;
line-height: 1.7;
color: var(--fg);
border-left: 4px solid var(--accent);
border-radius: 4px;
background: rgba(33, 129, 7, 0.1);
padding: 0.1rem 1rem;
}
.callout-title {
color: var(--link);
}
.callout-warning, .callout-attention, .callout-important {
border-left-color: #c9803a;
background: rgba(201, 128, 58, 0.1);
}
.callout-warning .callout-title,
.callout-attention .callout-title,
.callout-important .callout-title {
color: #d89a55;
}
/* ---- footer ---- */
footer {
margin-top: 4rem;
padding-top: 1.25rem;
border-top: 1px solid var(--hair);
font-size: 0.8rem;
color: var(--muted);
}
footer a {
color: var(--muted);
}
footer a:hover {
color: var(--fg);
}
.footer-quotes {
font-family: var(--serif);
font-style: italic;
font-size: 0.85rem;
margin-bottom: 0.75rem;
}
.footer-quotes p {
@@ -376,7 +615,7 @@ const showToc = headings.filter((h) => h.depth <= 3).length >= 2;
display: flex;
flex-wrap: wrap;
gap: 2px;
font-family: ui-monospace, 'Cascadia Mono', 'JetBrains Mono', monospace;
font-family: var(--mono);
font-size: 0.95rem;
font-variant-numeric: tabular-nums;
}
@@ -385,9 +624,10 @@ const showToc = headings.filter((h) => h.depth <= 3).length >= 2;
min-width: 1.3ch;
padding: 0.12em 0.08em;
text-align: center;
background: #1c1c1e;
color: #f2f2f3;
background: #11150e;
color: #56dd33;
border-radius: 3px;
border: 1px solid var(--hair);
border-bottom: 2px solid #000;
}
.odo-display .odo-sep {
@@ -395,63 +635,71 @@ const showToc = headings.filter((h) => h.depth <= 3).length >= 2;
}
.odo-caption {
margin-top: 0.35rem;
font-size: 0.75rem;
font-size: 0.72rem;
}
img {
max-width: 100%;
height: auto;
/* ---- homepage: typographic feed, like the blog's index ---- */
.home main h1 {
font-size: 1.35rem;
font-weight: 800;
margin: 2.4rem 0 0.75rem;
}
pre {
padding: 0.9rem 1rem;
border-radius: 6px;
overflow-x: auto;
font-size: 0.88rem;
}
:not(pre) > code {
background: var(--faint);
padding: 0.1em 0.35em;
border-radius: 4px;
font-size: 0.9em;
}
table {
border-collapse: collapse;
display: block;
overflow-x: auto;
max-width: 100%;
}
th, td {
border: 1px solid var(--faint);
padding: 0.35rem 0.6rem;
}
blockquote {
margin: 1rem 0;
padding: 0.1rem 1rem;
border-left: 3px solid var(--accent2);
/* the vault-authored links row at the very top: render as a small
uppercase link bar, not a display heading */
.home main > h1:first-child {
margin: 0 0 0.5rem;
font-size: 0.8rem;
font-weight: 400;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
}
.callout {
border-left-width: 4px;
border-radius: 4px;
background: color-mix(in srgb, var(--accent2) 8%, transparent);
.home main > h1:first-child a {
color: var(--muted);
text-decoration: none;
}
.callout-title {
color: var(--accent);
.home main > h1:first-child a:hover {
color: var(--link-bright);
text-decoration: underline;
}
.callout-warning, .callout-attention, .callout-important {
border-left-color: #c9803a;
.home main h2 {
font-size: 0.85rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--muted);
margin: 1.9rem 0 0.4rem;
}
.callout-warning .callout-title,
.callout-attention .callout-title,
.callout-important .callout-title {
color: #c9803a;
.home main hr {
margin: 2rem 0;
}
/* dark-mode-aware shiki dual themes */
@media (prefers-color-scheme: dark) {
.astro-code,
.astro-code span {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
.home main > ul {
list-style: none;
margin: 0.5rem 0 1.5rem;
padding: 0;
}
.home main > ul > li {
padding: 0.6rem 0;
border-bottom: 1px solid var(--hair);
color: var(--muted);
font-size: 0.9rem;
line-height: 1.6;
}
.home main > ul > li:last-child {
border-bottom: 0;
}
.home main > ul > li > a {
font-weight: 700;
}
.home main ul ul {
list-style: none;
margin: 0.4rem 0 0;
padding-left: 1.25rem;
font-size: 0.85rem;
}
.home main ul ul li {
padding: 0.15rem 0;
border: 0;
}
</style>
</body>