Content region gets a shared top padding on .page > main so every consuming site has the same nav-to-content gap (matches newerror's .about spacing). When newerror adopts the submodule, its per-page-type top paddings become deltas over this baseline. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C96hwEU9cM7mJpqATiv7R5
317 lines
9.3 KiB
CSS
317 lines
9.3 KiB
CSS
/* =====================================================================
|
|
static-design-system — base.css
|
|
Shared visual foundation for the bchen.dev static sites.
|
|
Canonical design: "A New Error" (newerror.bchen.dev) — the "Ledger"
|
|
direction: Spectral serif body, Helvetica sans UI, IBM Plex Mono.
|
|
|
|
HOW COLOR WORKS
|
|
Every color is a CSS custom property. The values below are DEFAULTS
|
|
(newerror's palette). Each consuming site overrides ONLY these color
|
|
tokens in its own colors.css, which loads AFTER this file. Fonts,
|
|
spacing, typography, nav/footer chrome, and dark-mode behavior are
|
|
shared and should NOT be re-declared per site.
|
|
|
|
IMPORTANT: keep this file Liquid-safe. Its contents are passed through the
|
|
Jekyll include tag by each site's served wrapper (assets/ds.css), so do NOT
|
|
introduce Liquid delimiters (double-brace or brace-percent sequences).
|
|
Plain CSS braces are fine.
|
|
===================================================================== */
|
|
|
|
:root {
|
|
/* Type */
|
|
--serif: "Spectral", Georgia, "Times New Roman", serif;
|
|
--sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
--mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;
|
|
|
|
/* Layout */
|
|
--measure: 760px; /* standard content column */
|
|
--read: 680px; /* narrower reading column (articles) */
|
|
--pad: 34px;
|
|
--gutter: 104px; /* date column width (ledger layouts) */
|
|
}
|
|
|
|
/* ---- Color tokens — DEFAULTS (newerror). Override per site in colors.css ---- */
|
|
:root, :root[data-theme="light"] {
|
|
--bg: #FAFBFC;
|
|
--ink: #1B2027;
|
|
--muted: #69717C;
|
|
--faint: #99A1AC;
|
|
--rule: #E6E9EF;
|
|
--rule-2: #b6b9be;
|
|
--accent: #1463C7;
|
|
--accent-hover: #0F4FA3;
|
|
--field: #F1F3F6;
|
|
}
|
|
:root[data-theme="dark"] {
|
|
--bg: #14171C;
|
|
--ink: #E2E6EC;
|
|
--muted: #9AA2AD;
|
|
--faint: #69717C;
|
|
--rule: #262B32;
|
|
--rule-2: #5e6670;
|
|
--accent: #6FA9F2;
|
|
--accent-hover: #97C1F8;
|
|
--field: #1D2128;
|
|
}
|
|
@media (prefers-color-scheme: dark) {
|
|
:root:not([data-theme="light"]) {
|
|
--bg: #14171C;
|
|
--ink: #E2E6EC;
|
|
--muted: #9AA2AD;
|
|
--faint: #69717C;
|
|
--rule: #262B32;
|
|
--rule-2: #5e6670;
|
|
--accent: #6FA9F2;
|
|
--accent-hover: #97C1F8;
|
|
--field: #1D2128;
|
|
}
|
|
}
|
|
|
|
/* =====================================================================
|
|
Base
|
|
===================================================================== */
|
|
* { box-sizing: border-box; }
|
|
html { -webkit-text-size-adjust: 100%; }
|
|
|
|
body {
|
|
margin: 0;
|
|
background: var(--bg);
|
|
color: var(--ink);
|
|
font-family: var(--serif);
|
|
font-size: 18px;
|
|
line-height: 1.6;
|
|
-webkit-font-smoothing: antialiased;
|
|
text-rendering: optimizeLegibility;
|
|
transition: background-color 0.25s ease, color 0.25s ease;
|
|
}
|
|
|
|
::selection { background: color-mix(in oklab, var(--accent) 22%, transparent); }
|
|
|
|
a { color: inherit; }
|
|
|
|
/* ---- shell / responsive width ---- */
|
|
.shell {
|
|
width: 100%;
|
|
max-width: var(--measure);
|
|
margin-inline: auto;
|
|
padding-inline: var(--pad);
|
|
}
|
|
.page { min-height: 100vh; display: flex; flex-direction: column; }
|
|
.page > main { flex: 1 0 auto; padding-top: 56px; } /* standard nav->content rhythm */
|
|
|
|
/* =====================================================================
|
|
Top navigation
|
|
===================================================================== */
|
|
.nav {
|
|
font-family: var(--sans);
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
padding: 38px 0 18px;
|
|
border-bottom: 1px solid var(--rule);
|
|
}
|
|
.nav.minimal { border-bottom: none; padding-bottom: 0; }
|
|
|
|
.mast {
|
|
font-family: var(--serif);
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
letter-spacing: 0.005em;
|
|
color: var(--ink);
|
|
text-decoration: none;
|
|
white-space: nowrap;
|
|
}
|
|
.mast:hover { color: var(--accent); }
|
|
|
|
.nav-links {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 26px;
|
|
}
|
|
.nav-links a, .iconbtn {
|
|
font-family: var(--sans);
|
|
font-size: 13.5px;
|
|
letter-spacing: 0.01em;
|
|
color: var(--muted);
|
|
text-decoration: none;
|
|
cursor: pointer;
|
|
background: none;
|
|
border: none;
|
|
padding: 0;
|
|
}
|
|
.nav-links a:hover, .iconbtn:hover { color: var(--accent); }
|
|
.nav-links a.active { color: var(--ink); }
|
|
|
|
.nav-tools { display: flex; align-items: center; gap: 18px; }
|
|
|
|
.iconbtn {
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
width: 26px; height: 26px; border-radius: 6px;
|
|
color: var(--muted);
|
|
}
|
|
.iconbtn:hover { color: var(--accent); background: var(--field); }
|
|
.iconbtn svg { width: 15px; height: 15px; display: block; }
|
|
|
|
/* hamburger — hidden on desktop */
|
|
.hamburger { display: none; }
|
|
.mobile-menu { display: none; }
|
|
|
|
/* =====================================================================
|
|
Footer
|
|
===================================================================== */
|
|
.foot {
|
|
font-family: var(--sans);
|
|
border-top: 1px solid var(--rule);
|
|
margin-top: 20px;
|
|
padding: 22px 0 40px;
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
gap: 16px;
|
|
font-size: 12.5px;
|
|
color: var(--faint);
|
|
flex: 0 0 auto;
|
|
}
|
|
.foot a { color: var(--muted); text-decoration: none; }
|
|
.foot a:hover { color: var(--accent); }
|
|
.foot .rss-link { display: inline-flex; align-items: center; gap: 7px; }
|
|
|
|
/* =====================================================================
|
|
Prose — reusable content typography (markdown pages, articles)
|
|
Wrap rendered content in <div class="prose"> to opt in.
|
|
===================================================================== */
|
|
.prose { font-size: 19.5px; line-height: 1.68; color: var(--ink); }
|
|
.prose > :first-child { margin-top: 0; }
|
|
.prose p { margin: 0 0 1.3em; text-wrap: pretty; }
|
|
.prose h1 {
|
|
font-family: var(--serif);
|
|
font-size: 32px; line-height: 1.16; font-weight: 600;
|
|
letter-spacing: -0.018em; color: var(--ink);
|
|
margin: 0 0 0.5em; text-wrap: pretty;
|
|
}
|
|
.prose h2 {
|
|
font-family: var(--serif);
|
|
font-size: 25px; font-weight: 600; line-height: 1.25;
|
|
letter-spacing: -0.01em;
|
|
margin: 2em 0 0.6em;
|
|
}
|
|
.prose h3 {
|
|
font-family: var(--serif);
|
|
font-size: 21px; font-weight: 600;
|
|
margin: 1.7em 0 0.5em;
|
|
}
|
|
.prose a {
|
|
color: var(--ink);
|
|
text-decoration: underline;
|
|
text-decoration-color: var(--rule-2);
|
|
text-underline-offset: 2px;
|
|
text-decoration-thickness: 1px;
|
|
}
|
|
.prose a:hover { color: var(--accent); text-decoration-color: var(--accent); }
|
|
.prose strong { font-weight: 600; }
|
|
.prose em { font-style: italic; }
|
|
|
|
.prose blockquote {
|
|
margin: 1.6em 0;
|
|
padding-left: 22px;
|
|
border-left: 2px solid var(--rule-2);
|
|
color: var(--muted);
|
|
font-style: italic;
|
|
}
|
|
.prose blockquote p:last-child { margin-bottom: 0; }
|
|
|
|
.prose ul, .prose ol { margin: 0 0 1.3em; padding-left: 1.3em; }
|
|
.prose li { margin: 0.3em 0; padding-left: 0.2em; }
|
|
.prose li::marker { color: var(--faint); }
|
|
|
|
.prose hr {
|
|
border: none; height: 0;
|
|
border-top: 1px solid var(--rule);
|
|
margin: 2.4em auto;
|
|
width: 40%;
|
|
}
|
|
|
|
.prose code {
|
|
font-family: var(--mono);
|
|
font-size: 0.82em;
|
|
background: var(--field);
|
|
padding: 0.12em 0.4em;
|
|
border-radius: 4px;
|
|
}
|
|
.prose pre {
|
|
font-family: var(--mono);
|
|
font-size: 14px; line-height: 1.55;
|
|
background: var(--field);
|
|
padding: 18px 20px;
|
|
border-radius: 8px;
|
|
overflow-x: auto;
|
|
margin: 1.5em 0;
|
|
}
|
|
.prose pre code { background: none; padding: 0; font-size: inherit; }
|
|
|
|
.prose figure { margin: 2em 0; }
|
|
.prose figure img { display: block; width: 100%; height: auto; border-radius: 3px; }
|
|
.prose figcaption {
|
|
font-family: var(--sans);
|
|
font-size: 12.5px; color: var(--faint);
|
|
margin-top: 10px; text-align: left;
|
|
}
|
|
.prose img { max-width: 100%; height: auto; }
|
|
|
|
/* =====================================================================
|
|
Mobile
|
|
===================================================================== */
|
|
@media (max-width: 640px) {
|
|
:root { --pad: 22px; --gutter: 74px; }
|
|
body { font-size: 17px; }
|
|
|
|
.nav-links { display: none; }
|
|
.hamburger { display: inline-flex; }
|
|
|
|
.mobile-menu {
|
|
display: none;
|
|
font-family: var(--sans);
|
|
}
|
|
.mobile-menu.open {
|
|
display: flex; flex-direction: column;
|
|
gap: 2px;
|
|
padding: 8px 0 14px;
|
|
border-bottom: 1px solid var(--rule);
|
|
}
|
|
.mobile-menu a, .mobile-menu button {
|
|
font-family: var(--sans);
|
|
text-align: left;
|
|
background: none; border: none; cursor: pointer;
|
|
color: var(--ink);
|
|
font-size: 16px;
|
|
padding: 12px 4px;
|
|
text-decoration: none;
|
|
border-radius: 6px;
|
|
}
|
|
.mobile-menu a:hover, .mobile-menu button:hover { color: var(--accent); }
|
|
.mobile-menu .row { display: flex; align-items: center; gap: 10px; }
|
|
|
|
.prose { font-size: 18.5px; }
|
|
.prose h1 { font-size: 30px; }
|
|
}
|
|
|
|
/* =====================================================================
|
|
Icon swaps (theme toggle + hamburger), driven by [data-theme] / .is-open
|
|
===================================================================== */
|
|
.theme-toggle .ico-sun { display: none; }
|
|
.theme-toggle .ico-moon { display: block; }
|
|
:root[data-theme="dark"] .theme-toggle .ico-moon { display: none; }
|
|
:root[data-theme="dark"] .theme-toggle .ico-sun { display: block; }
|
|
@media (prefers-color-scheme: dark) {
|
|
:root:not([data-theme="light"]) .theme-toggle .ico-moon { display: none; }
|
|
:root:not([data-theme="light"]) .theme-toggle .ico-sun { display: block; }
|
|
}
|
|
|
|
.hamburger .ico-close { display: none; }
|
|
.hamburger.is-open .ico-bars { display: none; }
|
|
.hamburger.is-open .ico-close { display: block; }
|
|
|
|
/* reduce motion */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
* { transition: none !important; }
|
|
}
|