@samyx/preview-stacks-ui 0.23.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/dist/assets/{ActionButton.vue_vue_type_script_setup_true_lang-CeingrPV.js → ActionButton.vue_vue_type_script_setup_true_lang-D5wrEmB2.js} +2 -2
  2. package/dist/assets/{ActionButton.vue_vue_type_script_setup_true_lang-CeingrPV.js.map → ActionButton.vue_vue_type_script_setup_true_lang-D5wrEmB2.js.map} +1 -1
  3. package/dist/assets/{AxesTab-vIQWJMZm.js → AxesTab-DPb0krkI.js} +2 -2
  4. package/dist/assets/{AxesTab-vIQWJMZm.js.map → AxesTab-DPb0krkI.js.map} +1 -1
  5. package/dist/assets/{ConfigTab-BeAIDTnl.js → ConfigTab-DLhjDiis.js} +2 -2
  6. package/dist/assets/{ConfigTab-BeAIDTnl.js.map → ConfigTab-DLhjDiis.js.map} +1 -1
  7. package/dist/assets/ConflictNote.vue_vue_type_script_setup_true_lang-HglPeTkY.js +2 -0
  8. package/dist/assets/{ConflictNote.vue_vue_type_script_setup_true_lang-fprimIle.js.map → ConflictNote.vue_vue_type_script_setup_true_lang-HglPeTkY.js.map} +1 -1
  9. package/dist/assets/{DangerTab-CcYJAftw.js → DangerTab-BLDIlbN5.js} +2 -2
  10. package/dist/assets/{DangerTab-CcYJAftw.js.map → DangerTab-BLDIlbN5.js.map} +1 -1
  11. package/dist/assets/DashboardView-DxZUkxRF.js +2 -0
  12. package/dist/assets/DashboardView-DxZUkxRF.js.map +1 -0
  13. package/dist/assets/DeploymentDetailView-CEg8sA5I.js +2 -0
  14. package/dist/assets/DeploymentDetailView-CEg8sA5I.js.map +1 -0
  15. package/dist/assets/DeploymentsView-BfhwFiiQ.js +2 -0
  16. package/dist/assets/DeploymentsView-BfhwFiiQ.js.map +1 -0
  17. package/dist/assets/{EquivalentCommand-D0Bfgz63.js → EquivalentCommand-C45BzkNz.js} +2 -2
  18. package/dist/assets/{EquivalentCommand-D0Bfgz63.js.map → EquivalentCommand-C45BzkNz.js.map} +1 -1
  19. package/dist/assets/{ErrorNote.vue_vue_type_script_setup_true_lang-DT5SbSbT.js → ErrorNote.vue_vue_type_script_setup_true_lang-B3hfwyPR.js} +2 -2
  20. package/dist/assets/{ErrorNote.vue_vue_type_script_setup_true_lang-DT5SbSbT.js.map → ErrorNote.vue_vue_type_script_setup_true_lang-B3hfwyPR.js.map} +1 -1
  21. package/dist/assets/HelpModal.vue_vue_type_script_setup_true_lang-BSOuxyyP.js +2 -0
  22. package/dist/assets/{HelpModal.vue_vue_type_script_setup_true_lang-2ev6wLk8.js.map → HelpModal.vue_vue_type_script_setup_true_lang-BSOuxyyP.js.map} +1 -1
  23. package/dist/assets/{JobDetailView-B5OFSqGO.js → JobDetailView-HFOJln2b.js} +2 -2
  24. package/dist/assets/{JobDetailView-B5OFSqGO.js.map → JobDetailView-HFOJln2b.js.map} +1 -1
  25. package/dist/assets/JobsView-dWw_uNGE.js +2 -0
  26. package/dist/assets/JobsView-dWw_uNGE.js.map +1 -0
  27. package/dist/assets/LogViewer.vue_vue_type_script_setup_true_lang-5r84oNls.js +3 -0
  28. package/dist/assets/{LogViewer.vue_vue_type_script_setup_true_lang-B5K26k3c.js.map → LogViewer.vue_vue_type_script_setup_true_lang-5r84oNls.js.map} +1 -1
  29. package/dist/assets/{LoginView-NzylzAuv.js → LoginView-0vIrAhlr.js} +2 -2
  30. package/dist/assets/{LoginView-NzylzAuv.js.map → LoginView-0vIrAhlr.js.map} +1 -1
  31. package/dist/assets/{LogsTab-DxhpYJY3.js → LogsTab-CFlgBsW3.js} +4 -4
  32. package/dist/assets/{LogsTab-DxhpYJY3.js.map → LogsTab-CFlgBsW3.js.map} +1 -1
  33. package/dist/assets/{NotFoundView-Cg_jPEQi.js → NotFoundView-jZIc0wDm.js} +2 -2
  34. package/dist/assets/{NotFoundView-Cg_jPEQi.js.map → NotFoundView-jZIc0wDm.js.map} +1 -1
  35. package/dist/assets/NotifiersView-DJu-c-a6.js +2 -0
  36. package/dist/assets/NotifiersView-DJu-c-a6.js.map +1 -0
  37. package/dist/assets/{OverviewTab-Cy7_mGTt.js → OverviewTab-DlJt0MIg.js} +2 -2
  38. package/dist/assets/{OverviewTab-Cy7_mGTt.js.map → OverviewTab-DlJt0MIg.js.map} +1 -1
  39. package/dist/assets/RefreshButton.vue_vue_type_script_setup_true_lang-CXCY3Vlc.js +2 -0
  40. package/dist/assets/RefreshButton.vue_vue_type_script_setup_true_lang-CXCY3Vlc.js.map +1 -0
  41. package/dist/assets/RegistriesView-BeiFx468.js +2 -0
  42. package/dist/assets/RegistriesView-BeiFx468.js.map +1 -0
  43. package/dist/assets/{RelativeTime.vue_vue_type_script_setup_true_lang-D7n5E9jw.js → RelativeTime.vue_vue_type_script_setup_true_lang-BGissyps.js} +2 -2
  44. package/dist/assets/{RelativeTime.vue_vue_type_script_setup_true_lang-D7n5E9jw.js.map → RelativeTime.vue_vue_type_script_setup_true_lang-BGissyps.js.map} +1 -1
  45. package/dist/assets/{RequiresTab-DDWsrZig.js → RequiresTab-Bb3_lYqC.js} +2 -2
  46. package/dist/assets/{RequiresTab-DDWsrZig.js.map → RequiresTab-Bb3_lYqC.js.map} +1 -1
  47. package/dist/assets/RoutingView-y8L_ex2z.js +9 -0
  48. package/dist/assets/RoutingView-y8L_ex2z.js.map +1 -0
  49. package/dist/assets/RuntimeTab-DWZ5eFho.js +2 -0
  50. package/dist/assets/RuntimeTab-DWZ5eFho.js.map +1 -0
  51. package/dist/assets/SelectMenu.vue_vue_type_script_setup_true_lang-D8NGgBfa.js +2 -0
  52. package/dist/assets/{SelectMenu.vue_vue_type_script_setup_true_lang-CSQS6ben.js.map → SelectMenu.vue_vue_type_script_setup_true_lang-D8NGgBfa.js.map} +1 -1
  53. package/dist/assets/{SettingsView-CQIMBeQh.js → SettingsView-C-xJVgVw.js} +2 -2
  54. package/dist/assets/{SettingsView-CQIMBeQh.js.map → SettingsView-C-xJVgVw.js.map} +1 -1
  55. package/dist/assets/{SkeletonList.vue_vue_type_script_setup_true_lang-DwoeliUC.js → SkeletonList.vue_vue_type_script_setup_true_lang-qMyLRAMp.js} +2 -2
  56. package/dist/assets/{SkeletonList.vue_vue_type_script_setup_true_lang-DwoeliUC.js.map → SkeletonList.vue_vue_type_script_setup_true_lang-qMyLRAMp.js.map} +1 -1
  57. package/dist/assets/{SpecDetailView-DSlpITFw.js → SpecDetailView-CGQZS7NU.js} +2 -2
  58. package/dist/assets/{SpecDetailView-DSlpITFw.js.map → SpecDetailView-CGQZS7NU.js.map} +1 -1
  59. package/dist/assets/SpecsView-D9mKql2j.js +2 -0
  60. package/dist/assets/SpecsView-D9mKql2j.js.map +1 -0
  61. package/dist/assets/{StateBadge.vue_vue_type_script_setup_true_lang-BsDpZsUH.js → StateBadge.vue_vue_type_script_setup_true_lang-BgbZLzlL.js} +2 -2
  62. package/dist/assets/{StateBadge.vue_vue_type_script_setup_true_lang-BsDpZsUH.js.map → StateBadge.vue_vue_type_script_setup_true_lang-BgbZLzlL.js.map} +1 -1
  63. package/dist/assets/{SubmitView-DqOEabaL.js → SubmitView-DuGtFMgF.js} +5 -5
  64. package/dist/assets/{SubmitView-DqOEabaL.js.map → SubmitView-DuGtFMgF.js.map} +1 -1
  65. package/dist/assets/Teleport-DfE2iP8c.js +4 -0
  66. package/dist/assets/{Teleport-BXE_6A8N.js.map → Teleport-DfE2iP8c.js.map} +1 -1
  67. package/dist/assets/{TerminalTab-lb8FY01Y.js → TerminalTab-D5ncE4Cv.js} +2 -2
  68. package/dist/assets/{TerminalTab-lb8FY01Y.js.map → TerminalTab-D5ncE4Cv.js.map} +1 -1
  69. package/dist/assets/UsersView-Be77zCYE.css +1 -0
  70. package/dist/assets/UsersView-BxU2ho4N.js +2 -0
  71. package/dist/assets/UsersView-BxU2ho4N.js.map +1 -0
  72. package/dist/assets/{VarEditor.vue_vue_type_script_setup_true_lang-ChzmZbEl.js → VarEditor.vue_vue_type_script_setup_true_lang-SKwJUsNC.js} +2 -2
  73. package/dist/assets/{VarEditor.vue_vue_type_script_setup_true_lang-ChzmZbEl.js.map → VarEditor.vue_vue_type_script_setup_true_lang-SKwJUsNC.js.map} +1 -1
  74. package/dist/assets/VariablesView-BnW2I-92.js +2 -0
  75. package/dist/assets/VariablesView-BnW2I-92.js.map +1 -0
  76. package/dist/assets/VariablesView-ByeOvDGJ.css +1 -0
  77. package/dist/assets/{index-wjzRhuU3.js → index-DVMQBHXF.js} +4 -4
  78. package/dist/assets/{index-wjzRhuU3.js.map → index-DVMQBHXF.js.map} +1 -1
  79. package/dist/assets/{index-Cyc_WOgY.css → index-lyuEu6lW.css} +1 -1
  80. package/dist/assets/{useDeployment-B7kMYmcq.js → useDeployment-DGzBsXE-.js} +2 -2
  81. package/dist/assets/{useDeployment-B7kMYmcq.js.map → useDeployment-DGzBsXE-.js.map} +1 -1
  82. package/dist/index.html +2 -2
  83. package/package.json +1 -1
  84. package/dist/assets/ConflictNote.vue_vue_type_script_setup_true_lang-fprimIle.js +0 -2
  85. package/dist/assets/DashboardView-Cvh03qbj.js +0 -2
  86. package/dist/assets/DashboardView-Cvh03qbj.js.map +0 -1
  87. package/dist/assets/DeploymentDetailView-BzEQBKhd.js +0 -2
  88. package/dist/assets/DeploymentDetailView-BzEQBKhd.js.map +0 -1
  89. package/dist/assets/DeploymentsView-f3RgqUkQ.js +0 -2
  90. package/dist/assets/DeploymentsView-f3RgqUkQ.js.map +0 -1
  91. package/dist/assets/HelpModal.vue_vue_type_script_setup_true_lang-2ev6wLk8.js +0 -2
  92. package/dist/assets/JobsView-B6RvX8WS.js +0 -2
  93. package/dist/assets/JobsView-B6RvX8WS.js.map +0 -1
  94. package/dist/assets/LogViewer.vue_vue_type_script_setup_true_lang-B5K26k3c.js +0 -3
  95. package/dist/assets/NotifiersView-B53fERhd.js +0 -2
  96. package/dist/assets/NotifiersView-B53fERhd.js.map +0 -1
  97. package/dist/assets/RegistriesView-dc-04uci.js +0 -2
  98. package/dist/assets/RegistriesView-dc-04uci.js.map +0 -1
  99. package/dist/assets/RoutingView-BheJjs2g.js +0 -9
  100. package/dist/assets/RoutingView-BheJjs2g.js.map +0 -1
  101. package/dist/assets/RuntimeTab-D4sJaoqc.js +0 -2
  102. package/dist/assets/RuntimeTab-D4sJaoqc.js.map +0 -1
  103. package/dist/assets/SelectMenu.vue_vue_type_script_setup_true_lang-CSQS6ben.js +0 -2
  104. package/dist/assets/SpecsView-Cq_Ny0u3.js +0 -2
  105. package/dist/assets/SpecsView-Cq_Ny0u3.js.map +0 -1
  106. package/dist/assets/Teleport-BXE_6A8N.js +0 -4
  107. package/dist/assets/UsersView-DpZ_4vlY.css +0 -1
  108. package/dist/assets/UsersView-mOC1UteJ.js +0 -2
  109. package/dist/assets/UsersView-mOC1UteJ.js.map +0 -1
  110. package/dist/assets/VariablesView-Cnpkn8AM.css +0 -1
  111. package/dist/assets/VariablesView-NBIFfXQ5.js +0 -2
  112. package/dist/assets/VariablesView-NBIFfXQ5.js.map +0 -1
@@ -1 +1 @@
1
- :root,:root[data-theme=dark]{color-scheme:dark;--bg: #0e1116;--bg-grad: radial-gradient(1100px 620px at 12% -12%, rgba(64, 106, 168, .22) 0%, transparent 70%), radial-gradient(900px 520px at 108% 8%, rgba(96, 76, 168, .13) 0%, transparent 68%);--panel: #171b22;--panel-2: #1e232c;--sunk: #11141a;--line: #2b323d;--line-soft: #21262f;--fg: #eef2f8;--fg-dim: #a4afbe;--fg-mute: #78838f;--accent: #4a9dff;--accent-soft: rgba(74, 157, 255, .18);--ok: #35d17e;--ok-soft: rgba(53, 209, 126, .17);--fail: #ff6159;--fail-soft: rgba(255, 97, 89, .17);--leak: #ffa62b;--leak-soft: rgba(255, 166, 43, .18);--neutral: #95a2b3;--neutral-soft: rgba(149, 162, 179, .16);--hairline: inset 0 1px 0 rgba(255, 255, 255, .055);--hairline-strong: inset 0 1px 0 rgba(255, 255, 255, .09);--elev-1: 0 1px 2px rgba(5, 8, 14, .5);--elev-2: 0 1px 2px rgba(5, 8, 14, .45), 0 6px 16px -4px rgba(5, 8, 14, .5);--elev-3: 0 1px 2px rgba(5, 8, 14, .5), 0 12px 32px -8px rgba(5, 8, 14, .62);--elev-4: 0 2px 4px rgba(5, 8, 14, .5), 0 24px 64px -12px rgba(5, 8, 14, .72);--shadow: var(--elev-2);--hover: rgba(255, 255, 255, .04);--hover-strong: rgba(255, 255, 255, .07);--press: rgba(0, 0, 0, .18);--skel: linear-gradient(90deg, #1c212a 0%, #262d38 50%, #1c212a 100%)}@media(prefers-color-scheme:light){:root:not([data-theme=dark]){color-scheme:light;--bg: #f5f6f8;--bg-grad: radial-gradient(1100px 620px at 12% -12%, rgba(31, 111, 235, .07) 0%, transparent 70%), radial-gradient(900px 520px at 108% 8%, rgba(120, 80, 220, .045) 0%, transparent 68%);--panel: #ffffff;--panel-2: #f4f6f9;--sunk: #eef1f5;--line: #dfe3e9;--line-soft: #eaedf1;--fg: #14181e;--fg-dim: #57616f;--fg-mute: #7d8794;--accent: #1f6feb;--accent-soft: rgba(31, 111, 235, .1);--ok: #1a7f37;--ok-soft: rgba(26, 127, 55, .1);--fail: #cf222e;--fail-soft: rgba(207, 34, 46, .1);--leak: #9a6700;--leak-soft: rgba(154, 103, 0, .12);--neutral: #656d76;--neutral-soft: rgba(101, 109, 118, .1);--hairline: inset 0 1px 0 rgba(255, 255, 255, .9);--hairline-strong: inset 0 1px 0 rgba(255, 255, 255, 1);--elev-1: 0 1px 1px rgba(16, 24, 40, .05);--elev-2: 0 1px 2px rgba(16, 24, 40, .06), 0 4px 12px -2px rgba(16, 24, 40, .07);--elev-3: 0 1px 2px rgba(16, 24, 40, .07), 0 10px 28px -6px rgba(16, 24, 40, .1);--elev-4: 0 2px 4px rgba(16, 24, 40, .07), 0 22px 56px -10px rgba(16, 24, 40, .14);--shadow: var(--elev-2);--hover: rgba(16, 24, 40, .035);--hover-strong: rgba(16, 24, 40, .06);--press: rgba(16, 24, 40, .07);--skel: linear-gradient(90deg, #e9edf2 0%, #f6f8fa 50%, #e9edf2 100%)}}:root[data-theme=light]{color-scheme:light;--bg: #f5f6f8;--bg-grad: radial-gradient(1100px 620px at 12% -12%, rgba(31, 111, 235, .07) 0%, transparent 70%), radial-gradient(900px 520px at 108% 8%, rgba(120, 80, 220, .045) 0%, transparent 68%);--panel: #ffffff;--panel-2: #f4f6f9;--sunk: #eef1f5;--line: #dfe3e9;--line-soft: #eaedf1;--fg: #14181e;--fg-dim: #57616f;--fg-mute: #7d8794;--accent: #1f6feb;--accent-soft: rgba(31, 111, 235, .1);--ok: #1a7f37;--ok-soft: rgba(26, 127, 55, .1);--fail: #cf222e;--fail-soft: rgba(207, 34, 46, .1);--leak: #9a6700;--leak-soft: rgba(154, 103, 0, .12);--neutral: #656d76;--neutral-soft: rgba(101, 109, 118, .1);--hairline: inset 0 1px 0 rgba(255, 255, 255, .9);--hairline-strong: inset 0 1px 0 rgba(255, 255, 255, 1);--elev-1: 0 1px 1px rgba(16, 24, 40, .05);--elev-2: 0 1px 2px rgba(16, 24, 40, .06), 0 4px 12px -2px rgba(16, 24, 40, .07);--elev-3: 0 1px 2px rgba(16, 24, 40, .07), 0 10px 28px -6px rgba(16, 24, 40, .1);--elev-4: 0 2px 4px rgba(16, 24, 40, .07), 0 22px 56px -10px rgba(16, 24, 40, .14);--shadow: var(--elev-2);--hover: rgba(16, 24, 40, .035);--hover-strong: rgba(16, 24, 40, .06);--press: rgba(16, 24, 40, .07);--skel: linear-gradient(90deg, #e9edf2 0%, #f6f8fa 50%, #e9edf2 100%)}:root{--t-xs: 12px;--t-sm: 13.5px;--t-md: 15px;--t-lg: 17px;--t-xl: 22px;--t-2xl: 28px;--t-3xl: 36px;--track-display: -.022em;--track-title: -.014em;--track-body: -.003em;--track-caps: .075em;--lh-tight: 1.15;--lh-body: 1.55;--sans: -apple-system, BlinkMacSystemFont, "Inter var", Inter, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;--mono: ui-monospace, SFMono-Regular, "JetBrains Mono", Menlo, Consolas, "Liberation Mono", monospace;--s1: 4px;--s2: 8px;--s3: 12px;--s4: 16px;--s5: 24px;--s6: 32px;--s7: 48px;--r0: 6px;--r1: 9px;--r2: 13px;--r3: 16px;--r4: 20px;--r-full: 999px;--control-h: 34px;--control-h-sm: 28px;--rail: 216px;--gap-shell: 12px;--measure: 1240px;--ring: 0 0 0 2px var(--bg), 0 0 0 4px color-mix(in srgb, var(--accent) 62%, transparent);--dur-fast: .11s;--dur: .17s;--dur-slow: .28s;--ease: cubic-bezier(.2, .7, .3, 1);--ease-spring: cubic-bezier(.22, 1.4, .36, 1);--stagger-step: 26ms}@media(prefers-reduced-motion:reduce){:root:not([data-motion=full]){--dur-fast: 0ms;--dur: 0ms;--dur-slow: 0ms;--stagger-step: 0ms}:root:not([data-motion=full]) *,:root:not([data-motion=full]) *:before,:root:not([data-motion=full]) *:after{animation-duration:1ms!important;animation-iteration-count:1!important;transition-duration:1ms!important;scroll-behavior:auto!important}:root:not([data-motion=full])::view-transition-old(root),:root:not([data-motion=full])::view-transition-new(root){animation:none!important}}:root[data-motion=none]{--dur-fast: 0ms;--dur: 0ms;--dur-slow: 0ms;--stagger-step: 0ms}:root[data-motion=none] *,:root[data-motion=none] *:before,:root[data-motion=none] *:after{animation-duration:1ms!important;animation-iteration-count:1!important;transition-duration:1ms!important;scroll-behavior:auto!important}:root[data-motion=none]::view-transition-old(root),:root[data-motion=none]::view-transition-new(root){animation:none!important}*,*:before,*:after{box-sizing:border-box}html,body,#app{height:100%}body{margin:0;background:var(--bg);background-image:var(--bg-grad);background-attachment:fixed;color:var(--fg);font:var(--t-md) / var(--lh-body) var(--sans);letter-spacing:var(--track-body);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-variant-numeric:tabular-nums;font-feature-settings:"cv05" 1;overflow-x:hidden}h1,h2,h3,p,ul,figure{margin:0}ul{padding:0;list-style:none}a{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}code,.mono{font-family:var(--mono);font-size:.92em}:focus-visible{outline:none;box-shadow:var(--ring);border-radius:var(--r1)}a:focus-visible{border-radius:var(--r0)}.skip{position:absolute;left:-9999px;top:0;z-index:100;padding:var(--s2) var(--s3);background:var(--panel);border:1px solid var(--line);border-radius:var(--r1)}.skip:focus{left:var(--s3);top:var(--s3)}.shell{display:grid;grid-template-columns:var(--rail) minmax(0,1fr);min-height:100%;padding:var(--gap-shell);gap:var(--gap-shell)}.shell.no-rail{grid-template-columns:minmax(0,1fr)}.shell.no-rail .view{max-width:none;min-height:100dvh;display:grid;place-items:center;padding:var(--s5)}.rail{border:1px solid var(--line);border-radius:var(--r4);background:color-mix(in srgb,var(--panel) 82%,transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);padding:var(--s4) var(--s3);position:sticky;top:var(--gap-shell);height:calc(100vh - var(--gap-shell) * 2);display:flex;flex-direction:column;gap:var(--s4);box-shadow:var(--shadow)}.brand{display:flex;align-items:center;gap:var(--s2);font-size:var(--t-lg);font-weight:650;letter-spacing:-.01em;color:var(--fg)}.brand:hover{text-decoration:none}.brand svg{color:var(--accent)}.rail nav{display:flex;flex-direction:column;gap:2px}.navlink{display:flex;align-items:center;gap:var(--s3);padding:var(--s2) var(--s3);border-radius:var(--r1);color:var(--fg-dim);font-weight:500;transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}.navlink:hover{background:var(--panel-2);color:var(--fg);text-decoration:none}.navlink.router-link-active{background:var(--accent-soft);color:var(--accent)}.navlink svg{flex:none}.navlink .count{margin-left:auto;font:600 var(--t-xs) / 1 var(--sans);font-variant-numeric:tabular-nums;color:var(--fg-mute);background:var(--panel-2);padding:3px 6px;border-radius:var(--r-full)}.rail .foot{margin-top:auto;font-size:var(--t-xs);color:var(--fg-mute);display:grid;gap:var(--s1);word-break:break-all}.rail .foot .foot-who{color:var(--fg-dim);font-weight:550;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.view{min-width:0;padding:var(--s3) var(--s4) var(--s7);max-width:none}@media(max-width:800px){.shell{grid-template-columns:minmax(0,1fr);padding:var(--gap-shell) var(--s2) 0}.rail{position:fixed;inset:auto var(--s2) calc(var(--s2) + env(safe-area-inset-bottom)) var(--s2);height:auto;flex-direction:row;align-items:center;gap:var(--s1);padding:var(--s2);background:color-mix(in srgb,var(--panel) 94%,transparent);z-index:20}.rail .brand,.rail .foot{display:none}.rail nav{flex-direction:row;flex:1;justify-content:space-around}.navlink{flex-direction:column;gap:2px;font-size:var(--t-xs);padding:var(--s1) var(--s2);min-width:56px;align-items:center}.navlink .count{display:none}.view{padding:var(--s4) var(--s4) calc(84px + env(safe-area-inset-bottom))}}.page-head{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;margin-bottom:var(--s5)}.page-head h1{font-size:var(--t-2xl);font-weight:640;letter-spacing:var(--track-display);line-height:var(--lh-tight)}.page-head .sub{color:var(--fg-dim);font-size:var(--t-sm);margin-top:2px}.grow{flex:1}h2.section{font-size:var(--t-xs);text-transform:uppercase;letter-spacing:var(--track-caps);color:var(--fg-dim);font-weight:620}h3{font-size:var(--t-md);font-weight:600}.dim{color:var(--fg-dim)}.mute{color:var(--fg-mute)}.nowrap{white-space:nowrap}.break{word-break:break-all}.panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--r3);padding:var(--s4) var(--s4) var(--s5);margin-bottom:var(--s4);min-width:0;container-type:inline-size;box-shadow:var(--hairline),var(--elev-2)}.panel.flush{padding:0;overflow:hidden}.panel>.phead{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;margin-bottom:var(--s3)}.panel.flush>.phead{padding:var(--s4) var(--s4) 0}.grid-2{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:var(--s4);align-items:start}.row{display:flex;gap:var(--s2);align-items:center;flex-wrap:wrap}button,.btn{font:530 var(--t-sm) / 1 var(--sans);letter-spacing:var(--track-body);color:var(--fg);background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r1);padding:var(--s2) var(--s3);min-height:var(--control-h);cursor:pointer;display:inline-flex;align-items:center;gap:var(--s2);position:relative;overflow:hidden;box-shadow:var(--hairline),var(--elev-1);transition:background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease)}button:hover:not(:disabled),.btn:hover:not(:disabled){border-color:color-mix(in srgb,var(--fg-mute) 60%,var(--line));background:color-mix(in srgb,var(--hover) 100%,var(--panel-2));text-decoration:none}button:active:not(:disabled){transform:translateY(1px);box-shadow:inset 0 2px 4px var(--press)}button:disabled{opacity:.45;cursor:not-allowed;box-shadow:none}button.primary{background:linear-gradient(180deg,color-mix(in srgb,var(--accent) 88%,#fff) 0%,var(--accent) 100%);border-color:color-mix(in srgb,var(--accent) 75%,#000);color:#fff;box-shadow:var(--hairline-strong),var(--elev-2),0 0 color-mix(in srgb,var(--accent) 40%,transparent)}button.primary:hover:not(:disabled){background:linear-gradient(180deg,color-mix(in srgb,var(--accent) 78%,#fff),color-mix(in srgb,var(--accent) 94%,#fff));border-color:color-mix(in srgb,var(--accent) 75%,#000);box-shadow:var(--hairline-strong),var(--elev-2),0 0 18px -2px color-mix(in srgb,var(--accent) 45%,transparent)}button.danger{background:var(--fail-soft);border-color:color-mix(in srgb,var(--fail) 45%,transparent);color:var(--fail)}button.danger:hover:not(:disabled){background:color-mix(in srgb,var(--fail) 26%,transparent);border-color:color-mix(in srgb,var(--fail) 62%,transparent)}button.ghost{background:transparent;box-shadow:none}button.ghost:hover:not(:disabled){background:var(--hover)}button.sm,.btn.sm{min-height:var(--control-h-sm);padding:var(--s1) var(--s2);font-size:var(--t-xs)}button.armed{background:var(--fail-soft);border-color:color-mix(in srgb,var(--fail) 70%,transparent);color:var(--fail);font-weight:600}button .progress{position:absolute;inset:auto 0 0 0;height:2px;background:currentColor;opacity:.65;animation:indeterminate 1.1s var(--ease) infinite;transform-origin:left}input[type=text],input[type=password],input[type=search],input[type=url],input[type=email],input[type=number],textarea,select{font:var(--t-sm) / 1.5 var(--sans);letter-spacing:var(--track-body);color:var(--fg);background:var(--sunk);border:1px solid var(--line);border-radius:var(--r1);padding:var(--s2) var(--s3);min-height:32px;width:100%;min-width:0;box-shadow:inset 0 1px 2px var(--press);transition:border-color var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease)}input[type=text]:hover,input[type=password]:hover,input[type=search]:hover,input[type=url]:hover,input[type=email]:hover,input[type=number]:hover,textarea:hover,select:hover{border-color:color-mix(in srgb,var(--fg-mute) 55%,var(--line))}input[type=text]:focus,input[type=password]:focus,input[type=search]:focus,input[type=url]:focus,input[type=email]:focus,input[type=number]:focus,textarea:focus,select:focus{outline:none;border-color:var(--accent);box-shadow:inset 0 1px 2px var(--press),0 0 0 3px color-mix(in srgb,var(--accent) 22%,transparent)}textarea{font-family:var(--mono);font-size:var(--t-sm);line-height:1.55;resize:vertical;white-space:pre;overflow-wrap:normal;overflow-x:auto}input::placeholder,textarea::placeholder{color:var(--fg-mute)}input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus{-webkit-box-shadow:0 0 0 1000px var(--sunk) inset;-webkit-text-fill-color:var(--fg);caret-color:var(--fg);transition:background-color 9999s ease-out}label{font-size:var(--t-sm);color:var(--fg-dim)}.field{display:grid;gap:var(--s2);min-width:0}.field+.field,.field+.hint,.hint+.field{margin-top:var(--s4)}.row>.field+.field,.row>.field+.hint,.row>.hint+.field,.phead>.field+.field,.phead>.field+.hint,.phead>.hint+.field{margin-top:0}.field.inline{display:flex;align-items:center;gap:var(--s2);margin-top:0}.field.inline>label{color:var(--fg-mute);font-size:var(--t-xs);white-space:nowrap}.phead>button,.phead>.btn,.phead>input,.phead>select,.phead>.check,.phead>.field>input,.phead>.field>select{min-height:var(--control-h)}.row.wrap>.field,.row>.field{align-self:stretch}.check{display:inline-flex;align-items:center;gap:var(--s2);cursor:pointer;color:var(--fg)}.check input{width:auto;min-height:0;accent-color:var(--accent)}.kv{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.4fr) auto;gap:var(--s2);margin-bottom:var(--s2);align-items:center;max-width:640px}.kv.head{font-size:var(--t-xs);color:var(--fg-mute);text-transform:uppercase;letter-spacing:.06em}@media(max-width:560px){.kv{grid-template-columns:minmax(0,1fr) auto}.kv.head{display:none}}.badge{display:inline-flex;align-items:center;gap:5px;font:500 var(--t-xs) / 1 var(--sans);padding:4px 8px;border-radius:var(--r-full);background:var(--neutral-soft);color:var(--fg-dim);border:1px solid transparent;white-space:nowrap}.badge.ok{background:var(--ok-soft);color:var(--ok)}.badge.failed,.badge.fail{background:var(--fail-soft);color:var(--fail)}.badge.leaked,.badge.warn{background:var(--leak-soft);color:var(--leak)}.badge.running,.badge.busy,.badge.info{background:var(--accent-soft);color:var(--accent)}.badge.unknown{background:var(--neutral-soft);color:var(--neutral)}.badge.shared{background:var(--leak-soft);color:var(--leak)}.badge.isolated{background:var(--accent-soft);color:var(--accent)}.badge.off{opacity:.38}.badge .dot{width:6px;height:6px;border-radius:var(--r-full);background:currentColor}.badge.running .dot,.dot.pulse{animation:pulse 1.6s var(--ease) infinite}.banner{border:1px solid var(--line);border-left-width:3px;border-radius:var(--r2);padding:var(--s3) var(--s4);margin:var(--s3) 0;background:var(--panel-2);font-size:var(--t-sm)}.banner b{color:var(--fg)}.banner p{margin-top:var(--s2);color:var(--fg-dim)}.banner.ok{border-left-color:var(--ok);background:var(--ok-soft)}.banner.failed{border-left-color:var(--fail);background:var(--fail-soft)}.banner.leaked,.banner.warn{border-left-color:var(--leak);background:var(--leak-soft)}.banner.info{border-left-color:var(--accent);background:var(--accent-soft)}.banner.plain{border-left-color:var(--fg-mute)}.hint{font-size:var(--t-sm);color:var(--fg-mute);margin-top:var(--s3)}.hint code,.banner code{background:var(--sunk);padding:1px 5px;border-radius:var(--r0)}table{width:100%;border-collapse:collapse;font-size:var(--t-sm)}th{text-align:left;font:620 var(--t-xs) / 1 var(--sans);text-transform:uppercase;letter-spacing:var(--track-caps);color:var(--fg-mute);padding:var(--s2) var(--s3);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:1;background:var(--panel);white-space:nowrap}td{padding:var(--s2) var(--s3);border-bottom:1px solid var(--line-soft);vertical-align:middle}tbody tr{transition:background var(--dur-fast) var(--ease)}tbody tr:hover{background:var(--hover)}tbody tr:last-child td{border-bottom:none}td.name{font-weight:600;word-break:break-all}@container (max-width: 460px){table.cards,table.cards tbody,table.cards tr,table.cards td{display:block;width:100%}table.cards thead{display:none}table.cards tr{border:1px solid var(--line);border-radius:var(--r2);padding:var(--s2) var(--s3);margin-bottom:var(--s2);background:var(--panel-2)}table.cards td{display:flex;justify-content:space-between;align-items:baseline;gap:var(--s3);border:0;padding:var(--s1) 0;text-align:right}table.cards td:before{content:attr(data-label);font:600 var(--t-xs) / 1.6 var(--sans);text-transform:uppercase;letter-spacing:.06em;color:var(--fg-mute);text-align:left;flex:none}table.cards td[colspan]{text-align:left}table.cards td[colspan]:before,table.cards td[data-label=""]:before{content:""}table.cards td[data-label=""]{justify-content:flex-end}}@container (min-width: 461px){.panel>table,.table-scroll{display:block;max-width:100%;overflow-x:auto}.panel>table>thead,.panel>table>tbody{display:table;width:100%;table-layout:auto}}.row-actions{text-align:end;white-space:nowrap}.row-actions>*+*{margin-inline-start:var(--s1)}.logs-split{display:grid;grid-template-columns:232px minmax(0,1fr);gap:var(--s4);align-items:start}@container (max-width: 720px){.logs-split{grid-template-columns:minmax(0,1fr)}.clist{max-height:220px}}.clist{display:flex;flex-direction:column;gap:2px;max-height:60vh;overflow-y:auto;padding-inline-end:var(--s1)}.clist-item{display:grid;gap:2px;text-align:start;justify-items:start;padding:var(--s2) var(--s3);min-height:0;background:transparent;border:1px solid transparent;box-shadow:none;width:100%}.clist-item:hover:not(:disabled){background:var(--hover);border-color:var(--line-soft)}.clist-item.on{background:var(--panel-2);border-color:var(--line);box-shadow:var(--hairline)}.clist-name{display:inline-flex;align-items:center;gap:var(--s2);font-weight:560}.clist-sub{font-size:var(--t-xs);color:var(--fg-mute);max-width:100%;overflow:hidden;text-overflow:ellipsis}.clist-state{font-size:var(--t-xs)}.logs-main{min-width:0}.lv-time{flex:none;color:var(--fg-mute);font-variant-numeric:tabular-nums;white-space:nowrap}.panel.banner-panel{border-color:color-mix(in srgb,var(--warn) 40%,var(--line));background:color-mix(in srgb,var(--warn) 8%,var(--panel))}.kvlist{display:grid;gap:1px;background:var(--line-soft);border-radius:var(--r2);overflow:hidden}.kvlist>li{display:flex;gap:var(--s3);padding:var(--s3);background:var(--panel);align-items:baseline;flex-wrap:wrap}.kvlist>li>.k{flex:none;width:128px;color:var(--fg-dim);font-size:var(--t-sm)}.kvlist>li>.v{flex:1;min-width:0;word-break:break-word}@media(max-width:480px){.kvlist>li>.k{width:100%}}pre.raw,pre.log{font-family:var(--mono);font-size:var(--t-sm);line-height:1.6;background:var(--sunk);border:1px solid var(--line);border-radius:var(--r2);padding:var(--s3);margin:var(--s3) 0 0;overflow:auto;white-space:pre}pre.raw{color:var(--fail);max-height:420px}pre.code{font-family:var(--mono);font-size:var(--t-sm);line-height:1.6;background:var(--sunk);border:1px solid var(--line);border-radius:var(--r2);padding:var(--s3);margin:0;max-height:520px;overflow:auto;white-space:pre;color:var(--fg-dim)}pre.log{max-height:460px;color:var(--fg-dim)}pre.log .t{color:var(--fg-mute)}pre.log .lv-error{color:var(--fail)}pre.log .lv-warn{color:var(--leak)}pre.log .lv-info{color:var(--fg)}pre.log mark{background:var(--leak-soft);color:var(--leak)}.masked{color:var(--fg-mute);letter-spacing:.12em}.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s2)}@container (min-width: 680px){.stats{grid-template-columns:repeat(6,1fr)}}.stat{background:var(--panel-2);border:1px solid var(--line-soft);border-radius:var(--r2);padding:var(--s3);box-shadow:var(--hairline);min-width:0}.stat .v{font:600 var(--t-2xl) / 1.1 var(--sans);letter-spacing:var(--track-display);font-variant-numeric:tabular-nums}.stat[data-zero=true] .v{color:var(--fg-mute);font-weight:500}.stat .k{font-size:var(--t-xs);color:var(--fg-mute);text-transform:uppercase;letter-spacing:.04em;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.stat.unknown .v{color:var(--neutral)}.stat.busy .v{color:var(--accent)}.stat.leak .v{color:var(--leak)}.tabs{display:flex;gap:var(--s1);border-bottom:1px solid var(--line);margin-bottom:var(--s4);overflow-x:auto;scrollbar-width:none}.tabs::-webkit-scrollbar{display:none}.tabs a{padding:var(--s2) var(--s3);color:var(--fg-dim);font-size:var(--t-sm);font-weight:500;border-bottom:2px solid transparent;margin-bottom:-1px;white-space:nowrap;transition:color var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)}.tabs a:hover{color:var(--fg);text-decoration:none}.tabs a.router-link-active{color:var(--fg);border-bottom-color:var(--accent)}.steps{display:grid;gap:1px;background:var(--line-soft);border-radius:var(--r2);overflow:hidden}.step{display:grid;grid-template-columns:24px minmax(0,1fr);gap:var(--s3);padding:var(--s3);background:var(--panel);align-items:start}.step .mark{font:600 var(--t-lg) / 1.2 var(--sans);text-align:center}.step .who{font-weight:550;word-break:break-all}.step .msg{font-size:var(--t-sm);color:var(--fg-dim);word-break:break-word}.s-ok{color:var(--ok)}.s-failed{color:var(--fail)}.s-leaked{color:var(--leak)}.s-unverifiable{color:var(--neutral)}.skel{background:var(--skel);background-size:200% 100%;border-radius:var(--r1);height:14px;animation:shimmer 1.3s linear infinite}.skel+.skel{margin-top:var(--s2)}.skel.tall{height:44px}.skel.w60{width:60%}.skel.w40{width:40%}@keyframes shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}@keyframes pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.35;transform:scale(.8)}}@keyframes indeterminate{0%{transform:scaleX(0)}50%{transform:scaleX(.7)}to{transform:scaleX(0);transform-origin:right}}@keyframes rise{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}@keyframes land{0%{transform:scale(.985);opacity:.4}60%{transform:scale(1.004)}to{transform:none;opacity:1}}.stagger>*{animation:rise var(--dur) var(--ease) backwards;animation-delay:calc(var(--i, 0) * var(--stagger-step))}.land{animation:land var(--dur-slow) var(--ease)}.view-enter-active,.view-leave-active{transition:opacity var(--dur) var(--ease),transform var(--dur) var(--ease)}.view-enter-from{opacity:0;transform:translateY(6px)}.view-leave-to{opacity:0;transform:translateY(-4px)}.toasts{position:fixed;right:var(--s4);bottom:var(--s4);z-index:50;display:grid;gap:var(--s2);width:min(360px,calc(100vw - var(--s5)))}@media(max-width:800px){.toasts{bottom:calc(84px + env(safe-area-inset-bottom))}}.toast{display:flex;gap:var(--s3);align-items:flex-start;background:var(--panel);border:1px solid var(--line);border-radius:var(--r2);padding:var(--s3) var(--s3) var(--s3) var(--s2);box-shadow:var(--hairline),var(--elev-4);font-size:var(--t-sm);position:relative}.toast:before{content:"";flex:none;width:8px;height:8px;margin:6px 0 0 var(--s2);border-radius:var(--r-full);background:var(--neutral);box-shadow:0 0 0 3px var(--neutral-soft)}.toast.ok:before{background:var(--ok);box-shadow:0 0 0 3px var(--ok-soft)}.toast.error:before{background:var(--fail);box-shadow:0 0 0 3px var(--fail-soft)}.toast.warn:before{background:var(--leak);box-shadow:0 0 0 3px var(--leak-soft)}.toast.info:before{background:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}.toast .x{margin-left:auto;background:none;border:0;min-height:0;padding:2px 6px;color:var(--fg-mute)}.toast-enter-active,.toast-leave-active{transition:opacity var(--dur) var(--ease),transform var(--dur) var(--ease)}.toast-enter-from,.toast-leave-to{opacity:0;transform:translate(12px)}.toast-move{transition:transform var(--dur) var(--ease)}.scrim{position:fixed;top:0;right:0;bottom:0;left:0;background:#0000008c;z-index:60;display:grid;place-items:center;padding:var(--s4)}.sheet{background:var(--panel);border:1px solid var(--line);border-radius:var(--r3);box-shadow:var(--shadow);padding:var(--s5);width:min(460px,100%);max-height:80vh;overflow:auto}.sheet dl{display:grid;grid-template-columns:auto minmax(0,1fr);gap:var(--s2) var(--s4);margin:var(--s4) 0 0;align-items:baseline}.sheet dt{text-align:right}.sheet dd{margin:0;color:var(--fg-dim);font-size:var(--t-sm)}kbd{font:500 var(--t-xs) / 1 var(--mono);background:var(--sunk);border:1px solid var(--line);border-bottom-width:2px;border-radius:var(--r0);padding:4px 6px;color:var(--fg)}.fade-enter-active,.fade-leave-active{transition:opacity var(--dur) var(--ease)}.fade-enter-from,.fade-leave-to{opacity:0}.hint-wrap{position:relative;display:inline-flex;vertical-align:middle;margin-inline-start:var(--s1)}.hint-btn{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;min-height:0;padding:0;border:0;border-radius:var(--r-full);background:none;color:var(--fg-mute);cursor:pointer;transition:color var(--dur-fast) var(--ease),background var(--dur-fast) var(--ease)}.hint-btn:hover,.hint-btn.on{color:var(--accent);background:var(--accent-soft)}.hint-bub{position:absolute;z-index:40;width:max-content;max-width:min(300px,74vw);padding:var(--s2) var(--s3);background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r2);box-shadow:var(--shadow);color:var(--fg-dim);font:400 var(--t-sm) / 1.5 var(--sans);text-transform:none;letter-spacing:normal;white-space:normal;text-align:start;pointer-events:none}.hint-bub.below{top:calc(100% + 6px)}.hint-bub.above{bottom:calc(100% + 6px)}.hint-bub.to-start{inset-inline-start:-2px}.hint-bub.to-end{inset-inline-end:-2px}.hint-bub code{color:var(--fg)}.hint-enter-active,.hint-leave-active{transition:opacity var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease)}.hint-enter-from,.hint-leave-to{opacity:0}.hint-bub.below.hint-enter-from,.hint-bub.below.hint-leave-to{transform:translateY(-3px)}.hint-bub.above.hint-enter-from,.hint-bub.above.hint-leave-to{transform:translateY(3px)}.palette-scrim{align-items:flex-start;padding-top:12vh}.palette{width:min(620px,calc(100vw - var(--s5)));background:var(--panel);border:1px solid var(--line);border-radius:var(--r3);box-shadow:var(--hairline-strong),var(--elev-4);overflow:hidden;display:flex;flex-direction:column;max-height:min(60vh,560px)}.palette-q{display:flex;align-items:center;gap:var(--s3);padding:var(--s3) var(--s4);border-bottom:1px solid var(--line-soft);color:var(--fg-mute)}.palette-q input{flex:1;background:none;border:none;box-shadow:none;padding:0;min-height:26px;font-size:var(--t-lg);letter-spacing:var(--track-title);color:var(--fg)}.palette-q input:focus{outline:none;border:none;box-shadow:none}.palette-list{overflow-y:auto;padding:var(--s2);min-height:0}.palette-group{font-size:var(--t-xs);text-transform:uppercase;letter-spacing:var(--track-caps);color:var(--fg-mute);padding:var(--s3) var(--s2) var(--s1)}.palette-row{display:flex;align-items:center;gap:var(--s3);width:100%;text-align:left;background:none;border:none;box-shadow:none;border-radius:var(--r1);padding:var(--s2) var(--s3);min-height:34px;color:var(--fg)}.palette-row[data-on=true]{background:var(--accent-soft);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--accent) 32%,transparent)}.palette-label{font-weight:520}.palette-hint{margin-left:auto;color:var(--fg-mute);font-size:var(--t-xs);font-family:var(--mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:45%}.palette-empty{color:var(--fg-mute);padding:var(--s5) var(--s3);text-align:center;font-size:var(--t-sm)}.palette-foot{display:flex;gap:var(--s4);align-items:center;padding:var(--s2) var(--s4);border-top:1px solid var(--line-soft);background:var(--panel-2);color:var(--fg-mute);font-size:var(--t-xs)}kbd{font:500 11px / 1 var(--mono);color:var(--fg-dim);background:var(--sunk);border:1px solid var(--line);border-radius:var(--r0);padding:3px 5px;margin-right:3px}.fade-enter-active .palette{animation:palette-in var(--dur-slow) var(--ease-spring)}@keyframes palette-in{0%{opacity:0;transform:translateY(-10px) scale(.98)}to{opacity:1;transform:none}}::view-transition-old(root),::view-transition-new(root){animation-duration:var(--dur);animation-timing-function:var(--ease)}::view-transition-old(root){animation-name:vt-out}::view-transition-new(root){animation-name:vt-in}@keyframes vt-out{to{opacity:0}}@keyframes vt-in{0%{opacity:0;transform:translateY(4px)}}.searchbox{display:flex;align-items:center;gap:var(--s2);flex:1;min-width:180px;padding-inline:var(--s3);background:var(--sunk);border:1px solid var(--line);border-radius:var(--r1);box-shadow:inset 0 1px 2px var(--press);color:var(--fg-mute);min-height:34px;transition:border-color var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease)}.searchbox:focus-within{border-color:var(--accent);box-shadow:inset 0 1px 2px var(--press),0 0 0 3px color-mix(in srgb,var(--accent) 22%,transparent)}.searchbox input{border:none;background:none;box-shadow:none;padding:0;min-height:0}.searchbox input:focus{outline:none;border:none;box-shadow:none}.searchbox input::-webkit-search-cancel-button{-webkit-appearance:none;-moz-appearance:none;appearance:none}select.compact{width:auto;min-height:34px;padding-inline-end:var(--s5)}.phead>.check{min-height:34px}.field>.selm-trigger,.selm-trigger{max-width:340px;width:100%}.selm-trigger{display:inline-flex;align-items:center;gap:var(--s2);justify-content:space-between;min-height:34px;padding:0 var(--s2) 0 var(--s3);background:var(--sunk);border:1px solid var(--line);border-radius:var(--r1);box-shadow:inset 0 1px 2px var(--press);font:var(--t-sm) / 1 var(--sans);color:var(--fg);cursor:pointer}.selm-trigger:hover:not(:disabled){border-color:color-mix(in srgb,var(--fg-mute) 55%,var(--line))}.selm-trigger[data-state=open]{border-color:var(--accent);box-shadow:inset 0 1px 2px var(--press),0 0 0 3px color-mix(in srgb,var(--accent) 22%,transparent)}.selm-value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.selm-caret{flex:none;color:var(--fg-mute);transition:transform var(--dur-fast) var(--ease)}.selm-trigger[data-state=open] .selm-caret{transform:rotate(180deg)}.selm-list{z-index:61;padding:var(--s1);max-height:280px;overflow-y:auto;background:var(--panel);border:1px solid var(--line);border-radius:var(--r2);box-shadow:var(--hairline-strong),var(--elev-4);min-width:var(--reka-select-trigger-width);animation:palette-in var(--dur) var(--ease-spring)}.selm-opt{display:flex;align-items:center;gap:var(--s2);padding:var(--s2);min-height:30px;border-radius:calc(var(--r1) - 2px);font-size:var(--t-sm);cursor:pointer;white-space:nowrap;-webkit-user-select:none;user-select:none}.selm-opt[data-highlighted]{background:var(--accent-soft);outline:none}.selm-opt[data-disabled]{opacity:.45;cursor:not-allowed}.selm-hint{color:var(--fg-mute);font-size:var(--t-xs);margin-inline-start:auto}.selm-tick{margin-inline-start:auto;color:var(--accent);display:inline-flex}.selm-hint+.selm-tick{margin-inline-start:var(--s2)}input[type=checkbox],input[type=radio]{-moz-appearance:none;appearance:none;-webkit-appearance:none;flex:none;width:17px;height:17px;margin:0;border:1px solid color-mix(in srgb,var(--fg-mute) 60%,var(--line));background:var(--sunk);box-shadow:inset 0 1px 2px var(--press);cursor:pointer;display:grid;place-content:center;transition:background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)}input[type=checkbox]{border-radius:var(--r0)}input[type=radio]{border-radius:var(--r-full)}input[type=checkbox]:hover:not(:disabled),input[type=radio]:hover:not(:disabled){border-color:var(--accent)}input[type=checkbox]:before,input[type=radio]:before{content:"";transform:scale(0);transition:transform var(--dur-fast) var(--ease-spring)}input[type=checkbox]:before{width:11px;height:11px;background:#fff;clip-path:polygon(14% 47%,0 61%,40% 100%,100% 22%,85% 9%,39% 71%)}input[type=radio]:before{width:7px;height:7px;border-radius:var(--r-full);background:#fff}input[type=checkbox]:checked,input[type=radio]:checked{background:var(--accent);border-color:var(--accent)}input[type=checkbox]:checked:before,input[type=radio]:checked:before{transform:scale(1)}input[type=checkbox]:disabled,input[type=radio]:disabled{opacity:.45;cursor:not-allowed}.helpq{display:inline-grid;place-items:center;width:18px;height:18px;padding:0;min-height:0;border-radius:var(--r-full);border:1px solid var(--line);background:var(--panel-2);box-shadow:none;color:var(--fg-mute);cursor:pointer;vertical-align:middle}.helpq:hover{color:var(--accent);border-color:var(--accent);background:var(--accent-soft)}.help-scrim{-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:70}.help-modal{position:fixed;z-index:71;top:50%;left:50%;transform:translate(-50%,-50%);width:min(620px,calc(100vw - var(--s5)));max-height:min(80vh,720px);display:flex;flex-direction:column;background:var(--panel);border:1px solid var(--line);border-radius:var(--r3);box-shadow:var(--hairline-strong),var(--elev-4);animation:help-in var(--dur-slow) var(--ease-spring)}@keyframes help-in{0%{opacity:0;transform:translate(-50%,-46%) scale(.97)}}.help-head{display:flex;align-items:center;gap:var(--s3);padding:var(--s4) var(--s4) var(--s3);border-bottom:1px solid var(--line-soft)}.help-title{font-size:var(--t-lg);font-weight:620;letter-spacing:var(--track-title);margin:0;flex:1}.help-body{padding:var(--s4);overflow-y:auto;color:var(--fg-dim);font-size:var(--t-sm);line-height:var(--lh-body)}.help-body>*+*{margin-top:var(--s3)}.help-body b,.help-body strong{color:var(--fg)}.check-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:var(--s2) var(--s4);margin-top:var(--s2)}.check-grid .check{min-height:26px}.settings-form .field input,.settings-form input[type=url],.settings-form input[type=password],.settings-form input[type=text]{max-width:560px}.settings-form .hint,.settings-form .mute.hint{max-width:640px}.lv{border:1px solid var(--line);border-radius:var(--r2);background:var(--sunk);overflow:hidden}.lv-bar{display:flex;align-items:center;gap:var(--s2);padding:var(--s2) var(--s3);border-bottom:1px solid var(--line-soft);font-size:var(--t-xs);color:var(--fg-mute)}.lv-box{max-height:520px;overflow-y:auto;padding:var(--s2) 0 var(--s3);font:var(--t-sm) / 1.6 var(--mono);overscroll-behavior:contain}.lv-empty{color:var(--fg-mute);padding:var(--s4) var(--s3);font-family:var(--sans)}.lv-row{display:grid;grid-template-columns:auto minmax(0,1fr);gap:0 var(--s3);padding:1px var(--s3);content-visibility:auto;contain-intrinsic-block-size:auto 22px}.lv-row:hover{background:var(--hover)}.lv-gutter{white-space:nowrap;color:var(--fg-mute);-webkit-user-select:none;user-select:none;font-variant-numeric:tabular-nums}.lv-msg{white-space:pre-wrap;overflow-wrap:anywhere;color:var(--fg-dim)}.lv-row.error .lv-msg{color:var(--fail)}.lv-row.warn .lv-msg{color:var(--leak)}.lv-row.ok .lv-msg{color:var(--ok)}.lv-row.svc-0 .lv-gutter{color:#7aa2f7}.lv-row.svc-1 .lv-gutter{color:#9ece6a}.lv-row.svc-2 .lv-gutter{color:#e0af68}.lv-row.svc-3 .lv-gutter{color:#bb9af7}.lv-row.svc-4 .lv-gutter{color:#7dcfff}.lv-row.svc-5 .lv-gutter{color:#f7768e}.lv-sep{display:flex;align-items:center;gap:var(--s3);padding:var(--s2) var(--s3);color:var(--fg-mute);font-family:var(--sans);font-size:var(--t-xs)}.lv-sep:before,.lv-sep:after{content:"";flex:1;border-top:1px solid var(--line-soft)}
1
+ :root,:root[data-theme=dark]{color-scheme:dark;--bg: #0e1116;--bg-grad: radial-gradient(1100px 620px at 12% -12%, rgba(64, 106, 168, .22) 0%, transparent 70%), radial-gradient(900px 520px at 108% 8%, rgba(96, 76, 168, .13) 0%, transparent 68%);--panel: #171b22;--panel-2: #1e232c;--sunk: #11141a;--line: #2b323d;--line-soft: #21262f;--fg: #eef2f8;--fg-dim: #a4afbe;--fg-mute: #78838f;--accent: #4a9dff;--accent-soft: rgba(74, 157, 255, .18);--ok: #35d17e;--ok-soft: rgba(53, 209, 126, .17);--fail: #ff6159;--fail-soft: rgba(255, 97, 89, .17);--leak: #ffa62b;--leak-soft: rgba(255, 166, 43, .18);--neutral: #95a2b3;--neutral-soft: rgba(149, 162, 179, .16);--hairline: inset 0 1px 0 rgba(255, 255, 255, .055);--hairline-strong: inset 0 1px 0 rgba(255, 255, 255, .09);--elev-1: 0 1px 2px rgba(5, 8, 14, .5);--elev-2: 0 1px 2px rgba(5, 8, 14, .45), 0 6px 16px -4px rgba(5, 8, 14, .5);--elev-3: 0 1px 2px rgba(5, 8, 14, .5), 0 12px 32px -8px rgba(5, 8, 14, .62);--elev-4: 0 2px 4px rgba(5, 8, 14, .5), 0 24px 64px -12px rgba(5, 8, 14, .72);--shadow: var(--elev-2);--hover: rgba(255, 255, 255, .04);--hover-strong: rgba(255, 255, 255, .07);--press: rgba(0, 0, 0, .18);--skel: linear-gradient(90deg, #1c212a 0%, #262d38 50%, #1c212a 100%)}@media(prefers-color-scheme:light){:root:not([data-theme=dark]){color-scheme:light;--bg: #f5f6f8;--bg-grad: radial-gradient(1100px 620px at 12% -12%, rgba(31, 111, 235, .07) 0%, transparent 70%), radial-gradient(900px 520px at 108% 8%, rgba(120, 80, 220, .045) 0%, transparent 68%);--panel: #ffffff;--panel-2: #f4f6f9;--sunk: #eef1f5;--line: #dfe3e9;--line-soft: #eaedf1;--fg: #14181e;--fg-dim: #57616f;--fg-mute: #7d8794;--accent: #1f6feb;--accent-soft: rgba(31, 111, 235, .1);--ok: #1a7f37;--ok-soft: rgba(26, 127, 55, .1);--fail: #cf222e;--fail-soft: rgba(207, 34, 46, .1);--leak: #9a6700;--leak-soft: rgba(154, 103, 0, .12);--neutral: #656d76;--neutral-soft: rgba(101, 109, 118, .1);--hairline: inset 0 1px 0 rgba(255, 255, 255, .9);--hairline-strong: inset 0 1px 0 rgba(255, 255, 255, 1);--elev-1: 0 1px 1px rgba(16, 24, 40, .05);--elev-2: 0 1px 2px rgba(16, 24, 40, .06), 0 4px 12px -2px rgba(16, 24, 40, .07);--elev-3: 0 1px 2px rgba(16, 24, 40, .07), 0 10px 28px -6px rgba(16, 24, 40, .1);--elev-4: 0 2px 4px rgba(16, 24, 40, .07), 0 22px 56px -10px rgba(16, 24, 40, .14);--shadow: var(--elev-2);--hover: rgba(16, 24, 40, .035);--hover-strong: rgba(16, 24, 40, .06);--press: rgba(16, 24, 40, .07);--skel: linear-gradient(90deg, #e9edf2 0%, #f6f8fa 50%, #e9edf2 100%)}}:root[data-theme=light]{color-scheme:light;--bg: #f5f6f8;--bg-grad: radial-gradient(1100px 620px at 12% -12%, rgba(31, 111, 235, .07) 0%, transparent 70%), radial-gradient(900px 520px at 108% 8%, rgba(120, 80, 220, .045) 0%, transparent 68%);--panel: #ffffff;--panel-2: #f4f6f9;--sunk: #eef1f5;--line: #dfe3e9;--line-soft: #eaedf1;--fg: #14181e;--fg-dim: #57616f;--fg-mute: #7d8794;--accent: #1f6feb;--accent-soft: rgba(31, 111, 235, .1);--ok: #1a7f37;--ok-soft: rgba(26, 127, 55, .1);--fail: #cf222e;--fail-soft: rgba(207, 34, 46, .1);--leak: #9a6700;--leak-soft: rgba(154, 103, 0, .12);--neutral: #656d76;--neutral-soft: rgba(101, 109, 118, .1);--hairline: inset 0 1px 0 rgba(255, 255, 255, .9);--hairline-strong: inset 0 1px 0 rgba(255, 255, 255, 1);--elev-1: 0 1px 1px rgba(16, 24, 40, .05);--elev-2: 0 1px 2px rgba(16, 24, 40, .06), 0 4px 12px -2px rgba(16, 24, 40, .07);--elev-3: 0 1px 2px rgba(16, 24, 40, .07), 0 10px 28px -6px rgba(16, 24, 40, .1);--elev-4: 0 2px 4px rgba(16, 24, 40, .07), 0 22px 56px -10px rgba(16, 24, 40, .14);--shadow: var(--elev-2);--hover: rgba(16, 24, 40, .035);--hover-strong: rgba(16, 24, 40, .06);--press: rgba(16, 24, 40, .07);--skel: linear-gradient(90deg, #e9edf2 0%, #f6f8fa 50%, #e9edf2 100%)}:root{--t-xs: 12px;--t-sm: 13.5px;--t-md: 15px;--t-lg: 17px;--t-xl: 22px;--t-2xl: 28px;--t-3xl: 36px;--track-display: -.022em;--track-title: -.014em;--track-body: -.003em;--track-caps: .075em;--lh-tight: 1.15;--lh-body: 1.55;--sans: -apple-system, BlinkMacSystemFont, "Inter var", Inter, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;--mono: ui-monospace, SFMono-Regular, "JetBrains Mono", Menlo, Consolas, "Liberation Mono", monospace;--s1: 4px;--s2: 8px;--s3: 12px;--s4: 16px;--s5: 24px;--s6: 32px;--s7: 48px;--r0: 6px;--r1: 9px;--r2: 13px;--r3: 16px;--r4: 20px;--r-full: 999px;--control-h: 34px;--control-h-sm: 28px;--rail: 216px;--gap-shell: 12px;--measure: 1240px;--ring: 0 0 0 2px var(--bg), 0 0 0 4px color-mix(in srgb, var(--accent) 62%, transparent);--dur-fast: .11s;--dur: .17s;--dur-slow: .28s;--ease: cubic-bezier(.2, .7, .3, 1);--ease-spring: cubic-bezier(.22, 1.4, .36, 1);--stagger-step: 26ms}@media(prefers-reduced-motion:reduce){:root:not([data-motion=full]){--dur-fast: 0ms;--dur: 0ms;--dur-slow: 0ms;--stagger-step: 0ms}:root:not([data-motion=full]) *,:root:not([data-motion=full]) *:before,:root:not([data-motion=full]) *:after{animation-duration:1ms!important;animation-iteration-count:1!important;transition-duration:1ms!important;scroll-behavior:auto!important}:root:not([data-motion=full])::view-transition-old(root),:root:not([data-motion=full])::view-transition-new(root){animation:none!important}}:root[data-motion=none]{--dur-fast: 0ms;--dur: 0ms;--dur-slow: 0ms;--stagger-step: 0ms}:root[data-motion=none] *,:root[data-motion=none] *:before,:root[data-motion=none] *:after{animation-duration:1ms!important;animation-iteration-count:1!important;transition-duration:1ms!important;scroll-behavior:auto!important}:root[data-motion=none]::view-transition-old(root),:root[data-motion=none]::view-transition-new(root){animation:none!important}*,*:before,*:after{box-sizing:border-box}html,body,#app{height:100%}body{margin:0;background:var(--bg);background-image:var(--bg-grad);background-attachment:fixed;color:var(--fg);font:var(--t-md) / var(--lh-body) var(--sans);letter-spacing:var(--track-body);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-variant-numeric:tabular-nums;font-feature-settings:"cv05" 1;overflow-x:hidden}h1,h2,h3,p,ul,figure{margin:0}ul{padding:0;list-style:none}a{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}code,.mono{font-family:var(--mono);font-size:.92em}:focus-visible{outline:none;box-shadow:var(--ring);border-radius:var(--r1)}a:focus-visible{border-radius:var(--r0)}.skip{position:absolute;left:-9999px;top:0;z-index:100;padding:var(--s2) var(--s3);background:var(--panel);border:1px solid var(--line);border-radius:var(--r1)}.skip:focus{left:var(--s3);top:var(--s3)}.shell{display:grid;grid-template-columns:var(--rail) minmax(0,1fr);min-height:100%;padding:var(--gap-shell);gap:var(--gap-shell)}.shell.no-rail{grid-template-columns:minmax(0,1fr)}.shell.no-rail .view{max-width:none;min-height:100dvh;display:grid;place-items:center;padding:var(--s5)}.rail{border:1px solid var(--line);border-radius:var(--r4);background:color-mix(in srgb,var(--panel) 82%,transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);padding:var(--s4) var(--s3);position:sticky;top:var(--gap-shell);height:calc(100vh - var(--gap-shell) * 2);display:flex;flex-direction:column;gap:var(--s4);box-shadow:var(--shadow)}.brand{display:flex;align-items:center;gap:var(--s2);font-size:var(--t-lg);font-weight:650;letter-spacing:-.01em;color:var(--fg)}.brand:hover{text-decoration:none}.brand svg{color:var(--accent)}.rail nav{display:flex;flex-direction:column;gap:2px}.navlink{display:flex;align-items:center;gap:var(--s3);padding:var(--s2) var(--s3);border-radius:var(--r1);color:var(--fg-dim);font-weight:500;transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}.navlink:hover{background:var(--panel-2);color:var(--fg);text-decoration:none}.navlink.router-link-active{background:var(--accent-soft);color:var(--accent)}.navlink svg{flex:none}.navlink .count{margin-left:auto;font:600 var(--t-xs) / 1 var(--sans);font-variant-numeric:tabular-nums;color:var(--fg-mute);background:var(--panel-2);padding:3px 6px;border-radius:var(--r-full)}.rail .foot{margin-top:auto;font-size:var(--t-xs);color:var(--fg-mute);display:grid;gap:var(--s1);word-break:break-all}.rail .foot .foot-who{color:var(--fg-dim);font-weight:550;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.view{min-width:0;padding:var(--s3) var(--s4) var(--s7);max-width:none}@media(max-width:800px){.shell{grid-template-columns:minmax(0,1fr);padding:var(--gap-shell) var(--s2) 0}.rail{position:fixed;inset:auto var(--s2) calc(var(--s2) + env(safe-area-inset-bottom)) var(--s2);height:auto;flex-direction:row;align-items:center;gap:var(--s1);padding:var(--s2);background:color-mix(in srgb,var(--panel) 94%,transparent);z-index:20}.rail .brand,.rail .foot{display:none}.rail nav{flex-direction:row;flex:1;justify-content:space-around}.navlink{flex-direction:column;gap:2px;font-size:var(--t-xs);padding:var(--s1) var(--s2);min-width:56px;align-items:center}.navlink .count{display:none}.view{padding:var(--s4) var(--s4) calc(84px + env(safe-area-inset-bottom))}}.page-head{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;margin-bottom:var(--s5)}.page-head h1{font-size:var(--t-2xl);font-weight:640;letter-spacing:var(--track-display);line-height:var(--lh-tight)}.page-head .sub{color:var(--fg-dim);font-size:var(--t-sm);margin-top:2px}.grow{flex:1}h2.section{font-size:var(--t-xs);text-transform:uppercase;letter-spacing:var(--track-caps);color:var(--fg-dim);font-weight:620}h3{font-size:var(--t-md);font-weight:600}.dim{color:var(--fg-dim)}.mute{color:var(--fg-mute)}.nowrap{white-space:nowrap}.break{word-break:break-all}.panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--r3);padding:var(--s4) var(--s4) var(--s5);margin-bottom:var(--s4);min-width:0;container-type:inline-size;box-shadow:var(--hairline),var(--elev-2)}.panel.flush{padding:0;overflow:hidden}.panel>.phead{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;margin-bottom:var(--s3)}.panel.flush>.phead{padding:var(--s4) var(--s4) 0}.grid-2{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:var(--s4);align-items:start}.row{display:flex;gap:var(--s2);align-items:center;flex-wrap:wrap}button,.btn{font:530 var(--t-sm) / 1 var(--sans);letter-spacing:var(--track-body);color:var(--fg);background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r1);padding:var(--s2) var(--s3);min-height:var(--control-h);cursor:pointer;display:inline-flex;align-items:center;gap:var(--s2);position:relative;overflow:hidden;box-shadow:var(--hairline),var(--elev-1);transition:background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease)}button:hover:not(:disabled),.btn:hover:not(:disabled){border-color:color-mix(in srgb,var(--fg-mute) 60%,var(--line));background:color-mix(in srgb,var(--hover) 100%,var(--panel-2));text-decoration:none}button:active:not(:disabled){transform:translateY(1px);box-shadow:inset 0 2px 4px var(--press)}button:disabled{opacity:.45;cursor:not-allowed;box-shadow:none}button.primary{background:linear-gradient(180deg,color-mix(in srgb,var(--accent) 88%,#fff) 0%,var(--accent) 100%);border-color:color-mix(in srgb,var(--accent) 75%,#000);color:#fff;box-shadow:var(--hairline-strong),var(--elev-2),0 0 color-mix(in srgb,var(--accent) 40%,transparent)}button.primary:hover:not(:disabled){background:linear-gradient(180deg,color-mix(in srgb,var(--accent) 78%,#fff),color-mix(in srgb,var(--accent) 94%,#fff));border-color:color-mix(in srgb,var(--accent) 75%,#000);box-shadow:var(--hairline-strong),var(--elev-2),0 0 18px -2px color-mix(in srgb,var(--accent) 45%,transparent)}button.danger{background:var(--fail-soft);border-color:color-mix(in srgb,var(--fail) 45%,transparent);color:var(--fail)}button.danger:hover:not(:disabled){background:color-mix(in srgb,var(--fail) 26%,transparent);border-color:color-mix(in srgb,var(--fail) 62%,transparent)}button.ghost{background:transparent;box-shadow:none}button.ghost:hover:not(:disabled){background:var(--hover)}button.sm,.btn.sm{min-height:var(--control-h-sm);padding:var(--s1) var(--s2);font-size:var(--t-xs)}button.armed{background:var(--fail-soft);border-color:color-mix(in srgb,var(--fail) 70%,transparent);color:var(--fail);font-weight:600}button .progress{position:absolute;inset:auto 0 0 0;height:2px;background:currentColor;opacity:.65;animation:indeterminate 1.1s var(--ease) infinite;transform-origin:left}input[type=text],input[type=password],input[type=search],input[type=url],input[type=email],input[type=number],textarea,select{font:var(--t-sm) / 1.5 var(--sans);letter-spacing:var(--track-body);color:var(--fg);background:var(--sunk);border:1px solid var(--line);border-radius:var(--r1);padding:var(--s2) var(--s3);min-height:32px;width:100%;min-width:0;box-shadow:inset 0 1px 2px var(--press);transition:border-color var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease)}input[type=text]:hover,input[type=password]:hover,input[type=search]:hover,input[type=url]:hover,input[type=email]:hover,input[type=number]:hover,textarea:hover,select:hover{border-color:color-mix(in srgb,var(--fg-mute) 55%,var(--line))}input[type=text]:focus,input[type=password]:focus,input[type=search]:focus,input[type=url]:focus,input[type=email]:focus,input[type=number]:focus,textarea:focus,select:focus{outline:none;border-color:var(--accent);box-shadow:inset 0 1px 2px var(--press),0 0 0 3px color-mix(in srgb,var(--accent) 22%,transparent)}textarea{font-family:var(--mono);font-size:var(--t-sm);line-height:1.55;resize:vertical;white-space:pre;overflow-wrap:normal;overflow-x:auto}input::placeholder,textarea::placeholder{color:var(--fg-mute)}input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus{-webkit-box-shadow:0 0 0 1000px var(--sunk) inset;-webkit-text-fill-color:var(--fg);caret-color:var(--fg);transition:background-color 9999s ease-out}label{font-size:var(--t-sm);color:var(--fg-dim)}.field{display:grid;gap:var(--s2);min-width:0}.field+.field,.field+.hint,.hint+.field{margin-top:var(--s4)}.row>.field+.field,.row>.field+.hint,.row>.hint+.field,.phead>.field+.field,.phead>.field+.hint,.phead>.hint+.field{margin-top:0}.field.inline{display:flex;align-items:center;gap:var(--s2);margin-top:0}.field.inline>label{color:var(--fg-mute);font-size:var(--t-xs);white-space:nowrap}.phead>button,.phead>.btn,.phead>input,.phead>select,.phead>.check,.phead>.field>input,.phead>.field>select{min-height:var(--control-h)}.row.wrap>.field,.row>.field{align-self:stretch}.check{display:inline-flex;align-items:center;gap:var(--s2);cursor:pointer;color:var(--fg)}.check input{width:auto;min-height:0;accent-color:var(--accent)}.kv{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.4fr) auto;gap:var(--s2);margin-bottom:var(--s2);align-items:center;max-width:640px}.kv.head{font-size:var(--t-xs);color:var(--fg-mute);text-transform:uppercase;letter-spacing:.06em}@media(max-width:560px){.kv{grid-template-columns:minmax(0,1fr) auto}.kv.head{display:none}}.badge{display:inline-flex;align-items:center;gap:5px;font:500 var(--t-xs) / 1 var(--sans);padding:4px 8px;border-radius:var(--r-full);background:var(--neutral-soft);color:var(--fg-dim);border:1px solid transparent;white-space:nowrap}.badge.ok{background:var(--ok-soft);color:var(--ok)}.badge.failed,.badge.fail{background:var(--fail-soft);color:var(--fail)}.badge.leaked,.badge.warn{background:var(--leak-soft);color:var(--leak)}.badge.running,.badge.busy,.badge.info{background:var(--accent-soft);color:var(--accent)}.badge.unknown{background:var(--neutral-soft);color:var(--neutral)}.badge.shared{background:var(--leak-soft);color:var(--leak)}.badge.isolated{background:var(--accent-soft);color:var(--accent)}.badge.off{opacity:.38}.badge .dot{width:6px;height:6px;border-radius:var(--r-full);background:currentColor}.badge.running .dot,.dot.pulse{animation:pulse 1.6s var(--ease) infinite}.banner{border:1px solid var(--line);border-left-width:3px;border-radius:var(--r2);padding:var(--s3) var(--s4);margin:var(--s3) 0;background:var(--panel-2);font-size:var(--t-sm)}.banner b{color:var(--fg)}.banner p{margin-top:var(--s2);color:var(--fg-dim)}.banner.ok{border-left-color:var(--ok);background:var(--ok-soft)}.banner.failed{border-left-color:var(--fail);background:var(--fail-soft)}.banner.leaked,.banner.warn{border-left-color:var(--leak);background:var(--leak-soft)}.banner.info{border-left-color:var(--accent);background:var(--accent-soft)}.banner.plain{border-left-color:var(--fg-mute)}.hint{font-size:var(--t-sm);color:var(--fg-mute);margin-top:var(--s3)}.hint code,.banner code{background:var(--sunk);padding:1px 5px;border-radius:var(--r0)}table{width:100%;border-collapse:collapse;font-size:var(--t-sm)}th{text-align:left;font:620 var(--t-xs) / 1 var(--sans);text-transform:uppercase;letter-spacing:var(--track-caps);color:var(--fg-mute);padding:var(--s2) var(--s3);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:1;background:var(--panel);white-space:nowrap}td{padding:var(--s2) var(--s3);border-bottom:1px solid var(--line-soft);vertical-align:middle}tbody tr{transition:background var(--dur-fast) var(--ease)}tbody tr:hover{background:var(--hover)}tbody tr:last-child td{border-bottom:none}td.name{font-weight:600;word-break:break-all}@container (max-width: 460px){table.cards,table.cards tbody,table.cards tr,table.cards td{display:block;width:100%}table.cards thead{display:none}table.cards tr{border:1px solid var(--line);border-radius:var(--r2);padding:var(--s2) var(--s3);margin-bottom:var(--s2);background:var(--panel-2)}table.cards td{display:flex;justify-content:space-between;align-items:baseline;gap:var(--s3);border:0;padding:var(--s1) 0;text-align:right}table.cards td:before{content:attr(data-label);font:600 var(--t-xs) / 1.6 var(--sans);text-transform:uppercase;letter-spacing:.06em;color:var(--fg-mute);text-align:left;flex:none}table.cards td[colspan]{text-align:left}table.cards td[colspan]:before,table.cards td[data-label=""]:before{content:""}table.cards td[data-label=""]{justify-content:flex-end}}@container (min-width: 461px){.panel>table,.table-scroll{display:block;max-width:100%;overflow-x:auto}.panel>table>thead,.panel>table>tbody{display:table;width:100%;table-layout:auto}}.row-actions{text-align:end;white-space:nowrap}.row-actions>*+*{margin-inline-start:var(--s1)}.logs-split{display:grid;grid-template-columns:232px minmax(0,1fr);gap:var(--s4);align-items:start}@container (max-width: 720px){.logs-split{grid-template-columns:minmax(0,1fr)}.clist{max-height:220px}}.clist{display:flex;flex-direction:column;gap:2px;max-height:60vh;overflow-y:auto;padding-inline-end:var(--s1)}.clist-item{display:grid;gap:2px;text-align:start;justify-items:start;padding:var(--s2) var(--s3);min-height:0;background:transparent;border:1px solid transparent;box-shadow:none;width:100%}.clist-item:hover:not(:disabled){background:var(--hover);border-color:var(--line-soft)}.clist-item.on{background:var(--panel-2);border-color:var(--line);box-shadow:var(--hairline)}.clist-name{display:inline-flex;align-items:center;gap:var(--s2);font-weight:560}.clist-sub{font-size:var(--t-xs);color:var(--fg-mute);max-width:100%;overflow:hidden;text-overflow:ellipsis}.clist-state{font-size:var(--t-xs)}.logs-main{min-width:0}.lv-time{flex:none;color:var(--fg-mute);font-variant-numeric:tabular-nums;white-space:nowrap}.panel.banner-panel{border-color:color-mix(in srgb,var(--warn) 40%,var(--line));background:color-mix(in srgb,var(--warn) 8%,var(--panel))}.kvlist{display:grid;gap:1px;background:var(--line-soft);border-radius:var(--r2);overflow:hidden}.kvlist>li{display:flex;gap:var(--s3);padding:var(--s3);background:var(--panel);align-items:baseline;flex-wrap:wrap}.kvlist>li>.k{flex:none;width:128px;color:var(--fg-dim);font-size:var(--t-sm)}.kvlist>li>.v{flex:1;min-width:0;word-break:break-word}@media(max-width:480px){.kvlist>li>.k{width:100%}}pre.raw,pre.log{font-family:var(--mono);font-size:var(--t-sm);line-height:1.6;background:var(--sunk);border:1px solid var(--line);border-radius:var(--r2);padding:var(--s3);margin:var(--s3) 0 0;overflow:auto;white-space:pre}pre.raw{color:var(--fail);max-height:420px}pre.code{font-family:var(--mono);font-size:var(--t-sm);line-height:1.6;background:var(--sunk);border:1px solid var(--line);border-radius:var(--r2);padding:var(--s3);margin:0;max-height:520px;overflow:auto;white-space:pre;color:var(--fg-dim)}pre.log{max-height:460px;color:var(--fg-dim)}pre.log .t{color:var(--fg-mute)}pre.log .lv-error{color:var(--fail)}pre.log .lv-warn{color:var(--leak)}pre.log .lv-info{color:var(--fg)}pre.log mark{background:var(--leak-soft);color:var(--leak)}.masked{color:var(--fg-mute);letter-spacing:.12em}.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s2)}@container (min-width: 680px){.stats{grid-template-columns:repeat(6,1fr)}}.stat{background:var(--panel-2);border:1px solid var(--line-soft);border-radius:var(--r2);padding:var(--s3);box-shadow:var(--hairline);min-width:0}.stat .v{font:600 var(--t-2xl) / 1.1 var(--sans);letter-spacing:var(--track-display);font-variant-numeric:tabular-nums}.stat[data-zero=true] .v{color:var(--fg-mute);font-weight:500}.stat .k{font-size:var(--t-xs);color:var(--fg-mute);text-transform:uppercase;letter-spacing:.04em;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.stat.unknown .v{color:var(--neutral)}.stat.busy .v{color:var(--accent)}.stat.leak .v{color:var(--leak)}.tabs{display:flex;gap:var(--s1);border-bottom:1px solid var(--line);margin-bottom:var(--s4);overflow-x:auto;scrollbar-width:none}.tabs::-webkit-scrollbar{display:none}.tabs a{padding:var(--s2) var(--s3);color:var(--fg-dim);font-size:var(--t-sm);font-weight:500;border-bottom:2px solid transparent;margin-bottom:-1px;white-space:nowrap;transition:color var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)}.tabs a:hover{color:var(--fg);text-decoration:none}.tabs a.router-link-active{color:var(--fg);border-bottom-color:var(--accent)}.steps{display:grid;gap:1px;background:var(--line-soft);border-radius:var(--r2);overflow:hidden}.step{display:grid;grid-template-columns:24px minmax(0,1fr);gap:var(--s3);padding:var(--s3);background:var(--panel);align-items:start}.step .mark{font:600 var(--t-lg) / 1.2 var(--sans);text-align:center}.step .who{font-weight:550;word-break:break-all}.step .msg{font-size:var(--t-sm);color:var(--fg-dim);word-break:break-word}.s-ok{color:var(--ok)}.s-failed{color:var(--fail)}.s-leaked{color:var(--leak)}.s-unverifiable{color:var(--neutral)}.skel{background:var(--skel);background-size:200% 100%;border-radius:var(--r1);height:14px;animation:shimmer 1.3s linear infinite}.skel+.skel{margin-top:var(--s2)}.skel.tall{height:44px}.skel.w60{width:60%}.skel.w40{width:40%}@keyframes shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}@keyframes pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.35;transform:scale(.8)}}@keyframes indeterminate{0%{transform:scaleX(0)}50%{transform:scaleX(.7)}to{transform:scaleX(0);transform-origin:right}}@keyframes rise{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}@keyframes land{0%{transform:scale(.985);opacity:.4}60%{transform:scale(1.004)}to{transform:none;opacity:1}}.stagger>*{animation:rise var(--dur) var(--ease) backwards;animation-delay:calc(var(--i, 0) * var(--stagger-step))}.land{animation:land var(--dur-slow) var(--ease)}.view-enter-active,.view-leave-active{transition:opacity var(--dur) var(--ease),transform var(--dur) var(--ease)}.view-enter-from{opacity:0;transform:translateY(6px)}.view-leave-to{opacity:0;transform:translateY(-4px)}.toasts{position:fixed;right:var(--s4);bottom:var(--s4);z-index:50;display:grid;gap:var(--s2);width:min(360px,calc(100vw - var(--s5)))}@media(max-width:800px){.toasts{bottom:calc(84px + env(safe-area-inset-bottom))}}.toast{display:flex;gap:var(--s3);align-items:flex-start;background:var(--panel);border:1px solid var(--line);border-radius:var(--r2);padding:var(--s3) var(--s3) var(--s3) var(--s2);box-shadow:var(--hairline),var(--elev-4);font-size:var(--t-sm);position:relative}.toast:before{content:"";flex:none;width:8px;height:8px;margin:6px 0 0 var(--s2);border-radius:var(--r-full);background:var(--neutral);box-shadow:0 0 0 3px var(--neutral-soft)}.toast.ok:before{background:var(--ok);box-shadow:0 0 0 3px var(--ok-soft)}.toast.error:before{background:var(--fail);box-shadow:0 0 0 3px var(--fail-soft)}.toast.warn:before{background:var(--leak);box-shadow:0 0 0 3px var(--leak-soft)}.toast.info:before{background:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}.toast .x{margin-left:auto;background:none;border:0;min-height:0;padding:2px 6px;color:var(--fg-mute)}.toast-enter-active,.toast-leave-active{transition:opacity var(--dur) var(--ease),transform var(--dur) var(--ease)}.toast-enter-from,.toast-leave-to{opacity:0;transform:translate(12px)}.toast-move{transition:transform var(--dur) var(--ease)}.scrim{position:fixed;top:0;right:0;bottom:0;left:0;background:#0000008c;z-index:60;display:grid;place-items:center;padding:var(--s4)}.sheet{background:var(--panel);border:1px solid var(--line);border-radius:var(--r3);box-shadow:var(--shadow);padding:var(--s5);width:min(460px,100%);max-height:80vh;overflow:auto}.sheet dl{display:grid;grid-template-columns:auto minmax(0,1fr);gap:var(--s2) var(--s4);margin:var(--s4) 0 0;align-items:baseline}.sheet dt{text-align:right}.sheet dd{margin:0;color:var(--fg-dim);font-size:var(--t-sm)}kbd{font:500 var(--t-xs) / 1 var(--mono);background:var(--sunk);border:1px solid var(--line);border-bottom-width:2px;border-radius:var(--r0);padding:4px 6px;color:var(--fg)}.fade-enter-active,.fade-leave-active{transition:opacity var(--dur) var(--ease)}.fade-enter-from,.fade-leave-to{opacity:0}.hint-wrap{position:relative;display:inline-flex;vertical-align:middle;margin-inline-start:var(--s1)}.hint-btn{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;min-height:0;padding:0;border:0;border-radius:var(--r-full);background:none;color:var(--fg-mute);cursor:pointer;transition:color var(--dur-fast) var(--ease),background var(--dur-fast) var(--ease)}.hint-btn:hover,.hint-btn.on{color:var(--accent);background:var(--accent-soft)}.hint-bub{position:absolute;z-index:40;width:max-content;max-width:min(300px,74vw);padding:var(--s2) var(--s3);background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r2);box-shadow:var(--shadow);color:var(--fg-dim);font:400 var(--t-sm) / 1.5 var(--sans);text-transform:none;letter-spacing:normal;white-space:normal;text-align:start;pointer-events:none}.hint-bub.below{top:calc(100% + 6px)}.hint-bub.above{bottom:calc(100% + 6px)}.hint-bub.to-start{inset-inline-start:-2px}.hint-bub.to-end{inset-inline-end:-2px}.hint-bub code{color:var(--fg)}.hint-enter-active,.hint-leave-active{transition:opacity var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease)}.hint-enter-from,.hint-leave-to{opacity:0}.hint-bub.below.hint-enter-from,.hint-bub.below.hint-leave-to{transform:translateY(-3px)}.hint-bub.above.hint-enter-from,.hint-bub.above.hint-leave-to{transform:translateY(3px)}.palette-scrim{align-items:flex-start;padding-top:12vh}.palette{width:min(620px,calc(100vw - var(--s5)));background:var(--panel);border:1px solid var(--line);border-radius:var(--r3);box-shadow:var(--hairline-strong),var(--elev-4);overflow:hidden;display:flex;flex-direction:column;max-height:min(60vh,560px)}.palette-q{display:flex;align-items:center;gap:var(--s3);padding:var(--s3) var(--s4);border-bottom:1px solid var(--line-soft);color:var(--fg-mute)}.palette-q input{flex:1;background:none;border:none;box-shadow:none;padding:0;min-height:26px;font-size:var(--t-lg);letter-spacing:var(--track-title);color:var(--fg)}.palette-q input:focus{outline:none;border:none;box-shadow:none}.palette-list{overflow-y:auto;padding:var(--s2);min-height:0}.palette-group{font-size:var(--t-xs);text-transform:uppercase;letter-spacing:var(--track-caps);color:var(--fg-mute);padding:var(--s3) var(--s2) var(--s1)}.palette-row{display:flex;align-items:center;gap:var(--s3);width:100%;text-align:left;background:none;border:none;box-shadow:none;border-radius:var(--r1);padding:var(--s2) var(--s3);min-height:34px;color:var(--fg)}.palette-row[data-on=true]{background:var(--accent-soft);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--accent) 32%,transparent)}.palette-label{font-weight:520}.palette-hint{margin-left:auto;color:var(--fg-mute);font-size:var(--t-xs);font-family:var(--mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:45%}.palette-empty{color:var(--fg-mute);padding:var(--s5) var(--s3);text-align:center;font-size:var(--t-sm)}.palette-foot{display:flex;gap:var(--s4);align-items:center;padding:var(--s2) var(--s4);border-top:1px solid var(--line-soft);background:var(--panel-2);color:var(--fg-mute);font-size:var(--t-xs)}kbd{font:500 11px / 1 var(--mono);color:var(--fg-dim);background:var(--sunk);border:1px solid var(--line);border-radius:var(--r0);padding:3px 5px;margin-right:3px}.fade-enter-active .palette{animation:palette-in var(--dur-slow) var(--ease-spring)}@keyframes palette-in{0%{opacity:0;transform:translateY(-10px) scale(.98)}to{opacity:1;transform:none}}::view-transition-old(root),::view-transition-new(root){animation-duration:var(--dur);animation-timing-function:var(--ease)}::view-transition-old(root){animation-name:vt-out}::view-transition-new(root){animation-name:vt-in}@keyframes vt-out{to{opacity:0}}@keyframes vt-in{0%{opacity:0;transform:translateY(4px)}}.searchbox{display:flex;align-items:center;gap:var(--s2);flex:1;min-width:180px;padding-inline:var(--s3);background:var(--sunk);border:1px solid var(--line);border-radius:var(--r1);box-shadow:inset 0 1px 2px var(--press);color:var(--fg-mute);min-height:34px;transition:border-color var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease)}.searchbox:focus-within{border-color:var(--accent);box-shadow:inset 0 1px 2px var(--press),0 0 0 3px color-mix(in srgb,var(--accent) 22%,transparent)}.searchbox input{border:none;background:none;box-shadow:none;padding:0;min-height:0}.searchbox input:focus{outline:none;border:none;box-shadow:none}.searchbox input::-webkit-search-cancel-button{-webkit-appearance:none;-moz-appearance:none;appearance:none}select.compact{width:auto;min-height:34px;padding-inline-end:var(--s5)}.phead>.check{min-height:34px}.field>.selm-trigger,.selm-trigger{max-width:340px;width:100%}.selm-trigger{display:inline-flex;align-items:center;gap:var(--s2);justify-content:space-between;min-height:34px;padding:0 var(--s2) 0 var(--s3);background:var(--sunk);border:1px solid var(--line);border-radius:var(--r1);box-shadow:inset 0 1px 2px var(--press);font:var(--t-sm) / 1 var(--sans);color:var(--fg);cursor:pointer}.selm-trigger:hover:not(:disabled){border-color:color-mix(in srgb,var(--fg-mute) 55%,var(--line))}.selm-trigger[data-state=open]{border-color:var(--accent);box-shadow:inset 0 1px 2px var(--press),0 0 0 3px color-mix(in srgb,var(--accent) 22%,transparent)}.selm-value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.selm-caret{flex:none;color:var(--fg-mute);transition:transform var(--dur-fast) var(--ease)}.selm-trigger[data-state=open] .selm-caret{transform:rotate(180deg)}.selm-list{z-index:61;padding:var(--s1);max-height:280px;overflow-y:auto;background:var(--panel);border:1px solid var(--line);border-radius:var(--r2);box-shadow:var(--hairline-strong),var(--elev-4);min-width:var(--reka-select-trigger-width);animation:palette-in var(--dur) var(--ease-spring)}.selm-opt{display:flex;align-items:center;gap:var(--s2);padding:var(--s2);min-height:30px;border-radius:calc(var(--r1) - 2px);font-size:var(--t-sm);cursor:pointer;white-space:nowrap;-webkit-user-select:none;user-select:none}.selm-opt[data-highlighted]{background:var(--accent-soft);outline:none}.selm-opt[data-disabled]{opacity:.45;cursor:not-allowed}.selm-hint{color:var(--fg-mute);font-size:var(--t-xs);margin-inline-start:auto}.selm-tick{margin-inline-start:auto;color:var(--accent);display:inline-flex}.selm-hint+.selm-tick{margin-inline-start:var(--s2)}input[type=checkbox],input[type=radio]{-moz-appearance:none;appearance:none;-webkit-appearance:none;flex:none;width:17px;height:17px;margin:0;border:1px solid color-mix(in srgb,var(--fg-mute) 60%,var(--line));background:var(--sunk);box-shadow:inset 0 1px 2px var(--press);cursor:pointer;display:grid;place-content:center;transition:background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)}input[type=checkbox]{border-radius:var(--r0)}input[type=radio]{border-radius:var(--r-full)}input[type=checkbox]:hover:not(:disabled),input[type=radio]:hover:not(:disabled){border-color:var(--accent)}input[type=checkbox]:before,input[type=radio]:before{content:"";transform:scale(0);transition:transform var(--dur-fast) var(--ease-spring)}input[type=checkbox]:before{width:11px;height:11px;background:#fff;clip-path:polygon(14% 47%,0 61%,40% 100%,100% 22%,85% 9%,39% 71%)}input[type=radio]:before{width:7px;height:7px;border-radius:var(--r-full);background:#fff}input[type=checkbox]:checked,input[type=radio]:checked{background:var(--accent);border-color:var(--accent)}input[type=checkbox]:checked:before,input[type=radio]:checked:before{transform:scale(1)}input[type=checkbox]:disabled,input[type=radio]:disabled{opacity:.45;cursor:not-allowed}.helpq{display:inline-grid;place-items:center;width:18px;height:18px;padding:0;min-height:0;border-radius:var(--r-full);border:1px solid var(--line);background:var(--panel-2);box-shadow:none;color:var(--fg-mute);cursor:pointer;vertical-align:middle}.helpq:hover{color:var(--accent);border-color:var(--accent);background:var(--accent-soft)}.help-scrim{-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:70}.help-modal{position:fixed;z-index:71;top:50%;left:50%;transform:translate(-50%,-50%);width:min(620px,calc(100vw - var(--s5)));max-height:min(80vh,720px);display:flex;flex-direction:column;background:var(--panel);border:1px solid var(--line);border-radius:var(--r3);box-shadow:var(--hairline-strong),var(--elev-4);animation:help-in var(--dur-slow) var(--ease-spring)}@keyframes help-in{0%{opacity:0;transform:translate(-50%,-46%) scale(.97)}}.help-head{display:flex;align-items:center;gap:var(--s3);padding:var(--s4) var(--s4) var(--s3);border-bottom:1px solid var(--line-soft)}.help-title{font-size:var(--t-lg);font-weight:620;letter-spacing:var(--track-title);margin:0;flex:1}.help-body{padding:var(--s4);overflow-y:auto;color:var(--fg-dim);font-size:var(--t-sm);line-height:var(--lh-body)}.help-body>*+*{margin-top:var(--s3)}.help-body b,.help-body strong{color:var(--fg)}.check-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:var(--s2) var(--s4);margin-top:var(--s2)}.check-grid .check{min-height:26px}.settings-form .field input,.settings-form input[type=url],.settings-form input[type=password],.settings-form input[type=text]{max-width:560px}.settings-form .hint,.settings-form .mute.hint{max-width:640px}.lv{border:1px solid var(--line);border-radius:var(--r2);background:var(--sunk);overflow:hidden}.lv-bar{display:flex;align-items:center;gap:var(--s2);padding:var(--s2) var(--s3);border-bottom:1px solid var(--line-soft);font-size:var(--t-xs);color:var(--fg-mute)}.lv-box{max-height:520px;overflow-y:auto;padding:var(--s2) 0 var(--s3);font:var(--t-sm) / 1.6 var(--mono);overscroll-behavior:contain}.lv-empty{color:var(--fg-mute);padding:var(--s4) var(--s3);font-family:var(--sans)}.lv-row{display:grid;grid-template-columns:auto minmax(0,1fr);gap:0 var(--s3);padding:1px var(--s3);content-visibility:auto;contain-intrinsic-block-size:auto 22px}.lv-row:hover{background:var(--hover)}.lv-gutter{white-space:nowrap;color:var(--fg-mute);-webkit-user-select:none;user-select:none;font-variant-numeric:tabular-nums}.lv-msg{white-space:pre-wrap;overflow-wrap:anywhere;color:var(--fg-dim)}.lv-row.error .lv-msg{color:var(--fail)}.lv-row.warn .lv-msg{color:var(--leak)}.lv-row.ok .lv-msg{color:var(--ok)}.lv-row.svc-0 .lv-gutter{color:#7aa2f7}.lv-row.svc-1 .lv-gutter{color:#9ece6a}.lv-row.svc-2 .lv-gutter{color:#e0af68}.lv-row.svc-3 .lv-gutter{color:#bb9af7}.lv-row.svc-4 .lv-gutter{color:#7dcfff}.lv-row.svc-5 .lv-gutter{color:#f7768e}.lv-sep{display:flex;align-items:center;gap:var(--s3);padding:var(--s2) var(--s3);color:var(--fg-mute);font-family:var(--sans);font-size:var(--t-xs)}.lv-sep:before,.lv-sep:after{content:"";flex:1;border-top:1px solid var(--line-soft)}.refresh-icon{display:inline-block;line-height:1}.refresh-icon.spin{animation:refresh-spin .9s linear infinite}@keyframes refresh-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.refresh-icon.spin{animation:none}}:root[data-motion=none] .refresh-icon.spin{animation:none}
@@ -1,2 +1,2 @@
1
- import{S as n,C as i,A as d,B as l,L as p,U as c}from"./index-wjzRhuU3.js";import{w as u,r as y}from"./useVars-VN9gYdR6.js";const e=n({id:"",detail:null,error:"",loading:!1,vars:[]}),f=i(()=>p(e.vars)),k=i(()=>c(e.id)),b=i(()=>{var a;return((a=e.detail)==null?void 0:a.kind)==="shared"}),h=i(()=>{var a;return(((a=e.detail)==null?void 0:a.axes)??[]).filter(s=>!s.verifiable).map(s=>s.name)});async function t(){const a=e.id;e.loading=!0;const s=await d.get(`/api/deployments/${encodeURIComponent(a)}${f.value}`);if(e.id!==a)return;if(e.loading=!1,!s.ok){e.detail=null,e.error=l(s,`GET /api/deployments/${a}`);return}e.error="";const r=s.body;e.detail={id:r.id??a,kind:r.kind==="shared"?"shared":"isolated",createdAt:r.createdAt,updatedAt:r.updatedAt,stack:typeof r.stack=="string"?r.stack:"",busy:r.busy??null,compose:r.compose?{file:r.compose.file??"?",profiles:r.compose.profiles??[],overlays:r.compose.overlays??[]}:null,requires:Array.isArray(r.requires)?r.requires:[],axes:(Array.isArray(r.axes)?r.axes:[]).map(o=>({name:o.name,hooks:Array.isArray(o.hooks)?o.hooks:[],verifiable:o.verifiable??(Array.isArray(o.hooks)&&o.hooks.includes("assert_gone"))})),env:Array.isArray(r.env)?r.env:[]}}function g(a){e.id===a&&(e.detail||e.error)||(e.id=a,e.detail=null,e.error="",e.vars=y(a),t())}function m(){u(e.id,e.vars)}function x(){m(),t()}export{x as a,e as d,b as i,g as o,m as p,k as r,h as u,f as v};
2
- //# sourceMappingURL=useDeployment-B7kMYmcq.js.map
1
+ import{U as n,C as i,A as d,B as l,N as p,V as c}from"./index-DVMQBHXF.js";import{w as u,r as y}from"./useVars-VN9gYdR6.js";const e=n({id:"",detail:null,error:"",loading:!1,vars:[]}),f=i(()=>p(e.vars)),k=i(()=>c(e.id)),b=i(()=>{var a;return((a=e.detail)==null?void 0:a.kind)==="shared"}),h=i(()=>{var a;return(((a=e.detail)==null?void 0:a.axes)??[]).filter(s=>!s.verifiable).map(s=>s.name)});async function t(){const a=e.id;e.loading=!0;const s=await d.get(`/api/deployments/${encodeURIComponent(a)}${f.value}`);if(e.id!==a)return;if(e.loading=!1,!s.ok){e.detail=null,e.error=l(s,`GET /api/deployments/${a}`);return}e.error="";const r=s.body;e.detail={id:r.id??a,kind:r.kind==="shared"?"shared":"isolated",createdAt:r.createdAt,updatedAt:r.updatedAt,stack:typeof r.stack=="string"?r.stack:"",busy:r.busy??null,compose:r.compose?{file:r.compose.file??"?",profiles:r.compose.profiles??[],overlays:r.compose.overlays??[]}:null,requires:Array.isArray(r.requires)?r.requires:[],axes:(Array.isArray(r.axes)?r.axes:[]).map(o=>({name:o.name,hooks:Array.isArray(o.hooks)?o.hooks:[],verifiable:o.verifiable??(Array.isArray(o.hooks)&&o.hooks.includes("assert_gone"))})),env:Array.isArray(r.env)?r.env:[]}}function g(a){e.id===a&&(e.detail||e.error)||(e.id=a,e.detail=null,e.error="",e.vars=y(a),t())}function m(){u(e.id,e.vars)}function x(){m(),t()}export{x as a,e as d,b as i,t as l,g as o,m as p,k as r,h as u,f as v};
2
+ //# sourceMappingURL=useDeployment-DGzBsXE-.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useDeployment-B7kMYmcq.js","sources":["../../src/composables/useDeployment.ts"],"sourcesContent":["/**\n * The deployment currently open in the detail view.\n *\n * A module singleton rather than provide/inject, because the six tabs are CHILD ROUTES: they are\n * siblings of each other and are mounted and unmounted independently, so passing the loaded\n * deployment down as a prop would mean re-fetching it on every tab change. Switching tabs must not\n * re-fetch or blank the panel — only opening a DIFFERENT deployment does.\n *\n * `vars` here are REQUEST-TIME variables, sent as `?query` on every route that resolves this\n * deployment. See `useVars.ts` for why they matter and what they can get wrong.\n */\n\nimport { computed, reactive } from 'vue';\nimport { api, problem, query } from '../api/client';\nimport type { Deployment, VarPair } from '../api/types';\nimport { readVars, writeVars } from './useVars';\nimport { rowFor } from './useControlPlane';\n\nexport const dep = reactive({\n id: '',\n detail: null as Deployment | null,\n /** The resolve failure, verbatim. It is a 400 that NAMES the missing variable. */\n error: '',\n loading: false,\n vars: [] as VarPair[],\n});\n\nexport const varsQuery = computed(() => query(dep.vars));\n\n/** The list row, which is the only place the server exposes stored `vars` and `specName` today. */\nexport const row = computed(() => rowFor(dep.id));\n\nexport const isShared = computed(() => dep.detail?.kind === 'shared');\n\nexport const unverifiableAxes = computed(() =>\n (dep.detail?.axes ?? []).filter((a) => !a.verifiable).map((a) => a.name),\n);\n\nexport async function loadDetail(): Promise<void> {\n const id = dep.id;\n dep.loading = true;\n const r = await api.get<Deployment>(`/api/deployments/${encodeURIComponent(id)}${varsQuery.value}`);\n // Navigated to another deployment while this was in flight: drop the answer rather than render\n // one deployment's spec under another's id.\n if (dep.id !== id) return;\n dep.loading = false;\n\n if (!r.ok) {\n dep.detail = null;\n dep.error = problem(r, `GET /api/deployments/${id}`);\n return;\n }\n dep.error = '';\n const b = r.body;\n dep.detail = {\n id: b.id ?? id,\n kind: b.kind === 'shared' ? 'shared' : 'isolated',\n createdAt: b.createdAt,\n updatedAt: b.updatedAt,\n stack: typeof b.stack === 'string' ? b.stack : '',\n busy: b.busy ?? null,\n compose: b.compose\n ? {\n file: b.compose.file ?? '?',\n profiles: b.compose.profiles ?? [],\n overlays: b.compose.overlays ?? [],\n }\n : null,\n requires: Array.isArray(b.requires) ? b.requires : [],\n axes: (Array.isArray(b.axes) ? b.axes : []).map((a) => ({\n name: a.name,\n hooks: Array.isArray(a.hooks) ? a.hooks : [],\n // Derive it if an older build omits the field. Defaulting to `false` would claim an axis is\n // unverifiable when it may define a perfectly good `assert_gone`.\n verifiable: a.verifiable ?? (Array.isArray(a.hooks) && a.hooks.includes('assert_gone')),\n })),\n env: Array.isArray(b.env) ? b.env : [],\n };\n}\n\n/** Point the singleton at a deployment. Resets everything a stale id could leak into the new one. */\nexport function openDeployment(id: string): void {\n if (dep.id === id && (dep.detail || dep.error)) return; // a tab change, not a navigation\n dep.id = id;\n dep.detail = null;\n dep.error = '';\n dep.vars = readVars(id);\n void loadDetail();\n}\n\nexport function persistVars(): void {\n writeVars(dep.id, dep.vars);\n}\n\nexport function applyVars(): void {\n persistVars();\n void loadDetail();\n}\n"],"names":["dep","reactive","varsQuery","computed","query","row","rowFor","isShared","_a","unverifiableAxes","a","loadDetail","id","r","api","problem","b","openDeployment","readVars","persistVars","writeVars","applyVars"],"mappings":"4HAkBO,MAAMA,EAAMC,EAAS,CAC1B,GAAI,GACJ,OAAQ,KAER,MAAO,GACP,QAAS,GACT,KAAM,CAAA,CACR,CAAC,EAEYC,EAAYC,EAAS,IAAMC,EAAMJ,EAAI,IAAI,CAAC,EAG1CK,EAAMF,EAAS,IAAMG,EAAON,EAAI,EAAE,CAAC,EAEnCO,EAAWJ,EAAS,IAAA,OAAM,QAAAK,EAAAR,EAAI,SAAJ,YAAAQ,EAAY,QAAS,SAAQ,EAEvDC,EAAmBN,EAAS,IAAA,OACtC,SAAAK,EAAAR,EAAI,SAAJ,YAAAQ,EAAY,OAAQ,CAAA,GAAI,OAAQE,GAAM,CAACA,EAAE,UAAU,EAAE,IAAKA,GAAMA,EAAE,IAAI,EACzE,EAEA,eAAsBC,GAA4B,CAChD,MAAMC,EAAKZ,EAAI,GACfA,EAAI,QAAU,GACd,MAAMa,EAAI,MAAMC,EAAI,IAAgB,oBAAoB,mBAAmBF,CAAE,CAAC,GAAGV,EAAU,KAAK,EAAE,EAGlG,GAAIF,EAAI,KAAOY,EAAI,OAGnB,GAFAZ,EAAI,QAAU,GAEV,CAACa,EAAE,GAAI,CACTb,EAAI,OAAS,KACbA,EAAI,MAAQe,EAAQF,EAAG,wBAAwBD,CAAE,EAAE,EACnD,MACF,CACAZ,EAAI,MAAQ,GACZ,MAAMgB,EAAIH,EAAE,KACZb,EAAI,OAAS,CACX,GAAIgB,EAAE,IAAMJ,EACZ,KAAMI,EAAE,OAAS,SAAW,SAAW,WACvC,UAAWA,EAAE,UACb,UAAWA,EAAE,UACb,MAAO,OAAOA,EAAE,OAAU,SAAWA,EAAE,MAAQ,GAC/C,KAAMA,EAAE,MAAQ,KAChB,QAASA,EAAE,QACP,CACE,KAAMA,EAAE,QAAQ,MAAQ,IACxB,SAAUA,EAAE,QAAQ,UAAY,CAAA,EAChC,SAAUA,EAAE,QAAQ,UAAY,CAAA,CAAC,EAEnC,KACJ,SAAU,MAAM,QAAQA,EAAE,QAAQ,EAAIA,EAAE,SAAW,CAAA,EACnD,MAAO,MAAM,QAAQA,EAAE,IAAI,EAAIA,EAAE,KAAO,CAAA,GAAI,IAAKN,IAAO,CACtD,KAAMA,EAAE,KACR,MAAO,MAAM,QAAQA,EAAE,KAAK,EAAIA,EAAE,MAAQ,CAAA,EAG1C,WAAYA,EAAE,aAAe,MAAM,QAAQA,EAAE,KAAK,GAAKA,EAAE,MAAM,SAAS,aAAa,EAAA,EACrF,EACF,IAAK,MAAM,QAAQM,EAAE,GAAG,EAAIA,EAAE,IAAM,CAAA,CAAC,CAEzC,CAGO,SAASC,EAAeL,EAAkB,CAC3CZ,EAAI,KAAOY,IAAOZ,EAAI,QAAUA,EAAI,SACxCA,EAAI,GAAKY,EACTZ,EAAI,OAAS,KACbA,EAAI,MAAQ,GACZA,EAAI,KAAOkB,EAASN,CAAE,EACjBD,EAAA,EACP,CAEO,SAASQ,GAAoB,CAClCC,EAAUpB,EAAI,GAAIA,EAAI,IAAI,CAC5B,CAEO,SAASqB,GAAkB,CAChCF,EAAA,EACKR,EAAA,CACP"}
1
+ {"version":3,"file":"useDeployment-DGzBsXE-.js","sources":["../../src/composables/useDeployment.ts"],"sourcesContent":["/**\n * The deployment currently open in the detail view.\n *\n * A module singleton rather than provide/inject, because the six tabs are CHILD ROUTES: they are\n * siblings of each other and are mounted and unmounted independently, so passing the loaded\n * deployment down as a prop would mean re-fetching it on every tab change. Switching tabs must not\n * re-fetch or blank the panel — only opening a DIFFERENT deployment does.\n *\n * `vars` here are REQUEST-TIME variables, sent as `?query` on every route that resolves this\n * deployment. See `useVars.ts` for why they matter and what they can get wrong.\n */\n\nimport { computed, reactive } from 'vue';\nimport { api, problem, query } from '../api/client';\nimport type { Deployment, VarPair } from '../api/types';\nimport { readVars, writeVars } from './useVars';\nimport { rowFor } from './useControlPlane';\n\nexport const dep = reactive({\n id: '',\n detail: null as Deployment | null,\n /** The resolve failure, verbatim. It is a 400 that NAMES the missing variable. */\n error: '',\n loading: false,\n vars: [] as VarPair[],\n});\n\nexport const varsQuery = computed(() => query(dep.vars));\n\n/** The list row, which is the only place the server exposes stored `vars` and `specName` today. */\nexport const row = computed(() => rowFor(dep.id));\n\nexport const isShared = computed(() => dep.detail?.kind === 'shared');\n\nexport const unverifiableAxes = computed(() =>\n (dep.detail?.axes ?? []).filter((a) => !a.verifiable).map((a) => a.name),\n);\n\nexport async function loadDetail(): Promise<void> {\n const id = dep.id;\n dep.loading = true;\n const r = await api.get<Deployment>(`/api/deployments/${encodeURIComponent(id)}${varsQuery.value}`);\n // Navigated to another deployment while this was in flight: drop the answer rather than render\n // one deployment's spec under another's id.\n if (dep.id !== id) return;\n dep.loading = false;\n\n if (!r.ok) {\n dep.detail = null;\n dep.error = problem(r, `GET /api/deployments/${id}`);\n return;\n }\n dep.error = '';\n const b = r.body;\n dep.detail = {\n id: b.id ?? id,\n kind: b.kind === 'shared' ? 'shared' : 'isolated',\n createdAt: b.createdAt,\n updatedAt: b.updatedAt,\n stack: typeof b.stack === 'string' ? b.stack : '',\n busy: b.busy ?? null,\n compose: b.compose\n ? {\n file: b.compose.file ?? '?',\n profiles: b.compose.profiles ?? [],\n overlays: b.compose.overlays ?? [],\n }\n : null,\n requires: Array.isArray(b.requires) ? b.requires : [],\n axes: (Array.isArray(b.axes) ? b.axes : []).map((a) => ({\n name: a.name,\n hooks: Array.isArray(a.hooks) ? a.hooks : [],\n // Derive it if an older build omits the field. Defaulting to `false` would claim an axis is\n // unverifiable when it may define a perfectly good `assert_gone`.\n verifiable: a.verifiable ?? (Array.isArray(a.hooks) && a.hooks.includes('assert_gone')),\n })),\n env: Array.isArray(b.env) ? b.env : [],\n };\n}\n\n/** Point the singleton at a deployment. Resets everything a stale id could leak into the new one. */\nexport function openDeployment(id: string): void {\n if (dep.id === id && (dep.detail || dep.error)) return; // a tab change, not a navigation\n dep.id = id;\n dep.detail = null;\n dep.error = '';\n dep.vars = readVars(id);\n void loadDetail();\n}\n\nexport function persistVars(): void {\n writeVars(dep.id, dep.vars);\n}\n\nexport function applyVars(): void {\n persistVars();\n void loadDetail();\n}\n"],"names":["dep","reactive","varsQuery","computed","query","row","rowFor","isShared","_a","unverifiableAxes","a","loadDetail","id","r","api","problem","b","openDeployment","readVars","persistVars","writeVars","applyVars"],"mappings":"4HAkBO,MAAMA,EAAMC,EAAS,CAC1B,GAAI,GACJ,OAAQ,KAER,MAAO,GACP,QAAS,GACT,KAAM,CAAA,CACR,CAAC,EAEYC,EAAYC,EAAS,IAAMC,EAAMJ,EAAI,IAAI,CAAC,EAG1CK,EAAMF,EAAS,IAAMG,EAAON,EAAI,EAAE,CAAC,EAEnCO,EAAWJ,EAAS,IAAA,OAAM,QAAAK,EAAAR,EAAI,SAAJ,YAAAQ,EAAY,QAAS,SAAQ,EAEvDC,EAAmBN,EAAS,IAAA,OACtC,SAAAK,EAAAR,EAAI,SAAJ,YAAAQ,EAAY,OAAQ,CAAA,GAAI,OAAQE,GAAM,CAACA,EAAE,UAAU,EAAE,IAAKA,GAAMA,EAAE,IAAI,EACzE,EAEA,eAAsBC,GAA4B,CAChD,MAAMC,EAAKZ,EAAI,GACfA,EAAI,QAAU,GACd,MAAMa,EAAI,MAAMC,EAAI,IAAgB,oBAAoB,mBAAmBF,CAAE,CAAC,GAAGV,EAAU,KAAK,EAAE,EAGlG,GAAIF,EAAI,KAAOY,EAAI,OAGnB,GAFAZ,EAAI,QAAU,GAEV,CAACa,EAAE,GAAI,CACTb,EAAI,OAAS,KACbA,EAAI,MAAQe,EAAQF,EAAG,wBAAwBD,CAAE,EAAE,EACnD,MACF,CACAZ,EAAI,MAAQ,GACZ,MAAMgB,EAAIH,EAAE,KACZb,EAAI,OAAS,CACX,GAAIgB,EAAE,IAAMJ,EACZ,KAAMI,EAAE,OAAS,SAAW,SAAW,WACvC,UAAWA,EAAE,UACb,UAAWA,EAAE,UACb,MAAO,OAAOA,EAAE,OAAU,SAAWA,EAAE,MAAQ,GAC/C,KAAMA,EAAE,MAAQ,KAChB,QAASA,EAAE,QACP,CACE,KAAMA,EAAE,QAAQ,MAAQ,IACxB,SAAUA,EAAE,QAAQ,UAAY,CAAA,EAChC,SAAUA,EAAE,QAAQ,UAAY,CAAA,CAAC,EAEnC,KACJ,SAAU,MAAM,QAAQA,EAAE,QAAQ,EAAIA,EAAE,SAAW,CAAA,EACnD,MAAO,MAAM,QAAQA,EAAE,IAAI,EAAIA,EAAE,KAAO,CAAA,GAAI,IAAKN,IAAO,CACtD,KAAMA,EAAE,KACR,MAAO,MAAM,QAAQA,EAAE,KAAK,EAAIA,EAAE,MAAQ,CAAA,EAG1C,WAAYA,EAAE,aAAe,MAAM,QAAQA,EAAE,KAAK,GAAKA,EAAE,MAAM,SAAS,aAAa,EAAA,EACrF,EACF,IAAK,MAAM,QAAQM,EAAE,GAAG,EAAIA,EAAE,IAAM,CAAA,CAAC,CAEzC,CAGO,SAASC,EAAeL,EAAkB,CAC3CZ,EAAI,KAAOY,IAAOZ,EAAI,QAAUA,EAAI,SACxCA,EAAI,GAAKY,EACTZ,EAAI,OAAS,KACbA,EAAI,MAAQ,GACZA,EAAI,KAAOkB,EAASN,CAAE,EACjBD,EAAA,EACP,CAEO,SAASQ,GAAoB,CAClCC,EAAUpB,EAAI,GAAIA,EAAI,IAAI,CAC5B,CAEO,SAASqB,GAAkB,CAChCF,EAAA,EACKR,EAAA,CACP"}
package/dist/index.html CHANGED
@@ -27,8 +27,8 @@
27
27
  /* private mode: fall through to the OS preference */
28
28
  }
29
29
  </script>
30
- <script type="module" crossorigin src="/assets/index-wjzRhuU3.js"></script>
31
- <link rel="stylesheet" crossorigin href="/assets/index-Cyc_WOgY.css">
30
+ <script type="module" crossorigin src="/assets/index-DVMQBHXF.js"></script>
31
+ <link rel="stylesheet" crossorigin href="/assets/index-lyuEu6lW.css">
32
32
  </head>
33
33
  <body>
34
34
  <div id="app"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@samyx/preview-stacks-ui",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "private": false,
5
5
  "description": "The advanced web UI for preview-stacks — an opt-in SPA that talks to the pstack HTTP API.",
6
6
  "type": "module",
@@ -1,2 +0,0 @@
1
- import{C as v,A as g,J as k,O as j,P as C,B as $,r as u,Q as R,y as x,R as I,b as T,d as L,c as r,E as N,a as d,t as b,f as i,e as S,w as U,j as B,o as l}from"./index-wjzRhuU3.js";import{d as a,v as D,i as E}from"./useDeployment-B7kMYmcq.js";import{a as f}from"./useFormat-DVXTfIS-.js";const h=u(""),c=u(""),w=u(null),m=u(""),A=v(()=>{var e;return((e=a.detail)==null?void 0:e.busy)===!0}),G=v(()=>{var e;return((e=x.health)==null?void 0:e.authEnforced)===!0&&!I.token&&!T.authed}),H=v(()=>{const e=a.vars.filter(o=>o.k).map(o=>o.k);return e.length?`Sending ${e.join(", ")} with every action.`:"Using the variables saved with this deployment."});function K(e,o=!1){if(!a.detail)return"The spec has not resolved — the server cannot compute the stack name.";if(A.value)return`A job is already in flight for ${a.detail.stack}.`;if(e==="down"&&E.value&&!o)return`Type the stack name "${a.detail.stack}" below to confirm a shared teardown.`}async function X(e,o={}){if(!a.detail)return;h.value=e,c.value="",w.value=null;const t=e==="down"?{verify:o.verify??!0,force:o.force??!1}:{},s=await g.post(`/api/deployments/${encodeURIComponent(a.id)}/${e}${D.value}`,t);if(h.value="",s.status===202){const n=s.body.job;if(n!=null&&n.id){k("info",`${f(e)} started on ${n.stack}`,{to:`/jobs/${encodeURIComponent(n.id)}`,toLabel:"Follow"}),j(),C.push(`/jobs/${encodeURIComponent(n.id)}`);return}c.value="The action was accepted, but the response carried nothing to follow.";return}if(s.status===409)return F(s.body);c.value=$(s,f(e).toLowerCase()),k("error",`${f(e)} was refused.`)}async function F(e){var p;const o=R(e);w.value=o,m.value="";const t=o.stack||((p=a.detail)==null?void 0:p.stack);if(o.kind!=="other"||!t)return;const n=((await g.get("/api/jobs")).body.jobs??[]).find(y=>y.state==="running"&&y.stack===t);n&&(m.value=n.id)}function Y(){h.value="",c.value="",w.value=null,m.value=""}const V={class:"raw",style:{color:"var(--fg-dim)","max-height":"200px"}},J={key:0},Q={key:1},z={key:2},M={key:3},O={key:4},Z=L({__name:"ConflictNote",props:{conflict:{},jobId:{}},setup(e){return(o,t)=>{const s=B("RouterLink");return l(),r("div",{class:N(["banner",e.conflict.kind==="shared"?"leaked":"info"]),role:"alert"},[t[5]||(t[5]=d("b",null,"Refused — nothing was started.",-1)),d("pre",V,b(e.conflict.text),1),e.conflict.kind==="shared"?(l(),r("p",J,[...t[0]||(t[0]=[i(" Type the stack name in the confirmation field above and press ",-1),d("code",null,"down",-1),i(" again. ",-1)])])):e.conflict.kind==="containers"?(l(),r("p",Q,[...t[1]||(t[1]=[i(" Run ",-1),d("code",null,"down",-1),i(" first. Forgetting the record now would orphan those containers beyond the control plane's view: nothing left would know their stack name, their axes, or how to tear them down. ",-1)])])):e.conflict.kind==="referenced"?(l(),r("p",z,[t[2]||(t[2]=i(" These deployments still use this spec: ",-1)),d("strong",null,b(e.conflict.deployments.join(", ")),1),t[3]||(t[3]=i(". Deleting it would leave them with no way to be torn down. ",-1))])):e.jobId?(l(),r("p",M,[S(s,{to:`/jobs/${encodeURIComponent(e.jobId)}`},{default:U(()=>[...t[4]||(t[4]=[i("Follow the running job →",-1)])]),_:1},8,["to"])])):(l(),r("p",O,"Nothing was retried. Wait for the current work to finish, then try again."))],2)}}});export{Z as _,X as a,A as b,c,w as d,m as e,F as o,h as p,Y as r,G as t,H as v,K as w};
2
- //# sourceMappingURL=ConflictNote.vue_vue_type_script_setup_true_lang-fprimIle.js.map
@@ -1,2 +0,0 @@
1
- import{d as L,p as N,c as a,a as e,u as t,q as _,t as l,f as r,e as u,w as c,_ as k,F as m,s as w,g as h,x as g,y as v,z as i,r as z,A as R,B as S,C as V,j as $,o,D as x,E as A}from"./index-wjzRhuU3.js";import{a as I,b as U,t as q}from"./useFormat-DVXTfIS-.js";import{_ as F}from"./StateBadge.vue_vue_type_script_setup_true_lang-BsDpZsUH.js";import{_ as C}from"./SkeletonList.vue_vue_type_script_setup_true_lang-DwoeliUC.js";const H={key:0,class:"banner leaked land"},J={class:"grid-2"},T={class:"panel"},M={class:"phead"},O={key:0,class:"badge"},P={key:0,class:"s-failed"},Y={key:0,class:"banner warn"},G={key:1,class:"banner warn"},K={key:2,class:"banner failed"},Q={key:3,class:"cards"},W={class:"stagger"},X={class:"name","data-label":"service"},Z={class:"name dim","data-label":"image"},ss={class:"panel"},es={class:"phead"},ts={key:0,class:"s-failed"},os={class:"stats"},ns=["data-zero"],as={class:"v"},ls=["data-zero"],rs={class:"v"},is=["data-zero"],ds={class:"v"},us=["data-zero"],cs={class:"v"},hs=["data-zero"],vs={class:"v"},ms={key:0,class:"stat unknown"},ps={class:"v"},ks={key:0,class:"hint"},ys={key:1,class:"hint"},bs={class:"panel"},gs={class:"phead"},fs={key:0,class:"s-failed"},_s={key:2,class:"kvlist stagger"},ws={class:"k"},zs={class:"v"},Cs={class:"mute",style:{"font-size":"var(--t-xs)"}},Es={key:0,class:"mute"},Ls=L({__name:"DashboardView",setup(Ds){const d=z(null),y=z(""),E=z(!1);async function D(){const b=await R.get("/api/control");if(E.value=!0,!b.ok){y.value=S(b,"load the control stack");return}y.value="";const s=b.body;d.value={project:s.project??"",reachable:s.reachable!==!1,parseError:!!s.parseError,services:Array.isArray(s.services)?s.services:[],managedBy:s.managedBy??"",actionable:s.actionable===!0,note:s.note??""}}N(()=>void D(),1e4);const B=V(()=>v.jobs.slice(0,8));return(b,s)=>{var j;const p=$("RouterLink");return o(),a("div",null,[s[28]||(s[28]=e("div",{class:"page-head"},[e("div",null,[e("h1",null,"Dashboard"),e("div",{class:"sub"},"Everything running on this host.")])],-1)),t(_).length?(o(),a("div",H,[e("b",null,l(t(_).length)+" teardown(s) left something behind.",1),e("p",null,[s[1]||(s[1]=r(" Something survived being torn down, and nothing else is going to remove it. ",-1)),u(k,{label:"what was already cleaned up"},{default:c(()=>[...s[0]||(s[0]=[e("code",null,"compose down -v",-1),r(" removed the containers, volumes and networks — whatever is left is outside compose's reach. ",-1)])]),_:1}),(o(!0),a(m,null,w(t(_).slice(0,3),n=>(o(),g(p,{key:n.id,to:`/jobs/${encodeURIComponent(n.id)}`,style:{"margin-left":"8px"}},{default:c(()=>[r(l(n.stack)+" →",1)]),_:2},1032,["to"]))),128))])])):h("",!0),e("div",J,[e("section",T,[e("div",M,[s[3]||(s[3]=e("h2",{class:"section"},"Control stack",-1)),u(k,{label:"why there are no actions here"},{default:c(()=>{var n;return[s[2]||(s[2]=r(" pstack itself runs in this stack, so starting or stopping it here would kill the process handling the request — and a failed self-upgrade would leave the host with no control plane and no way back in. It is managed from the host instead. ",-1)),(n=d.value)!=null&&n.managedBy?(o(),a(m,{key:0},[r("Managed by "+l(d.value.managedBy)+".",1)],64)):h("",!0)]}),_:1}),(j=d.value)!=null&&j.project?(o(),a("span",O,l(d.value.project),1)):h("",!0),s[4]||(s[4]=e("span",{class:"grow"},null,-1)),e("button",{class:"sm ghost",onClick:D},"Refresh")]),y.value?(o(),a("p",P,l(y.value),1)):E.value?d.value?(o(),a(m,{key:2},[d.value.reachable?d.value.parseError?(o(),a("div",G,[...s[8]||(s[8]=[e("b",null,"Docker's answer could not be read.",-1),e("p",null,"Service state is unknown for this refresh; the stack itself may be fine.",-1)])])):d.value.services.length?h("",!0):(o(),a("div",K,[...s[9]||(s[9]=[e("b",null,"Nothing is running in this project.",-1),e("p",null," Docker answered clearly, so the control stack really is down — yet you are reading a page it serves. You are most likely reaching it by some other route. ",-1)])])):(o(),a("div",Y,[s[7]||(s[7]=e("b",null,"Docker did not answer.",-1)),e("p",null,[s[6]||(s[6]=r(" Check Docker is running, then refresh. ",-1)),u(k,{label:"why this is not the same as nothing running"},{default:c(()=>[...s[5]||(s[5]=[r(" This is ",-1),e("em",null,"not",-1),r(" the same as “nothing is running”: the control stack may be perfectly healthy while this process cannot reach the Docker socket. ",-1)])]),_:1})])])),d.value.services.length?(o(),a("table",Q,[s[10]||(s[10]=e("thead",null,[e("tr",null,[e("th",null,"Service"),e("th",null,"State"),e("th",null,"Health"),e("th",null,"Image")])],-1)),e("tbody",W,[(o(!0),a(m,null,w(d.value.services,(n,f)=>(o(),a("tr",{key:n.name,style:x({"--i":f})},[e("td",X,l(n.name),1),e("td",{"data-label":"state",class:A(n.state==="running"?"s-ok":"s-failed")},l(n.state||"—"),3),e("td",{"data-label":"health",class:A(n.health==="healthy"?"s-ok":n.health?"s-failed":"")},l(n.health||"—"),3),e("td",Z,l(n.image||"—"),1)],4))),128))])])):h("",!0)],64)):h("",!0):(o(),g(C,{key:1,rows:3}))]),e("div",null,[e("section",ss,[e("div",es,[s[12]||(s[12]=e("h2",{class:"section"},"Deployments",-1)),s[13]||(s[13]=e("span",{class:"grow"},null,-1)),u(p,{to:"/deployments"},{default:c(()=>[...s[11]||(s[11]=[r("all →",-1)])]),_:1})]),t(v).deploymentsError?(o(),a("p",ts,l(t(v).deploymentsError),1)):t(v).deploymentsLoaded?(o(),a(m,{key:2},[e("div",os,[e("div",{class:"stat","data-zero":t(i).total===0},[e("div",as,l(t(i).total),1),s[14]||(s[14]=e("div",{class:"k"},"total",-1))],8,ns),e("div",{class:"stat","data-zero":t(i).isolated===0},[e("div",rs,l(t(i).isolated),1),s[15]||(s[15]=e("div",{class:"k"},"isolated",-1))],8,ls),e("div",{class:"stat","data-zero":t(i).shared===0},[e("div",ds,l(t(i).shared),1),s[16]||(s[16]=e("div",{class:"k"},"shared",-1))],8,is),e("div",{class:"stat","data-zero":t(i).running===0},[e("div",cs,l(t(i).running),1),s[17]||(s[17]=e("div",{class:"k"},"running",-1))],8,us),e("div",{class:"stat busy","data-zero":t(i).busy===0},[e("div",vs,l(t(i).busy),1),s[18]||(s[18]=e("div",{class:"k"},"busy",-1))],8,hs),t(i).unknown?(o(),a("div",ms,[e("div",ps,l(t(i).unknown),1),s[19]||(s[19]=e("div",{class:"k"},"unknown",-1))])):h("",!0)]),t(i).unresolved?(o(),a("p",ks,[r(l(t(i).unresolved)+" deployment(s) are missing variables. ",1),u(p,{to:"/deployments"},{default:c(()=>[...s[20]||(s[20]=[r("Open one and set them.",-1)])]),_:1})])):t(i).unknown?(o(),a("p",ys,[s[22]||(s[22]=r(" “Unknown” means it could not be determined ",-1)),u(k,{label:"what unknown means"},{default:c(()=>[...s[21]||(s[21]=[r(" — ",-1),e("em",null,"not",-1),r(" that the deployment is idle. An unknown is never counted as a zero, which is how a live stack gets reported as torn down. ",-1)])]),_:1})])):h("",!0)],64)):(o(),g(C,{key:1,rows:2,tall:""}))]),e("section",bs,[e("div",gs,[s[24]||(s[24]=e("h2",{class:"section"},"Recent jobs",-1)),s[25]||(s[25]=e("span",{class:"grow"},null,-1)),u(p,{to:"/jobs"},{default:c(()=>[...s[23]||(s[23]=[r("all →",-1)])]),_:1})]),t(v).jobsError?(o(),a("p",fs,l(t(v).jobsError),1)):t(v).jobsLoaded?(o(),a("ul",_s,[(o(!0),a(m,null,w(B.value,(n,f)=>(o(),a("li",{key:n.id,style:x({"--i":f})},[e("span",ws,[u(F,{state:n.state},null,8,["state"])]),e("span",zs,[u(p,{to:`/jobs/${encodeURIComponent(n.id)}`},{default:c(()=>[r(l(t(I)(n.action))+" "+l(n.stack),1)]),_:2},1032,["to"]),e("span",Cs," · "+l(t(U)(n.startedAt))+" · "+l(t(q)(n.startedAt,n.endedAt)),1)])],4))),128)),B.value.length?h("",!0):(o(),a("li",Es,[s[27]||(s[27]=r(" No jobs yet. ",-1)),u(k,{label:"how long job history is kept"},{default:c(()=>[...s[26]||(s[26]=[r(" History is held in memory, so restarting the server clears it. A job record is the transcript of an attempt, not the truth about what exists now. ",-1)])]),_:1})]))])):(o(),g(C,{key:1,rows:4}))])])])])}}});export{Ls as default};
2
- //# sourceMappingURL=DashboardView-Cvh03qbj.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DashboardView-Cvh03qbj.js","sources":["../../src/views/DashboardView.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Dashboard: control-stack health, deployment counts, recent jobs, activity.\n *\n * The deployment and job lists are already polled by the shell, so this view only fetches the one\n * thing nobody else needs — the control stack.\n */\nimport { computed, ref } from 'vue';\nimport { api, problem } from '../api/client';\nimport type { Control } from '../api/types';\nimport { leakedJobs, state, summary } from '../composables/useControlPlane';\nimport { usePolling } from '../composables/usePolling';\nimport { actionLabel, ago, took } from '../composables/useFormat';\nimport StateBadge from '../components/StateBadge.vue';\nimport SkeletonList from '../components/SkeletonList.vue';\nimport InfoHint from '../components/InfoHint.vue';\n\nconst control = ref<Control | null>(null);\nconst controlError = ref('');\nconst controlLoaded = ref(false);\n\nasync function loadControl(): Promise<void> {\n const r = await api.get<Control>('/api/control');\n controlLoaded.value = true;\n if (!r.ok) {\n controlError.value = problem(r, 'load the control stack');\n return;\n }\n controlError.value = '';\n const b = r.body;\n control.value = {\n project: b.project ?? '',\n // `reachable !== false`, not `!!reachable`: an older build that omits the field should not be\n // reported as \"docker did not answer\".\n reachable: b.reachable !== false,\n parseError: !!b.parseError,\n services: Array.isArray(b.services) ? b.services : [],\n managedBy: b.managedBy ?? '',\n actionable: b.actionable === true,\n note: b.note ?? '',\n };\n}\n\nusePolling(() => void loadControl(), 10000);\n\nconst recentJobs = computed(() => state.jobs.slice(0, 8));\n</script>\n\n<template>\n <div>\n <div class=\"page-head\">\n <div>\n <h1>Dashboard</h1>\n <div class=\"sub\">Everything running on this host.</div>\n </div>\n </div>\n\n <!--\n A leak is the single thing this whole tool exists to catch, so it outranks every other panel\n on the page. Nothing else will clean up what survived a teardown.\n -->\n <div v-if=\"leakedJobs.length\" class=\"banner leaked land\">\n <b>{{ leakedJobs.length }} teardown(s) left something behind.</b>\n <p>\n Something survived being torn down, and nothing else is going to remove it.\n <InfoHint label=\"what was already cleaned up\">\n <code>compose down -v</code> removed the containers, volumes and networks — whatever is\n left is outside compose's reach.\n </InfoHint>\n <RouterLink\n v-for=\"j in leakedJobs.slice(0, 3)\"\n :key=\"j.id\"\n :to=\"`/jobs/${encodeURIComponent(j.id)}`\"\n style=\"margin-left: 8px\"\n >{{ j.stack }} →</RouterLink\n >\n </p>\n </div>\n\n <div class=\"grid-2\">\n <!-- ============================ control stack ============================ -->\n <section class=\"panel\">\n <div class=\"phead\">\n <h2 class=\"section\">Control stack</h2>\n <InfoHint label=\"why there are no actions here\">\n pstack itself runs in this stack, so starting or stopping it here would kill the process\n handling the request — and a failed self-upgrade would leave the host with no control\n plane and no way back in. It is managed from the host instead.\n <template v-if=\"control?.managedBy\">Managed by {{ control.managedBy }}.</template>\n </InfoHint>\n <span v-if=\"control?.project\" class=\"badge\">{{ control.project }}</span>\n <span class=\"grow\" />\n <button class=\"sm ghost\" @click=\"loadControl\">Refresh</button>\n </div>\n\n <p v-if=\"controlError\" class=\"s-failed\">{{ controlError }}</p>\n <SkeletonList v-else-if=\"!controlLoaded\" :rows=\"3\" />\n\n <template v-else-if=\"control\">\n <!--\n Three distinct failure shapes. Collapsing any of them into \"nothing is running\" would be\n a lie an operator acts on.\n -->\n <div v-if=\"!control.reachable\" class=\"banner warn\">\n <b>Docker did not answer.</b>\n <p>\n Check Docker is running, then refresh.\n <InfoHint label=\"why this is not the same as nothing running\">\n This is <em>not</em> the same as “nothing is running”: the control stack may be\n perfectly healthy while this process cannot reach the Docker socket.\n </InfoHint>\n </p>\n </div>\n <div v-else-if=\"control.parseError\" class=\"banner warn\">\n <b>Docker's answer could not be read.</b>\n <p>Service state is unknown for this refresh; the stack itself may be fine.</p>\n </div>\n <div v-else-if=\"!control.services.length\" class=\"banner failed\">\n <b>Nothing is running in this project.</b>\n <p>\n Docker answered clearly, so the control stack really is down — yet you are reading a\n page it serves. You are most likely reaching it by some other route.\n </p>\n </div>\n\n <table v-if=\"control.services.length\" class=\"cards\">\n <thead>\n <tr>\n <th>Service</th>\n <th>State</th>\n <th>Health</th>\n <th>Image</th>\n </tr>\n </thead>\n <tbody class=\"stagger\">\n <tr v-for=\"(s, i) in control.services\" :key=\"s.name\" :style=\"{ '--i': i }\">\n <td class=\"name\" data-label=\"service\">{{ s.name }}</td>\n <td data-label=\"state\" :class=\"s.state === 'running' ? 's-ok' : 's-failed'\">\n {{ s.state || '—' }}\n </td>\n <td\n data-label=\"health\"\n :class=\"s.health === 'healthy' ? 's-ok' : s.health ? 's-failed' : ''\"\n >\n {{ s.health || '—' }}\n </td>\n <td class=\"name dim\" data-label=\"image\">{{ s.image || '—' }}</td>\n </tr>\n </tbody>\n </table>\n\n <!--\n NEVER ADD AN ACTION HERE, not even a safe one. The API serving this page runs INSIDE this\n stack: `up` would kill the process performing it, and a failed self-upgrade leaves the\n host with no control plane and no remote way in. The server says `actionable: false` for\n exactly this reason.\n\n This used to be a banner reading \"Read-only — there are no actions here\", which spent a\n block of the page announcing the ABSENCE of something. Nobody looks at a panel with no\n buttons and wonders why; the handful who do get the reason from the hint in the header.\n -->\n </template>\n </section>\n\n <!-- ============================ deployments + jobs ============================ -->\n <div>\n <section class=\"panel\">\n <div class=\"phead\">\n <h2 class=\"section\">Deployments</h2>\n <span class=\"grow\" />\n <RouterLink to=\"/deployments\">all →</RouterLink>\n </div>\n\n <p v-if=\"state.deploymentsError\" class=\"s-failed\">{{ state.deploymentsError }}</p>\n <SkeletonList v-else-if=\"!state.deploymentsLoaded\" :rows=\"2\" tall />\n <template v-else>\n <!-- `data-zero` dims a nought so it stops competing with the counts that moved. -->\n <div class=\"stats\">\n <div class=\"stat\" :data-zero=\"summary.total === 0\"><div class=\"v\">{{ summary.total }}</div><div class=\"k\">total</div></div>\n <div class=\"stat\" :data-zero=\"summary.isolated === 0\"><div class=\"v\">{{ summary.isolated }}</div><div class=\"k\">isolated</div></div>\n <div class=\"stat\" :data-zero=\"summary.shared === 0\"><div class=\"v\">{{ summary.shared }}</div><div class=\"k\">shared</div></div>\n <div class=\"stat\" :data-zero=\"summary.running === 0\"><div class=\"v\">{{ summary.running }}</div><div class=\"k\">running</div></div>\n <div class=\"stat busy\" :data-zero=\"summary.busy === 0\"><div class=\"v\">{{ summary.busy }}</div><div class=\"k\">busy</div></div>\n <!--\n The server sends `null`, never `false`, when it could not determine busy/running.\n An unknown must never be counted as a zero — that is how a live stack gets reported\n as torn down. It gets its own tile.\n -->\n <div v-if=\"summary.unknown\" class=\"stat unknown\">\n <div class=\"v\">{{ summary.unknown }}</div>\n <div class=\"k\">unknown</div>\n </div>\n </div>\n\n <p v-if=\"summary.unresolved\" class=\"hint\">\n {{ summary.unresolved }} deployment(s) are missing variables.\n <RouterLink to=\"/deployments\">Open one and set them.</RouterLink>\n </p>\n <p v-else-if=\"summary.unknown\" class=\"hint\">\n “Unknown” means it could not be determined\n <InfoHint label=\"what unknown means\">\n — <em>not</em> that the deployment is idle. An unknown is never counted as a zero,\n which is how a live stack gets reported as torn down.\n </InfoHint>\n </p>\n </template>\n </section>\n\n <section class=\"panel\">\n <div class=\"phead\">\n <h2 class=\"section\">Recent jobs</h2>\n <span class=\"grow\" />\n <RouterLink to=\"/jobs\">all →</RouterLink>\n </div>\n\n <p v-if=\"state.jobsError\" class=\"s-failed\">{{ state.jobsError }}</p>\n <SkeletonList v-else-if=\"!state.jobsLoaded\" :rows=\"4\" />\n <ul v-else class=\"kvlist stagger\">\n <li v-for=\"(j, i) in recentJobs\" :key=\"j.id\" :style=\"{ '--i': i }\">\n <span class=\"k\"><StateBadge :state=\"j.state\" /></span>\n <span class=\"v\">\n <RouterLink :to=\"`/jobs/${encodeURIComponent(j.id)}`\">\n {{ actionLabel(j.action) }} {{ j.stack }}\n </RouterLink>\n <span class=\"mute\" style=\"font-size: var(--t-xs)\">\n · {{ ago(j.startedAt) }} · {{ took(j.startedAt, j.endedAt) }}\n </span>\n </span>\n </li>\n <li v-if=\"!recentJobs.length\" class=\"mute\">\n No jobs yet.\n <InfoHint label=\"how long job history is kept\">\n History is held in memory, so restarting the server clears it. A job record is the\n transcript of an attempt, not the truth about what exists now.\n </InfoHint>\n </li>\n </ul>\n </section>\n </div>\n </div>\n </div>\n</template>\n"],"names":["control","ref","controlError","controlLoaded","loadControl","r","api","problem","b","usePolling","recentJobs","computed","state","_createElementBlock","_createElementVNode","_unref","leakedJobs","_openBlock","_hoisted_1","_toDisplayString","_createVNode","InfoHint","_cache","_Fragment","_renderList","j","_createBlock","_component_RouterLink","_hoisted_2","_hoisted_3","_hoisted_4","_a","_createTextVNode","_hoisted_5","_hoisted_6","_hoisted_8","_hoisted_9","_hoisted_7","_hoisted_10","_hoisted_11","s","i","_hoisted_12","_normalizeClass","_hoisted_13","SkeletonList","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","summary","_hoisted_19","_hoisted_21","_hoisted_23","_hoisted_25","_hoisted_27","_hoisted_28","_hoisted_29","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_hoisted_34","_hoisted_35","_hoisted_36","StateBadge","_hoisted_37","actionLabel","_hoisted_38","ago","_hoisted_39"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{d as B,H as c,c as i,a,e as l,w as r,t as m,u as t,f as o,E as L,g as d,x as y,F as N,s as S,_,j as x,o as s,T as j,k as q,I as z}from"./index-wjzRhuU3.js";import{s as E}from"./useFormat-DVXTfIS-.js";import{d as n,i as U,o as F}from"./useDeployment-B7kMYmcq.js";import{a as C,w as D,p as f,b as R,c as $,d as V,e as H,_ as J,r as O}from"./ConflictNote.vue_vue_type_script_setup_true_lang-fprimIle.js";import{_ as h}from"./ActionButton.vue_vue_type_script_setup_true_lang-CeingrPV.js";import{_ as I}from"./ErrorNote.vue_vue_type_script_setup_true_lang-DT5SbSbT.js";import"./useVars-VN9gYdR6.js";const G={class:"page-head"},K={class:"mute",style:{"font-size":"var(--t-sm)"}},M={style:{"font-size":"var(--t-xl)"}},P={class:"sub"},Q={key:0},W={key:1},X={key:2},Y={key:1,class:"badge busy"},Z={key:2,class:"row",style:{"flex-wrap":"nowrap"}},ee={class:"tabs","aria-label":"Deployment sections"},te={key:3,class:"hint"},se={key:4,class:"hint",style:{"margin-bottom":"var(--s4)"}},ue=B({__name:"DeploymentDetailView",props:{id:{}},setup(b){const v=b,g=q(),T=[{to:"overview",label:"Overview"},{to:"runtime",label:"Containers & routes"},{to:"config",label:"Config & variables"},{to:"axes",label:"Axes"},{to:"requires",label:"Requires"},{to:"logs",label:"Logs"},{to:"terminal",label:"Terminal"},{to:"danger",label:"Danger"}];return c(()=>v.id,p=>{F(p),O()},{immediate:!0}),c(()=>n.error,p=>{p&&g.currentRoute.value.name==="d.overview"&&g.replace(`/deployments/${encodeURIComponent(v.id)}/config`)}),(p,e)=>{var w;const k=x("RouterLink"),A=x("RouterView");return s(),i("div",null,[a("div",G,[a("div",null,[a("div",K,[l(k,{to:"/deployments"},{default:r(()=>[...e[2]||(e[2]=[o("← Deployments",-1)])]),_:1})]),a("h1",M,m(b.id),1),a("div",P,[t(n).detail?(s(),i("span",Q,[e[3]||(e[3]=o(" stack ",-1)),a("b",null,m(t(n).detail.stack),1)])):t(n).error?(s(),i("span",W,"unresolved")):(s(),i("span",X,"loading…"))])]),e[7]||(e[7]=a("span",{class:"grow"},null,-1)),t(n).detail?(s(),i("span",{key:0,class:L(["badge",t(n).detail.kind])},m(t(E)(t(n).detail.kind)),3)):d("",!0),((w=t(n).detail)==null?void 0:w.busy)===!0?(s(),i("span",Y,[...e[4]||(e[4]=[a("span",{class:"dot pulse"},null,-1),o("busy",-1)])])):d("",!0),t(n).detail?(s(),i("div",Z,[l(h,{variant:"primary",pending:t(f)==="up",disabled:!!t(f)||t(R),title:t(D)("up"),onClick:e[0]||(e[0]=u=>t(C)("up"))},{default:r(()=>[...e[5]||(e[5]=[o(" Deploy ",-1)])]),_:1},8,["pending","disabled","title"]),l(h,{pending:t(f)==="verify",disabled:!!t(f)||t(R),title:t(D)("verify"),onClick:e[1]||(e[1]=u=>t(C)("verify"))},{default:r(()=>[...e[6]||(e[6]=[o(" Verify ",-1)])]),_:1},8,["pending","disabled","title"])])):d("",!0)]),t($)?(s(),y(I,{key:0,text:t($),title:"The action was refused."},null,8,["text"])):d("",!0),t(V)?(s(),y(J,{key:1,conflict:t(V),"job-id":t(H),style:{"margin-bottom":"var(--s4)"}},null,8,["conflict","job-id"])):d("",!0),a("nav",ee,[(s(),i(N,null,S(T,u=>l(k,{key:u.to,to:`/deployments/${encodeURIComponent(b.id)}/${u.to}`},{default:r(()=>[o(m(u.label),1)]),_:2},1032,["to"])),64))]),t(n).error?(s(),y(I,{key:2,text:t(n).error,title:"Could not resolve this deployment."},null,8,["text"])):d("",!0),t(n).error?(s(),i("p",te,[e[9]||(e[9]=o(" If that message names a variable, add it under ",-1)),e[10]||(e[10]=a("b",null,"Config & variables",-1)),e[11]||(e[11]=o(" and press ",-1)),e[12]||(e[12]=a("b",null,"Apply & reload",-1)),e[13]||(e[13]=o(". ",-1)),l(_,{label:"why the rest of the page is unavailable"},{default:r(()=>[...e[8]||(e[8]=[o(" Until the spec resolves there is no stack name, and every action on this deployment needs one. ",-1)])]),_:1})])):d("",!0),t(U)?(s(),i("p",se,[e[15]||(e[15]=o(" Shared with every preview on this host. ",-1)),l(_,{label:"what a shared deployment is"},{default:r(()=>[...e[14]||(e[14]=[o(" A host singleton that previews borrow — a database, a queue, a registry mirror. It declares no axes, and tearing it down needs an explicit confirmation, because doing so destroys state every other deployment depends on. ",-1)])]),_:1})])):d("",!0),l(A,null,{default:r(({Component:u})=>[l(j,{name:"view",mode:"out-in"},{default:r(()=>[(s(),y(z(u)))]),_:2},1024)]),_:1})])}}});export{ue as default};
2
- //# sourceMappingURL=DeploymentDetailView-BzEQBKhd.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DeploymentDetailView-BzEQBKhd.js","sources":["../../src/views/DeploymentDetailView.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * The detail shell: breadcrumb, tabs, and the resolve-failure banner that gates the rest.\n *\n * A deployment whose spec will not resolve is not a dead end — the fix (its variables) lives on\n * the Config tab, so this sends the operator there rather than leaving them in front of an error\n * with no control in reach. Everything else stays unavailable until it resolves, because the\n * server cannot name the stack without the variables, and every action needs the stack name.\n */\nimport { watch } from 'vue';\nimport { sentence } from '../composables/useFormat';\nimport { useRouter } from 'vue-router';\nimport { dep, isShared, openDeployment } from '../composables/useDeployment';\nimport {\n act,\n actionError,\n busy,\n conflict,\n conflictJobId,\n pending,\n resetActions,\n whyDisabled,\n} from '../composables/useDeploymentActions';\nimport ActionButton from '../components/ActionButton.vue';\nimport ConflictNote from '../components/ConflictNote.vue';\nimport ErrorNote from '../components/ErrorNote.vue';\nimport InfoHint from '../components/InfoHint.vue';\n\nconst props = defineProps<{ id: string }>();\nconst router = useRouter();\n\nconst TABS = [\n { to: 'overview', label: 'Overview' },\n // Second, not buried: \"the hostname does not work\" is the most common question, and this is the\n // only tab that can answer it.\n { to: 'runtime', label: 'Containers & routes' },\n { to: 'config', label: 'Config & variables' },\n { to: 'axes', label: 'Axes' },\n { to: 'requires', label: 'Requires' },\n { to: 'logs', label: 'Logs' },\n // After Logs: a shell is what you reach for when the logs did not answer it.\n { to: 'terminal', label: 'Terminal' },\n { to: 'danger', label: 'Danger' },\n] as const;\n\nwatch(\n () => props.id,\n (id) => {\n openDeployment(id);\n // A stale \"refused\" from the previous deployment must not greet the next one.\n resetActions();\n },\n { immediate: true },\n);\n\n// Land the operator on the editor when the spec will not resolve — but only from the tab that has\n// nothing to show. Sending them away from Logs or Danger mid-read would be its own annoyance.\nwatch(\n () => dep.error,\n (err) => {\n if (err && router.currentRoute.value.name === 'd.overview') {\n void router.replace(`/deployments/${encodeURIComponent(props.id)}/config`);\n }\n },\n);\n</script>\n\n<template>\n <div>\n <div class=\"page-head\">\n <div>\n <div class=\"mute\" style=\"font-size: var(--t-sm)\">\n <RouterLink to=\"/deployments\">← Deployments</RouterLink>\n </div>\n <h1 style=\"font-size: var(--t-xl)\">{{ id }}</h1>\n <div class=\"sub\">\n <span v-if=\"dep.detail\">\n stack <b>{{ dep.detail.stack }}</b>\n </span>\n <span v-else-if=\"dep.error\">unresolved</span>\n <span v-else>loading…</span>\n </div>\n </div>\n <span class=\"grow\" />\n <span v-if=\"dep.detail\" class=\"badge\" :class=\"dep.detail.kind\">{{ sentence(dep.detail.kind) }}</span>\n <span v-if=\"dep.detail?.busy === true\" class=\"badge busy\"><span class=\"dot pulse\" />busy</span>\n <!--\n Deploy and Verify live HERE, on every tab — they are the product's routine actions, and they\n used to be reachable only through a tab named \"Danger\". Teardown stays there: the header\n carries what is safe to reach for, the Danger tab carries what deserves the walk.\n -->\n <!-- One flex unit, so on a narrow screen the pair wraps together instead of Verify being\n orphaned onto its own line under the title. -->\n <div v-if=\"dep.detail\" class=\"row\" style=\"flex-wrap: nowrap\">\n <ActionButton\n variant=\"primary\"\n :pending=\"pending === 'up'\"\n :disabled=\"!!pending || busy\"\n :title=\"whyDisabled('up')\"\n @click=\"act('up')\"\n >\n Deploy\n </ActionButton>\n <ActionButton\n :pending=\"pending === 'verify'\"\n :disabled=\"!!pending || busy\"\n :title=\"whyDisabled('verify')\"\n @click=\"act('verify')\"\n >\n Verify\n </ActionButton>\n </div>\n </div>\n\n <ErrorNote v-if=\"actionError\" :text=\"actionError\" title=\"The action was refused.\" />\n <ConflictNote\n v-if=\"conflict\"\n :conflict=\"conflict\"\n :job-id=\"conflictJobId\"\n style=\"margin-bottom: var(--s4)\"\n />\n\n <nav class=\"tabs\" aria-label=\"Deployment sections\">\n <RouterLink\n v-for=\"t in TABS\"\n :key=\"t.to\"\n :to=\"`/deployments/${encodeURIComponent(id)}/${t.to}`\"\n >{{ t.label }}</RouterLink\n >\n </nav>\n\n <ErrorNote v-if=\"dep.error\" :text=\"dep.error\" title=\"Could not resolve this deployment.\">\n </ErrorNote>\n <p v-if=\"dep.error\" class=\"hint\">\n If that message names a variable, add it under <b>Config &amp; variables</b> and press\n <b>Apply &amp; reload</b>.\n <InfoHint label=\"why the rest of the page is unavailable\">\n Until the spec resolves there is no stack name, and every action on this deployment needs one.\n </InfoHint>\n </p>\n\n <p v-if=\"isShared\" class=\"hint\" style=\"margin-bottom: var(--s4)\">\n Shared with every preview on this host.\n <InfoHint label=\"what a shared deployment is\">\n A host singleton that previews borrow — a database, a queue, a registry mirror. It declares no\n axes, and tearing it down needs an explicit confirmation, because doing so destroys state\n every other deployment depends on.\n </InfoHint>\n </p>\n\n <RouterView v-slot=\"{ Component }\">\n <Transition name=\"view\" mode=\"out-in\">\n <component :is=\"Component\" />\n </Transition>\n </RouterView>\n </div>\n</template>\n"],"names":["props","__props","router","useRouter","TABS","watch","id","openDeployment","resetActions","dep","err","_createElementBlock","_createElementVNode","_hoisted_1","_hoisted_2","_createVNode","_component_RouterLink","_cache","_hoisted_3","_toDisplayString","_hoisted_4","_unref","_hoisted_5","_openBlock","sentence","_hoisted_8","_hoisted_9","ActionButton","pending","busy","whyDisabled","act","actionError","_createBlock","ErrorNote","conflict","ConflictNote","conflictJobId","_hoisted_10","_Fragment","_renderList","t","_createTextVNode","_hoisted_11","InfoHint","isShared","_hoisted_12","_component_RouterView","_withCtx","Component","_Transition","_resolveDynamicComponent"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{d as $,o as l,c as n,a as t,f as o,t as a,u as r,z as g,e as u,w as k,i as w,v as B,g as f,G as L,y as p,x as N,F as b,s as C,r as h,C as x,j as R,D as U,E as D}from"./index-wjzRhuU3.js";import{s as I}from"./useFormat-DVXTfIS-.js";import{_ as z}from"./SkeletonList.vue_vue_type_script_setup_true_lang-DwoeliUC.js";import{_ as E}from"./RelativeTime.vue_vue_type_script_setup_true_lang-D7n5E9jw.js";import{_ as q}from"./SelectMenu.vue_vue_type_script_setup_true_lang-CSQS6ben.js";import"./Teleport-BXE_6A8N.js";const A={key:0,class:"badge busy"},F={key:1,class:"badge ok"},M={key:2,class:"badge unknown",title:"the server could not determine this — it is not the same as idle"},T={key:3,class:"badge"},j=$({__name:"RunStateBadge",props:{busy:{type:[Boolean,null]},running:{type:[Boolean,null]}},setup(m){return(y,i)=>m.busy===!0?(l(),n("span",A,[...i[0]||(i[0]=[t("span",{class:"dot pulse"},null,-1),o("Busy",-1)])])):m.running===!0?(l(),n("span",F,[...i[1]||(i[1]=[t("span",{class:"dot"},null,-1),o("Running",-1)])])):m.busy===null||m.running===null?(l(),n("span",M,"Unknown")):(l(),n("span",T,"Idle"))}}),G={class:"page-head"},K={class:"sub"},H={class:"panel"},J={class:"phead"},O={class:"searchbox"},P={key:0},Q={class:"check"},W={key:0,class:"s-failed"},X={class:"cards"},Y={class:"stagger"},Z={"data-label":"id"},ee={key:0,class:"mute",style:{"font-size":"var(--t-xs)"}},te={"data-label":"kind"},se={class:"name dim","data-label":"stack"},le={key:0},ne={key:1,class:"badge warn",title:"the spec could not be resolved without variables"},oe={"data-label":"state"},ae={class:"dim nowrap","data-label":"updated"},ie={key:0},re={colspan:"5",class:"mute"},de={class:"mono"},ke=$({__name:"DeploymentsView",setup(m){const y=h(""),i=h("all"),c=h(!1),_=x(()=>{const d=y.value.trim().toLowerCase();return p.deployments.filter(e=>i.value!=="all"&&e.kind!==i.value||c.value&&!(e.running===!0||e.busy===!0)?!1:d?e.id.toLowerCase().includes(d)||(e.stack??"").toLowerCase().includes(d)||(e.specName??"").toLowerCase().includes(d):!0)}),V=x(()=>p.deployments.filter(d=>d.unresolved));return(d,e)=>{const v=R("RouterLink");return l(),n("div",null,[t("div",G,[t("div",null,[e[3]||(e[3]=t("h1",null,"Deployments",-1)),t("div",K,a(r(g).total)+" submitted · "+a(r(g).running)+" running · "+a(r(g).busy)+" busy ",1)]),e[5]||(e[5]=t("span",{class:"grow"},null,-1)),u(v,{to:"/submit",class:"btn"},{default:k(()=>[...e[4]||(e[4]=[o("+ Submit",-1)])]),_:1})]),t("section",H,[t("div",J,[t("div",O,[e[6]||(e[6]=t("svg",{viewBox:"0 0 24 24",width:"15",height:"15","aria-hidden":"true"},[t("circle",{cx:"11",cy:"11",r:"7",fill:"none",stroke:"currentColor","stroke-width":"2"}),t("path",{d:"M16.5 16.5 21 21",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round"})],-1)),w(t("input",{id:"q","onUpdate:modelValue":e[0]||(e[0]=s=>y.value=s),"data-search":"",type:"search","aria-label":"Search deployments",placeholder:"Search by id, stack or spec",spellcheck:"false"},null,512),[[B,y.value]]),y.value?f("",!0):(l(),n("kbd",P,"/"))]),u(q,{modelValue:i.value,"onUpdate:modelValue":e[1]||(e[1]=s=>i.value=s),label:"Filter by kind",options:[{value:"all",label:"All kinds"},{value:"isolated",label:"Isolated"},{value:"shared",label:"Shared"}]},null,8,["modelValue"]),t("label",Q,[w(t("input",{"onUpdate:modelValue":e[2]||(e[2]=s=>c.value=s),type:"checkbox"},null,512),[[L,c.value]]),e[7]||(e[7]=o(" Running or busy only ",-1))])]),r(p).deploymentsError?(l(),n("p",W,a(r(p).deploymentsError),1)):r(p).deploymentsLoaded?(l(),n(b,{key:2},[t("table",X,[e[11]||(e[11]=t("thead",null,[t("tr",null,[t("th",null,"ID"),t("th",null,"Kind"),t("th",null,"Stack"),t("th",null,"State"),t("th",null,"Updated")])],-1)),t("tbody",Y,[(l(!0),n(b,null,C(_.value,(s,S)=>(l(),n("tr",{key:s.id,style:U({"--i":S})},[t("td",Z,[u(v,{to:`/deployments/${encodeURIComponent(s.id)}`},{default:k(()=>[o(a(s.id),1)]),_:2},1032,["to"]),s.specName?(l(),n("div",ee," spec: "+a(s.specName),1)):f("",!0)]),t("td",te,[t("span",{class:D(["badge",s.kind])},a(r(I)(s.kind)),3)]),t("td",se,[s.stack?(l(),n("span",le,a(s.stack),1)):(l(),n("span",ne," needs variables "))]),t("td",oe,[u(j,{busy:s.busy,running:s.running},null,8,["busy","running"])]),t("td",ae,[u(E,{at:s.updatedAt},null,8,["at"])])],4))),128)),_.value.length?f("",!0):(l(),n("tr",ie,[t("td",re,[r(p).deployments.length?(l(),n(b,{key:0},[o(" Nothing matches this filter. ")],64)):(l(),n(b,{key:1},[e[9]||(e[9]=o(" Nothing submitted yet — ",-1)),u(v,{to:"/submit"},{default:k(()=>[...e[8]||(e[8]=[o("submit a spec",-1)])]),_:1}),e[10]||(e[10]=o(" to put a deployment in the registry. ",-1))],64))])]))])]),(l(!0),n(b,null,C(V.value,s=>(l(),n("div",{key:`u-${s.id}`,class:"banner warn"},[t("b",null,a(s.id),1),e[19]||(e[19]=o(" could not be resolved: ",-1)),t("span",de,a(s.unresolved),1),t("p",null,[e[13]||(e[13]=o(" This listing resolves every spec with the ",-1)),e[14]||(e[14]=t("em",null,"same",-1)),e[15]||(e[15]=o(" (empty) request variables, so a spec with a ",-1)),e[16]||(e[16]=t("code",null,"${VAR}",-1)),e[17]||(e[17]=o(" the server does not already hold will always appear here. ",-1)),u(v,{to:`/deployments/${encodeURIComponent(s.id)}/config`},{default:k(()=>[...e[12]||(e[12]=[o(" Set its variables ",-1)])]),_:1},8,["to"]),e[18]||(e[18]=o(" and the detail view will resolve. ",-1))])]))),128))],64)):(l(),N(z,{key:1,rows:4,tall:""}))])])}}});export{ke as default};
2
- //# sourceMappingURL=DeploymentsView-f3RgqUkQ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DeploymentsView-f3RgqUkQ.js","sources":["../../src/components/RunStateBadge.vue","../../src/views/DeploymentsView.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * A deployment's live state, from the two TRI-STATE fields the server sends.\n *\n * `busy` and `running` are `boolean | null`, and `null` means \"the server could not determine\n * this\": an unresolved spec has no stack name to look up, and a docker that did not answer is not\n * the same fact as \"nothing is running\". Rendering either as \"idle\" would be a guess presented as\n * a fact — that is how a live stack gets reported as torn down and someone forgets it.\n *\n * So unknown says unknown, and it gets its own colour.\n */\ndefineProps<{ busy: boolean | null; running: boolean | null }>();\n</script>\n\n<template>\n <span v-if=\"busy === true\" class=\"badge busy\"><span class=\"dot pulse\" />Busy</span>\n <span v-else-if=\"running === true\" class=\"badge ok\"><span class=\"dot\" />Running</span>\n <span\n v-else-if=\"busy === null || running === null\"\n class=\"badge unknown\"\n title=\"the server could not determine this — it is not the same as idle\"\n >Unknown</span\n >\n <span v-else class=\"badge\">Idle</span>\n</template>\n","<script setup lang=\"ts\">\n/**\n * The deployment list: searchable, filterable, and honest about what could not be resolved.\n *\n * Filtering is client-side because the API has no query parameters for it and the list is one\n * host's worth of previews — a few dozen rows, already in memory from the shell's poll.\n */\nimport { computed, ref } from 'vue';\nimport { sentence } from '../composables/useFormat';\nimport { state, summary } from '../composables/useControlPlane';\n\nimport RunStateBadge from '../components/RunStateBadge.vue';\nimport SkeletonList from '../components/SkeletonList.vue';\nimport RelativeTime from '../components/RelativeTime.vue';\nimport SelectMenu from '../components/SelectMenu.vue';\n\nconst q = ref('');\nconst kind = ref<'all' | 'isolated' | 'shared'>('all');\nconst onlyLive = ref(false);\n\nconst rows = computed(() => {\n const needle = q.value.trim().toLowerCase();\n return state.deployments.filter((d) => {\n if (kind.value !== 'all' && d.kind !== kind.value) return false;\n // \"Live\" means DEMONSTRABLY live. An unknown is not evidence of either state, so it is not\n // silently included here — the filter says what it filters.\n if (onlyLive.value && !(d.running === true || d.busy === true)) return false;\n if (!needle) return true;\n return (\n d.id.toLowerCase().includes(needle) ||\n (d.stack ?? '').toLowerCase().includes(needle) ||\n (d.specName ?? '').toLowerCase().includes(needle)\n );\n });\n});\n\nconst unresolvedRows = computed(() => state.deployments.filter((d) => d.unresolved));\n</script>\n\n<template>\n <div>\n <div class=\"page-head\">\n <div>\n <h1>Deployments</h1>\n <div class=\"sub\">\n {{ summary.total }} submitted · {{ summary.running }} running · {{ summary.busy }} busy\n </div>\n </div>\n <span class=\"grow\" />\n <RouterLink to=\"/submit\" class=\"btn\">+ Submit</RouterLink>\n </div>\n\n <section class=\"panel\">\n <div class=\"phead\">\n <!--\n One row of equal-height controls. Each used to sit under its own stacked label, which cost\n a line of vertical space per control, put \"Search — press /\" on screen as a permanent\n instruction, and left the two fields 8px out of vertical alignment because a `select` and\n an `input` do not have the same intrinsic height. A placeholder says the same thing in the\n place you are already looking, and the select's own options say what it filters.\n -->\n <div class=\"searchbox\">\n <svg viewBox=\"0 0 24 24\" width=\"15\" height=\"15\" aria-hidden=\"true\">\n <circle cx=\"11\" cy=\"11\" r=\"7\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" />\n <path d=\"M16.5 16.5 21 21\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n <input\n id=\"q\"\n v-model=\"q\"\n data-search\n type=\"search\"\n aria-label=\"Search deployments\"\n placeholder=\"Search by id, stack or spec\"\n spellcheck=\"false\"\n />\n <kbd v-if=\"!q\">/</kbd>\n </div>\n <SelectMenu\n v-model=\"kind\"\n label=\"Filter by kind\"\n :options=\"[\n { value: 'all', label: 'All kinds' },\n { value: 'isolated', label: 'Isolated' },\n { value: 'shared', label: 'Shared' },\n ]\"\n />\n <label class=\"check\">\n <input v-model=\"onlyLive\" type=\"checkbox\" />\n Running or busy only\n </label>\n </div>\n\n <p v-if=\"state.deploymentsError\" class=\"s-failed\">{{ state.deploymentsError }}</p>\n <SkeletonList v-else-if=\"!state.deploymentsLoaded\" :rows=\"4\" tall />\n\n <template v-else>\n <table class=\"cards\">\n <thead>\n <tr>\n <th>ID</th>\n <th>Kind</th>\n <th>Stack</th>\n <th>State</th>\n <th>Updated</th>\n </tr>\n </thead>\n <tbody class=\"stagger\">\n <tr v-for=\"(d, i) in rows\" :key=\"d.id\" :style=\"{ '--i': i }\">\n <td data-label=\"id\">\n <RouterLink :to=\"`/deployments/${encodeURIComponent(d.id)}`\">\n {{ d.id }}\n </RouterLink>\n <div v-if=\"d.specName\" class=\"mute\" style=\"font-size: var(--t-xs)\">\n spec: {{ d.specName }}\n </div>\n </td>\n <td data-label=\"kind\"><span class=\"badge\" :class=\"d.kind\">{{ sentence(d.kind) }}</span></td>\n <td class=\"name dim\" data-label=\"stack\">\n <span v-if=\"d.stack\">{{ d.stack }}</span>\n <!--\n No stack name means the spec could not be resolved with the variables this\n listing had. It is not an error state for the deployment — it is a missing input.\n -->\n <span v-else class=\"badge warn\" title=\"the spec could not be resolved without variables\">\n needs variables\n </span>\n </td>\n <td data-label=\"state\"><RunStateBadge :busy=\"d.busy\" :running=\"d.running\" /></td>\n <td class=\"dim nowrap\" data-label=\"updated\"><RelativeTime :at=\"d.updatedAt\" /></td>\n </tr>\n <tr v-if=\"!rows.length\">\n <td colspan=\"5\" class=\"mute\">\n <template v-if=\"state.deployments.length\">\n Nothing matches this filter.\n </template>\n <template v-else>\n Nothing submitted yet — <RouterLink to=\"/submit\">submit a spec</RouterLink> to\n put a deployment in the registry.\n </template>\n </td>\n </tr>\n </tbody>\n </table>\n\n <!-- One message per unresolved row, verbatim: it names the missing variable. -->\n <div v-for=\"d in unresolvedRows\" :key=\"`u-${d.id}`\" class=\"banner warn\">\n <b>{{ d.id }}</b> could not be resolved:\n <span class=\"mono\">{{ d.unresolved }}</span>\n <p>\n This listing resolves every spec with the <em>same</em> (empty) request variables, so a\n spec with a <code>${VAR}</code> the server does not already hold will always appear\n here.\n <RouterLink :to=\"`/deployments/${encodeURIComponent(d.id)}/config`\">\n Set its variables\n </RouterLink>\n and the detail view will resolve.\n </p>\n </div>\n </template>\n </section>\n </div>\n</template>\n"],"names":["__props","_openBlock","_createElementBlock","_hoisted_1","_cache","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_4","q","ref","kind","onlyLive","rows","computed","needle","state","d","unresolvedRows","_toDisplayString","_unref","_createVNode","_component_RouterLink","_hoisted_5","$event","SelectMenu","_hoisted_7","_hoisted_8","_Fragment","_hoisted_9","_hoisted_10","_renderList","i","_hoisted_11","_createTextVNode","_hoisted_12","_hoisted_13","_normalizeClass","sentence","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","RunStateBadge","_hoisted_18","RelativeTime","_hoisted_19","_hoisted_20","_hoisted_21","_createBlock","SkeletonList"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{u as k,c as R,a as D,P as B,b as w,g as F,D as T,d as K,F as N,e as E,f as V,h as M,i as S,T as L}from"./Teleport-BXE_6A8N.js";import{d as g,V as H,W as v,u as e,r as b,o as c,x as _,w as u,X as m,Y as A,e as O,h as j,g as z,Z as U,$ as W,a as q,f as I,t as X}from"./index-wjzRhuU3.js";const[C,Y]=R("DialogRoot");var Z=g({inheritAttrs:!1,__name:"DialogRoot",props:{open:{type:Boolean,required:!1,default:void 0},defaultOpen:{type:Boolean,required:!1,default:!1},modal:{type:Boolean,required:!1,default:!0}},emits:["update:open"],setup(r,{emit:l}){const t=r,o=k(t,"open",l,{defaultValue:t.defaultOpen,passive:t.open===void 0}),d=b(),f=b(),{modal:i}=H(t);return Y({open:o,modal:i,openModal:()=>{o.value=!0},onOpenChange:n=>{o.value=n},onOpenToggle:()=>{o.value=!o.value},contentId:"",titleId:"",descriptionId:"",triggerElement:d,contentElement:f}),(n,s)=>v(n.$slots,"default",{open:e(o),close:()=>o.value=!1})}}),G=Z,J=g({__name:"DialogClose",props:{asChild:{type:Boolean,required:!1},as:{type:null,required:!1,default:"button"}},setup(r){const l=r;D();const t=C();return(a,o)=>(c(),_(e(B),m(l,{type:a.as==="button"?"button":void 0,onClick:o[0]||(o[0]=d=>e(t).onOpenChange(!1))}),{default:u(()=>[v(a.$slots,"default")]),_:3},16,["type"]))}}),Q=J,x=g({__name:"DialogContentImpl",props:{forceMount:{type:Boolean,required:!1},trapFocus:{type:Boolean,required:!1},disableOutsidePointerEvents:{type:Boolean,required:!1},asChild:{type:Boolean,required:!1},as:{type:null,required:!1}},emits:["escapeKeyDown","pointerDownOutside","focusOutside","interactOutside","openAutoFocus","closeAutoFocus"],setup(r,{emit:l}){const t=r,a=l,o=C(),{forwardRef:d,currentElement:f}=D();return o.titleId||(o.titleId=w(void 0,"reka-dialog-title")),o.descriptionId||(o.descriptionId=w(void 0,"reka-dialog-description")),A(()=>{o.contentElement=f,F()!==document.body&&(o.triggerElement.value=F())}),(i,n)=>(c(),_(e(N),{"as-child":"",loop:"",trapped:t.trapFocus,onMountAutoFocus:n[5]||(n[5]=s=>a("openAutoFocus",s)),onUnmountAutoFocus:n[6]||(n[6]=s=>a("closeAutoFocus",s))},{default:u(()=>[O(e(T),m({id:e(o).contentId,ref:e(d),as:i.as,"as-child":i.asChild,"disable-outside-pointer-events":i.disableOutsidePointerEvents,role:"dialog","aria-describedby":e(o).descriptionId,"aria-labelledby":e(o).titleId,"data-state":e(K)(e(o).open.value)},i.$attrs,{onDismiss:n[0]||(n[0]=s=>e(o).onOpenChange(!1)),onEscapeKeyDown:n[1]||(n[1]=s=>a("escapeKeyDown",s)),onFocusOutside:n[2]||(n[2]=s=>a("focusOutside",s)),onInteractOutside:n[3]||(n[3]=s=>a("interactOutside",s)),onPointerDownOutside:n[4]||(n[4]=s=>a("pointerDownOutside",s))}),{default:u(()=>[v(i.$slots,"default")]),_:3},16,["id","as","as-child","disable-outside-pointer-events","aria-describedby","aria-labelledby","data-state"])]),_:3},8,["trapped"]))}}),$=x,ee=g({__name:"DialogContentModal",props:{forceMount:{type:Boolean,required:!1},trapFocus:{type:Boolean,required:!1},disableOutsidePointerEvents:{type:Boolean,required:!1,default:!0},asChild:{type:Boolean,required:!1},as:{type:null,required:!1}},emits:["escapeKeyDown","pointerDownOutside","focusOutside","interactOutside","openAutoFocus","closeAutoFocus"],setup(r,{emit:l}){const t=r,a=l,o=C(),d=E(a),{forwardRef:f,currentElement:i}=D();return V(i),(n,s)=>(c(),_($,m({...t,...e(d)},{ref:e(f),"trap-focus":e(o).open.value,"disable-outside-pointer-events":t.disableOutsidePointerEvents,onCloseAutoFocus:s[0]||(s[0]=p=>{var y;p.defaultPrevented||(p.preventDefault(),(y=e(o).triggerElement.value)==null||y.focus())}),onPointerDownOutside:s[1]||(s[1]=p=>{const y=p.detail.originalEvent,P=y.button===0&&y.ctrlKey===!0;(y.button===2||P)&&p.preventDefault()}),onFocusOutside:s[2]||(s[2]=p=>{p.preventDefault()})}),{default:u(()=>[v(n.$slots,"default")]),_:3},16,["trap-focus","disable-outside-pointer-events"]))}}),te=ee,oe=g({__name:"DialogContentNonModal",props:{forceMount:{type:Boolean,required:!1},trapFocus:{type:Boolean,required:!1},disableOutsidePointerEvents:{type:Boolean,required:!1},asChild:{type:Boolean,required:!1},as:{type:null,required:!1}},emits:["escapeKeyDown","pointerDownOutside","focusOutside","interactOutside","openAutoFocus","closeAutoFocus"],setup(r,{emit:l}){const t=r,o=E(l);D();const d=C(),f=b(!1),i=b(!1);return(n,s)=>(c(),_($,m({...t,...e(o)},{"trap-focus":!1,"disable-outside-pointer-events":!1,onCloseAutoFocus:s[0]||(s[0]=p=>{var y;p.defaultPrevented||(f.value||(y=e(d).triggerElement.value)==null||y.focus(),p.preventDefault()),f.value=!1,i.value=!1}),onInteractOutside:s[1]||(s[1]=p=>{var h;p.defaultPrevented||(f.value=!0,p.detail.originalEvent.type==="pointerdown"&&(i.value=!0));const y=p.target;((h=e(d).triggerElement.value)==null?void 0:h.contains(y))&&p.preventDefault(),p.detail.originalEvent.type==="focusin"&&i.value&&p.preventDefault()})}),{default:u(()=>[v(n.$slots,"default")]),_:3},16))}}),ae=oe,se=g({__name:"DialogContent",props:{forceMount:{type:Boolean,required:!1},disableOutsidePointerEvents:{type:Boolean,required:!1,default:void 0},asChild:{type:Boolean,required:!1},as:{type:null,required:!1}},emits:["escapeKeyDown","pointerDownOutside","focusOutside","interactOutside","openAutoFocus","closeAutoFocus"],setup(r,{emit:l}){const t=r,a=l,o=C(),d=E(a),{forwardRef:f}=D();return(i,n)=>(c(),_(e(M),{present:i.forceMount||e(o).open.value},{default:u(()=>[e(o).modal.value?(c(),_(te,m({key:0,ref:e(f)},{...t,...e(d),...i.$attrs}),{default:u(()=>[v(i.$slots,"default")]),_:3},16)):(c(),_(ae,m({key:1,ref:e(f)},{...t,...e(d),...i.$attrs}),{default:u(()=>[v(i.$slots,"default")]),_:3},16))]),_:3},8,["present"]))}}),le=se,re=g({__name:"DialogOverlayImpl",props:{asChild:{type:Boolean,required:!1},as:{type:null,required:!1}},setup(r){const l=C();return S(!0),D(),(t,a)=>(c(),_(e(B),{as:t.as,"as-child":t.asChild,"data-state":e(l).open.value?"open":"closed",style:{"pointer-events":"auto"},onPointerdown:a[0]||(a[0]=j(()=>{},["left","self","prevent"]))},{default:u(()=>[v(t.$slots,"default")]),_:3},8,["as","as-child","data-state"]))}}),ne=re,ue=g({__name:"DialogOverlay",props:{forceMount:{type:Boolean,required:!1},asChild:{type:Boolean,required:!1},as:{type:null,required:!1}},setup(r){const l=C(),{forwardRef:t}=D();return(a,o)=>{var d;return(d=e(l))!=null&&d.modal.value?(c(),_(e(M),{key:0,present:a.forceMount||e(l).open.value},{default:u(()=>[O(ne,m(a.$attrs,{ref:e(t),as:a.as,"as-child":a.asChild}),{default:u(()=>[v(a.$slots,"default")]),_:3},16,["as","as-child"])]),_:3},8,["present"])):z("v-if",!0)}}}),ie=ue,de=g({__name:"DialogPortal",props:{to:{type:null,required:!1},disabled:{type:Boolean,required:!1},defer:{type:Boolean,required:!1},forceMount:{type:Boolean,required:!1}},setup(r){const l=r;return(t,a)=>(c(),_(e(L),U(W(l)),{default:u(()=>[v(t.$slots,"default")]),_:3},16))}}),pe=de,fe=g({__name:"DialogTitle",props:{asChild:{type:Boolean,required:!1},as:{type:null,required:!1,default:"h2"}},setup(r){const l=r,t=C();return D(),(a,o)=>(c(),_(e(B),m(l,{id:e(t).titleId}),{default:u(()=>[v(a.$slots,"default")]),_:3},16,["id"]))}}),ce=fe,_e=g({__name:"DialogTrigger",props:{asChild:{type:Boolean,required:!1},as:{type:null,required:!1,default:"button"}},setup(r){const l=r,t=C(),{forwardRef:a,currentElement:o}=D();return t.contentId||(t.contentId=w(void 0,"reka-dialog-content")),A(()=>{t.triggerElement.value=o.value}),(d,f)=>(c(),_(e(B),m(l,{ref:e(a),type:d.as==="button"?"button":void 0,"aria-haspopup":"dialog","aria-expanded":e(t).open.value||!1,"aria-controls":e(t).open.value?e(t).contentId:void 0,"data-state":e(t).open.value?"open":"closed",onClick:e(t).onOpenToggle}),{default:u(()=>[v(d.$slots,"default")]),_:3},16,["type","aria-expanded","aria-controls","data-state","onClick"]))}}),ve=_e;const ge={class:"help-head"},ye={class:"help-body"},Ce=g({__name:"HelpModal",props:{title:{},label:{}},setup(r){return(l,t)=>(c(),_(e(G),null,{default:u(()=>[O(e(ve),{class:"helpq","aria-label":r.label??r.title},{default:u(()=>[...t[0]||(t[0]=[q("svg",{viewBox:"0 0 24 24",width:"13",height:"13","aria-hidden":"true",fill:"none",stroke:"currentColor","stroke-width":"2.2","stroke-linecap":"round"},[q("path",{d:"M9.2 9a2.9 2.9 0 1 1 3.8 2.8c-.7.3-1 .9-1 1.6v.4"}),q("circle",{cx:"12",cy:"17.6",r:"0.9",fill:"currentColor",stroke:"none"})],-1)])]),_:1},8,["aria-label"]),O(e(pe),null,{default:u(()=>[O(e(ie),{class:"scrim help-scrim"}),O(e(le),{class:"help-modal"},{default:u(()=>[q("div",ge,[O(e(ce),{class:"help-title"},{default:u(()=>[I(X(r.title),1)]),_:1}),O(e(Q),{class:"ghost sm","aria-label":"Close"},{default:u(()=>[...t[1]||(t[1]=[I("Close",-1)])]),_:1})]),q("div",ye,[v(l.$slots,"default")])]),_:3})]),_:3})]),_:3}))}});export{Ce as _};
2
- //# sourceMappingURL=HelpModal.vue_vue_type_script_setup_true_lang-2ev6wLk8.js.map
@@ -1,2 +0,0 @@
1
- import{d as y,c as o,a as t,f as r,e as l,w as m,_ as w,i as g,v as x,g as k,u as n,y as i,t as d,x as C,F as _,s as V,r as f,C as L,o as a,D as S,j as $}from"./index-wjzRhuU3.js";import{a as A,t as N}from"./useFormat-DVXTfIS-.js";import{_ as B}from"./StateBadge.vue_vue_type_script_setup_true_lang-BsDpZsUH.js";import{_ as R}from"./SkeletonList.vue_vue_type_script_setup_true_lang-DwoeliUC.js";import{_ as F}from"./RelativeTime.vue_vue_type_script_setup_true_lang-D7n5E9jw.js";import{_ as T}from"./SelectMenu.vue_vue_type_script_setup_true_lang-CSQS6ben.js";import"./Teleport-BXE_6A8N.js";const U={class:"page-head"},D={class:"sub"},E={class:"panel"},M={class:"phead"},j={class:"searchbox"},q={key:0},I={key:0,class:"s-failed"},J={key:2,class:"cards"},z={class:"stagger"},O={"data-label":"state"},G={"data-label":"action"},H={class:"name","data-label":"stack"},K={class:"dim nowrap","data-label":"started"},P={class:"dim nowrap","data-label":"took"},Q={class:"dim","data-label":"steps"},W={key:0},X={colspan:"6",class:"mute"},nt=y({__name:"JobsView",setup(Y){const c=f(""),u=f("all"),p=L(()=>{const h=c.value.trim().toLowerCase();return i.jobs.filter(e=>u.value!=="all"&&e.state!==u.value?!1:h?e.stack.toLowerCase().includes(h)||e.action.includes(h):!0)});return(h,e)=>{const b=$("RouterLink");return a(),o("div",null,[t("div",U,[t("div",null,[e[4]||(e[4]=t("h1",null,"Jobs",-1)),t("div",D,[e[3]||(e[3]=r(" Most recent first, capped at the last 50 ",-1)),l(w,{label:"why old jobs disappear"},{default:m(()=>[...e[2]||(e[2]=[r(" The history is held in memory and a server restart clears it. A job record is the transcript of an attempt, not the truth about what exists — that truth lives in the containers themselves and in each axis's own probe. ",-1)])]),_:1})])])]),t("section",E,[t("div",M,[t("div",j,[e[5]||(e[5]=t("svg",{viewBox:"0 0 24 24",width:"15",height:"15","aria-hidden":"true"},[t("circle",{cx:"11",cy:"11",r:"7",fill:"none",stroke:"currentColor","stroke-width":"2"}),t("path",{d:"M16.5 16.5 21 21",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round"})],-1)),g(t("input",{id:"jq","onUpdate:modelValue":e[0]||(e[0]=s=>c.value=s),"data-search":"",type:"search","aria-label":"Search jobs",placeholder:"Search by stack or action",spellcheck:"false"},null,512),[[x,c.value]]),c.value?k("",!0):(a(),o("kbd",q,"/"))]),l(T,{id:"js",modelValue:u.value,"onUpdate:modelValue":e[1]||(e[1]=s=>u.value=s),label:"Filter by state",options:[{value:"all",label:"All states"},{value:"running",label:"Running"},{value:"ok",label:"Ok"},{value:"leaked",label:"Leaked"},{value:"failed",label:"Failed"}]},null,8,["modelValue"])]),n(i).jobsError?(a(),o("p",I,d(n(i).jobsError),1)):n(i).jobsLoaded?(a(),o("table",J,[e[6]||(e[6]=t("thead",null,[t("tr",null,[t("th",null,"State"),t("th",null,"Action"),t("th",null,"Stack"),t("th",null,"Started"),t("th",null,"Took"),t("th",null,"Steps")])],-1)),t("tbody",z,[(a(!0),o(_,null,V(p.value,(s,v)=>(a(),o("tr",{key:s.id,style:S({"--i":v})},[t("td",O,[l(b,{to:`/jobs/${encodeURIComponent(s.id)}`},{default:m(()=>[l(B,{state:s.state},null,8,["state"])]),_:2},1032,["to"])]),t("td",G,d(n(A)(s.action)),1),t("td",H,[l(b,{to:`/jobs/${encodeURIComponent(s.id)}`},{default:m(()=>[r(d(s.stack),1)]),_:2},1032,["to"])]),t("td",K,[l(F,{at:s.startedAt},null,8,["at"])]),t("td",P,d(n(N)(s.startedAt,s.endedAt)),1),t("td",Q,d(s.outcome?s.outcome.steps.length:"—"),1)],4))),128)),p.value.length?k("",!0):(a(),o("tr",W,[t("td",X,[n(i).jobs.length?(a(),o(_,{key:0},[r("Nothing matches this filter.")],64)):(a(),o(_,{key:1},[r("No jobs recorded.")],64))])]))])])):(a(),C(R,{key:1,rows:5}))])])}}});export{nt as default};
2
- //# sourceMappingURL=JobsView-B6RvX8WS.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"JobsView-B6RvX8WS.js","sources":["../../src/views/JobsView.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/** Job history. Polled by the shell already, so this view only filters what is in memory. */\nimport { computed, ref } from 'vue';\nimport { state } from '../composables/useControlPlane';\nimport { actionLabel, took } from '../composables/useFormat';\nimport StateBadge from '../components/StateBadge.vue';\nimport SkeletonList from '../components/SkeletonList.vue';\nimport RelativeTime from '../components/RelativeTime.vue';\nimport SelectMenu from '../components/SelectMenu.vue';\nimport InfoHint from '../components/InfoHint.vue';\nimport type { JobState } from '../api/types';\n\nconst q = ref('');\nconst only = ref<'all' | JobState>('all');\n\nconst rows = computed(() => {\n const needle = q.value.trim().toLowerCase();\n return state.jobs.filter((j) => {\n if (only.value !== 'all' && j.state !== only.value) return false;\n if (!needle) return true;\n return j.stack.toLowerCase().includes(needle) || j.action.includes(needle);\n });\n});\n</script>\n\n<template>\n <div>\n <div class=\"page-head\">\n <div>\n <h1>Jobs</h1>\n <div class=\"sub\">\n Most recent first, capped at the last 50\n <InfoHint label=\"why old jobs disappear\">\n The history is held in memory and a server restart clears it. A job record is the\n transcript of an attempt, not the truth about what exists — that truth lives in the\n containers themselves and in each axis's own probe.\n </InfoHint>\n </div>\n </div>\n </div>\n\n <section class=\"panel\">\n <!-- Same one-row toolbar as Deployments — this page had kept the old stacked-label layout,\n and two list pages with two different toolbars reads as two different products. -->\n <div class=\"phead\">\n <div class=\"searchbox\">\n <svg viewBox=\"0 0 24 24\" width=\"15\" height=\"15\" aria-hidden=\"true\">\n <circle cx=\"11\" cy=\"11\" r=\"7\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" />\n <path d=\"M16.5 16.5 21 21\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n <input\n id=\"jq\"\n v-model=\"q\"\n data-search\n type=\"search\"\n aria-label=\"Search jobs\"\n placeholder=\"Search by stack or action\"\n spellcheck=\"false\"\n />\n <kbd v-if=\"!q\">/</kbd>\n </div>\n <SelectMenu\n id=\"js\"\n v-model=\"only\"\n label=\"Filter by state\"\n :options=\"[\n { value: 'all', label: 'All states' },\n { value: 'running', label: 'Running' },\n { value: 'ok', label: 'Ok' },\n { value: 'leaked', label: 'Leaked' },\n { value: 'failed', label: 'Failed' },\n ]\"\n />\n </div>\n\n <p v-if=\"state.jobsError\" class=\"s-failed\">{{ state.jobsError }}</p>\n <SkeletonList v-else-if=\"!state.jobsLoaded\" :rows=\"5\" />\n\n <table v-else class=\"cards\">\n <thead>\n <tr>\n <th>State</th>\n <th>Action</th>\n <th>Stack</th>\n <th>Started</th>\n <th>Took</th>\n <th>Steps</th>\n </tr>\n </thead>\n <tbody class=\"stagger\">\n <tr v-for=\"(j, i) in rows\" :key=\"j.id\" :style=\"{ '--i': i }\">\n <td data-label=\"state\">\n <RouterLink :to=\"`/jobs/${encodeURIComponent(j.id)}`\">\n <StateBadge :state=\"j.state\" />\n </RouterLink>\n </td>\n <td data-label=\"action\">{{ actionLabel(j.action) }}</td>\n <td class=\"name\" data-label=\"stack\">\n <RouterLink :to=\"`/jobs/${encodeURIComponent(j.id)}`\">{{ j.stack }}</RouterLink>\n </td>\n <td class=\"dim nowrap\" data-label=\"started\"><RelativeTime :at=\"j.startedAt\" /></td>\n <td class=\"dim nowrap\" data-label=\"took\">{{ took(j.startedAt, j.endedAt) }}</td>\n <td class=\"dim\" data-label=\"steps\">{{ j.outcome ? j.outcome.steps.length : '—' }}</td>\n </tr>\n <tr v-if=\"!rows.length\">\n <td colspan=\"6\" class=\"mute\">\n <template v-if=\"state.jobs.length\">Nothing matches this filter.</template>\n <template v-else>No jobs recorded.</template>\n </td>\n </tr>\n </tbody>\n </table>\n </section>\n </div>\n</template>\n"],"names":["q","ref","only","rows","computed","needle","state","j","_createElementBlock","_createElementVNode","_hoisted_1","_cache","_hoisted_2","_createVNode","InfoHint","_hoisted_3","_hoisted_4","_hoisted_5","$event","_openBlock","SelectMenu","_unref","_hoisted_7","_toDisplayString","_hoisted_8","_hoisted_9","_Fragment","_renderList","i","_hoisted_10","_component_RouterLink","StateBadge","_hoisted_11","_hoisted_12","_createTextVNode","_hoisted_13","RelativeTime","_hoisted_14","took","_hoisted_15","_hoisted_16","_hoisted_17","_createBlock","SkeletonList"],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- import{d as x,H as b,Y as _,K as T,c as s,a,t as n,f as C,g as c,W as B,F as m,s as H,r as y,a2 as N,J as g,C as S,o as l,E as V}from"./index-wjzRhuU3.js";const F={class:"lv"},j={class:"lv-bar"},E={class:"lv-count"},L={key:0,class:"badge running"},z=["disabled"],D={key:0,class:"lv-empty"},J={key:0,class:"lv-sep"},K=["title"],M=["title"],P={class:"lv-msg"},W=x({__name:"LogViewer",props:{rows:{},live:{type:Boolean},copyText:{},emptyText:{}},setup(i){const r=i,d=y(null),u=y(!0);function f(){const t=d.value;return!!t&&t.scrollHeight-t.scrollTop-t.clientHeight<24}function k(){u.value=f()}async function v(){await N();const t=d.value;t&&u.value&&(t.scrollTop=t.scrollHeight)}b(()=>r.rows.length,v),_(v);function h(){u.value=!0,v()}async function w(){const t=r.copyText??r.rows.filter(o=>!o.separator).map(o=>[o.time,o.gutter,o.text].filter(Boolean).join(" ")).join(`
2
- `);try{await navigator.clipboard.writeText(t),g("ok","Copied.")}catch{g("error","Could not copy — your browser blocked clipboard access.")}}const p=S(()=>r.rows.filter(t=>!t.separator).length);return T(()=>{}),(t,o)=>(l(),s("div",F,[a("div",j,[a("span",E,n(p.value)+" line"+n(p.value===1?"":"s"),1),i.live?(l(),s("span",L,[...o[0]||(o[0]=[a("span",{class:"dot pulse"},null,-1),C("live",-1)])])):c("",!0),o[1]||(o[1]=a("span",{class:"grow"},null,-1)),i.live&&!u.value?(l(),s("button",{key:1,class:"ghost sm",onClick:h},"↓ Follow")):c("",!0),a("button",{class:"ghost sm",disabled:!p.value,onClick:w},"Copy",8,z),B(t.$slots,"actions")]),a("div",{ref_key:"box",ref:d,class:"lv-box",role:"log","aria-live":"polite",onScrollPassive:k},[i.rows.length?c("",!0):(l(),s("p",D,n(i.emptyText??"No output."),1)),(l(!0),s(m,null,H(i.rows,e=>(l(),s(m,{key:e.key},[e.separator?(l(),s("div",J,[a("span",null,n(e.text),1)])):(l(),s("div",{key:1,class:V(["lv-row",e.tone])},[e.time!==void 0?(l(),s("span",{key:0,class:"lv-time",title:e.timeTitle},n(e.time),9,K)):c("",!0),e.gutter!==void 0?(l(),s("span",{key:1,class:"lv-gutter",title:e.gutterTitle},n(e.gutter),9,M)):c("",!0),a("span",P,n(e.text),1)],2))],64))),128))],544)]))}});export{W as _};
3
- //# sourceMappingURL=LogViewer.vue_vue_type_script_setup_true_lang-B5K26k3c.js.map
@@ -1,2 +0,0 @@
1
- import{d as Z,H as ee,c as i,a as t,f as n,e as h,w as g,_ as T,x as D,g as c,F as f,t as r,s as E,i as L,v as X,r as v,C as S,A as y,B as _,o as l,D as te,u as R,E as F,J as U}from"./index-wjzRhuU3.js";import{s as I,c as se}from"./useFormat-DVXTfIS-.js";import{_ as M}from"./ActionButton.vue_vue_type_script_setup_true_lang-CeingrPV.js";import{_ as O}from"./ErrorNote.vue_vue_type_script_setup_true_lang-DT5SbSbT.js";import{_ as ae}from"./SkeletonList.vue_vue_type_script_setup_true_lang-DwoeliUC.js";import{_ as le}from"./RelativeTime.vue_vue_type_script_setup_true_lang-D7n5E9jw.js";import{_ as ie}from"./SelectMenu.vue_vue_type_script_setup_true_lang-CSQS6ben.js";import"./Teleport-BXE_6A8N.js";const oe={class:"page-head"},ne={class:"sub"},re={key:1,class:"panel"},de={key:0,class:"banner ok"},ue={class:"code"},ve={class:"row"},ce={class:"panel"},pe={key:1,class:"cards"},he={class:"stagger"},me={class:"name","data-label":"name"},fe={class:"mute",style:{"font-size":"var(--t-sm)"}},ye={"data-label":"events"},ke={key:0,class:"badge"},ge={key:1},_e={"data-label":"last delivery"},be={key:0,class:"mute"},we={key:2,class:"mute",style:{"font-size":"var(--t-sm)"}},$e={"data-label":""},xe={class:"row",style:{"justify-content":"flex-end"}},Ce={key:0,class:"badge off"},Te=["onClick"],Ee=["onClick"],Ne=["onClick"],Ve={colspan:"4"},Ae={key:0,class:"kvlist"},De={class:"k"},Se={class:"v"},Re={class:"mute",style:{"font-size":"var(--t-sm)"}},Ue={key:0,class:"s-failed",style:{"font-size":"var(--t-sm)"}},ze={key:1,class:"mute"},Be={key:2,class:"mute"},He={class:"panel"},Pe={key:0,class:"field",style:{"max-width":"320px"}},je={class:"field",style:{"max-width":"380px"}},Le=["for"],Xe=["id","onUpdate:modelValue","placeholder"],Fe={class:"section",style:{margin:"var(--s5) 0 var(--s3)"}},Ie={class:"row"},Me={class:"check"},Oe=["checked"],We={key:1,class:"check-grid"},qe=["checked","onChange"],Je={class:"row",style:{"margin-top":"var(--s4)"}},Ye={key:3,class:"hint"},Ge={key:4,class:"hint"},ot=Z({__name:"NotifiersView",setup(Ke){const N=v([]),k=v(null),z=v(!1),p=v(""),B=v(!1),b=v(null),o=v({name:"",type:"webhook",events:[],config:{}}),w=v(!1),x=v(""),m=v(null),V=v([]),W=S(()=>{var a;return(((a=k.value)==null?void 0:a.types)??[]).map(e=>({value:e.kind,label:e.label}))}),A=S(()=>{var a;return((a=k.value)==null?void 0:a.types.find(e=>e.kind===o.value.type))??null});ee(()=>o.value.type,()=>{o.value.config={}});const q=S(()=>{var a;return!w.value&&!!o.value.name.trim()&&o.value.events.length>0&&(((a=A.value)==null?void 0:a.fields)??[]).every(e=>{var u;return!e.required||!!((u=o.value.config[e.key])!=null&&u.trim())})});async function $(){const[a,e]=await Promise.all([y.get("/api/notifiers"),y.get("/api/notifiers/meta")]);if(z.value=!0,a.status===404||e.status===404){B.value=!0;return}if(!a.ok){p.value=_(a,"load the notifiers");return}p.value="",N.value=a.body.notifiers??[],e.ok&&(k.value=e.body)}$();function H(a){const e=o.value.events.indexOf(a);e===-1?o.value.events.push(a):o.value.events.splice(e,1)}async function J(){w.value=!0,x.value="";const a=await y.post("/api/notifiers",{name:o.value.name.trim(),type:o.value.type,events:o.value.events,config:o.value.config});if(w.value=!1,!a.ok){x.value=_(a,"register this notifier");return}b.value=a.body.secret?{name:a.body.notifier.name,secret:a.body.secret}:null,o.value={name:"",type:o.value.type,events:[],config:{}},$()}async function Y(a,e){const u=await y.patch(`/api/notifiers/${a.id}`,{enabled:e});u.ok||(p.value=_(u,"update this notifier")),$()}async function G(a){const e=await y.del(`/api/notifiers/${a.id}`);if(!e.ok){p.value=_(e,"delete this notifier");return}m.value===a.id&&(m.value=null),U("ok",`Removed ${a.name}.`),$()}async function K(a){const e=await y.post(`/api/notifiers/${a.id}/test`,{});if(!e.ok){p.value=_(e,"send a test delivery");return}const u=e.body.result;u.ok?U("ok",`${a.name} accepted the test delivery.`):U("error",`${a.name}: ${u.error??`HTTP ${u.status}`}`),$()}async function Q(a){if(m.value===a.id){m.value=null;return}const e=await y.get(`/api/notifiers/${a.id}/deliveries`);if(!e.ok){p.value=_(e,"load the delivery log");return}V.value=e.body.deliveries??[],m.value=a.id}return(a,e)=>{var u,P,j;return l(),i("div",null,[t("div",oe,[t("div",null,[e[6]||(e[6]=t("h1",null,"Notifiers",-1)),t("div",ne,[e[5]||(e[5]=n(" Where events on this host get sent ",-1)),h(T,{label:"what a notifier is"},{default:g(()=>[...e[4]||(e[4]=[n(" A registration that receives events — a teardown that leaked, a deployment created, a job that failed. Webhooks today; the server decides what other kinds exist, and this page renders whatever it offers. ",-1)])]),_:1})])])]),p.value?(l(),D(O,{key:0,text:p.value,title:"Could not load the notifiers."},null,8,["text"])):c("",!0),B.value?(l(),i("section",re,[...e[7]||(e[7]=[t("div",{class:"banner plain"},[t("b",null,"This server has no notifiers."),t("p",null,"It is an older build of pstack. Upgrade the host to register webhooks.")],-1)])])):(l(),i(f,{key:2},[b.value?(l(),i("div",de,[t("b",null,"Signing secret for “"+r(b.value.name)+"” — copy it now.",1),t("p",null,[e[9]||(e[9]=n(" This is the only time it is shown — the server keeps no way to show it again. Your receiver uses it to check that a delivery really came from here. ",-1)),h(T,{label:"how a receiver checks it"},{default:g(()=>[...e[8]||(e[8]=[n(" Each delivery carries a signature header computed from this secret and the exact body sent. Recompute it on your side and compare; a mismatch means the delivery was not sent by this host, or was altered on the way. ",-1)])]),_:1})]),t("pre",ue,r(b.value.secret),1),t("div",ve,[t("button",{class:"btn",onClick:e[0]||(e[0]=s=>b.value=null)},"I have stored it")])])):c("",!0),t("section",ce,[e[12]||(e[12]=t("div",{class:"phead"},[t("h2",{class:"section"},"Registered")],-1)),z.value?N.value.length?(l(),i("table",pe,[e[11]||(e[11]=t("thead",null,[t("tr",null,[t("th",null,"Name"),t("th",null,"Events"),t("th",null,"Last delivery"),t("th")])],-1)),t("tbody",he,[(l(!0),i(f,null,E(N.value,(s,C)=>(l(),i(f,{key:s.id},[t("tr",{style:te({"--i":C})},[t("td",me,[n(r(s.name)+" ",1),t("div",fe,r(R(I)(s.type))+" · "+r(String(s.config.url??s.config.webhookUrl??"")),1)]),t("td",ye,[s.events.includes("*")?(l(),i("span",ke,"all events")):(l(),i("span",ge,r(s.events.join(", ")),1))]),t("td",_e,[s.lastStatus?(l(),i("span",{key:1,class:F(s.lastStatus==="ok"?"s-ok":"s-failed")},r(s.lastStatus),3)):(l(),i("span",be,"never")),s.lastAt?(l(),i("div",we,[h(le,{at:s.lastAt},null,8,["at"])])):c("",!0)]),t("td",$e,[t("div",xe,[s.enabled?c("",!0):(l(),i("span",Ce,"disabled")),t("button",{class:"ghost sm",onClick:d=>Q(s)},r(m.value===s.id?"Hide":"Deliveries"),9,Te),t("button",{class:"ghost sm",onClick:d=>K(s)},"Test",8,Ee),t("button",{class:"ghost sm",onClick:d=>Y(s,!s.enabled)},r(s.enabled?"Disable":"Enable"),9,Ne),h(M,{variant:"danger",onClick:d=>G(s)},{default:g(()=>[...e[10]||(e[10]=[n("Remove",-1)])]),_:1},8,["onClick"])])])],4),m.value===s.id?(l(),i("tr",{key:`d${s.id}`},[t("td",Ve,[V.value.length?(l(),i("ul",Ae,[(l(!0),i(f,null,E(V.value,d=>(l(),i("li",{key:d.id},[t("span",De,[t("span",{class:F(d.status==="ok"?"s-ok":"s-failed")},r(R(I)(d.status)),3)]),t("span",Se,[n(r(d.event)+" ",1),t("span",Re,[n(" · "+r(R(se)(d.createdAt))+" · "+r(d.attempts)+" attempt(s)",1),d.responseCode?(l(),i(f,{key:0},[n(" · HTTP "+r(d.responseCode),1)],64)):c("",!0)]),d.error?(l(),i("div",Ue,r(d.error),1)):c("",!0)])]))),128))])):(l(),i("p",ze,"Nothing delivered yet."))])])):c("",!0)],64))),128))])])):(l(),i("p",Be," Nothing registered. Events still happen — nobody is being told about them. ")):(l(),D(ae,{key:0,rows:2}))]),t("section",He,[e[20]||(e[20]=t("h2",{class:"section",style:{"margin-bottom":"var(--s3)"}},"Add a notifier",-1)),k.value&&k.value.types.length>1?(l(),i("div",Pe,[e[13]||(e[13]=t("label",{for:"ty"},"Type",-1)),h(ie,{modelValue:o.value.type,"onUpdate:modelValue":e[1]||(e[1]=s=>o.value.type=s),id:"ty",label:"Notifier type",options:W.value},null,8,["modelValue","options"])])):c("",!0),t("div",je,[e[14]||(e[14]=t("label",{for:"nn"},"Name",-1)),L(t("input",{id:"nn","onUpdate:modelValue":e[2]||(e[2]=s=>o.value.name=s),type:"text",placeholder:"ops-slack-bridge",spellcheck:"false"},null,512),[[X,o.value.name,void 0,{trim:!0}]])]),(l(!0),i(f,null,E(((u=A.value)==null?void 0:u.fields)??[],s=>(l(),i("div",{key:s.key,class:"field",style:{"max-width":"380px"}},[t("label",{for:`cfg-${s.key}`},r(s.label),9,Le),L(t("input",{id:`cfg-${s.key}`,"onUpdate:modelValue":C=>o.value.config[s.key]=C,type:"text",placeholder:s.placeholder,spellcheck:"false"},null,8,Xe),[[X,o.value.config[s.key],void 0,{trim:!0}]])]))),128)),t("h2",Fe,[e[16]||(e[16]=n(" Events ",-1)),h(T,{label:"which events to pick"},{default:g(()=>[...e[15]||(e[15]=[t("b",null,"All events",-1),n(" also covers events added in later versions — a specific list does not, and the failure mode of that is silence nobody can explain. ",-1),t("code",null,"job.leaked",-1),n(" is the one worth alerting on: a teardown ran and something survived it. ",-1)])]),_:1})]),t("div",Ie,[t("label",Me,[t("input",{type:"checkbox",checked:o.value.events.includes("*"),onChange:e[3]||(e[3]=s=>H("*"))},null,40,Oe),e[17]||(e[17]=n(" All events ",-1))])]),o.value.events.includes("*")?c("",!0):(l(),i("div",We,[(l(!0),i(f,null,E(((P=k.value)==null?void 0:P.events)??[],s=>(l(),i("label",{key:s,class:"check"},[t("input",{type:"checkbox",checked:o.value.events.includes(s),onChange:C=>H(s)},null,40,qe),n(" "+r(s),1)]))),128))])),x.value?(l(),D(O,{key:2,text:x.value,title:"Could not register this notifier."},null,8,["text"])):c("",!0),t("div",Je,[h(M,{variant:"primary",pending:w.value,disabled:!q.value,onClick:J},{default:g(()=>[n(r(w.value?"Registering…":"Register"),1)]),_:1},8,["pending","disabled"])]),((j=A.value)==null?void 0:j.signs)!==!1?(l(),i("p",Ye,[e[19]||(e[19]=n(" Deliveries are signed with a secret shown once at registration, retried twice on failure, and logged here. ",-1)),h(T,{label:"how a receiver verifies a delivery"},{default:g(()=>[...e[18]||(e[18]=[n(" Recompute ",-1),t("code",null,"HMAC-SHA256(secret, `${timestamp}.${rawBody}`)",-1),n(" and compare against ",-1),t("code",null,"X-Pstack-Signature",-1),n(", using the ",-1),t("em",null,"raw",-1),n(" body — re-serialising it changes the bytes. Reject anything whose ",-1),t("code",null,"X-Pstack-Timestamp",-1),n(" is more than five minutes old, and dedupe on ",-1),t("code",null,"X-Pstack-Delivery",-1),n(": delivery is at-least-once, and that id is stable across retries. ",-1)])]),_:1})])):(l(),i("p",Ge," The webhook URL is the credential — it is stored write-only and scrubbed from logs, and no signing secret is involved. Deliveries are retried twice on failure and logged here. "))])],64))])}}});export{ot as default};
2
- //# sourceMappingURL=NotifiersView-B53fERhd.js.map