@treeseed/core 0.8.8 → 0.8.10

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 (90) hide show
  1. package/dist/components/SiteTitle.astro +2 -2
  2. package/dist/components/content/ContentStatusLegend.astro +4 -4
  3. package/dist/components/docs/BookFontControls.astro +9 -9
  4. package/dist/components/docs/DesktopSidebarToggle.astro +8 -8
  5. package/dist/components/docs/Footer.astro +7 -91
  6. package/dist/components/docs/Header.astro +9 -2
  7. package/dist/components/docs/PageTitle.astro +1 -1
  8. package/dist/components/docs/ThemeSelect.astro +3 -1
  9. package/dist/components/forms/ContactForm.astro +21 -21
  10. package/dist/components/forms/FooterSubscribeForm.astro +9 -9
  11. package/dist/components/site/BookList.astro +7 -7
  12. package/dist/components/site/CTASection.astro +4 -4
  13. package/dist/components/site/ChronicleList.astro +6 -6
  14. package/dist/components/site/Hero.astro +3 -3
  15. package/dist/components/site/PathCard.astro +5 -5
  16. package/dist/components/site/ProfileList.astro +5 -5
  17. package/dist/components/site/RouteNotFound.astro +6 -6
  18. package/dist/components/site/SectionIntro.astro +3 -3
  19. package/dist/components/site/StageBanner.astro +2 -2
  20. package/dist/components/site/TrustCallout.astro +3 -3
  21. package/dist/components/ui/data/ActionList.astro +51 -0
  22. package/dist/components/ui/data/Badge.astro +19 -0
  23. package/dist/components/ui/data/DataTable.astro +51 -0
  24. package/dist/components/ui/data/KeyValueList.astro +28 -0
  25. package/dist/components/ui/data/MetricCard.astro +25 -0
  26. package/dist/components/ui/data/MetricGrid.astro +27 -0
  27. package/dist/components/ui/data/StatusPill.astro +20 -0
  28. package/dist/components/ui/forms/Button.astro +52 -0
  29. package/dist/components/ui/forms/Field.astro +39 -0
  30. package/dist/components/ui/forms/FormActions.astro +12 -0
  31. package/dist/components/ui/forms/PasswordMeter.astro +80 -0
  32. package/dist/components/ui/forms/RadioGroup.astro +55 -0
  33. package/dist/components/ui/forms/Select.astro +44 -0
  34. package/dist/components/ui/forms/TextInput.astro +58 -0
  35. package/dist/components/ui/forms/Textarea.astro +45 -0
  36. package/dist/components/ui/layout/PageHeader.astro +45 -0
  37. package/dist/components/ui/shell/AppShell.astro +112 -0
  38. package/dist/components/ui/shell/BottomNav.astro +35 -0
  39. package/dist/components/ui/shell/ProjectHeader.astro +66 -0
  40. package/dist/components/ui/shell/PublicFooter.astro +39 -0
  41. package/dist/components/ui/shell/PublicShell.astro +179 -0
  42. package/dist/components/ui/shell/RailNav.astro +35 -0
  43. package/dist/components/ui/shell/TopBar.astro +52 -0
  44. package/dist/components/ui/surface/Card.astro +46 -0
  45. package/dist/components/ui/surface/EmptyState.astro +45 -0
  46. package/dist/components/ui/surface/Panel.astro +54 -0
  47. package/dist/components/ui/theme/ThemeMenu.astro +32 -0
  48. package/dist/components/ui/theme/ThemePreviewSwatch.astro +18 -0
  49. package/dist/components/ui/theme/ThemeScript.astro +111 -0
  50. package/dist/components/ui/theme/ThemeSelector.astro +202 -0
  51. package/dist/components/ui/types.js +0 -0
  52. package/dist/dev-watch.d.ts +6 -2
  53. package/dist/dev-watch.js +12 -3
  54. package/dist/dev.d.ts +10 -2
  55. package/dist/dev.js +352 -68
  56. package/dist/layouts/AuthoredEntryLayout.astro +27 -27
  57. package/dist/layouts/BookLayout.astro +10 -10
  58. package/dist/layouts/ContentLayout.astro +4 -4
  59. package/dist/layouts/MainLayout.astro +66 -193
  60. package/dist/layouts/NoteLayout.astro +6 -6
  61. package/dist/layouts/ProfileLayout.astro +17 -17
  62. package/dist/middleware/starlightRouteData.js +20 -14
  63. package/dist/pages/404.astro +8 -8
  64. package/dist/pages/[slug].astro +1 -1
  65. package/dist/pages/books/[slug].astro +5 -5
  66. package/dist/pages/contact.astro +4 -4
  67. package/dist/pages/docs-runtime/[...slug].astro +12 -12
  68. package/dist/pages/docs-runtime/index.astro +13 -13
  69. package/dist/pages/index.astro +28 -28
  70. package/dist/pages/ui/index.astro +216 -0
  71. package/dist/scripts/dev-platform.js +7 -1
  72. package/dist/site.js +53 -5
  73. package/dist/styles/app-shell.css +597 -0
  74. package/dist/styles/forms.css +258 -0
  75. package/dist/styles/global.css +125 -120
  76. package/dist/styles/prose.css +11 -11
  77. package/dist/styles/theme.css +177 -0
  78. package/dist/styles/tokens.css +62 -22
  79. package/dist/styles/ui.css +551 -0
  80. package/dist/utils/color-schemes/cedar.js +53 -0
  81. package/dist/utils/color-schemes/fern.js +53 -0
  82. package/dist/utils/color-schemes/index.js +13 -0
  83. package/dist/utils/color-schemes/lichen.js +53 -0
  84. package/dist/utils/color-schemes/shared.js +33 -0
  85. package/dist/utils/color-schemes/tidepool.js +53 -0
  86. package/dist/utils/content-status.js +5 -5
  87. package/dist/utils/site-config.js +2 -2
  88. package/dist/utils/starlight-nav.js +13 -7
  89. package/dist/utils/theme.js +133 -41
  90. package/package.json +36 -2
package/dist/site.js CHANGED
@@ -1,17 +1,19 @@
1
1
  import { defineConfig, envField } from "astro/config";
2
2
  import cloudflare from "@astrojs/cloudflare";
3
- import { existsSync, readFileSync } from "node:fs";
3
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
4
4
  import { resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
+ import { parse as parseYaml } from "yaml";
6
7
  import rehypeKatex from "rehype-katex";
7
8
  import remarkMath from "remark-math";
8
9
  import tailwindcss from "@tailwindcss/vite";
9
10
  import { parseSiteConfig } from "./utils/site-config-schema.js";
10
11
  import { buildTenantBookRuntime } from "@treeseed/sdk/platform/books-data";
11
12
  import { getStarlightSidebarConfigFromRuntime } from "./utils/starlight-nav.js";
12
- import { buildTenantThemeCss } from "./utils/theme.js";
13
+ import { buildTreeseedThemeCss } from "./utils/theme.js";
13
14
  import { loadTreeseedDeployConfig } from "@treeseed/sdk/platform/deploy-config";
14
15
  import { getTreeseedContentServingMode } from "@treeseed/sdk/platform/deploy-runtime";
16
+ import { getTenantContentRoot } from "@treeseed/sdk/platform/tenant-config";
15
17
  import { loadTreeseedPluginRuntime } from "@treeseed/sdk/platform/plugins";
16
18
  import {
17
19
  buildTreeseedSiteLayers,
@@ -41,7 +43,7 @@ const PACKAGE_ROUTE_ENTRIES = [
41
43
  { pattern: "/404", resourcePath: "pages/404.astro" },
42
44
  { pattern: "/contact", resourcePath: "pages/contact.astro" },
43
45
  { pattern: "/feed.xml", resourcePath: "pages/feed.xml", model: "notes" },
44
- { pattern: "/[slug]", resourcePath: "pages/[slug].astro", model: "pages" },
46
+ { pattern: "/ui", resourcePath: "pages/ui/index.astro" },
45
47
  { pattern: "/agents", resourcePath: "pages/agents/index.astro", model: "agents" },
46
48
  { pattern: "/agents/[slug]", resourcePath: "pages/agents/[slug].astro", model: "agents" },
47
49
  { pattern: "/books", resourcePath: "pages/books/index.astro", model: "books" },
@@ -59,6 +61,48 @@ const PACKAGE_ROUTE_ENTRIES = [
59
61
  { pattern: "/questions", resourcePath: "pages/questions/index.astro", model: "questions" },
60
62
  { pattern: "/questions/[slug]", resourcePath: "pages/questions/[slug].astro", model: "questions" }
61
63
  ];
64
+ const DYNAMIC_PAGE_ROUTE_ENTRY = { pattern: "/[slug]", resourcePath: "pages/[slug].astro", model: "pages" };
65
+ function collectMarkdownFiles(rootPath) {
66
+ if (!existsSync(rootPath)) {
67
+ return [];
68
+ }
69
+ const stats = statSync(rootPath);
70
+ if (stats.isFile()) {
71
+ return /\.(md|mdx)$/iu.test(rootPath) ? [rootPath] : [];
72
+ }
73
+ return readdirSync(rootPath, { withFileTypes: true }).flatMap((entry) => {
74
+ const fullPath = resolve(rootPath, entry.name);
75
+ if (entry.isDirectory()) {
76
+ return collectMarkdownFiles(fullPath);
77
+ }
78
+ return entry.isFile() && /\.(md|mdx)$/iu.test(entry.name) ? [fullPath] : [];
79
+ });
80
+ }
81
+ function readFrontmatter(filePath) {
82
+ const raw = readFileSync(filePath, "utf8");
83
+ const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
84
+ if (!match) {
85
+ return null;
86
+ }
87
+ return parseYaml(match[1]);
88
+ }
89
+ function collectLocalPageRouteEntries(tenantConfig, projectRoot) {
90
+ const pagesRoot = resolve(projectRoot, getTenantContentRoot(tenantConfig, "pages"));
91
+ const slugs = /* @__PURE__ */ new Set();
92
+ for (const filePath of collectMarkdownFiles(pagesRoot)) {
93
+ const frontmatter = readFrontmatter(filePath);
94
+ const slug = typeof frontmatter?.slug === "string" ? frontmatter.slug.replace(/^\/+|\/+$/g, "") : "";
95
+ if (!slug || slug.includes("/")) {
96
+ continue;
97
+ }
98
+ slugs.add(slug);
99
+ }
100
+ return [...slugs].sort().map((slug) => ({
101
+ pattern: `/${slug}`,
102
+ resourcePath: "pages/[slug].astro",
103
+ model: "pages"
104
+ }));
105
+ }
62
106
  function createTreeseedRoutesIntegration(tenantConfig, routes = []) {
63
107
  return {
64
108
  name: "treeseed-routes",
@@ -215,7 +259,7 @@ function createTreeseedSite(tenantConfig, { starlight }) {
215
259
  const bookRuntime = buildTenantBookRuntime(tenantConfig, { projectRoot });
216
260
  const docsRendered = isSiteRenderedModel(tenantConfig, "docs");
217
261
  const booksRendered = isSiteRenderedModel(tenantConfig, "books");
218
- const tenantThemeCss = buildTenantThemeCss(siteConfig.site.theme);
262
+ const tenantThemeCss = buildTreeseedThemeCss(siteConfig.site.theme);
219
263
  const siteLayers = buildTreeseedSiteLayers(pluginRuntime, {
220
264
  coreRoot: fileURLToPath(new URL(".", import.meta.url)),
221
265
  projectRoot,
@@ -233,12 +277,15 @@ function createTreeseedSite(tenantConfig, { starlight }) {
233
277
  const injectedProjectRoot = JSON.stringify(projectRoot);
234
278
  const injectedSiteConfig = JSON.stringify(siteConfig);
235
279
  const injectedDeployConfig = JSON.stringify(deployConfig);
280
+ const injectedBookRuntime = JSON.stringify(bookRuntime);
236
281
  const resolvedGlobalCss = resolveTreeseedStyleEntrypoint(siteLayers, "styles/global.css");
237
282
  const serverRendered = deployConfig.surfaces?.web?.provider === "cloudflare" || deployConfig.providers.deploy === "cloudflare";
238
283
  const allowedDomains = deriveTreeseedAstroAllowedDomains(deployConfig, { siteUrl: siteConfig.site.siteUrl });
239
284
  const publishedRuntime = getTreeseedContentServingMode() === "published_runtime";
285
+ const pageRoutes = publishedRuntime ? [DYNAMIC_PAGE_ROUTE_ENTRY] : collectLocalPageRouteEntries(tenantConfig, projectRoot);
240
286
  const packageRoutes = [
241
287
  ...PACKAGE_ROUTE_ENTRIES,
288
+ ...pageRoutes,
242
289
  ...docsRendered && publishedRuntime ? [
243
290
  { pattern: "/knowledge", resourcePath: "pages/docs-runtime/index.astro", model: "docs" },
244
291
  { pattern: "/knowledge/[...slug]", resourcePath: "pages/docs-runtime/[...slug].astro", model: "docs" }
@@ -263,7 +310,8 @@ function createTreeseedSite(tenantConfig, { starlight }) {
263
310
  __TREESEED_TENANT_CONFIG__: injectedTenantConfig,
264
311
  __TREESEED_PROJECT_ROOT__: injectedProjectRoot,
265
312
  __TREESEED_SITE_CONFIG__: injectedSiteConfig,
266
- __TREESEED_DEPLOY_CONFIG__: injectedDeployConfig
313
+ __TREESEED_DEPLOY_CONFIG__: injectedDeployConfig,
314
+ __TREESEED_BOOK_RUNTIME__: injectedBookRuntime
267
315
  },
268
316
  plugins: [
269
317
  createTenantThemeVitePlugin(tenantThemeCss),
@@ -0,0 +1,597 @@
1
+ .ts-skip-link {
2
+ background: var(--ts-color-accent);
3
+ border-radius: var(--ts-radius-md);
4
+ color: var(--ts-color-accent-text);
5
+ font-weight: 750;
6
+ left: var(--ts-space-3);
7
+ padding: var(--ts-space-2) var(--ts-space-3);
8
+ position: fixed;
9
+ top: var(--ts-space-3);
10
+ transform: translateY(-150%);
11
+ z-index: 100;
12
+ }
13
+
14
+ .ts-skip-link:focus {
15
+ transform: translateY(0);
16
+ }
17
+
18
+ .ts-app-shell {
19
+ background: var(--ts-color-canvas);
20
+ color: var(--ts-color-text);
21
+ display: grid;
22
+ grid-template-columns: 17.875rem minmax(0, 1fr);
23
+ min-height: 100vh;
24
+ }
25
+
26
+ .ts-app-shell__rail {
27
+ align-self: start;
28
+ background: var(--ts-color-canvas-subtle);
29
+ border-right: 1px solid var(--ts-color-border);
30
+ display: grid;
31
+ gap: var(--ts-space-3);
32
+ height: 100vh;
33
+ overflow: auto;
34
+ padding: var(--ts-space-3);
35
+ position: sticky;
36
+ top: 0;
37
+ }
38
+
39
+ .ts-shell-brand {
40
+ align-items: center;
41
+ color: var(--ts-color-text);
42
+ display: flex;
43
+ gap: var(--ts-space-2);
44
+ min-width: 0;
45
+ max-width: 100%;
46
+ text-decoration: none;
47
+ }
48
+
49
+ .ts-shell-brand:hover {
50
+ text-decoration: none;
51
+ }
52
+
53
+ .ts-shell-brand__mark {
54
+ align-items: center;
55
+ display: inline-flex;
56
+ flex: 0 0 auto;
57
+ font-weight: 800;
58
+ height: 3rem;
59
+ justify-content: center;
60
+ max-height: 3rem;
61
+ max-width: 3rem;
62
+ overflow: hidden;
63
+ width: 3rem;
64
+ }
65
+
66
+ .ts-shell-brand__mark img {
67
+ display: block;
68
+ height: 100%;
69
+ max-height: 100%;
70
+ max-width: 100%;
71
+ object-fit: contain;
72
+ width: 100%;
73
+ }
74
+
75
+ .ts-shell-brand__text {
76
+ display: grid;
77
+ gap: 0.1rem;
78
+ min-width: 0;
79
+ }
80
+
81
+ .ts-shell-brand__name {
82
+ font-size: 0.95rem;
83
+ font-weight: 750;
84
+ line-height: 1.15;
85
+ }
86
+
87
+ .ts-shell-brand__tag {
88
+ color: var(--ts-color-text-muted);
89
+ font-size: 0.74rem;
90
+ font-weight: 500;
91
+ line-height: 1.25;
92
+ max-width: 13rem;
93
+ }
94
+
95
+ .ts-top-bar {
96
+ align-items: center;
97
+ display: flex;
98
+ gap: var(--ts-space-2);
99
+ justify-content: space-between;
100
+ min-width: 0;
101
+ }
102
+
103
+ .ts-top-bar__actions {
104
+ align-items: center;
105
+ display: flex;
106
+ flex-wrap: wrap;
107
+ gap: var(--ts-space-1);
108
+ justify-content: flex-end;
109
+ min-width: 0;
110
+ }
111
+
112
+ .ts-app-shell__rail-context,
113
+ .ts-app-shell__quick-actions {
114
+ border-top: 1px solid var(--ts-color-border);
115
+ display: grid;
116
+ gap: var(--ts-space-2);
117
+ padding-top: var(--ts-space-2);
118
+ }
119
+
120
+ .ts-app-shell__eyebrow {
121
+ color: var(--ts-color-text-subtle);
122
+ font-size: 0.75rem;
123
+ font-weight: 750;
124
+ margin: 0;
125
+ text-transform: uppercase;
126
+ }
127
+
128
+ .ts-app-shell__quick-list {
129
+ display: grid;
130
+ gap: var(--ts-space-2);
131
+ }
132
+
133
+ .ts-rail-nav {
134
+ border-top: 1px solid var(--ts-color-border);
135
+ display: grid;
136
+ gap: 0.2rem;
137
+ padding-top: var(--ts-space-2);
138
+ }
139
+
140
+ .ts-rail-nav__link,
141
+ .ts-bottom-nav__link,
142
+ .ts-public-shell__link,
143
+ .ts-shell-tab {
144
+ color: var(--ts-color-text-muted);
145
+ text-decoration: none;
146
+ }
147
+
148
+ .ts-rail-nav__link {
149
+ border-radius: var(--ts-radius-md);
150
+ display: flex;
151
+ font-weight: 650;
152
+ justify-content: space-between;
153
+ padding: 0.55rem 0.55rem;
154
+ }
155
+
156
+ .ts-rail-nav__link[aria-current='page'],
157
+ .ts-rail-nav__link:hover {
158
+ background: var(--ts-color-surface);
159
+ color: var(--ts-color-text);
160
+ text-decoration: none;
161
+ }
162
+
163
+ .ts-app-shell__main {
164
+ display: grid;
165
+ gap: var(--ts-space-3);
166
+ padding: var(--ts-space-3);
167
+ }
168
+
169
+ .ts-app-shell__mobile-top {
170
+ display: none;
171
+ }
172
+
173
+ .ts-app-shell__header {
174
+ align-items: flex-start;
175
+ display: flex;
176
+ gap: var(--ts-space-3);
177
+ justify-content: space-between;
178
+ }
179
+
180
+ .ts-app-shell__title {
181
+ display: grid;
182
+ gap: var(--ts-space-1);
183
+ min-width: 0;
184
+ }
185
+
186
+ .ts-app-shell__title h1 {
187
+ color: var(--ts-color-text);
188
+ font-size: 1.55rem;
189
+ line-height: 1.12;
190
+ margin: 0;
191
+ }
192
+
193
+ .ts-app-shell__title p,
194
+ .ts-project-header p {
195
+ color: var(--ts-color-text-muted);
196
+ line-height: 1.5;
197
+ margin: 0;
198
+ }
199
+
200
+ .ts-app-shell__header-actions {
201
+ align-items: center;
202
+ display: flex;
203
+ flex-wrap: wrap;
204
+ gap: var(--ts-space-2);
205
+ justify-content: flex-end;
206
+ }
207
+
208
+ .ts-project-header {
209
+ background: var(--ts-color-surface);
210
+ border: 1px solid var(--ts-color-border);
211
+ border-radius: var(--ts-radius-lg);
212
+ display: grid;
213
+ gap: var(--ts-space-2);
214
+ padding: var(--ts-space-3);
215
+ }
216
+
217
+ .ts-project-header__main {
218
+ display: grid;
219
+ gap: var(--ts-space-2);
220
+ }
221
+
222
+ .ts-project-header__badges,
223
+ .ts-project-header__actions {
224
+ display: flex;
225
+ flex-wrap: wrap;
226
+ gap: var(--ts-space-2);
227
+ }
228
+
229
+ .ts-project-header h2 {
230
+ color: var(--ts-color-text);
231
+ font-size: 1.15rem;
232
+ line-height: 1.15;
233
+ margin: 0;
234
+ }
235
+
236
+ .ts-shell-tabs {
237
+ align-items: stretch;
238
+ display: flex;
239
+ flex-wrap: wrap;
240
+ gap: var(--ts-space-2);
241
+ }
242
+
243
+ .ts-shell-tab {
244
+ align-items: center;
245
+ background: var(--ts-color-surface-muted);
246
+ border: 1px solid var(--ts-color-border);
247
+ border-radius: var(--ts-radius-md);
248
+ box-sizing: border-box;
249
+ display: inline-flex;
250
+ flex: 1 1 7rem;
251
+ font-size: 0.875rem;
252
+ font-weight: 650;
253
+ justify-content: center;
254
+ line-height: 1.2;
255
+ min-height: 2.5rem;
256
+ padding: 0.55rem 0.75rem;
257
+ text-align: center;
258
+ white-space: nowrap;
259
+ }
260
+
261
+ .ts-shell-tab[aria-current='page'],
262
+ .ts-shell-tab[aria-selected='true'],
263
+ .ts-shell-tab:hover {
264
+ background: var(--ts-color-surface);
265
+ border-color: var(--ts-color-border-strong);
266
+ color: var(--ts-color-text);
267
+ text-decoration: none;
268
+ }
269
+
270
+ .ts-bottom-nav {
271
+ background: var(--ts-color-surface-overlay);
272
+ border-top: 1px solid var(--ts-color-border);
273
+ bottom: 0;
274
+ display: none;
275
+ gap: var(--ts-space-1);
276
+ grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
277
+ left: 0;
278
+ padding: var(--ts-space-2);
279
+ position: fixed;
280
+ right: 0;
281
+ z-index: 30;
282
+ }
283
+
284
+ .ts-bottom-nav__link {
285
+ border-radius: var(--ts-radius-md);
286
+ display: grid;
287
+ font-size: 0.75rem;
288
+ font-weight: 700;
289
+ min-height: 2.5rem;
290
+ place-items: center;
291
+ text-align: center;
292
+ }
293
+
294
+ .ts-bottom-nav__link[aria-current='page'],
295
+ .ts-bottom-nav__link:hover {
296
+ background: var(--ts-color-surface-muted);
297
+ color: var(--ts-color-text);
298
+ text-decoration: none;
299
+ }
300
+
301
+ .ts-public-shell {
302
+ background: var(--ts-color-canvas);
303
+ color: var(--ts-color-text);
304
+ margin: 0 auto;
305
+ max-width: var(--ts-shell-width);
306
+ min-height: 100vh;
307
+ padding: var(--ts-space-3);
308
+ }
309
+
310
+ .ts-public-shell--content .ts-public-shell__main {
311
+ margin-inline: auto;
312
+ max-width: var(--ts-content-width);
313
+ width: 100%;
314
+ }
315
+
316
+ .ts-public-shell__header {
317
+ display: grid;
318
+ gap: var(--ts-space-2);
319
+ padding-bottom: var(--ts-space-3);
320
+ }
321
+
322
+ .ts-public-shell__nav {
323
+ align-items: center;
324
+ display: flex;
325
+ flex-wrap: wrap;
326
+ gap: var(--ts-space-1);
327
+ justify-content: flex-end;
328
+ min-width: 0;
329
+ }
330
+
331
+ .ts-public-shell__link {
332
+ border: 1px solid transparent;
333
+ border-radius: 999px;
334
+ font-size: 0.94rem;
335
+ font-weight: 650;
336
+ padding: 0.42rem 0.7rem;
337
+ }
338
+
339
+ .ts-public-shell__link[aria-current='page'],
340
+ .ts-public-shell__summary--active,
341
+ .ts-public-shell__link:hover {
342
+ background: var(--ts-color-surface-raised);
343
+ border-color: var(--ts-color-border);
344
+ color: var(--ts-color-text);
345
+ text-decoration: none;
346
+ }
347
+
348
+ .ts-public-shell__nav-group {
349
+ position: relative;
350
+ }
351
+
352
+ .ts-public-shell__summary {
353
+ align-items: center;
354
+ cursor: pointer;
355
+ display: inline-flex;
356
+ gap: 0.35rem;
357
+ list-style: none;
358
+ }
359
+
360
+ .ts-public-shell__summary::-webkit-details-marker {
361
+ display: none;
362
+ }
363
+
364
+ .ts-public-shell__summary span {
365
+ color: var(--ts-color-text-subtle);
366
+ font-size: 0.75rem;
367
+ transition: transform 160ms ease;
368
+ }
369
+
370
+ .ts-public-shell__nav-group[open] .ts-public-shell__summary span {
371
+ transform: rotate(180deg);
372
+ }
373
+
374
+ .ts-public-shell__menu {
375
+ background: var(--ts-color-surface-overlay);
376
+ border: 1px solid var(--ts-color-border-strong);
377
+ border-radius: var(--ts-radius-md);
378
+ box-shadow: var(--ts-color-shadow);
379
+ display: grid;
380
+ gap: 0.15rem;
381
+ inset-block-start: calc(100% + 0.35rem);
382
+ inset-inline-end: 0;
383
+ min-width: 13rem;
384
+ padding: var(--ts-space-1);
385
+ position: absolute;
386
+ z-index: 40;
387
+ }
388
+
389
+ .ts-public-shell__menu-link {
390
+ border-radius: var(--ts-radius-sm);
391
+ color: var(--ts-color-text-muted);
392
+ font-size: 0.9rem;
393
+ font-weight: 600;
394
+ padding: 0.5rem 0.65rem;
395
+ text-decoration: none;
396
+ }
397
+
398
+ .ts-public-shell__menu-link[aria-current='page'],
399
+ .ts-public-shell__menu-link:hover,
400
+ .ts-public-shell__menu-link:focus-visible {
401
+ background: var(--ts-color-surface-muted);
402
+ color: var(--ts-color-text);
403
+ text-decoration: none;
404
+ }
405
+
406
+ .ts-public-shell__icon-link {
407
+ align-items: center;
408
+ border: 1px solid transparent;
409
+ border-radius: var(--ts-radius-md);
410
+ color: var(--ts-color-text-muted);
411
+ display: inline-flex;
412
+ height: 2.25rem;
413
+ justify-content: center;
414
+ text-decoration: none;
415
+ width: 2.25rem;
416
+ }
417
+
418
+ .ts-public-shell__icon-link:hover,
419
+ .ts-public-shell__icon-link:focus-visible {
420
+ background: var(--ts-color-surface-raised);
421
+ border-color: var(--ts-color-border);
422
+ color: var(--ts-color-text);
423
+ text-decoration: none;
424
+ }
425
+
426
+ .ts-public-shell__icon-link svg {
427
+ fill: currentColor;
428
+ height: 1.15rem;
429
+ width: 1.15rem;
430
+ }
431
+
432
+ .ts-public-shell__icon-link--stroke svg {
433
+ fill: none;
434
+ stroke: currentColor;
435
+ stroke-linecap: round;
436
+ stroke-linejoin: round;
437
+ stroke-width: 1.8;
438
+ }
439
+
440
+ .ts-public-shell__main {
441
+ display: grid;
442
+ gap: var(--ts-space-3);
443
+ padding-top: clamp(1.25rem, 3vw, 2.25rem);
444
+ }
445
+
446
+ .ts-public-footer {
447
+ border-top: 2px solid var(--ts-color-border-strong);
448
+ display: block;
449
+ margin-top: 4rem;
450
+ padding-top: 2rem;
451
+ width: 100%;
452
+ }
453
+
454
+ .site-footer-cta + .ts-public-footer {
455
+ margin-top: 0;
456
+ }
457
+
458
+ .ts-public-footer__inner {
459
+ display: grid;
460
+ gap: 2rem;
461
+ margin-inline: auto;
462
+ max-width: var(--ts-content-width);
463
+ padding-bottom: 3.75rem;
464
+ width: 100%;
465
+ }
466
+
467
+ .ts-public-footer__grid {
468
+ display: flex;
469
+ flex-wrap: wrap;
470
+ gap: 2rem;
471
+ justify-content: center;
472
+ }
473
+
474
+ .ts-public-footer__column {
475
+ align-content: start;
476
+ display: grid;
477
+ gap: 0.75rem;
478
+ width: 16rem;
479
+ }
480
+
481
+ .ts-public-footer__title,
482
+ .ts-public-footer__column-title {
483
+ color: var(--ts-color-text);
484
+ font-size: 1.25rem;
485
+ font-weight: 750;
486
+ line-height: 1.2;
487
+ margin: 0;
488
+ }
489
+
490
+ .ts-public-footer__heading {
491
+ color: var(--ts-color-info-text);
492
+ font-size: 0.82rem;
493
+ font-weight: 750;
494
+ letter-spacing: 0.14em;
495
+ line-height: 1.2;
496
+ margin: 0;
497
+ text-transform: uppercase;
498
+ }
499
+
500
+ .ts-public-footer__copy,
501
+ .ts-public-footer__links {
502
+ color: var(--ts-color-text-muted);
503
+ font-size: 1rem;
504
+ line-height: 1.9;
505
+ margin: 0;
506
+ }
507
+
508
+ .ts-public-footer__links {
509
+ display: flex;
510
+ flex-direction: column;
511
+ gap: 0.35rem;
512
+ }
513
+
514
+ .ts-public-footer__links a {
515
+ color: var(--ts-color-text-muted);
516
+ display: block;
517
+ text-decoration: none;
518
+ }
519
+
520
+ .ts-public-footer__links a:hover,
521
+ .ts-public-footer__links a:focus-visible {
522
+ color: var(--ts-color-text);
523
+ text-decoration: underline;
524
+ }
525
+
526
+ @media (min-width: 48rem) {
527
+ .ts-project-header {
528
+ align-items: center;
529
+ grid-template-columns: minmax(0, 1fr) auto;
530
+ }
531
+
532
+ .ts-project-header .ts-shell-tabs {
533
+ grid-column: 1 / -1;
534
+ }
535
+ }
536
+
537
+ @media (max-width: 61.25rem) {
538
+ .ts-app-shell {
539
+ display: block;
540
+ padding-bottom: 4.5rem;
541
+ }
542
+
543
+ .ts-app-shell__rail {
544
+ display: none;
545
+ }
546
+
547
+ .ts-app-shell__main {
548
+ padding: var(--ts-space-2);
549
+ }
550
+
551
+ .ts-app-shell__mobile-top {
552
+ background: var(--ts-color-surface-overlay);
553
+ border-bottom: 1px solid var(--ts-color-border);
554
+ display: flex;
555
+ margin: calc(var(--ts-space-2) * -1) calc(var(--ts-space-2) * -1) 0;
556
+ padding: var(--ts-space-2);
557
+ position: sticky;
558
+ top: 0;
559
+ z-index: 20;
560
+ }
561
+
562
+ .ts-app-shell__header {
563
+ flex-direction: column;
564
+ }
565
+
566
+ .ts-app-shell__header-actions {
567
+ justify-content: stretch;
568
+ width: 100%;
569
+ }
570
+
571
+ .ts-bottom-nav {
572
+ display: grid;
573
+ }
574
+ }
575
+
576
+ @media (max-width: 40rem) {
577
+ .ts-public-shell {
578
+ padding: var(--ts-space-2);
579
+ }
580
+
581
+ .ts-top-bar {
582
+ align-items: center;
583
+ flex-wrap: wrap;
584
+ }
585
+
586
+ .ts-top-bar__actions {
587
+ justify-content: flex-end;
588
+ }
589
+
590
+ .ts-public-shell__nav {
591
+ justify-content: flex-start;
592
+ }
593
+
594
+ .ts-public-shell__menu {
595
+ inset-inline: 0 auto;
596
+ }
597
+ }