rastrillo / fiesta Public

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

Plain git — no account needed to clone.

Download

Download this file

1/* day — rastrillo's default theme: an everyday blue on white and grey.
2 Structure lives in tokens.css; this file is colour, type and shape.
3 rastrillo new writes it once as static/theme.css.
4
5 The look: the ordinary, personable interface. A white page, a plain
6 grey text scale, one friendly blue that means "this does something",
7 and the conventional green/amber/red for status. Nothing here is
8 trying to be memorable — day is the theme an app ships on while it
9 works out what it wants to look like, and the one that never gets in
10 the way of the content. Semantic status colours are functional and
11 never the accent, so a pill can never be mistaken for a link.
12
13 ── One block, both schemes ───────────────────────────────────────────
14 Every token is declared once, as light-dark(<light>, <dark>), under a
15 single :root that sets color-scheme: light dark. The browser picks the
16 half that matches the resolved scheme, so there is no second copy of
17 the palette to keep in sync and no way to author dark half-done. The
18 two rules at the bottom are the whole toggle: setting color-scheme on
19 :root[data-theme=…] re-resolves every light-dark() in the file at
20 once, in both directions, which is why an explicit choice beats the OS
21 without restating a single colour.
22
23 Tokens with one value in both schemes — the font stack, the radii —
24 are written plain, because light-dark(x, x) says nothing twice.
25
26 light-dark() is a colour function: it may only stand where a <color>
27 is expected. So a shadow token wraps its colour in it and writes the
28 geometry once, outside the call — `0 8px 24px light-dark(a, b)`, never
29 `light-dark(0 8px 24px a, …)`, which no browser would accept as a
30 box-shadow.
31
32 ── The shape axis ────────────────────────────────────────────────────
33 Radius and shadow are the theme's now, not tokens.css's: a theme that
34 can only change colour cannot change how an app feels. day is soft and
35 unremarkable — 8px cards, 6px controls, shadows with a wide blur and
36 little alpha, the depth of paper resting on paper.
37
38 ── WCAG 2.2 AA, measured ─────────────────────────────────────────────
39 Normal text needs 4.5:1; large text and UI component boundaries need
40 3:1. Every pair below was computed from these exact hex values, in
41 both schemes. If you change a token, recompute its rows.
42
43 LIGHT ratio requirement
44 --rst-text on --rst-surface 16.91 4.5:1 text
45 --rst-text on --rst-bg 16.91 4.5:1 text
46 --rst-text on --rst-surface-2 15.77 4.5:1 text
47 --rst-text on --rst-accent-soft 15.21 4.5:1 text
48 --rst-text-muted on --rst-surface 7.56 4.5:1 text
49 --rst-text-muted on --rst-bg 7.56 4.5:1 text
50 --rst-text-muted on --rst-surface-2 7.05 4.5:1 text
51 --rst-text-muted on --rst-accent-soft 6.80 4.5:1 text
52 --rst-text-faint on --rst-surface 5.29 4.5:1 text
53 --rst-text-faint on --rst-bg 5.29 4.5:1 text
54 --rst-text-faint on --rst-surface-2 4.93 4.5:1 text
55 --rst-text-faint on --rst-accent-soft 4.76 4.5:1 text
56 --rst-accent on --rst-surface 5.28 4.5:1 text + focus ring
57 --rst-accent on --rst-bg 5.28 4.5:1 text + focus ring
58 --rst-accent on --rst-surface-2 4.93 4.5:1 text
59 --rst-accent on --rst-accent-soft 4.75 4.5:1 text
60 --rst-on-accent on --rst-accent 5.28 4.5:1 button label
61 --rst-on-accent on --rst-accent-strong 7.18 4.5:1 button label, hover
62 --rst-line-strong on --rst-surface 3.63 3:1 control border
63 --rst-line-strong on --rst-bg 3.63 3:1 control border
64 --rst-line-strong on --rst-surface-2 3.39 3:1 control border
65 pill neutral fg on its own tint 9.02 4.5:1 text
66 pill positive fg on its own tint 6.49 4.5:1 text
67 pill warning fg on its own tint 6.15 4.5:1 text
68 pill negative fg on its own tint 5.30 4.5:1 text
69 --rst-on-accent on negative fg (fill) 6.47 4.5:1 danger button label
70
71 DARK ratio requirement
72 --rst-text on --rst-surface 13.74 4.5:1 text
73 --rst-text on --rst-bg 15.32 4.5:1 text
74 --rst-text on --rst-surface-2 14.63 4.5:1 text
75 --rst-text on --rst-accent-soft 13.02 4.5:1 text
76 --rst-text-muted on --rst-surface 7.56 4.5:1 text
77 --rst-text-muted on --rst-bg 8.43 4.5:1 text
78 --rst-text-muted on --rst-surface-2 8.05 4.5:1 text
79 --rst-text-muted on --rst-accent-soft 7.16 4.5:1 text
80 --rst-text-faint on --rst-surface 6.33 4.5:1 text
81 --rst-text-faint on --rst-bg 7.06 4.5:1 text
82 --rst-text-faint on --rst-surface-2 6.74 4.5:1 text
83 --rst-text-faint on --rst-accent-soft 6.00 4.5:1 text
84 --rst-accent on --rst-surface 6.95 4.5:1 text + focus ring
85 --rst-accent on --rst-bg 7.75 4.5:1 text + focus ring
86 --rst-accent on --rst-surface-2 7.40 4.5:1 text
87 --rst-accent on --rst-accent-soft 6.59 4.5:1 text
88 --rst-on-accent on --rst-accent 7.86 4.5:1 button label
89 --rst-on-accent on --rst-accent-strong 10.29 4.5:1 button label, hover
90 --rst-line-strong on --rst-surface 4.26 3:1 control border
91 --rst-line-strong on --rst-bg 4.75 3:1 control border
92 --rst-line-strong on --rst-surface-2 4.53 3:1 control border
93 pill neutral fg on its own tint 8.44 4.5:1 text
94 pill positive fg on its own tint 10.18 4.5:1 text
95 pill warning fg on its own tint 9.62 4.5:1 text
96 pill negative fg on its own tint 7.85 4.5:1 text
97 --rst-on-accent on negative fg (fill) 8.99 4.5:1 danger button label
98
99 The tightest pair in the set is --rst-accent on --rst-accent-soft in
100 light, at 4.75:1 against a 4.5:1 floor. Put a token on a surface not
101 listed above and you are guessing; recompute first.
102
103 --rst-line is a hairline divider between rows, not a control border or
104 a meaningful graphic, so 1.4.11's 3:1 does not apply to it. Control
105 borders use --rst-line-strong, which does clear 3:1.
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 Pagination chips are the one deliberate exception: they are bordered
114 with --rst-line rather than --rst-line-strong, because a page strip
115 ringed in hard outlines shouts louder than the list it belongs to.
116 1.4.11 is satisfied without that border — each chip's meaning is
117 carried by its text label at 4.5:1 or better, and the current page
118 adds a filled background, a heavier weight and aria-current on top.
119
120 --rst-shadow-pop, --rst-shadow-knob, --rst-shadow-lift and
121 --rst-overlay are not in the table: they paint a translucent shadow or
122 scrim over whatever sits underneath, not text over a fixed
123 background, so a contrast ratio does not apply. The scrim deepens in
124 dark, matching --rst-shadow-pop's own jump: black reads lighter
125 against a dark backdrop, so the overlay needs more alpha to still
126 read as a dimming layer.
127 ──────────────────────────────────────────────────────────────────── */
128
129:root {
130 color-scheme: light dark;
131
132 /* Type: the family only. Sizes and spacing are structural and stay in
133 tokens.css. */
134 --rst-font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
135
136 /* Shape: soft, ordinary, unremarkable. */
137 --rst-radius: 8px;
138 --rst-radius-sm: 6px;
139 --rst-radius-pill: 999px;
140
141 /* Surfaces and lines */
142 --rst-bg: light-dark(#ffffff, #111418);
143 --rst-surface: light-dark(#ffffff, #1a1f26);
144 --rst-surface-2: light-dark(#f6f7f8, #15191f);
145 --rst-line: light-dark(#e5e7eb, #2a3038);
146 --rst-line-strong: light-dark(#7f8792, #79828e);
147
148 /* The page header's rule, derived rather than authored: the accent
149 folded into the line at 18%, so a theme that changes its accent
150 gets a matching rule with no second value to keep in step. day's
151 is barely there — a hairline you would call grey until you put it
152 beside plain's. Decorative: it carries no contrast floor. */
153 --rst-header-rule: color-mix(in oklab, var(--rst-accent) 18%, var(--rst-line));
154
155 /* Text */
156 --rst-text: light-dark(#1a1d21, #e8eaed);
157 --rst-text-muted: light-dark(#4b5563, #a8b0ba);
158 --rst-text-faint: light-dark(#656c78, #98a1ac);
159
160 /* Accent */
161 --rst-accent: light-dark(#2464e0, #7ba7ff);
162 --rst-accent-strong: light-dark(#1a4fc0, #a3c0ff);
163 --rst-accent-soft: light-dark(#eef3fe, #17233a);
164 --rst-on-accent: light-dark(#ffffff, #0b1220);
165
166 /* Status tones */
167 --rst-tone-neutral-fg: light-dark(#374151, #c3c9d1);
168 --rst-tone-neutral-bg: light-dark(#eef0f2, #262c34);
169 --rst-tone-positive-fg: light-dark(#166534, #6ee7a8);
170 --rst-tone-positive-bg: light-dark(#dcfce7, #10281c);
171 --rst-tone-warning-fg: light-dark(#854d0e, #f0c46a);
172 --rst-tone-warning-bg: light-dark(#fef3c7, #2c2110);
173 --rst-tone-negative-fg: light-dark(#b91c1c, #f79aa0);
174 --rst-tone-negative-bg: light-dark(#fee2e2, #331819);
175
176 /* Depth */
177 --rst-shadow-pop: 0 8px 24px light-dark(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.5));
178 --rst-shadow-knob: 0 1px 2px rgba(0, 0, 0, 0.3);
179 --rst-shadow-lift: 0 1px 2px rgba(0, 0, 0, 0.08);
180 --rst-overlay: light-dark(rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0.6));
181}
182
183/* The whole toggle. Setting color-scheme re-resolves every light-dark()
184 above, so an explicit choice beats the OS in both directions without
185 restating a colour. */
186:root[data-theme="light"] { color-scheme: light; }
187:root[data-theme="dark"] { color-scheme: dark; }
188