@rathnasgala/theme 2.0.12 → 2.0.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rathnasgala/theme",
3
- "version": "2.0.12",
3
+ "version": "2.0.15",
4
4
  "description": "Managed Gala static-site theme payload",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -8,7 +8,7 @@
8
8
  "url": "git+https://github.com/rathnasgala/site-template.git"
9
9
  },
10
10
  "gala": {
11
- "sourceCommit": "288c88e981fc57ab267a3ab7a1c22757a9a2649b"
11
+ "sourceCommit": "3c71d3fa099d04d5de82e6fadd49d202ccb614fc"
12
12
  },
13
13
  "files": [
14
14
  "payload"
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "themePackage": {
4
4
  "name": "@rathnasgala/theme",
5
- "version": "2.0.12",
5
+ "version": "2.0.15",
6
6
  "availableDesignThemes": [
7
7
  "editorial",
8
8
  "modern",
@@ -18,10 +18,10 @@
18
18
  ".gala/publish.yml.template": "d93da94c10378693cdd927cd6623a003ff57c15d8b8aeba3644c914f2753d824",
19
19
  ".gitignore": "b5fa24e10155097a0d372926fd2e59e6072e7cc2cb6399bbfb4beb8b33ea315b",
20
20
  "eleventy.config.js": "7772953f8c55673d9e11fb803c75470f8a61747de9e1cec0d03bbbedb7fae246",
21
- "lib/accent.js": "e6c921e0a3afe094b18709e3e40baa06692017fa6576d84b1ec6b7d788da8dd0",
22
- "lib/build-manifest.js": "240dd6900e1277986fa935449ad1757641c47a325599b8b847a4e8dfcb50181c",
21
+ "lib/accent.js": "24e5d2bcf00e6b3ad86cf8942e56dcb98b0d06ff8e0673ccb7cc85fa732e0837",
22
+ "lib/build-manifest.js": "b6fd412256515603a075d1fcf5f9fb57f197b4fd5f92c9ca28ca5fe2486daf11",
23
23
  "lib/engagement-snapshot.js": "298c11b1ab135a3a98a4e31b6320ab60dfd7fda6a9d9053df37d86282a5a6687",
24
- "lib/performance-budget.js": "c279622dfde237cd6e3c64775c91d770a0e1f54f5f94257ccc95d9a44de2c4c9",
24
+ "lib/performance-budget.js": "70c5d1d697302466e1fa982fd07b19abb299e3fcae0bb05aa8cdebf5d7b69241",
25
25
  "lib/prism-compiled-output.js": "0c1f93d025c70dbec10c78f17f59ae10a9a6de773b58adb2f26f42de62f7be2c",
26
26
  "lib/prism-session.js": "16a55d9d3d6b5bd2f95bfdb15a76a795b0406ddc51fae45014e0b0f5795194ca",
27
27
  "lib/provider-fixtures/embeds.v1.json": "5f26909fb433135321ddf7fdd14e45aeb702805c88f5676941166c5735143ee2",
@@ -30,19 +30,19 @@
30
30
  "lib/render-markdown.js": "275b7da721aef1f68cda515673153471c0d597061e8fdf867c5f2b32c98b91db",
31
31
  "lib/seo.js": "19cf1d67d5b711b8d3a533f207f267e770ee46fd4a4e6561c5f7fd4e9c1989ff",
32
32
  "lib/share-targets.js": "458aff86fab2b62a364442cd8c612565c6e0b53eef2f20cb6237cc562b1e0731",
33
- "lib/site-config.js": "55eccfc4eab65a58fdcb06aa53f578b7b423cc186b93cad18c30705aec219d34",
33
+ "lib/site-config.js": "e646e031b46a1f8d71ea3afce8cca45d31e65d7b39cbdac10ab5c62934dfbf7e",
34
34
  "package-lock.json": "dc11470b1ad897c58d91745f23ff25711c593e62972ec9fb83f4e10fd77e1ecd",
35
35
  "package.json": "7a3c2b559054b1613d84cbda3a1fd370bc725818f9f418f0fe90cf3f8f0a9caa",
36
36
  "scripts/build-reader.js": "743194c8dc9cfb9b6631db1732b5f36a92e3a4f905a2965c71d56e1ef50c2e45",
37
37
  "scripts/lint.js": "c4bb3c961686043fa8c79bed546758ef09d44441421d8209fec9d69f74171025",
38
38
  "src/_data/buildManifest.js": "a889cb4642c2f0beaa7f31f662fd8da7ab2d4dce819faf69a3aa984e55270336",
39
39
  "src/_data/engagementSnapshot.js": "9217dacebfaf008f7a0ad67ff4e8d1fa8fba609a9dc7e3430c78c5b32024da0e",
40
- "src/_data/feedLinks.js": "06c93352ebd888acb431a1c9a8be6ecff757895468e9f2d336761038751c2d5e",
40
+ "src/_data/feedLinks.js": "8317ec93ef58d2d73d0b23f753109e8485026249c877c2904c2b3b5c8d336782",
41
41
  "src/_data/languages.js": "1358748f7fa2f74406d3295a030827d6229a53e94da72cf712e719d7a356aeac",
42
- "src/_data/site.js": "432be73b49c20f088c304a2f7d7cd85906a747e0f3b381a4b395c5c44d68bb57",
43
- "src/_includes/components/ui.njk": "0634c206c2db0507f77686635e3b406e1d8878011fd7eac64563df8499fe8f60",
42
+ "src/_data/site.js": "41e60190d22337321d480a29be9774eaa93a98b848e92b5139129ae97c44fd97",
43
+ "src/_includes/components/ui.njk": "993ddb816a3a74f476040dc403abae3fd02896e99be480fd57177c342c8e8201",
44
44
  "src/_includes/layouts/base.njk": "054460a1293e55a5abc5902899ef2f7a6e256b50aa51375e8d209e2cf2ec2aeb",
45
- "src/_includes/layouts/post.njk": "46fd004846aed6c7d0668bad4ed0239f001038c33feb66a71638ee811c44f0ba",
45
+ "src/_includes/layouts/post.njk": "e48e00ca916b740d95e465caae1f1efc0523056ce4bdadd2d2593b80072de530",
46
46
  "src/_includes/layouts/prism-configuration.njk": "c984441ac50465eb6ee0e050c68c054e3a0bca98960fb92fb2f5795443301594",
47
47
  "src/404.njk": "be0d44370ac5402156aaf3d32ea581057bc61ec94c1a5f92bb809733af7a8a20",
48
48
  "src/accent.11ty.js": "52e7d3eb731c5f4649c14c4745f65da026c25b58cf462d075b8ef363f0e487dc",
@@ -51,29 +51,29 @@
51
51
  "src/assets/embed-x.svg": "0ae74edc6790ec7e933067fe5392bce756e93fa7ad71caacf1c1ca99fa4ec9b6",
52
52
  "src/assets/embed-youtube.svg": "10d192f2b14b67664fea88c8cf246321d20190def51d59fad5762e552219b067",
53
53
  "src/assets/engagement-comments.js": "eda0fee471c7e42ee01a25b8aa14ed6ae9690d52b3fbb34027d97534ab62998b",
54
- "src/assets/engagement-transport.js": "d4108cded823f859e7a8d6e36716162422ceaf5e4b94a57ed9bd7941d5096216",
54
+ "src/assets/engagement-transport.js": "7f69815c4eb4fc0e127a5c09702da4189130d47b73b4598fce4196d7d6f5cbe8",
55
55
  "src/assets/favicon.svg": "8615e3d96fe37ae9ed14afb1886e7c0e690eef5b10be66ca91cccfd085a74bb6",
56
- "src/assets/interactions.js": "db4d4d88d7fb415868d71ad62eaefd12a2333a3bec2fff5652b22ee0904a7318",
56
+ "src/assets/interactions.js": "cfc67fb45fbf77dc584e0c2dd3a8de797ba6410cbe225a6e82b7c074bc832c5d",
57
57
  "src/assets/preferences.js": "789127bee013ed6a1bbf8cefd7b9109291c16220e7a6e09314e3c93c54731d1d",
58
58
  "src/assets/prism-session.js": "1fab23725b843006c3f589af7669ef3ad6ad01f3264a3b00564e64b56738d2cd",
59
59
  "src/assets/reader.js": "0be5a7f7bae2c274f65e34421d74d7abcc228112fbbf49ec52e69980dad86ecd",
60
60
  "src/assets/search.js": "df425f0239277792ad39f2138bc89cb66cc4ecda5ed59042d46abc2f05372088",
61
- "src/assets/theme-mode.js": "944b29db11a577961a60ddcfa52f07ef2411f3f3631bea85bd79be16428c08be",
62
- "src/assets/theme.css": "342bf3219520c791340fd56fabc02e005fdc61d18500f1cb959643620695d97c",
63
- "src/assets/version.js": "fd555379eb050da48d4bcd25a8ee64dcd607d758c4f838c8d3e89fad90b59dfd",
61
+ "src/assets/theme-mode.js": "d81af8317b59f6d94dc8154c1dcba9d3e16accb37348bc3fce127712141d6c63",
62
+ "src/assets/theme.css": "7391086efd6f61791c47bbdf3523d7452e17b1cdb1fc91339861fe2f0a2c884b",
63
+ "src/assets/version.js": "57d1bb2bd949a7bdc00de6293138c1044a57b41f611ca6cc2da5aa168e5f0543",
64
64
  "src/client/reader.js": "643aec955c5beb6f902c737313dbc1a8232150fcb5d800350aa7fb1fb69f1760",
65
- "src/cname.11ty.js": "206fc224df91c569e18312158e7f69803061f2952513f501ada54bd06c4f8006",
65
+ "src/cname.11ty.js": "890f963f42fa8d20dce35f2784e099dcb6d7c03840909db3c9fa10c6a94cbeca",
66
66
  "src/contact.njk": "f4d74d038781e15af0acef571901c91e7753a2e21b6bef617429585698839a34",
67
- "src/feed.11ty.js": "009bd2384e08e02a9405683bab1653bab3aeaec16accb0fd01ba69b24c777da9",
68
- "src/index.njk": "5c313f0fcdad3ddbfb79376bc9671b3f37539ef70c14bdbbd26d6e2e6de250e8",
69
- "src/languages.11ty.js": "399559199c65570d7d5efd88e20254838e316f81c06d7b28ec34990e963db915",
67
+ "src/feed.11ty.js": "0082bb5d69bcb91618c4069c56766a48ecb756bf12df0c794ed63f3ae6936a88",
68
+ "src/index.njk": "98e415ad30a668e7696b4647533c7fed030f8da79760026634bc87702b015ee2",
69
+ "src/languages.11ty.js": "cf3df5a22676abd9c862af6ff7048c41c28dc2eaa6baddbeb44228b73ddfe7e3",
70
70
  "src/posts.11ty.js": "abdfd572fb93fc79c92e1ba2aa9601e768e2ee32ae108038a429407c0b1cb053",
71
71
  "src/prism-configurations.11ty.js": "ecfda10ef9c1092549e7eeb75b971c14481bea0f48919764b7df79bf026ec6aa",
72
72
  "src/redirects.11ty.js": "3c163246a59f5364861db6a6f05ae88afc938a5379d86cf42776d8d49b0031f3",
73
73
  "src/search-index.11ty.js": "700dc2a2be0ef20de3a828a4612fcf7a082691eade29c6e1d75f09c24b6c6024",
74
74
  "src/search.njk": "63f2e8aeebb63c90da2e375eece639ce096cad1eff7f28628cafc46faf7ceee6",
75
75
  "src/sitemap.11ty.js": "4f233e94fb4a913ad5659116518432ed264984a7b622eba3558c77b4ec6435dc",
76
- "src/styles/theme.css": "6fc1e8b8776a8ef52000e2f8a6afa082c9bf19ac5aed166377b5a4c7717267f1",
76
+ "src/styles/theme.css": "56fe8387182aee00df73f24d853f9d98fe0026f9e627e193e6d9deba9a4f631e",
77
77
  "src/version.njk": "c0833dcf14a246c069903d35f8be92d410935b968a26346af237bc1392c88340",
78
78
  "static/favicon.ico": "ad3cb0b02f0164f3af6280d0bfe712879d55cec0e9a7a567f658aaddca5a55a2",
79
79
  "static/robots.txt": "16ceb5ee3e0dc13aa9adf31a3ebbe45a1d965b8c2b9f72eaf84e5911e140ed95"
@@ -4,7 +4,7 @@
4
4
  * Offering a handful of named presets was not picking a colour, and an unconstrained colour picker
5
5
  * is worse: most colours a person likes fail contrast against one ground or the other, and a
6
6
  * writer cannot see that until the site is deployed. So the seed is treated as a *hue* the writer
7
- * chose, and the lightness is moved as little as possible until the result is readable on the
7
+ * chose, and the lightness is moved - as little as possible - until the result is readable on the
8
8
  * background it will actually sit on.
9
9
  *
10
10
  * The maths is OKLab, so a hue keeps its identity while its lightness changes. Doing this in sRGB
@@ -22,7 +22,7 @@ function absoluteHttps(value, field) {
22
22
  }
23
23
  }
24
24
 
25
- function validatedPost(post, index, seen) {
25
+ function validatedPost(post, index, seen, preview) {
26
26
  if (post == null || Array.isArray(post) || typeof post !== 'object') {
27
27
  throw new TypeError(`build manifest posts[${index}] must be a mapping`);
28
28
  }
@@ -30,7 +30,10 @@ function validatedPost(post, index, seen) {
30
30
  || post.source.split('/').some((part) => part === '.' || part === '..')) {
31
31
  throw new TypeError(`build manifest posts[${index}].source is invalid`);
32
32
  }
33
- if (!ULID.test(post.id)) {
33
+ const transientPreviewPost = preview
34
+ && post.publicationState === 'not-emitted'
35
+ && post.id === null;
36
+ if (!ULID.test(post.id) && !transientPreviewPost) {
34
37
  throw new TypeError(`build manifest posts[${index}].id is invalid`);
35
38
  }
36
39
  if (!SLUG.test(post.slug) || !LANGUAGE.test(post.language)) {
@@ -43,7 +46,8 @@ function validatedPost(post, index, seen) {
43
46
  }
44
47
  absoluteHttps(post.canonicalUrl, `build manifest posts[${index}].canonicalUrl`);
45
48
  absoluteHttps(post.pageUrl, `build manifest posts[${index}].pageUrl`);
46
- if (!STATES.has(post.publicationState)) {
49
+ if (!STATES.has(post.publicationState)
50
+ && !(preview && post.publicationState === 'not-emitted')) {
47
51
  throw new TypeError(`build manifest posts[${index}].publicationState is invalid`);
48
52
  }
49
53
  if (post.frontmatter == null || Array.isArray(post.frontmatter)
@@ -86,12 +90,14 @@ function validatedPost(post, index, seen) {
86
90
  return Object.freeze({ source, output });
87
91
  });
88
92
  }
89
- const identityVariant = `${post.id}\u0000${post.language.toLowerCase()}`;
93
+ const identityVariant = post.id === null
94
+ ? null
95
+ : `${post.id}\u0000${post.language.toLowerCase()}`;
90
96
  for (const [type, value] of [
91
97
  ['source', post.source],
92
98
  ['relativeUrl', post.relativeUrl],
93
99
  ['pageUrl', post.pageUrl],
94
- ['identity-language', identityVariant]
100
+ ...(identityVariant == null ? [] : [['identity-language', identityVariant]])
95
101
  ]) {
96
102
  const values = seen[type];
97
103
  if (values.has(value)) throw new TypeError(`build manifest duplicate ${type}: ${value}`);
@@ -132,7 +138,8 @@ function validatedRedirect(redirect, index, seen) {
132
138
  export function validateBuildManifest(value) {
133
139
  if (value == null || Array.isArray(value) || typeof value !== 'object'
134
140
  || ![1, 2].includes(value.schemaVersion) || !DATE.test(value.evaluationDate)
135
- || !Array.isArray(value.posts) || !Array.isArray(value.redirects)) {
141
+ || !Array.isArray(value.posts) || !Array.isArray(value.redirects)
142
+ || (value.preview != null && typeof value.preview !== 'boolean')) {
136
143
  throw new TypeError('Unsupported build manifest schema');
137
144
  }
138
145
  const seen = {
@@ -141,7 +148,8 @@ export function validateBuildManifest(value) {
141
148
  pageUrl: new Set(),
142
149
  'identity-language': new Set()
143
150
  };
144
- const posts = value.posts.map((post, index) => validatedPost(post, index, seen));
151
+ const preview = value.preview === true;
152
+ const posts = value.posts.map((post, index) => validatedPost(post, index, seen, preview));
145
153
  const redirects = value.redirects.map((redirect, index) =>
146
154
  validatedRedirect(redirect, index, seen)
147
155
  );
@@ -200,6 +208,7 @@ export function validateBuildManifest(value) {
200
208
  return Object.freeze({
201
209
  schemaVersion: value.schemaVersion,
202
210
  evaluationDate: value.evaluationDate,
211
+ ...(preview ? { preview: true } : {}),
203
212
  ...(assignedContentIds == null
204
213
  ? {}
205
214
  : { assignedContentIds: Object.freeze(assignedContentIds) }),
@@ -26,7 +26,7 @@ export async function enforcePerformanceBudgets({ outputDirectory, budgets }) {
26
26
  const files = await filesBelow(output);
27
27
  /*
28
28
  * Everything under `assets`, nested included. This used to compare `path.dirname` against the
29
- * assets directory exactly, so anything in a subdirectory was invisible to the budget the
29
+ * assets directory exactly, so anything in a subdirectory was invisible to the budget - the
30
30
  * moment the reader runtime moved into `assets/vendor` it would have stopped being counted, and
31
31
  * a budget that quietly ignores two thirds of the JavaScript it is meant to guard is worse than
32
32
  * having none.
@@ -56,7 +56,7 @@ export function validateCanonicalUrlTemplate(value) {
56
56
  * back to its own defaults for anything absent. Present-but-unknown is still an error, because
57
57
  * that is a writer expecting something the CSS will not do.
58
58
  */
59
- /** A free colour, not a menu but still a colour. */
59
+ /** A free colour, not a menu - but still a colour. */
60
60
  const ACCENT = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
61
61
 
62
62
  function validateImplementedDesign(config) {
@@ -6,7 +6,7 @@ const site = await loadSiteConfiguration();
6
6
 
7
7
  export default languages.map((language) => Object.freeze({
8
8
  language,
9
- title: `${site.site.name} ${language}`,
9
+ title: `${site.site.name} - ${language}`,
10
10
  href: siteUrl({
11
11
  canonicalBaseUrl: site.hosting.canonicalBaseUrl,
12
12
  pathPrefix: site.hosting.pathPrefix ?? '/',
@@ -21,7 +21,7 @@ export default async function siteConfiguration() {
21
21
  };
22
22
  /*
23
23
  * The writer picks one colour; the page needs two, because the same colour cannot be readable on
24
- * both a light and a dark ground. Derived here rather than in CSS so the contrast is exact a
24
+ * both a light and a dark ground. Derived here rather than in CSS so the contrast is exact - a
25
25
  * `color-mix()` approximation can land under 4.5:1 and nobody would know until a reader could
26
26
  * not read a link.
27
27
  *
@@ -5,7 +5,7 @@
5
5
  {% macro hero(title, description='', image='', imageAlt='') %}<header class="gala-hero">{% if image %}<img class="gala-hero__image" src="{{ image }}" alt="{{ imageAlt }}">{% endif %}<div class="gala-hero__text"><h1>{{ title }}</h1>{% if description %}<p>{{ description }}</p>{% endif %}</div></header>{% endmacro %}
6
6
  {% macro pageContent(content) %}<article class="gala-page-content">{{ content | safe }}</article>{% endmacro %}
7
7
  {% macro authorProfile(name, bio='', avatar='', links=[]) %}<section class="gala-author-profile" aria-label="Author profile">{% if avatar %}<img src="{{ avatar }}" alt="" width="80" height="80">{% endif %}<div><h2>{{ name }}</h2>{% if bio %}<p>{{ bio }}</p>{% endif %}{% if links.length %}<ul class="gala-social-links">{% for link in links %}<li><a href="{{ link.url }}" rel="me">{{ link.label }}</a></li>{% endfor %}</ul>{% endif %}</div></section>{% endmacro %}
8
- {% macro cardIndex(posts) %}<ol class="gala-card-index">{% for post in posts %}{% if post.publicationState == "published" %}<li><article class="gala-card" lang="{{ post.language | escape }}"><h2><a href="{{ post.relativeUrl | url }}">{{ post.frontmatter.title }}</a></h2>{% if post.frontmatter.description %}<p>{{ post.frontmatter.description }}</p>{% endif %}</article></li>{% endif %}{% endfor %}</ol>{% endmacro %}
8
+ {% macro cardIndex(posts, preview=false) %}<ol class="gala-card-index">{% for post in posts %}{% if post.publicationState == "published" or (preview and post.publicationState == "not-emitted") %}<li><article class="gala-card" lang="{{ post.language | escape }}"><h2><a href="{{ post.relativeUrl | url }}">{{ post.frontmatter.title }}</a></h2>{% if preview and post.publicationState == "not-emitted" %}<p>Scheduled for {{ post.frontmatter.publishAfterDate }}</p>{% elif post.frontmatter.description %}<p>{{ post.frontmatter.description }}</p>{% endif %}</article></li>{% endif %}{% endfor %}</ol>{% endmacro %}
9
9
  {% macro statsGraph(label, points) %}<figure class="gala-stats-graph"><svg role="img" aria-label="{{ label }}" viewBox="0 0 100 40" preserveAspectRatio="none"><polyline points="{{ points }}" vector-effect="non-scaling-stroke"></polyline></svg><figcaption>{{ label }}</figcaption></figure>{% endmacro %}
10
10
  {% macro loading(label='Loading') %}<div class="gala-loading" role="status"><span class="gala-loading__indicator" aria-hidden="true"></span><span class="gala-visually-hidden">{{ label }}</span></div>{% endmacro %}
11
11
  {% macro pagination(previous='', next='') %}<nav class="gala-pagination" aria-label="Pagination">{% if previous %}<a href="{{ previous }}" rel="prev">Previous</a>{% endif %}{% if next %}<a href="{{ next }}" rel="next">Next</a>{% endif %}</nav>{% endmacro %}
@@ -57,8 +57,8 @@
57
57
  at the moment of intent, and the intent is replayed once they are back. #}
58
58
  {# The conversation is an island: it owns its own state, because a thread five deep with a page
59
59
  cursor, an open reply form and an edit in progress is state, and hand-written DOM kept losing
60
- track of it. Nothing here is needed by a search engine comments have always arrived from the
61
- API after load so rendering them on the client costs nothing the article cares about. #}
60
+ track of it. Nothing here is needed by a search engine - comments have always arrived from the
61
+ API after load - so rendering them on the client costs nothing the article cares about. #}
62
62
  <div id="comments" data-gala-comments></div>
63
63
  <output class="gala-conversation__status" data-engagement-status aria-live="polite">Loading comments…</output>
64
64
  </div>
@@ -3,7 +3,7 @@ layout: layouts/base.njk
3
3
  ---
4
4
  {% from "components/ui.njk" import actionRail, conversation, languageSwitcher, tableOfContents %}
5
5
  <article id="article" class="gala-article">
6
- {% if post.publicationState == "published" %}<progress class="gala-reading-progress" data-reading-progress max="1" value="0" aria-label="Reading progress"></progress><header class="gala-article-header"><p class="gala-eyebrow">Published {{ post.frontmatter.publishAfterDate }} · {{ post.language }} · {{ readingMinutes }} min read</p><h1>{{ post.frontmatter.title }}</h1>{% set byline = post.frontmatter.author or site.site.author %}{% if byline and byline != "unavailable" and byline != "New Gala Site" and byline != site.site.name %}<p class="gala-byline">By {{ byline }}</p>{% endif %}</header>{% endif %}
6
+ {% if post.publicationState == "published" or (buildManifest.preview and post.publicationState == "not-emitted") %}<progress class="gala-reading-progress" data-reading-progress max="1" value="0" aria-label="Reading progress"></progress><header class="gala-article-header"><p class="gala-eyebrow">{% if post.publicationState == "published" %}Published{% else %}Scheduled for{% endif %} {{ post.frontmatter.publishAfterDate }} - {{ post.language }} - {{ readingMinutes }} min read</p><h1>{{ post.frontmatter.title }}</h1>{% set byline = post.frontmatter.author or site.site.author %}{% if byline and byline != "unavailable" and byline != "New Gala Site" and byline != site.site.name %}<p class="gala-byline">By {{ byline }}</p>{% endif %}</header>{% endif %}
7
7
  {% if post.publicationState == "published" %}{{ languageSwitcher(hreflangLinks, post.language) }}{% endif %}
8
8
  {% if prismConfigurations.length %}<nav class="gala-prism-selector" aria-label="Approved editions">
9
9
  <span aria-current="page">Complete</span>
@@ -2,7 +2,7 @@
2
2
  * The reader's identity, and the only way to write on their behalf.
3
3
  *
4
4
  * Both belong to the account frame, which is served by the API and runs on its origin. The
5
- * reader's token lives there and nowhere else this page never sees it, and never should: the
5
+ * reader's token lives there and nowhere else - this page never sees it, and never should: the
6
6
  * page is the writer's own site, and a reader's credentials are not the writer's to hold. So a
7
7
  * write is a request posted into the frame, and the frame answers with a result.
8
8
  *
@@ -384,8 +384,8 @@ window.addEventListener('focus', () => {
384
384
  /*
385
385
  * The sign-in window reports success to this page rather than to the account frame.
386
386
  *
387
- * It cannot reach the frame directly: a frame embedded in a publication has its storage and its
388
- * BroadcastChannel partitioned away from a window running at the top level on the API's origin,
387
+ * It cannot reach the frame directly: a frame embedded in a publication has its storage - and its
388
+ * BroadcastChannel - partitioned away from a window running at the top level on the API's origin,
389
389
  * so the session it wrote is invisible there. The signal carries no token; it only says a sign-in
390
390
  * happened, and this asks the frame to look again. Without it the frame never learns the reader
391
391
  * signed in, and every click asks them to sign in once more.
@@ -504,7 +504,7 @@ if (sessionFrame) {
504
504
  });
505
505
  return;
506
506
  }
507
- /* The frame is cross-origin, so its content height is not readable from here it reports
507
+ /* The frame is cross-origin, so its content height is not readable from here - it reports
508
508
  its own, and the box is sized to it. Without this the account panel scrolled inside a fixed
509
509
  box, clipping the first line of its own text. */
510
510
  if (event.data?.type === 'gala-session-height') {
@@ -3,7 +3,7 @@ const STORAGE_KEY = 'gala-color-mode';
3
3
 
4
4
  /*
5
5
  * The reader's own choice always wins. Absent one, the publication's `design.colorMode` decides
6
- * what they see first it is already on the element, server-rendered. This used to fall back to
6
+ * what they see first - it is already on the element, server-rendered. This used to fall back to
7
7
  * `system` unconditionally, which meant a writer could set a colour mode and no reader ever saw
8
8
  * it: the setting existed everywhere except in the page.
9
9
  */
@@ -1 +1 @@
1
- :root{color-scheme:light dark;--gala-color-background: light-dark(#fdfcfb, #131211);--gala-color-surface: light-dark(#f6f4f1, #1c1a18);--gala-color-raised: light-dark(#fffffe, #24211f);--gala-color-text: light-dark(#1a1817, #f2efec);--gala-color-muted: light-dark(#6b645e, #a8a099);--gala-color-border: light-dark(#968e86, #6b645e);--gala-color-hairline: light-dark(#e8e3dd, #2a2724);--gala-color-border-strong: light-dark(#c9c2ba, #46413d);--gala-color-accent: light-dark( var(--gala-accent-light, #8a4b2a), var(--gala-accent-dark, #e8a87c));--gala-font-body: ui-sans-serif, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;--gala-font-display: var(--gala-font-body);--gala-font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, monospace;--gala-text-xs: .78rem;--gala-text-sm: .875rem;--gala-text-base: clamp(1rem, .97rem + .15vw, 1.0625rem);--gala-text-lg: clamp(1.15rem, 1.09rem + .3vw, 1.3rem);--gala-text-xl: clamp(1.4rem, 1.28rem + .6vw, 1.75rem);--gala-text-2xl: clamp(1.75rem, 1.5rem + 1.2vw, 2.4rem);--gala-text-3xl: clamp(2.2rem, 1.7rem + 2.4vw, 3.4rem);--gala-leading-tight: 1.15;--gala-leading-body: 1.65;--gala-tracking-tight: -.018em;--gala-tracking-wide: .08em;--gala-weight-display: 640;--gala-step: 1rem;--gala-space-2xs: calc(var(--gala-step) * .25);--gala-space-xs: calc(var(--gala-step) * .5);--gala-space-sm: calc(var(--gala-step) * .75);--gala-space-md: var(--gala-step);--gala-space-lg: calc(var(--gala-step) * 1.75);--gala-space-xl: calc(var(--gala-step) * 3);--gala-space-page: clamp(1.25rem, 5vw, 4.5rem);--gala-radius-control: .625rem;--gala-radius-surface: 1rem;--gala-shadow-high: 0 1px 2px light-dark(rgb(26 24 23 / 5%), rgb(0 0 0 / 35%)), 0 12px 28px -12px light-dark(rgb(26 24 23 / 18%), rgb(0 0 0 / 60%));--gala-motion-fast: .12s;--gala-motion-base: .22s;--gala-ease: cubic-bezier(.2, 0, 0, 1);--gala-content-width: 72rem;--gala-measure: 68ch;--gala-widget-min-block-size: 8rem}:root[data-mode=light]{color-scheme:light;--gala-color-background: #fdfcfb;--gala-color-surface: #f6f4f1;--gala-color-raised: #fffffe;--gala-color-text: #1a1817;--gala-color-muted: #6b645e;--gala-color-border: #968e86;--gala-color-hairline: #e8e3dd;--gala-color-border-strong: #c9c2ba;--gala-color-accent: var(--gala-accent-light, #8a4b2a)}:root[data-mode=dark]{color-scheme:dark;--gala-color-background: #131211;--gala-color-surface: #1c1a18;--gala-color-raised: #24211f;--gala-color-text: #f2efec;--gala-color-muted: #a8a099;--gala-color-border: #6b645e;--gala-color-hairline: #2a2724;--gala-color-border-strong: #46413d;--gala-color-accent: var(--gala-accent-dark, #e8a87c)}:root[data-palette=ocean]{--gala-color-background: light-dark(#f8fbfd, #0b1a24);--gala-color-surface: light-dark(#eef4f9, #12252f);--gala-color-raised: light-dark(#ffffff, #172d39);--gala-color-text: light-dark(#12242f, #eaf3f8);--gala-color-muted: light-dark(#5a6f7d, #98aebb);--gala-color-border: light-dark(#7d8d99, #5f7d8c);--gala-color-hairline: light-dark(#dde7ee, #1d3644);--gala-color-border-strong: light-dark(#bdccd7, #33505f);--gala-color-accent: light-dark(#0f5f7a, #7fd0e8)}:root[data-palette=ocean][data-mode=light]{color-scheme:light;--gala-color-background: #f8fbfd;--gala-color-surface: #eef4f9;--gala-color-raised: #ffffff;--gala-color-text: #12242f;--gala-color-muted: #5a6f7d;--gala-color-border: #7d8d99;--gala-color-hairline: #dde7ee;--gala-color-border-strong: #bdccd7;--gala-color-accent: var(--gala-accent-light, #0f5f7a)}:root[data-palette=ocean][data-mode=dark]{color-scheme:dark;--gala-color-background: #0b1a24;--gala-color-surface: #12252f;--gala-color-raised: #172d39;--gala-color-text: #eaf3f8;--gala-color-muted: #98aebb;--gala-color-border: #5f7d8c;--gala-color-hairline: #1d3644;--gala-color-border-strong: #33505f;--gala-color-accent: var(--gala-accent-dark, #7fd0e8)}:root[data-palette=forest]{--gala-color-background: light-dark(#fbfcfa, #101410);--gala-color-surface: light-dark(#f0f4ee, #182018);--gala-color-raised: light-dark(#ffffff, #1f271f);--gala-color-text: light-dark(#18201a, #eef3ec);--gala-color-muted: light-dark(#5b665d, #9aa89b);--gala-color-border: light-dark(#849084, #5e685f);--gala-color-hairline: light-dark(#e2e9df, #232b23);--gala-color-border-strong: light-dark(#5b665d, #7d897e);--gala-color-accent: light-dark(#2f6b3f, #8fd3a1)}:root[data-palette=forest][data-mode=light]{color-scheme:light;--gala-color-background: #fbfcfa;--gala-color-surface: #f0f4ee;--gala-color-raised: #ffffff;--gala-color-text: #18201a;--gala-color-muted: #5b665d;--gala-color-border: #849084;--gala-color-hairline: #e2e9df;--gala-color-border-strong: #5b665d;--gala-color-accent: var(--gala-accent-light, #2f6b3f)}:root[data-palette=forest][data-mode=dark]{color-scheme:dark;--gala-color-background: #101410;--gala-color-surface: #182018;--gala-color-raised: #1f271f;--gala-color-text: #eef3ec;--gala-color-muted: #9aa89b;--gala-color-border: #5e685f;--gala-color-hairline: #232b23;--gala-color-border-strong: #7d897e;--gala-color-accent: var(--gala-accent-dark, #8fd3a1)}:root[data-palette=plum]{--gala-color-background: light-dark(#fdfbfd, #141016);--gala-color-surface: light-dark(#f5eff5, #1d1720);--gala-color-raised: light-dark(#ffffff, #241d28);--gala-color-text: light-dark(#1f1820, #f2ecf3);--gala-color-muted: light-dark(#665c69, #a99dac);--gala-color-border: light-dark(#948a95, #6b606d);--gala-color-hairline: light-dark(#ebe2ec, #281f2b);--gala-color-border-strong: light-dark(#665c69, #8b7f8d);--gala-color-accent: light-dark(#7a3d76, #dda6d8)}:root[data-palette=plum][data-mode=light]{color-scheme:light;--gala-color-background: #fdfbfd;--gala-color-surface: #f5eff5;--gala-color-raised: #ffffff;--gala-color-text: #1f1820;--gala-color-muted: #665c69;--gala-color-border: #948a95;--gala-color-hairline: #ebe2ec;--gala-color-border-strong: #665c69;--gala-color-accent: var(--gala-accent-light, #7a3d76)}:root[data-palette=plum][data-mode=dark]{color-scheme:dark;--gala-color-background: #141016;--gala-color-surface: #1d1720;--gala-color-raised: #241d28;--gala-color-text: #f2ecf3;--gala-color-muted: #a99dac;--gala-color-border: #6b606d;--gala-color-hairline: #281f2b;--gala-color-border-strong: #8b7f8d;--gala-color-accent: var(--gala-accent-dark, #dda6d8)}:root[data-theme=editorial]{--gala-font-body: ui-serif, "Iowan Old Style", Charter, "Source Serif 4", Georgia, serif;--gala-font-display: var(--gala-font-body);--gala-weight-display: 600;--gala-step: 1.1rem;--gala-leading-body: 1.7;--gala-radius-control: .5rem;--gala-radius-surface: .75rem;--gala-measure: 66ch;--gala-surface-border: var(--gala-color-hairline);--gala-surface-shadow: none}:root[data-theme=modern]{--gala-font-body: ui-sans-serif, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;--gala-font-display: var(--gala-font-body);--gala-weight-display: 640;--gala-step: 1rem;--gala-leading-body: 1.65;--gala-radius-control: .625rem;--gala-radius-surface: 1rem;--gala-measure: 70ch;--gala-surface-border: transparent;--gala-surface-shadow: var(--gala-shadow-high)}:root[data-theme=technical]{--gala-font-body: ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif;--gala-font-display: var(--gala-font-body);--gala-weight-display: 660;--gala-tracking-tight: -.022em;--gala-step: .9rem;--gala-leading-body: 1.6;--gala-radius-control: .375rem;--gala-radius-surface: .5rem;--gala-measure: 74ch;--gala-surface-border: var(--gala-color-border-strong);--gala-surface-shadow: none}:root[data-theme=technical] .gala-eyebrow,:root[data-theme=technical] .gala-engagement dt,:root[data-theme=technical] .gala-comment__meta time{font-family:var(--gala-font-mono)}@media(prefers-reduced-motion:reduce){:root{--gala-motion-fast: 0ms;--gala-motion-base: 0ms;scroll-behavior:auto}*,*:before,*:after{animation-duration:1ms!important;transition-duration:1ms!important}}:root[data-layout=portfolio]{--gala-content-width: 82rem}html{scroll-behavior:smooth}body{box-sizing:border-box;display:flex;flex-direction:column;min-block-size:100vh;min-block-size:100svh;margin:0;padding:var(--gala-space-page);color:var(--gala-color-text);background:var(--gala-color-background);font-family:var(--gala-font-body);font-size:var(--gala-text-base);line-height:var(--gala-leading-body);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}.gala-skip-link{position:fixed;inset-block-start:1rem;inset-inline-start:1rem;z-index:100;padding:.75rem 1rem;color:#fff;background:var(--gala-color-accent);border-radius:999px;transform:translateY(-200%)}.gala-skip-link:focus{transform:translateY(0)}.gala-site-name{color:var(--gala-color-text);font-family:var(--gala-font-display);font-size:var(--gala-text-lg);font-weight:var(--gala-weight-display);letter-spacing:var(--gala-tracking-tight);text-decoration:none;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gala-header-link{color:var(--gala-color-text);font-size:var(--gala-text-sm);text-decoration:none}.gala-account-control{display:inline-flex;align-items:center;gap:.5rem;min-block-size:2.75rem;padding-inline:.9rem;border-radius:999px}.gala-account-control svg{inline-size:1rem;block-size:1rem}.gala-article{max-inline-size:76rem;margin-inline:auto}.gala-page--article .gala-site-header,.gala-page--article main,.gala-page--article .gala-page-footer{max-inline-size:112rem}.gala-page--article .gala-article,.gala-page--article .gala-engagement{max-inline-size:none}.gala-article-header{padding-block:clamp(2.5rem,5vw,5rem)}.gala-article-header h1{max-inline-size:12ch;font-size:clamp(2.5rem,7vw,5.25rem);line-height:.96;letter-spacing:-.055em}.gala-byline{color:var(--gala-color-muted);font-size:var(--gala-text-sm)}.gala-markdown{max-inline-size:42rem;margin-inline:auto;font-size:clamp(1.1rem,1rem + .35vw,1.3rem)}.gala-markdown :where(h2){margin-block-start:clamp(3rem,7vw,5rem);font-size:clamp(2.2rem,5vw,3.8rem)}.gala-markdown :where(h2,h3,h4,h5,h6){scroll-margin-block-start:7rem}.gala-markdown :where(img,video){max-inline-size:100%;block-size:auto}.gala-markdown :where(pre){box-sizing:border-box;max-inline-size:100%;overflow-x:auto;scrollbar-color:var(--gala-color-border-strong) var(--gala-color-surface)}:where(h1,h2,h3,h4){font-family:var(--gala-font-display);font-weight:var(--gala-weight-display);line-height:var(--gala-leading-tight);letter-spacing:var(--gala-tracking-tight);text-wrap:balance;margin-block:0 var(--gala-space-sm)}:where(h1){font-size:var(--gala-text-3xl)}:where(h2){font-size:var(--gala-text-2xl)}:where(h3){font-size:var(--gala-text-xl)}:where(h4){font-size:var(--gala-text-lg)}:where(p,ul,ol,blockquote){margin-block:0 var(--gala-space-md)}:where(p){text-wrap:pretty}blockquote{margin-inline:0;padding-inline-start:var(--gala-space-md);border-inline-start:2px solid var(--gala-color-accent);color:var(--gala-color-muted)}:where(code,kbd,samp){font-family:var(--gala-font-mono);font-size:.9em}:where(pre){padding:var(--gala-space-md);overflow-x:auto;background:var(--gala-color-surface);border-radius:var(--gala-radius-control)}:where(hr){border:0;border-block-start:1px solid var(--gala-color-hairline);margin-block:var(--gala-space-xl)}:where(table){border-collapse:collapse;inline-size:100%}:where(th,td){padding:var(--gala-space-xs) var(--gala-space-sm);border-block-end:1px solid var(--gala-color-hairline);text-align:start}.gala-eyebrow,.gala-comment__meta time,.gala-comment__edited{font-size:var(--gala-text-xs);letter-spacing:var(--gala-tracking-wide);text-transform:uppercase;color:var(--gala-color-muted)}.gala-site-header{position:sticky;inset-block-start:0;z-index:10;display:flex;align-items:center;justify-content:space-between;gap:var(--gala-space-md);max-inline-size:var(--gala-content-width);margin-inline:auto;margin-block-end:var(--gala-space-xl);padding-block:var(--gala-space-xs);background:color-mix(in srgb,var(--gala-color-background) 88%,transparent);backdrop-filter:blur(8px);border-block-end:1px solid var(--gala-color-hairline)}@supports not (backdrop-filter: blur(8px)){.gala-site-header{background:var(--gala-color-background)}}.gala-site-header__actions{display:flex;align-items:center;gap:.5rem}.gala-header-link{display:inline-flex;align-items:center;min-block-size:2.75rem}.gala-icon-control{display:inline-grid;inline-size:2.75rem;block-size:2.75rem;box-sizing:border-box;padding:.6rem;place-items:center;color:inherit;border:.125rem solid transparent;border-radius:50%}.gala-icon-control{transition:background var(--gala-motion-fast) var(--gala-ease),color var(--gala-motion-fast) var(--gala-ease);color:var(--gala-color-muted)}.gala-icon-control:hover{background:var(--gala-color-surface);color:var(--gala-color-text)}.gala-icon-control:focus-visible{outline:.1875rem solid currentcolor;outline-offset:.1875rem}.gala-icon-control svg{inline-size:100%;block-size:100%;fill:none;stroke:currentcolor}.gala-dialog{inline-size:min(42rem,calc(100% - 2rem));max-block-size:calc(100% - 2rem);box-sizing:border-box;padding:1.5rem;color:var(--gala-color-text);background:var(--gala-color-background);border:1px solid var(--gala-surface-border);border-radius:var(--gala-radius-surface);box-shadow:var(--gala-shadow-high)}.gala-dialog::backdrop{background:#000000a6}.gala-account-dialog{inline-size:min(26rem,calc(100% - 2rem))}.gala-account-dialog iframe{display:block;inline-size:100%;block-size:7rem;border:0;overflow:hidden}.gala-dialog{display:grid;gap:var(--gala-space-sm)}.gala-dialog:not([open]){display:none}.gala-dialog__close{justify-self:end;margin:0}.gala-dialog__header{display:flex;align-items:center;justify-content:space-between;gap:var(--gala-space-md)}.gala-dialog__header h2{margin:0}main,.gala-page-footer{max-inline-size:var(--gala-content-width);margin-inline:auto}.gala-page-footer{box-sizing:border-box;inline-size:100%}main{flex:1 0 auto;inline-size:100%}a{color:var(--gala-color-accent)}button{min-block-size:2.75rem;padding-inline:var(--gala-space-md);color:inherit;background:var(--gala-color-surface);border:1px solid var(--gala-color-border);border-radius:var(--gala-radius-control);font:inherit;font-size:var(--gala-text-sm);cursor:pointer;transition:background var(--gala-motion-fast) var(--gala-ease),border-color var(--gala-motion-fast) var(--gala-ease)}button:hover{border-color:var(--gala-color-border-strong);background:var(--gala-color-raised)}button[disabled]{opacity:.55;cursor:not-allowed}button:focus-visible{outline:.1875rem solid currentcolor;outline-offset:.1875rem}.gala-button,.gala-badge,.gala-tag-chip{display:inline-flex;align-items:center;min-block-size:2.75rem;border:1px solid var(--gala-color-border);border-radius:var(--gala-radius-control);font-size:var(--gala-text-sm)}.gala-badge,.gala-tag-chip{padding-inline:.75rem}.gala-tag-chip{text-decoration:none}.gala-section-heading{margin-block:3rem 1rem}.gala-section-heading>:where(h2,p){margin-block:0 .5rem}.gala-hero{display:grid;gap:1.5rem;align-items:center}.gala-hero__image{inline-size:100%;block-size:auto;border-radius:var(--gala-radius-control)}.gala-page-content{max-inline-size:var(--gala-measure)}.gala-page-content :where(img,video){max-inline-size:100%;block-size:auto}.gala-author-profile{display:flex;gap:1rem;padding:1rem;background:var(--gala-color-surface);border-radius:var(--gala-radius-control)}.gala-author-profile img{border-radius:50%;object-fit:cover}.gala-social-links,.gala-page-footer ul,.gala-share ul{display:flex;flex-wrap:wrap;gap:1rem;padding:0;list-style:none}.gala-card-index{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,18rem),1fr));gap:1rem;padding:0;list-style:none}.gala-version-page{inline-size:min(100%,74rem);margin-inline:auto}.gala-version-page__header{max-inline-size:48rem}.gala-version-page__header>p{color:var(--gala-color-muted)}.gala-version-page__header .gala-button{margin-block-start:var(--gala-space-md)}.gala-version-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,18rem),1fr));gap:var(--gala-space-md);margin-block-start:var(--gala-space-lg)}.gala-version-card{display:grid;align-content:start;gap:var(--gala-space-sm);min-block-size:10rem;margin-block-start:var(--gala-space-lg);padding:var(--gala-space-lg);border:1px solid var(--gala-color-border);border-radius:var(--gala-radius-surface);background:var(--gala-color-surface)}.gala-version-grid .gala-version-card{margin-block-start:0}.gala-version-card>*{margin:0}.gala-version-commit{font-family:var(--gala-font-mono);font-weight:700}.gala-version-status{color:var(--gala-color-muted)}.gala-version-status--error{color:var(--gala-color-accent)}[data-layout=portfolio] .gala-card-index{grid-template-columns:repeat(auto-fit,minmax(min(100%,22rem),1fr));gap:1.5rem}[data-layout=portfolio] .gala-card{padding:clamp(1.25rem,3vw,2rem)}.gala-card{block-size:100%;box-sizing:border-box;padding:var(--gala-space-lg);background:var(--gala-color-surface);border:1px solid var(--gala-surface-border);border-radius:var(--gala-radius-surface);box-shadow:var(--gala-surface-shadow)}.gala-card{transition:transform var(--gala-motion-base) var(--gala-ease),box-shadow var(--gala-motion-base) var(--gala-ease)}.gala-card-index li:hover .gala-card{transform:translateY(-2px);box-shadow:var(--gala-shadow-high)}.gala-stats-graph{min-block-size:var(--gala-widget-min-block-size);margin-inline:0}.gala-stats-graph svg{inline-size:100%;block-size:8rem}.gala-stats-graph polyline{fill:none;stroke:var(--gala-color-accent);stroke-width:2}.gala-loading{display:grid;min-block-size:var(--gala-widget-min-block-size);place-items:center}.gala-loading__indicator{inline-size:2rem;block-size:2rem;border:.25rem solid var(--gala-color-border);border-block-start-color:var(--gala-color-accent);border-radius:50%;animation:gala-spin .8s linear infinite}.gala-pagination{display:flex;justify-content:space-between;gap:1rem}.gala-search{display:grid;grid-template-columns:1fr auto;gap:.5rem}.gala-search label{grid-column:1 / -1}.gala-search input{min-block-size:2.75rem;font:inherit}.gala-search-results{display:grid;gap:1rem;padding:0;list-style:none}.gala-search-results article{padding:1rem;background:var(--gala-color-surface);border-radius:var(--gala-radius-control)}.gala-search-results h2{margin-block-start:0}.gala-toc{box-sizing:border-box;min-inline-size:0;max-inline-size:42rem;margin-inline:auto;padding:1rem;background:var(--gala-color-surface)}.gala-toc summary{color:var(--gala-color-text);font-weight:var(--gala-weight-display);cursor:pointer}.gala-toc nav{margin-block-start:var(--gala-space-sm);overscroll-behavior:contain}.gala-toc ol{margin:0;padding-inline-start:1.25rem}.gala-toc a[aria-current=location]{color:var(--gala-color-text);font-weight:700}.gala-share__fallback{inline-size:min(100%,36rem)}.gala-engagement__placeholder{display:grid;min-block-size:var(--gala-widget-min-block-size);align-content:center;margin:0}.gala-engagement-profile>*{margin-block:0 .5rem}.gala-engagement-actions{display:grid;gap:1rem;margin-block-start:1.5rem}.gala-engagement-actions[hidden]{display:none}.gala-account-dialog__invite{margin-block:0 1rem;max-inline-size:34rem}.gala-account-dialog__invite[hidden]{display:none}.gala-engagement-actions form,[data-comment-editor]{display:grid;gap:.5rem;max-inline-size:42rem}.gala-engagement-actions label{display:grid;gap:.5rem}.gala-engagement-actions textarea,[data-comment-editor] textarea{min-block-size:7rem;padding:.75rem;font:inherit}.gala-page-footer{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--gala-space-lg);margin-block-start:var(--gala-space-xl);padding-block-start:var(--gala-space-md);border-block-start:.125rem solid var(--gala-color-border)}.gala-page-footer__identity{display:flex;gap:var(--gala-space-sm);max-inline-size:56rem}.gala-page-footer__identity img{flex:0 0 auto;border-radius:50%;object-fit:cover}.gala-page-footer__identity p{margin:0;color:var(--gala-color-muted);font-size:var(--gala-text-sm)}.gala-page-footer__details{display:grid;gap:var(--gala-space-2xs);align-content:center}.gala-page-footer__line{display:grid;grid-template-columns:repeat(4,max-content);align-items:baseline;gap:0 var(--gala-space-sm)}.gala-page-footer__line>*+*:before{content:"\b7";margin-inline-end:var(--gala-space-sm);color:var(--gala-color-border)}.gala-page-footer__bio{line-height:1.4}.gala-page-footer__author{color:var(--gala-color-text);font-weight:var(--gala-weight-display)}.gala-page-footer nav{margin-inline-start:auto}.gala-page-footer ul{justify-content:flex-end;margin:0}.gala-error-page{min-block-size:60vh;display:grid;align-content:center;justify-items:start}.gala-code-block{position:relative;box-sizing:border-box;min-inline-size:0;max-inline-size:100%;inline-size:100%;overflow:hidden}.gala-code-block>button{position:absolute;inset-block-start:.5rem;inset-inline-end:.5rem;background:var(--gala-color-background)}.gala-code-block pre{box-sizing:border-box;min-inline-size:0;max-inline-size:100%;inline-size:100%;overflow-x:auto;overscroll-behavior-inline:contain;padding:3.5rem 1rem 1rem;background:var(--gala-color-surface);border-radius:var(--gala-radius-control)}.gala-code-block code{display:block;inline-size:max-content;min-inline-size:100%}.gala-embed{display:grid;place-items:center;gap:.75rem;box-sizing:border-box;inline-size:100%;margin-inline:0;padding:1rem;overflow:hidden;background:var(--gala-color-surface);border:.125rem solid var(--gala-color-border);border-radius:var(--gala-radius-control)}.gala-embed--youtube{aspect-ratio:16 / 9}.gala-embed--codepen{min-block-size:25rem}.gala-embed--gist,.gala-embed--x{min-block-size:8rem}.gala-embed iframe{inline-size:100%;block-size:100%;border:0}.gala-embed__icon{inline-size:2rem;block-size:2rem;background:center / contain no-repeat}.gala-embed--youtube .gala-embed__icon{background-image:url(../assets/embed-youtube.svg)}.gala-embed--codepen .gala-embed__icon{background-image:url(../assets/embed-codepen.svg)}.gala-embed--gist .gala-embed__icon{background-image:url(../assets/embed-gist.svg)}.gala-embed--x .gala-embed__icon{background-image:url(../assets/embed-x.svg)}.shiki,.shiki span{color:inherit;background-color:var(--gala-color-surface)}.gala-visually-hidden{position:absolute;inline-size:1px;block-size:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.gala-contact form{display:grid;gap:1rem;max-inline-size:42rem}.gala-contact label{display:grid;gap:.35rem}.gala-contact input,.gala-contact textarea{font:inherit;padding:.65rem}.gala-contact textarea{min-block-size:12rem;resize:vertical}@keyframes gala-spin{to{transform:rotate(1turn)}}@media(min-width:48rem){.gala-hero{grid-template-columns:minmax(0,1fr) minmax(18rem,1fr)}}@media(prefers-reduced-motion:no-preference){@view-transition{navigation:auto}}.gala-comments-island{margin-block-start:var(--gala-space-xl)}.gala-comments__heading{font-size:var(--gala-text-lg);margin-block-end:var(--gala-space-md)}.gala-comments,.gala-comment-replies{list-style:none;margin:0;padding:0}.gala-comment-replies{margin-block-start:var(--gala-space-sm);margin-inline-start:var(--gala-space-xs);padding-inline-start:var(--gala-space-md);border-inline-start:1px solid var(--gala-color-hairline)}.gala-comment{padding-block:var(--gala-space-sm)}.gala-comment+.gala-comment{border-block-start:1px solid var(--gala-color-hairline)}.gala-comment-replies .gala-comment+.gala-comment{border-block-start:0}.gala-comment__meta{display:flex;align-items:baseline;gap:var(--gala-space-xs);margin-block-end:var(--gala-space-2xs);font-size:var(--gala-text-sm)}.gala-comment__meta strong{font-weight:600}.gala-comment__pending{font-size:var(--gala-text-xs);color:var(--gala-color-muted)}.gala-comment__body{margin-block:0;overflow-wrap:anywhere}.gala-comment-actions{display:flex;gap:var(--gala-space-2xs);margin-block-start:var(--gala-space-2xs);opacity:.72;transition:opacity var(--gala-motion-fast) var(--gala-ease)}.gala-comment:hover>.gala-comment-actions,.gala-comment:focus-within>.gala-comment-actions{opacity:1}.gala-comment-actions button{min-block-size:2rem;padding-inline:var(--gala-space-xs);font-size:var(--gala-text-xs);background:transparent;border-color:transparent;color:var(--gala-color-muted)}.gala-comment-actions button:hover{color:var(--gala-color-text);background:var(--gala-color-surface)}.gala-comment__form{display:grid;gap:var(--gala-space-xs);margin-block:var(--gala-space-sm)}.gala-comment__form textarea{inline-size:100%;box-sizing:border-box;padding:var(--gala-space-sm);color:inherit;background:var(--gala-color-raised);border:1px solid var(--gala-color-border);border-radius:var(--gala-radius-control);font:inherit;font-size:var(--gala-text-sm);line-height:var(--gala-leading-body);resize:vertical}.gala-comment__form textarea:focus-visible{outline:2px solid var(--gala-color-accent);outline-offset:1px}.gala-comment__controls{display:flex;gap:var(--gala-space-xs)}.gala-comments__status,.gala-comments__empty,.gala-comments__prompt{color:var(--gala-color-muted);font-size:var(--gala-text-sm)}.gala-comments__more{margin-block-start:var(--gala-space-md)}.gala-engagement{min-block-size:var(--gala-widget-min-block-size);max-inline-size:var(--gala-content-width);margin-block-start:var(--gala-space-xl);padding-block-start:var(--gala-space-lg);border-block-start:1px solid var(--gala-color-border)}.gala-engagement-profile{display:flex;align-items:baseline;gap:var(--gala-space-sm);padding:0;background:none}.gala-engagement-profile h2{font-size:var(--gala-text-lg);margin:0}.gala-engagement-profile p{margin:0;color:var(--gala-color-muted);font-size:var(--gala-text-sm)}.gala-engagement>dl{display:flex;flex-wrap:wrap;gap:var(--gala-space-lg);margin-block:var(--gala-space-md)}.gala-engagement>dl>div{display:flex;flex-direction:column-reverse;gap:.1rem}.gala-engagement>dl dt{font-size:var(--gala-text-xs);letter-spacing:var(--gala-tracking-wide);text-transform:uppercase;color:var(--gala-color-muted)}.gala-engagement>dl dd{margin:0;font-size:var(--gala-text-lg);font-variant-numeric:tabular-nums}.gala-reaction-actions{display:flex;flex-wrap:wrap;gap:var(--gala-space-2xs)}.gala-engagement-actions{display:grid;gap:var(--gala-space-sm);justify-items:start}.gala-engagement-actions>[data-follow-article]{inline-size:auto}.gala-share{margin-block-start:var(--gala-space-lg)}.gala-engagement{position:relative}.gala-reading-progress{position:fixed;z-index:20;inset:0 0 auto;inline-size:100%;block-size:.2rem;appearance:none;border:0;background:transparent;pointer-events:none}.gala-reading-progress::-webkit-progress-bar{background:transparent}.gala-reading-progress::-webkit-progress-value{background:var(--gala-color-accent)}.gala-reading-progress::-moz-progress-bar{background:var(--gala-color-accent)}.gala-reading-layout{display:block}.gala-conversation{max-width:var(--gala-measure);margin-inline:auto;padding-block:clamp(3rem,7vw,6rem)}.gala-conversation__header{margin-block-end:var(--gala-space-xl)}.gala-conversation__header h2{margin:0;font:var(--gala-weight-display) var(--gala-text-2xl)/var(--gala-leading-tight) var(--gala-font-display);letter-spacing:var(--gala-tracking-tight)}.gala-conversation__status{display:block;min-block-size:1.5em;color:var(--gala-color-muted)}.gala-conversation__status:empty{display:none}.gala-action-rail{position:static;z-index:4;inset-block-start:6rem;box-sizing:border-box;width:min(100%,42rem);margin:var(--gala-space-xl) auto 0;display:grid;grid-template-columns:1fr auto 1fr;gap:var(--gala-space-md);align-items:center;padding:var(--gala-space-md);border:1px solid var(--gala-color-hairline);border-radius:var(--gala-radius-surface);background:color-mix(in srgb,var(--gala-color-background) 88%,transparent);box-shadow:var(--gala-shadow-high);backdrop-filter:blur(16px)}.gala-action-rail button,.gala-action-rail a{inline-size:2.5rem;min-block-size:2.5rem;display:grid;place-items:center;padding:0;border:0;border-radius:50%;color:var(--gala-color-muted);background:transparent;font:600 var(--gala-text-xs)/1 var(--gala-font-body);text-decoration:none;cursor:pointer}.gala-action-rail svg{inline-size:1.2rem;block-size:1.2rem}.gala-action-rail button:hover,.gala-action-rail a:hover,.gala-action-rail button[aria-pressed=true]{color:var(--gala-color-background);background:var(--gala-color-accent)}.gala-engagement .gala-action-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--gala-space-xs);margin:0}.gala-action-stats>div{display:flex;min-block-size:2.5rem;align-items:center;justify-content:space-between;gap:.4rem;padding-inline:.25rem}.gala-action-stats>div+div{border-inline-start:1px solid var(--gala-color-hairline)}.gala-action-stats dt{display:grid;place-items:center;color:var(--gala-color-muted)}.gala-action-stats dt svg{inline-size:1.2rem;block-size:1.2rem}.gala-action-stats dd{margin:0;color:var(--gala-color-text);font:400 1.2rem/1 var(--gala-font-mono)}.gala-action-group{display:grid}.gala-reaction-actions,.gala-utility-actions,.gala-share{display:grid;grid-template-columns:repeat(6,2.5rem);gap:var(--gala-space-2xs);justify-content:center}.gala-utility-actions>.gala-share{display:contents}.gala-action-rail__separator{inline-size:1px;align-self:stretch;margin-block:.25rem;background:var(--gala-color-hairline)}.gala-action-rail .gala-share__fallback{position:fixed;inline-size:1px;block-size:1px;overflow:hidden;clip-path:inset(50%)}.gala-action-rail .gala-share__fallback--visible{z-index:10;inset:auto 1rem 1rem;inline-size:min(32rem,calc(100vw - 2rem));block-size:auto;padding:.75rem;overflow:visible;clip-path:none}.gala-action-dock{display:block;min-block-size:4.25rem}.gala-article-boundary{width:100%;margin:clamp(4rem,8vw,7rem) auto var(--gala-space-lg);padding-block-start:var(--gala-space-md);display:flex;align-items:baseline;justify-content:space-between;gap:var(--gala-space-md);border-block-start:.25rem solid var(--gala-color-text);font-size:var(--gala-text-sm)}@media(min-width:75rem){.gala-reading-layout{display:grid;grid-template-columns:minmax(10rem,15rem) minmax(0,1fr) 8.5rem;align-items:start;justify-content:space-between;gap:clamp(2rem,4vw,5rem)}.gala-reading-layout .gala-toc{grid-column:1;grid-row:1;position:sticky;inset-block-start:6rem;max-inline-size:none;margin-inline:0;max-block-size:calc(100vh - 8rem);transition:box-shadow var(--gala-motion-fast) var(--gala-ease)}.gala-reading-layout .gala-toc--floating{box-shadow:var(--gala-shadow-high)}.gala-reading-layout .gala-toc>summary{display:none}.gala-reading-layout .gala-toc>nav{display:block;max-block-size:calc(100vh - 10rem);margin-block-start:0;overflow-y:auto;scrollbar-width:thin}.gala-reading-layout .gala-toc--overflowing ol{padding-block:max(1rem,calc((100vh - 11.5rem)/2))}.gala-reading-layout .gala-markdown{grid-column:2;grid-row:1;max-inline-size:56rem;inline-size:100%;margin:0}.gala-article-boundary{grid-column:1 / -1;grid-row:2;margin-inline:0}.gala-action-dock{grid-column:2;grid-row:3}.gala-action-rail{grid-column:3;grid-row:1;position:sticky;inset-block-start:6rem;width:8.5rem;margin:0;display:grid;grid-template-columns:1fr;gap:var(--gala-space-sm);padding:var(--gala-space-sm);border-radius:var(--gala-radius-surface)}.gala-action-rail .gala-action-stats{gap:var(--gala-space-2xs)}.gala-action-rail:not(.gala-action-rail--integrated) .gala-action-stats{grid-template-columns:1fr}.gala-action-rail:not(.gala-action-rail--integrated) .gala-action-stats>div+div{border-inline-start:0;border-block-start:1px solid var(--gala-color-hairline)}.gala-action-rail .gala-action-stats>div{min-block-size:2.5rem;display:grid;grid-template-columns:repeat(2,2.5rem);justify-content:center;gap:.25rem;padding-inline:0}.gala-action-rail .gala-action-stats dd{justify-self:center}.gala-action-rail .gala-reaction-actions,.gala-action-rail .gala-utility-actions,.gala-action-rail .gala-share{grid-template-columns:repeat(2,2.5rem)}.gala-action-rail__separator{inline-size:auto;block-size:1px;margin:.25rem}.gala-action-rail--integrated{grid-column:2;grid-row:3;position:static;align-self:start;width:100%;margin:0;display:grid;grid-template-columns:minmax(0,1fr) 1px minmax(0,1fr);grid-template-rows:auto 1px auto;grid-template-areas:"reactions utility-separator utilities" "stats-separator stats-separator stats-separator" "stats stats stats";justify-content:stretch;gap:clamp(var(--gala-space-2xs),1vw,var(--gala-space-md));align-items:center;padding:var(--gala-space-md);border-radius:var(--gala-radius-surface)}.gala-action-rail--integrated .gala-action-rail__separator{grid-area:utility-separator;inline-size:1px;block-size:auto;margin:.25rem 0}.gala-action-rail--integrated .gala-action-rail__separator--stats{grid-area:stats-separator;inline-size:auto;block-size:1px;margin:0}.gala-action-rail--integrated .gala-action-group--reactions{grid-area:reactions}.gala-action-rail--integrated .gala-action-group--utilities{grid-area:utilities}.gala-action-rail--integrated .gala-reaction-actions{grid-template-columns:repeat(6,2.5rem)}.gala-action-rail--integrated .gala-utility-actions{grid-template-columns:repeat(4,2.5rem)}.gala-action-rail--integrated .gala-action-stats>div{min-block-size:2.5rem;display:flex;flex-direction:row;gap:.4rem;padding-inline:.25rem}.gala-action-rail--integrated .gala-action-stats{grid-area:stats;grid-template-columns:repeat(3,minmax(0,1fr))}}@media(max-width:74.99rem){.gala-action-rail{grid-template-columns:1fr;width:min(100%,42rem)}.gala-action-rail__separator{inline-size:auto;block-size:1px;margin:0}}@media(max-width:47.99rem){.gala-page-footer{flex-direction:column}.gala-page-footer__line{grid-template-columns:minmax(0,1fr);gap:var(--gala-space-2xs)}.gala-page-footer__line>*+*:before{content:none}.gala-page-footer nav{margin-inline-start:0}.gala-page-footer ul{justify-content:flex-start}.gala-site-name{flex:1 1 auto;min-inline-size:4rem;font-size:var(--gala-text-base)}.gala-header-link{display:none}.gala-site-header__actions{flex:0 0 auto;gap:.125rem}.gala-account-control{inline-size:2.75rem;padding:0;justify-content:center}.gala-account-control [data-user-label]{display:none}}
1
+ :root{color-scheme:light dark;--gala-color-background: light-dark(#fdfcfb, #131211);--gala-color-surface: light-dark(#f6f4f1, #1c1a18);--gala-color-raised: light-dark(#fffffe, #24211f);--gala-color-text: light-dark(#1a1817, #f2efec);--gala-color-muted: light-dark(#6b645e, #a8a099);--gala-color-border: light-dark(#968e86, #6b645e);--gala-color-hairline: light-dark(#e8e3dd, #2a2724);--gala-color-border-strong: light-dark(#c9c2ba, #46413d);--gala-color-accent: light-dark( var(--gala-accent-light, #8a4b2a), var(--gala-accent-dark, #e8a87c));--gala-font-body: ui-sans-serif, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;--gala-font-display: var(--gala-font-body);--gala-font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, monospace;--gala-text-xs: .78rem;--gala-text-sm: .875rem;--gala-text-base: clamp(1rem, .97rem + .15vw, 1.0625rem);--gala-text-lg: clamp(1.15rem, 1.09rem + .3vw, 1.3rem);--gala-text-xl: clamp(1.4rem, 1.28rem + .6vw, 1.75rem);--gala-text-2xl: clamp(1.75rem, 1.5rem + 1.2vw, 2.4rem);--gala-text-3xl: clamp(2.2rem, 1.7rem + 2.4vw, 3.4rem);--gala-leading-tight: 1.15;--gala-leading-body: 1.65;--gala-tracking-tight: -.018em;--gala-tracking-wide: .08em;--gala-weight-display: 640;--gala-step: 1rem;--gala-space-2xs: calc(var(--gala-step) * .25);--gala-space-xs: calc(var(--gala-step) * .5);--gala-space-sm: calc(var(--gala-step) * .75);--gala-space-md: var(--gala-step);--gala-space-lg: calc(var(--gala-step) * 1.75);--gala-space-xl: calc(var(--gala-step) * 3);--gala-space-page: clamp(1.25rem, 5vw, 4.5rem);--gala-radius-control: .625rem;--gala-radius-surface: 1rem;--gala-shadow-high: 0 1px 2px light-dark(rgb(26 24 23 / 5%), rgb(0 0 0 / 35%)), 0 12px 28px -12px light-dark(rgb(26 24 23 / 18%), rgb(0 0 0 / 60%));--gala-motion-fast: .12s;--gala-motion-base: .22s;--gala-ease: cubic-bezier(.2, 0, 0, 1);--gala-content-width: 72rem;--gala-measure: 68ch;--gala-widget-min-block-size: 8rem}:root[data-mode=light]{color-scheme:light;--gala-color-background: #fdfcfb;--gala-color-surface: #f6f4f1;--gala-color-raised: #fffffe;--gala-color-text: #1a1817;--gala-color-muted: #6b645e;--gala-color-border: #968e86;--gala-color-hairline: #e8e3dd;--gala-color-border-strong: #c9c2ba;--gala-color-accent: var(--gala-accent-light, #8a4b2a)}:root[data-mode=dark]{color-scheme:dark;--gala-color-background: #131211;--gala-color-surface: #1c1a18;--gala-color-raised: #24211f;--gala-color-text: #f2efec;--gala-color-muted: #a8a099;--gala-color-border: #6b645e;--gala-color-hairline: #2a2724;--gala-color-border-strong: #46413d;--gala-color-accent: var(--gala-accent-dark, #e8a87c)}:root[data-palette=ocean]{--gala-color-background: light-dark(#f8fbfd, #0b1a24);--gala-color-surface: light-dark(#eef4f9, #12252f);--gala-color-raised: light-dark(#ffffff, #172d39);--gala-color-text: light-dark(#12242f, #eaf3f8);--gala-color-muted: light-dark(#5a6f7d, #98aebb);--gala-color-border: light-dark(#7d8d99, #5f7d8c);--gala-color-hairline: light-dark(#dde7ee, #1d3644);--gala-color-border-strong: light-dark(#bdccd7, #33505f);--gala-color-accent: light-dark(#0f5f7a, #7fd0e8)}:root[data-palette=ocean][data-mode=light]{color-scheme:light;--gala-color-background: #f8fbfd;--gala-color-surface: #eef4f9;--gala-color-raised: #ffffff;--gala-color-text: #12242f;--gala-color-muted: #5a6f7d;--gala-color-border: #7d8d99;--gala-color-hairline: #dde7ee;--gala-color-border-strong: #bdccd7;--gala-color-accent: var(--gala-accent-light, #0f5f7a)}:root[data-palette=ocean][data-mode=dark]{color-scheme:dark;--gala-color-background: #0b1a24;--gala-color-surface: #12252f;--gala-color-raised: #172d39;--gala-color-text: #eaf3f8;--gala-color-muted: #98aebb;--gala-color-border: #5f7d8c;--gala-color-hairline: #1d3644;--gala-color-border-strong: #33505f;--gala-color-accent: var(--gala-accent-dark, #7fd0e8)}:root[data-palette=forest]{--gala-color-background: light-dark(#fbfcfa, #101410);--gala-color-surface: light-dark(#f0f4ee, #182018);--gala-color-raised: light-dark(#ffffff, #1f271f);--gala-color-text: light-dark(#18201a, #eef3ec);--gala-color-muted: light-dark(#5b665d, #9aa89b);--gala-color-border: light-dark(#849084, #5e685f);--gala-color-hairline: light-dark(#e2e9df, #232b23);--gala-color-border-strong: light-dark(#5b665d, #7d897e);--gala-color-accent: light-dark(#2f6b3f, #8fd3a1)}:root[data-palette=forest][data-mode=light]{color-scheme:light;--gala-color-background: #fbfcfa;--gala-color-surface: #f0f4ee;--gala-color-raised: #ffffff;--gala-color-text: #18201a;--gala-color-muted: #5b665d;--gala-color-border: #849084;--gala-color-hairline: #e2e9df;--gala-color-border-strong: #5b665d;--gala-color-accent: var(--gala-accent-light, #2f6b3f)}:root[data-palette=forest][data-mode=dark]{color-scheme:dark;--gala-color-background: #101410;--gala-color-surface: #182018;--gala-color-raised: #1f271f;--gala-color-text: #eef3ec;--gala-color-muted: #9aa89b;--gala-color-border: #5e685f;--gala-color-hairline: #232b23;--gala-color-border-strong: #7d897e;--gala-color-accent: var(--gala-accent-dark, #8fd3a1)}:root[data-palette=plum]{--gala-color-background: light-dark(#fdfbfd, #141016);--gala-color-surface: light-dark(#f5eff5, #1d1720);--gala-color-raised: light-dark(#ffffff, #241d28);--gala-color-text: light-dark(#1f1820, #f2ecf3);--gala-color-muted: light-dark(#665c69, #a99dac);--gala-color-border: light-dark(#948a95, #6b606d);--gala-color-hairline: light-dark(#ebe2ec, #281f2b);--gala-color-border-strong: light-dark(#665c69, #8b7f8d);--gala-color-accent: light-dark(#7a3d76, #dda6d8)}:root[data-palette=plum][data-mode=light]{color-scheme:light;--gala-color-background: #fdfbfd;--gala-color-surface: #f5eff5;--gala-color-raised: #ffffff;--gala-color-text: #1f1820;--gala-color-muted: #665c69;--gala-color-border: #948a95;--gala-color-hairline: #ebe2ec;--gala-color-border-strong: #665c69;--gala-color-accent: var(--gala-accent-light, #7a3d76)}:root[data-palette=plum][data-mode=dark]{color-scheme:dark;--gala-color-background: #141016;--gala-color-surface: #1d1720;--gala-color-raised: #241d28;--gala-color-text: #f2ecf3;--gala-color-muted: #a99dac;--gala-color-border: #6b606d;--gala-color-hairline: #281f2b;--gala-color-border-strong: #8b7f8d;--gala-color-accent: var(--gala-accent-dark, #dda6d8)}:root[data-theme=editorial]{--gala-font-body: ui-serif, "Iowan Old Style", Charter, "Source Serif 4", Georgia, serif;--gala-font-display: var(--gala-font-body);--gala-weight-display: 600;--gala-step: 1.1rem;--gala-leading-body: 1.7;--gala-radius-control: .5rem;--gala-radius-surface: .75rem;--gala-measure: 66ch;--gala-surface-border: var(--gala-color-hairline);--gala-surface-shadow: none}:root[data-theme=modern]{--gala-font-body: ui-sans-serif, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;--gala-font-display: var(--gala-font-body);--gala-weight-display: 640;--gala-step: 1rem;--gala-leading-body: 1.65;--gala-radius-control: .625rem;--gala-radius-surface: 1rem;--gala-measure: 70ch;--gala-surface-border: transparent;--gala-surface-shadow: var(--gala-shadow-high)}:root[data-theme=technical]{--gala-font-body: ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif;--gala-font-display: var(--gala-font-body);--gala-weight-display: 660;--gala-tracking-tight: -.022em;--gala-step: .9rem;--gala-leading-body: 1.6;--gala-radius-control: .375rem;--gala-radius-surface: .5rem;--gala-measure: 74ch;--gala-surface-border: var(--gala-color-border-strong);--gala-surface-shadow: none}:root[data-theme=technical] .gala-eyebrow,:root[data-theme=technical] .gala-engagement dt,:root[data-theme=technical] .gala-comment__meta time{font-family:var(--gala-font-mono)}@media(prefers-reduced-motion:reduce){:root{--gala-motion-fast: 0ms;--gala-motion-base: 0ms;scroll-behavior:auto}*,*:before,*:after{animation-duration:1ms!important;transition-duration:1ms!important}}:root[data-layout=portfolio]{--gala-content-width: 82rem}html{scroll-behavior:smooth}body{box-sizing:border-box;display:flex;flex-direction:column;min-block-size:100vh;min-block-size:100svh;margin:0;padding:var(--gala-space-page);color:var(--gala-color-text);background:var(--gala-color-background);font-family:var(--gala-font-body);font-size:var(--gala-text-base);line-height:var(--gala-leading-body);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}.gala-skip-link{position:fixed;inset-block-start:1rem;inset-inline-start:1rem;z-index:100;padding:.75rem 1rem;color:#fff;background:var(--gala-color-accent);border-radius:999px;transform:translateY(-200%)}.gala-skip-link:focus{transform:translateY(0)}.gala-site-name{color:var(--gala-color-text);font-family:var(--gala-font-display);font-size:var(--gala-text-lg);font-weight:var(--gala-weight-display);letter-spacing:var(--gala-tracking-tight);text-decoration:none;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gala-header-link{color:var(--gala-color-text);font-size:var(--gala-text-sm);text-decoration:none}.gala-account-control{display:inline-flex;align-items:center;gap:.5rem;min-block-size:2.75rem;padding-inline:.9rem;border-radius:999px}.gala-account-control svg{inline-size:1rem;block-size:1rem}.gala-article{max-inline-size:76rem;margin-inline:auto}.gala-page--article .gala-site-header,.gala-page--article main,.gala-page--article .gala-page-footer{max-inline-size:112rem}.gala-page--article .gala-article,.gala-page--article .gala-engagement{max-inline-size:none}.gala-article-header{padding-block:clamp(2.5rem,5vw,5rem)}.gala-article-header h1{max-inline-size:12ch;font-size:clamp(2.5rem,7vw,5.25rem);line-height:.96;letter-spacing:-.055em}.gala-byline{color:var(--gala-color-muted);font-size:var(--gala-text-sm)}.gala-markdown{max-inline-size:42rem;margin-inline:auto;font-size:clamp(1.1rem,1rem + .35vw,1.3rem)}.gala-markdown :where(h2){margin-block-start:clamp(3rem,7vw,5rem);font-size:clamp(2.2rem,5vw,3.8rem)}.gala-markdown :where(h2,h3,h4,h5,h6){scroll-margin-block-start:7rem}.gala-markdown :where(img,video){max-inline-size:100%;block-size:auto}.gala-markdown :where(pre){box-sizing:border-box;max-inline-size:100%;overflow-x:auto;scrollbar-color:var(--gala-color-border-strong) var(--gala-color-surface)}:where(h1,h2,h3,h4){font-family:var(--gala-font-display);font-weight:var(--gala-weight-display);line-height:var(--gala-leading-tight);letter-spacing:var(--gala-tracking-tight);text-wrap:balance;margin-block:0 var(--gala-space-sm)}:where(h1){font-size:var(--gala-text-3xl)}:where(h2){font-size:var(--gala-text-2xl)}:where(h3){font-size:var(--gala-text-xl)}:where(h4){font-size:var(--gala-text-lg)}:where(p,ul,ol,blockquote){margin-block:0 var(--gala-space-md)}:where(p){text-wrap:pretty}blockquote{margin-inline:0;padding-inline-start:var(--gala-space-md);border-inline-start:2px solid var(--gala-color-accent);color:var(--gala-color-muted)}:where(code,kbd,samp){font-family:var(--gala-font-mono);font-size:.9em}:where(pre){padding:var(--gala-space-md);overflow-x:auto;background:var(--gala-color-surface);border-radius:var(--gala-radius-control)}:where(hr){border:0;border-block-start:1px solid var(--gala-color-hairline);margin-block:var(--gala-space-xl)}:where(table){border-collapse:collapse;inline-size:100%}:where(th,td){padding:var(--gala-space-xs) var(--gala-space-sm);border-block-end:1px solid var(--gala-color-hairline);text-align:start}.gala-eyebrow,.gala-comment__meta time,.gala-comment__edited{font-size:var(--gala-text-xs);letter-spacing:var(--gala-tracking-wide);text-transform:uppercase;color:var(--gala-color-muted)}.gala-site-header{position:sticky;inset-block-start:0;z-index:10;box-sizing:border-box;inline-size:100%;display:flex;align-items:center;justify-content:space-between;gap:var(--gala-space-md);max-inline-size:var(--gala-content-width);margin-inline:auto;margin-block-end:var(--gala-space-xl);padding-block:var(--gala-space-xs);background:color-mix(in srgb,var(--gala-color-background) 88%,transparent);backdrop-filter:blur(8px);border-block-end:1px solid var(--gala-color-hairline)}@supports not (backdrop-filter: blur(8px)){.gala-site-header{background:var(--gala-color-background)}}.gala-site-header__actions{display:flex;align-items:center;gap:.5rem}.gala-header-link{display:inline-flex;align-items:center;min-block-size:2.75rem}.gala-icon-control{display:inline-grid;inline-size:2.75rem;block-size:2.75rem;box-sizing:border-box;padding:.6rem;place-items:center;color:inherit;border:.125rem solid transparent;border-radius:50%}.gala-icon-control{transition:background var(--gala-motion-fast) var(--gala-ease),color var(--gala-motion-fast) var(--gala-ease);color:var(--gala-color-muted)}.gala-icon-control:hover{background:var(--gala-color-surface);color:var(--gala-color-text)}.gala-icon-control:focus-visible{outline:.1875rem solid currentcolor;outline-offset:.1875rem}.gala-icon-control svg{inline-size:100%;block-size:100%;fill:none;stroke:currentcolor}.gala-dialog{inline-size:min(42rem,calc(100% - 2rem));max-block-size:calc(100% - 2rem);box-sizing:border-box;padding:1.5rem;color:var(--gala-color-text);background:var(--gala-color-background);border:1px solid var(--gala-surface-border);border-radius:var(--gala-radius-surface);box-shadow:var(--gala-shadow-high)}.gala-dialog::backdrop{background:#000000a6}.gala-account-dialog{inline-size:min(26rem,calc(100% - 2rem))}.gala-account-dialog iframe{display:block;inline-size:100%;block-size:7rem;border:0;overflow:hidden}.gala-dialog{display:grid;gap:var(--gala-space-sm)}.gala-dialog:not([open]){display:none}.gala-dialog__close{justify-self:end;margin:0}.gala-dialog__header{display:flex;align-items:center;justify-content:space-between;gap:var(--gala-space-md)}.gala-dialog__header h2{margin:0}main,.gala-page-footer{max-inline-size:var(--gala-content-width);margin-inline:auto}.gala-page-footer{box-sizing:border-box;inline-size:100%}main{flex:1 0 auto;inline-size:100%}a{color:var(--gala-color-accent)}button{min-block-size:2.75rem;padding-inline:var(--gala-space-md);color:inherit;background:var(--gala-color-surface);border:1px solid var(--gala-color-border);border-radius:var(--gala-radius-control);font:inherit;font-size:var(--gala-text-sm);cursor:pointer;transition:background var(--gala-motion-fast) var(--gala-ease),border-color var(--gala-motion-fast) var(--gala-ease)}button:hover{border-color:var(--gala-color-border-strong);background:var(--gala-color-raised)}button[disabled]{opacity:.55;cursor:not-allowed}button:focus-visible{outline:.1875rem solid currentcolor;outline-offset:.1875rem}.gala-button,.gala-badge,.gala-tag-chip{display:inline-flex;align-items:center;min-block-size:2.75rem;border:1px solid var(--gala-color-border);border-radius:var(--gala-radius-control);font-size:var(--gala-text-sm)}.gala-badge,.gala-tag-chip{padding-inline:.75rem}.gala-tag-chip{text-decoration:none}.gala-section-heading{margin-block:3rem 1rem}.gala-section-heading>:where(h2,p){margin-block:0 .5rem}.gala-hero{display:grid;gap:1.5rem;align-items:center}.gala-hero__image{inline-size:100%;block-size:auto;border-radius:var(--gala-radius-control)}.gala-page-content{max-inline-size:var(--gala-measure)}.gala-page-content :where(img,video){max-inline-size:100%;block-size:auto}.gala-author-profile{display:flex;gap:1rem;padding:1rem;background:var(--gala-color-surface);border-radius:var(--gala-radius-control)}.gala-author-profile img{border-radius:50%;object-fit:cover}.gala-social-links,.gala-page-footer ul,.gala-share ul{display:flex;flex-wrap:wrap;gap:1rem;padding:0;list-style:none}.gala-card-index{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,18rem),1fr));gap:1rem;padding:0;list-style:none}.gala-version-page{inline-size:min(100%,74rem);margin-inline:auto}.gala-version-page__header{max-inline-size:48rem}.gala-version-page__header>p{color:var(--gala-color-muted)}.gala-version-page__header .gala-button{margin-block-start:var(--gala-space-md)}.gala-version-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,18rem),1fr));gap:var(--gala-space-md);margin-block-start:var(--gala-space-lg)}.gala-version-card{display:grid;align-content:start;gap:var(--gala-space-sm);min-block-size:10rem;margin-block-start:var(--gala-space-lg);padding:var(--gala-space-lg);border:1px solid var(--gala-color-border);border-radius:var(--gala-radius-surface);background:var(--gala-color-surface)}.gala-version-grid .gala-version-card{margin-block-start:0}.gala-version-card>*{margin:0}.gala-version-commit{font-family:var(--gala-font-mono);font-weight:700}.gala-version-status{color:var(--gala-color-muted)}.gala-version-status--error{color:var(--gala-color-accent)}[data-layout=portfolio] .gala-card-index{grid-template-columns:repeat(auto-fit,minmax(min(100%,22rem),1fr));gap:1.5rem}[data-layout=portfolio] .gala-card{padding:clamp(1.25rem,3vw,2rem)}.gala-card{block-size:100%;box-sizing:border-box;padding:var(--gala-space-lg);background:var(--gala-color-surface);border:1px solid var(--gala-surface-border);border-radius:var(--gala-radius-surface);box-shadow:var(--gala-surface-shadow)}.gala-card{transition:transform var(--gala-motion-base) var(--gala-ease),box-shadow var(--gala-motion-base) var(--gala-ease)}.gala-card-index li:hover .gala-card{transform:translateY(-2px);box-shadow:var(--gala-shadow-high)}.gala-stats-graph{min-block-size:var(--gala-widget-min-block-size);margin-inline:0}.gala-stats-graph svg{inline-size:100%;block-size:8rem}.gala-stats-graph polyline{fill:none;stroke:var(--gala-color-accent);stroke-width:2}.gala-loading{display:grid;min-block-size:var(--gala-widget-min-block-size);place-items:center}.gala-loading__indicator{inline-size:2rem;block-size:2rem;border:.25rem solid var(--gala-color-border);border-block-start-color:var(--gala-color-accent);border-radius:50%;animation:gala-spin .8s linear infinite}.gala-pagination{display:flex;justify-content:space-between;gap:1rem}.gala-search{display:grid;grid-template-columns:1fr auto;gap:.5rem}.gala-search label{grid-column:1 / -1}.gala-search input{min-block-size:2.75rem;font:inherit}.gala-search-results{display:grid;gap:1rem;padding:0;list-style:none}.gala-search-results article{padding:1rem;background:var(--gala-color-surface);border-radius:var(--gala-radius-control)}.gala-search-results h2{margin-block-start:0}.gala-toc{box-sizing:border-box;min-inline-size:0;max-inline-size:42rem;margin-inline:auto;padding:1rem;background:var(--gala-color-surface)}.gala-toc summary{color:var(--gala-color-text);font-weight:var(--gala-weight-display);cursor:pointer}.gala-toc nav{margin-block-start:var(--gala-space-sm);overscroll-behavior:contain}.gala-toc ol{margin:0;padding-inline-start:1.25rem}.gala-toc a[aria-current=location]{color:var(--gala-color-text);font-weight:700}.gala-share__fallback{inline-size:min(100%,36rem)}.gala-engagement__placeholder{display:grid;min-block-size:var(--gala-widget-min-block-size);align-content:center;margin:0}.gala-engagement-profile>*{margin-block:0 .5rem}.gala-engagement-actions{display:grid;gap:1rem;margin-block-start:1.5rem}.gala-engagement-actions[hidden]{display:none}.gala-account-dialog__invite{margin-block:0 1rem;max-inline-size:34rem}.gala-account-dialog__invite[hidden]{display:none}.gala-engagement-actions form,[data-comment-editor]{display:grid;gap:.5rem;max-inline-size:42rem}.gala-engagement-actions label{display:grid;gap:.5rem}.gala-engagement-actions textarea,[data-comment-editor] textarea{min-block-size:7rem;padding:.75rem;font:inherit}.gala-page-footer{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--gala-space-lg);margin-block-start:var(--gala-space-xl);padding-block-start:var(--gala-space-md);border-block-start:.125rem solid var(--gala-color-border)}.gala-page-footer__identity{display:flex;gap:var(--gala-space-sm);max-inline-size:56rem}.gala-page-footer__identity img{flex:0 0 auto;border-radius:50%;object-fit:cover}.gala-page-footer__identity p{margin:0;color:var(--gala-color-muted);font-size:var(--gala-text-sm)}.gala-page-footer__details{display:grid;gap:var(--gala-space-2xs);align-content:center}.gala-page-footer__line{display:grid;grid-template-columns:repeat(4,max-content);align-items:baseline;gap:0 var(--gala-space-sm)}.gala-page-footer__line>*+*:before{content:"\b7";margin-inline-end:var(--gala-space-sm);color:var(--gala-color-border)}.gala-page-footer__bio{line-height:1.4}.gala-page-footer__author{color:var(--gala-color-text);font-weight:var(--gala-weight-display)}.gala-page-footer nav{margin-inline-start:auto}.gala-page-footer ul{justify-content:flex-end;margin:0}.gala-error-page{min-block-size:60vh;display:grid;align-content:center;justify-items:start}.gala-code-block{position:relative;box-sizing:border-box;min-inline-size:0;max-inline-size:100%;inline-size:100%;overflow:hidden}.gala-code-block>button{position:absolute;inset-block-start:.5rem;inset-inline-end:.5rem;background:var(--gala-color-background)}.gala-code-block pre{box-sizing:border-box;min-inline-size:0;max-inline-size:100%;inline-size:100%;overflow-x:auto;overscroll-behavior-inline:contain;padding:3.5rem 1rem 1rem;background:var(--gala-color-surface);border-radius:var(--gala-radius-control)}.gala-code-block code{display:block;inline-size:max-content;min-inline-size:100%}.gala-embed{display:grid;place-items:center;gap:.75rem;box-sizing:border-box;inline-size:100%;margin-inline:0;padding:1rem;overflow:hidden;background:var(--gala-color-surface);border:.125rem solid var(--gala-color-border);border-radius:var(--gala-radius-control)}.gala-embed--youtube{aspect-ratio:16 / 9}.gala-embed--codepen{min-block-size:25rem}.gala-embed--gist,.gala-embed--x{min-block-size:8rem}.gala-embed iframe{inline-size:100%;block-size:100%;border:0}.gala-embed__icon{inline-size:2rem;block-size:2rem;background:center / contain no-repeat}.gala-embed--youtube .gala-embed__icon{background-image:url(../assets/embed-youtube.svg)}.gala-embed--codepen .gala-embed__icon{background-image:url(../assets/embed-codepen.svg)}.gala-embed--gist .gala-embed__icon{background-image:url(../assets/embed-gist.svg)}.gala-embed--x .gala-embed__icon{background-image:url(../assets/embed-x.svg)}.shiki,.shiki span{color:inherit;background-color:var(--gala-color-surface)}.gala-visually-hidden{position:absolute;inline-size:1px;block-size:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.gala-contact form{display:grid;gap:1rem;max-inline-size:42rem}.gala-contact label{display:grid;gap:.35rem}.gala-contact input,.gala-contact textarea{font:inherit;padding:.65rem}.gala-contact textarea{min-block-size:12rem;resize:vertical}@keyframes gala-spin{to{transform:rotate(1turn)}}@media(min-width:48rem){.gala-hero{grid-template-columns:minmax(0,1fr) minmax(18rem,1fr)}}@media(prefers-reduced-motion:no-preference){@view-transition{navigation:auto}}.gala-comments-island{margin-block-start:var(--gala-space-xl)}.gala-comments__heading{font-size:var(--gala-text-lg);margin-block-end:var(--gala-space-md)}.gala-comments,.gala-comment-replies{list-style:none;margin:0;padding:0}.gala-comment-replies{margin-block-start:var(--gala-space-sm);margin-inline-start:var(--gala-space-xs);padding-inline-start:var(--gala-space-md);border-inline-start:1px solid var(--gala-color-hairline)}.gala-comment{padding-block:var(--gala-space-sm)}.gala-comment+.gala-comment{border-block-start:1px solid var(--gala-color-hairline)}.gala-comment-replies .gala-comment+.gala-comment{border-block-start:0}.gala-comment__meta{display:flex;align-items:baseline;gap:var(--gala-space-xs);margin-block-end:var(--gala-space-2xs);font-size:var(--gala-text-sm)}.gala-comment__meta strong{font-weight:600}.gala-comment__pending{font-size:var(--gala-text-xs);color:var(--gala-color-muted)}.gala-comment__body{margin-block:0;overflow-wrap:anywhere}.gala-comment-actions{display:flex;gap:var(--gala-space-2xs);margin-block-start:var(--gala-space-2xs);opacity:.72;transition:opacity var(--gala-motion-fast) var(--gala-ease)}.gala-comment:hover>.gala-comment-actions,.gala-comment:focus-within>.gala-comment-actions{opacity:1}.gala-comment-actions button{min-block-size:2rem;padding-inline:var(--gala-space-xs);font-size:var(--gala-text-xs);background:transparent;border-color:transparent;color:var(--gala-color-muted)}.gala-comment-actions button:hover{color:var(--gala-color-text);background:var(--gala-color-surface)}.gala-comment__form{display:grid;gap:var(--gala-space-xs);margin-block:var(--gala-space-sm)}.gala-comment__form textarea{inline-size:100%;box-sizing:border-box;padding:var(--gala-space-sm);color:inherit;background:var(--gala-color-raised);border:1px solid var(--gala-color-border);border-radius:var(--gala-radius-control);font:inherit;font-size:var(--gala-text-sm);line-height:var(--gala-leading-body);resize:vertical}.gala-comment__form textarea:focus-visible{outline:2px solid var(--gala-color-accent);outline-offset:1px}.gala-comment__controls{display:flex;gap:var(--gala-space-xs)}.gala-comments__status,.gala-comments__empty,.gala-comments__prompt{color:var(--gala-color-muted);font-size:var(--gala-text-sm)}.gala-comments__more{margin-block-start:var(--gala-space-md)}.gala-engagement{min-block-size:var(--gala-widget-min-block-size);max-inline-size:var(--gala-content-width);margin-block-start:var(--gala-space-xl);padding-block-start:var(--gala-space-lg);border-block-start:1px solid var(--gala-color-border)}.gala-engagement-profile{display:flex;align-items:baseline;gap:var(--gala-space-sm);padding:0;background:none}.gala-engagement-profile h2{font-size:var(--gala-text-lg);margin:0}.gala-engagement-profile p{margin:0;color:var(--gala-color-muted);font-size:var(--gala-text-sm)}.gala-engagement>dl{display:flex;flex-wrap:wrap;gap:var(--gala-space-lg);margin-block:var(--gala-space-md)}.gala-engagement>dl>div{display:flex;flex-direction:column-reverse;gap:.1rem}.gala-engagement>dl dt{font-size:var(--gala-text-xs);letter-spacing:var(--gala-tracking-wide);text-transform:uppercase;color:var(--gala-color-muted)}.gala-engagement>dl dd{margin:0;font-size:var(--gala-text-lg);font-variant-numeric:tabular-nums}.gala-reaction-actions{display:flex;flex-wrap:wrap;gap:var(--gala-space-2xs)}.gala-engagement-actions{display:grid;gap:var(--gala-space-sm);justify-items:start}.gala-engagement-actions>[data-follow-article]{inline-size:auto}.gala-share{margin-block-start:var(--gala-space-lg)}.gala-engagement{position:relative}.gala-reading-progress{position:fixed;z-index:20;inset:0 0 auto;inline-size:100%;block-size:.2rem;appearance:none;border:0;background:transparent;pointer-events:none}.gala-reading-progress::-webkit-progress-bar{background:transparent}.gala-reading-progress::-webkit-progress-value{background:var(--gala-color-accent)}.gala-reading-progress::-moz-progress-bar{background:var(--gala-color-accent)}.gala-reading-layout{display:block}.gala-conversation{max-width:var(--gala-measure);margin-inline:auto;padding-block:clamp(3rem,7vw,6rem)}.gala-conversation__header{margin-block-end:var(--gala-space-xl)}.gala-conversation__header h2{margin:0;font:var(--gala-weight-display) var(--gala-text-2xl)/var(--gala-leading-tight) var(--gala-font-display);letter-spacing:var(--gala-tracking-tight)}.gala-conversation__status{display:block;min-block-size:1.5em;color:var(--gala-color-muted)}.gala-conversation__status:empty{display:none}.gala-action-rail{position:static;z-index:4;inset-block-start:6rem;box-sizing:border-box;width:min(100%,42rem);margin:var(--gala-space-xl) auto 0;display:grid;grid-template-columns:1fr auto 1fr;gap:var(--gala-space-md);align-items:center;padding:var(--gala-space-md);border:1px solid var(--gala-color-hairline);border-radius:var(--gala-radius-surface);background:color-mix(in srgb,var(--gala-color-background) 88%,transparent);box-shadow:var(--gala-shadow-high);backdrop-filter:blur(16px)}.gala-action-rail button,.gala-action-rail a{inline-size:2.5rem;min-block-size:2.5rem;display:grid;place-items:center;padding:0;border:0;border-radius:50%;color:var(--gala-color-muted);background:transparent;font:600 var(--gala-text-xs)/1 var(--gala-font-body);text-decoration:none;cursor:pointer}.gala-action-rail svg{inline-size:1.2rem;block-size:1.2rem}.gala-action-rail button:hover,.gala-action-rail a:hover,.gala-action-rail button[aria-pressed=true]{color:var(--gala-color-background);background:var(--gala-color-accent)}.gala-engagement .gala-action-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--gala-space-xs);margin:0}.gala-action-stats>div{display:flex;min-block-size:2.5rem;align-items:center;justify-content:space-between;gap:.4rem;padding-inline:.25rem}.gala-action-stats>div+div{border-inline-start:1px solid var(--gala-color-hairline)}.gala-action-stats dt{display:grid;place-items:center;color:var(--gala-color-muted)}.gala-action-stats dt svg{inline-size:1.2rem;block-size:1.2rem}.gala-action-stats dd{margin:0;color:var(--gala-color-text);font:400 1.2rem/1 var(--gala-font-mono)}.gala-action-group{display:grid}.gala-reaction-actions,.gala-utility-actions,.gala-share{display:grid;grid-template-columns:repeat(6,2.5rem);gap:var(--gala-space-2xs);justify-content:center}.gala-utility-actions>.gala-share{display:contents}.gala-action-rail__separator{inline-size:1px;align-self:stretch;margin-block:.25rem;background:var(--gala-color-hairline)}.gala-action-rail .gala-share__fallback{position:fixed;inline-size:1px;block-size:1px;overflow:hidden;clip-path:inset(50%)}.gala-action-rail .gala-share__fallback--visible{z-index:10;inset:auto 1rem 1rem;inline-size:min(32rem,calc(100vw - 2rem));block-size:auto;padding:.75rem;overflow:visible;clip-path:none}.gala-action-dock{display:block;min-block-size:4.25rem}.gala-article-boundary{width:100%;margin:clamp(4rem,8vw,7rem) auto var(--gala-space-lg);padding-block-start:var(--gala-space-md);display:flex;align-items:baseline;justify-content:space-between;gap:var(--gala-space-md);border-block-start:.25rem solid var(--gala-color-text);font-size:var(--gala-text-sm)}@media(min-width:75rem){.gala-reading-layout{display:grid;grid-template-columns:minmax(10rem,15rem) minmax(0,1fr) 8.5rem;align-items:start;justify-content:space-between;gap:clamp(2rem,4vw,5rem)}.gala-reading-layout .gala-toc{grid-column:1;grid-row:1;position:sticky;inset-block-start:6rem;max-inline-size:none;margin-inline:0;max-block-size:calc(100vh - 8rem);transition:box-shadow var(--gala-motion-fast) var(--gala-ease)}.gala-reading-layout .gala-toc--floating{box-shadow:var(--gala-shadow-high)}.gala-reading-layout .gala-toc>summary{display:none}.gala-reading-layout .gala-toc>nav{display:block;max-block-size:calc(100vh - 10rem);margin-block-start:0;overflow-y:auto;scrollbar-width:thin}.gala-reading-layout .gala-toc--overflowing ol{padding-block:max(1rem,calc((100vh - 11.5rem)/2))}.gala-reading-layout .gala-markdown{grid-column:2;grid-row:1;max-inline-size:56rem;inline-size:100%;margin:0}.gala-article-boundary{grid-column:1 / -1;grid-row:2;margin-inline:0}.gala-action-dock{grid-column:2;grid-row:3}.gala-action-rail{grid-column:3;grid-row:1;position:sticky;inset-block-start:6rem;width:8.5rem;margin:0;display:grid;grid-template-columns:1fr;gap:var(--gala-space-sm);padding:var(--gala-space-sm);border-radius:var(--gala-radius-surface)}.gala-action-rail .gala-action-stats{gap:var(--gala-space-2xs)}.gala-action-rail:not(.gala-action-rail--integrated) .gala-action-stats{grid-template-columns:1fr}.gala-action-rail:not(.gala-action-rail--integrated) .gala-action-stats>div+div{border-inline-start:0;border-block-start:1px solid var(--gala-color-hairline)}.gala-action-rail .gala-action-stats>div{min-block-size:2.5rem;display:grid;grid-template-columns:repeat(2,2.5rem);justify-content:center;gap:.25rem;padding-inline:0}.gala-action-rail .gala-action-stats dd{justify-self:center}.gala-action-rail .gala-reaction-actions,.gala-action-rail .gala-utility-actions,.gala-action-rail .gala-share{grid-template-columns:repeat(2,2.5rem)}.gala-action-rail__separator{inline-size:auto;block-size:1px;margin:.25rem}.gala-action-rail--integrated{grid-column:2;grid-row:3;position:static;align-self:start;width:100%;margin:0;display:grid;grid-template-columns:minmax(0,1fr) 1px minmax(0,1fr);grid-template-rows:auto 1px auto;grid-template-areas:"reactions utility-separator utilities" "stats-separator stats-separator stats-separator" "stats stats stats";justify-content:stretch;gap:clamp(var(--gala-space-2xs),1vw,var(--gala-space-md));align-items:center;padding:var(--gala-space-md);border-radius:var(--gala-radius-surface)}.gala-action-rail--integrated .gala-action-rail__separator{grid-area:utility-separator;inline-size:1px;block-size:auto;margin:.25rem 0}.gala-action-rail--integrated .gala-action-rail__separator--stats{grid-area:stats-separator;inline-size:auto;block-size:1px;margin:0}.gala-action-rail--integrated .gala-action-group--reactions{grid-area:reactions}.gala-action-rail--integrated .gala-action-group--utilities{grid-area:utilities}.gala-action-rail--integrated .gala-reaction-actions{grid-template-columns:repeat(6,2.5rem)}.gala-action-rail--integrated .gala-utility-actions{grid-template-columns:repeat(4,2.5rem)}.gala-action-rail--integrated .gala-action-stats>div{min-block-size:2.5rem;display:flex;flex-direction:row;gap:.4rem;padding-inline:.25rem}.gala-action-rail--integrated .gala-action-stats{grid-area:stats;grid-template-columns:repeat(3,minmax(0,1fr))}}@media(max-width:74.99rem){.gala-action-rail{grid-template-columns:1fr;width:min(100%,42rem)}.gala-action-rail__separator{inline-size:auto;block-size:1px;margin:0}}@media(max-width:47.99rem){.gala-page-footer{flex-direction:column}.gala-page-footer__line{grid-template-columns:minmax(0,1fr);gap:var(--gala-space-2xs)}.gala-page-footer__line>*+*:before{content:none}.gala-page-footer nav{margin-inline-start:0}.gala-page-footer ul{justify-content:flex-start}.gala-site-name{flex:1 1 auto;min-inline-size:4rem;font-size:var(--gala-text-base)}.gala-header-link{display:none}.gala-site-header__actions{flex:0 0 auto;gap:.125rem}.gala-account-control{inline-size:2.75rem;padding:0;justify-content:center}.gala-account-control [data-user-label]{display:none}}
@@ -2,11 +2,11 @@
2
2
  const page = document.querySelector('[data-version-page]');
3
3
  if (!(page instanceof HTMLElement)) return;
4
4
  const modules = Object.freeze([
5
- { id: 'app', name: 'Gala App', url: 'https://app.gala67.com/version.json', repository: 'https://github.com/rathnasgala/app' },
6
- { id: 'api', name: 'Gala API', url: `${page.dataset.apiBaseUrl}/v1/version?siteId=${encodeURIComponent(page.dataset.siteId ?? '')}`, repository: 'https://github.com/rathnasgala/api' },
7
- { id: 'cli', name: 'Gala CLI', url: 'https://registry.npmjs.org/%40rathnasgala%2Fcli/latest', repository: 'https://github.com/rathnasgala/cli' },
8
- { id: 'theme', name: 'Gala Site Template', url: 'https://registry.npmjs.org/%40rathnasgala%2Ftheme/latest', repository: 'https://github.com/rathnasgala/site-template' },
9
- { id: 'content-validation', name: 'Gala Content Validation', url: 'https://registry.npmjs.org/%40rathnasgala%2Fcontent-validation/latest', repository: 'https://github.com/rathnasgala/publish' }
5
+ { id: 'app', name: 'Gala App', url: 'https://app.gala67.com/version.json' },
6
+ { id: 'api', name: 'Gala API', url: `${page.dataset.apiBaseUrl}/v1/version?siteId=${encodeURIComponent(page.dataset.siteId ?? '')}` },
7
+ { id: 'cli', name: 'Gala CLI', url: 'https://registry.npmjs.org/%40rathnasgala%2Fcli/latest', repository: 'https://github.com/rathnasgala/cli', repositoryName: 'rathnasgala/cli' },
8
+ { id: 'theme', name: 'Gala Site Template', url: 'https://registry.npmjs.org/%40rathnasgala%2Ftheme/latest', repository: 'https://github.com/rathnasgala/site-template', repositoryName: 'rathnasgala/site-template' },
9
+ { id: 'content-validation', name: 'Gala Content Validation', url: 'https://registry.npmjs.org/%40rathnasgala%2Fcontent-validation/latest', repository: 'https://github.com/rathnasgala/publish', repositoryName: 'rathnasgala/publish' }
10
10
  ]);
11
11
  const commitPattern = /^[0-9a-f]{40}$/;
12
12
  function exactCommit(value) {
@@ -31,23 +31,29 @@
31
31
  return;
32
32
  }
33
33
  const value = result.value;
34
- const commit = exactCommit(value);
35
34
  if (typeof value.version === 'string') {
36
35
  const release = document.createElement('p');
37
36
  release.textContent = `Release ${value.version}`;
38
37
  card.append(release);
39
38
  }
40
- if (commit) {
41
- const link = document.createElement('a');
42
- link.href = `${module.repository}/commit/${commit}`;
43
- link.className = 'gala-version-commit';
44
- link.textContent = commit.slice(0, 8);
45
- card.append(link);
46
- } else {
47
- const status = document.createElement('p');
48
- status.className = 'gala-version-status gala-version-status--error';
49
- status.textContent = 'The live source did not report an exact commit.';
50
- card.append(status);
39
+ if (module.repository) {
40
+ const repository = document.createElement('a');
41
+ repository.href = module.repository;
42
+ repository.textContent = module.repositoryName;
43
+ card.append(repository);
44
+ const commit = exactCommit(value);
45
+ if (commit) {
46
+ const link = document.createElement('a');
47
+ link.href = `${module.repository}/commit/${commit}`;
48
+ link.className = 'gala-version-commit';
49
+ link.textContent = commit.slice(0, 8);
50
+ card.append(link);
51
+ } else {
52
+ const status = document.createElement('p');
53
+ status.className = 'gala-version-status gala-version-status--error';
54
+ status.textContent = 'The live source did not report an exact commit.';
55
+ card.append(status);
56
+ }
51
57
  }
52
58
  if (typeof value.builtAt === 'string') {
53
59
  const built = document.createElement('time');
@@ -12,7 +12,7 @@ const PROVIDER_HOST = /\.github\.io$/;
12
12
  * The host this repository may claim as its own, or null.
13
13
  *
14
14
  * A site served under a path is served that way because GitHub gives it the domain held by the
15
- * owner's main site https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/about-custom-domains-and-github-pages
15
+ * owner's main site - https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/about-custom-domains-and-github-pages
16
16
  * puts a project site at `www.octocat.com/octo-project`. GitHub reads this file from the
17
17
  * published branch and treats it as *this* repository's own domain, which overrides that
18
18
  * inheritance: the blog would move to the domain root and take the address away from the site
@@ -28,7 +28,7 @@ export default class LanguageFeeds {
28
28
  });
29
29
  return renderAtomFeed({
30
30
  id: selfUrl,
31
- title: `${site.site.name} ${language}`,
31
+ title: `${site.site.name} - ${language}`,
32
32
  author: typeof site.site.author === 'string' && site.site.author.trim() !== ''
33
33
  ? site.site.author.trim()
34
34
  : site.site.name,
@@ -5,4 +5,4 @@ permalink: /index.html
5
5
  ---
6
6
  {% from "components/ui.njk" import cardIndex %}
7
7
  <h1>{{ site.site.name }}</h1>
8
- {{ cardIndex(buildManifest.posts) }}
8
+ {{ cardIndex(buildManifest.posts, buildManifest.preview) }}
@@ -22,9 +22,10 @@ export default class LanguageIndexes {
22
22
  }
23
23
 
24
24
  render({ buildManifest, language, site }) {
25
- const posts = buildManifest.posts.filter(
26
- (post) => post.publicationState === 'published' && post.language === language
27
- );
25
+ const posts = buildManifest.posts.filter((post) => (
26
+ post.publicationState === 'published'
27
+ || (buildManifest.preview === true && post.publicationState === 'not-emitted')
28
+ ) && post.language === language);
28
29
  const items = posts.map((post) => {
29
30
  const href = siteUrl({
30
31
  canonicalBaseUrl: site.hosting.canonicalBaseUrl,
@@ -33,6 +34,6 @@ export default class LanguageIndexes {
33
34
  });
34
35
  return `<li><a href="${html(href)}">${html(post.frontmatter.title)}</a></li>`;
35
36
  }).join('');
36
- return `<h1>${html(site.site.name)} ${html(language)}</h1><ol>${items}</ol>`;
37
+ return `<h1>${html(site.site.name)} - ${html(language)}</h1><ol>${items}</ol>`;
37
38
  }
38
39
  }
@@ -127,7 +127,7 @@
127
127
  }
128
128
 
129
129
 
130
- /* Two more, because colour is the choice a writer actually wants to make and the one that is
130
+ /* Two more, because colour is the choice a writer actually wants to make - and the one that is
131
131
  safe to offer, since a palette only swaps values every rule already reads and each is checked
132
132
  for contrast in both modes. */
133
133
  :root[data-palette='forest'] {
@@ -205,8 +205,8 @@
205
205
  *
206
206
  * Three, each designed whole.
207
207
  *
208
- * This replaced nine independent knobs typeface, spacing, density, radius, motion, surfaces,
209
- * palette which a writer set one at a time, blind, and only saw combined after a deploy. Nine
208
+ * This replaced nine independent knobs - typeface, spacing, density, radius, motion, surfaces,
209
+ * palette - which a writer set one at a time, blind, and only saw combined after a deploy. Nine
210
210
  * knobs is several hundred looks, and nobody had seen most of them: `mono` + `round` + `spacious`
211
211
  * + `raised` produced monospace headings inside page-wide pills, and it was reachable in four
212
212
  * clicks. A look is a set of decisions that agree with each other, so it is chosen as a set.
@@ -254,7 +254,7 @@
254
254
  --gala-surface-border: var(--gala-color-border-strong);
255
255
  --gala-surface-shadow: none;
256
256
  }
257
- /* Mono is an accent here labels, counts, metadata not a face to set a page in. */
257
+ /* Mono is an accent here - labels, counts, metadata - not a face to set a page in. */
258
258
  :root[data-theme='technical'] .gala-eyebrow,
259
259
  :root[data-theme='technical'] .gala-engagement dt,
260
260
  :root[data-theme='technical'] .gala-comment__meta time {
@@ -350,7 +350,7 @@ body {
350
350
  }
351
351
 
352
352
  /* Headings carry the hierarchy, so they get the display face, a tighter measure and tighter
353
- tracking large type set at body tracking is the single clearest sign of an unconsidered page. */
353
+ tracking - large type set at body tracking is the single clearest sign of an unconsidered page. */
354
354
  :where(h1, h2, h3, h4) {
355
355
  font-family: var(--gala-font-display);
356
356
  font-weight: var(--gala-weight-display);
@@ -394,13 +394,15 @@ blockquote {
394
394
 
395
395
  /*
396
396
  * Stays with the reader. It used to scroll away, so on a long post the only way back to the site
397
- * or to sign in was to scroll to the top. The negative inline margin lets the bar's background
397
+ * - or to sign in - was to scroll to the top. The negative inline margin lets the bar's background
398
398
  * reach the edge of the viewport while its contents stay on the page's own measure.
399
399
  */
400
400
  .gala-site-header {
401
401
  position: sticky;
402
402
  inset-block-start: 0;
403
403
  z-index: 10;
404
+ box-sizing: border-box;
405
+ inline-size: 100%;
404
406
  display: flex;
405
407
  align-items: center;
406
408
  justify-content: space-between;