1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
---
title: Rationale
permalink: /rationale/
section: Start here
summary: >-
The four rules this system's build actually enforces, and the one thing
about it that is not arbitrary.
---
## Where this comes from
Gloss is a name and nothing more — it is not an argument about the system.
The argument is in the umbrella it belongs to. Arbitrary Definitions is a
personal umbrella for side projects — self-hosted, single-user tools built
for one household or one person, never a SaaS product. Almost nothing in a
design system is derived: the accent is teal
because someone liked it, the type scale ratio is 1.20 at the small end and
1.25 at the large end because that is what looked right, not because either
number is correct. What makes it a *system* is not that the choices are
correct but that they were written down once, given names, actually used, and
are therefore changeable.
## What actually makes it a system
Not the quality of the individual choices. The properties below:
<div class="card-grid">
<article class="card">
<div class="card-body">
<h3>It is written down once</h3>
<p>
One hand-maintained stylesheet of custom properties. Not a Figma
library that disagrees with the CSS, and not a spreadsheet somebody
exports by hand.
</p>
</div>
</article>
<article class="card">
<div class="card-body">
<h3>It has names</h3>
<p>
<code>--gl-color-danger</code> survives a change of mind about which
red. <code>#ad3a2c</code> does not.
</p>
</div>
</article>
<article class="card">
<div class="card-body">
<h3>It is actually used</h3>
<p>
Every color, type, spacing, radius, elevation, and motion value in
the components is a <code>var(--gl-*)</code>. Not one is a literal.
</p>
</div>
</article>
<article class="card">
<div class="card-body">
<h3>It can be changed</h3>
<p>
Because of the three above, swapping the accent for Clay, Ochre, Ink
Blue, or Plum is a one-line diff.
</p>
</div>
</article>
</div>
## The one thing that is not arbitrary
Contrast. A ratio is a physical fact about two colors and a pair of eyes,
and it does not care what the brand guidelines say.
So it is the one thing this system checks rather than eyeballs. Five
pairings have to hold, computed once from the token values with the
standard WCAG 2.1 relative-luminance formula and written down as fact on the
[contract table](<%= relative_url('/foundations/color/') %>#contrast-that-has-to-hold)
rather than re-derived on every build — a personal site does not need a test
suite standing between an edit and a deploy to keep five numbers honest.
That contract is deliberately narrower than "every color in the system".
`--gl-color-text-tertiary` — this palette's own "muted-faint text" step — is
about 3.46:1 against the page in light mode, under the 4.5:1 floor for normal
text. That is not a bug to paper over by darkening a real brand value; it is
a documented, intentional property of the palette (see the
[Color page](<%= relative_url('/foundations/color/') %>)), so the contract
excludes it rather than silently forcing it to pass. Dividers get the same
treatment for the same reason: this system's own rule is that a bounded
surface reads by surface contrast, not by a border, so hairlines are
reserved for dividers inside a surface and this contract does not invent a
3:1 assertion for a boundary the system doesn't draw.
## The four rules
<div class="gl-callout">
<p class="type-label">1. No color and no duration outside tokens.css</p>
<p>
A hex or a duration in a component stylesheet is a decision made in the
dark, and it is the kind that breaks the moment somebody adds a theme. No
component stylesheet in this repository contains either. Even Select's
chevron, a data-URI that can't read a custom property, lives in
tokens.css as <code>--gl-icon-chevron-down</code>, redefined per theme.
</p>
</div>
<div class="gl-callout">
<p class="type-label">2. Components read aliases, never ramps</p>
<p>
<code>--gl-color-text-primary</code>, not <code>--gl-neutral-900</code>.
The ramp is raw material; the alias is the decision. This is the whole
reason the dark theme is a block of repointed aliases rather than a
second stylesheet.
</p>
</div>
<div class="gl-callout">
<p class="type-label">3. Every token says what it is for</p>
<p>
Every semantic alias on the <a href="<%= relative_url('/foundations/color/') %>">Color page</a>
carries a usage note. A token nobody can describe is a token nobody will
use correctly.
</p>
</div>
<div class="gl-callout">
<p class="type-label">4. One accent, one dark-mode convention</p>
<p>
Never two accents in one view. Dark mode is opt-in — a
<code>data-theme</code> toggle plus <code>prefers-color-scheme</code>,
never inherited silently from the OS alone.
</p>
</div>
## What this system does not have
Being honest about the design is being honest about the gaps too.
- **No formal component library or Figma file exists.** The sixteen
components documented here are a from-scratch, best-guess personal-tool
kit — not a literal recreation of any real app's screens, and not backed
by a source of truth beyond this site.
- **No logo or brand mark.** Render "Gloss" or the project's own name in
type wherever a mark would go — don't invent one.
- **The icon set is only what these pages use** — ten tokens, not a
library. Add one to `tokens.css` when a screen needs it.
- **Signal Teal, the default accent, is one pick among the sanctioned
alternates**, not a fixed identity.
- **No Table, Callout, or Progress component.** An earlier pass at this site
invented all three; they were removed rather than kept, since this system
doesn't define them. (This documentation site still uses a plain
`<table>` and an aside box for its own reference material — those are site
chrome, not system components, and are not documented as one.)
- **Loop and Archive are generic demonstrations**, not real production
screens.
Naming these is cheaper than being caught by them. For the shapes this
system actively refuses to reproduce when a new screen is built on top of
it — kickers, icon tiles over headings, pulsing status dots, and the rest —
see [Refusals](<%= relative_url('/refusals/') %>).