@agent-cms/agentcms 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/LICENSE +143 -0
  2. package/README.md +1119 -2
  3. package/changelog.json +20 -0
  4. package/dist/admin/admin-files.json +48 -0
  5. package/dist/admin/assets/CodeEditor-DcFzGUt8.js +24 -0
  6. package/dist/admin/assets/flexweg-logo-CdtuqAFA.png +0 -0
  7. package/dist/admin/assets/index-CLZ1gQZl.js +5460 -0
  8. package/dist/admin/assets/index-DMcGogR2.css +1 -0
  9. package/dist/admin/assets/sql-wasm-C1U8OeUW.wasm +0 -0
  10. package/dist/admin/assets/sql-wasm-CYl3LXH_.js +2 -0
  11. package/dist/admin/assets/sql-wasm-V5jTDcrT.js +1 -0
  12. package/dist/admin/config.js +11 -0
  13. package/dist/admin/external.default.json +72 -0
  14. package/dist/admin/index.html +116 -0
  15. package/dist/admin/plugins/core-seo/bundle.js +55 -0
  16. package/dist/admin/plugins/core-seo/manifest.json +7 -0
  17. package/dist/admin/plugins/flexweg-archives/bundle.js +1414 -0
  18. package/dist/admin/plugins/flexweg-archives/manifest.json +7 -0
  19. package/dist/admin/plugins/flexweg-multilang/bundle.js +1187 -0
  20. package/dist/admin/plugins/flexweg-multilang/manifest.json +7 -0
  21. package/dist/admin/plugins/flexweg-rss/bundle.js +1354 -0
  22. package/dist/admin/plugins/flexweg-rss/manifest.json +7 -0
  23. package/dist/admin/plugins/flexweg-search/bundle.js +1243 -0
  24. package/dist/admin/plugins/flexweg-search/manifest.json +7 -0
  25. package/dist/admin/plugins/flexweg-sitemaps/bundle.js +1293 -0
  26. package/dist/admin/plugins/flexweg-sitemaps/manifest.json +7 -0
  27. package/dist/admin/runtime/cms-runtime.js +164 -0
  28. package/dist/admin/runtime/react-dom-client.js +13 -0
  29. package/dist/admin/runtime/react-dom.js +16 -0
  30. package/dist/admin/runtime/react-i18next.js +21 -0
  31. package/dist/admin/runtime/react-jsx-runtime.js +17 -0
  32. package/dist/admin/runtime/react.js +55 -0
  33. package/dist/admin/themes/corporate/bundle.js +14465 -0
  34. package/dist/admin/themes/corporate/manifest.json +7 -0
  35. package/dist/admin/themes/corporate/theme.css +2 -0
  36. package/dist/admin/themes/magazine/bundle.js +10229 -0
  37. package/dist/admin/themes/magazine/manifest.json +7 -0
  38. package/dist/admin/themes/magazine/theme.css +2 -0
  39. package/dist/admin/themes/marketplace-core/bundle.js +11213 -0
  40. package/dist/admin/themes/marketplace-core/manifest.json +7 -0
  41. package/dist/admin/themes/marketplace-core/theme.css +1613 -0
  42. package/dist/admin/themes/portfolio/bundle.js +9195 -0
  43. package/dist/admin/themes/portfolio/manifest.json +7 -0
  44. package/dist/admin/themes/portfolio/theme.css +2 -0
  45. package/dist/admin/themes/storefront/bundle.js +13172 -0
  46. package/dist/admin/themes/storefront/manifest.json +7 -0
  47. package/dist/admin/themes/storefront/theme.css +2 -0
  48. package/dist/agent/agentcms.mjs +1711 -0
  49. package/dist/agent/chunks/hosting-D_uj-Mt1.mjs +117 -0
  50. package/dist/agent/chunks/index-CrvEoyi0.mjs +3608 -0
  51. package/dist/agent/chunks/install-DkCCcKAO.mjs +577 -0
  52. package/dist/agent/chunks/plan-EYKegfhp.mjs +245 -0
  53. package/dist/agent/chunks/registry-lkfb_E9O.mjs +53517 -0
  54. package/dist/agent/chunks/siteAdd-BqcYt8nu.mjs +118 -0
  55. package/dist/agent/chunks/sql-wasm-GjJDiefO.mjs +10 -0
  56. package/dist/agent/chunks/sqljs-DjSCStJ0.mjs +20 -0
  57. package/dist/agent/vendor/sql-wasm.cjs +188 -0
  58. package/dist/theme-assets/corporate-menu.js +266 -0
  59. package/dist/theme-assets/corporate-posts.js +571 -0
  60. package/dist/theme-assets/corporate.css +2 -0
  61. package/dist/theme-assets/default-menu.js +266 -0
  62. package/dist/theme-assets/default-posts.js +378 -0
  63. package/dist/theme-assets/default.css +1 -0
  64. package/dist/theme-assets/magazine-menu.js +227 -0
  65. package/dist/theme-assets/magazine-posts.js +361 -0
  66. package/dist/theme-assets/magazine.css +2 -0
  67. package/dist/theme-assets/portfolio-filters.js +104 -0
  68. package/dist/theme-assets/portfolio-menu.js +240 -0
  69. package/dist/theme-assets/portfolio-posts.js +358 -0
  70. package/dist/theme-assets/portfolio.css +2 -0
  71. package/dist/theme-assets/storefront-catalog.js +504 -0
  72. package/dist/theme-assets/storefront-menu.js +239 -0
  73. package/dist/theme-assets/storefront-posts.js +404 -0
  74. package/dist/theme-assets/storefront.css +2 -0
  75. package/dist/version.json +9 -0
  76. package/package.json +101 -4
  77. package/plugin/.claude-plugin/plugin.json +16 -0
  78. package/plugin/skills/agentcms-install/SKILL.md +110 -0
  79. package/plugin/skills/agentcms-install/references/cloudflare.md +15 -0
  80. package/plugin/skills/agentcms-install/references/flexweg.md +11 -0
  81. package/plugin/skills/agentcms-install/references/github.md +67 -0
  82. package/plugin/skills/agentcms-install/references/gitlab.md +15 -0
  83. package/plugin/skills/agentcms-install/references/s3.md +81 -0
  84. package/plugin/skills/agentcms-manage/SKILL.md +92 -0
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Magazine theme — runtime menu loader.
3
+ *
4
+ * Same contract as the default theme's menu-loader. Differences:
5
+ * - The injected logo `<img>` gets Tailwind utility classes
6
+ * (`h-8 w-auto`) so it sizes correctly inside the magazine
7
+ * header's flex layout without needing a theme-specific CSS rule.
8
+ * - The burger overlay uses `[data-cms-menu="header"]` containers
9
+ * and a separate `#burger-menu` overlay, both rendered by
10
+ * templates/BaseLayout.tsx.
11
+ */
12
+ (function () {
13
+ "use strict";
14
+
15
+ // ─── Base path ────────────────────────────────────────────────────
16
+ // Sites served from a sub-folder (e.g. GitHub Pages project sites)
17
+ // carry <meta name="x-cms-base" content="/repo/"> in <head>; no meta
18
+ // means the site lives at the domain root. URLs built at runtime from
19
+ // JSON data go through withBase() so they land under that folder.
20
+ var BASE = (function () {
21
+ var meta = document.querySelector('meta[name="x-cms-base"]');
22
+ var b = (meta && meta.getAttribute("content")) || "/";
23
+ if (b.charAt(0) !== "/") b = "/" + b;
24
+ if (b.charAt(b.length - 1) !== "/") b += "/";
25
+ return b;
26
+ })();
27
+
28
+ function withBase(url) {
29
+ if (BASE === "/" || !url) return url;
30
+ // Absolute URLs (http:, mailto:, data:, …), protocol-relative and
31
+ // fragment-only links pass through.
32
+ if (/^([a-z][a-z0-9+.-]*:|\/\/|#)/i.test(url)) return url;
33
+ if (url.indexOf(BASE) === 0 || url === BASE.slice(0, -1)) return url;
34
+ return BASE + (url.charAt(0) === "/" ? url.slice(1) : url);
35
+ }
36
+
37
+ function fetchMenu() {
38
+ return fetch(withBase("/data/menu.json"), { credentials: "omit" })
39
+ .then(function (res) {
40
+ if (!res.ok) throw new Error("HTTP " + res.status);
41
+ return res.json();
42
+ })
43
+ .catch(function (err) {
44
+ console.warn("[cms] menu.json load failed:", err);
45
+ return null;
46
+ });
47
+ }
48
+
49
+ // Picks the per-language label from item.labels (set by the admin
50
+ // in the menu builder) based on <html lang>, with a region-stripped
51
+ // fallback so "en-US" matches "en". Mono-lingual sites just return
52
+ // item.label.
53
+ function pickLabel(item) {
54
+ var lang = (document.documentElement.getAttribute("lang") || "").trim();
55
+ if (lang && item.labels && typeof item.labels[lang] === "string" && item.labels[lang]) {
56
+ return item.labels[lang];
57
+ }
58
+ if (lang && lang.indexOf("-") > 0) {
59
+ var base = lang.split("-")[0];
60
+ if (item.labels && typeof item.labels[base] === "string" && item.labels[base]) {
61
+ return item.labels[base];
62
+ }
63
+ }
64
+ return item.label || "";
65
+ }
66
+
67
+ function renderItem(item) {
68
+ var li = document.createElement("li");
69
+ var a = document.createElement("a");
70
+ a.href = withBase(item.href) || "#";
71
+ a.textContent = pickLabel(item);
72
+ if (samePath(a.href)) {
73
+ a.setAttribute("aria-current", "page");
74
+ }
75
+ li.appendChild(a);
76
+ if (item.children && item.children.length) {
77
+ var sub = document.createElement("ul");
78
+ sub.className = "menu-children";
79
+ item.children.forEach(function (child) {
80
+ sub.appendChild(renderItem(child));
81
+ });
82
+ li.appendChild(sub);
83
+ }
84
+ return li;
85
+ }
86
+
87
+ function samePath(href) {
88
+ try {
89
+ var url = new URL(href, window.location.origin);
90
+ var here = window.location.pathname.replace(/\/index\.html$/, "/");
91
+ var there = url.pathname.replace(/\/index\.html$/, "/");
92
+ return here === there;
93
+ } catch (e) {
94
+ return false;
95
+ }
96
+ }
97
+
98
+ function paint(menu) {
99
+ if (!menu) return;
100
+ document.querySelectorAll("[data-cms-menu]").forEach(function (host) {
101
+ var key = host.getAttribute("data-cms-menu");
102
+ var items = (menu && menu[key]) || [];
103
+ var list = host.querySelector("ul");
104
+ if (!list) return;
105
+ list.innerHTML = "";
106
+ items.forEach(function (item) {
107
+ list.appendChild(renderItem(item));
108
+ });
109
+ // Hide empty INLINE menu hosts (footer nav) so they don't
110
+ // reserve whitespace. Skip #burger-menu: it's `position: fixed`
111
+ // (no layout impact) AND any `hidden` attribute would `display:
112
+ // none` the panel, which the `.burger-menu.is-open { transform:
113
+ // translate(0) }` rule can never override — the burger toggle
114
+ // would open an invisible panel. Visibility of the burger UI is
115
+ // gated by the burger TOGGLE button below instead.
116
+ var isBurgerMenu = host.id === "burger-menu";
117
+ if (items.length === 0 && !isBurgerMenu) {
118
+ host.setAttribute("hidden", "");
119
+ } else {
120
+ host.removeAttribute("hidden");
121
+ }
122
+ });
123
+ // Hide the burger TOGGLE button when the header menu has no
124
+ // items — otherwise users see a button that opens an empty
125
+ // off-canvas panel and conclude "the burger is broken".
126
+ var headerItems = (menu && menu.header) || [];
127
+ document.querySelectorAll(".burger-toggle").forEach(function (toggle) {
128
+ if (headerItems.length === 0) {
129
+ toggle.setAttribute("hidden", "");
130
+ } else {
131
+ toggle.removeAttribute("hidden");
132
+ }
133
+ });
134
+ paintBranding(menu);
135
+ }
136
+
137
+ // Swap the wordmark for an <img> when the theme has a logo
138
+ // configured. Falls back to the static text in every other case.
139
+ function paintBranding(menu) {
140
+ var branding = menu && menu.branding;
141
+ var logoUrl = branding && branding.logoUrl;
142
+ if (!logoUrl) return;
143
+ document.querySelectorAll("[data-cms-brand]").forEach(function (host) {
144
+ var alt = host.textContent || "";
145
+ var img = document.createElement("img");
146
+ img.src = withBase(logoUrl);
147
+ img.alt = alt;
148
+ // Tailwind utilities — keeps the logo a comfortable height
149
+ // and proportional width without per-theme CSS rules.
150
+ img.className = "h-8 w-auto";
151
+ img.loading = "lazy";
152
+ host.innerHTML = "";
153
+ host.appendChild(img);
154
+ });
155
+ }
156
+
157
+ function ensureCloseButton(menu) {
158
+ if (menu.querySelector(".burger-close")) return menu.querySelector(".burger-close");
159
+ var close = document.createElement("button");
160
+ close.type = "button";
161
+ close.className = "burger-close";
162
+ close.setAttribute("aria-label", "Close menu");
163
+ close.innerHTML =
164
+ '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>';
165
+ menu.insertBefore(close, menu.firstChild);
166
+ return close;
167
+ }
168
+
169
+ function ensureBackdrop() {
170
+ var existing = document.querySelector(".burger-backdrop");
171
+ if (existing) return existing;
172
+ var backdrop = document.createElement("div");
173
+ backdrop.className = "burger-backdrop";
174
+ backdrop.setAttribute("aria-hidden", "true");
175
+ document.body.appendChild(backdrop);
176
+ return backdrop;
177
+ }
178
+
179
+ function wireBurger() {
180
+ var toggle = document.querySelector(".burger-toggle");
181
+ var menu = document.getElementById("burger-menu");
182
+ if (!toggle || !menu) return;
183
+
184
+ var close = ensureCloseButton(menu);
185
+ var backdrop = ensureBackdrop();
186
+
187
+ function setOpen(open) {
188
+ toggle.setAttribute("aria-expanded", open ? "true" : "false");
189
+ menu.classList.toggle("is-open", open);
190
+ backdrop.classList.toggle("is-open", open);
191
+ document.body.classList.toggle("burger-open", open);
192
+ }
193
+
194
+ toggle.addEventListener("click", function () {
195
+ var isOpen = toggle.getAttribute("aria-expanded") === "true";
196
+ setOpen(!isOpen);
197
+ });
198
+ close.addEventListener("click", function () {
199
+ setOpen(false);
200
+ });
201
+ backdrop.addEventListener("click", function () {
202
+ setOpen(false);
203
+ });
204
+ document.addEventListener("keydown", function (e) {
205
+ if (e.key === "Escape") setOpen(false);
206
+ });
207
+ menu.addEventListener("click", function (e) {
208
+ if (e.target.tagName === "A") setOpen(false);
209
+ });
210
+ document.addEventListener("pointerdown", function (e) {
211
+ if (toggle.getAttribute("aria-expanded") !== "true") return;
212
+ if (menu.contains(e.target)) return;
213
+ if (toggle.contains(e.target)) return;
214
+ setOpen(false);
215
+ });
216
+ }
217
+
218
+ function ready(fn) {
219
+ if (document.readyState !== "loading") fn();
220
+ else document.addEventListener("DOMContentLoaded", fn);
221
+ }
222
+
223
+ ready(function () {
224
+ wireBurger();
225
+ fetchMenu().then(paint);
226
+ });
227
+ })();
@@ -0,0 +1,361 @@
1
+ /**
2
+ * Magazine theme — runtime sidebar loader.
3
+ *
4
+ * Populates `[data-cms-related]` and `[data-cms-author-bio]` hosts
5
+ * from `/data/posts.json` and `/data/authors.json` respectively. Same
6
+ * lifecycle as default's posts-loader: fetched once on
7
+ * DOMContentLoaded, paint passes are independent and tolerate each
8
+ * other's failure.
9
+ *
10
+ * The injected DOM uses magazine-specific class names
11
+ * (`magazine-related-*`, `magazine-bio-*`) — matching CSS rules live
12
+ * in `theme.css` under `@layer components`. The author-bio host
13
+ * provides its own card chrome (background / border / padding /
14
+ * radius) via Tailwind utilities in `SingleTemplate.tsx`; the
15
+ * related host carries no chrome (just a section heading + bordered
16
+ * list).
17
+ *
18
+ * Failure is silent: missing data leaves the host hidden (related)
19
+ * or untouched (author-bio's host stays `hidden` from publish time).
20
+ */
21
+ (function () {
22
+ "use strict";
23
+
24
+ // ─── Base path ────────────────────────────────────────────────────
25
+ // Sites served from a sub-folder (e.g. GitHub Pages project sites)
26
+ // carry <meta name="x-cms-base" content="/repo/"> in <head>; no meta
27
+ // means the site lives at the domain root. URLs built at runtime from
28
+ // JSON data go through withBase() so they land under that folder.
29
+ var BASE = (function () {
30
+ var meta = document.querySelector('meta[name="x-cms-base"]');
31
+ var b = (meta && meta.getAttribute("content")) || "/";
32
+ if (b.charAt(0) !== "/") b = "/" + b;
33
+ if (b.charAt(b.length - 1) !== "/") b += "/";
34
+ return b;
35
+ })();
36
+
37
+ function withBase(url) {
38
+ if (BASE === "/" || !url) return url;
39
+ // Absolute URLs (http:, mailto:, data:, …), protocol-relative and
40
+ // fragment-only links pass through.
41
+ if (/^([a-z][a-z0-9+.-]*:|\/\/|#)/i.test(url)) return url;
42
+ if (url.indexOf(BASE) === 0 || url === BASE.slice(0, -1)) return url;
43
+ return BASE + (url.charAt(0) === "/" ? url.slice(1) : url);
44
+ }
45
+
46
+ // "/repo/fr/x.html" → "/fr/x.html" so path parsing ignores the base.
47
+ function stripBase(pathname) {
48
+ if (BASE === "/") return pathname;
49
+ if (pathname.indexOf(BASE) === 0) return "/" + pathname.slice(BASE.length);
50
+ if (pathname === BASE.slice(0, -1)) return "/";
51
+ return pathname;
52
+ }
53
+
54
+ // ─── Social icons ─────────────────────────────────────────────────
55
+ // Brand SVG paths + display labels for the curated SocialNetwork
56
+ // list. Mirror in core/socialIcons.tsx (and each other theme's
57
+ // posts-loader.js) when adding a network.
58
+ var SOCIAL_ICON_PATHS = {
59
+ twitter: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z",
60
+ linkedin: "M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z",
61
+ instagram: "M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z",
62
+ mastodon: "M23.193 7.88c0-5.207-3.411-6.733-3.411-6.733C18.062.357 15.108.025 12.041 0h-.076c-3.068.025-6.02.357-7.74 1.147 0 0-3.412 1.526-3.412 6.733 0 1.193-.023 2.619.015 4.13.124 5.092.934 10.11 5.641 11.355 2.17.574 4.034.695 5.535.612 2.722-.151 4.25-.972 4.25-.972l-.09-1.975s-1.945.613-4.129.539c-2.165-.074-4.449-.233-4.799-2.891a5.499 5.499 0 0 1-.048-.745s2.125.52 4.817.643c1.646.075 3.19-.097 4.758-.283 3.007-.359 5.625-2.212 5.954-3.905.52-2.667.477-6.508.477-6.508zm-4.024 6.709h-2.497V8.469c0-1.29-.543-1.944-1.628-1.944-1.2 0-1.802.776-1.802 2.312v3.349h-2.484v-3.35c0-1.536-.601-2.312-1.802-2.312-1.085 0-1.628.655-1.628 1.945v6.119H4.831V8.285c0-1.29.328-2.313.987-3.07.68-.756 1.57-1.144 2.674-1.144 1.278 0 2.246.491 2.886 1.474L12 6.585l.622-1.04c.64-.983 1.608-1.474 2.886-1.474 1.104 0 1.994.388 2.674 1.144.658.757.986 1.78.986 3.07v6.304z",
63
+ bluesky: "M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.137-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.952 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z",
64
+ github: "M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12",
65
+ website: "M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm6.93 6h-2.95a15.65 15.65 0 0 0-1.38-3.56A8.03 8.03 0 0 1 18.92 8zM12 4.04c.83 1.2 1.48 2.53 1.91 3.96h-3.82c.43-1.43 1.08-2.76 1.91-3.96zM4.26 14C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2 0 .68.06 1.34.14 2H4.26zm.82 2h2.95c.32 1.25.78 2.45 1.38 3.56A7.987 7.987 0 0 1 5.08 16zm2.95-8H5.08a7.987 7.987 0 0 1 4.33-3.56A15.65 15.65 0 0 0 8.03 8zM12 19.96c-.83-1.2-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.76-1.91 3.96zM14.34 14H9.66c-.09-.66-.16-1.32-.16-2 0-.68.07-1.35.16-2h4.68c.09.65.16 1.32.16 2 0 .68-.07 1.34-.16 2zm.25 5.56c.6-1.11 1.06-2.31 1.38-3.56h2.95a8.03 8.03 0 0 1-4.33 3.56zM16.36 14c.08-.66.14-1.32.14-2 0-.68-.06-1.34-.14-2h3.38c.16.64.26 1.31.26 2s-.1 1.36-.26 2h-3.38z",
66
+ };
67
+ var SOCIAL_ICON_LABELS = {
68
+ twitter: "Twitter / X",
69
+ linkedin: "LinkedIn",
70
+ instagram: "Instagram",
71
+ mastodon: "Mastodon",
72
+ bluesky: "Bluesky",
73
+ github: "GitHub",
74
+ website: "Website",
75
+ };
76
+ function socialIconSvg(network) {
77
+ var path = SOCIAL_ICON_PATHS[network];
78
+ if (!path) return "";
79
+ return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="currentColor" aria-hidden="true"><path d="' + path + '"/></svg>';
80
+ }
81
+ function socialIconLabel(network) {
82
+ return SOCIAL_ICON_LABELS[network] || network;
83
+ }
84
+
85
+ function fetchJson(path) {
86
+ return fetch(withBase(path), { credentials: "omit" })
87
+ .then(function (res) {
88
+ if (!res.ok) throw new Error("HTTP " + res.status);
89
+ return res.json();
90
+ })
91
+ .catch(function (err) {
92
+ console.warn("[cms] " + path + " load failed:", err);
93
+ return null;
94
+ });
95
+ }
96
+
97
+ // ─── Related posts ────────────────────────────────────────────────
98
+ //
99
+ // DOM emitted (matches the editorial mockup — small-caps section
100
+ // heading + flex-column list with top-bordered items):
101
+ //
102
+ // <h4 class="magazine-related-heading">Latest from {{site}}</h4>
103
+ // <div class="magazine-related-list">
104
+ // <a class="magazine-related-link group" href="/...">
105
+ // <span class="magazine-related-eyebrow">Category</span>
106
+ // <h5 class="magazine-related-title">Title</h5>
107
+ // <time class="magazine-related-date">Nov 12, 2024</time>
108
+ // </a>
109
+ // ...
110
+ // </div>
111
+
112
+ function renderRelatedItem(entry) {
113
+ var a = document.createElement("a");
114
+ a.href = withBase("/" + entry.url);
115
+ a.className = "magazine-related-link";
116
+ if (entry.category && entry.category.name) {
117
+ var eyebrow = document.createElement("span");
118
+ eyebrow.className = "magazine-related-eyebrow";
119
+ eyebrow.textContent = entry.category.name;
120
+ a.appendChild(eyebrow);
121
+ }
122
+ var title = document.createElement("h5");
123
+ title.className = "magazine-related-title";
124
+ title.textContent = entry.title || "";
125
+ a.appendChild(title);
126
+ if (entry.dateLabel) {
127
+ var date = document.createElement("time");
128
+ date.className = "magazine-related-date";
129
+ date.textContent = entry.dateLabel;
130
+ a.appendChild(date);
131
+ }
132
+ return a;
133
+ }
134
+
135
+ function renderRelated(host, posts) {
136
+ var termId = host.getAttribute("data-cms-term-id") || "";
137
+ var currentId = host.getAttribute("data-cms-current-id") || "";
138
+ var limit = parseInt(host.getAttribute("data-cms-limit") || "3", 10);
139
+ var label = host.getAttribute("data-cms-label") || "Continue reading";
140
+ var fallbackLabel =
141
+ host.getAttribute("data-cms-fallback-label") || "Latest articles";
142
+
143
+ var matching = [];
144
+ var heading = label;
145
+
146
+ if (termId) {
147
+ for (var i = 0; i < posts.length && matching.length < limit; i++) {
148
+ var p = posts[i];
149
+ if (p.id === currentId) continue;
150
+ if (p.type !== "post") continue;
151
+ if (p.primaryTermId !== termId) continue;
152
+ matching.push(p);
153
+ }
154
+ }
155
+
156
+ if (matching.length === 0) {
157
+ heading = fallbackLabel;
158
+ for (var j = 0; j < posts.length && matching.length < limit; j++) {
159
+ var pp = posts[j];
160
+ if (pp.id === currentId) continue;
161
+ if (pp.type !== "post") continue;
162
+ matching.push(pp);
163
+ }
164
+ }
165
+
166
+ if (matching.length === 0) {
167
+ host.setAttribute("hidden", "");
168
+ return;
169
+ }
170
+
171
+ host.removeAttribute("hidden");
172
+ host.innerHTML = "";
173
+ var headingEl = document.createElement("h4");
174
+ headingEl.className = "magazine-related-heading";
175
+ headingEl.textContent = heading;
176
+ host.appendChild(headingEl);
177
+ var list = document.createElement("div");
178
+ list.className = "magazine-related-list";
179
+ matching.forEach(function (entry) {
180
+ list.appendChild(renderRelatedItem(entry));
181
+ });
182
+ host.appendChild(list);
183
+ }
184
+
185
+ // ─── Author bio ───────────────────────────────────────────────────
186
+ //
187
+ // DOM emitted (matches the mockup — square rounded avatar, name in
188
+ // serif headline, role-style eyebrow underneath, bio paragraph,
189
+ // optional mailto icon link):
190
+ //
191
+ // <div class="magazine-bio-head">
192
+ // <div class="magazine-bio-avatar-wrap">
193
+ // <img class="magazine-bio-avatar-img" />
194
+ // OR <span class="magazine-bio-avatar-initials">JV</span>
195
+ // </div>
196
+ // <div class="magazine-bio-name-wrap">
197
+ // <h4 class="magazine-bio-name">…</h4>
198
+ // <p class="magazine-bio-role">…</p>
199
+ // </div>
200
+ // </div>
201
+ // <p class="magazine-bio-text">…</p>
202
+ // <div class="magazine-bio-socials">
203
+ // <a href="mailto:…" class="magazine-bio-social-link">
204
+ // <span class="material-symbols-outlined">alternate_email</span>
205
+ // </a>
206
+ // </div>
207
+
208
+ function authorInitials(name) {
209
+ if (!name) return "?";
210
+ var parts = name.trim().split(/\s+/);
211
+ if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
212
+ var first = parts[0][0] || "";
213
+ var last = parts[parts.length - 1][0] || "";
214
+ return (first + last).toUpperCase();
215
+ }
216
+
217
+ function authorAvatar(name, url) {
218
+ var wrap = document.createElement("div");
219
+ wrap.className = "magazine-bio-avatar-wrap";
220
+ if (url) {
221
+ var img = document.createElement("img");
222
+ img.className = "magazine-bio-avatar-img";
223
+ img.src = withBase(url);
224
+ img.alt = name || "";
225
+ img.loading = "lazy";
226
+ wrap.appendChild(img);
227
+ } else {
228
+ var span = document.createElement("span");
229
+ span.className = "magazine-bio-avatar-initials";
230
+ span.setAttribute("aria-hidden", "true");
231
+ span.textContent = authorInitials(name);
232
+ wrap.appendChild(span);
233
+ }
234
+ return wrap;
235
+ }
236
+
237
+ function renderAuthorBio(host, authors) {
238
+ var authorId = host.getAttribute("data-cms-author-id") || "";
239
+ if (!authorId) return;
240
+ var entry = authors[authorId];
241
+ if (!entry) return;
242
+
243
+ host.innerHTML = "";
244
+
245
+ // Header row — avatar + name + role-style eyebrow.
246
+ var head = document.createElement("div");
247
+ head.className = "magazine-bio-head";
248
+ head.appendChild(authorAvatar(entry.displayName, entry.avatar));
249
+
250
+ var nameWrap = document.createElement("div");
251
+ nameWrap.className = "magazine-bio-name-wrap";
252
+
253
+ // Author name — clickable when /authors.json carries a profile URL,
254
+ // otherwise a plain <h4>. Mirrors the default theme's behavior so
255
+ // archive links keep working transparently.
256
+ var nameEl;
257
+ if (entry.url) {
258
+ nameEl = document.createElement("a");
259
+ nameEl.href = withBase("/" + entry.url);
260
+ } else {
261
+ nameEl = document.createElement("h4");
262
+ }
263
+ nameEl.className = "magazine-bio-name";
264
+ nameEl.textContent = entry.displayName || "";
265
+ nameWrap.appendChild(nameEl);
266
+
267
+ // Title (e.g. "Journaliste") sits under the name as a label-caps
268
+ // role line. Replaces the legacy email-as-role line — email is
269
+ // admin-only data and never reaches the public site.
270
+ if (entry.title) {
271
+ var role = document.createElement("p");
272
+ role.className = "magazine-bio-role";
273
+ role.textContent = entry.title;
274
+ nameWrap.appendChild(role);
275
+ }
276
+ head.appendChild(nameWrap);
277
+ host.appendChild(head);
278
+
279
+ if (entry.bio) {
280
+ var bio = document.createElement("p");
281
+ bio.className = "magazine-bio-text";
282
+ bio.textContent = entry.bio;
283
+ host.appendChild(bio);
284
+ }
285
+
286
+ // Visible socials — already filtered server-side. Each entry
287
+ // produces an icon link to the user's external profile, opened in
288
+ // a new tab with rel=noopener noreferrer.
289
+ if (entry.socials && entry.socials.length) {
290
+ var socials = document.createElement("div");
291
+ socials.className = "magazine-bio-socials";
292
+ for (var i = 0; i < entry.socials.length; i++) {
293
+ var s = entry.socials[i];
294
+ var a = document.createElement("a");
295
+ a.className = "magazine-bio-social-link";
296
+ a.href = s.url;
297
+ a.target = "_blank";
298
+ a.rel = "noopener noreferrer";
299
+ a.setAttribute("aria-label", socialIconLabel(s.network));
300
+ a.title = socialIconLabel(s.network);
301
+ a.innerHTML = socialIconSvg(s.network);
302
+ socials.appendChild(a);
303
+ }
304
+ host.appendChild(socials);
305
+ }
306
+
307
+ host.removeAttribute("hidden");
308
+ }
309
+
310
+ // ─── Paint passes ─────────────────────────────────────────────────
311
+
312
+ function paintRelated(postsBlob) {
313
+ if (!postsBlob || !Array.isArray(postsBlob.posts)) return;
314
+ document.querySelectorAll("[data-cms-related]").forEach(function (host) {
315
+ renderRelated(host, postsBlob.posts);
316
+ });
317
+ }
318
+
319
+ function paintAuthorBios(authorsBlob) {
320
+ if (!authorsBlob || !authorsBlob.authors) return;
321
+ document.querySelectorAll("[data-cms-author-bio]").forEach(function (host) {
322
+ renderAuthorBio(host, authorsBlob.authors);
323
+ });
324
+ }
325
+
326
+ function ready(fn) {
327
+ if (document.readyState !== "loading") fn();
328
+ else document.addEventListener("DOMContentLoaded", fn);
329
+ }
330
+
331
+ // Multi-language helper — when the page lives under `/<lang>/...`,
332
+ // fetch the localised data file first and fall back to the root on
333
+ // 404. The multilang plugin generates `<lang>/data/posts.json` per
334
+ // enabled language so sidebar widgets reflect translations on
335
+ // non-primary pages. Sites without multilang stay on the root file.
336
+ function detectLocalePrefix() {
337
+ var path = stripBase(window.location.pathname).replace(/^\/+/, "");
338
+ var first = path.split("/")[0];
339
+ if (!first) return null;
340
+ if (/^[a-z]{2}(-[a-z]{2})?$/.test(first.toLowerCase())) return first.toLowerCase();
341
+ return null;
342
+ }
343
+ function fetchWithLocaleFallback(filename) {
344
+ var locale = detectLocalePrefix();
345
+ if (!locale) return fetchJson("/data/" + filename);
346
+ return fetchJson("/" + locale + "/data/" + filename).then(function (data) {
347
+ if (data) return data;
348
+ return fetchJson("/data/" + filename);
349
+ });
350
+ }
351
+
352
+ ready(function () {
353
+ Promise.all([
354
+ fetchWithLocaleFallback("posts.json"),
355
+ fetchWithLocaleFallback("authors.json"),
356
+ ]).then(function (results) {
357
+ paintRelated(results[0]);
358
+ paintAuthorBios(results[1]);
359
+ });
360
+ });
361
+ })();
@@ -0,0 +1,2 @@
1
+ @import url("https://fonts.googleapis.com/css2?family=Newsreader:ital,wght@0,400;0,500;0,600;0,700;0,800;1,400&family=Work+Sans:wght@400;500;600;700&display=swap");@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0&display=swap");*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }
2
+ /*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--font-sans),Work Sans,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--color-primary:0 0 0;--color-on-primary:255 255 255;--color-primary-container:28 27 27;--color-on-primary-container:133 131 131;--color-secondary:67 97 124;--color-background:248 249 250;--color-surface:248 249 250;--color-surface-container-low:243 244 245;--color-surface-container:237 238 239;--color-surface-container-high:231 232 233;--color-on-surface:25 28 29;--color-on-surface-variant:68 71 72;--color-outline:116 120 120;--color-outline-variant:196 199 199;--font-serif:"Newsreader";--font-sans:"Work Sans"}body{background-color:rgb(var(--color-background));color:rgb(var(--color-on-surface));font-family:var(--font-sans),system-ui,sans-serif}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.drop-cap:first-letter,.magazine-prose-drop-cap>p:first-of-type:first-letter{float:left;font-family:var(--font-serif),Georgia,serif;font-size:5rem;line-height:.8;padding-top:.25rem;padding-right:.75rem;font-weight:800}.magazine-prose{font-size:1.125rem;line-height:1.7;color:rgb(var(--color-on-surface))}.magazine-prose>p{margin-bottom:1.5rem}.magazine-prose>h2{font-size:1.75rem;line-height:1.3;color:rgb(var(--color-primary));margin-top:2rem;margin-bottom:1rem}.magazine-prose>h2,.magazine-prose>h3{font-family:var(--font-serif),Georgia,serif;font-weight:500}.magazine-prose>h3{font-size:1.375rem;line-height:1.4;margin-top:1.5rem;margin-bottom:.75rem}.magazine-prose>blockquote{margin:2rem 0;border-left:4px solid rgb(var(--color-secondary));padding-left:2rem;font-style:italic;font-family:var(--font-serif),Georgia,serif;font-size:1.5rem;line-height:1.4;color:rgb(var(--color-primary))}.magazine-prose>ol,.magazine-prose>ul{padding-left:1.5rem;margin-bottom:1.5rem}.magazine-prose>ul{list-style-type:disc}.magazine-prose>ol{list-style-type:decimal}.magazine-prose>ol>li,.magazine-prose>ul>li{margin-bottom:.5rem}.magazine-prose figure img,.magazine-prose img{border-radius:.5rem;margin:1.5rem 0}.magazine-prose a{color:rgb(var(--color-secondary));text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px}.burger-toggle{background:transparent;border:0;cursor:pointer;padding:.25rem;line-height:0}.burger-menu{position:fixed;top:0;left:0;height:100vh;width:min(360px,80vw);background:rgb(var(--color-background));border-right:1px solid rgb(var(--color-outline-variant));transform:translateX(-100%);transition:transform .25s ease;z-index:60;padding:4rem 1.5rem 1.5rem;overflow-y:auto}.burger-menu.is-open{transform:translateX(0)}.burger-menu ul{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:.5rem}.burger-menu a{display:block;padding:.5rem 0;color:rgb(var(--color-on-surface));font-family:var(--font-serif),Georgia,serif;font-size:1.5rem;text-decoration:none}.burger-menu a:hover{color:rgb(var(--color-secondary))}.burger-menu a[aria-current=page]{color:rgb(var(--color-primary));font-weight:600}.burger-menu .menu-children{margin-left:1rem;margin-top:.25rem}.burger-menu .menu-children a{font-size:1rem}.burger-close{position:absolute;top:1rem;right:1rem;background:transparent;border:0;color:rgb(var(--color-on-surface));cursor:pointer;padding:.5rem}.burger-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.4);opacity:0;pointer-events:none;transition:opacity .25s ease;z-index:55}.burger-backdrop.is-open{opacity:1;pointer-events:auto}body.burger-open{overflow:hidden}.magazine-bio-head{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.magazine-bio-avatar-wrap{width:4rem;height:4rem;flex-shrink:0;border-radius:.5rem;overflow:hidden;background:rgb(var(--color-surface-container-high));display:flex;align-items:center;justify-content:center}.magazine-bio-avatar-img{width:100%;height:100%;-o-object-fit:cover;object-fit:cover;display:block}.magazine-bio-avatar-initials{font-family:var(--font-sans),system-ui,sans-serif;font-weight:600;font-size:1rem;color:rgb(var(--color-on-surface));letter-spacing:.02em}.magazine-bio-name-wrap{min-width:0;padding-top:.125rem}.magazine-bio-name{font-family:var(--font-serif),Georgia,serif;font-size:1.125rem;font-weight:600;line-height:1.2;color:rgb(var(--color-primary));text-decoration:none;margin:0;display:block}.magazine-bio-role,a.magazine-bio-name:hover{color:rgb(var(--color-secondary))}.magazine-bio-role{font-family:var(--font-sans),system-ui,sans-serif;font-size:.625rem;font-weight:600;text-transform:uppercase;letter-spacing:.1em;margin:.25rem 0 0}.magazine-bio-text{font-size:.875rem;line-height:1.6;color:rgb(var(--color-on-surface-variant));margin:0 0 1rem}.magazine-bio-socials{display:flex;gap:.75rem}.magazine-bio-social-link{color:rgb(var(--color-on-surface-variant));line-height:0;transition:color .15s ease}.magazine-bio-social-link:hover{color:rgb(var(--color-primary))}.magazine-bio-social-link svg{width:18px;height:18px;display:block}.magazine-related-heading{font-family:var(--font-sans),system-ui,sans-serif;font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.2em;color:rgb(var(--color-on-surface-variant));margin:0 0 1.5rem}.magazine-related-list{display:flex;flex-direction:column}.magazine-related-link{display:block;padding:1.25rem 0;border-top:1px solid rgb(var(--color-outline-variant));text-decoration:none;color:inherit}.magazine-related-link:first-child{border-top:0;padding-top:0}.magazine-related-eyebrow,.magazine-related-link:hover .magazine-related-title{color:rgb(var(--color-secondary))}.magazine-related-eyebrow{display:block;font-family:var(--font-sans),system-ui,sans-serif;font-size:.625rem;font-weight:600;text-transform:uppercase;letter-spacing:.1em;margin-bottom:.5rem}.magazine-related-title{font-family:var(--font-serif),Georgia,serif;font-size:1rem;font-weight:500;line-height:1.3;color:rgb(var(--color-on-surface));margin:0;transition:color .15s ease}.magazine-related-date{display:block;font-family:var(--font-sans),system-ui,sans-serif;font-size:.6875rem;color:rgb(var(--color-on-surface-variant));margin-top:.5rem}.material-symbols-outlined{font-family:Material Symbols Outlined,sans-serif;font-weight:400;font-style:normal;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:"liga";font-variation-settings:"FILL" 0,"wght" 400,"GRAD" 0,"opsz" 24}.archives{max-width:1280px;margin:0 auto;padding:80px 24px}.archives__header{margin-bottom:2.5rem}.archives__back{margin:0 0 .75rem;font-family:var(--font-sans),system-ui,sans-serif;font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.1em}.archives__back a{color:rgb(var(--color-on-surface-variant));text-decoration:none}.archives__back a:hover{color:rgb(var(--color-secondary))}.archives__title{font-family:var(--font-serif),Georgia,serif;font-weight:600;font-size:clamp(2rem,5vw,3.75rem);line-height:1.05;margin:0 0 .5rem;color:rgb(var(--color-primary));letter-spacing:-.02em}.archives__subtitle{margin:0;font-size:1.125rem}.archives__empty,.archives__subtitle{color:rgb(var(--color-on-surface-variant))}.archives__empty{font-style:italic}.archives__years{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}.archives__year{border-top:1px solid rgb(var(--color-outline-variant));padding:1.5rem 0}.archives__year:first-child{border-top:0;padding-top:0}.archives__year-heading{font-family:var(--font-serif),Georgia,serif;font-weight:500;font-size:1.75rem;line-height:1.3;margin:0 0 .75rem;display:flex;align-items:baseline;gap:.5rem;color:rgb(var(--color-on-surface))}.archives__drilldown-link,.archives__group-link,.archives__item-link,.archives__year-link{color:rgb(var(--color-on-surface));text-decoration:none;border-bottom:1px solid transparent;transition:border-color .15s ease,color .15s ease}.archives__drilldown-link:hover,.archives__group-link:hover,.archives__item-link:hover,.archives__year-link:hover{color:rgb(var(--color-secondary));border-bottom-color:currentColor}.archives__count{color:rgb(var(--color-on-surface-variant));font-family:var(--font-sans),system-ui,sans-serif;font-size:.875rem;font-weight:400}.archives__drilldown{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.5rem 1.5rem}.archives__drilldown-item{display:inline-flex;align-items:baseline;gap:.35rem;font-family:var(--font-sans),system-ui,sans-serif;font-size:.95rem}.archives__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}.archives__item{display:flex;align-items:baseline;justify-content:space-between;gap:1.5rem;padding:.75rem 0;border-bottom:1px solid rgb(var(--color-outline-variant))}.archives__item:last-child{border-bottom:0}.archives__item-link{flex:1;font-family:var(--font-serif),Georgia,serif;font-size:1.0625rem;line-height:1.4}.archives__item-date{color:rgb(var(--color-on-surface-variant));font-family:var(--font-sans),system-ui,sans-serif;font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;white-space:nowrap}.archives__groups{display:flex;flex-direction:column;gap:2.5rem}.archives__group-heading{font-family:var(--font-serif),Georgia,serif;font-weight:500;font-size:1.25rem;margin:0 0 .75rem;display:flex;align-items:baseline;gap:.5rem;color:rgb(var(--color-on-surface))}.archives-link{margin:3rem 0 0;text-align:right;font-family:var(--font-sans),system-ui,sans-serif;font-size:.95rem}.archives-link a{color:rgb(var(--color-secondary));text-decoration:none;border-bottom:1px solid;padding-bottom:.1rem}.archives-link a:hover{color:rgb(var(--color-on-surface))}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.left-0{left:0}.left-1\/2{left:50%}.left-4{left:1rem}.right-0{right:0}.top-0{top:0}.top-28{top:7rem}.top-4{top:1rem}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.mx-auto{margin-left:auto;margin-right:auto}.my-4{margin-top:1rem;margin-bottom:1rem}.-mb-px{margin-bottom:-1px}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-stack-lg{margin-bottom:48px}.mb-stack-md{margin-bottom:24px}.mb-stack-sm{margin-bottom:8px}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-section-gap{margin-top:80px}.mt-stack-lg{margin-top:48px}.mt-stack-md{margin-top:24px}.mt-stack-sm{margin-top:8px}.line-clamp-2{-webkit-line-clamp:2}.line-clamp-2,.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical}.line-clamp-3{-webkit-line-clamp:3}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.aspect-\[16\/9\]{aspect-ratio:16/9}.aspect-\[4\/3\]{aspect-ratio:4/3}.aspect-square{aspect-ratio:1/1}.aspect-video{aspect-ratio:16/9}.h-20{height:5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-8{height:2rem}.h-full{height:100%}.min-h-\[60vh\]{min-height:60vh}.w-12{width:3rem}.w-24{width:6rem}.w-3{width:.75rem}.w-4{width:1rem}.w-40{width:10rem}.w-5{width:1.25rem}.w-8{width:2rem}.w-auto{width:auto}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-\[240px\]{max-width:240px}.max-w-container-max{max-width:1280px}.max-w-none{max-width:none}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-gutter{gap:24px}.gap-stack-lg{gap:48px}.gap-stack-md{gap:24px}.gap-stack-sm{gap:8px}.-space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(-.25rem*var(--tw-space-x-reverse));margin-left:calc(-.25rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.space-y-section-gap>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(80px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(80px*var(--tw-space-y-reverse))}.space-y-stack-lg>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(48px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(48px*var(--tw-space-y-reverse))}.space-y-stack-md>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(24px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(24px*var(--tw-space-y-reverse))}.space-y-stack-sm>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(8px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(8px*var(--tw-space-y-reverse))}.overflow-hidden,.truncate{overflow:hidden}.truncate{text-overflow:ellipsis;white-space:nowrap}.rounded{border-radius:.125rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.25rem}.border{border-width:1px}.border-y{border-top-width:1px}.border-b,.border-y{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-4{border-left-width:4px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-blue-600{--tw-border-opacity:1;border-color:rgb(37 99 235/var(--tw-border-opacity,1))}.border-on-surface{--tw-border-opacity:1;border-color:rgb(var(--color-on-surface)/var(--tw-border-opacity,1))}.border-outline-variant{--tw-border-opacity:1;border-color:rgb(var(--color-outline-variant)/var(--tw-border-opacity,1))}.border-primary{--tw-border-opacity:1;border-color:rgb(var(--color-primary)/var(--tw-border-opacity,1))}.border-transparent{border-color:transparent}.bg-background{--tw-bg-opacity:1;background-color:rgb(var(--color-background)/var(--tw-bg-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-outline-variant{--tw-bg-opacity:1;background-color:rgb(var(--color-outline-variant)/var(--tw-bg-opacity,1))}.bg-primary{--tw-bg-opacity:1;background-color:rgb(var(--color-primary)/var(--tw-bg-opacity,1))}.bg-surface{--tw-bg-opacity:1;background-color:rgb(var(--color-surface)/var(--tw-bg-opacity,1))}.bg-surface-container{--tw-bg-opacity:1;background-color:rgb(var(--color-surface-container)/var(--tw-bg-opacity,1))}.bg-surface-container-high{--tw-bg-opacity:1;background-color:rgb(var(--color-surface-container-high)/var(--tw-bg-opacity,1))}.bg-surface-container-low{--tw-bg-opacity:1;background-color:rgb(var(--color-surface-container-low)/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.from-primary\/80{--tw-gradient-from:rgb(var(--color-primary)/0.8) var(--tw-gradient-from-position);--tw-gradient-to:rgb(var(--color-primary)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.via-primary\/40{--tw-gradient-to:rgb(var(--color-primary)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),rgb(var(--color-primary)/0.4) var(--tw-gradient-via-position),var(--tw-gradient-to)}.to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-stack-md{padding:24px}.px-3{padding-left:.75rem;padding-right:.75rem}.px-margin-mobile{padding-left:16px;padding-right:16px}.px-stack-lg{padding-left:48px;padding-right:48px}.px-stack-md{padding-left:24px;padding-right:24px}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-stack-lg{padding-top:48px;padding-bottom:48px}.py-stack-md{padding-top:24px;padding-bottom:24px}.py-stack-sm{padding-top:8px;padding-bottom:8px}.pb-2{padding-bottom:.5rem}.pb-section-gap{padding-bottom:80px}.pb-stack-sm{padding-bottom:8px}.pl-stack-md{padding-left:24px}.pt-24{padding-top:6rem}.pt-stack-lg{padding-top:48px}.pt-stack-md{padding-top:24px}.pt-stack-sm{padding-top:8px}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:var(--font-sans),Work Sans,system-ui,sans-serif}.font-serif{font-family:var(--font-serif),Newsreader,Georgia,serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-6xl{font-size:3.75rem;line-height:1}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-light{font-weight:300}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-\[1\.05\]{line-height:1.05}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-on-primary{--tw-text-opacity:1;color:rgb(var(--color-on-primary)/var(--tw-text-opacity,1))}.text-on-primary\/70{color:rgb(var(--color-on-primary)/.7)}.text-on-surface{--tw-text-opacity:1;color:rgb(var(--color-on-surface)/var(--tw-text-opacity,1))}.text-on-surface-variant{--tw-text-opacity:1;color:rgb(var(--color-on-surface-variant)/var(--tw-text-opacity,1))}.text-outline-variant{--tw-text-opacity:1;color:rgb(var(--color-outline-variant)/var(--tw-text-opacity,1))}.text-primary{--tw-text-opacity:1;color:rgb(var(--color-primary)/var(--tw-text-opacity,1))}.text-secondary{--tw-text-opacity:1;color:rgb(var(--color-secondary)/var(--tw-text-opacity,1))}.decoration-1{text-decoration-thickness:1px}.outline{outline-style:solid}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-1,.ring-2{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-2{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-blue-500\/60{--tw-ring-color:rgba(59,130,246,.6)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-500{transition-duration:.5s}.duration-700{transition-duration:.7s}.hover\:bg-on-surface:hover{--tw-bg-opacity:1;background-color:rgb(var(--color-on-surface)/var(--tw-bg-opacity,1))}.hover\:bg-surface-container-low:hover{--tw-bg-opacity:1;background-color:rgb(var(--color-surface-container-low)/var(--tw-bg-opacity,1))}.hover\:text-on-primary:hover{--tw-text-opacity:1;color:rgb(var(--color-on-primary)/var(--tw-text-opacity,1))}.hover\:text-on-surface:hover{--tw-text-opacity:1;color:rgb(var(--color-on-surface)/var(--tw-text-opacity,1))}.hover\:text-on-surface-variant:hover{--tw-text-opacity:1;color:rgb(var(--color-on-surface-variant)/var(--tw-text-opacity,1))}.hover\:text-primary:hover{--tw-text-opacity:1;color:rgb(var(--color-primary)/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.group:hover .group-hover\:scale-105{--tw-scale-x:1.05;--tw-scale-y:1.05;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-secondary{--tw-text-opacity:1;color:rgb(var(--color-secondary)/var(--tw-text-opacity,1))}.group:hover .group-hover\:underline{text-decoration-line:underline}@media (min-width:640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width:768px){.md\:order-1{order:1}.md\:order-2{order:2}.md\:col-span-2{grid-column:span 2/span 2}.md\:col-span-4{grid-column:span 4/span 4}.md\:col-span-8{grid-column:span 8/span 8}.md\:flex{display:flex}.md\:aspect-\[21\/9\]{aspect-ratio:21/9}.md\:aspect-\[4\/3\]{aspect-ratio:4/3}.md\:aspect-square{aspect-ratio:1/1}.md\:h-32{height:8rem}.md\:w-32{width:8rem}.md\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-start{align-items:flex-start}.md\:justify-end{justify-content:flex-end}.md\:justify-between{justify-content:space-between}.md\:text-2xl{font-size:1.5rem;line-height:2rem}.md\:text-4xl{font-size:2.25rem;line-height:2.5rem}.md\:text-5xl{font-size:3rem;line-height:1}.md\:text-6xl{font-size:3.75rem;line-height:1}.md\:text-7xl{font-size:4.5rem;line-height:1}}@media (min-width:1024px){.lg\:col-span-12{grid-column:span 12/span 12}.lg\:col-span-3{grid-column:span 3/span 3}.lg\:col-span-4{grid-column:span 4/span 4}.lg\:col-span-7{grid-column:span 7/span 7}.lg\:col-span-8{grid-column:span 8/span 8}.lg\:col-span-9{grid-column:span 9/span 9}.lg\:col-start-2{grid-column-start:2}.lg\:col-start-9{grid-column-start:9}.lg\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:px-gutter{padding-left:24px;padding-right:24px}}@media (min-width:1280px){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (prefers-color-scheme:dark){.dark\:border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.dark\:bg-blue-950\/30{background-color:rgba(23,37,84,.3)}}