Skip to content
Gloss v2.0.0
Source

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

PathWhat it is
assets/css/tokens.cssEvery 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.rbThe whole site builder in one file — a literal list of pages, front matter, ERB, and Kramdown.
_layouts/page.erbThe 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>&lt;button&gt;Cancel&lt;/button&gt;
&lt;button data-variant="primary"&gt;Save&lt;/button&gt;</code></pre>
  </details>
</figure>