@sprig-and-prose/sprig-ui-csr 0.2.1 → 0.2.3

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/src/App.svelte CHANGED
@@ -210,10 +210,26 @@
210
210
  width: 100%;
211
211
  position: sticky;
212
212
  top: 0;
213
- background-color: var(--bg-color);
213
+ /* Background texture applied via JavaScript in main.js to match body texture */
214
+ /* Use semi-transparent background to allow texture to show while covering scrolling content */
215
+ background-color: rgba(250, 250, 250, 0.95); /* Light mode base with slight transparency */
214
216
  z-index: 100;
215
217
  }
216
218
 
219
+ @media (prefers-color-scheme: dark) {
220
+ .top-bar {
221
+ background-color: rgba(36, 34, 31, 0.95); /* Dark mode base with slight transparency */
222
+ }
223
+ }
224
+
225
+ :global(html[data-theme="dark"]) .top-bar {
226
+ background-color: rgba(36, 34, 31, 0.95); /* Dark mode base with slight transparency */
227
+ }
228
+
229
+ :global(html[data-theme="light"]) .top-bar {
230
+ background-color: rgba(250, 250, 250, 0.95); /* Light mode base with slight transparency */
231
+ }
232
+
217
233
  .main-content {
218
234
  padding: 64px 32px;
219
235
  min-height: calc(100vh - 200px);
@@ -397,7 +397,7 @@
397
397
  top: calc(100% + 4px);
398
398
  left: 0;
399
399
  right: 0;
400
- background: var(--bg-color);
400
+ background: var(--card-bg);
401
401
  border: 1px solid var(--border-color);
402
402
  border-radius: 4px;
403
403
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
@@ -71,7 +71,7 @@
71
71
  listItems.push(currentItem);
72
72
  }
73
73
  const match = lines[i].match(/^[-—*]\s+(.+)$/);
74
- currentItem = match[1];
74
+ currentItem = match && match[1] ? match[1] : '';
75
75
  } else {
76
76
  // Continuation line - append to current item
77
77
  if (currentItem !== null) {
@@ -113,7 +113,7 @@
113
113
  listItems.push(currentItem);
114
114
  }
115
115
  const match = lines[i].match(/^\d+\.\s+(.+)$/);
116
- currentItem = match[1];
116
+ currentItem = match && match[1] ? match[1] : '';
117
117
  } else {
118
118
  // Continuation line - append to current item
119
119
  if (currentItem !== null) {
@@ -15,6 +15,69 @@ export const universeGraph = writable(/** @type {UniverseGraph|null} */ (null));
15
15
 
16
16
  export const currentUniverseName = writable(/** @type {string|null} */ (null));
17
17
 
18
+ // Hierarchy order: universe > anthology > series > book > chapter > concept
19
+ const HIERARCHY_ORDER = ['universe', 'anthology', 'series', 'book', 'chapter', 'concept'];
20
+
21
+ /**
22
+ * Get the expected primary child kind for a given parent kind
23
+ * @param {string} parentKind
24
+ * @returns {string | null}
25
+ */
26
+ function getExpectedPrimaryKind(parentKind) {
27
+ const index = HIERARCHY_ORDER.indexOf(parentKind);
28
+ return index >= 0 && index < HIERARCHY_ORDER.length - 1
29
+ ? HIERARCHY_ORDER[index + 1]
30
+ : null;
31
+ }
32
+
33
+ /**
34
+ * Organize children into primary and other groups based on hierarchy
35
+ * Primary shows the highest-level child type that exists
36
+ * Other shows all remaining children
37
+ * @param {NodeModel[]} children
38
+ * @param {string} parentKind
39
+ * @returns {{ primary: NodeModel[], other: NodeModel[] }}
40
+ */
41
+ export function organizeChildren(children, parentKind) {
42
+ const expectedPrimary = getExpectedPrimaryKind(parentKind);
43
+ if (!expectedPrimary) {
44
+ return { primary: children, other: [] };
45
+ }
46
+
47
+ // Filter out relates nodes
48
+ const validChildren = children.filter(child => child.kind !== 'relates');
49
+
50
+ // Find highest-level child type that exists
51
+ const childrenByKind = new Map();
52
+ for (const child of validChildren) {
53
+ if (!childrenByKind.has(child.kind)) {
54
+ childrenByKind.set(child.kind, []);
55
+ }
56
+ childrenByKind.get(child.kind).push(child);
57
+ }
58
+
59
+ // Determine primary: use expected if it exists, otherwise find highest existing
60
+ let primaryKind = expectedPrimary;
61
+ if (!childrenByKind.has(primaryKind)) {
62
+ // Find the highest-level kind that exists (closest to parent in hierarchy)
63
+ for (const kind of HIERARCHY_ORDER) {
64
+ if (childrenByKind.has(kind) && HIERARCHY_ORDER.indexOf(kind) > HIERARCHY_ORDER.indexOf(parentKind)) {
65
+ primaryKind = kind;
66
+ break;
67
+ }
68
+ }
69
+ // If we still didn't find a primary kind, use the first available kind
70
+ if (!childrenByKind.has(primaryKind) && childrenByKind.size > 0) {
71
+ primaryKind = Array.from(childrenByKind.keys())[0];
72
+ }
73
+ }
74
+
75
+ const primary = childrenByKind.get(primaryKind) || [];
76
+ const other = validChildren.filter(child => child.kind !== primaryKind);
77
+
78
+ return { primary, other };
79
+ }
80
+
18
81
  export const currentUniverse = derived(
19
82
  [universeGraph, currentUniverseName],
20
83
  ([$g, $name]) => $g?.universes?.[$name] ?? null,
@@ -29,10 +92,11 @@ export const rootChildren = derived(
29
92
  [universeGraph, universeRootNode],
30
93
  ([$g, $root]) => {
31
94
  if (!$g || !$root) return [];
32
- return ($root.children || [])
95
+ const children = ($root.children || [])
33
96
  .map((id) => $g.nodes[id])
34
97
  .filter(Boolean)
35
98
  .filter((node) => node.kind !== 'relates'); // Exclude relates nodes from contents
99
+ return organizeChildren(children, 'universe');
36
100
  },
37
101
  );
38
102
 
@@ -75,8 +139,9 @@ export const currentSeries = derived(
75
139
  export const seriesChildren = derived(
76
140
  [universeGraph, currentSeries],
77
141
  ([$g, $series]) => {
78
- if (!$g || !$series) return [];
79
- return ($series.children || []).map((id) => $g.nodes[id]).filter(Boolean);
142
+ if (!$g || !$series) return { primary: [], other: [] };
143
+ const children = ($series.children || []).map((id) => $g.nodes[id]).filter(Boolean);
144
+ return organizeChildren(children, 'series');
80
145
  },
81
146
  );
82
147
 
@@ -87,17 +152,39 @@ export const currentAnthology = derived(
87
152
  ([$g, $anthologyId]) => ($g && $anthologyId ? $g.nodes[$anthologyId] : null),
88
153
  );
89
154
 
90
- export const anthologySeries = derived(
155
+ export const currentBookId = writable(/** @type {string|null} */ (null));
156
+
157
+ export const currentBook = derived(
158
+ [universeGraph, currentBookId],
159
+ ([$g, $bookId]) => ($g && $bookId ? $g.nodes[$bookId] : null),
160
+ );
161
+
162
+ export const bookChildren = derived(
163
+ [universeGraph, currentBook],
164
+ ([$g, $book]) => {
165
+ if (!$g || !$book) return { primary: [], other: [] };
166
+ const children = ($book.children || []).map((id) => $g.nodes[id]).filter(Boolean);
167
+ return organizeChildren(children, 'book');
168
+ },
169
+ );
170
+
171
+ export const anthologyChildren = derived(
91
172
  [universeGraph, currentAnthology],
92
173
  ([$g, $anthology]) => {
93
- if (!$g || !$anthology) return [];
94
- return ($anthology.children || [])
174
+ if (!$g || !$anthology) return { primary: [], other: [] };
175
+ const children = ($anthology.children || [])
95
176
  .map((id) => $g.nodes[id])
96
- .filter(Boolean)
97
- .filter((node) => node.kind === 'series');
177
+ .filter(Boolean);
178
+ return organizeChildren(children, 'anthology');
98
179
  },
99
180
  );
100
181
 
182
+ // Keep old name for backward compatibility during migration
183
+ export const anthologySeries = derived(
184
+ [anthologyChildren],
185
+ ([$organized]) => $organized.primary,
186
+ );
187
+
101
188
  /**
102
189
  * Get contextual relationships for a node
103
190
  * @param {UniverseGraph | null} graph
@@ -3,7 +3,7 @@ import { writable } from 'svelte/store';
3
3
  /**
4
4
  * Store for describe block rendering mode.
5
5
  * Values: 'plain' | 'lists'
6
- * Default: 'plain'
6
+ * Default: 'lists'
7
7
  */
8
- export const describeRenderMode = writable(/** @type {'plain' | 'lists'} */ ('plain'));
8
+ export const describeRenderMode = writable(/** @type {'plain' | 'lists'} */ ('lists'));
9
9
 
package/src/main.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import './styles/app.css';
2
+ import '@fortawesome/fontawesome-free/css/all.css';
2
3
  import './lib/stores/theme.js'; // Initialize theme store
3
4
  import { theme } from './lib/stores/theme.js';
4
5
  import { get } from 'svelte/store';
@@ -49,10 +50,21 @@ async function initTexture() {
49
50
  const effectiveTheme = getEffectiveTheme(themeValue);
50
51
  const url = effectiveTheme === 'dark' ? textureState.dark : textureState.light;
51
52
  if (url) {
53
+ // Apply texture to body
52
54
  document.body.style.backgroundImage = `url(${url})`;
53
55
  document.body.style.backgroundRepeat = 'repeat';
54
56
  document.body.style.backgroundSize = '1024px 1024px';
55
57
  document.body.style.backgroundAttachment = 'fixed';
58
+
59
+ // Apply same texture to top bar so it matches the background
60
+ const topBar = document.querySelector('.top-bar');
61
+ if (topBar) {
62
+ topBar.style.backgroundImage = `url(${url})`;
63
+ topBar.style.backgroundRepeat = 'repeat';
64
+ topBar.style.backgroundSize = '1024px 1024px';
65
+ topBar.style.backgroundAttachment = 'fixed';
66
+ topBar.style.backgroundPosition = '0 0'; // Align with body
67
+ }
56
68
  }
57
69
  }
58
70
 
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import { currentAnthology, anthologySeries, universeGraph, currentUniverseName, universeRootNode, getNodeRoute, currentAnthologyId } from '../lib/data/universeStore.js';
2
+ import { currentAnthology, anthologyChildren, universeGraph, currentUniverseName, universeRootNode, getNodeRoute, currentAnthologyId } from '../lib/data/universeStore.js';
3
3
  import { getDisplayTitle } from '../lib/format/title.js';
4
4
  import Prose from '../lib/components/Prose.svelte';
5
5
  import ContentsCard from '../lib/components/ContentsCard.svelte';
@@ -32,7 +32,10 @@
32
32
  </section>
33
33
 
34
34
  <aside class="index">
35
- <ContentsCard children={$anthologySeries} />
35
+ {#if $anthologyChildren.primary.length > 0 || $anthologyChildren.other.length > 0}
36
+ {@const allChildren = [...$anthologyChildren.primary, ...$anthologyChildren.other]}
37
+ <ContentsCard children={allChildren} />
38
+ {/if}
36
39
  </aside>
37
40
  </div>
38
41
 
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import { universeGraph, currentUniverseName, universeRootNode, getNodeRoute, getRelationshipsForNode, getAncestorChain } from '../lib/data/universeStore.js';
2
+ import { universeGraph, currentUniverseName, universeRootNode, getNodeRoute, getRelationshipsForNode, getAncestorChain, organizeChildren } from '../lib/data/universeStore.js';
3
3
  import { getDisplayTitle } from '../lib/format/title.js';
4
4
  import Prose from '../lib/components/Prose.svelte';
5
5
  import ContentsCard from '../lib/components/ContentsCard.svelte';
@@ -21,7 +21,8 @@
21
21
  // Decode the node ID from URL
22
22
  $: nodeId = decodeURIComponent(params.id);
23
23
  $: currentNode = $universeGraph?.nodes[nodeId];
24
- $: children = currentNode?.children?.map((id) => $universeGraph?.nodes[id]).filter(Boolean) || [];
24
+ $: rawChildren = currentNode?.children?.map((id) => $universeGraph?.nodes[id]).filter(Boolean) || [];
25
+ $: organizedChildren = currentNode ? organizeChildren(rawChildren, currentNode.kind) : { primary: [], other: [] };
25
26
  $: relationships = currentNode ? getRelationshipsForNode($universeGraph, nodeId) : [];
26
27
  $: ancestors = currentNode ? getAncestorChain($universeGraph, currentNode) : [];
27
28
  $: showContextLine = currentNode && (currentNode.kind === 'book' || currentNode.kind === 'chapter' || (currentNode.kind === 'concept' && currentNode.parent));
@@ -128,11 +129,34 @@
128
129
 
129
130
 
130
131
  $: subtitle = (() => {
132
+ if (!currentNode) return '';
131
133
  if (showContextLine) {
132
- if (currentNode.kind === 'book' && ancestors[0]) {
133
- const series = ancestors[0];
134
- const seriesRoute = getNodeRoute(series);
135
- return `A book in the <a href="${seriesRoute}">${getDisplayTitle(series)}</a> series`;
134
+ if (currentNode.kind === 'book') {
135
+ // Check if book belongs to a series
136
+ if (ancestors[0] && ancestors[0].kind === 'series') {
137
+ const series = ancestors[0];
138
+ const seriesRoute = getNodeRoute(series);
139
+ return `A book in the <a href="${seriesRoute}">${getDisplayTitle(series)}</a> series`;
140
+ }
141
+
142
+ // Check if book belongs to an anthology (but not a series)
143
+ if (currentNode.parent && $universeGraph) {
144
+ const parentNode = $universeGraph.nodes[currentNode.parent];
145
+ if (parentNode && parentNode.kind === 'anthology') {
146
+ const anthologyRoute = getNodeRoute(parentNode);
147
+ const anthologyName = getDisplayTitle(parentNode);
148
+ const universeLink = $universeRootNode
149
+ ? `<a href="/">${getDisplayTitle($universeRootNode) || params.universe}</a>`
150
+ : params.universe;
151
+ return `A book in <a href="${anthologyRoute}">${anthologyName}</a> (in ${universeLink})`;
152
+ }
153
+ }
154
+
155
+ // Standalone book - link to universe home page
156
+ const universeLink = $universeRootNode
157
+ ? `<a href="/">${getDisplayTitle($universeRootNode) || params.universe}</a>`
158
+ : params.universe;
159
+ return `A book in ${universeLink}`;
136
160
  } else if (currentNode.kind === 'chapter' && ancestors[0] && ancestors[1]) {
137
161
  const book = ancestors[0];
138
162
  const series = ancestors[1];
@@ -162,6 +186,13 @@
162
186
  }
163
187
  }
164
188
  }
189
+ // Fallback for books without ancestors - link to universe home page
190
+ if (currentNode.kind === 'book') {
191
+ const universeLink = $universeRootNode
192
+ ? `<a href="/">${getDisplayTitle($universeRootNode) || params.universe}</a>`
193
+ : params.universe;
194
+ return `A book in ${universeLink}`;
195
+ }
165
196
  return `${currentNode.kind} in ${params.universe}`;
166
197
  } else {
167
198
  if (currentNode.kind === 'concept') {
@@ -181,9 +212,10 @@
181
212
  <Prose textBlock={currentNode.describe} />
182
213
  </section>
183
214
 
184
- {#if children.length > 0}
215
+ {#if organizedChildren.primary.length > 0 || organizedChildren.other.length > 0}
216
+ {@const allChildren = [...organizedChildren.primary, ...organizedChildren.other]}
185
217
  <aside class="index">
186
- <ContentsCard children={children} currentNode={currentNode} />
218
+ <ContentsCard children={allChildren} currentNode={currentNode} />
187
219
  </aside>
188
220
  {/if}
189
221
  </div>
@@ -223,7 +255,7 @@
223
255
  <li class="relationship-item">
224
256
  <a class="relationship-link sprig-link" href={getNodeRoute(rel.otherNode)}>
225
257
  <span class="relationship-label">{rel.label}</span>
226
- <span class="relationship-separator">→</span>
258
+ <span class="relationship-separator"><i class="fas fa-arrow-right" aria-hidden="true"></i></span>
227
259
  <span class="relationship-name">{displayName}</span>
228
260
  <span class="relationship-kind">{rel.otherNode.kind}</span>
229
261
  </a>
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import { universeRootNode, rootChildren, rootAnthologies, rootUngroupedSeries, universeGraph } from '../lib/data/universeStore.js';
2
+ import { universeRootNode, rootChildren, universeGraph } from '../lib/data/universeStore.js';
3
3
  import UniverseHeader from '../lib/components/UniverseHeader.svelte';
4
4
  import Prose from '../lib/components/Prose.svelte';
5
5
  import ContentsCard from '../lib/components/ContentsCard.svelte';
@@ -15,15 +15,13 @@
15
15
  </section>
16
16
 
17
17
  <aside class="index">
18
- {#if $rootAnthologies.length > 0}
19
- <ContentsCard children={$rootAnthologies} title="Anthologies" />
20
- {#if $rootUngroupedSeries.length > 0}
21
- <div class="other-series">
22
- <ContentsCard children={$rootUngroupedSeries} title="Other series" />
23
- </div>
24
- {/if}
25
- {:else}
26
- <ContentsCard children={$rootChildren} title="Concepts in this universe" />
18
+ {#if $rootChildren.primary.length > 0}
19
+ <ContentsCard children={$rootChildren.primary} />
20
+ {/if}
21
+ {#if $rootChildren.other.length > 0}
22
+ <div class="other-contents">
23
+ <ContentsCard children={$rootChildren.other} title="Other" />
24
+ </div>
27
25
  {/if}
28
26
  </aside>
29
27
  </div>
@@ -55,7 +53,7 @@
55
53
  width: 100%;
56
54
  }
57
55
 
58
- .other-series {
56
+ .other-contents {
59
57
  margin-top: 1rem;
60
58
  }
61
59
 
@@ -151,7 +151,10 @@
151
151
  </section>
152
152
 
153
153
  <aside class="index">
154
- <ContentsCard children={$seriesChildren} />
154
+ {#if $seriesChildren.primary.length > 0 || $seriesChildren.other.length > 0}
155
+ {@const allChildren = [...$seriesChildren.primary, ...$seriesChildren.other]}
156
+ <ContentsCard children={allChildren} />
157
+ {/if}
155
158
  </aside>
156
159
  </div>
157
160
 
@@ -172,7 +175,7 @@
172
175
  <li class="relationship-item">
173
176
  <a class="relationship-link sprig-link" href={getNodeRoute(rel.otherNode)}>
174
177
  <span class="relationship-label">{rel.label}</span>
175
- <span class="relationship-separator">→</span>
178
+ <span class="relationship-separator"><i class="fas fa-arrow-right" aria-hidden="true"></i></span>
176
179
  <span class="relationship-name">{displayName}</span>
177
180
  <span class="relationship-kind">{rel.otherNode.kind}</span>
178
181
  </a>
@@ -44,7 +44,7 @@
44
44
  --sprig-link-anchor-underline: rgba(0, 0, 0, 0.35);
45
45
  --sprig-link-anchor-underline-hover: rgba(0, 0, 0, 0.5);
46
46
 
47
- --card-bg: rgba(235, 225, 210, 0.8); /* Original parchment tone for light theme */
47
+ --card-bg: rgb(235, 225, 210); /* Opaque parchment tone for light theme */
48
48
  --card-border: var(--border-color);
49
49
 
50
50
  --hairline: var(--border-color);
@@ -172,7 +172,7 @@ html[data-theme="light"] {
172
172
  --sprig-link-anchor-underline: rgba(0, 0, 0, 0.35);
173
173
  --sprig-link-anchor-underline-hover: rgba(0, 0, 0, 0.5);
174
174
 
175
- --card-bg: rgba(235, 225, 210, 0.8); /* Original parchment tone for light theme */
175
+ --card-bg: rgb(235, 225, 210); /* Opaque parchment tone for light theme */
176
176
  --card-border: var(--border-color);
177
177
 
178
178
  --hairline: var(--border-color);
@@ -1 +0,0 @@
1
- .sprig-design{--sp-font-tiny: .75rem;--sp-font-small: .875rem;--sp-font-body: 1rem;--sp-font-h1: 3rem;--sp-font-h2: 1.5rem;--sp-font-h3: 1.25rem;--sp-line-body: 1.7;--sp-line-tight: 1.3;--sp-line-loose: 1.9;--sp-space-1: .25rem;--sp-space-2: .5rem;--sp-space-3: .75rem;--sp-space-4: 1rem;--sp-space-6: 1.5rem;--sp-space-8: 2rem;--sp-space-12: 3rem}.sprig-design .sp-prose{font-size:var(--sp-font-body);line-height:var(--sp-line-body)}.sprig-design .sp-prose p{margin:0 0 var(--sp-space-4) 0}.sprig-design .sp-prose h1{font-size:var(--sp-font-h1);line-height:1.15;margin:0 0 var(--sp-space-12) 0}.sprig-design .sp-prose h2{font-size:var(--sp-font-h2);line-height:var(--sp-line-tight);margin:var(--sp-space-12) 0 var(--sp-space-3) 0}.sprig-design .sp-prose h3{font-size:var(--sp-font-h3);line-height:var(--sp-line-tight);margin:var(--sp-space-8) 0 var(--sp-space-2) 0}.sprig-design .sp-prose small,.sprig-design .sp-prose .sp-meta{font-size:var(--sp-font-small);line-height:var(--sp-line-tight)}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}:root{--font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;--font-prose: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;--text-color: #1a1a1a;--text-secondary: #4a4a4a;--text-tertiary: #464646;--bg-color: #fafafa;--border-color: #e0e0e0;--dictionary-bg: #f5f5f5;--code-bg: #f8f8f8;--code-border: #e8e8e8;--bg: var(--bg-color);--text: var(--text-color);--muted: var(--text-secondary);--link-structural: #2a2a2a;--link-exploratory: #3d3d3d;--link-underline: rgba(0, 0, 0, .2);--sprig-link-fg: #2a2a2a;--sprig-link-underline: rgba(0, 0, 0, .25);--sprig-link-underline-hover: rgba(0, 0, 0, .4);--sprig-link-anchor-fg: #1f1f1f;--sprig-link-anchor-underline: rgba(0, 0, 0, .35);--sprig-link-anchor-underline-hover: rgba(0, 0, 0, .5);--card-bg: rgba(235, 225, 210, .8);--card-border: var(--border-color);--hairline: var(--border-color);--hover: rgba(0, 0, 0, .04);--tex-a: .015;--tex-b: .01}@media(prefers-color-scheme:dark){:root{--text-color: #e8e8e8;--text-secondary: #b8b8b8;--text-tertiary: #b4b4b4;--bg-color: #24221f;--border-color: #3a3a3a;--dictionary-bg: #1c1a17;--code-bg: #1c1a17;--code-border: #2a2a2a;--bg: var(--bg-color);--text: var(--text-color);--muted: var(--text-secondary);--link-structural: #e8e8e8;--link-exploratory: #b8b8b8;--link-underline: rgba(255, 255, 255, .3);--sprig-link-fg: #e8e8e8;--sprig-link-underline: rgba(255, 255, 255, .35);--sprig-link-underline-hover: rgba(255, 255, 255, .5);--sprig-link-anchor-fg: #e8e8e8;--sprig-link-anchor-underline: rgba(255, 255, 255, .45);--sprig-link-anchor-underline-hover: rgba(255, 255, 255, .6);--card-bg: var(--dictionary-bg);--card-border: var(--border-color);--hairline: var(--border-color);--hover: rgba(255, 255, 255, .06);--tex-a: .03;--tex-b: .02}}html,body{margin:0;padding:0}html[data-theme=dark]{--text-color: #e8e8e8;--text-secondary: #b8b8b8;--text-tertiary: #b4b4b4;--bg-color: #24221f;--border-color: #3a3a3a;--dictionary-bg: #1c1a17;--code-bg: #1c1a17;--code-border: #2a2a2a;--bg: var(--bg-color);--text: var(--text-color);--muted: var(--text-secondary);--link-structural: #e8e8e8;--link-exploratory: #b8b8b8;--link-underline: rgba(255, 255, 255, .3);--sprig-link-fg: #e8e8e8;--sprig-link-underline: rgba(255, 255, 255, .35);--sprig-link-underline-hover: rgba(255, 255, 255, .5);--sprig-link-anchor-fg: #e8e8e8;--sprig-link-anchor-underline: rgba(255, 255, 255, .45);--sprig-link-anchor-underline-hover: rgba(255, 255, 255, .6);--card-bg: var(--dictionary-bg);--card-border: var(--border-color);--hairline: var(--border-color);--hover: rgba(255, 255, 255, .06);--tex-a: .03;--tex-b: .02}html[data-theme=light]{--text-color: #1a1a1a;--text-secondary: #4a4a4a;--text-tertiary: #464646;--bg-color: #fafafa;--border-color: #e0e0e0;--dictionary-bg: #f5f5f5;--code-bg: #f8f8f8;--code-border: #e8e8e8;--bg: var(--bg-color);--text: var(--text-color);--muted: var(--text-secondary);--link-structural: #2a2a2a;--link-exploratory: #3d3d3d;--link-underline: rgba(0, 0, 0, .2);--sprig-link-fg: #2a2a2a;--sprig-link-underline: rgba(0, 0, 0, .25);--sprig-link-underline-hover: rgba(0, 0, 0, .4);--sprig-link-anchor-fg: #1f1f1f;--sprig-link-anchor-underline: rgba(0, 0, 0, .35);--sprig-link-anchor-underline-hover: rgba(0, 0, 0, .5);--card-bg: rgba(235, 225, 210, .8);--card-border: var(--border-color);--hairline: var(--border-color);--hover: rgba(0, 0, 0, .04);--tex-a: .015;--tex-b: .01}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:var(--sp-font-body);line-height:var(--sp-line-body);color:var(--text-color);background-color:var(--bg-color);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{color:inherit;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.25rem;text-decoration-color:#00000040;transition:text-decoration-thickness .15s ease,text-decoration-color .15s ease;cursor:pointer}@media(prefers-color-scheme:dark){a{text-decoration-color:#ffffff59}}html[data-theme=dark] a{text-decoration-color:#ffffff59}html[data-theme=light] a{text-decoration-color:#00000040}a:hover{text-decoration-thickness:1.5px;text-decoration-color:#0006}@media(prefers-color-scheme:dark){a:hover{text-decoration-color:#ffffff80}}html[data-theme=dark] a:hover{text-decoration-color:#ffffff80}html[data-theme=light] a:hover{text-decoration-color:#0006}a:focus{outline:2px solid var(--text-tertiary);outline-offset:2px;border-radius:2px}a.sprig-link,.sprig-link{color:var(--sprig-link-fg);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px;text-decoration-color:#00000040;cursor:pointer;transition:text-decoration-thickness .15s ease,text-decoration-color .15s ease}@media(prefers-color-scheme:dark){a.sprig-link,.sprig-link{text-decoration-color:#ffffff59}}html[data-theme=dark] a.sprig-link,html[data-theme=dark] .sprig-link{text-decoration-color:#ffffff59}html[data-theme=light] a.sprig-link,html[data-theme=light] .sprig-link{text-decoration-color:#00000040}a.sprig-link:hover,.sprig-link:hover{text-decoration-thickness:1.5px;text-decoration-color:#0006}@media(prefers-color-scheme:dark){a.sprig-link:hover,.sprig-link:hover{text-decoration-color:#ffffff80}}html[data-theme=dark] a.sprig-link:hover,html[data-theme=dark] .sprig-link:hover{text-decoration-color:#ffffff80}html[data-theme=light] a.sprig-link:hover,html[data-theme=light] .sprig-link:hover{text-decoration-color:#0006}a.sprig-link:focus-visible,.sprig-link:focus-visible{outline:2px solid var(--text-tertiary);outline-offset:3px;border-radius:2px}a.sprig-link--quiet,.sprig-link--quiet{color:var(--sprig-link-fg);text-decoration-color:#00000040;opacity:.9}@media(prefers-color-scheme:dark){a.sprig-link--quiet,.sprig-link--quiet{text-decoration-color:#ffffff59}}html[data-theme=dark] a.sprig-link--quiet,html[data-theme=dark] .sprig-link--quiet{text-decoration-color:#ffffff59}html[data-theme=light] a.sprig-link--quiet,html[data-theme=light] .sprig-link--quiet{text-decoration-color:#00000040}a.sprig-link--quiet:hover,.sprig-link--quiet:hover{text-decoration-thickness:1.5px;text-decoration-color:#0006;opacity:1}@media(prefers-color-scheme:dark){a.sprig-link--quiet:hover,.sprig-link--quiet:hover{text-decoration-color:#ffffff80}}html[data-theme=dark] a.sprig-link--quiet:hover,html[data-theme=dark] .sprig-link--quiet:hover{text-decoration-color:#ffffff80}html[data-theme=light] a.sprig-link--quiet:hover,html[data-theme=light] .sprig-link--quiet:hover{text-decoration-color:#0006}.search-container.svelte-1ytcet{display:flex;flex:1}.search-wrapper.svelte-1ytcet{position:relative;max-width:500px;width:100%}.search-input.svelte-1ytcet{width:100%;padding:10px 14px;font-family:var(--font-ui);font-size:var(--sp-font-small);color:var(--text-color);background:var(--card-bg);border:none;border-radius:4px;outline:none;transition:box-shadow .2s}.search-input.svelte-1ytcet:focus{box-shadow:0 0 0 3px #0000000d}@media(prefers-color-scheme:dark){.search-input.svelte-1ytcet:focus{box-shadow:0 0 0 3px #ffffff0d}}html[data-theme=dark] .search-input.svelte-1ytcet:focus{box-shadow:0 0 0 3px #ffffff0d}.search-input.svelte-1ytcet::placeholder{color:var(--text-tertiary)}.results-dropdown.svelte-1ytcet{position:absolute;top:calc(100% + 4px);left:0;right:0;background:var(--bg-color);border:1px solid var(--border-color);border-radius:4px;box-shadow:0 4px 12px #00000014;max-height:400px;overflow-y:auto;z-index:1000;margin-top:4px}@media(prefers-color-scheme:dark){.results-dropdown.svelte-1ytcet{box-shadow:0 4px 12px #0000004d}}html[data-theme=dark] .results-dropdown.svelte-1ytcet{box-shadow:0 4px 12px #0000004d}.result-item.svelte-1ytcet{display:block;padding:12px 14px;text-decoration:none;color:inherit;border-bottom:1px solid var(--hairline);transition:background-color .15s;cursor:pointer}.result-item.svelte-1ytcet:last-child{border-bottom:none}.result-item.svelte-1ytcet:hover,.result-item.svelte-1ytcet:focus{background:var(--hover);outline:none}.result-item.svelte-1ytcet:focus-visible{outline:2px solid var(--text-tertiary);outline-offset:-2px}.result-item--active.svelte-1ytcet{background:var(--hover)}.result-item--active.svelte-1ytcet .result-title:where(.svelte-1ytcet){text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px;text-decoration-color:var(--text-secondary)}.result-content.svelte-1ytcet{display:flex;flex-direction:column;gap:4px}.result-title.svelte-1ytcet{font-family:var(--font-prose);font-size:var(--sp-font-body);color:var(--text-color);font-weight:400}.result-meta.svelte-1ytcet{display:flex;align-items:center;gap:8px;font-family:var(--font-ui);font-size:var(--sp-font-tiny)}.result-kind.svelte-1ytcet{color:var(--text-tertiary);text-transform:capitalize;font-weight:400}.result-context.svelte-1ytcet{color:var(--text-secondary)}.result-context.svelte-1ytcet:before{content:"·";margin-right:4px;color:var(--text-tertiary)}.header.svelte-162svzm{margin-bottom:48px}.title.svelte-162svzm{font-size:var(--sp-font-h1);font-weight:400;line-height:1.2;margin-bottom:0;color:var(--text-color);letter-spacing:-.5px;font-family:var(--font-prose)}.subtitle.svelte-162svzm{margin:0;font-size:var(--sp-font-body);line-height:1.6;color:var(--text-color);font-family:var(--font-ui)}.subtitle.svelte-162svzm a{color:inherit;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.25rem;text-decoration-color:#00000040;transition:text-decoration-thickness .15s ease,text-decoration-color .15s ease}@media(prefers-color-scheme:dark){:root:not([data-theme=light]) .subtitle.svelte-162svzm a{text-decoration-color:#ffffff59}}html[data-theme=dark] .subtitle.svelte-162svzm a{text-decoration-color:#ffffff59}html[data-theme=light] .subtitle.svelte-162svzm a{text-decoration-color:#00000040}.subtitle.svelte-162svzm a:hover{text-decoration-thickness:1.5px;text-decoration-color:#0006}@media(prefers-color-scheme:dark){:root:not([data-theme=light]) .subtitle.svelte-162svzm a:hover{text-decoration-color:#ffffff80}}html[data-theme=dark] .subtitle.svelte-162svzm a:hover{text-decoration-color:#ffffff80}html[data-theme=light] .subtitle.svelte-162svzm a:hover{text-decoration-color:#0006}@media(max-width:768px){.title.svelte-162svzm{font-size:36px;margin-bottom:32px;letter-spacing:-.3px}.subtitle.svelte-162svzm{font-size:var(--sp-font-body);line-height:1.65}}@media(max-width:480px){.title.svelte-162svzm{font-size:32px;margin-bottom:28px;letter-spacing:-.2px}.subtitle.svelte-162svzm{font-size:var(--sp-font-body)}}.prose.svelte-1szor9z{max-width:70ch;font-size:var(--sp-font-body);line-height:var(--sp-line-body)}p.svelte-1szor9z{font-size:var(--sp-font-body);line-height:var(--sp-line-body);margin-bottom:var(--sp-space-4);color:var(--text-color)}p.svelte-1szor9z:last-child{margin-bottom:0}ul.svelte-1szor9z{list-style:none;padding-left:0;margin-bottom:var(--sp-space-6)}ul.svelte-1szor9z li:where(.svelte-1szor9z){font-size:var(--sp-font-body);line-height:var(--sp-line-loose);color:var(--text-secondary);margin-bottom:var(--sp-space-3);padding-left:var(--sp-space-6);position:relative}ul.svelte-1szor9z li:where(.svelte-1szor9z):before{content:"—";position:absolute;left:0;color:var(--text-tertiary)}ul.svelte-1szor9z li:where(.svelte-1szor9z):last-child{margin-bottom:0}ol.svelte-1szor9z{margin-bottom:var(--sp-space-6);padding-left:var(--sp-space-6)}ol.svelte-1szor9z li:where(.svelte-1szor9z){font-size:var(--sp-font-body);line-height:var(--sp-line-body);margin-bottom:var(--sp-space-3);color:var(--text-color)}ol.svelte-1szor9z li:where(.svelte-1szor9z):last-child{margin-bottom:0}.empty.svelte-1szor9z{color:var(--text-tertiary);font-size:var(--sp-font-small);padding:10px 0}@media(max-width:480px){ul.svelte-1szor9z li:where(.svelte-1szor9z){padding-left:20px}}.card.svelte-fr86xg{background-color:var(--card-bg);border-radius:4px;padding:24px;font-size:var(--sp-font-small);line-height:1.6;width:100%;position:sticky;top:32px}.title.svelte-fr86xg{font-size:var(--sp-font-tiny);color:var(--text-tertiary);letter-spacing:.5px;margin-bottom:20px;font-family:var(--font-ui)}.list.svelte-fr86xg{list-style:none;padding:0;margin:0}.item.svelte-fr86xg{margin-bottom:20px;color:var(--text-secondary)}.item.svelte-fr86xg:last-child{margin-bottom:0}.link.svelte-fr86xg{align-items:center;background:none;border:none;cursor:pointer;display:flex;font-family:inherit;font-size:inherit;gap:.75rem;justify-content:space-between;padding:0;text-align:left;width:100%}.link.sprig-link.svelte-fr86xg{text-decoration:none}.link.sprig-link.svelte-fr86xg .name:where(.svelte-fr86xg){text-decoration:none}.link.sprig-link.svelte-fr86xg:hover .name:where(.svelte-fr86xg){text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.25rem;text-decoration-color:#00000040}@media(prefers-color-scheme:dark){:root:not([data-theme=light]) .link.sprig-link.svelte-fr86xg:hover .name:where(.svelte-fr86xg){text-decoration-color:#ffffff59}}html[data-theme=dark] .link.sprig-link.svelte-fr86xg:hover .name:where(.svelte-fr86xg){text-decoration-color:#ffffff59}html[data-theme=light] .link.sprig-link.svelte-fr86xg:hover .name:where(.svelte-fr86xg){text-decoration-color:#0006}.link.svelte-fr86xg:focus{outline:2px solid var(--text-tertiary);outline-offset:.25rem;border-radius:2px}.name.svelte-fr86xg{font-size:var(--sp-font-body);font-family:var(--font-prose);font-weight:400;color:var(--text-color)}.kind.svelte-fr86xg{font-size:var(--sp-font-tiny);color:var(--text-tertiary);font-family:var(--font-ui);font-style:italic;font-weight:400;text-decoration:none}.empty.svelte-fr86xg{color:var(--text-tertiary);font-size:var(--sp-font-small);margin:0;font-family:var(--font-ui)}@media(max-width:768px){.card.svelte-fr86xg{padding:20px;font-size:var(--sp-font-small);position:static}.item.svelte-fr86xg{margin-bottom:20px}}@media(max-width:480px){.card.svelte-fr86xg{padding:18px;font-size:var(--sp-font-tiny)}}.footer.svelte-1ynevzn{padding:2rem 0;border-top:1px solid var(--border-color);margin-top:4rem;width:100%;overflow-x:hidden;display:flex;justify-content:space-between;gap:18px;font-size:var(--sp-font-tiny);color:var(--text-tertiary);max-width:1200px;margin-left:auto;margin-right:auto}.left.svelte-1ynevzn,.right.svelte-1ynevzn{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.label.svelte-1ynevzn{color:var(--text-tertiary)}.value.svelte-1ynevzn{color:var(--text-secondary)}.dot.svelte-1ynevzn{color:var(--text-tertiary)}@media(max-width:768px){.footer.svelte-1ynevzn{padding:2rem 0;margin-top:48px;font-size:var(--sp-font-tiny)}}@media(max-width:480px){.footer.svelte-1ynevzn{padding:1.5rem 0;margin-top:40px;font-size:var(--sp-font-tiny)}}.grid.svelte-bpgxme{display:grid;grid-template-columns:1fr 350px;gap:64px;align-items:start;max-width:1200px;margin:0 auto;width:100%}.narrative.svelte-bpgxme{max-width:680px;min-width:0;width:100%}.index.svelte-bpgxme{min-width:0;width:100%}.other-series.svelte-bpgxme{margin-top:1rem}.loading.svelte-bpgxme{color:var(--text-tertiary);padding:24px 0}@media(max-width:768px){.grid.svelte-bpgxme{grid-template-columns:1fr;gap:32px}}@media(max-width:480px){.grid.svelte-bpgxme{gap:32px}}.grid.svelte-1f5uo2k{display:grid;grid-template-columns:1fr 350px;gap:64px;align-items:start;max-width:1200px;margin:0 auto;width:100%}.narrative.svelte-1f5uo2k{max-width:680px;min-width:0;width:100%}.index.svelte-1f5uo2k{min-width:0;width:100%}.relationships.svelte-1f5uo2k{margin-top:32px;padding-top:24px;border-top:1px solid var(--hairline)}.relationships-title.svelte-1f5uo2k{font-family:var(--font-ui);font-size:var(--sp-font-tiny);letter-spacing:.02em;text-transform:none;color:var(--text-secondary);margin:0 0 .75rem}.relationships-list.svelte-1f5uo2k{list-style:none;padding:0;margin:0}.relationship-item.svelte-1f5uo2k{margin-bottom:2rem}.relationship-item.svelte-1f5uo2k:last-child{margin-bottom:0}.relationship-link.svelte-1f5uo2k{display:flex;align-items:center;gap:8px;padding:4px 0}.relationship-link.sprig-link.svelte-1f5uo2k{text-decoration:none}.relationship-link.sprig-link.svelte-1f5uo2k .relationship-name:where(.svelte-1f5uo2k){text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.1875rem;text-decoration-color:var(--sprig-link-underline)}.relationship-link.sprig-link.svelte-1f5uo2k:hover .relationship-name:where(.svelte-1f5uo2k){text-decoration-thickness:1.5px;text-decoration-color:var(--sprig-link-underline-hover)}.relationship-label.svelte-1f5uo2k{font-family:var(--font-ui);font-size:var(--sp-font-small);color:var(--text-secondary)}.relationship-separator.svelte-1f5uo2k{font-family:var(--font-ui);font-size:var(--sp-font-small);color:var(--text-tertiary);opacity:.6}.relationship-name.svelte-1f5uo2k{font-family:var(--font-prose);font-size:var(--sp-font-small);color:inherit}.relationship-kind.svelte-1f5uo2k{font-family:var(--font-ui);font-size:var(--sp-font-tiny);color:var(--text-tertiary);margin-left:auto}.relationship-description.svelte-1f5uo2k{margin:8px 0 0;font-family:var(--font-prose);font-size:var(--sp-font-body);color:var(--text-secondary);line-height:1.6;max-width:70ch}.loading.svelte-1f5uo2k{color:var(--text-tertiary);padding:24px 0}.references.svelte-1f5uo2k{margin-top:32px;padding-top:24px;border-top:1px solid var(--hairline)}.references-title.svelte-1f5uo2k{font-family:var(--font-ui);font-size:var(--sp-font-tiny);letter-spacing:.02em;text-transform:none;color:var(--text-secondary);margin:0 0 .75rem}.references-subtitle.svelte-1f5uo2k{font-family:var(--font-ui);font-size:var(--sp-font-tiny);color:var(--text-tertiary);margin:0 0 1.5rem}.reference-list.svelte-1f5uo2k{list-style:none;padding:0;margin:0}.reference-item.svelte-1f5uo2k{margin-bottom:2rem}.reference-item.svelte-1f5uo2k:last-child{margin-bottom:0}.reference-repo-pill.svelte-1f5uo2k{display:inline-flex;align-items:center;gap:6px;padding:2px 10px;border-radius:999px;font-family:var(--font-ui);font-size:var(--sp-font-small);text-transform:lowercase;color:var(--text-tertiary);border:1px solid var(--hairline);margin-bottom:1rem;text-decoration:none}.reference-path-link.svelte-1f5uo2k{display:block;margin-top:2px;font-family:ui-monospace,SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace;font-size:var(--sp-font-body);color:inherit;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.1875rem;text-decoration-color:var(--sprig-link-underline)}.reference-row.svelte-1f5uo2k{display:flex;align-items:baseline;gap:8px}.reference-kind.svelte-1f5uo2k{margin-left:auto;font-family:var(--font-ui);font-size:var(--sp-font-small);color:var(--text-tertiary)}.reference-description.svelte-1f5uo2k,.reference-note.svelte-1f5uo2k{margin:6px 0 0;font-family:var(--font-prose);font-size:var(--sp-font-body);color:var(--text-secondary);line-height:1.5;max-width:70ch}.reference-links-list.svelte-1f5uo2k{list-style:none;padding:0;margin:8px 0 0}.reference-group-list.svelte-1f5uo2k{list-style:none;padding:0;margin:0}.reference-group-item.svelte-1f5uo2k+.reference-group-item:where(.svelte-1f5uo2k){margin-top:2rem}.reference-links-item.svelte-1f5uo2k{margin-bottom:6px}.reference-links-item.svelte-1f5uo2k:last-child{margin-bottom:0}@media(max-width:768px){.grid.svelte-1f5uo2k{grid-template-columns:1fr;gap:32px}}@media(max-width:480px){.grid.svelte-1f5uo2k{gap:32px}}.grid.svelte-10bbj5c{display:grid;grid-template-columns:1fr 350px;gap:64px;align-items:start;max-width:1200px;margin:0 auto;width:100%}.narrative.svelte-10bbj5c{max-width:680px;min-width:0;width:100%}.index.svelte-10bbj5c{min-width:0;width:100%}.loading.svelte-10bbj5c{color:var(--text-tertiary);padding:24px 0}@media(max-width:768px){.grid.svelte-10bbj5c{grid-template-columns:1fr;gap:32px}}@media(max-width:480px){.grid.svelte-10bbj5c{gap:32px}}.grid.svelte-9edgfz{display:grid;grid-template-columns:1fr 350px;gap:64px;align-items:start;max-width:1200px;margin:0 auto;width:100%}.narrative.svelte-9edgfz{max-width:680px;min-width:0;width:100%}.index.svelte-9edgfz{min-width:0;width:100%}.chapter-navigation.svelte-9edgfz{margin-top:20px;padding-top:18px}.chapter-navigation-title.svelte-9edgfz{font-family:var(--font-prose);font-size:var(--sp-font-small);letter-spacing:0;text-transform:none;color:var(--text-secondary);margin:0 0 .5rem;font-weight:400}.chapter-navigation-list.svelte-9edgfz{list-style:none;padding:0;margin:0}.chapter-navigation-item.svelte-9edgfz{margin-bottom:.4rem}.chapter-navigation-item.svelte-9edgfz:last-child{margin-bottom:0}.chapter-navigation-link.svelte-9edgfz{display:inline-block;font-family:var(--font-prose);font-size:var(--sp-font-body);font-weight:400;color:inherit;padding:2px 0;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.1875rem;text-decoration-color:var(--sprig-link-underline)}.chapter-navigation-link.svelte-9edgfz:hover{text-decoration-thickness:1.5px;text-decoration-color:var(--sprig-link-underline-hover)}.relationships.svelte-9edgfz{margin-top:32px;padding-top:24px;border-top:1px solid var(--hairline)}.relationships-title.svelte-9edgfz{font-family:var(--font-ui);font-size:var(--sp-font-tiny);letter-spacing:.02em;text-transform:none;color:var(--text-secondary);margin:0 0 .75rem}.relationships-list.svelte-9edgfz{list-style:none;padding:0;margin:0}.relationship-item.svelte-9edgfz{margin-bottom:2rem}.relationship-item.svelte-9edgfz:last-child{margin-bottom:0}.relationship-link.svelte-9edgfz{display:flex;align-items:center;gap:8px;padding:4px 0}.relationship-link.sprig-link.svelte-9edgfz{text-decoration:none}.relationship-link.sprig-link.svelte-9edgfz .relationship-name:where(.svelte-9edgfz){text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.1875rem;text-decoration-color:var(--sprig-link-underline)}.relationship-link.sprig-link.svelte-9edgfz:hover .relationship-name:where(.svelte-9edgfz){text-decoration-thickness:1.5px;text-decoration-color:var(--sprig-link-underline-hover)}.relationship-label.svelte-9edgfz{font-family:var(--font-ui);font-size:var(--sp-font-small);color:var(--text-secondary)}.relationship-separator.svelte-9edgfz{font-family:var(--font-ui);font-size:var(--sp-font-small);color:var(--text-tertiary);opacity:.6}.relationship-name.svelte-9edgfz{font-family:var(--font-prose);font-size:var(--sp-font-small);color:inherit}.relationship-kind.svelte-9edgfz{font-family:var(--font-ui);font-size:var(--sp-font-tiny);color:var(--text-tertiary);margin-left:auto}.relationship-description.svelte-9edgfz{margin:8px 0 0;font-family:var(--font-prose);font-size:var(--sp-font-body);color:var(--text-secondary);line-height:1.6;max-width:70ch}.loading.svelte-9edgfz{color:var(--text-tertiary);padding:24px 0}.references.svelte-9edgfz{margin-top:32px;padding-top:24px;border-top:1px solid var(--hairline)}.references-title.svelte-9edgfz{font-family:var(--font-ui);font-size:var(--sp-font-tiny);letter-spacing:.02em;text-transform:none;color:var(--text-secondary);margin:0 0 .75rem}.references-subtitle.svelte-9edgfz{font-family:var(--font-ui);font-size:var(--sp-font-tiny);color:var(--text-tertiary);margin:0 0 1.5rem}.reference-list.svelte-9edgfz{list-style:none;padding:0;margin:0}.reference-item.svelte-9edgfz{margin-bottom:2rem}.reference-item.svelte-9edgfz:last-child{margin-bottom:0}.reference-repo-pill.svelte-9edgfz{display:inline-flex;align-items:center;gap:6px;padding:2px 10px;border-radius:999px;font-family:var(--font-ui);font-size:var(--sp-font-small);text-transform:lowercase;color:var(--text-tertiary);border:1px solid var(--hairline);margin-bottom:1rem;text-decoration:none}.reference-path-link.svelte-9edgfz{display:block;margin-top:2px;font-family:ui-monospace,SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace;font-size:var(--sp-font-body);color:inherit;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.1875rem;text-decoration-color:var(--sprig-link-underline)}.reference-row.svelte-9edgfz{display:flex;align-items:baseline;gap:8px}.reference-kind.svelte-9edgfz{margin-left:auto;font-family:var(--font-ui);font-size:var(--sp-font-small);color:var(--text-tertiary)}.reference-description.svelte-9edgfz,.reference-note.svelte-9edgfz{margin:6px 0 0;font-family:var(--font-prose);font-size:var(--sp-font-body);color:var(--text-secondary);line-height:1.5;max-width:70ch}.reference-links-list.svelte-9edgfz{list-style:none;padding:0;margin:8px 0 0}.reference-group-list.svelte-9edgfz{list-style:none;padding:0;margin:0}.reference-group-item.svelte-9edgfz+.reference-group-item:where(.svelte-9edgfz){margin-top:2rem}.reference-links-item.svelte-9edgfz{margin-bottom:6px}.reference-links-item.svelte-9edgfz:last-child{margin-bottom:0}.documentation.svelte-9edgfz{margin-top:32px;padding-top:24px;border-top:1px solid var(--hairline)}.documentation-title.svelte-9edgfz{font-family:var(--font-ui);font-size:var(--sp-font-tiny);letter-spacing:.02em;text-transform:none;color:var(--text-secondary);margin:0 0 .75rem}.documentation-subtitle.svelte-9edgfz{font-family:var(--font-ui);font-size:var(--sp-font-tiny);color:var(--text-tertiary);margin:0 0 1.5rem}.documentation-list.svelte-9edgfz{list-style:none;padding:0;margin:0}.documentation-item.svelte-9edgfz{margin-bottom:1.5rem}.documentation-item.svelte-9edgfz:last-child{margin-bottom:0}.documentation-link.svelte-9edgfz{display:flex;align-items:center;gap:8px;padding:4px 0;text-decoration:none}.documentation-title-text.svelte-9edgfz{font-family:var(--font-prose);font-size:var(--sp-font-body);color:inherit;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.1875rem;text-decoration-color:var(--sprig-link-underline)}.documentation-link.svelte-9edgfz:hover .documentation-title-text:where(.svelte-9edgfz){text-decoration-thickness:1.5px;text-decoration-color:var(--sprig-link-underline-hover)}.documentation-kind.svelte-9edgfz{font-family:var(--font-ui);font-size:var(--sp-font-tiny);letter-spacing:.05em;text-transform:lowercase;color:var(--text-tertiary);font-weight:400;padding:2px 6px;background:var(--card-bg);border-radius:4px}.documentation-path.svelte-9edgfz{margin:6px 0 0;font-family:ui-monospace,SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace;font-size:var(--sp-font-tiny);color:var(--text-tertiary);font-variant-numeric:tabular-nums;letter-spacing:.01em}.documentation-description.svelte-9edgfz{margin:8px 0 0;font-family:var(--font-prose);font-size:var(--sp-font-body);color:var(--text-secondary);line-height:1.5;max-width:70ch}@media(max-width:768px){.grid.svelte-9edgfz{grid-template-columns:1fr;gap:32px}}@media(max-width:480px){.grid.svelte-9edgfz{gap:32px}}.reference-section.svelte-1gel1uo{margin-top:24px}.reference-section-title.svelte-1gel1uo{font-family:var(--font-ui);font-size:var(--sp-font-tiny);color:var(--text-secondary);margin:0 0 .75rem}.reference-links-list.svelte-1gel1uo{list-style:none;padding:0;margin:0}.reference-links-item.svelte-1gel1uo{margin-bottom:.5rem}.reference-links-item.svelte-1gel1uo:last-child{margin-bottom:0}.reference-link.svelte-1gel1uo{display:inline-block;font-family:ui-monospace,SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace;font-size:var(--sp-font-body)}.loading.svelte-1gel1uo{color:var(--text-tertiary);padding:24px 0}.app.svelte-1n46o8q{min-height:100vh;width:100%}.page.svelte-1n46o8q{max-width:1200px;margin:0 auto;width:100%}.top-bar.svelte-1n46o8q{padding:24px 32px;border-bottom:1px solid var(--border-color);display:flex;justify-content:space-between;align-items:center;gap:1rem;width:100%;position:sticky;top:0;background-color:var(--bg-color);z-index:100}.main-content.svelte-1n46o8q{padding:64px 32px;min-height:calc(100vh - 200px);width:100%}.theme-toggle.svelte-1n46o8q{background:var(--card-bg);border:none;border-radius:4px;color:var(--text-color);font-family:var(--font-ui);font-size:var(--sp-font-small);padding:8px 12px;cursor:pointer;white-space:nowrap;transition:background .2s,opacity .2s}.theme-toggle.svelte-1n46o8q:hover{background:var(--hover);opacity:.8}.theme-toggle.svelte-1n46o8q:focus{outline:2px solid var(--text-tertiary);outline-offset:2px;border-radius:2px}.loading.svelte-1n46o8q,.error.svelte-1n46o8q{color:var(--text-tertiary);padding:24px 0;font-size:var(--sp-font-body)}.error.svelte-1n46o8q{color:#d32f2f}@media(max-width:768px){.top-bar.svelte-1n46o8q{padding:20px 24px}.main-content.svelte-1n46o8q{padding:48px 24px}}@media(max-width:480px){.top-bar.svelte-1n46o8q{padding:16px 20px;flex-wrap:wrap;gap:8px}.main-content.svelte-1n46o8q{padding:32px 20px}}