Using the CSS
Three stylesheets, almost no JavaScript, no build step. Then a dozen custom properties if you want it to stop looking like this site.
The three files
The system compiles to three stylesheets you’d actually reuse elsewhere.
tokens.css is a hand-maintained block of custom properties; base.css is
reset and typography; components.css is the components. The order
matters — each file reads custom properties the one before it defines.
<link rel="stylesheet" href="tokens.css">
<link rel="stylesheet" href="base.css">
<link rel="stylesheet" href="components.css">
All three are on this site at
/assets/css/tokens.css,
/assets/css/base.css, and
/assets/css/components.css.
This site also loads docs.css and patterns.css — its own sidebar/header
chrome and the Loop/Archive pattern-page CSS — but neither is part of the
design system, so don’t link them elsewhere.
Load IBM Plex Mono separately — it is the system’s one webfont, and nothing else is fetched:
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap');
Almost nothing here needs JavaScript. assets/js/system.js adds keyboard
handling for Tabs and the theme
toggle — Tooltip, Checkbox, Radio, and Switch are pure CSS, and Dialog/Toast
are shown as static states for documentation rather than wired up as
production widgets.
Dark theme
Dark mode is opt-in via a data-theme="dark" attribute plus
prefers-color-scheme, applied explicitly rather than inherited silently
from the OS — the toggle UI on every page depends on this exact mechanism.
Both repoint the same semantic aliases at the inverted neutral ramp.
:root { --gl-color-surface-page: #faf9f7; }
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) { --gl-color-surface-page: #0e0d0b; }
}
:root[data-theme="dark"] { --gl-color-surface-page: #0e0d0b; }
To wire up your own toggle, set or clear data-theme on <html> and persist
the choice. Apply it in a blocking inline script in <head> or the page will
flash the wrong theme before your bundle runs.
Retheming
Because every component reads an alias, retheming is a matter of repointing
a handful of custom properties after the token file loads — most of all,
--gl-color-accent, which -ink and -soft re-derive from automatically via
color-mix().
:root {
--gl-color-accent: #9a5a3c; /* Clay */
}
Re-check contrast after retheming. The system's contrast guarantees on the Color page are about the system's own values — swap the accent and you own the result. The WCAG 2.1 relative-luminance formula is standard and easy to run against your own palette if you want the same numbers.
Building this site
There is no Jekyll here — the whole site is a Rakefile driving plain ERB
templates and Kramdown (see lib/build.rb). It still builds on GitHub
Actions and uploads the result to Pages, mainly so the build always runs on
the pinned Ruby 4.0 rather than whatever GitHub’s Pages runner happens to
ship. Locally:
$ rbenv install 4.0.6 # or however you get Ruby 4.0
$ bundle install
$ bundle exec rake # builds the site into _site/
$ bundle exec rake serve # http://127.0.0.1:4000
What is where
| Path | What it is |
|---|---|
assets/css/tokens.css | Every value in the system, hand-maintained. |
_sass/ | One plain CSS file per component group, concatenated into base.css, components.css, docs.css, and patterns.css at build time (see CSS_BUNDLES in lib/build.rb). No hexes, no pixels, no durations. |
lib/build.rb | The whole site builder in one file — a literal list of pages, front matter, ERB, and Kramdown. |
_layouts/page.erb | The one page shell (head, header, sidebar, footer). |
_components/, _foundations/, _patterns/ | Static Markdown and HTML — the content itself, hand-written. |
How the example demos work
Every demo on this site is plain, static markup: a <figure> with the live
preview in one <div> and, underneath it, a <details> holding the exact
same markup as literal, escaped text in a <pre><code>. There is no
generator keeping the two in sync — copying the demo’s markup by hand into
the page is how the source panel gets written, so there is nothing to drift.
<figure class="example">
<figcaption>Variants</figcaption>
<div>
<button>Cancel</button>
<button data-variant="primary">Save</button>
</div>
<details><summary>Markup</summary>
<pre><code><button>Cancel</button>
<button data-variant="primary">Save</button></code></pre>
</details>
</figure>