rastrillo / fiesta Public

Clone
git clone https://amadan.net/rastrillo/fiesta

Plain git — no account needed to clone.

Download

Download this file

1/* plain — the skeleton: greyscale, system type, almost no shape.
2 Structure lives in tokens.css; this file is colour, type and shape.
3
4 The look: nothing. plain is the theme you pick when you intend to
5 write your own — a working, accessible, entirely unstyled-looking app
6 that shows you the structure and none of the taste, so the first
7 colour you add is visibly yours. There is no accent hue: the accent
8 is near-black in light and near-white in dark, which is to say a link
9 reads as text with an underline on hover and a primary button reads as
10 a filled rectangle. That is deliberate. Add the hue.
11
12 Status still has to signal. A skeleton that renders an error the same
13 grey as a success is not minimal, it is broken, so the four tone
14 pairs keep conventional hues at very low chroma — a green you would
15 call grey-green, an ochre, a brick — each still clearing 4.5:1 on its
16 own tint. Colour is never the only channel (the pills carry words),
17 but it is not thrown away either.
18
19 Shadows are real and minimal. tokens.css paints with
20 var(--rst-shadow-*) unconditionally and a theme cannot opt out of a
21 property it must declare, so "no shadows" here means one hairline
22 layer at low alpha rather than a value the CSS parser would drop.
23 You get an edge, not a lift.
24
25 ── One block, both schemes ───────────────────────────────────────────
26 Every token is declared once, as light-dark(<light>, <dark>), under a
27 single :root that sets color-scheme: light dark. The two rules at the
28 bottom are the whole toggle: setting color-scheme on
29 :root[data-theme=…] re-resolves every light-dark() in the file at
30 once, in both directions. Tokens with one value in both schemes — the
31 font stack, the radii — are written plain.
32
33 light-dark() is a colour function: it may only stand where a <color>
34 is expected. So a shadow token wraps its colour in it and writes the
35 geometry once, outside the call — `0 8px 24px light-dark(a, b)`, never
36 `light-dark(0 8px 24px a, …)`, which no browser would accept as a
37 box-shadow.
38
39 ── WCAG 2.2 AA, measured ─────────────────────────────────────────────
40 Normal text needs 4.5:1; large text and UI component boundaries need
41 3:1. Every pair below was computed from these exact hex values, in
42 both schemes. If you change a token, recompute its rows.
43
44 LIGHT ratio requirement
45 --rst-text on --rst-surface 18.88 4.5:1 text
46 --rst-text on --rst-bg 18.88 4.5:1 text
47 --rst-text on --rst-surface-2 17.17 4.5:1 text
48 --rst-text on --rst-accent-soft 16.13 4.5:1 text
49 --rst-text-muted on --rst-surface 8.86 4.5:1 text
50 --rst-text-muted on --rst-bg 8.86 4.5:1 text
51 --rst-text-muted on --rst-surface-2 8.06 4.5:1 text
52 --rst-text-muted on --rst-accent-soft 7.57 4.5:1 text
53 --rst-text-faint on --rst-surface 6.01 4.5:1 text
54 --rst-text-faint on --rst-bg 6.01 4.5:1 text
55 --rst-text-faint on --rst-surface-2 5.46 4.5:1 text
56 --rst-text-faint on --rst-accent-soft 5.13 4.5:1 text
57 --rst-accent on --rst-surface 18.88 4.5:1 text + focus ring
58 --rst-accent on --rst-bg 18.88 4.5:1 text + focus ring
59 --rst-accent on --rst-surface-2 17.17 4.5:1 text
60 --rst-accent on --rst-accent-soft 16.13 4.5:1 text
61 --rst-on-accent on --rst-accent 18.88 4.5:1 button label
62 --rst-on-accent on --rst-accent-strong 21.00 4.5:1 button label, hover
63 --rst-line-strong on --rst-surface 4.54 3:1 control border
64 --rst-line-strong on --rst-bg 4.54 3:1 control border
65 --rst-line-strong on --rst-surface-2 4.13 3:1 control border
66 pill neutral fg on its own tint 8.75 4.5:1 text
67 pill positive fg on its own tint 6.46 4.5:1 text
68 pill warning fg on its own tint 6.09 4.5:1 text
69 pill negative fg on its own tint 7.55 4.5:1 text
70 --rst-on-accent on negative fg (fill) 9.44 4.5:1 danger button label
71
72 DARK ratio requirement
73 --rst-text on --rst-surface 16.01 4.5:1 text
74 --rst-text on --rst-bg 17.12 4.5:1 text
75 --rst-text on --rst-surface-2 16.60 4.5:1 text
76 --rst-text on --rst-accent-soft 13.87 4.5:1 text
77 --rst-text-muted on --rst-surface 8.55 4.5:1 text
78 --rst-text-muted on --rst-bg 9.14 4.5:1 text
79 --rst-text-muted on --rst-surface-2 8.86 4.5:1 text
80 --rst-text-muted on --rst-accent-soft 7.40 4.5:1 text
81 --rst-text-faint on --rst-surface 6.86 4.5:1 text
82 --rst-text-faint on --rst-bg 7.33 4.5:1 text
83 --rst-text-faint on --rst-surface-2 7.11 4.5:1 text
84 --rst-text-faint on --rst-accent-soft 5.94 4.5:1 text
85 --rst-accent on --rst-surface 16.01 4.5:1 text + focus ring
86 --rst-accent on --rst-bg 17.12 4.5:1 text + focus ring
87 --rst-accent on --rst-surface-2 16.60 4.5:1 text
88 --rst-accent on --rst-accent-soft 13.87 4.5:1 text
89 --rst-on-accent on --rst-accent 17.12 4.5:1 button label
90 --rst-on-accent on --rst-accent-strong 19.17 4.5:1 button label, hover
91 --rst-line-strong on --rst-surface 5.54 3:1 control border
92 --rst-line-strong on --rst-bg 5.93 3:1 control border
93 --rst-line-strong on --rst-surface-2 5.75 3:1 control border
94 pill neutral fg on its own tint 9.05 4.5:1 text
95 pill positive fg on its own tint 8.70 4.5:1 text
96 pill warning fg on its own tint 8.82 4.5:1 text
97 pill negative fg on its own tint 7.63 4.5:1 text
98 --rst-on-accent on negative fg (fill) 8.93 4.5:1 danger button label
99
100 The tightest pair in the set is --rst-text-faint on the accent tint —
101 5.13:1 in light, 5.94:1 in dark, against a 4.5:1 floor. Everything
102 else has room, which is what a greyscale palette buys you.
103
104 --rst-line is a hairline divider, not a control border, so 1.4.11's
105 3:1 does not apply to it. Control borders use --rst-line-strong.
106
107 --rst-header-rule is not in the table either, and deliberately so
108 (design doc §6-v2.2): the page header's rule is decoration, not
109 structure — the heading's size, weight and spacing carry the
110 structure — so no contrast floor applies to it and it is not in
111 ui/contrast_test.go's pair table. Do not argue it up to 3:1.
112
113 --rst-shadow-pop, --rst-shadow-knob, --rst-shadow-lift and
114 --rst-overlay are not in the table: they paint a translucent layer
115 over whatever sits underneath, not text over a fixed background, so a
116 contrast ratio does not apply.
117 ──────────────────────────────────────────────────────────────────── */
118
119:root {
120 color-scheme: light dark;
121
122 /* Type: whatever the machine already has. */
123 --rst-font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
124
125 /* Shape: barely rounded. A corner you notice is a decision plain has
126 not made yet. */
127 --rst-radius: 4px;
128 --rst-radius-sm: 3px;
129 --rst-radius-pill: 999px;
130
131 /* Surfaces and lines */
132 --rst-bg: light-dark(#ffffff, #0f0f0f);
133 --rst-surface: light-dark(#ffffff, #171717);
134 --rst-surface-2: light-dark(#f4f4f4, #131313);
135 --rst-line: light-dark(#e0e0e0, #2b2b2b);
136 --rst-line-strong: light-dark(#767676, #8f8f8f);
137
138 /* The page header's rule. plain has no accent hue to fold in, so it
139 is the line and nothing else — the same derived token every theme
140 declares, resolving here to plain grey. Decorative: it carries no
141 contrast floor. */
142 --rst-header-rule: var(--rst-line);
143
144 /* Text */
145 --rst-text: light-dark(#111111, #f2f2f2);
146 --rst-text-muted: light-dark(#4a4a4a, #b3b3b3);
147 --rst-text-faint: light-dark(#636363, #a0a0a0);
148
149 /* Accent: none. The "accent" is the text colour, so a link is text
150 that underlines on hover and a primary button is a filled
151 rectangle. */
152 --rst-accent: light-dark(#111111, #f2f2f2);
153 --rst-accent-strong: light-dark(#000000, #ffffff);
154 --rst-accent-soft: light-dark(#ededed, #242424);
155 --rst-on-accent: light-dark(#ffffff, #0f0f0f);
156
157 /* Status tones: conventional hues held to very low chroma. Muted
158 enough to read as greyscale at a glance, separated enough that an
159 error is not a success. */
160 --rst-tone-neutral-fg: light-dark(#3f3f3f, #c8c8c8);
161 --rst-tone-neutral-bg: light-dark(#eaeaea, #262626);
162 --rst-tone-positive-fg: light-dark(#2e5b3e, #9fc8ac);
163 --rst-tone-positive-bg: light-dark(#e4ebe6, #1a231d);
164 --rst-tone-warning-fg: light-dark(#6a5320, #d3c08a);
165 --rst-tone-warning-bg: light-dark(#efeadd, #262218);
166 --rst-tone-negative-fg: light-dark(#7a2c2c, #dba3a3);
167 --rst-tone-negative-bg: light-dark(#f0e3e3, #2a1c1c);
168
169 /* Depth: one hairline layer. Real values, minimal effect. */
170 --rst-shadow-pop: 0 1px 3px light-dark(rgba(0, 0, 0, 0.14), rgba(0, 0, 0, 0.5));
171 --rst-shadow-knob: 0 1px 1px light-dark(rgba(0, 0, 0, 0.22), rgba(0, 0, 0, 0.4));
172 --rst-shadow-lift: 0 1px 1px light-dark(rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0.3));
173 --rst-overlay: light-dark(rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.6));
174}
175
176/* The whole toggle. Setting color-scheme re-resolves every light-dark()
177 above, so an explicit choice beats the OS in both directions without
178 restating a colour. */
179:root[data-theme="light"] { color-scheme: light; }
180:root[data-theme="dark"] { color-scheme: dark; }
181