toolroll 0.9.86 → 0.9.87

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 (171) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/dist/agents-board.d.ts +12 -0
  3. package/dist/agents-board.js +26 -0
  4. package/dist/approval-rules-ui.d.ts +4 -1
  5. package/dist/approval-rules-ui.js +31 -15
  6. package/dist/assignment-ui.js +1 -1
  7. package/dist/backup-ui.d.ts +5 -4
  8. package/dist/backup-ui.js +65 -32
  9. package/dist/browser/terminal.css +1 -1
  10. package/dist/browser/terminal.js +57 -54
  11. package/dist/browser/workspace.css +2 -2
  12. package/dist/browser/workspace.js +35 -70
  13. package/dist/browser-crew.js +1 -1
  14. package/dist/browser-workspace.d.ts +329 -183
  15. package/dist/browser-workspace.js +10 -9
  16. package/dist/chat-controls.d.ts +1 -1
  17. package/dist/chat-controls.js +1 -1
  18. package/dist/chat-settings-page.d.ts +29 -9
  19. package/dist/chat-settings-page.js +59 -28
  20. package/dist/check-levels-ui.d.ts +2 -1
  21. package/dist/check-levels-ui.js +67 -58
  22. package/dist/contracts/cli.d.ts +43 -0
  23. package/dist/contracts/cli.js +4 -0
  24. package/dist/contracts/console-api.d.ts +1 -1
  25. package/dist/contracts/console-api.js +1 -1
  26. package/dist/credentials-ui.d.ts +5 -3
  27. package/dist/credentials-ui.js +58 -31
  28. package/dist/design/kit.css +685 -0
  29. package/dist/design/kit.d.ts +208 -0
  30. package/dist/design/kit.js +177 -0
  31. package/dist/design/tokens.css +19 -1
  32. package/dist/discord-settings.js +8 -4
  33. package/dist/export-ui.d.ts +6 -4
  34. package/dist/export-ui.js +18 -8
  35. package/dist/flow-changed.d.ts +14 -0
  36. package/dist/flow-changed.js +53 -0
  37. package/dist/flow-gallery-ui.d.ts +41 -4
  38. package/dist/flow-gallery-ui.js +95 -63
  39. package/dist/flow-starters-ui.d.ts +3 -9
  40. package/dist/flow-starters-ui.js +12 -23
  41. package/dist/flow-unattended-words.d.ts +20 -0
  42. package/dist/flow-unattended-words.js +24 -0
  43. package/dist/flow-unattended.d.ts +9 -5
  44. package/dist/flow-unattended.js +45 -23
  45. package/dist/flows-cli.js +7 -3
  46. package/dist/flows-ui.d.ts +12 -6
  47. package/dist/flows-ui.js +141 -30
  48. package/dist/integrations-ui.d.ts +6 -4
  49. package/dist/integrations-ui.js +34 -40
  50. package/dist/integrations.d.ts +2 -2
  51. package/dist/integrations.js +4 -4
  52. package/dist/kits-ui.d.ts +8 -10
  53. package/dist/kits-ui.js +29 -33
  54. package/dist/kits.js +1 -1
  55. package/dist/knowledge-ui.js +76 -19
  56. package/dist/ledger-view.d.ts +2 -0
  57. package/dist/ledger-view.js +41 -38
  58. package/dist/models-ui.d.ts +8 -3
  59. package/dist/models-ui.js +82 -59
  60. package/dist/monitoring-ui.d.ts +4 -2
  61. package/dist/monitoring-ui.js +44 -13
  62. package/dist/needs-you.d.ts +1 -1
  63. package/dist/needs-you.js +8 -0
  64. package/dist/operate-remote-arguments.js +1 -0
  65. package/dist/operate-remote.js +1 -1
  66. package/dist/operate.d.ts +1 -1
  67. package/dist/operate.js +38 -4
  68. package/dist/passwordless.d.ts +1 -1
  69. package/dist/passwordless.js +1 -1
  70. package/dist/people-audit-ui.d.ts +2 -1
  71. package/dist/people-audit-ui.js +25 -23
  72. package/dist/policy-ui.d.ts +3 -2
  73. package/dist/policy-ui.js +27 -21
  74. package/dist/policy.d.ts +3 -0
  75. package/dist/policy.js +14 -1
  76. package/dist/project-delete-ui.d.ts +4 -2
  77. package/dist/project-delete-ui.js +135 -126
  78. package/dist/project-knowledge.d.ts +10 -10
  79. package/dist/publish.d.ts +11 -0
  80. package/dist/publish.js +16 -3
  81. package/dist/pull-request-ui.d.ts +2 -1
  82. package/dist/pull-request-ui.js +39 -28
  83. package/dist/recipe-ui.d.ts +4 -2
  84. package/dist/recipe-ui.js +14 -4
  85. package/dist/release-adapters.d.ts +3 -0
  86. package/dist/release-adapters.js +22 -2
  87. package/dist/release-cli.js +81 -9
  88. package/dist/release.d.ts +21 -0
  89. package/dist/release.js +40 -4
  90. package/dist/releases.js +1 -1
  91. package/dist/request-budget-ui.d.ts +4 -2
  92. package/dist/request-budget-ui.js +30 -19
  93. package/dist/retention-ui.d.ts +4 -3
  94. package/dist/retention-ui.js +15 -12
  95. package/dist/scope.d.ts +3 -0
  96. package/dist/scope.js +6 -0
  97. package/dist/serve.d.ts +0 -1
  98. package/dist/serve.js +51 -7
  99. package/dist/server/agents-computers.d.ts +9 -0
  100. package/dist/server/agents-computers.js +67 -0
  101. package/dist/server/chat.js +16 -16
  102. package/dist/server/chrome.d.ts +1 -1
  103. package/dist/server/chrome.js +19 -9
  104. package/dist/server/console.css +2 -2
  105. package/dist/server/flows.js +64 -36
  106. package/dist/server/home.d.ts +35 -0
  107. package/dist/server/home.js +104 -0
  108. package/dist/server/http.d.ts +3 -0
  109. package/dist/server/http.js +5 -0
  110. package/dist/server/kit-standalone.d.ts +22 -0
  111. package/dist/server/kit-standalone.js +69 -0
  112. package/dist/server/kit.d.ts +405 -0
  113. package/dist/server/kit.js +361 -0
  114. package/dist/server/pages.d.ts +2 -1
  115. package/dist/server/pages.js +213 -174
  116. package/dist/server/people-tokens.js +26 -85
  117. package/dist/server/render-history.d.ts +51 -0
  118. package/dist/server/render-history.js +228 -0
  119. package/dist/server/render-new-task.d.ts +29 -0
  120. package/dist/server/render-new-task.js +96 -0
  121. package/dist/server/render-next.d.ts +63 -0
  122. package/dist/server/render-next.js +109 -0
  123. package/dist/server/render-pages.d.ts +22 -190
  124. package/dist/server/render-pages.js +123 -575
  125. package/dist/server/render-people.d.ts +24 -3
  126. package/dist/server/render-people.js +93 -72
  127. package/dist/server/render-projects.d.ts +103 -0
  128. package/dist/server/render-projects.js +247 -0
  129. package/dist/server/render-results.d.ts +5 -24
  130. package/dist/server/render-results.js +48 -185
  131. package/dist/server/render-settings.d.ts +5 -74
  132. package/dist/server/render-settings.js +102 -493
  133. package/dist/server/render-tasks.d.ts +35 -5
  134. package/dist/server/render-tasks.js +114 -85
  135. package/dist/server/route-table.js +20 -5
  136. package/dist/server/settings.js +276 -255
  137. package/dist/server/task-views.d.ts +8 -0
  138. package/dist/server/task-views.js +85 -2
  139. package/dist/server/tasks.d.ts +8 -0
  140. package/dist/server/tasks.js +95 -40
  141. package/dist/server/terminals.js +1 -1
  142. package/dist/server/welcome.d.ts +22 -0
  143. package/dist/server/welcome.js +69 -0
  144. package/dist/settings-groups-ui.d.ts +279 -0
  145. package/dist/settings-groups-ui.js +615 -0
  146. package/dist/settings-kit.d.ts +42 -6
  147. package/dist/settings-kit.js +69 -7
  148. package/dist/setup-guide.d.ts +2 -2
  149. package/dist/skills-ui.js +59 -7
  150. package/dist/slack-settings.js +12 -5
  151. package/dist/spend-ui.d.ts +45 -26
  152. package/dist/spend-ui.js +124 -56
  153. package/dist/sso-ui.d.ts +5 -2
  154. package/dist/sso-ui.js +63 -31
  155. package/dist/storage-ui.d.ts +3 -2
  156. package/dist/storage-ui.js +56 -50
  157. package/dist/store.d.ts +112 -3
  158. package/dist/store.js +292 -20
  159. package/dist/surface.js +5 -1
  160. package/dist/teams-settings.d.ts +2 -1
  161. package/dist/teams-settings.js +24 -41
  162. package/dist/telegram-settings.d.ts +0 -4
  163. package/dist/telegram-settings.js +52 -25
  164. package/dist/toolroll-update-ui.d.ts +8 -4
  165. package/dist/toolroll-update-ui.js +55 -45
  166. package/dist/tools-ui.d.ts +5 -3
  167. package/dist/tools-ui.js +107 -42
  168. package/dist/work-index.js +11 -7
  169. package/dist/workspace-ui.d.ts +1 -1
  170. package/dist/workspace-ui.js +7 -4
  171. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,64 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.9.87 — 2026-11-03
4
+
5
+ - **The whole app is redesigned.** Every page, from sign-in to Settings,
6
+ now has one calm look: the same buttons, forms, status words and phone
7
+ layout everywhere, and amber only for what needs you.
8
+ - **A new Home.** One summary of where things stand and one Needs-you count,
9
+ the same count you see in the side rail, the phone dock and the tab title.
10
+ - **A new task page.** One column with a five-step progress line (Plan ·
11
+ Approval · Build · Checks · Ready), then Plan or Result, Activity and
12
+ Attempts. Approving asks for a password only when one is needed: with
13
+ Passwordless or a remembered password it is one click, and an automatic
14
+ rule shows nothing to press. The box keeps the exact terms it showed you;
15
+ if they change, it offers Reload, never a yes.
16
+ - **Tasks, as a list or a board.** Filter by project and by Needs you,
17
+ Running, Queued or Finished, each with its count; each waiting task says
18
+ what it asks for and offers one action.
19
+ - **Ship shows how long each check took**, every pull request check on one
20
+ timeline.
21
+ - **Release progress.** A release task shows every step in order, where it
22
+ stands ("Deploy to this Mac · Step 6 of 13") and why it stopped.
23
+ - **A new lead chat**, plus **⌘K search** from anywhere and a `/search` page.
24
+ - **Flows on the phone.** The flow canvas pans and pinch-zooms on a phone,
25
+ and the Flows list, templates, kits and starter flows are on the new look.
26
+ - **Settings in eight groups**, with what needs you at the top. Each section
27
+ saves on its own. Spend and Models live in Settings too.
28
+ - **A first-run guide at `/welcome`**: set a password, add a project, pick an
29
+ agent and models, turn on phone alerts, file a first task. The next step is
30
+ always the one highlighted.
31
+ - **New task is one box**: pick the project, type, send. Everything else is
32
+ under More options.
33
+ - **Some Settings saves work again.** Turning sign-in with a provider on or
34
+ off, turning Passwordless on, request limits and adding a tool no longer
35
+ fail with "Toolroll refused this (404)", and a save that stays on the same
36
+ page now shows what was saved.
37
+ - **From the terminal:** `toolroll task ship <task>` shows a task's pull
38
+ request checks, `toolroll release status [<task>]` shows release progress,
39
+ `toolroll task list --view queued` lists queued work, and `toolroll release
40
+ --branch <name>` releases a branch named like one of the command's words.
41
+
42
+ ### Safety
43
+
44
+ - **Approving a flow's script is bound to the exact version you read.** If
45
+ the script changes after you looked, the approval doesn't count.
46
+ - **Changing a flow ends its "run on its own" approvals**; it waits for you
47
+ again.
48
+ - **Password pages open no live connection** to the rest of the app.
49
+ - **Project credential forms always show the password field**, even with
50
+ Passwordless on (Where builds write, Home folder, Check access, Network).
51
+ Before, they hid it and every save was refused.
52
+ - **Choosing providers no longer widens by accident.** "Any provider" now
53
+ means every provider ticked; ticking some saves exactly those.
54
+ - **Releases ignore the advisory youiyoux check**, so a design warning never
55
+ holds up a release.
56
+
57
+ ### For developers
58
+
59
+ - **youiyoux enforces the kit in CI.** A pull request that adds design drift
60
+ against the shared kit (`src/design/KIT.md`) fails the youiyoux job.
61
+
3
62
  ## 0.9.86 — 2026-11-02
4
63
 
5
64
  - **Old tasks tidy themselves.** A routine's newer run puts away its older
@@ -130,4 +130,16 @@ export declare function laneNewestBuildSql(): string;
130
130
  export declare function agentLanesOf(store: Store, now: Date, access: {
131
131
  repos: readonly string[] | null;
132
132
  }, account: string, window: AgentLaneWindow, path?: string): BrowserAgentLanes | null;
133
+ /**
134
+ * The Agents list's every live agent, not only builds (UI revamp wave B): the build board's groups, with each running
135
+ * planner, scout and reviewer in the admitted projects added under Working (or Needs you when it asks). Reads the
136
+ * open leases only (store.liveRuns), then each run through the same admitted read the opened view uses.
137
+ */
138
+ export declare function agentsListOf(store: Store, now: Date, access: {
139
+ repos: readonly string[] | null;
140
+ }, account: string, root?: string): {
141
+ key: AgentGroupKey;
142
+ label: string;
143
+ rows: BrowserAgentRow[];
144
+ }[];
133
145
  export {};
@@ -332,3 +332,29 @@ export function agentLanesOf(store, now, access, account, window, path = "/agent
332
332
  running: tasks.length === 0 ? 0 : Number(tasks[0]["running"]),
333
333
  };
334
334
  }
335
+ /** The word a running planner, scout or reviewer wears on the Agents list (a build keeps its own state word). */
336
+ const ROLE_WORDS = { planner: "Planning", scout: "Investigating", reviewer: "Reviewing" };
337
+ /**
338
+ * The Agents list's every live agent, not only builds (UI revamp wave B): the build board's groups, with each running
339
+ * planner, scout and reviewer in the admitted projects added under Working (or Needs you when it asks). Reads the
340
+ * open leases only (store.liveRuns), then each run through the same admitted read the opened view uses.
341
+ */
342
+ export function agentsListOf(store, now, access, account, root) {
343
+ const groups = agentsBoardOf(store, now, access, account, root);
344
+ const shown = new Set(groups.flatMap(group => group.rows.map(row => row.runId)));
345
+ const extra = [];
346
+ for (const run of store.liveRuns(now)) {
347
+ const role = run.role;
348
+ if (!(role in ROLE_WORDS) || shown.has(run.id))
349
+ continue;
350
+ const facts = agentFactsFor(store, run.id, access, account);
351
+ if (facts === null)
352
+ continue;
353
+ const row = agentRowOf(store, facts, now, root);
354
+ extra.push(row.group === "working" || row.group === "stuck" ? { ...row, group: "working", label: ROLE_WORDS[role] } : row);
355
+ }
356
+ if (extra.length === 0)
357
+ return groups;
358
+ const all = [...groups.flatMap(group => group.rows), ...extra];
359
+ return AGENT_GROUPS.map(group => ({ ...group, rows: all.filter(row => row.group === group.key) })).filter(group => group.rows.length > 0);
360
+ }
@@ -30,7 +30,10 @@ export type ReleaseApprovalView = {
30
30
  at: string | null;
31
31
  canChange: boolean;
32
32
  };
33
- export declare function releaseApprovalHtml(view: ReleaseApprovalView): Html;
33
+ export declare function releaseApprovalHtml(view: ReleaseApprovalView, notice?: {
34
+ said?: string | null;
35
+ problem?: string | null;
36
+ }): Html;
34
37
  export declare function approvalRulesHtml(view: ApprovalRulesView, notice: {
35
38
  said?: string | null;
36
39
  problem?: string | null;
@@ -4,7 +4,9 @@
4
4
  * the identity provider); everyone else reads them. Every change is in the
5
5
  * ledger, before → after.
6
6
  */
7
- import { html, postForm, reauth } from "./html.js";
7
+ import { joinHtml } from "./html.js";
8
+ import { formRow, note, radios, settingsSection, switchInput, textarea } from "./server/kit.js";
9
+ import { kitSectionForm } from "./settings-kit.js";
8
10
  const RULES_CSS = `.approval-rules{max-width:720px;min-width:0}.approval-rules fieldset{border:0;padding:0;margin:18px 0 0;min-width:0}` +
9
11
  `.approval-rules legend{font-weight:600;font-size:.875rem;margin-bottom:8px}.approval-rules .choice{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;align-items:start;margin:0 0 10px;font-weight:400}` +
10
12
  `.approval-rules .choice input{margin:.2rem 0 0}.approval-rules .choice strong{display:block;font-size:.875rem;font-weight:500}.approval-rules .choice small{display:block;color:var(--muted-foreground);font-size:.8125rem;margin-top:2px}` +
@@ -24,23 +26,37 @@ export function rulesSummary(rules) {
24
26
  parts.push(`Work touching ${rules.protectedPaths.join(", ")} is protected: two people approve it, never a subagent or an operating mode.`);
25
27
  return parts.length === 0 ? "No approval rules: anyone who can approve on this project can approve its work, including their own." : parts.join(" ");
26
28
  }
27
- export function releaseApprovalHtml(view) {
28
- const since = view.setBy === null ? "" : html ` <span class="meta">Changed by ${view.setBy} on ${(view.at ?? "").slice(0, 10)}.</span>`;
29
- const current = html `<p class="current">${view.auto ? "Releases approve themselves once the pull request's CI and the release check pass on the exact commit. Anything red still asks you." : "Every release waits for your approval."}${since}</p>`;
30
- const heading = html `<h2>Release approval</h2>`;
29
+ export function releaseApprovalHtml(view, notice = {}) {
30
+ const since = view.setBy === null ? "" : ` · changed by ${view.setBy} on ${(view.at ?? "").slice(0, 10)}`;
31
+ const current = view.auto ? "Releases approve themselves once the pull request’s CI and the release check pass on the exact commit. Anything red still asks you." : "Every release waits for your approval.";
31
32
  if (!view.canChange)
32
- return html `<section class="release-approval">${heading}${current}<p class="meta">An approver of this project sets this.</p></section>`;
33
- const choice = (value, title, hint) => html `<label class="choice"><input type="radio" name="action" value="${value}"${(view.auto ? "auto" : "ask") === value ? html ` checked` : ""}><span><strong>${title}</strong><small>${hint}</small></span></label>`;
34
- return html `<section class="release-approval">${heading}${current}${postForm("/settings/release-approval", html `<fieldset aria-label="Release approval">${choice("ask", "Ask me", "A release deploys only after you approve it.")}${choice("auto", "Approve automatically when checks pass", "You're told when a release approves itself. A failed check, red CI or a CI failure after the deploy still stops and asks you.")}</fieldset><div class="step-up"><label>Your Toolroll password (to approve automatically)<input type="password" name="password" autocomplete="current-password"></label></div><button type="submit">Save</button>`, { hidden: { repo: view.repo } })}</section>`;
33
+ return settingsSection({ id: "release-approval", title: "Releases", state: since, body: joinHtml([note(current), note("An approver of this project sets this.")]) });
34
+ return settingsSection({ id: "release-approval", title: "Releases", state: since, lead: current,
35
+ body: kitSectionForm({ proof: "release-approval", action: "/settings/release-approval", id: "release-form", gate: true, hidden: { repo: view.repo }, proofWhen: ["action", "auto"],
36
+ confirm: "Approve releases automatically", said: notice.said ?? null, problem: notice.problem ?? null,
37
+ body: formRow("Releases", "Turning this on asks for your password, every time, even with Passwordless on.", radios({ name: "action", legend: "Releases", current: view.auto ? "auto" : "ask", items: [
38
+ { value: "ask", label: "Ask me", text: "A release deploys only after you approve it." },
39
+ { value: "auto", label: "Approve automatically when checks pass", text: "You’re told when a release approves itself. A failed check, red CI or a CI failure after the deploy still stops and asks you." }
40
+ ] }), "wide") }) });
35
41
  }
36
42
  export function approvalRulesHtml(view, notice) {
37
- const note = notice.problem ? html `<p class="problem" role="alert">${notice.problem}</p>` : notice.said ? html `<p role="status">${notice.said}</p>` : "";
38
- const changed = view.rules.updatedBy === null ? "" : html ` <span class="meta">Changed by ${view.rules.updatedBy} on ${(view.rules.updatedAt ?? "").slice(0, 10)}.</span>`;
39
- const current = html `<p class="current">${rulesSummary(view.rules)}${changed}</p>`;
43
+ const changed = view.rules.updatedBy === null ? "" : ` · changed by ${view.rules.updatedBy} on ${(view.rules.updatedAt ?? "").slice(0, 10)}`;
44
+ const current = rulesSummary(view.rules);
40
45
  if (!view.canChange)
41
- return html `<section class="approval-rules">${note}${current}<p class="meta">An instance operator sets these.</p></section>`;
46
+ return settingsSection({ id: "rules", title: `Approval rules · ${view.name}`, state: changed, body: joinHtml([note(current), note("An instance operator sets these.")]) });
42
47
  const protect = view.rules.protectProject ? "project" : view.rules.protectedPaths.length > 0 ? "paths" : "none";
43
- const radio = (value, title, hint) => html `<label class="choice"><input type="radio" name="protect" value="${value}"${protect === value ? html ` checked` : ""}><span><strong>${title}</strong><small>${hint}</small></span></label>`;
44
- const few = view.approvers < 2 ? html `<p class="meta">Only ${view.approvers === 1 ? "one person" : "no one"} can approve on this project, so protected work would wait for a second approver. Add one in People first.</p>` : "";
45
- return html `<section class="approval-rules">${note}${current}${postForm("/settings/approval", html `<fieldset><legend>Who approves</legend><label class="choice"><input type="checkbox" name="not_requester" value="1"${view.rules.notRequester ? html ` checked` : ""}><span><strong>Someone other than the requester</strong><small>The person who filed a task, or asked for a revision, can't approve it. Operating modes stop approving their signer's own filings here.</small></span></label></fieldset><fieldset><legend>Protected work</legend>${radio("none", "Nothing protected", html `One approval is enough.`)}${radio("project", "The whole project", html `Every task needs two different people to approve the same scope.`)}${radio("paths", "Only these paths", html `Tasks that touch them, or don't say what they touch, need two people.`)}<div class="paths"><label>Protected paths, one per line<textarea name="paths" spellcheck="false" placeholder="infra/**&#10;migrations/**">${view.rules.protectedPaths.join("\n")}</textarea></label></div>${few}</fieldset><div class="step-up">${reauth(html `<label>Your Toolroll password<input type="password" name="password" autocomplete="current-password"></label>`)}</div><button type="submit">Save rules</button>`, { hidden: { repo: view.repo } })}</section>`;
48
+ const few = view.approvers < 2 ? note(`Only ${view.approvers === 1 ? "one person" : "no one"} can approve on this project, so protected work would wait for a second approver. Add one in People first.`) : "";
49
+ return settingsSection({ id: "rules", title: `Approval rules · ${view.name}`, state: changed, lead: current,
50
+ body: kitSectionForm({ proof: "approval", action: "/settings/approval", id: "rules-form", gate: true, hidden: { repo: view.repo }, confirm: "Change approval rules",
51
+ said: notice.said ?? null, problem: notice.problem ?? null,
52
+ body: joinHtml([
53
+ formRow("Someone other than the requester", "The person who filed a task, or asked for a revision, can’t approve it. Operating modes stop approving their signer’s own filings here.", switchInput({ id: "rules-not-requester", name: "not_requester", label: "Required", on: view.rules.notRequester, attrs: { value: "1", "aria-label": "Someone other than the requester" } }), "inline"),
54
+ formRow("Protected work", "Changes here always wait for two people, never a subagent or an operating mode.", radios({ name: "protect", legend: "Protected work", current: protect, items: [
55
+ { value: "none", label: "Nothing protected", text: "One approval is enough." },
56
+ { value: "project", label: "The whole project", text: "Every task needs two different people to approve the same scope." },
57
+ { value: "paths", label: "Only these paths", text: "Tasks that touch them, or don’t say what they touch, need two people." }
58
+ ] }), "wide"),
59
+ formRow("Protected paths", "One per line. Used when “Only these paths” is chosen.", textarea({ id: "rules-paths", name: "paths", value: view.rules.protectedPaths.join("\n"), rows: 3, attrs: { spellcheck: "false", placeholder: "infra/**\nmigrations/**", "aria-label": "Protected paths" } }), "top"),
60
+ few,
61
+ ]) }) });
46
62
  }
@@ -29,7 +29,7 @@ export function assignmentActionHref(assignment) {
29
29
  if (action.code === 'inspect-decisions')
30
30
  return '/';
31
31
  if (action.code === 'sign-in')
32
- return '/settings#providers';
32
+ return '/settings/agents#providers';
33
33
  // The confirmation sits on the task page, behind the password.
34
34
  if (action.code === 'confirm-stopped')
35
35
  return `/t/${encodeURIComponent(assignment.rootId)}#confirm-stopped`;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Settings → Backups (sprint 8): how the last backup went and one button to
3
- * back up now, then the schedule. Past backups and how to restore sit in
4
- * disclosures.
3
+ * back up now, then the schedule, past backups and how to restore. Built from
4
+ * the revamp kit (src/design/KIT.md); the Settings frame adds the title.
5
5
  */
6
6
  import { type Html } from "./html.js";
7
7
  import type { BackupRun, BackupSettings, LiveBackupState } from "./store.js";
@@ -10,7 +10,8 @@ export declare const BACKUP_EVERY_HOURS: readonly [1, 6, 12, 24];
10
10
  /** The continuous copy's choices, in minutes (live-backup.ts LIVE_EVERY_MINUTES; here so the page never loads it). */
11
11
  export declare const LIVE_EVERY: readonly [1, 5, 15, 30];
12
12
  export declare const MAX_KEEP = 100;
13
- export declare const BACKUP_CSS: string;
13
+ /** The page is kit pieces now; nothing of the old look is left. Kept as an export for the shared stylesheet. */
14
+ export declare const BACKUP_CSS = "";
14
15
  export type BackupView = {
15
16
  settings: BackupSettings;
16
17
  folder: string;
@@ -25,7 +26,7 @@ export type BackupView = {
25
26
  defaultFolder: string;
26
27
  };
27
28
  };
28
- export declare function backupHtml(view: BackupView, notice: {
29
+ export declare function backupHtml(view: BackupView, said: {
29
30
  said?: string | null;
30
31
  problem?: string | null;
31
32
  }): Html;
package/dist/backup-ui.js CHANGED
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * Settings → Backups (sprint 8): how the last backup went and one button to
3
- * back up now, then the schedule. Past backups and how to restore sit in
4
- * disclosures.
3
+ * back up now, then the schedule, past backups and how to restore. Built from
4
+ * the revamp kit (src/design/KIT.md); the Settings frame adds the title.
5
5
  */
6
- import { html, postForm, reauth } from "./html.js";
6
+ import { html, joinHtml, postForm } from "./html.js";
7
7
  import { bytesWords } from "./storage.js";
8
8
  import { whenUtc } from "./when-html.js";
9
+ import { btn, chip, codeLine, formRow, infoLine, input, note, notice, select, settingsRecord, settingsSection } from "./server/kit.js";
10
+ import { kitSectionForm } from "./settings-kit.js";
9
11
  /** The schedules on offer and the most copies kept. Here rather than in backup.ts so the page never loads `node:sqlite`. */
10
12
  export const BACKUP_EVERY_HOURS = [1, 6, 12, 24];
11
13
  /** The continuous copy's choices, in minutes (live-backup.ts LIVE_EVERY_MINUTES; here so the page never loads it). */
@@ -15,53 +17,80 @@ const when = (at) => whenUtc(at);
15
17
  const whenWords = (at) => `${at.slice(0, 16).replace("T", " ")} UTC`;
16
18
  const everyWords = (hours) => hours === 1 ? "Every hour" : hours === 24 ? "Every day" : `Every ${hours} hours`;
17
19
  const fileName = (path) => path.slice(path.lastIndexOf("/") + 1);
18
- export const BACKUP_CSS = `.backups{max-width:720px;min-width:0;overflow-wrap:anywhere}.backups .backup-state{display:flex;gap:16px;align-items:flex-start;justify-content:space-between;flex-wrap:wrap}` +
19
- `.backups .backup-state>div{flex:1 1 320px;min-width:0}.backups .backup-state h2{margin:0;font-size:1.0625rem}.backups .backup-state p{margin:4px 0 0}.backups .backup-state .problem{color:var(--danger)}` +
20
- `.backups .backup-state form{margin:0}.backups .backup-state button{white-space:nowrap}` +
21
- `.backups fieldset{border:0;padding:0;margin:0;min-width:0}.backups label{display:grid;gap:4px;margin:12px 0 0;font-size:.875rem}` +
22
- `.backups input[type=text],.backups input[type=number],.backups input[type=password],.backups select{width:100%;box-sizing:border-box;max-width:100%}` +
23
- `.backups .pair{display:grid;grid-template-columns:1fr 1fr;gap:12px}.backups button[type=submit]{margin-top:14px}` +
24
- `.backups details{margin-top:16px}.backups summary{cursor:pointer}.backups ol{list-style:none;padding:0;margin:8px 0 0}` +
25
- `.backups li{display:flex;gap:8px 12px;flex-wrap:wrap;padding:8px 0;border-top:1px solid var(--line, rgba(0,0,0,.08));font-size:.875rem}` +
26
- `.backups li .failed{color:var(--danger)}.backups code{white-space:nowrap}.backups pre{overflow-x:auto;margin:8px 0}` +
27
- `@media (max-width:900px){.backups .backup-state form,.backups .backup-state button{width:100%}.backups .pair{grid-template-columns:1fr}}`;
20
+ /** The page is kit pieces now; nothing of the old look is left. Kept as an export for the shared stylesheet. */
21
+ export const BACKUP_CSS = "";
28
22
  /** The continuous copy in one line: its latest verified copy, or why there is none. */
29
23
  function liveLine(view) {
30
24
  const live = view.live;
31
25
  if (live === undefined)
32
26
  return "";
33
27
  if (!live.state.settings.enabled)
34
- return html `<p class="meta">Continuous copy is off.</p>`;
28
+ return note("Continuous copy is off.");
35
29
  if (live.state.problem !== null)
36
- return html `<p class="problem" role="alert">The continuous copy failed: ${live.state.problem}</p>`;
30
+ return notice(`The continuous copy failed: ${live.state.problem}`);
37
31
  if (live.state.latest === null)
38
- return html `<p class="meta">The first continuous copy is made within a few minutes of Toolroll starting.</p>`;
39
- return html `<p class="meta" data-live-copy>Continuous copy checked ${when(live.state.latest.madeAt)}, every ${live.state.settings.everyMinutes === 1 ? "minute" : `${live.state.settings.everyMinutes} minutes`}.</p>`;
32
+ return note("The first continuous copy is made within a few minutes of Toolroll starting.");
33
+ return html `<p class="k-note" data-live-copy>Continuous copy checked ${when(live.state.latest.madeAt)}, every ${live.state.settings.everyMinutes === 1 ? "minute" : `${live.state.settings.everyMinutes} minutes`}.</p>`;
40
34
  }
41
- /** The state in one line, and the next backup (if any), for the top of the page. */
35
+ /** The last backup as one record: what happened, the next one, and Back up now. */
42
36
  function state(view) {
43
37
  const last = view.runs[0];
44
38
  const good = view.runs.find(one => one.ok === true);
45
39
  const next = !view.settings.enabled ? "Scheduled backups are off."
46
40
  : good === undefined ? "The first scheduled backup runs within a minute or two of the console starting."
47
41
  : `Next one about ${whenWords(new Date(Date.parse(good.startedAt) + view.settings.everyHours * 3_600_000).toISOString())}.`;
42
+ const now = postForm("/settings/backups/now", btn("Back up now", { sm: true, type: "submit" }));
48
43
  if (last === undefined)
49
- return html `<h2>No backups yet</h2><p class="meta">${next}</p>${liveLine(view)}`;
44
+ return settingsRecord({ title: "No backups yet", sub: next, action: now });
50
45
  if (last.ok === null)
51
- return html `<h2>Backing up</h2><p class="meta">Started ${when(last.startedAt)}.</p>`;
46
+ return settingsRecord({ title: html `Backing up ${chip("Running", "live")}`, sub: html `Started ${when(last.startedAt)}.`, action: now });
52
47
  if (last.ok === false) {
53
- return html `<h2 data-backup-state="failed">Last backup failed</h2><p class="problem" role="alert">${when(last.startedAt)}: ${last.error ?? "no reason was recorded"}</p><p class="meta">${good === undefined ? "No backup has succeeded yet." : html `Last good backup ${when(good.startedAt)}.`} ${next}</p>`;
48
+ return settingsRecord({ title: html `Last backup failed ${chip("Failed", "failed")}`, attrs: { "data-backup-state": "failed" }, action: now,
49
+ sub: html `${good === undefined ? "No backup has succeeded yet." : html `Last good backup ${when(good.startedAt)}.`} ${next}`,
50
+ more: notice(html `${when(last.startedAt)}: ${last.error ?? "no reason was recorded"}`) });
54
51
  }
55
- return html `<h2 data-backup-state="ok">Backed up ${when(last.startedAt)}</h2><p class="meta">${last.bytes === null ? "" : `${bytesWords(last.bytes)} · `}${next}</p>${liveLine(view)}`;
52
+ return settingsRecord({ title: html `Backed up ${when(last.startedAt)}`, attrs: { "data-backup-state": "ok" }, action: now,
53
+ sub: `${last.bytes === null ? "" : `${bytesWords(last.bytes)} · `}${next}` });
56
54
  }
57
- export function backupHtml(view, notice) {
55
+ /** One past backup: when, how it went, its file, and whether it was by hand. */
56
+ function runRow(run) {
57
+ const how = run.trigger === "manual" ? "By hand" : "Scheduled";
58
+ const attrs = { "data-backup-run": run.id };
59
+ if (run.ok === true) {
60
+ return settingsRecord({ title: when(run.startedAt), attrs, when: chip("Finished", "done"),
61
+ sub: html `${how}${run.bytes === null ? "" : ` · ${bytesWords(run.bytes)}`}${run.file === null ? "" : html ` · <span class="k-mono">${fileName(run.file)}</span>`}` });
62
+ }
63
+ if (run.ok === false)
64
+ return settingsRecord({ title: when(run.startedAt), attrs, when: chip("Failed", "failed"), sub: `${how} · ${run.error ?? "no reason recorded"}` });
65
+ return settingsRecord({ title: when(run.startedAt), attrs, when: chip("Running", "live"), sub: how });
66
+ }
67
+ export function backupHtml(view, said) {
58
68
  const s = view.settings;
59
- const note = notice.problem ? html `<p class="problem" role="alert">${notice.problem}</p>` : notice.said ? html `<p role="status">${notice.said}</p>` : "";
60
- const choices = [html `<option value="off"${s.enabled ? "" : html ` selected`}>Off</option>`,
61
- ...BACKUP_EVERY_HOURS.map(hours => html `<option value="${hours}"${s.enabled && s.everyHours === hours ? html ` selected` : ""}>${everyWords(hours)}</option>`)];
62
- const runs = view.runs.map(run => html `<li data-backup-run="${run.id}"><span>${when(run.startedAt)}</span>${run.ok === true ? html `<span>Succeeded${run.bytes === null ? "" : ` · ${bytesWords(run.bytes)}`}</span>${run.file === null ? "" : html `<span class="mono meta">${fileName(run.file)}</span>`}`
63
- : run.ok === false ? html `<span class="failed">Failed: ${run.error ?? "no reason recorded"}</span>` : html `<span>Running</span>`}<span class="meta">${run.trigger === "manual" ? "by hand" : "scheduled"}</span></li>`);
64
- return html `<section class="backups">${note}<div class="card backup-state"><div>${state(view)}</div>${postForm("/settings/backups/now", html `<button type="submit">Back up now</button>`)}</div><h2>Schedule</h2>${postForm("/settings/backups", html `<fieldset><div class="pair"><label>Back up<select name="every">${choices}</select></label><label>Keep the newest<input type="number" name="keep" min="1" max="${MAX_KEEP}" step="1" value="${s.keep}" required></label></div><label>Folder<input type="text" name="folder" value="${s.folder ?? ""}" placeholder="${view.defaultFolder}" spellcheck="false"></label>${liveFields(view)}${reauth(html `<label>Your Toolroll password<input type="password" name="password" autocomplete="current-password"></label>`)}</fieldset><button type="submit">Save</button>`)}<details><summary>Recent backups${view.runs.length === 0 ? "" : ` (${view.runs.length})`}</summary>${runs.length === 0 ? html `<p class="meta">None yet.</p>` : html `<ol>${runs}</ol>`}<p class="meta">In <span class="mono">${view.folder}</span>. Only the database is copied: provider keys and sign-in files stay out.</p></details><details><summary>Restore a backup</summary><p>Stop Toolroll, then run:</p><pre><code>toolroll restore &lt;file&gt; --dry-run</code></pre><p class="meta">The dry run checks the backup (its version and ledger chain) and changes nothing. Run it again without <code>--dry-run</code> to restore; the current database is kept as a copy first.</p>${view.live === undefined ? "" : html `<p class="meta">Continuous copies are in <span class="mono">${view.live.folder}</span>; restore one the same way.</p>`}</details></section>`;
69
+ const answer = said.problem ? notice(said.problem) : said.said ? infoLine(said.said) : "";
70
+ const now = settingsSection({ id: "backup-now", title: "Last backup", body: joinHtml([answer, state(view), liveLine(view)]) });
71
+ const every = select({ id: "backup-every", name: "every", label: "Back up", current: s.enabled ? String(s.everyHours) : "off",
72
+ items: [["off", "Off"], ...BACKUP_EVERY_HOURS.map(hours => [String(hours), everyWords(hours)])] });
73
+ const schedule = settingsSection({ id: "backup-schedule", title: "Schedule", lead: "Only the database is copied: provider keys and sign-in files stay out.",
74
+ body: kitSectionForm({ proof: "backups", action: "/settings/backups", id: "backup-form", gate: true,
75
+ body: joinHtml([
76
+ formRow("Back up", null, every, "inline"),
77
+ formRow("Keep the newest", "How many backups to keep. Older ones are removed.", input({ id: "backup-keep", name: "keep", type: "number", value: String(s.keep),
78
+ attrs: { min: 1, max: MAX_KEEP, step: 1, required: true, "aria-label": "Keep the newest" } }), "inline"),
79
+ formRow("Folder", "Blank: the default folder.", input({ id: "backup-folder", name: "folder", value: s.folder ?? "",
80
+ attrs: { placeholder: view.defaultFolder, spellcheck: "false", "aria-label": "Folder" } })),
81
+ liveFields(view),
82
+ ]) }) });
83
+ const runs = view.runs.map(runRow);
84
+ const history = settingsSection({ id: "backup-history", title: "Past backups", state: view.runs.length === 0 ? "" : ` · ${view.runs.length}`,
85
+ lead: html `In <span class="k-mono">${view.folder}</span>.`,
86
+ body: runs.length === 0 ? note("None yet.") : joinHtml(runs) });
87
+ const restore = settingsSection({ id: "backup-restore", title: "Restore a backup", lead: "Stop Toolroll, then run:",
88
+ body: joinHtml([
89
+ codeLine("toolroll restore <file> --dry-run"),
90
+ note(html `The dry run checks the backup (its version and ledger chain) and changes nothing. Run it again without <code class="k-mono">--dry-run</code> to restore; the current database is kept as a copy first.`),
91
+ view.live === undefined ? "" : note(html `Continuous copies are in <span class="k-mono">${view.live.folder}</span>; restore one the same way.`),
92
+ ]) });
93
+ return joinHtml([now, schedule, history, restore]);
65
94
  }
66
95
  /** The continuous copy's two choices, beside the schedule's: how often, and where (blank: beside the database). */
67
96
  function liveFields(view) {
@@ -69,7 +98,11 @@ function liveFields(view) {
69
98
  if (live === undefined)
70
99
  return "";
71
100
  const on = live.state.settings;
72
- const choices = [html `<option value="off"${on.enabled ? "" : html ` selected`}>Off</option>`,
73
- ...LIVE_EVERY.map(minutes => html `<option value="${minutes}"${on.enabled && on.everyMinutes === minutes ? html ` selected` : ""}>${minutes === 1 ? "Every minute" : `Every ${minutes} minutes`}</option>`)];
74
- return html `<div class="pair"><label>Copy continuously<select name="live_every">${choices}</select></label><label>Copy folder<input type="text" name="live_folder" value="${on.folder ?? ""}" placeholder="${live.defaultFolder}" spellcheck="false"></label></div>`;
101
+ const every = select({ id: "backup-live-every", name: "live_every", label: "Copy continuously", current: on.enabled ? String(on.everyMinutes) : "off",
102
+ items: [["off", "Off"], ...LIVE_EVERY.map(minutes => [String(minutes), minutes === 1 ? "Every minute" : `Every ${minutes} minutes`])] });
103
+ return joinHtml([
104
+ formRow("Copy continuously", "A checked copy of the database every few minutes, between backups.", every, "inline"),
105
+ formRow("Copy folder", "Blank: beside the database.", input({ id: "backup-live-folder", name: "live_folder", value: on.folder ?? "",
106
+ attrs: { placeholder: live.defaultFolder, spellcheck: "false", "aria-label": "Copy folder" } })),
107
+ ]);
75
108
  }
@@ -1,4 +1,4 @@
1
- .xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;inset:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;inset:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:fit-content}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}:root{--t-ground: #0C0E12;--t-surface: #14171D;--t-inset: #1B1F27;--t-line: #262B35;--t-text: #E6E8EC;--t-muted: #8A93A3;--t-blue: #5B9DFF;--t-green: #3FB97F;--t-red: #F06464;--t-amber: #F5A524;--t-sans: "Geist", "Geist Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;--t-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;color-scheme:dark}@font-face{font-family:Geist;src:url(/fonts/geist-sans-400.woff2) format("woff2");font-weight:400;font-display:swap}@font-face{font-family:Geist;src:url(/fonts/geist-sans-500.woff2) format("woff2");font-weight:500;font-display:swap}@font-face{font-family:Geist;src:url(/fonts/geist-sans-600.woff2) format("woff2");font-weight:600;font-display:swap}@font-face{font-family:Geist Mono;src:url(/fonts/geist-mono-400.woff2) format("woff2");font-weight:400;font-display:swap}*{box-sizing:border-box}html,body{margin:0;height:100%;background:var(--t-ground);color:var(--t-text);font:14px/1.45 var(--t-sans);-webkit-font-smoothing:antialiased}body{overscroll-behavior:none}#so-term{height:100dvh}button,select,input{font:inherit;color:inherit}.term-app{display:grid;grid-template-columns:264px 1fr;height:100dvh}.term-app--loading{display:grid;place-items:center;color:var(--t-muted)}.term-side{background:var(--t-surface);border-right:1px solid var(--t-line);overflow-y:auto}.term-scrim{display:none}.term-main{display:flex;flex-direction:column;min-width:0;min-height:0}.term-list{display:flex;flex-direction:column;padding:8px;gap:2px}.term-list-head{display:flex;align-items:center;gap:8px;padding:6px 6px 10px}.term-list-head h1{font-size:15px;font-weight:600;margin:0;flex:1}.term-back{color:var(--t-muted);text-decoration:none;padding:2px 6px;border-radius:6px}.term-back:hover{color:var(--t-text);background:var(--t-inset)}.term-list-empty{padding:4px 8px}.term-item{display:flex;align-items:center;gap:10px;width:100%;text-align:left;padding:8px;border:0;border-radius:8px;background:none;cursor:pointer}.term-item:hover{background:var(--t-inset)}.term-item--on{background:var(--t-inset);box-shadow:inset 0 0 0 1px var(--t-line)}.term-item-text{display:flex;flex-direction:column;min-width:0;flex:1}.term-item-title{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.term-item-meta{color:var(--t-muted);font:11.5px/1.4 var(--t-mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.term-dot{width:7px;height:7px;border-radius:50%;background:var(--t-line);flex:none}.term-dot--live{background:var(--t-blue);box-shadow:0 0 0 3px color-mix(in srgb,var(--t-blue) 20%,transparent)}.term-glyph{display:inline-grid;place-items:center;width:22px;height:22px;border-radius:6px;font:600 11px/1 var(--t-mono);flex:none;background:color-mix(in srgb,currentColor 12%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,currentColor 30%,transparent)}.term-glyph--claude{color:#e8956b}.term-glyph--codex{color:var(--t-blue)}.term-glyph--shell{color:var(--t-muted)}.term-bar{display:flex;align-items:center;gap:10px;height:44px;padding:0 12px;border-bottom:1px solid var(--t-line);background:var(--t-ground);flex:none}.term-menu{display:none;background:none;border:0;font-size:18px;padding:4px 6px;cursor:pointer}.term-bar-title{display:flex;align-items:center;gap:8px;font-weight:500;flex:1;min-width:0;white-space:nowrap;overflow:hidden}.term-bar-branch{color:var(--t-muted);font:12px var(--t-mono);overflow:hidden;text-overflow:ellipsis}.term-link{font-size:12px;color:var(--t-muted);white-space:nowrap}.term-link--live{color:var(--t-blue)}.term-link--signed-out,.term-link--gone{color:var(--t-red)}.term-link--busy{color:var(--t-text)}.term-screen{flex:1;min-height:0;padding:6px 4px 4px 8px;background:var(--t-ground)}.term-screen .xterm{height:100%}.term-screen .xterm-viewport{background:var(--t-ground)!important}.term-keys{display:none;gap:6px;padding:6px 8px calc(6px + env(safe-area-inset-bottom));background:var(--t-surface);border-top:1px solid var(--t-line);overflow-x:auto;flex:none}.term-key{min-width:40px;height:34px;padding:0 10px;border-radius:8px;border:1px solid var(--t-line);background:var(--t-inset);font:13px var(--t-mono);touch-action:manipulation;flex:none}.term-key:active,.term-key--on{background:var(--t-line);border-color:var(--t-muted)}.term-new{max-width:440px;margin:40px auto;padding:0 16px;display:flex;flex-direction:column;gap:14px}.term-new h2{margin:0;font-size:18px;font-weight:600}.term-new p{margin:0}.term-muted{color:var(--t-muted)}.term-field{display:flex;flex-direction:column;gap:6px}.term-field span{font-size:12px;color:var(--t-muted)}.term-field select,.term-field input{height:38px;padding:0 10px;border-radius:8px;border:1px solid var(--t-line);background:var(--t-inset)}.term-programs{border:0;padding:0;margin:0;display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.term-programs legend{font-size:12px;color:var(--t-muted);margin-bottom:6px}.term-program{display:flex;align-items:center;gap:8px;padding:10px;border-radius:10px;border:1px solid var(--t-line);background:var(--t-surface);cursor:pointer;font-size:13px}.term-program input{position:absolute;opacity:0;pointer-events:none}.term-program--on{border-color:var(--t-blue);box-shadow:inset 0 0 0 1px var(--t-blue)}.term-ceremony{display:flex;flex-direction:column;gap:10px;padding:12px;border-radius:10px;border:1px solid color-mix(in srgb,var(--t-amber) 45%,transparent);background:color-mix(in srgb,var(--t-amber) 6%,transparent)}.term-ceremony p{font-size:13px}.term-error{color:var(--t-red)}.term-actions{display:flex;justify-content:flex-end;gap:8px}.term-button{display:inline-flex;align-items:center;height:36px;padding:0 14px;border-radius:8px;border:1px solid transparent;background:var(--t-text);color:var(--t-ground);font-weight:500;cursor:pointer;text-decoration:none}.term-button:disabled{opacity:.5;cursor:default}.term-button--quiet{background:none;color:var(--t-text);border-color:var(--t-line)}.term-button--small{height:28px;padding:0 10px;font-size:12.5px}@media(max-width:720px){.term-app{grid-template-columns:1fr}.term-side{position:fixed;inset:0 auto 0 0;width:min(86vw,320px);z-index:20;transform:translate(-100%);transition:transform .2s ease;padding-top:env(safe-area-inset-top)}.term-app--drawer .term-side{transform:none}.term-app--drawer .term-scrim{display:block;position:fixed;inset:0;z-index:10;border:0;background:#00000080}.term-menu{display:block}.term-bar{padding-top:env(safe-area-inset-top);height:calc(44px + env(safe-area-inset-top))}.term-keys{display:flex}.term-screen{padding:4px 2px 2px 4px}}
1
+ .xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;inset:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;inset:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:fit-content}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}:root{color-scheme:light;--so-accent: #171717;--so-accent-hover: #383838;--so-accent-text: #171717;--so-attention: var(--so-signal);--so-attention-soft: var(--so-signal-soft);--so-code-bg: #fafafa;--so-danger: #c4320a;--so-danger-soft: #feebe7;--so-ease-out: cubic-bezier(.23, 1, .32, 1);--so-field-line: #8f8f8f;--so-font-mono: "Geist Mono", ui-monospace, "SF Mono", "SFMono-Regular", "Menlo", "Consolas", monospace;--so-font-sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;--so-ground: #efefef;--so-info: #0d74ce;--so-info-soft: #e6f4fe;--so-ink: #171717;--so-input-line: #d4d4d4;--so-line: #e6e6e6;--so-live: #0d74ce;--so-muted: #666666;--so-nav-current: #ffffff;--so-nav-current-ink: #171717;--so-nav-hover: #e4e4e4;--so-nav-ink: #525252;--so-needs: var(--so-warning);--so-needs-soft: var(--so-warning-soft);--so-neutral-ink: #525252;--so-neutral-soft: #f0f0f0;--so-on-accent: #ffffff;--so-on-attention: var(--so-on-signal);--so-on-signal: #ffffff;--so-overlay: rgb(0 0 0 / .32);--so-overlay-line: #b8b8b8;--so-paper: #ffffff;--so-phone-block: 14px;--so-phone-card: 12px;--so-phone-gap: 12px;--so-phone-gutter: 16px;--so-phone-row: 8px;--so-pill-shadow: 0px 0px 0px 1px rgb(0 0 0 / .06), 0px 1px 2px 0px rgb(0 0 0 / .06);--so-radius-badge: 5px;--so-radius-card: 10px;--so-radius-full: 9999px;--so-radius-md: 8px;--so-radius-sheet: 12px;--so-radius-sm: 6px;--so-raised: #f5f5f5;--so-ring: var(--so-ink);--so-scrim: rgb(0 0 0 / .22);--so-scroll: #cfcfcf;--so-selection: #d4d4d4;--so-shadow-overlay: 0px 0px 0px 1px rgb(0 0 0 / .08), 0px 24px 48px -12px rgb(0 0 0 / .22);--so-sheet-shadow: 0px 0px 0px 1px rgb(0 0 0 / .06), 0px 1px 2px 0px rgb(0 0 0 / .04), 0px 4px 12px -6px rgb(0 0 0 / .06);--so-sidebar: #efefef;--so-signal: #171717;--so-signal-hover: #383838;--so-signal-soft: #e8e8e8;--so-soft: #f2f2f2;--so-space-2xl: 24px;--so-space-3xl: 28px;--so-space-lg: 16px;--so-space-md: 12px;--so-space-sm: 8px;--so-space-xl: 20px;--so-space-xs: 4px;--so-success: #218358;--so-success-soft: #e6f6eb;--so-typography-badge: var(--so-typography-badge-font-weight) var(--so-typography-badge-font-size)/var(--so-typography-badge-line-height) var(--so-typography-badge-font-family);--so-typography-badge-font-family: var(--so-font-sans);--so-typography-badge-font-size: 11.5px;--so-typography-badge-font-weight: 500;--so-typography-badge-line-height: 1.5652;--so-typography-body: var(--so-typography-body-font-weight) var(--so-typography-body-font-size)/var(--so-typography-body-line-height) var(--so-typography-body-font-family);--so-typography-body-font-family: var(--so-font-sans);--so-typography-body-font-size: 13px;--so-typography-body-font-weight: 400;--so-typography-body-line-height: 1.5;--so-typography-body-reading: var(--so-typography-body-reading-font-weight) var(--so-typography-body-reading-font-size)/var(--so-typography-body-reading-line-height) var(--so-typography-body-reading-font-family);--so-typography-body-reading-font-family: var(--so-font-sans);--so-typography-body-reading-font-size: 14px;--so-typography-body-reading-font-weight: 400;--so-typography-body-reading-line-height: 1.7;--so-typography-caption: var(--so-typography-caption-font-weight) var(--so-typography-caption-font-size)/var(--so-typography-caption-line-height) var(--so-typography-caption-font-family);--so-typography-caption-font-family: var(--so-font-sans);--so-typography-caption-font-size: 12px;--so-typography-caption-font-weight: 500;--so-typography-caption-line-height: 1.5;--so-typography-display: var(--so-typography-display-font-weight) var(--so-typography-display-font-size)/var(--so-typography-display-line-height) var(--so-typography-display-font-family);--so-typography-display-font-family: var(--so-font-sans);--so-typography-display-font-size: 26px;--so-typography-display-font-weight: 600;--so-typography-display-letter-spacing: -.65px;--so-typography-display-line-height: 1.25;--so-typography-headline: var(--so-typography-headline-font-weight) var(--so-typography-headline-font-size)/var(--so-typography-headline-line-height) var(--so-typography-headline-font-family);--so-typography-headline-font-family: var(--so-font-sans);--so-typography-headline-font-size: 18px;--so-typography-headline-font-weight: 600;--so-typography-headline-line-height: 1.375;--so-typography-label: var(--so-typography-label-font-weight) var(--so-typography-label-font-size)/var(--so-typography-label-line-height) var(--so-typography-label-font-family);--so-typography-label-font-family: var(--so-font-sans);--so-typography-label-font-size: 13px;--so-typography-label-font-weight: 500;--so-typography-label-line-height: 1.2;--so-typography-mono: var(--so-typography-mono-font-weight) var(--so-typography-mono-font-size)/var(--so-typography-mono-line-height) var(--so-typography-mono-font-family);--so-typography-mono-count: var(--so-typography-mono-count-font-weight) var(--so-typography-mono-count-font-size)/var(--so-typography-mono-count-line-height) var(--so-typography-mono-count-font-family);--so-typography-mono-count-font-family: var(--so-font-mono);--so-typography-mono-count-font-size: 11px;--so-typography-mono-count-font-weight: 500;--so-typography-mono-count-line-height: 1;--so-typography-mono-font-family: var(--so-font-mono);--so-typography-mono-font-size: 12px;--so-typography-mono-font-weight: 400;--so-typography-mono-line-height: 1.5;--so-typography-title: var(--so-typography-title-font-weight) var(--so-typography-title-font-size)/var(--so-typography-title-line-height) var(--so-typography-title-font-family);--so-typography-title-font-family: var(--so-font-sans);--so-typography-title-font-size: 15px;--so-typography-title-font-weight: 600;--so-typography-title-letter-spacing: -.15px;--so-typography-title-line-height: 1.4;--so-typography-title-sm: var(--so-typography-title-sm-font-weight) var(--so-typography-title-sm-font-size)/var(--so-typography-title-sm-line-height) var(--so-typography-title-sm-font-family);--so-typography-title-sm-font-family: var(--so-font-sans);--so-typography-title-sm-font-size: 14px;--so-typography-title-sm-font-weight: 600;--so-typography-title-sm-letter-spacing: -.14px;--so-typography-title-sm-line-height: 1.3;--so-user-bubble: #f2f2f2;--so-warning: #ab6400;--so-warning-soft: #fff4d5}@media(prefers-color-scheme:dark){:root:not([data-theme=light]){color-scheme:dark;--so-accent: #ededed;--so-accent-hover: #ffffff;--so-accent-text: #ededed;--so-code-bg: #111111;--so-danger: #ff977d;--so-danger-soft: rgb(255 151 125 / .12);--so-field-line: #6b6b6b;--so-ground: #0b0b0b;--so-info: #70b8ff;--so-info-soft: rgb(112 184 255 / .12);--so-ink: #ededed;--so-input-line: #363636;--so-line: #262626;--so-live: #70b8ff;--so-muted: #a1a1a1;--so-nav-current: #1f1f1f;--so-nav-current-ink: #ededed;--so-nav-hover: #171717;--so-nav-ink: #a1a1a1;--so-neutral-ink: #b4b4b4;--so-neutral-soft: #1f1f1f;--so-on-accent: #0a0a0a;--so-on-signal: #0a0a0a;--so-overlay: rgb(0 0 0 / .6);--so-overlay-line: #4a4a4a;--so-paper: #161616;--so-pill-shadow: 0px 0px 0px 1px #2a2a2a, 0px 1px 2px 0px rgb(0 0 0 / .5);--so-raised: #1c1c1c;--so-scrim: rgb(0 0 0 / .5);--so-scroll: #333333;--so-selection: #3a3a3a;--so-shadow-overlay: 0px 0px 0px 1px #2e2e2e, 0px 24px 48px -12px rgb(0 0 0 / .7);--so-sheet-shadow: 0px 0px 0px 1px #262626, 0px 1px 2px 0px rgb(0 0 0 / .4);--so-sidebar: #0b0b0b;--so-signal: #ededed;--so-signal-hover: #ffffff;--so-signal-soft: #2e2e2e;--so-soft: #1f1f1f;--so-success: #3dd68c;--so-success-soft: rgb(61 214 140 / .12);--so-user-bubble: #202020;--so-warning: #ffca16;--so-warning-soft: rgb(255 202 22 / .12)}}:root[data-theme=dark]{color-scheme:dark;--so-accent: #ededed;--so-accent-hover: #ffffff;--so-accent-text: #ededed;--so-code-bg: #111111;--so-danger: #ff977d;--so-danger-soft: rgb(255 151 125 / .12);--so-field-line: #6b6b6b;--so-ground: #0b0b0b;--so-info: #70b8ff;--so-info-soft: rgb(112 184 255 / .12);--so-ink: #ededed;--so-input-line: #363636;--so-line: #262626;--so-live: #70b8ff;--so-muted: #a1a1a1;--so-nav-current: #1f1f1f;--so-nav-current-ink: #ededed;--so-nav-hover: #171717;--so-nav-ink: #a1a1a1;--so-neutral-ink: #b4b4b4;--so-neutral-soft: #1f1f1f;--so-on-accent: #0a0a0a;--so-on-signal: #0a0a0a;--so-overlay: rgb(0 0 0 / .6);--so-overlay-line: #4a4a4a;--so-paper: #161616;--so-pill-shadow: 0px 0px 0px 1px #2a2a2a, 0px 1px 2px 0px rgb(0 0 0 / .5);--so-raised: #1c1c1c;--so-scrim: rgb(0 0 0 / .5);--so-scroll: #333333;--so-selection: #3a3a3a;--so-shadow-overlay: 0px 0px 0px 1px #2e2e2e, 0px 24px 48px -12px rgb(0 0 0 / .7);--so-sheet-shadow: 0px 0px 0px 1px #262626, 0px 1px 2px 0px rgb(0 0 0 / .4);--so-sidebar: #0b0b0b;--so-signal: #ededed;--so-signal-hover: #ffffff;--so-signal-soft: #2e2e2e;--so-soft: #1f1f1f;--so-success: #3dd68c;--so-success-soft: rgb(61 214 140 / .12);--so-user-bubble: #202020;--so-warning: #ffca16;--so-warning-soft: rgb(255 202 22 / .12)}:root{--so-needs-ink: color-mix(in srgb, var(--so-needs) 78%, var(--so-ink));--so-live-ink: color-mix(in srgb, var(--so-info) 82%, var(--so-ink));--so-done-ink: color-mix(in srgb, var(--so-success) 80%, var(--so-ink));--so-fail-ink: color-mix(in srgb, var(--so-danger) 85%, var(--so-ink));--m-quick: .12s;--m-base: .16s;--m-slow: .22s;--m-ease: var(--so-ease-out)}.k-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;margin:0;padding:0;border:0}.k-mono{font-family:var(--so-font-mono);font-size:12px;font-weight:400}.k-num{font-variant-numeric:tabular-nums}.k-muted{color:var(--so-muted)}.k-grow{flex:1}.k-i{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round;flex:none}.k-i-sm{width:14px;height:14px}.k-link{color:inherit;text-decoration:underline;text-decoration-color:var(--so-field-line);text-underline-offset:3px}.k-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;box-sizing:border-box;height:32px;min-height:0;margin:0;padding:0 12px;border-radius:var(--so-radius-md);border:1px solid transparent;background:transparent;color:var(--so-ink);font:var(--so-typography-label);white-space:nowrap;text-decoration:none;position:relative;cursor:pointer;user-select:none;box-shadow:none;transition:background-color var(--m-quick) var(--m-ease),color var(--m-quick) var(--m-ease),border-color var(--m-quick) var(--m-ease),transform var(--m-quick) var(--m-ease)}.k-btn:active:not(:disabled):not([aria-disabled=true]){transform:scale(.97)}.k-btn.k-btn-primary{background:var(--so-accent);color:var(--so-on-accent);border-color:var(--so-accent)}.k-btn.k-btn-primary.busy{background:var(--so-accent-hover)}.k-btn.k-btn-outline{background:var(--so-paper);border-color:var(--so-field-line)}.k-btn.k-btn-ghost{color:var(--so-muted)}.k-btn.k-btn-danger{background:var(--so-paper);border-color:color-mix(in srgb,var(--so-danger) 55%,transparent);color:var(--so-fail-ink)}.k-btn-sm{height:28px;padding:0 10px;font-size:12.5px}.k-btn-icon{width:32px;padding:0}.k-btn-sm.k-btn-icon{width:28px}.k-btn:disabled,.k-btn[aria-disabled=true]{cursor:default;opacity:.55}.k-face{display:inline-flex;align-items:center;gap:6px}.k-btn.swap .k-face{animation:k-face var(--m-base) var(--m-ease) both}.k-spin{width:14px;height:14px;border-radius:50%;border:1.5px solid currentColor;border-right-color:transparent;animation:k-spin .6s linear infinite}.k-check-draw path{stroke-dasharray:24;stroke-dashoffset:24;animation:k-draw var(--m-slow) var(--m-ease) 40ms forwards}@keyframes k-face{0%{opacity:0;transform:translateY(3px)}}@keyframes k-spin{to{transform:rotate(360deg)}}@keyframes k-draw{to{stroke-dashoffset:0}}.k-chip{display:inline-flex;align-items:center;gap:6px;height:20px;padding:0 7px;border-radius:6px;font:var(--so-typography-badge);background:var(--so-neutral-soft);color:var(--so-neutral-ink);white-space:nowrap;flex:none}.k-chip:before{content:"";width:6px;height:6px;border-radius:50%;background:var(--dot, var(--so-muted));flex:none}.k-chip.needs{background:var(--so-needs-soft);color:var(--so-needs-ink);--dot: var(--so-needs)}.k-chip.ask{background:var(--so-neutral-soft);color:var(--so-ink);--dot: var(--so-needs)}.k-chip.live{background:var(--so-info-soft);color:var(--so-live-ink);--dot: var(--so-info)}.k-chip.done{background:var(--so-success-soft);color:var(--so-done-ink);--dot: var(--so-success)}.k-chip.failed{background:var(--so-danger-soft);color:var(--so-fail-ink);--dot: var(--so-danger)}.k-chip.nodot:before{display:none}.k-count{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;border-radius:999px;font:500 11px/18px var(--so-font-sans);font-variant-numeric:tabular-nums;background:var(--so-neutral-soft);color:var(--so-neutral-ink)}.k-count.ink{background:var(--so-ink);color:var(--so-paper)}.k-count.zero{background:transparent;color:var(--so-muted)}.k-dot{width:8px;height:8px;border-radius:50%;background:var(--dot, var(--so-muted));flex:none;display:inline-block}.k-dot.needs{--dot: var(--so-needs)}.k-seg{display:inline-flex;padding:2px;gap:2px;border-radius:9px;background:var(--so-raised)}.k-seg>a,.k-seg>button{display:inline-flex;align-items:center;gap:6px;height:26px;min-height:0;margin:0;padding:0 9px;border:0;border-radius:7px;background:transparent;color:var(--so-muted);font:var(--so-typography-label);font-size:12.5px;white-space:nowrap;text-decoration:none;cursor:pointer;box-shadow:none}.k-seg>[aria-current],.k-seg>[aria-pressed=true],.k-seg>[aria-selected=true]{background:var(--so-paper);color:var(--so-ink);box-shadow:inset 0 0 0 1px var(--so-field-line)}.k-seg .k-count{background:transparent;padding:0 1px;min-width:0;color:inherit;height:auto;line-height:1}.k-seg .k-count.ink{background:var(--so-ink);color:var(--so-paper);padding:0 5px;min-width:18px;height:18px;line-height:18px}.k-tabs{display:flex;gap:20px;border-bottom:1px solid var(--so-line);margin:0;padding:0}.k-tabs>button,.k-tabs>a{display:inline-flex;align-items:center;gap:6px;min-height:0;margin:0 0 -1px;padding:10px 0;border:0;border-bottom:2px solid transparent;border-radius:0;background:transparent;color:var(--so-muted);font:var(--so-typography-label);text-decoration:none;cursor:pointer;box-shadow:none;transition:color var(--m-quick) var(--m-ease),border-color var(--m-quick) var(--m-ease)}.k-tabs>[aria-selected=true],.k-tabs>[aria-current]{color:var(--so-ink);border-bottom-color:var(--so-ink)}.k-tabs .k-count{margin-left:2px}.k-field{display:grid;gap:6px;margin:0;min-width:0}.k-label{display:block;margin:0;font:var(--so-typography-caption);color:var(--so-ink)}.k-hint{margin:0;font-size:12px;color:var(--so-muted);line-height:1.45}.k-input.k-input,.k-textarea.k-textarea{box-sizing:border-box;width:100%;margin:0;border:1px solid var(--so-field-line);border-radius:8px;background:var(--so-paper);color:var(--so-ink);font:400 13px/1.4 var(--so-font-sans);box-shadow:none}.k-input.k-input{height:32px;min-height:0;padding:0 10px}.k-textarea.k-textarea{min-height:72px;padding:8px 10px;resize:vertical;max-width:640px}.k-input:focus-visible,.k-textarea:focus-visible{outline:2px solid var(--so-ring);outline-offset:1px;box-shadow:none}.k-input[aria-invalid=true],.k-textarea[aria-invalid=true],.k-sel[aria-invalid=true]{border-color:var(--so-danger)}.k-err{display:block;margin:0;font-size:12px;color:var(--so-fail-ink);line-height:1.45}.k-err:empty{display:none}.k-selw{position:relative;display:inline-block;min-width:0;max-width:100%}.k-selw:after{content:"";position:absolute;right:12px;top:50%;margin-top:-5px;width:6px;height:6px;border:solid var(--so-muted);border-width:0 1.5px 1.5px 0;transform:rotate(45deg);pointer-events:none}.k-sel.k-sel{appearance:none;-webkit-appearance:none;box-sizing:border-box;width:100%;height:32px;min-height:0;margin:0;padding:0 30px 0 10px;border:1px solid var(--so-field-line);border-radius:8px;background:var(--so-paper);color:var(--so-ink);font:400 13px/1 var(--so-font-sans);text-overflow:ellipsis;cursor:pointer;box-shadow:none}.k-sel:focus-visible{outline:2px solid var(--so-ring);outline-offset:1px}.k-sel:disabled{color:var(--so-muted);cursor:default}.k-selw.sm .k-sel{height:28px;font:500 12.5px/1 var(--so-font-sans);padding:0 26px 0 9px}.k-selw.sm:after{right:10px}.k-selw.wide{display:block;width:100%}.k-switch{position:relative;display:inline-flex;align-items:center;gap:8px;min-height:28px;margin:0;padding:0;border:0;background:transparent;font:500 12.5px/1 var(--so-font-sans);color:var(--so-muted);cursor:pointer;box-shadow:none}.k-trk{position:relative;width:32px;height:18px;border-radius:9px;border:1px solid var(--so-field-line);background:var(--so-paper);transition:background-color var(--m-quick) var(--m-ease),border-color var(--m-quick) var(--m-ease);flex:none;box-sizing:border-box}.k-trk:after{content:"";position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:var(--so-muted);transition:transform var(--m-quick) var(--m-ease),background-color var(--m-quick) var(--m-ease)}.k-switch[aria-checked=true],.k-switch:has(input:checked){color:var(--so-ink)}.k-switch[aria-checked=true] .k-trk,.k-switch input:checked+.k-trk{background:var(--so-ink);border-color:var(--so-ink)}.k-switch[aria-checked=true] .k-trk:after,.k-switch input:checked+.k-trk:after{transform:translate(14px);background:var(--so-paper)}.k-switch .k-switch-input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer;z-index:1}.k-switch:focus-visible,.k-switch:has(input:focus-visible){outline:2px solid var(--so-ring);outline-offset:3px;border-radius:4px}.k-radios{display:grid;gap:8px;grid-template-columns:1fr 1fr;margin:0;padding:0;border:0;min-width:0}.k-opt{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:12px;align-items:start;margin:0;padding:11px 14px;border:1px solid var(--so-field-line);border-radius:10px;font:var(--so-typography-body);cursor:pointer}.k-opt input{margin:3px 0 0;accent-color:var(--so-ink)}.k-opt>span{display:grid;gap:3px}.k-opt>span>span{font-size:12.5px;color:var(--so-muted)}.k-opt:has(input:checked){border-color:var(--so-ink);box-shadow:inset 0 0 0 1px var(--so-ink)}.k-checks{display:flex;flex-wrap:wrap;gap:8px 18px;font-size:13px}.k-checks label{display:inline-flex;gap:8px;align-items:center;min-height:28px;margin:0;font:var(--so-typography-body)}.k-checks input{accent-color:var(--so-ink);width:15px;height:15px;margin:0}.k-frow{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,300px);gap:8px 24px;align-items:center;min-height:52px;padding:10px 0;border-bottom:1px solid var(--so-line)}.k-frow.wide{grid-template-columns:minmax(0,1fr)}.k-frow.top{align-items:start}.k-frow-l{display:grid;gap:2px;min-width:0}.k-frow-t{margin:0;font-weight:500;font-size:13px;display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap;color:var(--so-ink)}.k-frow-h{font-size:12.5px;color:var(--so-muted);line-height:1.45}.k-frow-c{display:flex;align-items:center;justify-content:flex-end;gap:8px;min-width:0;flex-wrap:wrap}.k-frow-c .k-input,.k-frow-c .k-selw{max-width:300px;width:100%}.k-frow-c .k-seg{flex:none}.k-frow .k-err{width:100%;text-align:right}.k-frow.wide .k-frow-c{justify-content:flex-start}.k-frow.wide .k-frow-c>*{flex:1;min-width:0}.k-frow.wide .k-frow-c>.k-btn,.k-frow.wide .k-frow-c>.k-switch{flex:none}.k-acts{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.k-facts{display:grid;grid-template-columns:112px minmax(0,1fr);gap:10px 16px;margin:0;font-size:12.5px;line-height:1.45}.k-facts dt{color:var(--so-muted);margin:0}.k-facts dd{min-width:0;margin:0;overflow-wrap:anywhere}.k-facts a{color:inherit;text-decoration:underline;text-decoration-color:var(--so-field-line);text-underline-offset:3px}.k-note{margin:0;font-size:12px;color:var(--so-muted);line-height:1.45}.k-notice{display:flex;gap:8px;align-items:flex-start;margin:0;font-size:12.5px;color:var(--so-fail-ink);line-height:1.45}.k-notice .k-i{margin-top:1px}.k-notice.info{color:var(--so-ink);background:var(--so-raised);border-radius:7px;padding:8px 10px}.k-empty{display:grid;justify-items:start;gap:10px;padding:28px 24px}.k-empty-t{color:var(--so-ink);font-weight:600;font-size:14px;margin:0}.k-empty-x{color:var(--so-muted);font-size:13px;margin:0;max-width:60ch}.k-doc .k-empty,.k-sbody .k-empty,.k-drawer .k-empty,.k-tabbody .k-empty{padding:16px 0}.k-terms{margin:0;font-size:13px;font-weight:500;padding:8px 10px;background:var(--so-raised);border-radius:7px;justify-self:start}.k-disclose>summary{cursor:pointer;list-style:none;display:inline-flex;align-items:center;gap:6px;min-height:0;margin:0;padding:0;font-size:12.5px;font-weight:400;color:var(--so-ink);text-decoration:underline;text-decoration-color:var(--so-field-line);text-underline-offset:3px}.k-disclose>summary::-webkit-details-marker{display:none}.k-disclose>summary:before{content:"";width:6px;height:6px;border:solid currentColor;border-width:0 1.5px 1.5px 0;transform:rotate(-45deg);transition:transform var(--m-quick) var(--m-ease);margin-right:2px}.k-disclose[open]>summary:before{transform:rotate(45deg)}.k-disclose{margin:0;padding:0;border:0}.k-grp{display:flex;align-items:center;gap:8px;height:36px;margin:8px 0 0;padding:0 24px;font:600 12.5px/1 var(--so-font-sans);border-bottom:1px solid var(--so-line);color:var(--so-ink)}.k-row{display:grid;grid-template-columns:96px minmax(160px,30%) minmax(0,1fr) auto 124px;align-items:center;gap:16px;min-height:48px;padding:6px 24px;border-bottom:1px solid var(--so-line);position:relative}.k-row-t{font-weight:500;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--so-ink);text-decoration:none}.k-row.wait .k-row-t{font-weight:600}.k-row-t:before{content:"";position:absolute;inset:0}.k-row.k-row-static .k-row-t:before{content:none}.k-row-d{color:var(--so-muted);font-size:12.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.k-row-m{display:flex;gap:12px;color:var(--so-muted);font-size:12px;white-space:nowrap}.k-row-a{display:flex;justify-content:flex-end}.k-row-a .k-btn{min-width:108px}.k-row-c,.k-row-a,.k-row-msg{position:relative;z-index:1}.k-row-msg{grid-column:2 / -1}.k-filter{display:inline-flex;align-items:center;gap:6px;box-sizing:border-box;height:28px;width:168px;margin:0;padding:0 8px;border:1px solid var(--so-field-line);border-radius:var(--so-radius-md);background:var(--so-paper);color:var(--so-muted);cursor:text}.k-filter>input{flex:1;min-width:0;height:100%;margin:0;padding:0;border:0;border-radius:0;background:transparent;box-shadow:none;outline:none;color:var(--so-ink);font:400 12.5px/1 var(--so-font-sans)}.k-filter>input::placeholder{color:var(--so-muted)}.k-filter>input::-webkit-search-cancel-button{display:none}.k-filter:focus-within{border-color:var(--so-ink);box-shadow:inset 0 0 0 1px var(--so-ink)}.k-seg.k-seg-icons>a,.k-seg.k-seg-icons>button{padding:0 6px}.k-tbp{display:none}.k-foot{margin:0;padding:12px 24px;font-size:12.5px;color:var(--so-muted)}.k-foot a{color:var(--so-ink);text-decoration:underline;text-decoration-color:var(--so-field-line);text-underline-offset:3px}.k-board{display:grid;grid-template-columns:repeat(var(--k-cols, 4),minmax(0,1fr));align-items:stretch;flex:1;min-height:0}.k-col{min-width:0;border-right:1px solid var(--so-line)}.k-col:last-child{border-right:0}.k-col-h{display:flex;align-items:center;gap:8px;height:40px;margin:0;padding:0 16px;border-bottom:1px solid var(--so-line);font:600 12.5px/1 var(--so-font-sans);color:var(--so-ink)}.k-col-h.needs:before{content:"";width:7px;height:7px;border-radius:50%;background:var(--so-needs);flex:none}.k-card{display:grid;gap:5px;padding:11px 16px;border-bottom:1px solid var(--so-line);color:var(--so-ink);text-decoration:none;outline-offset:-2px}.k-card-t{font-weight:500;font-size:13px;line-height:1.35;overflow-wrap:anywhere}.k-card-m{display:flex;flex-wrap:wrap;gap:8px;align-items:center;color:var(--so-muted);font-size:12px}.k-col-e{margin:0;padding:12px 16px;font-size:12.5px;color:var(--so-muted)}.k-colpager{display:none}.k-colpager>.k-seg{display:flex;width:100%}.k-tb{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px;min-height:48px;padding:8px 24px;border-bottom:1px solid var(--so-line);position:sticky;top:0;z-index:6;background:var(--so-paper)}.k-tb h1{margin:0;font:600 15px/1.3 var(--so-font-sans);letter-spacing:-.01em}.k-tb-ctx{color:var(--so-muted);font-size:12.5px}.k-tb-ctx>.k-seg{vertical-align:middle}.k-tb-ctx>.k-seg+.k-seg{margin-left:8px}.k-ph{display:none}.k-doc{box-sizing:border-box;width:100%;max-width:760px;margin:0 auto;padding:22px 28px 120px;display:grid;grid-template-columns:minmax(0,1fr);gap:22px;align-content:start}.k-backlink{display:inline-flex;align-items:center;gap:6px;color:var(--so-muted);font:var(--so-typography-label);justify-self:start;min-height:24px;text-decoration:none}.k-dh{display:flex;align-items:flex-start;gap:6px}.k-dh>div{flex:1;display:grid;gap:6px;min-width:0}.k-dh h1{margin:0;font:600 24px/1.3 var(--so-font-sans);letter-spacing:-.02em;color:var(--so-ink)}.k-dh h1:first-letter{text-transform:none}.k-dh-meta{margin:0;font-size:12.5px;color:var(--so-muted)}.k-same{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}@media(min-width:761px){.k-same{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}}.k-sec{display:grid;gap:10px}.k-sec h3,.k-secthead h3{margin:0;font:600 13px/1.3 var(--so-font-sans)}.k-secthead{display:flex;align-items:center;gap:8px;padding-bottom:8px;border-bottom:1px solid var(--so-line)}.k-secthead h3{flex:1;display:flex;align-items:center;gap:8px}.k-steps{--k-n: 5;position:relative;display:grid;grid-template-columns:repeat(var(--k-n),minmax(0,1fr));margin:0;padding:2px 0 0;list-style:none}.k-steps:before,.k-steps-fill{content:"";position:absolute;top:8px;left:calc(50% / var(--k-n));right:calc(50% / var(--k-n));height:1.5px;background:var(--so-line)}.k-steps-fill{background:var(--so-success);transform-origin:left center;transform:scaleX(var(--k-fill, 0));transition:transform var(--m-slow) var(--m-ease)}.k-step{position:relative;z-index:1;display:grid;justify-items:center;align-content:start;gap:7px;min-width:0;margin:0;padding:0;text-align:center;font-size:12px;color:var(--so-muted)}.k-step>b{display:block;position:relative;box-sizing:border-box;width:13px;height:13px;margin-top:2px;border-radius:50%;border:1.5px solid var(--so-field-line);background:var(--so-paper)}.k-step.done>b{border-color:var(--so-success);background:var(--so-success)}.k-step.done>b:before{content:"";position:absolute;left:3px;top:1px;width:3px;height:6px;border:solid var(--so-paper);border-width:0 1.5px 1.5px 0;transform:rotate(45deg)}.k-step.now,.k-step.live,.k-step.failed{color:var(--so-ink);font-weight:600}.k-step.now>b{border-color:var(--so-needs);background:var(--so-needs);box-shadow:inset 0 0 0 2.5px var(--so-paper)}.k-step.live>b{border-color:var(--so-info);background:var(--so-info);box-shadow:inset 0 0 0 2.5px var(--so-paper)}.k-step.failed>b{border-color:var(--so-danger);background:var(--so-danger)}.k-step-l{line-height:1.2;white-space:nowrap}.k-step-s{margin-top:-4px;min-height:1.3em;font-size:11.5px;font-weight:400;line-height:1.3;color:var(--so-muted);white-space:nowrap}.k-slots{border:1px solid var(--so-line);border-radius:var(--so-radius-card);padding:16px 18px;display:grid;gap:10px;background:var(--so-paper);transition:border-color var(--m-slow) var(--m-ease)}.k-slots.wait{border-color:var(--so-needs)}.k-slot-status{display:flex;align-items:center;gap:10px;min-height:24px;flex-wrap:wrap}.k-slot-status h2{margin:0;font:600 15px/1.35 var(--so-font-sans)}.k-slot-text{margin:0;color:var(--so-muted);font-size:13px;line-height:1.5;min-height:1.5em}.k-slot-acts{min-height:32px}.k-slot-acts .k-btn{min-width:136px}.k-slot-acts .k-btn.k-btn-ghost{min-width:0}.k-slot-terms{margin:0;font-size:12px;color:var(--so-muted);line-height:1.5;min-height:1.5em}.k-slot-err:empty{display:none}.k-slot-body{display:grid;gap:12px;min-width:0}.k-opt>.k-chip{align-self:start}.k-reauth{display:grid;gap:6px;max-width:320px}.k-needs{border:1px solid var(--so-needs);border-radius:var(--so-radius-card);background:var(--so-paper)}.k-needs-h{display:flex;align-items:center;gap:8px;margin:0;padding:12px 16px;border-bottom:1px solid var(--so-line);font:600 13px/1.3 var(--so-font-sans)}.k-needs-h:before{content:"";width:7px;height:7px;border-radius:50%;background:var(--so-needs)}.k-needs-item{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:4px 16px;align-items:center;padding:12px 16px}.k-needs-item+.k-needs-item{border-top:1px solid var(--so-line)}.k-needs-item b{font-weight:600}.k-needs-item p{margin:2px 0 0;font-size:12.5px;color:var(--so-muted);line-height:1.45}.k-needs-item .k-acts .k-btn{min-width:124px}.k-scrim{position:fixed;inset:0;z-index:25;background:transparent;animation:k-fade var(--m-slow) var(--m-ease) both}.k-scrim.dim{background:var(--so-scrim)}.k-pop{position:fixed;z-index:40;box-sizing:border-box;width:336px;max-width:calc(100vw - 16px);padding:14px;border-radius:10px;background:var(--so-paper);color:var(--so-ink);border:1px solid var(--so-overlay-line);display:grid;gap:10px}.k-pop-h{display:flex;align-items:center;gap:8px;margin:-4px -6px 0 0}.k-pop-h h3{margin:0;font:var(--so-typography-title-sm);flex:1}.k-pop p{margin:0;font-size:12.5px;color:var(--so-muted);line-height:1.5}.k-pop .k-pop-terms{color:var(--so-ink);font-weight:500;font-size:13px;padding:8px 10px;background:var(--so-raised);border-radius:7px}.k-pop .k-pop-foot{font-size:12px;border-top:1px solid var(--so-line);padding-top:10px}.k-pop .k-input{height:36px}.k-pop.k-pop-menu{width:240px}.k-drawer{position:fixed;top:8px;right:8px;bottom:8px;width:400px;max-width:calc(100vw - 16px);z-index:30;background:var(--so-paper);color:var(--so-ink);border-radius:12px;border:1px solid var(--so-overlay-line);overflow:auto;display:flex;flex-direction:column}.k-drawer-h{display:flex;align-items:center;gap:6px;padding:10px 10px 10px 20px;border-bottom:1px solid var(--so-line);position:sticky;top:0;background:var(--so-paper)}.k-drawer-h h2{margin:0;font:600 14px/1.3 var(--so-font-sans);flex:1}.k-drawer-b{padding:18px 20px 28px;display:grid;gap:22px;align-content:start}.k-sheet{position:fixed;left:8px;right:8px;bottom:calc(8px + env(safe-area-inset-bottom));z-index:45;max-height:calc(100dvh - 16px);display:flex;flex-direction:column;background:var(--so-paper);color:var(--so-ink);border-radius:14px;border:1px solid var(--so-overlay-line)}.k-sheet-h{display:flex;align-items:center;gap:8px;padding:6px 6px 8px 16px;border-bottom:1px solid var(--so-line);flex:none}.k-sheet-ht{flex:1;min-width:0;display:grid;gap:2px;padding-top:4px}.k-sheet-h h2{margin:0;font:600 15px/1.3 var(--so-font-sans);display:flex;gap:8px;align-items:center;white-space:nowrap}.k-sheet-b{overflow:auto;padding:0 0 12px}.k-pop:focus,.k-drawer:focus,.k-sheet:focus{outline:none}.k-pop[hidden],.k-drawer[hidden],.k-sheet[hidden]{display:none}.k-scrim.stacked{z-index:48}.k-pop.stacked,.k-sheet.stacked,.k-drawer.stacked{z-index:50}.k-menu{display:grid;gap:1px;margin:0 -6px}.k-menu>button,.k-menu>a{display:flex;align-items:center;box-sizing:border-box;width:100%;min-height:32px;margin:0;padding:0 8px;border:0;border-radius:6px;background:transparent;color:var(--so-ink);font:var(--so-typography-label);text-align:left;text-decoration:none;cursor:pointer;box-shadow:none}.k-menu>[aria-current=true]{font-weight:600}.k-sheet .k-menu{margin:0;padding:6px 8px 4px}.k-grow-in{transform-origin:var(--origin, top left);animation:k-grow var(--m-base) var(--m-ease) both}.k-drawer.k-grow-in,.k-sheet.k-grow-in{animation-duration:var(--m-slow)}@keyframes k-grow{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:none}}@keyframes k-fade{0%{opacity:0}}.k-msg-in{animation:k-msg var(--m-base) var(--m-ease) both}@keyframes k-msg{0%{opacity:0;transform:translateY(-3px)}}.k-swap-in{animation:k-swap var(--m-base) var(--m-ease) both}@keyframes k-swap{0%{opacity:0;transform:translateY(4px)}}.k-composer{--c-r: 22px;box-sizing:border-box;border:1px solid var(--so-field-line);border-radius:var(--c-r);background:var(--so-paper);display:grid;padding:4px 6px 6px;outline:3px solid transparent;outline-offset:0;transition:border-color var(--m-quick) var(--m-ease),outline-color var(--m-quick) var(--m-ease)}.k-composer:focus-within{border-color:var(--so-ink);outline-color:color-mix(in srgb,var(--so-ink) 10%,transparent)}.k-composer.off{border-color:var(--so-line);background:var(--so-raised)}.k-composer-ta.k-composer-ta{box-sizing:border-box;width:100%;min-height:40px;margin:0;padding:10px 10px 6px;border:0;border-radius:0;outline:none;resize:none;background:transparent;box-shadow:none;color:var(--so-ink);font:var(--so-typography-body-reading);line-height:1.5;overflow-y:hidden;scrollbar-width:thin}.k-composer-ta::placeholder{color:var(--so-muted)}.k-composer-ta:focus,.k-composer-ta:focus-visible{outline:none;box-shadow:none}.k-composer:has(.k-composer-ta[aria-invalid=true]){border-color:var(--so-danger);outline-color:transparent}.k-composer+.k-err{margin-top:6px}.k-composer-bar{display:flex;align-items:center;gap:6px;padding:2px 0 0 2px;flex-wrap:wrap;min-height:36px}.k-composer-plus{box-sizing:border-box;width:32px;height:32px;min-height:0;margin:0;padding:0;border-radius:50%;display:grid;place-items:center;color:var(--so-muted);border:1px solid var(--so-line);background:transparent;cursor:pointer;box-shadow:none;transition:background-color var(--m-quick) var(--m-ease),color var(--m-quick) var(--m-ease)}.k-composer-chip{box-sizing:border-box;height:32px;min-height:0;margin:0;display:inline-flex;align-items:center;gap:4px;padding:0 8px 0 10px;border:0;border-radius:999px;font:500 12.5px/1 var(--so-font-sans);color:var(--so-muted);background:transparent;cursor:pointer;box-shadow:none;transition:background-color var(--m-quick) var(--m-ease),color var(--m-quick) var(--m-ease)}.k-composer-plus:disabled,.k-composer-chip:disabled{opacity:.5;pointer-events:none}.k-send-slot{position:relative;display:inline-grid;width:34px;height:34px;flex:none}.k-send-slot .k-send{grid-area:1 / 1;position:relative;box-sizing:border-box;width:34px;height:34px;min-height:0;margin:0;padding:0;border-radius:50%;display:grid;place-items:center;background:var(--so-ink);color:var(--so-paper);border:0;cursor:pointer;box-shadow:none;transition:background-color var(--m-quick) var(--m-ease),color var(--m-quick) var(--m-ease),transform var(--m-base) var(--m-ease)}.k-send:before{content:"";position:absolute;inset:-5px}.k-send .k-i{width:17px;height:17px;stroke-width:2.2}.k-send[aria-disabled=true],.k-composer:not(.has-text) .k-send:not(.k-stop){background:var(--so-raised);color:var(--so-muted)}.k-send[aria-disabled=true]{cursor:default}.k-send:not([aria-disabled=true]):active{transform:scale(.94)}.k-stop{visibility:hidden}.k-stop .k-i{fill:currentColor;width:12px;height:12px}.k-composer.working .k-send:not(.k-stop){visibility:hidden}.k-composer.working .k-stop{visibility:visible}.k-composer.working .k-stop .k-i,.k-composer.was-working:not(.working) .k-send:not(.k-stop) .k-i{animation:k-morph var(--m-base) var(--m-ease)}@keyframes k-morph{0%{opacity:0;transform:scale(.82)}}.k-send:focus-visible{outline:2px solid var(--so-ring);outline-offset:2px}.k-composer-files{display:flex;flex-wrap:wrap;gap:6px;padding:0 8px}.k-composer-files:empty{display:none}.k-composer-file{display:inline-flex;align-items:center;gap:6px;height:28px;margin-top:6px;padding:0 4px 0 10px;border:1px solid var(--so-line);border-radius:999px;font-size:12px}.k-composer-file button{width:22px;height:22px;min-height:0;margin:0;padding:0;display:grid;place-items:center;border:0;border-radius:50%;background:transparent;color:var(--so-muted)}.k-composer-note,.k-composer-err{padding:2px 10px 6px}.k-composer-err:empty{display:none}.k-composer.line{grid-template-columns:minmax(0,1fr) auto;align-items:end;padding:4px 6px 4px 8px}.k-composer.line .k-composer-ta{padding:8px 6px;min-height:36px}.k-composer.line .k-composer-bar{padding:0 0 1px;min-height:0}.k-composer.line .k-composer-bar .k-grow{display:none}.k-composer.line .k-composer-files,.k-composer.line .k-composer-err,.k-composer.line .k-composer-note{grid-column:1 / -1}.k-composer-dock{position:sticky;bottom:0;z-index:4;padding:12px 24px 14px;background:var(--so-paper);border-top:1px solid var(--so-line)}.k-timing{border:1px solid var(--so-line);border-radius:var(--so-radius-card);background:var(--so-paper);overflow:hidden}.k-timing-h{display:flex;align-items:center;gap:10px;min-height:52px;padding:8px 10px 8px 16px;border-bottom:1px solid var(--so-line)}.k-timing-h h2{margin:0;font:600 13.5px/1.3 var(--so-font-sans)}.k-timing-h .k-timing-state{margin-left:auto;display:flex;gap:8px;align-items:center}.k-timing-b{padding:12px 16px;display:grid;gap:2px}.k-timing-f{padding:10px 16px 12px;border-top:1px solid var(--so-line);font-size:12px;color:var(--so-muted);display:flex;gap:8px;align-items:center;flex-wrap:wrap}.k-timing-f:empty{display:none}.k-crow{display:grid;grid-template-columns:16px 220px minmax(0,1fr) 62px 60px;gap:10px;align-items:center;min-height:40px;font-size:13px}.k-crow.head{min-height:20px;font-size:11.5px;color:var(--so-muted)}.k-crow-i{display:grid;place-items:center;width:16px;height:16px}.k-crow-i .k-qd{width:10px;height:10px;border-radius:50%;border:1.5px dashed var(--so-field-line);box-sizing:border-box}.k-crow-i .k-rund{width:10px;height:10px;border-radius:50%;border:2px solid var(--so-info);background:color-mix(in srgb,var(--so-info) 30%,transparent);box-sizing:border-box}.k-crow-i .k-wd{width:9px;height:9px;border-radius:50%;background:var(--so-needs)}.k-crow-i svg{width:14px;height:14px}.k-crow.ok .k-crow-i{color:var(--so-success)}.k-crow.bad .k-crow-i{color:var(--so-danger)}.k-crow-n{min-width:0;white-space:normal;line-height:1.3}.k-crow-n .k-crow-sub{display:block;font-size:11.5px;color:var(--so-muted);font-weight:400}.k-crow-w{font-size:12px;color:var(--so-muted)}.k-crow.bad .k-crow-w{color:var(--so-fail-ink);font-weight:500}.k-crow.run .k-crow-w{color:var(--so-live-ink)}.k-crow.wait .k-crow-w{color:var(--so-needs-ink);font-weight:600}.k-crow.now .k-crow-n,.k-crow.now .k-crow-w{font-weight:600}.k-crow-lane{position:relative;height:14px}.k-crow-bar{position:absolute;top:4px;height:6px;border-radius:3px;background:var(--so-info);min-width:3px;transition:width var(--m-base) linear,background-color var(--m-slow) var(--m-ease)}.k-crow.ok .k-crow-bar{background:var(--so-success)}.k-crow.bad .k-crow-bar{background:var(--so-danger)}.k-crow.wait .k-crow-bar{background:var(--so-needs)}.k-crow-s{text-align:right;color:var(--so-muted);font-size:12px;font-variant-numeric:tabular-nums}.k-nf .k-empty{padding:40px 24px}.k-nf .k-empty-t{font-size:15px}.k-settings{display:grid;grid-template-columns:200px minmax(0,1fr);flex:1}.k-snav{border-right:1px solid var(--so-line);padding:14px 10px;display:grid;gap:1px;align-content:start}.k-nav{display:flex;align-items:center;gap:9px;height:30px;padding:0 8px;border-radius:6px;color:var(--so-nav-ink);font:500 13px/1 var(--so-font-sans);text-decoration:none}.k-nav[aria-current]{background:var(--so-nav-hover);color:var(--so-ink)}.k-nav>.k-nav-l{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.k-nav-top{margin-bottom:8px}.k-nav-flag{width:6px;height:6px;border-radius:50%;background:var(--so-needs);flex:none}.k-sbody{box-sizing:border-box;max-width:760px;width:100%;padding:24px 32px 80px;display:grid;gap:24px;align-content:start}.k-sbody>header h2{margin:0;font:600 20px/1.3 var(--so-font-sans);letter-spacing:-.015em}.k-sbody>header p{margin:4px 0 0;color:var(--so-muted)}.k-crumbs{display:inline-flex;align-items:center;gap:6px;min-width:0}.k-crumbs a{color:var(--so-muted);text-decoration:none}.k-crumbs .k-sep{color:var(--so-field-line)}.k-crumbs b{font-weight:500;color:var(--so-ink)}@media(hover:hover)and (pointer:fine){.k-link:hover{text-decoration-color:var(--so-ink)}.k-btn.k-btn-primary:hover{background:var(--so-accent-hover);border-color:var(--so-accent-hover)}.k-btn.k-btn-outline:hover{background:var(--so-soft)}.k-btn.k-btn-ghost:hover{background:var(--so-soft);color:var(--so-ink)}.k-btn.k-btn-danger:hover{background:var(--so-danger-soft)}.k-seg>a:hover,.k-seg>button:hover{color:var(--so-ink)}.k-tabs>button:hover,.k-tabs>a:hover{color:var(--so-ink)}.k-switch:hover{background:transparent}.k-opt:hover{border-color:var(--so-ink)}.k-row:hover{background:color-mix(in srgb,var(--so-raised) 60%,transparent)}.k-row.k-row-static:hover{background:transparent}.k-card:hover{background:color-mix(in srgb,var(--so-raised) 60%,transparent)}.k-backlink:hover{color:var(--so-ink)}.k-menu>button:hover,.k-menu>a:hover{background:var(--so-soft)}.k-composer-plus:hover,.k-composer-chip:hover{background:var(--so-raised);color:var(--so-ink)}.k-nav:hover{background:var(--so-nav-hover);color:var(--so-ink)}.k-crumbs a:hover{color:var(--so-ink)}}.k-code{display:inline-block;max-width:100%;box-sizing:border-box;margin:0;padding:6px 10px;border-radius:7px;background:var(--so-raised);color:var(--so-ink);font:12.5px/1.45 var(--so-font-mono);overflow-wrap:anywhere;user-select:all}.k-dock{display:none}.k-dock-needs{display:grid;align-content:center;gap:1px;box-sizing:border-box;width:136px;min-height:48px;margin:0;padding:0 12px;border-radius:8px;border:1px solid var(--so-field-line);background:var(--so-paper);color:var(--so-ink);text-align:left;white-space:nowrap;cursor:pointer;box-shadow:none}.k-dock-needs-l{display:inline-flex;align-items:center;gap:7px;font:500 14px/1.2 var(--so-font-sans)}.k-dock-needs-s{overflow:hidden;text-overflow:ellipsis;font-size:11.5px;color:var(--so-muted);padding-left:14px}.k-dock-needs:focus-visible{outline:2px solid var(--so-ring);outline-offset:2px}@media(max-width:760px){.k-desk-only{display:none!important}.k-btn,.k-btn-sm{height:44px;padding:0 16px;font-size:14px}.k-btn-icon,.k-btn-sm.k-btn-icon{width:44px;padding:0}.k-input.k-input,.k-textarea.k-textarea,.k-sel.k-sel{font-size:16px}.k-input.k-input,.k-pop .k-input.k-input,.k-sel.k-sel,.k-selw.sm .k-sel{height:44px}.k-selw:after{right:13px}.k-seg>a,.k-seg>button{height:44px;font-size:13.5px}.k-tabs>button,.k-tabs>a{min-height:44px}.k-disclose>summary{min-height:44px}.k-facts a{display:inline-flex;align-items:center;min-height:44px}.k-checks label,.k-switch{min-height:44px}.k-opt{padding:13px 14px}.k-radios{grid-template-columns:1fr}.k-facts{grid-template-columns:1fr;gap:3px}.k-facts dd{margin-bottom:8px}.k-tb{display:none}.k-ph{display:flex;align-items:center;gap:2px;height:52px;padding:0 4px;position:sticky;top:0;z-index:8;background:var(--so-paper);border-bottom:1px solid var(--so-line)}.k-ph-t{flex:1;min-width:0;margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:600 16px/1.2 var(--so-font-sans);padding-left:4px}.k-grp{padding:0 16px}.k-row{grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;padding:12px 16px}.k-row-c{grid-row:2;grid-column:1;display:flex;gap:8px;align-items:center;min-width:0}.k-row-t{grid-row:1;grid-column:1;white-space:normal;font-size:14px}.k-row-d{grid-row:3;grid-column:1 / -1;white-space:normal}.k-row-m{display:none}.k-row-a{grid-row:1 / 3;grid-column:2}.k-row-a .k-btn{min-width:0;padding:0 12px;font-size:13.5px}.k-row-a:empty{display:none}.k-row-msg{grid-column:1 / -1}.k-tbp{display:flex;gap:8px;align-items:center;padding:10px 16px;border-bottom:1px solid var(--so-line);background:var(--so-paper)}.k-tbp>.k-selw{flex:1;min-width:0}.k-tbp{flex-wrap:wrap}.k-tbp>.k-filter{flex:1 1 100%;width:auto;height:44px;order:2}.k-filter>input{font-size:16px}.k-foot{padding:12px 16px}.k-foot a{display:inline-flex;align-items:center;min-height:44px}.k-colpager{display:block;margin:10px 16px 0;overflow-x:auto;scrollbar-width:none}.k-colpager .k-seg>button,.k-colpager .k-seg>a{flex:1;justify-content:center;padding:0 8px}.k-board{grid-template-columns:minmax(0,1fr);margin-top:8px}.k-col{border-right:0;display:none}.k-col.on{display:block}.k-col-h{display:none}.k-card{padding:12px 16px}.k-step{font-size:11px}.k-step-s{font-size:10.5px;white-space:normal}.k-doc{padding:14px 16px 40px;gap:18px}.k-dh h1{font-size:20px}.k-backlink,.k-slot-acts .k-btn.k-btn-primary.k-docked{display:none}.k-slot-acts{min-height:44px}.k-needs-item{grid-template-columns:minmax(0,1fr)}.k-needs-item .k-acts .k-btn{width:100%}.k-pop{width:auto}.k-pop.as-sheet{left:8px!important;right:8px;top:auto!important;bottom:calc(8px + env(safe-area-inset-bottom));border-radius:14px;padding:16px;max-height:calc(100dvh - 16px);overflow:auto}.k-pop .k-acts .k-btn{flex:1}.k-drawer{inset:auto 8px 8px;width:auto;max-height:calc(100dvh - 16px)}.k-menu>button,.k-menu>a{min-height:44px;font-size:15px}.k-frow{grid-template-columns:minmax(0,1fr);gap:10px;padding:12px 0}.k-frow.inline{grid-template-columns:minmax(0,1fr) auto}.k-frow-c{justify-content:flex-start}.k-frow.inline .k-frow-c{justify-content:flex-end}.k-frow-c .k-input,.k-frow-c .k-selw{max-width:none}.k-frow .k-err{text-align:left}.k-frow-c .k-seg{width:100%}.k-frow-c .k-seg>button{flex:1;justify-content:center}.k-composer-ta.k-composer-ta{font-size:16px}.k-composer-bar .k-btn-sm{height:44px}.k-send-slot,.k-send-slot .k-send{width:44px;height:44px}.k-send-slot .k-send{background:radial-gradient(circle,var(--so-ink) 17.5px,transparent 18px)}.k-send[aria-disabled=true],.k-composer:not(.has-text) .k-send:not(.k-stop){background:radial-gradient(circle,var(--so-raised) 17.5px,transparent 18px)}.k-send:before{content:none}.k-composer-plus{width:44px;height:44px;border:0;background:radial-gradient(circle,transparent 15.5px,var(--so-line) 16px,var(--so-line) 16.5px,transparent 17px)}.k-composer-chip{height:44px}.k-composer-bar{gap:2px}.k-composer-file button{width:32px;height:32px}.k-composer-dock{padding:12px 16px 16px}html.kb-open .k-composer-dock{position:fixed;left:0;right:0;bottom:var(--kb, 0px);z-index:13}html.kb-open .k-dock{display:none}.k-crow{grid-template-columns:14px minmax(0,1fr) 52px 48px;gap:6px;font-size:12.5px}.k-crow-lane{display:none}.k-timing.show-chart .k-crow{grid-template-columns:14px 112px minmax(0,1fr) 46px 44px}.k-timing.show-chart .k-crow-lane{display:block}.k-crow-w,.k-crow-s{font-size:11.5px}.k-nf .k-empty{padding:28px 16px}.k-settings{display:block}.k-snav{display:none}.k-sbody{padding:18px 16px 40px}.k-dock{display:flex;gap:8px;align-items:stretch;position:fixed;left:0;right:0;bottom:0;z-index:12;padding:10px 12px calc(10px + env(safe-area-inset-bottom));background:var(--so-paper);border-top:1px solid var(--so-line)}.k-dock-primary{flex:1;display:flex}.k-dock-primary .k-btn{width:100%}}@media(min-width:761px){.k-phone-only{display:none!important}}body:has(.k-out){background:var(--so-paper)}main:has(>.k-out){max-width:none;margin:0;padding:0}.k-out{box-sizing:border-box;min-height:100dvh;display:grid;align-content:center;justify-items:center;gap:20px;padding:48px 16px 64px}.k-out-c{box-sizing:border-box;width:100%;max-width:380px;display:grid;gap:18px;min-width:0}.k-out-brand{display:inline-flex;align-items:center;gap:8px;justify-self:start;margin:0 0 10px;color:var(--so-ink);font:600 14px/1 var(--so-font-sans);letter-spacing:-.01em;text-decoration:none}.k-out h1{margin:0;font:600 24px/1.3 var(--so-font-sans);letter-spacing:-.02em;color:var(--so-ink)}.k-out-sub{margin:-8px 0 0;color:var(--so-muted);font-size:13px;line-height:1.5}.k-out-sub b{color:var(--so-ink);font-weight:600}.k-out-note{margin:-6px 0 0;padding:8px 10px;border-radius:7px;background:var(--so-raised);font-size:13px;line-height:1.5;color:var(--so-ink)}.k-out-f{box-sizing:border-box;width:100%;max-width:380px;margin:0;padding-top:14px;border-top:1px solid var(--so-line);color:var(--so-muted);font-size:12px;line-height:1.6}.k-out-f code,.k-out .k-mono{font-family:var(--so-font-mono);font-size:12px}.k-out .k-facts{padding:12px 0;border-top:1px solid var(--so-line);border-bottom:1px solid var(--so-line);grid-template-columns:96px minmax(0,1fr)}.k-out .k-slots{padding:16px}.k-out .k-slot-acts:empty,.k-out .k-slot-terms:empty{display:none}.k-form{display:grid;gap:14px;margin:0;min-width:0}.k-form .k-input.k-input{height:36px}.k-btn.k-wide{width:100%;height:36px}.k-out .k-disclose>summary{min-height:32px}.k-refusal .k-empty-t:first-letter,.k-refusal .k-notice>span:first-letter{text-transform:uppercase}.k-composer .k-off-note{display:none}.k-composer:has(.k-switch-input):not(:has(.k-switch-input:checked)) .k-on-note{display:none}.k-composer:has(.k-switch-input):not(:has(.k-switch-input:checked)) .k-off-note{display:inline}.k-composer .k-composer-ta.k-composer-ta:focus-visible{outline:none;box-shadow:none}.k-slot-acts>form.k-approve.k-form{flex:1 1 100%;min-width:0}.k-check{display:grid;margin:0;padding:0;list-style:none;border-top:1px solid var(--so-line)}.k-check-row{display:grid;grid-template-columns:20px minmax(0,1fr) auto;gap:12px;align-items:center;min-height:56px;margin:0;padding:10px 0;border-bottom:1px solid var(--so-line)}.k-check-mark{box-sizing:border-box;width:18px;height:18px;border-radius:50%;border:1.5px solid var(--so-field-line);display:grid;place-items:center;background:var(--so-paper)}.k-check-mark.ok{background:var(--so-success);border-color:var(--so-success);color:var(--so-paper)}.k-check-mark.ok .k-i{width:11px;height:11px;stroke-width:3}.k-check-mark.run{border-color:var(--so-info);background:color-mix(in srgb,var(--so-info) 22%,transparent)}.k-check-t{display:grid;gap:2px;min-width:0}.k-check-t b{font-weight:600;font-size:13.5px;color:var(--so-ink)}.k-check-row.done .k-check-t b{font-weight:500;color:var(--so-muted)}.k-check-t>span{font-size:12.5px;line-height:1.45;color:var(--so-muted);overflow-wrap:anywhere}.k-check-a{display:flex;justify-content:flex-end}.k-check-a .k-btn{min-width:108px}.k-hello{display:grid;gap:6px}.k-hello h1,.k-hello h2{margin:0;font:600 20px/1.3 var(--so-font-sans);letter-spacing:-.015em;color:var(--so-ink)}.k-hello p{margin:0;font-size:13px;color:var(--so-muted)}.k-ideas{display:flex;flex-wrap:wrap;gap:8px;margin:0;padding:0}.k-btn.k-idea{height:auto;min-height:36px;padding:6px 14px;border-radius:999px;border-color:var(--so-line);font-weight:400;white-space:normal;text-align:left}@media(pointer:coarse){.k-btn.k-idea{min-height:44px}}@media(max-width:760px){.k-out{align-content:start;padding-top:32px}.k-form .k-input.k-input,.k-btn.k-wide{height:44px}.k-out-brand{min-height:44px;margin-bottom:0}.k-out .k-facts{grid-template-columns:1fr}.k-out .k-disclose>summary{min-height:44px}.k-check-row{grid-template-columns:20px minmax(0,1fr)}.k-check-a{grid-column:2;justify-content:flex-start}.k-check-a:empty,.k-check-a:not(:has(.k-btn:not(.k-docked))){display:none}.k-btn.k-idea{min-height:44px;padding:10px 14px;font-size:14px}.k-check-a .k-btn.k-docked{display:none}.k-doc:has(~.k-dock){padding-bottom:96px}.k-dock-send .k-composer .k-send-slot{display:none}}@media(prefers-reduced-motion:reduce){.k-btn,.k-send,.k-composer,.k-composer-plus,.k-composer-chip,.k-trk,.k-trk:after,.k-tabs>*,.k-slots,.k-crow-bar{transition:none}.k-steps-fill{transition:none}.k-grow-in,.k-msg-in,.k-swap-in,.k-scrim,.k-btn.swap .k-face,.k-check-draw path,.k-composer .k-i{animation:none!important}.k-check-draw path{stroke-dashoffset:0}.k-spin{animation:none;border-right-color:currentColor;opacity:.5}}.k-ssec{display:grid;align-content:start;min-width:0;scroll-margin-top:64px}.k-ssec-state{font-weight:400;font-size:12.5px;color:var(--so-muted)}.k-ssec-lead{margin:0;padding:10px 0 2px;font-size:12.5px;color:var(--so-muted);line-height:1.5;max-width:66ch}.k-ssec>.k-note,.k-ssec>.k-notice{margin-top:10px}.k-slinks{display:grid}.k-slink{display:grid;grid-template-columns:20px minmax(0,1fr) auto 16px;gap:4px 12px;align-items:center;min-height:56px;padding:10px 0;border-bottom:1px solid var(--so-line);color:var(--so-ink);text-decoration:none}.k-slink.noico{grid-template-columns:minmax(0,1fr) auto 16px}.k-slink>.k-i{color:var(--so-muted)}.k-sl{display:grid;gap:3px;min-width:0}.k-sl-t{display:inline-flex;align-items:center;gap:8px 10px;flex-wrap:wrap;font-weight:500;font-size:13px;min-width:0;overflow-wrap:anywhere}.k-sl-h{font-size:12.5px;color:var(--so-muted);line-height:1.45;overflow-wrap:anywhere}.k-slink-r{display:flex;align-items:center;gap:8px}.k-chev{width:7px;height:7px;border:solid var(--so-muted);border-width:1.5px 1.5px 0 0;transform:rotate(45deg);justify-self:center}.k-sflag{display:inline-flex;align-items:center;gap:6px;font:500 12px/1 var(--so-font-sans);color:var(--so-neutral-ink)}.k-sflag:before{content:"";width:6px;height:6px;border-radius:50%;background:var(--so-needs)}.k-srec{display:grid;grid-template-columns:minmax(0,1fr) auto 124px;gap:4px 16px;align-items:center;min-height:52px;padding:10px 0;border-bottom:1px solid var(--so-line)}.k-srec-when{font-size:12px;color:var(--so-muted);white-space:nowrap}.k-srec-a{display:flex;justify-content:flex-end;gap:8px}.k-srec-a .k-btn{min-width:108px}.k-srec-more{grid-column:1 / -1;min-width:0}.k-srec-more:empty{display:none}.k-scode{display:block;justify-self:start;max-width:100%;box-sizing:border-box;margin:8px 0 0;padding:8px 10px;border-radius:7px;background:var(--so-raised);font:12px/1.5 var(--so-font-mono);overflow-wrap:anywhere;user-select:all}.k-sform{display:grid;min-width:0;margin:0}.k-sform fieldset{border:0;margin:0;padding:0;min-width:0}.k-ssave{display:flex;align-items:center;gap:12px;min-height:48px;padding:8px 0;background:var(--so-paper)}.k-ssave-said{flex:1;min-width:0;font-size:12.5px;color:var(--so-muted)}.k-ssave .k-btn{min-width:96px}.k-sform[data-dirty] .k-ssave{position:sticky;bottom:0;z-index:2;border-top:1px solid var(--so-line)}.k-sform[data-dirty] .k-ssave-said{color:var(--so-ink);font-weight:500}.k-ssave-err:empty{display:none}.k-ssave-err .k-notice{margin:0 0 8px}.k-sproof label,.k-sproof .k-field{display:grid;gap:6px;margin:8px 0 0;font:var(--so-typography-caption);color:var(--so-ink);max-width:320px}.k-sproof input[type=password]{box-sizing:border-box;width:100%;height:32px;min-height:0;margin:0;padding:0 10px;border:1px solid var(--so-field-line);border-radius:8px;background:var(--so-paper);color:var(--so-ink);font:400 13px/1.4 var(--so-font-sans);box-shadow:none}.k-pop .k-sproof label{margin:0;max-width:none}html.k-js .k-sform>.k-sproof{display:none}html.k-js .k-sform[data-k-gate]:not([data-dirty]) .k-ssave .k-btn{display:none}html.k-js .k-sform[data-k-gate]:not([data-dirty]) .k-ssave:has(.k-ssave-said:empty){display:none}.k-sopts{display:grid;gap:8px;padding:10px 0}.k-sopt{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;align-items:start;min-height:32px;font-size:13px;color:var(--so-ink);cursor:pointer}.k-sopt input{margin:2px 0 0;accent-color:var(--so-ink)}.k-sopt b{display:block;font-weight:500}.k-sopt span span{display:block;color:var(--so-muted);font-size:12.5px;line-height:1.45}.k-secret-val{display:block;padding:8px 10px;border-radius:7px;background:var(--so-raised);font:12.5px/1.4 var(--so-font-mono);overflow-wrap:anywhere;user-select:all}@media(hover:hover)and (pointer:fine){.k-slink:hover .k-sl-t>span:first-child{text-decoration:underline;text-decoration-color:var(--so-field-line);text-underline-offset:3px}}@media(max-width:760px){.k-slink{min-height:64px;padding:12px 0}.k-srec{grid-template-columns:minmax(0,1fr) auto}.k-srec-when{grid-column:1}.k-srec-a{grid-column:2;grid-row:1 / span 2}.k-srec-a .k-btn{min-width:0}.k-ssave .k-btn{min-height:44px}.k-sproof input[type=password]{height:44px;font-size:16px}.k-sproof label{max-width:none}.k-sopt{min-height:44px}}.k-srec-a .k-sform{display:block}.k-srec-a .k-ssave{min-height:0;padding:0;background:none}.k-srec-a .k-ssave-said:empty{display:none}pre.k-scode{white-space:pre-wrap}@font-face{font-family:Geist;src:url(/fonts/geist-sans-400.woff2) format("woff2");font-weight:400;font-display:swap}@font-face{font-family:Geist;src:url(/fonts/geist-sans-500.woff2) format("woff2");font-weight:500;font-display:swap}@font-face{font-family:Geist;src:url(/fonts/geist-sans-600.woff2) format("woff2");font-weight:600;font-display:swap}@font-face{font-family:Geist Mono;src:url(/fonts/geist-mono-400.woff2) format("woff2");font-weight:400;font-display:swap}*{box-sizing:border-box}html,body{margin:0;height:100%;background:var(--so-paper);color:var(--so-ink);font:400 13px/1.5 var(--so-font-sans);-webkit-font-smoothing:antialiased}body{overscroll-behavior:none}#so-term{height:100dvh}.term-app{display:flex;flex-direction:column;height:100dvh}.term-app--loading{display:grid;place-items:center}.term-tb{display:flex;align-items:center;gap:10px;min-height:48px;padding:var(--so-space-sm) var(--so-space-2xl);border-bottom:1px solid var(--so-line);flex:none}.term-tb h1{margin:0;font:600 15px/1.3 var(--so-font-sans);letter-spacing:-.01em}.term-ctx{color:var(--so-muted);font-size:12.5px}.term-back{display:inline-flex;align-items:center;gap:var(--so-space-xs);margin-right:6px;color:var(--so-muted);font-size:12.5px;text-decoration:none}.term-grid{flex:1;min-height:0;display:grid;grid-template-columns:280px minmax(0,1fr)}.term-side{border-right:1px solid var(--so-line);overflow-y:auto}.term-main{display:flex;flex-direction:column;min-width:0;min-height:0;overflow-y:auto}.term-list{display:grid;padding:0}.term-none{margin:0;padding:var(--so-space-md) var(--so-space-lg);font-size:12.5px;color:var(--so-muted)}.term-item{display:grid;text-decoration:none;gap:5px;width:100%;margin:0;padding:10px var(--so-space-lg);border:0;border-bottom:1px solid var(--so-line);background:transparent;color:var(--so-ink);font:inherit;text-align:left;cursor:pointer}.term-item[aria-current]{box-shadow:inset 2px 0 0 var(--so-ink)}.term-item[aria-current] .term-item-t{font-weight:600}.term-item-t{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.term-item-m{display:flex;align-items:center;gap:var(--so-space-sm);min-width:0;color:var(--so-muted)}.term-item-m .k-mono{font-size:11.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.term-pane{flex:1;display:flex;flex-direction:column;gap:var(--so-space-md);min-height:0;padding:var(--so-space-lg) var(--so-space-2xl) var(--so-space-2xl)}.term-ph{display:flex;align-items:center;gap:var(--so-space-md)}.term-ph>div{flex:1;display:grid;gap:2px;min-width:0}.term-ph b{font-weight:600;font-size:13.5px}.term-ph-m{color:var(--so-muted);font-size:12px}.term-link{font-size:12px;color:var(--so-muted);white-space:nowrap}.term-link--live{color:var(--so-live-ink)}.term-link--signed-out,.term-link--gone{color:var(--so-fail-ink)}.term-link--busy{color:var(--so-ink)}.term-screen{flex:1;min-height:320px;padding:10px var(--so-space-md);border:1px solid var(--so-line);border-radius:var(--so-radius-card);background:var(--so-code-bg);overflow:hidden}.term-screen .xterm{height:100%}.term-screen .xterm-viewport{background:var(--so-code-bg)!important}.term-keys{display:none;gap:6px;overflow-x:auto;flex:none;padding-bottom:env(safe-area-inset-bottom)}.term-key{min-width:44px;font-family:var(--so-font-mono);flex:none;touch-action:manipulation}.term-key[aria-pressed=true]{background:var(--so-soft);border-color:var(--so-ink)}.term-form{display:grid;gap:14px;align-content:start;max-width:760px;padding:var(--so-space-xl) var(--so-space-2xl)}.term-terms{justify-self:start;margin:0;padding:var(--so-space-sm) 10px;border-radius:7px;background:var(--so-raised);font-size:12.5px}.term-radios .k-radios{grid-template-columns:repeat(3,minmax(0,1fr))}@media(hover:hover)and (pointer:fine){.term-item:hover{background:color-mix(in srgb,var(--so-raised) 60%,transparent)}.term-back:hover{color:var(--so-ink)}}@media(max-width:760px){.term-tb{padding:0 var(--so-space-sm) 0 var(--so-space-xs);padding-top:env(safe-area-inset-top);min-height:calc(52px + env(safe-area-inset-top))}.term-tb .k-btn-primary{height:44px}.term-ctx{display:none}.term-tb h1{flex:1}.term-grid{grid-template-columns:minmax(0,1fr)}.term-side{border-right:0}.term-app--pane .term-side{display:none}.term-app:not(.term-app--pane) .term-main{display:none}.term-pane{padding:var(--so-space-sm) var(--so-space-sm) var(--so-space-sm);gap:var(--so-space-sm)}.term-screen{padding:var(--so-space-xs) 6px;border-radius:var(--so-radius-md)}.term-keys{display:flex}.term-form{padding:var(--so-phone-gutter)}}
2
2
  /*! Bundled license information:
3
3
 
4
4
  @xterm/xterm/css/xterm.css: