ankka-console 0.10.0 → 0.12.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 (75) hide show
  1. package/dist/client/control-plane.d.ts +87 -1
  2. package/dist/client/control-plane.js +201 -1
  3. package/dist/client/schemas.d.ts +1835 -0
  4. package/dist/client/schemas.js +595 -0
  5. package/dist/context.d.ts +98 -0
  6. package/dist/context.js +73 -0
  7. package/dist/extensions/render.d.ts +2 -0
  8. package/dist/extensions/render.js +5 -0
  9. package/dist/extensions/types.d.ts +1 -1
  10. package/dist/extensions/types.js +29 -0
  11. package/dist/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
  12. package/dist/fonts/inter-latin-wght-normal.woff2 +0 -0
  13. package/dist/index.d.ts +9 -2
  14. package/dist/index.js +7 -1
  15. package/dist/routes/auth.sign-out.js +8 -3
  16. package/dist/routes/front.d.ts +62 -2
  17. package/dist/routes/front.js +45 -10
  18. package/dist/routes/logs.d.ts +92 -0
  19. package/dist/routes/logs.js +15 -14
  20. package/dist/routes/machines.d.ts +78 -0
  21. package/dist/routes/machines.js +78 -0
  22. package/dist/routes/members.js +11 -8
  23. package/dist/routes/organization-new.js +7 -4
  24. package/dist/routes/organization.d.ts +29 -1
  25. package/dist/routes/organization.js +38 -9
  26. package/dist/routes/project-new.js +8 -4
  27. package/dist/routes/project.d.ts +347 -2
  28. package/dist/routes/project.js +182 -9
  29. package/dist/routes/service-apply.d.ts +5 -2
  30. package/dist/routes/service-apply.js +17 -14
  31. package/dist/routes/service-history.d.ts +32 -0
  32. package/dist/routes/service-history.js +82 -0
  33. package/dist/routes/service-topology.d.ts +210 -0
  34. package/dist/routes/service-topology.js +54 -0
  35. package/dist/routes/service.d.ts +91 -10
  36. package/dist/routes/service.js +87 -23
  37. package/dist/routes/stream.service.js +18 -1
  38. package/dist/routes/tokens.js +8 -6
  39. package/dist/routes.js +3 -0
  40. package/dist/runtime.d.ts +3 -1
  41. package/dist/runtime.js +1 -0
  42. package/dist/styles.css +2 -481
  43. package/dist/testing/fake-control-plane.d.ts +334 -1
  44. package/dist/testing/fake-control-plane.js +1194 -15
  45. package/dist/testing/index.d.ts +1 -1
  46. package/dist/testing/scenarios.js +6 -0
  47. package/dist/theme.css +66 -0
  48. package/dist/ui/console.d.ts +19 -6
  49. package/dist/ui/console.js +9 -2
  50. package/dist/ui/errors.js +7 -5
  51. package/dist/ui/grants.d.ts +3 -0
  52. package/dist/ui/grants.js +13 -0
  53. package/dist/ui/hosting.d.ts +11 -0
  54. package/dist/ui/hosting.js +20 -0
  55. package/dist/ui/primitives/button.d.ts +11 -0
  56. package/dist/ui/primitives/button.js +21 -0
  57. package/dist/ui/primitives/select.d.ts +10 -0
  58. package/dist/ui/primitives/select.js +4 -0
  59. package/dist/ui/primitives/switch.d.ts +9 -0
  60. package/dist/ui/primitives/switch.js +4 -0
  61. package/dist/ui/shape.d.ts +4 -0
  62. package/dist/ui/shape.js +36 -0
  63. package/dist/ui/shell.d.ts +76 -0
  64. package/dist/ui/shell.js +114 -0
  65. package/dist/ui/tokens.d.ts +82 -0
  66. package/dist/ui/tokens.js +172 -0
  67. package/dist/ui/topology/Graph.d.ts +13 -0
  68. package/dist/ui/topology/Graph.js +56 -0
  69. package/dist/ui/topology/Table.d.ts +10 -0
  70. package/dist/ui/topology/Table.js +14 -0
  71. package/dist/ui/topology/layout.d.ts +113 -0
  72. package/dist/ui/topology/layout.js +177 -0
  73. package/dist/ui/use-stream.d.ts +251 -1
  74. package/dist/ui/use-stream.js +11 -1
  75. package/package.json +11 -3
@@ -1,13 +1,14 @@
1
- import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
3
  * An organization's deploy tokens. A new token's secret is shown exactly once: the creation
4
4
  * redirects (so a reload can never create a second token), carrying the secret across in a sealed
5
5
  * cookie that this page reads and clears on its next render.
6
6
  */
7
7
  import { redirect, useLoaderData } from "react-router";
8
- import { act, guard, pageData, text, useConsoleContext } from "../context.js";
8
+ import { act, guard, organizationShell, pageData, text, useConsoleContext } from "../context.js";
9
9
  import { ConsoleErrorBoundary } from "../ui/errors.js";
10
- import { Breadcrumbs, ConsoleForm, Field, Submit, useConsole, when } from "../ui/console.js";
10
+ import { ConsoleForm, Field, Submit, useConsole, when } from "../ui/console.js";
11
+ import { Page, SectionTitle } from "../ui/shell.js";
11
12
  import { Refused, useRefusal } from "../ui/refused.js";
12
13
  import { HostActions } from "../extensions/render.js";
13
14
  export const meta = () => [{ title: "Deploy tokens · ankka" }];
@@ -15,10 +16,10 @@ export async function loader({ request, params, context }) {
15
16
  const ctx = useConsoleContext(context);
16
17
  const id = params.organizationId;
17
18
  return guard(ctx, async () => {
18
- const [organization, tokens, page] = await Promise.all([ctx.client.getOrganization(id), ctx.client.tokens(id), pageData(ctx)]);
19
+ const [organization, tokens, projects, page] = await Promise.all([ctx.client.getOrganization(id), ctx.client.tokens(id), ctx.client.listProjects(), pageData(ctx)]);
19
20
  const created = await ctx.runtime.tokenFlash.take(request, ctx.headers);
20
21
  // Shown from the one-time cookie alone: the listing is a projection and may not show the new token yet.
21
- return { console: page, organization, tokens, created };
22
+ return { console: organizationShell(page, organization, projects, "tokens", [{ label: "Deploy tokens" }]), organization, tokens, created };
22
23
  });
23
24
  }
24
25
  export async function action({ request, params, context }) {
@@ -45,6 +46,7 @@ export default function Tokens() {
45
46
  const { organization: o, tokens, created } = useLoaderData();
46
47
  const { shows } = useConsole();
47
48
  const refusal = useRefusal("create");
48
- return (_jsxs("section", { className: "ac-page", children: [_jsx(Breadcrumbs, { trail: [{ label: "Organizations", to: "" }, { label: o.name, to: `organizations/${encodeURIComponent(o.id)}` }, { label: "Deploy tokens" }] }), _jsxs("h1", { children: ["Deploy tokens for ", o.name] }), _jsx("p", { className: "ac-lede", children: "A deploy token lets a machine, such as a CI job, deploy as a member of this organization. It cannot manage members or tokens." }), created ? (_jsxs("div", { className: "ac-notice", role: "status", children: [_jsxs("p", { children: [_jsxs("strong", { children: ["Copy the token for ", created.label, " now."] }), " It is shown this once and cannot be retrieved later."] }), _jsx("code", { className: "ac-secret", "data-secret": true, children: created.secret })] })) : null, tokens.length === 0 ? (_jsx("p", { className: "ac-empty", children: "No deploy tokens." })) : (_jsx("div", { className: "ac-table-wrap", children: _jsxs("table", { className: "ac-table", children: [_jsx("caption", { className: "ac-visually-hidden", children: "Deploy tokens" }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Label" }), _jsx("th", { scope: "col", children: "Id" }), _jsx("th", { scope: "col", children: "Created" }), _jsx("th", { scope: "col", children: "Expires" }), _jsx("th", { scope: "col", children: "Last used" }), _jsx("th", { scope: "col", children: "Revoke" })] }) }), _jsx("tbody", { children: tokens.map((t) => (_jsxs("tr", { "data-token": t.id, children: [_jsx("td", { children: t.label }), _jsx("td", { children: t.id }), _jsxs("td", { children: [when(t.createdAt), t.createdBy ? ` by ${t.createdBy}` : ""] }), _jsx("td", { children: t.expiresAt ? when(t.expiresAt) : "Never" }), _jsx("td", { children: t.lastUsed ?? "Never" }), _jsx("td", { children: shows("token.revoke") ? (_jsxs(ConsoleForm, { intent: "revoke", children: [_jsx("input", { type: "hidden", name: "tokenId", value: t.id }), _jsx(Submit, { intent: "revoke", danger: true, children: "Revoke" })] })) : null })] }, t.id))) })] }) })), _jsx(Refused, { intent: "revoke" }), shows("token.create") ? (_jsxs(_Fragment, { children: [_jsx("h2", { children: "Create a deploy token" }), _jsxs(ConsoleForm, { intent: "create", className: "ac-inline", children: [_jsx(Field, { label: "Label", name: "label", required: true, hint: "What uses it, such as a repository's CI.", defaultValue: refusal?.values.label, autoComplete: "off" }), _jsx(Field, { label: "Expires after days", name: "expiresInDays", type: "number", min: 0, max: 365, hint: "Empty for the platform's default of 90 days; 0 for never; at most 365.", defaultValue: refusal?.values.expiresInDays }), _jsx(Submit, { intent: "create", children: "Create token" })] }), _jsx(Refused, { intent: "create" }), _jsx("div", { className: "ac-actions", children: _jsx(HostActions, { operation: "token.create", entity: o }) })] })) : null] }));
49
+ const inspector = shows("token.create") ? (_jsxs("section", { "aria-labelledby": "create-token", className: "ac-form", children: [_jsx(SectionTitle, { children: _jsx("span", { id: "create-token", children: "Create a deploy token" }) }), _jsxs(ConsoleForm, { intent: "create", className: "ac-inline", children: [_jsx(Field, { label: "Label", name: "label", required: true, hint: "What uses it, such as a repository's CI.", defaultValue: refusal?.values.label, autoComplete: "off" }), _jsx(Field, { label: "Expires after days", name: "expiresInDays", type: "number", min: 0, max: 365, hint: "Empty for the platform's default of 90 days; 0 for never; at most 365.", defaultValue: refusal?.values.expiresInDays }), _jsx(Submit, { intent: "create", primary: true, children: "Create token" })] }), _jsx(Refused, { intent: "create" }), _jsx("div", { className: "ac-ops", children: _jsx(HostActions, { operation: "token.create", entity: o }) })] })) : null;
50
+ return (_jsxs(Page, { inspector: inspector, children: [_jsxs("h1", { children: ["Deploy tokens for ", o.name] }), _jsx("p", { className: "ac-lede", children: "A deploy token lets a machine, such as a CI job, deploy as a member of this organization. It cannot manage members or tokens." }), created ? (_jsxs("div", { className: "ac-notice", role: "status", children: [_jsxs("p", { children: [_jsxs("strong", { children: ["Copy the token for ", created.label, " now."] }), " It is shown this once and cannot be retrieved later."] }), _jsx("code", { className: "ac-secret", "data-secret": true, children: created.secret })] })) : null, _jsxs("section", { className: "ac-card", "aria-label": "Deploy tokens", children: [tokens.length === 0 ? (_jsx("p", { className: "ac-empty", children: "No deploy tokens." })) : (_jsx("div", { className: "ac-table-wrap", children: _jsxs("table", { className: "ac-table", children: [_jsx("caption", { className: "ac-visually-hidden", children: "Deploy tokens" }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Label" }), _jsx("th", { scope: "col", children: "Id" }), _jsx("th", { scope: "col", children: "Created" }), _jsx("th", { scope: "col", children: "Expires" }), _jsx("th", { scope: "col", children: "Last used" }), _jsx("th", { scope: "col", children: "Revoke" })] }) }), _jsx("tbody", { children: tokens.map((t) => (_jsxs("tr", { "data-token": t.id, children: [_jsx("td", { children: t.label }), _jsx("td", { children: t.id }), _jsxs("td", { children: [when(t.createdAt), t.createdBy ? ` by ${t.createdBy}` : ""] }), _jsx("td", { children: t.expiresAt ? when(t.expiresAt) : "Never" }), _jsx("td", { children: t.lastUsed ?? "Never" }), _jsx("td", { children: shows("token.revoke") ? (_jsxs(ConsoleForm, { intent: "revoke", children: [_jsx("input", { type: "hidden", name: "tokenId", value: t.id }), _jsx(Submit, { intent: "revoke", className: "ac-button ac-button-small ac-button-danger", children: "Revoke" })] })) : null })] }, t.id))) })] }) })), _jsx(Refused, { intent: "revoke" })] })] }));
49
51
  }
50
52
  export const ErrorBoundary = ConsoleErrorBoundary;
package/dist/routes.js CHANGED
@@ -34,11 +34,14 @@ export function consoleRoutes(options = {}) {
34
34
  page("organizations/:organizationId", "organization"),
35
35
  page("organizations/:organizationId/members", "members"),
36
36
  page("organizations/:organizationId/tokens", "tokens"),
37
+ page("organizations/:organizationId/machines", "machines"),
37
38
  page("organizations/:organizationId/projects/new", "project-new"),
38
39
  page("projects/:projectId", "project"),
39
40
  page("projects/:projectId/services/apply", "service-apply"),
40
41
  page("projects/:projectId/services/:name", "service"),
41
42
  page("projects/:projectId/services/:name/logs", "logs"),
43
+ page("projects/:projectId/services/:name/topology", "service-topology"),
44
+ page("projects/:projectId/services/:name/history", "service-history"),
42
45
  resource("stream/projects/:projectId", "stream.project"),
43
46
  resource("stream/services/:projectId/:name", "stream.service"),
44
47
  ...(auth
package/dist/runtime.d.ts CHANGED
@@ -3,7 +3,7 @@ import { SealedFlash, type SessionStore } from "./session/cookie-store.ts";
3
3
  import { SessionTokenSource, type TokenSource } from "./session/token-source.ts";
4
4
  import { type FetchLike } from "./server/transport.ts";
5
5
  import type { ConsoleOptions } from "./options.ts";
6
- import type { DeployTokenCreated } from "./client/schemas.ts";
6
+ import type { DeployTokenCreated, MachineRegistered } from "./client/schemas.ts";
7
7
  export interface ConsoleRuntime {
8
8
  options: ConsoleOptions;
9
9
  mount: string;
@@ -16,6 +16,8 @@ export interface ConsoleRuntime {
16
16
  controlPlaneFetch: FetchLike;
17
17
  /** A deploy token's secret, carried across one redirect and shown once. */
18
18
  tokenFlash: SealedFlash<DeployTokenCreated>;
19
+ /** A registered machine's client secret, carried across one redirect and shown once, as a token's is. */
20
+ machineFlash: SealedFlash<MachineRegistered>;
19
21
  pendingLogin: SealedFlash<{
20
22
  state: string;
21
23
  nonce: string;
package/dist/runtime.js CHANGED
@@ -71,6 +71,7 @@ export function createRuntime(options) {
71
71
  sessionTokens,
72
72
  controlPlaneFetch,
73
73
  tokenFlash: new SealedFlash({ secret: secret ?? "unused", secure, name: "ankka_console_flash", maxAgeSeconds: 60 }),
74
+ machineFlash: new SealedFlash({ secret: secret ?? "unused", secure, name: "ankka_console_machine_flash", maxAgeSeconds: 60 }),
74
75
  pendingLogin: new SealedFlash({ secret: secret ?? "unused", secure, name: "ankka_console_login", maxAgeSeconds: 600 }),
75
76
  log: options.log ?? ((line) => process.stdout.write(JSON.stringify(line) + "\n")),
76
77
  };
package/dist/styles.css CHANGED
@@ -1,481 +1,2 @@
1
- /* The console's pages. Every class is prefixed `ac-`; every colour, face and space is a custom
2
- property on .ac-root, so a host restyles the pages by overriding properties, not rules.
3
-
4
- Birch paper and lake ink by day, the lake at night after dark. One accent, duckbill amber, is kept
5
- for focus and for what is live; red is kept for failure. No web fonts: a console inside a cluster
6
- must not fetch anything from outside it. */
7
-
8
- .ac-root {
9
- --ac-paper: #f1f4f1;
10
- --ac-surface: #fbfcfb;
11
- --ac-ink: #13343b;
12
- --ac-reed: #4f6b56;
13
- --ac-water: #d5e2de;
14
- --ac-amber: #e0a526;
15
- --ac-amber-ink: #6b4a00;
16
- --ac-red: #a8231b;
17
- --ac-red-wash: #fbe9e7;
18
- --ac-green: #1f6b3a;
19
- --ac-serif: Charter, "Bitstream Charter", "Sitka Text", Cambria, Georgia, serif;
20
- --ac-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
21
- --ac-step: 1rem;
22
- --ac-measure: 72rem;
23
- --ac-radius-control: 6px;
24
-
25
- color: var(--ac-ink);
26
- background: var(--ac-paper);
27
- font-family: var(--ac-sans);
28
- font-size: 1rem;
29
- line-height: 1.5;
30
- font-variant-numeric: tabular-nums;
31
- min-height: 100vh;
32
- }
33
-
34
- @media (prefers-color-scheme: dark) {
35
- .ac-root {
36
- --ac-paper: #0f2226;
37
- --ac-surface: #142b30;
38
- --ac-ink: #e3ecea;
39
- --ac-reed: #9fbcaa;
40
- --ac-water: #26434a;
41
- --ac-amber: #f0b83c;
42
- --ac-amber-ink: #f0b83c;
43
- --ac-red: #ff8a80;
44
- --ac-red-wash: #3a1b19;
45
- --ac-green: #7fd4a0;
46
- }
47
- }
48
-
49
- .ac-root *,
50
- .ac-root *::before,
51
- .ac-root *::after {
52
- box-sizing: border-box;
53
- }
54
-
55
- /* ── Frame ───────────────────────────────────────────────────────────────── */
56
-
57
- .ac-bar {
58
- display: flex;
59
- align-items: baseline;
60
- gap: var(--ac-step);
61
- flex-wrap: wrap;
62
- padding: calc(var(--ac-step) * 0.75) var(--ac-step);
63
- border-bottom: 1px solid var(--ac-water);
64
- }
65
-
66
- .ac-wordmark {
67
- font-family: var(--ac-serif);
68
- font-size: 1.5rem;
69
- font-weight: 700;
70
- letter-spacing: -0.01em;
71
- color: var(--ac-ink);
72
- text-decoration: none;
73
- }
74
-
75
- .ac-wordmark-sub {
76
- font-family: var(--ac-serif);
77
- font-style: italic;
78
- color: var(--ac-reed);
79
- }
80
-
81
- .ac-bar-person {
82
- margin-left: auto;
83
- display: flex;
84
- align-items: baseline;
85
- gap: calc(var(--ac-step) * 0.75);
86
- color: var(--ac-reed);
87
- }
88
-
89
- .ac-bar-person form {
90
- display: inline;
91
- }
92
-
93
- .ac-main {
94
- max-width: var(--ac-measure);
95
- padding: var(--ac-step);
96
- margin: 0 auto;
97
- }
98
-
99
- .ac-page > * + * {
100
- margin-top: calc(var(--ac-step) * 1.5);
101
- }
102
-
103
- .ac-root h1,
104
- .ac-root h2 {
105
- font-family: var(--ac-serif);
106
- line-height: 1.2;
107
- margin: 0;
108
- font-weight: 700;
109
- }
110
-
111
- .ac-root h1 {
112
- font-size: clamp(1.75rem, 1.4rem + 1.5vw, 2.5rem);
113
- letter-spacing: -0.015em;
114
- }
115
-
116
- .ac-root h2 {
117
- font-size: 1.35rem;
118
- margin-top: calc(var(--ac-step) * 2.5);
119
- }
120
-
121
- .ac-root p {
122
- margin: 0;
123
- max-width: 68ch;
124
- }
125
-
126
- .ac-lede {
127
- color: var(--ac-reed);
128
- }
129
-
130
- .ac-root a {
131
- color: inherit;
132
- text-decoration-color: var(--ac-reed);
133
- text-underline-offset: 0.2em;
134
- }
135
-
136
- .ac-root a:hover {
137
- text-decoration-color: var(--ac-amber);
138
- text-decoration-thickness: 2px;
139
- }
140
-
141
- .ac-root :focus-visible {
142
- outline: 3px solid var(--ac-amber);
143
- outline-offset: 2px;
144
- border-radius: 2px;
145
- }
146
-
147
- /* ── Breadcrumbs ─────────────────────────────────────────────────────────── */
148
-
149
- .ac-crumbs ol {
150
- display: flex;
151
- flex-wrap: wrap;
152
- gap: 0.25rem;
153
- list-style: none;
154
- padding: 0;
155
- margin: 0;
156
- color: var(--ac-reed);
157
- }
158
-
159
- .ac-crumbs li + li::before {
160
- content: "›";
161
- margin-right: 0.25rem;
162
- }
163
-
164
- /* ── Tables: every listing is one ───────────────────────────────────────── */
165
-
166
- .ac-table-wrap {
167
- overflow-x: auto;
168
- }
169
-
170
- .ac-table {
171
- width: 100%;
172
- border-collapse: collapse;
173
- }
174
-
175
- .ac-table th,
176
- .ac-table td {
177
- text-align: left;
178
- padding: 0.6rem 0.75rem 0.6rem 0;
179
- border-bottom: 1px solid var(--ac-water);
180
- vertical-align: top;
181
- }
182
-
183
- .ac-table th {
184
- font-weight: 600;
185
- color: var(--ac-reed);
186
- font-size: 0.9rem;
187
- }
188
-
189
- .ac-table td.ac-num,
190
- .ac-table th.ac-num {
191
- text-align: right;
192
- }
193
-
194
- .ac-empty {
195
- padding: var(--ac-step) 0;
196
- color: var(--ac-reed);
197
- }
198
-
199
- /* ── Facts: a detail page's fields ──────────────────────────────────────── */
200
-
201
- .ac-facts {
202
- display: grid;
203
- grid-template-columns: minmax(9rem, max-content) 1fr;
204
- gap: 0.4rem var(--ac-step);
205
- margin: 0;
206
- }
207
-
208
- .ac-facts dt {
209
- color: var(--ac-reed);
210
- }
211
-
212
- .ac-facts dd {
213
- margin: 0;
214
- overflow-wrap: anywhere;
215
- }
216
-
217
- /* ── Status ─────────────────────────────────────────────────────────────── */
218
-
219
- .ac-status {
220
- display: inline-flex;
221
- align-items: baseline;
222
- gap: 0.4em;
223
- font-weight: 600;
224
- white-space: nowrap;
225
- }
226
-
227
- .ac-status-mark {
228
- font-size: 0.85em;
229
- letter-spacing: -0.15em;
230
- }
231
-
232
- .ac-status-ready .ac-status-mark {
233
- color: var(--ac-green);
234
- }
235
-
236
- .ac-status-moving .ac-status-mark,
237
- .ac-status-partial .ac-status-mark {
238
- color: var(--ac-amber-ink);
239
- }
240
-
241
- .ac-status-trouble {
242
- color: var(--ac-red);
243
- }
244
-
245
- .ac-status-stopped .ac-status-mark,
246
- .ac-status-idle .ac-status-mark {
247
- color: var(--ac-reed);
248
- }
249
-
250
- .ac-status-note {
251
- font-weight: 400;
252
- color: var(--ac-reed);
253
- }
254
-
255
- .ac-live {
256
- display: inline-flex;
257
- align-items: center;
258
- gap: 0.4em;
259
- color: var(--ac-reed);
260
- font-size: 0.9rem;
261
- }
262
-
263
- .ac-live::before {
264
- content: "";
265
- width: 0.5rem;
266
- height: 0.5rem;
267
- border-radius: 50%;
268
- background: var(--ac-amber);
269
- }
270
-
271
- @media (prefers-reduced-motion: no-preference) {
272
- .ac-live::before {
273
- animation: ac-ripple 2.4s ease-out infinite;
274
- }
275
- }
276
-
277
- @keyframes ac-ripple {
278
- 0% {
279
- box-shadow: 0 0 0 0 color-mix(in srgb, var(--ac-amber) 60%, transparent);
280
- }
281
- 100% {
282
- box-shadow: 0 0 0 0.6rem transparent;
283
- }
284
- }
285
-
286
- /* ── Forms ──────────────────────────────────────────────────────────────── */
287
-
288
- .ac-field {
289
- display: grid;
290
- gap: 0.25rem;
291
- max-width: 32rem;
292
- }
293
-
294
- .ac-field label {
295
- font-weight: 600;
296
- }
297
-
298
- .ac-root input,
299
- .ac-root select,
300
- .ac-root textarea {
301
- font: inherit;
302
- color: var(--ac-ink);
303
- background: var(--ac-surface);
304
- border: 1px solid var(--ac-reed);
305
- border-radius: var(--ac-radius-control);
306
- padding: 0.5rem 0.6rem;
307
- width: 100%;
308
- }
309
-
310
- .ac-root textarea {
311
- font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
312
- font-size: 0.9rem;
313
- min-height: 16rem;
314
- }
315
-
316
- .ac-root input[type="checkbox"] {
317
- width: auto;
318
- }
319
-
320
- .ac-root [aria-invalid="true"] {
321
- border-color: var(--ac-red);
322
- }
323
-
324
- .ac-hint {
325
- color: var(--ac-reed);
326
- font-size: 0.9rem;
327
- }
328
-
329
- .ac-field-error {
330
- color: var(--ac-red);
331
- }
332
-
333
- .ac-form {
334
- display: grid;
335
- gap: var(--ac-step);
336
- }
337
-
338
- .ac-inline {
339
- display: flex;
340
- flex-wrap: wrap;
341
- gap: 0.5rem;
342
- align-items: end;
343
- }
344
-
345
- .ac-inline .ac-field {
346
- flex: 1 1 12rem;
347
- }
348
-
349
- .ac-button {
350
- font: inherit;
351
- font-weight: 600;
352
- display: inline-block;
353
- padding: 0.45rem 0.9rem;
354
- border-radius: var(--ac-radius-control);
355
- border: 1px solid var(--ac-ink);
356
- background: var(--ac-ink);
357
- color: var(--ac-paper);
358
- cursor: pointer;
359
- text-decoration: none;
360
- white-space: nowrap;
361
- }
362
-
363
- .ac-button-quiet {
364
- background: transparent;
365
- color: var(--ac-ink);
366
- }
367
-
368
- .ac-button-danger {
369
- background: var(--ac-red);
370
- border-color: var(--ac-red);
371
- color: #fff;
372
- }
373
-
374
- .ac-button[disabled] {
375
- opacity: 0.55;
376
- cursor: progress;
377
- }
378
-
379
- .ac-actions {
380
- display: flex;
381
- flex-wrap: wrap;
382
- gap: 0.5rem;
383
- align-items: center;
384
- }
385
-
386
- .ac-actions form {
387
- display: inline;
388
- }
389
-
390
- /* Secondary and destructive operations wait behind a disclosure, so a page shows its state first. */
391
- .ac-more {
392
- border-top: 1px solid var(--ac-water);
393
- padding-top: var(--ac-step);
394
- }
395
-
396
- .ac-more summary {
397
- cursor: pointer;
398
- font-weight: 600;
399
- }
400
-
401
- .ac-more[open] > * + * {
402
- margin-top: var(--ac-step);
403
- }
404
-
405
- .ac-danger-zone {
406
- border-left: 3px solid var(--ac-red);
407
- padding-left: var(--ac-step);
408
- }
409
-
410
- /* ── Messages ───────────────────────────────────────────────────────────── */
411
-
412
- .ac-refusal {
413
- border-left: 3px solid var(--ac-red);
414
- background: var(--ac-red-wash);
415
- padding: 0.6rem 0.8rem;
416
- }
417
-
418
- .ac-refusal ul {
419
- margin: 0.4rem 0 0;
420
- padding-left: 1.2rem;
421
- }
422
-
423
- .ac-notice {
424
- border-left: 3px solid var(--ac-amber);
425
- padding: 0.6rem 0.8rem;
426
- background: var(--ac-surface);
427
- }
428
-
429
- .ac-secret {
430
- display: block;
431
- font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
432
- background: var(--ac-surface);
433
- border: 1px dashed var(--ac-reed);
434
- padding: 0.6rem;
435
- overflow-wrap: anywhere;
436
- user-select: all;
437
- }
438
-
439
- /* ── Logs ───────────────────────────────────────────────────────────────── */
440
-
441
- .ac-log {
442
- font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
443
- font-size: 0.85rem;
444
- background: var(--ac-surface);
445
- border: 1px solid var(--ac-water);
446
- padding: 0.75rem;
447
- max-height: 32rem;
448
- overflow: auto;
449
- white-space: pre-wrap;
450
- overflow-wrap: anywhere;
451
- margin: 0;
452
- }
453
-
454
- /* ── Panels a host adds ─────────────────────────────────────────────────── */
455
-
456
- .ac-panel {
457
- border-top: 1px solid var(--ac-water);
458
- padding-top: var(--ac-step);
459
- }
460
-
461
- .ac-panel-failed {
462
- color: var(--ac-red);
463
- }
464
-
465
- .ac-visually-hidden {
466
- position: absolute;
467
- width: 1px;
468
- height: 1px;
469
- overflow: hidden;
470
- clip-path: inset(50%);
471
- white-space: nowrap;
472
- }
473
-
474
- @media (max-width: 40rem) {
475
- .ac-facts {
476
- grid-template-columns: 1fr;
477
- }
478
- .ac-facts dd {
479
- margin-bottom: 0.5rem;
480
- }
481
- }
1
+ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ @layer theme{:root,:host{--ac-spacing:.25rem;--ac-color-mesh-base:#111f26;--ac-color-mesh-slate:#1e2e3a;--ac-color-glow:#d4805857;--ac-color-peach:#deaa8429;--ac-color-dot:#ffffff14;--ac-color-glass:#ffffff0d;--ac-color-glass-strong:#ffffff17;--ac-color-glass-line:#fff3;--ac-color-tile:#ffffff0f;--ac-color-tile-line:#ffffff24;--ac-color-node:#ffffff1a;--ac-color-node-line:#ffffff61;--ac-color-inset:#0003;--ac-color-edge:#ffffffb3;--ac-color-ink:#f5f8f7;--ac-color-ink-2:#dfe8e6;--ac-color-ink-3:#ccd9d6;--ac-color-amber:#f0b83c;--ac-color-amber-ink:#13343b;--ac-color-green:#8fe0ad;--ac-color-red:#ffc4bc;--ac-color-red-wash:#ff8a8029;--ac-shadow-part:0 18px 50px #050f1247;--ac-radius-panel:20px;--ac-radius-card:14px;--ac-radius-control:10px;--ac-radius-node:18px;--ac-font-sans:"Inter Variable", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--ac-font-mono:ui-monospace, "SF Mono", Menlo, Consolas, monospace;--ac-size-rail:56px;--ac-size-panel:232px;--ac-size-inspector:300px;--ac-size-bar:64px}:root:has(.ac-light){--ac-color-mesh-base:#e6eeee;--ac-color-mesh-slate:#cfe0dc;--ac-color-glow:#e0a5264d;--ac-color-peach:#f1d5c2cc;--ac-color-dot:#13343b1a;--ac-color-glass:#ffffff80;--ac-color-glass-strong:#ffffffd9;--ac-color-glass-line:#13343b24;--ac-color-tile:#ffffff80;--ac-color-tile-line:#13343b1a;--ac-color-node:#ffffff9e;--ac-color-node-line:#13343b38;--ac-color-inset:#13343b0f;--ac-color-edge:#13343b8c;--ac-color-ink:#13343b;--ac-color-ink-2:#33504f;--ac-color-ink-3:#4a6465;--ac-color-amber:#e0a526;--ac-color-amber-ink:#13343b;--ac-color-green:#1f6b3a;--ac-color-red:#a8231b;--ac-color-red-wash:#fbe9e7;--ac-shadow-part:0 18px 50px #13343b1a}}@layer base{.ac-root{color-scheme:dark;isolation:isolate;min-height:100vh;color:var(--ac-color-ink);font-family:var(--ac-font-sans);font-variant-numeric:tabular-nums;-webkit-font-smoothing:antialiased;font-size:.875rem;line-height:1.5;position:relative}.ac-root.ac-light{color-scheme:light}.ac-root *,.ac-root :before,.ac-root :after{box-sizing:border-box}.ac-root h1,.ac-root h2,.ac-root h3,.ac-root p,.ac-root dl,.ac-root dd,.ac-root figure{margin:0}.ac-root h1{letter-spacing:-.01em;text-wrap:balance;font-size:1.5rem;font-weight:600;line-height:1.2}.ac-root h2{font-size:.9375rem;font-weight:600}.ac-root h3{font-size:.875rem;font-weight:600}.ac-root p{max-width:72ch}.ac-root a{color:inherit;-webkit-text-decoration-color:var(--ac-color-ink-3);-webkit-text-decoration-color:var(--ac-color-ink-3);text-decoration-color:var(--ac-color-ink-3);text-underline-offset:.2em}.ac-root a:hover{-webkit-text-decoration-color:var(--ac-color-amber);-webkit-text-decoration-color:var(--ac-color-amber);text-decoration-color:var(--ac-color-amber);text-decoration-thickness:2px}.ac-root :focus-visible{outline:3px solid var(--ac-color-amber);outline-offset:2px;border-radius:4px}.ac-root code,.ac-root pre{font-family:var(--ac-font-mono)}.ac-root input,.ac-root select,.ac-root textarea{font:inherit;color:var(--ac-color-ink);background:var(--ac-color-inset);border:1px solid var(--ac-color-glass-line);border-radius:var(--ac-radius-control);width:100%;padding:.5rem .75rem}.ac-root input::placeholder,.ac-root textarea::placeholder{color:var(--ac-color-ink-3)}.ac-root textarea{font-family:var(--ac-font-mono);min-height:16rem;font-size:.8125rem}.ac-root input[type=checkbox],.ac-root input[type=radio]{width:auto;accent-color:var(--ac-color-amber)}.ac-root input[type=file]{padding:.4rem}.ac-root [aria-invalid=true]{border-color:var(--ac-color-red)}}@layer components{.ac-backdrop{z-index:-1;pointer-events:none;background:radial-gradient(var(--ac-color-dot) 1px, transparent 1.3px) 0 0 / 16px 16px, radial-gradient(42% 46% at 56% 52%, var(--ac-color-glow) 0%, transparent 72%), radial-gradient(40% 50% at 90% 88%, var(--ac-color-peach) 0%, transparent 65%), radial-gradient(55% 60% at 8% 10%, var(--ac-color-mesh-slate) 0%, transparent 70%), linear-gradient(160deg, var(--ac-color-mesh-base), var(--ac-color-mesh-slate));position:fixed;inset:0}.ac-rail,.ac-bar,.ac-listing,.ac-inspector{background:var(--ac-color-glass);-webkit-backdrop-filter:blur(20px)saturate(150%);backdrop-filter:blur(20px)saturate(150%);border:1px solid var(--ac-color-glass-line);border-radius:var(--ac-radius-panel)}@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){.ac-rail,.ac-bar,.ac-listing,.ac-inspector,.ac-card,.ac-panel,.ac-part{background:linear-gradient(var(--ac-color-glass), var(--ac-color-glass)), var(--ac-color-mesh-base)}}.ac-shell{--ac-shell-gap:12px;--ac-shell-rail:0px;--ac-shell-listing:0px;--ac-shell-inspector:0px;grid-template-columns:var(--ac-shell-rail) var(--ac-shell-listing) minmax(0, 1fr) var(--ac-shell-inspector);column-gap:0;row-gap:var(--ac-shell-gap);padding:var(--ac-shell-gap);grid-template-rows:auto 1fr;align-items:start;display:grid}.ac-shell:has(>.ac-rail){--ac-shell-rail:calc(var(--ac-size-rail) + var(--ac-shell-gap))}.ac-shell:has(>.ac-listing){--ac-shell-listing:calc(var(--ac-size-panel) + var(--ac-shell-gap))}.ac-shell:has(.ac-inspector){--ac-shell-inspector:calc(var(--ac-size-inspector) + var(--ac-shell-gap))}.ac-rail{top:var(--ac-shell-gap);max-height:calc(100vh - 2 * var(--ac-shell-gap));grid-area:1/1/3;margin-inline-end:var(--ac-shell-gap);position:sticky}.ac-bar{grid-area:1/2/auto/-1}.ac-listing{top:calc(var(--ac-size-bar) + 2 * var(--ac-shell-gap));max-height:calc(100vh - var(--ac-size-bar) - 3 * var(--ac-shell-gap));grid-area:2/2;margin-inline-end:var(--ac-shell-gap);position:sticky}.ac-page{display:contents}.ac-body{flex-direction:column;grid-area:2/3;gap:16px;min-width:0;padding-block-end:24px;display:flex}.ac-inspector{top:calc(var(--ac-size-bar) + 2 * var(--ac-shell-gap));max-height:calc(100vh - var(--ac-size-bar) - 3 * var(--ac-shell-gap));flex-direction:column;grid-area:2/4;gap:14px;margin-inline-start:var(--ac-shell-gap);padding:14px;display:flex;position:sticky;overflow:auto}.ac-rail{flex-direction:column;align-items:center;gap:6px;padding:10px 0;display:flex}.ac-rail-areas{flex-direction:column;align-items:center;gap:6px;margin:0;padding:0;list-style:none;display:flex}.ac-rail-foot{margin-top:auto}.ac-mark{width:40px;height:40px;color:var(--ac-color-ink);place-items:center;margin-bottom:8px;display:grid}.ac-rail-item{width:40px;height:40px;color:var(--ac-color-ink-2);cursor:pointer;background:0 0;border:0;border-radius:12px;place-items:center;padding:0;display:grid}.ac-rail-item svg{width:20px;height:20px}a.ac-rail-item:hover,button.ac-rail-item:hover{background:var(--ac-color-glass-strong);color:var(--ac-color-ink)}.ac-rail-item[aria-current]{background:var(--ac-color-amber);color:var(--ac-color-amber-ink)}.ac-rail-item[aria-disabled=true]{color:var(--ac-color-ink-3);opacity:.5;cursor:default}.ac-bar{min-height:var(--ac-size-bar);grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);align-items:center;gap:16px;padding:8px 16px;display:grid}.ac-bar-start,.ac-bar-end{align-items:center;gap:16px;min-width:0;display:flex}.ac-bar-end{justify-content:flex-end}.ac-wordmark{letter-spacing:-.01em;white-space:nowrap;font-size:1rem;font-weight:600}.ac-root a.ac-wordmark{text-decoration:none}.ac-wordmark span{color:var(--ac-color-ink-2);font-weight:400}.ac-person{background:var(--ac-color-glass-strong);border:1px solid var(--ac-color-glass-line);border-radius:50%;flex:none;place-items:center;width:32px;height:32px;font-size:.75rem;font-weight:600;display:grid}.ac-crumbs ol{color:var(--ac-color-ink-2);white-space:nowrap;align-items:center;gap:8px;margin:0;padding:0;list-style:none;display:flex}.ac-crumbs li+li:before{content:"/";color:var(--ac-color-ink-3);margin-right:8px}.ac-root .ac-crumbs a{text-decoration:none}.ac-root .ac-crumbs a:hover{color:var(--ac-color-ink);text-decoration:underline;-webkit-text-decoration-color:var(--ac-color-amber);-webkit-text-decoration-color:var(--ac-color-amber);text-decoration-color:var(--ac-color-amber)}.ac-crumbs [aria-current=page]{color:var(--ac-color-ink);font-weight:500}.ac-listing{flex-direction:column;gap:12px;min-height:0;padding:14px;display:flex}.ac-listing-items{gap:4px;min-height:0;margin:0;padding:0;list-style:none;display:grid;overflow:auto}.ac-listing-items>li:has(>[aria-current=page]){z-index:1;position:sticky;top:0;bottom:0}.ac-listing-item{border-radius:var(--ac-radius-control);background:var(--ac-color-tile);border:1px solid #0000;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:2px 8px;padding:8px 10px;display:grid}.ac-root a.ac-listing-item{text-decoration:none}.ac-listing-item:hover{background:var(--ac-color-glass-strong)}.ac-listing-item[aria-current=page]{background:linear-gradient(var(--ac-color-glass-strong), var(--ac-color-glass-strong)), var(--ac-color-mesh-base);border-color:var(--ac-color-glass-line)}.ac-listing-name{text-overflow:ellipsis;white-space:nowrap;font-weight:500;overflow:hidden}.ac-listing-count{color:var(--ac-color-ink-2);grid-area:1/2/3;font-size:.75rem}.ac-section-title{letter-spacing:.08em;text-transform:uppercase;color:var(--ac-color-ink-3);justify-content:space-between;align-items:center;margin:0;font-size:.6875rem;font-weight:600;display:flex}.ac-seg{background:var(--ac-color-inset);border-radius:999px;grid-auto-columns:1fr;grid-auto-flow:column;padding:3px;display:inline-grid}.ac-seg a{text-align:center;color:var(--ac-color-ink-2);white-space:nowrap;border-radius:999px;padding:6px 14px;font-weight:500}.ac-root .ac-seg a{text-decoration:none}.ac-seg a[aria-current=page]{background:var(--ac-color-glass-strong);color:var(--ac-color-ink);box-shadow:0 1px 2px #0003}.ac-head{flex-wrap:wrap;align-items:center;gap:12px 16px;padding:4px 6px 0;display:flex}.ac-head .ac-seg{margin-left:auto}.ac-lede,.ac-hint,.ac-empty{color:var(--ac-color-ink-2)}.ac-hint{font-size:.8125rem}.ac-card,.ac-panel{background:var(--ac-color-tile);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);border:1px solid var(--ac-color-tile-line);border-radius:var(--ac-radius-card);flex-direction:column;gap:12px;min-width:0;padding:16px;display:flex}.ac-panel-failed{color:var(--ac-color-red)}.ac-table-wrap{overflow-x:auto}.ac-table{border-collapse:collapse;width:100%}.ac-table th,.ac-table td{text-align:left;border-top:1px solid var(--ac-color-tile-line);vertical-align:top;padding:9px 12px 9px 0}.ac-table thead th{color:var(--ac-color-ink-2);border-top:0;padding-top:0;font-size:.8125rem;font-weight:500}.ac-table .ac-num{text-align:right}.ac-facts{grid-template-columns:minmax(8rem,max-content) minmax(0,1fr);column-gap:24px;display:grid}.ac-facts dt,.ac-facts dd{border-top:1px solid var(--ac-color-tile-line);padding:9px 0}.ac-facts dt{color:var(--ac-color-ink-2)}.ac-facts dd{overflow-wrap:anywhere}.ac-facts>div{display:contents}.ac-status{white-space:nowrap;align-items:baseline;gap:6px;font-weight:500;display:inline-flex}.ac-status-mark{letter-spacing:-.15em;font-size:.75em}.ac-status-ready .ac-status-mark{color:var(--ac-color-green)}.ac-status-moving .ac-status-mark,.ac-status-partial .ac-status-mark{color:var(--ac-color-amber)}.ac-status-trouble{color:var(--ac-color-red)}.ac-status-stopped .ac-status-mark,.ac-status-idle .ac-status-mark{color:var(--ac-color-ink-3)}.ac-status-note{color:var(--ac-color-ink-2);font-weight:400}.ac-pill{background:var(--ac-color-glass-strong);border:1px solid var(--ac-color-glass-line);border-radius:999px;padding:4px 10px 4px 8px}.ac-live{color:var(--ac-color-ink-2);align-items:center;gap:8px;font-size:.8125rem;display:inline-flex}.ac-live:before{content:"";background:var(--ac-color-amber);border-radius:50%;flex:none;width:8px;height:8px}@media (prefers-reduced-motion:no-preference){.ac-live:before{animation:2.4s ease-out infinite ac-ripple}}.ac-field{gap:4px;min-width:0;max-width:32rem;display:grid}.ac-field label{font-weight:500}.ac-field-error{color:var(--ac-color-red)}.ac-form{gap:16px;display:grid}.ac-inline{flex-wrap:wrap;align-items:end;gap:8px;display:flex}.ac-inline .ac-field{flex:12rem}.ac-inspector .ac-inline{flex-direction:column;align-items:stretch}.ac-inspector .ac-inline .ac-field{flex:none}.ac-inspector .ac-field{max-width:none}.ac-switch{cursor:pointer;align-items:center;gap:10px;display:inline-flex}.ac-root .ac-switch input{opacity:0;width:1px;height:1px;position:absolute}.ac-switch-track{background:var(--ac-color-inset);border:1px solid var(--ac-color-glass-line);border-radius:999px;flex:none;width:40px;height:24px;position:relative}.ac-switch-track:after{content:"";background:var(--ac-color-ink);border-radius:50%;width:18px;height:18px;position:absolute;top:2px;left:2px}.ac-switch input:checked+.ac-switch-track{background:var(--ac-color-amber);border-color:var(--ac-color-amber)}.ac-switch input:checked+.ac-switch-track:after{background:var(--ac-color-amber-ink);transform:translate(16px)}.ac-switch input:focus-visible+.ac-switch-track{outline:3px solid var(--ac-color-amber);outline-offset:2px}@media (prefers-reduced-motion:no-preference){.ac-switch-track,.ac-switch-track:after{transition:background .15s,transform .15s}}.ac-button{font:inherit;border:1px solid var(--ac-color-glass-line);background:var(--ac-color-glass-strong);color:var(--ac-color-ink);cursor:pointer;white-space:nowrap;border-radius:999px;justify-content:center;align-items:center;gap:8px;padding:7px 14px;font-weight:500;display:inline-flex}.ac-root a.ac-button{color:var(--ac-color-ink);text-decoration:none}.ac-button svg{width:16px;height:16px}.ac-button:hover{background:var(--ac-color-glass-line)}.ac-button-primary,.ac-root a.ac-button-primary{background:var(--ac-color-amber);border-color:var(--ac-color-amber);color:var(--ac-color-amber-ink)}.ac-button-primary:hover{background:var(--ac-color-amber)}@supports (color:color-mix(in lab, red, red)){.ac-button-primary:hover{background:color-mix(in srgb, var(--ac-color-amber) 88%, white)}}.ac-button-danger,.ac-root a.ac-button-danger{background:var(--ac-color-red);border-color:var(--ac-color-red);color:var(--ac-color-mesh-base)}.ac-button-danger:hover{background:var(--ac-color-red)}@supports (color:color-mix(in lab, red, red)){.ac-button-danger:hover{background:color-mix(in srgb, var(--ac-color-red) 88%, white)}}.ac-button-quiet{background:0 0}.ac-button-small{padding:4px 10px;font-size:.8125rem}.ac-button[disabled]{opacity:.55;cursor:progress}.ac-actions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.ac-actions form{display:inline}.ac-ops{gap:8px;display:grid}.ac-ops>form,.ac-ops>.ac-button,.ac-ops>form>.ac-button{width:100%}.ac-more{border-top:1px solid var(--ac-color-glass-line);padding-top:12px}.ac-more summary{cursor:pointer;font-weight:500}.ac-more[open]>*+*{margin-top:12px}.ac-danger-zone{border-left:3px solid var(--ac-color-red);gap:10px;padding:8px 0 8px 12px;display:grid}.ac-danger-zone p{color:var(--ac-color-ink-2);font-size:.8125rem}.ac-refusal{border-left:3px solid var(--ac-color-red);background:var(--ac-color-red-wash);border-radius:0 var(--ac-radius-control) var(--ac-radius-control) 0;padding:10px 14px}.ac-refusal ul{margin:6px 0 0;padding-left:1.2rem}.ac-notice{border-left:3px solid var(--ac-color-amber);background:var(--ac-color-tile);border-radius:0 var(--ac-radius-control) var(--ac-radius-control) 0;padding:10px 14px}.ac-secret{font-family:var(--ac-font-mono);background:var(--ac-color-inset);border:1px dashed var(--ac-color-ink-3);border-radius:var(--ac-radius-control);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all;padding:10px;display:block}.ac-log{font-family:var(--ac-font-mono);background:var(--ac-color-inset);border:1px solid var(--ac-color-tile-line);border-radius:var(--ac-radius-control);white-space:pre-wrap;overflow-wrap:anywhere;max-height:32rem;margin:0;padding:12px;font-size:.8125rem;overflow:auto}.ac-mounts{gap:4px;margin:0;padding:0;list-style:none;display:grid}.ac-visually-hidden{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.ac-shape{border-radius:var(--ac-radius-panel);border:1px solid var(--ac-color-glass-line);padding:28px 20px 20px}.ac-tree{justify-items:center;max-width:720px;margin:0 auto;display:grid}.ac-row{justify-items:center;width:100%;display:grid}.ac-row-many{gap:24px}.ac-part{background:var(--ac-color-node);-webkit-backdrop-filter:blur(18px)saturate(140%);backdrop-filter:blur(18px)saturate(140%);border:1px solid var(--ac-color-node-line);border-radius:var(--ac-radius-node);width:100%;max-width:300px;box-shadow:var(--ac-shadow-part);grid-template-columns:auto minmax(0,1fr);align-items:center;gap:2px 12px;padding:16px 16px 14px;display:grid;position:relative}.ac-part-self{box-shadow:var(--ac-shadow-part), 0 0 0 2px var(--ac-color-amber), 0 0 24px var(--ac-color-amber)}@supports (color:color-mix(in lab, red, red)){.ac-part-self{box-shadow:var(--ac-shadow-part), 0 0 0 2px var(--ac-color-amber), 0 0 24px color-mix(in srgb, var(--ac-color-amber) 45%, transparent)}}.ac-part-icon{width:40px;height:40px;color:var(--ac-color-ink);grid-row:1/3}.ac-part-icon svg{width:40px;height:40px}.ac-part-title,.ac-part-sub{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.ac-part-title{font-weight:500}.ac-part-sub{color:var(--ac-color-ink-2);font-size:.8125rem}.ac-part-inset{background:var(--ac-color-inset);border-radius:10px;grid-column:1/3;justify-content:space-between;align-items:center;gap:8px;margin-top:10px;padding:7px 12px;font-size:.8125rem;display:flex}.ac-part-up:before,.ac-part-down:after{content:"";background:var(--ac-color-node);border:1px solid var(--ac-color-node-line);width:12px;height:7px;position:absolute;left:50%;transform:translate(-50%)}.ac-part-down:after{border-top:0;border-radius:0 0 7px 7px;bottom:-7px}.ac-part-up:before{border-bottom:0;border-radius:7px 7px 0 0;top:-7px}.ac-part-tab{background:var(--ac-color-node);border:1px solid var(--ac-color-node-line);border-bottom:0;border-radius:12px 12px 0 0;gap:2px;padding:2px 8px 6px;display:flex;position:absolute;top:-27px;left:50%;transform:translate(-50%)}.ac-part-tab form{display:contents}.ac-tab-control{width:24px;height:20px;color:var(--ac-color-ink);cursor:pointer;background:0 0;border:0;border-radius:6px;place-items:center;padding:0;display:grid}.ac-tab-control:hover{background:var(--ac-color-glass-strong)}.ac-tab-control svg{width:14px;height:14px}.ac-part-tabbed{margin-top:27px}.ac-part-tabbed.ac-part-up:before{display:none}.ac-edge{width:100%;height:48px;color:var(--ac-color-edge);display:block;overflow:visible}.ac-edge path{fill:none;stroke:currentColor;stroke-width:1.5px;vector-effect:non-scaling-stroke}.ac-topology{align-items:flex-start;gap:16px;display:flex}.ac-topology-picture{border-radius:var(--ac-radius-panel);border:1px solid var(--ac-color-glass-line);flex:1;min-width:0;padding:8px;overflow-x:auto}.ac-topology-detail{flex:0 0 18rem}.ac-topology-node rect{fill:var(--ac-color-node);stroke:var(--ac-color-node-line);stroke-width:1px}.ac-topology-node{cursor:pointer}.ac-topology-node:focus-visible rect,.ac-topology-selected rect{stroke:var(--ac-color-amber);stroke-width:2px}.ac-topology-node:focus{outline:none}.ac-topology-outside rect,.ac-topology-differs rect{stroke-dasharray:4 3}.ac-topology-platform rect{fill:var(--ac-color-inset)}.ac-topology-name{fill:var(--ac-color-ink);font-size:12px;font-weight:600}.ac-topology-kind{fill:var(--ac-color-ink-2);font-size:11px}.ac-topology-declared{fill:none;stroke:var(--ac-color-edge);stroke-width:1.25px}.ac-topology-call{fill:none;stroke:var(--ac-color-ink);stroke-dasharray:5 4}.ac-topology-warning{stroke:var(--ac-color-red)}.ac-topology-mark{fill:var(--ac-color-red);font-size:14px;font-weight:700}@media (forced-colors:active){.ac-rail,.ac-bar,.ac-listing,.ac-inspector,.ac-card,.ac-panel,.ac-part,.ac-listing-item{border:1px solid canvastext}.ac-button,.ac-rail-item,.ac-seg a{border:1px solid buttontext}.ac-rail-item[aria-current],.ac-seg a[aria-current=page],.ac-listing-item[aria-current=page]{outline:2px solid highlight}}@media (max-width:1180px){.ac-shell,.ac-shell:has(>.ac-listing),.ac-shell:has(.ac-inspector){grid-template-columns:var(--ac-shell-rail) minmax(0, 1fr);grid-template-rows:none;grid-auto-rows:auto}.ac-rail{grid-row:1/span 5}.ac-bar,.ac-listing,.ac-body,.ac-inspector{grid-area:auto/2;max-height:none;margin-inline:0;position:static}.ac-listing-items{grid-template-columns:repeat(auto-fill,minmax(200px,1fr));max-height:18rem}}@media (max-width:720px){.ac-shell,.ac-shell:has(>.ac-rail),.ac-shell:has(>.ac-listing),.ac-shell:has(.ac-inspector){grid-template-columns:minmax(0,1fr)}.ac-rail{flex-flow:wrap;grid-area:auto/1;justify-content:flex-start;max-height:none;margin:0;padding:8px 10px;position:static}.ac-rail-areas{flex-flow:wrap}.ac-mark{margin:0 6px 0 0}.ac-rail-foot{margin-top:0;margin-left:auto}.ac-bar,.ac-listing,.ac-body,.ac-inspector{grid-column:1}.ac-bar{grid-template-columns:minmax(0,1fr) auto}.ac-bar-start{overflow:hidden}.ac-wordmark span{display:none}.ac-crumbs{grid-area:2/1/auto/-1}.ac-crumbs ol{white-space:normal;flex-wrap:wrap;row-gap:2px}.ac-head .ac-seg{width:100%;margin-left:0}.ac-row-many{gap:20px;grid-template-columns:minmax(0,1fr)!important}.ac-edge-split{display:none}.ac-facts{grid-template-columns:minmax(0,1fr)}.ac-facts dd{border-top:0;padding-top:0}.ac-topology{flex-direction:column}.ac-topology-detail{flex-basis:auto;width:100%}}}@layer utilities;@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./fonts/inter-latin-wght-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./fonts/inter-latin-ext-wght-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@keyframes ac-ripple{0%{box-shadow:0 0 0 0 color-mix(in srgb, var(--ac-color-amber) 60%, transparent)}to{box-shadow:0 0 0 .6rem #0000}}