main
1/* ============================================================
2 Flux Design Sandbox
3 Combining ideas from: Beat Hagenlocher, Gwern, Daniel Miessler,
4 Christian Tietze, Crafting Interpreters, Tufte CSS, David Larlet,
5 Adactio, Butterick, Pawel Grzybek
6 ============================================================ */
7
8/* --- Design Tokens --- */
9:root {
10 /* Typography */
11 --font-body: "Iowan Old Style", "Palatino Linotype", "URW Palladio L",
12 P052, Palatino, serif;
13 --font-heading: Seravek, "Gill Sans Nova", Ubuntu, Calibri, "DejaVu Sans",
14 source-sans-pro, sans-serif;
15 --font-mono: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo,
16 Consolas, "DejaVu Sans Mono", monospace;
17
18 /* Vertical rhythm — everything derives from this */
19 --base-font-size: 18px;
20 --base-line-height: 1.6;
21 --lh: calc(var(--base-font-size) * var(--base-line-height));
22
23 /* Colors — warm parchment (Miessler-inspired) */
24 --color-bg: #f4f1eb;
25 --color-bg-alt: #eae7e0;
26 --color-bg-card: #fff;
27 --color-text: #2c2c2c;
28 --color-text-muted: #6b6b6b;
29 --color-text-faint: #999;
30 --color-accent: #4a7c59;
31 --color-accent-soft: rgba(74, 124, 89, 0.08);
32 --color-link: #2a6496;
33 --color-link-hover: #1a4060;
34 --color-border: #ddd;
35 --color-border-light: #eee;
36 --color-code-bg: #f0ece4;
37 --color-tag-bg: var(--color-accent-soft);
38 --color-tag-text: var(--color-accent);
39 --color-new: #2d8a56;
40 --color-updated: #7a6c2a;
41 --color-sidenote-bg: transparent;
42 --color-theme-toggle-bg: var(--color-bg-alt);
43 --color-theme-toggle-fg: var(--color-text-muted);
44
45 /* Syntax highlighting — Tonsky (light defaults) */
46 --hl-string-bg: #e0f6e0;
47 --hl-string-fg: #1a3a1a;
48 --hl-comment-bg: #f8f0d0;
49 --hl-comment-fg: #5a4a1a;
50 --hl-def-bg: #ecedff;
51 --hl-def-fg: #1a1a3a;
52 --hl-constant: #531ab6;
53 --hl-number: #531ab6;
54 --hl-type: #595959;
55
56 /* Layout */
57 --content-width: 640px;
58 --content-padding: 1.5rem;
59 --margin-note-width: 220px;
60}
61
62/* Dark mode handled entirely by [data-theme="dark"] below.
63 No @media query needed — JS sets data-theme on load. */
64
65/* --- Theme & Accent Controls --- */
66
67.site-controls {
68 position: fixed;
69 top: 1rem;
70 right: 1rem;
71 display: flex;
72 align-items: center;
73 gap: 0.3em;
74 background: var(--color-bg-alt);
75 border: 1px solid var(--color-border);
76 border-radius: 99px;
77 padding: 0.3em 0.5em;
78 z-index: 100;
79}
80
81.theme-toggle {
82 background: none;
83 border: none;
84 cursor: pointer;
85 font-size: 1rem;
86 line-height: 1;
87 padding: 0.15em;
88 color: var(--color-text-muted);
89 transition: color 0.2s;
90}
91
92.theme-toggle:hover {
93 color: var(--color-text);
94}
95
96.accent-dot {
97 width: 1em;
98 height: 1em;
99 border-radius: 50%;
100 border: 2px solid transparent;
101 cursor: pointer;
102 transition: all 0.2s;
103 padding: 0;
104 background: none;
105}
106
107.accent-dot:hover {
108 transform: scale(1.25);
109}
110
111.accent-dot.active {
112 border-color: var(--color-text);
113 box-shadow: 0 0 0 1px var(--color-bg);
114}
115
116.accent-divider {
117 width: 1px;
118 height: 1.2em;
119 background: var(--color-border);
120 margin: 0 0.15em;
121}
122
123/* Force light/dark via data attribute, overriding prefers-color-scheme */
124[data-theme="light"] {
125 --color-bg: #f4f1eb;
126 --color-bg-alt: #eae7e0;
127 --color-bg-card: #fff;
128 --color-text: #2c2c2c;
129 --color-text-muted: #6b6b6b;
130 --color-text-faint: #999;
131 --color-accent: #4a7c59;
132 --color-accent-soft: rgba(74, 124, 89, 0.08);
133 --color-link: #2a6496;
134 --color-link-hover: #1a4060;
135 --color-border: #ddd;
136 --color-border-light: #eee;
137 --color-code-bg: #f0ece4;
138 --color-tag-bg: var(--color-accent-soft);
139 --color-tag-text: var(--color-accent);
140 --color-new: #2d8a56;
141 --color-updated: #7a6c2a;
142 --hl-string-bg: #e0f6e0;
143 --hl-string-fg: #1a3a1a;
144 --hl-comment-bg: #f8f0d0;
145 --hl-comment-fg: #5a4a1a;
146 --hl-def-bg: #ecedff;
147 --hl-def-fg: #1a1a3a;
148 --hl-constant: #531ab6;
149 --hl-number: #531ab6;
150 --hl-type: #595959;
151}
152
153[data-theme="light"] a {
154 text-decoration-color: rgba(42, 100, 150, 0.3);
155}
156
157[data-theme="dark"] {
158 --color-bg: #1a1a1f;
159 --color-bg-alt: #222228;
160 --color-bg-card: rgba(51, 51, 57, 1);
161 --color-text: #d4d4d8;
162 --color-text-muted: #9ca3af;
163 --color-text-faint: #6b7280;
164 --color-accent: #6aab7b;
165 --color-accent-soft: rgba(106, 171, 123, 0.1);
166 --color-link: #7daacd;
167 --color-link-hover: #a3c4df;
168 --color-border: #333;
169 --color-border-light: #2a2a2f;
170 --color-code-bg: #2a2a30;
171 --color-tag-bg: var(--color-accent-soft);
172 --color-tag-text: var(--color-accent);
173 --color-new: #4ade80;
174 --color-updated: #d4aa3c;
175 --hl-string-bg: #1a2e1a;
176 --hl-string-fg: #b0d8b0;
177 --hl-comment-bg: #2a2518;
178 --hl-comment-fg: #d4c89a;
179 --hl-def-bg: #1a1a2e;
180 --hl-def-fg: #a0a8d0;
181 --hl-constant: #b6a0ff;
182 --hl-number: #b6a0ff;
183 --hl-type: #989898;
184}
185
186[data-theme="dark"] a {
187 text-decoration-color: rgba(125, 170, 205, 0.3);
188}
189
190/* --- Reset & Base --- */
191*,
192*::before,
193*::after {
194 box-sizing: border-box;
195 margin: 0;
196 padding: 0;
197}
198
199html {
200 font-size: var(--base-font-size);
201 line-height: var(--base-line-height);
202 -webkit-text-size-adjust: 100%;
203 scroll-behavior: smooth;
204}
205
206body {
207 font-family: var(--font-body);
208 color: var(--color-text);
209 background-color: var(--color-bg);
210 max-width: calc(var(--content-width) + var(--margin-note-width) + 4rem);
211 margin: 0 auto;
212 padding: var(--content-padding);
213 padding-top: 3rem;
214}
215
216/* --- Vertical Rhythm ---
217 Using lh units where supported, calc fallback otherwise.
218 Butterick: 120-145% line spacing.
219 Pawel Grzybek: lh/rlh units for rhythm.
220 Christian Tietze: consistent custom property spacing. */
221
222p,
223ul,
224ol,
225blockquote,
226pre,
227table,
228figure,
229.stream-card {
230 margin-bottom: 1lh;
231 margin-bottom: var(--lh);
232}
233
234/* --- Typography --- */
235
236h1,
237h2,
238h3,
239h4 {
240 font-family: var(--font-heading);
241 font-weight: 600;
242 line-height: 1.25;
243 color: var(--color-text);
244}
245
246h1 {
247 font-size: 2rem;
248 margin-bottom: 0.5lh;
249 margin-bottom: calc(var(--lh) * 0.5);
250 letter-spacing: -0.02em;
251}
252
253h2 {
254 font-size: 1.4rem;
255 margin-top: 2lh;
256 margin-top: calc(var(--lh) * 2);
257 margin-bottom: 0.5lh;
258 margin-bottom: calc(var(--lh) * 0.5);
259}
260
261/* Crafting Interpreters: § anchor on hover */
262h2, h3, h4 {
263 position: relative;
264}
265h2 a.anchor,
266h3 a.anchor,
267h4 a.anchor {
268 position: absolute;
269 left: -1.5em;
270 color: transparent;
271 text-decoration: none;
272 font-weight: normal;
273 transition: color 0.2s ease;
274}
275h2:hover a.anchor,
276h3:hover a.anchor,
277h4:hover a.anchor {
278 color: var(--color-text-faint);
279}
280
281h3 {
282 font-size: 1.15rem;
283 margin-top: 1.5lh;
284 margin-top: calc(var(--lh) * 1.5);
285 margin-bottom: 0.25lh;
286 margin-bottom: calc(var(--lh) * 0.25);
287 font-style: italic;
288}
289
290.subtitle {
291 font-family: var(--font-body);
292 font-size: 1.1rem;
293 font-weight: normal;
294 font-style: italic;
295 color: var(--color-text-muted);
296 margin-top: -0.25lh;
297 margin-top: calc(var(--lh) * -0.25);
298 margin-bottom: 1.5lh;
299 margin-bottom: calc(var(--lh) * 1.5);
300}
301
302/* --- Links ---
303 Adactio: styled underlines with text-decoration-* */
304
305a {
306 color: var(--color-link);
307 text-decoration-line: underline;
308 text-decoration-color: rgba(42, 100, 150, 0.3);
309 text-decoration-thickness: 1px;
310 text-underline-offset: 0.15em;
311 transition: color 0.2s ease, text-decoration-color 0.2s ease;
312}
313
314a:hover {
315 color: var(--color-link-hover);
316 text-decoration-color: var(--color-link-hover);
317}
318
319/* Dark link underline color handled by [data-theme="dark"] below. */
320
321/* --- Lists --- */
322
323ul {
324 padding-left: 1.5em;
325 list-style-type: "✧ "; /* white star */
326}
327
328ol {
329 padding-left: 1.5em;
330}
331
332li {
333 margin-bottom: 0.25lh;
334 margin-bottom: calc(var(--lh) * 0.25);
335}
336
337/* --- Blockquotes ---
338 Stylish, with subtle background, accent border, optional attribution */
339
340blockquote {
341 border-left: 3px solid var(--color-accent);
342 padding: 1em 1.2em;
343 margin-left: 0;
344 margin-right: 0;
345 color: var(--color-text-muted);
346 background: var(--color-accent-soft);
347 border-radius: 0 6px 6px 0;
348 position: relative;
349}
350
351blockquote::before {
352 content: "\201C";
353 position: absolute;
354 top: -0.15em;
355 left: 0.15em;
356 font-size: 3rem;
357 line-height: 1;
358 color: var(--color-accent);
359 opacity: 0.2;
360 font-family: Georgia, serif;
361}
362
363blockquote p {
364 margin-bottom: 0.5em;
365}
366
367blockquote p:last-child {
368 margin-bottom: 0;
369}
370
371blockquote cite,
372blockquote .attribution {
373 display: block;
374 margin-top: 0.5em;
375 font-size: 0.85em;
376 font-style: normal;
377 color: var(--color-text-faint);
378 font-family: var(--font-heading);
379}
380
381blockquote cite::before,
382blockquote .attribution::before {
383 content: "— ";
384}
385
386/* Epigraph style: centered, no border, more typographic */
387blockquote.epigraph {
388 border-left: none;
389 background: transparent;
390 text-align: center;
391 max-width: 80%;
392 margin-left: auto;
393 margin-right: auto;
394 padding: 1.5em 0;
395 font-size: 1.1em;
396}
397
398blockquote.epigraph::before {
399 content: none;
400}
401
402blockquote.epigraph cite {
403 text-align: center;
404}
405
406/* Pullquote: larger, accent-colored, editorial */
407blockquote.pullquote {
408 border-left: none;
409 border-top: 2px solid var(--color-accent);
410 border-bottom: 2px solid var(--color-accent);
411 border-radius: 0;
412 background: transparent;
413 padding: 1em 0;
414 font-size: 1.15em;
415 font-style: italic;
416 color: var(--color-accent);
417 text-align: center;
418}
419
420blockquote.pullquote::before {
421 content: none;
422}
423
424/* --- Code ---
425 Monospace, subtle background, respects rhythm */
426
427code {
428 font-family: var(--font-mono);
429 font-size: 0.85em;
430 background: var(--color-code-bg);
431 padding: 0.1em 0.35em;
432 border-radius: 3px;
433}
434
435pre {
436 background: var(--color-code-bg);
437 padding: 1em 1.2em;
438 border-radius: 6px;
439 overflow-x: auto;
440 font-size: 0.85rem;
441 line-height: 1.5;
442}
443
444pre code {
445 background: none;
446 padding: 0;
447}
448
449/* --- Syntax Highlighting ---
450 Tonsky-inspired: minimal colors, background-based for key elements.
451 Only 4 semantic categories get color:
452 1. Strings → green bg
453 2. Constants → purple/magenta
454 3. Definitions → blue bg
455 4. Comments → warm/yellow bg
456 Everything else: default foreground. No bold. */
457
458/* All --hl-* vars defined in :root, [data-theme="light"], and
459 [data-theme="dark"] blocks above — no duplicate needed here. */
460
461/* Strings: green background, dark text */
462pre .s, pre .s1, pre .s2, pre .string,
463pre .str {
464 background: var(--hl-string-bg);
465 color: var(--hl-string-fg);
466 border-radius: 2px;
467 padding: 0 0.15em;
468}
469
470/* Comments: warm yellow background */
471pre .c, pre .c1, pre .cm, pre .comment,
472pre .cmt {
473 background: var(--hl-comment-bg);
474 color: var(--hl-comment-fg);
475 border-radius: 2px;
476 padding: 0 0.15em;
477 font-style: italic;
478}
479
480/* Function/method definitions: blue background */
481pre .nf, pre .fm, pre .def,
482pre .fn-def {
483 background: var(--hl-def-bg);
484 color: var(--hl-def-fg);
485 border-radius: 2px;
486 padding: 0 0.15em;
487}
488
489/* Constants, numbers, booleans: purple text (no bg — sparse enough) */
490pre .mi, pre .mf, pre .mb, pre .mh, pre .mo,
491pre .num, pre .const,
492pre .kc {
493 color: var(--hl-constant);
494}
495
496/* Types: dimmed (they're everywhere in Go/Rust) */
497pre .nc, pre .type, pre .typ {
498 color: var(--hl-type);
499}
500
501/* Everything else: default text color — keywords, variables, calls,
502 operators, punctuation. No color, no bold. This IS the code. */
503pre .k, pre .kw, pre .kd, pre .kr, /* keywords */
504pre .nb, pre .bp, /* builtins */
505pre .n, pre .na, pre .nx, /* names/attrs */
506pre .o, pre .p, /* operators/punctuation */
507pre .nv, pre .vi, pre .var, /* variables */
508pre .nd /* decorators */
509{
510 color: inherit;
511 font-weight: normal;
512 font-style: normal;
513}
514
515/* --- Org-mode htmlize class mappings (org-html-htmlize-output-type 'css) ---
516 Maps org-* face classes to Tonsky highlighting.
517 These classes come from Emacs font-lock faces via htmlize. */
518
519/* Strings → green background */
520pre .org-string,
521pre .org-doc {
522 background: var(--hl-string-bg);
523 color: var(--hl-string-fg);
524 border-radius: 2px;
525 padding: 0 0.15em;
526}
527
528/* Comments → warm background */
529pre .org-comment,
530pre .org-comment-delimiter {
531 background: var(--hl-comment-bg);
532 color: var(--hl-comment-fg);
533 border-radius: 2px;
534 padding: 0 0.15em;
535 font-style: italic;
536}
537
538/* Function/type definitions → blue background */
539pre .org-function-name {
540 background: var(--hl-def-bg);
541 color: var(--hl-def-fg);
542 border-radius: 2px;
543 padding: 0 0.15em;
544}
545
546/* Constants, numbers → purple text */
547pre .org-constant,
548pre .org-number {
549 color: var(--hl-constant);
550}
551
552/* Types → dimmed */
553pre .org-type {
554 color: var(--hl-type);
555}
556
557/* Nix-mode classes → Tonsky mapping */
558pre .org-nix-attribute { color: inherit; }
559pre .org-nix-constant { color: var(--hl-constant); }
560pre .org-nix-antiquote { color: inherit; }
561
562/* Everything else from org → default (Tonsky: de-emphasize) */
563pre .org-keyword,
564pre .org-builtin,
565pre .org-nix-keyword,
566pre .org-nix-builtin,
567pre .org-variable-name,
568pre .org-property-name,
569pre .org-css-property,
570pre .org-css-selector,
571pre .org-preprocessor,
572pre .org-negation-char {
573 color: inherit;
574 font-weight: normal;
575 font-style: normal;
576}
577
578/* --- Org export structure mappings --- */
579
580/* Main content wrapper */
581article.content {
582 counter-reset: sidenote-counter;
583}
584
585/* Section structure */
586.outline-2,
587.outline-3,
588.outline-4 {
589 /* no special styling needed, headings handle it */
590}
591
592/* Code blocks from org */
593.org-src-container {
594 margin-bottom: 1lh;
595 margin-bottom: var(--lh);
596}
597
598.org-src-container > pre.src {
599 background: var(--color-code-bg);
600 padding: 1em 1.2em;
601 border-radius: 6px;
602 overflow-x: auto;
603 font-size: 0.85rem;
604 line-height: 1.5;
605 font-family: var(--font-mono);
606}
607
608/* ox-tufte sidenote toggle (checkbox hack for mobile) */
609.margin-toggle {
610 display: none;
611}
612
613label.margin-toggle.sidenote-number {
614 display: inline;
615}
616
617.margin-toggle:checked + .sidenote,
618.margin-toggle:checked + .marginnote {
619 display: block;
620}
621
622/* ox-tufte epigraph (blockquote with caption/footer) */
623blockquote footer {
624 font-size: 0.85em;
625 font-style: normal;
626 color: var(--color-text-faint);
627 font-family: var(--font-heading);
628 margin-top: 0.5em;
629}
630
631blockquote footer::before {
632 content: "— ";
633}
634
635/* Org figure numbering */
636.figure-number {
637 font-family: var(--font-heading);
638 font-weight: 600;
639 font-style: normal;
640}
641
642/* Org tags on headings */
643.tag {
644 font-family: var(--font-mono);
645 font-size: 0.7em;
646 font-weight: normal;
647 color: var(--color-text-faint);
648}
649
650/* Org timestamps */
651.timestamp-wrapper,
652.timestamp {
653 font-family: var(--font-mono);
654 font-size: 0.82rem;
655 color: var(--color-text-faint);
656}
657
658a.timestamp-link {
659 color: var(--color-text-faint);
660 text-decoration: none;
661 border-bottom: 1px dotted var(--color-border);
662 transition: color 0.2s, border-color 0.2s;
663}
664
665a.timestamp-link:hover {
666 color: var(--color-accent);
667 border-color: var(--color-accent);
668}
669
670/* Org lists */
671.org-ul {
672 padding-left: 1.5em;
673 list-style-type: "✧ ";
674}
675
676.org-ol {
677 padding-left: 1.5em;
678}
679
680/* Subtitle from #+SUBTITLE */
681.subtitle {
682 font-family: var(--font-body);
683 font-size: 1.1rem;
684 font-weight: normal;
685 font-style: italic;
686 color: var(--color-text-muted);
687 margin-top: calc(var(--lh) * -0.25);
688 margin-bottom: calc(var(--lh) * 1.5);
689}
690
691/* Postamble (footer) - hide validation link */
692.status .validation {
693 display: none;
694}
695
696.status {
697 margin-top: calc(var(--lh) * 3);
698 padding-top: var(--lh);
699 border-top: 1px solid var(--color-border);
700 font-size: 0.8rem;
701 color: var(--color-text-faint);
702 font-family: var(--font-heading);
703}
704
705/* --- Sidenotes / Margin Notes ---
706 Tufte CSS + Gwern: margin notes for thinking */
707
708.sidenote,
709.marginnote {
710 float: right;
711 clear: right;
712 margin-right: calc(-1 * var(--margin-note-width) - 2rem);
713 width: var(--margin-note-width);
714 font-size: 0.8rem;
715 line-height: 1.4;
716 color: var(--color-text-muted);
717 position: relative;
718}
719
720.sidenote {
721 border-left: 2px solid var(--color-border);
722 padding-left: 0.75em;
723}
724
725.sidenote-number {
726 counter-increment: sidenote-counter;
727}
728
729.sidenote-number::after {
730 content: counter(sidenote-counter);
731 font-size: 0.7em;
732 position: relative;
733 top: -0.5em;
734 color: var(--color-accent);
735 padding-left: 0.1em;
736}
737
738.sidenote::before {
739 content: counter(sidenote-counter);
740 font-size: 0.7em;
741 position: relative;
742 top: -0.5em;
743 color: var(--color-accent);
744 padding-right: 0.3em;
745}
746
747/* Collapse sidenotes on small screens */
748@media (max-width: 900px) {
749 body {
750 max-width: var(--content-width);
751 }
752 .sidenote,
753 .marginnote {
754 float: none;
755 display: block;
756 margin: 0.5lh 0;
757 margin: calc(var(--lh) * 0.5) 0;
758 width: 100%;
759 font-size: 0.85rem;
760 background: var(--color-bg-alt);
761 padding: 0.75em 1em;
762 border-radius: 4px;
763 border-left: 3px solid var(--color-border);
764 margin-right: 0;
765 }
766}
767
768/* --- Callouts ---
769 Crafting Interpreters design-note style, extended with types.
770 Each type has: left border color, subtle bg, icon prefix. */
771
772:root {
773 --callout-note-color: #2a6496;
774 --callout-note-bg: rgba(42, 100, 150, 0.06);
775 --callout-tip-color: #4a7c59;
776 --callout-tip-bg: rgba(74, 124, 89, 0.06);
777 --callout-info-color: #3a7ca5;
778 --callout-info-bg: rgba(58, 124, 165, 0.06);
779 --callout-warning-color: #9a7b2a;
780 --callout-warning-bg: rgba(154, 123, 42, 0.06);
781 --callout-danger-color: #b44;
782 --callout-danger-bg: rgba(180, 68, 68, 0.06);
783 --callout-design-color: var(--color-accent);
784 --callout-design-bg: var(--color-accent-soft);
785}
786
787/* Dark callout colors handled by [data-theme="dark"] below. */
788
789[data-theme="light"] {
790 --callout-note-color: #2a6496;
791 --callout-note-bg: rgba(42, 100, 150, 0.06);
792 --callout-tip-color: #4a7c59;
793 --callout-tip-bg: rgba(74, 124, 89, 0.06);
794 --callout-info-color: #3a7ca5;
795 --callout-info-bg: rgba(58, 124, 165, 0.06);
796 --callout-warning-color: #9a7b2a;
797 --callout-warning-bg: rgba(154, 123, 42, 0.06);
798 --callout-danger-color: #b44;
799 --callout-danger-bg: rgba(180, 68, 68, 0.06);
800}
801
802[data-theme="dark"] {
803 --callout-note-color: #7daacd;
804 --callout-note-bg: rgba(125, 170, 205, 0.08);
805 --callout-tip-color: #6aab7b;
806 --callout-tip-bg: rgba(106, 171, 123, 0.08);
807 --callout-info-color: #6aafcf;
808 --callout-info-bg: rgba(106, 175, 207, 0.08);
809 --callout-warning-color: #d4aa3c;
810 --callout-warning-bg: rgba(212, 170, 60, 0.08);
811 --callout-danger-color: #e07070;
812 --callout-danger-bg: rgba(224, 112, 112, 0.08);
813}
814
815.callout {
816 border-left: 3px solid var(--callout-border, var(--color-accent));
817 background: var(--callout-bg, var(--color-accent-soft));
818 border-radius: 0 6px 6px 0;
819 padding: 0.9em 1.2em;
820 margin: 1lh 0;
821 margin: var(--lh) 0;
822 font-family: var(--font-heading);
823 font-size: 0.9rem;
824 color: var(--color-text-muted);
825}
826
827.callout-title {
828 font-weight: 600;
829 text-transform: uppercase;
830 letter-spacing: 0.05em;
831 font-size: 0.72rem;
832 color: var(--callout-border, var(--color-accent));
833 margin-bottom: 0.4em;
834 display: flex;
835 align-items: center;
836 gap: 0.4em;
837}
838
839.callout-title::before {
840 font-size: 1em;
841 line-height: 1;
842}
843
844.callout p:last-child {
845 margin-bottom: 0;
846}
847
848/* --- Callout Types --- */
849
850.callout-note {
851 --callout-border: var(--callout-note-color);
852 --callout-bg: var(--callout-note-bg);
853}
854.callout-note .callout-title::before { content: "✎"; }
855
856.callout-tip {
857 --callout-border: var(--callout-tip-color);
858 --callout-bg: var(--callout-tip-bg);
859}
860.callout-tip .callout-title::before { content: "✦"; }
861
862.callout-info {
863 --callout-border: var(--callout-info-color);
864 --callout-bg: var(--callout-info-bg);
865}
866.callout-info .callout-title::before { content: "ℹ"; }
867
868.callout-warning {
869 --callout-border: var(--callout-warning-color);
870 --callout-bg: var(--callout-warning-bg);
871}
872.callout-warning .callout-title::before { content: "⚠"; }
873
874.callout-danger {
875 --callout-border: var(--callout-danger-color);
876 --callout-bg: var(--callout-danger-bg);
877}
878.callout-danger .callout-title::before { content: "✖"; }
879
880.callout-design {
881 --callout-border: var(--callout-design-color);
882 --callout-bg: var(--callout-design-bg);
883}
884.callout-design .callout-title::before { content: "◆"; }
885
886/* --- Dropcap ---
887 Gwern: classic typographic dropcap */
888
889.dropcap::first-letter {
890 float: left;
891 font-size: 3.2em;
892 line-height: 0.8;
893 padding-right: 0.08em;
894 padding-top: 0.07em;
895 font-weight: 600;
896 color: var(--color-accent);
897}
898
899/* --- Small Caps ---
900 Gwern: small caps for emphasis/theming */
901
902.smallcaps {
903 font-variant: small-caps;
904 letter-spacing: 0.05em;
905}
906
907/* --- Horizontal Rule --- */
908
909hr {
910 border: none;
911 border-top: 1px solid var(--color-border);
912 margin: 2lh 0;
913 margin: calc(var(--lh) * 2) 0;
914}
915
916/* ============================================================
917 STREAM / FLUX COMPONENTS
918 Inspired by Beat Hagenlocher's /stream/
919 ============================================================ */
920
921.flux {
922 counter-reset: sidenote-counter;
923}
924
925.flux-header {
926 margin-bottom: 2lh;
927 margin-bottom: calc(var(--lh) * 2);
928}
929
930.flux-header h1 {
931 font-size: 1.6rem;
932}
933
934.flux-header .description {
935 color: var(--color-text-muted);
936 font-size: 0.95rem;
937}
938
939.flux-feed-links {
940 display: flex;
941 gap: 1em;
942 margin-top: 0.5lh;
943 margin-top: calc(var(--lh) * 0.5);
944 font-size: 0.8rem;
945 font-family: var(--font-mono);
946}
947
948.flux-feed-links a {
949 color: var(--color-text-faint);
950 text-decoration: none;
951 border: 1px solid var(--color-border);
952 padding: 0.2em 0.6em;
953 border-radius: 4px;
954 transition: all 0.2s;
955}
956
957.flux-feed-links a:hover {
958 color: var(--color-link);
959 border-color: var(--color-link);
960}
961
962/* --- Stream Card (streamlet) ---
963 Beat-style: rounded card with date, title, body, tags */
964
965.stream-card {
966 background: var(--color-bg-card);
967 border-radius: 10px;
968 padding: 1.2em 1.4em;
969 box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06),
970 inset 0 1px 0 0 rgba(148, 163, 184, 0.06);
971 position: relative;
972}
973
974.stream-card .card-date {
975 font-family: var(--font-mono);
976 font-size: 0.72rem;
977 color: var(--color-text-faint);
978 margin-bottom: 0.3em;
979}
980
981.stream-card .card-title {
982 font-family: var(--font-heading);
983 font-size: 1.05rem;
984 font-weight: 600;
985 margin-bottom: 0.5em;
986 line-height: 1.3;
987}
988
989.stream-card .card-body {
990 font-size: 0.9rem;
991 line-height: 1.55;
992 color: var(--color-text-muted);
993}
994
995.stream-card .card-body p:last-child {
996 margin-bottom: 0;
997}
998
999/* Section anchor on cards */
1000.stream-card .card-anchor {
1001 position: absolute;
1002 left: -1.5em;
1003 top: 1.2em;
1004 font-size: 1.1rem;
1005 color: transparent;
1006 text-decoration: none;
1007 transition: color 0.2s;
1008}
1009
1010.stream-card:hover .card-anchor {
1011 color: var(--color-text-faint);
1012}
1013
1014/* --- Tags --- */
1015
1016.tags {
1017 display: flex;
1018 flex-wrap: wrap;
1019 gap: 0.4em;
1020 margin-top: 0.7em;
1021}
1022
1023.tag {
1024 font-family: var(--font-heading);
1025 font-size: 0.68rem;
1026 font-weight: 500;
1027 background: var(--color-tag-bg);
1028 color: var(--color-tag-text);
1029 padding: 0.25em 0.7em;
1030 border-radius: 99px;
1031 white-space: nowrap;
1032 text-decoration: none;
1033 transition: background 0.2s, color 0.2s;
1034}
1035
1036a.tag:hover {
1037 background: var(--color-tag-text);
1038 color: var(--color-bg);
1039}
1040
1041/* Tags inline in headings (org export) */
1042h2 .tags,
1043h3 .tags,
1044h4 .tags {
1045 display: inline-flex;
1046 margin-top: 0;
1047 margin-left: 0.5em;
1048 vertical-align: middle;
1049}
1050
1051/* --- Page Update Entry ---
1052 Beat-style: compact one-liner for new (+) or updated (~) pages */
1053
1054.page-entry {
1055 display: flex;
1056 align-items: center;
1057 gap: 0.6em;
1058 padding: 0.5em 0.8em;
1059 border-radius: 8px;
1060 border: 1px solid var(--color-border-light);
1061 transition: background 0.2s;
1062 text-decoration: none;
1063 margin-bottom: 0.4lh;
1064 margin-bottom: calc(var(--lh) * 0.4);
1065}
1066
1067.page-entry:hover {
1068 background: var(--color-bg-alt);
1069 text-decoration: none;
1070}
1071
1072.page-entry .marker {
1073 font-size: 0.8rem;
1074 font-weight: 600;
1075 flex-shrink: 0;
1076}
1077
1078.page-entry .marker.new {
1079 color: var(--color-new);
1080}
1081
1082.page-entry .marker.updated {
1083 color: var(--color-updated);
1084}
1085
1086.page-entry .page-title {
1087 font-family: var(--font-heading);
1088 font-size: 0.85rem;
1089 font-weight: 500;
1090 color: var(--color-text);
1091 flex: 1;
1092}
1093
1094.page-entry .page-date {
1095 font-family: var(--font-mono);
1096 font-size: 0.68rem;
1097 color: var(--color-text-faint);
1098 margin-left: auto;
1099 white-space: nowrap;
1100}
1101
1102.page-entry .arrow {
1103 color: var(--color-accent);
1104 font-size: 0.75rem;
1105 transition: transform 0.2s;
1106}
1107
1108.page-entry:hover .arrow {
1109 transform: rotate(0deg) translateY(1px);
1110}
1111
1112/* --- GitHub Entry ---
1113 Compact PR/issue/release entries */
1114
1115.github-entry {
1116 display: flex;
1117 align-items: flex-start;
1118 gap: 0.6em;
1119 padding: 0.6em 0;
1120 border-bottom: 1px solid var(--color-border-light);
1121 font-size: 0.88rem;
1122}
1123
1124.github-entry:last-child {
1125 border-bottom: none;
1126}
1127
1128.github-entry .gh-icon {
1129 flex-shrink: 0;
1130 width: 1.3em;
1131 text-align: center;
1132 margin-top: 0.15em;
1133}
1134
1135.github-entry .gh-icon.pr {
1136 color: var(--color-new);
1137}
1138.github-entry .gh-icon.issue {
1139 color: var(--color-updated);
1140}
1141.github-entry .gh-icon.release {
1142 color: var(--color-accent);
1143}
1144
1145.github-entry .gh-content {
1146 flex: 1;
1147 min-width: 0;
1148}
1149
1150.github-entry .gh-title {
1151 color: var(--color-text);
1152}
1153
1154.github-entry .gh-title a {
1155 text-decoration: none;
1156}
1157
1158.github-entry .gh-title a:hover {
1159 text-decoration: underline;
1160 text-decoration-color: var(--color-link);
1161}
1162
1163.github-entry .gh-repo {
1164 font-family: var(--font-mono);
1165 font-size: 0.78rem;
1166 color: var(--color-text-faint);
1167}
1168
1169.github-entry .gh-date {
1170 font-family: var(--font-mono);
1171 font-size: 0.7rem;
1172 color: var(--color-text-faint);
1173 white-space: nowrap;
1174 margin-top: 0.15em;
1175}
1176
1177/* --- Bookmark Entry --- */
1178
1179.bookmark-entry {
1180 padding: 0.6em 0;
1181 border-bottom: 1px solid var(--color-border-light);
1182}
1183
1184.bookmark-entry:last-child {
1185 border-bottom: none;
1186}
1187
1188.bookmark-entry .bm-title {
1189 font-size: 0.9rem;
1190}
1191
1192.bookmark-entry .bm-note {
1193 font-size: 0.82rem;
1194 color: var(--color-text-muted);
1195 margin-top: 0.2em;
1196 font-style: italic;
1197}
1198
1199.bookmark-entry .bm-meta {
1200 font-family: var(--font-mono);
1201 font-size: 0.7rem;
1202 color: var(--color-text-faint);
1203 margin-top: 0.2em;
1204}
1205
1206/* --- Release highlight --- */
1207
1208.release-card {
1209 background: var(--color-accent-soft);
1210 border: 1px solid var(--color-accent);
1211 border-radius: 8px;
1212 padding: 0.8em 1em;
1213 margin-bottom: 1lh;
1214 margin-bottom: var(--lh);
1215}
1216
1217.release-card .release-version {
1218 font-family: var(--font-mono);
1219 font-weight: 600;
1220 color: var(--color-accent);
1221}
1222
1223.release-card .release-project {
1224 font-family: var(--font-heading);
1225 font-weight: 500;
1226}
1227
1228.release-card .release-date {
1229 font-family: var(--font-mono);
1230 font-size: 0.72rem;
1231 color: var(--color-text-faint);
1232}
1233
1234/* --- Flux navigation --- */
1235
1236.flux-years {
1237 font-family: var(--font-mono);
1238 font-size: 0.85rem;
1239 color: var(--color-text-faint);
1240 margin-bottom: 1.5lh;
1241 margin-bottom: calc(var(--lh) * 1.5);
1242}
1243
1244.flux-years a {
1245 color: var(--color-text-muted);
1246}
1247
1248.flux-years strong {
1249 color: var(--color-text);
1250 text-decoration: none;
1251}
1252
1253.flux-stats {
1254 font-family: var(--font-mono);
1255 font-size: 0.8rem;
1256 color: var(--color-text-faint);
1257 margin-bottom: 1.5lh;
1258 margin-bottom: calc(var(--lh) * 1.5);
1259}
1260
1261.flux-archive-link {
1262 font-family: var(--font-heading);
1263 font-size: 0.9rem;
1264 color: var(--color-text-muted);
1265 margin-top: 2lh;
1266 margin-top: calc(var(--lh) * 2);
1267}
1268
1269/* --- Year Separator --- */
1270
1271.year-separator {
1272 font-family: var(--font-heading);
1273 font-size: 0.75rem;
1274 font-weight: 600;
1275 text-transform: uppercase;
1276 letter-spacing: 0.1em;
1277 color: var(--color-text-faint);
1278 margin: 2lh 0 1lh 0;
1279 margin: calc(var(--lh) * 2) 0 calc(var(--lh) * 1) 0;
1280 padding-bottom: 0.3em;
1281 border-bottom: 1px solid var(--color-border);
1282}
1283
1284/* --- Table --- */
1285
1286table {
1287 width: 100%;
1288 border-collapse: collapse;
1289 font-size: 0.9rem;
1290 margin-bottom: 1lh;
1291 margin-bottom: var(--lh);
1292}
1293
1294th,
1295td {
1296 text-align: left;
1297 padding: 0.4em 0.8em;
1298 border-bottom: 1px solid var(--color-border-light);
1299}
1300
1301th {
1302 font-family: var(--font-heading);
1303 font-weight: 600;
1304 font-size: 0.8rem;
1305 text-transform: uppercase;
1306 letter-spacing: 0.04em;
1307 color: var(--color-text-muted);
1308}
1309
1310/* --- Footer --- */
1311
1312footer {
1313 margin-top: 3lh;
1314 margin-top: calc(var(--lh) * 3);
1315 padding-top: 1lh;
1316 padding-top: var(--lh);
1317 border-top: 1px solid var(--color-border);
1318 font-size: 0.8rem;
1319 color: var(--color-text-faint);
1320 font-family: var(--font-heading);
1321}
1322
1323/* --- Figures & Images --- */
1324
1325figure {
1326 margin: 1.5lh 0;
1327 margin: calc(var(--lh) * 1.5) 0;
1328}
1329
1330figure img {
1331 display: block;
1332 max-width: 100%;
1333 height: auto;
1334 border-radius: 4px;
1335}
1336
1337figcaption {
1338 font-family: var(--font-heading);
1339 font-size: 0.82rem;
1340 color: var(--color-text-muted);
1341 font-style: italic;
1342 margin-top: 0.5em;
1343 line-height: 1.4;
1344}
1345
1346figcaption strong {
1347 font-style: normal;
1348 color: var(--color-text);
1349}
1350
1351/* Full-width figure — breaks out of content column */
1352figure.fullwidth {
1353 max-width: calc(var(--content-width) + var(--margin-note-width) + 2rem);
1354 width: 100%;
1355}
1356
1357figure.fullwidth img {
1358 width: 100%;
1359}
1360
1361/* Margin figure — Tufte-style, floats in the right margin */
1362figure.margin {
1363 float: right;
1364 clear: right;
1365 margin-right: calc(-1 * var(--margin-note-width) - 2rem);
1366 width: var(--margin-note-width);
1367 margin-top: 0;
1368 margin-bottom: 1lh;
1369 margin-bottom: var(--lh);
1370}
1371
1372figure.margin img {
1373 width: 100%;
1374}
1375
1376figure.margin figcaption {
1377 font-size: 0.75rem;
1378}
1379
1380@media (max-width: 900px) {
1381 figure.margin {
1382 float: none;
1383 width: 100%;
1384 margin-right: 0;
1385 margin: 1lh 0;
1386 margin: var(--lh) 0;
1387 }
1388}
1389
1390/* Bordered figure — subtle frame */
1391figure.bordered img {
1392 border: 1px solid var(--color-border);
1393 padding: 0.5em;
1394 background: var(--color-bg-card);
1395 border-radius: 6px;
1396}
1397
1398/* Figure grid — side by side images */
1399.figure-grid {
1400 display: grid;
1401 gap: 1em;
1402 margin: 1.5lh 0;
1403 margin: calc(var(--lh) * 1.5) 0;
1404}
1405
1406.figure-grid.cols-2 {
1407 grid-template-columns: 1fr 1fr;
1408}
1409
1410.figure-grid.cols-3 {
1411 grid-template-columns: 1fr 1fr 1fr;
1412}
1413
1414@media (max-width: 600px) {
1415 .figure-grid.cols-2,
1416 .figure-grid.cols-3 {
1417 grid-template-columns: 1fr;
1418 }
1419}
1420
1421.figure-grid figure {
1422 margin: 0;
1423}
1424
1425/* Screenshot — drop shadow, slight rounding */
1426figure.screenshot img {
1427 border-radius: 8px;
1428 box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12),
1429 0 1px 4px rgba(0, 0, 0, 0.08);
1430}
1431
1432[data-theme="dark"] figure.screenshot img {
1433 box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4),
1434 0 1px 4px rgba(0, 0, 0, 0.2);
1435}
1436
1437/* Inline image in text — small, flows with text */
1438img.inline {
1439 display: inline;
1440 height: 1.2em;
1441 width: auto;
1442 vertical-align: text-bottom;
1443 margin: 0 0.1em;
1444}
1445
1446/* --- Color Palette Demo --- */
1447
1448.palette {
1449 display: flex;
1450 gap: 0.5em;
1451 flex-wrap: wrap;
1452 margin-bottom: 1lh;
1453 margin-bottom: var(--lh);
1454}
1455
1456.swatch {
1457 width: 3em;
1458 height: 3em;
1459 border-radius: 6px;
1460 border: 1px solid var(--color-border);
1461 display: flex;
1462 align-items: flex-end;
1463 padding: 0.2em;
1464 font-family: var(--font-mono);
1465 font-size: 0.5rem;
1466 color: #fff;
1467 text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
1468}
1469
1470/* --- Accent Picker --- */
1471
1472.accent-picker {
1473 margin-bottom: 1lh;
1474 margin-bottom: var(--lh);
1475}
1476
1477.accent-group {
1478 margin-bottom: 0.8em;
1479}
1480
1481.accent-group-label {
1482 font-family: var(--font-heading);
1483 font-size: 0.72rem;
1484 font-weight: 600;
1485 text-transform: uppercase;
1486 letter-spacing: 0.06em;
1487 color: var(--color-text-faint);
1488 margin-bottom: 0.3em;
1489}
1490
1491.accent-group .palette {
1492 margin-bottom: 0.3em;
1493}
1494
1495.accent-swatch {
1496 width: 2.4em;
1497 height: 2.4em;
1498 border-radius: 8px;
1499 border: 2px solid transparent;
1500 cursor: pointer;
1501 transition: all 0.2s ease;
1502 position: relative;
1503 font-size: 0;
1504 /* color set via inline style, overridden by JS on theme change */
1505}
1506
1507.accent-swatch:hover {
1508 transform: scale(1.15);
1509 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
1510}
1511
1512.accent-swatch.active {
1513 border-color: var(--color-text);
1514 transform: scale(1.1);
1515 box-shadow: 0 0 0 2px var(--color-bg), 0 0 0 4px var(--color-text);
1516}
1517
1518.accent-current {
1519 font-family: var(--font-mono);
1520 font-size: 0.82rem;
1521 color: var(--color-text-muted);
1522 margin-top: 0.5em;
1523}
1524
1525.accent-current span {
1526 color: var(--color-accent);
1527 font-weight: 600;
1528}
1529
1530/* --- Utility classes (avoid inline styles for CSP) --- */
1531
1532.nav-toc {
1533 font-family: var(--font-heading);
1534 font-size: 0.85rem;
1535 margin-bottom: calc(var(--lh) * 2);
1536}
1537
1538.text-base { font-size: 1rem; }
1539.text-sm { font-size: 0.85rem; }
1540.text-italic { font-style: italic; }
1541.text-bold { font-weight: bold; }
1542.text-semibold { font-weight: 600; }
1543.mt-sm { margin-top: 0.3em; }
1544
1545.specimen-headings {
1546 background: transparent;
1547 padding: 0;
1548}
1549.specimen-headings h1,
1550.specimen-headings h2,
1551.specimen-headings h3 {
1552 margin: 0.3em 0;
1553}
1554.specimen-headings h1 { margin: 0; }
1555
1556/* Link style demos */
1557a.link-thick { text-decoration-thickness: 2px; }
1558a.link-offset { text-underline-offset: 0.3em; }
1559a.link-accent { text-decoration-color: var(--color-accent); }
1560a.link-dotted { text-decoration-style: dotted; }
1561
1562/* Tonsky inline highlight pills */
1563.hl-pill {
1564 padding: 0.1em 0.3em;
1565 border-radius: 2px;
1566}
1567.hl-pill-string { background: var(--hl-string-bg); }
1568.hl-pill-comment { background: var(--hl-comment-bg); font-style: italic; }
1569.hl-pill-def { background: var(--hl-def-bg); }
1570.hl-pill-constant { color: var(--hl-constant); }
1571
1572/* Stream card compact variant (for grouped entries) */
1573.stream-card-compact {
1574 padding: 0.8em 1.2em;
1575}
1576.stream-card-compact .card-date {
1577 margin-bottom: 0.6em;
1578}
1579
1580/* Color palette demo swatches — colors set by JS */
1581.swatch {
1582 /* background set via data-bg attribute + JS */
1583}
1584
1585/* --- Typography Specimen --- */
1586
1587.specimen {
1588 padding: 1.2em;
1589 background: var(--color-bg-alt);
1590 border-radius: 8px;
1591 margin-bottom: 1lh;
1592 margin-bottom: var(--lh);
1593}
1594
1595.specimen .label {
1596 font-family: var(--font-mono);
1597 font-size: 0.7rem;
1598 color: var(--color-text-faint);
1599 margin-bottom: 0.3em;
1600}
1601
1602.specimen-serif {
1603 font-family: var(--font-body);
1604}
1605.specimen-sans {
1606 font-family: var(--font-heading);
1607}
1608.specimen-mono {
1609 font-family: var(--font-mono);
1610}
1611
1612/* Marker candidates for comparison (sandbox only) */
1613ul.marker-endash { list-style-type: "– "; }
1614ul.marker-hyphen { list-style-type: "⁃ "; }
1615ul.marker-hedera { list-style-type: "❧ "; }
1616ul.marker-reference { list-style-type: "※ "; }