carlos / carloku Public

Clone
git clone https://amadan.net/carlos/carloku

Plain git — no account needed to clone.

Download

Download this file

1/* πŸ€– carloku.com/docs β€” the documentation skin.
2
3 Loaded after site.css, never instead of it. Every colour, measure,
4 type stack, focus ring, scrollbar and selection colour here comes
5 from that file's tokens, so both schemes come along for free: the
6 whole palette swaps under `prefers-color-scheme: dark`, which is the
7 one theme mechanism this site has. There is no [data-theme] switch to
8 match, and inventing a second, half-supported one for these pages
9 only would put the docs out of step with / and /get-started.
10
11 What this file adds is the shape site.css has no page for β€” a
12 sidebar, a reference column, and fenced code. It stays inside the
13 house rules in DESIGN.md while it does it:
14
15 - hairlines divide, boxes do not enclose (no bordered cards, and
16 no border heavier than 1px anywhere below);
17 - one purple carries links, focus and the you-are-here mark, over
18 an accent-soft wash β€” the same wash the code chips and the quiet
19 button's hover already use;
20 - a fence wears the terminal's clothes and stays dark in both
21 schemes, because anything terminal-shaped does (--term-*);
22 - mono carries commands and addresses, never prose;
23 - weights come off the variable axis at the tuned steps
24 (480/560/620/640/650/680), and tracking tightens as size grows.
25
26 Same build rules as the rest of the site: nothing fetched, no
27 @import, no JavaScript. Motion is colour-only and short, so the
28 global prefers-reduced-motion kill switch in site.css covers it. */
29
30/* ---------------------------------------------------------------- tokens -- */
31
32:root {
33 /* The two measures site.css lacks, both computed from the real Geist
34 metrics rather than borrowed.
35
36 Body copy sets at 1rem (site.css `body`). Geist's prose advance β€”
37 its letters weighted by English frequency, plus a space every 5.7
38 characters β€” is 0.467em, so a 65-75 character line wants 30.4rem
39 to 35.0rem. --docs-measure sits near the top of that band at
40 roughly 73 characters, and is also site.css's existing lede width,
41 so the docs read at the same measure the rest of the site does.
42
43 The column is wider than the measure because a reference page also
44 carries command lines. The longest in the corpus is 66 characters;
45 in Geist Mono (a true 0.6em advance) at the 0.88rem fences use,
46 that is 34.9rem, and 42rem of column leaves it 4.6rem of room
47 inside the fence's padding. So the ordinary command sits in its box
48 and only a genuinely long one has to scroll. 42rem is also what
49 site.css already caps /get-started's prose at. */
50 --docs-measure: 34rem;
51 --docs-column: 42rem;
52}
53
54/* ------------------------------------------------------------ page frame -- */
55
56/* .docs-body and .language-sh carry nothing of their own, deliberately.
57 site.css's `body` rule already sets the ground, the type and the
58 voice; and the site ships no highlighter, so a fence's language class
59 has nothing to say. Inventing a declaration so the hooks appear in
60 this file would be worse than leaving them alone. */
61
62/* Where you are, in words, above a hairline. The drawn wordmark and the
63 sticky translucent header belong to the pages that are a destination;
64 a reference page gets a line of text and gets out of the way. */
65.brandline {
66 display: flex;
67 align-items: baseline;
68 flex-wrap: wrap;
69 gap: 0.5rem;
70 max-width: var(--wrap);
71 margin-inline: auto;
72 padding: 1.3rem 1.5rem 0.85rem;
73 border-bottom: 1px solid var(--line);
74 font-size: 0.9rem;
75 color: var(--muted);
76}
77.brandline a { color: var(--muted); text-decoration: none; transition: color 120ms ease-out; }
78.brandline a:hover { color: var(--accent); }
79.brandline b { font-weight: 640; letter-spacing: -0.01em; color: var(--ink); }
80.brandline a:hover b { color: inherit; }
81.brandline .here { color: var(--ink); font-weight: 560; }
82
83/* The folio is an address, so it sets as data β€” mono, the way every
84 other identifier on this site does β€” and it is the first thing a
85 narrow viewport gives up. */
86.folio {
87 margin-left: auto;
88 font-family: var(--mono);
89 font-size: 0.78rem;
90 letter-spacing: 0.01em;
91 color: var(--faint);
92}
93@media (max-width: 40rem) { .folio { display: none; } }
94
95/* The skip link is site.css's .skip, whole: parked at top: -3rem and
96 slid into view on :focus-visible. It is the site's own idiom and it
97 already does what these pages need β€” with 40+ sidebar links ahead of
98 the article and no search to route around them, a keyboard user needs
99 the way past. Restating it here would only let the two drift. */
100
101/* ----------------------------------------------------------------- shell -- */
102
103.docs-shell {
104 max-width: var(--wrap);
105 margin-inline: auto;
106 padding: clamp(1.75rem, 4vw, 2.75rem) 1.5rem;
107 display: grid;
108 grid-template-columns: minmax(0, 1fr);
109 gap: 2.25rem;
110 align-items: start;
111}
112
113/* Both children are grid items, so both get min-width: 0. Without it a
114 grid child's min-width: auto refuses to shrink below its widest
115 unbreakable content, and a long command line would scroll the page
116 sideways instead of scrolling inside its own fence. */
117.docs-shell > * { min-width: 0; }
118
119/* Two columns once there is room for both. Below this the nav keeps its
120 document order β€” it is written before the article β€” so it simply
121 stacks above the content, with no toggle and no script. */
122@media (min-width: 60rem) {
123 .docs-shell {
124 grid-template-columns: 15rem minmax(0, 1fr);
125 gap: clamp(2.5rem, 5vw, 4rem);
126 }
127 .docs-nav {
128 position: sticky;
129 top: 1.75rem;
130 max-height: calc(100vh - 3.5rem);
131 overflow-y: auto;
132 overscroll-behavior: contain;
133 }
134}
135
136/* ------------------------------------------------------------------- nav -- */
137
138/* Every link is padded rather than pulled out with a negative margin:
139 the sidebar becomes a scroll container at the two-column breakpoint,
140 and an overhang inside `overflow-y: auto` would give the nav its own
141 horizontal scrollbar. The labels above are padded to match, so the
142 column still aligns with itself. */
143.docs-nav { font-size: 0.94rem; }
144.docs-nav ul { list-style: none; padding: 0; }
145.docs-nav li { margin-top: 0.1rem; }
146
147.docs-nav a {
148 display: block;
149 padding: 0.26rem 0.55rem;
150 border-radius: 0.4rem;
151 color: var(--muted);
152 font-weight: 480;
153 text-decoration: none;
154 transition: color 120ms ease-out, background 120ms ease-out;
155}
156.docs-nav a:hover { color: var(--ink); }
157
158/* The page you are on, marked with the accent over the accent-soft wash
159 β€” the same pair the code chips, the step numerals and the quiet
160 button's hover already use, so the mark is house vocabulary rather
161 than a new device. Keyed to both the class the template stamps and
162 the aria-current it stamps beside it, so the mark cannot outlive
163 either one. */
164.docs-nav a.active,
165.docs-nav a[aria-current="page"] {
166 background: var(--accent-soft);
167 color: var(--accent);
168 font-weight: 560;
169}
170
171.docs-nav-title {
172 margin-bottom: 1.15rem;
173 padding-inline: 0.55rem;
174 font-size: 1.05rem;
175 font-weight: 640;
176 letter-spacing: -0.01em;
177}
178.docs-nav-title a { color: var(--ink); font-weight: inherit; }
179.docs-nav-title a:hover { color: var(--accent); }
180
181/* A section label, not a heading and not data: it stays in the voice
182 face at a quiet weight above a hairline. This site never sets tracked
183 small caps, and importing them here to say "documentation" would be
184 borrowing a convention rather than using ours. */
185.docs-nav-section {
186 margin-top: 1.6rem;
187 padding-top: 0.9rem;
188 margin-bottom: 0.5rem;
189 padding-inline: 0.55rem;
190 border-top: 1px solid var(--line);
191 font-size: 0.82rem;
192 font-weight: 560;
193 color: var(--faint);
194}
195.docs-nav-title + .docs-nav-section { margin-top: 0; padding-top: 0; border-top: 0; }
196
197/* The open page's own sections, indented under it against a hairline. */
198.docs-subnav {
199 margin: 0.35rem 0 0.7rem 0.85rem;
200 padding-left: 0.5rem;
201 border-left: 1px solid var(--line);
202 font-size: 0.875rem;
203}
204.docs-subnav li { margin-top: 0; }
205.docs-subnav a {
206 padding: 0.16rem 0.45rem;
207 font-weight: 400;
208 color: var(--faint);
209}
210.docs-subnav a:hover { color: var(--accent); }
211
212/* --------------------------------------------------------------- article -- */
213
214.docs-article { max-width: var(--docs-column); min-width: 0; }
215
216.docs-article h1 {
217 font-size: clamp(2rem, 4.4vw, 2.7rem);
218 line-height: 1.06;
219 letter-spacing: -0.032em;
220 font-weight: 680;
221 text-wrap: balance;
222 /* site.css's element-level h1/h2 rules carry a margin-bottom for the
223 landing page's rhythm. Here the following element owns the gap, so
224 the heading gives it up rather than adding to it. */
225 margin-bottom: 0;
226}
227.docs-article h1 + p {
228 margin-top: 1.15rem;
229 font-size: 1.12rem;
230 line-height: 1.65;
231 max-width: var(--docs-measure);
232}
233
234/* A group opens on a full hairline β€” the same divider /get-started uses
235 between its sections. The reference reads as a run of divided
236 entries, never as a stack of boxes. */
237.docs-article h2 {
238 margin-top: clamp(2.75rem, 5.5vw, 4rem);
239 padding-top: clamp(1.6rem, 3.2vw, 2.25rem);
240 border-top: 1px solid var(--line);
241 font-size: clamp(1.35rem, 2.4vw, 1.7rem);
242 line-height: 1.2;
243 letter-spacing: -0.025em;
244 font-weight: 650;
245 text-wrap: balance;
246 margin-bottom: 0;
247 /* No measure cap: the hairline is the divider, so it runs the width of
248 the column rather than stopping short of the fences beneath it. The
249 longest heading in the corpus is 37 characters β€” 29rem at this size
250 β€” so nothing wraps for want of the cap. */
251}
252
253/* h3/h4 and the block elements further down are the floor for markdown
254 this corpus does not use yet β€” it is authored in this repo and grows
255 by hand. Kept deliberately short: enough that a new page cannot land
256 unstyled, not so much that it becomes a theme nobody asked for. */
257.docs-article h3 {
258 margin-top: 2.2rem;
259 font-size: 1.08rem;
260 font-weight: 620;
261 letter-spacing: -0.01em;
262 color: var(--ink);
263}
264.docs-article h4 {
265 margin-top: 1.8rem;
266 font-size: 0.98rem;
267 font-weight: 620;
268 letter-spacing: -0.01em;
269 color: var(--ink);
270}
271
272.docs-article :is(h1, h2, h3, h4) { scroll-margin-top: 1.5rem; }
273
274.docs-article p {
275 margin-top: 1.05rem;
276 max-width: var(--docs-measure);
277 color: var(--muted);
278 text-wrap: pretty;
279}
280.docs-article :is(h2, h3, h4) + p { margin-top: 0.85rem; }
281.docs-article strong { color: var(--ink); font-weight: 620; }
282.docs-article em { color: var(--ink); }
283
284.docs-article ul:not(.docs-cards),
285.docs-article ol {
286 margin-top: 1rem;
287 padding-left: 1.2rem;
288 max-width: var(--docs-measure);
289 color: var(--muted);
290}
291/* Scoped with a child combinator rather than `.docs-article li + li`,
292 which would outrank `.docs-cards li` below and break the index
293 grid's row alignment. */
294.docs-article ul:not(.docs-cards) > li + li,
295.docs-article ol > li + li { margin-top: 0.45rem; }
296.docs-article blockquote {
297 margin-top: 1.15rem;
298 padding-left: 1.1rem;
299 border-left: 1px solid var(--line-strong);
300 max-width: var(--docs-measure);
301 color: var(--faint);
302 font-size: 0.95rem;
303}
304.docs-article hr {
305 margin-block: 2.25rem;
306 border: 0;
307 border-top: 1px solid var(--line);
308}
309.docs-article table {
310 margin-top: 1.25rem;
311 width: 100%;
312 border-collapse: collapse;
313 font-size: 0.95rem;
314}
315.docs-article :is(th, td) {
316 text-align: left;
317 padding: 0.6rem 0.9rem 0.6rem 0;
318 border-top: 1px solid var(--line);
319 color: var(--muted);
320 vertical-align: baseline;
321}
322.docs-article th { color: var(--ink); font-weight: 620; }
323
324.docs-article a {
325 color: var(--accent);
326 text-decoration: none;
327}
328.docs-article a:hover { text-decoration: underline; text-underline-offset: 0.2em; }
329
330/* ------------------------------------------------------------------ code -- */
331
332/* A fence is a box that scrolls itself: the page must never scroll
333 sideways because a command was long. It wears the terminal's clothes
334 and keeps them in both schemes, under the rule that anything
335 terminal-shaped sits on Terminal Black β€” the same clothes
336 /get-started's blocks already wear, and the reason a Carloku page
337 reads as a Carloku page. */
338.docs-article pre {
339 margin: 1.15rem 0 0;
340 max-width: 100%;
341 min-width: 0;
342 overflow-x: auto;
343 overscroll-behavior-x: contain;
344 -webkit-overflow-scrolling: touch;
345 padding: 1rem 1.2rem;
346 border: 1px solid var(--term-line);
347 border-radius: 0.7rem;
348 background: var(--term-bg);
349 color: var(--term-ink);
350 font-family: var(--mono);
351 font-size: 0.88rem;
352 line-height: 1.7;
353}
354.docs-article p + pre { margin-top: 0.9rem; }
355
356/* Inline code is a chip: mono on an accent-soft wash, the way the
357 commands appear in prose everywhere else on this site. Inside a fence
358 that chip would tile the whole block, so it is undone there. */
359.docs-article code {
360 font-family: var(--mono);
361 font-size: 0.88em;
362 background: var(--accent-soft);
363 color: var(--accent-ink);
364 padding: 0.12em 0.4em;
365 border-radius: 0.3em;
366}
367.docs-article pre code {
368 display: block;
369 padding: 0;
370 border-radius: 0;
371 background: none;
372 color: inherit;
373 font-size: inherit;
374 white-space: pre;
375}
376.docs-article a code { color: inherit; }
377
378/* ------------------------------------------------------------- the index -- */
379
380/* The index's entries: a label and a line saying what is inside. They
381 are not cards and they are not boxed β€” this site separates siblings
382 with a single hairline and whitespace, the way the feature list and
383 the guide's sections do. Two ruled columns of contents, nothing to
384 lift off the page. */
385.docs-cards {
386 margin-top: 1.25rem;
387 display: grid;
388 grid-template-columns: minmax(0, 1fr);
389 column-gap: 2.5rem;
390 list-style: none;
391 padding: 0;
392}
393@media (min-width: 46rem) {
394 .docs-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
395}
396.docs-cards li {
397 min-width: 0;
398 margin-top: 0;
399 padding: 1.05rem 0 1.15rem;
400 border-top: 1px solid var(--line);
401}
402.docs-cards a { display: inline-block; text-decoration: none; }
403.docs-cards a strong {
404 font-size: 1.05rem;
405 font-weight: 620;
406 letter-spacing: -0.01em;
407 color: var(--ink);
408 transition: color 120ms ease-out;
409}
410.docs-cards a:hover strong { color: var(--accent); }
411.docs-cards a:hover { text-decoration: none; }
412.docs-cards span {
413 display: block;
414 margin-top: 0.25rem;
415 font-size: 0.95rem;
416 color: var(--muted);
417 text-wrap: pretty;
418}
419
420/* The index's h2s head a grid rather than prose, so they need less air
421 under them and no measure cap. */
422.docs-article h2 + .docs-cards { margin-top: 1.4rem; }
423
424/* ------------------------------------------------------------------ feet -- */
425
426/* Qualified so it outranks `.docs-article p` β€” this is a <p> inside the
427 article, and the unqualified class would lose the colour and the top
428 margin to it. */
429.docs-article .docs-foot {
430 margin-top: clamp(2.75rem, 5.5vw, 4rem);
431 padding-top: 1.15rem;
432 border-top: 1px solid var(--line);
433 max-width: var(--docs-measure);
434 font-size: 0.9rem;
435 color: var(--faint);
436}
437.docs-article .docs-foot a { color: var(--faint); }
438.docs-article .docs-foot a:hover { color: var(--accent); }
439
440/* site.css's <footer> already gives the rule, the muted voice and the
441 block padding; these pages have no .wrap element inside it, so the
442 measure and the gutters are what is left to supply. */
443.docs-sitefoot {
444 max-width: var(--wrap);
445 margin-inline: auto;
446 padding-inline: 1.5rem;
447}
448.docs-provenance { font-size: 0.85rem; color: var(--faint); }
449.docs-provenance a { color: var(--faint); }
450.docs-provenance a:hover { color: var(--accent); }
451