@geekity/cms 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +177 -6
- package/admin/pages/account/login.njk +3 -0
- package/admin/pages/documents/editor.njk +7 -0
- package/admin/pages/indieauth/consent.njk +51 -0
- package/admin/pages/indieauth/refused.njk +11 -0
- package/admin/pages/settings/general.njk +9 -0
- package/admin/pages/settings/reading.njk +93 -0
- package/admin/pages/users/apps.njk +74 -0
- package/admin/pages/users/edit.njk +12 -0
- package/admin/static/admin.css +27 -0
- package/dist/admin/accounts.d.ts +3 -0
- package/dist/admin/accounts.d.ts.map +1 -1
- package/dist/admin/accounts.js +5 -0
- package/dist/admin/accounts.js.map +1 -1
- package/dist/admin/documents.d.ts +2 -0
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +17 -1
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/headers.d.ts +5 -1
- package/dist/admin/headers.d.ts.map +1 -1
- package/dist/admin/headers.js +7 -3
- package/dist/admin/headers.js.map +1 -1
- package/dist/admin/menu.d.ts.map +1 -1
- package/dist/admin/menu.js +2 -1
- package/dist/admin/menu.js.map +1 -1
- package/dist/admin/routes.d.ts.map +1 -1
- package/dist/admin/routes.js +48 -5
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/settings-general.js +1 -1
- package/dist/admin/settings-general.js.map +1 -1
- package/dist/admin/settings-reading.d.ts.map +1 -1
- package/dist/admin/settings-reading.js +15 -1
- package/dist/admin/settings-reading.js.map +1 -1
- package/dist/admin/settings.d.ts +79 -2
- package/dist/admin/settings.d.ts.map +1 -1
- package/dist/admin/settings.js +168 -2
- package/dist/admin/settings.js.map +1 -1
- package/dist/admin/templates.d.ts +3 -0
- package/dist/admin/templates.d.ts.map +1 -1
- package/dist/admin/templates.js +3 -0
- package/dist/admin/templates.js.map +1 -1
- package/dist/admin/users.d.ts +8 -0
- package/dist/admin/users.d.ts.map +1 -1
- package/dist/admin/users.js +9 -0
- package/dist/admin/users.js.map +1 -1
- package/dist/config.d.ts +30 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/env.d.ts +14 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/federation/article.d.ts.map +1 -1
- package/dist/federation/article.js +18 -5
- package/dist/federation/article.js.map +1 -1
- package/dist/images/icons.d.ts +44 -25
- package/dist/images/icons.d.ts.map +1 -1
- package/dist/images/icons.js +205 -60
- package/dist/images/icons.js.map +1 -1
- package/dist/images/index.d.ts +2 -2
- package/dist/images/index.d.ts.map +1 -1
- package/dist/images/index.js +1 -1
- package/dist/images/index.js.map +1 -1
- package/dist/images/markup.d.ts +14 -0
- package/dist/images/markup.d.ts.map +1 -1
- package/dist/images/markup.js +16 -11
- package/dist/images/markup.js.map +1 -1
- package/dist/images/variants.d.ts.map +1 -1
- package/dist/images/variants.js +3 -4
- package/dist/images/variants.js.map +1 -1
- package/dist/index.d.ts +14 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -1
- package/dist/index.js.map +1 -1
- package/dist/indexnow.d.ts +34 -0
- package/dist/indexnow.d.ts.map +1 -0
- package/dist/indexnow.js +141 -0
- package/dist/indexnow.js.map +1 -0
- package/dist/indieauth/bearer.d.ts +39 -0
- package/dist/indieauth/bearer.d.ts.map +1 -0
- package/dist/indieauth/bearer.js +63 -0
- package/dist/indieauth/bearer.js.map +1 -0
- package/dist/indieauth/client.d.ts +61 -0
- package/dist/indieauth/client.d.ts.map +1 -0
- package/dist/indieauth/client.js +139 -0
- package/dist/indieauth/client.js.map +1 -0
- package/dist/indieauth/connected-apps.d.ts +23 -0
- package/dist/indieauth/connected-apps.d.ts.map +1 -0
- package/dist/indieauth/connected-apps.js +73 -0
- package/dist/indieauth/connected-apps.js.map +1 -0
- package/dist/indieauth/consent.d.ts +28 -0
- package/dist/indieauth/consent.d.ts.map +1 -0
- package/dist/indieauth/consent.js +185 -0
- package/dist/indieauth/consent.js.map +1 -0
- package/dist/indieauth/discovery.d.ts +87 -0
- package/dist/indieauth/discovery.d.ts.map +1 -0
- package/dist/indieauth/discovery.js +127 -0
- package/dist/indieauth/discovery.js.map +1 -0
- package/dist/indieauth/grants.d.ts +57 -0
- package/dist/indieauth/grants.d.ts.map +1 -0
- package/dist/indieauth/grants.js +35 -0
- package/dist/indieauth/grants.js.map +1 -0
- package/dist/indieauth/identity.d.ts +36 -0
- package/dist/indieauth/identity.d.ts.map +1 -0
- package/dist/indieauth/identity.js +78 -0
- package/dist/indieauth/identity.js.map +1 -0
- package/dist/indieauth/redeem.d.ts +47 -0
- package/dist/indieauth/redeem.d.ts.map +1 -0
- package/dist/indieauth/redeem.js +69 -0
- package/dist/indieauth/redeem.js.map +1 -0
- package/dist/indieauth/request.d.ts +47 -0
- package/dist/indieauth/request.d.ts.map +1 -0
- package/dist/indieauth/request.js +104 -0
- package/dist/indieauth/request.js.map +1 -0
- package/dist/indieauth/token.d.ts +19 -0
- package/dist/indieauth/token.d.ts.map +1 -0
- package/dist/indieauth/token.js +110 -0
- package/dist/indieauth/token.js.map +1 -0
- package/dist/indieauth/tokens.d.ts +131 -0
- package/dist/indieauth/tokens.d.ts.map +1 -0
- package/dist/indieauth/tokens.js +205 -0
- package/dist/indieauth/tokens.js.map +1 -0
- package/dist/web/archive.d.ts +1 -1
- package/dist/web/archive.d.ts.map +1 -1
- package/dist/web/archive.js +3 -2
- package/dist/web/archive.js.map +1 -1
- package/dist/web/context.d.ts +25 -0
- package/dist/web/context.d.ts.map +1 -1
- package/dist/web/context.js +18 -0
- package/dist/web/context.js.map +1 -1
- package/dist/web/feed-atom.d.ts.map +1 -1
- package/dist/web/feed-atom.js +3 -1
- package/dist/web/feed-atom.js.map +1 -1
- package/dist/web/feed-item.d.ts +11 -2
- package/dist/web/feed-item.d.ts.map +1 -1
- package/dist/web/feed-item.js +9 -3
- package/dist/web/feed-item.js.map +1 -1
- package/dist/web/feed-json.d.ts +4 -0
- package/dist/web/feed-json.d.ts.map +1 -1
- package/dist/web/feed-json.js +4 -1
- package/dist/web/feed-json.js.map +1 -1
- package/dist/web/feed-rss.d.ts.map +1 -1
- package/dist/web/feed-rss.js +16 -3
- package/dist/web/feed-rss.js.map +1 -1
- package/dist/web/feed-source.d.ts +28 -0
- package/dist/web/feed-source.d.ts.map +1 -1
- package/dist/web/feed-source.js +31 -0
- package/dist/web/feed-source.js.map +1 -1
- package/dist/web/feed-xml.d.ts +2 -0
- package/dist/web/feed-xml.d.ts.map +1 -1
- package/dist/web/feed-xml.js +2 -0
- package/dist/web/feed-xml.js.map +1 -1
- package/dist/web/feeds.d.ts.map +1 -1
- package/dist/web/feeds.js +8 -1
- package/dist/web/feeds.js.map +1 -1
- package/dist/web/index.d.ts +3 -1
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +2 -1
- package/dist/web/index.js.map +1 -1
- package/dist/web/indexnow.d.ts +9 -0
- package/dist/web/indexnow.d.ts.map +1 -0
- package/dist/web/indexnow.js +27 -0
- package/dist/web/indexnow.js.map +1 -0
- package/dist/web/llms.d.ts +58 -0
- package/dist/web/llms.d.ts.map +1 -0
- package/dist/web/llms.js +91 -0
- package/dist/web/llms.js.map +1 -0
- package/dist/web/locale.d.ts +41 -0
- package/dist/web/locale.d.ts.map +1 -0
- package/dist/web/locale.js +56 -0
- package/dist/web/locale.js.map +1 -0
- package/dist/web/manifest.d.ts +50 -0
- package/dist/web/manifest.d.ts.map +1 -0
- package/dist/web/manifest.js +56 -0
- package/dist/web/manifest.js.map +1 -0
- package/dist/web/negotiate.d.ts.map +1 -1
- package/dist/web/negotiate.js +6 -0
- package/dist/web/negotiate.js.map +1 -1
- package/dist/web/render.d.ts +6 -1
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +68 -22
- package/dist/web/render.js.map +1 -1
- package/dist/web/robots.d.ts +89 -0
- package/dist/web/robots.d.ts.map +1 -0
- package/dist/web/robots.js +259 -0
- package/dist/web/robots.js.map +1 -0
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +105 -6
- package/dist/web/routes.js.map +1 -1
- package/dist/web/share-image.d.ts +51 -0
- package/dist/web/share-image.d.ts.map +1 -0
- package/dist/web/share-image.js +43 -0
- package/dist/web/share-image.js.map +1 -0
- package/dist/web/sitemap.d.ts +0 -26
- package/dist/web/sitemap.d.ts.map +1 -1
- package/dist/web/sitemap.js +0 -44
- package/dist/web/sitemap.js.map +1 -1
- package/dist/web/templates.d.ts +16 -9
- package/dist/web/templates.d.ts.map +1 -1
- package/dist/web/templates.js +83 -55
- package/dist/web/templates.js.map +1 -1
- package/dist/web/themes.d.ts +33 -0
- package/dist/web/themes.d.ts.map +1 -1
- package/dist/web/themes.js +57 -0
- package/dist/web/themes.js.map +1 -1
- package/dist/webmention/discovery.d.ts +4 -2
- package/dist/webmention/discovery.d.ts.map +1 -1
- package/dist/webmention/discovery.js +14 -8
- package/dist/webmention/discovery.js.map +1 -1
- package/dist/webmention/fetch-public.d.ts +2 -0
- package/dist/webmention/fetch-public.d.ts.map +1 -1
- package/dist/webmention/fetch-public.js +1 -1
- package/dist/webmention/fetch-public.js.map +1 -1
- package/package.json +7 -2
- package/themes/default/README.md +320 -139
- package/themes/default/layouts/404.njk +2 -0
- package/themes/default/layouts/500.njk +2 -0
- package/themes/default/layouts/503.njk +2 -0
- package/themes/default/layouts/author.njk +3 -1
- package/themes/default/layouts/base.njk +96 -17
- package/themes/default/layouts/category.njk +4 -2
- package/themes/default/layouts/front-page.njk +7 -2
- package/themes/default/layouts/home.njk +10 -0
- package/themes/default/layouts/page.njk +7 -4
- package/themes/default/layouts/post.njk +35 -25
- package/themes/default/layouts/search.njk +5 -9
- package/themes/default/layouts/tag.njk +7 -1
- package/themes/default/partials/archive.njk +3 -1
- package/themes/default/partials/bio.njk +9 -2
- package/themes/default/partials/breadcrumbs.njk +20 -0
- package/themes/default/partials/comment-form.njk +8 -0
- package/themes/default/partials/contact-form.njk +3 -0
- package/themes/default/partials/conversation.njk +14 -4
- package/themes/default/partials/jsonld.njk +19 -4
- package/themes/default/partials/kicker.njk +36 -0
- package/themes/default/partials/lang.njk +7 -0
- package/themes/default/partials/post-list.njk +43 -47
- package/themes/default/partials/reply-context.njk +14 -5
- package/themes/default/src/style.css +1109 -0
- package/themes/default/static/style.css +2124 -1160
- package/themes/default/theme.json +3 -1
|
@@ -0,0 +1,1109 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The default theme's stylesheet: Paper (doc-9, decision-22).
|
|
3
|
+
*
|
|
4
|
+
* The source. `pnpm build` compiles it with Tailwind v4 to `static/style.css`,
|
|
5
|
+
* which is what a page loads and what the package ships; that file is a build
|
|
6
|
+
* product and gitignored. Nothing about Tailwind reaches a reader: no script,
|
|
7
|
+
* no CDN, no web font, one stylesheet.
|
|
8
|
+
*
|
|
9
|
+
* One warm column at 42rem, serif throughout, sans reserved for small labels.
|
|
10
|
+
* Only an article has a headline; every other kind of post is its words under
|
|
11
|
+
* a small-caps kicker that names the kind. Dark mode follows the system.
|
|
12
|
+
*
|
|
13
|
+
* The look lives here, on the theme's semantic class names, through `@apply`:
|
|
14
|
+
* the templates carry no utility classes, so a site theme that has CSS for the
|
|
15
|
+
* class names keeps working, and one that wants to restyle a single thing
|
|
16
|
+
* overrides a custom property or a class.
|
|
17
|
+
*
|
|
18
|
+
* The `--color-*` custom properties below are the override contract (see the
|
|
19
|
+
* theme README, "Colours"). `src/web/theme-colors.test.ts` reads them out of
|
|
20
|
+
* the compiled file and computes the WCAG 2.2 ratio of every pair the design
|
|
21
|
+
* puts on screen: every run of text at 7:1, every border a reader relies on at
|
|
22
|
+
* 3:1, in both schemes. `--color-rule` is the one exception, a decorative
|
|
23
|
+
* hairline nothing a reader needs is drawn with.
|
|
24
|
+
*/
|
|
25
|
+
@import 'tailwindcss' source(none);
|
|
26
|
+
@source '../layouts';
|
|
27
|
+
@source '../partials';
|
|
28
|
+
|
|
29
|
+
:root {
|
|
30
|
+
/* Light and dark are both drawn below, so a browser may paint its own form
|
|
31
|
+
controls, scrollbars and spellcheck marks to match. */
|
|
32
|
+
color-scheme: light dark;
|
|
33
|
+
|
|
34
|
+
/* `body` is the paper and `text` the ink. `muted` is every small line of
|
|
35
|
+
sans and every quote; `primary` is links, the kind a kicker names and the
|
|
36
|
+
citation rule; `secondary` is tags and the focus outline. `rule` is a
|
|
37
|
+
decorative hairline and `edge` is a border somebody relies on to find a
|
|
38
|
+
field or a card. `base` is the sunk surface of a field or a code block;
|
|
39
|
+
`base-2` and `base-3` are the cooler and the raised ones. */
|
|
40
|
+
--color-body: #faf7f2;
|
|
41
|
+
--color-text: #1c1917;
|
|
42
|
+
--color-muted: #534c46;
|
|
43
|
+
--color-primary: #8c2f1f;
|
|
44
|
+
--color-secondary: #2b5580;
|
|
45
|
+
--color-rule: #e4dccf;
|
|
46
|
+
--color-edge: #8a867e;
|
|
47
|
+
--color-base: #f3eee5;
|
|
48
|
+
--color-base-2: #f5f6f7;
|
|
49
|
+
--color-base-3: #ffffff;
|
|
50
|
+
--color-code-background: #f3eee5;
|
|
51
|
+
--color-code-text: #1c1917;
|
|
52
|
+
--color-error: #9c1f18;
|
|
53
|
+
|
|
54
|
+
/* Syntax highlighting: the Tomorrow palette, light member (TASK-86). The
|
|
55
|
+
names are what each colour marks up, and the base16 slot they come from is
|
|
56
|
+
in the comment; the highlighter is highlight.js, whose base16 Tomorrow
|
|
57
|
+
theme is the mapping these follow.
|
|
58
|
+
|
|
59
|
+
None of them is the stock colour. Tomorrow was drawn for an editor, where
|
|
60
|
+
a faint comment is a feature; here code is text like any other and meets
|
|
61
|
+
7:1 on the block, so each colour was darkened along its own hue until it
|
|
62
|
+
did and no further. */
|
|
63
|
+
--color-code-comment: #4e4f4d; /* base03, stock #8e908c */
|
|
64
|
+
--color-code-tag: #4e4f4e; /* base04, stock #969896 */
|
|
65
|
+
--color-code-name: #991f1f; /* base08, stock #c82829 */
|
|
66
|
+
--color-code-literal: #77420f; /* base09, stock #f5871f */
|
|
67
|
+
--color-code-class: #624c00; /* base0A, stock #eab700 */
|
|
68
|
+
--color-code-string: #455500; /* base0B, stock #718c00 */
|
|
69
|
+
--color-code-support: #23565a; /* base0C, stock #3e999f */
|
|
70
|
+
--color-code-function: #2f507c; /* base0D, stock #4271ae */
|
|
71
|
+
--color-code-keyword: #63417a; /* base0E, stock #8959a8 */
|
|
72
|
+
--color-code-meta: #6d453c; /* base0F, stock #a3685a */
|
|
73
|
+
--color-code-added-background: #dcedd3;
|
|
74
|
+
--color-code-removed-background: #f5d8d6;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@media (prefers-color-scheme: dark) {
|
|
78
|
+
:root {
|
|
79
|
+
--color-body: #171412;
|
|
80
|
+
--color-text: #ece6de;
|
|
81
|
+
--color-muted: #b2aaa0;
|
|
82
|
+
--color-primary: #ee9370;
|
|
83
|
+
--color-secondary: #86b8e2;
|
|
84
|
+
--color-rule: #3a332e;
|
|
85
|
+
--color-edge: #706a67;
|
|
86
|
+
--color-base: #221d1a;
|
|
87
|
+
--color-base-2: #222124;
|
|
88
|
+
--color-base-3: #2d2421;
|
|
89
|
+
--color-code-background: #221d1a;
|
|
90
|
+
--color-code-text: #ece6de;
|
|
91
|
+
--color-error: #ff8f9f;
|
|
92
|
+
|
|
93
|
+
/* The other member of the family, Tomorrow Night, the palette highlight.js
|
|
94
|
+
ships under that name. Four of its colours were lightened toward white,
|
|
95
|
+
each until it met 7:1 on the block. */
|
|
96
|
+
--color-code-comment: #a9a9a9; /* base03, stock #999999 */
|
|
97
|
+
--color-code-tag: #b4b7b4; /* base04 */
|
|
98
|
+
--color-code-name: #f48b8d; /* base08, stock #f2777a */
|
|
99
|
+
--color-code-literal: #f99157; /* base09 */
|
|
100
|
+
--color-code-class: #ffcc66; /* base0A */
|
|
101
|
+
--color-code-string: #99cc99; /* base0B */
|
|
102
|
+
--color-code-support: #66cccc; /* base0C */
|
|
103
|
+
--color-code-function: #83add6; /* base0D, stock #6699cc */
|
|
104
|
+
--color-code-keyword: #cc99cc; /* base0E */
|
|
105
|
+
--color-code-meta: #c6a198; /* base0F, stock #a3685a */
|
|
106
|
+
--color-code-added-background: #203622;
|
|
107
|
+
--color-code-removed-background: #401e1e;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* Tailwind's utilities, drawn from the tokens above rather than its own
|
|
112
|
+
palette, which is cleared so a utility can only name a colour of this
|
|
113
|
+
design. `inline` puts the `var()` in the utility, so the scheme the custom
|
|
114
|
+
properties flip under flips every utility with them. */
|
|
115
|
+
@theme inline reference {
|
|
116
|
+
--color-*: initial;
|
|
117
|
+
--color-paper: var(--color-body);
|
|
118
|
+
--color-ink: var(--color-text);
|
|
119
|
+
--color-muted: var(--color-muted);
|
|
120
|
+
--color-accent: var(--color-primary);
|
|
121
|
+
--color-accent-2: var(--color-secondary);
|
|
122
|
+
--color-rule: var(--color-rule);
|
|
123
|
+
--color-edge: var(--color-edge);
|
|
124
|
+
--color-surface: var(--color-base);
|
|
125
|
+
--color-code: var(--color-code-background);
|
|
126
|
+
--color-error: var(--color-error);
|
|
127
|
+
--font-serif: 'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', Georgia, serif;
|
|
128
|
+
--font-sans: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
129
|
+
--font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* A link or control that stands on its own, rather than inside a sentence, is
|
|
133
|
+
at least 24 by 24 CSS pixels (WCAG 2.5.8, TASK-145). `inline-flex` grows the
|
|
134
|
+
box without moving the words off the baseline they share with their line.
|
|
135
|
+
Pixels rather than a spacing step, because 24px is the rule's number and the
|
|
136
|
+
root here is 18px. */
|
|
137
|
+
@utility target {
|
|
138
|
+
display: inline-flex;
|
|
139
|
+
align-items: center;
|
|
140
|
+
min-block-size: 24px;
|
|
141
|
+
min-inline-size: 24px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* A link outside prose still says it is a link at rest, with a thin underline
|
|
145
|
+
in its own colour; hover and focus thicken it and turn it accent, so the
|
|
146
|
+
change is never colour alone (WCAG 1.4.1). */
|
|
147
|
+
@utility quiet-link {
|
|
148
|
+
@apply underline decoration-current/50 decoration-1 underline-offset-4 hover:text-accent hover:decoration-accent hover:decoration-2 focus-visible:decoration-2;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@layer base {
|
|
152
|
+
/* `scrollbar-gutter` keeps the scrollbar's room whether or not the page is
|
|
153
|
+
long enough to scroll, so moving between a short page and a long one does
|
|
154
|
+
not shift the column sideways. */
|
|
155
|
+
html {
|
|
156
|
+
font-size: 18px;
|
|
157
|
+
-webkit-text-size-adjust: 100%;
|
|
158
|
+
text-size-adjust: 100%;
|
|
159
|
+
scrollbar-gutter: stable;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
body {
|
|
163
|
+
@apply bg-paper font-serif leading-relaxed text-ink antialiased;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
h1,
|
|
167
|
+
h2,
|
|
168
|
+
h3,
|
|
169
|
+
h4,
|
|
170
|
+
h5,
|
|
171
|
+
h6 {
|
|
172
|
+
@apply font-bold tracking-tight;
|
|
173
|
+
text-wrap: balance;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/* Prose wraps `pretty`, which keeps a paragraph from ending on one short
|
|
177
|
+
word; headings wrap `balance`, which evens their lines out. */
|
|
178
|
+
p,
|
|
179
|
+
li,
|
|
180
|
+
dd,
|
|
181
|
+
blockquote,
|
|
182
|
+
figcaption {
|
|
183
|
+
text-wrap: pretty;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
a {
|
|
187
|
+
@apply text-accent underline decoration-accent/40 underline-offset-[3px] motion-safe:transition-colors;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
a:hover {
|
|
191
|
+
@apply decoration-accent;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* One focus ring for everything that takes focus: a link, a control, a code
|
|
195
|
+
block that scrolls. Nothing here removes it, and a forced palette redraws
|
|
196
|
+
an outline in its own colour. */
|
|
197
|
+
:focus-visible {
|
|
198
|
+
@apply rounded-xs outline-2 outline-offset-2 outline-accent-2;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
hr {
|
|
202
|
+
@apply my-10 border-0 border-t border-rule;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
::selection {
|
|
206
|
+
@apply bg-accent/20;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
code,
|
|
210
|
+
kbd,
|
|
211
|
+
samp,
|
|
212
|
+
pre {
|
|
213
|
+
@apply font-mono;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
strong,
|
|
217
|
+
b {
|
|
218
|
+
@apply font-bold;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
@layer components {
|
|
223
|
+
/* Screen reader text. The skip link is this until it is focused, and then it
|
|
224
|
+
is a box at the top of the page. */
|
|
225
|
+
.screen-reader-text {
|
|
226
|
+
position: absolute;
|
|
227
|
+
width: 1px;
|
|
228
|
+
height: 1px;
|
|
229
|
+
margin: -1px;
|
|
230
|
+
padding: 0;
|
|
231
|
+
overflow: hidden;
|
|
232
|
+
border: 0;
|
|
233
|
+
clip-path: inset(50%);
|
|
234
|
+
white-space: nowrap;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.screen-reader-text:focus {
|
|
238
|
+
@apply z-50 m-0 block h-auto w-auto bg-(--color-base-3) p-4 font-sans font-bold text-ink no-underline;
|
|
239
|
+
inset-block-start: 0.5rem;
|
|
240
|
+
inset-inline-start: 0.5rem;
|
|
241
|
+
clip-path: none;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* The page shell. One wrapper at the measure; nothing is full-bleed. */
|
|
245
|
+
.global-wrapper {
|
|
246
|
+
@apply mx-auto max-w-2xl px-5 pt-8 pb-16 sm:px-6;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/* The header is two shapes. At the root: the site title, the tagline and
|
|
250
|
+
the site menu as a line of its own under a hairline. Everywhere else: the
|
|
251
|
+
small link home with the menu beside it on one line. */
|
|
252
|
+
.global-header {
|
|
253
|
+
@apply mb-12;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.global-wrapper:not([data-is-root-path='true']) .global-header {
|
|
257
|
+
display: flex;
|
|
258
|
+
@apply flex-wrap items-baseline gap-x-6 gap-y-2;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.global-wrapper[data-is-root-path='true'] .global-header {
|
|
262
|
+
@apply mb-14;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.main-heading {
|
|
266
|
+
@apply text-4xl leading-none sm:text-5xl;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.main-heading a,
|
|
270
|
+
.header-link-home {
|
|
271
|
+
@apply text-ink no-underline hover:text-accent hover:underline hover:decoration-2 hover:underline-offset-[6px] focus-visible:underline focus-visible:decoration-2;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.header-link-home {
|
|
275
|
+
@apply target text-lg font-bold;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.site-tagline {
|
|
279
|
+
@apply mt-3 text-lg text-muted italic;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.hlist {
|
|
283
|
+
@apply flex list-none flex-wrap p-0;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.site-nav ul {
|
|
287
|
+
@apply gap-x-5 gap-y-1 font-sans text-[0.78rem] tracking-[0.12em] uppercase;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.site-nav a {
|
|
291
|
+
@apply target quiet-link text-muted;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.site-nav a[aria-current='page'] {
|
|
295
|
+
@apply font-semibold text-ink;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.global-wrapper[data-is-root-path='true'] .global-header .site-nav {
|
|
299
|
+
@apply mt-6 border-t border-rule pt-4;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* The footer: the copyright and the colophon on one side, the footer menu
|
|
303
|
+
on the other, wrapping on a narrow screen. */
|
|
304
|
+
.global-wrapper > footer {
|
|
305
|
+
@apply mt-20 flex flex-wrap items-center justify-between gap-4 border-t border-rule pt-6 font-sans text-sm text-muted;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.global-wrapper > footer .site-nav ul {
|
|
309
|
+
@apply gap-x-4 text-sm tracking-normal normal-case;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/* The kicker: what a thing is, said once, small, above it. The kind word is
|
|
313
|
+
the accent; the date and the categories after it are quiet links. */
|
|
314
|
+
.kicker {
|
|
315
|
+
@apply mb-2 flex flex-wrap items-center gap-x-2 font-sans text-[0.72rem] tracking-[0.14em] text-muted uppercase;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.kicker a {
|
|
319
|
+
@apply target quiet-link text-muted;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.kicker-kind {
|
|
323
|
+
@apply font-semibold text-accent;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/* The breadcrumb: where the page sits, on one quiet line above it. The
|
|
327
|
+
crumbs are links like the kicker's; the last is the page itself. */
|
|
328
|
+
.breadcrumbs ol {
|
|
329
|
+
@apply mb-6 gap-x-2 font-sans text-sm text-muted;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.breadcrumbs a {
|
|
333
|
+
@apply target quiet-link text-muted;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.breadcrumbs-sep {
|
|
337
|
+
@apply me-2;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/* Titles: what heads a listing, an archive, search and an error page. */
|
|
341
|
+
.page-title {
|
|
342
|
+
@apply mt-1 mb-8 text-4xl leading-[1.08] sm:text-[2.75rem];
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.section-title {
|
|
346
|
+
@apply mt-14 mb-6 font-sans text-[0.72rem] font-semibold tracking-[0.14em] text-muted uppercase;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.empty {
|
|
350
|
+
@apply text-muted italic;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/* Prose: whatever a document's words render into. The entry's `e-content`,
|
|
354
|
+
a posts page's and a front page's `page-body`, a note in a feed, a
|
|
355
|
+
comment. Each context sets its own size; these are the shapes. */
|
|
356
|
+
.e-content > * + *,
|
|
357
|
+
.page-body > * + * {
|
|
358
|
+
@apply mt-5;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
:is(.e-content, .page-body) :is(h2, h3, h4, h5, h6) {
|
|
362
|
+
@apply mb-3;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
:is(.e-content, .page-body) h2 {
|
|
366
|
+
@apply mt-10 text-2xl;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
:is(.e-content, .page-body) h3 {
|
|
370
|
+
@apply mt-8 text-xl;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
:is(.e-content, .page-body) :is(h4, h5, h6) {
|
|
374
|
+
@apply mt-6 text-lg;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
:is(.e-content, .page-body) ul {
|
|
378
|
+
@apply list-disc ps-6;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
:is(.e-content, .page-body) ol {
|
|
382
|
+
@apply list-decimal ps-6;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
:is(.e-content, .page-body) li + li,
|
|
386
|
+
:is(.e-content, .page-body) li > :is(ul, ol) {
|
|
387
|
+
@apply mt-2;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
:is(.e-content, .page-body) li > p + p {
|
|
391
|
+
@apply mt-2;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
:is(.e-content, .page-body) blockquote {
|
|
395
|
+
@apply my-8 border-s-2 border-accent ps-5 text-xl leading-snug text-muted italic;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
:is(.e-content, .page-body) blockquote > * + * {
|
|
399
|
+
@apply mt-3;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
:is(.e-content, .page-body) img,
|
|
403
|
+
:is(.e-content, .page-body) video {
|
|
404
|
+
@apply h-auto max-w-full rounded-md;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
:is(.e-content, .page-body) figcaption {
|
|
408
|
+
@apply mt-2 font-sans text-sm text-muted;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
:is(.e-content, .page-body) hr {
|
|
412
|
+
@apply my-10;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
:is(.e-content, .page-body) table {
|
|
416
|
+
@apply w-full border-collapse font-sans text-sm;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
:is(.e-content, .page-body) :is(th, td) {
|
|
420
|
+
@apply border-b border-rule px-2 py-1.5 text-start align-top;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
:is(.e-content, .page-body) th {
|
|
424
|
+
@apply border-edge font-semibold;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
:is(.e-content, .page-body) dt {
|
|
428
|
+
@apply font-bold;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
:is(.e-content, .page-body) dd {
|
|
432
|
+
@apply ps-6;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
:is(.e-content, .page-body) details summary {
|
|
436
|
+
@apply cursor-pointer;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
:is(.e-content, .page-body) kbd {
|
|
440
|
+
@apply rounded-sm border border-edge px-1 text-[0.85em];
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/* Code. A file path or an identifier is one long word, and a narrow screen
|
|
444
|
+
would otherwise carry it off the side of the page; a block of code
|
|
445
|
+
scrolls instead, and is focusable (the CMS renders it `tabindex="0"`) so
|
|
446
|
+
a keyboard can scroll it too. */
|
|
447
|
+
code {
|
|
448
|
+
@apply rounded-sm bg-code px-1.5 py-0.5 text-[0.85em] text-(--color-code-text);
|
|
449
|
+
overflow-wrap: break-word;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
pre {
|
|
453
|
+
@apply overflow-x-auto rounded-md border border-edge bg-code p-4 text-[0.85rem] leading-relaxed text-(--color-code-text);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
pre code {
|
|
457
|
+
@apply rounded-none bg-transparent p-0 text-[length:inherit];
|
|
458
|
+
overflow-wrap: normal;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.footnotes {
|
|
462
|
+
@apply mt-10 border-t border-rule pt-6 font-sans text-sm;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.footnotes-sep {
|
|
466
|
+
@apply hidden;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.footnote-item > p {
|
|
470
|
+
@apply mt-0;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/* Syntax highlighting (TASK-86).
|
|
474
|
+
*
|
|
475
|
+
* The CMS renders a fenced block as `pre > code.language-x` and highlights
|
|
476
|
+
* nothing; `static/highlight.js` marks the tokens up on the client, and
|
|
477
|
+
* these are its colours. The scopes and the slots they map to are
|
|
478
|
+
* highlight.js's own base16 Tomorrow theme, so a token it invents later
|
|
479
|
+
* lands somewhere sensible rather than nowhere.
|
|
480
|
+
*
|
|
481
|
+
* Every colour is a custom property, so a site that wants another palette
|
|
482
|
+
* redefines a dozen tokens instead of writing a syntax theme. Delimiters,
|
|
483
|
+
* operators and substitutions are deliberately the block's own ink: they
|
|
484
|
+
* are most of the characters on screen and a colour there is noise.
|
|
485
|
+
*/
|
|
486
|
+
.hljs-comment {
|
|
487
|
+
color: var(--color-code-comment);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.hljs-tag {
|
|
491
|
+
color: var(--color-code-tag);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.hljs-subst,
|
|
495
|
+
.hljs-punctuation,
|
|
496
|
+
.hljs-operator {
|
|
497
|
+
color: var(--color-code-text);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.hljs-bullet,
|
|
501
|
+
.hljs-variable,
|
|
502
|
+
.hljs-template-variable,
|
|
503
|
+
.hljs-selector-tag,
|
|
504
|
+
.hljs-name {
|
|
505
|
+
color: var(--color-code-name);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.hljs-symbol,
|
|
509
|
+
.hljs-number,
|
|
510
|
+
.hljs-link,
|
|
511
|
+
.hljs-attr,
|
|
512
|
+
.hljs-variable.constant_,
|
|
513
|
+
.hljs-literal {
|
|
514
|
+
color: var(--color-code-literal);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
.hljs-title,
|
|
518
|
+
.hljs-class .hljs-title,
|
|
519
|
+
.hljs-title.class_ {
|
|
520
|
+
color: var(--color-code-class);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.hljs-strong {
|
|
524
|
+
color: var(--color-code-class);
|
|
525
|
+
font-weight: 700;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
.hljs-code,
|
|
529
|
+
.hljs-string,
|
|
530
|
+
.hljs-title.class_.inherited__ {
|
|
531
|
+
color: var(--color-code-string);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.hljs-built_in,
|
|
535
|
+
.hljs-doctag,
|
|
536
|
+
.hljs-quote,
|
|
537
|
+
.hljs-regexp,
|
|
538
|
+
.hljs-keyword.hljs-atrule {
|
|
539
|
+
color: var(--color-code-support);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.hljs-attribute,
|
|
543
|
+
.hljs-function .hljs-title,
|
|
544
|
+
.hljs-section,
|
|
545
|
+
.hljs-title.function_ {
|
|
546
|
+
color: var(--color-code-function);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
.hljs-keyword,
|
|
550
|
+
.hljs-template-tag,
|
|
551
|
+
.hljs-type {
|
|
552
|
+
color: var(--color-code-keyword);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.hljs-emphasis {
|
|
556
|
+
color: var(--color-code-keyword);
|
|
557
|
+
font-style: italic;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
.hljs-meta,
|
|
561
|
+
.hljs-meta .hljs-keyword,
|
|
562
|
+
.hljs-meta .hljs-string {
|
|
563
|
+
color: var(--color-code-meta);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/* A diff reads by the line, not by the token: the whole line takes a tint
|
|
567
|
+
out to the edges of the block (the negative margin cancels the `pre`
|
|
568
|
+
padding and the padding puts it back) and keeps the block's own ink,
|
|
569
|
+
which is the pair the contrast test checks. The `+` and the `-` stay in
|
|
570
|
+
the text, so the meaning does not rest on the colour alone. */
|
|
571
|
+
.hljs-addition,
|
|
572
|
+
.hljs-deletion {
|
|
573
|
+
display: block;
|
|
574
|
+
margin-inline: -1rem;
|
|
575
|
+
padding-inline: 1rem;
|
|
576
|
+
color: var(--color-code-text);
|
|
577
|
+
text-decoration: none;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
.hljs-addition {
|
|
581
|
+
background-color: var(--color-code-added-background);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
.hljs-deletion {
|
|
585
|
+
background-color: var(--color-code-removed-background);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/* A listing: `h-feed` of `h-entry`, hairlines between. An article is the
|
|
589
|
+
only entry with a headline; a note or a reply is its words. */
|
|
590
|
+
.feed {
|
|
591
|
+
@apply mt-2;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
.feed-separator {
|
|
595
|
+
@apply my-9;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
.feed-title {
|
|
599
|
+
@apply mt-1 mb-3 text-3xl leading-tight;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
.feed-title a {
|
|
603
|
+
@apply text-ink no-underline hover:text-accent hover:underline hover:decoration-2 hover:underline-offset-[6px] focus-visible:underline focus-visible:decoration-2;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.feed-excerpt.p-summary {
|
|
607
|
+
@apply text-[1.05rem];
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
.feed-item > .e-content {
|
|
611
|
+
@apply text-[1.12rem] leading-[1.6];
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
.feed-more,
|
|
615
|
+
.front-links {
|
|
616
|
+
@apply mt-3 font-sans text-sm;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.feed-more a,
|
|
620
|
+
.front-links a {
|
|
621
|
+
@apply target gap-1 hover:decoration-2;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
.front-links {
|
|
625
|
+
@apply mt-10 flex flex-wrap gap-x-6;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/* A citation: what a reply answers. A rule on the start side, a sans line
|
|
629
|
+
naming it, and its words as an italic quote. */
|
|
630
|
+
.cite {
|
|
631
|
+
@apply my-3 border-s-2 border-accent ps-4;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
.cite-line {
|
|
635
|
+
@apply font-sans text-sm text-muted;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
.cite-line a {
|
|
639
|
+
@apply target quiet-link font-medium text-ink;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
.cite-quote {
|
|
643
|
+
@apply mt-1 text-[0.98rem] leading-snug text-muted italic;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/* One post or page: `article.blog-post.h-entry`. */
|
|
647
|
+
.post-header {
|
|
648
|
+
@apply mb-8;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
.post-header h1 {
|
|
652
|
+
@apply mt-1 text-4xl leading-[1.08] sm:text-[2.75rem];
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.post-deck {
|
|
656
|
+
@apply mt-4 text-xl leading-snug text-muted italic;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
.blog-post > .e-content {
|
|
660
|
+
@apply text-[1.08rem] leading-[1.65];
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/* An untitled post is its words, set larger. It is the one entry whose
|
|
664
|
+
heading is the hidden one TASK-144 gave it. */
|
|
665
|
+
.blog-post > .screen-reader-text ~ .e-content {
|
|
666
|
+
@apply text-[1.3rem] leading-[1.55];
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
.entry-meta,
|
|
670
|
+
.page-meta {
|
|
671
|
+
@apply mt-8 flex flex-wrap items-center gap-x-2 font-sans text-sm text-muted;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/* A page usually carries no date, and then this line has nothing in it. */
|
|
675
|
+
.page-meta:empty {
|
|
676
|
+
@apply hidden;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
.entry-meta a,
|
|
680
|
+
.page-meta a {
|
|
681
|
+
@apply target quiet-link text-muted;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/* The tags under an entry. The `#` is drawn rather than printed, so the
|
|
685
|
+
`p-category` a parser reads is the tag and not the hash. */
|
|
686
|
+
.post-categories {
|
|
687
|
+
@apply mt-2 flex flex-wrap gap-x-3 font-sans text-sm;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
.post-categories a {
|
|
691
|
+
@apply target quiet-link text-accent-2;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.post-categories a[rel='tag']::before {
|
|
695
|
+
content: '#';
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.blog-post > hr {
|
|
699
|
+
@apply mt-10 mb-8;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/* The posts either side of this one, as two cards. */
|
|
703
|
+
.blog-post-nav {
|
|
704
|
+
@apply my-12 font-sans text-sm;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.blog-post-nav ul {
|
|
708
|
+
@apply grid list-none gap-4 p-0 sm:grid-cols-2;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
.blog-post-nav li:has(> a[rel='next']) {
|
|
712
|
+
@apply sm:col-start-2;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
.blog-post-nav a {
|
|
716
|
+
@apply target h-full w-full flex-col items-start rounded-md border border-edge p-4 text-ink no-underline hover:border-2 hover:border-accent hover:p-[calc(1rem-1px)] hover:text-accent;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
.blog-post-nav a[rel='next'] {
|
|
720
|
+
@apply sm:items-end sm:text-end;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
.blog-post-nav-label {
|
|
724
|
+
@apply mb-1 block text-[0.7rem] tracking-[0.14em] text-muted uppercase;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/* The bio: a round photo and the person beside it. */
|
|
728
|
+
.bio {
|
|
729
|
+
@apply flex items-start gap-4;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
.bio-avatar {
|
|
733
|
+
@apply shrink-0;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
.bio-avatar img {
|
|
737
|
+
@apply size-14 rounded-full object-cover;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.bio .p-name {
|
|
741
|
+
@apply font-bold text-ink;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
.bio-note {
|
|
745
|
+
@apply mt-1 text-[0.95rem] text-muted;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
.bio-links {
|
|
749
|
+
@apply mt-1 gap-x-4 font-sans text-sm;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.bio-links a {
|
|
753
|
+
@apply target;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
.global-wrapper[data-is-root-path='true'] .bio {
|
|
757
|
+
@apply mt-2;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/* An archive's header: the kicker naming what it is, then its name. */
|
|
761
|
+
.archive-header .page-title {
|
|
762
|
+
@apply mb-4;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
.archive-header {
|
|
766
|
+
@apply mb-10;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.category-description {
|
|
770
|
+
@apply text-lg text-muted italic;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.author-header + .bio {
|
|
774
|
+
@apply mb-12;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/* The archive page: every post there has been, month by month. */
|
|
778
|
+
.archive h2 {
|
|
779
|
+
@apply mt-10 mb-3 text-2xl;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
.archive ol {
|
|
783
|
+
@apply list-none space-y-1 p-0;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.archive a {
|
|
787
|
+
@apply target;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
/* Pagination: two words, the newer at the start and the older at the end. */
|
|
791
|
+
.pagination {
|
|
792
|
+
@apply mt-12 flex flex-wrap gap-4 font-sans text-sm;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
.pagination a {
|
|
796
|
+
@apply target quiet-link gap-1;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
.pagination-next {
|
|
800
|
+
@apply ms-auto;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/* Search: the box, what it found, and each result as a feed entry. */
|
|
804
|
+
.search-form {
|
|
805
|
+
@apply mb-8 flex gap-2;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
.search-form label {
|
|
809
|
+
@apply flex-1;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
.search-summary {
|
|
813
|
+
@apply mb-8 font-sans text-sm text-muted;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
.search-result + .search-result {
|
|
817
|
+
@apply mt-9 border-t border-rule pt-9;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
.search-result .feed-title {
|
|
821
|
+
@apply text-2xl;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
.search-snippet mark {
|
|
825
|
+
@apply rounded-xs bg-accent/20 px-0.5 text-ink;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/* The error pages. */
|
|
829
|
+
:is(.not-found, .server-error, .maintenance) > p {
|
|
830
|
+
@apply text-[1.08rem];
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/* Reactions: the likes, the boosts and the pages that mentioned a post, as
|
|
834
|
+
rows of faces under a small label. */
|
|
835
|
+
.reactions-section {
|
|
836
|
+
@apply mt-14 mb-10 flex flex-wrap gap-x-10 gap-y-4;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.reaction-group {
|
|
840
|
+
@apply min-w-0;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
.reaction-title {
|
|
844
|
+
@apply mb-2 font-sans text-[0.72rem] font-normal tracking-[0.14em] text-muted uppercase;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
.reaction-count {
|
|
848
|
+
@apply ms-1 font-semibold text-ink;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
.facepile {
|
|
852
|
+
@apply flex flex-wrap items-center;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
.facepile > a,
|
|
856
|
+
.facepile > span {
|
|
857
|
+
@apply relative -ms-2 rounded-full ring-2 ring-paper first:ms-0 hover:z-10 motion-safe:transition-transform motion-safe:hover:scale-110;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
.facepile img {
|
|
861
|
+
@apply size-8 rounded-full;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/* A reaction with no avatar has nothing to recognise anybody by, so the
|
|
865
|
+
emoji of its kind and the name stand in, as a pill. */
|
|
866
|
+
.facepile > :has(.reaction-name) {
|
|
867
|
+
@apply target ms-1 gap-1 bg-surface px-2 font-sans text-sm text-ink no-underline ring-0 first:ms-0;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
.reaction-icon {
|
|
871
|
+
@apply text-xs;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/* The thread: every reply from every door, each one an h-entry. */
|
|
875
|
+
.comments-area {
|
|
876
|
+
@apply mt-14;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
.comments-title {
|
|
880
|
+
@apply mb-5 text-xl;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
.comment-list {
|
|
884
|
+
@apply m-0 list-none space-y-8 p-0;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
.comment-list .children {
|
|
888
|
+
@apply mt-6 list-none space-y-6 border-s border-rule ps-6 sm:ps-12;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
.comment-body {
|
|
892
|
+
@apply flex flex-col gap-2;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
.comment-meta {
|
|
896
|
+
@apply flex flex-wrap items-center gap-x-3 gap-y-1 font-sans text-sm;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
.comment-author {
|
|
900
|
+
@apply flex items-center gap-2;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
.comment-author .avatar,
|
|
904
|
+
.comment-avatar-empty {
|
|
905
|
+
@apply size-8 shrink-0 rounded-full;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
.comment-avatar-empty {
|
|
909
|
+
@apply inline-flex items-center justify-center bg-surface font-semibold text-muted;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
.comment-author a {
|
|
913
|
+
@apply target quiet-link text-ink;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
.comment-metadata a {
|
|
917
|
+
@apply target quiet-link text-muted;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
.comment-metadata {
|
|
921
|
+
@apply text-muted;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
.comment-source {
|
|
925
|
+
@apply text-muted italic;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
.comment-content {
|
|
929
|
+
@apply text-[1.02rem];
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
.reply {
|
|
933
|
+
@apply font-sans text-sm;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
.reply a {
|
|
937
|
+
@apply target;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
.no-comments {
|
|
941
|
+
@apply mt-8 font-sans text-sm text-muted italic;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
/* The comment form under an open post and the contact form on a page that
|
|
945
|
+
asked for one, which wears the same class. */
|
|
946
|
+
.comment-respond {
|
|
947
|
+
@apply mt-12 border-t border-rule pt-10;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
.comment-reply-title,
|
|
951
|
+
.contact-form-title {
|
|
952
|
+
@apply mb-5 text-xl;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
.comment-help {
|
|
956
|
+
@apply -mt-3 mb-5 text-[0.95rem] text-muted;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
.comment-respond form {
|
|
960
|
+
@apply flex flex-col gap-4;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
.field-row {
|
|
964
|
+
@apply grid gap-x-4 gap-y-4 sm:grid-cols-2;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
.comment-respond label {
|
|
968
|
+
@apply mb-1 block font-sans text-sm;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
.comment-optional,
|
|
972
|
+
.contact-optional,
|
|
973
|
+
.comment-hint,
|
|
974
|
+
.contact-hint {
|
|
975
|
+
@apply text-muted;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
.comment-hint,
|
|
979
|
+
.contact-hint,
|
|
980
|
+
.comment-field-error,
|
|
981
|
+
.contact-field-error {
|
|
982
|
+
@apply mt-1 block font-sans text-sm;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
.comment-field-error,
|
|
986
|
+
.contact-field-error {
|
|
987
|
+
@apply text-error;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
:is(.comment-respond, .search-form) :is(input:not([type='checkbox'], [type='hidden']), textarea) {
|
|
991
|
+
@apply block w-full rounded-md border border-edge bg-surface px-3 py-2 font-serif text-base text-ink;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
/* A field the reader has left invalid, or one a refused submission marked,
|
|
995
|
+
says so with a heavier border in the error colour, without JavaScript. */
|
|
996
|
+
:is(.comment-respond, .search-form)
|
|
997
|
+
:is(input, textarea):is(:user-invalid, [aria-invalid='true']) {
|
|
998
|
+
@apply border-2 border-error px-[calc(0.75rem-1px)] py-[calc(0.5rem-1px)];
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
.comment-check {
|
|
1002
|
+
@apply flex items-center gap-2;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
.comment-check label {
|
|
1006
|
+
@apply mb-0;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
.comment-respond input[type='checkbox'] {
|
|
1010
|
+
inline-size: 24px;
|
|
1011
|
+
block-size: 24px;
|
|
1012
|
+
margin: 0;
|
|
1013
|
+
accent-color: var(--color-primary);
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
.search-form button,
|
|
1017
|
+
.comment-respond .form-submit button,
|
|
1018
|
+
.comment-respond .form-submit input[type='submit'] {
|
|
1019
|
+
@apply cursor-pointer rounded-md bg-accent px-5 py-2.5 font-sans text-sm font-semibold text-paper hover:bg-ink;
|
|
1020
|
+
min-block-size: 24px;
|
|
1021
|
+
min-inline-size: 24px;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
.comment-signed-in,
|
|
1025
|
+
.comment-replying-to {
|
|
1026
|
+
@apply font-sans text-sm text-muted;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
.comment-signed-in a,
|
|
1030
|
+
.comment-replying-to a {
|
|
1031
|
+
@apply text-accent;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
.comment-notice,
|
|
1035
|
+
.contact-notice {
|
|
1036
|
+
@apply rounded-md border border-edge bg-surface p-4 font-sans text-sm text-ink;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
/* A refused form's summary: what went wrong as its heading, then a link to
|
|
1040
|
+
each field to put right. */
|
|
1041
|
+
.comment-error,
|
|
1042
|
+
.contact-error {
|
|
1043
|
+
@apply my-6 border-s-2 border-error ps-4 font-sans text-sm;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
.comment-error h3,
|
|
1047
|
+
.contact-error h3 {
|
|
1048
|
+
@apply font-sans text-base font-semibold text-error;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
.comment-error ul,
|
|
1052
|
+
.contact-error ul {
|
|
1053
|
+
@apply mt-2 list-disc ps-5;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
.comment-error a,
|
|
1057
|
+
.contact-error a {
|
|
1058
|
+
@apply target;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
/* The honeypot. Taken out of the flow rather than `display: none`, because
|
|
1062
|
+
some form fillers skip fields a browser would not paint at all and this
|
|
1063
|
+
one is meant to be filled in. */
|
|
1064
|
+
.comment-trap,
|
|
1065
|
+
.contact-trap {
|
|
1066
|
+
position: absolute;
|
|
1067
|
+
inset-inline-start: -10000px;
|
|
1068
|
+
width: 1px;
|
|
1069
|
+
height: 1px;
|
|
1070
|
+
overflow: hidden;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
/* Forced colours: Windows High Contrast and the like, where the reader's own
|
|
1075
|
+
palette replaces every colour here. Borders and outlines survive that and
|
|
1076
|
+
backgrounds do not, so anything drawn by a background alone takes a border
|
|
1077
|
+
in a system colour: the buttons, a hairline, code, a matched word and the
|
|
1078
|
+
face that is a pill. Focus needs nothing: every ring here is an outline,
|
|
1079
|
+
which the forced palette redraws in its own colour. */
|
|
1080
|
+
@media (forced-colors: active) {
|
|
1081
|
+
.search-form button,
|
|
1082
|
+
.comment-respond .form-submit button,
|
|
1083
|
+
.comment-respond .form-submit input[type='submit'] {
|
|
1084
|
+
border: 1px solid ButtonText;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
hr {
|
|
1088
|
+
border-block-start: 1px solid CanvasText;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
pre {
|
|
1092
|
+
border: 1px solid CanvasText;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
code,
|
|
1096
|
+
.search-snippet mark,
|
|
1097
|
+
.comment-avatar-empty {
|
|
1098
|
+
border: 1px solid CanvasText;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
pre code {
|
|
1102
|
+
border: 0;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
.facepile > a,
|
|
1106
|
+
.facepile > span {
|
|
1107
|
+
outline: 1px solid CanvasText;
|
|
1108
|
+
}
|
|
1109
|
+
}
|