15.5 KB
raw
// heartwood — palette evokes the dense red-brown center of a tree.
:root {
--bg: #1a1410;
--surface: #221a14;
--surface-2: #2a2018;
--border: #3d2f24;
--text: #e8dccc;
--text-mute: #9c8a72;
--accent: #b8543a; // heartwood red
--accent-2: #c4a574; // sap gold
--green: #6b9e78;
--code-bg: #15100c;
--add-bg: #1f2e1f;
--add-fg: #95c895;
--del-bg: #2e1f1f;
--del-fg: #d08585;
--hunk-fg: #8aa9c4;
--mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
--prose: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
* { box-sizing: border-box; }
html, body {
margin: 0;
padding: 0;
background: var(--bg);
color: var(--text);
font-family: var(--prose);
font-size: 15px;
line-height: 1.55;
}
// Sticky footer: body fills viewport, main takes the slack so the
// footer-bar pins to the bottom on short pages (empty repo list, 404).
body {
min-height: 100vh;
display: flex;
flex-direction: column;
}
main { flex: 1 0 auto; }
a {
color: var(--accent-2);
text-decoration: none;
&:hover { text-decoration: underline; }
}
code, pre, .sha, .clone-box input {
font-family: var(--mono);
}
.container {
max-width: 1100px;
margin: 0 auto;
padding: 0 1.25rem;
}
// --- topbar ---
.topbar {
position: relative;
background: linear-gradient(180deg, var(--surface-2) 0%, var(--surface) 100%);
border-bottom: 1px solid var(--border);
padding: 1.15rem 0;
// The outer accent stripe is a horizontal cross-section of the brand
// mark: heartwood-red core, sap-gold middle ring, green outer ring.
// Reads as a tree-ring slice across the top of every page.
&::before {
content: "";
position: absolute;
inset: 0 0 auto 0;
height: 2px;
background: linear-gradient(
90deg,
var(--accent) 0%,
var(--accent-2) 50%,
var(--green) 100%
);
opacity: 0.75;
}
&__row {
display: flex;
align-items: center;
gap: 1rem;
flex-wrap: wrap;
}
// 1px vertical hairline between brand and tagline, like a path-component
// separator. Hidden on narrow screens where the tagline drops out anyway.
&__divider {
width: 1px;
height: 1.4rem;
background: var(--border);
@media (max-width: 540px) { display: none; }
}
}
.brand {
display: inline-flex;
align-items: center;
gap: 0.7rem;
color: var(--text);
font-family: var(--mono);
font-weight: 600;
font-size: 1.15rem;
&:hover {
text-decoration: none;
color: var(--accent-2);
}
}
.brand-mark {
width: 32px;
height: 32px;
// Each ring gets a slow color tween so hovering the brand feels like the
// wood warming under a thumb. Strokes shift one step inward toward red.
circle { transition: stroke 350ms ease, fill 350ms ease; }
}
.brand:hover .brand-mark {
.brand-mark__r1 { stroke: var(--accent-2); }
.brand-mark__r2 { stroke: var(--accent-2); }
.brand-mark__r3 { stroke: var(--accent); }
.brand-mark__core { fill: var(--accent-2); }
}
.brand-text { letter-spacing: 0.03em; }
.tagline {
color: var(--text-mute);
font-family: var(--mono);
font-style: italic;
font-size: 0.85rem;
letter-spacing: 0.02em;
@media (max-width: 540px) { display: none; }
}
.topnav {
margin-left: auto;
display: inline-flex;
align-items: center;
gap: 0.25rem;
&__link {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: var(--text-mute);
font-family: var(--mono);
font-size: 0.85rem;
text-transform: lowercase;
letter-spacing: 0.04em;
padding: 0.35rem 0.75rem;
border: 1px solid transparent;
border-radius: 3px;
transition: color 150ms ease, border-color 150ms ease, background 150ms ease;
&:hover {
color: var(--text);
border-color: var(--border);
background: var(--surface-2);
text-decoration: none;
}
// Current-page state: a subtle outlined "tab" with the accent dot lit.
&.is-active {
color: var(--text);
border-color: var(--border);
background: var(--surface-2);
.topnav__dot {
background: var(--accent);
box-shadow: 0 0 0 2px rgba(184, 84, 58, 0.15);
}
}
}
&__dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--text-mute);
opacity: 0.6;
}
}
// --- breadcrumbs ---
.breadcrumbs {
background: var(--surface);
border-bottom: 1px solid var(--border);
font-family: var(--mono);
font-size: 0.9rem;
color: var(--text-mute);
padding: 0.85rem 0;
strong { color: var(--text); font-weight: 600; }
// Explicit separator span so we don't depend on whitespace stripping in
// the templates. Each path component is its own anchor; the slashes are
// visual-only and get a touch of horizontal margin.
&__sep {
margin: 0 0.35rem;
color: var(--text-mute);
opacity: 0.6;
}
&__ref {
margin-left: 0.75rem;
color: var(--accent-2);
}
}
main { padding: 3rem 0 4rem; }
// --- hero / index ---
.hero {
margin-bottom: 2.5rem;
h1 {
font-family: var(--mono);
font-size: 2rem;
margin: 0 0 0.5rem;
letter-spacing: -0.01em;
}
.lede { color: var(--text-mute); margin: 0; }
}
.empty {
color: var(--text-mute);
font-style: italic;
}
.repo-list {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: 1px;
background: var(--border);
border: 1px solid var(--border);
border-radius: 4px;
overflow: hidden;
}
.repo-row {
background: var(--surface);
padding: 1rem 1.25rem;
&:hover { background: var(--surface-2); }
&__head {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: 1rem;
}
&__name {
font-family: var(--mono);
font-weight: 600;
font-size: 1.1rem;
color: var(--accent-2);
}
&__age {
color: var(--text-mute);
font-size: 0.85rem;
white-space: nowrap;
}
&__desc {
margin: 0.35rem 0 0;
color: var(--text);
}
&__last {
margin: 0.35rem 0 0;
color: var(--text-mute);
font-size: 0.88rem;
}
&__last-sha {
font-family: var(--mono);
color: var(--accent);
margin-right: 0.4rem;
}
}
// --- repo head ---
.repo-head {
margin-bottom: 2rem;
&__title-row {
display: flex;
align-items: baseline;
gap: 0.75rem;
flex-wrap: wrap;
h1 {
font-family: var(--mono);
font-size: 1.75rem;
margin: 0;
}
}
&__branch {
background: var(--surface-2);
color: var(--accent-2);
border: 1px solid var(--border);
padding: 0.1rem 0.5rem;
border-radius: 3px;
font-family: var(--mono);
font-size: 0.85rem;
}
&__desc {
color: var(--text-mute);
margin: 0.5rem 0 1rem;
}
}
.clone-box {
display: flex;
align-items: center;
gap: 0.75rem;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 4px;
padding: 0.5rem 0.75rem;
margin-bottom: 1rem;
max-width: 640px;
label {
color: var(--text-mute);
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
input {
flex: 1;
background: transparent;
border: 0;
color: var(--text);
font-size: 0.9rem;
outline: none;
padding: 0.25rem 0;
}
}
.repo-nav {
display: flex;
gap: 1.25rem;
border-bottom: 1px solid var(--border);
padding-bottom: 0.5rem;
font-family: var(--mono);
font-size: 0.92rem;
a {
color: var(--text-mute);
&:hover { color: var(--accent-2); text-decoration: none; }
}
}
// --- two column layout (overview) ---
.two-col {
display: grid;
// `minmax(0, ...)` is load-bearing: CSS grid items default to min-width:
// auto, so an unwrappable child (e.g. a wide <pre> inside the README)
// would force the main column wider than its 2fr share and crush the
// sidebar. Capping the min at 0 makes the columns respect the fr ratio
// regardless of content width; overflow scrolls within the child.
grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
gap: 2rem;
@media (max-width: 760px) {
grid-template-columns: minmax(0, 1fr);
}
}
.col-main { min-width: 0; }
.col-side { min-width: 0; }
.side-h {
font-family: var(--mono);
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-mute);
margin: 0 0 0.5rem;
}
.commit-list {
list-style: none;
margin: 0;
padding: 0;
li {
border-bottom: 1px dashed var(--border);
padding: 0.55rem 0;
font-size: 0.92rem;
}
.sha {
color: var(--accent);
margin-right: 0.4rem;
}
.summary { display: block; color: var(--text); }
.meta { color: var(--text-mute); font-size: 0.82rem; }
}
// --- readme ---
.readme {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 4px;
padding: 1.5rem 2rem;
h1, h2, h3, h4 {
font-family: var(--mono);
letter-spacing: -0.01em;
}
h1 { font-size: 1.7rem; margin-top: 0; }
h2 { font-size: 1.35rem; border-bottom: 1px solid var(--border); padding-bottom: 0.3rem; }
h3 { font-size: 1.1rem; }
p, ul, ol { line-height: 1.65; }
code { background: var(--code-bg); padding: 0.1rem 0.35rem; border-radius: 3px; font-size: 0.92em; }
pre {
background: var(--code-bg);
padding: 1rem;
border-radius: 4px;
overflow-x: auto;
code { background: transparent; padding: 0; }
}
blockquote {
border-left: 3px solid var(--accent);
padding-left: 1rem;
color: var(--text-mute);
margin: 1rem 0;
}
table {
border-collapse: collapse;
margin: 1rem 0;
th, td {
border: 1px solid var(--border);
padding: 0.35rem 0.75rem;
}
th { background: var(--surface-2); }
}
hr { border: 0; border-top: 1px solid var(--border); }
}
// --- log ---
.log-list {
list-style: none;
padding: 0;
margin: 0;
}
.log-row {
display: flex;
gap: 1rem;
padding: 0.75rem 0;
border-bottom: 1px solid var(--border);
.sha { color: var(--accent); flex-shrink: 0; }
.summary { margin: 0; }
.meta { margin: 0; color: var(--text-mute); font-size: 0.85rem; }
}
// --- tree ---
.tree {
width: 100%;
border-collapse: collapse;
font-family: var(--mono);
font-size: 0.92rem;
tr { border-bottom: 1px solid var(--border); }
td { padding: 0.5rem 0.75rem; }
&__name { width: 100%; }
&__name--tree a::before { content: ""; color: var(--accent-2); }
&__name--blob a::before { content: ""; color: var(--text-mute); }
&__size { color: var(--text-mute); text-align: right; white-space: nowrap; }
}
// --- blob view ---
.blob-head {
display: flex;
justify-content: space-between;
align-items: center;
background: var(--surface);
border: 1px solid var(--border);
border-bottom: 0;
padding: 0.5rem 0.75rem;
border-radius: 4px 4px 0 0;
font-size: 0.85rem;
color: var(--text-mute);
font-family: var(--mono);
}
.blob {
border: 1px solid var(--border);
border-radius: 0 0 4px 4px;
overflow-x: auto;
background: var(--code-bg);
.hl {
margin: 0;
padding: 0.75rem 0;
font-family: var(--mono);
font-size: 0.85rem;
line-height: 1.55;
}
.ln {
display: inline-block;
width: 4ch;
padding-right: 1rem;
text-align: right;
color: var(--text-mute);
user-select: none;
&::before { content: attr(data-n); }
}
.l { display: inline; }
}
// --- diff ---
.commit-head {
margin-bottom: 1.5rem;
h1 {
font-family: var(--mono);
font-size: 1.35rem;
margin: 0 0 0.5rem;
}
.sha { color: var(--accent); }
.meta { color: var(--text-mute); margin: 0 0 1rem; }
}
.commit-msg {
background: var(--surface);
border: 1px solid var(--border);
padding: 0.75rem 1rem;
border-radius: 4px;
font-size: 0.9rem;
white-space: pre-wrap;
margin: 0;
}
.file-diff {
margin-top: 1.5rem;
border: 1px solid var(--border);
border-radius: 4px;
overflow: hidden;
&__head {
background: var(--surface);
padding: 0.5rem 0.75rem;
display: flex;
align-items: center;
gap: 0.75rem;
font-family: var(--mono);
font-size: 0.88rem;
}
}
.status {
font-family: var(--mono);
font-size: 0.75rem;
text-transform: uppercase;
padding: 0.05rem 0.45rem;
border-radius: 3px;
letter-spacing: 0.05em;
&--added { background: rgba(149, 200, 149, 0.15); color: var(--add-fg); }
&--deleted { background: rgba(208, 133, 133, 0.15); color: var(--del-fg); }
&--modified { background: var(--surface-2); color: var(--text-mute); }
&--renamed { background: rgba(196, 165, 116, 0.15); color: var(--accent-2); }
}
.hunk {
margin: 0;
padding: 0.5rem 0;
background: var(--code-bg);
font-family: var(--mono);
font-size: 0.82rem;
line-height: 1.35;
overflow-x: auto;
}
.hunk-hdr {
display: block;
padding: 0.15rem 0.75rem;
color: var(--hunk-fg);
background: rgba(138, 169, 196, 0.08);
}
.line {
display: block;
padding: 0 0.75rem;
white-space: pre;
&--add { background: var(--add-bg); color: var(--add-fg);
&::before { content: "+"; display: inline-block; width: 1.2ch; color: var(--add-fg); opacity: 0.6; }
}
&--del { background: var(--del-bg); color: var(--del-fg);
&::before { content: "-"; display: inline-block; width: 1.2ch; color: var(--del-fg); opacity: 0.6; }
}
&--ctx { color: var(--text);
&::before { content: " "; display: inline-block; width: 1.2ch; }
}
}
// --- footer ---
.footer {
position: relative;
margin-top: 4rem;
padding: 3.5rem 0 3rem;
border-top: 1px solid var(--border);
background: linear-gradient(180deg, var(--surface) 0%, var(--bg) 100%);
overflow: hidden;
&__grid {
display: grid;
gap: 2.5rem;
grid-template-columns: minmax(0, 2.4fr) minmax(0, 1fr) minmax(0, 1fr);
position: relative;
z-index: 1;
@media (max-width: 760px) {
grid-template-columns: minmax(0, 1fr);
gap: 2rem;
}
}
&__label {
font-family: var(--mono);
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--accent-2);
opacity: 0.7;
margin-bottom: 0.9rem;
}
&__about p {
color: var(--text-mute);
font-size: 0.9rem;
line-height: 1.7;
margin: 0 0 0.85rem;
max-width: 56ch;
a {
color: var(--text);
text-decoration: underline;
text-underline-offset: 2px;
text-decoration-color: var(--border);
&:hover { color: var(--accent-2); text-decoration-color: var(--accent-2); }
}
}
&__tagline {
font-style: italic;
color: var(--text-mute);
opacity: 0.75;
}
&__col {
ul {
list-style: none;
margin: 0;
padding: 0;
}
li { margin-bottom: 0.55rem; }
a {
color: var(--text-mute);
font-size: 0.9rem;
transition: color 150ms ease;
&:hover { color: var(--accent-2); text-decoration: none; }
}
}
// Tree-rings flourish, echoing the brand mark. Anchored bottom-right,
// bled off the edge so only an arc is visible. `currentColor` so the
// hue follows the footer text color and the opacity below sets it.
&-rings {
position: absolute;
right: -120px;
bottom: -120px;
width: 460px;
height: 460px;
color: var(--accent);
opacity: 0.07;
pointer-events: none;
z-index: 0;
}
}
// Slim copyright bar, like blog/status/analytics.
.footer-bar {
background: var(--code-bg);
border-top: 1px solid var(--border);
padding: 0.9rem 0;
color: var(--text-mute);
font-size: 0.78rem;
&__row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
@media (max-width: 480px) {
flex-direction: column;
gap: 0.6rem;
text-align: center;
}
}
&__link {
display: inline-flex;
color: var(--text-mute);
transition: color 150ms ease;
&:hover { color: var(--accent-2); }
}
}