gazetta 0.4.0 → 0.5.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 (58) hide show
  1. package/admin-dist/assets/{index-DjGNi6yy.js → index-BZAFKsUp.js} +22 -22
  2. package/admin-dist/assets/index-BpRotMuK.css +1 -0
  3. package/admin-dist/index.html +2 -2
  4. package/dist/admin-api/index.d.ts +8 -2
  5. package/dist/admin-api/index.d.ts.map +1 -1
  6. package/dist/admin-api/index.js +31 -5
  7. package/dist/admin-api/index.js.map +1 -1
  8. package/dist/admin-api/routes/compare.d.ts +2 -1
  9. package/dist/admin-api/routes/compare.d.ts.map +1 -1
  10. package/dist/admin-api/routes/compare.js +2 -1
  11. package/dist/admin-api/routes/compare.js.map +1 -1
  12. package/dist/admin-api/routes/fragments.d.ts +2 -1
  13. package/dist/admin-api/routes/fragments.d.ts.map +1 -1
  14. package/dist/admin-api/routes/fragments.js +3 -1
  15. package/dist/admin-api/routes/fragments.js.map +1 -1
  16. package/dist/admin-api/routes/pages.d.ts +2 -1
  17. package/dist/admin-api/routes/pages.d.ts.map +1 -1
  18. package/dist/admin-api/routes/pages.js +3 -1
  19. package/dist/admin-api/routes/pages.js.map +1 -1
  20. package/dist/admin-api/routes/publish.d.ts +2 -1
  21. package/dist/admin-api/routes/publish.d.ts.map +1 -1
  22. package/dist/admin-api/routes/publish.js +121 -27
  23. package/dist/admin-api/routes/publish.js.map +1 -1
  24. package/dist/cli/index.js +75 -12
  25. package/dist/cli/index.js.map +1 -1
  26. package/dist/compare.d.ts +7 -0
  27. package/dist/compare.d.ts.map +1 -1
  28. package/dist/compare.js +39 -40
  29. package/dist/compare.js.map +1 -1
  30. package/dist/concurrency.d.ts +63 -0
  31. package/dist/concurrency.d.ts.map +1 -0
  32. package/dist/concurrency.js +134 -0
  33. package/dist/concurrency.js.map +1 -0
  34. package/dist/hash.d.ts +15 -0
  35. package/dist/hash.d.ts.map +1 -1
  36. package/dist/hash.js +47 -7
  37. package/dist/hash.js.map +1 -1
  38. package/dist/publish-rendered.d.ts +6 -5
  39. package/dist/publish-rendered.d.ts.map +1 -1
  40. package/dist/publish-rendered.js +39 -44
  41. package/dist/publish-rendered.js.map +1 -1
  42. package/dist/publish.d.ts +38 -0
  43. package/dist/publish.d.ts.map +1 -1
  44. package/dist/publish.js +154 -14
  45. package/dist/publish.js.map +1 -1
  46. package/dist/sidecars.d.ts +56 -0
  47. package/dist/sidecars.d.ts.map +1 -0
  48. package/dist/sidecars.js +141 -0
  49. package/dist/sidecars.js.map +1 -0
  50. package/dist/site-loader.d.ts.map +1 -1
  51. package/dist/site-loader.js +13 -10
  52. package/dist/site-loader.js.map +1 -1
  53. package/dist/source-sidecars.d.ts +13 -0
  54. package/dist/source-sidecars.d.ts.map +1 -0
  55. package/dist/source-sidecars.js +52 -0
  56. package/dist/source-sidecars.js.map +1 -0
  57. package/package.json +1 -1
  58. package/admin-dist/assets/index-Bh_y1d_l.css +0 -1
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Sidecar file I/O for pages and fragments — one module owning all reads
3
+ * and writes of the three sidecar kinds:
4
+ *
5
+ * .{8hex}.hash — content hash, used by compare-targets
6
+ * .uses-{fragment} — one per @ reference; used by dependents lookup
7
+ * .tpl-{template} — template name; used to flag republish-needed
8
+ *
9
+ * Filenames encode the whole picture — a single readDir returns the full
10
+ * dependency state of an item without any content reads. Scaling goal:
11
+ * listing calls, not GETs, at 10k pages.
12
+ *
13
+ * Publish-rendered.ts, compare.ts, publish.ts all used to inline this
14
+ * logic separately; centralizing here reduces duplication and gives us
15
+ * one place to swap the storage shape (e.g. future single-index file)
16
+ * without touching every caller.
17
+ */
18
+ import { parseSidecarName, sidecarNameFor, parseUsesSidecarName, usesSidecarNameFor, parseTemplateSidecarName, templateSidecarNameFor, } from './hash.js';
19
+ import { mapLimit } from './concurrency.js';
20
+ /**
21
+ * Read sidecar filenames for a single item directory. Returns null if
22
+ * the directory doesn't exist or has no hash sidecar. `uses` and
23
+ * `template` default to empty/null when their sidecars are absent —
24
+ * old items published before we started writing them will still work,
25
+ * the caller just won't have dependency info for them.
26
+ */
27
+ export async function readSidecars(storage, dir) {
28
+ let entries;
29
+ try {
30
+ entries = await storage.readDir(dir);
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ let hash = null;
36
+ const uses = [];
37
+ let template = null;
38
+ for (const e of entries) {
39
+ if (e.isDirectory)
40
+ continue;
41
+ const h = parseSidecarName(e.name);
42
+ if (h) {
43
+ hash = h;
44
+ continue;
45
+ }
46
+ const u = parseUsesSidecarName(e.name);
47
+ if (u) {
48
+ uses.push(u);
49
+ continue;
50
+ }
51
+ const t = parseTemplateSidecarName(e.name);
52
+ if (t)
53
+ template = t;
54
+ }
55
+ if (!hash)
56
+ return null;
57
+ return { hash, uses, template };
58
+ }
59
+ /**
60
+ * Write (or rewrite) all three sidecar kinds for one item. Stale sidecars
61
+ * of any kind that aren't in the new state are removed first, so
62
+ * fragment-references removed from a page's components don't linger as
63
+ * .uses-*.
64
+ */
65
+ export async function writeSidecars(storage, dir, state) {
66
+ const want = new Set([sidecarNameFor(state.hash)]);
67
+ for (const frag of state.uses)
68
+ want.add(usesSidecarNameFor(frag));
69
+ if (state.template)
70
+ want.add(templateSidecarNameFor(state.template));
71
+ // Remove stale sidecars of known kinds that aren't in `want`.
72
+ try {
73
+ const entries = await storage.readDir(dir);
74
+ for (const e of entries) {
75
+ if (want.has(e.name))
76
+ continue;
77
+ if (parseSidecarName(e.name) || parseUsesSidecarName(e.name) || parseTemplateSidecarName(e.name)) {
78
+ try {
79
+ await storage.rm(`${dir}/${e.name}`);
80
+ }
81
+ catch { /* already gone */ }
82
+ }
83
+ }
84
+ }
85
+ catch { /* dir doesn't exist yet — mkdir below */ }
86
+ await storage.mkdir(dir);
87
+ // Parallel tiny writes; each is a zero-byte file.
88
+ await Promise.all([...want].map(name => storage.writeFile(`${dir}/${name}`, '')));
89
+ }
90
+ /**
91
+ * Walk a directory tree collecting every sub-directory's sidecar state.
92
+ * Bounded-parallel recursion — flat Promise.all over 10k dirs would blow
93
+ * the fd limit or provider rate limit.
94
+ *
95
+ * Keys are paths relative to `rootDir` (e.g. `home`, `blog/[slug]`). Items
96
+ * without a .hash sidecar are skipped. `writeSidecars` always writes all
97
+ * three kinds together, so partial state doesn't occur in real operation.
98
+ */
99
+ export async function listSidecars(storage, rootDir) {
100
+ const out = new Map();
101
+ async function walk(dir, relative) {
102
+ let entries;
103
+ try {
104
+ entries = await storage.readDir(dir);
105
+ }
106
+ catch {
107
+ return;
108
+ }
109
+ if (relative) {
110
+ const state = await readSidecars(storage, dir).catch(() => null);
111
+ if (state)
112
+ out.set(relative, state);
113
+ }
114
+ const subdirs = entries.filter(e => e.isDirectory);
115
+ await mapLimit(subdirs, (e) => walk(`${dir}/${e.name}`, relative ? `${relative}/${e.name}` : e.name));
116
+ }
117
+ await walk(rootDir, '');
118
+ return out;
119
+ }
120
+ /**
121
+ * Walk a component tree and collect every @fragment reference, recursing
122
+ * into inline components' children. Used when building SidecarState from
123
+ * a live manifest (source-side).
124
+ */
125
+ export function collectFragmentRefs(components) {
126
+ const refs = new Set();
127
+ function walk(entries) {
128
+ if (!Array.isArray(entries))
129
+ return;
130
+ for (const entry of entries) {
131
+ if (typeof entry === 'string' && entry.startsWith('@'))
132
+ refs.add(entry.slice(1));
133
+ else if (typeof entry === 'object' && entry !== null) {
134
+ walk(entry.components);
135
+ }
136
+ }
137
+ }
138
+ walk(components);
139
+ return [...refs];
140
+ }
141
+ //# sourceMappingURL=sidecars.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidecars.js","sourceRoot":"","sources":["../src/sidecars.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"site-loader.d.ts","sourceRoot":"","sources":["../src/site-loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAG/F,8FAA8F;AAC9F,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED,MAAM,WAAW,IAAI;IACnB,QAAQ,EAAE,YAAY,CAAA;IACtB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClD,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC1D,OAAO,EAAE,MAAM,CAAA;IACf,+FAA+F;IAC/F,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,eAAe,CAAA;CACzB;AAgED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,eAAe,CAAA;IACxB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wBAAsB,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,eAAe,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhH"}
1
+ {"version":3,"file":"site-loader.d.ts","sourceRoot":"","sources":["../src/site-loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAI/F,8FAA8F;AAC9F,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED,MAAM,WAAW,IAAI;IACnB,QAAQ,EAAE,YAAY,CAAA;IACtB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClD,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC1D,OAAO,EAAE,MAAM,CAAA;IACf,+FAA+F;IAC/F,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,eAAe,CAAA;CACzB;AAoED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,eAAe,CAAA;IACxB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wBAAsB,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,eAAe,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhH"}
@@ -1,5 +1,6 @@
1
1
  import { join } from 'node:path';
2
2
  import { parseSiteManifest, parsePageManifest, parseFragmentManifest } from './manifest.js';
3
+ import { mapLimit } from './concurrency.js';
3
4
  /** Derive route from page folder name: home → /, about → /about, blog/[slug] → /blog/:slug */
4
5
  export function deriveRoute(pageName) {
5
6
  if (pageName === 'home')
@@ -13,9 +14,10 @@ async function discoverPages(storage, pagesDir, pages = new Map(), prefix = '')
13
14
  return pages;
14
15
  }
15
16
  const entries = await storage.readDir(pagesDir);
16
- for (const entry of entries) {
17
- if (!entry.isDirectory)
18
- continue;
17
+ const subdirs = entries.filter(e => e.isDirectory);
18
+ // Parallelize manifest reads — sequential is untenable at 10k pages.
19
+ // Bounded concurrency protects the fd table and cloud rate limits.
20
+ await mapLimit(subdirs, async (entry) => {
19
21
  const dir = join(pagesDir, entry.name);
20
22
  const name = prefix ? `${prefix}/${entry.name}` : entry.name;
21
23
  const manifestPath = join(dir, 'page.json');
@@ -29,9 +31,11 @@ async function discoverPages(storage, pagesDir, pages = new Map(), prefix = '')
29
31
  console.warn(` Warning: skipping page "${name}": ${err.message}`);
30
32
  }
31
33
  }
32
- // Recurse into subdirectories to find nested pages (e.g., blog/[slug])
34
+ // Recurse into subdirectories to find nested pages (e.g., blog/[slug]).
35
+ // Recursive call inherits the same bounded mapLimit — workers at each
36
+ // level compete for the same concurrency budget.
33
37
  await discoverPages(storage, dir, pages, name);
34
- }
38
+ });
35
39
  return pages;
36
40
  }
37
41
  async function discoverFragments(storage, fragmentsDir) {
@@ -41,13 +45,12 @@ async function discoverFragments(storage, fragmentsDir) {
41
45
  return fragments;
42
46
  }
43
47
  const entries = await storage.readDir(fragmentsDir);
44
- for (const entry of entries) {
45
- if (!entry.isDirectory)
46
- continue;
48
+ const subdirs = entries.filter(e => e.isDirectory);
49
+ await mapLimit(subdirs, async (entry) => {
47
50
  const fragDir = join(fragmentsDir, entry.name);
48
51
  const manifestPath = join(fragDir, 'fragment.json');
49
52
  if (!await storage.exists(manifestPath))
50
- continue;
53
+ return;
51
54
  try {
52
55
  const manifest = await parseFragmentManifest(storage, manifestPath);
53
56
  fragments.set(entry.name, { ...manifest, dir: fragDir });
@@ -55,7 +58,7 @@ async function discoverFragments(storage, fragmentsDir) {
55
58
  catch (err) {
56
59
  console.warn(` Warning: skipping fragment "${entry.name}": ${err.message}`);
57
60
  }
58
- }
61
+ });
59
62
  return fragments;
60
63
  }
61
64
  export async function loadSite(siteDirOrOpts, storage) {
@@ -1 +1 @@
1
- {"version":3,"file":"site-loader.js","sourceRoot":"","sources":["../src/site-loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"site-loader.js","sourceRoot":"","sources":["../src/site-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { StorageProvider } from './types.js';
2
+ import type { TemplateInfo } from './templates-scan.js';
3
+ export interface SourceSidecarWriter {
4
+ writeFor(kind: 'page' | 'fragment', name: string): Promise<void>;
5
+ invalidate(): void;
6
+ }
7
+ export interface SourceSidecarWriterOptions {
8
+ storage: StorageProvider;
9
+ siteDir: string;
10
+ scanTemplates: () => Promise<TemplateInfo[]>;
11
+ }
12
+ export declare function createSourceSidecarWriter(opts: SourceSidecarWriterOptions): SourceSidecarWriter;
13
+ //# sourceMappingURL=source-sidecars.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-sidecars.d.ts","sourceRoot":"","sources":["../src/source-sidecars.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAMvD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAChE,UAAU,IAAI,IAAI,CAAA;CACnB;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,eAAe,CAAA;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,EAAE,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;CAC7C;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,0BAA0B,GAAG,mBAAmB,CAkC/F"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Source-side sidecar writer. Keeps `sites/<name>/pages/` and
3
+ * `sites/<name>/fragments/` in the same filename-encoded shape as published
4
+ * targets — .{hash}.hash,
5
+ * .uses-{frag}, .tpl-{template} — so compare and incremental publish can
6
+ * read them without re-hashing manifests.
7
+ *
8
+ * Single responsibility: given (kind, name), hash the manifest with current
9
+ * template hashes and write its three sidecars. Nothing else.
10
+ *
11
+ * Template hashes are cached. A template edit flips every dependent item's
12
+ * content hash, so the file watcher calls invalidate() — next writeFor()
13
+ * rescans.
14
+ */
15
+ import { join } from 'node:path';
16
+ import { templateHashesFrom } from './templates-scan.js';
17
+ import { hashManifest } from './hash.js';
18
+ import { writeSidecars, collectFragmentRefs } from './sidecars.js';
19
+ export function createSourceSidecarWriter(opts) {
20
+ let templateHashes = null;
21
+ const getTemplateHashes = () => {
22
+ if (!templateHashes)
23
+ templateHashes = opts.scanTemplates().then(templateHashesFrom);
24
+ return templateHashes;
25
+ };
26
+ return {
27
+ async writeFor(kind, name) {
28
+ const subdir = kind === 'page' ? 'pages' : 'fragments';
29
+ const manifestName = kind === 'page' ? 'page.json' : 'fragment.json';
30
+ const itemDir = join(opts.siteDir, subdir, name);
31
+ const manifestPath = join(itemDir, manifestName);
32
+ let manifest;
33
+ try {
34
+ manifest = JSON.parse(await opts.storage.readFile(manifestPath));
35
+ }
36
+ catch {
37
+ return;
38
+ }
39
+ const hashes = await getTemplateHashes();
40
+ const hash = hashManifest(manifest, { templateHashes: hashes });
41
+ await writeSidecars(opts.storage, itemDir, {
42
+ hash,
43
+ uses: collectFragmentRefs(manifest.components),
44
+ template: manifest.template,
45
+ });
46
+ },
47
+ invalidate() {
48
+ templateHashes = null;
49
+ },
50
+ };
51
+ }
52
+ //# sourceMappingURL=source-sidecars.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-sidecars.js","sourceRoot":"","sources":["../src/source-sidecars.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAGhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAclE,MAAM,UAAU,yBAAyB,CAAC,IAAgC;IACxE,IAAI,cAAc,GAAwC,IAAI,CAAA;IAE9D,MAAM,iBAAiB,GAAG,GAAG,EAAE;QAC7B,IAAI,CAAC,cAAc;YAAE,cAAc,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;QACnF,OAAO,cAAc,CAAA;IACvB,CAAC,CAAA;IAED,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI;YACvB,MAAM,MAAM,GAAG,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAA;YACtD,MAAM,YAAY,GAAG,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,eAAe,CAAA;YACpE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,CAAA;YAChD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;YAEhD,IAAI,QAAyC,CAAA;YAC7C,IAAI,CAAC;gBACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAA;YAClE,CAAC;YAAC,MAAM,CAAC;gBACP,OAAM;YACR,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,iBAAiB,EAAE,CAAA;YACxC,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAA;YAC/D,MAAM,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE;gBACzC,IAAI;gBACJ,IAAI,EAAE,mBAAmB,CAAC,QAAQ,CAAC,UAAU,CAAC;gBAC9C,QAAQ,EAAE,QAAQ,CAAC,QAAQ;aAC5B,CAAC,CAAA;QACJ,CAAC;QACD,UAAU;YACR,cAAc,GAAG,IAAI,CAAA;QACvB,CAAC;KACF,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gazetta",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Stateless CMS for composable websites",
5
5
  "keywords": [
6
6
  "cms",
@@ -1 +0,0 @@
1
- .publish-content[data-v-a2ebf90d]{flex-direction:column;gap:1rem;display:flex}.publish-item[data-v-a2ebf90d]{align-items:center;gap:.5rem;font-size:1rem;font-weight:600;display:flex}.publish-empty[data-v-a2ebf90d]{color:var(--color-muted);font-size:.875rem}.publish-label[data-v-a2ebf90d]{text-transform:uppercase;color:var(--color-muted);letter-spacing:.03em;align-items:center;gap:.5rem;font-size:.75rem;display:flex}.publish-label-hint[data-v-a2ebf90d]{text-transform:none;letter-spacing:0;color:var(--color-muted);font-size:.75rem;font-weight:400}.publish-select-all[data-v-a2ebf90d]{color:var(--color-primary);cursor:pointer;border-radius:var(--p-border-radius-sm);text-transform:none;letter-spacing:0;background:0 0;border:0;margin-left:auto;padding:.125rem .25rem;font-size:.75rem;font-weight:400}.publish-select-all[data-v-a2ebf90d]:hover{background:var(--color-hover-bg)}.publish-targets[data-v-a2ebf90d]{flex-direction:column;gap:.5rem;display:flex}.publish-target[data-v-a2ebf90d]{align-items:center;gap:.5rem;display:flex}.publish-target label[data-v-a2ebf90d]{cursor:pointer}.publish-warning[data-v-a2ebf90d]{border-radius:var(--p-border-radius-md);background:var(--color-danger-bg);color:var(--color-danger-fg);align-items:center;gap:.5rem;padding:.5rem .75rem;font-size:.875rem;display:flex}.publish-firstpublish[data-v-a2ebf90d]{border-radius:var(--p-border-radius-md);background:var(--color-info-bg);color:var(--color-info-fg);align-items:center;gap:.5rem;padding:.5rem .75rem;font-size:.875rem;display:flex}.publish-confirm-banner[data-v-a2ebf90d]{border-radius:var(--p-border-radius-md);background:var(--color-danger-bg);color:var(--color-danger-fg);align-items:center;gap:.5rem;padding:.5rem .75rem;font-size:.875rem;display:flex}.publish-invalid-body[data-v-a2ebf90d]{flex-direction:column;flex:1;gap:.375rem;display:flex}.publish-invalid-body p[data-v-a2ebf90d]{margin:0}.publish-invalid-list[data-v-a2ebf90d]{flex-direction:column;gap:.25rem;margin:0;padding:0;list-style:none;display:flex}.publish-invalid-list li[data-v-a2ebf90d]{flex-direction:column;gap:.125rem;font-size:.8125rem;display:flex}.publish-invalid-name[data-v-a2ebf90d]{font-family:monospace;font-weight:600}.publish-invalid-error[data-v-a2ebf90d]{opacity:.85;font-size:.75rem}.publish-target-label[data-v-a2ebf90d]{cursor:pointer;align-items:center;gap:.5rem;display:inline-flex}.publish-env-badge[data-v-a2ebf90d]{text-transform:uppercase;letter-spacing:.03em;border-radius:var(--p-border-radius-sm);padding:.125rem .375rem;font-size:.6875rem;font-weight:600}.publish-env-prod[data-v-a2ebf90d]{background:var(--color-env-prod-bg);color:var(--color-env-prod-fg)}.publish-env-staging[data-v-a2ebf90d]{background:var(--color-env-staging-bg);color:var(--color-env-staging-fg)}.publish-changes[data-v-a2ebf90d]{flex-direction:column;gap:.5rem;display:flex}.publish-nochanges[data-v-a2ebf90d]{color:var(--color-muted);font-size:.875rem}.publish-changes-group[data-v-a2ebf90d]{flex-direction:column;gap:.25rem;display:flex}.publish-changes-group+.publish-changes-group[data-v-a2ebf90d]{margin-top:.5rem}.publish-group-label[data-v-a2ebf90d]{text-transform:uppercase;color:var(--color-muted);letter-spacing:.05em;margin:0 0 .125rem .25rem;font-size:.6875rem;font-weight:600}.publish-changes-list[data-v-a2ebf90d]{flex-direction:column;gap:.125rem;max-height:240px;display:flex;overflow-y:auto}.publish-change-row[data-v-a2ebf90d]{border-radius:var(--p-border-radius-sm);cursor:pointer;align-items:center;gap:.5rem;padding:.375rem .5rem;display:flex}.publish-change-row[data-v-a2ebf90d]:hover{background:var(--color-hover-bg)}.publish-change-row-deleted[data-v-a2ebf90d]{cursor:default;opacity:.55}.publish-change-row-deleted[data-v-a2ebf90d]:hover{background:0 0}.publish-change-nocheckbox[data-v-a2ebf90d]{flex-shrink:0;width:20px;display:inline-block}.publish-change-mark[data-v-a2ebf90d]{text-align:center;width:10px;font-family:monospace;font-weight:700}.publish-change-mark.added[data-v-a2ebf90d]{color:var(--color-change-added)}.publish-change-mark.modified[data-v-a2ebf90d]{color:var(--color-change-modified)}.publish-change-mark.deleted[data-v-a2ebf90d]{color:var(--color-change-deleted)}.publish-change-icon[data-v-a2ebf90d]{color:var(--color-muted);font-size:.8rem}.publish-change-label[data-v-a2ebf90d]{font-size:.875rem}.publish-progress[data-v-a2ebf90d]{flex-direction:column;gap:.75rem;display:flex}.publish-progress-row[data-v-a2ebf90d]{flex-direction:column;gap:.25rem;display:flex}.publish-progress-header[data-v-a2ebf90d]{justify-content:space-between;align-items:baseline;font-size:.8125rem;display:flex}.publish-progress-target[data-v-a2ebf90d]{font-weight:600}.publish-progress-count[data-v-a2ebf90d]{color:var(--color-muted);font-variant-numeric:tabular-nums;font-size:.75rem}.publish-progress-bar[data-v-a2ebf90d]{background:var(--color-hover-bg);border-radius:2px;height:4px;overflow:hidden}.publish-progress-fill[data-v-a2ebf90d]{background:var(--color-primary);height:100%;transition:width .2s}.publish-progress-label[data-v-a2ebf90d]{color:var(--color-muted);text-overflow:ellipsis;white-space:nowrap;font-family:monospace;font-size:.75rem;overflow:hidden}.publish-results[data-v-a2ebf90d]{flex-direction:column;gap:.5rem;display:flex}.publish-result[data-v-a2ebf90d]{border-radius:var(--p-border-radius-md);align-items:center;gap:.5rem;padding:.5rem;display:flex}.publish-result.success[data-v-a2ebf90d]{background:var(--color-success-bg);color:var(--color-success-fg)}.publish-result.error[data-v-a2ebf90d]{background:var(--color-danger-bg);color:var(--color-danger-fg)}.result-target[data-v-a2ebf90d]{font-weight:600}.result-detail[data-v-a2ebf90d]{opacity:.8;margin-left:auto;font-size:.875rem}.fetch-content[data-v-28aee561]{flex-direction:column;gap:1rem;display:flex}.fetch-empty[data-v-28aee561]{color:var(--color-muted);font-size:.875rem}.fetch-label[data-v-28aee561]{color:var(--color-muted);margin-bottom:.5rem;font-size:.875rem}.fetch-list[data-v-28aee561]{width:100%}.fetch-result[data-v-28aee561]{border-radius:var(--p-border-radius-md);align-items:flex-start;gap:.75rem;padding:.75rem;display:flex}.fetch-result.success[data-v-28aee561]{background:var(--color-success-bg);color:var(--color-success-fg)}.fetch-result.error[data-v-28aee561]{background:var(--color-danger-bg);color:var(--color-danger-fg)}.fetch-items[data-v-28aee561]{opacity:.7;margin-top:.25rem;font-size:.75rem}.changes-header[data-v-8918ea89]{justify-content:space-between;align-items:center;gap:.5rem;width:100%;display:flex}.changes-title[data-v-8918ea89]{font-size:1rem;font-weight:600}.changes-body[data-v-8918ea89]{flex-direction:column;gap:1rem;padding-top:.25rem;display:flex}.changes-empty[data-v-8918ea89]{color:var(--color-muted);font-size:.875rem}.changes-target-row[data-v-8918ea89]{align-items:center;gap:.75rem;display:flex}.changes-target[data-v-8918ea89]{flex:1;min-width:0}.changes-lastchecked[data-v-8918ea89]{color:var(--color-muted);white-space:nowrap;font-size:.75rem}.changes-loading[data-v-8918ea89]{color:var(--color-muted);align-items:center;gap:.5rem;font-size:.875rem;display:flex}.changes-warning[data-v-8918ea89]{border-radius:var(--p-border-radius-md);background:var(--color-danger-bg);color:var(--color-danger-fg);gap:.5rem;padding:.75rem;font-size:.875rem;display:flex}.changes-warning-body[data-v-8918ea89]{flex-direction:column;flex:1;gap:.375rem;display:flex}.changes-warning-body p[data-v-8918ea89]{margin:0}.changes-warning-detail[data-v-8918ea89]{opacity:.8;font-size:.8125rem}.changes-state[data-v-8918ea89]{border-radius:var(--p-border-radius-md);background:var(--color-info-bg);color:var(--color-info-fg);align-items:center;gap:.5rem;padding:.75rem;font-size:.875rem;display:flex}.changes-state-sync[data-v-8918ea89]{background:var(--color-success-bg);color:var(--color-success-fg)}.changes-summary[data-v-8918ea89]{color:var(--color-muted);margin:0;font-size:.8125rem}.changes-list-wrapper[data-v-8918ea89]{flex-direction:column;gap:.75rem;display:flex}.changes-group[data-v-8918ea89]{flex-direction:column;gap:.25rem;display:flex}.changes-group-label[data-v-8918ea89]{text-transform:uppercase;color:var(--color-muted);letter-spacing:.05em;margin:0 0 .125rem .25rem;font-size:.6875rem;font-weight:600}.changes-rows[data-v-8918ea89]{flex-direction:column;gap:.125rem;display:flex}.changes-row[data-v-8918ea89]{border-radius:var(--p-border-radius-sm);color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:.5rem;width:100%;padding:.375rem .5rem;display:flex}.changes-row[data-v-8918ea89]:hover{background:var(--color-hover-bg)}.changes-row-deleted[data-v-8918ea89]{cursor:default;opacity:.55}.changes-row-deleted[data-v-8918ea89]:hover{background:0 0}.changes-row-unchanged[data-v-8918ea89]{opacity:.75}.changes-mark[data-v-8918ea89]{text-align:center;flex-shrink:0;width:10px;font-family:monospace;font-weight:700}.changes-mark.added[data-v-8918ea89]{color:var(--color-change-added)}.changes-mark.modified[data-v-8918ea89]{color:var(--color-change-modified)}.changes-mark.deleted[data-v-8918ea89]{color:var(--color-change-deleted)}.changes-mark.unchanged[data-v-8918ea89]{color:var(--color-muted);font-weight:400}.changes-icon[data-v-8918ea89]{color:var(--color-muted);flex-shrink:0;font-size:.8rem}.changes-label[data-v-8918ea89]{text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;overflow:hidden}.changes-unchanged[data-v-8918ea89]{border-top:1px solid var(--color-border);flex-direction:column;gap:.5rem;padding-top:.5rem;display:flex}.changes-unchanged-toggle[data-v-8918ea89]{color:var(--color-muted);cursor:pointer;border-radius:var(--p-border-radius-sm);background:0 0;border:0;align-items:center;gap:.5rem;padding:.25rem .5rem;font-size:.8125rem;display:flex}.changes-unchanged-toggle[data-v-8918ea89]:hover{background:var(--color-hover-bg);color:inherit}.changes-unchanged-body[data-v-8918ea89]{flex-direction:column;gap:.5rem;display:flex}.cms-toolbar[data-v-d907b333]{border-top:0;border-left:0;border-right:0;border-radius:0}.cms-logo[data-v-d907b333]{align-items:center;gap:.5rem;font-size:1.125rem;font-weight:700;display:flex}.cms-site-name[data-v-d907b333]{color:var(--color-muted);margin-left:1rem;font-size:.875rem}.cms-btn[data-v-d907b333]{margin-left:.5rem}.cms-toast[data-v-d907b333]{align-items:center;gap:.375rem;font-size:.8125rem;display:flex}.cms-toast-error[data-v-d907b333]{color:var(--color-danger-fg)}.fade-enter-active[data-v-d907b333],.fade-leave-active[data-v-d907b333]{transition:opacity .2s}.fade-enter-from[data-v-d907b333],.fade-leave-to[data-v-d907b333]{opacity:0}.unsaved-message[data-v-70fd0516]{color:#374151;margin:0;font-size:.875rem;line-height:1.5}.unsaved-actions[data-v-70fd0516]{justify-content:flex-end;gap:.5rem;width:100%;display:flex}*{box-sizing:border-box;margin:0;padding:0}html,body,#app,.cms-app{height:100%}body{color:var(--color-fg);background:var(--color-bg);font-family:system-ui,-apple-system,sans-serif}.cms-error{color:var(--color-danger-fg);padding:2rem}.cms-loading{color:var(--color-muted);padding:2rem}.global-toast{z-index:1001;background:var(--color-bg);color:var(--color-fg);border:1px solid var(--color-border);border-top:none;border-radius:0 0 8px 8px;align-items:center;gap:8px;max-width:400px;padding:8px 20px;font-size:13px;font-weight:500;display:flex;position:fixed;top:0;left:50%;transform:translate(-50%);box-shadow:0 4px 12px #00000026}.toast-success{color:var(--color-success-fg)}.toast-error{color:var(--color-danger-fg)}.toast-link{color:inherit;text-decoration:underline}.toast-dismiss{color:inherit;cursor:pointer;opacity:.7;background:0 0;border:0;align-items:center;margin-left:4px;padding:2px 4px;display:flex}.toast-dismiss:hover{opacity:1}.toast-dismiss .pi{font-size:11px}.toast-enter-active{transition:transform .2s ease-out,opacity .2s ease-out}.toast-leave-active{transition:transform .15s ease-in,opacity .15s ease-in}.toast-enter-from,.toast-leave-to{opacity:0;transform:translate(-50%)translateY(-100%)}.create-content[data-v-b4d1c25e]{flex-direction:column;gap:1rem;display:flex}.create-field[data-v-b4d1c25e]{flex-direction:column;gap:.375rem;display:flex}.create-field label[data-v-b4d1c25e]{text-transform:uppercase;color:#888;letter-spacing:.03em;font-size:.75rem}.create-input[data-v-b4d1c25e],.create-list[data-v-b4d1c25e]{width:100%}.create-hint[data-v-b4d1c25e]{color:#666;font-size:.75rem}.create-error[data-v-b4d1c25e]{color:#f87171;font-size:.875rem}.create-content[data-v-0b98775c]{flex-direction:column;gap:1rem;display:flex}.create-field[data-v-0b98775c]{flex-direction:column;gap:.375rem;display:flex}.create-field label[data-v-0b98775c]{text-transform:uppercase;color:#888;letter-spacing:.03em;font-size:.75rem}.create-input[data-v-0b98775c],.create-list[data-v-0b98775c]{width:100%}.create-error[data-v-0b98775c]{color:#f87171;font-size:.875rem}.site-tree[data-v-6b0b06db]{font-size:13px;line-height:22px}.section-label[data-v-6b0b06db]{text-transform:uppercase;letter-spacing:.05em;color:#9ca3af;padding:4px 8px;font-size:11px;font-weight:600}.section-divider[data-v-6b0b06db]{border-top:1px solid #80808026;margin:4px 8px}.node-item[data-v-6b0b06db]{cursor:pointer;border-radius:3px;align-items:center;gap:4px;height:22px;margin:0 2px;padding:0 6px;display:flex}.node-item[data-v-6b0b06db]:hover{background:#80808014}.node-item.selected[data-v-6b0b06db]{background:#a78bfa26;box-shadow:inset 2px 0 #a78bfa}.node-icon[data-v-6b0b06db]{text-align:center;color:#999;flex-shrink:0;width:16px;font-size:10px}.node-label[data-v-6b0b06db]{white-space:nowrap;text-overflow:ellipsis;color:#6b7280;flex:1;overflow:hidden}.node-item.selected .node-label[data-v-6b0b06db],.node-item:hover .node-label[data-v-6b0b06db]{color:#374151}.dark{color:#e4e4e7;background:#ffffff0d;border-top-color:#27272a}.node-dirty-dot[data-v-6b0b06db]{background:var(--color-warning-fg);border-radius:50%;flex-shrink:0;width:6px;height:6px;margin-right:2px}.node-delete[data-v-6b0b06db]{opacity:0;flex-shrink:0;transition:opacity .1s}.node-item:hover .node-delete[data-v-6b0b06db]{opacity:1}.new-btns[data-v-6b0b06db]{gap:.5rem;margin-top:8px;padding:0 6px;display:flex}.add-content[data-v-de3d43d5]{flex-direction:column;gap:1rem;display:flex}.add-field[data-v-de3d43d5]{flex-direction:column;gap:.375rem;display:flex}.add-field label[data-v-de3d43d5]{text-transform:uppercase;color:#888;letter-spacing:.03em;font-size:.75rem}.add-input[data-v-de3d43d5],.add-list[data-v-de3d43d5]{width:100%}.add-error[data-v-de3d43d5]{color:#f87171;font-size:.875rem}.component-tree[data-v-b1b905e2]{font-size:13px;line-height:22px}.empty[data-v-b1b905e2]{color:var(--color-muted)}.node-item[data-v-b1b905e2]{cursor:pointer;border-radius:3px;align-items:center;gap:4px;height:22px;margin:0 2px;padding:0 6px;display:flex}.node-item[data-v-b1b905e2]:hover,.node-item.hovered[data-v-b1b905e2]{background:var(--color-hover-bg)}.node-item.selected[data-v-b1b905e2]{box-shadow:inset 2px 0 0 var(--p-violet-400);background:#a78bfa26}.node-root[data-v-b1b905e2]{border-bottom:1px solid var(--color-border);border-radius:0;height:26px;margin:0 0 2px;padding:0 6px;font-weight:600;line-height:26px}.node-root.selected[data-v-b1b905e2]{box-shadow:none;border-bottom-color:var(--p-violet-400);background:#a78bfa1a}.node-icon[data-v-b1b905e2]{text-align:center;width:16px;color:var(--color-muted);flex-shrink:0;font-size:10px}.node-label[data-v-b1b905e2]{white-space:nowrap;text-overflow:ellipsis;color:var(--color-muted);flex:1;overflow:hidden}.node-item.selected .node-label[data-v-b1b905e2],.node-item:hover .node-label[data-v-b1b905e2],.node-item.hovered .node-label[data-v-b1b905e2],.node-root .node-label[data-v-b1b905e2]{color:var(--color-fg)}.node-error-icon[data-v-b1b905e2]{color:var(--color-danger-fg)}.node-dirty-dot[data-v-b1b905e2]{background:var(--color-warning-fg);border-radius:50%;flex-shrink:0;width:6px;height:6px}.node-revert[data-v-b1b905e2]{opacity:0;flex-shrink:0;width:18px;height:18px;transition:opacity .1s}.node-item:hover .node-revert[data-v-b1b905e2]{opacity:1}.node-actions[data-v-b1b905e2]{opacity:0;flex-shrink:0;gap:0;transition:opacity .1s;display:flex}.node-item:hover .node-actions[data-v-b1b905e2]{opacity:1}.add-btn[data-v-b1b905e2]{margin-top:6px}.editor-panel h3[data-v-1e2cf67e]{text-transform:uppercase;color:var(--color-muted);letter-spacing:.05em;margin-bottom:1rem;font-size:.75rem}.editor-error[data-v-1e2cf67e]{color:var(--color-danger-fg);text-align:center;flex-direction:column;align-items:center;gap:.5rem;padding-top:3rem;font-size:.875rem;display:flex}.editor-error .pi[data-v-1e2cf67e]{font-size:2rem}.editor-error p[data-v-1e2cf67e]{max-width:300px;line-height:1.5}.editor-empty[data-v-1e2cf67e]{color:var(--color-muted);flex-direction:column;align-items:center;padding-top:3rem;font-size:.875rem;display:flex}.editor-container[data-v-1e2cf67e]{font-size:.875rem}.editor-no-schema[data-v-1e2cf67e]{color:var(--color-muted);font-size:.875rem}.preview-panel[data-v-4aacb015]{flex-direction:column;height:100%;display:flex}.preview-panel.fullscreen[data-v-4aacb015]{z-index:1000;background:#f8f8fa;position:fixed;inset:0}.preview-empty[data-v-4aacb015]{color:#aaa;flex-direction:column;align-items:center;padding:3rem 1rem 1rem;font-size:.875rem;display:flex}.preview-toolbar[data-v-4aacb015]{border-bottom:1px solid #e5e7eb;justify-content:space-between;align-items:center;padding:.375rem .5rem;display:flex}.preview-devices[data-v-4aacb015],.preview-actions[data-v-4aacb015]{align-items:center;gap:.25rem;display:flex}.device-btn[data-v-4aacb015]{color:#9ca3af;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:4px;padding:.25rem .5rem;font-size:.875rem}.device-btn[data-v-4aacb015]:hover{color:#374151;border-color:#d1d5db}.device-btn.active[data-v-4aacb015]{color:#a78bfa;border-color:#a78bfa}.host-page-select[data-v-4aacb015]{color:#374151;cursor:pointer;background:#f3f4f6;border:1px solid #d1d5db;border-radius:4px;padding:.2rem .4rem;font-size:.75rem}.preview-separator[data-v-4aacb015]{background:#d1d5db;width:1px;height:14px;margin-left:8px;margin-right:8px}.preview-route[data-v-4aacb015]{color:#6b7280;background:#f3f4f6;border:1px solid #e5e7eb;border-radius:9999px;align-items:center;gap:6px;height:24px;padding:2px 10px;font-family:ui-monospace,monospace;font-size:12px;display:inline-flex}.preview-route .pi[data-v-4aacb015]{color:#9ca3af;font-size:10px}.preview-frame-wrapper[data-v-4aacb015]{background:#e5e7eb;flex:1;justify-content:center;display:flex;overflow:auto}.preview-iframe[data-v-4aacb015]{background:#fff;border:0;flex:none;height:100%;transition:width .2s}.dark .preview-panel.fullscreen{background:#09090b}.dark .preview-toolbar{border-bottom-color:#27272a}.dark .device-btn{color:#71717a}.dark .device-btn:hover{color:#e4e4e7;border-color:#3f3f46}.dark .host-page-select{color:#e0e0e0;background:#1e1e2e;border-color:#3f3f46}.dark .preview-separator{background:#3f3f46}.dark .preview-route{color:#a1a1aa;background:#18181b;border-color:#27272a}.dark .preview-route .pi{color:#52525b}.dark .preview-frame-wrapper{background:#1a1a2e}.cms-editor[data-v-f9c0172b]{height:calc(100% - 60px);display:flex}.cms-left[data-v-f9c0172b]{border-right:1px solid #27272a;flex-shrink:0;width:250px;overflow:auto}.cms-left-wide[data-v-f9c0172b]{width:55%;max-width:900px;overflow:hidden}.cms-splitter[data-v-f9c0172b]{border:0;border-radius:0;height:100%}.cms-preview[data-v-f9c0172b]{flex:1;min-width:0;overflow:hidden}.cms-panel[data-v-f9c0172b]{overflow:auto}.cms-panel-content[data-v-f9c0172b]{padding:1rem}.playground[data-v-073d12d3]{height:calc(100% - 60px);display:flex}.playground-sidebar[data-v-073d12d3]{border-right:1px solid #e5e7eb;flex-shrink:0;width:220px;padding:.75rem 0;overflow-y:auto}.sidebar-header[data-v-073d12d3]{text-transform:uppercase;letter-spacing:.05em;color:#6b7280;margin-bottom:.75rem;padding:0 1rem;font-size:.75rem;font-weight:700}.sidebar-loading[data-v-073d12d3]{color:#9ca3af;padding:1rem;font-size:.8125rem}.sidebar-section[data-v-073d12d3]{margin-bottom:.5rem}.section-label[data-v-073d12d3]{text-transform:uppercase;letter-spacing:.05em;color:#9ca3af;padding:.375rem 1rem;font-size:.625rem;font-weight:600}.section-label-toggle[data-v-073d12d3]{cursor:pointer;-webkit-user-select:none;user-select:none;align-items:center;gap:.375rem;display:flex}.section-label-toggle[data-v-073d12d3]:hover{color:#6b7280}.toggle-icon[data-v-073d12d3]{font-size:.5rem}.sidebar-item[data-v-073d12d3]{cursor:pointer;color:#6b7280;align-items:center;gap:.5rem;padding:.3125rem 1rem;font-size:.8125rem;display:flex}.sidebar-item[data-v-073d12d3]:hover{color:#374151;background:#80808014}.sidebar-item.active[data-v-073d12d3]{color:#667eea;background:#667eea1a}.item-icon[data-v-073d12d3]{text-align:center;flex-shrink:0;width:14px;font-size:.6875rem}.item-name[data-v-073d12d3]{white-space:nowrap;text-overflow:ellipsis;flex:1;overflow:hidden}.sidebar-empty[data-v-073d12d3]{color:#9ca3af;padding:1.5rem 1rem;font-size:.8125rem;line-height:1.6}.sidebar-empty .hint[data-v-073d12d3]{margin-top:.75rem}.sidebar-empty code[data-v-073d12d3]{background:#8080801a;border-radius:3px;padding:1px 4px;font-family:monospace;font-size:.75rem}.playground-main[data-v-073d12d3]{flex-direction:column;flex:1;display:flex;overflow:hidden}.main-empty[data-v-073d12d3]{color:#9ca3af;flex-direction:column;justify-content:center;align-items:center;height:100%;font-size:.875rem;display:flex}.main-toolbar[data-v-073d12d3]{border-bottom:1px solid #e5e7eb;flex-shrink:0;align-items:center;gap:.75rem;padding:.5rem 1rem;font-size:.8125rem;display:flex}.toolbar-label[data-v-073d12d3]{color:#6b7280;flex:1;align-items:baseline;gap:.5rem;display:flex}.toolbar-type[data-v-073d12d3]{text-transform:uppercase;letter-spacing:.03em;font-size:.6875rem}.toolbar-label strong[data-v-073d12d3]{color:#374151;font-size:.875rem}.toolbar-hint[data-v-073d12d3]{color:#9ca3af;font-size:.6875rem;font-style:italic}.toolbar-btn[data-v-073d12d3]{color:#6b7280;cursor:pointer;white-space:nowrap;background:0 0;border:1px solid #e5e7eb;border-radius:6px;align-items:center;gap:.375rem;padding:.25rem .625rem;font-size:.75rem;display:flex}.toolbar-btn[data-v-073d12d3]:hover{color:#374151;background:#80808014}.main-body[data-v-073d12d3]{flex:1;display:flex;overflow:hidden}.main-content[data-v-073d12d3]{flex:1;min-width:0;padding:1.5rem;overflow-y:auto}.mount-container[data-v-073d12d3]{max-width:600px}.mount-error[data-v-073d12d3]{color:#dc2626;background:#dc262614;border-radius:6px;margin-bottom:1rem;padding:.75rem;font-size:.8125rem}.value-inspector[data-v-073d12d3]{border-left:1px solid #e5e7eb;flex-direction:column;flex:1;min-width:0;display:flex;overflow-y:auto}.inspector-header[data-v-073d12d3]{text-transform:uppercase;letter-spacing:.05em;color:#9ca3af;border-bottom:1px solid #e5e7eb;flex-shrink:0;padding:.5rem .75rem;font-size:.625rem;font-weight:600}.inspector-value[data-v-073d12d3]{color:#374151;white-space:pre-wrap;word-break:break-word;flex:1;margin:0;padding:.75rem;font-family:JetBrains Mono,Fira Code,monospace;font-size:.75rem;line-height:1.7}.inspector-value .jv-key[data-v-073d12d3]{color:#6b7280}.inspector-value .jv-str[data-v-073d12d3]{color:#16a34a}.inspector-value .jv-num[data-v-073d12d3]{color:#d97706}.inspector-value .jv-bool[data-v-073d12d3]{color:#7c3aed}.inspector-value .jv-null[data-v-073d12d3]{color:#9ca3af}.dark .playground-sidebar{border-right-color:#27272a}.dark .sidebar-header{color:#666}.dark .section-label{color:#555}.dark .section-label-toggle:hover{color:#999}.dark .sidebar-item{color:#bbb}.dark .sidebar-item:hover{color:#e4e4e7;background:#ffffff0d}.dark .sidebar-item.active{color:#667eea;background:#667eea26}.dark .main-toolbar{border-bottom-color:#27272a}.dark .toolbar-label{color:#999}.dark .toolbar-label strong{color:#e4e4e7}.dark .toolbar-hint{color:#555}.dark .toolbar-btn{color:#999;border-color:#333}.dark .toolbar-btn:hover{color:#e4e4e7;background:#ffffff0d}.dark .mount-error{color:#f87171;background:#f8717114}.dark .value-inspector{background:#0c0c14;border-left-color:#27272a}.dark .inspector-header{color:#666;border-bottom-color:#27272a}.dark .inspector-value{color:#e4e4e7}.dark .inspector-value .jv-key{color:#8888a0}.dark .inspector-value .jv-str{color:#4ade80}.dark .inspector-value .jv-num{color:#fbbf24}.dark .inspector-value .jv-bool{color:#a78bfa}.dark .inspector-value .jv-null{color:#52525b}:root{--color-bg:var(--p-content-background);--color-fg:var(--p-text-color);--color-muted:var(--p-text-muted-color);--color-border:var(--p-content-border-color);--color-hover-bg:var(--p-content-hover-background);--color-input-bg:var(--p-form-field-background);--color-input-border:var(--p-form-field-border-color);--color-primary:var(--p-primary-color);--color-danger-bg:var(--p-red-50);--color-danger-fg:var(--p-red-700);--color-success-bg:var(--p-green-50);--color-success-fg:var(--p-green-700);--color-warning-bg:var(--p-amber-50);--color-warning-fg:var(--p-amber-900);--color-info-bg:var(--p-blue-50);--color-info-fg:var(--p-blue-900);--color-env-prod-bg:var(--p-red-100);--color-env-prod-fg:var(--p-red-800);--color-env-staging-bg:var(--p-amber-100);--color-env-staging-fg:var(--p-amber-800);--color-change-added:var(--p-green-700);--color-change-modified:var(--p-amber-700);--color-change-deleted:var(--p-gray-500);--color-bg-code:var(--p-surface-100);--color-bg-chip:var(--p-content-hover-background)}.dark{--color-danger-bg:var(--p-red-950);--color-danger-fg:var(--p-red-300);--color-success-bg:var(--p-green-950);--color-success-fg:var(--p-green-400);--color-warning-bg:var(--p-amber-950);--color-warning-fg:var(--p-amber-300);--color-info-bg:var(--p-blue-950);--color-info-fg:var(--p-blue-300);--color-env-prod-bg:var(--p-red-950);--color-env-prod-fg:var(--p-red-300);--color-env-staging-bg:var(--p-amber-950);--color-env-staging-fg:var(--p-amber-300);--color-change-added:var(--p-green-400);--color-change-modified:var(--p-amber-400);--color-change-deleted:var(--p-gray-400);--color-bg-code:var(--p-surface-900)}